@tangle-network/sandbox-cli 0.8.3-develop.20260623085144.b80a88e → 0.8.3-develop.20260623200213.63e05e9

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/index.mjs CHANGED
@@ -1,4 +1,7 @@
1
- import{createRequire as e}from"node:module";import"dotenv/config";import{Command as t}from"commander";import{randomBytes as n,randomUUID as r}from"node:crypto";import i from"chalk";import*as a from"node:fs";import{existsSync as o,mkdirSync as s,readFileSync as c,renameSync as l,writeFileSync as u}from"node:fs";import*as d from"node:path";import{basename as f,dirname as p,extname as ee,join as te,resolve as ne}from"node:path";import{AuthError as re,NetworkError as m,NotFoundError as ie,QuotaError as ae,Sandbox as h,ServerError as g,StateError as _,TimeoutError as oe,ValidationError as se,createConfidentialSandbox as ce,generateAttestationNonce as le}from"@tangle-network/sandbox";import*as ue from"node:os";import{homedir as de,tmpdir as fe}from"node:os";import{execFileSync as v,spawn as pe}from"node:child_process";import{HubClient as me,HubSdkError as he}from"@tangle-network/hub-sdk";import ge from"ora";import{createMcpServer as _e}from"@tangle-network/sandbox/agent";import{readFile as ve}from"node:fs/promises";import{fileURLToPath as ye}from"node:url";import be from"ws";import{supervise as xe,workerFromBackend as Se}from"@tangle-network/agent-runtime/loops";import{createIntelligenceClient as Ce}from"@tangle-network/sandbox/intelligence";function we(e){if(e.startsWith(`github:`)){let[t,n]=e.slice(7).split(`@`,2),r=t.split(`/`).filter(Boolean);if(r.length<3)throw Error(`invalid github ref "${e}": expected github:<owner>/<repo>/<path>[@<ref>]`);let i=`${r[0]}/${r[1]}`,a=r.slice(2).join(`/`);return{kind:`github`,repository:i,path:a,...n?{ref:n}:{},name:f(a)}}let t;try{t=c(e,`utf8`)}catch{throw Error(`cannot read skill/tool "${e}": not a readable file and not a github: ref`)}return{kind:`inline`,name:f(e),content:t}}function Te(e){let t=(e.skills??[]).map(we),n=(e.tools??[]).map(we),r=t.length>0||n.length>0;if(!(!e.model&&!e.systemPrompt&&!r))return{...e.model?{model:{default:e.model}}:{},...e.systemPrompt?{prompt:{systemPrompt:e.systemPrompt}}:{},...r?{resources:{...t.length>0?{skills:t}:{},...n.length>0?{tools:n}:{}}}:{}}}async function Ee(e){let t;if(e.startsWith(`github:`)){let[n,r]=e.slice(7).split(`@`,2),i=n.split(`/`).filter(Boolean);if(i.length<3)throw Error(`invalid --profile github ref "${e}": expected github:<owner>/<repo>/<path>[@<ref>]`);let a=r??`main`;t=await Pe(`https://raw.githubusercontent.com/${i[0]}/${i[1]}/${a}/${i.slice(2).join(`/`)}`)}else t=/^https?:\/\//.test(e)?await Pe(e):c(e,`utf8`);let n;try{n=JSON.parse(t)}catch{throw Error(`profile at "${e}" is not valid JSON`)}return Ae(n,e),n}const De=[`prompt`,`model`,`permissions`,`tools`,`mcp`,`connections`,`subagents`,`resources`,`hooks`,`modes`,`confidential`,`extensions`],Oe=new Set([...De,`name`,`description`,`version`,`tags`,`metadata`]),ke=[`files`,`tools`,`skills`,`agents`,`commands`];function Ae(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`profile at "${t}" is not an object`);let n=Object.keys(e),r=n.some(e=>De.includes(e)),i=n.includes(`name`)&&n.every(e=>Oe.has(e));if(!r&&!i)throw Error(`"${t}" does not look like an agent profile: no recognized profile keys (model, prompt, resources, tools, connections, …). Got: ${n.slice(0,6).join(`, `)||`(empty object)`}.`);je(e,t)}function je(e,t){let n=e.resources;if(!n||typeof n!=`object`)return;for(let e of ke){let r=n[e];if(r!==void 0){if(!Array.isArray(r))throw Error(`profile at "${t}" is malformed: resources.${e} must be an array`);for(let n of r)Ne(e===`files`?Me(n):n,t)}}let r=n.instructions;r!==void 0&&typeof r!=`string`&&Ne(r,t)}function Me(e){return e&&typeof e==`object`?e.resource:e}function Ne(e,t){let n=e&&typeof e==`object`?e.kind:void 0;if(n!==`inline`&&n!==`github`)throw Error(`profile at "${t}" has an invalid resource ref kind ${JSON.stringify(n)}: expected "inline" or "github"`)}async function Pe(e){let t=await fetch(e);if(!t.ok)throw Error(`failed to fetch ${e} (${t.status})`);return t.text()}async function Fe(e){let t=e.profileSource?await Ee(e.profileSource):void 0,n=Te(e);return t?n?{...t,...n,...n.resources?{resources:{...t.resources,...n.resources}}:{}}:t:n}const Ie=d.join(ue.homedir(),`.tangle`),y=d.join(Ie,`credentials.json`),b=`tangle-sandbox-cli`,Le=`TANGLE_ALLOW_PLAINTEXT_CREDENTIALS`;var Re=class extends Error{constructor(e,t){super(`Credentials file at ${e} is corrupted and cannot be parsed. Inspect or remove it manually before retrying — refusing to overwrite it automatically.`),this.filePath=e,this.name=`CredentialsFileCorruptedError`,t&&(this.cause=t)}},ze=class extends Error{constructor(){super(`Could not store credential in the OS keychain, and the plaintext fallback is not enabled. Install a keychain provider (macOS Keychain or libsecret/secret-tool on Linux), or set ${Le}=1 to opt into a plaintext credentials.json with mode 0600.`),this.name=`KeychainUnavailableError`}};function Be(e){let t=We(e);if(t)return{value:t,source:`keychain`};let n=qe(e);return n?{value:n,source:`file`}:{source:`none`}}function Ve(e,t){if(Ge(e,t))return Ye(e),`keychain`;if(!Ue())throw new ze;return Je(e,t),`file`}function He(e){Ke(e),Ye(e)}function Ue(){let e=process.env[Le];if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function We(e){if(process.platform===`darwin`)try{return v(`security`,[`find-generic-password`,`-s`,b,`-a`,x(e),`-w`],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{return}if(process.platform===`linux`)try{return v(`secret-tool`,[`lookup`,`service`,b,`account`,x(e)],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{return}}function Ge(e,t){if(process.platform===`darwin`)try{return v(`security`,[`add-generic-password`,`-U`,`-s`,b,`-a`,x(e),`-w`,t],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}if(process.platform===`linux`)try{return v(`secret-tool`,[`store`,`--label=Tangle Sandbox CLI`,`service`,b,`account`,x(e)],{input:t,stdio:[`pipe`,`ignore`,`ignore`]}),!0}catch{return!1}return!1}function Ke(e){if(process.platform===`darwin`){try{v(`security`,[`delete-generic-password`,`-s`,b,`-a`,x(e)],{stdio:[`ignore`,`ignore`,`ignore`]})}catch{}return}if(process.platform===`linux`)try{v(`secret-tool`,[`clear`,`service`,b,`account`,x(e)],{stdio:[`ignore`,`ignore`,`ignore`]})}catch{}}function qe(e){return Xe()[e]}function Je(e,t){let n=Xe();n[e]=t,Ze(n)}function Ye(e){let t;try{t=Xe()}catch(e){if(e instanceof Re)return;throw e}e in t&&(delete t[e],Ze(t))}function Xe(){let e;try{e=a.readFileSync(y,`utf8`)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{};throw e}try{let t=JSON.parse(e);if(typeof t!=`object`||!t||Array.isArray(t))throw new Re(y);let n={};for(let[e,r]of Object.entries(t))typeof r==`string`&&(n[e]=r);return n}catch(e){throw e instanceof Re?e:new Re(y,e instanceof Error?e:void 0)}}function Ze(e){if(Qe(),Object.keys(e).length===0){a.existsSync(y)&&a.unlinkSync(y);return}let t=`${y}.${process.pid}.tmp`;a.writeFileSync(t,`${JSON.stringify(e,null,2)}\n`,{mode:384}),a.renameSync(t,y)}function Qe(){if(!a.existsSync(Ie)){a.mkdirSync(Ie,{mode:448,recursive:!0});return}if(process.platform!==`win32`)try{(a.statSync(Ie).mode&511)!=448&&a.chmodSync(Ie,448)}catch{}}function x(e){return`profile:${e}`}const $e=d.join(ue.homedir(),`.tangle`),et=d.join($e,`credentials`),S=d.join($e,`config.json`),C=`default`;function tt(){a.existsSync($e)||a.mkdirSync($e,{mode:448,recursive:!0})}function nt(e,t){tt();let n=`${e}.${process.pid}.tmp`;a.writeFileSync(n,t,{mode:384}),a.renameSync(n,e)}function rt(){try{if(a.existsSync(et)){let e=a.readFileSync(et,`utf-8`).trim();return it(e)?e:e.match(/api_key\s*=\s*(\S+)/)?.[1]}}catch{}}function it(e){return e.startsWith(`sk_`)||e.startsWith(`sk-tan-`)}function at(){try{a.existsSync(et)&&a.unlinkSync(et)}catch{}}function w(){return Ct(St())}function T(e){let t=wt(w(),e);nt(S,`${JSON.stringify(t,null,2)}\n`)}function E(e){return Tt(e||process.env.TANGLE_PROFILE||process.env.SANDBOX_PROFILE||w().activeProfile||C)}function ot(e){T({activeProfile:Tt(e)})}function st(){return process.env.TANGLE_SANDBOX||w().currentSandbox||void 0}function ct(e){T({currentSandbox:e})}function lt(){let e=w();delete e.currentSandbox,nt(S,`${JSON.stringify(e,null,2)}\n`)}function ut(e){let t=e||st();if(!t)throw Error("No sandbox specified. Pass it positionally, set a default with `tangle use <id>`, pass `--box <id>`, or set TANGLE_SANDBOX.");return t}function dt(){let e=w(),t=E(),n=new Set([C,...Object.keys(e.profiles??{})]);return e.activeProfile&&n.add(Tt(e.activeProfile)),[...n].map(e=>{let n=Be(e),r=e===C?rt():void 0,i=n.source===`none`?r?`legacy-file`:`none`:n.source;return{name:e,active:e===t,hasApiKey:n.source!==`none`||!!r,baseUrl:gt(void 0,e),apiKeySource:i}}).sort((e,t)=>e.name.localeCompare(t.name))}function ft(e){let t=E(e);return{name:t,active:t===E(),apiKey:D(void 0,t),baseUrl:gt(void 0,t),credentialSource:ht(void 0,t)}}function pt(e,t){let n=Tt(e),r=w(),i=xt(n,r),a={},o=t.baseUrl??i.baseUrl;o&&(a.baseUrl=o);let s=t.activeTeamId??i.activeTeamId;s&&(a.activeTeamId=s);let c=t.activeTeamName??i.activeTeamName;c&&(a.activeTeamName=c);let l={...r.profiles??{}};a.baseUrl||a.activeTeamId||a.activeTeamName?l[n]=a:delete l[n];let u;return t.apiKey&&(u=Ve(n,t.apiKey),n===C&&at()),T({profiles:Object.keys(l).length>0?l:{}}),u}function mt(e){let t=E(e),n={...w().profiles??{}},r=n[t];if(r){let e={...r,apiKey:void 0};e.baseUrl||e.activeTeamId||e.activeTeamName?n[t]=e:delete n[t]}T({profiles:n}),He(t),t===C&&at()}function D(e,t){if(e)return e;let n=process.env.TANGLE_API_KEY||process.env.SANDBOX_API_KEY;if(n)return n;let r=E(t),i=Be(r);if(i.value)return i.value;if(r===C)return rt()}function ht(e,t){if(e)return`flag`;if(process.env.TANGLE_API_KEY||process.env.SANDBOX_API_KEY)return`env`;let n=E(t),r=Be(n);return r.source===`none`?n===C&&rt()?`legacy-file`:`none`:r.source}function gt(e,t){if(e)return e;let n=process.env.TANGLE_BASE_URL||process.env.SANDBOX_BASE_URL;if(n)return n;let r=E(t),i=w(),a=xt(r,i);return a.baseUrl?a.baseUrl:r===C&&i.baseUrl?i.baseUrl:`https://sandbox.tangle.tools`}function _t(e){if(e)return e.replace(/\/v1\/hub\/?$/,``)}function O(e){let t=E(e.profile),n=D(e.apiKey,t);if(!n)throw Error(`No API key found for profile '${t}'. Set TANGLE_API_KEY or run: tangle auth login${t===C?``:` --profile ${t}`}`);return{apiKey:n,baseUrl:gt(e.baseUrl,t),timeout:e.timeout??3e4,profile:t,...vt(t)}}function vt(e){let t=w(),n=xt(E(e),t);return{activeTeamId:n.activeTeamId,activeTeamName:n.activeTeamName}}function yt(e,t){pt(E(t),{activeTeamId:e.id,activeTeamName:e.name})}function bt(e){let t=E(e),n=w(),r={...n.profiles??{}},i={baseUrl:xt(t,n).baseUrl};i.baseUrl?r[t]=i:delete r[t],T({profiles:r})}function xt(e,t=w()){let n=Tt(e);return{...n===C?{baseUrl:t.baseUrl,activeTeamId:t.profiles?.[C]?.activeTeamId,activeTeamName:t.profiles?.[C]?.activeTeamName}:{},...t.profiles?.[n]??{}}}function St(){try{if(a.existsSync(S)){let e=a.readFileSync(S,`utf-8`);return JSON.parse(e)}}catch{}return{}}function Ct(e){let t=!1,n={};e.apiKey&&(Ve(C,e.apiKey),at(),t=!0);for(let[r,i]of Object.entries(e.profiles??{})){i.apiKey&&(Ve(r,i.apiKey),t=!0);let e={};i.baseUrl&&(e.baseUrl=i.baseUrl),i.activeTeamId&&(e.activeTeamId=i.activeTeamId),i.activeTeamName&&(e.activeTeamName=i.activeTeamName),Object.keys(e).length>0&&(n[r]=e)}let r={...e,apiKey:void 0,profiles:Object.keys(n).length>0?n:void 0};return t&&nt(S,`${JSON.stringify(r,null,2)}\n`),r}function wt(e,t){let n=t.profiles===void 0?{...e.profiles??{}}:Object.fromEntries(Object.entries(t.profiles).filter(([,e])=>!!(e.apiKey||e.baseUrl||e.activeTeamId||e.activeTeamName)));return{...e,...t,profiles:Object.keys(n).length>0?n:void 0}}function Tt(e){let t=e.trim().toLowerCase();if(!t)throw Error(`Profile name cannot be empty`);if(!/^[a-z0-9][a-z0-9._-]*$/.test(t))throw Error(`Profile names may only contain lowercase letters, numbers, dots, underscores, and hyphens`);return t}let k=null,A=null;function j(e){if(e)return k&&A&&A.apiKey===e.apiKey&&A.baseUrl===e.baseUrl?k:(k=new h({apiKey:e.apiKey,baseUrl:e.baseUrl,timeoutMs:e.timeout}),A=e,k);if(k)return k;let t=O({});return k=new h({apiKey:t.apiKey,baseUrl:t.baseUrl,timeoutMs:t.timeout}),A=t,k}function Et(){k=null,A=null}function Dt(e,t){return[...t,e]}function Ot(e){let t=new Map,n=[];for(let r of e){let e=r.trim(),i=e.indexOf(`:`);if(i===-1)throw Error(`Invalid --connection "${r}": expected <connectionId>:<capability>[,<capability>]. List connection ids with \`tangle hub connections\` and capability paths with \`tangle hub tools search <keyword>\`.`);let a=e.slice(0,i).trim();if(a.length===0)throw Error(`Invalid --connection "${r}": connection id is empty. Use <connectionId>:<capability> — list ids with \`tangle hub connections\`.`);let o=e.slice(i+1).split(`,`).map(e=>e.trim()).filter(e=>e.length>0);if(o.length===0)throw Error(`Invalid --connection "${r}": grant at least one capability, e.g. ${a}:gmail.messages.list. Discover paths with \`tangle hub tools search <keyword>\`.`);let s=t.get(a);s===void 0&&(s=new Set,t.set(a,s),n.push(a));for(let e of o)s.add(e)}return n.map(e=>{let n=t.get(e);return{connectionId:e,capabilities:n?[...n]:[]}})}function kt(e){return e==null?i.dim(`-`):typeof e==`boolean`?e?i.green(`yes`):i.red(`no`):e instanceof Date?jt(e):typeof e==`string`&&At(e)?jt(new Date(e)):String(e)}function At(e){return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)}function jt(e){let t=Date.now()-e.getTime();if(t<6e4)return`just now`;if(t<36e5)return`${Math.floor(t/6e4)} min ago`;if(t<864e5){let e=Math.floor(t/36e5);return`${e} hour${e>1?`s`:``} ago`}let n=Math.floor(t/864e5);return`${n} day${n>1?`s`:``} ago`}function Mt(e){switch(e){case`running`:return i.green(e);case`pending`:case`provisioning`:return i.yellow(e);case`stopped`:return i.gray(e);case`failed`:case`deleted`:return i.red(e);default:return e}}function M(e,t){if(e.length===0){console.log(i.dim(`No items found.`));return}let n=t.map(t=>{let n=t.header.length,r=Math.max(...e.map(e=>kt(e[t.key]).length));return t.width??Math.max(n,r)+2}),r=t.map((e,t)=>i.bold(e.header.padEnd(n[t]))).join(``);console.log(r);for(let r of e){let e=t.map((e,t)=>{let i=kt(r[e.key]);return e.key===`status`&&(i=Mt(String(r[e.key]))),i.padEnd(n[t])}).join(``);console.log(e)}}function N(e){console.log(JSON.stringify(e,null,2))}function P(e){console.log(i.green(`✓`),e)}function F(e){console.error(i.red(`✗`),e)}function Nt(e){console.log(i.yellow(`!`),e)}function I(e){console.log(i.blue(`→`),e)}function L(e){return ge({text:e,color:`cyan`})}function R(e,t=0){let n=` `.repeat(t);for(let[t,r]of Object.entries(e))r!=null&&console.log(`${n}${i.dim(`${t}:`)} ${kt(r)}`)}function Pt(e){if(console.log(),console.log(i.bold(`Sandbox Details`)),console.log(i.dim(`─`.repeat(40))),R({ID:e.id,Name:e.name,Status:Mt(e.status),Created:e.createdAt,Expires:e.expiresAt}),e.connection){if(console.log(),console.log(i.bold(`Connection`)),console.log(i.dim(`─`.repeat(40))),e.connection.ssh){let{ssh:t}=e.connection,n=process.platform===`win32`?`NUL`:`/dev/null`,r=`ssh -o ProxyCommand="${t.proxyCommand}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=${n} -o GlobalKnownHostsFile=${n} -o LogLevel=ERROR -o ServerAliveInterval=15 -o ServerAliveCountMax=4 -o TCPKeepAlive=yes ${t.username}@localhost -p ${t.port}`;R({SSH:process.platform===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN='<token>'; ${r}`:`TANGLE_SSH_PROXY_AUTH_TOKEN='<token>' ${r}`})}e.connection.webTerminalUrl&&R({"Web Terminal":e.connection.webTerminalUrl}),e.connection.runtimeUrl&&R({"API URL":e.connection.runtimeUrl})}console.log()}function z(e,t){t?N({error:e.message}):F(e.message),process.exit(1)}function B(e){N(e)}function V(e,t){if(t.length===0){console.log(i.dim(`No items found.`));return}let n=e.map((e,n)=>{let r=Math.max(...t.map(e=>String(e[n]??``).length));return Math.max(e.length,r)+2});console.log(e.map((e,t)=>i.bold(e.padEnd(n[t]))).join(``));for(let e of t)console.log(e.map((e,t)=>String(e??``).padEnd(n[t])).join(``))}function H(e,t=!1){t&&(N(Ft(e)),process.exit(Ht(e)));let n=It(e);console.error(i.red(`Error:`),n),process.exit(Ht(e))}function Ft(e){return e instanceof he?{error:{code:e.code,message:e.message,...typeof e.status==`number`?{status:e.status}:{},...e.details===void 0?{}:{details:e.details}}}:Vt(e)?{error:{code:e.code,message:e.message,status:e.status,...e.details===void 0?{}:{details:e.details}}}:{error:{message:It(e)}}}function It(e){if(e instanceof re)return`Authentication failed. Run 'tangle auth login' to authenticate.`;if(e instanceof ie)return`Resource not found. Check the ID and try again.`;if(e instanceof ae)return`Quota exceeded. Upgrade your plan or wait for quota reset.`;if(e instanceof se)return`Invalid input: ${e.message}`;if(e instanceof _)return`Invalid state: ${e.message}`;if(e instanceof oe)return`Request timed out. Try again or increase timeout with --timeout.`;if(e instanceof m)return`Network error. Check your connection and try again.`;if(e instanceof g)return`${e.status?`HTTP ${e.status}`:`server error`}: ${e.message}`;if(e instanceof he){let t=typeof e.status==`number`?` (HTTP ${e.status})`:``;return e.code===`HUB_CONNECTION_MISSING`?Lt(e.code,t,e.message,e.details):e.code===`HUB_APPROVAL_REQUIRED`?zt(e.code,t,e.message):e.code===`HUB_UNAUTHENTICATED`?Bt(e.code,t,e.message):`${e.code}${t}: ${e.message}`}return Vt(e)?e.code===`HUB_CONNECTION_MISSING`?Lt(e.code,` (HTTP ${e.status})`,e.message,e.details):e.code===`HUB_APPROVAL_REQUIRED`?zt(e.code,` (HTTP ${e.status})`,e.message):e.code===`HUB_UNAUTHENTICATED`?Bt(e.code,` (HTTP ${e.status})`,e.message):`${e.code} (HTTP ${e.status}): ${e.message}`:e instanceof Error?e.message:String(e)}function Lt(e,t,n,r){let i=Rt(r);return`${e}${t}: ${n}${i?`. Run: tangle hub connect ${i}`:``}`}function Rt(e){if(!e||typeof e!=`object`)return;let t=e.provider;return typeof t==`string`&&t.length>0?t:void 0}function zt(e,t,n){return`${e}${t}: ${n}. Run the command again with --auto-approve, or run: tangle hub resume <approval-id> --accept. See: tangle hub resume --help`}function Bt(e,t,n){return`${e}${t}: ${n}. Hub commands need a platform API key or Hub capability token. Set TANGLE_HUB_CAPABILITY_TOKEN, TANGLE_API_KEY, or SANDBOX_API_KEY. Stored credentials from tangle auth login may be sandbox JWTs and incompatible with Hub endpoints.`}function Vt(e){if(!(e instanceof Error))return!1;let t=e;return typeof t.code==`string`&&t.code.startsWith(`HUB_`)&&typeof t.status==`number`}function Ht(e){return e instanceof se?2:1}const Ut=[`anthropic`,`openai`,`vercel-ai`,`mastra`,`mcp-local`,`claude-desktop`,`cursor`,`zed`];function Wt(e,t,n){switch(e){case`anthropic`:return`// pnpm add @anthropic-ai/sdk @tangle-network/sandbox
1
+ import{createRequire as e}from"node:module";import"dotenv/config";import{Command as t}from"commander";import{createHash as n,randomBytes as r,randomUUID as i}from"node:crypto";import a from"chalk";import*as o from"node:fs";import{existsSync as s,mkdirSync as c,readFileSync as l,renameSync as u,writeFileSync as d}from"node:fs";import*as f from"node:path";import{basename as p,dirname as ee,extname as te,join as ne,resolve as re}from"node:path";import{AuthError as ie,NetworkError as m,NotFoundError as ae,QuotaError as h,Sandbox as g,ServerError as _,StateError as oe,TimeoutError as se,ValidationError as ce,createConfidentialSandbox as le,generateAttestationNonce as ue}from"@tangle-network/sandbox";import*as de from"node:os";import{homedir as fe,tmpdir as pe}from"node:os";import{execFileSync as v,spawn as me}from"node:child_process";import{HubClient as he,HubSdkError as ge}from"@tangle-network/hub-sdk";import _e from"ora";import{createMcpServer as ve}from"@tangle-network/sandbox/agent";import{readFile as ye}from"node:fs/promises";import{fileURLToPath as be}from"node:url";import xe from"ws";import{supervise as Se,workerFromBackend as Ce}from"@tangle-network/agent-runtime/loops";import{createIntelligenceClient as we}from"@tangle-network/sandbox/intelligence";function Te(e){if(e.startsWith(`github:`)){let[t,n]=e.slice(7).split(`@`,2),r=t.split(`/`).filter(Boolean);if(r.length<3)throw Error(`invalid github ref "${e}": expected github:<owner>/<repo>/<path>[@<ref>]`);let i=`${r[0]}/${r[1]}`,a=r.slice(2).join(`/`);return{kind:`github`,repository:i,path:a,...n?{ref:n}:{},name:p(a)}}let t;try{t=l(e,`utf8`)}catch{throw Error(`cannot read skill/tool "${e}": not a readable file and not a github: ref`)}return{kind:`inline`,name:p(e),content:t}}function Ee(e){let t=(e.skills??[]).map(Te),n=(e.tools??[]).map(Te),r=t.length>0||n.length>0;if(!(!e.model&&!e.systemPrompt&&!r))return{...e.model?{model:{default:e.model}}:{},...e.systemPrompt?{prompt:{systemPrompt:e.systemPrompt}}:{},...r?{resources:{...t.length>0?{skills:t}:{},...n.length>0?{tools:n}:{}}}:{}}}async function De(e){let t;if(e.startsWith(`github:`)){let[n,r]=e.slice(7).split(`@`,2),i=n.split(`/`).filter(Boolean);if(i.length<3)throw Error(`invalid --profile github ref "${e}": expected github:<owner>/<repo>/<path>[@<ref>]`);let a=r??`main`;t=await Fe(`https://raw.githubusercontent.com/${i[0]}/${i[1]}/${a}/${i.slice(2).join(`/`)}`)}else t=/^https?:\/\//.test(e)?await Fe(e):l(e,`utf8`);let n;try{n=JSON.parse(t)}catch{throw Error(`profile at "${e}" is not valid JSON`)}return je(n,e),n}const Oe=[`prompt`,`model`,`permissions`,`tools`,`mcp`,`connections`,`subagents`,`resources`,`hooks`,`modes`,`confidential`,`extensions`],ke=new Set([...Oe,`name`,`description`,`version`,`tags`,`metadata`]),Ae=[`files`,`tools`,`skills`,`agents`,`commands`];function je(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`profile at "${t}" is not an object`);let n=Object.keys(e),r=n.some(e=>Oe.includes(e)),i=n.includes(`name`)&&n.every(e=>ke.has(e));if(!r&&!i)throw Error(`"${t}" does not look like an agent profile: no recognized profile keys (model, prompt, resources, tools, connections, …). Got: ${n.slice(0,6).join(`, `)||`(empty object)`}.`);Me(e,t)}function Me(e,t){let n=e.resources;if(!n||typeof n!=`object`)return;for(let e of Ae){let r=n[e];if(r!==void 0){if(!Array.isArray(r))throw Error(`profile at "${t}" is malformed: resources.${e} must be an array`);for(let n of r)Pe(e===`files`?Ne(n):n,t)}}let r=n.instructions;r!==void 0&&typeof r!=`string`&&Pe(r,t)}function Ne(e){return e&&typeof e==`object`?e.resource:e}function Pe(e,t){let n=e&&typeof e==`object`?e.kind:void 0;if(n!==`inline`&&n!==`github`)throw Error(`profile at "${t}" has an invalid resource ref kind ${JSON.stringify(n)}: expected "inline" or "github"`)}async function Fe(e){let t=await fetch(e);if(!t.ok)throw Error(`failed to fetch ${e} (${t.status})`);return t.text()}async function Ie(e){let t=e.profileSource?await De(e.profileSource):void 0,n=Ee(e);return t?n?{...t,...n,...n.resources?{resources:{...t.resources,...n.resources}}:{}}:t:n}const Le=f.join(de.homedir(),`.tangle`),y=f.join(Le,`credentials.json`),b=`tangle-sandbox-cli`,Re=`TANGLE_ALLOW_PLAINTEXT_CREDENTIALS`;var ze=class extends Error{constructor(e,t){super(`Credentials file at ${e} is corrupted and cannot be parsed. Inspect or remove it manually before retrying — refusing to overwrite it automatically.`),this.filePath=e,this.name=`CredentialsFileCorruptedError`,t&&(this.cause=t)}},Be=class extends Error{constructor(){super(`Could not store credential in the OS keychain, and the plaintext fallback is not enabled. Install a keychain provider (macOS Keychain or libsecret/secret-tool on Linux), or set ${Re}=1 to opt into a plaintext credentials.json with mode 0600.`),this.name=`KeychainUnavailableError`}};function Ve(e){let t=Ge(e);if(t)return{value:t,source:`keychain`};let n=Je(e);return n?{value:n,source:`file`}:{source:`none`}}function He(e,t){if(Ke(e,t))return Xe(e),`keychain`;if(!We())throw new Be;return Ye(e,t),`file`}function Ue(e){qe(e),Xe(e)}function We(){let e=process.env[Re];if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function Ge(e){if(process.platform===`darwin`)try{return v(`security`,[`find-generic-password`,`-s`,b,`-a`,x(e),`-w`],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{return}if(process.platform===`linux`)try{return v(`secret-tool`,[`lookup`,`service`,b,`account`,x(e)],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{return}}function Ke(e,t){if(process.platform===`darwin`)try{return v(`security`,[`add-generic-password`,`-U`,`-s`,b,`-a`,x(e),`-w`,t],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}if(process.platform===`linux`)try{return v(`secret-tool`,[`store`,`--label=Tangle Sandbox CLI`,`service`,b,`account`,x(e)],{input:t,stdio:[`pipe`,`ignore`,`ignore`]}),!0}catch{return!1}return!1}function qe(e){if(process.platform===`darwin`){try{v(`security`,[`delete-generic-password`,`-s`,b,`-a`,x(e)],{stdio:[`ignore`,`ignore`,`ignore`]})}catch{}return}if(process.platform===`linux`)try{v(`secret-tool`,[`clear`,`service`,b,`account`,x(e)],{stdio:[`ignore`,`ignore`,`ignore`]})}catch{}}function Je(e){return Ze()[e]}function Ye(e,t){let n=Ze();n[e]=t,Qe(n)}function Xe(e){let t;try{t=Ze()}catch(e){if(e instanceof ze)return;throw e}e in t&&(delete t[e],Qe(t))}function Ze(){let e;try{e=o.readFileSync(y,`utf8`)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{};throw e}try{let t=JSON.parse(e);if(typeof t!=`object`||!t||Array.isArray(t))throw new ze(y);let n={};for(let[e,r]of Object.entries(t))typeof r==`string`&&(n[e]=r);return n}catch(e){throw e instanceof ze?e:new ze(y,e instanceof Error?e:void 0)}}function Qe(e){if($e(),Object.keys(e).length===0){o.existsSync(y)&&o.unlinkSync(y);return}let t=`${y}.${process.pid}.tmp`;o.writeFileSync(t,`${JSON.stringify(e,null,2)}\n`,{mode:384}),o.renameSync(t,y)}function $e(){if(!o.existsSync(Le)){o.mkdirSync(Le,{mode:448,recursive:!0});return}if(process.platform!==`win32`)try{(o.statSync(Le).mode&511)!=448&&o.chmodSync(Le,448)}catch{}}function x(e){return`profile:${e}`}const et=f.join(de.homedir(),`.tangle`),tt=f.join(et,`credentials`),nt=f.join(et,`config.json`),S=`default`;function rt(){o.existsSync(et)||o.mkdirSync(et,{mode:448,recursive:!0})}function it(e,t){rt();let n=`${e}.${process.pid}.tmp`;o.writeFileSync(n,t,{mode:384}),o.renameSync(n,e)}function at(){try{if(o.existsSync(tt)){let e=o.readFileSync(tt,`utf-8`).trim();return ot(e)?e:e.match(/api_key\s*=\s*(\S+)/)?.[1]}}catch{}}function ot(e){return e.startsWith(`sk_`)||e.startsWith(`sk-tan-`)}function st(){try{o.existsSync(tt)&&o.unlinkSync(tt)}catch{}}function C(){return Dt(Et())}function w(e){let t=Ot(C(),e);it(nt,`${JSON.stringify(t,null,2)}\n`)}function T(e){return kt(e||process.env.TANGLE_PROFILE||process.env.SANDBOX_PROFILE||C().activeProfile||S)}function ct(e){w({activeProfile:kt(e)})}function lt(){return process.env.TANGLE_SANDBOX||C().currentSandbox||void 0}function ut(e){w({currentSandbox:e})}function dt(){let e=C();delete e.currentSandbox,it(nt,`${JSON.stringify(e,null,2)}\n`)}function ft(){let e=C().deviceId;if(e&&/^[A-Za-z0-9_.-]{1,64}$/.test(e))return e;let t=de.hostname().replace(/[^A-Za-z0-9_.-]/g,`-`).replace(/^-+|-+$/g,``).slice(0,32),n=r(4).toString(`hex`),i=`${t?`${t}-`:`device-`}${n}`;return w({deviceId:i}),i}function pt(e){let t=e||lt();if(!t)throw Error("No sandbox specified. Pass it positionally, set a default with `tangle use <id>`, pass `--box <id>`, or set TANGLE_SANDBOX.");return t}function mt(){let e=C(),t=T(),n=new Set([S,...Object.keys(e.profiles??{})]);return e.activeProfile&&n.add(kt(e.activeProfile)),[...n].map(e=>{let n=Ve(e),r=e===S?at():void 0,i=n.source===`none`?r?`legacy-file`:`none`:n.source;return{name:e,active:e===t,hasApiKey:n.source!==`none`||!!r,baseUrl:bt(void 0,e),apiKeySource:i}}).sort((e,t)=>e.name.localeCompare(t.name))}function ht(e){let t=T(e);return{name:t,active:t===T(),apiKey:vt(void 0,t),baseUrl:bt(void 0,t),credentialSource:yt(void 0,t)}}function gt(e,t){let n=kt(e),r=C(),i=Tt(n,r),a={},o=t.baseUrl??i.baseUrl;o&&(a.baseUrl=o);let s=t.activeTeamId??i.activeTeamId;s&&(a.activeTeamId=s);let c=t.activeTeamName??i.activeTeamName;c&&(a.activeTeamName=c);let l={...r.profiles??{}};a.baseUrl||a.activeTeamId||a.activeTeamName?l[n]=a:delete l[n];let u;return t.apiKey&&(u=He(n,t.apiKey),n===S&&st()),w({profiles:Object.keys(l).length>0?l:{}}),u}function _t(e){let t=T(e),n={...C().profiles??{}},r=n[t];if(r){let e={...r,apiKey:void 0};e.baseUrl||e.activeTeamId||e.activeTeamName?n[t]=e:delete n[t]}w({profiles:n}),Ue(t),t===S&&st()}function vt(e,t){if(e)return e;let n=process.env.TANGLE_API_KEY||process.env.SANDBOX_API_KEY;if(n)return n;let r=T(t),i=Ve(r);if(i.value)return i.value;if(r===S)return at()}function yt(e,t){if(e)return`flag`;if(process.env.TANGLE_API_KEY||process.env.SANDBOX_API_KEY)return`env`;let n=T(t),r=Ve(n);return r.source===`none`?n===S&&at()?`legacy-file`:`none`:r.source}function bt(e,t){if(e)return e;let n=process.env.TANGLE_BASE_URL||process.env.SANDBOX_BASE_URL;if(n)return n;let r=T(t),i=C(),a=Tt(r,i);return a.baseUrl?a.baseUrl:r===S&&i.baseUrl?i.baseUrl:`https://sandbox.tangle.tools`}function xt(e){if(e)return e.replace(/\/v1\/hub\/?$/,``)}function E(e){let t=T(e.profile),n=vt(e.apiKey,t);if(!n)throw Error(`No API key found for profile '${t}'. Set TANGLE_API_KEY or run: tangle auth login${t===S?``:` --profile ${t}`}`);return{apiKey:n,baseUrl:bt(e.baseUrl,t),timeout:e.timeout??3e4,profile:t,...St(t)}}function St(e){let t=C(),n=Tt(T(e),t);return{activeTeamId:n.activeTeamId,activeTeamName:n.activeTeamName}}function Ct(e,t){gt(T(t),{activeTeamId:e.id,activeTeamName:e.name})}function wt(e){let t=T(e),n=C(),r={...n.profiles??{}},i={baseUrl:Tt(t,n).baseUrl};i.baseUrl?r[t]=i:delete r[t],w({profiles:r})}function Tt(e,t=C()){let n=kt(e);return{...n===S?{baseUrl:t.baseUrl,activeTeamId:t.profiles?.[S]?.activeTeamId,activeTeamName:t.profiles?.[S]?.activeTeamName}:{},...t.profiles?.[n]??{}}}function Et(){try{if(o.existsSync(nt)){let e=o.readFileSync(nt,`utf-8`);return JSON.parse(e)}}catch{}return{}}function Dt(e){let t=!1,n={};e.apiKey&&(He(S,e.apiKey),st(),t=!0);for(let[r,i]of Object.entries(e.profiles??{})){i.apiKey&&(He(r,i.apiKey),t=!0);let e={};i.baseUrl&&(e.baseUrl=i.baseUrl),i.activeTeamId&&(e.activeTeamId=i.activeTeamId),i.activeTeamName&&(e.activeTeamName=i.activeTeamName),Object.keys(e).length>0&&(n[r]=e)}let r={...e,apiKey:void 0,profiles:Object.keys(n).length>0?n:void 0};return t&&it(nt,`${JSON.stringify(r,null,2)}\n`),r}function Ot(e,t){let n=t.profiles===void 0?{...e.profiles??{}}:Object.fromEntries(Object.entries(t.profiles).filter(([,e])=>!!(e.apiKey||e.baseUrl||e.activeTeamId||e.activeTeamName)));return{...e,...t,profiles:Object.keys(n).length>0?n:void 0}}function kt(e){let t=e.trim().toLowerCase();if(!t)throw Error(`Profile name cannot be empty`);if(!/^[a-z0-9][a-z0-9._-]*$/.test(t))throw Error(`Profile names may only contain lowercase letters, numbers, dots, underscores, and hyphens`);return t}let D=null,O=null;function k(e){if(e)return D&&O&&O.apiKey===e.apiKey&&O.baseUrl===e.baseUrl&&O.timeout===e.timeout?D:(D=new g({apiKey:e.apiKey,baseUrl:e.baseUrl,timeoutMs:e.timeout}),O=e,D);if(D)return D;let t=E({});return D=new g({apiKey:t.apiKey,baseUrl:t.baseUrl,timeoutMs:t.timeout}),O=t,D}function At(){D=null,O=null}async function jt(e,t){let n=t.trim();if(n.length===0)throw Error(`Connection reference is empty.`);if(n.startsWith(`hubconn_`))return n;let{connections:r}=await e.connections.list();return Mt(r,n)}function Mt(e,t){let n=t.trim();if(n.length===0)throw Error(`Connection reference is empty.`);let r=e.find(e=>e.id===n);if(r)return r.id;let i=n.indexOf(`:`),a=(i===-1?n:n.slice(0,i)).trim().toLowerCase(),o=i===-1?null:n.slice(i+1).trim(),s=e.filter(e=>e.status!==`revoked`&&e.providerId.toLowerCase()===a);if(o&&o.length>0){let e=o.toLowerCase();s=s.filter(t=>(t.accountDisplay??``).toLowerCase()===e||t.displayName.toLowerCase()===e)}if(s.length===1)return s[0].id;throw s.length===0?Error(`No hub connection matches "${t}". List your connections with \`tangle hub connections\`.`):Error(Nt(t,s))}function Nt(e,t){let n=t.map(e=>`- ${e.id} (provider: ${e.providerId}, account: ${e.accountDisplay??e.displayName})`).join(`
2
+ `);return`Hub connection reference is ambiguous: "${e}" matches ${t.length} connections. Use a connection id or provider:account instead.
3
+ `+n}function Pt(e,t){return[...t,e]}async function Ft(e,t){let n=e.map(e=>{let t=e.trim(),n=t.indexOf(`:`);return n===-1?{raw:e,ref:null,tail:null}:{raw:e,ref:t.slice(0,n).trim(),tail:t.slice(n+1)}});if(!n.some(e=>e.ref!==null&&e.ref!==`*`&&!e.ref.startsWith(`hubconn_`)))return[...e];let{connections:r}=await(await t()).connections.list();return n.map(e=>e.ref===null||e.ref===`*`||e.ref.startsWith(`hubconn_`)?e.raw:`${Mt(r,e.ref)}:${e.tail}`)}function It(e){let t=new Map,n=[];for(let r of e){let e=r.trim(),i=e.indexOf(`:`);if(i===-1)throw Error(`Invalid --connection "${r}": expected <connectionId>:<capability>[,<capability>]. List connection ids with \`tangle hub connections\` and capability paths with \`tangle hub tools search <keyword>\`.`);let a=e.slice(0,i).trim();if(a.length===0)throw Error(`Invalid --connection "${r}": connection id is empty. Use <connectionId>:<capability> — list ids with \`tangle hub connections\`.`);let o=e.slice(i+1).split(`,`).map(e=>e.trim()).filter(e=>e.length>0);if(o.length===0)throw Error(`Invalid --connection "${r}": grant at least one capability, e.g. ${a}:gmail.messages.list. Discover paths with \`tangle hub tools search <keyword>\`.`);if(o.includes(`*`)&&o.length>1)throw Error(`Invalid --connection "${r}": "*" grants all capabilities and can't be combined with specific paths. Use <connectionId>:* alone, or list explicit paths.`);if(a===`*`&&!(o.length===1&&o[0]===`*`))throw Error(`Invalid --connection "${r}": a "*" connection is only valid as "*:*" (all connections, all capabilities). Name a connection id for specific paths.`);let s=t.get(a);s===void 0&&(s=new Set,t.set(a,s),n.push(a));for(let e of o)s.add(e)}return n.map(e=>{let n=t.get(e),r=n?[...n]:[];if(r.includes(`*`)&&r.length>1)throw Error(`Invalid --connection for "${e}": "*" can't be combined with specific capability paths across repeated --connection flags.`);return{connectionId:e,capabilities:r}})}function Lt(e){return e==null?a.dim(`-`):typeof e==`boolean`?e?a.green(`yes`):a.red(`no`):e instanceof Date?zt(e):typeof e==`string`&&Rt(e)?zt(new Date(e)):String(e)}function Rt(e){return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)}function zt(e){let t=Date.now()-e.getTime();if(t<6e4)return`just now`;if(t<36e5)return`${Math.floor(t/6e4)} min ago`;if(t<864e5){let e=Math.floor(t/36e5);return`${e} hour${e>1?`s`:``} ago`}let n=Math.floor(t/864e5);return`${n} day${n>1?`s`:``} ago`}function Bt(e){switch(e){case`running`:return a.green(e);case`pending`:case`provisioning`:return a.yellow(e);case`stopped`:return a.gray(e);case`failed`:case`deleted`:return a.red(e);default:return e}}function A(e,t){if(e.length===0){console.log(a.dim(`No items found.`));return}let n=t.map(t=>{let n=t.header.length,r=Math.max(...e.map(e=>Lt(e[t.key]).length));return t.width??Math.max(n,r)+2}),r=t.map((e,t)=>a.bold(e.header.padEnd(n[t]))).join(``);console.log(r);for(let r of e){let e=t.map((e,t)=>{let i=Lt(r[e.key]);return e.key===`status`&&(i=Bt(String(r[e.key]))),i.padEnd(n[t])}).join(``);console.log(e)}}function j(e){console.log(JSON.stringify(e,null,2))}function M(e){console.log(a.green(`✓`),e)}function N(e){console.error(a.red(`✗`),e)}function Vt(e){console.log(a.yellow(`!`),e)}function P(e){console.log(a.blue(`→`),e)}const Ht=new Set;function F(e){let t=_e({text:e,color:`cyan`});return Ht.add(t),t}function Ut(){for(let e of Ht)e.isSpinning&&e.stop();Ht.clear()}function I(e,t=0){let n=` `.repeat(t);for(let[t,r]of Object.entries(e))r!=null&&console.log(`${n}${a.dim(`${t}:`)} ${Lt(r)}`)}function Wt(e){if(console.log(),console.log(a.bold(`Sandbox Details`)),console.log(a.dim(`─`.repeat(40))),I({ID:e.id,Name:e.name,Status:Bt(e.status),Created:e.createdAt,Expires:e.expiresAt}),e.connection){if(console.log(),console.log(a.bold(`Connection`)),console.log(a.dim(`─`.repeat(40))),e.connection.ssh){let{ssh:t}=e.connection,n=process.platform===`win32`?`NUL`:`/dev/null`,r=`ssh -o ProxyCommand="${t.proxyCommand}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=${n} -o GlobalKnownHostsFile=${n} -o LogLevel=ERROR -o ServerAliveInterval=15 -o ServerAliveCountMax=4 -o TCPKeepAlive=yes ${t.username}@localhost -p ${t.port}`;I({SSH:process.platform===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN='<token>'; ${r}`:`TANGLE_SSH_PROXY_AUTH_TOKEN='<token>' ${r}`})}e.connection.webTerminalUrl&&I({"Web Terminal":e.connection.webTerminalUrl}),e.connection.runtimeUrl&&I({"API URL":e.connection.runtimeUrl})}console.log()}function L(e,t){Ut(),t?j({error:e.message}):N(e.message),process.exit(1)}function R(e){j(e)}function z(e,t){if(t.length===0){console.log(a.dim(`No items found.`));return}let n=e.map((e,n)=>{let r=Math.max(...t.map(e=>String(e[n]??``).length));return Math.max(e.length,r)+2});console.log(e.map((e,t)=>a.bold(e.padEnd(n[t]))).join(``));for(let e of t)console.log(e.map((e,t)=>String(e??``).padEnd(n[t])).join(``))}function B(e,t=!1){Ut(),t&&(j(Gt(e)),process.exit(Qt(e)));let n=Kt(e);console.error(a.red(`Error:`),n),process.exit(Qt(e))}function Gt(e){return e instanceof ge?{error:{code:e.code,message:e.message,...typeof e.status==`number`?{status:e.status}:{},...e.details===void 0?{}:{details:e.details}}}:Zt(e)?{error:{code:e.code,message:e.message,status:e.status,...e.details===void 0?{}:{details:e.details}}}:{error:{message:Kt(e)}}}function Kt(e){if(e instanceof ie)return`Authentication failed. Run 'tangle auth login' to authenticate.`;if(e instanceof ae)return`Resource not found. Check the ID and try again.`;if(e instanceof h)return`Quota exceeded. Upgrade your plan or wait for quota reset.`;if(e instanceof ce)return`Invalid input: ${e.message}`;if(e instanceof oe)return`Invalid state: ${e.message}`;if(e instanceof se)return`Request timed out after ${e.timeoutMs} ms. Retry, or re-run with a longer --timeout <ms> on commands that accept it (e.g. create, resume).`;if(e instanceof m)return`Network error. Check your connection and try again.`;if(e instanceof _)return`${e.status?`HTTP ${e.status}`:`server error`}: ${e.message}`;if(e instanceof ge){let t=typeof e.status==`number`?` (HTTP ${e.status})`:``;return e.code===`HUB_CONNECTION_MISSING`?qt(e.code,t,e.message,e.details):e.code===`HUB_APPROVAL_REQUIRED`?Yt(e.code,t,e.message):e.code===`HUB_UNAUTHENTICATED`?Xt(e.code,t,e.message):`${e.code}${t}: ${e.message}`}return Zt(e)?e.code===`HUB_CONNECTION_MISSING`?qt(e.code,` (HTTP ${e.status})`,e.message,e.details):e.code===`HUB_APPROVAL_REQUIRED`?Yt(e.code,` (HTTP ${e.status})`,e.message):e.code===`HUB_UNAUTHENTICATED`?Xt(e.code,` (HTTP ${e.status})`,e.message):`${e.code} (HTTP ${e.status}): ${e.message}`:e instanceof Error?e.message:String(e)}function qt(e,t,n,r){let i=Jt(r);return`${e}${t}: ${n}${i?`. Run: tangle hub connect ${i}`:``}`}function Jt(e){if(!e||typeof e!=`object`)return;let t=e.provider;return typeof t==`string`&&t.length>0?t:void 0}function Yt(e,t,n){return`${e}${t}: ${n}. Run the command again with --auto-approve, or run: tangle hub resume <approval-id> --accept. See: tangle hub resume --help`}function Xt(e,t,n){return`${e}${t}: ${n}. The CLI auto-mints a short-lived Hub key from your login session, so this usually means that session has expired — run 'tangle auth login' to re-authenticate. To use a credential directly instead, set TANGLE_API_KEY, SANDBOX_API_KEY, or TANGLE_HUB_CAPABILITY_TOKEN (and pass --no-hub-key to skip auto-minting).`}function Zt(e){if(!(e instanceof Error))return!1;let t=e;return typeof t.code==`string`&&t.code.startsWith(`HUB_`)&&typeof t.status==`number`}function Qt(e){return e instanceof ce?2:1}function $t(e,t){return n(`sha256`).update(`${e}${t}`).digest(`hex`).slice(0,32)}function en(e){return`${e}:hub`}function tn(e){let{value:t}=Ve(en(e));if(!t)return null;try{let e=JSON.parse(t);if(typeof e.key==`string`&&typeof e.expiresAt==`string`&&typeof e.platformUrl==`string`&&typeof e.sessionFingerprint==`string`)return{key:e.key,expiresAt:e.expiresAt,platformUrl:e.platformUrl,sessionFingerprint:e.sessionFingerprint}}catch{}return null}function nn(e,t){try{He(en(e),JSON.stringify(t))}catch{}}async function rn(e,t,n){let r=`${e.replace(/\/+$/,``)}/auth/cli/hub-key`,i;try{i=await fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${t}`},body:JSON.stringify({device_id:n})})}catch(e){throw Error(`Could not reach ${r} to mint a Hub key: ${e instanceof Error?e.message:String(e)}`)}let a=await i.text(),o;try{o=JSON.parse(a)}catch{o=null}if(!i.ok||!o?.success){let e=typeof o?.error?.message==`string`?o.error.message:`HTTP ${i.status}`;throw Error(`Hub key minting failed: ${e}. Your sandbox session may have expired — run \`tangle auth login\`.`)}let s=o.data;if(typeof s?.api_key!=`string`||typeof s?.expires_at!=`string`||typeof s?.platform_url!=`string`)throw Error(`Hub key minting returned an unexpected response shape.`);return{key:s.api_key,expiresAt:s.expires_at,platformUrl:s.platform_url}}var an=class{cache;fingerprint;constructor(e,t,n,r){this.profile=e,this.sandboxBaseUrl=t,this.sessionToken=n,this.deviceId=r,this.fingerprint=$t(t,n);let i=tn(e);this.cache=i&&i.sessionFingerprint===this.fingerprint?i:null}isFresh(e){return e!==null&&Date.parse(e.expiresAt)-Date.now()>6e4}async ensure(e=!1){if(!e&&this.isFresh(this.cache))return this.cache;let t={...await rn(this.sandboxBaseUrl,this.sessionToken,this.deviceId),sessionFingerprint:this.fingerprint};return this.cache=t,nn(this.profile,t),t}};function on(e){if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function sn(e,t){if(e.baseUrl)return e.baseUrl;let n=xt(process.env.TANGLE_HUB_URL);if(n)return n;let r=tn(t);return r?r.platformUrl:`https://id.tangle.tools`}function cn(e,t){let n=T(),r=vt(e.apiKey,n),i=yt(e.apiKey,n),a=process.env.TANGLE_HUB_CAPABILITY_TOKEN?.trim()||void 0;if(a&&i===`env`)throw Error(`Set exactly one of TANGLE_API_KEY/SANDBOX_API_KEY or TANGLE_HUB_CAPABILITY_TOKEN, not both`);if(i===`flag`&&r)return{kind:`static`,apiKey:r,baseUrl:sn(e,n)};if(i===`env`&&r)return{kind:`static`,apiKey:a??r,baseUrl:sn(e,n)};if(a)return{kind:`static`,apiKey:a,baseUrl:sn(e,n)};if(!r)throw Error(`No API key found for profile '${n}'. Set TANGLE_API_KEY or run: tangle auth login${n===`default`?``:` --profile ${n}`}`);return t?{kind:`static`,apiKey:r,baseUrl:sn(e,n)}:{kind:`managed`,profile:n,sandboxBaseUrl:bt(void 0,n),sessionToken:r,deviceId:ft(),baseUrlOverride:e.baseUrl}}async function V(e={}){let t=cn(e,e.hubKey===!1||on(process.env.TANGLE_SKIP_HUB_KEY));if(t.kind===`static`)return new he({baseUrl:t.baseUrl,apiKey:t.apiKey});let n=new an(t.profile,t.sandboxBaseUrl,t.sessionToken,t.deviceId),r=await n.ensure();return new he({baseUrl:t.baseUrlOverride??r.platformUrl,authHeaders:async()=>({Authorization:`Bearer ${(await n.ensure()).key}`}),fetch:async(e,t)=>{let r=await fetch(e,t);if(r.status!==401)return r;let i=await n.ensure(!0),a=new Headers(t?.headers);return a.set(`Authorization`,`Bearer ${i.key}`),fetch(e,{...t,headers:a})}})}function ln(e){return e instanceof Date?e.toISOString():String(e)}function un(e,t){return`Sandbox name is ambiguous: ${e}. Use a sandbox id instead.\n${t.map(e=>`- ${e.id} (status: ${e.status}, created: ${ln(e.createdAt)})`).join(`
4
+ `)}`}function dn(e){return e.activeTeamId?`team:${e.activeTeamId}`:void 0}async function H(e,t,n){let r=await e.get(n);if(r||n.startsWith(`sandbox-`)){if(!r)throw Error(`Sandbox not found: ${n}`);return r}let i=(await e.list({scope:dn(t)})).filter(e=>e.name?.toLowerCase()===n.toLowerCase());if(i.length===0)throw Error(`Sandbox not found: ${n}`);if(i.length>1)throw Error(un(n,i));return i[0]}async function U(e,t){if(e.status!==`stopped`)return e;let n=t?.resumeTimeoutMs??12e4;P(`Sandbox ${e.id} is stopped. Resuming...`);try{await e.resume({timeoutMs:n}),await e.waitFor(`running`,{timeoutMs:n})}catch(t){let r=t instanceof Error?t.message:String(t);throw Error(`Failed to resume sandbox ${e.id}: ${r}. Run \`tangle sandbox resume ${e.id} --timeout ${n}\` and retry.`)}return e}const fn=[`anthropic`,`openai`,`vercel-ai`,`mastra`,`mcp-local`,`claude-desktop`,`cursor`,`zed`];function pn(e,t,n){switch(e){case`anthropic`:return`// pnpm add @anthropic-ai/sdk @tangle-network/sandbox
2
5
  import Anthropic from "@anthropic-ai/sdk";
3
6
  import { Sandbox } from "@tangle-network/sandbox";
4
7
  import { anthropicTools } from "@tangle-network/sandbox/agent";
@@ -118,20 +121,19 @@ await connect(new StdioServerTransport());`;case`claude-desktop`:return`// Add t
118
121
  }
119
122
  }
120
123
  }
121
- }`}}function Gt(e){return{anthropic:`Anthropic Messages API (Claude)`,openai:`OpenAI Chat Completions (function calling)`,"vercel-ai":`Vercel AI SDK (generateText / streamText)`,mastra:`Mastra agent framework`,"mcp-local":`Local MCP server bridge (stdio)`,"claude-desktop":`Claude Desktop config (uses local MCP)`,cursor:`Cursor config (uses local MCP)`,zed:`Zed config (uses local MCP)`}[e]}function Kt(){return new t(`connect`).description(`Print a copy-paste integration snippet for one of: ${Ut.join(`, `)}`).argument(`<framework>`,Ut.join(` | `)).option(`-i, --sandbox <id>`,`Sandbox ID to embed in the snippet`,`<SANDBOX_ID>`).option(`-s, --session <id>`,`Session ID to embed in the snippet`,`default`).action((e,t)=>{Ut.includes(e)||(console.error(i.red(`unknown framework: ${e}`),`\nsupported: ${Ut.join(`, `)}`),process.exit(2));let n=e;process.stdout.write(i.cyan(`# ${Gt(n)}\n\n`)),process.stdout.write(`${Wt(n,t.sandbox,t.session)}\n`)})}async function qt(e){let{Writable:t}=await import(`node:stream`),n=await import(`node:readline`),r=!1,i=new t({write(e,t,n){r||process.stdout.write(e,t),n()}}),a=n.createInterface({input:process.stdin,output:i,terminal:!0});return process.stdout.write(e),r=!0,await new Promise(e=>{a.question(``,t=>{r=!1,a.close(),process.stdout.write(`
122
- `),e(t.trim())})})}async function U(e){let t=(await import(`node:readline`)).createInterface({input:process.stdin,output:process.stdout}),n=await new Promise(n=>{t.question(e,e=>{t.close(),n(e.trim().toLowerCase())})});return n===`y`||n===`yes`}async function W(e,t){let n=(await import(`node:readline`)).createInterface({input:process.stdin,output:process.stdout}),r=t?` [${t}]`:``;return await new Promise(t=>{n.question(`${e}${r}: `,e=>{n.close(),t(e.trim())})})||t||``}async function Jt(){if(process.stdin.isTTY)throw Error(`Cannot read secret from stdin when stdin is a TTY`);let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString(`utf8`).replace(/\r?\n$/,``)}function Yt(){let e=new t(`profile`).description(`Create, inspect, and validate portable agent profiles`);return e.command(`create [output]`).description(`Create a profile — interactively (a wizard), or fully via flags`).option(`--name <name>`,`Profile name (when set, skips the wizard)`).option(`--description <text>`,`Profile description`).option(`--model <model>`,`Model (provider/model)`).option(`--system-prompt <text>`,`System prompt`).option(`--skills <ref...>`,`Skill refs: local path or github:<owner>/<repo>/<path>[@<ref>]`).option(`--tools <ref...>`,`Tool refs: local path or github:<owner>/<repo>/<path>[@<ref>]`).option(`--harness <name>`,`Harness hint shown in the run command`).option(`--json`,`Print the profile as JSON instead of writing a file`).action(async(e,t)=>{try{let n=t.name,r=t.description,i=t.harness,a=t.model,o=t.systemPrompt,s=t.skills??[],c=t.tools??[];if(!n&&process.stdin.isTTY&&(n=await W(`Profile name`,`my-agent`),r=await W(`Description (optional)`)||void 0,i=await W(`Harness`,`claude-code`)||void 0,a=await W(`Model (optional, provider/model)`)||void 0,o=await W(`System prompt (optional)`)||void 0,s=await Xt(`Skill ref (local path or github:..., blank to finish)`),c=await Xt(`Tool ref (blank to finish)`)),!n)throw Error(process.stdin.isTTY?`Profile name is required.`:"`agent profile create` needs at least --name in a non-interactive shell (no TTY to prompt). Pass --name <name> (and optionally --model/--skills/--tools/--system-prompt).");let l=Te({model:a,systemPrompt:o,skills:s,tools:c}),d={...n?{name:n}:{},...r?{description:r}:{},...l??{}};if(t.json){N(d);return}let f=e??`agent-profile.json`;u(f,`${JSON.stringify(d,null,2)}\n`),I(`Wrote ${f}`),I(`Run it: tangle agent prompt <box> --profile ${f}${i?` --harness ${i}`:``}`)}catch(e){H(e,t.json)}}),e.command(`show <source>`).description(`Load and print a profile (local path, https URL, or github:owner/repo/path[@ref])`).action(async e=>{try{N(await Ee(e))}catch(e){H(e,!0)}}),e.command(`validate <source>`).description(`Check a profile loads and is a well-formed object`).action(async e=>{try{let t=await Ee(e);I(`OK — "${typeof t.name==`string`?t.name:`(unnamed)`}" loaded as a valid profile object`)}catch(e){H(e)}}),e}async function Xt(e){let t=[];for(;;){let n=await W(e);if(!n)break;t.push(n)}return t}function Zt(e){let t=typeof e.type==`string`?e.type:void 0,n=t===`tool-invocation`||t===`tool_call`||t===`computer-use`||t===`computer_call`,r=e.toolInvocation??e.tool_invocation??e.computerUse??e.computer_use;if(!r&&!n)return;let i=r??e;if(t===`computer-use`||t===`computer_call`)return`computer-use:${i.action?.type??`action`}`;let a=i.toolName??i.tool_name??i.name;return typeof a==`string`&&a.length>0?a:void 0}function Qt(e){return([process.env.SANDBOX_WEB_URL,process.env.TANGLE_SANDBOX_WEB_URL].map(e=>e?.trim()).find(e=>!!e)??e).replace(/\/+$/,``)}function $t(e){let t=e.toolInvocation??e.tool_invocation??e.computerUse??e.computer_use??e,n=t.state?.status,r=typeof t.status==`string`?t.status:void 0;return n??r}function en(e,t){if(process.exitCode=1,e.status===`blocked_on_approval`){console.error(i.yellow(`⚠ Blocked on a hub approval.`));let t=e.approval?.approvalId;console.error(t?`Approve it: tangle hub approvals approve ${t}`:"Approve the pending request (`tangle hub approvals`), then re-run.");return}if(e.status===`awaiting_question`){console.error(i.yellow(`⚠ Agent is awaiting an answer to a question.`)),console.error(`Re-run with --interactive to answer it, or answer programmatically via box.session(<id>).answer({ ... }).`);return}console.error(i.red(`✗ ${e.error&&e.error.length>0?e.error:t}`))}function tn(e,t){return process.exitCode=1,t&&N({status:`awaiting_question`,needsInput:e}),`Agent is awaiting an answer (questionId: ${e.questionId??`unknown`}). Re-run with --interactive to answer, or answer via box.session(<id>).answer({ ... }).`}function nn(e){let t=e.part;if(t?.type===`text`)return t.text??t.content??void 0}function rn(e){return e.finalText??e.response??e.output??e.content??e.text??void 0}function an(e){if(typeof e==`string`)return e;try{return JSON.stringify(e)??``}catch{return String(e)}}function on(e,t=0){if(t>6||typeof e!=`object`||!e)return;let n=e,r=n.approval;if(r&&typeof r.id==`string`)return r.id;for(let e of Object.values(n)){let n=on(e,t+1);if(n)return n}}function sn(e){let t=e?.toolInvocations;if(!Array.isArray(t))return;let n=t.find(e=>e?.isError===!0);if(n){if(an(n.result).includes(`HUB_APPROVAL_REQUIRED`)){let e=on(n.result);return e?`Blocked on hub approval — approve with: tangle hub approvals approve ${e}`:"Blocked on hub approval — approve the pending request (`tangle hub approvals`) then re-run."}return`Tool "${n.toolName??`unknown`}" failed`}}function cn(e){if(e.sawError){console.error(i.red(`✗ ${e.errorMsg??`Agent run failed`}`)),process.exitCode=1;return}let t=Date.now()-e.startedAt,n=e.tokenUsage,r=[`${t}ms`,n?.inputTokens===void 0?void 0:`${n.inputTokens} in`,n?.outputTokens===void 0?void 0:`${n.outputTokens} out`].filter(e=>!!e);console.log(i.green(`✓ Done`),i.dim(`(${r.join(`, `)})`))}function ln(e,t){let n=Zt(e);if(!n)return;let r=$t(e),a=e.toolCallId??e.tool_call_id??e.callId??e.id,o=typeof a==`string`&&a.length>0?a:`${n}#${t.size}`;r===`running`||r===`in_progress`||r===void 0?t.has(o)||(t.add(o),console.log(i.dim(`\n[Tool: ${n}]`))):r===`completed`?console.log(i.dim(`[Tool ${n} completed]`)):(r===`failed`||r===`error`)&&console.log(i.yellow(`[Tool ${n} failed]`))}function un(e){let t=Ot(e??[]);if(t.length!==0)return{profile:{connections:t}}}function dn(){let e=new t(`agent`).description(`Interact with AI agent`);return e.command(`prompt <idOrMessage> [message]`).description("Send a single prompt to the agent. With one arg it's the prompt and the box comes from `tangle use` / --box / TANGLE_SANDBOX; with two it's <id> <message>.").option(`--box <id>`,`Target sandbox (overrides the active one)`).option(`--session <id>`,`Continue existing session`).option(`--model <model>`,`Model to use`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`,`300000`).option(`--stream`,`Stream response in real-time`).option(`--interactive`,`Spawn the harness's interactive TUI in the sandbox, inject this prompt, and print a link to watch + drive the live session in the browser (omit for the default headless run)`).option(`--harness <name>`,`Harness that executes this run (claude-code, codex, kimi-code, opencode, pi, amp, hermes). Defaults to the sandbox's configured backend. The box ships all harnesses, so this is a per-run choice.`).option(`--profile <source>`,`Agent profile to run: a local JSON path, an https URL, or github:<owner>/<repo>/<path>[@<ref>]`).option(`--skills <ref...>`,`Attach skills (repeatable): a local file path, or github:<owner>/<repo>/<path>[@<ref>] to pull from a repo`).option(`--tools <ref...>`,`Attach tools (repeatable): a local file path, or github:<owner>/<repo>/<path>[@<ref>]`).option(`--system-prompt <text>`,`Override the agent's system prompt for this run`).option(`--connection <spec>`,"Grant a hub connection to the agent as MCP tools: <connectionId>:<cap1>,<cap2> (repeatable). Ids: `tangle hub connections`. Paths: `tangle hub tools search <keyword>`.",Dt,[]).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let a=t===void 0?e:t,o=t===void 0?ut(n.box):e,s=O({apiKey:n.apiKey,baseUrl:n.baseUrl}),c=j(s);if(n.interactive){let e=[n.profile?`--profile`:null,n.skills?.length?`--skills`:null,n.tools?.length?`--tools`:null,n.systemPrompt?`--system-prompt`:null,n.connection?.length?`--connection`:null].filter(e=>e!==null);if(e.length>0)throw Error(`${e.join(`, `)} ${e.length===1?`is`:`are`} not supported with --interactive: the interactive harness launches its own TUI and is configured by --harness/--model. Drop --interactive to run with a profile, or bake the agent into the box with \`tangle backend configure\`.`)}let l=await Fe({profileSource:n.profile,systemPrompt:n.systemPrompt,skills:n.skills,tools:n.tools}),u=un(n.connection),d=l||u?{...l??{},...u?.profile??{}}:void 0,f=d||n.harness?{...n.harness?{type:n.harness}:{},...d?{profile:d}:{}}:void 0,p=await c.get(o);if(!p)throw Error(`Sandbox not found: ${o}`);if(n.interactive){let e=n.session??`int-${r()}`,t=n.harness??(await p.backend.status()).type,i=p.session(e).interactive(),c=L(`Starting interactive ${t} session...`);c.start();let l;try{l=await i.start({harness:t,...n.model?{model:n.model}:{}})}finally{c.stop()}try{await i.sendPrompt(a)}catch(e){throw await i.stop().catch(()=>void 0),e}let u=`${Qt(s.baseUrl)}/dashboard/sandbox/${encodeURIComponent(o)}?interactive=${encodeURIComponent(l.sessionId)}`;n.json?N({sessionId:l.sessionId,harness:l.harness,streamUrl:l.streamUrl,webUrl:u}):(I(`Interactive ${l.harness} session started — prompt sent.`),console.log(),R({"Watch & drive":u,Session:l.sessionId}),console.log(),I(`Open the link to watch the agent and type to take over. Send more prompts with --session ${l.sessionId} --interactive.`));return}if(n.stream){I(`Streaming response...`),console.log();let e=Date.now(),t=``,r=!1,o,s,c,l=e=>{if(e.startsWith(t)){let n=e.slice(t.length);n&&process.stdout.write(n)}else process.stdout.write(e);t=e};try{for await(let e of p.streamPrompt(a,{sessionId:n.session,model:n.model,timeoutMs:Number.parseInt(n.timeout,10),...f?{backend:f}:{}})){switch(e.type){case`token`:{let n=e.data?.value;typeof n==`string`&&(process.stdout.write(n),t+=n);break}case`message.part.updated`:{let t=nn(e.data);typeof t==`string`&&t.length>0&&l(t);break}case`result`:s=e.data;break;case`question`:{let t=e.data;c={questionId:t.questionId,questions:t.questions};break}case`error`:r=!0,o=e.data.message??JSON.stringify(e.data);break}if(c)break}}catch(e){r=!0,o=e instanceof Error?e.message:String(e)}if(c){t.length>0&&console.log();let e=tn(c,n.json);n.json||console.error(i.yellow(`⚠ ${e}`));return}if(t.length===0&&s){let e=rn(s);typeof e==`string`&&e.length>0&&(process.stdout.write(e),t=e)}if(!r){let e=sn(s);e&&(r=!0,o=e)}t.length>0&&console.log(),cn({sawError:r,errorMsg:o,startedAt:e,tokenUsage:s?.tokenUsage})}else{let e=L(`Processing prompt...`);e.start();let t=await p.prompt(a,{sessionId:n.session,model:n.model,timeoutMs:Number.parseInt(n.timeout,10),...f?{backend:f}:{}});e.stop(),n.json?(N(t),t.success===!1&&(process.exitCode=1)):t.success===!1?en(t,`Agent prompt failed`):(console.log(t.response),console.log(),R({Duration:`${t.durationMs}ms`,"Input Tokens":t.usage?.inputTokens,"Output Tokens":t.usage?.outputTokens}))}}catch(e){H(e,n.json)}}),e.command(`task <idOrPrompt> [prompt]`).description("Execute a multi-turn task. One arg = the task (box from `tangle use` / --box / TANGLE_SANDBOX); two = <id> <prompt>.").option(`--box <id>`,`Target sandbox (overrides the active one)`).option(`--session <id>`,`Continue existing session`).option(`--model <model>`,`Model to use`).option(`--max-turns <n>`,`Maximum turns`,`10`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`,`600000`).option(`--stream`,`Stream events in real-time`).option(`--connection <spec>`,"Grant a hub connection to the agent as MCP tools: <connectionId>:<cap1>,<cap2> (repeatable). Ids: `tangle hub connections`. Paths: `tangle hub tools search <keyword>`.",Dt,[]).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=t===void 0?e:t,a=t===void 0?ut(n.box):e,o=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),s=un(n.connection),c=await o.get(a);if(!c)throw Error(`Sandbox not found: ${a}`);if(n.stream){I(`Executing task...`),console.log();let e=new Set,t=Date.now(),a=``,o=!1,l,u,d,f=e=>{if(e.startsWith(a)){let t=e.slice(a.length);t&&process.stdout.write(t)}else process.stdout.write(e);a=e};try{for await(let t of c.streamTask(r,{sessionId:n.session,model:n.model,maxTurns:Number.parseInt(n.maxTurns,10),timeoutMs:Number.parseInt(n.timeout,10),...s?{backend:s}:{}})){switch(t.type){case`token`:{let e=t.data?.value;typeof e==`string`&&(process.stdout.write(e),a+=e);break}case`message.part.updated`:{let e=nn(t.data);typeof e==`string`&&e.length>0&&f(e);break}case`raw`:ln(t.data,e);break;case`result`:u=t.data;break;case`question`:{let e=t.data;d={questionId:e.questionId,questions:e.questions};break}case`error`:o=!0,l=t.data.message??JSON.stringify(t.data);break}if(d)break}}catch(e){o=!0,l=e instanceof Error?e.message:String(e)}if(d){a.length>0&&console.log();let e=tn(d,n.json);n.json||console.error(i.yellow(`⚠ ${e}`));return}if(a.length===0&&u){let e=rn(u);typeof e==`string`&&e.length>0&&(process.stdout.write(e),a=e)}if(!o){let e=sn(u);e&&(o=!0,l=e)}a.length>0&&console.log(),cn({sawError:o,errorMsg:l,startedAt:t,tokenUsage:u?.tokenUsage})}else{let e=L(`Executing task...`);e.start();let t=await c.task(r,{sessionId:n.session,model:n.model,maxTurns:Number.parseInt(n.maxTurns,10),timeoutMs:Number.parseInt(n.timeout,10),...s?{backend:s}:{}});e.stop(),n.json?(N(t),t.success===!1&&(process.exitCode=1)):t.success===!1?en(t,`Agent task failed`):(console.log(t.response),console.log(),R({"Session ID":t.sessionId,"Turns Used":t.turnsUsed,Duration:`${t.durationMs}ms`,"Input Tokens":t.usage?.inputTokens,"Output Tokens":t.usage?.outputTokens}))}}catch(e){H(e,n.json)}}),e.addCommand(Kt()),e.addCommand(Yt()),e}async function fn(e){let t=e.timeoutMs??1e4,n=e.baseUrl.replace(/\/$/,``),r=`${n}/v1/account/me`;try{let n=await fetch(r,{headers:{Accept:`application/json`,Authorization:`Bearer ${e.apiKey}`},signal:AbortSignal.timeout(t)});if(!n.ok){let e=await mn(n);throw n.status===401||n.status===403?new re(e||`Invalid API key`):n.status>=500?new g(e||`Sandbox API returned an unexpected error`,n.status):Error(e||`Credential validation failed with status ${n.status}`)}let i=await n.json();if(!i.success||!i.data)throw Error(`Sandbox API returned an invalid account response`);return{customerId:i.data.customer_id,email:i.data.email,name:i.data.name,tier:i.data.tier,createdAt:i.data.created_at}}catch(e){throw e instanceof re||e instanceof g||e instanceof oe?e:e instanceof Error&&e.name===`AbortError`?new oe(t,`Timed out validating credentials against ${n}`):e instanceof Error&&!(e instanceof TypeError)?e:new m(`Failed to reach ${n}`,pn(e))}}function pn(e){return e instanceof Error?e:void 0}async function mn(e){let t=await e.text();if(t)try{let e=JSON.parse(t);return e.error?.message??e.message??t}catch{return t}}function hn(e){if(!_n(e.hostHeader))return{kind:`host-mismatch`};let t;try{t=new URL(e.requestUrl??`/`,`http://127.0.0.1`)}catch{return{kind:`not-found`}}if(t.pathname!==`/callback`)return{kind:`not-found`};if(t.searchParams.get(`state`)!==e.expectedState)return{kind:`state-mismatch`};let n=t.searchParams.get(`error`);if(n)return{kind:`error`,reason:n};let r=t.searchParams.get(`grant_token`);return r?{kind:`ok`,token:r}:{kind:`missing-token`}}async function gn(e){let t=e.timeoutMs??12e4,r=e.baseUrl.replace(/\/$/,``),i=await import(`node:http`),a=n(32).toString(`hex`),o=null,s=null,c=new Promise((e,t)=>{o=e,s=t}),l=i.createServer((e,t)=>{try{let n=hn({hostHeader:e.headers.host,requestUrl:e.url,expectedState:a});switch(n.kind){case`host-mismatch`:t.writeHead(421,{"content-type":`text/plain; charset=utf-8`}),t.end(`Misdirected request`);return;case`not-found`:t.writeHead(404,{"content-type":`text/plain; charset=utf-8`}),t.end(`Not found`);return;case`state-mismatch`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Sn(`State mismatch — refusing login`)),s?.(Error(`Browser login state mismatch — refusing potentially hijacked callback`));return;case`error`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Sn(n.reason)),s?.(Error(`Browser login failed: ${n.reason}`));return;case`missing-token`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Sn(null)),s?.(Error(`Browser login did not return a grant token`));return;case`ok`:t.writeHead(200,{"content-type":`text/html; charset=utf-8`}),t.end(Sn(null)),o?.(n.token);return}}catch(e){s?.(e instanceof Error?e:Error(`Browser login callback failed`))}});await new Promise((e,t)=>{l.once(`error`,t),l.listen(0,`127.0.0.1`,()=>e())});try{let n=l.address();if(!n||typeof n==`string`)throw Error(`Failed to bind local callback server`);let i=new URL(`http://127.0.0.1:${n.port}/callback`);i.searchParams.set(`state`,a);let o=new URL(`${r}/auth/cli/login`);o.searchParams.set(`callback_url`,i.toString()),e.provider&&o.searchParams.set(`provider`,e.provider);let s=await bn(o.toString());e.onLoginUrl?.({loginUrl:o.toString(),browserOpened:s});let u=await yn({baseUrl:r,grantToken:await vn(c,t),timeoutMs:t});return{apiKey:u.apiKey,email:u.email,name:u.name,tier:u.tier}}finally{await new Promise((e,t)=>{l.close(n=>{if(n){t(n);return}e()})}).catch(()=>void 0)}}function _n(e){if(!e)return!1;let t=e.toLowerCase().match(/^(\[[^\]]+\]|[^:]+)(?::\d+)?$/);if(!t)return!1;let n=t[1];return n===`127.0.0.1`||n===`localhost`||n===`[::1]`}async function vn(e,t){return await new Promise((n,r)=>{let i=setTimeout(()=>{r(new oe(t,`Timed out waiting for browser login to complete`))},t);e.then(e=>{clearTimeout(i),n(e)},e=>{clearTimeout(i),r(e)})})}async function yn(e){let t=await fetch(`${e.baseUrl}/auth/cli/exchange`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify({grant_token:e.grantToken}),signal:AbortSignal.timeout(e.timeoutMs)}).catch(t=>{throw new m(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),n=await t.json().catch(()=>null);if(!t.ok||!n?.success||!n.data?.api_key)throw Error(n?.error?.message||`Failed to exchange browser login grant`);return{apiKey:n.data.api_key,email:n.data.email,name:n.data.name,tier:n.data.tier}}async function bn(e){let{spawn:t}=await import(`node:child_process`),n=process.platform===`darwin`?[`open`,e]:process.platform===`win32`?[`cmd`,`/c`,`start`,``,e]:[`xdg-open`,e];return await new Promise(e=>{let r=t(n[0],n.slice(1),{detached:!0,stdio:`ignore`});r.once(`error`,()=>e(!1)),r.once(`spawn`,()=>{r.unref(),e(!0)})})}function xn(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#39;`)}function Sn(e){return`<!doctype html>
124
+ }`}}function mn(e){return{anthropic:`Anthropic Messages API (Claude)`,openai:`OpenAI Chat Completions (function calling)`,"vercel-ai":`Vercel AI SDK (generateText / streamText)`,mastra:`Mastra agent framework`,"mcp-local":`Local MCP server bridge (stdio)`,"claude-desktop":`Claude Desktop config (uses local MCP)`,cursor:`Cursor config (uses local MCP)`,zed:`Zed config (uses local MCP)`}[e]}function hn(){return new t(`connect`).description(`Print a copy-paste integration snippet for one of: ${fn.join(`, `)}`).argument(`<framework>`,fn.join(` | `)).option(`-i, --sandbox <id>`,`Sandbox ID to embed in the snippet`,`<SANDBOX_ID>`).option(`-s, --session <id>`,`Session ID to embed in the snippet`,`default`).action((e,t)=>{fn.includes(e)||(console.error(a.red(`unknown framework: ${e}`),`\nsupported: ${fn.join(`, `)}`),process.exit(2));let n=e;process.stdout.write(a.cyan(`# ${mn(n)}\n\n`)),process.stdout.write(`${pn(n,t.sandbox,t.session)}\n`)})}async function gn(e){let{Writable:t}=await import(`node:stream`),n=await import(`node:readline`),r=!1,i=new t({write(e,t,n){r||process.stdout.write(e,t),n()}}),a=n.createInterface({input:process.stdin,output:i,terminal:!0});return process.stdout.write(e),r=!0,await new Promise(e=>{a.question(``,t=>{r=!1,a.close(),process.stdout.write(`
125
+ `),e(t.trim())})})}async function W(e){let t=(await import(`node:readline`)).createInterface({input:process.stdin,output:process.stdout}),n=await new Promise(n=>{t.question(e,e=>{t.close(),n(e.trim().toLowerCase())})});return n===`y`||n===`yes`}async function G(e,t){let n=(await import(`node:readline`)).createInterface({input:process.stdin,output:process.stdout}),r=t?` [${t}]`:``;return await new Promise(t=>{n.question(`${e}${r}: `,e=>{n.close(),t(e.trim())})})||t||``}async function _n(){if(process.stdin.isTTY)throw Error(`Cannot read secret from stdin when stdin is a TTY`);let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString(`utf8`).replace(/\r?\n$/,``)}function vn(){let e=new t(`profile`).description(`Create, inspect, and validate portable agent profiles`);return e.command(`create [output]`).description(`Create a profile — interactively (a wizard), or fully via flags`).option(`--name <name>`,`Profile name (when set, skips the wizard)`).option(`--description <text>`,`Profile description`).option(`--model <model>`,`Model (provider/model)`).option(`--system-prompt <text>`,`System prompt`).option(`--skills <ref...>`,`Skill refs: local path or github:<owner>/<repo>/<path>[@<ref>]`).option(`--tools <ref...>`,`Tool refs: local path or github:<owner>/<repo>/<path>[@<ref>]`).option(`--harness <name>`,`Harness hint shown in the run command`).option(`--json`,`Print the profile as JSON instead of writing a file`).action(async(e,t)=>{try{let n=t.name,r=t.description,i=t.harness,a=t.model,o=t.systemPrompt,s=t.skills??[],c=t.tools??[];if(!n&&process.stdin.isTTY&&(n=await G(`Profile name`,`my-agent`),r=await G(`Description (optional)`)||void 0,i=await G(`Harness`,`claude-code`)||void 0,a=await G(`Model (optional, provider/model)`)||void 0,o=await G(`System prompt (optional)`)||void 0,s=await yn(`Skill ref (local path or github:..., blank to finish)`),c=await yn(`Tool ref (blank to finish)`)),!n)throw Error(process.stdin.isTTY?`Profile name is required.`:"`agent profile create` needs at least --name in a non-interactive shell (no TTY to prompt). Pass --name <name> (and optionally --model/--skills/--tools/--system-prompt).");let l=Ee({model:a,systemPrompt:o,skills:s,tools:c}),u={...n?{name:n}:{},...r?{description:r}:{},...l??{}};if(t.json){j(u);return}let f=e??`agent-profile.json`;d(f,`${JSON.stringify(u,null,2)}\n`),P(`Wrote ${f}`),P(`Run it: tangle agent prompt <box> --profile ${f}${i?` --harness ${i}`:``}`)}catch(e){B(e,t.json)}}),e.command(`show <source>`).description(`Load and print a profile (local path, https URL, or github:owner/repo/path[@ref])`).action(async e=>{try{j(await De(e))}catch(e){B(e,!0)}}),e.command(`validate <source>`).description(`Check a profile loads and is a well-formed object`).action(async e=>{try{let t=await De(e);P(`OK — "${typeof t.name==`string`?t.name:`(unnamed)`}" loaded as a valid profile object`)}catch(e){B(e)}}),e}async function yn(e){let t=[];for(;;){let n=await G(e);if(!n)break;t.push(n)}return t}function bn(e){let t=typeof e.type==`string`?e.type:void 0,n=t===`tool-invocation`||t===`tool_call`||t===`computer-use`||t===`computer_call`,r=e.toolInvocation??e.tool_invocation??e.computerUse??e.computer_use;if(!r&&!n)return;let i=r??e;if(t===`computer-use`||t===`computer_call`)return`computer-use:${i.action?.type??`action`}`;let a=i.toolName??i.tool_name??i.name;return typeof a==`string`&&a.length>0?a:void 0}function xn(e){return([process.env.SANDBOX_WEB_URL,process.env.TANGLE_SANDBOX_WEB_URL].map(e=>e?.trim()).find(e=>!!e)??e).replace(/\/+$/,``)}function Sn(e){let t=e.toolInvocation??e.tool_invocation??e.computerUse??e.computer_use??e,n=t.state?.status,r=typeof t.status==`string`?t.status:void 0;return n??r}function Cn(e,t){if(process.exitCode=1,e.status===`blocked_on_approval`){console.error(a.yellow(`⚠ Blocked on a hub approval.`));let t=e.approval?.approvalId;console.error(t?`Approve it: tangle hub approvals approve ${t}`:"Approve the pending request (`tangle hub approvals`), then re-run.");return}if(e.status===`awaiting_question`){console.error(a.yellow(`⚠ Agent is awaiting an answer to a question.`)),console.error(`Re-run with --interactive to answer it, or answer programmatically via box.session(<id>).answer({ ... }).`);return}console.error(a.red(`✗ ${e.error&&e.error.length>0?e.error:t}`))}function wn(e,t){return process.exitCode=1,t&&j({status:`awaiting_question`,needsInput:e}),`Agent is awaiting an answer (questionId: ${e.questionId??`unknown`}). Re-run with --interactive to answer, or answer via box.session(<id>).answer({ ... }).`}function Tn(e){let t=e.part;if(t?.type===`text`)return t.text??t.content??void 0}function En(e){return e.finalText??e.response??e.output??e.content??e.text??void 0}function Dn(e){if(typeof e==`string`)return e;try{return JSON.stringify(e)??``}catch{return String(e)}}function On(e,t=0){if(t>6||typeof e!=`object`||!e)return;let n=e,r=n.approval;if(r&&typeof r.id==`string`)return r.id;for(let e of Object.values(n)){let n=On(e,t+1);if(n)return n}}function kn(e){let t=e?.toolInvocations;if(!Array.isArray(t))return;let n=t.find(e=>e?.isError===!0);if(n){if(Dn(n.result).includes(`HUB_APPROVAL_REQUIRED`)){let e=On(n.result);return e?`Blocked on hub approval — approve with: tangle hub approvals approve ${e}`:"Blocked on hub approval — approve the pending request (`tangle hub approvals`) then re-run."}return`Tool "${n.toolName??`unknown`}" failed`}}function An(e){if(e.sawError){console.error(a.red(`✗ ${e.errorMsg??`Agent run failed`}`)),process.exitCode=1;return}let t=Date.now()-e.startedAt,n=e.tokenUsage,r=[`${t}ms`,n?.inputTokens===void 0?void 0:`${n.inputTokens} in`,n?.outputTokens===void 0?void 0:`${n.outputTokens} out`].filter(e=>!!e);console.log(a.green(`✓ Done`),a.dim(`(${r.join(`, `)})`))}function jn(e,t){let n=bn(e);if(!n)return;let r=Sn(e),i=e.toolCallId??e.tool_call_id??e.callId??e.id,o=typeof i==`string`&&i.length>0?i:`${n}#${t.size}`;r===`running`||r===`in_progress`||r===void 0?t.has(o)||(t.add(o),console.log(a.dim(`\n[Tool: ${n}]`))):r===`completed`?console.log(a.dim(`[Tool ${n} completed]`)):(r===`failed`||r===`error`)&&console.log(a.yellow(`[Tool ${n} failed]`))}function Mn(e){let t=It(e??[]);if(t.length!==0)return{profile:{connections:t}}}async function Nn(e){let t=It(e.connection??[]);if(t.length===0)throw Error(`--allow-writes needs at least one --connection to grant writes for.`);if(t.some(e=>e.connectionId===`*`))throw Error("--allow-writes needs explicit --connection ids; the `*:*` wildcard can't be bulk-granted. Grant per connection, e.g. --connection conn_x:* --allow-writes.");let n=await V({hubKey:e.hubKey});for(let r of t){let t=await n.permissions.allowWrites(r.connectionId);e.json||P(`Allowed ${t.writeActions} write action${t.writeActions===1?``:`s`} for connection ${r.connectionId} (${t.granted} newly granted).`)}e.json||P(`Revert anytime: ${t.map(e=>`tangle hub permissions revert-writes --connection ${e.connectionId}`).join(` · `)}`)}async function Pn(e){!e.connection||e.connection.length===0||(e.connection=await Ft(e.connection,()=>V({hubKey:e.hubKey})))}function Fn(){let e=new t(`agent`).description(`Interact with AI agent`);return e.command(`prompt <idOrMessage> [message]`).description("Send a single prompt to the agent. With one arg it's the prompt and the box comes from `tangle use` / --box / TANGLE_SANDBOX; with two it's <id> <message>.").option(`--box <id>`,`Target sandbox (overrides the active one)`).option(`--session <id>`,`Continue existing session`).option(`--model <model>`,`Model to use`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`,`300000`).option(`--stream`,`Stream response in real-time`).option(`--interactive`,`Spawn the harness's interactive TUI in the sandbox, inject this prompt, and print a link to watch + drive the live session in the browser (omit for the default headless run)`).option(`--harness <name>`,`Harness that executes this run (claude-code, codex, kimi-code, opencode, pi, amp, hermes). Defaults to the sandbox's configured backend. The box ships all harnesses, so this is a per-run choice.`).option(`--profile <source>`,`Agent profile to run: a local JSON path, an https URL, or github:<owner>/<repo>/<path>[@<ref>]`).option(`--skills <ref...>`,`Attach skills (repeatable): a local file path, or github:<owner>/<repo>/<path>[@<ref>] to pull from a repo`).option(`--tools <ref...>`,`Attach tools (repeatable): a local file path, or github:<owner>/<repo>/<path>[@<ref>]`).option(`--system-prompt <text>`,`Override the agent's system prompt for this run`).option(`--connection <spec>`,"Grant a hub connection to the agent as MCP tools (repeatable). The connection is a connection id or a provider name. Modes: <connection>:<cap1>,<cap2> (least privilege, recommended), <connection>:* (all of one connection), or *:* (all connections). List connections with `tangle hub connections`; paths with `tangle hub tools search <keyword>`.",Pt,[]).option(`--allow-writes`,"Pre-approve every WRITE action of each granted --connection so the agent can write unattended (reads are already allowed; destructive actions still prompt). Revert with `tangle hub permissions revert-writes`.").option(`--no-hub-key`,`Do not auto-mint a platform Hub key for --allow-writes; use the stored credential as-is`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=t===void 0?e:t,o=t===void 0?pt(n.box):e,s=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),c=k(s);if(n.interactive){let e=[n.profile?`--profile`:null,n.skills?.length?`--skills`:null,n.tools?.length?`--tools`:null,n.systemPrompt?`--system-prompt`:null,n.connection?.length?`--connection`:null,n.allowWrites?`--allow-writes`:null].filter(e=>e!==null);if(e.length>0)throw Error(`${e.join(`, `)} ${e.length===1?`is`:`are`} not supported with --interactive: the interactive harness launches its own TUI and is configured by --harness/--model. Drop --interactive to run with a profile, or bake the agent into the box with \`tangle backend configure\`.`)}let l=await Ie({profileSource:n.profile,systemPrompt:n.systemPrompt,skills:n.skills,tools:n.tools});await Pn(n);let u=Mn(n.connection);n.allowWrites&&await Nn(n);let d=l||u?{...l??{},...u?.profile??{}}:void 0,f=d||n.harness?{...n.harness?{type:n.harness}:{},...d?{profile:d}:{}}:void 0,p=await H(c,s,o);if(p=await U(p),n.interactive){let e=n.session??`int-${i()}`,t=n.harness??(await p.backend.status()).type,a=p.session(e).interactive(),c=F(`Starting interactive ${t} session...`);c.start();let l;try{l=await a.start({harness:t,...n.model?{model:n.model}:{}})}finally{c.stop()}try{await a.sendPrompt(r)}catch(e){throw await a.stop().catch(()=>void 0),e}let u=`${xn(s.baseUrl)}/dashboard/sandbox/${encodeURIComponent(o)}?interactive=${encodeURIComponent(l.sessionId)}`;n.json?j({sessionId:l.sessionId,harness:l.harness,streamUrl:l.streamUrl,webUrl:u}):(P(`Interactive ${l.harness} session started — prompt sent.`),console.log(),I({"Watch & drive":u,Session:l.sessionId}),console.log(),P(`Open the link to watch the agent and type to take over. Send more prompts with --session ${l.sessionId} --interactive.`));return}if(n.stream){P(`Streaming response...`),console.log();let e=Date.now(),t=``,i=!1,o,s,c,l=e=>{if(e.startsWith(t)){let n=e.slice(t.length);n&&process.stdout.write(n)}else process.stdout.write(e);t=e};try{for await(let e of p.streamPrompt(r,{sessionId:n.session,model:n.model,timeoutMs:Number.parseInt(n.timeout,10),...f?{backend:f}:{}})){switch(e.type){case`token`:{let n=e.data?.value;typeof n==`string`&&(process.stdout.write(n),t+=n);break}case`message.part.updated`:{let t=Tn(e.data);typeof t==`string`&&t.length>0&&l(t);break}case`result`:s=e.data;break;case`question`:{let t=e.data;c={questionId:t.questionId,questions:t.questions};break}case`error`:i=!0,o=e.data.message??JSON.stringify(e.data);break}if(c)break}}catch(e){i=!0,o=e instanceof Error?e.message:String(e)}if(c){t.length>0&&console.log();let e=wn(c,n.json);n.json||console.error(a.yellow(`⚠ ${e}`));return}if(t.length===0&&s){let e=En(s);typeof e==`string`&&e.length>0&&(process.stdout.write(e),t=e)}if(!i){let e=kn(s);e&&(i=!0,o=e)}t.length>0&&console.log(),An({sawError:i,errorMsg:o,startedAt:e,tokenUsage:s?.tokenUsage})}else{let e=F(`Processing prompt...`);e.start();let t=await p.prompt(r,{sessionId:n.session,model:n.model,timeoutMs:Number.parseInt(n.timeout,10),...f?{backend:f}:{}});e.stop(),n.json?(j(t),t.success===!1&&(process.exitCode=1)):t.success===!1?Cn(t,`Agent prompt failed`):(console.log(t.response),console.log(),I({Duration:`${t.durationMs}ms`,"Input Tokens":t.usage?.inputTokens,"Output Tokens":t.usage?.outputTokens}))}}catch(e){B(e,n.json)}}),e.command(`task <idOrPrompt> [prompt]`).description("Execute a multi-turn task. One arg = the task (box from `tangle use` / --box / TANGLE_SANDBOX); two = <id> <prompt>.").option(`--box <id>`,`Target sandbox (overrides the active one)`).option(`--session <id>`,`Continue existing session`).option(`--model <model>`,`Model to use`).option(`--max-turns <n>`,`Maximum turns`,`10`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`,`600000`).option(`--stream`,`Stream events in real-time`).option(`--connection <spec>`,"Grant a hub connection to the agent as MCP tools (repeatable). The connection is a connection id or a provider name. Modes: <connection>:<cap1>,<cap2> (least privilege, recommended), <connection>:* (all of one connection), or *:* (all connections). List connections with `tangle hub connections`; paths with `tangle hub tools search <keyword>`.",Pt,[]).option(`--allow-writes`,"Pre-approve every WRITE action of each granted --connection so the agent can write unattended (reads are already allowed; destructive actions still prompt). Revert with `tangle hub permissions revert-writes`.").option(`--no-hub-key`,`Do not auto-mint a platform Hub key for --allow-writes; use the stored credential as-is`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=t===void 0?e:t,i=t===void 0?pt(n.box):e,o=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),s=k(o);await Pn(n);let c=Mn(n.connection);n.allowWrites&&await Nn(n);let l=await H(s,o,i);if(l=await U(l),n.stream){P(`Executing task...`),console.log();let e=new Set,t=Date.now(),i=``,o=!1,s,u,d,f=e=>{if(e.startsWith(i)){let t=e.slice(i.length);t&&process.stdout.write(t)}else process.stdout.write(e);i=e};try{for await(let t of l.streamTask(r,{sessionId:n.session,model:n.model,maxTurns:Number.parseInt(n.maxTurns,10),timeoutMs:Number.parseInt(n.timeout,10),...c?{backend:c}:{}})){switch(t.type){case`token`:{let e=t.data?.value;typeof e==`string`&&(process.stdout.write(e),i+=e);break}case`message.part.updated`:{let e=Tn(t.data);typeof e==`string`&&e.length>0&&f(e);break}case`raw`:jn(t.data,e);break;case`result`:u=t.data;break;case`question`:{let e=t.data;d={questionId:e.questionId,questions:e.questions};break}case`error`:o=!0,s=t.data.message??JSON.stringify(t.data);break}if(d)break}}catch(e){o=!0,s=e instanceof Error?e.message:String(e)}if(d){i.length>0&&console.log();let e=wn(d,n.json);n.json||console.error(a.yellow(`⚠ ${e}`));return}if(i.length===0&&u){let e=En(u);typeof e==`string`&&e.length>0&&(process.stdout.write(e),i=e)}if(!o){let e=kn(u);e&&(o=!0,s=e)}i.length>0&&console.log(),An({sawError:o,errorMsg:s,startedAt:t,tokenUsage:u?.tokenUsage})}else{let e=F(`Executing task...`);e.start();let t=await l.task(r,{sessionId:n.session,model:n.model,maxTurns:Number.parseInt(n.maxTurns,10),timeoutMs:Number.parseInt(n.timeout,10),...c?{backend:c}:{}});e.stop(),n.json?(j(t),t.success===!1&&(process.exitCode=1)):t.success===!1?Cn(t,`Agent task failed`):(console.log(t.response),console.log(),I({"Session ID":t.sessionId,"Turns Used":t.turnsUsed,Duration:`${t.durationMs}ms`,"Input Tokens":t.usage?.inputTokens,"Output Tokens":t.usage?.outputTokens}))}}catch(e){B(e,n.json)}}),e.addCommand(hn()),e.addCommand(vn()),e}async function In(e){let t=e.timeoutMs??1e4,n=e.baseUrl.replace(/\/$/,``),r=`${n}/v1/account/me`;try{let n=await fetch(r,{headers:{Accept:`application/json`,Authorization:`Bearer ${e.apiKey}`},signal:AbortSignal.timeout(t)});if(!n.ok){let e=await Rn(n);throw n.status===401||n.status===403?new ie(e||`Invalid API key`):n.status>=500?new _(e||`Sandbox API returned an unexpected error`,n.status):Error(e||`Credential validation failed with status ${n.status}`)}let i=await n.json();if(!i.success||!i.data)throw Error(`Sandbox API returned an invalid account response`);return{customerId:i.data.customer_id,email:i.data.email,name:i.data.name,tier:i.data.tier,createdAt:i.data.created_at}}catch(e){throw e instanceof ie||e instanceof _||e instanceof se?e:e instanceof Error&&e.name===`AbortError`?new se(t,`Timed out validating credentials against ${n}`):e instanceof Error&&!(e instanceof TypeError)?e:new m(`Failed to reach ${n}`,Ln(e))}}function Ln(e){return e instanceof Error?e:void 0}async function Rn(e){let t=await e.text();if(t)try{let e=JSON.parse(t);return e.error?.message??e.message??t}catch{return t}}function zn(e){if(!Vn(e.hostHeader))return{kind:`host-mismatch`};let t;try{t=new URL(e.requestUrl??`/`,`http://127.0.0.1`)}catch{return{kind:`not-found`}}if(t.pathname!==`/callback`)return{kind:`not-found`};if(t.searchParams.get(`state`)!==e.expectedState)return{kind:`state-mismatch`};let n=t.searchParams.get(`error`);if(n)return{kind:`error`,reason:n};let r=t.searchParams.get(`grant_token`);return r?{kind:`ok`,token:r}:{kind:`missing-token`}}async function Bn(e){let t=e.timeoutMs??12e4,n=e.baseUrl.replace(/\/$/,``),i=await import(`node:http`),a=r(32).toString(`hex`),o=null,s=null,c=new Promise((e,t)=>{o=e,s=t}),l=i.createServer((e,t)=>{try{let n=zn({hostHeader:e.headers.host,requestUrl:e.url,expectedState:a});switch(n.kind){case`host-mismatch`:t.writeHead(421,{"content-type":`text/plain; charset=utf-8`}),t.end(`Misdirected request`);return;case`not-found`:t.writeHead(404,{"content-type":`text/plain; charset=utf-8`}),t.end(`Not found`);return;case`state-mismatch`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Kn(`State mismatch — refusing login`)),s?.(Error(`Browser login state mismatch — refusing potentially hijacked callback`));return;case`error`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Kn(n.reason)),s?.(Error(`Browser login failed: ${n.reason}`));return;case`missing-token`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Kn(null)),s?.(Error(`Browser login did not return a grant token`));return;case`ok`:t.writeHead(200,{"content-type":`text/html; charset=utf-8`}),t.end(Kn(null)),o?.(n.token);return}}catch(e){s?.(e instanceof Error?e:Error(`Browser login callback failed`))}});await new Promise((e,t)=>{l.once(`error`,t),l.listen(0,`127.0.0.1`,()=>e())});try{let r=l.address();if(!r||typeof r==`string`)throw Error(`Failed to bind local callback server`);let i=new URL(`http://127.0.0.1:${r.port}/callback`);i.searchParams.set(`state`,a);let o=new URL(`${n}/auth/cli/login`);o.searchParams.set(`callback_url`,i.toString()),e.provider&&o.searchParams.set(`provider`,e.provider);let s=await Wn(o.toString());e.onLoginUrl?.({loginUrl:o.toString(),browserOpened:s});let u=await Un({baseUrl:n,grantToken:await Hn(c,t),timeoutMs:t});return{apiKey:u.apiKey,email:u.email,name:u.name,tier:u.tier}}finally{await new Promise((e,t)=>{l.close(n=>{if(n){t(n);return}e()})}).catch(()=>void 0)}}function Vn(e){if(!e)return!1;let t=e.toLowerCase().match(/^(\[[^\]]+\]|[^:]+)(?::\d+)?$/);if(!t)return!1;let n=t[1];return n===`127.0.0.1`||n===`localhost`||n===`[::1]`}async function Hn(e,t){return await new Promise((n,r)=>{let i=setTimeout(()=>{r(new se(t,`Timed out waiting for browser login to complete`))},t);e.then(e=>{clearTimeout(i),n(e)},e=>{clearTimeout(i),r(e)})})}async function Un(e){let t=await fetch(`${e.baseUrl}/auth/cli/exchange`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify({grant_token:e.grantToken}),signal:AbortSignal.timeout(e.timeoutMs)}).catch(t=>{throw new m(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),n=await t.json().catch(()=>null);if(!t.ok||!n?.success||!n.data?.api_key)throw Error(n?.error?.message||`Failed to exchange browser login grant`);return{apiKey:n.data.api_key,email:n.data.email,name:n.data.name,tier:n.data.tier}}async function Wn(e){let{spawn:t}=await import(`node:child_process`),n=process.platform===`darwin`?[`open`,e]:process.platform===`win32`?[`cmd`,`/c`,`start`,``,e]:[`xdg-open`,e];return await new Promise(e=>{let r=t(n[0],n.slice(1),{detached:!0,stdio:`ignore`});r.once(`error`,()=>e(!1)),r.once(`spawn`,()=>{r.unref(),e(!0)})})}function Gn(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#39;`)}function Kn(e){return`<!doctype html>
123
126
  <html lang="en">
124
127
  <head>
125
128
  <meta charset="utf-8" />
126
129
  <title>Sandbox CLI Login</title>
127
130
  </head>
128
131
  <body>
129
- <p>${e?`Sandbox CLI login failed: ${xn(e)}`:`Sandbox CLI login complete. You can close this window.`}</p>
132
+ <p>${e?`Sandbox CLI login failed: ${Gn(e)}`:`Sandbox CLI login complete. You can close this window.`}</p>
130
133
  </body>
131
- </html>`}const Cn=15*6e4;function wn(e){return Number.isFinite(e)&&e>0?e:Cn}async function Tn(e){let t=e.timeoutMs??Cn,n=Date.now(),r=await En({baseUrl:e.baseUrl,timeoutMs:t,provider:e.provider});for(e.onInstructions?.({userCode:r.user_code,verificationUrl:r.verification_uri,verificationUrlComplete:r.verification_uri_complete,expiresIn:r.expires_in,intervalSeconds:r.interval});;){if(Date.now()-n>t)throw new oe(t,`Timed out waiting for device authorization to complete`);let i=await Dn({baseUrl:e.baseUrl,deviceCode:r.device_code,timeoutMs:t});if(i.status===`approved`)return i.data;let a=i.intervalSeconds*1e3;await new Promise(e=>setTimeout(e,a))}}async function En(e){let t=wn(e.timeoutMs),n=await fetch(`${On(e.baseUrl)}/auth/cli/device/start`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify(e.provider?{provider:e.provider}:{}),signal:AbortSignal.timeout(t)}).catch(t=>{throw new m(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),r=await n.json().catch(()=>null);if(!n.ok||!r?.success||!r.data?.device_code)throw Error(r?.error?.message||`Failed to start device login`);return r.data}async function Dn(e){let t=wn(e.timeoutMs),n=await fetch(`${On(e.baseUrl)}/auth/cli/device/poll`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify({device_code:e.deviceCode}),signal:AbortSignal.timeout(t)}).catch(t=>{throw new m(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),r=await n.json().catch(()=>null);if(n.status===428&&r?.error?.code===`AUTHORIZATION_PENDING`)return{status:`pending`,intervalSeconds:typeof r.data?.interval==`number`&&r.data.interval>0?r.data.interval:5};if(!n.ok||!r?.success||!r.data?.api_key||!r.data.email)throw Error(r?.error?.message||`Failed to complete device authorization`);return{status:`approved`,data:{apiKey:r.data.api_key,email:r.data.email,name:r.data.name,tier:r.data.tier}}}function On(e){return e.replace(/\/$/,``)}function kn(){let e=new t(`auth`).description(`Manage authentication`);e.command(`login`).description(`Authenticate with browser login or an API key`).option(`--api-key <key>`,`API key`).option(`--no-browser`,`Use device-code login instead of opening a browser`).option(`--profile <name>`,`Profile name`).option(`--provider <provider>`,`Identity provider (github, google, microsoft)`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=e.apiKey,n=E(e.profile),r=Fn(e.provider),i=gt(e.baseUrl,n),a=e.browser!==!1;if(!t){if(a){let a=L(`Starting browser login...`);a.start();let o=await gn({baseUrl:i,provider:r,onLoginUrl:({loginUrl:e,browserOpened:t})=>{a.stop(),I(t?`Browser login opened.`:`Open this URL to continue browser login:`),console.log(e)}}).finally(()=>{a.stop()});t=o.apiKey,Mn({profile:n,apiKey:t,baseUrl:e.baseUrl?i:void 0}),Et(),P(`Authenticated`),R({Profile:n,Email:o.email,Tier:o.tier,"Base URL":i}),I(Nn);return}let o=L(`Starting device login...`);o.start();let s=await Tn({baseUrl:i,provider:r,onInstructions:({userCode:e,verificationUrl:t,verificationUrlComplete:n})=>{o.stop(),I(`Complete login in a browser on any device:`),R({"Verification URL":t,"Verification URL (prefilled)":n,"Device Code":e})}}).finally(()=>{o.stop()});t=s.apiKey,Mn({profile:n,apiKey:t,baseUrl:e.baseUrl?i:void 0}),Et(),P(`Authenticated`),R({Profile:n,Email:s.email,Tier:s.tier,"Base URL":i}),I(Nn);return}t||(F(`No API key provided.`),process.exit(1)),it(t)||(F(`Invalid API key format. Keys should start with 'sk_' or 'sk-tan-'.`),process.exit(1));let o=L(`Validating credentials...`);o.start();let s=await fn({apiKey:t,baseUrl:i});o.stop(),Mn({profile:n,apiKey:t,baseUrl:e.baseUrl?i:void 0}),Et(),P(`Authenticated`),R({Profile:n,Email:s.email,Tier:s.tier,"Base URL":i}),I(Nn)}catch(e){H(e)}}),e.command(`logout`).description(`Remove stored credentials`).option(`--profile <name>`,`Profile name`).action(e=>{try{let t=E(e.profile);mt(t),Et(),P(`Logged out successfully.`),I(`Credentials removed for profile '${t}'.`)}catch(e){H(e)}}),e.command(`status`).description(`Show current authentication status`).option(`--json`,`Output as JSON`).option(`--profile <name>`,`Profile name`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=E(e.profile),n=D(e.apiKey,t),r=gt(e.baseUrl,t),i=ht(e.apiKey,t);if(!n){if(e.json){N({authenticated:!1,reason:`missing_credentials`,profile:t,baseUrl:r,credentialSource:null});return}F(`Not authenticated`),I(`Run 'tangle auth login --profile ${t}' to authenticate.`),process.exit(1)}let a=e.json?null:L(`Checking credentials...`);a?.start();try{let o=await fn({apiKey:n,baseUrl:r});if(a?.stop(),e.json){N({authenticated:!0,profile:t,baseUrl:r,credentialSource:i,account:o});return}P(`Authenticated`),R({Profile:t,"API Key":An(n),"Base URL":r,Source:jn(i),Email:o.email,Tier:o.tier})}catch(o){a?.stop(),e.json&&(N({authenticated:!1,profile:t,baseUrl:r,credentialSource:i,error:o instanceof Error?o.message:String(o)}),process.exit(1)),o instanceof re?F(`Stored credentials are invalid.`):Nt(`Stored credentials found, but validation could not complete.`),R({Profile:t,"API Key":An(n),"Base URL":r,Source:jn(i),Error:o instanceof Error?o.message:String(o)}),process.exit(1)}}catch(e){H(e)}});let n=new t(`profiles`).description(`Manage CLI profiles`);return n.command(`list`).description(`List configured profiles`).option(`--json`,`Output as JSON`).action(e=>{try{let t=dt();if(e.json){N(t);return}if(t.length===0){I(`No profiles found.`);return}V([`Profile`,`Active`,`Base URL`,`Credentials`,`Source`],t.map(e=>[e.name,e.active?`yes`:`no`,e.baseUrl,e.hasApiKey?`configured`:`none`,e.apiKeySource]))}catch(e){H(e)}}),n.command(`use <name>`).description(`Set the active profile`).action(e=>{try{ot(e);let t=ft(e);P(`Active profile set to '${t.name}'.`),R({"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`})}catch(e){H(e)}}),n.command(`current`).description(`Show the active profile`).option(`--json`,`Output as JSON`).action(e=>{try{let t=ft();if(e.json){N(t);return}R({Profile:t.name,"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`,Source:jn(t.credentialSource)})}catch(e){H(e)}}),e.addCommand(n),e}function An(e){return e.length<=14?e:`${e.slice(0,10)}...${e.slice(-4)}`}function jn(e){switch(e){case`flag`:return`command flag`;case`env`:return`environment`;case`keychain`:return`OS keychain`;case`file`:return`credentials file`;case`legacy-file`:return`legacy credentials file`;default:return`unknown`}}function Mn(e){let t=pt(e.profile,{apiKey:e.apiKey,...e.baseUrl?{baseUrl:e.baseUrl}:{}});ot(e.profile),T({...e.baseUrl&&e.profile===`default`?{baseUrl:e.baseUrl}:{}}),Nn=Pn(e.profile,t)}let Nn=`Credentials updated.`;function Pn(e,t){return t===`keychain`?e===`default`?`API key saved to the OS keychain for the default profile`:`API key saved to the OS keychain for profile '${e}'`:t===`file`?e===`default`?`API key saved to ~/.tangle/credentials.json for the default profile`:`API key saved to ~/.tangle/credentials.json for profile '${e}'`:`Profile '${e}' updated.`}function Fn(e){if(e===void 0||e===`github`||e===`google`||e===`microsoft`)return e;throw Error(`--provider must be one of: github, google, microsoft`)}function In(){let e=new t(`backend`).description(`Manage sandbox AI agent backend`);return e.command(`status <sandboxId>`).description(`Get backend agent status`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching backend status...`);r.start();let i=await n.get(e);if(!i)throw r.stop(),Error(`Sandbox ${e} not found`);let a=await i.backend.status();r.stop(),t.json?N(a):(I(`Backend Type: ${a.type}`),I(`Status: ${a.status}`),a.version&&I(`Version: ${a.version}`),a.error&&I(`Error: ${a.error}`),a.metadata&&I(`Metadata: ${JSON.stringify(a.metadata,null,2)}`))}catch(e){H(e)}}),e.command(`capabilities <sandboxId>`).description(`Get backend capabilities`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching capabilities...`);r.start();let i=await n.get(e);if(!i)throw r.stop(),Error(`Sandbox ${e} not found`);let a=await i.backend.capabilities();r.stop(),t.json?N(a):(I(`Backend Capabilities:`),I(` Streaming: ${a.streaming?`✓`:`✗`}`),I(` Tool Use: ${a.toolUse?`✓`:`✗`}`),I(` Reasoning: ${a.reasoning?`✓`:`✗`}`),I(` Multimodal: ${a.multimodal?`✓`:`✗`}`),I(` Context Window: ${a.contextWindow.toLocaleString()} tokens`))}catch(e){H(e)}}),e.command(`configure <sandboxId>`).description(`Update backend configuration`).option(`--model <model>`,`Model string (format: provider/model)`).option(`--max-thinking-tokens <n>`,`Maximum thinking tokens`).option(`--profile <name>`,`Backend profile name`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Updating backend config...`);r.start();let i=await n.get(e);if(!i)throw r.stop(),Error(`Sandbox ${e} not found`);let a={};if(t.profile&&(a.profile=t.profile),t.model||t.maxThinkingTokens){if(a.model={},t.model){let e=t.model.split(`/`);e.length>=2?(a.model.provider=e[0],a.model.model=e.slice(1).join(`/`)):a.model.model=t.model}t.maxThinkingTokens&&(a.model.maxThinkingTokens=Number.parseInt(t.maxThinkingTokens,10))}await i.backend.updateConfig(a),r.stop(),P(`Backend configuration updated`),t.json&&N(a)}catch(e){H(e)}}),e.command(`add-mcp <sandboxId>`).description(`Add an MCP server to the backend`).requiredOption(`--name <name>`,`MCP server name`).requiredOption(`--command <cmd>`,`Command to run (e.g., npx)`).option(`--args <args...>`,`Command arguments`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`--cwd <dir>`,`Working directory`).option(`--url <url>`,`Remote MCP server URL (for SSE)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Adding MCP server...`);r.start();let i=await n.get(e);if(!i)throw r.stop(),Error(`Sandbox ${e} not found`);let a={};if(t.env)for(let e of t.env){let[t,...n]=e.split(`=`);t&&n.length>0&&(a[t]=n.join(`=`))}await i.backend.addMcp(t.name,{command:t.command,args:t.args,env:Object.keys(a).length>0?a:void 0,cwd:t.cwd,url:t.url}),r.stop(),P(`MCP server "${t.name}" added`),t.json&&N({name:t.name,command:t.command,args:t.args,env:Object.keys(a).length>0?a:void 0,cwd:t.cwd,url:t.url})}catch(e){H(e)}}),e.command(`mcp-status <sandboxId>`).description(`Get status of MCP servers`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching MCP status...`);r.start();let i=await n.get(e);if(!i)throw r.stop(),Error(`Sandbox ${e} not found`);let a=await i.backend.getMcpStatus();if(r.stop(),t.json)N(a);else{let e=Object.entries(a);e.length===0?I(`No MCP servers configured`):M(e.map(([e,t])=>{let n=t;return{name:e,status:n.status,error:n.error??``}}),[{key:`name`,header:`Name`,width:24},{key:`status`,header:`Status`,width:12},{key:`error`,header:`Error`,width:40}])}}catch(e){H(e)}}),e.command(`restart <sandboxId>`).description(`Restart the backend agent`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Restarting backend...`);r.start();let i=await n.get(e);if(!i)throw r.stop(),Error(`Sandbox ${e} not found`);await i.backend.restart(),r.stop(),P(`Backend restarted`)}catch(e){H(e)}}),e}function Ln(e){let t=e.indexOf(`=`);if(t<=0)throw Error(`Invalid --task "${e}": expected format id=message (e.g. t1=summarize README)`);let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();if(!n||!r)throw Error(`Invalid --task "${e}": id and message must be non-empty`);return{id:n,message:r}}function Rn(e){let t;try{t=JSON.parse(e)}catch(e){throw Error(`--tasks file is not valid JSON: ${e.message}`)}let n=Array.isArray(t)?t:t?.tasks;if(!Array.isArray(n))throw Error(`--tasks file must contain an array or an object with a "tasks" array`);return n.map((e,t)=>{if(!e||typeof e!=`object`)throw Error(`--tasks[${t}] must be an object`);let n=e,r=typeof n.id==`string`?n.id.trim():``,i=typeof n.message==`string`?n.message:``;if(!r)throw Error(`--tasks[${t}].id must be a non-empty string`);if(!i.trim())throw Error(`--tasks[${t}].message must be a non-empty string`);let a={id:r,message:i};return n.context&&typeof n.context==`object`&&(a.context=n.context),typeof n.timeoutMs==`number`&&n.timeoutMs>0&&(a.timeoutMs=n.timeoutMs),a})}function zn(e){let t=e.readFile??(e=>c(e,`utf8`)),n=[];e.file&&n.push(...Rn(t(e.file)));for(let t of e.inline??[])n.push(Ln(t));if(n.length===0)throw Error(`No tasks provided. Use --tasks <file> and/or --task id=message.`);let r=new Set;for(let e of n){if(r.has(e.id))throw Error(`Duplicate task id: ${e.id}`);r.add(e.id)}return n}function Bn(e){if(e!==`fastest`&&e!==`balanced`&&e!==`cheapest`)throw Error(`--scaling must be one of: fastest, balanced, cheapest (got "${e}")`);return e}function Vn(e){let t=e.trim(),n=t.indexOf(`/`);if(n<=0||n===t.length-1)throw Error(`--model must be in the form provider/model (got "${e}")`);return{provider:t.slice(0,n),model:t.slice(n+1)}}function Hn(){let e=new t(`batch`).description(`Run multiple agent tasks in parallel across sandboxes`);return e.command(`run`).description(`Execute a batch of tasks. Provide tasks via --tasks <file.json> and/or repeated --task id=message flags.`).option(`--tasks <file>`,`Path to a JSON file with an array of tasks (or {tasks: [...]})`).option(`--task <id=message>`,`Inline task, id=message. Repeatable.`,(e,t=[])=>[...t,e],[]).option(`--stream`,`Stream per-task events as they arrive`).option(`-t, --timeout <ms>`,`Total batch timeout in milliseconds`,`300000`).option(`--scaling <mode>`,`Scaling mode: fastest | balanced | cheapest`,`balanced`).option(`--persistent`,`Keep sandboxes alive after completion`,!1).option(`--model <provider/model>`,`Model override, e.g. anthropic/claude-sonnet-4-5-20250929`).option(`--profile <id>`,`Named execution profile to apply to every task`).option(`--json`,`Output the final result as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{let t=new AbortController,n=!1,r=()=>{n||(n=!0,I(`Cancel requested — stopping stream...`),t.abort())};process.on(`SIGINT`,r),process.on(`SIGTERM`,r);try{let n=zn({file:e.tasks,inline:e.task}),r=Bn(e.scaling),a=Number(e.timeout);if(!Number.isFinite(a)||a<=0)throw Error(`--timeout must be a positive number of milliseconds`);let o=j(O({apiKey:e.apiKey,baseUrl:e.baseUrl})),s={type:`opencode`};e.model&&(s.model=Vn(e.model)),e.profile&&(s.profile=String(e.profile));let c={timeoutMs:a,scalingMode:r,persistent:!!e.persistent,signal:t.signal,backend:s};if(e.stream){I(`Streaming batch of ${n.length} task(s)...`),console.log();let t=new Map;for await(let e of o.streamBatch(n,c)){let r=e.data,a=r.taskId??``;switch(e.type){case`batch.started`:I(`Batch started (${r.totalTasks??n.length} tasks)`);break;case`task.started`:a&&console.log(i.dim(`→ ${a} started`));break;case`task.retry`:a&&console.log(i.yellow(`↻ ${a} retry ${r.attempt??`?`}: ${r.error??`retrying`}`));break;case`task.completed`:if(a){let e=r.usage,n=(e?.inputTokens??0)+(e?.outputTokens??0);t.set(a,{success:!0,durationMs:r.durationMs,retries:r.retries,tokensUsed:r.tokensUsed??(n>0?n:void 0),response:r.resultSummary??r.response}),console.log(i.green(`✓ ${a} completed in ${r.durationMs??`?`}ms`+(r.retries?` (${r.retries} retries)`:``)))}break;case`task.failed`:a&&(t.set(a,{success:!1,durationMs:r.durationMs,retries:r.retries,error:r.error}),console.log(i.red(`✗ ${a} failed: ${r.error??`unknown error`}`)));break;case`batch.failed`:throw Error(r.error??`Batch failed`);case`batch.completed`:break}}let r=[...t.values()].filter(e=>e.success).length,a=[...t.values()].filter(e=>!e.success).length,s=[...t.values()].reduce((e,t)=>e+(t.retries??0),0);console.log(),e.json?N({totalTasks:n.length,succeeded:r,failed:a,totalRetries:s,successRate:n.length>0?r/n.length*100:0,results:Array.from(t.entries()).map(([e,t])=>({taskId:e,...t}))}):R({"Total tasks":n.length,Succeeded:r,Failed:a,"Total retries":s,"Success rate":n.length>0?`${(r/n.length*100).toFixed(1)}%`:`0%`}),a>0&&(process.exitCode=1)}else{I(`Running batch of ${n.length} task(s)...`);let t=await o.runBatch(n,c);if(e.json)N(t);else if(console.log(),R({"Total tasks":t.totalTasks,Succeeded:t.succeeded,Failed:t.failed,"Total retries":t.totalRetries,"Success rate":`${t.successRate.toFixed(1)}%`}),t.results.length>0){console.log(),console.log(i.bold(`Task Results`)),console.log(i.dim(`─`.repeat(40)));for(let e of t.results){let t=e.success?i.green(`✓`):i.red(`✗`),n=typeof e.tokensUsed==`number`?` • ${e.tokensUsed} tokens`:``;console.log(`${t} ${e.taskId} ${i.dim(`(${e.durationMs}ms, ${e.retries} retries${n})`)}`),e.error&&console.log(i.red(` ${e.error}`))}}t.failed>0&&(process.exitCode=1)}}catch(e){if(n){console.log(),I(`Batch cancelled.`),process.exitCode=130;return}H(e)}finally{process.off(`SIGINT`,r),process.off(`SIGTERM`,r)}}),e}function Un(){let e=new t(`checkpoint`).description(`Manage sandbox filesystem checkpoints`);return e.command(`create`).description(`Create a checkpoint of the current sandbox state`).argument(`<id>`,`Sandbox ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Creating checkpoint...`);t.json||r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let a=await i.checkpoint();r.stop(),t.json?N(a):P(`Checkpoint created: ${a.checkpointId}`)}catch(e){H(e)}}),e.command(`list`).alias(`ls`).description(`List checkpoints for a sandbox`).argument(`<id>`,`Sandbox ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching checkpoints...`);t.json||r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let a=await i.listCheckpoints();r.stop(),t.json?N(a):a.length===0?console.log(`No checkpoints found`):V([`ID`,`Created`],a.map(e=>[e.checkpointId,e.createdAt.toLocaleString()]))}catch(e){H(e)}}),e.command(`delete`).alias(`rm`).description(`Delete a checkpoint`).argument(`<id>`,`Sandbox ID`).argument(`<checkpoint-id>`,`Checkpoint ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Deleting checkpoint...`);n.json||i.start();let a=await r.get(e);if(!a)throw Error(`Sandbox not found: ${e}`);await a.deleteCheckpoint(t),i.stop(),n.json?N({success:!0,deleted:t}):P(`Checkpoint deleted: ${t}`)}catch(e){H(e)}}),e}function Wn(){let e=new t(`environments`).alias(`env`).description(`Manage sandbox environments`);return e.command(`list`).alias(`ls`).description(`List available environments`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=j(O({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=L(`Fetching environments...`);e.json||n.start();let r=await t.environments.list();n.stop(),e.json?N(r):r.length===0?console.log(`No environments found`):V([`ID`,`Description`,`Version`],r.map(e=>[e.id,e.description??``,e.version]))}catch(e){H(e)}}),e.command(`get`).description(`Get environment details`).argument(`<id>`,`Environment ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching environment...`);t.json||r.start();let i=await n.environments.get(e);if(r.stop(),!i){console.error(`Environment not found: ${e}`),process.exit(1);return}t.json?N(i):(console.log(`ID: ${i.id}`),console.log(`Description: ${i.description??`-`}`),console.log(`Version: ${i.version}`),i.base&&console.log(`Base: ${i.base}`))}catch(e){H(e)}}),e}function Gn(){return new t(`exec`).description(`Execute a command in a sandbox`).argument(`<id>`,`Sandbox ID`).argument(`<command...>`,`Command to execute`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`,`60000`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=t.join(` `),a={};if(n.env)for(let e of n.env){let[t,...n]=e.split(`=`);t&&n.length>0&&(a[t]=n.join(`=`))}let o=L(`Executing: ${i}`);n.json||o.start();let s=await r.get(e);if(!s)throw Error(`Sandbox not found: ${e}`);let c=await s.exec(i,{cwd:n.cwd,env:Object.keys(a).length>0?a:void 0,timeoutMs:Number.parseInt(n.timeout,10)});o.stop(),n.json?N(c):(c.stdout&&process.stdout.write(c.stdout),c.stderr&&process.stderr.write(c.stderr),c.exitCode!==0&&process.exit(c.exitCode))}catch(e){if(e instanceof m){let t=`Exec transport lost before command status was confirmed. Remote command status is unknown. Original error: ${e.message}. For long-running commands, use \`tangle process spawn\`, \`tangle process logs\`, and \`tangle process kill --tree\`.`;return H(Error(t,{cause:e}))}H(e)}})}const Kn=[`list`,`create`,`delete`,`exec`,`prompt`,`read`,`write`];function qn(){let e=new t(`fleet`).description(`Manage sandbox fleets`);return e.command(`create`).description(`Create a sandbox fleet`).option(`--fleet-id <id>`,`Stable fleet id (generated when omitted)`).option(`--count <n>`,`Number of worker machines`,`1`).option(`--image <env>`,`Environment/image for each machine`).option(`--cpu <cores>`,`CPU cores per machine`).option(`--memory <mb>`,`Memory in MB per machine`).option(`--disk <gb>`,`Disk in GB per machine`).option(`--driver <type>`,`Infrastructure driver type`).option(`--backend <id>`,`Agent backend type`).option(`--workspace <mode>`,`Workspace mode: isolated | shared`,`isolated`).option(`--max-spend-usd <n>`,`Fleet spend cap in USD (policy)`).option(`--max-lifetime <s>`,`Max machine lifetime in seconds (policy)`).option(`--spec <file.json>`,`Path to a JSON file describing the fleet (overrides synthesized machines)`).option(`--coordinator`,`Create a coordinator + workers fleet (routes to createWithCoordinator)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=j(O({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=L(`Creating fleet...`);n.start();let r=e.coordinator?await t.fleets.createWithCoordinator(Zn(e)):await t.fleets.create(Xn(e));n.stop();let i=er(r.machines);e.json?N({fleetId:r.fleetId,machines:i}):(P(`Fleet created: ${r.fleetId}`),M(i,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}]))}catch(e){H(e)}}),e.command(`list <fleet-id>`).description(`List the machines of one fleet (fleet id is required)`).option(`--status <status>`,`Filter machines by status`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching fleet...`);r.start();let i=await n.fleets.list({fleetId:e,status:t.status});r.stop();let a=er(i.machines);t.json?N({fleetId:i.fleetId,machines:a}):M(a,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}])}catch(e){H(e)}}),e.command(`get <fleet-id>`).description(`Show one fleet's manifest (server record)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching manifest...`);r.start();let i=await n.fleets.manifest(e);r.stop(),t.json?N(i):(R({"Fleet ID":i.fleetId??i.id,Machines:i.machines.length,"Workspace mode":i.workspace?.mode,"Workspace status":i.workspace?.status,"Max lifetime (s)":i.policy?.maxLifetimeSeconds,"Max spend (USD)":i.policy?.maxSpendUsd,Created:i.createdAt,Updated:i.updatedAt}),M(i.machines.map(e=>({machineId:e.machineId,sandboxId:e.sandboxId,role:e.role,status:e.status})),[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`role`,header:`Role`,width:14},{key:`status`,header:`Status`,width:14}]))}catch(e){H(e)}}),e.command(`delete <fleet-id>`).description(`Delete a fleet's machine sandboxes and its record`).option(`--continue-on-error`,`Keep deleting remaining machines if one delete fails`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Deleting fleet...`);r.start(),await n.fleets.delete(e,{continueOnError:t.continueOnError}),r.stop(),t.json?N({success:!0,fleetId:e}):P(`Fleet deleted: ${e}`)}catch(e){H(e)}}),e.command(`reap`).description(`TTL cleanup of all expired fleets (fleet-wide)`).option(`--dry-run`,`Report what would be reaped without deleting`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=j(O({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=L(`Reaping expired fleets...`);n.start();let r=await t.fleets.reapExpired({dryRun:e.dryRun});n.stop(),e.json?N(r):(R({"Dry run":r.dryRun,Expired:r.expired,Deleted:r.deleted}),M(r.fleets.map(e=>({fleetId:e.fleetId,expiredAt:e.expiredAt,deleted:e.deleted})),[{key:`fleetId`,header:`Fleet`,width:24},{key:`expiredAt`,header:`Expired`,width:18},{key:`deleted`,header:`Deleted`,width:10}]))}catch(e){H(e)}}),e.command(`reconcile`).description(`Drop fleet records whose underlying sandboxes vanished`).option(`--dry-run`,`Report orphans without removing them`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=j(O({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=L(`Reconciling fleets...`);n.start();let r=await t.fleets.reconcile({dryRun:e.dryRun});n.stop(),e.json?N(r):(R({"Dry run":r.dryRun,Checked:r.checked,Orphaned:r.orphaned,Removed:r.removed}),M(r.machines.map(e=>({fleetId:e.fleetId,machineId:e.machineId,sandboxId:e.sandboxId,removed:e.removed})),[{key:`fleetId`,header:`Fleet`,width:24},{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`removed`,header:`Removed`,width:10}]))}catch(e){H(e)}}),e.addCommand(Jn()),e.command(`exec <fleet-id> <command>`).description(`Run a shell command across the fleet's machines`).option(`--machine <id...>`,`Restrict to a subset of machine ids (default: all)`).option(`--cwd <dir>`,`Working directory for the command`).option(`--timeout <ms>`,`Per-machine timeout in milliseconds`).option(`--max-concurrent <n>`,`Max concurrent dispatches`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Dispatching command...`);i.start();let a=await(await r.fleets.list({fleetId:e})).dispatchExecDetailed(t,{machines:n.machine,cwd:n.cwd,timeoutMs:n.timeout?Number(n.timeout):void 0,maxConcurrent:n.maxConcurrent?Number(n.maxConcurrent):void 0});if(i.stop(),n.json)N(a);else{M(a.results.map(e=>({machineId:e.machineId,ok:e.ok,exitCode:e.result?.exitCode,durationMs:e.durationMs})),[{key:`machineId`,header:`Machine`,width:20},{key:`ok`,header:`OK`,width:6},{key:`exitCode`,header:`Exit`,width:8},{key:`durationMs`,header:`Duration(ms)`,width:14}]);for(let e of a.results){let t=e.result?.stdout,n=e.result?.stderr;t&&(console.log(`\n[${e.machineId}] stdout:`),console.log(t)),n&&(console.log(`\n[${e.machineId}] stderr:`),console.log(n)),e.error&&console.log(`\n[${e.machineId}] error: ${e.error.message}`)}}a.results.some(e=>e.ok===!1)&&(process.exitCode=1)}catch(e){H(e)}}),e.command(`capabilities`).description(`List fleet drivers and their supported features`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=j(O({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=L(`Fetching capabilities...`);n.start();let r=await t.fleets.capabilities();n.stop(),e.json?N(r):M(r.drivers.map(e=>({driverType:e.driverType,sharedWorkspace:e.sharedWorkspace,accelerators:e.accelerators,queueTimings:e.queueTimings})),[{key:`driverType`,header:`Driver`,width:16},{key:`sharedWorkspace`,header:`Shared WS`,width:12},{key:`accelerators`,header:`Accel`,width:8},{key:`queueTimings`,header:`Queue`,width:8}])}catch(e){H(e)}}),e.command(`usage <fleet-id>`).description(`Show fleet usage and reliability insights`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching usage...`);r.start();let i=await n.fleets.usage(e);if(r.stop(),t.json)N(i);else if(R({"Fleet ID":i.usage.fleetId,Status:i.usage.status,Machines:i.usage.machineCount,Running:i.usage.runningMachines,Failed:i.usage.failedMachines,"Runtime (ms)":i.usage.meteredUsage?.runtimeMs,"Reliability score":i.insights.reliabilityScore,"Failure rate":i.insights.failureRate}),i.insights.recommendedActions.length>0){console.log(`
132
- Recommended actions:`);for(let e of i.insights.recommendedActions)console.log(` - ${e}`)}}catch(e){H(e)}}),e.command(`cost <fleet-id>`).description(`Show the fleet's cost estimate`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Estimating cost...`);r.start();let i=await n.fleets.cost(e);r.stop(),t.json?N(i):R({Plan:i.plan,Currency:i.currency,"Hourly (USD)":i.hourlyUsd,"Max lifetime (s)":i.maxLifetimeSeconds,"Estimated max lifetime (USD)":i.estimatedMaxLifetimeUsd,Machines:i.requestedResources.machines,"Total CPU":i.requestedResources.totalCpu,"Total memory (MB)":i.requestedResources.totalMemoryMb})}catch(e){H(e)}}),e.command(`token <fleet-id>`).description(`Mint a scoped fleet bearer token (treated as a secret)`).option(`--action <a...>`,`Allowed actions: list create delete exec prompt read write`).option(`--ttl-minutes <n>`,`Token lifetime in minutes`).option(`--json`,`Output as JSON (only path that prints the full token)`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Minting fleet token...`);r.start();let i=await n.fleets.createToken(e,{actions:tr(t.action),ttlMinutes:t.ttlMinutes?Number(t.ttlMinutes):void 0});r.stop(),t.json?N(i):(R({"Fleet ID":i.fleetId,Token:nr(i.token),"Expires at":new Date(i.expiresAt).toISOString(),Actions:i.actions.join(`, `)}),console.log(`
133
- Re-run with --json to print the full token value.`))}catch(e){H(e)}}),e}function Jn(){let e=new t(`workspace`).description(`Manage a fleet's shared workspace`);return e.command(`snapshot <fleet-id>`).description(`Snapshot the fleet's shared workspace`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Creating workspace snapshot...`);r.start();let i=await n.fleets.createWorkspaceSnapshot(e);r.stop(),t.json?N(i):P(`Workspace snapshot created: ${i.snapshotId??i.id}`)}catch(e){H(e)}}),e.command(`restore <fleet-id> <snapshot-id>`).description(`Restore the fleet's shared workspace from a snapshot`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Restoring workspace...`);i.start();let a=await r.fleets.restoreWorkspaceSnapshot(e,t);i.stop(),n.json?N(a):P(`Workspace restored from ${a.snapshotId??t}`)}catch(e){H(e)}}),e.command(`reconcile <fleet-id>`).description(`Re-mount the shared workspace on all fleet machines`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Reconciling workspace...`);r.start();let i=await n.fleets.reconcileWorkspace(e);r.stop(),t.json?N(i):(R({"Fleet ID":i.fleetId,Checked:i.checked,"Orphaned mounts":i.orphanedMounts}),M(i.machines.map(e=>({machineId:e.machineId,sandboxId:e.sandboxId,mounted:e.mounted})),[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`mounted`,header:`Mounted`,width:10}]))}catch(e){H(e)}}),e}function Yn(e){if(e.spec){let t=JSON.parse(c(e.spec,`utf8`));return{base:{fleetId:e.fleetId,defaults:t.defaults,policy:t.policy,workspace:t.workspace,metadata:t.metadata},machines:t.machines??[]}}let t=Qn(e),n={...e.image?{environment:e.image}:{},...t?{resources:t}:{},...e.driver?{driver:{type:e.driver}}:{},...e.backend?{backend:{type:e.backend}}:{}},r=$n(e),i=Math.max(1,Number(e.count)||1),a=Array.from({length:i},(e,t)=>({machineId:`worker-${t+1}`}));return{base:{fleetId:e.fleetId,defaults:Object.keys(n).length>0?n:void 0,policy:r,workspace:{mode:e.workspace}},machines:a}}function Xn(e){let{base:t,machines:n}=Yn(e);return{...t,machines:n}}function Zn(e){let{base:t,machines:n}=Yn(e);return{...t,workers:n}}function Qn(e){let t={};return e.cpu&&(t.cpuCores=Number(e.cpu)),e.memory&&(t.memoryMB=Number(e.memory)),e.disk&&(t.diskGB=Number(e.disk)),Object.keys(t).length>0?t:void 0}function $n(e){let t={};return e.maxSpendUsd&&(t.maxSpendUsd=Number(e.maxSpendUsd)),e.maxLifetime&&(t.maxLifetimeSeconds=Number(e.maxLifetime)),Object.keys(t).length>0?t:void 0}function er(e){return[...e.entries()].map(([e,t])=>({machineId:e,sandboxId:t.id,status:t.status}))}function tr(e){if(!(!e||e.length===0)){for(let t of e)if(!Kn.includes(t))throw Error(`Invalid token action '${t}'. Allowed: ${Kn.join(`, `)}`);return e}}function nr(e){return e.length<=12?`****`:`${e.slice(0,6)}...${e.slice(-4)} (masked — use --json for full value)`}function rr(){let e=new t(`fs`).description(`File system operations on sandboxes`);return G(e.command(`upload`).description(`Upload a file to a sandbox`).argument(`<sandbox-id>`,`Sandbox ID`).argument(`<local-path>`,`Local file path`).argument(`<remote-path>`,`Remote destination path`).option(`--json`,`Output as JSON`)).action(async(e,t,n,r)=>{try{let i=await K(r).get(e);if(!i)throw Error(`Sandbox not found: ${e}`);if(!a.existsSync(t))throw Error(`Local file not found: ${t}`);let o=a.statSync(t),s=Date.now();console.log(`Uploading ${t} to ${n}...`),await i.fs.upload(t,n,{onProgress:e=>{let t=e.percentage.toFixed(1);process.stdout.write(`\rProgress: ${t}% (${e.bytesUploaded}/${e.totalBytes} bytes)`)}});let c=Date.now()-s;console.log(``),r.json?B({success:!0,localPath:t,remotePath:n,size:o.size,durationMs:c}):console.log(`✓ Uploaded ${o.size} bytes in ${c}ms`)}catch(e){z(e,r.json)}}),G(e.command(`download`).description(`Download a file from a sandbox`).argument(`<sandbox-id>`,`Sandbox ID`).argument(`<remote-path>`,`Remote file path`).argument(`<local-path>`,`Local destination path`).option(`--json`,`Output as JSON`)).action(async(e,t,n,r)=>{try{let i=await K(r).get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let o=Date.now();console.log(`Downloading ${t} to ${n}...`),await i.fs.download(t,n,{onProgress:e=>{let t=e.percentage.toFixed(1);process.stdout.write(`\rProgress: ${t}% (${e.bytesDownloaded}/${e.totalBytes} bytes)`)}});let s=Date.now()-o,c=a.statSync(n);console.log(``),r.json?B({success:!0,remotePath:t,localPath:n,size:c.size,durationMs:s}):console.log(`✓ Downloaded ${c.size} bytes in ${s}ms`)}catch(e){z(e,r.json)}}),G(e.command(`ls`).description(`List directory contents`).argument(`<sandbox-id>`,`Sandbox ID`).argument(`[path]`,`Directory path`,`.`).option(`-l, --long`,`Show detailed information`).option(`-a, --all`,`Include hidden files`).option(`--json`,`Output as JSON`)).action(async(e,t,n)=>{try{let r=await K(n).get(e);if(!r)throw Error(`Sandbox not found: ${e}`);let i=await r.fs.list(t.startsWith(`/`)?t:`/${t}`,{all:n.all,long:n.long});if(n.json)B(i);else if(n.long)V([`Mode`,`Owner`,`Group`,`Size`,`Modified`,`Name`],i.map(e=>{let t=e.isDir?`d`:e.isSymlink?`l`:`-`,n=ir(e.permissions),r=e.isDir?`<DIR>`:ar(e.size),i=e.modTime.toLocaleDateString();return[t+n,e.owner,e.group,r,i,e.name]}));else{let e=i.map(e=>e.isDir?`${e.name}/`:e.name);console.log(e.join(` `))}}catch(e){z(e,n.json)}}),G(e.command(`stat`).description(`Get file or directory information`).argument(`<sandbox-id>`,`Sandbox ID`).argument(`<path>`,`Path to file or directory`).option(`--json`,`Output as JSON`)).action(async(e,t,n)=>{try{let r=await K(n).get(e);if(!r)throw Error(`Sandbox not found: ${e}`);let i=await r.fs.stat(t.startsWith(`/`)?t:`/${t}`);n.json?B(i):(console.log(` File: ${i.name}`),console.log(` Path: ${i.path}`),console.log(` Size: ${ar(i.size)} (${i.size} bytes)`),console.log(` Type: ${i.isDir?`directory`:i.isSymlink?`symlink`:`file`}`),console.log(` Mode: ${ir(i.permissions)} (${i.permissions.toString(8)})`),console.log(` Owner: ${i.owner}`),console.log(` Group: ${i.group}`),console.log(` Modified: ${i.modTime.toISOString()}`),console.log(` Accessed: ${i.accessTime.toISOString()}`))}catch(e){z(e,n.json)}}),G(e.command(`cat`).description(`Print file contents`).argument(`<sandbox-id>`,`Sandbox ID`).argument(`<path>`,`Path to file`).option(`--json`,`Output as JSON`)).action(async(e,t,n)=>{try{let r=await K(n).get(e);if(!r)throw Error(`Sandbox not found: ${e}`);let i=await r.read(t.startsWith(`/`)?t:`/${t}`);n.json?B({path:t,content:i}):console.log(i)}catch(e){z(e,n.json)}}),G(e.command(`rm`).description(`Delete a file or directory`).argument(`<sandbox-id>`,`Sandbox ID`).argument(`<path>`,`Path to delete`).option(`-r, --recursive`,`Delete directories recursively`).option(`--json`,`Output as JSON`)).action(async(e,t,n)=>{try{let r=await K(n).get(e);if(!r)throw Error(`Sandbox not found: ${e}`);await r.fs.delete(t.startsWith(`/`)?t:`/${t}`,{recursive:n.recursive}),n.json?B({success:!0,path:t,deleted:!0}):console.log(`✓ Deleted: ${t}`)}catch(e){z(e,n.json)}}),G(e.command(`mkdir`).description(`Create a directory`).argument(`<sandbox-id>`,`Sandbox ID`).argument(`<path>`,`Directory path to create`).option(`-p, --parents`,`Create parent directories as needed`).option(`--json`,`Output as JSON`)).action(async(e,t,n)=>{try{let r=await K(n).get(e);if(!r)throw Error(`Sandbox not found: ${e}`);await r.fs.mkdir(t.startsWith(`/`)?t:`/${t}`,{recursive:n.parents}),n.json?B({success:!0,path:t,created:!0}):console.log(`✓ Created: ${t}`)}catch(e){z(e,n.json)}}),G(e.command(`exists`).description(`Check if a path exists`).argument(`<sandbox-id>`,`Sandbox ID`).argument(`<path>`,`Path to check`).option(`--json`,`Output as JSON`)).action(async(e,t,n)=>{try{let r=await K(n).get(e);if(!r)throw Error(`Sandbox not found: ${e}`);let i=await r.fs.exists(t.startsWith(`/`)?t:`/${t}`);n.json?B({path:t,exists:i}):(console.log(i?`exists`:`not found`),process.exit(+!i))}catch(e){z(e,n.json)}}),e}function ir(e){let t=[`r`,`w`,`x`],n=``;for(let r=2;r>=0;r--){let i=r*3;for(let r=0;r<3;r++)n+=e>>i+(2-r)&1?t[r]:`-`}return n}function ar(e){let t=[`B`,`KB`,`MB`,`GB`,`TB`],n=e,r=0;for(;n>=1024&&r<t.length-1;)n/=1024,r++;return r===0?`${n}${t[r]}`:`${n.toFixed(1)}${t[r]}`}function G(e){return e.option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`)}function K(e){return j(O({apiKey:e.apiKey,baseUrl:e.baseUrl}))}function or(){let e=new t(`git`).description(`Git operations in a sandbox workspace`);return e.command(`status`).description(`Show git repository status`).argument(`<id>`,`Sandbox ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching status...`);t.json||r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let a=await i.git.status();if(r.stop(),t.json)N(a);else{if(console.log(`Branch: ${a.branch}`),console.log(`HEAD: ${a.head.slice(0,7)}`),console.log(`Dirty: ${a.isDirty?`yes`:`no`}`),a.ahead&&console.log(`Ahead: ${a.ahead}`),a.behind&&console.log(`Behind: ${a.behind}`),a.staged.length>0){console.log(`\nStaged (${a.staged.length}):`);for(let e of a.staged)console.log(` + ${e}`)}if(a.modified.length>0){console.log(`\nModified (${a.modified.length}):`);for(let e of a.modified)console.log(` M ${e}`)}if(a.untracked.length>0){console.log(`\nUntracked (${a.untracked.length}):`);for(let e of a.untracked)console.log(` ? ${e}`)}}}catch(e){H(e)}}),e.command(`log`).description(`Show commit log`).argument(`<id>`,`Sandbox ID`).option(`-n, --limit <count>`,`Max commits to show`,`10`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching log...`);t.json||r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let a=await i.git.log(Number.parseInt(t.limit,10));if(r.stop(),t.json)N(a);else if(a.length===0)console.log(`No commits found`);else for(let e of a)console.log(`${e.shortSha} ${e.message.split(`
134
- `)[0]} (${e.author}, ${e.date.toLocaleDateString()})`)}catch(e){H(e)}}),e.command(`diff`).description(`Show diff`).argument(`<id>`,`Sandbox ID`).option(`--ref <ref>`,`Ref to diff against`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching diff...`);t.json||r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let a=await i.git.diff(t.ref);r.stop(),t.json?N(a):a.raw?console.log(a.raw):console.log(`${a.additions} additions, ${a.deletions} deletions across ${a.files.length} files`)}catch(e){H(e)}}),e.command(`add`).description(`Stage files`).argument(`<id>`,`Sandbox ID`).argument(`<paths...>`,`Paths to stage`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=await j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})).get(e);if(!r)throw Error(`Sandbox not found: ${e}`);await r.git.add(t),P(`Staged: ${t.join(`, `)}`)}catch(e){H(e)}}),e.command(`commit`).description(`Create a commit`).argument(`<id>`,`Sandbox ID`).requiredOption(`-m, --message <msg>`,`Commit message`).option(`--amend`,`Amend the previous commit`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})).get(e);if(!n)throw Error(`Sandbox not found: ${e}`);let r=await n.git.commit(t.message,{amend:t.amend});t.json?N(r):P(`Committed: ${r.shortSha} ${r.message}`)}catch(e){H(e)}}),e.command(`push`).description(`Push to remote`).argument(`<id>`,`Sandbox ID`).option(`--force`,`Force push`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Pushing...`);r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);await i.git.push({force:t.force}),r.stop(),P(`Pushed to remote`)}catch(e){H(e)}}),e.command(`pull`).description(`Pull from remote`).argument(`<id>`,`Sandbox ID`).option(`--rebase`,`Rebase instead of merge`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Pulling...`);r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);await i.git.pull({rebase:t.rebase}),r.stop(),P(`Pulled from remote`)}catch(e){H(e)}}),e.command(`branches`).description(`List branches`).argument(`<id>`,`Sandbox ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching branches...`);t.json||r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let a=await i.git.branches();r.stop(),t.json?N(a):a.length===0?console.log(`No branches found`):V([`Name`,`Current`,`Remote`],a.map(e=>[e.name,e.current?`* `:` `,e.upstream??`-`]))}catch(e){H(e)}}),e.command(`checkout`).description(`Checkout a branch or ref`).argument(`<id>`,`Sandbox ID`).argument(`<ref>`,`Branch name or ref`).option(`-b, --create`,`Create a new branch`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=await j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})).get(e);if(!r)throw Error(`Sandbox not found: ${e}`);await r.git.checkout(t,{create:n.create}),P(`Checked out: ${t}${n.create?` (new)`:``}`)}catch(e){H(e)}}),e}function sr(){let e=new t(`hub`).description(`Discover and run Tangle Hub tools`);e.option(`--json`,`Output as JSON`),e.hook(`preAction`,(e,t)=>{ur(t)}),e.command(`connect`).description(`Connect a provider account`).argument(`provider`,`Provider to connect`).option(`--no-browser`,`Print the authorization URL instead of opening it`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await q(t).connections.start(e,{cli:!0});if(t.json){N(Dr(n));return}Er(n,t.browser===!1?!1:await bn(n.redirectUrl))}catch(e){J(e,t)}});let n=new t(`connections`).description(`List Hub provider connections`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=await q(e).connections.list();if(e.json){N(t);return}Tr(t.connections)}catch(t){J(t,e)}});n.command(`revoke <connection-id>`).description(`Revoke a Hub provider connection`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{if(!t.force&&!await U(`Revoke Hub connection ${e}? `)){I(`Revoke cancelled.`);return}let n=await q(t).connections.revoke(e);if(t.json){N(n);return}I(`Revoked Hub connection ${n.connection.id}.`)}catch(e){J(e,t)}}),e.addCommand(n);let r=new t(`permissions`).description(`Manage Hub action permissions`);r.command(`list`).description(`List Hub permissions for a connection`).requiredOption(`--connection <id>`,`Hub connection ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{if(!e.connection)throw Error(`--connection is required.`);let t=await q(e).permissions.list(e.connection);if(e.json){N(t);return}br(t.policies)}catch(t){J(t,e)}}),r.command(`set`).description(`Set Hub permission for one action`).requiredOption(`--connection <id>`,`Hub connection ID`).requiredOption(`--action <path>`,`Executor action path`).requiredOption(`--decision <allow|ask|deny>`,`Permission decision`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{if(!e.connection)throw Error(`--connection is required.`);if(!e.action)throw Error(`--action is required.`);let t=xr(e.decision),n=await q(e).permissions.set({connectionId:e.connection,actionPath:e.action,decision:t});if(e.json){N(n);return}br([n.policy])}catch(t){J(t,e)}}),e.addCommand(r);let i=new t(`approvals`).description(`List and resolve Hub execution approvals`);i.command(`list`).description(`List pending Hub execution approvals`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=await q(e).approvals.list();if(e.json){N(t);return}hr(t.approvals)}catch(t){J(t,e)}}),i.command(`approve`).description(`Approve a pending Hub execution approval`).argument(`approval-id`,`Hub approval ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{mr(e),gr(await q(t).approvals.approve(e),t.json===!0)}catch(e){J(e,t)}}),i.command(`deny`).description(`Deny a pending Hub execution approval`).argument(`approval-id`,`Hub approval ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{mr(e),gr(await q(t).approvals.deny(e),t.json===!0)}catch(e){J(e,t)}}),e.addCommand(i);let a=new t(`tools`).description(`Discover Hub tools`);return a.command(`sources`).description(`List Hub tool sources`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=await q(e).tools.sources();if(e.json){N(t);return}Sr(t.sources)}catch(t){J(t,e)}}),a.command(`describe`).description(`Describe a Hub tool`).argument(`path`,`Executor tool path`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await q(t).tools.describe(e);if(t.json){N(n);return}Cr(n.tool)}catch(e){J(e,t)}}),a.command(`search`).description(`Search Hub tools`).argument(`<query...>`,`Search query`).option(`--provider <provider>`,`Filter by provider/source ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await q(t).tools.search(e.join(` `),{provider:t.provider});if(t.json){N(n);return}yr(n.tools)}catch(e){J(e,t)}}),e.addCommand(a),e.addCommand(lr(`call`)),e.addCommand(lr(`exec`)),e.command(`resume`).description(`Resolve a Hub approval created by a paused execution`).argument(`approval-id`,`Hub approval ID from HUB_APPROVAL_REQUIRED`).option(`--accept`,`Approve the execution approval`).option(`--decline`,`Deny the execution approval`).option(`--cancel`,`Unsupported for approval-backed Hub resume`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{if(mr(e),t.cancel)throw Error(`Hub approval resume does not support --cancel. Use --decline to deny the approval.`);if(t.accept&&t.decline)throw Error(`Choose only one of --accept or --decline.`);if(!t.accept&&!t.decline)throw Error(`Choose --accept to approve or --decline to deny the Hub approval.`);let n=q(t);gr(t.decline?await n.approvals.deny(e):await n.approvals.approve(e),t.json===!0)}catch(e){J(e,t)}}),e.command(`status`).description(`Show Hub auth and connection status`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=await q(e).status();if(e.json){N(t);return}Or(t)}catch(t){J(t,e)}}),e}function q(e){let t=cr(e);return new me({baseUrl:t.baseUrl,apiKey:t.apiKey})}function cr(e){let t=D(e.apiKey),n=ht(e.apiKey),r=process.env.TANGLE_HUB_CAPABILITY_TOKEN?.trim();if(r&&n===`env`)throw Error(`Set exactly one of TANGLE_API_KEY/SANDBOX_API_KEY or TANGLE_HUB_CAPABILITY_TOKEN, not both`);return O({apiKey:n===`flag`?t:r||t,baseUrl:e.baseUrl??_t(process.env.TANGLE_HUB_URL)})}function lr(e){return new t(e).description(`Execute a Hub tool`).argument(`<args...>`,`Tool path tokens followed by JSON input`).option(`--connection <id>`,`Hub connection ID`).option(`--auto-approve`,`Approve a HUB_APPROVAL_REQUIRED execution and retry once`).option(`--approve`,`Alias for --auto-approve`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let{args:n,approve:r}=pr(e,t),{path:i,input:a}=vr(n);N((await q(t).tools.invoke(i,a,{connectionId:t.connection,approve:r})).result)}catch(e){J(e,t)}})}function ur(e){if(!dr(e,`json`)||e.getOptionValue(`json`)!==void 0)return;let t=e.parent;for(;t;){let n=t.getOptionValue(`json`);if(n!==void 0){e.setOptionValue(`json`,n);return}t=t.parent}}function dr(e,t){return e.options.some(e=>e.attributeName()===t)}function fr(e){return e.json===!0}function J(e,t){return fr(t)?H(e,!0):H(e)}function pr(e,t){let n=t.autoApprove;return{args:e.filter(e=>e!==`--approve`&&e!==`--auto-approve`),approve:t.approve===!0||n===!0||e.includes(`--approve`)||e.includes(`--auto-approve`)}}function mr(e){if(!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`Hub approval ID must contain only letters, numbers, underscores, and dashes.`)}function hr(e){M(e.map(e=>({id:e.id,provider:e.providerId,action:e.actionPath,connection:e.connectionId,status:e.status,expires:e.expiresAt})),[{key:`id`,header:`ID`},{key:`provider`,header:`Provider`},{key:`action`,header:`Action`},{key:`connection`,header:`Connection`},{key:`status`,header:`Status`},{key:`expires`,header:`Expires`}])}function gr(e,t){if(t){N(_r(e));return}I(`Hub approval ${e.approval.id} ${e.approval.status}.`),e.capabilityToken&&I("Capability token minted. Re-run the original command with `--approve` to execute automatically.")}function _r(e){return{approval:e.approval,...e.capabilityToken?{capabilityToken:{tokenId:e.capabilityToken.tokenId,expiresAt:e.capabilityToken.expiresAt}}:{}}}function vr(e){if(e.length<2)throw Error(`Usage: tangle hub call <path> <json-input>`);let t=e.at(-1);if(t===void 0)throw Error(`Usage: tangle hub call <path> <json-input>`);try{return{path:e.slice(0,-1).join(`.`),input:JSON.parse(t)}}catch{throw Error(`Hub call input must be valid JSON.`)}}function yr(e){M(e.map(e=>({path:e.path,provider:e.providerId??e.requiredConnectionProviderId,title:e.title,description:e.description,connection:wr(e),policy:e.policyState})),[{key:`path`,header:`Path`},{key:`provider`,header:`Provider`},{key:`title`,header:`Title`},{key:`description`,header:`Description`},{key:`connection`,header:`Connection`},{key:`policy`,header:`Policy`}])}function br(e){M(e.map(e=>({connection:e.connectionId,provider:e.providerId,action:e.actionPath,decision:e.decision,updated:e.updatedAt})),[{key:`connection`,header:`Connection`},{key:`provider`,header:`Provider`},{key:`action`,header:`Action`},{key:`decision`,header:`Decision`},{key:`updated`,header:`Updated`}])}function xr(e){if(e===`allow`||e===`ask`||e===`deny`)return e;throw Error(`--decision must be one of: allow, ask, deny.`)}function Sr(e){M(e.map(e=>({source:e.sourceId,provider:e.displayName,tools:e.toolCount,connection:e.connectionStatus,health:e.health,configured:e.configured})),[{key:`source`,header:`Source`},{key:`provider`,header:`Provider`},{key:`tools`,header:`Tools`},{key:`connection`,header:`Connection`},{key:`health`,header:`Health`},{key:`configured`,header:`Configured`}])}function Cr(e){R({Path:e.path,Provider:e.providerId??e.requiredConnectionProviderId,Title:e.title,Description:e.description,Connection:wr(e),Policy:e.policyState}),e.inputSchema!==void 0&&(I(`Input schema`),console.log(JSON.stringify(e.inputSchema,null,2))),e.outputSchema!==void 0&&(I(`Output schema`),console.log(JSON.stringify(e.outputSchema,null,2)))}function wr(e){if(e.connectionRequired===!1)return`not required`;if(e.connectionStatus)return e.connectionStatus}function Tr(e){M(e.map(e=>({id:e.id,provider:e.providerId,account:e.accountDisplay??e.displayName,scopes:e.scopes.join(`, `),status:e.status,health:e.health,lastUsed:e.lastUsedAt})),[{key:`id`,header:`ID`},{key:`provider`,header:`Provider`},{key:`account`,header:`Account`},{key:`scopes`,header:`Scopes`},{key:`status`,header:`Status`},{key:`health`,header:`Health`},{key:`lastUsed`,header:`Last Used`}])}function Er(e,t){t?I(`Opened browser to connect ${e.provider}.`):(I(`Open this URL to connect ${e.provider}:`),console.log(e.redirectUrl)),I("Finish authorization in the browser, then rerun `tangle hub status`.")}function Dr(e){return{provider:e.provider,redirectUrl:e.redirectUrl,expiresAt:e.expiresAt,scopes:e.scopes,cli:e.cli}}function Or(e){let{principal:t,connections:n}=e;I(`Hub status`),R({Principal:t.kind,"User ID":t.userId,"API Key ID":t.apiKeyId,"Sandbox ID":t.sandboxId,"Connected Providers":n.connectedProviderCount,"Unhealthy Providers":n.unhealthyProviderCount}),n.unhealthyProviderCount>0&&I(`Some providers require reconnect.`)}const kr=[`codex`,`claude-code`,`nanoclaw`,`kimi-code`,`opencode`,`pi`,`openclaw`,`hermes`],Ar=[`codex`,`claude-code`],jr=[`codex`,`claude-code`,`nanoclaw`],Mr=[`SessionStart`,`UserPromptSubmit`,`PreToolUse`,`PostToolUse`,`Stop`],Nr={codex:{kind:`native`,surface:`codex`,label:`Codex`,buildFiles:Gr},"claude-code":{kind:`native`,surface:`claude-code`,label:`Claude Code`,buildFiles:Kr},nanoclaw:{kind:`native`,surface:`nanoclaw`,label:`NanoClaw`,buildFiles:Kr},"kimi-code":{kind:`manual`,surface:`kimi-code`,label:`Kimi Code`,reason:`Kimi Code loads hooks through an explicit config file, so use standard OTLP env wiring until the native config adapter is verified.`},opencode:{kind:`manual`,surface:`opencode`,label:`OpenCode`,reason:`OpenCode hooks run as plugins; use standard OTLP env wiring until the native plugin adapter is verified.`},pi:{kind:`manual`,surface:`pi`,label:`Pi`,reason:`Pi hooks run through TypeScript extensions; use standard OTLP env wiring until the native extension adapter is verified.`},openclaw:{kind:`manual`,surface:`openclaw`,label:`OpenClaw`,reason:`OpenClaw project hooks require user opt-in; use standard OTLP env wiring until the hook toggle and adapter are verified.`},hermes:{kind:`manual`,surface:`hermes`,label:`Hermes`,reason:`Hermes project plugins require explicit enablement; use standard OTLP env wiring until the plugin adapter is verified.`}};function Pr(e){let t=e.split(`,`).map(e=>e.trim()).filter(Boolean).flatMap(e=>Wr(e));return t.length===0?[...Ar]:ii(t)}function Fr(e){return Object.hasOwn(Nr,e)}function Ir(e=process.cwd()){return f(ne(e))||`agent-workspace`}function Lr(){return te(de(),`.tangle`,`intelligence.json`)}function Rr(e=Lr()){if(!o(e))return null;let t=ti(e),n=ai(t,`apiKey`),r=ai(t,`endpoint`),i=ai(t,`serviceName`),a=ai(t,`environment`);if(!n||!r||!i||!a)throw Error(`${e} is missing apiKey, endpoint, serviceName, or environment`);return{apiKey:n,endpoint:r,serviceName:i,environment:a}}async function zr(e){let t=ne(e.workspace),n=Lr(),r=Pr(e.selection),i=[],a=[],o=[],s={apiKey:e.apiKey,endpoint:Ur(e.endpoint),serviceName:e.serviceName,environment:e.environment};e.dryRun||Qr(n,s),o.push(n);for(let n of r){let r=Nr[n];if(r.kind===`manual`){a.push({agent:r.surface,label:r.label,reason:r.reason});continue}i.push(r.surface);let s=t=>Br(e.hookCommand,r.surface,t);for(let n of r.buildFiles(s)){let r=te(t,n.relPath);if(e.dryRun){o.push(r);continue}ei(r,JSON.parse(n.content),n.mode),o.push(r)}}return!e.smoke||e.dryRun?{configPath:n,written:o,agents:r,nativeAgents:i,manual:a}:{configPath:n,written:o,agents:r,nativeAgents:i,manual:a,smokeTraceId:await Hr({agent:i[0]??r[0]??`codex`,event:`install.smoke`,endpoint:s.endpoint,apiKey:s.apiKey,serviceName:s.serviceName,environment:s.environment,sessionId:`install-smoke-${Date.now()}`,payload:{source:`tangle intelligence connect`}})}}function Br(e,t,n){return`${e.trim()} --agent ${t} --event ${n} --non-blocking`}function Vr(e){let t=BigInt(Date.now())*1000000n,n=si(16),r=si(8),i=e.sessionId??qr(e.payload),a={"service.name":e.serviceName,"deployment.environment":e.environment,"tangle.agent.surface":e.agent,"tangle.agent.hook.event":e.event,"tangle.agent.hook.source":`local-hook`,...Jr(e.payload)};return i&&(a[`session.id`]=i,a[`gen_ai.conversation.id`]=i,a[`tangle.sessionId`]=i),{body:{resourceSpans:[{resource:{attributes:[ci(`service.name`,e.serviceName),ci(`deployment.environment`,e.environment),ci(`tangle.agent.surface`,e.agent)]},scopeSpans:[{scope:{name:`tangle.intelligence.agent-hook`,version:`1.0.0`},spans:[{traceId:n,spanId:r,name:`agent.${e.agent}.${e.event}`,kind:1,startTimeUnixNano:t.toString(),endTimeUnixNano:(t+1000000n).toString(),attributes:Object.entries(a).map(([e,t])=>ci(e,t)),status:{code:1}}]}]}]},traceId:n}}async function Hr(e){let{body:t,traceId:n}=Vr(e),r=await fetch(`${Ur(e.endpoint)}/v1/traces`,{method:`POST`,headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":`application/json`},body:JSON.stringify(t)});if(!r.ok){let e=await r.text().catch(()=>``);throw Error(`OTLP smoke ingest failed: ${r.status}${e?` ${e}`:``}`)}return n}function Ur(e){let t=e.trim().replace(/\/+$/,``);return t.endsWith(`/v1/traces`)?t.slice(0,-10):t.endsWith(`/v1/logs`)?t.slice(0,-8):t}function Wr(e){switch(e){case`local`:case`both`:return[...Ar];case`all`:return[...jr];case`claude`:return[`claude-code`];case`kimi`:return[`kimi-code`];default:if(Fr(e))return[e];throw Error(`agent must be one of: local, all, both, ${kr.join(`, `)}`)}}function Gr(e){let t=Object.fromEntries(Mr.map(t=>[t,[{command:e(t),timeoutMs:3e3,blocking:!1,matcher:`*`}]]));return[{relPath:`.codex/hooks.json`,content:JSON.stringify({hooks:t},null,2)}]}function Kr(e){let t=Object.fromEntries(Mr.map(t=>[t,[{matcher:`*`,hooks:[{type:`command`,command:e(t),timeout:3}]}]]));return[{relPath:`.claude/settings.json`,content:JSON.stringify({hooks:t},null,2)}]}function qr(e){return Yr(e,[`session.id`,`sessionId`,`session_id`,`conversationId`,`conversation_id`,`threadId`,`thread_id`,`transcriptId`,`transcript_id`])||process.env.TANGLE_SESSION_ID||process.env.CODEX_THREAD_ID||process.env.CLAUDE_SESSION_ID||process.env.OPENCODE_SESSION_ID}function Jr(e){let t={},n=Y(e,[`tool.name`,`toolName`,`tool_name`,`tool`]),r=Y(e,[`command`,`cmd`,`shell_command`,`shellCommand`]),i=Y(e,[`tool.input`,`toolInput`,`tool_input`,`input`,`arguments`,`args`]),a=Y(e,[`tool.output`,`toolOutput`,`tool_output`,`output`,`result`]),o=Y(e,[`tool.exit_code`,`exitCode`,`exit_code`,`status`]),s=Y(e,[`tool.error.message`,`errorMessage`,`error_message`,`error`]);return n&&(t[`tool.name`]=n),r&&(t[`process.command`]=r),i&&(t[`tool.input.summary`]=i),a&&(t[`tool.output.summary`]=a),o&&(t[`tool.exit_code`]=o),s&&(t[`tool.error.message`]=s),t}function Y(e,t){let n=Xr(e,t);if(n===void 0)return null;if(typeof n==`string`)return Zr(n);if(typeof n==`number`||typeof n==`boolean`||typeof n==`bigint`)return String(n);try{return Zr(JSON.stringify(n))}catch{return null}}function Yr(e,t){let n=Xr(e,t);return typeof n==`string`&&n.length>0?n:void 0}function Xr(e,t){if(typeof e!=`object`||!e)return;let n=[e],r=new Set;for(;n.length;){let e=n.pop();if(typeof e!=`object`||!e||r.has(e))continue;r.add(e);let i=e;for(let e of t){let t=i[e];if(t!=null&&t!==``)return t}for(let e of Object.values(i))typeof e==`object`&&e&&n.push(e)}}function Zr(e){return e.length>4096?`${e.slice(0,4093)}...`:e}function Qr(e,t){$r(e,`${JSON.stringify(t,null,2)}\n`)}function $r(e,t){s(p(e),{mode:448,recursive:!0});let n=`${e}.${process.pid}.tmp`;u(n,t,{mode:384}),l(n,e)}function ei(e,t,n){s(p(e),{recursive:!0});let r=ni(ti(e),t);u(e,`${JSON.stringify(r,null,2)}\n`,{mode:n??420})}function ti(e){if(!o(e))return{};let t=JSON.parse(c(e,`utf8`));if(!oi(t))throw Error(`${e} must contain a JSON object`);return t}function ni(e,t){let n={...e};for(let[e,r]of Object.entries(t)){let t=n[e];oi(t)&&oi(r)?n[e]=ni(t,r):Array.isArray(t)&&Array.isArray(r)?n[e]=ri([...t,...r]):n[e]=r}return n}function ri(e){let t=new Set,n=[];for(let r of e){let e=JSON.stringify(r);t.has(e)||(t.add(e),n.push(r))}return n}function ii(e){return[...new Set(e)]}function ai(e,t){let n=e[t];return typeof n==`string`&&n.length>0?n:void 0}function oi(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&(Object.getPrototypeOf(e)===Object.prototype||Object.getPrototypeOf(e)===null)}function si(e){return n(e).toString(`hex`)}function ci(e,t){return{key:e,value:{stringValue:t}}}function li(){let e=new t(`intelligence`).description(`Create and inspect trace intelligence reports`);return e.command(`connect [agent]`).alias(`connect-agent`).description(`Connect local agent CLIs to Tangle Intelligence`).option(`--api-key <key>`,`Intelligence ingest API key`).option(`--endpoint <url>`,`OTLP endpoint base`,`https://intelligence.tangle.tools/v1/otlp`).option(`--workspace <path>`,`Workspace to write hook files into`,`.`).option(`--service-name <name>`,`OTel service.name label`).option(`--environment <name>`,`OTel deployment.environment label`,`local`).option(`--dry-run`,`Print planned writes without changing files`).option(`--hook-command <command>`,`Command native hooks should run`,`tangle intelligence hook`).option(`--no-smoke`,`Skip the install smoke trace`).option(`--json`,`Output as JSON`).action(async(e,t)=>{try{let n=e??`local`;Pr(n);let r=ui(t.apiKey),i=await zr({selection:n,workspace:t.workspace,apiKey:r,endpoint:t.endpoint,serviceName:t.serviceName??Ir(t.workspace),environment:t.environment,smoke:t.smoke,dryRun:!!t.dryRun,hookCommand:t.hookCommand}),a={configPath:i.configPath,agents:i.agents,nativeAgents:i.nativeAgents,manual:i.manual,written:i.written,smokeTraceId:i.smokeTraceId};if(t.json){N(a);return}R({Config:i.configPath,Agents:i.agents.join(`, `),"Native Hooks":i.nativeAgents.join(`, `)||void 0,"Manual Setup":i.manual.length?i.manual.map(e=>`${e.label}: ${e.reason}`).join(` `):void 0,Files:i.written.join(`, `),"Smoke Trace":i.smokeTraceId})}catch(e){H(e)}}),e.command(`hook`).description(`Emit one local agent hook event to Tangle Intelligence`).requiredOption(`--agent <agent>`,`Agent surface`).requiredOption(`--event <event>`,`Hook event name`).option(`--payload <json>`,`Hook payload JSON`).option(`--api-key <key>`,`Intelligence ingest API key`).option(`--endpoint <url>`,`OTLP endpoint base`).option(`--service-name <name>`,`OTel service.name label`).option(`--environment <name>`,`OTel deployment.environment label`).option(`--session-id <id>`,`Session id override`).option(`--dry-run`,`Build the OTLP request without sending it`).option(`--non-blocking`,`Do not fail the parent agent process`).option(`--json`,`Output as JSON`).action(async e=>{try{let t=di(e.agent),n=Rr(),r={agent:t,event:e.event,endpoint:e.endpoint??n?.endpoint??`https://intelligence.tangle.tools/v1/otlp`,apiKey:ui(e.apiKey??n?.apiKey),serviceName:e.serviceName??n?.serviceName??Ir(process.cwd()),environment:e.environment??n?.environment??`local`,sessionId:e.sessionId,payload:e.payload===void 0?await pi():fi(e.payload)};if(e.dryRun){let n=Vr(r);if(e.json){N(n);return}R({Trace:n.traceId,Agent:t,Event:e.event});return}let i=await Hr(r);if(e.json){N({traceId:i});return}R({Trace:i,Agent:t,Event:e.event})}catch(t){if(e.nonBlocking){let n=t instanceof Error?t.message:String(t);e.json?N({ok:!1,error:n}):console.error(`Tangle Intelligence hook skipped: ${n}`);return}H(t)}}),e.command(`sandbox <sandbox-id>`).description(`Create an intelligence report for one sandbox`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{await mi({type:`sandbox`,id:e},t)}),e.command(`fleet <fleet-id>`).description(`Create an intelligence report for a sandbox fleet`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{await mi({type:`fleet`,id:e},t)}),e.command(`create`).description(`Create a trace intelligence report`).requiredOption(`--subject-type <type>`,`sandbox | fleet`).requiredOption(`--subject-id <id>`,`Subject identifier`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{await mi({type:gi(e.subjectType),id:e.subjectId},e)}),e.command(`get <job-id>`).description(`Get an intelligence report`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=t.json?null:L(`Fetching intelligence report...`);r?.start();let i=await n.intelligence.getReport(e);if(r?.stop(),t.json){N(i);return}hi(i)}catch(e){H(e)}}),e.command(`list`).description(`List intelligence reports`).option(`--subject-type <type>`,`sandbox | fleet`).option(`--subject-id <id>`,`Subject identifier`).option(`--limit <count>`,`Maximum reports to return`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=j(O({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=e.json?null:L(`Fetching intelligence reports...`);n?.start();let r=await t.intelligence.listReports({subjectType:e.subjectType===void 0?void 0:gi(e.subjectType),subjectId:e.subjectId,limit:e.limit===void 0?void 0:yi(e.limit)});if(n?.stop(),e.json){N(r);return}M(r.map(e=>({jobId:e.jobId,subject:`${e.subject.type}:${e.subject.id}`,mode:e.mode,status:e.status,cost:`$${e.billing.costUsd.toFixed(2)}`,updatedAt:e.updatedAt})),[{key:`jobId`,header:`Job`,width:20},{key:`subject`,header:`Subject`,width:28},{key:`mode`,header:`Mode`,width:15},{key:`status`,header:`Status`,width:14},{key:`cost`,header:`Cost`,width:10},{key:`updatedAt`,header:`Updated`,width:18}])}catch(e){H(e)}}),e}function ui(e){let t=e??process.env.TANGLE_INTELLIGENCE_API_KEY??process.env.TANGLE_API_KEY;if(!t)throw Error(`--api-key, TANGLE_INTELLIGENCE_API_KEY, or TANGLE_API_KEY is required`);return t}function di(e){if(Fr(e))return e;throw Error(`agent must be a known Tangle Intelligence agent surface`)}function fi(e){try{return JSON.parse(e)}catch(e){throw Error(`--payload must be JSON: ${e instanceof Error?e.message:String(e)}`)}}async function pi(){if(process.stdin.isTTY)return;let e=``;for await(let t of process.stdin)if(e+=typeof t==`string`?t:t.toString(`utf8`),e.length>65536)throw Error(`hook payload exceeds 65536 bytes`);let t=e.trim();if(t)try{return JSON.parse(t)}catch{return{body:t.slice(0,4096)}}}async function mi(e,t){try{let n=_i(t.mode),r=bi(t.metadata),i=t.maxUsd===void 0?void 0:vi(t.maxUsd);if(n===`agentic`&&i===void 0)throw Error(`Agentic intelligence reports require --max-usd`);let a=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),o=t.json?null:L(`Creating intelligence report...`);o?.start();let s=await a.intelligence.createReport({subject:e,mode:n,...i===void 0?{}:{budget:{billTo:`customer`,maxUsd:i}},...r===void 0?{}:{metadata:r}});if(o?.stop(),t.json){N(s);return}hi(s)}catch(e){H(e)}}function hi(e){R({Job:e.jobId,Subject:`${e.subject.type}:${e.subject.id}`,Mode:e.mode,Status:e.status,"Billed To":e.billing.billedTo,Cost:`$${e.billing.costUsd.toFixed(2)}`,Budget:e.billing.budgetMaxUsd===void 0?void 0:`$${e.billing.budgetMaxUsd.toFixed(2)}`,Updated:e.updatedAt}),e.result!==null&&(console.log(),N(e.result))}function gi(e){if(e===`sandbox`||e===`fleet`)return e;throw Error(`subject type must be sandbox or fleet`)}function _i(e){if(e===`deterministic`||e===`agentic`)return e;throw Error(`mode must be deterministic or agentic`)}function vi(e){let t=Number(e);if(!Number.isFinite(t)||t<0)throw Error(`--max-usd must be a non-negative number`);return t}function yi(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function bi(e){if(e===void 0)return;let t=JSON.parse(e);if(!t||typeof t!=`object`||Array.isArray(t))throw Error(`--metadata must be a JSON object`);return t}const xi=[`router`,`sandbox`,`blueprint-agent`,`evals`,`agent-builder`];function Si(e){return(e?.trim()||process.env.TANGLE_PLATFORM_URL?.trim()||`https://id.tangle.tools`).replace(/\/+$/,``)}async function Ci(e,t,n={}){let r=new Headers(n.headers);r.set(`Authorization`,`Bearer ${t}`),n.body&&!r.has(`content-type`)&&r.set(`content-type`,`application/json`);let i=await fetch(e,{...n,headers:r});if(n.expected!==void 0&&i.status!==n.expected){let t=await i.text().catch(()=>``),n=t?`: ${t.slice(0,400)}`:``;throw Error(`Platform request to ${e} returned ${i.status}${n}`)}return i}const wi=[`ID`,`Prefix`,`Name`,`Product`,`Created`,`Last used`,`Expires`];function Ti(e){return[e.id,e.keyPrefix??``,e.name,e.product??`all`,e.createdAt,e.lastUsedAt??`—`,e.expiresAt??`—`]}function Ei(){let e=new t(`keys`).description(`Manage sk-tan-* API keys on id.tangle.tools`);return e.command(`list`).description(`List your active API keys`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key (overrides configured credentials)`).option(`--base-url <url>`,`Sandbox API base URL (not platform URL)`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async e=>{try{let t=O({apiKey:e.apiKey,baseUrl:e.baseUrl}),n=await(await Ci(`${Si(e.platformUrl)}/v1/keys`,t.apiKey,{expected:200})).json();if(e.json){N(n);return}V(wi,n.data.map(Ti))}catch(e){H(e)}}),e.command(`create`).description(`Create a new API key`).argument(`<name>`,`Human-readable name for the key`).option(`--product <product>`,`Restrict the key to one product (${xi.join(`|`)}). Omit for all products.`).option(`--budget-usd <amount>`,`Hard budget cap in USD`).option(`--rpm-limit <limit>`,`Requests-per-minute cap`).option(`--expires-in-days <days>`,`Expire the key after N days (integer)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key (overrides configured credentials)`).option(`--base-url <url>`,`Sandbox API base URL (not platform URL)`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{try{if(t.product!==void 0&&!xi.includes(t.product))throw Error(`Invalid --product. Expected one of ${xi.join(`, `)}`);let n=O({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=Si(t.platformUrl),i=t.expiresInDays===void 0?void 0:new Date(Date.now()+Number.parseInt(t.expiresInDays,10)*24*60*60*1e3).toISOString(),a=L(`Creating API key...`);a.start();let o=await Ci(`${r}/v1/keys`,n.apiKey,{method:`POST`,expected:201,body:JSON.stringify({name:e,product:t.product,budgetUsd:t.budgetUsd?Number.parseFloat(t.budgetUsd):void 0,rpmLimit:t.rpmLimit?Number.parseInt(t.rpmLimit,10):void 0,expiresAt:i})});a.stop();let s=await o.json();if(t.json){N(s);return}P(`API key created: ${s.data.prefix}…`),I(`Copy this key now — it will never be shown again:\n${s.data.key}`)}catch(e){H(e)}}),e.command(`revoke`).description(`Revoke an API key`).argument(`<keyId>`,"Key ID (from `tcloud keys list`)").option(`--yes`,`Skip the confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key (overrides configured credentials)`).option(`--base-url <url>`,`Sandbox API base URL (not platform URL)`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{try{let n=O({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=Si(t.platformUrl);if(!t.yes&&!await U(`Revoke key ${e}? Any service still using it will start to fail.`)){I(`Aborted.`);return}let i=await(await Ci(`${r}/v1/keys/${encodeURIComponent(e)}`,n.apiKey,{method:`DELETE`,expected:200})).json();if(t.json){N(i);return}P(`Revoked ${e}`)}catch(e){H(e)}}),e}function Di(){let e=new t(`mcp`).description(`Model Context Protocol bridge commands.`);return e.command(`serve <id>`).description(`Run a local MCP server (stdio) backed by the given sandbox. Pipe its stdio from an MCP client config to expose sandbox tools.`).option(`-s, --session <id>`,`Session id for kernel scoping`,`mcp-local`).option(`--name <name>`,`MCP server name reported to clients`,`tangle-sandbox`).action(async(e,t)=>{try{let n=await j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})).get(e);if(!n)throw Error(`Sandbox not found: ${e}`);let r;try{r=(await import(`@modelcontextprotocol/sdk/server/stdio.js`)).StdioServerTransport}catch{throw Error("`@modelcontextprotocol/sdk` is not installed in this environment. Install it with: pnpm add -g @modelcontextprotocol/sdk (or as a dev dep in the project running this command).")}let{connect:i,close:a}=await _e(n,{sessionId:t.session,name:t.name});await i(new r),process.stdin.resume(),process.stdin.on(`end`,()=>{a().finally(()=>process.exit(0))});for(let e of[`SIGINT`,`SIGTERM`])process.on(e,()=>{a().finally(()=>process.exit(0))})}catch(e){H(e)}}),e}function Oi(){let e=new t(`permissions`).description(`Manage sandbox user permissions`);return e.command(`list <sandboxId>`).description(`List all users in a sandbox`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching users...`);r.start();let i=await n.get(e);if(!i)throw r.stop(),Error(`Sandbox ${e} not found`);let a=await i.permissions.list();r.stop(),t.json?N(a):M(a.map(e=>({userId:e.userId,username:e.username,role:e.role,homeDir:e.homeDir,createdAt:e.createdAt.toISOString().split(`T`)[0]})),[{key:`userId`,header:`User ID`,width:20},{key:`username`,header:`Username`,width:16},{key:`role`,header:`Role`,width:12},{key:`homeDir`,header:`Home Directory`,width:24},{key:`createdAt`,header:`Created`,width:16}])}catch(e){H(e)}}),e.command(`get <sandboxId> <userId>`).description(`Get details for a specific user`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Fetching user...`);i.start();let a=await r.get(e);if(!a)throw i.stop(),Error(`Sandbox ${e} not found`);let o=await a.permissions.get(t);if(i.stop(),!o)throw Error(`User ${t} not found in sandbox ${e}`);n.json?N(o):(I(`User: ${o.userId}`),I(` Username: ${o.username}`),I(` Role: ${o.role}`),I(` Home: ${o.homeDir}`),I(` SSH Keys: ${o.sshKeys.length}`),I(` Created: ${o.createdAt.toISOString()}`))}catch(e){H(e)}}),e.command(`add <sandboxId>`).description(`Add a user to a sandbox`).requiredOption(`--user-id <id>`,`User ID (from your auth system)`).option(`--username <name>`,`Preferred username`).option(`--role <role>`,`Permission level (owner, admin, developer, viewer)`,`developer`).option(`--ssh-key <key>`,`SSH public key for access`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Adding user...`);r.start();let i=await n.get(e);if(!i)throw r.stop(),Error(`Sandbox ${e} not found`);let a=await i.permissions.add({userId:t.userId,username:t.username,role:t.role,sshKeys:t.sshKey?[t.sshKey]:void 0});r.stop(),t.json?N(a):(P(`User ${a.userId} added as ${a.role}`),I(` Username: ${a.username}`),I(` Home: ${a.homeDir}`))}catch(e){H(e)}}),e.command(`update <sandboxId> <userId>`).description(`Update a user's permissions`).option(`--role <role>`,`New permission level (owner, admin, developer, viewer)`).option(`--add-ssh-key <key>`,`Add SSH public key`).option(`--remove-ssh-key <key>`,`Remove SSH public key`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Updating user...`);i.start();let a=await r.get(e);if(!a)throw i.stop(),Error(`Sandbox ${e} not found`);let o=await a.permissions.update(t,{role:n.role,addSshKeys:n.addSshKey?[n.addSshKey]:void 0,removeSshKeys:n.removeSshKey?[n.removeSshKey]:void 0});i.stop(),n.json?N(o):(P(`User ${t} updated`),I(` Role: ${o.role}`),I(` SSH Keys: ${o.sshKeys.length}`))}catch(e){H(e)}}),e.command(`remove <sandboxId> <userId>`).description(`Remove a user from a sandbox`).option(`--preserve-home`,`Keep user's home directory`).option(`-f, --force`,`Skip confirmation`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{if(!n.force){let e=(await import(`node:readline`)).createInterface({input:process.stdin,output:process.stdout});if(!await new Promise(n=>{e.question(`Remove user ${t} from sandbox? [y/N] `,t=>{e.close(),n(t.toLowerCase()===`y`)})})){I(`Cancelled.`);return}}let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Removing user...`);i.start();let a=await r.get(e);if(!a)throw i.stop(),Error(`Sandbox ${e} not found`);await a.permissions.remove(t,{preserveHomeDir:n.preserveHome}),i.stop(),P(`User ${t} removed from sandbox ${e}`)}catch(e){H(e)}}),e.command(`policies <sandboxId> <userId>`).description(`Get access policies for a user`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Fetching policies...`);i.start();let a=await r.get(e);if(!a)throw i.stop(),Error(`Sandbox ${e} not found`);let o=await a.permissions.getAccessPolicies(t);i.stop(),n.json?N(o):o.length===0?I(`No access policies configured`):M(o.map(e=>({pattern:e.pattern,permission:e.permission,priority:e.priority??0})),[{key:`pattern`,header:`Pattern`,width:30},{key:`permission`,header:`Permission`,width:12},{key:`priority`,header:`Priority`,width:10}])}catch(e){H(e)}}),e.command(`check <sandboxId> <userId> <path> <action>`).description(`Check if a user can perform an action on a path`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n,r,i)=>{try{if(![`read`,`write`,`execute`].includes(r))throw Error(`Action must be: read, write, or execute`);let a=j(O({apiKey:i.apiKey,baseUrl:i.baseUrl})),o=L(`Checking access...`);o.start();let s=await a.get(e);if(!s)throw o.stop(),Error(`Sandbox ${e} not found`);let c=await s.permissions.checkAccess(t,n,r);o.stop(),c?P(`✓ User ${t} CAN ${r} ${n}`):I(`✗ User ${t} CANNOT ${r} ${n}`)}catch(e){H(e)}}),e}function ki(){let e=new t(`preview`).description(`Manage sandbox preview links`);return e.command(`list`).alias(`ls`).description(`List active preview links for a sandbox`).argument(`<id>`,`Sandbox ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching preview links...`);t.json||r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let a=await i.previewLinks.list();r.stop(),t.json?N(a):a.length===0?console.log(`No preview links found`):V([`Preview ID`,`Port`,`URL`,`Status`],a.map(e=>[e.previewId.slice(0,12),String(e.port),e.url,e.status]))}catch(e){H(e)}}),e.command(`create`).description(`Create a preview link for a port`).argument(`<id>`,`Sandbox ID`).argument(`<port>`,`Port number to preview`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Creating preview for port ${t}...`);n.json||i.start();let a=await r.get(e);if(!a)throw Error(`Sandbox not found: ${e}`);let o=await a.previewLinks.create(Number.parseInt(t,10));i.stop(),n.json?N(o):(P(`Preview created: ${o.url}`),console.log(`Preview ID: ${o.previewId}`))}catch(e){H(e)}}),e.command(`remove`).alias(`rm`).description(`Remove a preview link`).argument(`<id>`,`Sandbox ID`).argument(`<preview-id>`,`Preview link ID (from 'preview list')`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Removing preview...`);n.json||i.start();let a=await r.get(e);if(!a)throw Error(`Sandbox not found: ${e}`);await a.previewLinks.remove(t),i.stop(),n.json?N({success:!0,previewId:t}):P(`Preview removed: ${t}`)}catch(e){H(e)}}),e}function Ai(){let e=new t(`process`).description(`Manage processes in a sandbox`);return e.command(`spawn`).description(`Spawn a process without blocking (returns PID)`).argument(`<id>`,`Sandbox ID`).argument(`<command>`,`Command to execute`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`).option(`--blocking`,`Wait for completion (default: false)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i={};if(n.env)for(let e of n.env){let[t,...n]=e.split(`=`);t&&n.length>0&&(i[t]=n.join(`=`))}let a=L(`Spawning: ${t}`);n.json||a.start();let o=await r.get(e);if(!o)throw Error(`Sandbox not found: ${e}`);if(n.blocking){let e=await o.exec(t,{cwd:n.cwd,env:Object.keys(i).length>0?i:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});a.stop(),n.json?N(e):(e.stdout&&globalThis.process.stdout.write(e.stdout),e.stderr&&globalThis.process.stderr.write(e.stderr),e.exitCode!==0&&globalThis.process.exit(e.exitCode))}else{let r=await o.process.spawn(t,{cwd:n.cwd,env:Object.keys(i).length>0?i:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});a.stop(),n.json?N({pid:r.pid,command:r.command}):(console.log(`Process started with PID: ${r.pid}`),console.log(`Use 'tangle process logs ${e} ${r.pid}' to view output`))}}catch(e){H(e)}}),e.command(`list`).alias(`ls`).description(`List all processes in a sandbox`).argument(`<id>`,`Sandbox ID`).option(`--running`,`Show only running processes`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching processes...`);t.json||r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let a=await i.process.list();t.running&&(a=a.filter(e=>e.running)),r.stop(),t.json?N(a):a.length===0?console.log(`No processes found`):V([`PID`,`Command`,`Status`,`Exit Code`,`Started`],a.map(e=>[String(e.pid),e.command.length>40?`${e.command.slice(0,37)}...`:e.command,e.running?`running`:`exited`,String(e.exitCode),e.startedAt.toLocaleString()]))}catch(e){H(e)}}),e.command(`get`).description(`Get detailed info about a process`).argument(`<id>`,`Sandbox ID`).argument(`<pid>`,`Process ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Fetching process info...`);n.json||i.start();let a=await r.get(e);if(!a)throw Error(`Sandbox not found: ${e}`);let o=await a.process.get(Number.parseInt(t,10));if(i.stop(),!o){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}let s=await o.status();n.json?N(s):(console.log(`PID: ${s.pid}`),console.log(`Command: ${s.command}`),console.log(`CWD: ${s.cwd||`(default)`}`),console.log(`Status: ${s.running?`running`:`exited`}`),console.log(`Exit Code: ${s.exitCode}`),s.exitSignal&&console.log(`Signal: ${s.exitSignal}`),console.log(`Started: ${s.startedAt.toLocaleString()}`),s.exitedAt&&console.log(`Exited: ${s.exitedAt.toLocaleString()}`))}catch(e){H(e)}}),e.command(`kill`).description(`Kill a process`).argument(`<id>`,`Sandbox ID`).argument(`<pid>`,`Process ID`).option(`-s, --signal <signal>`,`Signal to send (SIGTERM, SIGKILL, etc.)`,`SIGTERM`).option(`--tree`,`Also kill descendants of the tracked process`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Sending ${n.signal} to PID ${t}...`);n.json||i.start();let a=await r.get(e);if(!a)throw Error(`Sandbox not found: ${e}`);let o=await a.process.get(Number.parseInt(t,10));if(!o){i.stop(),console.error(`Process ${t} not found`),globalThis.process.exit(1);return}n.tree?await o.kill(n.signal,{tree:!0}):await o.kill(n.signal),i.stop(),n.json?N({pid:Number.parseInt(t,10),signal:n.signal,...n.tree===!0?{tree:!0}:{},killed:!0}):console.log(n.tree?`Sent ${n.signal} to process tree ${t}`:`Sent ${n.signal} to process ${t}`)}catch(e){H(e)}}),e.command(`logs`).description(`Stream buffered and live process logs until the process exits`).argument(`<id>`,`Sandbox ID`).argument(`<pid>`,`Process ID`).option(`--stdout-only`,`Only show stdout`).option(`--stderr-only`,`Only show stderr`).option(`--json`,`Output as JSON lines`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=await j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})).get(e);if(!r)throw Error(`Sandbox not found: ${e}`);let i=await r.process.get(Number.parseInt(t,10));if(!i){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}for await(let e of i.logs())n.stdoutOnly&&e.type!==`stdout`||n.stderrOnly&&e.type!==`stderr`||(n.json?console.log(JSON.stringify(e)):e.type===`stdout`?globalThis.process.stdout.write(e.data):globalThis.process.stderr.write(e.data))}catch(e){H(e)}}),e.command(`run-code`).description(`Execute Python code directly`).argument(`<id>`,`Sandbox ID`).argument(`<code>`,`Python code to execute`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i={};if(n.env)for(let e of n.env){let[t,...n]=e.split(`=`);t&&n.length>0&&(i[t]=n.join(`=`))}let a=L(`Executing Python code...`);n.json||a.start();let o=await r.get(e);if(!o)throw Error(`Sandbox not found: ${e}`);let s=await o.process.runCode(t,{cwd:n.cwd,env:Object.keys(i).length>0?i:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});a.stop(),n.json?N(s):(s.stdout&&globalThis.process.stdout.write(s.stdout),s.stderr&&globalThis.process.stderr.write(s.stderr),s.exitCode!==0&&globalThis.process.exit(s.exitCode))}catch(e){H(e)}}),e}const ji=[`python`,`node`,`typescript`,`bash`];function Mi(e){switch(ee(e).toLowerCase()){case`.py`:return`python`;case`.js`:case`.mjs`:case`.cjs`:return`node`;case`.ts`:case`.tsx`:return`typescript`;case`.sh`:case`.bash`:return`bash`;default:return}}async function Ni(e){if(e===`-`){let e=[];for await(let t of process.stdin)e.push(typeof t==`string`?Buffer.from(t):t);return Buffer.concat(e).toString(`utf8`)}return await ve(ne(e),`utf8`)}async function Pi(e,t,n=Ni){let r=t?ji.find(e=>e===t)??(()=>{throw Error(`unknown --lang ${t}: must be one of ${ji.join(`, `)}`)})():void 0;if(!e||e===`-`){if(!r)throw Error(`reading from stdin requires --lang. Example: tangle run <id> -l python -`);return{language:r,source:await n(`-`)}}let i=Mi(e);return{language:r??i??(()=>{throw Error(`cannot infer language from "${e}". Pass it explicitly: tangle run <id> -l <python|node|typescript|bash> ${e}`)})(),source:await n(e)}}function Fi(e){return te(fe(),`tangle-run-images`,e)}function Ii(){return new t(`run`).description(`Run code in a persistent kernel inside a sandbox. Variables persist across calls in the same --session.`).argument(`<id>`,`Sandbox ID`).argument(`[file]`,`Path to source file. Language is inferred from extension. Use - for stdin (requires --lang).`).option(`-l, --lang <lang>`,`Force language: ${ji.join(` | `)}. Required for stdin.`).option(`-s, --session <id>`,`Session id for kernel scoping`).option(`-t, --timeout <ms>`,`Per-call timeout in ms (0 disables)`,`60000`).option(`--save-images <dir>`,`Write image results into this directory (default: $TMPDIR/tangle-run-images/<sandbox>/).`).option(`--no-save-images`,`Don't write image results to disk; print summary only`).option(`--json`,`Output the full CodeExecutionResult as JSON`).action(async(e,t,n)=>{try{let{language:r,source:a}=await Pi(t,n.lang),o=await j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})).get(e);if(!o)throw Error(`Sandbox not found: ${e}`);let c=L(`Running ${r} (${a.length}b)…`);n.json||c.start();let l=await o.runCode(r,a,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10)});if(c.stop(),n.json){N(l),l.exitCode!==0&&process.exit(l.exitCode);return}l.stdout&&process.stdout.write(l.stdout),l.stderr&&process.stderr.write(l.stderr);let d=0;for(let t of l.results)if(t.type===`image`)if(n.saveImages!==!1){let r=typeof n.saveImages==`string`?n.saveImages:Fi(e);s(r,{recursive:!0});let a=`${r}/${Date.now()}-${d}.${t.format}`;u(a,Buffer.from(t.data,`base64`)),process.stderr.write(i.green(`✓ image → ${a}\n`)),d++}else process.stderr.write(i.gray(`[image: ${t.format}, ${t.data.length}b base64]\n`));else if(t.type===`dataframe`){let e=t.columns.map(e=>`${e.name}:${e.dtype}`).join(` | `);process.stderr.write(i.gray(`[dataframe ${t.rows.length}×${t.columns.length}${t.truncated?` (truncated)`:``}]\n`)),process.stderr.write(`${e}\n`);for(let e of t.rows.slice(0,20))process.stderr.write(`${e.map(e=>String(e)).join(` | `)}\n`);t.rows.length>20&&process.stderr.write(i.gray(`… ${t.rows.length-20} more rows\n`))}else t.type===`json`?(process.stderr.write(i.gray(`[json] `)),process.stderr.write(`${JSON.stringify(t.value,null,2)}\n`)):t.type===`html`?process.stderr.write(i.gray(`[html ${t.value.length}b]\n`)):t.type===`error`?(process.stderr.write(i.red(`✗ ${t.name}: ${t.message}\n`)),t.traceback&&process.stderr.write(`${t.traceback}\n`)):t.type===`text`&&process.stderr.write(`${t.value}\n`);l.error&&(process.stderr.write(i.red(`\n✗ ${l.error.name}: ${l.error.message}\n`)),l.error.traceback&&process.stderr.write(`${l.error.traceback}\n`)),l.exitCode!==0&&process.exit(l.exitCode)}catch(e){H(e)}})}function Li(e){return`${e.name} (${e.id})`}async function Ri(e,t){if(t.startsWith(`team_`))return e.teams.get(t);let n=(await e.teams.list()).filter(e=>e.name.toLowerCase()===t.toLowerCase());if(n.length===0)throw Error(`Team not found: ${t}`);if(n.length>1)throw Error(`Team name is ambiguous: ${t}. Use a team id instead.`);return n[0]}async function X(e,t,n){if(t)return Ri(e,t);let r=vt(n);if(!r.activeTeamId)throw Error("No active team. Run `tangle team switch <team>` or pass `--team <team>`.");return e.teams.get(r.activeTeamId)}function zi(e,t){yt({id:e.id,name:e.name},t)}function Bi(e){bt(e)}const Vi=[{flag:`--git-token`,guidance:`Use --git-token-env <NAME> or --git-token-stdin so the secret never appears in argv (visible to other processes via /proc/<pid>/cmdline) or in shell history.`},{flag:`--storage-secret-access-key`,guidance:`Use --storage-secret-access-key-env <NAME> or --storage-secret-access-key-stdin so the secret never appears in argv (visible to other processes via /proc/<pid>/cmdline) or in shell history.`},{flag:`--backend-api-key`,guidance:`Use --backend-api-key-env <NAME> or --backend-api-key-stdin so the BYOK secret never appears in argv (visible to other processes via /proc/<pid>/cmdline) or in shell history.`}];function Hi(e){for(let{flag:t,guidance:n}of Vi){let r=`${t}=`;if(e.some(e=>e===t||e.startsWith(r)))throw Error(`Refusing to read secret from ${t} on the command line. ${n}`)}}async function Ui(e){let t=typeof e.envVarName==`string`&&e.envVarName.length>0?e.envVarName:null,n=!!e.fromStdin;if(t&&n)throw Error(`Pass either ${e.flagPrefix}-env or ${e.flagPrefix}-stdin, not both`);if(t){let n=process.env[t];if(!n||n.length===0)throw Error(`${e.flagPrefix}-env points at ${t}, but that environment variable is empty or unset`);return n}if(n){let t=await Jt();if(t.length===0)throw Error(`${e.flagPrefix}-stdin received empty input on stdin`);return t}}function Wi(e){let t=e.split(`/`);return t.length>=2?{provider:t[0],model:t.slice(1).join(`/`)}:{model:e}}function Gi(){let e=new t(`sandbox`).description(`Manage sandboxes`);return e.command(`create`).description(`Create a new sandbox`).option(`-n, --name <name>`,`Sandbox name`).option(`-e, --environment <environment>`,`Environment name (e.g. universal, node, python)`).option(`-i, --image <image>`,`Alias for --environment (deprecated)`).option(`--bare`,`Create a bare sandbox without the agent runtime`).option(`--ssh`,`Enable SSH access`).option(`--ssh-key <key>`,`SSH public key for authentication`).option(`--ssh-keys <names...>`,`Stored SSH key names or IDs for authentication`).option(`--ssh-key-file <paths...>`,`SSH public key file paths for authentication`).option(`--web-terminal`,`Enable web terminal`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`--secret <names...>`,`Secrets to inject as environment variables`).option(`--metadata <entries...>`,`Metadata entries (KEY=VALUE or KEY=JSON)`).option(`--cpu <cores>`,`CPU cores`,`2`).option(`--memory <mb>`,`Memory in MB`,`4096`).option(`--disk <gb>`,`Disk size in GB`,`20`).option(`--accelerator-kind <kind>`,`Accelerator kind, for example nvidia-h100 or amd-mi300x`).option(`--accelerator-count <count>`,`Accelerator device count`,`1`).option(`--accelerator-memory <mb>`,`Minimum accelerator memory in MB`).option(`--lifetime <seconds>`,`Max lifetime in seconds`,`3600`).option(`--idle-timeout <seconds>`,`Idle timeout in seconds`,`900`).option(`--from-snapshot <id>`,`Create the sandbox from a snapshot`).option(`--public-template <id-or-slug>`,`Create the sandbox from a published public template`).option(`--public-template-version <id>`,`Pin creation to a specific published public-template version`).option(`--team <team>`,`Create in a team by id or name`).option(`--personal`,`Create a personal sandbox even when a team is active`).option(`--port <ports...>`,`Ports to expose at creation time`).option(`--git-url <url>`,`Git repository URL to clone during provisioning`).option(`--git-ref <ref>`,`Git branch, tag, or commit to checkout`).option(`--git-depth <depth>`,`Git clone depth`).option(`--git-sparse <paths...>`,`Sparse checkout paths`).option(`--git-token-env <name>`,`Name of an environment variable containing the Git HTTPS auth token`).option(`--git-token-stdin`,`Read the Git HTTPS auth token from stdin`).option(`--git-token <token>`,`[removed] use --git-token-env or --git-token-stdin`).option(`--tool <specs...>`,`Tool versions to preinstall (NAME=VERSION)`).option(`--storage-type <type>`,`BYOS3 storage type (s3, gcs, r2)`).option(`--storage-bucket <name>`,`BYOS3 bucket name`).option(`--storage-endpoint <url>`,`BYOS3 endpoint URL`).option(`--storage-region <region>`,`BYOS3 region`).option(`--storage-prefix <prefix>`,`BYOS3 path prefix`).option(`--storage-access-key-id <id>`,`BYOS3 access key ID`).option(`--storage-secret-access-key-env <name>`,`Name of an environment variable containing the BYOS3 secret access key`).option(`--storage-secret-access-key-stdin`,`Read the BYOS3 secret access key from stdin`).option(`--storage-secret-access-key <key>`,`[removed] use --storage-secret-access-key-env or --storage-secret-access-key-stdin`).option(`--default-role <role>`,`Default permission role (owner, admin, developer, viewer)`).option(`--initial-user <specs...>`,`Initial users (USER_ID or USER_ID:ROLE)`).option(`--multi-user`,`Enable multi-user permissions at creation`).option(`--driver <type>`,`Infrastructure driver (docker, firecracker, host-agent, tangle)`).option(`--driver-criu`,`Enable CRIU checkpointing (firecracker only)`).option(`--driver-region <region>`,`Preferred region for host-agent driver`).option(`--backend <type>`,`Backend agent type (opencode, claude-code, codex, cursor, amp)`).option(`--backend-profile <name>`,`Backend profile name`).option(`--backend-model <model>`,`Model override (format: provider/model)`).option(`--backend-api-key-env <name>`,`Name of an environment variable containing the BYOK backend API key`).option(`--backend-api-key-stdin`,`Read the BYOK backend API key from stdin`).option(`--backend-api-key <key>`,`[removed] use --backend-api-key-env or --backend-api-key-stdin`).option(`--tee <type>`,`Require a TEE backend (any, tdx, nitro, sev-snp, phala-dstack)`).option(`--sealed`,`Request TEE sealed-secret support`).option(`--attestation-nonce <hex|auto>`,`Deploy-time attestation nonce; use auto to generate one`).option(`--attestation-refresh`,`Generate a fresh deploy-time attestation nonce when --tee is set`).option(`--require-attestation`,`Fail unless TEE attestation evidence is returned`).option(`--block-network`,`Block all outbound network traffic`).option(`--allow-list <cidrs>`,`CIDR allowlist for outbound traffic (comma-separated)`).option(`--wait`,`Wait for sandbox to be running`,!0).option(`--timeout <ms>`,`HTTP timeout in milliseconds`,`30000`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{Hi(process.argv);let t=await Ui({envVarName:e.gitTokenEnv,fromStdin:e.gitTokenStdin,flagPrefix:`--git-token`}),n=await Ui({envVarName:e.storageSecretAccessKeyEnv,fromStdin:e.storageSecretAccessKeyStdin,flagPrefix:`--storage-secret-access-key`}),r=await Ui({envVarName:e.backendApiKeyEnv,fromStdin:e.backendApiKeyStdin,flagPrefix:`--backend-api-key`}),i=O({apiKey:e.apiKey,baseUrl:e.baseUrl,timeout:e.timeout?Number.parseInt(e.timeout,10):void 0}),a=j(i),o=L(`Creating sandbox...`);o.start();let s=await ea({client:a,explicitTeam:e.team,personal:e.personal,activeTeamId:i.activeTeamId}),l={};if(e.env)for(let t of e.env){let[e,...n]=t.split(`=`);e&&n.length>0&&(l[e]=n.join(`=`))}let u=e.tool?qi(e.tool,`--tool`,`tool spec`):void 0,d=e.metadata?Ji(e.metadata):void 0,f=Zi(e,t),p=Qi(e,n),ee=$i(e),te=e.port?Xi(e.port,`--port`):void 0,ne=e.driver?{type:e.driver,enableCriu:e.driverCriu||void 0,preferredRegion:e.driverRegion}:void 0,re=e.backend||e.backendProfile||e.backendModel?{type:e.backend??`opencode`,profile:e.backendProfile,model:e.backendModel||r?{...e.backendModel?Wi(e.backendModel):{},apiKey:r}:void 0}:void 0,m=e.blockNetwork||e.allowList||te?{blockOutbound:e.blockNetwork||void 0,allowList:e.allowList?e.allowList.split(`,`).map(e=>e.trim()):void 0,ports:te}:void 0,ie=[...e.sshKey?[e.sshKey]:[],...(e.sshKeyFile??[]).map(e=>c(e,`utf8`).trim())],ae={name:e.name,environment:e.environment??e.image,bare:e.bare||void 0,sshEnabled:e.ssh||!!e.sshKey||ie.length>0||!!e.sshKeys?.length,sshPublicKeys:ie.length>0?ie:void 0,sshKeyIds:e.sshKeys,webTerminalEnabled:e.webTerminal,env:Object.keys(l).length>0?l:void 0,git:f,tools:u,resources:{cpuCores:Number.parseInt(e.cpu,10),memoryMB:Number.parseInt(e.memory,10),diskGB:Number.parseInt(e.disk,10),accelerator:e.acceleratorKind?{kind:aa(String(e.acceleratorKind)),count:oa(String(e.acceleratorCount),`--accelerator-count`),memoryMB:e.acceleratorMemory?oa(String(e.acceleratorMemory),`--accelerator-memory`):void 0}:void 0},maxLifetimeSeconds:Number.parseInt(e.lifetime,10),idleTimeoutSeconds:Number.parseInt(e.idleTimeout,10),storage:p,fromSnapshot:e.fromSnapshot,publicTemplateId:e.publicTemplate,publicTemplateVersionId:e.publicTemplateVersion,teamId:s,secrets:e.secret,metadata:d,driver:ne,backend:re,permissions:ee,network:m},h=e.tee?{tee:e.tee,sealed:e.sealed||void 0,attestationRefresh:e.attestationRefresh||e.attestationNonce===`auto`||void 0}:void 0,g=h?await ce(a,{...ae,confidential:h,attestationNonce:e.attestationNonce??(e.attestationRefresh?`auto`:void 0),requireAttestation:e.requireAttestation??!0}):void 0,_=g?.sandbox??await a.create(ae);e.wait&&(o.text=`Waiting for sandbox to start...`,await _.waitFor(`running`,{timeoutMs:12e4}),await _.refresh()),o.stop(),e.json?N({id:_.id,name:_.name,status:_.status,createdAt:_.createdAt,expiresAt:_.expiresAt,connection:Ki(_.connection),teamId:s,confidential:h,attestation:g?.attestation,attestationNonce:g?.attestationNonce}):(P(`Sandbox created: ${_.id}`),Pt({id:_.id,name:_.name,status:_.status,createdAt:_.createdAt?.toISOString(),expiresAt:_.expiresAt?.toISOString(),connection:_.connection}),s&&console.log(`Team: ${s}`),h&&(console.log(`TEE: ${h.tee}`),console.log(`Attestation: ${g?.attestation?`present`:`not returned`}`),g?.attestationNonce&&console.log(`Attestation nonce: ${g.attestationNonce}`)))}catch(e){H(e)}}),e.command(`attestation <id>`).description(`Fetch TEE attestation evidence for a sandbox`).option(`--nonce <hex|auto>`,`Nonce to bind into a fresh attestation report; use auto to generate one`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=t.nonce===`auto`?le():t.nonce,i=L(`Fetching TEE attestation...`);i.start();let a=await n.get(e);if(!a)throw Error(`Sandbox not found: ${e}`);let o=await a.getTeeAttestation(r?{attestationNonce:r}:void 0);i.stop(),t.json?N(o):(P(`Attestation fetched for ${e}`),console.log(`TEE type: ${o.attestation.tee_type}`),console.log(`Evidence bytes: ${o.attestation.evidence.length}`),console.log(`Measurement bytes: ${o.attestation.measurement.length}`),console.log(`Timestamp: ${o.attestation.timestamp}`),o.attestationNonce&&console.log(`Nonce: ${o.attestationNonce}`))}catch(e){H(e)}}),e.command(`list`).description(`List all sandboxes`).option(`-s, --status <status>`,`Filter by status (running, stopped, all)`).option(`-l, --limit <n>`,`Limit results`,`50`).option(`--team <team>`,`List sandboxes for a team by id or name`).option(`--personal`,`List personal sandboxes`).option(`--all-scopes`,`List personal and team sandboxes`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=O({apiKey:e.apiKey,baseUrl:e.baseUrl}),n=j(t),r=L(`Fetching sandboxes...`);r.start();let i=await ta({client:n,explicitTeam:e.team,personal:e.personal,allScopes:e.allScopes,activeTeamId:t.activeTeamId}),a=await n.list({status:e.status===`all`?void 0:e.status,limit:Number.parseInt(e.limit,10),scope:i});r.stop(),e.json?N(a):M(a.map(e=>({id:e.id,status:e.status,createdAt:e.createdAt,name:e.name??``})),[{key:`id`,header:`ID`,width:24},{key:`status`,header:`Status`,width:14},{key:`createdAt`,header:`Created`,width:16},{key:`name`,header:`Name`,width:20}])}catch(e){H(e)}}),e.command(`get <id>`).description(`Get sandbox details`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching sandbox...`);r.start();let i=await n.get(e);if(r.stop(),!i)throw Error(`Sandbox not found: ${e}`);t.json?N(i):Pt({id:i.id,name:i.name,status:i.status,createdAt:i.createdAt?.toISOString(),expiresAt:i.expiresAt?.toISOString(),connection:i.connection})}catch(e){H(e)}}),e.command(`delete <id>`).description(`Delete a sandbox`).option(`-f, --force`,`Skip confirmation`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{if(!t.force){let t=(await import(`node:readline`)).createInterface({input:process.stdin,output:process.stdout});if(!await new Promise(n=>{t.question(`Delete sandbox ${e}? [y/N] `,e=>{t.close(),n(e.toLowerCase()===`y`)})})){I(`Cancelled.`);return}}let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Deleting sandbox...`);r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);await i.delete(),r.stop(),P(`Sandbox ${e} deleted.`)}catch(e){H(e)}}),e.command(`stop <id>`).description(`Stop a running sandbox`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Stopping sandbox...`);r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);await i.stop(),r.stop(),P(`Sandbox ${e} stopped.`)}catch(e){H(e)}}),e.command(`resume <id>`).description(`Resume a stopped sandbox`).option(`--wait`,`Wait for sandbox to be running`,!0).option(`-t, --timeout <ms>`,`Resume timeout in milliseconds`,`120000`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=Number.parseInt(t.timeout,10);if(!Number.isFinite(n)||n<=0)throw Error(`--timeout must be a positive number of milliseconds`);let r=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),i=L(`Resuming sandbox...`);i.start();let a=await r.get(e);if(!a)throw Error(`Sandbox not found: ${e}`);await a.resume({timeoutMs:n}),t.wait&&(i.text=`Waiting for sandbox to start...`,await a.waitFor(`running`,{timeoutMs:n})),i.stop(),P(`Sandbox ${e} resumed.`)}catch(e){H(e)}}),e.command(`network <id>`).description(`Update network configuration for a sandbox`).option(`--block-outbound`,`Block all outbound network traffic`).option(`--allow-list <cidrs>`,`CIDR allowlist for outbound traffic (comma-separated)`).option(`--clear`,`Clear all network restrictions (allow all traffic)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Updating network configuration...`);r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);if(t.clear)await i.network.update({blockOutbound:!1,allowList:[]});else if(t.blockOutbound)await i.network.update({blockOutbound:!0});else if(t.allowList){let e=t.allowList.split(`,`).map(e=>e.trim());await i.network.update({allowList:e})}else{r.stop();let e=await i.network.getConfig();t.json?N(e):(I(`Network Configuration:`),e.blockOutbound?I(` Block Outbound: true (all outbound traffic blocked)`):e.allowList&&e.allowList.length>0?I(` Allow List: ${e.allowList.join(`, `)}`):I(` No restrictions (all traffic allowed)`),e.ports&&e.ports.length>0&&I(` Exposed Ports: ${e.ports.join(`, `)}`));return}r.stop();let a=await i.network.getConfig();t.json?N(a):(P(`Network configuration updated.`),a.blockOutbound?I(` Block Outbound: true`):a.allowList&&a.allowList.length>0?I(` Allow List: ${a.allowList.join(`, `)}`):I(` All traffic allowed`))}catch(e){H(e)}}),e.command(`expose <id>`).description(`Expose a port and get a public URL`).option(`-p, --port <port>`,`Port to expose`,`8000`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=Number.parseInt(t.port,10);if(Number.isNaN(r)||r<1||r>65535)throw Error(`Port must be a number between 1 and 65535`);let i=L(`Exposing port ${r}...`);i.start();let a=await n.get(e);if(!a)throw Error(`Sandbox not found: ${e}`);let o=await a.network.exposePort(r);i.stop(),t.json?N({port:r,url:o}):(P(`Port ${r} exposed.`),I(` URL: ${o}`))}catch(e){H(e)}}),e.command(`urls <id>`).description(`List exposed port URLs for a sandbox`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching exposed URLs...`);r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let a=await i.network.listUrls();if(r.stop(),t.json)N(a);else{let e=Object.entries(a);if(e.length===0)I(`No ports exposed.`);else{I(`Exposed Ports:`);for(let[t,n]of e)I(` ${t}: ${n}`)}}}catch(e){H(e)}}),e}function Ki(e){return!e||e.authToken===void 0?e:{...e,authToken:`[REDACTED]`}}function qi(e,t,n){let r={};for(let i of e){let[e,...a]=i.split(`=`);if(!e||a.length===0)throw Error(`${t} expects ${n} values in KEY=VALUE format`);r[e]=a.join(`=`)}return r}function Ji(e){let t={};for(let n of e){let[e,...r]=n.split(`=`);if(!e||r.length===0)throw Error(`--metadata expects values in KEY=VALUE or KEY=JSON format`);t[e]=Yi(r.join(`=`))}return t}function Yi(e){try{return JSON.parse(e)}catch{return e}}function Xi(e,t){return e.map(e=>{let n=Number.parseInt(e,10);if(Number.isNaN(n)||n<1||n>65535)throw Error(`${t} values must be integers between 1 and 65535`);return n})}function Zi(e,t){if(!(!e.gitUrl&&!e.gitRef&&!e.gitDepth&&!e.gitSparse&&!t)){if(!e.gitUrl||typeof e.gitUrl!=`string`)throw Error(`--git-url is required when using git provisioning options`);return{url:e.gitUrl,ref:typeof e.gitRef==`string`?e.gitRef:void 0,depth:typeof e.gitDepth==`string`?oa(e.gitDepth,`--git-depth`):void 0,sparse:Array.isArray(e.gitSparse)?e.gitSparse:void 0,auth:t?{token:t}:void 0}}}function Qi(e,t){if(!(!e.storageType&&!e.storageBucket&&!e.storageEndpoint&&!e.storageRegion&&!e.storagePrefix&&!e.storageAccessKeyId&&!t)){if(typeof e.storageType!=`string`||typeof e.storageBucket!=`string`||typeof e.storageAccessKeyId!=`string`||!t)throw Error(`Storage config requires --storage-type, --storage-bucket, --storage-access-key-id, and one of --storage-secret-access-key-env / --storage-secret-access-key-stdin`);return{type:ia(e.storageType),bucket:e.storageBucket,endpoint:typeof e.storageEndpoint==`string`?e.storageEndpoint:void 0,region:typeof e.storageRegion==`string`?e.storageRegion:void 0,prefix:typeof e.storagePrefix==`string`?e.storagePrefix:void 0,credentials:{accessKeyId:e.storageAccessKeyId,secretAccessKey:t}}}}function $i(e){let t=Array.isArray(e.initialUser)?e.initialUser.map(na):void 0,n=typeof e.defaultRole==`string`?ra(e.defaultRole):void 0,r=e.multiUser?!0:void 0;if(!(!n&&!t&&!r))return{defaultRole:n,initialUsers:t,multiUser:r}}async function ea(e){if(e.explicitTeam&&e.personal)throw Error(`--team and --personal cannot be used together`);if(!e.personal)return e.explicitTeam?(await Ri(e.client,e.explicitTeam)).id:e.activeTeamId}async function ta(e){if([!!e.explicitTeam,!!e.personal,!!e.allScopes].filter(Boolean).length>1)throw Error(`--team, --personal, and --all-scopes are mutually exclusive`);if(e.allScopes)return`all`;if(e.personal)return`personal`;if(e.explicitTeam)return`team:${(await Ri(e.client,e.explicitTeam)).id}`;if(e.activeTeamId)return`team:${e.activeTeamId}`}function na(e){let[t,n]=e.split(`:`);if(!t)throw Error(`--initial-user expects USER_ID or USER_ID:ROLE`);return{userId:t,role:n?ra(n):void 0}}function ra(e){if(e===`owner`||e===`admin`||e===`developer`||e===`viewer`)return e;throw Error(`--default-role and --initial-user roles must be one of owner, admin, developer, viewer`)}function ia(e){if(e===`s3`||e===`gcs`||e===`r2`)return e;throw Error(`--storage-type must be one of s3, gcs, or r2`)}function aa(e){let t=e.trim().toLowerCase();if(/^[a-z0-9][a-z0-9._-]*$/.test(t))return t;throw Error(`--accelerator-kind must contain only letters, numbers, dots, underscores, or hyphens`)}function oa(e,t){let n=Number.parseInt(e,10);if(Number.isNaN(n)||n<1)throw Error(`${t} must be a positive integer`);return n}function sa(){return new t(`search`).description(`Search for text patterns in sandbox files (ripgrep)`).argument(`<id>`,`Sandbox ID`).argument(`<pattern>`,`Search pattern (regex)`).option(`-g, --glob <pattern>`,`File glob filter (e.g. '**/*.ts')`).option(`-n, --max-results <count>`,`Max results to return`).option(`-i, --ignore-case`,`Case-insensitive search`).option(`--json`,`Output as JSON lines`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Searching...`);n.json||i.start();let a=await r.get(e);if(!a)throw Error(`Sandbox not found: ${e}`);let o=0,s=n.maxResults?Number.parseInt(n.maxResults,10):void 0,c={};n.glob&&(c.glob=n.glob),n.ignoreCase&&(c.ignoreCase=!0),s&&(c.maxResults=s);for await(let e of a.search(t,c))if(o===0&&i.stop(),o++,n.json?console.log(JSON.stringify(e)):console.log(`${e.path}:${e.line}:${e.column??0}: ${e.text}`),s&&o>=s)break;i.stop(),o===0&&!n.json&&console.log(`No matches found`)}catch(e){H(e)}})}function ca(){let e=new t(`secret`).description(`Manage secrets`);return e.command(`create`).description(`Create a new secret`).argument(`<name>`,`Secret name (e.g., HF_TOKEN, AWS_ACCESS_KEY)`).argument(`[value]`,`Secret value`).option(`--value-stdin`,`Read secret value from stdin`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=await la({value:t,valueStdin:n.valueStdin,prompt:`Enter value for secret '${e}': `}),a=L(`Creating secret...`);a.start();let o=await r.secrets.create(e,i);a.stop(),n.json?N({name:o.name,createdAt:o.createdAt.toISOString(),updatedAt:o.updatedAt.toISOString()}):(P(`Secret created: ${o.name}`),I(`Use --secrets ${o.name} when creating a sandbox to inject it as an environment variable.`))}catch(e){H(e)}}),e.command(`list`).description(`List all secrets`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=j(O({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=L(`Fetching secrets...`);n.start();let r=await t.secrets.list();n.stop(),e.json?N(r.map(e=>({name:e.name,createdAt:e.createdAt.toISOString(),updatedAt:e.updatedAt.toISOString()}))):r.length===0?(I(`No secrets found.`),I(`Use 'tangle secret create <name> [value]' to create one.`)):V([`Name`,`Created At`,`Updated At`],r.map(e=>[e.name,e.createdAt.toLocaleString(),e.updatedAt.toLocaleString()]))}catch(e){H(e)}}),e.command(`show`).description(`Show a secret value (requires --reveal to print plaintext)`).argument(`<name>`,`Secret name`).option(`--reveal`,`Print the plaintext secret value to stdout. Without this flag the command exits with a redaction notice.`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{if(!t.reveal){process.stderr.write(`Refusing to print secret '${e}' as plaintext. Re-run with --reveal to confirm and write the value to stdout.
135
- `),process.exitCode=1;return}let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching secret...`);r.start();let i=await n.secrets.get(e);r.stop(),process.stderr.write(`WARNING: secret '${e}' is being printed in plaintext. Avoid storing this output in shell history, screenshots, or logs.
136
- `),t.json?N({name:e,value:i}):console.log(i)}catch(e){H(e)}}),e.command(`update`).description(`Update a secret value`).argument(`<name>`,`Secret name`).argument(`[value]`,`New secret value`).option(`--value-stdin`,`Read secret value from stdin`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=await la({value:t,valueStdin:n.valueStdin,prompt:`Enter new value for secret '${e}': `}),a=L(`Updating secret...`);a.start();let o=await r.secrets.update(e,i);a.stop(),n.json?N({name:o.name,createdAt:o.createdAt.toISOString(),updatedAt:o.updatedAt.toISOString()}):P(`Secret updated: ${o.name}`)}catch(e){H(e)}}),e.command(`delete`).description(`Delete a secret`).argument(`<name>`,`Secret name`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl}));if(!t.force&&!await U(`Are you sure you want to delete secret '${e}'? This cannot be undone. (y/N) `)){I(`Cancelled.`);return}let r=L(`Deleting secret...`);r.start(),await n.secrets.delete(e),r.stop(),t.json?N({success:!0,deleted:e}):P(`Secret deleted: ${e}`)}catch(e){H(e)}}),e}async function la(e){if(e.value!==void 0&&e.valueStdin)throw Error(`Provide either a secret value argument or --value-stdin, not both`);if(e.value!==void 0){if(e.value.length===0)throw Error(`Secret value cannot be empty`);return e.value}if(e.valueStdin){let e=await Jt();if(e.length===0)throw Error(`Secret value from stdin cannot be empty`);return e}let t=await qt(e.prompt);if(t.length===0)throw Error(`Secret value cannot be empty`);return t}function ua(){let e=new t(`skill`).description(`Print paths to shipped skill documentation`);return e.command(`path`).description(`Print the absolute path to the SKILL.md shipped with this CLI`).action(()=>{let e=d.dirname(ye(import.meta.url)),t=d.resolve(e,`..`,`SKILL.md`);console.log(t)}),e}function da(){let e=new t(`snapshot`).description(`Manage snapshots`);return e.command(`create <sandbox-id>`).description(`Create a snapshot of a sandbox`).option(`--tags <tags...>`,`Tags for the snapshot`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Creating snapshot...`);r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let a=await i.snapshot({tags:t.tags});r.stop(),t.json?N(a):(P(`Snapshot created: ${a.snapshotId}`),console.log(`Size: ${fa(a.sizeBytes??0)}`))}catch(e){H(e)}}),e.command(`list <sandbox-id>`).description(`List snapshots for a sandbox`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching snapshots...`);r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let a=await i.listSnapshots();r.stop(),t.json?N(a):M(a.map(e=>({...e,size:fa(e.sizeBytes??0)})),[{key:`snapshotId`,header:`ID`,width:24},{key:`createdAt`,header:`Created`,width:16},{key:`size`,header:`Size`,width:12},{key:`sandboxId`,header:`Sandbox`,width:20}])}catch(e){H(e)}}),e.command(`restore <sandbox-id> <snapshot-id>`).description(`Create a new sandbox from a snapshot`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Restoring from snapshot...`);i.start();let a=await r.create({fromSnapshot:t,fromSandboxId:e});await a.waitFor(`running`,{timeoutMs:12e4}),i.stop(),n.json?N({sandboxId:a.id,restoredFrom:t,status:a.status}):(P(`New sandbox created: ${a.id}`),console.log(`Source snapshot: ${t}`))}catch(e){H(e)}}),e.command(`revert <sandbox-id> <snapshot-id>`).description(`Revert an existing sandbox to a snapshot`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Reverting sandbox to snapshot...`);i.start();let a=await r.get(e);if(!a)throw Error(`Sandbox not found: ${e}`);let o=await a.revertToSnapshot(t);await a.refresh(),i.stop(),n.json?N({sandboxId:a.id,snapshotId:o.snapshotId,status:a.status}):(P(`Sandbox reverted: ${a.id}`),console.log(`Source snapshot: ${o.snapshotId}`))}catch(e){H(e)}}),e.command(`delete <sandbox-id> <snapshot-id>`).description(`Delete a sandbox snapshot`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=j(O({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=L(`Deleting snapshot...`);i.start();let a=await r.get(e);if(!a)throw Error(`Sandbox not found: ${e}`);await a.deleteSnapshot(t),i.stop(),n.json?N({success:!0,sandboxId:e,snapshotId:t}):P(`Snapshot deleted: ${t}`)}catch(e){H(e)}}),e}function fa(e){if(e===0)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`,`TB`],r=Math.floor(Math.log(e)/Math.log(t));return`${Number.parseFloat((e/t**r).toFixed(1))} ${n[r]}`}function pa(e,t){return`tangle ssh-proxy ${e.replace(/\/+$/,``)}/v1/sidecar-proxy/${t}/ssh`}function ma(e){return/^[A-Za-z0-9_/:=@%+.,-]+$/.test(e)?e:`'${e.replace(/'/g,`'"'"'`)}'`}function ha(e){return`'${e.replace(/'/g,`''`)}'`}function ga(e){return e===`win32`?`NUL`:`/dev/null`}function _a(e,t){return t===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN=${ha(`<token>`)}; ssh ${e.map(ha).join(` `)}`:`TANGLE_SSH_PROXY_AUTH_TOKEN=${ma(`<token>`)} ssh ${e.map(ma).join(` `)}`}function va(e){return e instanceof Date?e.toISOString():String(e)}function ya(e,t){return`Sandbox name is ambiguous: ${e}. Use a sandbox id instead.\n${t.map(e=>`- ${e.id} (status: ${e.status}, created: ${va(e.createdAt)})`).join(`
137
- `)}`}function ba(e){return e.activeTeamId?`team:${e.activeTeamId}`:void 0}async function xa(e,t,n){let r=await e.get(n);if(r||n.startsWith(`sandbox-`)){if(!r)throw Error(`Sandbox not found: ${n}`);return r}let i=(await e.list({scope:ba(t)})).filter(e=>e.name?.toLowerCase()===n.toLowerCase());if(i.length===0)throw Error(`Sandbox not found: ${n}`);if(i.length>1)throw Error(ya(n,i));return i[0]}async function Sa(e){if(e.status===`stopped`){I(`Sandbox ${e.id} is stopped. Resuming...`);try{await e.resume(),await e.waitFor(`running`,{timeoutMs:12e4})}catch(t){let n=t instanceof Error?t.message:String(t);throw Error(`Failed to resume sandbox ${e.id}: ${n}. Run \`tangle sandbox resume ${e.id}\` and retry SSH.`)}}}function Ca(e){return e.connection!==void 0&&!e.connection.ssh}function wa(){F(`SSH is not enabled for this sandbox.`),I(`Create a sandbox with --ssh to enable SSH access.`),process.exit(1)}function Ta(e,t=[],n=process.platform){let r=ga(n);return[`-o`,`ProxyCommand=${e.proxyCommand}`,`-o`,`StrictHostKeyChecking=no`,`-o`,`UserKnownHostsFile=${r}`,`-o`,`GlobalKnownHostsFile=${r}`,`-o`,`LogLevel=ERROR`,`-o`,`ServerAliveInterval=15`,`-o`,`ServerAliveCountMax=4`,`-o`,`TCPKeepAlive=yes`,`${e.username}@localhost`,`-p`,String(e.port),...t]}function Ea(){return new t(`ssh`).description(`Open SSH session to a sandbox`).argument(`<ref>`,`Sandbox ID or name`).argument(`[sshArgs...]`,`Extra args passed through to ssh`).option(`-i, --identity-file <path>`,`Private key file to pass to ssh`).option(`--print`,`Print SSH command instead of connecting`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).allowUnknownOption(!0).action(async(e,t,n)=>{try{let r=O({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=j(r),a=L(`Getting SSH credentials...`);a.start();let o=await xa(i,r,e);if(Ca(o)){a.stop(),wa();return}await Sa(o);let s=await o.ssh();if(a.stop(),!s){wa();return}let c={...s,proxyCommand:pa(r.baseUrl,o.id)};if(!r.apiKey)throw Error(`SSH proxy requires API key auth. Set TANGLE_API_KEY or pass --api-key.`);let l=Ta(c,[...n.identityFile?[`-i`,n.identityFile,`-o`,`IdentitiesOnly=yes`]:[],...t]);if(n.print){console.log(_a(l,process.platform));return}I(`Connecting via tunnel...`);let u=pe(`ssh`,l,{stdio:`inherit`,env:{...process.env,TANGLE_SSH_PROXY_AUTH_TOKEN:r.apiKey}});u.on(`error`,e=>{e.code===`ENOENT`&&(F(`SSH client not found. Please install OpenSSH.`),process.exit(1)),H(e)}),u.on(`exit`,e=>{process.exit(e??0)})}catch(e){H(e)}})}function Da(){let e=new t(`ssh-keys`).description(`Manage SSH keys`);return e.command(`list`).description(`List SSH keys`).option(`--json`,`Output as JSON`).action(async e=>{let t=L(`Fetching SSH keys...`);try{t.start();let n=await j(O(e)).sshKeys.list();t.stop(),e.json?N({sshKeys:n}):n.length===0?I(`No SSH keys found.`):V([`Name`,`Type`,`Fingerprint`,`Created`],n.map(e=>[e.name,e.keyType,e.fingerprint,e.createdAt.toLocaleString()]))}catch(e){t.stop(),H(e)}}),e.command(`add`).description(`Add SSH key`).argument(`<name>`,`SSH key name`).requiredOption(`--key-file <path>`,`Public key file path`).option(`--json`,`Output as JSON`).action(async(e,t)=>{let n=L(`Adding SSH key...`);try{let r=c(t.keyFile,`utf8`).trim();n.start();let i=await j(O(t)).sshKeys.create(e,r);n.stop(),t.json?N({sshKey:i}):P(`Added SSH key ${i.name} (${i.fingerprint})`)}catch(e){n.stop(),H(e)}}),e.command(`delete`).description(`Delete SSH key`).argument(`<name>`,`SSH key name or ID`).action(async(e,t)=>{let n=L(`Deleting SSH key...`);try{n.start(),await j(O(t)).sshKeys.delete(e),n.stop(),P(`Deleted SSH key ${e}`)}catch(e){n.stop(),H(e)}}),e}function Oa(e,t=1){process.stderr.write(`${e}\n`),process.exit(t)}function ka(){return new t(`ssh-proxy`).description(`SSH proxy helper — pipes stdin/stdout to WebSocket`).argument(`<sidecar-url>`,`Sidecar WebSocket URL`).action(async e=>{let t=process.env.TANGLE_SSH_PROXY_AUTH_TOKEN;t||Oa(`TANGLE_SSH_PROXY_AUTH_TOKEN not set`);let n=new be(new URL(e.replace(/^http/,`ws`)),{headers:{Authorization:`Bearer ${t}`},perMessageDeflate:!1}),r;function i(){r&&=(clearInterval(r),void 0)}n.on(`open`,()=>{r=setInterval(()=>{n.readyState===be.OPEN&&n.ping()},15e3),r.unref?.(),process.stdin.on(`data`,e=>{n.readyState===be.OPEN&&n.send(e,{binary:!0,compress:!1})}),process.stdin.on(`end`,()=>n.close(1e3))}),n.on(`message`,e=>{let t=Buffer.isBuffer(e)?e:Array.isArray(e)?Buffer.concat(e):Buffer.from(e);process.stdout.write(t)}),n.on(`error`,e=>{i(),Oa(`WebSocket error: ${e.message}`)}),n.on(`close`,e=>{i(),process.exit(e===1e3?0:1)}),process.stdin.on(`error`,()=>n.close())})}const Aa=[`claude-code`,`opencode`,`codex`,`kimi-code`],ja=[`session`,`project`,`read-only`],Ma={min:1,max:15},Na=process.env.TANGLE_ROUTER_URL??`https://router.tangle.tools/v1`;function Pa(e){let t=e.harness??`claude-code`;if(!Aa.includes(t))throw Error(`Unknown --harness '${t}'. Supported: ${Aa.join(`, `)}.`);let n=e.tokenScope??`session`;if(!ja.includes(n))throw Error(`Unknown --token-scope '${n}'. Supported: ${ja.join(`, `)}.`);let r=Fa(e.maxTokens,2e5,`--max-tokens`),i=Fa(e.maxIterations,50,`--max-iterations`),a=Fa(e.tokenTtl,10,`--token-ttl`);if(a<Ma.min||a>Ma.max)throw Error(`--token-ttl ${a} out of range; the SDK clamps to [${Ma.min}, ${Ma.max}] minutes.`);let o=e.maxWorkers===void 0?void 0:Fa(e.maxWorkers,0,`--max-workers`);return{harness:t,...e.model?{model:e.model}:{},maxTokens:r,maxIterations:i,tokenScope:n,tokenTtl:a,...o===void 0?{}:{maxWorkers:o}}}function Fa(e,t,n){if(e===void 0)return t;let r=Number.parseInt(e,10);if(!Number.isFinite(r)||r<=0)throw Error(`${n} must be a positive integer, got '${e}'.`);return r}function Ia(e){let t={maxTokens:e.maxTokens,maxIterations:e.maxIterations};return e.maxWorkers===void 0?{budget:t}:{budget:t,perWorker:{maxTokens:Math.max(1,Math.floor(e.maxTokens/e.maxWorkers)),maxIterations:Math.max(1,Math.floor(e.maxIterations/e.maxWorkers))}}}function La(e){let{client:t,scope:n,ttlMinutes:i,onScope:a}=e,o={async create(o){let s=await t.create(Ra(o)),c={scope:n,ttlMinutes:i,...n===`session`?{sessionId:e.sessionIdFor?.(s)??`supervise-${r()}`}:{}},l=await s.mintScopedToken(c);return a({id:s.id,scope:l.scope,expiresAt:l.expiresAt,status:`spawned`}),s}};return typeof t.criuStatus==`function`&&(o.criuStatus=t.criuStatus.bind(t)),o}function Ra(e){if(!e?.env)return e;let{TANGLE_API_KEY:t,SANDBOX_API_KEY:n,...r}=e.env;return{...e,env:r}}function za(e){if(e.kind===`no-winner`)return{text:``,tokenUsage:{input:0,output:0},costUsd:0,status:`no-winner (${e.reason})`};let t=e.out;return{text:typeof t==`string`?t:Ba(t)?t.content:JSON.stringify(t),tokenUsage:{input:e.spentTotal.tokens.input,output:e.spentTotal.tokens.output},costUsd:e.spentTotal.usd,status:`winner`}}function Ba(e){return typeof e==`object`&&!!e&&typeof e.content==`string`}const Va={makeClient:e=>j(O({apiKey:e.apiKey,baseUrl:e.baseUrl})),resolveRouter:e=>({routerBaseUrl:Na,routerKey:O({apiKey:e.apiKey}).apiKey,model:e.model}),supervise:xe};async function Ha(e,t,n,i=Va){let a=i.makeClient({apiKey:n.apiKey,baseUrl:n.baseUrl}),{budget:o,perWorker:s}=Ia(t),c=[],l=La({client:a,scope:t.tokenScope,ttlMinutes:t.tokenTtl,onScope:e=>{if(c.push(e),!n.json){let n=`ttl ${t.tokenTtl}m`;I(`worker ${e.id} [${e.scope} token ${n}] spawned`)}}}),u=Se({backend:`sandbox`,harness:t.harness,sandboxClient:l,maxIterations:1}),d={name:`supervisor`,...t.model?{model:t.model}:{}},f=i.resolveRouter({apiKey:n.apiKey,model:t.model??`deepseek-v4-flash`}),p=za(await i.supervise(d,{goal:e},{budget:o,makeWorkerAgent:u,router:f,...s?{perWorker:s}:{},...t.model?{allowedModels:[t.model]}:{},runId:`supervise-${r()}`})),ee=p.status===`winner`?`settled`:`failed`;for(let e of c)e.status=ee,n.json||I(`worker ${e.id} [${e.scope} token ttl ${t.tokenTtl}m] settled (${e.status})`);return{task:e,result:p.text,workers:c,tokenUsage:p.tokenUsage,costUsd:p.costUsd,status:p.status}}function Ua(){let e=new t(`supervise`);return e.description(`Run a budget-conserving supervisor that spawns isolated sandbox workers to deliver a task. Each worker box mints a short-lived scoped token instead of receiving the root API key.`).argument(`<task>`,`What the supervisor should accomplish`).option(`--harness <name>`,`Worker harness (${Aa.join(` | `)})`,`claude-code`).option(`--model <id>`,`Model for the supervisor + workers`).option(`--max-tokens <n>`,`Conserved token budget for the whole run`,`200000`).option(`--max-iterations <n>`,`Conserved iteration budget for the whole run`,`50`).option(`--token-scope <scope>`,`Per-worker token scope (${ja.join(` | `)})`,`session`).option(`--token-ttl <min>`,`Per-worker token TTL in minutes (SDK clamps to [1, 15])`,`10`).option(`--max-workers <n>`,`Bound the fanout; each worker reserves floor(max-tokens / n) tokens and floor(max-iterations / n) iterations`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=Pa({harness:t.harness,model:t.model,maxTokens:t.maxTokens,maxIterations:t.maxIterations,tokenScope:t.tokenScope,tokenTtl:t.tokenTtl,maxWorkers:t.maxWorkers});t.json||(I(`Supervising: ${e}`),I(`harness=${n.harness} budget=${n.maxTokens}tok/${n.maxIterations}it scope=${n.tokenScope} ttl=${n.tokenTtl}m`),console.log());let r=await Ha(e,n,{apiKey:t.apiKey,baseUrl:t.baseUrl,json:t.json});if(t.json){N(r),r.status!==`winner`&&(process.exitCode=1);return}if(console.log(),r.status!==`winner`)throw Error(`Supervisor finished without a winner: ${r.status}`);console.log(r.result),console.log(),R({"Input Tokens":r.tokenUsage.input,"Output Tokens":r.tokenUsage.output,Cost:`$${r.costUsd.toFixed(4)}`})}catch(e){H(e,t.json)}}),e}function Wa(){let e=new t(`team`).description(`Manage teams`);return e.command(`list`).description(`List teams for the current account`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async e=>{try{let t=O(e),n=j(t),r=e.json?null:L(`Fetching teams...`);r?.start();let i=await n.teams.list();if(r?.stop(),e.json){N({teams:i,activeTeamId:t.activeTeamId??null});return}M(i.map(e=>({active:e.id===t.activeTeamId,id:e.id,name:e.name,role:e.currentUserRole,members:e.memberCount})),[{key:`active`,header:`Active`,width:8},{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:24},{key:`role`,header:`Role`,width:10},{key:`members`,header:`Members`,width:10}])}catch(e){H(e)}}),e.command(`create <name>`).description(`Create a team`).option(`--org-id <id>`,`External organization id`).option(`--no-switch`,`Do not set the new team as active`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=t.json?null:L(`Creating team...`);i?.start();let a=await r.teams.create({name:e,orgId:t.orgId});if(t.switch&&zi(a,n.profile),i?.stop(),t.json){N({team:a,active:!!t.switch});return}P(`Team created: ${Li(a)}`),t.switch&&P(`Active team set to ${a.name}`)}catch(e){H(e)}}),e.command(`switch <team>`).description(`Set the active team for the current profile`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=await Ri(j(n),e);if(zi(r,n.profile),t.json){N({team:r,activeTeamId:r.id});return}P(`Active team set to ${Li(r)}`)}catch(e){H(e)}}),e.command(`current`).description(`Show the active team for the current profile`).option(`--json`,`Output as JSON`).option(`--profile <profile>`,`Credential profile`).action(e=>{try{let t=vt(e.profile);if(e.json){N(t.activeTeamId?t:{activeTeamId:null});return}if(!t.activeTeamId){console.log(`No active team.`);return}R({ID:t.activeTeamId,Name:t.activeTeamName})}catch(e){H(e)}}),e.command(`clear`).description(`Clear the active team for the current profile`).option(`--json`,`Output as JSON`).option(`--profile <profile>`,`Credential profile`).action(e=>{try{if(Bi(e.profile),e.json){N({activeTeamId:null});return}P(`Active team cleared.`)}catch(e){H(e)}}),e.command(`members [team]`).description(`List team members`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=await X(r,e,n.profile),a=await r.teams.listMembers(i.id);if(t.json){N({team:i,members:a});return}M(a.map(e=>({id:e.id,email:e.customerEmail,role:e.role,status:e.status,joinedAt:e.joinedAt})),[{key:`id`,header:`ID`,width:36},{key:`email`,header:`Email`,width:28},{key:`role`,header:`Role`,width:10},{key:`status`,header:`Status`,width:10},{key:`joinedAt`,header:`Joined`,width:16}])}catch(e){H(e)}}),e.command(`update-member <member-id>`).description(`Update a team member role`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).requiredOption(`--role <role>`,`Role: admin, member, viewer`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=await X(r,t.team,n.profile),a=Ga(t.role),o=await r.teams.updateMember(i.id,e,{role:a});if(t.json){N({team:i,member:o});return}P(`Member updated: ${o.customerEmail}`),R({Team:i.name,Role:o.role,Status:o.status})}catch(e){H(e)}}),e.command(`invite <email>`).description(`Invite a user to a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--role <role>`,`Role: admin, member, viewer`,`member`).option(`--ttl-hours <hours>`,`Invitation lifetime in hours`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=await X(r,t.team,n.profile),a=Ga(t.role),o=await r.teams.invite(i.id,{email:e,role:a,ttlHours:t.ttlHours?Number.parseInt(t.ttlHours,10):void 0});if(t.json){N({team:i,invitation:o});return}P(`Invitation created for ${o.email}`),R({Team:i.name,Role:o.role,Expires:o.expiresAt,"Invitation ID":o.id}),P(`Re-run with --json to retrieve the invitation token for sharing.`)}catch(e){H(e)}}),e.command(`leave [team]`).description(`Leave a team as the current user`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=await X(r,e,n.profile);if(!t.force&&!t.json&&!await U(`Leave team '${i.name}'? (y/N) `))return;if(await r.teams.leave(i.id),n.activeTeamId===i.id&&Bi(n.profile),t.json){N({success:!0,teamId:i.id});return}P(`Left team: ${i.name}`)}catch(e){H(e)}}),e.command(`transfer <new-owner-customer-id> [team]`).description(`Transfer team ownership to another active member`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t,n)=>{try{let r=O(n),i=j(r),a=await X(i,t,r.profile);if(!n.force&&!n.json&&!await U(`Transfer ownership of '${a.name}' to ${e}? This cannot be undone without the new owner's cooperation. (y/N) `))return;if(await i.teams.transferOwnership(a.id,e),n.json){N({success:!0,teamId:a.id,newOwnerCustomerId:e});return}P(`Ownership transferred for ${a.name}`)}catch(e){H(e)}}),e.addCommand(Ka()),e.addCommand(qa()),e.command(`invitations [team]`).description(`List pending and historical team invitations`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=await X(r,e,n.profile),a=await r.teams.listInvitations(i.id);if(t.json){N({team:i,invitations:a});return}M(a.map(e=>({id:e.id,email:e.email,role:e.role,status:e.status,expiresAt:e.expiresAt})),[{key:`id`,header:`ID`,width:38},{key:`email`,header:`Email`,width:28},{key:`role`,header:`Role`,width:10},{key:`status`,header:`Status`,width:12},{key:`expiresAt`,header:`Expires`,width:16}])}catch(e){H(e)}}),e.command(`accept <token>`).description(`Accept a team invitation`).option(`--no-switch`,`Do not set the accepted team as active`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=await r.teams.acceptInvitation(e),a=t.switch===!1?null:await r.teams.get(i.teamId);if(a&&zi(a,n.profile),t.json){N({member:i,activeTeamId:a?.id??null});return}P(`Invitation accepted for team ${i.teamId}`),a&&P(`Active team set to ${a.name}`)}catch(e){H(e)}}),e.command(`revoke-invitation <invitation-id>`).description(`Revoke a pending team invitation`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{if(await j(O(t)).teams.revokeInvitation(e),t.json){N({success:!0,invitationId:e});return}P(`Invitation revoked: ${e}`)}catch(e){H(e)}}),e.command(`remove-member <member-id>`).description(`Remove a member from a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=await X(r,t.team,n.profile);if(await r.teams.removeMember(i.id,e),t.json){N({success:!0,teamId:i.id,memberId:e});return}P(`Member removed: ${e}`)}catch(e){H(e)}}),e}function Ga(e){if(e===`admin`||e===`member`||e===`viewer`)return e;throw Error(`Role must be one of: admin, member, viewer`)}function Ka(){let e=new t(`secret`).description(`Manage team secrets`);return e.command(`list [team]`).description(`List team secret names`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=await X(r,e,n.profile),a=await r.teams.listSecrets(i.id);if(t.json){N({team:i,secrets:a});return}M(a.map(e=>({name:e.name,updatedAt:e.updatedAt,updatedBy:e.updatedBy})),[{key:`name`,header:`Name`,width:28},{key:`updatedAt`,header:`Updated`,width:24},{key:`updatedBy`,header:`Updated By`,width:28}])}catch(e){H(e)}}),e.command(`set <name> [value]`).description(`Create or replace a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--value-stdin`,`Read secret value from stdin`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t,n)=>{try{let r=O(n),i=j(r),a=await X(i,n.team,r.profile),o=await Ja({value:t,valueStdin:n.valueStdin,prompt:`Enter value for team secret '${e}': `}),s=await i.teams.upsertSecret(a.id,e,o);if(n.json){N({team:a,secret:s});return}P(`Team secret saved: ${s.name}`)}catch(e){H(e)}}),e.command(`delete <name>`).description(`Delete a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=await X(r,t.team,n.profile);if(!t.force&&!t.json&&!await U(`Delete team secret '${e}' from '${i.name}'? (y/N) `))return;if(await r.teams.deleteSecret(i.id,e),t.json){N({success:!0,teamId:i.id,name:e});return}P(`Team secret deleted: ${e}`)}catch(e){H(e)}}),e.command(`reveal <name>`).description(`Reveal a team secret value`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=await X(r,t.team,n.profile),a=await r.teams.revealSecret(i.id,e);if(t.json){N({teamId:i.id,...a});return}console.log(a.value)}catch(e){H(e)}}),e}function qa(){let e=new t(`templates`).description(`Manage team golden-path templates`);return e.command(`list [team]`).description(`List a team's golden-path templates`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=await X(r,e,n.profile),a=await r.teams.listTemplates(i.id);if(t.json){N({team:i,templates:a});return}if(a.length===0){console.log(`No templates yet for ${i.name}.`);return}M(a.map(e=>({id:e.id,name:e.name,environment:e.environment,snapshot:`${e.snapshotId.slice(0,12)}…`,updated:e.updatedAt})),[{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:28},{key:`environment`,header:`Env`,width:14},{key:`snapshot`,header:`Snapshot`,width:16},{key:`updated`,header:`Updated`,width:24}])}catch(e){H(e)}}),e.command(`create <name> <snapshot-id>`).description(`Create a golden-path template from a snapshot`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`-d, --description <description>`,`Human-readable description shown in the dashboard`).option(`-e, --environment <environment>`,`Default environment to apply (defaults to 'universal')`).option(`--config <json>`,`Optional JSON config object merged into sandboxes created from this template`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t,n)=>{try{let r=O(n),i=j(r),a=await X(i,n.team,r.profile),o;if(n.config)try{let e=JSON.parse(n.config);if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`--config must be a JSON object`);o=e}catch(e){throw Error(`--config is not valid JSON: ${e instanceof Error?e.message:String(e)}`)}let s=await i.teams.createTemplate(a.id,{name:e,snapshotId:t,description:n.description,environment:n.environment,config:o});if(n.json){N({team:a,template:s});return}P(`Team template created: ${s.name} (${s.id})`)}catch(e){H(e)}}),e.command(`delete <template-id>`).description(`Delete a team golden-path template`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=O(t),r=j(n),i=await X(r,t.team,n.profile);if(!t.force&&!t.json&&!await U(`Delete template '${e}' from '${i.name}'? (y/N) `))return;if(await r.teams.deleteTemplate(i.id,e),t.json){N({success:!0,teamId:i.id,templateId:e});return}P(`Team template deleted: ${e}`)}catch(e){H(e)}}),e}async function Ja(e){if(e.value!==void 0&&e.valueStdin)throw Error(`Provide either a secret value argument or --value-stdin, not both`);if(e.value!==void 0){if(e.value.length===0)throw Error(`Secret value cannot be empty`);return e.value}if(e.valueStdin){let e=await Jt();if(e.length===0)throw Error(`Secret value from stdin cannot be empty`);return e}let t=await qt(e.prompt);if(t.length===0)throw Error(`Secret value cannot be empty`);return t}function Ya(){let e=new t(`template`).description(`Manage published public templates`);return e.command(`list`).option(`-q, --query <query>`,`Search query`).option(`--tag <tag>`,`Filter by tag`).option(`--featured`,`Show featured templates only`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=j(O(e)),n=e.featured?await t.publicTemplates.featured():await t.publicTemplates.list({query:e.query,tag:e.tag});if(e.json){N({templates:n});return}M(n.map(e=>({slug:e.slug,name:e.name,forks:e.forkCount,sandboxes:e.sandboxCount,updated:e.updatedAt})),[{key:`slug`,header:`Slug`,width:28},{key:`name`,header:`Name`,width:28},{key:`forks`,header:`Forks`,width:8},{key:`sandboxes`,header:`Sandboxes`,width:12},{key:`updated`,header:`Updated`,width:24}])}catch(e){H(e)}}),e.command(`get <id-or-slug>`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await j(O(t)).publicTemplates.get(e);if(t.json){N({template:n});return}N(n)}catch(e){H(e)}}),e.command(`versions <id-or-slug>`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await j(O(t)).publicTemplates.versions(e);if(t.json){N({versions:n});return}M(n.map(e=>({...e})),[{key:`id`,header:`Version ID`,width:38},{key:`versionNumber`,header:`Version`,width:8},{key:`snapshotId`,header:`Snapshot`,width:20},{key:`createdAt`,header:`Created`,width:24}])}catch(e){H(e)}}),e.command(`publish <name> <snapshot-id> <sandbox-id>`).option(`--slug <slug>`,`Stable public slug`).option(`-d, --description <description>`,`Template description`).option(`--readme <markdown>`,`README markdown`).option(`--tags <tags...>`,`Template tags`).option(`--release-notes <text>`,`Release notes`).option(`--team-id <id>`,`Publish under a team`).option(`--forked-from <id>`,`Fork source template id`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n,r)=>{try{let i=await j(O(r)).publicTemplates.publish({name:e,slug:r.slug,description:r.description,snapshotId:t,sourceSandboxId:n,readmeMarkdown:r.readme,tags:r.tags,releaseNotes:r.releaseNotes,teamId:r.teamId,forkedFromTemplateId:r.forkedFrom});if(r.json){N({template:i});return}P(`Published template: ${i.slug}`)}catch(e){H(e)}}),e.command(`publish-version <id-or-slug> <snapshot-id> <sandbox-id>`).option(`--readme <markdown>`,`README markdown`).option(`--tags <tags...>`,`Template tags`).option(`--release-notes <text>`,`Release notes`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n,r)=>{try{let i=await j(O(r)).publicTemplates.publishVersion(e,{snapshotId:t,sourceSandboxId:n,readmeMarkdown:r.readme,tags:r.tags,releaseNotes:r.releaseNotes});if(r.json){N({version:i});return}P(`Published template version: ${i.id}`)}catch(e){H(e)}}),e}function Xa(){let e=new t(`tools`).description(`Manage language runtimes and tools in a sandbox (via mise)`);return e.command(`list`).alias(`ls`).description(`List installed tools in a sandbox`).argument(`<id>`,`Sandbox ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=j(O({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=L(`Fetching tools...`);t.json||r.start();let i=await n.get(e);if(!i)throw Error(`Sandbox not found: ${e}`);let a=await i.tools.list();r.stop(),t.json?N(a):a.length===0?console.log(`No tools installed`):V([`Tool`,`Version`,`Active`],a.map(e=>[e.name,e.version,e.active?`yes`:`no`]))}catch(e){H(e)}}),e.command(`install`).description(`Install a tool version`).argument(`<id>`,`Sandbox ID`).argument(`<tool>`,`Tool name (e.g. node, python, go)`).argument(`<version>`,`Version to install (e.g. 20, 3.12, latest)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n,r)=>{try{let i=j(O({apiKey:r.apiKey,baseUrl:r.baseUrl})),a=L(`Installing ${t}@${n}...`);r.json||a.start();let o=await i.get(e);if(!o)throw Error(`Sandbox not found: ${e}`);await o.tools.install(t,n),a.stop(),r.json?N({tool:t,version:n,installed:!0}):P(`Installed ${t}@${n}`)}catch(e){H(e)}}),e.command(`use`).description(`Activate a tool version for the current session`).argument(`<id>`,`Sandbox ID`).argument(`<tool>`,`Tool name`).argument(`<version>`,`Version to activate`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n,r)=>{try{let i=await j(O({apiKey:r.apiKey,baseUrl:r.baseUrl})).get(e);if(!i)throw Error(`Sandbox not found: ${e}`);await i.tools.use(t,n),P(`Activated ${t}@${n}`)}catch(e){H(e)}}),e.command(`run`).description(`Run a command with a specific tool`).argument(`<id>`,`Sandbox ID`).argument(`<tool>`,`Tool name`).argument(`<args...>`,`Command arguments`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n,r)=>{try{let i=j(O({apiKey:r.apiKey,baseUrl:r.baseUrl})),a=L(`Running ${t} ${n.join(` `)}...`);r.json||a.start();let o=await i.get(e);if(!o)throw Error(`Sandbox not found: ${e}`);let s=await o.tools.run(t,n);a.stop(),r.json?N(s):(s.stdout&&process.stdout.write(s.stdout),s.stderr&&process.stderr.write(s.stderr),s.exitCode!==0&&process.exit(s.exitCode))}catch(e){H(e)}}),e}function Za(){let e=new t(`traces`).description(`Read hosted agent traces, spans, and eval-runs from Tangle Intelligence`);return e.command(`list`).description(`List trace summaries (one row per trace), newest first`).option(`--from <iso>`,`ISO-8601 lower bound on received time (inclusive)`).option(`--to <iso>`,`ISO-8601 upper bound on received time (inclusive)`).option(`--model <model>`,`Exact model match (any span carried this model)`).option(`--run <runId>`,`Exact run id match`).option(`--status <status>`,`ERROR | OK`).option(`-q, --query <text>`,`Substring over span name`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Page size (clamped server-side to [1, 200])`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Intelligence API base URL`).action(async e=>{try{let t={from:e.from,to:e.to,model:e.model,runId:e.run,status:e.status===void 0?void 0:co(e.status),q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:mo(e.limit)},n=$a(e),r=e.json?null:L(`Fetching traces...`);r?.start();let i=await n.listTraces(t);if(r?.stop(),e.json)return N(i);no(i.items),oo(i.nextCursor)}catch(t){to(t,e)}}),e.command(`get <traceId>`).description(`Show one trace's spans. Streams NDJSON to stdout with --ndjson.`).option(`--ndjson`,`Stream the full span set as NDJSON to stdout`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Spans per page`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Intelligence API base URL`).action(async(e,t)=>{try{let n=$a(t);if(t.ndjson){await eo(n,e);return}let r=t.json?null:L(`Fetching trace spans...`);r?.start();let i=await n.getTraceSpans(e,{cursor:t.cursor,limit:t.limit===void 0?void 0:mo(t.limit)});if(r?.stop(),t.json)return N(i);ro(i.items),i.truncated&&R({Spans:`${i.items.length} of ${i.total} (truncated)`}),oo(i.nextCursor)}catch(e){to(e,t)}}),e.addCommand(Qa()),e}function Qa(){let e=new t(`runs`).description(`Read eval-runs pivoted off the trace surface`);return e.command(`list`).description(`List eval-runs, newest first`).option(`--status <status>`,`Run status filter`).option(`--gate <decision>`,`Promotion-gate decision filter`).option(`--label <key:value>`,`Match over the run's labels`).option(`--from <iso>`,`ISO-8601 lower bound on received time`).option(`--to <iso>`,`ISO-8601 upper bound on received time`).option(`-q, --query <text>`,`Substring over run dir`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Page size`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Intelligence API base URL`).action(async e=>{try{let t={status:e.status===void 0?void 0:uo(e.status),gate:e.gate===void 0?void 0:po(e.gate),label:e.label,from:e.from,to:e.to,q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:mo(e.limit)},n=$a(e),r=e.json?null:L(`Fetching runs...`);r?.start();let i=await n.listRuns(t);if(r?.stop(),e.json)return N(i);io(i.items),oo(i.nextCursor)}catch(t){to(t,e)}}),e.command(`get <runId>`).description(`Show a single eval-run`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Intelligence API base URL`).action(async(e,t)=>{try{let n=$a(t),r=t.json?null:L(`Fetching run...`);r?.start();let i=await n.getRun(e);if(r?.stop(),t.json)return N(i);ao(i)}catch(e){to(e,t)}}),e}function $a(e){let t=D(e.apiKey);if(!t)throw Error(`No API key found. Set TANGLE_API_KEY or run: tangle auth login`);return Ce({apiKey:t,baseUrl:e.baseUrl??process.env.TANGLE_INTELLIGENCE_BASE_URL})}async function eo(e,t){let n=(await e.exportTraceSpansNdjson(t)).getReader();try{for(;;){let{value:e,done:t}=await n.read();if(t)break;e&&process.stdout.write(Buffer.from(e))}}finally{n.releaseLock()}}function to(e,t){return H(e,t.json===!0)}function no(e){M(e.map(e=>({traceId:e.traceId,root:e.rootName??`-`,model:e.model??`-`,spans:e.spanCount,errors:e.errorCount,durationMs:e.durationMs,cost:so(e.costUsd)})),[{key:`traceId`,header:`Trace`,width:36},{key:`root`,header:`Root`,width:24},{key:`model`,header:`Model`,width:22},{key:`spans`,header:`Spans`,width:8},{key:`errors`,header:`Errors`,width:8},{key:`durationMs`,header:`Duration(ms)`,width:14},{key:`cost`,header:`Cost`,width:10}])}function ro(e){M(e.map(e=>({spanId:e.id,name:e.name,model:e.model??`-`,status:e.statusCode??`-`,cost:e.costUsd===null?`-`:`$${e.costUsd}`})),[{key:`spanId`,header:`Span`,width:40},{key:`name`,header:`Name`,width:28},{key:`model`,header:`Model`,width:22},{key:`status`,header:`Status`,width:10},{key:`cost`,header:`Cost`,width:12}])}function io(e){M(e.map(e=>({runId:e.id,status:e.status,gate:e.gateDecision??`-`,cost:e.totalCostUsd===null?`-`:`$${e.totalCostUsd}`,receivedAt:e.receivedAt})),[{key:`runId`,header:`Run`,width:24},{key:`status`,header:`Status`,width:22},{key:`gate`,header:`Gate`,width:18},{key:`cost`,header:`Cost`,width:12},{key:`receivedAt`,header:`Received`,width:18}])}function ao(e){R({Run:e.id,Status:e.status,Gate:e.gateDecision??void 0,"Run Dir":e.runDir??void 0,Cost:e.totalCostUsd===null?void 0:`$${e.totalCostUsd}`,Duration:e.totalDurationMs===null?void 0:`${e.totalDurationMs}ms`,"Holdout Lift":e.holdoutLift??void 0,Received:e.receivedAt})}function oo(e){e&&R({"Next page":`--cursor ${e}`})}function so(e){return e===null?`-`:`$${e.toFixed(4)}`}function co(e){if(e===`ERROR`||e===`OK`)return e;throw Error(`--status must be ERROR or OK`)}const lo=[`started`,`baseline-complete`,`generation-complete`,`gate-decided`,`finished`,`errored`];function uo(e){let t=lo.find(t=>t===e);if(t)return t;throw Error(`--status must be one of ${lo.join(`, `)}`)}const fo=[`ship`,`hold`,`need_more_work`,`model_ceiling`,`arch_ceiling`];function po(e){let t=fo.find(t=>t===e);if(t)return t;throw Error(`--gate must be one of ${fo.join(`, `)}`)}function mo(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function ho(){return new t(`usage`).description(`Show account usage and billing information`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=j(O({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=e.json?null:L(`Fetching usage...`);n?.start();let[r,i]=await Promise.all([t.usage(),t.subscription().catch(()=>null)]);n?.stop(),e.json?N({...r,subscription:i}):(console.log(),console.log(`Account Usage`),console.log(`─`.repeat(40)),R({"Active Sandboxes":r.activeSandboxes,"Total Sandboxes":r.totalSandboxes,"Compute Minutes":go(r.computeMinutes)}),i&&(console.log(),console.log(`Subscription`),console.log(`─`.repeat(40)),R({Plan:i.plan,Status:i.status,"Credits Available":_o(i.creditsAvailableUsd),"Credits Used":_o(i.creditsUsedUsd),"Monthly Balance":_o(i.monthlyBalanceUsd)})),console.log(),console.log(`Billing Period`),console.log(`─`.repeat(40)),R({Start:r.periodStart.toLocaleDateString(),End:r.periodEnd.toLocaleDateString()}),console.log())}catch(e){H(e)}})}function go(e){if(e===void 0)return`-`;if(e<60)return`${e} min`;let t=Math.floor(e/60),n=e%60;return n===0?`${t} hr`:`${t} hr ${n} min`}function _o(e){return e<0?`-$${(-e).toFixed(2)}`:`$${e.toFixed(2)}`}function vo(){return new t(`use`).description(`Set or show the active sandbox (used when a command omits the id)`).argument(`[id]`,`Sandbox id to make active`).option(`--clear`,`Clear the active sandbox`).action((e,t)=>{try{if(t.clear){lt(),I(`Cleared the active sandbox.`);return}if(e){ct(e),I(`Active sandbox set to ${e}. Commands now default to it; override with --box or TANGLE_SANDBOX.`);return}let n=st();I(n?`Active sandbox: ${n}`:"No active sandbox. Set one with `tangle use <id>`.")}catch(e){H(e)}})}function yo(){let e=new t(`workflows`).description(`Create and manage Tangle workflows`);return e.option(`--json`,`Output as JSON`),e.hook(`preAction`,(e,t)=>{xo(t)}),e.command(`list`).description(`List your workflows`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=await Z(e).workflows.list();if(e.json)return N(t);Co(t)}catch(t){Q(t,e)}}),e.command(`get`).description(`Show a workflow's definition and compiled triggers`).argument(`<id>`,`Workflow ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await Z(t).workflows.get(e);if(t.json)return N(n);wo(n)}catch(e){Q(e,t)}}),e.command(`create`).description(`Create a workflow from a YAML file`).argument(`<file>`,`Path to the workflow YAML`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=bo(e),r=await Z(t).workflows.create(n);if(t.json)return N(r);I(`Created workflow ${r.id} (${r.name}).`),wo(r)}catch(e){Q(e,t)}}),e.command(`update`).description(`Replace a workflow's definition from a YAML file`).argument(`<id>`,`Workflow ID`).argument(`<file>`,`Path to the workflow YAML`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=bo(t),i=await Z(n).workflows.update(e,r);if(n.json)return N(i);I(`Updated workflow ${i.id} (${i.name}).`),wo(i)}catch(e){Q(e,n)}}),e.command(`delete`).description(`Delete a workflow and its triggers`).argument(`<id>`,`Workflow ID`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{if(!t.force&&!await U(`Delete workflow ${e}? `)){I(`Delete cancelled.`);return}if(await Z(t).workflows.delete(e),t.json)return N({deleted:!0,id:e});I(`Deleted workflow ${e}.`)}catch(e){Q(e,t)}}),e.command(`validate`).description(`Validate a workflow YAML file without saving it`).argument(`<file>`,`Path to the workflow YAML`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=bo(e),r=await Z(t).workflows.validate(n);if(t.json)return N(r);if(r.valid)I(`Valid: ${r.name} (${r.actionCount} action(s), ${r.triggerCount} trigger(s)).`);else{I(`Invalid workflow:`);for(let e of r.errors)console.log(` ${e.path}: ${e.message}`);process.exitCode=1}}catch(e){Q(e,t)}}),e.command(`schema`).description(`Print the JSON Schema for the workflow YAML`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{N(await Z(e).workflows.schema())}catch(t){Q(t,e)}}),e}function bo(e){try{return c(e,`utf8`)}catch(t){throw Error(`Could not read workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function Z(e){let t=O({apiKey:D(e.apiKey),baseUrl:e.baseUrl??_t(process.env.TANGLE_HUB_URL)});return new me({baseUrl:t.baseUrl,apiKey:t.apiKey})}function xo(e){if(!So(e,`json`)||e.getOptionValue(`json`)!==void 0)return;let t=e.parent;for(;t;){let n=t.getOptionValue(`json`);if(n!==void 0){e.setOptionValue(`json`,n);return}t=t.parent}}function So(e,t){return e.options.some(e=>e.attributeName()===t)}function Q(e,t){return H(e,t.json===!0)}function Co(e){M(e.map(e=>({id:e.id,name:e.name,enabled:e.enabled?`yes`:`no`,issues:e.validationErrors.length,updated:e.updatedAt})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`enabled`,header:`Enabled`},{key:`issues`,header:`Issues`},{key:`updated`,header:`Updated`}])}function wo(e){if(R({ID:e.id,Name:e.name,Description:e.description??``,Enabled:e.enabled?`yes`:`no`,Actions:e.actions.length}),e.triggers&&e.triggers.length>0&&(I(`Triggers`),To(e.triggers)),e.validationErrors.length>0){I(`Validation issues`);for(let t of e.validationErrors)console.log(` ${t.path}: ${t.message}`)}}function To(e){M(e.map(e=>({id:e.id,kind:e.kind,enabled:e.enabled?`yes`:`no`,detail:e.kind===`schedule`?`${e.cron??``} (${e.timezone??``})`:`${e.provider??``}:${e.eventFilter?.event??``}${e.eventFilter?.action?`.${e.eventFilter.action}`:``}`})),[{key:`id`,header:`ID`},{key:`kind`,header:`Kind`},{key:`enabled`,header:`Enabled`},{key:`detail`,header:`Detail`}])}function Eo(e){let t={...Do(e)??{},...e.optsWithGlobals()};for(let n of e.options){let r=n.attributeName();e.getOptionValue(r)===void 0&&t[r]!==void 0&&e.setOptionValue(r,t[r])}}function Do(e){let t=e;for(;t?.parent;)t=t.parent;return t?t.opts():void 0}const Oo=e(import.meta.url)(`../package.json`),$=new t;$.name(`tangle`).description(`CLI for Tangle Sandbox operations`).version(Oo.version??`0.0.0`).option(`--api-key <key>`,`API key (or set TANGLE_API_KEY)`).option(`--base-url <url>`,`API base URL`),$.hook(`preAction`,(e,t)=>{Eo(t)}),$.addCommand(kn()),$.addCommand(Gi()),$.addCommand(vo()),$.addCommand(ca()),$.addCommand(Ei()),$.addCommand(Gn()),$.addCommand(Ea()),$.addCommand(Da()),$.addCommand(ka()),$.addCommand(dn()),$.addCommand(da()),$.addCommand(qn()),$.addCommand(ho()),$.addCommand(Wa()),$.addCommand(Ya()),$.addCommand(Oi()),$.addCommand(In()),$.addCommand(Hn()),$.addCommand(Ai()),$.addCommand(rr()),$.addCommand(or()),$.addCommand(sr()),$.addCommand(yo()),$.addCommand(Wn()),$.addCommand(Xa()),$.addCommand(sa()),$.addCommand(ua()),$.addCommand(Un()),$.addCommand(ki()),$.addCommand(li()),$.addCommand(Ii()),$.addCommand(Di()),$.addCommand(Za()),$.addCommand(Ua()),$.parseAsync(process.argv).catch(e=>{console.error(`Fatal error:`,e.message),process.exit(1)});export{};
134
+ </html>`}const qn=15*6e4;function Jn(e){return Number.isFinite(e)&&e>0?e:qn}async function Yn(e){let t=e.timeoutMs??qn,n=Date.now(),r=await Xn({baseUrl:e.baseUrl,timeoutMs:t,provider:e.provider});for(e.onInstructions?.({userCode:r.user_code,verificationUrl:r.verification_uri,verificationUrlComplete:r.verification_uri_complete,expiresIn:r.expires_in,intervalSeconds:r.interval});;){if(Date.now()-n>t)throw new se(t,`Timed out waiting for device authorization to complete`);let i=await Zn({baseUrl:e.baseUrl,deviceCode:r.device_code,timeoutMs:t});if(i.status===`approved`)return i.data;let a=i.intervalSeconds*1e3;await new Promise(e=>setTimeout(e,a))}}async function Xn(e){let t=Jn(e.timeoutMs),n=await fetch(`${Qn(e.baseUrl)}/auth/cli/device/start`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify(e.provider?{provider:e.provider}:{}),signal:AbortSignal.timeout(t)}).catch(t=>{throw new m(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),r=await n.json().catch(()=>null);if(!n.ok||!r?.success||!r.data?.device_code)throw Error(r?.error?.message||`Failed to start device login`);return r.data}async function Zn(e){let t=Jn(e.timeoutMs),n=await fetch(`${Qn(e.baseUrl)}/auth/cli/device/poll`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify({device_code:e.deviceCode}),signal:AbortSignal.timeout(t)}).catch(t=>{throw new m(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),r=await n.json().catch(()=>null);if(n.status===428&&r?.error?.code===`AUTHORIZATION_PENDING`)return{status:`pending`,intervalSeconds:typeof r.data?.interval==`number`&&r.data.interval>0?r.data.interval:5};if(!n.ok||!r?.success||!r.data?.api_key||!r.data.email)throw Error(r?.error?.message||`Failed to complete device authorization`);return{status:`approved`,data:{apiKey:r.data.api_key,email:r.data.email,name:r.data.name,tier:r.data.tier}}}function Qn(e){return e.replace(/\/$/,``)}function $n(){let e=new t(`auth`).description(`Manage authentication`);e.command(`login`).description(`Authenticate with browser login or an API key`).option(`--api-key <key>`,`API key`).option(`--no-browser`,`Use device-code login instead of opening a browser`).option(`--profile <name>`,`Profile name`).option(`--provider <provider>`,`Identity provider (github, google, microsoft)`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=e.apiKey,n=T(e.profile),r=ar(e.provider),i=bt(e.baseUrl,n),a=e.browser!==!1;if(!t){if(a){let a=F(`Starting browser login...`);a.start();let o=await Bn({baseUrl:i,provider:r,onLoginUrl:({loginUrl:e,browserOpened:t})=>{a.stop(),P(t?`Browser login opened.`:`Open this URL to continue browser login:`),console.log(e)}}).finally(()=>{a.stop()});t=o.apiKey,nr({profile:n,apiKey:t,baseUrl:e.baseUrl?i:void 0}),At(),M(`Authenticated`),I({Profile:n,Email:o.email,Tier:o.tier,"Base URL":i}),P(rr);return}let o=F(`Starting device login...`);o.start();let s=await Yn({baseUrl:i,provider:r,onInstructions:({userCode:e,verificationUrl:t,verificationUrlComplete:n})=>{o.stop(),P(`Complete login in a browser on any device:`),I({"Verification URL":t,"Verification URL (prefilled)":n,"Device Code":e})}}).finally(()=>{o.stop()});t=s.apiKey,nr({profile:n,apiKey:t,baseUrl:e.baseUrl?i:void 0}),At(),M(`Authenticated`),I({Profile:n,Email:s.email,Tier:s.tier,"Base URL":i}),P(rr);return}t||(N(`No API key provided.`),process.exit(1)),ot(t)||(N(`Invalid API key format. Keys should start with 'sk_' or 'sk-tan-'.`),process.exit(1));let o=F(`Validating credentials...`);o.start();let s=await In({apiKey:t,baseUrl:i});o.stop(),nr({profile:n,apiKey:t,baseUrl:e.baseUrl?i:void 0}),At(),M(`Authenticated`),I({Profile:n,Email:s.email,Tier:s.tier,"Base URL":i}),P(rr)}catch(e){B(e)}}),e.command(`logout`).description(`Remove stored credentials`).option(`--profile <name>`,`Profile name`).action(e=>{try{let t=T(e.profile);_t(t),At(),M(`Logged out successfully.`),P(`Credentials removed for profile '${t}'.`)}catch(e){B(e)}}),e.command(`status`).description(`Show current authentication status`).option(`--json`,`Output as JSON`).option(`--profile <name>`,`Profile name`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=T(e.profile),n=vt(e.apiKey,t),r=bt(e.baseUrl,t),i=yt(e.apiKey,t);if(!n){if(e.json){j({authenticated:!1,reason:`missing_credentials`,profile:t,baseUrl:r,credentialSource:null});return}N(`Not authenticated`),P(`Run 'tangle auth login --profile ${t}' to authenticate.`),process.exit(1)}let a=e.json?null:F(`Checking credentials...`);a?.start();try{let o=await In({apiKey:n,baseUrl:r});if(a?.stop(),e.json){j({authenticated:!0,profile:t,baseUrl:r,credentialSource:i,account:o});return}M(`Authenticated`),I({Profile:t,"API Key":er(n),"Base URL":r,Source:tr(i),Email:o.email,Tier:o.tier})}catch(o){a?.stop(),e.json&&(j({authenticated:!1,profile:t,baseUrl:r,credentialSource:i,error:o instanceof Error?o.message:String(o)}),process.exit(1)),o instanceof ie?N(`Stored credentials are invalid.`):Vt(`Stored credentials found, but validation could not complete.`),I({Profile:t,"API Key":er(n),"Base URL":r,Source:tr(i),Error:o instanceof Error?o.message:String(o)}),process.exit(1)}}catch(e){B(e)}});let n=new t(`profiles`).description(`Manage CLI profiles`);return n.command(`list`).description(`List configured profiles`).option(`--json`,`Output as JSON`).action(e=>{try{let t=mt();if(e.json){j(t);return}if(t.length===0){P(`No profiles found.`);return}z([`Profile`,`Active`,`Base URL`,`Credentials`,`Source`],t.map(e=>[e.name,e.active?`yes`:`no`,e.baseUrl,e.hasApiKey?`configured`:`none`,e.apiKeySource]))}catch(e){B(e)}}),n.command(`use <name>`).description(`Set the active profile`).action(e=>{try{ct(e);let t=ht(e);M(`Active profile set to '${t.name}'.`),I({"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`})}catch(e){B(e)}}),n.command(`current`).description(`Show the active profile`).option(`--json`,`Output as JSON`).action(e=>{try{let t=ht();if(e.json){j(t);return}I({Profile:t.name,"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`,Source:tr(t.credentialSource)})}catch(e){B(e)}}),e.addCommand(n),e}function er(e){return e.length<=14?e:`${e.slice(0,10)}...${e.slice(-4)}`}function tr(e){switch(e){case`flag`:return`command flag`;case`env`:return`environment`;case`keychain`:return`OS keychain`;case`file`:return`credentials file`;case`legacy-file`:return`legacy credentials file`;default:return`unknown`}}function nr(e){let t=gt(e.profile,{apiKey:e.apiKey,...e.baseUrl?{baseUrl:e.baseUrl}:{}});ct(e.profile),w({...e.baseUrl&&e.profile===`default`?{baseUrl:e.baseUrl}:{}}),rr=ir(e.profile,t)}let rr=`Credentials updated.`;function ir(e,t){return t===`keychain`?e===`default`?`API key saved to the OS keychain for the default profile`:`API key saved to the OS keychain for profile '${e}'`:t===`file`?e===`default`?`API key saved to ~/.tangle/credentials.json for the default profile`:`API key saved to ~/.tangle/credentials.json for profile '${e}'`:`Profile '${e}' updated.`}function ar(e){if(e===void 0||e===`github`||e===`google`||e===`microsoft`)return e;throw Error(`--provider must be one of: github, google, microsoft`)}function or(){let e=new t(`backend`).description(`Manage sandbox AI agent backend`);return e.command(`status <sandboxId-or-name>`).description(`Get backend agent status`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching backend status...`);i.start();let a=await(await H(r,n,e)).backend.status();i.stop(),t.json?j(a):(P(`Backend Type: ${a.type}`),P(`Status: ${a.status}`),a.version&&P(`Version: ${a.version}`),a.error&&P(`Error: ${a.error}`),a.metadata&&P(`Metadata: ${JSON.stringify(a.metadata,null,2)}`))}catch(e){B(e)}}),e.command(`capabilities <sandboxId-or-name>`).description(`Get backend capabilities`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching capabilities...`);i.start();let a=await(await H(r,n,e)).backend.capabilities();i.stop(),t.json?j(a):(P(`Backend Capabilities:`),P(` Streaming: ${a.streaming?`✓`:`✗`}`),P(` Tool Use: ${a.toolUse?`✓`:`✗`}`),P(` Reasoning: ${a.reasoning?`✓`:`✗`}`),P(` Multimodal: ${a.multimodal?`✓`:`✗`}`),P(` Context Window: ${a.contextWindow.toLocaleString()} tokens`))}catch(e){B(e)}}),e.command(`configure <sandboxId-or-name>`).description(`Update backend configuration`).option(`--model <model>`,`Model string (format: provider/model)`).option(`--max-thinking-tokens <n>`,`Maximum thinking tokens`).option(`--profile <name>`,`Backend profile name`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Updating backend config...`);i.start();let a=await H(r,n,e),o={};if(t.profile&&(o.profile=t.profile),t.model||t.maxThinkingTokens){if(o.model={},t.model){let e=t.model.split(`/`);e.length>=2?(o.model.provider=e[0],o.model.model=e.slice(1).join(`/`)):o.model.model=t.model}t.maxThinkingTokens&&(o.model.maxThinkingTokens=Number.parseInt(t.maxThinkingTokens,10))}await a.backend.updateConfig(o),i.stop(),M(`Backend configuration updated`),t.json&&j(o)}catch(e){B(e)}}),e.command(`add-mcp <sandboxId-or-name>`).description(`Add an MCP server to the backend`).requiredOption(`--name <name>`,`MCP server name`).requiredOption(`--command <cmd>`,`Command to run (e.g., npx)`).option(`--args <args...>`,`Command arguments`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`--cwd <dir>`,`Working directory`).option(`--url <url>`,`Remote MCP server URL (for SSE)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Adding MCP server...`);i.start();let a=await H(r,n,e),o={};if(t.env)for(let e of t.env){let[t,...n]=e.split(`=`);t&&n.length>0&&(o[t]=n.join(`=`))}await a.backend.addMcp(t.name,{command:t.command,args:t.args,env:Object.keys(o).length>0?o:void 0,cwd:t.cwd,url:t.url}),i.stop(),M(`MCP server "${t.name}" added`),t.json&&j({name:t.name,command:t.command,args:t.args,env:Object.keys(o).length>0?o:void 0,cwd:t.cwd,url:t.url})}catch(e){B(e)}}),e.command(`mcp-status <sandboxId-or-name>`).description(`Get status of MCP servers`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching MCP status...`);i.start();let a=await(await H(r,n,e)).backend.getMcpStatus();if(i.stop(),t.json)j(a);else{let e=Object.entries(a);e.length===0?P(`No MCP servers configured`):A(e.map(([e,t])=>{let n=t;return{name:e,status:n.status,error:n.error??``}}),[{key:`name`,header:`Name`,width:24},{key:`status`,header:`Status`,width:12},{key:`error`,header:`Error`,width:40}])}}catch(e){B(e)}}),e.command(`restart <sandboxId-or-name>`).description(`Restart the backend agent`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Restarting backend...`);i.start(),await(await H(r,n,e)).backend.restart(),i.stop(),M(`Backend restarted`)}catch(e){B(e)}}),e}function sr(e){let t=e.indexOf(`=`);if(t<=0)throw Error(`Invalid --task "${e}": expected format id=message (e.g. t1=summarize README)`);let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();if(!n||!r)throw Error(`Invalid --task "${e}": id and message must be non-empty`);return{id:n,message:r}}function cr(e){let t;try{t=JSON.parse(e)}catch(e){throw Error(`--tasks file is not valid JSON: ${e.message}`)}let n=Array.isArray(t)?t:t?.tasks;if(!Array.isArray(n))throw Error(`--tasks file must contain an array or an object with a "tasks" array`);return n.map((e,t)=>{if(!e||typeof e!=`object`)throw Error(`--tasks[${t}] must be an object`);let n=e,r=typeof n.id==`string`?n.id.trim():``,i=typeof n.message==`string`?n.message:``;if(!r)throw Error(`--tasks[${t}].id must be a non-empty string`);if(!i.trim())throw Error(`--tasks[${t}].message must be a non-empty string`);let a={id:r,message:i};return n.context&&typeof n.context==`object`&&(a.context=n.context),typeof n.timeoutMs==`number`&&n.timeoutMs>0&&(a.timeoutMs=n.timeoutMs),a})}function lr(e){let t=e.readFile??(e=>l(e,`utf8`)),n=[];e.file&&n.push(...cr(t(e.file)));for(let t of e.inline??[])n.push(sr(t));if(n.length===0)throw Error(`No tasks provided. Use --tasks <file> and/or --task id=message.`);let r=new Set;for(let e of n){if(r.has(e.id))throw Error(`Duplicate task id: ${e.id}`);r.add(e.id)}return n}function ur(e){if(e!==`fastest`&&e!==`balanced`&&e!==`cheapest`)throw Error(`--scaling must be one of: fastest, balanced, cheapest (got "${e}")`);return e}function dr(e){let t=e.trim(),n=t.indexOf(`/`);if(n<=0||n===t.length-1)throw Error(`--model must be in the form provider/model (got "${e}")`);return{provider:t.slice(0,n),model:t.slice(n+1)}}function fr(){let e=new t(`batch`).description(`Run multiple agent tasks in parallel across sandboxes`);return e.command(`run`).description(`Execute a batch of tasks. Provide tasks via --tasks <file.json> and/or repeated --task id=message flags.`).option(`--tasks <file>`,`Path to a JSON file with an array of tasks (or {tasks: [...]})`).option(`--task <id=message>`,`Inline task, id=message. Repeatable.`,(e,t=[])=>[...t,e],[]).option(`--stream`,`Stream per-task events as they arrive`).option(`-t, --timeout <ms>`,`Total batch timeout in milliseconds`,`300000`).option(`--scaling <mode>`,`Scaling mode: fastest | balanced | cheapest`,`balanced`).option(`--persistent`,`Keep sandboxes alive after completion`,!1).option(`--model <provider/model>`,`Model override, e.g. anthropic/claude-sonnet-4-5-20250929`).option(`--profile <id>`,`Named execution profile to apply to every task`).option(`--json`,`Output the final result as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{let t=new AbortController,n=!1,r=()=>{n||(n=!0,P(`Cancel requested — stopping stream...`),t.abort())};process.on(`SIGINT`,r),process.on(`SIGTERM`,r);try{let n=lr({file:e.tasks,inline:e.task}),r=ur(e.scaling),i=Number(e.timeout);if(!Number.isFinite(i)||i<=0)throw Error(`--timeout must be a positive number of milliseconds`);let o=k(E({apiKey:e.apiKey,baseUrl:e.baseUrl})),s={type:`opencode`};e.model&&(s.model=dr(e.model)),e.profile&&(s.profile=String(e.profile));let c={timeoutMs:i,scalingMode:r,persistent:!!e.persistent,signal:t.signal,backend:s};if(e.stream){P(`Streaming batch of ${n.length} task(s)...`),console.log();let t=new Map;for await(let e of o.streamBatch(n,c)){let r=e.data,i=r.taskId??``;switch(e.type){case`batch.started`:P(`Batch started (${r.totalTasks??n.length} tasks)`);break;case`task.started`:i&&console.log(a.dim(`→ ${i} started`));break;case`task.retry`:i&&console.log(a.yellow(`↻ ${i} retry ${r.attempt??`?`}: ${r.error??`retrying`}`));break;case`task.completed`:if(i){let e=r.usage,n=(e?.inputTokens??0)+(e?.outputTokens??0);t.set(i,{success:!0,durationMs:r.durationMs,retries:r.retries,tokensUsed:r.tokensUsed??(n>0?n:void 0),response:r.resultSummary??r.response}),console.log(a.green(`✓ ${i} completed in ${r.durationMs??`?`}ms`+(r.retries?` (${r.retries} retries)`:``)))}break;case`task.failed`:i&&(t.set(i,{success:!1,durationMs:r.durationMs,retries:r.retries,error:r.error}),console.log(a.red(`✗ ${i} failed: ${r.error??`unknown error`}`)));break;case`batch.failed`:throw Error(r.error??`Batch failed`);case`batch.completed`:break}}let r=[...t.values()].filter(e=>e.success).length,i=[...t.values()].filter(e=>!e.success).length,s=[...t.values()].reduce((e,t)=>e+(t.retries??0),0);console.log(),e.json?j({totalTasks:n.length,succeeded:r,failed:i,totalRetries:s,successRate:n.length>0?r/n.length*100:0,results:Array.from(t.entries()).map(([e,t])=>({taskId:e,...t}))}):I({"Total tasks":n.length,Succeeded:r,Failed:i,"Total retries":s,"Success rate":n.length>0?`${(r/n.length*100).toFixed(1)}%`:`0%`}),i>0&&(process.exitCode=1)}else{P(`Running batch of ${n.length} task(s)...`);let t=await o.runBatch(n,c);if(e.json)j(t);else if(console.log(),I({"Total tasks":t.totalTasks,Succeeded:t.succeeded,Failed:t.failed,"Total retries":t.totalRetries,"Success rate":`${t.successRate.toFixed(1)}%`}),t.results.length>0){console.log(),console.log(a.bold(`Task Results`)),console.log(a.dim(`─`.repeat(40)));for(let e of t.results){let t=e.success?a.green(`✓`):a.red(`✗`),n=typeof e.tokensUsed==`number`?` • ${e.tokensUsed} tokens`:``;console.log(`${t} ${e.taskId} ${a.dim(`(${e.durationMs}ms, ${e.retries} retries${n})`)}`),e.error&&console.log(a.red(` ${e.error}`))}}t.failed>0&&(process.exitCode=1)}}catch(e){if(n){console.log(),P(`Batch cancelled.`),process.exitCode=130;return}B(e)}finally{process.off(`SIGINT`,r),process.off(`SIGTERM`,r)}}),e}function pr(){let e=new t(`checkpoint`).description(`Manage sandbox filesystem checkpoints`);return e.command(`create`).description(`Create a checkpoint of the current sandbox state`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Creating checkpoint...`);t.json||i.start();let a=await(await H(r,n,e)).checkpoint();i.stop(),t.json?j(a):M(`Checkpoint created: ${a.checkpointId}`)}catch(e){B(e)}}),e.command(`list`).alias(`ls`).description(`List checkpoints for a sandbox`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching checkpoints...`);t.json||i.start();let a=await(await H(r,n,e)).listCheckpoints();i.stop(),t.json?j(a):a.length===0?console.log(`No checkpoints found`):z([`ID`,`Created`],a.map(e=>[e.checkpointId,e.createdAt.toLocaleString()]))}catch(e){B(e)}}),e.command(`delete`).alias(`rm`).description(`Delete a checkpoint`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<checkpoint-id>`,`Checkpoint ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Deleting checkpoint...`);n.json||a.start(),await(await H(i,r,e)).deleteCheckpoint(t),a.stop(),n.json?j({success:!0,deleted:t}):M(`Checkpoint deleted: ${t}`)}catch(e){B(e)}}),e}function mr(){let e=new t(`environments`).alias(`env`).description(`Manage sandbox environments`);return e.command(`list`).alias(`ls`).description(`List available environments`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=k(E({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=F(`Fetching environments...`);e.json||n.start();let r=await t.environments.list();n.stop(),e.json?j(r):r.length===0?console.log(`No environments found`):z([`ID`,`Description`,`Version`],r.map(e=>[e.id,e.description??``,e.version]))}catch(e){B(e)}}),e.command(`get`).description(`Get environment details`).argument(`<id>`,`Environment ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=F(`Fetching environment...`);t.json||r.start();let i=await n.environments.get(e);if(r.stop(),!i){console.error(`Environment not found: ${e}`),process.exit(1);return}t.json?j(i):(console.log(`ID: ${i.id}`),console.log(`Description: ${i.description??`-`}`),console.log(`Version: ${i.version}`),i.base&&console.log(`Base: ${i.base}`))}catch(e){B(e)}}),e}function hr(){return new t(`exec`).description(`Execute a command in a sandbox`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<command...>`,`Command to execute`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`,`60000`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=t.join(` `),o={};if(n.env)for(let e of n.env){let[t,...n]=e.split(`=`);t&&n.length>0&&(o[t]=n.join(`=`))}let s=F(`Executing: ${a}`);n.json||s.start();let c=await H(i,r,e);c=await U(c);let l=await c.exec(a,{cwd:n.cwd,env:Object.keys(o).length>0?o:void 0,timeoutMs:Number.parseInt(n.timeout,10)});s.stop(),n.json?j(l):(l.stdout&&process.stdout.write(l.stdout),l.stderr&&process.stderr.write(l.stderr),l.exitCode!==0&&process.exit(l.exitCode))}catch(e){if(e instanceof m){let t=`Exec transport lost before command status was confirmed. Remote command status is unknown. Original error: ${e.message}. For long-running commands, use \`tangle process spawn\`, \`tangle process logs\`, and \`tangle process kill --tree\`.`;return B(Error(t,{cause:e}))}B(e)}})}const gr=[`list`,`create`,`delete`,`exec`,`prompt`,`read`,`write`];function _r(){let e=new t(`fleet`).description(`Manage sandbox fleets`);return e.command(`create`).description(`Create a sandbox fleet`).option(`--fleet-id <id>`,`Stable fleet id (generated when omitted)`).option(`--count <n>`,`Number of worker machines`,`1`).option(`--image <env>`,`Environment/image for each machine`).option(`--cpu <cores>`,`CPU cores per machine`).option(`--memory <mb>`,`Memory in MB per machine`).option(`--disk <gb>`,`Disk in GB per machine`).option(`--driver <type>`,`Infrastructure driver type`).option(`--backend <id>`,`Agent backend type`).option(`--workspace <mode>`,`Workspace mode: isolated | shared`,`isolated`).option(`--max-spend-usd <n>`,`Fleet spend cap in USD (policy)`).option(`--max-lifetime <s>`,`Max machine lifetime in seconds (policy)`).option(`--spec <file.json>`,`Path to a JSON file describing the fleet (overrides synthesized machines)`).option(`--coordinator`,`Create a coordinator + workers fleet (routes to createWithCoordinator)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=k(E({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=F(`Creating fleet...`);n.start();let r=e.coordinator?await t.fleets.createWithCoordinator(xr(e)):await t.fleets.create(br(e));n.stop();let i=wr(r.machines);e.json?j({fleetId:r.fleetId,machines:i}):(M(`Fleet created: ${r.fleetId}`),A(i,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}]))}catch(e){B(e)}}),e.command(`list <fleet-id>`).description(`List the machines of one fleet (fleet id is required)`).option(`--status <status>`,`Filter machines by status`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=F(`Fetching fleet...`);r.start();let i=await n.fleets.list({fleetId:e,status:t.status});r.stop();let a=wr(i.machines);t.json?j({fleetId:i.fleetId,machines:a}):A(a,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}])}catch(e){B(e)}}),e.command(`get <fleet-id>`).description(`Show one fleet's manifest (server record)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=F(`Fetching manifest...`);r.start();let i=await n.fleets.manifest(e);r.stop(),t.json?j(i):(I({"Fleet ID":i.fleetId??i.id,Machines:i.machines.length,"Workspace mode":i.workspace?.mode,"Workspace status":i.workspace?.status,"Max lifetime (s)":i.policy?.maxLifetimeSeconds,"Max spend (USD)":i.policy?.maxSpendUsd,Created:i.createdAt,Updated:i.updatedAt}),A(i.machines.map(e=>({machineId:e.machineId,sandboxId:e.sandboxId,role:e.role,status:e.status})),[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`role`,header:`Role`,width:14},{key:`status`,header:`Status`,width:14}]))}catch(e){B(e)}}),e.command(`delete <fleet-id>`).description(`Delete a fleet's machine sandboxes and its record`).option(`--continue-on-error`,`Keep deleting remaining machines if one delete fails`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=F(`Deleting fleet...`);r.start(),await n.fleets.delete(e,{continueOnError:t.continueOnError}),r.stop(),t.json?j({success:!0,fleetId:e}):M(`Fleet deleted: ${e}`)}catch(e){B(e)}}),e.command(`reap`).description(`TTL cleanup of all expired fleets (fleet-wide)`).option(`--dry-run`,`Report what would be reaped without deleting`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=k(E({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=F(`Reaping expired fleets...`);n.start();let r=await t.fleets.reapExpired({dryRun:e.dryRun});n.stop(),e.json?j(r):(I({"Dry run":r.dryRun,Expired:r.expired,Deleted:r.deleted}),A(r.fleets.map(e=>({fleetId:e.fleetId,expiredAt:e.expiredAt,deleted:e.deleted})),[{key:`fleetId`,header:`Fleet`,width:24},{key:`expiredAt`,header:`Expired`,width:18},{key:`deleted`,header:`Deleted`,width:10}]))}catch(e){B(e)}}),e.command(`reconcile`).description(`Drop fleet records whose underlying sandboxes vanished`).option(`--dry-run`,`Report orphans without removing them`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=k(E({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=F(`Reconciling fleets...`);n.start();let r=await t.fleets.reconcile({dryRun:e.dryRun});n.stop(),e.json?j(r):(I({"Dry run":r.dryRun,Checked:r.checked,Orphaned:r.orphaned,Removed:r.removed}),A(r.machines.map(e=>({fleetId:e.fleetId,machineId:e.machineId,sandboxId:e.sandboxId,removed:e.removed})),[{key:`fleetId`,header:`Fleet`,width:24},{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`removed`,header:`Removed`,width:10}]))}catch(e){B(e)}}),e.addCommand(vr()),e.command(`exec <fleet-id> <command>`).description(`Run a shell command across the fleet's machines`).option(`--machine <id...>`,`Restrict to a subset of machine ids (default: all)`).option(`--cwd <dir>`,`Working directory for the command`).option(`--timeout <ms>`,`Per-machine timeout in milliseconds`).option(`--max-concurrent <n>`,`Max concurrent dispatches`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=k(E({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=F(`Dispatching command...`);i.start();let a=await(await r.fleets.list({fleetId:e})).dispatchExecDetailed(t,{machines:n.machine,cwd:n.cwd,timeoutMs:n.timeout?Number(n.timeout):void 0,maxConcurrent:n.maxConcurrent?Number(n.maxConcurrent):void 0});if(i.stop(),n.json)j(a);else{A(a.results.map(e=>({machineId:e.machineId,ok:e.ok,exitCode:e.result?.exitCode,durationMs:e.durationMs})),[{key:`machineId`,header:`Machine`,width:20},{key:`ok`,header:`OK`,width:6},{key:`exitCode`,header:`Exit`,width:8},{key:`durationMs`,header:`Duration(ms)`,width:14}]);for(let e of a.results){let t=e.result?.stdout,n=e.result?.stderr;t&&(console.log(`\n[${e.machineId}] stdout:`),console.log(t)),n&&(console.log(`\n[${e.machineId}] stderr:`),console.log(n)),e.error&&console.log(`\n[${e.machineId}] error: ${e.error.message}`)}}a.results.some(e=>e.ok===!1)&&(process.exitCode=1)}catch(e){B(e)}}),e.command(`capabilities`).description(`List fleet drivers and their supported features`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=k(E({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=F(`Fetching capabilities...`);n.start();let r=await t.fleets.capabilities();n.stop(),e.json?j(r):A(r.drivers.map(e=>({driverType:e.driverType,sharedWorkspace:e.sharedWorkspace,accelerators:e.accelerators,queueTimings:e.queueTimings})),[{key:`driverType`,header:`Driver`,width:16},{key:`sharedWorkspace`,header:`Shared WS`,width:12},{key:`accelerators`,header:`Accel`,width:8},{key:`queueTimings`,header:`Queue`,width:8}])}catch(e){B(e)}}),e.command(`usage <fleet-id>`).description(`Show fleet usage and reliability insights`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=F(`Fetching usage...`);r.start();let i=await n.fleets.usage(e);if(r.stop(),t.json)j(i);else if(I({"Fleet ID":i.usage.fleetId,Status:i.usage.status,Machines:i.usage.machineCount,Running:i.usage.runningMachines,Failed:i.usage.failedMachines,"Runtime (ms)":i.usage.meteredUsage?.runtimeMs,"Reliability score":i.insights.reliabilityScore,"Failure rate":i.insights.failureRate}),i.insights.recommendedActions.length>0){console.log(`
135
+ Recommended actions:`);for(let e of i.insights.recommendedActions)console.log(` - ${e}`)}}catch(e){B(e)}}),e.command(`cost <fleet-id>`).description(`Show the fleet's cost estimate`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=F(`Estimating cost...`);r.start();let i=await n.fleets.cost(e);r.stop(),t.json?j(i):I({Plan:i.plan,Currency:i.currency,"Hourly (USD)":i.hourlyUsd,"Max lifetime (s)":i.maxLifetimeSeconds,"Estimated max lifetime (USD)":i.estimatedMaxLifetimeUsd,Machines:i.requestedResources.machines,"Total CPU":i.requestedResources.totalCpu,"Total memory (MB)":i.requestedResources.totalMemoryMb})}catch(e){B(e)}}),e.command(`token <fleet-id>`).description(`Mint a scoped fleet bearer token (treated as a secret)`).option(`--action <a...>`,`Allowed actions: list create delete exec prompt read write`).option(`--ttl-minutes <n>`,`Token lifetime in minutes`).option(`--json`,`Output as JSON (only path that prints the full token)`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=F(`Minting fleet token...`);r.start();let i=await n.fleets.createToken(e,{actions:Tr(t.action),ttlMinutes:t.ttlMinutes?Number(t.ttlMinutes):void 0});r.stop(),t.json?j(i):(I({"Fleet ID":i.fleetId,Token:Er(i.token),"Expires at":new Date(i.expiresAt).toISOString(),Actions:i.actions.join(`, `)}),console.log(`
136
+ Re-run with --json to print the full token value.`))}catch(e){B(e)}}),e}function vr(){let e=new t(`workspace`).description(`Manage a fleet's shared workspace`);return e.command(`snapshot <fleet-id>`).description(`Snapshot the fleet's shared workspace`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=F(`Creating workspace snapshot...`);r.start();let i=await n.fleets.createWorkspaceSnapshot(e);r.stop(),t.json?j(i):M(`Workspace snapshot created: ${i.snapshotId??i.id}`)}catch(e){B(e)}}),e.command(`restore <fleet-id> <snapshot-id>`).description(`Restore the fleet's shared workspace from a snapshot`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=k(E({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=F(`Restoring workspace...`);i.start();let a=await r.fleets.restoreWorkspaceSnapshot(e,t);i.stop(),n.json?j(a):M(`Workspace restored from ${a.snapshotId??t}`)}catch(e){B(e)}}),e.command(`reconcile <fleet-id>`).description(`Re-mount the shared workspace on all fleet machines`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=F(`Reconciling workspace...`);r.start();let i=await n.fleets.reconcileWorkspace(e);r.stop(),t.json?j(i):(I({"Fleet ID":i.fleetId,Checked:i.checked,"Orphaned mounts":i.orphanedMounts}),A(i.machines.map(e=>({machineId:e.machineId,sandboxId:e.sandboxId,mounted:e.mounted})),[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`mounted`,header:`Mounted`,width:10}]))}catch(e){B(e)}}),e}function yr(e){if(e.spec){let t=JSON.parse(l(e.spec,`utf8`));return{base:{fleetId:e.fleetId,defaults:t.defaults,policy:t.policy,workspace:t.workspace,metadata:t.metadata},machines:t.machines??[]}}let t=Sr(e),n={...e.image?{environment:e.image}:{},...t?{resources:t}:{},...e.driver?{driver:{type:e.driver}}:{},...e.backend?{backend:{type:e.backend}}:{}},r=Cr(e),i=Math.max(1,Number(e.count)||1),a=Array.from({length:i},(e,t)=>({machineId:`worker-${t+1}`}));return{base:{fleetId:e.fleetId,defaults:Object.keys(n).length>0?n:void 0,policy:r,workspace:{mode:e.workspace}},machines:a}}function br(e){let{base:t,machines:n}=yr(e);return{...t,machines:n}}function xr(e){let{base:t,machines:n}=yr(e);return{...t,workers:n}}function Sr(e){let t={};return e.cpu&&(t.cpuCores=Number(e.cpu)),e.memory&&(t.memoryMB=Number(e.memory)),e.disk&&(t.diskGB=Number(e.disk)),Object.keys(t).length>0?t:void 0}function Cr(e){let t={};return e.maxSpendUsd&&(t.maxSpendUsd=Number(e.maxSpendUsd)),e.maxLifetime&&(t.maxLifetimeSeconds=Number(e.maxLifetime)),Object.keys(t).length>0?t:void 0}function wr(e){return[...e.entries()].map(([e,t])=>({machineId:e,sandboxId:t.id,status:t.status}))}function Tr(e){if(!(!e||e.length===0)){for(let t of e)if(!gr.includes(t))throw Error(`Invalid token action '${t}'. Allowed: ${gr.join(`, `)}`);return e}}function Er(e){return e.length<=12?`****`:`${e.slice(0,6)}...${e.slice(-4)} (masked — use --json for full value)`}function Dr(){let e=new t(`fs`).description(`File system operations on sandboxes`);return K(e.command(`upload`).description(`Upload a file to a sandbox`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<local-path>`,`Local file path`).argument(`<remote-path>`,`Remote destination path`).option(`--json`,`Output as JSON`)).action(async(e,t,n,r)=>{try{let{context:i,client:a}=q(r),s=await H(a,i,e);if(s=await U(s),!o.existsSync(t))throw Error(`Local file not found: ${t}`);let c=o.statSync(t),l=Date.now();console.log(`Uploading ${t} to ${n}...`),await s.fs.upload(t,n,{onProgress:e=>{let t=e.percentage.toFixed(1);process.stdout.write(`\rProgress: ${t}% (${e.bytesUploaded}/${e.totalBytes} bytes)`)}});let u=Date.now()-l;console.log(``),r.json?R({success:!0,localPath:t,remotePath:n,size:c.size,durationMs:u}):console.log(`✓ Uploaded ${c.size} bytes in ${u}ms`)}catch(e){L(e,r.json)}}),K(e.command(`download`).description(`Download a file from a sandbox`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<remote-path>`,`Remote file path`).argument(`<local-path>`,`Local destination path`).option(`--json`,`Output as JSON`)).action(async(e,t,n,r)=>{try{let{context:i,client:a}=q(r),s=await H(a,i,e);s=await U(s);let c=Date.now();console.log(`Downloading ${t} to ${n}...`),await s.fs.download(t,n,{onProgress:e=>{let t=e.percentage.toFixed(1);process.stdout.write(`\rProgress: ${t}% (${e.bytesDownloaded}/${e.totalBytes} bytes)`)}});let l=Date.now()-c,u=o.statSync(n);console.log(``),r.json?R({success:!0,remotePath:t,localPath:n,size:u.size,durationMs:l}):console.log(`✓ Downloaded ${u.size} bytes in ${l}ms`)}catch(e){L(e,r.json)}}),K(e.command(`ls`).description(`List directory contents`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`[path]`,`Directory path`,`.`).option(`-l, --long`,`Show detailed information`).option(`-a, --all`,`Include hidden files`).option(`--json`,`Output as JSON`)).action(async(e,t,n)=>{try{let{context:r,client:i}=q(n),a=await H(i,r,e);a=await U(a);let o=await a.fs.list(t.startsWith(`/`)?t:`/${t}`,{all:n.all,long:n.long});if(n.json)R(o);else if(n.long)z([`Mode`,`Owner`,`Group`,`Size`,`Modified`,`Name`],o.map(e=>{let t=e.isDir?`d`:e.isSymlink?`l`:`-`,n=Or(e.permissions),r=e.isDir?`<DIR>`:kr(e.size),i=e.modTime.toLocaleDateString();return[t+n,e.owner,e.group,r,i,e.name]}));else{let e=o.map(e=>e.isDir?`${e.name}/`:e.name);console.log(e.join(` `))}}catch(e){L(e,n.json)}}),K(e.command(`stat`).description(`Get file or directory information`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to file or directory`).option(`--json`,`Output as JSON`)).action(async(e,t,n)=>{try{let{context:r,client:i}=q(n),a=await H(i,r,e);a=await U(a);let o=await a.fs.stat(t.startsWith(`/`)?t:`/${t}`);n.json?R(o):(console.log(` File: ${o.name}`),console.log(` Path: ${o.path}`),console.log(` Size: ${kr(o.size)} (${o.size} bytes)`),console.log(` Type: ${o.isDir?`directory`:o.isSymlink?`symlink`:`file`}`),console.log(` Mode: ${Or(o.permissions)} (${o.permissions.toString(8)})`),console.log(` Owner: ${o.owner}`),console.log(` Group: ${o.group}`),console.log(` Modified: ${o.modTime.toISOString()}`),console.log(` Accessed: ${o.accessTime.toISOString()}`))}catch(e){L(e,n.json)}}),K(e.command(`cat`).description(`Print file contents`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to file`).option(`--json`,`Output as JSON`)).action(async(e,t,n)=>{try{let{context:r,client:i}=q(n),a=await H(i,r,e);a=await U(a);let o=await a.read(t.startsWith(`/`)?t:`/${t}`);n.json?R({path:t,content:o}):console.log(o)}catch(e){L(e,n.json)}}),K(e.command(`rm`).description(`Delete a file or directory`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to delete`).option(`-r, --recursive`,`Delete directories recursively`).option(`--json`,`Output as JSON`)).action(async(e,t,n)=>{try{let{context:r,client:i}=q(n),a=await H(i,r,e);a=await U(a),await a.fs.delete(t.startsWith(`/`)?t:`/${t}`,{recursive:n.recursive}),n.json?R({success:!0,path:t,deleted:!0}):console.log(`✓ Deleted: ${t}`)}catch(e){L(e,n.json)}}),K(e.command(`mkdir`).description(`Create a directory`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Directory path to create`).option(`-p, --parents`,`Create parent directories as needed`).option(`--json`,`Output as JSON`)).action(async(e,t,n)=>{try{let{context:r,client:i}=q(n),a=await H(i,r,e);a=await U(a),await a.fs.mkdir(t.startsWith(`/`)?t:`/${t}`,{recursive:n.parents}),n.json?R({success:!0,path:t,created:!0}):console.log(`✓ Created: ${t}`)}catch(e){L(e,n.json)}}),K(e.command(`exists`).description(`Check if a path exists`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to check`).option(`--json`,`Output as JSON`)).action(async(e,t,n)=>{try{let{context:r,client:i}=q(n),a=await H(i,r,e);a=await U(a);let o=await a.fs.exists(t.startsWith(`/`)?t:`/${t}`);n.json?R({path:t,exists:o}):(console.log(o?`exists`:`not found`),process.exit(+!o))}catch(e){L(e,n.json)}}),e}function Or(e){let t=[`r`,`w`,`x`],n=``;for(let r=2;r>=0;r--){let i=r*3;for(let r=0;r<3;r++)n+=e>>i+(2-r)&1?t[r]:`-`}return n}function kr(e){let t=[`B`,`KB`,`MB`,`GB`,`TB`],n=e,r=0;for(;n>=1024&&r<t.length-1;)n/=1024,r++;return r===0?`${n}${t[r]}`:`${n.toFixed(1)}${t[r]}`}function K(e){return e.option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`)}function q(e){let t=E({apiKey:e.apiKey,baseUrl:e.baseUrl});return{context:t,client:k(t)}}function Ar(){let e=new t(`git`).description(`Git operations in a sandbox workspace`);return e.command(`status`).description(`Show git repository status`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching status...`);t.json||i.start();let a=await H(r,n,e);a=await U(a);let o=await a.git.status();if(i.stop(),t.json)j(o);else{if(console.log(`Branch: ${o.branch}`),console.log(`HEAD: ${o.head.slice(0,7)}`),console.log(`Dirty: ${o.isDirty?`yes`:`no`}`),o.ahead&&console.log(`Ahead: ${o.ahead}`),o.behind&&console.log(`Behind: ${o.behind}`),o.staged.length>0){console.log(`\nStaged (${o.staged.length}):`);for(let e of o.staged)console.log(` + ${e}`)}if(o.modified.length>0){console.log(`\nModified (${o.modified.length}):`);for(let e of o.modified)console.log(` M ${e}`)}if(o.untracked.length>0){console.log(`\nUntracked (${o.untracked.length}):`);for(let e of o.untracked)console.log(` ? ${e}`)}}}catch(e){B(e)}}),e.command(`log`).description(`Show commit log`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`-n, --limit <count>`,`Max commits to show`,`10`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching log...`);t.json||i.start();let a=await H(r,n,e);a=await U(a);let o=await a.git.log(Number.parseInt(t.limit,10));if(i.stop(),t.json)j(o);else if(o.length===0)console.log(`No commits found`);else for(let e of o)console.log(`${e.shortSha} ${e.message.split(`
137
+ `)[0]} (${e.author}, ${e.date.toLocaleDateString()})`)}catch(e){B(e)}}),e.command(`diff`).description(`Show diff`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--ref <ref>`,`Ref to diff against`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching diff...`);t.json||i.start();let a=await H(r,n,e);a=await U(a);let o=await a.git.diff(t.ref);i.stop(),t.json?j(o):o.raw?console.log(o.raw):console.log(`${o.additions} additions, ${o.deletions} deletions across ${o.files.length} files`)}catch(e){B(e)}}),e.command(`add`).description(`Stage files`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<paths...>`,`Paths to stage`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=await H(k(r),r,e);i=await U(i),await i.git.add(t),M(`Staged: ${t.join(`, `)}`)}catch(e){B(e)}}),e.command(`commit`).description(`Create a commit`).argument(`<id-or-name>`,`Sandbox ID or name`).requiredOption(`-m, --message <msg>`,`Commit message`).option(`--amend`,`Amend the previous commit`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=await H(k(n),n,e);r=await U(r);let i=await r.git.commit(t.message,{amend:t.amend});t.json?j(i):M(`Committed: ${i.shortSha} ${i.message}`)}catch(e){B(e)}}),e.command(`push`).description(`Push to remote`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--force`,`Force push`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Pushing...`);i.start();let a=await H(r,n,e);a=await U(a),await a.git.push({force:t.force}),i.stop(),M(`Pushed to remote`)}catch(e){B(e)}}),e.command(`pull`).description(`Pull from remote`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--rebase`,`Rebase instead of merge`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Pulling...`);i.start();let a=await H(r,n,e);a=await U(a),await a.git.pull({rebase:t.rebase}),i.stop(),M(`Pulled from remote`)}catch(e){B(e)}}),e.command(`branches`).description(`List branches`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching branches...`);t.json||i.start();let a=await H(r,n,e);a=await U(a);let o=await a.git.branches();i.stop(),t.json?j(o):o.length===0?console.log(`No branches found`):z([`Name`,`Current`,`Remote`],o.map(e=>[e.name,e.current?`* `:` `,e.upstream??`-`]))}catch(e){B(e)}}),e.command(`checkout`).description(`Checkout a branch or ref`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<ref>`,`Branch name or ref`).option(`-b, --create`,`Create a new branch`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=await H(k(r),r,e);i=await U(i),await i.git.checkout(t,{create:n.create}),M(`Checked out: ${t}${n.create?` (new)`:``}`)}catch(e){B(e)}}),e}function jr(){let e=new t(`hub`).description(`Discover and run Tangle Hub tools`);e.option(`--json`,`Output as JSON`),e.hook(`preAction`,(e,t)=>{Nr(t)}),e.command(`connect`).description(`Connect a provider account`).argument(`provider`,`Provider to connect`).option(`--no-browser`,`Print the authorization URL instead of opening it`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await(await V(t)).connections.start(e,{cli:!0});if(t.json){j(Xr(n));return}Yr(n,t.browser===!1?!1:await Wn(n.redirectUrl))}catch(e){J(e,t)}});let n=new t(`connections`).description(`List Hub provider connections`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=await(await V(e)).connections.list();if(e.json){j(t);return}Jr(t.connections)}catch(t){J(t,e)}});n.command(`revoke <connection-id>`).description(`Revoke a Hub provider connection`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await V(t),r=await jt(n,e);if(!t.force&&!await W(`Revoke Hub connection ${r}? `)){P(`Revoke cancelled.`);return}let i=await n.connections.revoke(r);if(t.json){j(i);return}P(`Revoked Hub connection ${i.connection.id}.`)}catch(e){J(e,t)}}),e.addCommand(n);let r=new t(`permissions`).description(`Manage Hub action permissions`);r.command(`list`).description(`List Hub permissions for a connection`).requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{if(!e.connection)throw Error(`--connection is required.`);let t=await V(e),n=await jt(t,e.connection),r=await t.permissions.list(n);if(e.json){j(r);return}Ur(r.policies)}catch(t){J(t,e)}}),r.command(`set`).description(`Set Hub permission for one action`).requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).requiredOption(`--action <path>`,`Executor action path`).requiredOption(`--decision <allow|ask|deny>`,`Permission decision`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{if(!e.connection)throw Error(`--connection is required.`);if(!e.action)throw Error(`--action is required.`);let t=Wr(e.decision),n=await V(e),r=await jt(n,e.connection),i=await n.permissions.set({connectionId:r,actionPath:e.action,decision:t});if(e.json){j(i);return}Ur([i.policy])}catch(t){J(t,e)}}),r.command(`revert-writes`).description("Revoke a bulk `--allow-writes` grant for a connection (deletes only the auto-granted write rows; manual permissions are untouched)").requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{if(!e.connection)throw Error(`--connection is required.`);let t=await V(e),n=await jt(t,e.connection),r=await t.permissions.revertWrites(n);if(e.json){j(r);return}P(`Reverted ${r.reverted} write permission${r.reverted===1?``:`s`} for connection ${r.connectionId}.`)}catch(t){J(t,e)}}),e.addCommand(r);let i=new t(`approvals`).description(`List and resolve Hub execution approvals`);i.command(`list`).description(`List pending Hub execution approvals`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=await(await V(e)).approvals.list();if(e.json){j(t);return}Rr(t.approvals)}catch(t){J(t,e)}}),i.command(`approve`).description(`Approve a pending Hub execution approval`).argument(`approval-id`,`Hub approval ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{Lr(e),zr(await(await V(t)).approvals.approve(e),t.json===!0)}catch(e){J(e,t)}}),i.command(`deny`).description(`Deny a pending Hub execution approval`).argument(`approval-id`,`Hub approval ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{Lr(e),zr(await(await V(t)).approvals.deny(e),t.json===!0)}catch(e){J(e,t)}}),e.addCommand(i);let a=new t(`tools`).description(`Discover Hub tools`);return a.command(`sources`).description(`List Hub tool sources`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=await(await V(e)).tools.sources();if(e.json){j(t);return}Gr(t.sources)}catch(t){J(t,e)}}),a.command(`describe`).description(`Describe a Hub tool`).argument(`path`,`Executor tool path`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await(await V(t)).tools.describe(e);if(t.json){j(n);return}Kr(n.tool)}catch(e){J(e,t)}}),a.command(`search`).description(`Search Hub tools`).argument(`<query...>`,`Search query`).option(`--provider <provider>`,`Filter by provider/source ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await(await V(t)).tools.search(e.join(` `),{provider:t.provider});if(t.json){j(n);return}Hr(n.tools)}catch(e){J(e,t)}}),e.addCommand(a),e.addCommand(Mr(`call`)),e.addCommand(Mr(`exec`)),e.command(`resume`).description(`Resolve a Hub approval created by a paused execution`).argument(`approval-id`,`Hub approval ID from HUB_APPROVAL_REQUIRED`).option(`--accept`,`Approve the execution approval`).option(`--decline`,`Deny the execution approval`).option(`--cancel`,`Unsupported for approval-backed Hub resume`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{if(Lr(e),t.cancel)throw Error(`Hub approval resume does not support --cancel. Use --decline to deny the approval.`);if(t.accept&&t.decline)throw Error(`Choose only one of --accept or --decline.`);if(!t.accept&&!t.decline)throw Error(`Choose --accept to approve or --decline to deny the Hub approval.`);let n=await V(t);zr(t.decline?await n.approvals.deny(e):await n.approvals.approve(e),t.json===!0)}catch(e){J(e,t)}}),e.command(`status`).description(`Show Hub auth and connection status`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=await(await V(e)).status();if(e.json){j(t);return}Zr(t)}catch(t){J(t,e)}}),e}function Mr(e){return new t(e).description(`Execute a Hub tool`).argument(`<args...>`,`Tool path tokens followed by JSON input`).option(`--connection <ref>`,`Hub connection id, or provider[:account]`).option(`--auto-approve`,`Approve a HUB_APPROVAL_REQUIRED execution and retry once`).option(`--approve`,`Alias for --auto-approve`).option(`--no-hub-key`,`Do not auto-mint a platform Hub key; use the stored credential as-is`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let{args:n,approve:r}=Ir(e,t),{path:i,input:a}=Vr(n),o=await V(t),s=t.connection?await jt(o,t.connection):void 0;j((await o.tools.invoke(i,a,{connectionId:s,approve:r})).result)}catch(e){J(e,t)}})}function Nr(e){if(!Pr(e,`json`)||e.getOptionValue(`json`)!==void 0)return;let t=e.parent;for(;t;){let n=t.getOptionValue(`json`);if(n!==void 0){e.setOptionValue(`json`,n);return}t=t.parent}}function Pr(e,t){return e.options.some(e=>e.attributeName()===t)}function Fr(e){return e.json===!0}function J(e,t){return Fr(t)?B(e,!0):B(e)}function Ir(e,t){let n=t.autoApprove;return{args:e.filter(e=>e!==`--approve`&&e!==`--auto-approve`),approve:t.approve===!0||n===!0||e.includes(`--approve`)||e.includes(`--auto-approve`)}}function Lr(e){if(!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`Hub approval ID must contain only letters, numbers, underscores, and dashes.`)}function Rr(e){A(e.map(e=>({id:e.id,provider:e.providerId,action:e.actionPath,connection:e.connectionId,status:e.status,expires:e.expiresAt})),[{key:`id`,header:`ID`},{key:`provider`,header:`Provider`},{key:`action`,header:`Action`},{key:`connection`,header:`Connection`},{key:`status`,header:`Status`},{key:`expires`,header:`Expires`}])}function zr(e,t){if(t){j(Br(e));return}P(`Hub approval ${e.approval.id} ${e.approval.status}.`),e.capabilityToken&&P("Capability token minted. Re-run the original command with `--approve` to execute automatically.")}function Br(e){return{approval:e.approval,...e.capabilityToken?{capabilityToken:{tokenId:e.capabilityToken.tokenId,expiresAt:e.capabilityToken.expiresAt}}:{}}}function Vr(e){if(e.length<2)throw Error(`Usage: tangle hub call <path> <json-input>`);let t=e.at(-1);if(t===void 0)throw Error(`Usage: tangle hub call <path> <json-input>`);try{return{path:e.slice(0,-1).join(`.`),input:JSON.parse(t)}}catch{throw Error(`Hub call input must be valid JSON.`)}}function Hr(e){A(e.map(e=>({path:e.path,provider:e.providerId??e.requiredConnectionProviderId,title:e.title,description:e.description,connection:qr(e),policy:e.policyState})),[{key:`path`,header:`Path`},{key:`provider`,header:`Provider`},{key:`title`,header:`Title`},{key:`description`,header:`Description`},{key:`connection`,header:`Connection`},{key:`policy`,header:`Policy`}])}function Ur(e){A(e.map(e=>({connection:e.connectionId,provider:e.providerId,action:e.actionPath,decision:e.decision,updated:e.updatedAt})),[{key:`connection`,header:`Connection`},{key:`provider`,header:`Provider`},{key:`action`,header:`Action`},{key:`decision`,header:`Decision`},{key:`updated`,header:`Updated`}])}function Wr(e){if(e===`allow`||e===`ask`||e===`deny`)return e;throw Error(`--decision must be one of: allow, ask, deny.`)}function Gr(e){A(e.map(e=>({source:e.sourceId,provider:e.displayName,tools:e.toolCount,connection:e.connectionStatus,health:e.health,configured:e.configured})),[{key:`source`,header:`Source`},{key:`provider`,header:`Provider`},{key:`tools`,header:`Tools`},{key:`connection`,header:`Connection`},{key:`health`,header:`Health`},{key:`configured`,header:`Configured`}])}function Kr(e){I({Path:e.path,Provider:e.providerId??e.requiredConnectionProviderId,Title:e.title,Description:e.description,Connection:qr(e),Policy:e.policyState}),e.inputSchema!==void 0&&(P(`Input schema`),console.log(JSON.stringify(e.inputSchema,null,2))),e.outputSchema!==void 0&&(P(`Output schema`),console.log(JSON.stringify(e.outputSchema,null,2)))}function qr(e){if(e.connectionRequired===!1)return`not required`;if(e.connectionStatus)return e.connectionStatus}function Jr(e){A(e.map(e=>({id:e.id,provider:e.providerId,account:e.accountDisplay??e.displayName,scopes:e.scopes.join(`, `),status:e.status,health:e.health,lastUsed:e.lastUsedAt})),[{key:`id`,header:`ID`},{key:`provider`,header:`Provider`},{key:`account`,header:`Account`},{key:`scopes`,header:`Scopes`},{key:`status`,header:`Status`},{key:`health`,header:`Health`},{key:`lastUsed`,header:`Last Used`}])}function Yr(e,t){t?P(`Opened browser to connect ${e.provider}.`):(P(`Open this URL to connect ${e.provider}:`),console.log(e.redirectUrl)),P("Finish authorization in the browser, then rerun `tangle hub status`.")}function Xr(e){return{provider:e.provider,redirectUrl:e.redirectUrl,expiresAt:e.expiresAt,scopes:e.scopes,cli:e.cli}}function Zr(e){let{principal:t,connections:n}=e;P(`Hub status`),I({Principal:t.kind,"User ID":t.userId,"API Key ID":t.apiKeyId,"Sandbox ID":t.sandboxId,"Connected Providers":n.connectedProviderCount,"Unhealthy Providers":n.unhealthyProviderCount}),n.unhealthyProviderCount>0&&P(`Some providers require reconnect.`)}const Qr=[`codex`,`claude-code`,`nanoclaw`,`kimi-code`,`opencode`,`pi`,`openclaw`,`hermes`],$r=[`codex`,`claude-code`],ei=[`codex`,`claude-code`,`nanoclaw`],ti=[`SessionStart`,`UserPromptSubmit`,`PreToolUse`,`PostToolUse`,`Stop`],ni={codex:{kind:`native`,surface:`codex`,label:`Codex`,buildFiles:mi},"claude-code":{kind:`native`,surface:`claude-code`,label:`Claude Code`,buildFiles:hi},nanoclaw:{kind:`native`,surface:`nanoclaw`,label:`NanoClaw`,buildFiles:hi},"kimi-code":{kind:`manual`,surface:`kimi-code`,label:`Kimi Code`,reason:`Kimi Code loads hooks through an explicit config file, so use standard OTLP env wiring until the native config adapter is verified.`},opencode:{kind:`manual`,surface:`opencode`,label:`OpenCode`,reason:`OpenCode hooks run as plugins; use standard OTLP env wiring until the native plugin adapter is verified.`},pi:{kind:`manual`,surface:`pi`,label:`Pi`,reason:`Pi hooks run through TypeScript extensions; use standard OTLP env wiring until the native extension adapter is verified.`},openclaw:{kind:`manual`,surface:`openclaw`,label:`OpenClaw`,reason:`OpenClaw project hooks require user opt-in; use standard OTLP env wiring until the hook toggle and adapter are verified.`},hermes:{kind:`manual`,surface:`hermes`,label:`Hermes`,reason:`Hermes project plugins require explicit enablement; use standard OTLP env wiring until the plugin adapter is verified.`}};function ri(e){let t=e.split(`,`).map(e=>e.trim()).filter(Boolean).flatMap(e=>pi(e));return t.length===0?[...$r]:Di(t)}function ii(e){return Object.hasOwn(ni,e)}function ai(e=process.cwd()){return p(re(e))||`agent-workspace`}function oi(){return ne(fe(),`.tangle`,`intelligence.json`)}function si(e=oi()){if(!s(e))return null;let t=wi(e),n=Oi(t,`apiKey`),r=Oi(t,`endpoint`),i=Oi(t,`serviceName`),a=Oi(t,`environment`);if(!n||!r||!i||!a)throw Error(`${e} is missing apiKey, endpoint, serviceName, or environment`);return{apiKey:n,endpoint:r,serviceName:i,environment:a}}async function ci(e){let t=re(e.workspace),n=oi(),r=ri(e.selection),i=[],a=[],o=[],s={apiKey:e.apiKey,endpoint:fi(e.endpoint),serviceName:e.serviceName,environment:e.environment};e.dryRun||xi(n,s),o.push(n);for(let n of r){let r=ni[n];if(r.kind===`manual`){a.push({agent:r.surface,label:r.label,reason:r.reason});continue}i.push(r.surface);let s=t=>li(e.hookCommand,r.surface,t);for(let n of r.buildFiles(s)){let r=ne(t,n.relPath);if(e.dryRun){o.push(r);continue}Ci(r,JSON.parse(n.content),n.mode),o.push(r)}}return!e.smoke||e.dryRun?{configPath:n,written:o,agents:r,nativeAgents:i,manual:a}:{configPath:n,written:o,agents:r,nativeAgents:i,manual:a,smokeTraceId:await di({agent:i[0]??r[0]??`codex`,event:`install.smoke`,endpoint:s.endpoint,apiKey:s.apiKey,serviceName:s.serviceName,environment:s.environment,sessionId:`install-smoke-${Date.now()}`,payload:{source:`tangle intelligence connect`}})}}function li(e,t,n){return`${e.trim()} --agent ${t} --event ${n} --non-blocking`}function ui(e){let t=BigInt(Date.now())*1000000n,n=Ai(16),r=Ai(8),i=e.sessionId??gi(e.payload),a={"service.name":e.serviceName,"deployment.environment":e.environment,"tangle.agent.surface":e.agent,"tangle.agent.hook.event":e.event,"tangle.agent.hook.source":`local-hook`,..._i(e.payload)};return i&&(a[`session.id`]=i,a[`gen_ai.conversation.id`]=i,a[`tangle.sessionId`]=i),{body:{resourceSpans:[{resource:{attributes:[ji(`service.name`,e.serviceName),ji(`deployment.environment`,e.environment),ji(`tangle.agent.surface`,e.agent)]},scopeSpans:[{scope:{name:`tangle.intelligence.agent-hook`,version:`1.0.0`},spans:[{traceId:n,spanId:r,name:`agent.${e.agent}.${e.event}`,kind:1,startTimeUnixNano:t.toString(),endTimeUnixNano:(t+1000000n).toString(),attributes:Object.entries(a).map(([e,t])=>ji(e,t)),status:{code:1}}]}]}]},traceId:n}}async function di(e){let{body:t,traceId:n}=ui(e),r=await fetch(`${fi(e.endpoint)}/v1/traces`,{method:`POST`,headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":`application/json`},body:JSON.stringify(t)});if(!r.ok){let e=await r.text().catch(()=>``);throw Error(`OTLP smoke ingest failed: ${r.status}${e?` ${e}`:``}`)}return n}function fi(e){let t=e.trim().replace(/\/+$/,``);return t.endsWith(`/v1/traces`)?t.slice(0,-10):t.endsWith(`/v1/logs`)?t.slice(0,-8):t}function pi(e){switch(e){case`local`:case`both`:return[...$r];case`all`:return[...ei];case`claude`:return[`claude-code`];case`kimi`:return[`kimi-code`];default:if(ii(e))return[e];throw Error(`agent must be one of: local, all, both, ${Qr.join(`, `)}`)}}function mi(e){let t=Object.fromEntries(ti.map(t=>[t,[{command:e(t),timeoutMs:3e3,blocking:!1,matcher:`*`}]]));return[{relPath:`.codex/hooks.json`,content:JSON.stringify({hooks:t},null,2)}]}function hi(e){let t=Object.fromEntries(ti.map(t=>[t,[{matcher:`*`,hooks:[{type:`command`,command:e(t),timeout:3}]}]]));return[{relPath:`.claude/settings.json`,content:JSON.stringify({hooks:t},null,2)}]}function gi(e){return vi(e,[`session.id`,`sessionId`,`session_id`,`conversationId`,`conversation_id`,`threadId`,`thread_id`,`transcriptId`,`transcript_id`])||process.env.TANGLE_SESSION_ID||process.env.CODEX_THREAD_ID||process.env.CLAUDE_SESSION_ID||process.env.OPENCODE_SESSION_ID}function _i(e){let t={},n=Y(e,[`tool.name`,`toolName`,`tool_name`,`tool`]),r=Y(e,[`command`,`cmd`,`shell_command`,`shellCommand`]),i=Y(e,[`tool.input`,`toolInput`,`tool_input`,`input`,`arguments`,`args`]),a=Y(e,[`tool.output`,`toolOutput`,`tool_output`,`output`,`result`]),o=Y(e,[`tool.exit_code`,`exitCode`,`exit_code`,`status`]),s=Y(e,[`tool.error.message`,`errorMessage`,`error_message`,`error`]);return n&&(t[`tool.name`]=n),r&&(t[`process.command`]=r),i&&(t[`tool.input.summary`]=i),a&&(t[`tool.output.summary`]=a),o&&(t[`tool.exit_code`]=o),s&&(t[`tool.error.message`]=s),t}function Y(e,t){let n=yi(e,t);if(n===void 0)return null;if(typeof n==`string`)return bi(n);if(typeof n==`number`||typeof n==`boolean`||typeof n==`bigint`)return String(n);try{return bi(JSON.stringify(n))}catch{return null}}function vi(e,t){let n=yi(e,t);return typeof n==`string`&&n.length>0?n:void 0}function yi(e,t){if(typeof e!=`object`||!e)return;let n=[e],r=new Set;for(;n.length;){let e=n.pop();if(typeof e!=`object`||!e||r.has(e))continue;r.add(e);let i=e;for(let e of t){let t=i[e];if(t!=null&&t!==``)return t}for(let e of Object.values(i))typeof e==`object`&&e&&n.push(e)}}function bi(e){return e.length>4096?`${e.slice(0,4093)}...`:e}function xi(e,t){Si(e,`${JSON.stringify(t,null,2)}\n`)}function Si(e,t){c(ee(e),{mode:448,recursive:!0});let n=`${e}.${process.pid}.tmp`;d(n,t,{mode:384}),u(n,e)}function Ci(e,t,n){c(ee(e),{recursive:!0});let r=Ti(wi(e),t);d(e,`${JSON.stringify(r,null,2)}\n`,{mode:n??420})}function wi(e){if(!s(e))return{};let t=JSON.parse(l(e,`utf8`));if(!ki(t))throw Error(`${e} must contain a JSON object`);return t}function Ti(e,t){let n={...e};for(let[e,r]of Object.entries(t)){let t=n[e];ki(t)&&ki(r)?n[e]=Ti(t,r):Array.isArray(t)&&Array.isArray(r)?n[e]=Ei([...t,...r]):n[e]=r}return n}function Ei(e){let t=new Set,n=[];for(let r of e){let e=JSON.stringify(r);t.has(e)||(t.add(e),n.push(r))}return n}function Di(e){return[...new Set(e)]}function Oi(e,t){let n=e[t];return typeof n==`string`&&n.length>0?n:void 0}function ki(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&(Object.getPrototypeOf(e)===Object.prototype||Object.getPrototypeOf(e)===null)}function Ai(e){return r(e).toString(`hex`)}function ji(e,t){return{key:e,value:{stringValue:t}}}function Mi(){let e=new t(`intelligence`).description(`Create and inspect trace intelligence reports`);return e.command(`connect [agent]`).alias(`connect-agent`).description(`Connect local agent CLIs to Tangle Intelligence`).option(`--api-key <key>`,`Intelligence ingest API key`).option(`--endpoint <url>`,`OTLP endpoint base`,`https://intelligence.tangle.tools/v1/otlp`).option(`--workspace <path>`,`Workspace to write hook files into`,`.`).option(`--service-name <name>`,`OTel service.name label`).option(`--environment <name>`,`OTel deployment.environment label`,`local`).option(`--dry-run`,`Print planned writes without changing files`).option(`--hook-command <command>`,`Command native hooks should run`,`tangle intelligence hook`).option(`--no-smoke`,`Skip the install smoke trace`).option(`--json`,`Output as JSON`).action(async(e,t)=>{try{let n=e??`local`;ri(n);let r=Ni(t.apiKey),i=await ci({selection:n,workspace:t.workspace,apiKey:r,endpoint:t.endpoint,serviceName:t.serviceName??ai(t.workspace),environment:t.environment,smoke:t.smoke,dryRun:!!t.dryRun,hookCommand:t.hookCommand}),a={configPath:i.configPath,agents:i.agents,nativeAgents:i.nativeAgents,manual:i.manual,written:i.written,smokeTraceId:i.smokeTraceId};if(t.json){j(a);return}I({Config:i.configPath,Agents:i.agents.join(`, `),"Native Hooks":i.nativeAgents.join(`, `)||void 0,"Manual Setup":i.manual.length?i.manual.map(e=>`${e.label}: ${e.reason}`).join(` `):void 0,Files:i.written.join(`, `),"Smoke Trace":i.smokeTraceId})}catch(e){B(e)}}),e.command(`hook`).description(`Emit one local agent hook event to Tangle Intelligence`).requiredOption(`--agent <agent>`,`Agent surface`).requiredOption(`--event <event>`,`Hook event name`).option(`--payload <json>`,`Hook payload JSON`).option(`--api-key <key>`,`Intelligence ingest API key`).option(`--endpoint <url>`,`OTLP endpoint base`).option(`--service-name <name>`,`OTel service.name label`).option(`--environment <name>`,`OTel deployment.environment label`).option(`--session-id <id>`,`Session id override`).option(`--dry-run`,`Build the OTLP request without sending it`).option(`--non-blocking`,`Do not fail the parent agent process`).option(`--json`,`Output as JSON`).action(async e=>{try{let t=Pi(e.agent),n=si(),r={agent:t,event:e.event,endpoint:e.endpoint??n?.endpoint??`https://intelligence.tangle.tools/v1/otlp`,apiKey:Ni(e.apiKey??n?.apiKey),serviceName:e.serviceName??n?.serviceName??ai(process.cwd()),environment:e.environment??n?.environment??`local`,sessionId:e.sessionId,payload:e.payload===void 0?await Ii():Fi(e.payload)};if(e.dryRun){let n=ui(r);if(e.json){j(n);return}I({Trace:n.traceId,Agent:t,Event:e.event});return}let i=await di(r);if(e.json){j({traceId:i});return}I({Trace:i,Agent:t,Event:e.event})}catch(t){if(e.nonBlocking){let n=t instanceof Error?t.message:String(t);e.json?j({ok:!1,error:n}):console.error(`Tangle Intelligence hook skipped: ${n}`);return}B(t)}}),e.command(`sandbox <sandbox-id>`).description(`Create an intelligence report for one sandbox`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{await Li({type:`sandbox`,id:e},t)}),e.command(`fleet <fleet-id>`).description(`Create an intelligence report for a sandbox fleet`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{await Li({type:`fleet`,id:e},t)}),e.command(`create`).description(`Create a trace intelligence report`).requiredOption(`--subject-type <type>`,`sandbox | fleet`).requiredOption(`--subject-id <id>`,`Subject identifier`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{await Li({type:zi(e.subjectType),id:e.subjectId},e)}),e.command(`get <job-id>`).description(`Get an intelligence report`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=t.json?null:F(`Fetching intelligence report...`);r?.start();let i=await n.intelligence.getReport(e);if(r?.stop(),t.json){j(i);return}Ri(i)}catch(e){B(e)}}),e.command(`list`).description(`List intelligence reports`).option(`--subject-type <type>`,`sandbox | fleet`).option(`--subject-id <id>`,`Subject identifier`).option(`--limit <count>`,`Maximum reports to return`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=k(E({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=e.json?null:F(`Fetching intelligence reports...`);n?.start();let r=await t.intelligence.listReports({subjectType:e.subjectType===void 0?void 0:zi(e.subjectType),subjectId:e.subjectId,limit:e.limit===void 0?void 0:Hi(e.limit)});if(n?.stop(),e.json){j(r);return}A(r.map(e=>({jobId:e.jobId,subject:`${e.subject.type}:${e.subject.id}`,mode:e.mode,status:e.status,cost:`$${e.billing.costUsd.toFixed(2)}`,updatedAt:e.updatedAt})),[{key:`jobId`,header:`Job`,width:20},{key:`subject`,header:`Subject`,width:28},{key:`mode`,header:`Mode`,width:15},{key:`status`,header:`Status`,width:14},{key:`cost`,header:`Cost`,width:10},{key:`updatedAt`,header:`Updated`,width:18}])}catch(e){B(e)}}),e}function Ni(e){let t=e??process.env.TANGLE_INTELLIGENCE_API_KEY??process.env.TANGLE_API_KEY;if(!t)throw Error(`--api-key, TANGLE_INTELLIGENCE_API_KEY, or TANGLE_API_KEY is required`);return t}function Pi(e){if(ii(e))return e;throw Error(`agent must be a known Tangle Intelligence agent surface`)}function Fi(e){try{return JSON.parse(e)}catch(e){throw Error(`--payload must be JSON: ${e instanceof Error?e.message:String(e)}`)}}async function Ii(){if(process.stdin.isTTY)return;let e=``;for await(let t of process.stdin)if(e+=typeof t==`string`?t:t.toString(`utf8`),e.length>65536)throw Error(`hook payload exceeds 65536 bytes`);let t=e.trim();if(t)try{return JSON.parse(t)}catch{return{body:t.slice(0,4096)}}}async function Li(e,t){try{let n=Bi(t.mode),r=Ui(t.metadata),i=t.maxUsd===void 0?void 0:Vi(t.maxUsd);if(n===`agentic`&&i===void 0)throw Error(`Agentic intelligence reports require --max-usd`);let a=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl})),o=t.json?null:F(`Creating intelligence report...`);o?.start();let s=await a.intelligence.createReport({subject:e,mode:n,...i===void 0?{}:{budget:{billTo:`customer`,maxUsd:i}},...r===void 0?{}:{metadata:r}});if(o?.stop(),t.json){j(s);return}Ri(s)}catch(e){B(e)}}function Ri(e){I({Job:e.jobId,Subject:`${e.subject.type}:${e.subject.id}`,Mode:e.mode,Status:e.status,"Billed To":e.billing.billedTo,Cost:`$${e.billing.costUsd.toFixed(2)}`,Budget:e.billing.budgetMaxUsd===void 0?void 0:`$${e.billing.budgetMaxUsd.toFixed(2)}`,Updated:e.updatedAt}),e.result!==null&&(console.log(),j(e.result))}function zi(e){if(e===`sandbox`||e===`fleet`)return e;throw Error(`subject type must be sandbox or fleet`)}function Bi(e){if(e===`deterministic`||e===`agentic`)return e;throw Error(`mode must be deterministic or agentic`)}function Vi(e){let t=Number(e);if(!Number.isFinite(t)||t<0)throw Error(`--max-usd must be a non-negative number`);return t}function Hi(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function Ui(e){if(e===void 0)return;let t=JSON.parse(e);if(!t||typeof t!=`object`||Array.isArray(t))throw Error(`--metadata must be a JSON object`);return t}const Wi=[`router`,`sandbox`,`blueprint-agent`,`evals`,`agent-builder`];function Gi(e){return(e?.trim()||process.env.TANGLE_PLATFORM_URL?.trim()||`https://id.tangle.tools`).replace(/\/+$/,``)}async function Ki(e,t,n={}){let r=new Headers(n.headers);r.set(`Authorization`,`Bearer ${t}`),n.body&&!r.has(`content-type`)&&r.set(`content-type`,`application/json`);let i=await fetch(e,{...n,headers:r});if(n.expected!==void 0&&i.status!==n.expected){let t=await i.text().catch(()=>``),n=t?`: ${t.slice(0,400)}`:``;throw Error(`Platform request to ${e} returned ${i.status}${n}`)}return i}const qi=[`ID`,`Prefix`,`Name`,`Product`,`Created`,`Last used`,`Expires`];function Ji(e){return[e.id,e.keyPrefix??``,e.name,e.product??`all`,e.createdAt,e.lastUsedAt??`—`,e.expiresAt??`—`]}function Yi(){let e=new t(`keys`).description(`Manage sk-tan-* API keys on id.tangle.tools`);return e.command(`list`).description(`List your active API keys`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key (overrides configured credentials)`).option(`--base-url <url>`,`Sandbox API base URL (not platform URL)`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async e=>{try{let t=E({apiKey:e.apiKey,baseUrl:e.baseUrl}),n=await(await Ki(`${Gi(e.platformUrl)}/v1/keys`,t.apiKey,{expected:200})).json();if(e.json){j(n);return}z(qi,n.data.map(Ji))}catch(e){B(e)}}),e.command(`create`).description(`Create a new API key`).argument(`<name>`,`Human-readable name for the key`).option(`--product <product>`,`Restrict the key to one product (${Wi.join(`|`)}). Omit for all products.`).option(`--budget-usd <amount>`,`Hard budget cap in USD`).option(`--rpm-limit <limit>`,`Requests-per-minute cap`).option(`--expires-in-days <days>`,`Expire the key after N days (integer)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key (overrides configured credentials)`).option(`--base-url <url>`,`Sandbox API base URL (not platform URL)`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{try{if(t.product!==void 0&&!Wi.includes(t.product))throw Error(`Invalid --product. Expected one of ${Wi.join(`, `)}`);let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=Gi(t.platformUrl),i=t.expiresInDays===void 0?void 0:new Date(Date.now()+Number.parseInt(t.expiresInDays,10)*24*60*60*1e3).toISOString(),a=F(`Creating API key...`);a.start();let o=await Ki(`${r}/v1/keys`,n.apiKey,{method:`POST`,expected:201,body:JSON.stringify({name:e,product:t.product,budgetUsd:t.budgetUsd?Number.parseFloat(t.budgetUsd):void 0,rpmLimit:t.rpmLimit?Number.parseInt(t.rpmLimit,10):void 0,expiresAt:i})});a.stop();let s=await o.json();if(t.json){j(s);return}M(`API key created: ${s.data.prefix}…`),P(`Copy this key now — it will never be shown again:\n${s.data.key}`)}catch(e){B(e)}}),e.command(`revoke`).description(`Revoke an API key`).argument(`<keyId>`,"Key ID (from `tcloud keys list`)").option(`--yes`,`Skip the confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key (overrides configured credentials)`).option(`--base-url <url>`,`Sandbox API base URL (not platform URL)`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=Gi(t.platformUrl);if(!t.yes&&!await W(`Revoke key ${e}? Any service still using it will start to fail.`)){P(`Aborted.`);return}let i=await(await Ki(`${r}/v1/keys/${encodeURIComponent(e)}`,n.apiKey,{method:`DELETE`,expected:200})).json();if(t.json){j(i);return}M(`Revoked ${e}`)}catch(e){B(e)}}),e}function Xi(){let e=new t(`mcp`).description(`Model Context Protocol bridge commands.`);return e.command(`serve <id-or-name>`).description(`Run a local MCP server (stdio) backed by the given sandbox (ID or name). Pipe its stdio from an MCP client config to expose sandbox tools.`).option(`-s, --session <id>`,`Session id for kernel scoping`,`mcp-local`).option(`--name <name>`,`MCP server name reported to clients`,`tangle-sandbox`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=await H(k(n),n,e),i;try{i=(await import(`@modelcontextprotocol/sdk/server/stdio.js`)).StdioServerTransport}catch{throw Error("`@modelcontextprotocol/sdk` is not installed in this environment. Install it with: pnpm add -g @modelcontextprotocol/sdk (or as a dev dep in the project running this command).")}let{connect:a,close:o}=await ve(r,{sessionId:t.session,name:t.name});await a(new i),process.stdin.resume(),process.stdin.on(`end`,()=>{o().finally(()=>process.exit(0))});for(let e of[`SIGINT`,`SIGTERM`])process.on(e,()=>{o().finally(()=>process.exit(0))})}catch(e){B(e)}}),e}function Zi(){let e=new t(`permissions`).description(`Manage sandbox user permissions`);return e.command(`list <sandboxId-or-name>`).description(`List all users in a sandbox`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching users...`);i.start();let a=await(await H(r,n,e)).permissions.list();i.stop(),t.json?j(a):A(a.map(e=>({userId:e.userId,username:e.username,role:e.role,homeDir:e.homeDir,createdAt:e.createdAt.toISOString().split(`T`)[0]})),[{key:`userId`,header:`User ID`,width:20},{key:`username`,header:`Username`,width:16},{key:`role`,header:`Role`,width:12},{key:`homeDir`,header:`Home Directory`,width:24},{key:`createdAt`,header:`Created`,width:16}])}catch(e){B(e)}}),e.command(`get <sandboxId-or-name> <userId>`).description(`Get details for a specific user`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Fetching user...`);a.start();let o=await(await H(i,r,e)).permissions.get(t);if(a.stop(),!o)throw Error(`User ${t} not found in sandbox ${e}`);n.json?j(o):(P(`User: ${o.userId}`),P(` Username: ${o.username}`),P(` Role: ${o.role}`),P(` Home: ${o.homeDir}`),P(` SSH Keys: ${o.sshKeys.length}`),P(` Created: ${o.createdAt.toISOString()}`))}catch(e){B(e)}}),e.command(`add <sandboxId-or-name>`).description(`Add a user to a sandbox`).requiredOption(`--user-id <id>`,`User ID (from your auth system)`).option(`--username <name>`,`Preferred username`).option(`--role <role>`,`Permission level (owner, admin, developer, viewer)`,`developer`).option(`--ssh-key <key>`,`SSH public key for access`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Adding user...`);i.start();let a=await(await H(r,n,e)).permissions.add({userId:t.userId,username:t.username,role:t.role,sshKeys:t.sshKey?[t.sshKey]:void 0});i.stop(),t.json?j(a):(M(`User ${a.userId} added as ${a.role}`),P(` Username: ${a.username}`),P(` Home: ${a.homeDir}`))}catch(e){B(e)}}),e.command(`update <sandboxId-or-name> <userId>`).description(`Update a user's permissions`).option(`--role <role>`,`New permission level (owner, admin, developer, viewer)`).option(`--add-ssh-key <key>`,`Add SSH public key`).option(`--remove-ssh-key <key>`,`Remove SSH public key`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Updating user...`);a.start();let o=await(await H(i,r,e)).permissions.update(t,{role:n.role,addSshKeys:n.addSshKey?[n.addSshKey]:void 0,removeSshKeys:n.removeSshKey?[n.removeSshKey]:void 0});a.stop(),n.json?j(o):(M(`User ${t} updated`),P(` Role: ${o.role}`),P(` SSH Keys: ${o.sshKeys.length}`))}catch(e){B(e)}}),e.command(`remove <sandboxId-or-name> <userId>`).description(`Remove a user from a sandbox`).option(`--preserve-home`,`Keep user's home directory`).option(`-f, --force`,`Skip confirmation`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{if(!n.force){let e=(await import(`node:readline`)).createInterface({input:process.stdin,output:process.stdout});if(!await new Promise(n=>{e.question(`Remove user ${t} from sandbox? [y/N] `,t=>{e.close(),n(t.toLowerCase()===`y`)})})){P(`Cancelled.`);return}}let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Removing user...`);a.start(),await(await H(i,r,e)).permissions.remove(t,{preserveHomeDir:n.preserveHome}),a.stop(),M(`User ${t} removed from sandbox ${e}`)}catch(e){B(e)}}),e.command(`policies <sandboxId-or-name> <userId>`).description(`Get access policies for a user`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Fetching policies...`);a.start();let o=await(await H(i,r,e)).permissions.getAccessPolicies(t);a.stop(),n.json?j(o):o.length===0?P(`No access policies configured`):A(o.map(e=>({pattern:e.pattern,permission:e.permission,priority:e.priority??0})),[{key:`pattern`,header:`Pattern`,width:30},{key:`permission`,header:`Permission`,width:12},{key:`priority`,header:`Priority`,width:10}])}catch(e){B(e)}}),e.command(`check <sandboxId-or-name> <userId> <path> <action>`).description(`Check if a user can perform an action on a path`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n,r,i)=>{try{if(![`read`,`write`,`execute`].includes(r))throw Error(`Action must be: read, write, or execute`);let a=E({apiKey:i.apiKey,baseUrl:i.baseUrl}),o=k(a),s=F(`Checking access...`);s.start();let c=await(await H(o,a,e)).permissions.checkAccess(t,n,r);s.stop(),c?M(`✓ User ${t} CAN ${r} ${n}`):P(`✗ User ${t} CANNOT ${r} ${n}`)}catch(e){B(e)}}),e}function Qi(){let e=new t(`preview`).description(`Manage sandbox preview links`);return e.command(`list`).alias(`ls`).description(`List active preview links for a sandbox`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching preview links...`);t.json||i.start();let a=await(await H(r,n,e)).previewLinks.list();i.stop(),t.json?j(a):a.length===0?console.log(`No preview links found`):z([`Preview ID`,`Port`,`URL`,`Status`],a.map(e=>[e.previewId.slice(0,12),String(e.port),e.url,e.status]))}catch(e){B(e)}}),e.command(`create`).description(`Create a preview link for a port`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<port>`,`Port number to preview`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Creating preview for port ${t}...`);n.json||a.start();let o=await(await H(i,r,e)).previewLinks.create(Number.parseInt(t,10));a.stop(),n.json?j(o):(M(`Preview created: ${o.url}`),console.log(`Preview ID: ${o.previewId}`))}catch(e){B(e)}}),e.command(`remove`).alias(`rm`).description(`Remove a preview link`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<preview-id>`,`Preview link ID (from 'preview list')`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Removing preview...`);n.json||a.start(),await(await H(i,r,e)).previewLinks.remove(t),a.stop(),n.json?j({success:!0,previewId:t}):M(`Preview removed: ${t}`)}catch(e){B(e)}}),e}function $i(){let e=new t(`process`).description(`Manage processes in a sandbox`);return e.command(`spawn`).description(`Spawn a process without blocking (returns PID)`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<command>`,`Command to execute`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`).option(`--blocking`,`Wait for completion (default: false)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a={};if(n.env)for(let e of n.env){let[t,...n]=e.split(`=`);t&&n.length>0&&(a[t]=n.join(`=`))}let o=F(`Spawning: ${t}`);n.json||o.start();let s=await H(i,r,e);if(s=await U(s),n.blocking){let e=await s.exec(t,{cwd:n.cwd,env:Object.keys(a).length>0?a:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});o.stop(),n.json?j(e):(e.stdout&&globalThis.process.stdout.write(e.stdout),e.stderr&&globalThis.process.stderr.write(e.stderr),e.exitCode!==0&&globalThis.process.exit(e.exitCode))}else{let r=await s.process.spawn(t,{cwd:n.cwd,env:Object.keys(a).length>0?a:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});o.stop(),n.json?j({pid:r.pid,command:r.command}):(console.log(`Process started with PID: ${r.pid}`),console.log(`Use 'tangle process logs ${e} ${r.pid}' to view output`))}}catch(e){B(e)}}),e.command(`list`).alias(`ls`).description(`List all processes in a sandbox`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--running`,`Show only running processes`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching processes...`);t.json||i.start();let a=await H(r,n,e);a=await U(a);let o=await a.process.list();t.running&&(o=o.filter(e=>e.running)),i.stop(),t.json?j(o):o.length===0?console.log(`No processes found`):z([`PID`,`Command`,`Status`,`Exit Code`,`Started`],o.map(e=>[String(e.pid),e.command.length>40?`${e.command.slice(0,37)}...`:e.command,e.running?`running`:`exited`,String(e.exitCode),e.startedAt.toLocaleString()]))}catch(e){B(e)}}),e.command(`get`).description(`Get detailed info about a process`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Fetching process info...`);n.json||a.start();let o=await H(i,r,e);o=await U(o);let s=await o.process.get(Number.parseInt(t,10));if(a.stop(),!s){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}let c=await s.status();n.json?j(c):(console.log(`PID: ${c.pid}`),console.log(`Command: ${c.command}`),console.log(`CWD: ${c.cwd||`(default)`}`),console.log(`Status: ${c.running?`running`:`exited`}`),console.log(`Exit Code: ${c.exitCode}`),c.exitSignal&&console.log(`Signal: ${c.exitSignal}`),console.log(`Started: ${c.startedAt.toLocaleString()}`),c.exitedAt&&console.log(`Exited: ${c.exitedAt.toLocaleString()}`))}catch(e){B(e)}}),e.command(`kill`).description(`Kill a process`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).option(`-s, --signal <signal>`,`Signal to send (SIGTERM, SIGKILL, etc.)`,`SIGTERM`).option(`--tree`,`Also kill descendants of the tracked process`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Sending ${n.signal} to PID ${t}...`);n.json||a.start();let o=await H(i,r,e);o=await U(o);let s=await o.process.get(Number.parseInt(t,10));if(!s){a.stop(),console.error(`Process ${t} not found`),globalThis.process.exit(1);return}n.tree?await s.kill(n.signal,{tree:!0}):await s.kill(n.signal),a.stop(),n.json?j({pid:Number.parseInt(t,10),signal:n.signal,...n.tree===!0?{tree:!0}:{},killed:!0}):console.log(n.tree?`Sent ${n.signal} to process tree ${t}`:`Sent ${n.signal} to process ${t}`)}catch(e){B(e)}}),e.command(`logs`).description(`Stream buffered and live process logs until the process exits`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).option(`--stdout-only`,`Only show stdout`).option(`--stderr-only`,`Only show stderr`).option(`--json`,`Output as JSON lines`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=await H(k(r),r,e);i=await U(i);let a=await i.process.get(Number.parseInt(t,10));if(!a){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}for await(let e of a.logs())n.stdoutOnly&&e.type!==`stdout`||n.stderrOnly&&e.type!==`stderr`||(n.json?console.log(JSON.stringify(e)):e.type===`stdout`?globalThis.process.stdout.write(e.data):globalThis.process.stderr.write(e.data))}catch(e){B(e)}}),e.command(`run-code`).description(`Execute Python code directly`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<code>`,`Python code to execute`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a={};if(n.env)for(let e of n.env){let[t,...n]=e.split(`=`);t&&n.length>0&&(a[t]=n.join(`=`))}let o=F(`Executing Python code...`);n.json||o.start();let s=await H(i,r,e);s=await U(s);let c=await s.process.runCode(t,{cwd:n.cwd,env:Object.keys(a).length>0?a:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});o.stop(),n.json?j(c):(c.stdout&&globalThis.process.stdout.write(c.stdout),c.stderr&&globalThis.process.stderr.write(c.stderr),c.exitCode!==0&&globalThis.process.exit(c.exitCode))}catch(e){B(e)}}),e}const ea=[`python`,`node`,`typescript`,`bash`];function ta(e){switch(te(e).toLowerCase()){case`.py`:return`python`;case`.js`:case`.mjs`:case`.cjs`:return`node`;case`.ts`:case`.tsx`:return`typescript`;case`.sh`:case`.bash`:return`bash`;default:return}}async function na(e){if(e===`-`){let e=[];for await(let t of process.stdin)e.push(typeof t==`string`?Buffer.from(t):t);return Buffer.concat(e).toString(`utf8`)}return await ye(re(e),`utf8`)}async function ra(e,t,n=na){let r=t?ea.find(e=>e===t)??(()=>{throw Error(`unknown --lang ${t}: must be one of ${ea.join(`, `)}`)})():void 0;if(!e||e===`-`){if(!r)throw Error(`reading from stdin requires --lang. Example: tangle run <id> -l python -`);return{language:r,source:await n(`-`)}}let i=ta(e);return{language:r??i??(()=>{throw Error(`cannot infer language from "${e}". Pass it explicitly: tangle run <id> -l <python|node|typescript|bash> ${e}`)})(),source:await n(e)}}function ia(e){return ne(pe(),`tangle-run-images`,e)}function aa(){return new t(`run`).description(`Run code in a persistent kernel inside a sandbox. Variables persist across calls in the same --session.`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`[file]`,`Path to source file. Language is inferred from extension. Use - for stdin (requires --lang).`).option(`-l, --lang <lang>`,`Force language: ${ea.join(` | `)}. Required for stdin.`).option(`-s, --session <id>`,`Session id for kernel scoping`).option(`-t, --timeout <ms>`,`Per-call timeout in ms (0 disables)`,`60000`).option(`--save-images <dir>`,`Write image results into this directory (default: $TMPDIR/tangle-run-images/<sandbox>/).`).option(`--no-save-images`,`Don't write image results to disk; print summary only`).option(`--json`,`Output the full CodeExecutionResult as JSON`).action(async(e,t,n)=>{try{let{language:r,source:i}=await ra(t,n.lang),o=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),s=await H(k(o),o,e);s=await U(s);let l=F(`Running ${r} (${i.length}b)…`);n.json||l.start();let u=await s.runCode(r,i,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10)});if(l.stop(),n.json){j(u),u.exitCode!==0&&process.exit(u.exitCode);return}u.stdout&&process.stdout.write(u.stdout),u.stderr&&process.stderr.write(u.stderr);let f=0;for(let t of u.results)if(t.type===`image`)if(n.saveImages!==!1){let r=typeof n.saveImages==`string`?n.saveImages:ia(e);c(r,{recursive:!0});let i=`${r}/${Date.now()}-${f}.${t.format}`;d(i,Buffer.from(t.data,`base64`)),process.stderr.write(a.green(`✓ image → ${i}\n`)),f++}else process.stderr.write(a.gray(`[image: ${t.format}, ${t.data.length}b base64]\n`));else if(t.type===`dataframe`){let e=t.columns.map(e=>`${e.name}:${e.dtype}`).join(` | `);process.stderr.write(a.gray(`[dataframe ${t.rows.length}×${t.columns.length}${t.truncated?` (truncated)`:``}]\n`)),process.stderr.write(`${e}\n`);for(let e of t.rows.slice(0,20))process.stderr.write(`${e.map(e=>String(e)).join(` | `)}\n`);t.rows.length>20&&process.stderr.write(a.gray(`… ${t.rows.length-20} more rows\n`))}else t.type===`json`?(process.stderr.write(a.gray(`[json] `)),process.stderr.write(`${JSON.stringify(t.value,null,2)}\n`)):t.type===`html`?process.stderr.write(a.gray(`[html ${t.value.length}b]\n`)):t.type===`error`?(process.stderr.write(a.red(`✗ ${t.name}: ${t.message}\n`)),t.traceback&&process.stderr.write(`${t.traceback}\n`)):t.type===`text`&&process.stderr.write(`${t.value}\n`);u.error&&(process.stderr.write(a.red(`\n✗ ${u.error.name}: ${u.error.message}\n`)),u.error.traceback&&process.stderr.write(`${u.error.traceback}\n`)),u.exitCode!==0&&process.exit(u.exitCode)}catch(e){B(e)}})}function oa(e){return`${e.name} (${e.id})`}async function sa(e,t){if(t.startsWith(`team_`))return e.teams.get(t);let n=(await e.teams.list()).filter(e=>e.name.toLowerCase()===t.toLowerCase());if(n.length===0)throw Error(`Team not found: ${t}`);if(n.length>1)throw Error(`Team name is ambiguous: ${t}. Use a team id instead.`);return n[0]}async function X(e,t,n){if(t)return sa(e,t);let r=St(n);if(!r.activeTeamId)throw Error("No active team. Run `tangle team switch <team>` or pass `--team <team>`.");return e.teams.get(r.activeTeamId)}function ca(e,t){Ct({id:e.id,name:e.name},t)}function la(e){wt(e)}const ua=[{flag:`--git-token`,guidance:`Use --git-token-env <NAME> or --git-token-stdin so the secret never appears in argv (visible to other processes via /proc/<pid>/cmdline) or in shell history.`},{flag:`--storage-secret-access-key`,guidance:`Use --storage-secret-access-key-env <NAME> or --storage-secret-access-key-stdin so the secret never appears in argv (visible to other processes via /proc/<pid>/cmdline) or in shell history.`},{flag:`--backend-api-key`,guidance:`Use --backend-api-key-env <NAME> or --backend-api-key-stdin so the BYOK secret never appears in argv (visible to other processes via /proc/<pid>/cmdline) or in shell history.`}];function da(e){for(let{flag:t,guidance:n}of ua){let r=`${t}=`;if(e.some(e=>e===t||e.startsWith(r)))throw Error(`Refusing to read secret from ${t} on the command line. ${n}`)}}async function fa(e){let t=typeof e.envVarName==`string`&&e.envVarName.length>0?e.envVarName:null,n=!!e.fromStdin;if(t&&n)throw Error(`Pass either ${e.flagPrefix}-env or ${e.flagPrefix}-stdin, not both`);if(t){let n=process.env[t];if(!n||n.length===0)throw Error(`${e.flagPrefix}-env points at ${t}, but that environment variable is empty or unset`);return n}if(n){let t=await _n();if(t.length===0)throw Error(`${e.flagPrefix}-stdin received empty input on stdin`);return t}}function pa(e){let t=e.split(`/`);return t.length>=2?{provider:t[0],model:t.slice(1).join(`/`)}:{model:e}}function ma(){let e=new t(`sandbox`).description(`Manage sandboxes`);return e.command(`create`).description(`Create a new sandbox`).option(`-n, --name <name>`,`Sandbox name`).option(`-e, --environment <environment>`,`Environment name (e.g. universal, node, python)`).option(`-i, --image <image>`,`Alias for --environment (deprecated)`).option(`--bare`,`Create a bare sandbox without the agent runtime`).option(`--ssh`,`Enable SSH access`).option(`--ssh-key <key>`,`SSH public key for authentication`).option(`--ssh-keys <names...>`,`Stored SSH key names or IDs for authentication`).option(`--ssh-key-file <paths...>`,`SSH public key file paths for authentication`).option(`--web-terminal`,`Enable web terminal`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`--secret <names...>`,`Secrets to inject as environment variables`).option(`--metadata <entries...>`,`Metadata entries (KEY=VALUE or KEY=JSON)`).option(`--cpu <cores>`,`CPU cores`,`2`).option(`--memory <mb>`,`Memory in MB`,`4096`).option(`--disk <gb>`,`Disk size in GB`,`20`).option(`--accelerator-kind <kind>`,`Accelerator kind, for example nvidia-h100 or amd-mi300x`).option(`--accelerator-count <count>`,`Accelerator device count`,`1`).option(`--accelerator-memory <mb>`,`Minimum accelerator memory in MB`).option(`--lifetime <seconds>`,`Max wall-clock lifetime before the sandbox is deleted (default 3600 = 1h). Raise it for long sessions, e.g. --lifetime 7200`,`3600`).option(`--idle-timeout <seconds>`,"Idle time before the sandbox is stopped — not deleted (default 900 = 15m). Resume it later with `tangle sandbox resume <id-or-name>`, or it auto-resumes on next use. Raise it for demos, e.g. --idle-timeout 3600",`900`).option(`--from-snapshot <id>`,`Create the sandbox from a snapshot`).option(`--public-template <id-or-slug>`,`Create the sandbox from a published public template`).option(`--public-template-version <id>`,`Pin creation to a specific published public-template version`).option(`--team <team>`,`Create in a team by id or name`).option(`--personal`,`Create a personal sandbox even when a team is active`).option(`--port <ports...>`,`Ports to expose at creation time`).option(`--git-url <url>`,`Git repository URL to clone during provisioning`).option(`--git-ref <ref>`,`Git branch, tag, or commit to checkout`).option(`--git-depth <depth>`,`Git clone depth`).option(`--git-sparse <paths...>`,`Sparse checkout paths`).option(`--git-token-env <name>`,`Name of an environment variable containing the Git HTTPS auth token`).option(`--git-token-stdin`,`Read the Git HTTPS auth token from stdin`).option(`--git-token <token>`,`[removed] use --git-token-env or --git-token-stdin`).option(`--tool <specs...>`,`Tool versions to preinstall (NAME=VERSION)`).option(`--storage-type <type>`,`BYOS3 storage type (s3, gcs, r2)`).option(`--storage-bucket <name>`,`BYOS3 bucket name`).option(`--storage-endpoint <url>`,`BYOS3 endpoint URL`).option(`--storage-region <region>`,`BYOS3 region`).option(`--storage-prefix <prefix>`,`BYOS3 path prefix`).option(`--storage-access-key-id <id>`,`BYOS3 access key ID`).option(`--storage-secret-access-key-env <name>`,`Name of an environment variable containing the BYOS3 secret access key`).option(`--storage-secret-access-key-stdin`,`Read the BYOS3 secret access key from stdin`).option(`--storage-secret-access-key <key>`,`[removed] use --storage-secret-access-key-env or --storage-secret-access-key-stdin`).option(`--default-role <role>`,`Default permission role (owner, admin, developer, viewer)`).option(`--initial-user <specs...>`,`Initial users (USER_ID or USER_ID:ROLE)`).option(`--multi-user`,`Enable multi-user permissions at creation`).option(`--driver <type>`,`Infrastructure driver (docker, firecracker, host-agent, tangle)`).option(`--driver-criu`,`Enable CRIU checkpointing (firecracker only)`).option(`--driver-region <region>`,`Preferred region for host-agent driver`).option(`--backend <type>`,`Backend agent type (opencode, claude-code, codex, cursor, amp)`).option(`--backend-profile <name>`,`Backend profile name`).option(`--backend-model <model>`,`Model override (format: provider/model)`).option(`--backend-api-key-env <name>`,`Name of an environment variable containing the BYOK backend API key`).option(`--backend-api-key-stdin`,`Read the BYOK backend API key from stdin`).option(`--backend-api-key <key>`,`[removed] use --backend-api-key-env or --backend-api-key-stdin`).option(`--tee <type>`,`Require a TEE backend (any, tdx, nitro, sev-snp, phala-dstack)`).option(`--sealed`,`Request TEE sealed-secret support`).option(`--attestation-nonce <hex|auto>`,`Deploy-time attestation nonce; use auto to generate one`).option(`--attestation-refresh`,`Generate a fresh deploy-time attestation nonce when --tee is set`).option(`--require-attestation`,`Fail unless TEE attestation evidence is returned`).option(`--block-network`,`Block all outbound network traffic`).option(`--allow-list <cidrs>`,`CIDR allowlist for outbound traffic (comma-separated)`).option(`--wait`,`Wait for sandbox to be running`,!0).option(`--timeout <ms>`,`HTTP timeout in milliseconds`,`30000`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{da(process.argv);let t=await fa({envVarName:e.gitTokenEnv,fromStdin:e.gitTokenStdin,flagPrefix:`--git-token`}),n=await fa({envVarName:e.storageSecretAccessKeyEnv,fromStdin:e.storageSecretAccessKeyStdin,flagPrefix:`--storage-secret-access-key`}),r=await fa({envVarName:e.backendApiKeyEnv,fromStdin:e.backendApiKeyStdin,flagPrefix:`--backend-api-key`}),i=E({apiKey:e.apiKey,baseUrl:e.baseUrl,timeout:e.timeout?Number.parseInt(e.timeout,10):void 0}),a=k(i),o=F(`Creating sandbox...`);o.start();let s=await Ca({client:a,explicitTeam:e.team,personal:e.personal,activeTeamId:i.activeTeamId}),c={};if(e.env)for(let t of e.env){let[e,...n]=t.split(`=`);e&&n.length>0&&(c[e]=n.join(`=`))}let u=e.tool?ga(e.tool,`--tool`,`tool spec`):void 0,d=e.metadata?_a(e.metadata):void 0,f=ba(e,t),p=xa(e,n),ee=Sa(e),te=e.port?ya(e.port,`--port`):void 0,ne=e.driver?{type:e.driver,enableCriu:e.driverCriu||void 0,preferredRegion:e.driverRegion}:void 0,re=e.backend||e.backendProfile||e.backendModel?{type:e.backend??`opencode`,profile:e.backendProfile,model:e.backendModel||r?{...e.backendModel?pa(e.backendModel):{},apiKey:r}:void 0}:void 0,ie=e.blockNetwork||e.allowList||te?{blockOutbound:e.blockNetwork||void 0,allowList:e.allowList?e.allowList.split(`,`).map(e=>e.trim()):void 0,ports:te}:void 0,m=[...e.sshKey?[e.sshKey]:[],...(e.sshKeyFile??[]).map(e=>l(e,`utf8`).trim())],ae={name:e.name,environment:e.environment??e.image,bare:e.bare||void 0,sshEnabled:e.ssh||!!e.sshKey||m.length>0||!!e.sshKeys?.length,sshPublicKeys:m.length>0?m:void 0,sshKeyIds:e.sshKeys,webTerminalEnabled:e.webTerminal,env:Object.keys(c).length>0?c:void 0,git:f,tools:u,resources:{cpuCores:Number.parseInt(e.cpu,10),memoryMB:Number.parseInt(e.memory,10),diskGB:Number.parseInt(e.disk,10),accelerator:e.acceleratorKind?{kind:Oa(String(e.acceleratorKind)),count:ka(String(e.acceleratorCount),`--accelerator-count`),memoryMB:e.acceleratorMemory?ka(String(e.acceleratorMemory),`--accelerator-memory`):void 0}:void 0},maxLifetimeSeconds:Number.parseInt(e.lifetime,10),idleTimeoutSeconds:Number.parseInt(e.idleTimeout,10),storage:p,fromSnapshot:e.fromSnapshot,publicTemplateId:e.publicTemplate,publicTemplateVersionId:e.publicTemplateVersion,teamId:s,secrets:e.secret,metadata:d,driver:ne,backend:re,permissions:ee,network:ie},h=e.tee?{tee:e.tee,sealed:e.sealed||void 0,attestationRefresh:e.attestationRefresh||e.attestationNonce===`auto`||void 0}:void 0,g=h?await le(a,{...ae,confidential:h,attestationNonce:e.attestationNonce??(e.attestationRefresh?`auto`:void 0),requireAttestation:e.requireAttestation??!0}):void 0,_=g?.sandbox??await a.create(ae);e.wait&&(o.text=`Waiting for sandbox to start...`,await _.waitFor(`running`,{timeoutMs:12e4}),await _.refresh()),o.stop(),e.json?j({id:_.id,name:_.name,status:_.status,createdAt:_.createdAt,expiresAt:_.expiresAt,connection:ha(_.connection),teamId:s,confidential:h,attestation:g?.attestation,attestationNonce:g?.attestationNonce}):(M(`Sandbox created: ${_.id}`),Wt({id:_.id,name:_.name,status:_.status,createdAt:_.createdAt?.toISOString(),expiresAt:_.expiresAt?.toISOString(),connection:_.connection}),s&&console.log(`Team: ${s}`),h&&(console.log(`TEE: ${h.tee}`),console.log(`Attestation: ${g?.attestation?`present`:`not returned`}`),g?.attestationNonce&&console.log(`Attestation nonce: ${g.attestationNonce}`)))}catch(e){B(e)}}),e.command(`attestation <id-or-name>`).description(`Fetch TEE attestation evidence for a sandbox`).option(`--nonce <hex|auto>`,`Nonce to bind into a fresh attestation report; use auto to generate one`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=t.nonce===`auto`?ue():t.nonce,a=F(`Fetching TEE attestation...`);a.start();let o=await(await H(r,n,e)).getTeeAttestation(i?{attestationNonce:i}:void 0);a.stop(),t.json?j(o):(M(`Attestation fetched for ${e}`),console.log(`TEE type: ${o.attestation.tee_type}`),console.log(`Evidence bytes: ${o.attestation.evidence.length}`),console.log(`Measurement bytes: ${o.attestation.measurement.length}`),console.log(`Timestamp: ${o.attestation.timestamp}`),o.attestationNonce&&console.log(`Nonce: ${o.attestationNonce}`))}catch(e){B(e)}}),e.command(`list`).description(`List all sandboxes`).option(`-s, --status <status>`,`Filter by status (running, stopped, all)`).option(`-l, --limit <n>`,`Limit results`,`50`).option(`--team <team>`,`List sandboxes for a team by id or name`).option(`--personal`,`List personal sandboxes`).option(`--all-scopes`,`List personal and team sandboxes`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=E({apiKey:e.apiKey,baseUrl:e.baseUrl}),n=k(t),r=F(`Fetching sandboxes...`);r.start();let i=await wa({client:n,explicitTeam:e.team,personal:e.personal,allScopes:e.allScopes,activeTeamId:t.activeTeamId}),a=await n.list({status:e.status===`all`?void 0:e.status,limit:Number.parseInt(e.limit,10),scope:i});r.stop(),e.json?j(a):A(a.map(e=>({id:e.id,status:e.status,createdAt:e.createdAt,name:e.name??``})),[{key:`id`,header:`ID`,width:24},{key:`status`,header:`Status`,width:14},{key:`createdAt`,header:`Created`,width:16},{key:`name`,header:`Name`,width:20}])}catch(e){B(e)}}),e.command(`get <id-or-name>`).description(`Get sandbox details`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching sandbox...`);i.start();let a=await H(r,n,e);i.stop(),t.json?j(a):Wt({id:a.id,name:a.name,status:a.status,createdAt:a.createdAt?.toISOString(),expiresAt:a.expiresAt?.toISOString(),connection:a.connection})}catch(e){B(e)}}),e.command(`delete <id-or-name>`).description(`Delete a sandbox`).option(`-f, --force`,`Skip confirmation`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{if(!t.force){let t=(await import(`node:readline`)).createInterface({input:process.stdin,output:process.stdout});if(!await new Promise(n=>{t.question(`Delete sandbox ${e}? [y/N] `,e=>{t.close(),n(e.toLowerCase()===`y`)})})){P(`Cancelled.`);return}}let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Deleting sandbox...`);i.start(),await(await H(r,n,e)).delete(),i.stop(),M(`Sandbox ${e} deleted.`)}catch(e){B(e)}}),e.command(`stop <id-or-name>`).description(`Stop a running sandbox`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Stopping sandbox...`);i.start(),await(await H(r,n,e)).stop(),i.stop(),M(`Sandbox ${e} stopped.`)}catch(e){B(e)}}),e.command(`resume <id-or-name>`).description(`Resume a stopped sandbox`).option(`--wait`,`Wait for sandbox to be running`,!0).option(`-t, --timeout <ms>`,`Resume timeout in milliseconds; a cold resume re-provisions the sandbox, so this defaults higher than other commands (default 120000)`,`120000`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=Number.parseInt(t.timeout,10);if(!Number.isFinite(n)||n<=0)throw Error(`--timeout must be a positive number of milliseconds`);let r=E({apiKey:t.apiKey,baseUrl:t.baseUrl,timeout:n}),i=k(r),a=F(`Resuming sandbox...`);a.start();let o=await H(i,r,e);await o.resume({timeoutMs:n}),t.wait&&(a.text=`Waiting for sandbox to start...`,await o.waitFor(`running`,{timeoutMs:n})),a.stop(),M(`Sandbox ${o.id} resumed.`)}catch(e){B(e)}}),e.command(`network <id-or-name>`).description(`Update network configuration for a sandbox`).option(`--block-outbound`,`Block all outbound network traffic`).option(`--allow-list <cidrs>`,`CIDR allowlist for outbound traffic (comma-separated)`).option(`--clear`,`Clear all network restrictions (allow all traffic)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Updating network configuration...`);i.start();let a=await H(r,n,e);if(t.clear)await a.network.update({blockOutbound:!1,allowList:[]});else if(t.blockOutbound)await a.network.update({blockOutbound:!0});else if(t.allowList){let e=t.allowList.split(`,`).map(e=>e.trim());await a.network.update({allowList:e})}else{i.stop();let e=await a.network.getConfig();t.json?j(e):(P(`Network Configuration:`),e.blockOutbound?P(` Block Outbound: true (all outbound traffic blocked)`):e.allowList&&e.allowList.length>0?P(` Allow List: ${e.allowList.join(`, `)}`):P(` No restrictions (all traffic allowed)`),e.ports&&e.ports.length>0&&P(` Exposed Ports: ${e.ports.join(`, `)}`));return}i.stop();let o=await a.network.getConfig();t.json?j(o):(M(`Network configuration updated.`),o.blockOutbound?P(` Block Outbound: true`):o.allowList&&o.allowList.length>0?P(` Allow List: ${o.allowList.join(`, `)}`):P(` All traffic allowed`))}catch(e){B(e)}}),e.command(`expose <id-or-name>`).description(`Expose a port and get a public URL`).option(`-p, --port <port>`,`Port to expose`,`8000`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=Number.parseInt(t.port,10);if(Number.isNaN(i)||i<1||i>65535)throw Error(`Port must be a number between 1 and 65535`);let a=F(`Exposing port ${i}...`);a.start();let o=await(await H(r,n,e)).network.exposePort(i);a.stop(),t.json?j({port:i,url:o}):(M(`Port ${i} exposed.`),P(` URL: ${o}`))}catch(e){B(e)}}),e.command(`urls <id-or-name>`).description(`List exposed port URLs for a sandbox`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching exposed URLs...`);i.start();let a=await(await H(r,n,e)).network.listUrls();if(i.stop(),t.json)j(a);else{let e=Object.entries(a);if(e.length===0)P(`No ports exposed.`);else{P(`Exposed Ports:`);for(let[t,n]of e)P(` ${t}: ${n}`)}}}catch(e){B(e)}}),e}function ha(e){return!e||e.authToken===void 0?e:{...e,authToken:`[REDACTED]`}}function ga(e,t,n){let r={};for(let i of e){let[e,...a]=i.split(`=`);if(!e||a.length===0)throw Error(`${t} expects ${n} values in KEY=VALUE format`);r[e]=a.join(`=`)}return r}function _a(e){let t={};for(let n of e){let[e,...r]=n.split(`=`);if(!e||r.length===0)throw Error(`--metadata expects values in KEY=VALUE or KEY=JSON format`);t[e]=va(r.join(`=`))}return t}function va(e){try{return JSON.parse(e)}catch{return e}}function ya(e,t){return e.map(e=>{let n=Number.parseInt(e,10);if(Number.isNaN(n)||n<1||n>65535)throw Error(`${t} values must be integers between 1 and 65535`);return n})}function ba(e,t){if(!(!e.gitUrl&&!e.gitRef&&!e.gitDepth&&!e.gitSparse&&!t)){if(!e.gitUrl||typeof e.gitUrl!=`string`)throw Error(`--git-url is required when using git provisioning options`);return{url:e.gitUrl,ref:typeof e.gitRef==`string`?e.gitRef:void 0,depth:typeof e.gitDepth==`string`?ka(e.gitDepth,`--git-depth`):void 0,sparse:Array.isArray(e.gitSparse)?e.gitSparse:void 0,auth:t?{token:t}:void 0}}}function xa(e,t){if(!(!e.storageType&&!e.storageBucket&&!e.storageEndpoint&&!e.storageRegion&&!e.storagePrefix&&!e.storageAccessKeyId&&!t)){if(typeof e.storageType!=`string`||typeof e.storageBucket!=`string`||typeof e.storageAccessKeyId!=`string`||!t)throw Error(`Storage config requires --storage-type, --storage-bucket, --storage-access-key-id, and one of --storage-secret-access-key-env / --storage-secret-access-key-stdin`);return{type:Da(e.storageType),bucket:e.storageBucket,endpoint:typeof e.storageEndpoint==`string`?e.storageEndpoint:void 0,region:typeof e.storageRegion==`string`?e.storageRegion:void 0,prefix:typeof e.storagePrefix==`string`?e.storagePrefix:void 0,credentials:{accessKeyId:e.storageAccessKeyId,secretAccessKey:t}}}}function Sa(e){let t=Array.isArray(e.initialUser)?e.initialUser.map(Ta):void 0,n=typeof e.defaultRole==`string`?Ea(e.defaultRole):void 0,r=e.multiUser?!0:void 0;if(!(!n&&!t&&!r))return{defaultRole:n,initialUsers:t,multiUser:r}}async function Ca(e){if(e.explicitTeam&&e.personal)throw Error(`--team and --personal cannot be used together`);if(!e.personal)return e.explicitTeam?(await sa(e.client,e.explicitTeam)).id:e.activeTeamId}async function wa(e){if([!!e.explicitTeam,!!e.personal,!!e.allScopes].filter(Boolean).length>1)throw Error(`--team, --personal, and --all-scopes are mutually exclusive`);if(e.allScopes)return`all`;if(e.personal)return`personal`;if(e.explicitTeam)return`team:${(await sa(e.client,e.explicitTeam)).id}`;if(e.activeTeamId)return`team:${e.activeTeamId}`}function Ta(e){let[t,n]=e.split(`:`);if(!t)throw Error(`--initial-user expects USER_ID or USER_ID:ROLE`);return{userId:t,role:n?Ea(n):void 0}}function Ea(e){if(e===`owner`||e===`admin`||e===`developer`||e===`viewer`)return e;throw Error(`--default-role and --initial-user roles must be one of owner, admin, developer, viewer`)}function Da(e){if(e===`s3`||e===`gcs`||e===`r2`)return e;throw Error(`--storage-type must be one of s3, gcs, or r2`)}function Oa(e){let t=e.trim().toLowerCase();if(/^[a-z0-9][a-z0-9._-]*$/.test(t))return t;throw Error(`--accelerator-kind must contain only letters, numbers, dots, underscores, or hyphens`)}function ka(e,t){let n=Number.parseInt(e,10);if(Number.isNaN(n)||n<1)throw Error(`${t} must be a positive integer`);return n}function Aa(){return new t(`search`).description(`Search for text patterns in sandbox files (ripgrep)`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pattern>`,`Search pattern (regex)`).option(`-g, --glob <pattern>`,`File glob filter (e.g. '**/*.ts')`).option(`-n, --max-results <count>`,`Max results to return`).option(`-i, --ignore-case`,`Case-insensitive search`).option(`--json`,`Output as JSON lines`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Searching...`);n.json||a.start();let o=await H(i,r,e),s=0,c=n.maxResults?Number.parseInt(n.maxResults,10):void 0,l={};n.glob&&(l.glob=n.glob),n.ignoreCase&&(l.ignoreCase=!0),c&&(l.maxResults=c);for await(let e of o.search(t,l))if(s===0&&a.stop(),s++,n.json?console.log(JSON.stringify(e)):console.log(`${e.path}:${e.line}:${e.column??0}: ${e.text}`),c&&s>=c)break;a.stop(),s===0&&!n.json&&console.log(`No matches found`)}catch(e){B(e)}})}function ja(){let e=new t(`secret`).description(`Manage secrets`);return e.command(`create`).description(`Create a new secret`).argument(`<name>`,`Secret name (e.g., HF_TOKEN, AWS_ACCESS_KEY)`).argument(`[value]`,`Secret value`).option(`--value-stdin`,`Read secret value from stdin`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=k(E({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=await Ma({value:t,valueStdin:n.valueStdin,prompt:`Enter value for secret '${e}': `}),a=F(`Creating secret...`);a.start();let o=await r.secrets.create(e,i);a.stop(),n.json?j({name:o.name,createdAt:o.createdAt.toISOString(),updatedAt:o.updatedAt.toISOString()}):(M(`Secret created: ${o.name}`),P(`Use --secrets ${o.name} when creating a sandbox to inject it as an environment variable.`))}catch(e){B(e)}}),e.command(`list`).description(`List all secrets`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=k(E({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=F(`Fetching secrets...`);n.start();let r=await t.secrets.list();n.stop(),e.json?j(r.map(e=>({name:e.name,createdAt:e.createdAt.toISOString(),updatedAt:e.updatedAt.toISOString()}))):r.length===0?(P(`No secrets found.`),P(`Use 'tangle secret create <name> [value]' to create one.`)):z([`Name`,`Created At`,`Updated At`],r.map(e=>[e.name,e.createdAt.toLocaleString(),e.updatedAt.toLocaleString()]))}catch(e){B(e)}}),e.command(`show`).description(`Show a secret value (requires --reveal to print plaintext)`).argument(`<name>`,`Secret name`).option(`--reveal`,`Print the plaintext secret value to stdout. Without this flag the command exits with a redaction notice.`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{if(!t.reveal){process.stderr.write(`Refusing to print secret '${e}' as plaintext. Re-run with --reveal to confirm and write the value to stdout.
138
+ `),process.exitCode=1;return}let n=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=F(`Fetching secret...`);r.start();let i=await n.secrets.get(e);r.stop(),process.stderr.write(`WARNING: secret '${e}' is being printed in plaintext. Avoid storing this output in shell history, screenshots, or logs.
139
+ `),t.json?j({name:e,value:i}):console.log(i)}catch(e){B(e)}}),e.command(`update`).description(`Update a secret value`).argument(`<name>`,`Secret name`).argument(`[value]`,`New secret value`).option(`--value-stdin`,`Read secret value from stdin`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=k(E({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=await Ma({value:t,valueStdin:n.valueStdin,prompt:`Enter new value for secret '${e}': `}),a=F(`Updating secret...`);a.start();let o=await r.secrets.update(e,i);a.stop(),n.json?j({name:o.name,createdAt:o.createdAt.toISOString(),updatedAt:o.updatedAt.toISOString()}):M(`Secret updated: ${o.name}`)}catch(e){B(e)}}),e.command(`delete`).description(`Delete a secret`).argument(`<name>`,`Secret name`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=k(E({apiKey:t.apiKey,baseUrl:t.baseUrl}));if(!t.force&&!await W(`Are you sure you want to delete secret '${e}'? This cannot be undone. (y/N) `)){P(`Cancelled.`);return}let r=F(`Deleting secret...`);r.start(),await n.secrets.delete(e),r.stop(),t.json?j({success:!0,deleted:e}):M(`Secret deleted: ${e}`)}catch(e){B(e)}}),e}async function Ma(e){if(e.value!==void 0&&e.valueStdin)throw Error(`Provide either a secret value argument or --value-stdin, not both`);if(e.value!==void 0){if(e.value.length===0)throw Error(`Secret value cannot be empty`);return e.value}if(e.valueStdin){let e=await _n();if(e.length===0)throw Error(`Secret value from stdin cannot be empty`);return e}let t=await gn(e.prompt);if(t.length===0)throw Error(`Secret value cannot be empty`);return t}function Na(){let e=new t(`skill`).description(`Print paths to shipped skill documentation`);return e.command(`path`).description(`Print the absolute path to the SKILL.md shipped with this CLI`).action(()=>{let e=f.dirname(be(import.meta.url)),t=f.resolve(e,`..`,`SKILL.md`);console.log(t)}),e}function Pa(){let e=new t(`snapshot`).description(`Manage snapshots`);return e.command(`create <sandbox-id-or-name>`).description(`Create a snapshot of a sandbox`).option(`--tags <tags...>`,`Tags for the snapshot`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Creating snapshot...`);i.start();let a=await(await H(r,n,e)).snapshot({tags:t.tags});i.stop(),t.json?j(a):(M(`Snapshot created: ${a.snapshotId}`),console.log(`Size: ${Fa(a.sizeBytes??0)}`))}catch(e){B(e)}}),e.command(`list <sandbox-id-or-name>`).description(`List snapshots for a sandbox`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching snapshots...`);i.start();let a=await(await H(r,n,e)).listSnapshots();i.stop(),t.json?j(a):A(a.map(e=>({...e,size:Fa(e.sizeBytes??0)})),[{key:`snapshotId`,header:`ID`,width:24},{key:`createdAt`,header:`Created`,width:16},{key:`size`,header:`Size`,width:12},{key:`sandboxId`,header:`Sandbox`,width:20}])}catch(e){B(e)}}),e.command(`restore <sandbox-id> <snapshot-id>`).description(`Create a new sandbox from a snapshot`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=k(E({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=F(`Restoring from snapshot...`);i.start();let a=await r.create({fromSnapshot:t,fromSandboxId:e});await a.waitFor(`running`,{timeoutMs:12e4}),i.stop(),n.json?j({sandboxId:a.id,restoredFrom:t,status:a.status}):(M(`New sandbox created: ${a.id}`),console.log(`Source snapshot: ${t}`))}catch(e){B(e)}}),e.command(`revert <sandbox-id-or-name> <snapshot-id>`).description(`Revert an existing sandbox to a snapshot`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Reverting sandbox to snapshot...`);a.start();let o=await H(i,r,e),s=await o.revertToSnapshot(t);await o.refresh(),a.stop(),n.json?j({sandboxId:o.id,snapshotId:s.snapshotId,status:o.status}):(M(`Sandbox reverted: ${o.id}`),console.log(`Source snapshot: ${s.snapshotId}`))}catch(e){B(e)}}),e.command(`delete <sandbox-id-or-name> <snapshot-id>`).description(`Delete a sandbox snapshot`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Deleting snapshot...`);a.start(),await(await H(i,r,e)).deleteSnapshot(t),a.stop(),n.json?j({success:!0,sandboxId:e,snapshotId:t}):M(`Snapshot deleted: ${t}`)}catch(e){B(e)}}),e}function Fa(e){if(e===0)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`,`TB`],r=Math.floor(Math.log(e)/Math.log(t));return`${Number.parseFloat((e/t**r).toFixed(1))} ${n[r]}`}function Ia(e,t){return`tangle ssh-proxy ${e.replace(/\/+$/,``)}/v1/sidecar-proxy/${t}/ssh`}function La(e){return/^[A-Za-z0-9_/:=@%+.,-]+$/.test(e)?e:`'${e.replace(/'/g,`'"'"'`)}'`}function Ra(e){return`'${e.replace(/'/g,`''`)}'`}function za(e){return e===`win32`?`NUL`:`/dev/null`}function Ba(e,t){return t===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN=${Ra(`<token>`)}; ssh ${e.map(Ra).join(` `)}`:`TANGLE_SSH_PROXY_AUTH_TOKEN=${La(`<token>`)} ssh ${e.map(La).join(` `)}`}function Va(e){return e.connection!==void 0&&!e.connection.ssh}function Ha(){N(`SSH is not enabled for this sandbox.`),P(`Create a sandbox with --ssh to enable SSH access.`),process.exit(1)}function Ua(e,t=[],n=process.platform){let r=za(n);return[`-o`,`ProxyCommand=${e.proxyCommand}`,`-o`,`StrictHostKeyChecking=no`,`-o`,`UserKnownHostsFile=${r}`,`-o`,`GlobalKnownHostsFile=${r}`,`-o`,`LogLevel=ERROR`,`-o`,`ServerAliveInterval=15`,`-o`,`ServerAliveCountMax=4`,`-o`,`TCPKeepAlive=yes`,`${e.username}@localhost`,`-p`,String(e.port),...t]}function Wa(){return new t(`ssh`).description(`Open SSH session to a sandbox`).argument(`<ref>`,`Sandbox ID or name`).argument(`[sshArgs...]`,`Extra args passed through to ssh`).option(`-i, --identity-file <path>`,`Private key file to pass to ssh`).option(`--print`,`Print SSH command instead of connecting`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).allowUnknownOption(!0).action(async(e,t,n)=>{try{let r=E({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Getting SSH credentials...`);a.start();let o=await H(i,r,e);if(Va(o)){a.stop(),Ha();return}o=await U(o);let s=await o.ssh();if(a.stop(),!s){Ha();return}let c={...s,proxyCommand:Ia(r.baseUrl,o.id)};if(!r.apiKey)throw Error(`SSH proxy requires API key auth. Set TANGLE_API_KEY or pass --api-key.`);let l=Ua(c,[...n.identityFile?[`-i`,n.identityFile,`-o`,`IdentitiesOnly=yes`]:[],...t]);if(n.print){console.log(Ba(l,process.platform));return}P(`Connecting via tunnel...`);let u=me(`ssh`,l,{stdio:`inherit`,env:{...process.env,TANGLE_SSH_PROXY_AUTH_TOKEN:r.apiKey}});u.on(`error`,e=>{e.code===`ENOENT`&&(N(`SSH client not found. Please install OpenSSH.`),process.exit(1)),B(e)}),u.on(`exit`,e=>{process.exit(e??0)})}catch(e){B(e)}})}function Ga(){let e=new t(`ssh-keys`).description(`Manage SSH keys`);return e.command(`list`).description(`List SSH keys`).option(`--json`,`Output as JSON`).action(async e=>{let t=F(`Fetching SSH keys...`);try{t.start();let n=await k(E(e)).sshKeys.list();t.stop(),e.json?j({sshKeys:n}):n.length===0?P(`No SSH keys found.`):z([`Name`,`Type`,`Fingerprint`,`Created`],n.map(e=>[e.name,e.keyType,e.fingerprint,e.createdAt.toLocaleString()]))}catch(e){t.stop(),B(e)}}),e.command(`add`).description(`Add SSH key`).argument(`<name>`,`SSH key name`).requiredOption(`--key-file <path>`,`Public key file path`).option(`--json`,`Output as JSON`).action(async(e,t)=>{let n=F(`Adding SSH key...`);try{let r=l(t.keyFile,`utf8`).trim();n.start();let i=await k(E(t)).sshKeys.create(e,r);n.stop(),t.json?j({sshKey:i}):M(`Added SSH key ${i.name} (${i.fingerprint})`)}catch(e){n.stop(),B(e)}}),e.command(`delete`).description(`Delete SSH key`).argument(`<name>`,`SSH key name or ID`).action(async(e,t)=>{let n=F(`Deleting SSH key...`);try{n.start(),await k(E(t)).sshKeys.delete(e),n.stop(),M(`Deleted SSH key ${e}`)}catch(e){n.stop(),B(e)}}),e}function Ka(e,t=1){process.stderr.write(`${e}\n`),process.exit(t)}function qa(){return new t(`ssh-proxy`).description(`SSH proxy helper — pipes stdin/stdout to WebSocket`).argument(`<sidecar-url>`,`Sidecar WebSocket URL`).action(async e=>{let t=process.env.TANGLE_SSH_PROXY_AUTH_TOKEN;t||Ka(`TANGLE_SSH_PROXY_AUTH_TOKEN not set`);let n=new xe(new URL(e.replace(/^http/,`ws`)),{headers:{Authorization:`Bearer ${t}`},perMessageDeflate:!1}),r;function i(){r&&=(clearInterval(r),void 0)}n.on(`open`,()=>{r=setInterval(()=>{n.readyState===xe.OPEN&&n.ping()},15e3),r.unref?.(),process.stdin.on(`data`,e=>{n.readyState===xe.OPEN&&n.send(e,{binary:!0,compress:!1})}),process.stdin.on(`end`,()=>n.close(1e3))}),n.on(`message`,e=>{let t=Buffer.isBuffer(e)?e:Array.isArray(e)?Buffer.concat(e):Buffer.from(e);process.stdout.write(t)}),n.on(`error`,e=>{i(),Ka(`WebSocket error: ${e.message}`)}),n.on(`close`,e=>{i(),process.exit(e===1e3?0:1)}),process.stdin.on(`error`,()=>n.close())})}const Ja=[`claude-code`,`opencode`,`codex`,`kimi-code`],Ya=[`session`,`project`,`read-only`],Xa={min:1,max:15},Za=process.env.TANGLE_ROUTER_URL??`https://router.tangle.tools/v1`;function Qa(e){let t=e.harness??`claude-code`;if(!Ja.includes(t))throw Error(`Unknown --harness '${t}'. Supported: ${Ja.join(`, `)}.`);let n=e.tokenScope??`session`;if(!Ya.includes(n))throw Error(`Unknown --token-scope '${n}'. Supported: ${Ya.join(`, `)}.`);let r=$a(e.maxTokens,2e5,`--max-tokens`),i=$a(e.maxIterations,50,`--max-iterations`),a=$a(e.tokenTtl,10,`--token-ttl`);if(a<Xa.min||a>Xa.max)throw Error(`--token-ttl ${a} out of range; the SDK clamps to [${Xa.min}, ${Xa.max}] minutes.`);let o=e.maxWorkers===void 0?void 0:$a(e.maxWorkers,0,`--max-workers`);return{harness:t,...e.model?{model:e.model}:{},maxTokens:r,maxIterations:i,tokenScope:n,tokenTtl:a,...o===void 0?{}:{maxWorkers:o}}}function $a(e,t,n){if(e===void 0)return t;let r=Number.parseInt(e,10);if(!Number.isFinite(r)||r<=0)throw Error(`${n} must be a positive integer, got '${e}'.`);return r}function eo(e){let t={maxTokens:e.maxTokens,maxIterations:e.maxIterations};return e.maxWorkers===void 0?{budget:t}:{budget:t,perWorker:{maxTokens:Math.max(1,Math.floor(e.maxTokens/e.maxWorkers)),maxIterations:Math.max(1,Math.floor(e.maxIterations/e.maxWorkers))}}}function to(e){let{client:t,scope:n,ttlMinutes:r,onScope:a}=e,o={async create(o){let s=await t.create(no(o)),c={scope:n,ttlMinutes:r,...n===`session`?{sessionId:e.sessionIdFor?.(s)??`supervise-${i()}`}:{}},l=await s.mintScopedToken(c);return a({id:s.id,scope:l.scope,expiresAt:l.expiresAt,status:`spawned`}),s}};return typeof t.criuStatus==`function`&&(o.criuStatus=t.criuStatus.bind(t)),o}function no(e){if(!e?.env)return e;let{TANGLE_API_KEY:t,SANDBOX_API_KEY:n,...r}=e.env;return{...e,env:r}}function ro(e){if(e.kind===`no-winner`)return{text:``,tokenUsage:{input:0,output:0},costUsd:0,status:`no-winner (${e.reason})`};let t=e.out;return{text:typeof t==`string`?t:io(t)?t.content:JSON.stringify(t),tokenUsage:{input:e.spentTotal.tokens.input,output:e.spentTotal.tokens.output},costUsd:e.spentTotal.usd,status:`winner`}}function io(e){return typeof e==`object`&&!!e&&typeof e.content==`string`}const ao={makeClient:e=>k(E({apiKey:e.apiKey,baseUrl:e.baseUrl})),resolveRouter:e=>({routerBaseUrl:Za,routerKey:E({apiKey:e.apiKey}).apiKey,model:e.model}),supervise:Se};async function oo(e,t,n,r=ao){let a=r.makeClient({apiKey:n.apiKey,baseUrl:n.baseUrl}),{budget:o,perWorker:s}=eo(t),c=[],l=to({client:a,scope:t.tokenScope,ttlMinutes:t.tokenTtl,onScope:e=>{if(c.push(e),!n.json){let n=`ttl ${t.tokenTtl}m`;P(`worker ${e.id} [${e.scope} token ${n}] spawned`)}}}),u=Ce({backend:`sandbox`,harness:t.harness,sandboxClient:l,maxIterations:1}),d={name:`supervisor`,...t.model?{model:t.model}:{}},f=r.resolveRouter({apiKey:n.apiKey,model:t.model??`deepseek-v4-flash`}),p=ro(await r.supervise(d,{goal:e},{budget:o,makeWorkerAgent:u,router:f,...s?{perWorker:s}:{},...t.model?{allowedModels:[t.model]}:{},runId:`supervise-${i()}`})),ee=p.status===`winner`?`settled`:`failed`;for(let e of c)e.status=ee,n.json||P(`worker ${e.id} [${e.scope} token ttl ${t.tokenTtl}m] settled (${e.status})`);return{task:e,result:p.text,workers:c,tokenUsage:p.tokenUsage,costUsd:p.costUsd,status:p.status}}function so(){let e=new t(`supervise`);return e.description(`Run a budget-conserving supervisor that spawns isolated sandbox workers to deliver a task. Each worker box mints a short-lived scoped token instead of receiving the root API key.`).argument(`<task>`,`What the supervisor should accomplish`).option(`--harness <name>`,`Worker harness (${Ja.join(` | `)})`,`claude-code`).option(`--model <id>`,`Model for the supervisor + workers`).option(`--max-tokens <n>`,`Conserved token budget for the whole run`,`200000`).option(`--max-iterations <n>`,`Conserved iteration budget for the whole run`,`50`).option(`--token-scope <scope>`,`Per-worker token scope (${Ya.join(` | `)})`,`session`).option(`--token-ttl <min>`,`Per-worker token TTL in minutes (SDK clamps to [1, 15])`,`10`).option(`--max-workers <n>`,`Bound the fanout; each worker reserves floor(max-tokens / n) tokens and floor(max-iterations / n) iterations`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=Qa({harness:t.harness,model:t.model,maxTokens:t.maxTokens,maxIterations:t.maxIterations,tokenScope:t.tokenScope,tokenTtl:t.tokenTtl,maxWorkers:t.maxWorkers});t.json||(P(`Supervising: ${e}`),P(`harness=${n.harness} budget=${n.maxTokens}tok/${n.maxIterations}it scope=${n.tokenScope} ttl=${n.tokenTtl}m`),console.log());let r=await oo(e,n,{apiKey:t.apiKey,baseUrl:t.baseUrl,json:t.json});if(t.json){j(r),r.status!==`winner`&&(process.exitCode=1);return}if(console.log(),r.status!==`winner`)throw Error(`Supervisor finished without a winner: ${r.status}`);console.log(r.result),console.log(),I({"Input Tokens":r.tokenUsage.input,"Output Tokens":r.tokenUsage.output,Cost:`$${r.costUsd.toFixed(4)}`})}catch(e){B(e,t.json)}}),e}function co(){let e=new t(`team`).description(`Manage teams`);return e.command(`list`).description(`List teams for the current account`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async e=>{try{let t=E(e),n=k(t),r=e.json?null:F(`Fetching teams...`);r?.start();let i=await n.teams.list();if(r?.stop(),e.json){j({teams:i,activeTeamId:t.activeTeamId??null});return}A(i.map(e=>({active:e.id===t.activeTeamId,id:e.id,name:e.name,role:e.currentUserRole,members:e.memberCount})),[{key:`active`,header:`Active`,width:8},{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:24},{key:`role`,header:`Role`,width:10},{key:`members`,header:`Members`,width:10}])}catch(e){B(e)}}),e.command(`create <name>`).description(`Create a team`).option(`--org-id <id>`,`External organization id`).option(`--no-switch`,`Do not set the new team as active`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=t.json?null:F(`Creating team...`);i?.start();let a=await r.teams.create({name:e,orgId:t.orgId});if(t.switch&&ca(a,n.profile),i?.stop(),t.json){j({team:a,active:!!t.switch});return}M(`Team created: ${oa(a)}`),t.switch&&M(`Active team set to ${a.name}`)}catch(e){B(e)}}),e.command(`switch <team>`).description(`Set the active team for the current profile`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=await sa(k(n),e);if(ca(r,n.profile),t.json){j({team:r,activeTeamId:r.id});return}M(`Active team set to ${oa(r)}`)}catch(e){B(e)}}),e.command(`current`).description(`Show the active team for the current profile`).option(`--json`,`Output as JSON`).option(`--profile <profile>`,`Credential profile`).action(e=>{try{let t=St(e.profile);if(e.json){j(t.activeTeamId?t:{activeTeamId:null});return}if(!t.activeTeamId){console.log(`No active team.`);return}I({ID:t.activeTeamId,Name:t.activeTeamName})}catch(e){B(e)}}),e.command(`clear`).description(`Clear the active team for the current profile`).option(`--json`,`Output as JSON`).option(`--profile <profile>`,`Credential profile`).action(e=>{try{if(la(e.profile),e.json){j({activeTeamId:null});return}M(`Active team cleared.`)}catch(e){B(e)}}),e.command(`members [team]`).description(`List team members`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=await X(r,e,n.profile),a=await r.teams.listMembers(i.id);if(t.json){j({team:i,members:a});return}A(a.map(e=>({id:e.id,email:e.customerEmail,role:e.role,status:e.status,joinedAt:e.joinedAt})),[{key:`id`,header:`ID`,width:36},{key:`email`,header:`Email`,width:28},{key:`role`,header:`Role`,width:10},{key:`status`,header:`Status`,width:10},{key:`joinedAt`,header:`Joined`,width:16}])}catch(e){B(e)}}),e.command(`update-member <member-id>`).description(`Update a team member role`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).requiredOption(`--role <role>`,`Role: admin, member, viewer`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=await X(r,t.team,n.profile),a=lo(t.role),o=await r.teams.updateMember(i.id,e,{role:a});if(t.json){j({team:i,member:o});return}M(`Member updated: ${o.customerEmail}`),I({Team:i.name,Role:o.role,Status:o.status})}catch(e){B(e)}}),e.command(`invite <email>`).description(`Invite a user to a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--role <role>`,`Role: admin, member, viewer`,`member`).option(`--ttl-hours <hours>`,`Invitation lifetime in hours`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=await X(r,t.team,n.profile),a=lo(t.role),o=await r.teams.invite(i.id,{email:e,role:a,ttlHours:t.ttlHours?Number.parseInt(t.ttlHours,10):void 0});if(t.json){j({team:i,invitation:o});return}M(`Invitation created for ${o.email}`),I({Team:i.name,Role:o.role,Expires:o.expiresAt,"Invitation ID":o.id}),M(`Re-run with --json to retrieve the invitation token for sharing.`)}catch(e){B(e)}}),e.command(`leave [team]`).description(`Leave a team as the current user`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=await X(r,e,n.profile);if(!t.force&&!t.json&&!await W(`Leave team '${i.name}'? (y/N) `))return;if(await r.teams.leave(i.id),n.activeTeamId===i.id&&la(n.profile),t.json){j({success:!0,teamId:i.id});return}M(`Left team: ${i.name}`)}catch(e){B(e)}}),e.command(`transfer <new-owner-customer-id> [team]`).description(`Transfer team ownership to another active member`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t,n)=>{try{let r=E(n),i=k(r),a=await X(i,t,r.profile);if(!n.force&&!n.json&&!await W(`Transfer ownership of '${a.name}' to ${e}? This cannot be undone without the new owner's cooperation. (y/N) `))return;if(await i.teams.transferOwnership(a.id,e),n.json){j({success:!0,teamId:a.id,newOwnerCustomerId:e});return}M(`Ownership transferred for ${a.name}`)}catch(e){B(e)}}),e.addCommand(uo()),e.addCommand(fo()),e.command(`invitations [team]`).description(`List pending and historical team invitations`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=await X(r,e,n.profile),a=await r.teams.listInvitations(i.id);if(t.json){j({team:i,invitations:a});return}A(a.map(e=>({id:e.id,email:e.email,role:e.role,status:e.status,expiresAt:e.expiresAt})),[{key:`id`,header:`ID`,width:38},{key:`email`,header:`Email`,width:28},{key:`role`,header:`Role`,width:10},{key:`status`,header:`Status`,width:12},{key:`expiresAt`,header:`Expires`,width:16}])}catch(e){B(e)}}),e.command(`accept <token>`).description(`Accept a team invitation`).option(`--no-switch`,`Do not set the accepted team as active`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=await r.teams.acceptInvitation(e),a=t.switch===!1?null:await r.teams.get(i.teamId);if(a&&ca(a,n.profile),t.json){j({member:i,activeTeamId:a?.id??null});return}M(`Invitation accepted for team ${i.teamId}`),a&&M(`Active team set to ${a.name}`)}catch(e){B(e)}}),e.command(`revoke-invitation <invitation-id>`).description(`Revoke a pending team invitation`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{if(await k(E(t)).teams.revokeInvitation(e),t.json){j({success:!0,invitationId:e});return}M(`Invitation revoked: ${e}`)}catch(e){B(e)}}),e.command(`remove-member <member-id>`).description(`Remove a member from a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=await X(r,t.team,n.profile);if(await r.teams.removeMember(i.id,e),t.json){j({success:!0,teamId:i.id,memberId:e});return}M(`Member removed: ${e}`)}catch(e){B(e)}}),e}function lo(e){if(e===`admin`||e===`member`||e===`viewer`)return e;throw Error(`Role must be one of: admin, member, viewer`)}function uo(){let e=new t(`secret`).description(`Manage team secrets`);return e.command(`list [team]`).description(`List team secret names`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=await X(r,e,n.profile),a=await r.teams.listSecrets(i.id);if(t.json){j({team:i,secrets:a});return}A(a.map(e=>({name:e.name,updatedAt:e.updatedAt,updatedBy:e.updatedBy})),[{key:`name`,header:`Name`,width:28},{key:`updatedAt`,header:`Updated`,width:24},{key:`updatedBy`,header:`Updated By`,width:28}])}catch(e){B(e)}}),e.command(`set <name> [value]`).description(`Create or replace a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--value-stdin`,`Read secret value from stdin`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t,n)=>{try{let r=E(n),i=k(r),a=await X(i,n.team,r.profile),o=await po({value:t,valueStdin:n.valueStdin,prompt:`Enter value for team secret '${e}': `}),s=await i.teams.upsertSecret(a.id,e,o);if(n.json){j({team:a,secret:s});return}M(`Team secret saved: ${s.name}`)}catch(e){B(e)}}),e.command(`delete <name>`).description(`Delete a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=await X(r,t.team,n.profile);if(!t.force&&!t.json&&!await W(`Delete team secret '${e}' from '${i.name}'? (y/N) `))return;if(await r.teams.deleteSecret(i.id,e),t.json){j({success:!0,teamId:i.id,name:e});return}M(`Team secret deleted: ${e}`)}catch(e){B(e)}}),e.command(`reveal <name>`).description(`Reveal a team secret value`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=await X(r,t.team,n.profile),a=await r.teams.revealSecret(i.id,e);if(t.json){j({teamId:i.id,...a});return}console.log(a.value)}catch(e){B(e)}}),e}function fo(){let e=new t(`templates`).description(`Manage team golden-path templates`);return e.command(`list [team]`).description(`List a team's golden-path templates`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=await X(r,e,n.profile),a=await r.teams.listTemplates(i.id);if(t.json){j({team:i,templates:a});return}if(a.length===0){console.log(`No templates yet for ${i.name}.`);return}A(a.map(e=>({id:e.id,name:e.name,environment:e.environment,snapshot:`${e.snapshotId.slice(0,12)}…`,updated:e.updatedAt})),[{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:28},{key:`environment`,header:`Env`,width:14},{key:`snapshot`,header:`Snapshot`,width:16},{key:`updated`,header:`Updated`,width:24}])}catch(e){B(e)}}),e.command(`create <name> <snapshot-id>`).description(`Create a golden-path template from a snapshot`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`-d, --description <description>`,`Human-readable description shown in the dashboard`).option(`-e, --environment <environment>`,`Default environment to apply (defaults to 'universal')`).option(`--config <json>`,`Optional JSON config object merged into sandboxes created from this template`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t,n)=>{try{let r=E(n),i=k(r),a=await X(i,n.team,r.profile),o;if(n.config)try{let e=JSON.parse(n.config);if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`--config must be a JSON object`);o=e}catch(e){throw Error(`--config is not valid JSON: ${e instanceof Error?e.message:String(e)}`)}let s=await i.teams.createTemplate(a.id,{name:e,snapshotId:t,description:n.description,environment:n.environment,config:o});if(n.json){j({team:a,template:s});return}M(`Team template created: ${s.name} (${s.id})`)}catch(e){B(e)}}),e.command(`delete <template-id>`).description(`Delete a team golden-path template`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).option(`--profile <profile>`,`Credential profile`).action(async(e,t)=>{try{let n=E(t),r=k(n),i=await X(r,t.team,n.profile);if(!t.force&&!t.json&&!await W(`Delete template '${e}' from '${i.name}'? (y/N) `))return;if(await r.teams.deleteTemplate(i.id,e),t.json){j({success:!0,teamId:i.id,templateId:e});return}M(`Team template deleted: ${e}`)}catch(e){B(e)}}),e}async function po(e){if(e.value!==void 0&&e.valueStdin)throw Error(`Provide either a secret value argument or --value-stdin, not both`);if(e.value!==void 0){if(e.value.length===0)throw Error(`Secret value cannot be empty`);return e.value}if(e.valueStdin){let e=await _n();if(e.length===0)throw Error(`Secret value from stdin cannot be empty`);return e}let t=await gn(e.prompt);if(t.length===0)throw Error(`Secret value cannot be empty`);return t}function mo(){let e=new t(`template`).description(`Manage published public templates`);return e.command(`list`).option(`-q, --query <query>`,`Search query`).option(`--tag <tag>`,`Filter by tag`).option(`--featured`,`Show featured templates only`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=k(E(e)),n=e.featured?await t.publicTemplates.featured():await t.publicTemplates.list({query:e.query,tag:e.tag});if(e.json){j({templates:n});return}A(n.map(e=>({slug:e.slug,name:e.name,forks:e.forkCount,sandboxes:e.sandboxCount,updated:e.updatedAt})),[{key:`slug`,header:`Slug`,width:28},{key:`name`,header:`Name`,width:28},{key:`forks`,header:`Forks`,width:8},{key:`sandboxes`,header:`Sandboxes`,width:12},{key:`updated`,header:`Updated`,width:24}])}catch(e){B(e)}}),e.command(`get <id-or-slug>`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await k(E(t)).publicTemplates.get(e);if(t.json){j({template:n});return}j(n)}catch(e){B(e)}}),e.command(`versions <id-or-slug>`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await k(E(t)).publicTemplates.versions(e);if(t.json){j({versions:n});return}A(n.map(e=>({...e})),[{key:`id`,header:`Version ID`,width:38},{key:`versionNumber`,header:`Version`,width:8},{key:`snapshotId`,header:`Snapshot`,width:20},{key:`createdAt`,header:`Created`,width:24}])}catch(e){B(e)}}),e.command(`publish <name> <snapshot-id> <sandbox-id>`).option(`--slug <slug>`,`Stable public slug`).option(`-d, --description <description>`,`Template description`).option(`--readme <markdown>`,`README markdown`).option(`--tags <tags...>`,`Template tags`).option(`--release-notes <text>`,`Release notes`).option(`--team-id <id>`,`Publish under a team`).option(`--forked-from <id>`,`Fork source template id`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n,r)=>{try{let i=await k(E(r)).publicTemplates.publish({name:e,slug:r.slug,description:r.description,snapshotId:t,sourceSandboxId:n,readmeMarkdown:r.readme,tags:r.tags,releaseNotes:r.releaseNotes,teamId:r.teamId,forkedFromTemplateId:r.forkedFrom});if(r.json){j({template:i});return}M(`Published template: ${i.slug}`)}catch(e){B(e)}}),e.command(`publish-version <id-or-slug> <snapshot-id> <sandbox-id>`).option(`--readme <markdown>`,`README markdown`).option(`--tags <tags...>`,`Template tags`).option(`--release-notes <text>`,`Release notes`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n,r)=>{try{let i=await k(E(r)).publicTemplates.publishVersion(e,{snapshotId:t,sourceSandboxId:n,readmeMarkdown:r.readme,tags:r.tags,releaseNotes:r.releaseNotes});if(r.json){j({version:i});return}M(`Published template version: ${i.id}`)}catch(e){B(e)}}),e}function ho(){let e=new t(`tools`).description(`Manage language runtimes and tools in a sandbox (via mise)`);return e.command(`list`).alias(`ls`).description(`List installed tools in a sandbox`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=E({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching tools...`);t.json||i.start();let a=await(await H(r,n,e)).tools.list();i.stop(),t.json?j(a):a.length===0?console.log(`No tools installed`):z([`Tool`,`Version`,`Active`],a.map(e=>[e.name,e.version,e.active?`yes`:`no`]))}catch(e){B(e)}}),e.command(`install`).description(`Install a tool version`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<tool>`,`Tool name (e.g. node, python, go)`).argument(`<version>`,`Version to install (e.g. 20, 3.12, latest)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n,r)=>{try{let i=E({apiKey:r.apiKey,baseUrl:r.baseUrl}),a=k(i),o=F(`Installing ${t}@${n}...`);r.json||o.start(),await(await H(a,i,e)).tools.install(t,n),o.stop(),r.json?j({tool:t,version:n,installed:!0}):M(`Installed ${t}@${n}`)}catch(e){B(e)}}),e.command(`use`).description(`Activate a tool version for the current session`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<tool>`,`Tool name`).argument(`<version>`,`Version to activate`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n,r)=>{try{let i=E({apiKey:r.apiKey,baseUrl:r.baseUrl});await(await H(k(i),i,e)).tools.use(t,n),M(`Activated ${t}@${n}`)}catch(e){B(e)}}),e.command(`run`).description(`Run a command with a specific tool`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<tool>`,`Tool name`).argument(`<args...>`,`Command arguments`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n,r)=>{try{let i=E({apiKey:r.apiKey,baseUrl:r.baseUrl}),a=k(i),o=F(`Running ${t} ${n.join(` `)}...`);r.json||o.start();let s=await(await H(a,i,e)).tools.run(t,n);o.stop(),r.json?j(s):(s.stdout&&process.stdout.write(s.stdout),s.stderr&&process.stderr.write(s.stderr),s.exitCode!==0&&process.exit(s.exitCode))}catch(e){B(e)}}),e}function go(){let e=new t(`traces`).description(`Read hosted agent traces, spans, and eval-runs from Tangle Intelligence`);return e.command(`list`).description(`List trace summaries (one row per trace), newest first`).option(`--from <iso>`,`ISO-8601 lower bound on received time (inclusive)`).option(`--to <iso>`,`ISO-8601 upper bound on received time (inclusive)`).option(`--model <model>`,`Exact model match (any span carried this model)`).option(`--run <runId>`,`Exact run id match`).option(`--status <status>`,`ERROR | OK`).option(`-q, --query <text>`,`Substring over span name`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Page size (clamped server-side to [1, 200])`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Intelligence API base URL`).action(async e=>{try{let t={from:e.from,to:e.to,model:e.model,runId:e.run,status:e.status===void 0?void 0:Do(e.status),q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:Mo(e.limit)},n=vo(e),r=e.json?null:F(`Fetching traces...`);r?.start();let i=await n.listTraces(t);if(r?.stop(),e.json)return j(i);xo(i.items),To(i.nextCursor)}catch(t){bo(t,e)}}),e.command(`get <traceId>`).description(`Show one trace's spans. Streams NDJSON to stdout with --ndjson.`).option(`--ndjson`,`Stream the full span set as NDJSON to stdout`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Spans per page`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Intelligence API base URL`).action(async(e,t)=>{try{let n=vo(t);if(t.ndjson){await yo(n,e);return}let r=t.json?null:F(`Fetching trace spans...`);r?.start();let i=await n.getTraceSpans(e,{cursor:t.cursor,limit:t.limit===void 0?void 0:Mo(t.limit)});if(r?.stop(),t.json)return j(i);So(i.items),i.truncated&&I({Spans:`${i.items.length} of ${i.total} (truncated)`}),To(i.nextCursor)}catch(e){bo(e,t)}}),e.addCommand(_o()),e}function _o(){let e=new t(`runs`).description(`Read eval-runs pivoted off the trace surface`);return e.command(`list`).description(`List eval-runs, newest first`).option(`--status <status>`,`Run status filter`).option(`--gate <decision>`,`Promotion-gate decision filter`).option(`--label <key:value>`,`Match over the run's labels`).option(`--from <iso>`,`ISO-8601 lower bound on received time`).option(`--to <iso>`,`ISO-8601 upper bound on received time`).option(`-q, --query <text>`,`Substring over run dir`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Page size`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Intelligence API base URL`).action(async e=>{try{let t={status:e.status===void 0?void 0:ko(e.status),gate:e.gate===void 0?void 0:jo(e.gate),label:e.label,from:e.from,to:e.to,q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:Mo(e.limit)},n=vo(e),r=e.json?null:F(`Fetching runs...`);r?.start();let i=await n.listRuns(t);if(r?.stop(),e.json)return j(i);Co(i.items),To(i.nextCursor)}catch(t){bo(t,e)}}),e.command(`get <runId>`).description(`Show a single eval-run`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Intelligence API base URL`).action(async(e,t)=>{try{let n=vo(t),r=t.json?null:F(`Fetching run...`);r?.start();let i=await n.getRun(e);if(r?.stop(),t.json)return j(i);wo(i)}catch(e){bo(e,t)}}),e}function vo(e){let t=vt(e.apiKey);if(!t)throw Error(`No API key found. Set TANGLE_API_KEY or run: tangle auth login`);return we({apiKey:t,baseUrl:e.baseUrl??process.env.TANGLE_INTELLIGENCE_BASE_URL})}async function yo(e,t){let n=(await e.exportTraceSpansNdjson(t)).getReader();try{for(;;){let{value:e,done:t}=await n.read();if(t)break;e&&process.stdout.write(Buffer.from(e))}}finally{n.releaseLock()}}function bo(e,t){return B(e,t.json===!0)}function xo(e){A(e.map(e=>({traceId:e.traceId,root:e.rootName??`-`,model:e.model??`-`,spans:e.spanCount,errors:e.errorCount,durationMs:e.durationMs,cost:Eo(e.costUsd)})),[{key:`traceId`,header:`Trace`,width:36},{key:`root`,header:`Root`,width:24},{key:`model`,header:`Model`,width:22},{key:`spans`,header:`Spans`,width:8},{key:`errors`,header:`Errors`,width:8},{key:`durationMs`,header:`Duration(ms)`,width:14},{key:`cost`,header:`Cost`,width:10}])}function So(e){A(e.map(e=>({spanId:e.id,name:e.name,model:e.model??`-`,status:e.statusCode??`-`,cost:e.costUsd===null?`-`:`$${e.costUsd}`})),[{key:`spanId`,header:`Span`,width:40},{key:`name`,header:`Name`,width:28},{key:`model`,header:`Model`,width:22},{key:`status`,header:`Status`,width:10},{key:`cost`,header:`Cost`,width:12}])}function Co(e){A(e.map(e=>({runId:e.id,status:e.status,gate:e.gateDecision??`-`,cost:e.totalCostUsd===null?`-`:`$${e.totalCostUsd}`,receivedAt:e.receivedAt})),[{key:`runId`,header:`Run`,width:24},{key:`status`,header:`Status`,width:22},{key:`gate`,header:`Gate`,width:18},{key:`cost`,header:`Cost`,width:12},{key:`receivedAt`,header:`Received`,width:18}])}function wo(e){I({Run:e.id,Status:e.status,Gate:e.gateDecision??void 0,"Run Dir":e.runDir??void 0,Cost:e.totalCostUsd===null?void 0:`$${e.totalCostUsd}`,Duration:e.totalDurationMs===null?void 0:`${e.totalDurationMs}ms`,"Holdout Lift":e.holdoutLift??void 0,Received:e.receivedAt})}function To(e){e&&I({"Next page":`--cursor ${e}`})}function Eo(e){return e===null?`-`:`$${e.toFixed(4)}`}function Do(e){if(e===`ERROR`||e===`OK`)return e;throw Error(`--status must be ERROR or OK`)}const Oo=[`started`,`baseline-complete`,`generation-complete`,`gate-decided`,`finished`,`errored`];function ko(e){let t=Oo.find(t=>t===e);if(t)return t;throw Error(`--status must be one of ${Oo.join(`, `)}`)}const Ao=[`ship`,`hold`,`need_more_work`,`model_ceiling`,`arch_ceiling`];function jo(e){let t=Ao.find(t=>t===e);if(t)return t;throw Error(`--gate must be one of ${Ao.join(`, `)}`)}function Mo(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function No(){return new t(`usage`).description(`Show account usage and billing information`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=k(E({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=e.json?null:F(`Fetching usage...`);n?.start();let[r,i]=await Promise.all([t.usage(),t.subscription().catch(()=>null)]);n?.stop(),e.json?j({...r,subscription:i}):(console.log(),console.log(`Account Usage`),console.log(`─`.repeat(40)),I({"Active Sandboxes":r.activeSandboxes,"Total Sandboxes":r.totalSandboxes,"Compute Minutes":Po(r.computeMinutes)}),i&&(console.log(),console.log(`Subscription`),console.log(`─`.repeat(40)),I({Plan:i.plan,Status:i.status,"Credits Available":Fo(i.creditsAvailableUsd),"Credits Used":Fo(i.creditsUsedUsd),"Monthly Balance":Fo(i.monthlyBalanceUsd)})),console.log(),console.log(`Billing Period`),console.log(`─`.repeat(40)),I({Start:r.periodStart.toLocaleDateString(),End:r.periodEnd.toLocaleDateString()}),console.log())}catch(e){B(e)}})}function Po(e){if(e===void 0)return`-`;if(e<60)return`${e} min`;let t=Math.floor(e/60),n=e%60;return n===0?`${t} hr`:`${t} hr ${n} min`}function Fo(e){return e<0?`-$${(-e).toFixed(2)}`:`$${e.toFixed(2)}`}function Io(){return new t(`use`).description(`Set or show the active sandbox (used when a command omits the id)`).argument(`[id]`,`Sandbox id to make active`).option(`--clear`,`Clear the active sandbox`).action((e,t)=>{try{if(t.clear){dt(),P(`Cleared the active sandbox.`);return}if(e){ut(e),P(`Active sandbox set to ${e}. Commands now default to it; override with --box or TANGLE_SANDBOX.`);return}let n=lt();P(n?`Active sandbox: ${n}`:"No active sandbox. Set one with `tangle use <id>`.")}catch(e){B(e)}})}function Lo(){let e=new t(`workflows`).description(`Create and manage Tangle workflows`);return e.option(`--json`,`Output as JSON`),e.hook(`preAction`,(e,t)=>{zo(t)}),e.command(`list`).description(`List your workflows`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=await Z(e).workflows.list();if(e.json)return j(t);Vo(t)}catch(t){Q(t,e)}}),e.command(`get`).description(`Show a workflow's definition and compiled triggers`).argument(`<id>`,`Workflow ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=await Z(t).workflows.get(e);if(t.json)return j(n);Ho(n)}catch(e){Q(e,t)}}),e.command(`create`).description(`Create a workflow from a YAML file`).argument(`<file>`,`Path to the workflow YAML`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=Ro(e),r=await Z(t).workflows.create(n);if(t.json)return j(r);P(`Created workflow ${r.id} (${r.name}).`),Ho(r)}catch(e){Q(e,t)}}),e.command(`update`).description(`Replace a workflow's definition from a YAML file`).argument(`<id>`,`Workflow ID`).argument(`<file>`,`Path to the workflow YAML`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{try{let r=Ro(t),i=await Z(n).workflows.update(e,r);if(n.json)return j(i);P(`Updated workflow ${i.id} (${i.name}).`),Ho(i)}catch(e){Q(e,n)}}),e.command(`delete`).description(`Delete a workflow and its triggers`).argument(`<id>`,`Workflow ID`).option(`--force`,`Skip confirmation prompt`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{if(!t.force&&!await W(`Delete workflow ${e}? `)){P(`Delete cancelled.`);return}if(await Z(t).workflows.delete(e),t.json)return j({deleted:!0,id:e});P(`Deleted workflow ${e}.`)}catch(e){Q(e,t)}}),e.command(`validate`).description(`Validate a workflow YAML file without saving it`).argument(`<file>`,`Path to the workflow YAML`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=Ro(e),r=await Z(t).workflows.validate(n);if(t.json)return j(r);if(r.valid)P(`Valid: ${r.name} (${r.actionCount} action(s), ${r.triggerCount} trigger(s)).`);else{P(`Invalid workflow:`);for(let e of r.errors)console.log(` ${e.path}: ${e.message}`);process.exitCode=1}}catch(e){Q(e,t)}}),e.command(`schema`).description(`Print the JSON Schema for the workflow YAML`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{j(await Z(e).workflows.schema())}catch(t){Q(t,e)}}),e}function Ro(e){try{return l(e,`utf8`)}catch(t){throw Error(`Could not read workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function Z(e){let t=E({apiKey:vt(e.apiKey),baseUrl:e.baseUrl??xt(process.env.TANGLE_HUB_URL)});return new he({baseUrl:t.baseUrl,apiKey:t.apiKey})}function zo(e){if(!Bo(e,`json`)||e.getOptionValue(`json`)!==void 0)return;let t=e.parent;for(;t;){let n=t.getOptionValue(`json`);if(n!==void 0){e.setOptionValue(`json`,n);return}t=t.parent}}function Bo(e,t){return e.options.some(e=>e.attributeName()===t)}function Q(e,t){return B(e,t.json===!0)}function Vo(e){A(e.map(e=>({id:e.id,name:e.name,enabled:e.enabled?`yes`:`no`,issues:e.validationErrors.length,updated:e.updatedAt})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`enabled`,header:`Enabled`},{key:`issues`,header:`Issues`},{key:`updated`,header:`Updated`}])}function Ho(e){if(I({ID:e.id,Name:e.name,Description:e.description??``,Enabled:e.enabled?`yes`:`no`,Actions:e.actions.length}),e.triggers&&e.triggers.length>0&&(P(`Triggers`),Uo(e.triggers)),e.validationErrors.length>0){P(`Validation issues`);for(let t of e.validationErrors)console.log(` ${t.path}: ${t.message}`)}}function Uo(e){A(e.map(e=>({id:e.id,kind:e.kind,enabled:e.enabled?`yes`:`no`,detail:e.kind===`schedule`?`${e.cron??``} (${e.timezone??``})`:`${e.provider??``}:${e.eventFilter?.event??``}${e.eventFilter?.action?`.${e.eventFilter.action}`:``}`})),[{key:`id`,header:`ID`},{key:`kind`,header:`Kind`},{key:`enabled`,header:`Enabled`},{key:`detail`,header:`Detail`}])}function Wo(e){let t={...Go(e)??{},...e.optsWithGlobals()};for(let n of e.options){let r=n.attributeName();e.getOptionValue(r)===void 0&&t[r]!==void 0&&e.setOptionValue(r,t[r])}}function Go(e){let t=e;for(;t?.parent;)t=t.parent;return t?t.opts():void 0}const Ko=e(import.meta.url)(`../package.json`),$=new t;$.name(`tangle`).description(`CLI for Tangle Sandbox operations`).version(Ko.version??`0.0.0`).option(`--api-key <key>`,`API key (or set TANGLE_API_KEY)`).option(`--base-url <url>`,`API base URL`),$.hook(`preAction`,(e,t)=>{Wo(t)}),$.addCommand($n()),$.addCommand(ma()),$.addCommand(Io()),$.addCommand(ja()),$.addCommand(Yi()),$.addCommand(hr()),$.addCommand(Wa()),$.addCommand(Ga()),$.addCommand(qa()),$.addCommand(Fn()),$.addCommand(Pa()),$.addCommand(_r()),$.addCommand(No()),$.addCommand(co()),$.addCommand(mo()),$.addCommand(Zi()),$.addCommand(or()),$.addCommand(fr()),$.addCommand($i()),$.addCommand(Dr()),$.addCommand(Ar()),$.addCommand(jr()),$.addCommand(Lo()),$.addCommand(mr()),$.addCommand(ho()),$.addCommand(Aa()),$.addCommand(Na()),$.addCommand(pr()),$.addCommand(Qi()),$.addCommand(Mi()),$.addCommand(aa()),$.addCommand(Xi()),$.addCommand(go()),$.addCommand(so()),$.parseAsync(process.argv).catch(e=>{console.error(`Fatal error:`,e.message),process.exit(1)});export{};