@anyforge/control 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +70 -70
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
`),console.log(
|
|
4
|
-
`),{label:"Claude Code usage telemetry (global)",path:n})}async function
|
|
5
|
-
`),o="";try{o=await P.readFile(e,"utf8")}catch{}let i;return o.includes(Oe)?i=o.replace(new RegExp(`${Oe}[\\s\\S]*?${
|
|
2
|
+
var Ei=Object.defineProperty;var _i=(t,e)=>()=>(t&&(e=t(t=0)),e);var $i=(t,e)=>{for(var n in e)Ei(t,n,{get:e[n],enumerable:!0})};var ir={};$i(ir,{default:()=>pc});var pc,sr=_i(()=>{pc={name:"@anyforge/control",version:"0.6.1",description:"AnyForge CLI \u2014 hosted Oracle conversations, a governed LLM proxy, and a scriptable client for approvals, crews, work items and workflows.",license:"Apache-2.0",homepage:"https://anyforge.ai",repository:{type:"git",url:"git+https://github.com/pootonline/sovereign-engineering.git",directory:"packages/control/cli"},publishConfig:{access:"public"},type:"module",main:"dist/cli.js",bin:{anyforge:"dist/cli.js",control:"dist/cli.js"},files:["dist","README.md"],scripts:{build:"esbuild src/cli.ts --bundle --minify --platform=node --format=esm --outfile=dist/cli.js --packages=external && chmod +x dist/cli.js","type-check":"tsc --noEmit",test:"npm run build && node scripts/test.mjs",dev:"tsx src/cli.ts",prepublishOnly:"npm run build","publish:beta":"npm publish --access public --tag beta","publish:stable":"npm publish --access public"},engines:{node:">=22.19.0"},dependencies:{"@earendil-works/pi-tui":"^0.87.1",kleur:"^4.1.5",open:"^10.0.0",prompts:"^2.4.2","proper-lockfile":"^4.1.2"},devDependencies:{"@types/node":"^22.20.0","@types/prompts":"^2.4.9","@types/proper-lockfile":"^4.1.4",esbuild:"^0.25.0","node-pty":"^1.1.0",tsx:"^4.7.0",typescript:"^7.0.2"}}});import{red as fi,yellow as Nc,dim as xt,bold as B}from"kleur/colors";import{execFileSync as On}from"child_process";import Bi from"open";import vn from"prompts";import{green as et,dim as L,bold as Z,yellow as ke,cyan as Lt}from"kleur/colors";import{promises as _t}from"fs";import{homedir as Pi}from"os";import{join as yr,dirname as Jc}from"path";var vr=yr(Pi(),".anyforge"),hn=yr(vr,"credentials");async function Or(t){await _t.mkdir(vr,{recursive:!0,mode:448}),await _t.writeFile(hn,JSON.stringify(t,null,2),{mode:384})}async function ve(){try{let t=await _t.readFile(hn,"utf8");return JSON.parse(t)}catch(t){if(t.code==="ENOENT")return null;throw t}}async function br(){try{return await _t.unlink(hn),!0}catch(t){if(t.code==="ENOENT")return!1;throw t}}import{promises as P}from"fs";import{execFileSync as Li}from"child_process";import{homedir as le}from"os";import{join as M}from"path";import $t from"prompts";import{dim as X,green as yn,yellow as Pt}from"kleur/colors";var Oe="# === AnyForge Control \u2014 added by `anyforge init` ===",Ze="# === end AnyForge Control ===",xe=".anyforge-bak",Fi=/claude_(max|pro|team|enterprise)/i,Ni=["CLAUDE_CODE_ENABLE_TELEMETRY","OTEL_METRICS_EXPORTER","OTEL_EXPORTER_OTLP_PROTOCOL","OTEL_EXPORTER_OTLP_ENDPOINT","OTEL_EXPORTER_OTLP_HEADERS","OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"];async function Sr(t){let e=[],n=await qi(t);if(n&&e.push(n),t.scope==="repo"){let r=await Mi(t);return r&&e.push(r),e}for(let r of ji){let o=await r.detect();if(!(!o||!(await $t({type:"confirm",name:"go",message:`Patch ${r.label} via shell rc (${X(o.path)}) ?`,initial:!0})).go))try{await r.patch(o,t),e.push({label:r.label,path:o.path}),console.log(yn(" \u2714")+" "+r.label)}catch(s){console.warn(" \u26A0 Skipped "+r.label+": "+s.message)}}return e}async function qi(t){let e=t.scope==="repo"&&t.repoRoot?{dir:M(t.repoRoot,".claude"),file:"settings.local.json"}:{dir:M(le(),".claude"),file:"settings.json"},n=M(e.dir,e.file);if(!(await $t({type:"confirm",name:"go",message:`Patch Claude Code config at ${X(n)} ?`,initial:!0})).go)return null;await P.mkdir(e.dir,{recursive:!0});let o=await P.readFile(n,"utf8").catch(()=>"{}"),i;try{i=JSON.parse(o)}catch{i={}}let s=i.env??{},a=s.ANTHROPIC_BASE_URL;return a&&!a.includes(t.endpoint)&&(a.includes("localhost")||a.includes("127.0.0.1")||a.includes("0.0.0.0"))&&(console.log(),console.log(Pt(" \u26A0 Local LLM proxy detected: ")+X(a)),console.log(X(" AnyForge only routes Anthropic Claude models. Local models (Ollama,")),console.log(X(" LM Studio, etc.) will not work in Claude Code after this patch.")),console.log(X(" To restore: remove ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN")),console.log(X(` from ${n}`)),console.log(),!(await $t({type:"confirm",name:"go",message:"Overwrite existing local LLM proxy config?",initial:!1})).go)?null:(await re(n)&&!await re(n+xe)&&await P.copyFile(n,n+xe),s.ANTHROPIC_BASE_URL=`${t.endpoint}/v1/anthropic`,s.ANTHROPIC_AUTH_TOKEN=t.apiKey,delete s.ANTHROPIC_API_KEY,i.env=s,await P.writeFile(n,JSON.stringify(i,null,2)+`
|
|
3
|
+
`),console.log(yn(" \u2714")+" Claude Code"),{label:t.scope==="repo"?"Claude Code (repo)":"Claude Code (global)",path:n})}async function Ir(t){let e=M(le(),".claude"),n=M(e,"settings.json");await P.mkdir(e,{recursive:!0});let r=await P.readFile(n,"utf8").catch(()=>"{}"),o;try{o=JSON.parse(r)}catch{o={}}let i=o.env??{},s=i.OTEL_EXPORTER_OTLP_ENDPOINT;return s&&!wn(s,Er(t.endpoint))?(console.log(Pt(" \u26A0 An OpenTelemetry endpoint is already configured: ")+X(s)),console.log(X(" Leaving it untouched. To send Claude Code usage to AnyForge, point")),console.log(X(" OTEL_EXPORTER_OTLP_ENDPOINT at "+t.endpoint+"/api/otel")),null):(await re(n)&&!await re(n+xe)&&await P.copyFile(n,n+xe),i.CLAUDE_CODE_ENABLE_TELEMETRY="1",i.OTEL_METRICS_EXPORTER="otlp",i.OTEL_EXPORTER_OTLP_PROTOCOL="http/json",i.OTEL_EXPORTER_OTLP_ENDPOINT=`${t.endpoint}/api/otel`,i.OTEL_EXPORTER_OTLP_HEADERS=`Authorization=Bearer ${t.apiKey}`,i.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="delta",o.env=i,await P.writeFile(n,JSON.stringify(o,null,2)+`
|
|
4
|
+
`),{label:"Claude Code usage telemetry (global)",path:n})}async function Mi(t){if(!t.repoRoot)return null;let e=M(t.repoRoot,".env");if(!(await $t({type:"confirm",name:"go",message:`Write AnyForge env block to ${X(e)} ?`,initial:!0})).go)return null;let r=[Oe,`ANYFORGE_API_KEY=${t.apiKey}`,`ANTHROPIC_BASE_URL=${t.endpoint}/v1/anthropic`,`ANTHROPIC_AUTH_TOKEN=${t.apiKey}`,`OPENAI_BASE_URL=${t.endpoint}/v1/openai`,`OPENAI_API_KEY=${t.apiKey}`,Ze,""].join(`
|
|
5
|
+
`),o="";try{o=await P.readFile(e,"utf8")}catch{}let i;return o.includes(Oe)?i=o.replace(new RegExp(`${Oe}[\\s\\S]*?${Ze}\\n?`),r):o.length===0?i=r:i=o.endsWith(`
|
|
6
6
|
`)?`${o}${r}`:`${o}
|
|
7
|
-
${r}`,i!==o&&await P.writeFile(e,i),await
|
|
8
|
-
`).map(i=>i.trim()).some(i=>i===".env"||i==="/.env"||i==="*.env")||console.log(
|
|
9
|
-
`);for(let n of[".zshrc",".bashrc"]){let r=M(le(),n);if(!await re(r))continue;let o=await P.readFile(r,"utf8"),i;o.includes(Oe)?i=o.replace(new RegExp(`${Oe}[\\s\\S]*?${
|
|
7
|
+
${r}`,i!==o&&await P.writeFile(e,i),await Ui(t.repoRoot),console.log(yn(" \u2714")+" .env"),{label:".env (repo)",path:e}}async function Ui(t){let e=M(t,".gitignore");try{(await P.readFile(e,"utf8")).split(`
|
|
8
|
+
`).map(i=>i.trim()).some(i=>i===".env"||i==="/.env"||i==="*.env")||console.log(Pt(" \u26A0 .env is not in .gitignore \u2014 add it before committing."))}catch{console.log(Pt(" \u26A0 No .gitignore found \u2014 make sure .env is excluded before committing."))}}var ji=[{label:"Cursor (shell hint)",async detect(){let t=M(le(),".cursor");return await re(t)?{path:".cursor (shell hint)"}:null},async patch(t,e){await Rr(e)}},{label:"Cline / Continue (shell hint)",async detect(){let t=await re(M(le(),".cline")),e=await re(M(le(),".continue"));return t||e?{path:"~/.cline or ~/.continue (shell hint)"}:null},async patch(t,e){await Rr(e)}}];async function Rr(t){let e=[Oe,`export ANYFORGE_API_KEY="${t.apiKey}"`,`export ANTHROPIC_BASE_URL="${t.endpoint}/v1/anthropic"`,`export ANTHROPIC_AUTH_TOKEN="${t.apiKey}"`,`export OPENAI_BASE_URL="${t.endpoint}/v1/openai"`,`export OPENAI_API_KEY="${t.apiKey}"`,"unset ANTHROPIC_API_KEY 2>/dev/null || true",Ze,""].join(`
|
|
9
|
+
`);for(let n of[".zshrc",".bashrc"]){let r=M(le(),n);if(!await re(r))continue;let o=await P.readFile(r,"utf8"),i;o.includes(Oe)?i=o.replace(new RegExp(`${Oe}[\\s\\S]*?${Ze}\\n?`),e):i=o.endsWith(`
|
|
10
10
|
`)?`${o}
|
|
11
11
|
${e}`:`${o}
|
|
12
12
|
|
|
13
|
-
${e}`,i!==o&&await P.writeFile(r,i)}}async function re(t){try{return await P.access(t),!0}catch{return!1}}async function
|
|
14
|
-
`),!0):!1}async function
|
|
13
|
+
${e}`,i!==o&&await P.writeFile(r,i)}}async function re(t){try{return await P.access(t),!0}catch{return!1}}async function Cr(){try{let t=await P.readFile(M(le(),".claude.json"),"utf8"),n=JSON.parse(t).oauthAccount,r=n?.organizationType??"";if(n&&Fi.test(r))return{isSubscription:!0,plan:/max/i.test(r)?"Max":/pro/i.test(r)?"Pro":/enterprise/i.test(r)?"Enterprise":/team/i.test(r)?"Team":r,email:n.emailAddress??null}}catch{}return{isSubscription:!1,plan:null,email:null}}async function Tr(t={}){let e=t.endpoint?Er(t.endpoint):null,n=[],r=M(le(),".claude","settings.json");await Ar(r,e)&&n.push(r);for(let i of[".zshrc",".bashrc"]){let s=M(le(),i);await xr(s)&&n.push(s)}let o=t.repoRoot??Di(process.cwd());if(o){let i=M(o,".claude","settings.local.json");await Ar(i,e)&&n.push(i);let s=M(o,".env");await xr(s)&&n.push(s)}return{reverted:n}}function wn(t,e){return t?t.includes("anyforge")?!0:e?t.includes(e):!1:!1}async function Ar(t,e){if(!await re(t))return!1;if(await re(t+xe))return await P.copyFile(t+xe,t),await P.unlink(t+xe).catch(()=>{}),!0;let n;try{n=JSON.parse(await P.readFile(t,"utf8"))}catch{return!1}let r=n.env;if(!r)return!1;let o=!1,i=[["ANTHROPIC_BASE_URL","ANTHROPIC_AUTH_TOKEN"],["OPENAI_BASE_URL","OPENAI_API_KEY"]];for(let[s,a]of i)wn(r[s],e)&&(delete r[s],delete r[a],o=!0);if(r.ANYFORGE_API_KEY&&(delete r.ANYFORGE_API_KEY,o=!0),wn(r.OTEL_EXPORTER_OTLP_ENDPOINT,e))for(let s of Ni)s in r&&(delete r[s],o=!0);return o?(Object.keys(r).length===0&&delete n.env,await P.writeFile(t,JSON.stringify(n,null,2)+`
|
|
14
|
+
`),!0):!1}async function xr(t){let e;try{e=await P.readFile(t,"utf8")}catch{return!1}if(!e.includes(Oe))return!1;let n=e.replace(new RegExp(`\\n?${kr(Oe)}[\\s\\S]*?${kr(Ze)}\\n?`),`
|
|
15
15
|
`).replace(/\n{3,}/g,`
|
|
16
16
|
|
|
17
|
-
`);return await P.writeFile(t,n),!0}function kr(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function
|
|
18
|
-
`),n=0);let o=await(await fetch(t.pollUrl)).json();if(o.status==="authorized"&&o.data)return process.stdout.write(" "+
|
|
17
|
+
`);return await P.writeFile(t,n),!0}function kr(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Er(t){try{return new URL(t).host}catch{return null}}function Di(t){try{return Li("git",["rev-parse","--show-toplevel"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}var Gi=2e3,zi=900*1e3;async function $r(t){let{endpoint:e}=t;console.log(Z("AnyForge Control \u2014 device authorisation")),console.log(L(` endpoint: ${e}`));let n=process.cwd(),r=_r(n),o=r?Yi(r):null,s=await(await fetch(`${e}/api/cli/init`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({repo:o})})).json();if(!s.ok||!s.data)throw new Error(`Could not start the authorisation flow: ${s.error??"unknown error"}`);let{code:a,authUrl:c,pollUrl:p}=s.data;console.log(),console.log("Open this URL in your browser to authorise:"),console.log(` ${Lt(c)}`),console.log(L(` Code: ${a}`)),console.log();try{await Bi(c)}catch{}let l=await Wi({pollUrl:p,endpoint:e});await Or(l),console.log(et("\u2714")+" API key saved to "+L("~/.anyforge/credentials"));let u=await Cr();if(u.isSubscription&&!t.force){await Ki(u,e,l.apiKey);return}let v=process.cwd(),k=_r(v),x=await Hi(k),b=await Sr({endpoint:e,apiKey:l.apiKey,scope:x,repoRoot:k});b.length===0?(console.log(ke("No agent configs were patched.")),console.log(L(" Set ANTHROPIC_BASE_URL="+e+"/v1/anthropic and")),console.log(L(" ANTHROPIC_AUTH_TOKEN=<your AnyForge key> manually if needed."))):Ji(b),console.log(),u.isSubscription&&t.force&&(console.log(ke(` \u26A0 --force: your Claude ${u.plan??""} subscription login is now shadowed`)),console.log(ke(" by the AnyForge token \u2014 Claude Code will use the BYOK proxy, which")),console.log(ke(" needs an Anthropic API key on your company. Run ")+Z("anyforge logout")),console.log(ke(" to revert and restore your subscription."))),x==="repo"&&(console.log(L(" Re-run this command in another repo to patch it too,")),console.log(L(' or run from any directory and choose "global" to install system-wide.'))),console.log(Z("Done.")+" Visit "+Lt(`${e}/usage`)+" to see your traffic.")}async function Wi(t){let e=Date.now();process.stdout.write("Waiting for browser authorisation\u2026 ");let n=0;for(;Date.now()-e<zi;){await new Promise(i=>setTimeout(i,Gi)),process.stdout.write("."),n+=1,n>40&&(process.stdout.write(`
|
|
18
|
+
`),n=0);let o=await(await fetch(t.pollUrl)).json();if(o.status==="authorized"&&o.data)return process.stdout.write(" "+et("done")+`
|
|
19
19
|
`),{apiKey:o.data.apiKey,companyId:o.data.companyId,endpoint:t.endpoint,savedAt:new Date().toISOString()};if(o.status==="expired"||o.status==="not_found")throw process.stdout.write(`
|
|
20
|
-
`),new Error(`Authorisation ${o.status}. Re-run \`anyforge init\`.`)}throw new Error("Authorisation timed out (15 min). Re-run `anyforge init`.")}async function
|
|
21
|
-
`)}function
|
|
22
|
-
`)),process.exit(1));let n=
|
|
23
|
-
`);let r=await
|
|
20
|
+
`),new Error(`Authorisation ${o.status}. Re-run \`anyforge init\`.`)}throw new Error("Authorisation timed out (15 min). Re-run `anyforge init`.")}async function Ki(t,e,n){let r=t.email?` (${t.email})`:"";console.log(),console.log(ke(` \u26A0 Claude ${t.plan??""} subscription login detected${r}.`)),console.log(),console.log(" AnyForge Control\u2019s inference proxy is "+Z("BYOK-only")+" \u2014 it routes"),console.log(" Claude Code through your own Anthropic API key for metering and"),console.log(" governance. Pointing Claude Code at the proxy would "+Z("override and")),console.log(" "+Z("disable your subscription login")+", so we did NOT patch your config."),console.log(),console.log(" Instead, use your subscription for inference and add the "+Z("AnyForge")),console.log(" "+Z("MCP server")+" for control (HIL approvals, work items, crews):"),console.log();let o=`claude mcp add anyforge --env ANYFORGE_API_KEY=${n} -- npx -y @anyforge/mcp-server`;if((await vn({type:"confirm",name:"go",message:"Add the AnyForge MCP server to Claude Code now?",initial:!0})).go)try{On("claude",["mcp","add","anyforge","--env",`ANYFORGE_API_KEY=${n}`,"--","npx","-y","@anyforge/mcp-server"],{stdio:"inherit"}),console.log(et(" \u2714")+" AnyForge MCP server added to Claude Code.")}catch{console.log(ke(" Could not run `claude mcp add` automatically (is the `claude` CLI on PATH?).")),console.log(L(" Add it manually:")),console.log(" "+o)}else console.log(L(" Add it later with:")),console.log(" "+o);if(console.log(),(await vn({type:"confirm",name:"go",message:"Send Claude Code usage to your AnyForge dashboard? (token counts only \u2014 no prompt content)",initial:!0})).go){let a=await Ir({endpoint:e,apiKey:n});a&&(console.log(et(" \u2714")+" Usage telemetry enabled \u2014 view it at "+Lt(`${e}/usage`)),console.log(L(" (written to "+a.path+"; `anyforge logout` removes it)")))}else console.log(L(" Skipped \u2014 your subscription usage stays local to Claude Code."));console.log(),console.log(L(" Want the metered BYOK proxy instead? Re-run with ")+Z("--force")+L(" using an")),console.log(L(" Anthropic API key on your company (this disables your subscription in")),console.log(L(" Claude Code; ")+Z("anyforge logout")+L(" reverts it).")),console.log(),console.log(Z("Done.")+" Visit "+Lt(`${e}/usage`)+" to see your traffic.")}function _r(t){try{return On("git",["rev-parse","--show-toplevel"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return null}}async function Hi(t){return t?(await vn({type:"select",name:"scope",message:"Where should AnyForge patch Claude Code?",choices:[{title:`This repo only (${t}/.claude/settings.local.json + .env)`,value:"repo"},{title:"Globally (~/.claude/settings.json)",value:"global"}],initial:0})).scope??"repo":(console.log(L(" Not a git repo root \u2014 installing globally.")),console.log(L(" Run this from a repo root if you want a per-repo install instead.")),"global")}function Ji(t){console.log(et("\u2714")+" Patched "+t.length+" agent config"+(t.length===1?"":"s")+":");for(let e of t)console.log(` ${L("\u2022")} ${e.label} ${L("("+e.path+")")}`)}function Yi(t){try{let e=On("git",["remote","get-url","origin"],{cwd:t,encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim(),n=e.match(/^git@[\w.-]+:([\w.-]+\/[\w.-]+?)(?:\.git)?$/);if(n)return n[1];let r=e.match(/^https?:\/\/[\w.-]+\/([\w.-]+\/[\w.-]+?)(?:\.git)?$/);return r?r[1]:null}catch{return null}}import{dim as Rn,yellow as Zi,bold as es}from"kleur/colors";var m={OK:0,FAILURE:1,USAGE:2,NO_CREDENTIALS:3,API_ERROR:4,INTERRUPTED:130},f=class extends Error{exitCode;hint;constructor(e,n=m.FAILURE,r){super(e),this.name="CliError",this.exitCode=n,this.hint=r}},y=class extends f{constructor(e,n){super(e,m.USAGE,n),this.name="UsageError"}},oe=class extends f{constructor(){super("Not authenticated \u2014 no ANYFORGE_API_TOKEN and no saved credential.",m.NO_CREDENTIALS,"Run `npx @anyforge/control init`, or set ANYFORGE_API_TOKEN for unattended use."),this.name="NotAuthenticatedError"}},be=class extends f{code;status;constructor(e,n,r){super(r?`${e}: ${r}`:e,m.API_ERROR,Qi(e,n)),this.name="ControlApiError",this.code=e,this.status=n}};function Qi(t,e){if(t==="missing_api_key"||t==="invalid_api_key"||t==="invalid_token"||e===401)return"The key was rejected. Re-run `npx @anyforge/control init`.";if(t==="insufficient_scope"||e===403)return"This key lacks the scope for that command. Run `anyforge whoami` to see its scopes.";if(e===404)return"No such id in this company. Check it with the matching list command.";if(e===429)return"Rate limited. Retry after a short pause."}var Pr="https://crew.anyforge.ai";async function Fe(t){let e=process.env.ANYFORGE_API_TOKEN,n=t||process.env.ANYFORGE_API_URL;if(e)return{apiKey:e,endpoint:n||Pr};let r=await ve();if(r?.apiKey)return{apiKey:r.apiKey,endpoint:n||r.endpoint||Pr};throw new oe}async function E(t,e,n,r){let o=`${t.endpoint.replace(/\/$/,"")}/api/v1/control${n}`,i;try{i=await fetch(o,{method:e,headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.apiKey}`},...r!==void 0?{body:JSON.stringify(r)}:{}})}catch(a){throw new f(`Cannot reach ${t.endpoint}: ${a instanceof Error?a.message:String(a)}`,m.FAILURE,"Check your network, or pass --endpoint if this workspace is self-hosted.")}let s;try{s=await i.json()}catch{throw new f(`Non-JSON response from ${o} (HTTP ${i.status}).`,m.FAILURE)}if(!i.ok||s.ok===!1){let a=typeof s.error=="string"?s.error:`http_${i.status}`,c=typeof s.message=="string"?s.message:typeof s.detail=="string"?s.detail:void 0;throw new be(a,i.status,c)}return s.data}function H(t){let e=Object.entries(t).filter(([,n])=>n!==void 0&&n!=="").map(([n,r])=>`${encodeURIComponent(n)}=${encodeURIComponent(String(r))}`);return e.length?`?${e.join("&")}`:""}async function tt(t){return E(t,"GET","/me")}function bn(t,e,n,r){let o=t?.entityLabels?.[e]?.[n];return typeof o=="string"&&o.trim()?o:r}async function Lr(t){try{return await tt(t)}catch{return null}}function Fr(t){return[...t].length}function Ne(t,e){if(e<=0)return"";let n=[...t];return n.length<=e?t:e===1?"\u2026":`${n.slice(0,e-1).join("")}\u2026`}function z(t,e){if(t.length===0)return"";let n=t.map(i=>e.map(s=>{let a=s.value(i)??"";return s.max?Ne(a,s.max):a})),r=e.map((i,s)=>Math.max(Fr(i.header),...n.map(a=>Fr(a[s])))),o=i=>i.map((s,a)=>a===i.length-1?s:s.padEnd(r[a]+2)).join("").replace(/\s+$/,"");return[o(e.map(i=>i.header)),...n.map(o)].join(`
|
|
21
|
+
`)}function C(t){return JSON.stringify(t,null,2)}function Nr(t,e=Date.now()){let n=Vi(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 Vi(t){if(typeof t=="number")return Number.isFinite(t)?t:null;if(typeof t=="string"){let e=Date.parse(t);return Number.isNaN(e)?null:e}return null}function T(t,e,n="\u2014"){let r=t[e];return typeof r=="string"&&r.trim()?r:typeof r=="number"&&Number.isFinite(r)?String(r):n}function G(t,e,n="\u2014"){for(let r of e){let o=t[r];if(typeof o=="string"&&o.trim())return o}return n}function ie(t){let e=Array.isArray(t)?t:t&&typeof t=="object"?Xi(t):null;return e?e.filter(n=>!!n&&typeof n=="object"&&!Array.isArray(n)):[]}function Xi(t){for(let e of["items","results","rows","data"])if(Array.isArray(t[e]))return t[e];return null}function Ft(t,e,n){let r=t?`last ${t}d`:"all time";return!e||!n?r:`last ${Math.max(1,Math.round((Date.now()-n)/864e5))}d of ${t?`${t}d`:"all time"} \u2014 read cap`}async function qr(t){let e=await Fe(t.endpoint),n=await tt(e);if(t.json){console.log(C(n));return}console.log(`Company: ${es(n.companyName??n.companyId)}${n.companyName?Rn(` (${n.companyId})`):""}`),console.log(`Endpoint: ${e.endpoint}`),console.log(`Scopes: ${n.scopes.length?n.scopes.join(", "):Zi("none")}`),n.userId&&console.log(`User: ${n.userId}`);let r=await ve();console.log(r?Rn(`Key tail: \u2026${r.apiKey.slice(-4)} \xB7 saved ${new Date(r.savedAt).toLocaleString()}`):Rn("Key from: ANYFORGE_API_TOKEN (no saved credential file)"))}import{green as Mr,dim as Nt,yellow as ts}from"kleur/colors";async function Ur(){let t=await ve(),e=await br(),{reverted:n}=await Tr({endpoint:t?.endpoint??null});if(console.log(e?Mr("\u2714")+" Local credentials cleared.":ts("No credentials were saved on this machine.")),n.length){console.log(Mr("\u2714")+" Reverted patched configs:");for(let r of n)console.log(` ${Nt("\u2022")} ${r}`);console.log(Nt(" Your previous Claude Code login (if any) is restored."))}else console.log(Nt(" No AnyForge config patches found to revert."));console.log(Nt(" Revoke the key server-side at /settings \u2192 API keys."))}import{green as ns,red as qt,yellow as rs,dim as Mt}from"kleur/colors";async function jr(t){let e=await ve();if(!e){console.log(rs("Not logged in.")+" Run "+Mt("npx @anyforge/control init")+" first.");return}let n=t.endpoint||e.endpoint;console.log(`Endpoint: ${n}`),console.log(`Company: ${e.companyId}`);let r={model:"claude-3-5-haiku-20241022",max_tokens:1,messages:[{role:"user",content:"Hi"}]},o;try{o=await fetch(`${n}/v1/anthropic/v1/messages`,{method:"POST",headers:{"Content-Type":"application/json","anthropic-version":"2023-06-01",Authorization:`Bearer ${e.apiKey}`},body:JSON.stringify(r)})}catch(i){console.log(qt("\u2717 Proxy unreachable: ")+i.message),process.exit(1)}o.status===401&&(console.log(qt("\u2717 API key rejected.")+" Re-run "+Mt("npx @anyforge/control init")+"."),process.exit(1)),o.status===502&&(console.log(qt("\u2717 No BYOK Anthropic key configured for your company.")),console.log(Mt(" Add one at ")+n+Mt("/settings \u2192 API keys.")),process.exit(1)),o.ok||(console.log(qt(`\u2717 Proxy returned ${o.status}: `)+(await o.text()).slice(0,200)),process.exit(1)),console.log(ns("\u2714 Proxy reachable, key valid, BYOK configured."))}import{spawn as os}from"node:child_process";import{readFile as is}from"node:fs/promises";import{red as nt,green as An,yellow as ss,dim as rt,bold as Dr}from"kleur/colors";async function Br(t){let e=await as(t.patchFile);e.trim()||(process.stderr.write(nt(`Empty patch \u2014 nothing to apply.
|
|
22
|
+
`)),process.exit(1));let n=cs(e);process.stderr.write(rt(`Patch: ${n.files} ${n.files===1?"file":"files"}, `)+An(`+${n.added}`)+" "+nt(`-${n.removed}`)+`
|
|
23
|
+
`);let r=await xn(["apply","--check"],e);if(r.code!==0){if(t.threeWay){let i=await xn(["apply","--3way"],e);i.code!==0&&(process.stderr.write(nt(`3-way apply failed:
|
|
24
24
|
`)+i.stderr+`
|
|
25
|
-
`),process.exit(1)),process.stderr.write(
|
|
26
|
-
`));return}process.stderr.write(
|
|
25
|
+
`),process.exit(1)),process.stderr.write(ss(`\u2713 Applied via 3-way merge \u2014 review conflicts before committing.
|
|
26
|
+
`));return}process.stderr.write(nt(`Patch does not apply cleanly:
|
|
27
27
|
`)+r.stderr+`
|
|
28
|
-
`),process.stderr.write(
|
|
29
|
-
`)),process.exit(1)}if(t.dryRun){process.stderr.write(
|
|
30
|
-
`));return}let o=await
|
|
28
|
+
`),process.stderr.write(rt("Try ")+Dr("--3way")+rt(` to attempt a 3-way merge against the index.
|
|
29
|
+
`)),process.exit(1)}if(t.dryRun){process.stderr.write(An(`\u2713 Patch would apply cleanly.
|
|
30
|
+
`));return}let o=await xn(["apply"],e);o.code!==0&&(process.stderr.write(nt(`git apply failed:
|
|
31
31
|
`)+o.stderr+`
|
|
32
|
-
`),process.exit(1)),process.stderr.write(
|
|
33
|
-
`)),n.files>0&&process.stderr.write(
|
|
34
|
-
`))}async function
|
|
35
|
-
`))if(o.startsWith("diff --git"))e+=1;else{if(o.startsWith("+++")||o.startsWith("---"))continue;o.startsWith("+")?n+=1:o.startsWith("-")&&(r+=1)}return e===0&&(n>0||r>0)&&(e=(t.match(/^\+\+\+ /gm)??[]).length),{files:e,added:n,removed:r}}import{bold as
|
|
36
|
-
${n.length} pending \xB7 approve with `)+
|
|
37
|
-
Last ${i.length} messages:`));for(let s of i){let a=G(s,["agentRole","role","author","agent","type"],"?"),c=G(s,["content","body","text","summary"],"");c&&console.log(`${In(`[${a}]`)} ${Ne(c.replace(/\s+/g," "),160)}`)}}}async function
|
|
38
|
-
${c} \u2014 this crew is waiting on a person.`));let p=
|
|
39
|
-
${c}`;console.log(c==="COMPLETE"?p:
|
|
40
|
-
${s}`)}${a}`)}import{bold as ks,dim as
|
|
41
|
-
Dispatch with `)+ks("anyforge run <id>"))}async function
|
|
42
|
-
`));let n=await
|
|
43
|
-
Biggest fixable gap: `)+
|
|
44
|
-
Read cap reached \u2014 these are the most recent reviews${i?` (back to ${i})`:""}, not the whole window. Every count is a lower bound.`))}e.reviews&&e.skippedShare!=null&&e.skippedShare>0&&r(
|
|
45
|
-
${e.reviews.skipped} of ${e.reviews.total} reviews were skipped (${
|
|
46
|
-
${i}`))}import{bold as
|
|
47
|
-
Feedback reached the author in ${
|
|
32
|
+
`),process.exit(1)),process.stderr.write(An(`\u2713 Applied.
|
|
33
|
+
`)),n.files>0&&process.stderr.write(rt(" Run ")+Dr("git diff --stat")+rt(` to review.
|
|
34
|
+
`))}async function as(t){if(t)return await is(t,"utf8");let e=[];for await(let n of process.stdin)e.push(n);return Buffer.concat(e).toString("utf8")}function xn(t,e){return new Promise((n,r)=>{let o=os("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 cs(t){let e=0,n=0,r=0;for(let o of t.split(`
|
|
35
|
+
`))if(o.startsWith("diff --git"))e+=1;else{if(o.startsWith("+++")||o.startsWith("---"))continue;o.startsWith("+")?n+=1:o.startsWith("-")&&(r+=1)}return e===0&&(n>0||r>0)&&(e=(t.match(/^\+\+\+ /gm)??[]).length),{files:e,added:n,removed:r}}import{bold as ls,dim as kn,green as ds,red as us}from"kleur/colors";async function Gr(t){let e=await E(t.creds,"GET",`/hil${H({limit:t.limit})}`);if(t.json){console.log(C(e));return}let n=ie(e);if(n.length===0){console.log(kn("No approvals pending."));return}console.log(z(n,[{header:"ID",value:r=>T(r,"id")},{header:"CREW",value:r=>T(r,"crewId"),max:24},{header:"AGE",value:r=>Nr(r.requestedAt)},{header:"SUMMARY",value:r=>G(r,["planSummary","summary","title","description"]),max:60}])),console.log(kn(`
|
|
36
|
+
${n.length} pending \xB7 approve with `)+ls("anyforge approve <id>"))}async function Sn(t){if(!t.approvalId)throw new y(`${t.decision==="APPROVED"?"approve":"reject"} requires an approval id.`,"List them with `anyforge approvals`.");let e=await E(t.creds,"POST",`/hil/${encodeURIComponent(t.approvalId)}`,{decision:t.decision,...t.notes?{notes:t.notes}:{}});if(t.json){console.log(C(e));return}let n=t.decision==="APPROVED"?ds("Approved"):us("Rejected");console.log(`${n} ${t.approvalId}`);let r=e&&typeof e=="object"?e.signature:void 0;typeof r=="string"&&r&&console.log(kn(`Audit signature: ${r}`))}import{bold as ps,dim as In}from"kleur/colors";async function zr(t){let e=await E(t.creds,"GET",`/crews${H({status:t.status,activeOnly:t.activeOnly,limit:t.limit})}`);if(t.json){console.log(C(e));return}let n=ie(e);if(n.length===0){console.log(In(t.activeOnly?"No active crews.":"No crews."));return}console.log(z(n,[{header:"ID",value:r=>T(r,"id")},{header:"STATUS",value:r=>T(r,"status")},{header:"TASK",value:r=>G(r,["task"],"\u2014"),max:52},{header:"NOTE",value:r=>G(r,["errorMessage"],""),max:40}]))}async function Wr(t){if(!t.crewId)throw new y("crew requires a crew id.","List them with `anyforge crews`.");let e=await E(t.creds,"GET",`/crews/${encodeURIComponent(t.crewId)}${H({messages:t.messages})}`);if(t.json){console.log(C(e));return}let n=e?.crew&&typeof e.crew=="object"?e.crew:e;console.log(`${ps(fs(G(n,["taskDescription"],T(n,"id"))))}`),console.log(`Status: ${T(n,"status")}`),console.log(`Repo: ${G(n,["githubRepo"])}`);let r=T(n,"prUrl","");r&&console.log(`PR: ${r}`);let o=T(n,"url","");o&&console.log(`Console: ${o}`);let i=ie(e?.chat);if(i.length>0){console.log(In(`
|
|
37
|
+
Last ${i.length} messages:`));for(let s of i){let a=G(s,["agentRole","role","author","agent","type"],"?"),c=G(s,["content","body","text","summary"],"");c&&console.log(`${In(`[${a}]`)} ${Ne(c.replace(/\s+/g," "),160)}`)}}}async function Cn(t){if(!t.crewId)throw new y(`${t.action} requires a crew id.`,"List them with `anyforge crews`.");let e=await E(t.creds,"POST",`/crews/${encodeURIComponent(t.crewId)}/${t.action}`);if(t.json){console.log(C(e));return}console.log(`${t.action==="halt"?"Halted":"Resumed"} ${t.crewId}`)}function fs(t){return Ne(t.split(/\r?\n/).find(e=>e.trim())?.trim()??t,80)}import{bold as ms,dim as qe,red as Kr,yellow as Jr}from"kleur/colors";var gs=new Set(["COMPLETE","HALTED","REJECTED","CANCELLED"]),hs=new Set(["HIL_PENDING","HIL_SHIP","PERMISSION_PENDING","PAUSED"]),ws={HIL_PENDING:"Decide it with `anyforge approvals`, or from the Slack alert.",HIL_SHIP:"Decide it with `anyforge approvals`, or from the Slack alert.",PERMISSION_PENDING:"The agent asked for a tool outside its profile. Allow or deny it in the Console.",PAUSED:"Restart it with `anyforge resume <id>`."};async function Yr(t){if(!t.workItemId)throw new y("crew start requires a work item id.","Find one with `anyforge work --status READY`.");let e=await E(t.creds,"PATCH",`/work/${encodeURIComponent(t.workItemId)}`,{action:"dispatch",...t.profileId?{runProfileId:t.profileId}:{}});if(t.json&&!t.follow){console.log(C(e));return}let n=typeof e?.crewId=="string"?e.crewId:"";if(!n)throw new f("Dispatch was accepted but returned no crew id.",m.FAILURE,"Check `anyforge crews --active` to see whether one started.");for(let r of e?.warnings??[])console.error(Jr(`warning: ${r}`));if(!t.follow){console.log(`Started ${ms(n)} on ${t.workItemId}`),console.log(qe(`Follow it with \`anyforge crew follow ${n}\``));return}await Tn({creds:t.creds,json:t.json,crewId:n,intervalSeconds:t.intervalSeconds})}var ys=5,vs=10,Os=120,Hr=30;async function Tn(t){if(!t.crewId)throw new y("crew follow requires a crew id.","List them with `anyforge crews --active`.");let e=Math.min(Math.max(t.intervalSeconds??vs,ys),Os)*1e3,n=Date.now()+Hr*6e4,r=new Set,o="",i=!1;for(;;){let s=await E(t.creds,"GET",`/crews/${encodeURIComponent(t.crewId)}?messages=50`),a=s?.crew??{},c=T(a,"status","");for(let p of s?.chat??[]){let l=T(p,"id","");!l||r.has(l)||(r.add(l),i&&!t.json&&bs(p))}if(i=!0,c&&c!==o&&(t.json||console.log(qe(`\u2500\u2500 ${c}`)),o=c),hs.has(c)){if(t.json)console.log(C({crewId:t.crewId,status:c,waiting:!0,url:T(a,"url","")}));else{console.log(Jr(`
|
|
38
|
+
${c} \u2014 this crew is waiting on a person.`));let p=ws[c];p&&console.log(qe(p));let l=T(a,"url","");l&&console.log(qe(l))}return}if(gs.has(c)){if(t.json)console.log(C({crewId:t.crewId,status:c,waiting:!1,url:T(a,"url","")}));else{let p=`
|
|
39
|
+
${c}`;console.log(c==="COMPLETE"?p:Kr(p));let l=T(a,"prUrl","");l&&console.log(qe(l));let u=T(a,"errorMessage","");u&&console.log(Kr(u))}if(c!=="COMPLETE")throw new f(`Crew ${t.crewId} ended ${c}.`,m.FAILURE);return}if(Date.now()>=n)throw new f(`Still ${c||"running"} after ${Hr} minutes \u2014 giving up watching.`,m.FAILURE,`The crew is unaffected. Check it with \`anyforge crew ${t.crewId}\`.`);await As(e)}}function bs(t){let e=T(t,"agentRole","")||T(t,"type","?"),n=Rs(t,["content","text","summary"]);n&&console.log(`${qe(`[${e}]`)} ${Ne(n.replace(/\s+/g," "),160)}`)}function Rs(t,e){for(let n of e){let r=t[n];if(typeof r=="string"&&r.trim())return r.trim()}return""}function As(t){return new Promise(e=>{setTimeout(e,t)})}import{dim as Ut}from"kleur/colors";var Vr=100;function Qr(t){let e=t&&typeof t=="object"?t:{};return{total:typeof e.total=="number"?e.total:null,hasMore:e.hasMore===!0,cursor:typeof e.nextCursor=="string"?e.nextCursor:null}}async function xs(t){let e=s=>`/work${H({status:t.status,type:t.type,priority:t.priority,initiative:t.initiative,program:t.program,search:t.search,assignee:t.assignee,includeArchived:t.includeArchived,limit:t.limit,cursor:s})}`,n=await E(t.creds,"GET",e()),r=ie(n),o=Qr(n),i=1;if(!t.all)return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i};for(;o.hasMore&&o.cursor&&i<Vr;){let s=await E(t.creds,"GET",e(o.cursor));r.push(...ie(s)),o=Qr(s),i+=1}return{rows:r,total:o.total,hasMore:o.hasMore,raw:n,pagesFetched:i}}async function Xr(t){let e=await xs(t);if(t.json){console.log(C(t.all?{items:e.rows,total:e.total,hasMore:e.hasMore,nextCursor:null}:e.raw));return}let n=e.rows,r=await Lr(t.creds),o=bn(r,"work_item","plural","Work items");if(n.length===0){console.log(Ut(`No ${o.toLowerCase()} match that filter.`));return}console.log(z(n,[{header:"ID",value:c=>T(c,"id")},{header:"PRI",value:c=>T(c,"priority","")},{header:"TYPE",value:c=>T(c,"type","")},{header:"STATUS",value:c=>T(c,"status")},{header:"TITLE",value:c=>G(c,["title","name","summary"]),max:58}]));let i=(n.length===1?bn(r,"work_item","singular","work item"):o).toLowerCase(),s=e.total!==null&&e.total!==n.length?`${n.length} of ${e.total} ${o.toLowerCase()}`:`${n.length} ${i}`,a=e.hasMore?t.all?Ut(` \u2014 stopped after ${Vr} pages; narrow the filter`):Ut(" \u2014 pass --all for the rest"):"";console.log(`${Ut(`
|
|
40
|
+
${s}`)}${a}`)}import{bold as ks,dim as jt}from"kleur/colors";async function Zr(t){let e=await E(t.creds,"GET","/workflows");if(t.json){console.log(C(e));return}let n=ie(e);if(n.length===0){console.log(jt("No workflows defined."));return}console.log(z(n,[{header:"ID",value:r=>T(r,"id")},{header:"STATUS",value:r=>G(r,["status","state"],"")},{header:"NAME",value:r=>G(r,["name","title"]),max:58}])),console.log(jt(`
|
|
41
|
+
Dispatch with `)+ks("anyforge run <id>"))}async function eo(t){if(!t.workflowId)throw new y("run requires a workflow id.","List them with `anyforge workflows`.");let e;if(t.input!==void 0){try{e=JSON.parse(t.input)}catch(o){throw new y(`--input is not valid JSON: ${o instanceof Error?o.message:String(o)}`,`Example: --input '{"repo":"acme/web"}'`)}if(!e||typeof e!="object"||Array.isArray(e))throw new y("--input must be a JSON object.",`Example: --input '{"repo":"acme/web"}'`)}let n=await E(t.creds,"POST",`/workflows/${encodeURIComponent(t.workflowId)}/run`,e===void 0?void 0:{inputs:e});if(t.json){console.log(C(n));return}let r=G(n??{},["id","runId"],"");console.log(`Queued run ${r||jt("(id not returned)")}`),console.log(jt("Runs pause at gate steps for an operator decision."))}import{dim as Ss}from"kleur/colors";async function to(t){let e=t.question?.trim();if(!e)throw new y("ask requires a question.",'Example: anyforge ask "which initiatives slipped this cycle?"');!t.json&&process.stderr.isTTY&&process.stderr.write(Ss(`Asking the Oracle (this can take a few minutes)\u2026
|
|
42
|
+
`));let n=await E(t.creds,"POST","/oracle",{question:e,...t.context?{context:t.context}:{}});if(t.json){console.log(C(n));return}let r=n&&typeof n=="object"?["answer","text","content","response"].map(o=>n[o]).find(o=>typeof o=="string"&&o.trim()):void 0;console.log(typeof r=="string"?r:C(n))}import{bold as En,dim as no,green as Is,yellow as Cs}from"kleur/colors";function Ts(t){return typeof t=="number"?`${Math.round(t*100)}%`:"\u2014"}async function ro(t){let e=await E(t.creds,"GET",`/backtest-corpus${H({days:t.days})}`);if(t.json){console.log(C(e));return}let n=e.incidentsInWindow??0,r=e.backTestable??0,o=e.windowDays?`last ${e.windowDays}d`:"all time";console.log(`${En(String(r))} of ${En(String(n))} incidents are back-testable `+no(`(${Ts(e.coverage)} \xB7 ${o})`)),e.viable?console.log(Is("Enough to run a back-test.")):console.log(Cs(`Not yet viable \u2014 ${e.shortfall??0} more needed.`));let i=(e.excluded??[]).filter(s=>s.count>0);i.length>0&&console.log(z(i,[{header:"EXCLUDED",value:s=>String(s.count)},{header:"REASON",value:s=>s.label,max:56}])),e.biggestGap&&console.log(no(`
|
|
43
|
+
Biggest fixable gap: `)+En(`${e.biggestGap.label} (${e.biggestGap.count})`))}import{bold as Dt,dim as ot,green as Es,yellow as oo}from"kleur/colors";var _n=t=>typeof t=="number"?`${Math.round(t*1e3)/10}%`:"\u2014";async function io(t){let e=await E(t.creds,"GET",`/review-interception${H({days:t.days})}`);if(t.json){console.log(C(e));return}let n=Ft(e.windowDays,e.truncated,e.oldestReviewMs),r=i=>{console.log(i)};if(r(`${Dt(String(e.seriousRaised??0))} serious findings raised across ${Dt(String(e.prsReviewed??0))} pull requests ${ot(`(${n})`)}`),e.verdict==="measured")r(`${Es(String(e.disappearedSerious??0))} no longer raised by the next round \u2014 ${Dt(_n(e.interceptionFloor))} to ${Dt(_n(e.interceptionCeiling))}`),r(ot(`floor counts every unmeasured finding as unresolved \xB7 ceiling is over the ${e.measurableSerious??0} that had a later round`));else{r(oo("Not enough findings had a later round to measure a rate."));for(let i of e.inconclusiveReasons??[])r(ot(` ${i}`))}let o=(e.byLens??[]).filter(i=>i.serious>0);if(o.length>0&&r(z(o,[{header:"LENS",value:i=>i.lens,max:16},{header:"RAISED",value:i=>String(i.raised)},{header:"SERIOUS",value:i=>String(i.serious)},{header:"CHECKED",value:i=>String(i.measurable)},{header:"GONE",value:i=>String(i.disappeared)}])),e.truncated){let i=e.oldestReviewMs?new Date(e.oldestReviewMs).toISOString().slice(0,10):null;r(oo(`
|
|
44
|
+
Read cap reached \u2014 these are the most recent reviews${i?` (back to ${i})`:""}, not the whole window. Every count is a lower bound.`))}e.reviews&&e.skippedShare!=null&&e.skippedShare>0&&r(ot(`
|
|
45
|
+
${e.reviews.skipped} of ${e.reviews.total} reviews were skipped (${_n(e.skippedShare)}) \u2014 drafts, size caps or path policy.`));for(let i of e.caveats??[])r(ot(`
|
|
46
|
+
${i}`))}import{bold as it,dim as Se,green as _s,red as $s,yellow as $n}from"kleur/colors";var Ps=t=>typeof t=="number"?`${Math.round(t*1e3)/10}%`:"\u2014";function Pn(t){if(typeof t!="number")return"\u2014";if(t<60)return`${t}m`;if(t<1440){let n=Math.floor(t/60);return`${n}h ${Math.round(t-n*60)}m`}let e=Math.floor(t/1440);return`${e}d ${Math.round((t-e*1440)/60)}h`}var Ls={capacity:"a limit fired",policy:"configured off",by_design:"correctly declined",unclassified:"reason not recognised"};async function so(t){let e=await E(t.creds,"GET",`/review-coverage${H({days:t.days})}`);if(t.json){console.log(C(e));return}let n=s=>{console.log(s)},r=Ft(e.windowDays,e.truncated,e.oldestRecordMs);n(`${it(String(e.pullRequestsReviewed??0))} of ${it(String(e.pullRequestsSeen??0))} recorded pull requests reviewed ${e.coverageRate!=null?it(`(${Ps(e.coverageRate)})`):""} ${Se(`(${r})`)}`),e.repositoriesReviewed&&n(`across ${it(String(e.repositoriesReviewed))} repositories`),n(Se("recorded = pull requests AnyForge was enabled to watch, not every pull request you opened")),e.medianLatencyMinutes!=null?(n(`
|
|
47
|
+
Feedback reached the author in ${_s(Pn(e.medianLatencyMinutes))} median, ${it(Pn(e.p90LatencyMinutes))} at p90 ${Se(`(${e.latencySamples??0} reviews)`)}`),e.medianOnOpenLatencyMinutes!=null&&n(Se(` ${Pn(e.medianOnOpenLatencyMinutes)} median on pull-request open (${e.onOpenSamples??0} reviews, no quiet period in the way)`))):n($n(`
|
|
48
48
|
Not enough timed reviews to report a latency figure.`));let o=e.capacityGapPullRequests??0;o>0&&n(`
|
|
49
|
-
${
|
|
50
|
-
${s}`));if(e.truncated){let s=e.oldestRecordMs?new Date(e.oldestRecordMs).toISOString().slice(0,10):null;n(
|
|
51
|
-
Read cap reached \u2014 these are the most recent records${s?` (back to ${s})`:""}, not the whole window. Every count is a lower bound.`))}for(let s of e.caveats??[])n(
|
|
52
|
-
${s}`))}import{promises as
|
|
49
|
+
${$s(String(o))} pull requests went unreviewed because a limit fired `+Se("\u2014 a cap or a diff over the size ceiling, not a decision anyone made"));let i=e.bySkipClass??[];i.length>0&&n(z(i,[{header:"WHY UNREVIEWED",value:s=>Ls[s.skipClass]??s.skipClass,max:24},{header:"PRS",value:s=>String(s.pullRequests)},{header:"REASONS",value:s=>s.reasons.join(", "),max:46}])),e.failedOnlyPullRequests&&n(Se(`${e.failedOnlyPullRequests} pull requests had every review attempt error out.`));for(let s of e.inconclusiveReasons??[])n($n(`
|
|
50
|
+
${s}`));if(e.truncated){let s=e.oldestRecordMs?new Date(e.oldestRecordMs).toISOString().slice(0,10):null;n($n(`
|
|
51
|
+
Read cap reached \u2014 these are the most recent records${s?` (back to ${s})`:""}, not the whole window. Every count is a lower bound.`))}for(let s of e.caveats??[])n(Se(`
|
|
52
|
+
${s}`))}import{promises as st}from"node:fs";import{homedir as Ms}from"node:os";import{dirname as co,join as Ie}from"node:path";import{dim as lo,green as Us,yellow as js}from"kleur/colors";var se="anyforge-platform",Fs="Orient an agent to AnyForge's structure, delivery model, surfaces, live control tools, and safety boundaries.",ao="anyforge://guide/platform",Ns="text/markdown";var Bt={"SKILL.md":`---
|
|
53
53
|
name: anyforge-platform
|
|
54
54
|
description: >
|
|
55
55
|
Orient an agent to AnyForge's structure, delivery model, surfaces, live control
|
|
@@ -256,40 +256,40 @@ these sources can grant network, filesystem, tool, or approval authority.
|
|
|
256
256
|
Do not place API keys, tokens, credentials, private tenant records, or customer
|
|
257
257
|
data in a reusable skill, prompt, log, or generated example. Use the client's
|
|
258
258
|
credential mechanism and let the server enforce access.
|
|
259
|
-
`},
|
|
260
|
-
`);return}console.log(Ms("Installed ")+`${r.name} ${co(`(${r.scope}, ${r.client})`)}`),console.log(` ${r.directory}`),console.log(co(` ${r.files.length} files installed. Re-run with --force to refresh them.`)),r.scope==="project"&&r.client==="agents"&&console.log(Us(" This portable location is detected by AnyForge repository analysis."))}import{randomUUID as uc}from"node:crypto";import{open as pc,realpath as fc,stat as mc}from"node:fs/promises";import{basename as gc,join as hc,resolve as wc}from"node:path";import{bold as di,cyan as yc,dim as Rt,yellow as an}from"kleur/colors";import{ProcessTerminal as vc,SelectList as Oc,Text as bc,TuiAltScreen as Rc}from"@earendil-works/pi-tui";var Gs=new Set(["find_callers","find_definition","find_imports","trace_path","get_neighbors","graph_stats"]);function zs(t){return Gs.has(t)?"querying the code graph":t==="search_code_semantic"?"searching the code index":t==="search_codebase_docs"?"searching codebase docs":null}function Bt(t){let e=zs(t);if(e)return e;let n=/^mcp__(.+?)__(.+)$/.exec(t);return n?`${n[1].replace(/[_-]+/g," ")} \xB7 ${n[2].replace(/_/g," ")}`:t.replace(/_/g," ")}import{truncateToWidth as Qt,wrapTextWithAnsi as Po}from"@earendil-works/pi-tui";import{cyan as Lo,dim as He,green as Fo,italic as Aa,red as Yn,yellow as Qn}from"kleur/colors";import{truncateToWidth as st,visibleWidth as Nn,wrapTextWithAnsi as Hs}from"@earendil-works/pi-tui";import{bold as Js,dim as Ys}from"kleur/colors";var Ws=/\x1B(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\)|[PX^_][\s\S]*?\x1B\\|[@-_])/g,Ks=/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g;function d(t){return t.replace(Ws,"").replace(Ks,"")}function Ln(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 po(t){return t.replace(/\x1B\]8;;([^\x1B\x07]*)(?:\x07|\x1B\\)/g,(e,n)=>Ln(n)?e:"\x1B]8;;\x07")}function Fn(t){let n=d(t).replace(/(!?)\[([^\]\n]+)\]\((<[^>\n]*>|[^\s)]+)(?:\s+[^)]*)?\)/g,(i,s,a,c)=>{let p=c.startsWith("<")&&c.endsWith(">")?c.slice(1,-1):c,l=Ln(p);return l?`${s}[${a}](${l})`:a}),r=new Map,o=n.replace(/^(\s{0,3}\[([^\]]+)\]:\s*)(\S+)(.*)$/gm,(i,s,a,c,p)=>{let l=Ln(c);return r.set(a.trim().toLowerCase(),l),l?`${s}${l}${p}`:""});return r.size===0?o:o.replace(/(!?)\[([^\]\n]+)\](?:\[([^\]\n]*)\])?/g,(i,s,a,c)=>{let p=(c||a).trim().toLowerCase();return!r.has(p)||r.get(p)?i:a})}function de(t){return typeof t=="string"?d(t):Array.isArray(t)?t.map(e=>de(e)):t&&typeof t=="object"?Object.fromEntries(Object.entries(t).map(([e,n])=>[d(e),de(n)])):t}function N(t){return t<1024?`${t} B`:t<1024*1024?`${at(t/1024)} KiB`:`${at(t/(1024*1024))} MiB`}function ct(t){let e=Math.max(0,t);if(e<1e4)return`${at(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 qn(t){let e=Math.floor(Math.max(0,t)/1e3);return e<60?`${e}s`:`${Math.floor(e/60)}m ${String(e%60).padStart(2,"0")}s`}function ee(t){return Math.abs(t)<1e3?String(Math.round(t)):Math.abs(t)<1e6?`${at(t/1e3,t<1e5?1:0)}k`:`${at(t/1e6)}M`}function at(t,e=1){return t.toFixed(e).replace(/\.0+$/,"")}function Qs(t){return d(t).replace(/(Ms|Bytes)$/,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").toLowerCase().trim()}function Vs(t,e){return typeof e=="boolean"?e?"on":"off":typeof e=="string"?d(e):/Ms$/.test(t)?ct(e):/Bytes$/.test(t)?N(e):/tokens?/i.test(t)?ee(e):String(e)}function fo(t){return t?Object.entries(t).filter(e=>e[1]!==null).map(([e,n])=>`${Qs(e)} ${Vs(e,n)}`):[]}function Mn(t,e,n=2){let r=Math.min(16,Math.max(...t.map(([s])=>Nn(s)),0)+2),o=Math.max(10,e-n-r),i=[];for(let[s,a]of t)Hs(a,o).forEach((p,l)=>{let u=l===0?Ys(st(s,r-1).padEnd(r)):" ".repeat(r);i.push(st(`${" ".repeat(n)}${u}${p}`,e))});return i}function mo(t,e,n){return[st(Js(t),n),...Mn(e,n)]}function go(t,e,n){let r=Nn(n),o=e.filter(Boolean).join(" \xB7 ");if(r+4>t)return st(o||n,t);let i=t-r-2,s=st(o,i),a=Math.max(2,t-Nn(s)-r);return`${s}${" ".repeat(a)}${n}`}import{bold as dt,cyan as lt,dim as Re,green as Xs,italic as ho,strikethrough as Zs,underline as wo,yellow as ea}from"kleur/colors";import{Markdown as ta}from"@earendil-works/pi-tui";var na={heading:t=>dt(lt(t)),link:t=>wo(lt(t)),linkUrl:t=>Re(t),code:t=>ea(t),codeBlock:t=>t,codeBlockBorder:t=>Re(t),quote:t=>ho(t),quoteBorder:t=>Re(t),hr:t=>Re(t),listBullet:t=>lt(t),bold:t=>dt(t),italic:t=>ho(t),strikethrough:t=>Zs(t),underline:t=>wo(t)},ut={selectedPrefix:t=>lt(t),selectedText:t=>dt(t),description:t=>Re(t),scrollInfo:t=>Re(t),noMatch:t=>Re(t)},yo={borderColor:t=>Re(t),selectList:ut};var Me=class{content;markdown;cache;constructor(e){this.content=d(e),this.markdown=new ta(Fn(this.content),0,0,na)}getText(){return this.content}setText(e){let n=d(e);n!==this.content&&(this.content=n,this.markdown.setText(Fn(n)),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(po):[];return this.cache={width:n,lines:r},r}};function pt(t,e){return t==="user"?`${dt(Xs(e?d(e):"You"))}`:`${dt(lt("Oracle"))}`}function ue(t){return t.shared||t.visibility==="company"?`Shared with the company${t.entityKey?` \xB7 ${d(t.entityKey)}`:""}`:"Private to you"}function vo(t){return t.shared||t.visibility==="company"?"shared":"private"}import{createReadStream as ha}from"node:fs";import{stat as wa}from"node:fs/promises";import{basename as ya}from"node:path";import{setTimeout as Co}from"node:timers/promises";var Oo={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 bo(t){let e=t.slice(t.lastIndexOf(".")+1).toLowerCase();return Object.hasOwn(Oo,e)?Oo[e]:null}var Un="/api/v1/oracle";function fe(t){let e;try{e=new URL(t)}catch{throw new f(`Invalid Oracle endpoint: ${t}`,m.USAGE)}if(!["http:","https:"].includes(e.protocol)||e.username||e.password)throw new f("Oracle endpoint must be an http or https URL without embedded credentials.",m.USAGE);if(e.pathname!=="/"||e.search||e.hash)throw new f("Oracle endpoint must be the workspace origin, without a path, query or fragment.",m.USAGE);return e.origin}function pe(t,e){return`${fe(t)}${Un}${e}`}function ra(t,e,n){let r;try{r=new URL(t)}catch{throw new f(`Oracle server returned an invalid ${n} endpoint.`,m.API_ERROR)}let o=new URL(fe(e));if(r.origin!==o.origin||!r.pathname.startsWith("/api/oauth/")||r.search||r.hash||r.username||r.password)throw new f(`Oracle server returned an unsafe ${n} endpoint.`,m.API_ERROR);return r.toString()}function oa(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]=ra(n[i],e,i)}return o}async function Ge(t,e=fetch,n){let r=fe(t),o;try{o=await e(pe(r,"/config"),{headers:{Accept:"application/json",...n?{Authorization:`Bearer ${n}`}:{}},redirect:"error",signal:AbortSignal.timeout(2e4)})}catch(l){throw new f(`Cannot reach ${r}: ${l instanceof Error?l.message:String(l)}`,m.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}let i=await De(o,pe(r,"/config")),s=$(je(i,o.status)),a=`${r}${Un}`;if(s.protocolVersion!==1)throw new f(`Oracle protocol mismatch: this CLI supports ${1}, and the server reports ${String(s.protocolVersion)}.`,m.API_ERROR,"Update @anyforge/control to a version supported by this workspace.");if(s.resource!==a)throw new f("Oracle server resource does not match this workspace origin.",m.API_ERROR);let c=Array.isArray(s.scopes)?s.scopes:null;if(!c||!c.every(l=>l==="read"||l==="write"||l==="approve"))throw new f("Oracle server returned an invalid scope list.",m.API_ERROR);let p={protocolVersion:1,resource:a,scopes:c,oauth:oa(s.oauth,r)};if(s.identity!==void 0){let l=$(s.identity);if(typeof l.uid!="string"||typeof l.companyId!="string")throw new f("Oracle server returned an invalid identity.",m.API_ERROR);p.identity={uid:d(l.uid),companyId:d(l.companyId)}}if(s.capabilities!==void 0){let l=$(s.capabilities);if(![l.read,l.write,l.approve].every(u=>typeof u=="boolean"))throw new f("Oracle server returned invalid capabilities.",m.API_ERROR);p.capabilities={read:l.read,write:l.write,approve:l.approve}}if(s.model!==void 0){let l=$(s.model);if(typeof l.id!="string"||typeof l.provider!="string")throw new f("Oracle server returned invalid model metadata.",m.API_ERROR);p.model={id:d(l.id),provider:d(l.provider)}}if(s.limits!==void 0){let l=$(s.limits);if(Object.values(l).some(u=>!["string","number","boolean"].includes(typeof u)&&u!==null))throw new f("Oracle server returned invalid limits metadata.",m.API_ERROR);p.limits=Object.fromEntries(Object.entries(l).map(([u,v])=>[d(u),typeof v=="string"?d(v):v]))}return Array.isArray(s.commands)&&(p.commands=ia(s.commands)),p}function ia(t){let e=[];for(let n of t.slice(0,50)){let r=$(n);if(typeof r.name!="string"||!/^[a-z][a-z0-9_-]{0,31}$/.test(r.name)||typeof r.description!="string"||e.some(i=>i.name===r.name))continue;let o=typeof r.args=="string"?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 zt=class{endpoint;scopes;source;#e;#t;cachedConfig;constructor(e,n=fetch){this.endpoint=fe(e.endpoint),this.#e=e.getAccessToken??(async()=>e.accessToken),this.#t=n,this.scopes=new Set(e.scopes),this.source=e.source}async config(){if(!this.cachedConfig){let e=await this.#e();try{this.cachedConfig=await Ge(this.endpoint,this.#t,e)}catch(n){if(this.source!=="oauth"||!(n instanceof be)||n.status!==401)throw n;let r=await this.#e(e);if(r===e)throw n;this.cachedConfig=await Ge(this.endpoint,this.#t,r)}}return this.cachedConfig}async listSessions(){let e=await this.json("GET","/sessions"),n=Array.isArray(e)?e:$(e).sessions;if(!Array.isArray(n))throw new f("Oracle server returned an invalid sessions list.",m.API_ERROR);return n.map(ko)}async createSession(e={}){let n=await this.json("POST","/sessions",e),r=$(n);return!Array.isArray(r.messages)&&typeof r.sessionId=="string"?this.getSession(r.sessionId):Ro(n)}async getSession(e){return Ro(await this.json("GET",`/sessions/${encodeURIComponent(e)}`))}async submitTurn(e,n,r,o){let i,s=pe(this.endpoint,`/sessions/${encodeURIComponent(e)}/turns`),a=async p=>this.#t(s,{method:"POST",headers:{Authorization:`Bearer ${p}`,Accept:"text/event-stream, application/json","Content-Type":"application/json"},redirect:"error",body:JSON.stringify(n),...r?{signal:r}:{}});try{let p=await this.#e();if(i=await a(p),i.status===401&&this.source==="oauth"){let l=await this.#e(p);l!==p&&(i=await a(l))}}catch(p){throw p instanceof f||r?.aborted?p:new f(`Oracle connection was interrupted: ${p instanceof Error?p.message:String(p)}`,m.FAILURE,"The server may still be working. Resume this session to replay its saved stream.")}if(o?.(i),i.ok||await Ue(i),!(i.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){let p=await De(i,pe(this.endpoint,`/sessions/${e}/turns`)),l=je(p,i.status);throw new f(`Oracle server did not start a stream (${sa(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 Ue(s),(s.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*ft(s,o);return}let c=je(await De(s,pe(this.endpoint,i)),s.status),p=Array.isArray(c)?c:$(c).events;if(!Array.isArray(p))throw new f("Oracle replay response did not contain events.",m.API_ERROR);for(let l of p)yield jn(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 Ue(s),(s.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*ft(s,o);return}let c=je(await De(s,pe(this.endpoint,i)),s.status),p=Array.isArray(c)?c:$(c).events;if(!Array.isArray(p))throw new f("Oracle request replay response did not contain events.",m.API_ERROR);for(let l of p)yield jn(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 Ue(o),aa(je(await De(o,pe(this.endpoint,"/uploads")),o.status))}async download(e,n){let r=await this.authenticatedFetch("GET",`/sessions/${encodeURIComponent(e)}/files/${encodeURIComponent(n)}`,{headers:{Accept:"application/octet-stream, application/json"}});return r.ok||await Ue(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 Ue(o),je(await De(o,pe(this.endpoint,n)),o.status)}async authenticatedFetch(e,n,r={},o=2e4){try{let i=pe(this.endpoint,n),s=Object.fromEntries(new Headers(r.headers).entries()),a=r.signal||o<=0?void 0:AbortSignal.timeout(o),c=v=>this.#t(i,{...r,method:e,headers:{...s,Authorization:`Bearer ${v}`},redirect:"error",...a?{signal:a}:{}}),p=await this.#e(),l=await c(p),u=r.body===void 0||typeof r.body=="string"||r.body===null;if(l.status===401&&this.source==="oauth"){let v=await this.#e(p);v!==p&&u&&(l=await c(v))}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*ft(t,e){if(!t.body)throw new f("Oracle stream has no response body.",m.FAILURE);let n=t.body.getReader(),r=new TextDecoder,o="",i=0,s=[],a=0,c=-1,p=()=>{if(s.length===0)return null;let l=s.join(`
|
|
261
|
-
`);if(s=[],a=0,l==="[DONE]")return null;let u;try{u=JSON.parse(l)}catch{throw new f("Oracle stream returned invalid JSON.",m.API_ERROR)}let v=
|
|
262
|
-
`,
|
|
263
|
-
`,
|
|
264
|
-
`,{mode:384,flag:"wx"}),await W.rename(e,me),await W.chmod(me,384)}finally{await W.rm(e,{force:!0}).catch(()=>{})}}async function
|
|
265
|
-
`,{mode:384,flag:"wx"}),await W.rename(n,t),await W.chmod(t,384)}finally{await W.rm(n,{force:!0}).catch(()=>{})}}async function Ht(t){await W.mkdir(mt,{recursive:!0,mode:448});let e=await Io.lock(me,{realpath:!1,lockfilePath:`${me}.refresh-lock`,stale:6e4,update:1e4,retries:{retries:300,minTimeout:100,maxTimeout:100,randomize:!1}});try{return await t()}finally{await e()}}var zn=8192,To=10*1048576,va=20*1048576,_o=10,$o=3;function Wn(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 t.name!=="ask_user"}var Ee=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:Wn(e,this.toolIds)?this.answer="":e.type==="question"?this.question=Jn(e):e.type==="error"?this.error=Hn(e):e.type==="done"?this.done=e:e.type==="navigator_file_created"&&Oa(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 Jt(t,e,n,r,o,i=new Ee){let s=async u=>{let v=i.streamId;i.accept(u)&&(i.streamId&&i.streamId!==v&&r.onStream?.(i.streamId),await r.onEvent(u))},a=()=>Kn(t,e,i,s,o,r.onActivity),c=async()=>{try{for await(let u of t.streamRequestEvents(e,n.requestId,-1,r.onActivity))await s(u)}catch(u){throw o?.aborted?u:new f("Oracle connection failed and the submitted request could not be recovered by its request id. It was not resubmitted with a new id.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the saved session.`)}if(i.settled)return i.outcome();if(i.streamId)return a();throw new f("Oracle request lookup returned no stream events. It was not resubmitted with a new id.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the saved session.`)},p=async()=>{try{let u=await t.submitTurn(e,n,o);for await(let v of ft(u,r.onActivity))await s(v)}catch(u){if(o?.aborted||u instanceof f&&u.exitCode===m.API_ERROR)throw u;return i.streamId?a():c()}return i.settled?i.outcome():i.streamId?a():c()},l;try{l=await t.submitTurn(e,n,o)}catch(u){if(o?.aborted||u instanceof f&&u.exitCode!==m.FAILURE)throw u;return p()}if(!l)throw new f("Oracle did not return a stream response.",m.FAILURE);r.onResponse?.();try{for await(let u of ft(l,r.onActivity))await s(u)}catch(u){if(o?.aborted||u instanceof f)throw u;return i.streamId?a():p()}return i.settled?i.outcome():i.streamId?a():p()}async function Kn(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<$o;){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 Co(300,void 0,o?{signal:o}:void 0)}}catch(c){if(o?.aborted||c instanceof f&&c.exitCode===m.API_ERROR||(a+=1,a>=$o))throw c;await Co(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 gt(t,e){let n=e.done,r=n?.servedBy,o=Ce(n?.tokens),i=U(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(We):void 0),p=e.error?"error":e.question?"awaiting_input":a?"complete":"interrupted";return{protocolVersion:1,sessionId:t,status:p,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:de(r)}:{},...o?{usage:{...o,...i!==void 0?{rounds:i}:{}}}:{},...i!==void 0?{rounds:i}:{},...s?{exitReason:s}:{},...c?.length?{files:de(c)}:{}}}function S(t,e){return typeof t=="string"?d(t).slice(0,e):""}function Hn(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 Jn(t){let e=t.question;if(!e||typeof e!="object")throw new f("Oracle question event omitted its question card.",m.API_ERROR);return ba(e)}function We(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 Oa(t,e){let n=We(e);t.some(r=>r.fileId===n.fileId)||t.push(n)}function ba(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 U(t){return typeof t=="number"&&Number.isFinite(t)?t:void 0}function Ce(t){if(typeof t=="number"&&Number.isFinite(t))return{totalTokens:t};if(!t||typeof t!="object"||Array.isArray(t))return;let e=t,n=U(e.in)??U(e.input)??U(e.inputTokens),r=U(e.cacheRead),o=U(e.cacheWrite),i=n===void 0?void 0:n+(r??0)+(o??0),s=U(e.out)??U(e.output)??U(e.outputTokens),a=U(e.total)??U(e.totalTokens)??(i!==void 0||s!==void 0?(i??0)+(s??0):void 0);if(!(i===void 0&&s===void 0&&a===void 0))return{...i!==void 0?{inputTokens:i}:{},...r?{cachedInputTokens:r}:{},...s!==void 0?{outputTokens:s}:{},...a!==void 0?{totalTokens:a}:{}}}function Ke(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 ht(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 wt(t,e){await Eo(t,e).catch(()=>{})}async function Yt(t,e,n,r){if(!n.length)return[];if(n.length>_o)throw new y(`Attach no more than ${_o} files per turn.`);let o=0,i=[];for(let a of n){let c=await wa(a);if(!c.isFile())throw new y(`Attachment is not a file: ${a}`);if(c.size>To)throw new y(`Attachment exceeds the 10 MiB per-file CLI limit: ${a}`);let p=await Ra(a,To);if(o+=p.byteLength,o>va)throw new y("Attachments exceed the 20 MiB total CLI limit.");let l=ya(a).replace(/[\u0000-\u001f\u007f/\\]/g,"_").slice(0,200)||"attachment",u=bo(l)??"";if(!u)throw new y(`Unsupported attachment type: ${a}`);i.push({content:p,name:l,mediaType:u})}let s=[];for(let{content:a,name:c,mediaType:p}of i){await r(d(c),a.byteLength);let l=new ArrayBuffer(a.byteLength);new Uint8Array(l).set(a);let u=new File([l],c,{type:p});s.push(await t.upload(e,u))}return s}async function Ra(t,e){let n=[],r=0;for await(let o of ha(t)){let i=Buffer.isBuffer(o)?o:Buffer.from(o);if(r+=i.byteLength,r>e)throw new y(`Attachment exceeds the ${N(e)} limit: ${t}`);n.push(i)}return Buffer.concat(n)}var yt=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],ka=2e4,xa=6,Ia={lookup:"Looking things up",quick_edit:"Making a quick edit",final_answer:"Composing the answer",follow_up:"Suggesting follow-ups"},Sa={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"},Vt=class{constructor(e,n){this.startedAt=e;this.sessionId=n;this.lastSignalAt=e}phase="sending";answer="";tools=[];notices=[];files=[];lastSignalAt;endedAt;end;done;upload;round;maxRounds;serverPhase;agents=new Map;toolIds=new Set;get toolCount(){return this.tools.length}get failedCount(){return this.tools.filter(e=>e.status==="failed").length}get finished(){return this.end!==void 0}setUploading(e,n,r){this.phase="uploading",this.upload=`${e} (${N(n)})`,this.lastSignalAt=r}setPhase(e,n){this.phase=e,this.lastSignalAt=n}touch(e){this.lastSignalAt=e}apply(e,n){if(this.lastSignalAt=n,this.phase==="cancelling")return this.record(e);switch(e.type){case"stream_start":case"thinking":this.phase!=="finishing"&&(this.phase="thinking");break;case"round_start":this.round=U(e.round),this.maxRounds=U(e.maxRounds)??this.maxRounds;for(let r=this.tools.length-1;r>=0;r--)this.tools[r]?.started&&this.tools.splice(r,1);this.phase!=="finishing"&&(this.phase="thinking");break;case"phase":this.serverPhase=typeof e.phase=="string"?e.phase:void 0;break;case"delta":this.phase!=="finishing"&&(this.phase="writing");break;case"tool_result":this.phase!=="finishing"&&(this.phase="thinking");break;case"finalizing":this.phase="finishing";break}this.record(e)}record(e){switch(e.type){case"delta":typeof e.content=="string"&&(this.answer+=e.content);break;case"tool_call_start":case"tool_call":this.recordToolCall(e);break;case"tool_result":{let n=this.tools.find(r=>r.id!==void 0&&r.id===e.toolUseId);n&&(n.status=e.ok===!1?"failed":"ok");break}case"subagent_start":typeof e.spawnId=="string"&&this.agents.set(e.spawnId,"running");break;case"subagent_done":typeof e.spawnId=="string"&&this.agents.set(e.spawnId,"done");break;case"warning":this.notices.push({tone:"warning",text:`Warning: ${S(e.message,500)}`});break;case"navigator_file_error":this.notices.push({tone:"warning",text:`Could not generate ${S(e.filename,200)}: ${S(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:`${S(r.name,160)}: ${S(r.message,500)}`})}break;case"provider_fallback":{let n=S(e.from,120),r=S(e.to,120),o=S(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=We(e.file);if(this.files.some(r=>r.fileId===n.fileId))break;this.files.push(n),this.notices.push({tone:"info",text:`Generated ${n.filename} (${N(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`});break}case"error":this.notices.push({tone:"error",text:Hn(e)});break;case"done":this.done=e;break}}recordToolCall(e){let n=typeof e.id=="string"?e.id:void 0,r=Wn(e,this.toolIds),o=typeof e.name=="string"?e.name:"";if(o==="ask_user")return;let i=S(typeof e.label=="string"?e.label:Bt(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&&Ia[this.serverPhase]||"Thinking"}statusLine(e,n){let r=[this.label(),qn(e-this.startedAt)];this.round&&r.push(this.maxRounds?`step ${this.round}/${this.maxRounds}`:`step ${this.round}`);let o=e-this.lastSignalAt;return o>=ka&&this.phase!=="cancelling"&&r.push(`no update for ${qn(o)}`),n&&e-this.startedAt>=n*.9&&this.phase!=="finishing"&&r.push("wrapping up"),r.join(" \xB7 ")}summaryLine(){let e=[],n=ct((this.endedAt??this.startedAt)-this.startedAt),r=typeof this.done?.exitReason=="string"?this.done.exitReason:void 0,o;this.end==="complete"?o=Fo("\u2713"):this.end==="awaiting_input"?o=Lo("?")+" Waiting for your answer":this.end==="cancelled"?o=Qn("\u2717")+" Interrupted":this.end==="error"?o=Yn("\u2717")+" Error":o=Qn("\u2717")+` Stopped: ${r&&Sa[r]||"no final answer"}`,e.push(n),this.tools.length&&e.push(`${this.tools.length} tool${this.tools.length===1?"":"s"}`);let i=Ce(this.done?.tokens);(i?.inputTokens!==void 0||i?.outputTokens!==void 0)&&e.push(`${ee(i.inputTokens??0)} in${i.cachedInputTokens?` (${ee(i.cachedInputTokens)} cached)`:""} / ${ee(i.outputTokens??0)} out`);let s=vt(this.done?.servedBy);return s&&e.push(s),`${o} ${He(e.join(" \xB7 "))}`}};function vt(t){if(!t||typeof t!="object")return"";let e=t,n=S(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"?`: ${S(r.reason,40).replaceAll("_"," ")}`:"";return`${n} (fallback from ${S(r.from,100)}${o})`}return n}var Xt=class{constructor(e,n){this.activity=e;this.view=n}answer=new Me("");getText(){return this.answer.getText()}invalidate(){this.answer.invalidate()}render(e){let n=this.activity;this.answer.setText(n.answer);let r=[pt("assistant")];r.push(...this.renderTools(e)),r.push(...this.answer.render(e));for(let o of n.notices){let i=o.tone==="error"?Yn:o.tone==="warning"?Qn:He;r.push(...Po(i(o.text),e))}return n.finished&&r.push(Qt(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[Qt(He(` \u23BF ${a}`),e)]}let r=this.activity.finished?n:n.slice(-xa),o=n.length-r.length,i=[];return o&&i.push(Qt(He(` \u23BF \u2026 ${o} earlier tool${o===1?"":"s"}`),e)),r.forEach((s,a)=>{if(s.note)for(let u of Po(s.note,Math.max(10,e-4)).slice(0,3))i.push(` ${He(Aa(u))}`);let c=s.status==="running"?Lo(yt[this.view.frame()%yt.length]??"*"):s.status==="ok"?Fo("\u2713"):Yn("\u2717"),p=a===0&&!o?" \u23BF ":" ",l=s.spawnId?` ${He("agent \xB7")} `:"";i.push(Qt(`${p}${l}${c} ${s.label}`,e))}),i}};import{randomUUID as Ma}from"node:crypto";import{stat as Ua}from"node:fs/promises";import{basename as zo}from"node:path";import{bold as ja,cyan as Wo,dim as Ko,red as nn}from"kleur/colors";import{Container as Da,Editor as Ba,ProcessTerminal as Ga,ScrollView as za,SelectList as Wa,TuiAltScreen as Ka,VStack as Ha,getNativeClipboard as Ja,matchesKey as rn,truncateToWidth as Ho,wrapTextWithAnsi as Ya}from"@earendil-works/pi-tui";import{truncateToWidth as _a,visibleWidth as $a,wrapTextWithAnsi as Uo}from"@earendil-works/pi-tui";import{bold as Pa,cyan as La,dim as ge}from"kleur/colors";import{CombinedAutocompleteProvider as Ea}from"@earendil-works/pi-tui";var Ot=[{name:"help",description:"Show commands and keyboard shortcuts"},{name:"status",description:"Show session, access, model, usage and limits"},{name:"model",description:"Show the workspace model and the model that answered last"},{name:"usage",description:"Show turns and tokens used in this terminal"},{name:"new",args:"[shared]",description:"Start a new conversation",idleOnly:!0,completions:["shared"]},{name:"clear",description:"Clear the screen and start a new private conversation",idleOnly:!0},{name:"resume",args:"[session-id]",description:"Pick or open a saved conversation",idleOnly:!0},{name:"context",args:"[clear|program|initiative|codebase <id>]",description:"Show or change the context for the next message",completions:["clear","program ","initiative ","codebase "]},{name:"attach",args:"<path>",description:"Attach a file to your next message"},{name:"copy",description:"Copy the last answer as Markdown"},{name:"files",description:"List files Oracle generated in this conversation"},{name:"exit",description:"Leave the Oracle",aliases:["quit"]}],Ca=[{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 No(t){let e=new Set(Ot.flatMap(n=>[n.name,...n.aliases??[]]));return(t??Ca).filter(n=>!e.has(n.name))}function qo(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=Ot.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 Mo(t,e){let n=[...Ot.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=>Ta(i.completions??[],s)}:{}})),...t.map(i=>({name:i.name,description:i.description,...i.args?{argumentHint:i.args}:{}}))],r=new Ea(n,e),o=/^\s*\/attach\s+/;return{async getSuggestions(i,s,a,c){let p=(i[s]??"").slice(0,a);return s!==0||!p.trimStart().startsWith("/")?null:o.test(p)?r.getSuggestions(i,s,a,{...c,force:!0}):r.getSuggestions(i,s,a,c)},applyCompletion(i,s,a,c,p){return r.applyCompletion(i,s,a,c,p)},shouldTriggerFileCompletion(i,s,a){return s===0&&o.test((i[s]??"").slice(0,a))}}}function Ta(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 Zt(t,e){return t?e?"write + approve":"write":"read only"}function Je(t){return t?`${t.kind} ${d(t.id)}`:"no context"}function jo(t,e){let n=[`${Pa(La("AnyForge Oracle"))}${ge(` \xB7 v${d(t.version)}`)}`,`${ue(t.session)} \xB7 ${t.access} \xB7 ${Je(t.context)}`,...t.session.messages.length?[`Resumed: ${d(t.session.title)}`]:[],ge("Only your messages and the files you attach leave this terminal."),ge("/help commands \xB7 /status details")];if(e<24)return n.flatMap(s=>Uo(s,Math.max(1,e)));let r=Math.min(e,76),o=r-4,i=[ge(`\u256D${"\u2500".repeat(r-2)}\u256E`)];for(let s of n.flatMap(a=>Uo(a,o))){let a=_a(s,o);i.push(`${ge("\u2502")} ${a}${" ".repeat(Math.max(0,o-$a(a)))} ${ge("\u2502")}`)}return i.push(ge(`\u2570${"\u2500".repeat(r-2)}\u256F`)),i}function Do(t){let e=(r,o)=>r?`${ge(r)} ${o}`:o,n=[{title:"Commands",rows:Ot.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(["",ge("Acting on /catchup decisions needs a session started with `anyforge oracle --write --approve`.")]),n.push({title:"Workspace commands (answered by Oracle)",rows:r})}return n.push({title:"Keys",rows:[["Enter","Send. While Oracle works, queues one message for when it finishes"],["Shift+Enter","New line (Ctrl+J also works)"],["Esc","Interrupt the current answer"],["Ctrl+C","Interrupt the answer, or clear the input; press twice to exit"],["Ctrl+D","Exit when the input is empty"],["Ctrl+O","Show or hide tool activity for finished answers"],["Ctrl+Shift+F","Search the conversation"],["Up / Down","Recall messages sent in this terminal"],["Tab","Complete a command, or a file path after /attach"],["PgUp / PgDn","Scroll; Home and End jump to the top and bottom"]]}),n}function Vn(t){let n=[["Model",`workspace default ${t.model?`${d(t.model.provider)}/${d(t.model.id)}`:"chosen by the server"}`]],r=vt(t.lastServedBy);if(r){let o=t.lastServedBy,i=S(o.routing,40).replaceAll("_"," ");n.push(["Last answer",`${r}${i?` \xB7 ${i}`:""}`])}return n}function Xn(t){return[["This run",t.turns?`${t.turns} turn${t.turns===1?"":"s"} \xB7 ${t.tools} tool${t.tools===1?"":"s"} \xB7 ${ee(t.inputTokens)} in / ${ee(t.outputTokens)} out tokens`:"no turns yet"]]}function Zn(t){if(!t?.finished)return[];let e=[ct((t.endedAt??t.startedAt)-t.startedAt)];e.push(`${t.toolCount} tool${t.toolCount===1?"":"s"}${t.failedCount?` (${t.failedCount} failed)`:""}`);let n=U(t.done?.rounds);n!==void 0&&e.push(`${n} round${n===1?"":"s"}`);let r=Ce(t.done?.tokens);(r?.inputTokens!==void 0||r?.outputTokens!==void 0)&&e.push(`${ee(r.inputTokens??0)} in${r.cachedInputTokens?` (${ee(r.cachedInputTokens)} cached)`:""} / ${ee(r.outputTokens??0)} out tokens`);let o=S(t.done?.exitReason,40);return e.push(o?o.replaceAll("_"," "):t.end??""),[["Last turn",e.filter(Boolean).join(" \xB7 ")]]}function Bo(t){let e=t.capabilities?["read","write","approve"].filter(o=>t.capabilities?.[o]).join(", ")||"none":"not reported",n=t.contextText?` \xB7 note ${N(Buffer.byteLength(t.contextText,"utf8"))}`:"",r=fo(t.limits);return[["Session",`${t.session.sessionId} \xB7 ${d(t.session.title)||"Untitled"}`],["Audience",ue(t.session)],["Access",`this session ${Zt(t.write,t.approve)} \xB7 grant ${t.grantScopes.join(", ")||"none"} \xB7 workspace role ${e}`],["Context",`${Je(t.context)}${n}`],...Vn(t),...Zn(t.lastTurn),...Xn(t.totals),["Limits",r.length?r.join(" \xB7 "):"not reported"],...t.identity?[["Workspace",`company ${t.identity.companyId} \xB7 user ${t.identity.uid}`]]:[],["Endpoint",t.endpoint],["Version",`CLI ${d(t.version)} \xB7 protocol ${1}`],["Attached",t.pendingFiles.length?`${t.pendingFiles.map(d).join(", ")} (uploads with your next message)`:"nothing waiting"]]}function Go(t,e){return e.length?e.map((n,r)=>[`${r+1}.`,`${d(n.filename)} (${N(n.sizeBytes)}) \xB7 anyforge oracle download ${t} ${d(n.fileId)} --output .`]):[["Files","Oracle has not generated files in this conversation."]]}import{bold as Fa,cyan as er,dim as en,yellow as Na}from"kleur/colors";import{Input as qa,Text as Te,matchesKey as Ye}from"@earendil-works/pi-tui";var tn=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 qa({prompt:`${er("Your answer: ")} `,placeholder:"Write a short answer and press Enter",placeholderStyle:en});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 Te(`${Fa(er(d(n.header)))}${en(o)}`,0,0).render(r),...new Te(d(n.question),0,0).render(r),...this.renderOptions(n,r)];return this.mode==="custom"?(i.push(...this.customInput.render(r)),i.push(...new Te(en(`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 Te(en(this.instructions(n)),0,0).render(r)),this.errorMessage&&i.push(...new Te(Na(this.errorMessage),0,0).render(r)),i.map(s=>`${er("\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(Ye(e,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.handleInput(e);return}if(Ye(e,"up")){this.optionIndex=Math.max(0,this.optionIndex-1),this.errorMessage="",this.tui.requestRender();return}if(Ye(e,"down")){this.optionIndex=Math.min(n.options.length-1,this.optionIndex+1),this.errorMessage="",this.tui.requestRender();return}if(Ye(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(Ye(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(Ye(e,"enter")){if(r.size===0){this.errorMessage="Select an option explicitly, type a custom answer, or skip if optional.",this.tui.requestRender();return}this.recordCurrent()}}renderOptions(e,n){let r=this.selectedFor(e),o=[];return e.options.forEach((i,s)=>{let a=r.has(i.id),c=e.multiSelect?a?"[x]":"[ ]":a?"(x)":"( )",p=s===this.optionIndex?"\u203A":" ",l=i.recommended?" \xB7 recommended":"",u=i.confirms?" \xB7 confirms the shown action":"",v=`${p} ${s+1}. ${c} ${d(i.label)}${l}${u}`;o.push(...new Te(v,0,0).render(n)),o.push(...new Te(` ${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 Jo=1500,Qa=100,Va="\x1B]133;A\x07";function Qe(t){return{render:t,invalidate(){}}}function Yo(t,e,n){let r=new Me(e);return{getText:()=>r.getText(),invalidate:()=>r.invalidate(),render:o=>t==="user"?["",`${Va}${pt("user",n)}`,...r.render(o)]:[pt("assistant"),...r.render(o)]}}async function Qo(t){let{client:e,config:n}=t,r=new Ga,o=new Ka(r,void 0,void 0,{scrollToEndIndicator:()=>" more below \xB7 End to jump "}),i=new Da,s=new za(i,{follow:"end",primary:!0,overscroll:"chain"}),a=new Ba(o,yo),c=No(n.commands),p=typeof n.limits?.turnSoftMs=="number"?n.limits.turnSoftMs:void 0,l=t.session,u=t.initialContext,v=t.contextText,x=t.canWrite,k=t.canApprove,b,O,R,V,K=[...t.initialFiles],ae=!1,cn=!1,kt=!1,ln=0,_e,cr=0,Ae="",xt,dn,$e=[],Pe={turns:0,inputTokens:0,outputTokens:0,tools:0},It=new Map,ce,gi=Qe(g=>{if(b){let w=Wo(yt[ln%yt.length]??"*");return[Ho(`${w} ${b.activity.statusLine(Date.now(),p)}`,g)]}return ce?[Ho(`${Wo("?")} Waiting for your answer to the question above`,g)]:[]}),hi=Qe(g=>{let w=[Zt(x,k),Je(u),vo(l),K.length?`${K.length} file${K.length===1?"":"s"} attached`:"",O!==void 0?"1 message queued":""];return[Ko(go(g,w,b?"esc to interrupt":"/help \xB7 /status"))]});o.setLayoutRoot(new Ha([{component:s,basis:0,grow:1,minSize:1},{component:gi,basis:"auto",shrink:0},{component:a,basis:"auto",shrink:0,minSize:2},{component:hi,basis:"auto",shrink:0,minSize:1}]));let Y=()=>o.requestRender(),F=g=>o.flash(d(g),3e3),we=g=>{i.addChild(g),Y()},te=(g,w=Ko)=>{let h=d(g);we(Qe(A=>Ya(w(h),Math.max(1,A))))},St=(g,w)=>{we(Qe(h=>["",...mo(g,w,h)]))},wi=()=>{_e||(_e=setInterval(()=>{ln+=1,Y()},Qa),_e.unref())},un=()=>{_e&&clearInterval(_e),_e=void 0},Ve=()=>{ae||o.hasOverlay()||o.setFocus(ce??a)},lr=g=>{R=g;let w=It.get(g.id);w&&i.removeChild(w);let h=new tn(o,g,A=>{It.delete(g.id),ce===h&&(ce=void 0),i.removeChild(h),Oi(A??{questionId:g.id,skipped:!0,answers:[]}),Ve()});It.set(g.id,h),ce=h,we(h)},pn=g=>{i.clear(),It.clear(),ce=void 0,l=g,R=void 0,V=void 0,$e=[],Ae="";let w={version:t.version,session:g,access:Zt(x,k),context:u};we(Qe(A=>jo(w,A)));let h;for(let A of g.messages){we(Yo(A.role,A.content,A.authorName)),A.role==="assistant"&&(Ae=A.content),A.question&&(h=A.question),A.questionResponse&&(te("A stored response was recorded for this question."),h?.id===A.questionResponse.questionId&&(h=void 0));for(let I of A.files??[])$e.some(q=>q.fileId===I.fileId)||$e.push(I),te(`File: ${I.filename} (${I.mediaType}, ${N(I.sizeBytes)}) \xB7 anyforge oracle download ${g.sessionId} ${I.fileId} --output .`)}h&&lr(h),Ve(),wt(g.sessionId,e.endpoint)},dr,yi=new Promise(g=>{dr=g}),Et=()=>{ae||(ae=!0,un(),b?.controller.abort(new Error("Detached from the active Oracle stream.")),o.stop(),dr())},fn=async()=>{let g=b;if(!g||g.cancelling)return;g.cancelling=!0,g.activity.setPhase("cancelling",Date.now()),Y();let{streamId:w,requestId:h}=g;g.controller.abort(new Error("Turn cancelled by user."));let A;if(w)try{A=Ke(await e.cancelTurn(l.sessionId,w))}catch(I){A=`Could not confirm server cancellation: ${Q(I)}`}else if(h)try{A=Ke(await e.cancelRequest(l.sessionId,h))}catch(I){A=`Could not confirm server cancellation by request id: ${Q(I)}`}else A="The turn had not reached the server; nothing was sent.";g.activity.note("info",A),Y()},Le=async g=>{if(b||ae)return;if(g.kind==="submit"&&g.response){let _=R;if(!_||_.id!==g.response.questionId){F("That question is no longer active. Resume the session to refresh it.");return}te(Xa(_,g.response)),R=void 0}else g.kind==="submit"&&we(Yo("user",g.text));let w=l.sessionId,h=new Vt(Date.now(),w),A=new Xt(h,{expanded:()=>kt,frame:()=>ln}),I={activity:h,view:A,controller:new AbortController,cancelling:!1};b=I,we(A),wi();let q=new Ee,gr=_=>{h.apply(_,Date.now()),_.type==="question"&&(lr(Jn(_)),Ve()),Y()},hr={onEvent:gr,onStream:_=>{I.streamId=_},onResponse:()=>{h.phase==="sending"&&h.setPhase("preparing",Date.now())},onActivity:()=>h.touch(Date.now())},ye="error";try{if(g.kind==="replay"){q.streamId=g.streamId,I.streamId=g.streamId,h.setPhase("thinking",Date.now());let _=await Kn(e,w,q,async ne=>{q.accept(ne)&&gr(ne)},I.controller.signal,hr.onActivity);ye=gt(w,_).status}else{let _=g.response?[]:K.splice(0),ne=await Yt(e,w,_,(mn,Ei)=>{h.setUploading(mn,Ei,Date.now()),Y()});I.controller.signal.throwIfAborted(),h.setPhase("sending",Date.now());let Ct=Ma();I.requestId=Ct;let Ii={requestId:Ct,text:g.response?"":g.text,readOnly:!x,...k?{allowApprove:!0}:{},...u?{context:u}:{},...v?{contextText:v}:{},...g.response?{questionResponse:g.response}:{},...ne.length?{attachments:ne.map(mn=>({fileId:mn.fileId}))}:{}},Si=await Jt(e,w,Ii,hr,I.controller.signal,q);ye=gt(w,Si).status}}catch(_){if(I.controller.signal.aborted)ye="cancelled";else{ye="error";let ne=_ instanceof f&&_.hint?` ${d(_.hint)}`:"";h.note("error",`${Q(_)}${ne}`)}}finally{h.finish(ye,Date.now()),b=void 0,un(),ae||(cn=ye==="cancelled"),xt=h,h.answer.trim()&&(Ae=h.answer),h.done?.servedBy&&(dn=h.done.servedBy);let _=Ce(h.done?.tokens);Pe.turns+=1,Pe.tools+=h.toolCount,Pe.inputTokens+=_?.inputTokens??0,Pe.outputTokens+=_?.outputTokens??0;for(let ne of h.files)$e.some(Ct=>Ct.fileId===ne.fileId)||$e.push(ne);Y()}if(!ae){if(I.streamId&&ye!=="cancelled"){let _=await e.getSession(w).catch(()=>{});_&&_.sessionId===l.sessionId&&(l=_)}vi(ye)}},vi=g=>{if(!(ae||b)){if(V){let w=V;V=void 0,Le({kind:"submit",text:"",response:w});return}if(O!==void 0){let w=O;if(O=void 0,g==="complete"&&!ce){Le({kind:"submit",text:w});return}a.getText()||a.setText(w),F("Your queued message is back in the input; press Enter to send it.")}Ve(),Y()}},Oi=g=>{if(b){V=g,F("Answer saved; Oracle continues once the current turn settles.");return}Le({kind:"submit",text:"",response:g})},ur=async g=>{try{let w=await e.getSession(g);pn(w),w.activeStreamId&&Le({kind:"replay",streamId:w.activeStreamId}),F(`Resumed ${w.title||w.sessionId}.`)}catch(w){te(Q(w),nn)}},bi=async()=>{try{let g=await e.listSessions();if(!g.length){F("No saved conversations to resume.");return}let w=new Wa(g.map(q=>({value:q.sessionId,label:q.title,description:ue(q)})),Math.min(12,g.length),ut),h=await Kt(e.endpoint),A=h?g.findIndex(q=>q.sessionId===h):-1;A>=0&&w.setSelectedIndex(A);let I=o.showOverlay(w,{width:"85%",maxHeight:"80%",anchor:"center"});w.onSelect=q=>{I.hide(),ur(q.value)},w.onCancel=()=>{I.hide(),Ve()},I.focus()}catch(g){te(Q(g),nn)}},pr=async g=>{if(g&&(!u||u.kind!=="program"&&u.kind!=="initiative")){F("Use /context program <id> or /context initiative <id> before /new shared.");return}try{let w=await e.createSession(ht(u,g));pn(w),F(`Started a new conversation \xB7 ${ue(w)}.`)}catch(w){te(Q(w),nn)}},Ri=()=>({session:l,write:x,approve:k,grantScopes:[...e.scopes],...n.capabilities?{capabilities:n.capabilities}:{},...u?{context:u}:{},...v?{contextText:v}:{},...n.model?{model:n.model}:{},lastServedBy:dn,...xt?{lastTurn:xt}:{},totals:{...Pe},...n.limits?{limits:n.limits}:{},...n.identity?{identity:n.identity}:{},endpoint:e.endpoint,version:t.version,pendingFiles:K.map(g=>zo(g))}),Ai=async()=>{if(!Ae.trim()){F("There is no answer to copy yet.");return}try{let g=Ja();g?.setText?await g.setText(Ae):r.write(`\x1B]52;c;${Buffer.from(Ae,"utf8").toString("base64")}\x07`),F(`Copied the last answer (${Ae.length} characters).`)}catch(g){F(`Could not copy: ${Q(g)}`)}},ki=async(g,w,h)=>{if(g.idleOnly&&b){F(`Wait for Oracle to finish, or press Esc, before /${g.name}.`);return}switch(g.name){case"help":we(Qe(A=>["",...Do({server:c,canApprove:k}).flatMap(I=>[ja(I.title),...Mn(I.rows,A)])]));return;case"status":St("Status",Bo(Ri()));return;case"model":St("Model",Vn({...n.model?{model:n.model}:{},lastServedBy:dn}));return;case"usage":St("Usage",[...Zn(xt),...Xn(Pe)]);return;case"files":St("Generated files",Go(l.sessionId,$e));return;case"copy":await Ai();return;case"exit":Et();return;case"new":if(h&&h!=="shared"){F("Usage: /new or /new shared");return}await pr(h==="shared");return;case"clear":await pr(!1);return;case"resume":h?await ur(h):await bi();return;case"context":{if(!h){te(`Context: ${Je(u)}${v?" + free-text note":""}. Use /context <program|initiative|codebase> <id> or /context clear.`);return}if(h==="clear")u=void 0;else{let[A,I,...q]=w;if(!["program","initiative","codebase"].includes(A??"")||!I||q.length){F("Usage: /context program <id>, /context initiative <id>, /context codebase <id>, or /context clear");return}u={kind:A,id:I}}te(`Context for your next message: ${Je(u)}.`);return}case"attach":{if(!h){F("Usage: /attach <file path>");return}let A=await Ua(h).catch(()=>{});if(!A?.isFile()){F(`Not a readable file: ${h}`);return}K.push(h),te(`Attached ${zo(h)} (${N(A.size)}). It uploads with your next message.`);return}}},fr=g=>{let w=g.trim();if(!w)return;a.addToHistory(w);let h=qo(w,c);if(h?.kind==="local"){ki(h.command,h.args,h.arg).catch(A=>te(Q(A),nn));return}if(h?.kind==="unknown"){a.setText(w),F(`Unknown command /${h.name}. Type /help to see the commands.`);return}if(b){let A=O!==void 0;O=w,F(A?"Replaced your queued message. It sends when Oracle finishes.":"Queued. It sends when Oracle finishes; Esc interrupts instead."),Y();return}Le({kind:"submit",text:w})},xi=o.addInputListener(g=>{if(rn(g,"ctrl+c")){if(b)return fn(),{consume:!0};if(o.hasOverlay())return;if(o.getFocusedComponent()===a&&a.getText())return a.setText(""),Y(),{consume:!0};let w=Date.now();return w-cr<=Jo?Et():(cr=w,o.flash("Press Ctrl+C again to exit",Jo)),{consume:!0}}if(rn(g,"escape")){let w=ce!==void 0&&o.getFocusedComponent()===ce;return b&&!a.isShowingAutocomplete()&&!o.hasOverlay()&&!w?(fn(),{consume:!0}):void 0}if(rn(g,"ctrl+d"))return o.getFocusedComponent()===a&&!a.getText()?(Et(),{consume:!0}):void 0;if(rn(g,"ctrl+o"))return kt=!kt,F(kt?"Showing tool activity":"Hiding tool activity"),Y(),{consume:!0}}),mr=()=>{let g=!!b;fn().finally(()=>{g&&(cn=!0),Et()})};process.on("SIGINT",mr),a.onSubmit=fr,a.onChange=()=>Y(),a.setAutocompleteProvider(Mo(c,process.cwd())),pn(t.session),o.start(),l.activeStreamId&&Le({kind:"replay",streamId:l.activeStreamId}),t.initialPrompt&&fr(t.initialPrompt),await yi,xi(),process.off("SIGINT",mr),un(),b?.controller.abort(),await r.drainInput().catch(()=>{}),cn&&(process.exitCode=130)}function Xa(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 Za,randomBytes as Vo,timingSafeEqual as ec}from"node:crypto";import{createServer as tc}from"node:http";import nc from"open";var rc=6e4,oc=5*6e4,on=new Map;async function tr(t){let e=fe(t.endpoint),n=await Ge(e),r=["read"];t.write&&r.push("write"),t.approve&&(r.includes("write")||r.push("write"),r.push("approve"));let o=Vo(32).toString("base64url"),i=await ac(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 cc(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=Vo(32).toString("base64url"),p=Za("sha256").update(c).digest("base64url"),l={client_id:a.client_id,redirect_uri:i.redirectUri,response_type:"code",scope:r.join(" "),state:o,code_challenge:p,code_challenge_method:"S256",resource:n.resource},u=new URL(n.oauth.authorization);for(let[R,V]of Object.entries(l))u.searchParams.set(R,String(V));t.onAuthorizationUrl?.(u.toString());try{t.openBrowser?await t.openBrowser(u.toString()):await nc(u.toString())}catch{process.stderr.write(`Open this URL to authorize AnyForge Oracle:
|
|
259
|
+
`},Rd=Object.entries(Bt).map(([t,e])=>({uri:t==="SKILL.md"?ao:`${ao}/${t}`,name:t==="SKILL.md"?se:`${se}/${t.replace(/^references\//,"")}`,title:t==="SKILL.md"?"AnyForge platform guide":t,description:t==="SKILL.md"?Fs:`Reference for the ${se} skill: ${t}`,mimeType:Ns,size:new TextEncoder().encode(e).byteLength}));var qs=Bt["SKILL.md"],Ad=qs.replace(/^---[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/,"");var uo={agents:".agents/skills",claude:".claude/skills",codex:".codex/skills"};function Ds(t){let e=t.scope==="user"?t.homeDir??Ms():t.cwd??process.cwd();if(t.scope==="user"&&t.client==="codex"){let n=t.codexHome??process.env.CODEX_HOME??Ie(e,".codex");return Ie(n,"skills",se)}return Ie(e,uo[t.client],se)}function Bs(t){if(t.scope!=="project"&&t.scope!=="user")throw new y(`--scope must be project or user, got "${t.scope}".`);if(!Object.hasOwn(uo,t.client))throw new y(`--client must be agents, claude, or codex, got "${t.client}".`)}async function Ln(t){try{return(await st.lstat(t)).isSymbolicLink()}catch(e){if(e.code==="ENOENT")return!1;throw e}}async function Gs(t){Bs(t);let e=Ds(t),n=Object.entries(Bt),r=n.map(([s])=>Ie(e,s));if(await Ln(e))throw new y(`Refusing to install through the symbolic link ${e}.`);let o=new Set(n.map(([s])=>co(s)).filter(s=>s!=="."));for(let s of o)if(await Ln(Ie(e,s)))throw new y(`Refusing to install through the symbolic link ${Ie(e,s)}.`);if(!t.force){let s=[];for(let a of r)try{await st.access(a),s.push(a)}catch(c){if(c.code!=="ENOENT")throw c}if(s.length>0)throw new y(`The ${se} skill already exists at ${e}.`,"Use --force only if you want to replace AnyForge-managed files in that directory.")}await st.mkdir(e,{recursive:!0});let i=[];for(let[s,a]of n){let c=Ie(e,s);if(await st.mkdir(co(c),{recursive:!0}),await Ln(c))throw new y(`Refusing to replace the symbolic link ${c}.`);await st.writeFile(c,a,{encoding:"utf8",mode:420}),i.push(s)}return{name:se,scope:t.scope,client:t.client,directory:e,files:i}}async function po(t){if(t.subcommand!=="install")throw new y(`Unknown skill command${t.subcommand?`: ${t.subcommand}`:""}.`,"Use `anyforge skill install anyforge-platform`.");if(t.name!==se)throw new y(`Unknown skill${t.name?`: ${t.name}`:""}.`,`The only portable platform skill is ${se}.`);let e=t.scope??"project",n=t.client??"agents";if(!["project","user"].includes(e))throw new y(`--scope must be project or user, got "${e}".`);if(!["agents","claude","codex"].includes(n))throw new y(`--client must be agents, claude, or codex, got "${n}".`);let r=await Gs({scope:e,client:n,force:t.force});if(t.json){process.stdout.write(JSON.stringify(r)+`
|
|
260
|
+
`);return}console.log(Us("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(js(" This portable location is detected by AnyForge repository analysis."))}import{randomUUID as fc}from"node:crypto";import{open as mc,realpath as gc,stat as hc}from"node:fs/promises";import{basename as wc,join as yc,resolve as vc}from"node:path";import{bold as ui,cyan as Oc,dim as At,yellow as cn}from"kleur/colors";import{ProcessTerminal as bc,SelectList as Rc,Text as Ac,TuiAltScreen as xc}from"@earendil-works/pi-tui";var zs=new Set(["find_callers","find_definition","find_imports","trace_path","get_neighbors","graph_stats"]);function Ws(t){return zs.has(t)?"querying the code graph":t==="search_code_semantic"?"searching the code index":t==="search_codebase_docs"?"searching codebase docs":null}function Gt(t){let e=Ws(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 Ks=new Set(["ask_user","present_catch_up_decision","present_memory_candidates"]);function Me(t){return typeof t=="string"&&Ks.has(t)}import{truncateToWidth as Vt,wrapTextWithAnsi as Lo}from"@earendil-works/pi-tui";import{cyan as Fo,dim as Je,green as No,italic as ka,red as Qn,yellow as Vn}from"kleur/colors";import{truncateToWidth as at,visibleWidth as qn,wrapTextWithAnsi as Ys}from"@earendil-works/pi-tui";import{bold as Qs,dim as Vs}from"kleur/colors";var Hs=/\x1B(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\)|[PX^_][\s\S]*?\x1B\\|[@-_])/g,Js=/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g;function d(t){return t.replace(Hs,"").replace(Js,"")}function Fn(t){try{let e=new URL(t);return e.protocol!=="https:"&&e.protocol!=="http:"||!e.hostname||e.username||e.password?null:e.toString()}catch{return null}}function fo(t){return t.replace(/\x1B\]8;;([^\x1B\x07]*)(?:\x07|\x1B\\)/g,(e,n)=>Fn(n)?e:"\x1B]8;;\x07")}function Nn(t){let n=d(t).replace(/(!?)\[([^\]\n]+)\]\((<[^>\n]*>|[^\s)]+)(?:\s+[^)]*)?\)/g,(i,s,a,c)=>{let p=c.startsWith("<")&&c.endsWith(">")?c.slice(1,-1):c,l=Fn(p);return l?`${s}[${a}](${l})`:a}),r=new Map,o=n.replace(/^(\s{0,3}\[([^\]]+)\]:\s*)(\S+)(.*)$/gm,(i,s,a,c,p)=>{let l=Fn(c);return r.set(a.trim().toLowerCase(),l),l?`${s}${l}${p}`:""});return r.size===0?o:o.replace(/(!?)\[([^\]\n]+)\](?:\[([^\]\n]*)\])?/g,(i,s,a,c)=>{let p=(c||a).trim().toLowerCase();return!r.has(p)||r.get(p)?i:a})}function de(t){return typeof t=="string"?d(t):Array.isArray(t)?t.map(e=>de(e)):t&&typeof t=="object"?Object.fromEntries(Object.entries(t).map(([e,n])=>[d(e),de(n)])):t}function N(t){return t<1024?`${t} B`:t<1024*1024?`${ct(t/1024)} KiB`:`${ct(t/(1024*1024))} MiB`}function lt(t){let e=Math.max(0,t);if(e<1e4)return`${ct(e/1e3)}s`;let n=Math.round(e/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/3600),o=Math.floor(n%3600/60),i=n%60;return r?o?`${r}h ${o}m`:`${r}h`:i?`${o}m ${i}s`:`${o}m`}function Mn(t){let e=Math.floor(Math.max(0,t)/1e3);return e<60?`${e}s`:`${Math.floor(e/60)}m ${String(e%60).padStart(2,"0")}s`}function ee(t){return Math.abs(t)<1e3?String(Math.round(t)):Math.abs(t)<1e6?`${ct(t/1e3,t<1e5?1:0)}k`:`${ct(t/1e6)}M`}function ct(t,e=1){return t.toFixed(e).replace(/\.0+$/,"")}function Xs(t){return d(t).replace(/(Ms|Bytes)$/,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").toLowerCase().trim()}function Zs(t,e){return typeof e=="boolean"?e?"on":"off":typeof e=="string"?d(e):/Ms$/.test(t)?lt(e):/Bytes$/.test(t)?N(e):/tokens?/i.test(t)?ee(e):String(e)}function mo(t){return t?Object.entries(t).filter(e=>e[1]!==null).map(([e,n])=>`${Xs(e)} ${Zs(e,n)}`):[]}function Un(t,e,n=2){let r=Math.min(16,Math.max(...t.map(([s])=>qn(s)),0)+2),o=Math.max(10,e-n-r),i=[];for(let[s,a]of t)Ys(a,o).forEach((p,l)=>{let u=l===0?Vs(at(s,r-1).padEnd(r)):" ".repeat(r);i.push(at(`${" ".repeat(n)}${u}${p}`,e))});return i}function go(t,e,n){return[at(Qs(t),n),...Un(e,n)]}function ho(t,e,n){let r=qn(n),o=e.filter(Boolean).join(" \xB7 ");if(r+4>t)return at(o||n,t);let i=t-r-2,s=at(o,i),a=Math.max(2,t-qn(s)-r);return`${s}${" ".repeat(a)}${n}`}import{bold as ut,cyan as dt,dim as Re,green as ea,italic as wo,strikethrough as ta,underline as yo,yellow as na}from"kleur/colors";import{Markdown as ra}from"@earendil-works/pi-tui";var oa={heading:t=>ut(dt(t)),link:t=>yo(dt(t)),linkUrl:t=>Re(t),code:t=>na(t),codeBlock:t=>t,codeBlockBorder:t=>Re(t),quote:t=>wo(t),quoteBorder:t=>Re(t),hr:t=>Re(t),listBullet:t=>dt(t),bold:t=>ut(t),italic:t=>wo(t),strikethrough:t=>ta(t),underline:t=>yo(t)},pt={selectedPrefix:t=>dt(t),selectedText:t=>ut(t),description:t=>Re(t),scrollInfo:t=>Re(t),noMatch:t=>Re(t)},vo={borderColor:t=>Re(t),selectList:pt};var Ue=class{content;markdown;cache;constructor(e){this.content=d(e),this.markdown=new ra(Nn(this.content),0,0,oa)}getText(){return this.content}setText(e){let n=d(e);n!==this.content&&(this.content=n,this.markdown.setText(Nn(n)),this.cache=void 0)}invalidate(){this.markdown.invalidate(),this.cache=void 0}render(e){let n=Math.max(12,e);if(this.cache?.width===n)return this.cache.lines;let r=this.content?this.markdown.render(n).map(fo):[];return this.cache={width:n,lines:r},r}};function ft(t,e){return t==="user"?`${ut(ea(e?d(e):"You"))}`:`${ut(dt("Oracle"))}`}function ue(t){return t.shared||t.visibility==="company"?`Shared with the company${t.entityKey?` \xB7 ${d(t.entityKey)}`:""}`:"Private to you"}function Oo(t){return t.shared||t.visibility==="company"?"shared":"private"}import{createReadStream as ya}from"node:fs";import{stat as va}from"node:fs/promises";import{basename as Oa}from"node:path";import{setTimeout as Eo}from"node:timers/promises";var bo={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 Ro(t){let e=t.slice(t.lastIndexOf(".")+1).toLowerCase();return Object.hasOwn(bo,e)?bo[e]:null}var jn="/api/v1/oracle";function fe(t){let e;try{e=new URL(t)}catch{throw new f(`Invalid Oracle endpoint: ${t}`,m.USAGE)}if(!["http:","https:"].includes(e.protocol)||e.username||e.password)throw new f("Oracle endpoint must be an http or https URL without embedded credentials.",m.USAGE);if(e.pathname!=="/"||e.search||e.hash)throw new f("Oracle endpoint must be the workspace origin, without a path, query or fragment.",m.USAGE);return e.origin}function pe(t,e){return`${fe(t)}${jn}${e}`}function ia(t,e,n){let r;try{r=new URL(t)}catch{throw new f(`Oracle server returned an invalid ${n} endpoint.`,m.API_ERROR)}let o=new URL(fe(e));if(r.origin!==o.origin||!r.pathname.startsWith("/api/oauth/")||r.search||r.hash||r.username||r.password)throw new f(`Oracle server returned an unsafe ${n} endpoint.`,m.API_ERROR);return r.toString()}function sa(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]=ia(n[i],e,i)}return o}async function ze(t,e=fetch,n){let r=fe(t),o;try{o=await e(pe(r,"/config"),{headers:{Accept:"application/json",...n?{Authorization:`Bearer ${n}`}:{}},redirect:"error",signal:AbortSignal.timeout(2e4)})}catch(l){throw new f(`Cannot reach ${r}: ${l instanceof Error?l.message:String(l)}`,m.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}let i=await Be(o,pe(r,"/config")),s=$(De(i,o.status)),a=`${r}${jn}`;if(s.protocolVersion!==1)throw new f(`Oracle protocol mismatch: this CLI supports ${1}, and the server reports ${String(s.protocolVersion)}.`,m.API_ERROR,"Update @anyforge/control to a version supported by this workspace.");if(s.resource!==a)throw new f("Oracle server resource does not match this workspace origin.",m.API_ERROR);let c=Array.isArray(s.scopes)?s.scopes:null;if(!c||!c.every(l=>l==="read"||l==="write"||l==="approve"))throw new f("Oracle server returned an invalid scope list.",m.API_ERROR);let p={protocolVersion:1,resource:a,scopes:c,oauth:sa(s.oauth,r)};if(s.identity!==void 0){let l=$(s.identity);if(typeof l.uid!="string"||typeof l.companyId!="string")throw new f("Oracle server returned an invalid identity.",m.API_ERROR);p.identity={uid:d(l.uid),companyId:d(l.companyId)}}if(s.capabilities!==void 0){let l=$(s.capabilities);if(![l.read,l.write,l.approve].every(u=>typeof u=="boolean"))throw new f("Oracle server returned invalid capabilities.",m.API_ERROR);p.capabilities={read:l.read,write:l.write,approve:l.approve}}if(s.model!==void 0){let l=$(s.model);if(typeof l.id!="string"||typeof l.provider!="string")throw new f("Oracle server returned invalid model metadata.",m.API_ERROR);p.model={id:d(l.id),provider:d(l.provider)}}if(s.limits!==void 0){let l=$(s.limits);if(Object.values(l).some(u=>!["string","number","boolean"].includes(typeof u)&&u!==null))throw new f("Oracle server returned invalid limits metadata.",m.API_ERROR);p.limits=Object.fromEntries(Object.entries(l).map(([u,v])=>[d(u),typeof v=="string"?d(v):v]))}return Array.isArray(s.commands)&&(p.commands=aa(s.commands)),p}function aa(t){let e=[];for(let n of t.slice(0,50)){let r=$(n);if(typeof r.name!="string"||!/^[a-z][a-z0-9_-]{0,31}$/.test(r.name)||typeof r.description!="string"||e.some(i=>i.name===r.name))continue;let o=typeof r.args=="string"?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 Wt=class{endpoint;scopes;source;#e;#t;cachedConfig;constructor(e,n=fetch){this.endpoint=fe(e.endpoint),this.#e=e.getAccessToken??(async()=>e.accessToken),this.#t=n,this.scopes=new Set(e.scopes),this.source=e.source}async config(){if(!this.cachedConfig){let e=await this.#e();try{this.cachedConfig=await ze(this.endpoint,this.#t,e)}catch(n){if(this.source!=="oauth"||!(n instanceof be)||n.status!==401)throw n;let r=await this.#e(e);if(r===e)throw n;this.cachedConfig=await ze(this.endpoint,this.#t,r)}}return this.cachedConfig}async listSessions(){let e=await this.json("GET","/sessions"),n=Array.isArray(e)?e:$(e).sessions;if(!Array.isArray(n))throw new f("Oracle server returned an invalid sessions list.",m.API_ERROR);return n.map(ko)}async createSession(e={}){let n=await this.json("POST","/sessions",e),r=$(n);return!Array.isArray(r.messages)&&typeof r.sessionId=="string"?this.getSession(r.sessionId):Ao(n)}async getSession(e){return Ao(await this.json("GET",`/sessions/${encodeURIComponent(e)}`))}async submitTurn(e,n,r,o){let i,s=pe(this.endpoint,`/sessions/${encodeURIComponent(e)}/turns`),a=async p=>this.#t(s,{method:"POST",headers:{Authorization:`Bearer ${p}`,Accept:"text/event-stream, application/json","Content-Type":"application/json"},redirect:"error",body:JSON.stringify(n),...r?{signal:r}:{}});try{let p=await this.#e();if(i=await a(p),i.status===401&&this.source==="oauth"){let l=await this.#e(p);l!==p&&(i=await a(l))}}catch(p){throw p instanceof f||r?.aborted?p:new f(`Oracle connection was interrupted: ${p instanceof Error?p.message:String(p)}`,m.FAILURE,"The server may still be working. Resume this session to replay its saved stream.")}if(o?.(i),i.ok||await je(i),!(i.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){let p=await Be(i,pe(this.endpoint,`/sessions/${e}/turns`)),l=De(p,i.status);throw new f(`Oracle server did not start a stream (${ca(l)}).`,m.API_ERROR)}return i}async replayEvents(e,n,r){let o=[];for await(let i of this.streamReplayEvents(e,n,r))o.push(i);return o}async*streamReplayEvents(e,n,r,o){let i=`/sessions/${encodeURIComponent(e)}/events?streamId=${encodeURIComponent(n)}&from=${Math.max(0,r)}`,s=await this.authenticatedFetch("GET",i,{headers:{Accept:"text/event-stream, application/json"}},0);if(s.ok||await je(s),(s.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*mt(s,o);return}let c=De(await Be(s,pe(this.endpoint,i)),s.status),p=Array.isArray(c)?c:$(c).events;if(!Array.isArray(p))throw new f("Oracle replay response did not contain events.",m.API_ERROR);for(let l of p)yield Dn(l)}async*streamRequestEvents(e,n,r=-1,o){let i=`/sessions/${encodeURIComponent(e)}/events?requestId=${encodeURIComponent(n)}&from=${r}`,s=await this.authenticatedFetch("GET",i,{headers:{Accept:"text/event-stream, application/json"}},0);if(s.ok||await je(s),(s.headers.get("content-type")?.toLowerCase()??"").includes("text/event-stream")){yield*mt(s,o);return}let c=De(await Be(s,pe(this.endpoint,i)),s.status),p=Array.isArray(c)?c:$(c).events;if(!Array.isArray(p))throw new f("Oracle request replay response did not contain events.",m.API_ERROR);for(let l of p)yield Dn(l)}async cancelTurn(e,n){return this.json("POST",`/sessions/${encodeURIComponent(e)}/cancel`,{streamId:n})}async cancelRequest(e,n){return this.json("POST",`/sessions/${encodeURIComponent(e)}/cancel`,{requestId:n})}async upload(e,n){let r=new FormData;r.set("sessionId",e),r.set("file",n,n.name);let o=await this.authenticatedFetch("POST","/uploads",{method:"POST",body:r,headers:{Accept:"application/json"}});return o.ok||await je(o),la(De(await Be(o,pe(this.endpoint,"/uploads")),o.status))}async download(e,n){let r=await this.authenticatedFetch("GET",`/sessions/${encodeURIComponent(e)}/files/${encodeURIComponent(n)}`,{headers:{Accept:"application/octet-stream, application/json"}});return r.ok||await je(r),r}async json(e,n,r){let o=await this.authenticatedFetch(e,n,{headers:{Accept:"application/json",...r!==void 0?{"Content-Type":"application/json"}:{}},...r!==void 0?{body:JSON.stringify(r)}:{}});return o.ok||await je(o),De(await Be(o,pe(this.endpoint,n)),o.status)}async authenticatedFetch(e,n,r={},o=2e4){try{let i=pe(this.endpoint,n),s=Object.fromEntries(new Headers(r.headers).entries()),a=r.signal||o<=0?void 0:AbortSignal.timeout(o),c=v=>this.#t(i,{...r,method:e,headers:{...s,Authorization:`Bearer ${v}`},redirect:"error",...a?{signal:a}:{}}),p=await this.#e(),l=await c(p),u=r.body===void 0||typeof r.body=="string"||r.body===null;if(l.status===401&&this.source==="oauth"){let v=await this.#e(p);v!==p&&u&&(l=await c(v))}return l}catch(i){throw i instanceof f?i:new f(`Cannot reach ${this.endpoint}: ${i instanceof Error?i.message:String(i)}`,m.FAILURE,"Check your network, or pass --endpoint for a self-hosted workspace.")}}};async function*mt(t,e){if(!t.body)throw new f("Oracle stream has no response body.",m.FAILURE);let n=t.body.getReader(),r=new TextDecoder,o="",i=0,s=[],a=0,c=-1,p=()=>{if(s.length===0)return null;let l=s.join(`
|
|
261
|
+
`);if(s=[],a=0,l==="[DONE]")return null;let u;try{u=JSON.parse(l)}catch{throw new f("Oracle stream returned invalid JSON.",m.API_ERROR)}let v=Dn(u);return v.type==="finalizing"?v:v.idx<=c?null:(c=v.idx,v)};try{for(;;){let{value:u,done:v}=await n.read();u?.byteLength&&e?.();let k=r.decode(u,{stream:!v});if(o+=k,i+=zt(k),i>2*1024*1024)throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR);let x=0,b=o.indexOf(`
|
|
262
|
+
`,x);for(;b>=0;){let O=o.slice(x,b).replace(/\r$/,"");if(i-=zt(o.slice(x,b+1)),x=b+1,O===""){let R=p();R&&(yield R)}else if(!O.startsWith(":")){let R=O.indexOf(":"),V=R<0?O:O.slice(0,R),K=R<0?"":O.slice(R+1).replace(/^ /,"");if(V==="data"&&(s.push(K),a+=zt(K)+1,a>2*1024*1024))throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR)}b=o.indexOf(`
|
|
263
|
+
`,x)}if(o=o.slice(x),v)break}if(o.trim()){let u=o.replace(/\r$/,"");if(u.startsWith("data:")&&(s.push(u.slice(5).replace(/^ /,"")),a+=zt(s[s.length-1]??"")+1,a>2*1024*1024))throw new f("Oracle stream event exceeded the 2 MiB protocol limit.",m.API_ERROR)}let l=p();l&&(yield l)}catch(l){throw await n.cancel("Invalid or oversized Oracle event stream.").catch(()=>{}),l}finally{n.releaseLock()}}function zt(t){return Buffer.byteLength(t,"utf8")}function Bn(t){let e=["program","initiative","codebase"].filter(o=>typeof t[o]=="string");if(e.length>1)throw new f("Choose only one of --program, --initiative or --codebase.",m.USAGE);let n=e[0];if(!n)return;let r=t[n];if(typeof r!="string"||!r.trim())throw new f(`--${n} needs an id.`,m.USAGE);return{kind:n,id:r.trim()}}function $(t){return!t||typeof t!="object"||Array.isArray(t)?{}:t}function ca(t){if(typeof t=="string")return d(t);try{return d(JSON.stringify(t))}catch{return"unexpected response"}}function De(t,e){let n=$(t);if(n.ok===!1){let r=xo(n.error,e),o=typeof n.message=="string"?d(n.message).slice(0,2e3):void 0;throw new be(r,e,o)}return n.ok===!0&&"data"in n?n.data:t}async function Be(t,e){try{return await t.json()}catch{throw new f(`Non-JSON response from ${e} (HTTP ${t.status}).`,m.FAILURE)}}async function je(t){let e;try{e=await t.clone().json()}catch{e=null}let n=$(e),r=xo(n.error??n.error_description,t.status),o=typeof n.message=="string"?n.message:typeof n.error_description=="string"?n.error_description:typeof n.detail=="string"?n.detail:void 0;throw new be(r,t.status,typeof o=="string"?d(o).slice(0,2e3):void 0)}function xo(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 ko(t){let e=$(t);if(typeof e.sessionId!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(e.sessionId)||typeof e.title!="string"||e.visibility!=="private"&&e.visibility!=="company"||typeof e.shared!="boolean")throw new f("Oracle server returned an invalid session summary.",m.API_ERROR);return{sessionId:e.sessionId,title: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 Ao(t){let e=$(t),n=ko(e);if(!Array.isArray(e.messages))throw new f("Oracle server returned an invalid session transcript.",m.API_ERROR);let r=e.messages.map((o,i)=>{let s=$(o);if(s.role!=="user"&&s.role!=="assistant"||typeof s.content!="string")throw new f(`Oracle session message ${i+1} is invalid.`,m.API_ERROR);let a=Array.isArray(s.attachments)?s.attachments.map(fa):void 0,c=Array.isArray(s.files)?s.files.map(ma):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:da(s.question)}:{},...s.questionResponse&&typeof s.questionResponse=="object"?{questionResponse:ua(s.questionResponse)}:{},...a?{attachments:a}:{},...c?{files:c}:{}}});return{...n,messages:r,...typeof e.activeStreamId=="string"?{activeStreamId:e.activeStreamId}:{}}}function Dn(t){let e=$(t);if(e.protocolVersion!==1||typeof e.idx!="number"||!Number.isSafeInteger(e.idx)||e.idx<0||typeof e.type!="string")throw new f("Oracle stream event does not match protocol version 1.",m.API_ERROR);return de(e)}function la(t){let e=$(t);if(typeof e.fileId!="string"||typeof e.name!="string"||typeof e.mediaType!="string")throw new f("Oracle upload response is missing file metadata.",m.API_ERROR);return{fileId:e.fileId,name:d(e.name),mediaType:d(e.mediaType),...typeof e.sizeBytes=="number"?{sizeBytes:e.sizeBytes}:{}}}function da(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),questions:e.questions.map((n,r)=>{let o=$(n);if(typeof o.id!="string"||typeof o.header!="string"||typeof o.question!="string"||typeof o.multiSelect!="boolean"||!Array.isArray(o.options))throw new f(`Oracle question ${r+1} is invalid.`,m.API_ERROR);return{id:d(o.id),header:d(o.header),question:d(o.question),multiSelect:o.multiSelect,options:o.options.map((i,s)=>{let a=$(i);if(typeof a.id!="string"||typeof a.label!="string"||typeof a.description!="string")throw new f(`Oracle question option ${s+1} is invalid.`,m.API_ERROR);return{id: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 ua(t){let e=$(t);if(typeof e.questionId!="string"||!Array.isArray(e.answers))throw new f("Oracle returned an invalid question response.",m.API_ERROR);return{questionId:d(e.questionId),answers:e.answers.map(pa)}}function pa(t){let e=$(t);if(typeof e.questionId!="string"||!Array.isArray(e.optionIds)||!e.optionIds.every(n=>typeof n=="string"))throw new f("Oracle returned an invalid question answer.",m.API_ERROR);return{questionId:d(e.questionId),optionIds:e.optionIds.map(n=>d(n)),...typeof e.customText=="string"?{customText:d(e.customText).slice(0,8e3)}:{}}}function fa(t){let e=$(t);if(typeof e.fileId!="string"||typeof e.name!="string"||typeof e.mediaType!="string")throw new f("Oracle session attachment metadata is invalid.",m.API_ERROR);return{fileId:d(e.fileId),name:d(e.name),mediaType:d(e.mediaType),...typeof e.sizeBytes=="number"&&Number.isFinite(e.sizeBytes)?{sizeBytes:e.sizeBytes}:{}}}function ma(t){let e=$(t);if(typeof e.fileId!="string"||typeof e.filename!="string"||typeof e.mediaType!="string"||typeof e.sizeBytes!="number"||!Number.isFinite(e.sizeBytes))throw new f("Oracle session file metadata is invalid.",m.API_ERROR);return{fileId: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 So}from"node:crypto";import{promises as W}from"node:fs";import{homedir as ga}from"node:os";import{join as Gn}from"node:path";import*as Io from"proper-lockfile";var gt=Gn(ga(),".anyforge"),me=Gn(gt,"oracle"),Co=Gn(gt,"oracle.last-session");function ha(t){if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t;return e.version!==1||typeof e.endpoint!="string"||typeof e.clientId!="string"||typeof e.redirectUri!="string"||typeof e.accessToken!="string"||typeof e.refreshToken!="string"||typeof e.expiresAt!="number"||!Number.isFinite(e.expiresAt)||!Array.isArray(e.scopes)||!e.scopes.every(n=>typeof n=="string")||e.lastSessionId!==void 0&&typeof e.lastSessionId!="string"?null:{version:1,endpoint:e.endpoint,clientId:e.clientId,redirectUri:e.redirectUri,accessToken:e.accessToken,refreshToken:e.refreshToken,expiresAt:e.expiresAt,scopes:e.scopes,...typeof e.lastSessionId=="string"?{lastSessionId:e.lastSessionId}:{}}}async function zn(t){await W.mkdir(gt,{recursive:!0,mode:448});let e=`${me}.${So()}.tmp`;try{await W.writeFile(e,`${JSON.stringify(t,null,2)}
|
|
264
|
+
`,{mode:384,flag:"wx"}),await W.rename(e,me),await W.chmod(me,384)}finally{await W.rm(e,{force:!0}).catch(()=>{})}}async function Kt(){let t;try{t=await W.readFile(me,"utf8")}catch(r){if(r.code==="ENOENT")return null;throw r}let e;try{e=JSON.parse(t)}catch{throw new Error(`Oracle credentials at ${me} are invalid JSON; run \`anyforge oracle logout\` and sign in again.`)}let n=ha(e);if(!n)throw new Error(`Oracle credentials at ${me} have an unsupported format; run \`anyforge oracle logout\` and sign in again.`);return n}async function We(){try{return await W.unlink(me),!0}catch(t){if(t.code==="ENOENT")return!1;throw t}}async function To(t,e){await wa(Co,{version:1,endpoint:e,sessionId:t})}async function Ht(t){let e;try{e=await W.readFile(Co,"utf8")}catch(o){if(o.code==="ENOENT")return;throw o}let n;try{n=JSON.parse(e)}catch{return}if(!n||typeof n!="object"||Array.isArray(n))return;let r=n;return r.version===1&&r.endpoint===t&&typeof r.sessionId=="string"?r.sessionId:void 0}async function wa(t,e){await W.mkdir(gt,{recursive:!0,mode:448});let n=`${t}.${So()}.tmp`;try{await W.writeFile(n,`${JSON.stringify(e,null,2)}
|
|
265
|
+
`,{mode:384,flag:"wx"}),await W.rename(n,t),await W.chmod(t,384)}finally{await W.rm(n,{force:!0}).catch(()=>{})}}async function Jt(t){await W.mkdir(gt,{recursive:!0,mode:448});let e=await Io.lock(me,{realpath:!1,lockfilePath:`${me}.refresh-lock`,stale:6e4,update:1e4,retries:{retries:300,minTimeout:100,maxTimeout:100,randomize:!1}});try{return await t()}finally{await e()}}var Wn=8192,_o=10*1048576,ba=20*1048576,$o=10,Po=3;function Kn(t,e){if(t.type!=="tool_call"&&t.type!=="tool_call_start"||typeof t.spawnId=="string")return!1;let n=typeof t.id=="string"?t.id:void 0;if(n){if(e.has(n))return!1;e.add(n)}return!Me(t.name)}var Ce=class{lastIdx=-1;answer="";question;error;done;streamId;files=[];toolIds=new Set;accept(e){return e.type==="finalizing"?!0:e.idx<=this.lastIdx?!1:(this.lastIdx=e.idx,e.type==="stream_start"&&typeof e.streamId=="string"?this.streamId=d(e.streamId):e.type==="delta"&&typeof e.content=="string"?this.answer+=e.content:Kn(e,this.toolIds)?this.answer="":e.type==="question"?this.question=Yn(e):e.type==="error"?this.error=Jn(e):e.type==="done"?this.done=e:e.type==="navigator_file_created"&&Ra(this.files,e.file),!0)}get settled(){return!!(this.done||this.error)}outcome(){return{answer:this.answer,...this.question?{question:this.question}:{},...this.error?{error:this.error}:{},...this.done?{done:this.done}:{},...this.streamId?{streamId:this.streamId}:{},...this.files.length?{files:[...this.files]}:{}}}};async function Yt(t,e,n,r,o,i=new Ce){let s=async u=>{let v=i.streamId;i.accept(u)&&(i.streamId&&i.streamId!==v&&r.onStream?.(i.streamId),await r.onEvent(u))},a=()=>Hn(t,e,i,s,o,r.onActivity),c=async()=>{try{for await(let u of t.streamRequestEvents(e,n.requestId,-1,r.onActivity))await s(u)}catch(u){throw o?.aborted?u:new f("Oracle connection failed and the submitted request could not be recovered by its request id. It was not resubmitted with a new id.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the saved session.`)}if(i.settled)return i.outcome();if(i.streamId)return a();throw new f("Oracle request lookup returned no stream events. It was not resubmitted with a new id.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the saved session.`)},p=async()=>{try{let u=await t.submitTurn(e,n,o);for await(let v of mt(u,r.onActivity))await s(v)}catch(u){if(o?.aborted||u instanceof f&&u.exitCode===m.API_ERROR)throw u;return i.streamId?a():c()}return i.settled?i.outcome():i.streamId?a():c()},l;try{l=await t.submitTurn(e,n,o)}catch(u){if(o?.aborted||u instanceof f&&u.exitCode!==m.FAILURE)throw u;return p()}if(!l)throw new f("Oracle did not return a stream response.",m.FAILURE);r.onResponse?.();try{for await(let u of mt(l,r.onActivity))await s(u)}catch(u){if(o?.aborted||u instanceof f)throw u;return i.streamId?a():p()}return i.settled?i.outcome():i.streamId?a():p()}async function Hn(t,e,n,r,o,i){let s=n.streamId;if(!s)throw new f("Oracle stream replay needs a stream id.",m.FAILURE);let a=0;for(;!n.settled&&a<Po;){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 Eo(300,void 0,o?{signal:o}:void 0)}}catch(c){if(o?.aborted||c instanceof f&&c.exitCode===m.API_ERROR||(a+=1,a>=Po))throw c;await Eo(300,void 0,o?{signal:o}:void 0)}}if(!n.settled)throw new f("Oracle stream could not be fully replayed; the turn was not submitted again.",m.FAILURE,`Run anyforge oracle resume ${e} to inspect the session.`);return n.outcome()}function ht(t,e){let n=e.done,r=n?.servedBy,o=Te(n?.tokens),i=U(n?.rounds),s=typeof n?.exitReason=="string"?d(n.exitReason):void 0,a=n?.exitReason==="completed"&&!e.question,c=e.files??(Array.isArray(n?.files)?n.files.map(Ke):void 0),p=e.error?"error":e.question?"awaiting_input":a?"complete":"interrupted";return{protocolVersion:1,sessionId:t,status:p,answer: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:de(r)}:{},...o?{usage:{...o,...i!==void 0?{rounds:i}:{}}}:{},...i!==void 0?{rounds:i}:{},...s?{exitReason:s}:{},...c?.length?{files:de(c)}:{}}}function I(t,e){return typeof t=="string"?d(t).slice(0,e):""}function Jn(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 Yn(t){let e=t.question;if(!e||typeof e!="object")throw new f("Oracle question event omitted its question card.",m.API_ERROR);return Aa(e)}function Ke(t){let e=t&&typeof t=="object"&&!Array.isArray(t)?t:{};if(typeof e.fileId!="string"||!e.fileId||typeof e.filename!="string"||!e.filename||typeof e.mediaType!="string"||!e.mediaType||typeof e.sizeBytes!="number"||!Number.isSafeInteger(e.sizeBytes)||e.sizeBytes<0)throw new f("Oracle generated-file event omitted safe file metadata.",m.API_ERROR);return{fileId:d(e.fileId),filename:d(e.filename),mediaType:d(e.mediaType),sizeBytes:e.sizeBytes,...typeof e.format=="string"?{format:d(e.format)}:{}}}function Ra(t,e){let n=Ke(e);t.some(r=>r.fileId===n.fileId)||t.push(n)}function Aa(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 U(t){return typeof t=="number"&&Number.isFinite(t)?t:void 0}function Te(t){if(typeof t=="number"&&Number.isFinite(t))return{totalTokens:t};if(!t||typeof t!="object"||Array.isArray(t))return;let e=t,n=U(e.in)??U(e.input)??U(e.inputTokens),r=U(e.cacheRead),o=U(e.cacheWrite),i=n===void 0?void 0:n+(r??0)+(o??0),s=U(e.out)??U(e.output)??U(e.outputTokens),a=U(e.total)??U(e.totalTokens)??(i!==void 0||s!==void 0?(i??0)+(s??0):void 0);if(!(i===void 0&&s===void 0&&a===void 0))return{...i!==void 0?{inputTokens:i}:{},...r?{cachedInputTokens:r}:{},...s!==void 0?{outputTokens:s}:{},...a!==void 0?{totalTokens:a}:{}}}function He(t){if(t&&typeof t=="object"){let e=t;if(typeof e.accepted=="boolean")return e.accepted?"Oracle server accepted the cancellation request.":"Oracle server did not accept the cancellation request.";if(typeof e.cancelled=="boolean")return e.cancelled?"Oracle server cancelled the active turn.":"Oracle server did not cancel the active turn."}return"Oracle server acknowledged the cancellation request."}function wt(t,e){let n=e&&t&&(t.kind==="program"||t.kind==="initiative")?{kind:t.kind,id:t.id}:void 0;return{...!e&&t?{context:t}:{},...n?{sharedEntity:n}:{},visibility:e?"company":"private"}}async function yt(t,e){await To(t,e).catch(()=>{})}async function Qt(t,e,n,r){if(!n.length)return[];if(n.length>$o)throw new y(`Attach no more than ${$o} files per turn.`);let o=0,i=[];for(let a of n){let c=await va(a);if(!c.isFile())throw new y(`Attachment is not a file: ${a}`);if(c.size>_o)throw new y(`Attachment exceeds the 10 MiB per-file CLI limit: ${a}`);let p=await xa(a,_o);if(o+=p.byteLength,o>ba)throw new y("Attachments exceed the 20 MiB total CLI limit.");let l=Oa(a).replace(/[\u0000-\u001f\u007f/\\]/g,"_").slice(0,200)||"attachment",u=Ro(l)??"";if(!u)throw new y(`Unsupported attachment type: ${a}`);i.push({content:p,name:l,mediaType:u})}let s=[];for(let{content:a,name:c,mediaType:p}of i){await r(d(c),a.byteLength);let l=new ArrayBuffer(a.byteLength);new Uint8Array(l).set(a);let u=new File([l],c,{type:p});s.push(await t.upload(e,u))}return s}async function xa(t,e){let n=[],r=0;for await(let o of ya(t)){let i=Buffer.isBuffer(o)?o:Buffer.from(o);if(r+=i.byteLength,r>e)throw new y(`Attachment exceeds the ${N(e)} limit: ${t}`);n.push(i)}return Buffer.concat(n)}var vt=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],Sa=2e4,Ia=6,Ca={lookup:"Looking things up",quick_edit:"Making a quick edit",final_answer:"Composing the answer",follow_up:"Suggesting follow-ups"},Ta={max_rounds:"reached the step limit",max_tokens:"reached the output limit",token_budget:"reached the token budget",deadline:"ran out of time",interrupted:"interrupted",loop_detected:"stopped a repeating loop",cancelled:"cancelled"},Xt=class{constructor(e,n){this.startedAt=e;this.sessionId=n;this.lastSignalAt=e}phase="sending";answer="";tools=[];notices=[];files=[];lastSignalAt;endedAt;end;done;upload;round;maxRounds;serverPhase;agents=new Map;toolIds=new Set;get toolCount(){return this.tools.length}get failedCount(){return this.tools.filter(e=>e.status==="failed").length}get finished(){return this.end!==void 0}setUploading(e,n,r){this.phase="uploading",this.upload=`${e} (${N(n)})`,this.lastSignalAt=r}setPhase(e,n){this.phase=e,this.lastSignalAt=n}touch(e){this.lastSignalAt=e}apply(e,n){if(this.lastSignalAt=n,this.phase==="cancelling")return this.record(e);switch(e.type){case"stream_start":case"thinking":this.phase!=="finishing"&&(this.phase="thinking");break;case"round_start":this.round=U(e.round),this.maxRounds=U(e.maxRounds)??this.maxRounds;for(let r=this.tools.length-1;r>=0;r--)this.tools[r]?.started&&this.tools.splice(r,1);this.phase!=="finishing"&&(this.phase="thinking");break;case"phase":this.serverPhase=typeof e.phase=="string"?e.phase:void 0;break;case"delta":this.phase!=="finishing"&&(this.phase="writing");break;case"tool_result":this.phase!=="finishing"&&(this.phase="thinking");break;case"finalizing":this.phase="finishing";break}this.record(e)}record(e){switch(e.type){case"delta":typeof e.content=="string"&&(this.answer+=e.content);break;case"tool_call_start":case"tool_call":this.recordToolCall(e);break;case"tool_result":{let n=this.tools.find(r=>r.id!==void 0&&r.id===e.toolUseId);n&&(n.status=e.ok===!1?"failed":"ok");break}case"subagent_start":typeof e.spawnId=="string"&&this.agents.set(e.spawnId,"running");break;case"subagent_done":typeof e.spawnId=="string"&&this.agents.set(e.spawnId,"done");break;case"warning":this.notices.push({tone:"warning",text:`Warning: ${I(e.message,500)}`});break;case"navigator_file_error":this.notices.push({tone:"warning",text:`Could not generate ${I(e.filename,200)}: ${I(e.error,500)}`});break;case"attachment_notice":if(Array.isArray(e.notices))for(let n of e.notices){let r=n&&typeof n=="object"?n:{};this.notices.push({tone:"warning",text:`${I(r.name,160)}: ${I(r.message,500)}`})}break;case"provider_fallback":{let n=I(e.from,120),r=I(e.to,120),o=I(e.reason,40).replaceAll("_"," ");this.notices.push({tone:"info",text:`Switched model${n?` from ${n}`:""}${r?` to ${r}`:""}${o?` (${o})`:""}.`});break}case"navigator_file_created":{let n=Ke(e.file);if(this.files.some(r=>r.fileId===n.fileId))break;this.files.push(n),this.notices.push({tone:"info",text:`Generated ${n.filename} (${N(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`});break}case"error":this.notices.push({tone:"error",text:Jn(e)});break;case"done":this.done=e;break}}recordToolCall(e){let n=typeof e.id=="string"?e.id:void 0,r=Kn(e,this.toolIds),o=typeof e.name=="string"?e.name:"";if(Me(o))return;let i=I(typeof e.label=="string"?e.label:Gt(o),120)||"tool",s=n?this.tools.find(c=>c.id===n):void 0;if(s){s.label=i,e.type==="tool_call"&&delete s.started;return}let a={label:i,status:"running",...n?{id:n}:{},...typeof e.spawnId=="string"?{spawnId:e.spawnId}:{},...e.type==="tool_call_start"?{started:!0}:{}};r&&this.answer.trim()&&(a.note=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&&Ca[this.serverPhase]||"Thinking"}statusLine(e,n){let r=[this.label(),Mn(e-this.startedAt)];this.round&&r.push(this.maxRounds?`step ${this.round}/${this.maxRounds}`:`step ${this.round}`);let o=e-this.lastSignalAt;return o>=Sa&&this.phase!=="cancelling"&&r.push(`no update for ${Mn(o)}`),n&&e-this.startedAt>=n*.9&&this.phase!=="finishing"&&r.push("wrapping up"),r.join(" \xB7 ")}summaryLine(){let e=[],n=lt((this.endedAt??this.startedAt)-this.startedAt),r=typeof this.done?.exitReason=="string"?this.done.exitReason:void 0,o;this.end==="complete"?o=No("\u2713"):this.end==="awaiting_input"?o=Fo("?")+" Waiting for your answer":this.end==="cancelled"?o=Vn("\u2717")+" Interrupted":this.end==="error"?o=Qn("\u2717")+" Error":o=Vn("\u2717")+` Stopped: ${r&&Ta[r]||"no final answer"}`,e.push(n),this.tools.length&&e.push(`${this.tools.length} tool${this.tools.length===1?"":"s"}`);let i=Te(this.done?.tokens);(i?.inputTokens!==void 0||i?.outputTokens!==void 0)&&e.push(`${ee(i.inputTokens??0)} in${i.cachedInputTokens?` (${ee(i.cachedInputTokens)} cached)`:""} / ${ee(i.outputTokens??0)} out`);let s=Ot(this.done?.servedBy);return s&&e.push(s),`${o} ${Je(e.join(" \xB7 "))}`}};function Ot(t){if(!t||typeof t!="object")return"";let e=t,n=I(e.model??e.id,100);if(!n)return"";let r=e.fallback&&typeof e.fallback=="object"?e.fallback:void 0;if(r&&typeof r.from=="string"){let o=typeof r.reason=="string"?`: ${I(r.reason,40).replaceAll("_"," ")}`:"";return`${n} (fallback from ${I(r.from,100)}${o})`}return n}var Zt=class{constructor(e,n){this.activity=e;this.view=n}answer=new Ue("");getText(){return this.answer.getText()}invalidate(){this.answer.invalidate()}render(e){let n=this.activity;this.answer.setText(n.answer);let r=[ft("assistant")];r.push(...this.renderTools(e)),r.push(...this.answer.render(e));for(let o of n.notices){let i=o.tone==="error"?Qn:o.tone==="warning"?Vn:Je;r.push(...Lo(i(o.text),e))}return n.finished&&r.push(Vt(n.summaryLine(),e)),r}renderTools(e){let{tools:n}=this.activity;if(!n.length)return[];if(this.activity.finished&&!this.view.expanded()){let s=this.activity.failedCount,a=`Used ${n.length} tool${n.length===1?"":"s"}${s?` \xB7 ${s} failed`:""} (ctrl+o to expand)`;return[Vt(Je(` \u23BF ${a}`),e)]}let r=this.activity.finished?n:n.slice(-Ia),o=n.length-r.length,i=[];return o&&i.push(Vt(Je(` \u23BF \u2026 ${o} earlier tool${o===1?"":"s"}`),e)),r.forEach((s,a)=>{if(s.note)for(let u of Lo(s.note,Math.max(10,e-4)).slice(0,3))i.push(` ${Je(ka(u))}`);let c=s.status==="running"?Fo(vt[this.view.frame()%vt.length]??"*"):s.status==="ok"?No("\u2713"):Qn("\u2717"),p=a===0&&!o?" \u23BF ":" ",l=s.spawnId?` ${Je("agent \xB7")} `:"";i.push(Vt(`${p}${l}${c} ${s.label}`,e))}),i}};import{randomUUID as ja}from"node:crypto";import{stat as Da}from"node:fs/promises";import{basename as Wo}from"node:path";import{bold as Ba,cyan as Ko,dim as Ho,red as rn}from"kleur/colors";import{Container as Ga,Editor as za,ProcessTerminal as Wa,ScrollView as Ka,SelectList as Ha,TuiAltScreen as Ja,VStack as Ya,getNativeClipboard as Qa,matchesKey as on,truncateToWidth as Jo,wrapTextWithAnsi as Va}from"@earendil-works/pi-tui";import{truncateToWidth as Pa,visibleWidth as La,wrapTextWithAnsi as jo}from"@earendil-works/pi-tui";import{bold as Fa,cyan as Na,dim as ge}from"kleur/colors";import{CombinedAutocompleteProvider as Ea}from"@earendil-works/pi-tui";var bt=[{name:"help",description:"Show commands and keyboard shortcuts"},{name:"status",description:"Show session, access, model, usage and limits"},{name:"model",description:"Show the workspace model and the model that answered last"},{name:"usage",description:"Show turns and tokens used in this terminal"},{name:"new",args:"[shared]",description:"Start a new conversation",idleOnly:!0,completions:["shared"]},{name:"clear",description:"Clear the screen and start a new private conversation",idleOnly:!0},{name:"resume",args:"[session-id]",description:"Pick or open a saved conversation",idleOnly:!0},{name:"context",args:"[clear|program|initiative|codebase <id>]",description:"Show or change the context for the next message",completions:["clear","program ","initiative ","codebase "]},{name:"attach",args:"<path>",description:"Attach a file to your next message"},{name:"copy",description:"Copy the last answer as Markdown"},{name:"files",description:"List files Oracle generated in this conversation"},{name:"exit",description:"Leave the Oracle",aliases:["quit"]}],_a=[{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 qo(t){let e=new Set(bt.flatMap(n=>[n.name,...n.aliases??[]]));return(t??_a).filter(n=>!e.has(n.name))}function Mo(t,e){let n=/^\/([A-Za-z][\w-]*)(?:\s+([\s\S]*))?$/.exec(t.trim());if(!n)return null;let r=(n[1]??"").toLowerCase(),o=(n[2]??"").trim(),i=bt.find(a=>a.name===r||a.aliases?.includes(r));if(i)return{kind:"local",command:i,arg:o,args:o?o.split(/\s+/):[]};let s=e.find(a=>a.name===r);return s?{kind:"server",command:s}:{kind:"unknown",name:r}}function Uo(t,e){let n=[...bt.flatMap(i=>[i,...(i.aliases??[]).map(s=>({...i,name:s}))]).map(i=>({name:i.name,description:i.description,...i.args?{argumentHint:i.args}:{},...i.completions?{getArgumentCompletions:s=>$a(i.completions??[],s)}:{}})),...t.map(i=>({name:i.name,description:i.description,...i.args?{argumentHint:i.args}:{}}))],r=new Ea(n,e),o=/^\s*\/attach\s+/;return{async getSuggestions(i,s,a,c){let p=(i[s]??"").slice(0,a);return s!==0||!p.trimStart().startsWith("/")?null:o.test(p)?r.getSuggestions(i,s,a,{...c,force:!0}):r.getSuggestions(i,s,a,c)},applyCompletion(i,s,a,c,p){return r.applyCompletion(i,s,a,c,p)},shouldTriggerFileCompletion(i,s,a){return s===0&&o.test((i[s]??"").slice(0,a))}}}function $a(t,e){let n=t.filter(r=>r.startsWith(e.toLowerCase())&&r!==e).map(r=>({value:r,label:r.trim()}));return n.length?n:null}function en(t,e){return t?e?"write + approve":"write":"read only"}function Ye(t){return t?`${t.kind} ${d(t.id)}`:"no context"}function Do(t,e){let n=[`${Fa(Na("AnyForge Oracle"))}${ge(` \xB7 v${d(t.version)}`)}`,`${ue(t.session)} \xB7 ${t.access} \xB7 ${Ye(t.context)}`,...t.session.messages.length?[`Resumed: ${d(t.session.title)}`]:[],ge("Only your messages and the files you attach leave this terminal."),ge("/help commands \xB7 /status details")];if(e<24)return n.flatMap(s=>jo(s,Math.max(1,e)));let r=Math.min(e,76),o=r-4,i=[ge(`\u256D${"\u2500".repeat(r-2)}\u256E`)];for(let s of n.flatMap(a=>jo(a,o))){let a=Pa(s,o);i.push(`${ge("\u2502")} ${a}${" ".repeat(Math.max(0,o-La(a)))} ${ge("\u2502")}`)}return i.push(ge(`\u2570${"\u2500".repeat(r-2)}\u256F`)),i}function Bo(t){let e=(r,o)=>r?`${ge(r)} ${o}`:o,n=[{title:"Commands",rows:bt.map(r=>[`/${r.name}`,e(r.args,r.aliases?.length?`${r.description} (also /${r.aliases.join(", /")})`:r.description)])}];if(t.server.length){let r=t.server.map(o=>[`/${o.name}`,e(o.args,d(o.description))]);t.server.some(o=>o.name==="catchup")&&!t.canApprove&&r.push(["",ge("Acting on /catchup decisions needs a session started with `anyforge oracle --write --approve`.")]),n.push({title:"Workspace commands (answered by Oracle)",rows:r})}return n.push({title:"Keys",rows:[["Enter","Send. While Oracle works, queues one message for when it finishes"],["Shift+Enter","New line (Ctrl+J also works)"],["Esc","Interrupt the current answer"],["Ctrl+C","Interrupt the answer, or clear the input; press twice to exit"],["Ctrl+D","Exit when the input is empty"],["Ctrl+O","Show or hide tool activity for finished answers"],["Ctrl+Shift+F","Search the conversation"],["Up / Down","Recall messages sent in this terminal"],["Tab","Complete a command, or a file path after /attach"],["PgUp / PgDn","Scroll; Home and End jump to the top and bottom"]]}),n}function Xn(t){let n=[["Model",`workspace default ${t.model?`${d(t.model.provider)}/${d(t.model.id)}`:"chosen by the server"}`]],r=Ot(t.lastServedBy);if(r){let o=t.lastServedBy,i=I(o.routing,40).replaceAll("_"," ");n.push(["Last answer",`${r}${i?` \xB7 ${i}`:""}`])}return n}function Zn(t){return[["This run",t.turns?`${t.turns} turn${t.turns===1?"":"s"} \xB7 ${t.tools} tool${t.tools===1?"":"s"} \xB7 ${ee(t.inputTokens)} in / ${ee(t.outputTokens)} out tokens`:"no turns yet"]]}function er(t){if(!t?.finished)return[];let e=[lt((t.endedAt??t.startedAt)-t.startedAt)];e.push(`${t.toolCount} tool${t.toolCount===1?"":"s"}${t.failedCount?` (${t.failedCount} failed)`:""}`);let n=U(t.done?.rounds);n!==void 0&&e.push(`${n} round${n===1?"":"s"}`);let r=Te(t.done?.tokens);(r?.inputTokens!==void 0||r?.outputTokens!==void 0)&&e.push(`${ee(r.inputTokens??0)} in${r.cachedInputTokens?` (${ee(r.cachedInputTokens)} cached)`:""} / ${ee(r.outputTokens??0)} out tokens`);let o=I(t.done?.exitReason,40);return e.push(o?o.replaceAll("_"," "):t.end??""),[["Last turn",e.filter(Boolean).join(" \xB7 ")]]}function Go(t){let e=t.capabilities?["read","write","approve"].filter(o=>t.capabilities?.[o]).join(", ")||"none":"not reported",n=t.contextText?` \xB7 note ${N(Buffer.byteLength(t.contextText,"utf8"))}`:"",r=mo(t.limits);return[["Session",`${t.session.sessionId} \xB7 ${d(t.session.title)||"Untitled"}`],["Audience",ue(t.session)],["Access",`this session ${en(t.write,t.approve)} \xB7 grant ${t.grantScopes.join(", ")||"none"} \xB7 workspace role ${e}`],["Context",`${Ye(t.context)}${n}`],...Xn(t),...er(t.lastTurn),...Zn(t.totals),["Limits",r.length?r.join(" \xB7 "):"not reported"],...t.identity?[["Workspace",`company ${t.identity.companyId} \xB7 user ${t.identity.uid}`]]:[],["Endpoint",t.endpoint],["Version",`CLI ${d(t.version)} \xB7 protocol ${1}`],["Attached",t.pendingFiles.length?`${t.pendingFiles.map(d).join(", ")} (uploads with your next message)`:"nothing waiting"]]}function zo(t,e){return e.length?e.map((n,r)=>[`${r+1}.`,`${d(n.filename)} (${N(n.sizeBytes)}) \xB7 anyforge oracle download ${t} ${d(n.fileId)} --output .`]):[["Files","Oracle has not generated files in this conversation."]]}import{bold as qa,cyan as tr,dim as tn,yellow as Ma}from"kleur/colors";import{Input as Ua,Text as Ee,matchesKey as Qe}from"@earendil-works/pi-tui";var nn=class{constructor(e,n,r){this.tui=e;this.question=n;this.onComplete=r;(n.questions[0]?.options.length??0)===0&&(this.mode="custom"),this.customInput.onSubmit=o=>{let i=o.trim().slice(0,8e3);if(!i){this.errorMessage="Enter a short answer before continuing.",this.tui.requestRender();return}this.recordCurrent(i)},this.customInput.onEscape=()=>{if(!this.question.questions[this.questionIndex]?.options.length){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.setValue(""),this.mode="select",this.tui.setFocus(this),this.tui.requestRender()}}focused=!1;questionIndex=0;optionIndex=0;mode="select";errorMessage="";selected=new Map;answers=[];customInput=new Ua({prompt:`${tr("Your answer: ")} `,placeholder:"Write a short answer and press Enter",placeholderStyle:tn});invalidate(){}render(e){let n=this.question.questions[this.questionIndex];if(!n)return[];this.customInput.focused=this.focused&&this.mode==="custom";let r=Math.max(12,e-2),o=this.question.questions.length>1?` \xB7 ${this.questionIndex+1}/${this.question.questions.length}`:"",i=[...new Ee(`${qa(tr(d(n.header)))}${tn(o)}`,0,0).render(r),...new Ee(d(n.question),0,0).render(r),...this.renderOptions(n,r)];return this.mode==="custom"?(i.push(...this.customInput.render(r)),i.push(...new Ee(tn(`Enter submits your text${n.options.length?" \xB7 Esc back to the choices":this.question.optional?" \xB7 Esc skip":""}`),0,0).render(r))):i.push(...new Ee(tn(this.instructions(n)),0,0).render(r)),this.errorMessage&&i.push(...new Ee(Ma(this.errorMessage),0,0).render(r)),i.map(s=>`${tr("\u2502")} ${s}`)}handleInput(e){if(this.mode==="custom"){this.customInput.handleInput(e);return}let n=this.question.questions[this.questionIndex];if(!n)return;let r=this.selectedFor(n);if(n.options.length===0){if(e.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(Qe(e,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}this.customInput.handleInput(e);return}if(Qe(e,"up")){this.optionIndex=Math.max(0,this.optionIndex-1),this.errorMessage="",this.tui.requestRender();return}if(Qe(e,"down")){this.optionIndex=Math.min(n.options.length-1,this.optionIndex+1),this.errorMessage="",this.tui.requestRender();return}if(Qe(e,"escape")){this.question.optional?this.finish(null):this.requireAnswer();return}if(e.toLowerCase()==="s"&&this.question.optional){this.finish(null);return}if(e.toLowerCase()==="o"){this.mode="custom",this.tui.setFocus(this),this.tui.requestRender();return}let o=Number(e);if(Number.isInteger(o)&&o>=1&&o<=n.options.length){let i=n.options[o-1]?.id;i&&(this.optionIndex=o-1,n.multiSelect?r.has(i)?r.delete(i):r.add(i):(r.clear(),r.add(i)),this.tui.requestRender());return}if(Qe(e,"space")&&n.multiSelect){let i=n.options[this.optionIndex];i&&(r.has(i.id)?r.delete(i.id):r.add(i.id),this.tui.requestRender());return}if(Qe(e,"enter")){if(r.size===0){this.errorMessage="Select an option explicitly, type a custom answer, or skip if optional.",this.tui.requestRender();return}this.recordCurrent()}}renderOptions(e,n){let r=this.selectedFor(e),o=[];return e.options.forEach((i,s)=>{let a=r.has(i.id),c=e.multiSelect?a?"[x]":"[ ]":a?"(x)":"( )",p=s===this.optionIndex?"\u203A":" ",l=i.recommended?" \xB7 recommended":"",u=i.confirms?" \xB7 confirms the shown action":"",v=`${p} ${s+1}. ${c} ${d(i.label)}${l}${u}`;o.push(...new Ee(v,0,0).render(n)),o.push(...new Ee(` ${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 Yo=1500,Xa=100,Za="\x1B]133;A\x07";function Ve(t){return{render:t,invalidate(){}}}function Qo(t,e,n){let r=new Ue(e);return{getText:()=>r.getText(),invalidate:()=>r.invalidate(),render:o=>t==="user"?["",`${Za}${ft("user",n)}`,...r.render(o)]:[ft("assistant"),...r.render(o)]}}async function Vo(t){let{client:e,config:n}=t,r=new Wa,o=new Ja(r,void 0,void 0,{scrollToEndIndicator:()=>" more below \xB7 End to jump "}),i=new Ga,s=new Ka(i,{follow:"end",primary:!0,overscroll:"chain"}),a=new za(o,vo),c=qo(n.commands),p=typeof n.limits?.turnSoftMs=="number"?n.limits.turnSoftMs:void 0,l=t.session,u=t.initialContext,v=t.contextText,k=t.canWrite,x=t.canApprove,b,O,R,V,K=[...t.initialFiles],ae=!1,ln=!1,kt=!1,dn=0,_e,lr=0,Ae="",St,un,$e=[],Pe={turns:0,inputTokens:0,outputTokens:0,tools:0},It=new Map,ce,hi=Ve(g=>{if(b){let w=Ko(vt[dn%vt.length]??"*");return[Jo(`${w} ${b.activity.statusLine(Date.now(),p)}`,g)]}return ce?[Jo(`${Ko("?")} Waiting for your answer to the question above`,g)]:[]}),wi=Ve(g=>{let w=[en(k,x),Ye(u),Oo(l),K.length?`${K.length} file${K.length===1?"":"s"} attached`:"",O!==void 0?"1 message queued":""];return[Ho(ho(g,w,b?"esc to interrupt":"/help \xB7 /status"))]});o.setLayoutRoot(new Ya([{component:s,basis:0,grow:1,minSize:1},{component:hi,basis:"auto",shrink:0},{component:a,basis:"auto",shrink:0,minSize:2},{component:wi,basis:"auto",shrink:0,minSize:1}]));let Y=()=>o.requestRender(),F=g=>o.flash(d(g),3e3),we=g=>{i.addChild(g),Y()},te=(g,w=Ho)=>{let h=d(g);we(Ve(A=>Va(w(h),Math.max(1,A))))},Ct=(g,w)=>{we(Ve(h=>["",...go(g,w,h)]))},yi=()=>{_e||(_e=setInterval(()=>{dn+=1,Y()},Xa),_e.unref())},pn=()=>{_e&&clearInterval(_e),_e=void 0},Xe=()=>{ae||o.hasOverlay()||o.setFocus(ce??a)},dr=g=>{R=g;let w=It.get(g.id);w&&i.removeChild(w);let h=new nn(o,g,A=>{It.delete(g.id),ce===h&&(ce=void 0),i.removeChild(h),bi(A??{questionId:g.id,skipped:!0,answers:[]}),Xe()});It.set(g.id,h),ce=h,we(h)},fn=g=>{i.clear(),It.clear(),ce=void 0,l=g,R=void 0,V=void 0,$e=[],Ae="";let w={version:t.version,session:g,access:en(k,x),context:u};we(Ve(A=>Do(w,A)));let h;for(let A of g.messages){we(Qo(A.role,A.content,A.authorName)),A.role==="assistant"&&(Ae=A.content),A.question&&(h=A.question),A.questionResponse&&(te("A stored response was recorded for this question."),h?.id===A.questionResponse.questionId&&(h=void 0));for(let S of A.files??[])$e.some(q=>q.fileId===S.fileId)||$e.push(S),te(`File: ${S.filename} (${S.mediaType}, ${N(S.sizeBytes)}) \xB7 anyforge oracle download ${g.sessionId} ${S.fileId} --output .`)}h&&dr(h),Xe(),yt(g.sessionId,e.endpoint)},ur,vi=new Promise(g=>{ur=g}),Tt=()=>{ae||(ae=!0,pn(),b?.controller.abort(new Error("Detached from the active Oracle stream.")),o.stop(),ur())},mn=async()=>{let g=b;if(!g||g.cancelling)return;g.cancelling=!0,g.activity.setPhase("cancelling",Date.now()),Y();let{streamId:w,requestId:h}=g;g.controller.abort(new Error("Turn cancelled by user."));let A;if(w)try{A=He(await e.cancelTurn(l.sessionId,w))}catch(S){A=`Could not confirm server cancellation: ${Q(S)}`}else if(h)try{A=He(await e.cancelRequest(l.sessionId,h))}catch(S){A=`Could not confirm server cancellation by request id: ${Q(S)}`}else A="The turn had not reached the server; nothing was sent.";g.activity.note("info",A),Y()},Le=async g=>{if(b||ae)return;if(g.kind==="submit"&&g.response){let _=R;if(!_||_.id!==g.response.questionId){F("That question is no longer active. Resume the session to refresh it.");return}te(ec(_,g.response)),R=void 0}else g.kind==="submit"&&we(Qo("user",g.text));let w=l.sessionId,h=new Xt(Date.now(),w),A=new Zt(h,{expanded:()=>kt,frame:()=>dn}),S={activity:h,view:A,controller:new AbortController,cancelling:!1};b=S,we(A),yi();let q=new Ce,hr=_=>{h.apply(_,Date.now()),_.type==="question"&&(dr(Yn(_)),Xe()),Y()},wr={onEvent:hr,onStream:_=>{S.streamId=_},onResponse:()=>{h.phase==="sending"&&h.setPhase("preparing",Date.now())},onActivity:()=>h.touch(Date.now())},ye="error";try{if(g.kind==="replay"){q.streamId=g.streamId,S.streamId=g.streamId,h.setPhase("thinking",Date.now());let _=await Hn(e,w,q,async ne=>{q.accept(ne)&&hr(ne)},S.controller.signal,wr.onActivity);ye=ht(w,_).status}else{let _=g.response?[]:K.splice(0),ne=await Qt(e,w,_,(gn,Ti)=>{h.setUploading(gn,Ti,Date.now()),Y()});S.controller.signal.throwIfAborted(),h.setPhase("sending",Date.now());let Et=ja();S.requestId=Et;let Ii={requestId:Et,text:g.response?"":g.text,readOnly:!k,...x?{allowApprove:!0}:{},...u?{context:u}:{},...v?{contextText:v}:{},...g.response?{questionResponse:g.response}:{},...ne.length?{attachments:ne.map(gn=>({fileId:gn.fileId}))}:{}},Ci=await Yt(e,w,Ii,wr,S.controller.signal,q);ye=ht(w,Ci).status}}catch(_){if(S.controller.signal.aborted)ye="cancelled";else{ye="error";let ne=_ instanceof f&&_.hint?` ${d(_.hint)}`:"";h.note("error",`${Q(_)}${ne}`)}}finally{h.finish(ye,Date.now()),b=void 0,pn(),ae||(ln=ye==="cancelled"),St=h,h.answer.trim()&&(Ae=h.answer),h.done?.servedBy&&(un=h.done.servedBy);let _=Te(h.done?.tokens);Pe.turns+=1,Pe.tools+=h.toolCount,Pe.inputTokens+=_?.inputTokens??0,Pe.outputTokens+=_?.outputTokens??0;for(let ne of h.files)$e.some(Et=>Et.fileId===ne.fileId)||$e.push(ne);Y()}if(!ae){if(S.streamId&&ye!=="cancelled"){let _=await e.getSession(w).catch(()=>{});_&&_.sessionId===l.sessionId&&(l=_)}Oi(ye)}},Oi=g=>{if(!(ae||b)){if(V){let w=V;V=void 0,Le({kind:"submit",text:"",response:w});return}if(O!==void 0){let w=O;if(O=void 0,g==="complete"&&!ce){Le({kind:"submit",text:w});return}a.getText()||a.setText(w),F("Your queued message is back in the input; press Enter to send it.")}Xe(),Y()}},bi=g=>{if(b){V=g,F("Answer saved; Oracle continues once the current turn settles.");return}Le({kind:"submit",text:"",response:g})},pr=async g=>{try{let w=await e.getSession(g);fn(w),w.activeStreamId&&Le({kind:"replay",streamId:w.activeStreamId}),F(`Resumed ${w.title||w.sessionId}.`)}catch(w){te(Q(w),rn)}},Ri=async()=>{try{let g=await e.listSessions();if(!g.length){F("No saved conversations to resume.");return}let w=new Ha(g.map(q=>({value:q.sessionId,label:q.title,description:ue(q)})),Math.min(12,g.length),pt),h=await Ht(e.endpoint),A=h?g.findIndex(q=>q.sessionId===h):-1;A>=0&&w.setSelectedIndex(A);let S=o.showOverlay(w,{width:"85%",maxHeight:"80%",anchor:"center"});w.onSelect=q=>{S.hide(),pr(q.value)},w.onCancel=()=>{S.hide(),Xe()},S.focus()}catch(g){te(Q(g),rn)}},fr=async g=>{if(g&&(!u||u.kind!=="program"&&u.kind!=="initiative")){F("Use /context program <id> or /context initiative <id> before /new shared.");return}try{let w=await e.createSession(wt(u,g));fn(w),F(`Started a new conversation \xB7 ${ue(w)}.`)}catch(w){te(Q(w),rn)}},Ai=()=>({session:l,write:k,approve:x,grantScopes:[...e.scopes],...n.capabilities?{capabilities:n.capabilities}:{},...u?{context:u}:{},...v?{contextText:v}:{},...n.model?{model:n.model}:{},lastServedBy:un,...St?{lastTurn:St}:{},totals:{...Pe},...n.limits?{limits:n.limits}:{},...n.identity?{identity:n.identity}:{},endpoint:e.endpoint,version:t.version,pendingFiles:K.map(g=>Wo(g))}),xi=async()=>{if(!Ae.trim()){F("There is no answer to copy yet.");return}try{let g=Qa();g?.setText?await g.setText(Ae):r.write(`\x1B]52;c;${Buffer.from(Ae,"utf8").toString("base64")}\x07`),F(`Copied the last answer (${Ae.length} characters).`)}catch(g){F(`Could not copy: ${Q(g)}`)}},ki=async(g,w,h)=>{if(g.idleOnly&&b){F(`Wait for Oracle to finish, or press Esc, before /${g.name}.`);return}switch(g.name){case"help":we(Ve(A=>["",...Bo({server:c,canApprove:x}).flatMap(S=>[Ba(S.title),...Un(S.rows,A)])]));return;case"status":Ct("Status",Go(Ai()));return;case"model":Ct("Model",Xn({...n.model?{model:n.model}:{},lastServedBy:un}));return;case"usage":Ct("Usage",[...er(St),...Zn(Pe)]);return;case"files":Ct("Generated files",zo(l.sessionId,$e));return;case"copy":await xi();return;case"exit":Tt();return;case"new":if(h&&h!=="shared"){F("Usage: /new or /new shared");return}await fr(h==="shared");return;case"clear":await fr(!1);return;case"resume":h?await pr(h):await Ri();return;case"context":{if(!h){te(`Context: ${Ye(u)}${v?" + free-text note":""}. Use /context <program|initiative|codebase> <id> or /context clear.`);return}if(h==="clear")u=void 0;else{let[A,S,...q]=w;if(!["program","initiative","codebase"].includes(A??"")||!S||q.length){F("Usage: /context program <id>, /context initiative <id>, /context codebase <id>, or /context clear");return}u={kind:A,id:S}}te(`Context for your next message: ${Ye(u)}.`);return}case"attach":{if(!h){F("Usage: /attach <file path>");return}let A=await Da(h).catch(()=>{});if(!A?.isFile()){F(`Not a readable file: ${h}`);return}K.push(h),te(`Attached ${Wo(h)} (${N(A.size)}). It uploads with your next message.`);return}}},mr=g=>{let w=g.trim();if(!w)return;a.addToHistory(w);let h=Mo(w,c);if(h?.kind==="local"){ki(h.command,h.args,h.arg).catch(A=>te(Q(A),rn));return}if(h?.kind==="unknown"){a.setText(w),F(`Unknown command /${h.name}. Type /help to see the commands.`);return}if(b){let A=O!==void 0;O=w,F(A?"Replaced your queued message. It sends when Oracle finishes.":"Queued. It sends when Oracle finishes; Esc interrupts instead."),Y();return}Le({kind:"submit",text:w})},Si=o.addInputListener(g=>{if(on(g,"ctrl+c")){if(b)return mn(),{consume:!0};if(o.hasOverlay())return;if(o.getFocusedComponent()===a&&a.getText())return a.setText(""),Y(),{consume:!0};let w=Date.now();return w-lr<=Yo?Tt():(lr=w,o.flash("Press Ctrl+C again to exit",Yo)),{consume:!0}}if(on(g,"escape")){let w=ce!==void 0&&o.getFocusedComponent()===ce;return b&&!a.isShowingAutocomplete()&&!o.hasOverlay()&&!w?(mn(),{consume:!0}):void 0}if(on(g,"ctrl+d"))return o.getFocusedComponent()===a&&!a.getText()?(Tt(),{consume:!0}):void 0;if(on(g,"ctrl+o"))return kt=!kt,F(kt?"Showing tool activity":"Hiding tool activity"),Y(),{consume:!0}}),gr=()=>{let g=!!b;mn().finally(()=>{g&&(ln=!0),Tt()})};process.on("SIGINT",gr),a.onSubmit=mr,a.onChange=()=>Y(),a.setAutocompleteProvider(Uo(c,process.cwd())),fn(t.session),o.start(),l.activeStreamId&&Le({kind:"replay",streamId:l.activeStreamId}),t.initialPrompt&&mr(t.initialPrompt),await vi,Si(),process.off("SIGINT",gr),pn(),b?.controller.abort(),await r.drainInput().catch(()=>{}),ln&&(process.exitCode=130)}function ec(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 tc,randomBytes as Xo,timingSafeEqual as nc}from"node:crypto";import{createServer as rc}from"node:http";import oc from"open";var ic=6e4,sc=5*6e4,sn=new Map;async function nr(t){let e=fe(t.endpoint),n=await ze(e),r=["read"];t.write&&r.push("write"),t.approve&&(r.includes("write")||r.push("write"),r.push("approve"));let o=Xo(32).toString("base64url"),i=await lc(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 dc(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=Xo(32).toString("base64url"),p=tc("sha256").update(c).digest("base64url"),l={client_id:a.client_id,redirect_uri:i.redirectUri,response_type:"code",scope:r.join(" "),state:o,code_challenge:p,code_challenge_method:"S256",resource:n.resource},u=new URL(n.oauth.authorization);for(let[R,V]of Object.entries(l))u.searchParams.set(R,String(V));t.onAuthorizationUrl?.(u.toString());try{t.openBrowser?await t.openBrowser(u.toString()):await oc(u.toString())}catch{process.stderr.write(`Open this URL to authorize AnyForge Oracle:
|
|
266
266
|
${u.toString()}
|
|
267
|
-
`)}let v=await i.wait();if(!
|
|
267
|
+
`)}let v=await i.wait();if(!ni(v.state,o))throw new f("Oracle sign-in callback state did not match; authorization was rejected.",m.API_ERROR);if(v.error)throw new f(`Oracle authorization failed: ${d(v.error)}${v.errorDescription?` (${d(v.errorDescription)})`:""}`,m.API_ERROR);if(!v.code)throw new f("Oracle authorization callback did not include a code.",m.API_ERROR);let k={client_id:a.client_id,grant_type:"authorization_code",code:v.code,redirect_uri:i.redirectUri,code_verifier:c,resource:n.resource},x=await ii(n.oauth.token,k);oi(x);let b=ri(x.scope);if(!b.includes("read")||b.some(R=>!r.includes(R)))throw await or(n.oauth.revocation,a.client_id,x.access_token,x.refresh_token).catch(()=>{}),new f("The granted Oracle scopes are invalid for this request.",m.API_ERROR);let O={version:1,endpoint:e,clientId:a.client_id,redirectUri:i.redirectUri,accessToken:x.access_token,refreshToken:x.refresh_token,expiresAt:Date.now()+x.expires_in*1e3,scopes:b};return await Jt(()=>zn(O)),O}finally{await i.close()}}async function ei(){let t=await Jt(async()=>{let e=await Kt();if(!e)return{hadCredentials:!1,revoked:!1,revokeFailure:void 0};try{let n=await ze(e.endpoint);return await or(n.oauth.revocation,e.clientId,e.accessToken,e.refreshToken),await We(),{hadCredentials:!0,revoked:!0,revokeFailure:void 0}}catch(n){return await We(),{hadCredentials:!0,revoked:!1,revokeFailure:n}}});if(t.hadCredentials&&!t.revoked)throw new f(`Local Oracle credentials were cleared, but server revocation failed: ${t.revokeFailure instanceof Error?d(t.revokeFailure.message):"unknown error"}`,m.FAILURE,"Run `anyforge oracle login` again if you still need access. The server will expire this access token automatically.");return{hadCredentials:t.hadCredentials,revoked:t.revoked}}async function ti(t){let e=t||process.env.ANYFORGE_ENDPOINT;if(process.env.ANYFORGE_API_TOKEN)return Zo(e);let n=await Kt();if(n&&(!e||fe(e)===n.endpoint)){let r=n.endpoint;return{endpoint:r,accessToken:n.accessToken,scopes:n.scopes.filter(rr),source:"oauth",getAccessToken:async o=>ac(r,o)}}try{return await Zo(e)}catch(r){throw n&&e&&fe(e)!==n.endpoint?new oe:r instanceof oe?new oe:r}}async function Zo(t){let e=await Fe(t),r=(await tt({apiKey:e.apiKey,endpoint:e.endpoint})).scopes.filter(rr);return{endpoint:e.endpoint,accessToken:e.apiKey,scopes:r,source:"control"}}async function ac(t,e){let n=fe(t),r=sn.get(n);if(r)return r;let o=Jt(()=>cc(n,e));sn.set(n,o);try{return await o}finally{sn.get(n)===o&&sn.delete(n)}}async function cc(t,e){let n=await Kt();if(!n||n.endpoint!==t)throw new oe;if(n.expiresAt>Date.now()+ic&&(!e||n.accessToken!==e))return n.accessToken;let r=await ze(n.endpoint),o;try{let s={client_id:n.clientId,grant_type:"refresh_token",refresh_token:n.refreshToken,resource:r.resource};o=await ii(r.oauth.token,s)}catch(s){throw s instanceof an&&["invalid_grant","invalid_client","invalid_target"].includes(s.code)?(await We(),new oe):s}oi(o);let i;try{i=ri(o.scope)}catch(s){throw await We(),s}if(i.some(s=>!n?.scopes.includes(s)))throw await or(r.oauth.revocation,n.clientId,o.access_token,o.refresh_token),await We(),new f("Oracle refresh attempted to widen the saved grant; credentials were cleared.",m.API_ERROR);return n={...n,accessToken:o.access_token,refreshToken:o.refresh_token,expiresAt:Date.now()+o.expires_in*1e3,scopes:i},await zn(n),n.accessToken}var an=class extends f{constructor(n,r,o){super(`OAuth ${n}: ${r}`,o===401?m.NO_CREDENTIALS:m.API_ERROR);this.code=n;this.name="OAuthResponseError"}};async function lc(t){let e,n,r=!1,o=new Promise((c,p)=>{e=c,n=p});o.catch(()=>{});let i=rc((c,p)=>{if((c.url?.length??0)>8192){p.writeHead(414,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is too large.");return}let l=c.url??"/";if(!l.startsWith("/callback")||l.startsWith("//")){p.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response path is invalid.");return}let u=new URL(l,"http://127.0.0.1");if(c.method!=="GET"||u.pathname!=="/callback"){p.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}).end("Not found");return}let v=u.searchParams.get("code")?.slice(0,2048)??"",k=u.searchParams.get("state")?.slice(0,256)??"",x=u.searchParams.get("error")?.slice(0,256)??void 0,b=u.searchParams.get("error_description")?.slice(0,1024)??void 0;if(!k){p.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response is missing state.");return}if(!ni(k,t)){p.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response state did not match.");return}if(r){p.writeHead(409,{"Content-Type":"text/plain; charset=utf-8"}).end("Authorization response already received.");return}r=!0,p.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","Referrer-Policy":"no-referrer","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'"}).end('<!doctype html><meta charset="utf-8"><title>AnyForge Oracle</title><p>Sign-in response received. You may close this tab.</p>'),e({code:v,state:k,...x?{error:x}:{},...b?{errorDescription:b}:{}})});await new Promise((c,p)=>{i.once("error",p),i.listen(0,"127.0.0.1",()=>{i.removeListener("error",p),c()})});let s=i.address();if(!s||typeof s=="string")throw new f("Could not bind an Oracle sign-in callback port.",m.FAILURE);let a=setTimeout(()=>{r||(r=!0,n(new f("Oracle sign-in timed out before the browser returned.",m.FAILURE)))},sc);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&&nc(n,r)}function ri(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 oi(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 dc(t,e){return si(t,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(e)})}async function ii(t,e){return si(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 si(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 an(i,s,n.status)}if(!r||typeof r!="object"||Array.isArray(r))throw new f(`OAuth endpoint returned invalid JSON (${n.status}).`,m.API_ERROR);return r}async function or(t,e,n,r){let o=async i=>{let s=await fetch(t,{method:"POST",redirect:"error",signal:AbortSignal.timeout(2e4),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams({client_id:e,token:i}).toString()});if(!s.ok){let a=`HTTP ${s.status}`;try{let c=await s.json();typeof c.error_description=="string"&&(a=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 kc=1048576,Sc=25*1048576;async function pi(t){let[e,...n]=t.positional,r=["exec","sessions","resume","login","logout","download"].includes(e??""),o=r?void 0:t.positional.join(" ");if(j(t.flags,"read-only")&&(j(t.flags,"write")||j(t.flags,"approve")))throw new y("--read-only cannot be combined with --write or --approve.");if(!r&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new y("Interactive Oracle needs a terminal.",'Use `anyforge oracle exec "your question"` for scripts and pipes.');if(e==="login"){if(n.length)throw new y("oracle login does not accept positional arguments.");let k=await nr({endpoint:t.endpointOverride??t.endpoint,write:j(t.flags,"write"),approve:j(t.flags,"approve")}),x=k.scopes.join(", "),O=[j(t.flags,"write")?"write":void 0,j(t.flags,"approve")?"approve":void 0].filter(R=>!!R).filter(R=>!k.scopes.includes(R));process.stdout.write(`Connected to ${k.endpoint} with scopes: ${x}.
|
|
268
268
|
`),O.length&&process.stderr.write(`This account was granted read only; the server withheld: ${O.join(", ")}.
|
|
269
|
-
`);return}if(e==="logout"){if(n.length)throw new y("oracle logout does not accept positional arguments.");let
|
|
269
|
+
`);return}if(e==="logout"){if(n.length)throw new y("oracle logout does not accept positional arguments.");let k=await ei();process.stdout.write(k.hadCredentials?`Oracle credentials cleared and revoked.
|
|
270
270
|
`:`No saved Oracle credentials.
|
|
271
|
-
`);return}let i;try{i=await
|
|
272
|
-
`),i=await
|
|
273
|
-
`)),V={requestId:
|
|
271
|
+
`);return}let i;try{i=await ci(t.endpointOverride)}catch(k){if(!r&&k instanceof f&&k.exitCode===m.NO_CREDENTIALS&&process.stdin.isTTY&&process.stdout.isTTY){let x=(await import("prompts")).default;if((await x({type:"confirm",name:"login",message:"Sign in to AnyForge Oracle now?",initial:!0})).login!==!0)throw k;let O=await nr({endpoint:t.endpointOverride??t.endpoint});process.stderr.write(`Connected to ${O.endpoint} with scopes: ${O.scopes.join(", ")}.
|
|
272
|
+
`),i=await ci(t.endpointOverride)}else throw k}if(e==="sessions"){if(n.length)throw new y("oracle sessions does not accept positional arguments.");let k=await i.listSessions();Cc(k,t.flags.json===!0);return}if(e==="download"){await $c(i,n,t.flags);return}if(e==="exec"){if(j(t.flags,"write")||j(t.flags,"approve"))throw new y("oracle exec is read-only. Use interactive `anyforge oracle --write` for authorized actions.");if(t.flags.json===!0&&j(t.flags,"stream-json"))throw new y("Choose either --json or --stream-json.");let k=await Ic(n.join(" ")),x=await i.config();li(i,x),di(Rt(t.flags,"context"));let b=Bn(t.flags),O=await i.createSession(wt(b,!1));await yt(O.sessionId,i.endpoint);let R=await Qt(i,O.sessionId,ai(t.flags),(K,ae)=>J(process.stderr,`Uploading explicit attachment ${K} (${N(ae)}).
|
|
273
|
+
`)),V={requestId:fc(),text:k,readOnly:!0,...b?{context:b}:{},...Rt(t.flags,"context")?{contextText:Rt(t.flags,"context")}:{},...R.length?{attachments:R.map(K=>({fileId:K.fileId}))}:{}};await Ec(i,O.sessionId,V,{json:t.flags.json===!0,streamJson:j(t.flags,"stream-json"),config:x});return}if(e==="resume"&&n.length>1)throw new y("oracle resume accepts at most one session id.");if(e==="resume"&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new y("oracle resume is interactive and needs a terminal.","Use `anyforge oracle sessions` to list sessions, or run `anyforge oracle exec` for a new scripted turn.");let s=await i.config();li(i,s);let a=Bn(t.flags),c=Rt(t.flags,"context");di(c);let p=j(t.flags,"shared"),l=j(t.flags,"write")||j(t.flags,"approve");if(l&&(!i.scopes.has("write")||s.capabilities?.write!==!0))throw new f("This Oracle grant or current workspace role does not allow write actions.",m.API_ERROR);if(j(t.flags,"approve")&&(!i.scopes.has("approve")||s.capabilities?.approve!==!0))throw new f("This Oracle grant or current workspace role does not allow approval actions.",m.API_ERROR);if(p&&(!a||a.kind!=="program"&&a.kind!=="initiative"))throw new y("--shared requires --program or --initiative.");let u;if(e==="resume"){let x=(n[0]||void 0)??await Tc(await i.listSessions(),await Ht(i.endpoint));u=await i.getSession(x)}else u=await i.createSession(wt(a,p));await yt(u.sessionId,i.endpoint);let v=await Promise.resolve().then(()=>(sr(),ir));await Vo({version:v.default.version,client:i,config:s,session:u,initialPrompt:o,initialContext:a,contextText:c,shared:p,canWrite:l,canApprove:j(t.flags,"approve"),initialFiles:ai(t.flags)})}function j(t,e){return t[e]===!0}function Rt(t,e){let n=t[e];return typeof n=="string"?n:void 0}function ai(t){let e=t.file;return typeof e=="string"?[e]:Array.isArray(e)?e:[]}async function ci(t){try{return new Wt(await ti(t))}catch(e){throw e instanceof f&&e.exitCode===m.NO_CREDENTIALS?new f("Not authenticated for the hosted Oracle.",m.NO_CREDENTIALS,"Run `anyforge oracle login`, or set ANYFORGE_API_TOKEN for an existing Control grant."):e}}function li(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 di(t){if(t&&Buffer.byteLength(t,"utf8")>Wn)throw new y(`--context must be ${Wn/1024} KiB or less.`)}async function Ic(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>kc)throw new y("Piped Oracle input exceeds the 1 MiB limit.");n.push(s)}let o=Buffer.concat(n).toString("utf8").trim();if(!e&&!o)throw new y("oracle exec needs a prompt in argv or piped stdin.");return[e,o].filter(Boolean).join(`
|
|
274
274
|
|
|
275
|
-
`)}function
|
|
275
|
+
`)}function Cc(t,e){if(e){process.stdout.write(`${JSON.stringify(t,null,2)}
|
|
276
276
|
`);return}if(!t.length){process.stdout.write(`No Oracle sessions are available.
|
|
277
|
-
`);return}for(let n of t){let r=ue(n);process.stdout.write(`${
|
|
278
|
-
`)}}async function
|
|
277
|
+
`);return}for(let n of t){let r=ue(n);process.stdout.write(`${ui(n.sessionId)} ${d(n.title)} ${At(r)}
|
|
278
|
+
`)}}async function Tc(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 bc,i=new xc(o),s=new Ac(ui("Resume an Oracle session")),a=new Rc(t.map(u=>({value:u.sessionId,label:u.title,description:ue(u)})),12,pt),c=e?t.findIndex(u=>u.sessionId===e):-1;c>=0&&a.setSelectedIndex(c),i.addChild(s),i.addChild(a),a.onSelect=u=>{l(),n(u.value)},a.onCancel=()=>{l(),r(new f("Session selection cancelled.",m.FAILURE))};let p=()=>{l(),r(new f("Session selection interrupted.",m.INTERRUPTED))},l=()=>{process.off("SIGINT",p),i.stop()};process.once("SIGINT",p),i.start()})}async function J(t,e){t.write(e)||await new Promise(n=>t.once("drain",n))}async function Ec(t,e,n,r){let o=new Ce,i=!1,s,a=new AbortController,c=()=>s??=p(),p=async()=>{if(i=!0,process.exitCode=130,a.abort(new Error("Turn cancelled by Ctrl+C.")),o.streamId)try{let R=await t.cancelTurn(e,o.streamId);await J(process.stderr,`${He(R)}
|
|
279
279
|
`)}catch(R){await J(process.stderr,`Could not confirm server cancellation: ${Q(R)}
|
|
280
|
-
`)}else try{let R=await t.cancelRequest(e,n.requestId);await J(process.stderr,`${
|
|
280
|
+
`)}else try{let R=await t.cancelRequest(e,n.requestId);await J(process.stderr,`${He(R)}
|
|
281
281
|
`)}catch(R){await J(process.stderr,`Could not confirm server cancellation by request id: ${Q(R)}
|
|
282
282
|
`)}},l=()=>{c().catch(()=>{})};process.on("SIGINT",l);let u=async R=>J(process.stdout,`${JSON.stringify(de(R))}
|
|
283
|
-
`),v=new
|
|
283
|
+
`),v=new ar(e),k=-1,x=async R=>{if(r.streamJson){if(R.idx<=k)return;R.type!=="finalizing"&&(k=R.idx),await u({...R,sessionId:e})}else await v.emit(R)},b;try{b=await Yt(t,e,n,{onEvent:x},a.signal,o)}catch(R){if(!i)throw process.off("SIGINT",l),R;b=o.outcome()}finally{process.off("SIGINT",l),s&&await s}let O=ht(e,b);return r.streamJson?await u({protocolVersion:1,type:"result",result:O}):r.json?await J(process.stdout,`${JSON.stringify(O,null,2)}
|
|
284
284
|
`):(O.answer&&await J(process.stdout,`${O.answer}
|
|
285
285
|
`),O.status==="awaiting_input"&&await J(process.stderr,`Oracle needs a response; resume this session interactively to answer the question.
|
|
286
286
|
`),O.status==="interrupted"&&await J(process.stderr,`Oracle turn ended without a complete final answer.
|
|
287
287
|
`),O.status==="error"&&O.error&&await J(process.stderr,`Oracle error: ${d(O.error)}
|
|
288
|
-
`),(O.servedBy||O.usage||O.rounds!==void 0)&&await J(process.stderr,
|
|
289
|
-
`)}describe(e){switch(e.type){case"tool_call":{if(e.name
|
|
290
|
-
`):"";default:return""}}};function
|
|
291
|
-
`:""}async function
|
|
292
|
-
`)}function
|
|
288
|
+
`),(O.servedBy||O.usage||O.rounds!==void 0)&&await J(process.stderr,_c(O.servedBy,O.usage,O.rounds))),i?process.exitCode=130:O.status==="error"?process.exitCode=m.API_ERROR:O.status==="interrupted"&&(process.exitCode=m.FAILURE),O}var ar=class{constructor(e){this.sessionId=e}labels=new Map;announced=new Set;async emit(e){let n=this.describe(e);n&&await J(process.stderr,`${n}
|
|
289
|
+
`)}describe(e){switch(e.type){case"tool_call":{if(Me(e.name))return"";let n=I(typeof e.label=="string"?e.label:Gt(I(e.name,240)),120),r=typeof e.id=="string"?e.id:void 0;if(r){if(this.labels.set(r,n),this.announced.has(r))return"";this.announced.add(r)}return`${At(typeof e.spawnId=="string"?"Oracle \xB7 agent \xB7":"Oracle \xB7")} ${Oc(n)}`}case"tool_result":{if(e.ok!==!1)return"";let n=typeof e.toolUseId=="string"?this.labels.get(e.toolUseId):void 0;return cn(`Oracle \xB7 ${n??"a tool"} failed`)}case"warning":return cn(`Warning: ${I(e.message,500)}`);case"navigator_file_error":return cn(`Could not generate ${I(e.filename,200)}: ${I(e.error,500)}`);case"navigator_file_created":{let n=Ke(e.file);return At(`Generated ${n.filename} (${N(n.sizeBytes)}). Download: anyforge oracle download ${this.sessionId} ${n.fileId} --output .`)}case"provider_fallback":{let n=I(e.from,120),r=I(e.to,120);return At(`Oracle switched model${n?` from ${n}`:""}${r?` to ${r}`:""}.`)}case"attachment_notice":return Array.isArray(e.notices)?e.notices.map(n=>{let r=n&&typeof n=="object"?n:{};return`${cn("Attachment")} ${I(r.name,160)}: ${I(r.message,500)}`}).join(`
|
|
290
|
+
`):"";default:return""}}};function _c(t,e,n){let r=[];if(t&&typeof t=="object"){let o=t,i=Ot(o);i&&r.push(`model ${i}`),typeof o.routing=="string"&&r.push(I(o.routing.replaceAll("_"," "),40)),typeof o.configuredModel=="string"&&o.configuredModel!==o.model&&r.push(`configured ${I(o.configuredModel,100)}`),typeof o.provider=="string"&&r.push(I(o.provider,100))}return e?.inputTokens!==void 0||e?.outputTokens!==void 0?r.push(`${e.inputTokens??0} in${e.cachedInputTokens?` (${e.cachedInputTokens} cached)`:""} / ${e.outputTokens??0} out tokens`):e?.totalTokens!==void 0&&r.push(`${e.totalTokens} tokens`),n!==void 0&&r.push(`${n} rounds`),r.length?`${At(r.join(" \xB7 "))}
|
|
291
|
+
`:""}async function $c(t,e,n){if(e.length!==2)throw new y("oracle download needs exactly a session id and file id.");let[r,o]=e;if(!r||!o)throw new y("oracle download needs a session id and file id.");let i=Rt(n,"output");if(!i)throw new y("oracle download requires --output <existing-directory>.");let s=vc(i),a=await gc(s);if(!(await hc(a)).isDirectory())throw new y("--output must point to an existing directory.");let p=await t.download(r,o),l=Lc(Pc(p.headers.get("content-disposition"))),u=yc(a,l),v=await Fc(p,Sc),k;try{k=await mc(u,"wx",384),await k.writeFile(v)}catch(x){throw x.code==="EEXIST"?new f(`Refusing to overwrite ${u}.`,m.FAILURE):x}finally{await k?.close()}process.stdout.write(`Downloaded ${d(l)} to ${d(u)} (${N(v.byteLength)}).
|
|
292
|
+
`)}function Pc(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 Lc(t){let e=wc(t.replace(/\\/g,"/")).replace(/[\u0000-\u001f\u007f/:]/g,"_").replace(/^\.+/,"").trim().slice(0,180);return!e||e==="."||e===".."?"oracle-file.bin":e}async function Fc(t,e){if(!t.body)return Buffer.alloc(0);let n=t.body.getReader(),r=[],o=0;try{for(;;){let{value:i,done:s}=await n.read();if(s)break;let a=Buffer.from(i);if(o+=a.byteLength,o>e)throw new f(`Oracle download exceeds the ${N(e)} limit.`,m.API_ERROR);r.push(a)}}catch(i){throw await n.cancel("Oracle download exceeded its byte limit.").catch(()=>{}),i}finally{n.releaseLock()}return Buffer.concat(r)}var gi="https://crew.anyforge.ai",qc=new Set(["endpoint","limit","status","type","priority","initiative","program","search","assignee","notes","input","context","messages","scope","client","days","profile","interval","codebase","file","output"]),Mc=new Set(["help","version","json","active","archived","all","follow","3way","dry-run","force","shared","write","approve","read-only","stream-json"]);function Uc(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(qc.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(Mc.has(i)){e.flags[i]=s===void 0?!0:s!=="false";continue}throw new y(`Unknown option: ${r}`,"Run `anyforge --help` for the command list.")}return e}function he(t,e){if(t===void 0||typeof t=="boolean")return;let n=Number(t);if(!Number.isFinite(n)||n<=0)throw new y(`--${e} must be a positive number, got "${t}".`);return n}function D(t){return typeof t=="string"?t:void 0}function cr(t){return t===!0?!0:void 0}function jc(){console.log(`
|
|
293
293
|
${B("AnyForge Control")} \u2014 governed LLM proxy, and a scriptable AnyForge client.
|
|
294
294
|
|
|
295
295
|
${B("USAGE")}
|
|
@@ -307,7 +307,7 @@ ${B("SKILLS")}
|
|
|
307
307
|
Install the portable AnyForge platform guide
|
|
308
308
|
(--scope project|user, --client agents|claude|codex)
|
|
309
309
|
|
|
310
|
-
${B("APPROVALS")} ${
|
|
310
|
+
${B("APPROVALS")} ${xt("(the gate that blocks a human)")}
|
|
311
311
|
approvals List HIL approvals awaiting a decision
|
|
312
312
|
approve <id> Approve one, optionally with --notes
|
|
313
313
|
reject <id> Reject one, optionally with --notes
|
|
@@ -346,7 +346,7 @@ ${B("MEASUREMENT")}
|
|
|
346
346
|
|
|
347
347
|
${B("OPTIONS")}
|
|
348
348
|
--json Print the raw API payload instead of a table
|
|
349
|
-
--endpoint <url> Override the base URL (default: ${
|
|
349
|
+
--endpoint <url> Override the base URL (default: ${xt(gi)})
|
|
350
350
|
--limit <n> Page size on list commands (work: 1-200, default 50)
|
|
351
351
|
--all work: follow the cursor until the backlog is exhausted
|
|
352
352
|
--notes <text> approve/reject: reviewer notes, recorded in the audit trail
|
|
@@ -381,7 +381,7 @@ ${B("EXAMPLES")}
|
|
|
381
381
|
anyforge review-interception --days 30
|
|
382
382
|
anyforge review-coverage --days 30
|
|
383
383
|
anyforge ask "which initiatives slipped this cycle?"
|
|
384
|
-
`)}function
|
|
384
|
+
`)}function Dc(){console.log(`
|
|
385
385
|
${B("AnyForge Oracle")} \u2014 chat with your hosted, workspace-governed Oracle.
|
|
386
386
|
|
|
387
387
|
${B("USAGE")}
|
|
@@ -433,8 +433,8 @@ Examples:
|
|
|
433
433
|
anyforge oracle --shared --program prog_123
|
|
434
434
|
anyforge oracle exec "Summarize current risks" --json
|
|
435
435
|
cat incident.log | anyforge oracle exec "Explain this log" --stream-json
|
|
436
|
-
`)}async function
|
|
437
|
-
`),t.hint?process.stderr.write(
|
|
438
|
-
`):t instanceof y&&process.stderr.write(
|
|
439
|
-
`),process.exit(t.exitCode)),process.stderr.write(
|
|
440
|
-
`),process.exit(m.FAILURE)}
|
|
436
|
+
`)}async function Bc(t,e,n,r){let o=e.flags.json===!0,[i]=e.positional;if(t==="oracle")return pi({positional:e.positional,flags:e.flags,endpointOverride:r,endpoint:n});switch(t){case"init":return $r({endpoint:n,force:e.flags.force===!0});case"logout":return Ur();case"status":return jr({endpoint:n});case"whoami":return qr({endpoint:r,json:o});case"apply-patch":return Br({patchFile:i,threeWay:e.flags["3way"]===!0,dryRun:e.flags["dry-run"]===!0});case"proxy":console.log(Nc("Local proxy mode is coming in a future release.")),console.log(xt(" Until then, your agents talk directly to the AnyForge proxy."));return;case"skill":return po({subcommand:i,name:e.positional[1],scope:D(e.flags.scope),client:D(e.flags.client),force:e.flags.force===!0,json:o})}let s=await Fe(r);switch(t){case"approvals":return Gr({creds:s,json:o,limit:he(e.flags.limit,"limit")});case"approve":return Sn({creds:s,json:o,approvalId:i,decision:"APPROVED",notes:D(e.flags.notes)});case"reject":return Sn({creds:s,json:o,approvalId:i,decision:"REJECTED",notes:D(e.flags.notes)});case"crews":return zr({creds:s,json:o,status:D(e.flags.status),activeOnly:cr(e.flags.active),limit:he(e.flags.limit,"limit")});case"crew":{let[a,c]=e.positional;return a==="start"?Yr({creds:s,json:o,workItemId:c,profileId:D(e.flags.profile),follow:e.flags.follow===!0,intervalSeconds:he(e.flags.interval,"interval")}):a==="follow"?Tn({creds:s,json:o,crewId:c,intervalSeconds:he(e.flags.interval,"interval")}):Wr({creds:s,json:o,crewId:i,messages:he(e.flags.messages,"messages")})}case"halt":return Cn({creds:s,json:o,crewId:i,action:"halt"});case"resume":return Cn({creds:s,json:o,crewId:i,action:"resume"});case"work":return Xr({creds:s,json:o,status:D(e.flags.status),type:D(e.flags.type),priority:D(e.flags.priority),initiative:D(e.flags.initiative),program:D(e.flags.program),search:D(e.flags.search),assignee:D(e.flags.assignee),includeArchived:cr(e.flags.archived),limit:he(e.flags.limit,"limit"),all:cr(e.flags.all)});case"workflows":return Zr({creds:s,json:o});case"run":return eo({creds:s,json:o,workflowId:i,input:D(e.flags.input)});case"ask":return to({creds:s,json:o,question:e.positional.join(" "),context:D(e.flags.context)});case"backtest-corpus":return ro({creds:s,json:o,days:he(e.flags.days,"days")});case"review-interception":return io({creds:s,json:o,days:he(e.flags.days,"days")});case"review-coverage":return so({creds:s,json:o,days:he(e.flags.days,"days")});default:throw new y(`Unknown command: ${t}`,"Run `anyforge --help` for the command list.")}}async function Gc(){let t;try{t=Uc(process.argv.slice(2))}catch(r){mi(r);return}if(t.flags.version===!0){let r=await Promise.resolve().then(()=>(sr(),ir));console.log(r.default.version);return}if(t.command==="oracle"&&t.flags.help===!0){Dc();return}if(t.flags.help===!0||!t.command){jc();return}let e=D(t.flags.endpoint)??process.env.ANYFORGE_ENDPOINT,n=e??gi;try{if(t.command!=="oracle"){let o=["approve","codebase","file","output","read-only","shared","stream-json","write"].find(i=>t.flags[i]!==void 0);if(o)throw new y(`--${o} is only supported by the oracle command.`)}await Bc(t.command,t,n,e)}catch(r){mi(r)}}function mi(t){t instanceof f&&(process.stderr.write(fi("Error: ")+d(t.message)+`
|
|
437
|
+
`),t.hint?process.stderr.write(xt(d(t.hint))+`
|
|
438
|
+
`):t instanceof y&&process.stderr.write(xt("Run `anyforge --help`.")+`
|
|
439
|
+
`),process.exit(t.exitCode)),process.stderr.write(fi("Error: ")+d(t instanceof Error?t.message:String(t))+`
|
|
440
|
+
`),process.exit(m.FAILURE)}Gc();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anyforge/control",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
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",
|