@tangle-network/sandbox-cli 0.20.8 → 0.20.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +21 -21
  2. package/package.json +8 -6
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
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{agentInteractiveSessionRunRef as a,canonicalAgentProfileDigest as o,modelProvider as s}from"@tangle-network/agent-interface";import{ALL_BACKEND_TYPES as c,AuthError as l,NetworkError as u,NotFoundError as d,PublicTemplatePublishError as f,QuotaError as p,Sandbox as m,SandboxError as h,ServerError as g,StateError as ee,TimeoutError as te,ValidationError as ne,createAgentRunOutcomeTracker as re,createBatchResultAccumulator as ie,createConfidentialSandbox as ae,generateAttestationNonce as oe,parseBackendType as se,parseSSEStream as ce,validateBatchRunRequest as le}from"@tangle-network/sandbox";import _ from"chalk";import*as v from"node:fs";import{chmodSync as ue,existsSync as de,mkdirSync as fe,readFileSync as y,renameSync as pe,writeFileSync as me}from"node:fs";import*as b from"node:path";import{basename as he,dirname as ge,extname as _e,join as ve,resolve as ye}from"node:path";import*as be from"node:os";import{homedir as xe,tmpdir as Se}from"node:os";import{execFile as Ce,execFileSync as we,spawn as Te}from"node:child_process";import{lockSync as Ee}from"proper-lockfile";import{HubClient as De,HubSdkError as Oe}from"@tangle-network/hub-sdk";import ke from"ora";import{CONTENT_COMPLETION_KEY as Ae,CONTENT_PROMPT_KEY as je,CONTENT_TOOL_ARGS_KEY as Me,CONTENT_TOOL_NAME_KEY as Ne,CONTENT_TOOL_RESULT_KEY as Pe,TANGLE_SUBJECT_KEY as Fe,asContentField as x,asContentString as Ie}from"@tangle-network/agent-core/telemetry";import*as S from"node:fs/promises";import{open as Le,readFile as Re}from"node:fs/promises";import{createMcpServer as ze}from"@tangle-network/sandbox/agent";import{ensureAgentPreview as Be,publishAgentPreview as Ve,resolveSelfSandbox as He}from"@tangle-network/sandbox/preview";import{fileURLToPath as Ue}from"node:url";import{generatePrivateKey as We,privateKeyToAccount as Ge}from"viem/accounts";import{promisify as Ke}from"node:util";import{createPublicClient as qe,createWalletClient as Je,decodeAbiParameters as Ye,decodeEventLog as Xe,encodeAbiParameters as Ze,getAddress as Qe,http as $e,isAddress as et,keccak256 as tt,parseAbi as nt,parseAbiItem as rt,parseAbiParameters as it,stringToHex as at,toHex as ot}from"viem";import{tempoModerato as st}from"viem/chains";import{Actions as ct,withRelay as lt}from"viem/tempo";import ut from"ws";import{createIntelligenceClient as dt}from"@tangle-network/sandbox/intelligence";function ft(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:he(a)}}let t;try{t=y(e,`utf8`)}catch{throw Error(`cannot read skill/tool "${e}": not a readable file and not a github: ref`)}return{kind:`inline`,name:he(e),content:t}}function pt(e){let t=(e.skills??[]).map(ft),n=(e.tools??[]).map(ft),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 mt(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 St(`https://raw.githubusercontent.com/${i[0]}/${i[1]}/${a}/${i.slice(2).join(`/`)}`)}else t=/^https?:\/\//.test(e)?await St(e):y(e,`utf8`);let n;try{n=JSON.parse(t)}catch{throw Error(`profile at "${e}" is not valid JSON`)}return vt(n,e),n}const ht=[`prompt`,`model`,`permissions`,`tools`,`mcp`,`connections`,`subagents`,`resources`,`hooks`,`modes`,`confidential`,`extensions`],gt=new Set([...ht,`name`,`description`,`version`,`tags`,`metadata`]),_t=[`files`,`tools`,`skills`,`agents`,`commands`];function vt(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=>ht.includes(e)),i=n.includes(`name`)&&n.every(e=>gt.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)`}.`);yt(e,t)}function yt(e,t){let n=e.resources;if(!n||typeof n!=`object`)return;for(let e of _t){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)xt(e===`files`?bt(n):n,t)}}let r=n.instructions;r!==void 0&&typeof r!=`string`&&xt(r,t)}function bt(e){return e&&typeof e==`object`?e.resource:e}function xt(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 St(e){let t=await fetch(e);if(!t.ok)throw Error(`failed to fetch ${e} (${t.status})`);return t.text()}async function Ct(e){let t=e.profileSource?await mt(e.profileSource):void 0,n=pt(e);return t?n?{...t,...n,...n.resources?{resources:{...t.resources,...n.resources}}:{}}:t:n}const wt=b.join(be.homedir(),`.tangle`),Tt=b.join(wt,`credentials.json`),Et=`tangle-sandbox-cli`,Dt=new Int32Array(new SharedArrayBuffer(4)),Ot=`TANGLE_ALLOW_PLAINTEXT_CREDENTIALS`;var kt=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)}},At=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 ${Ot}=1 to opt into a plaintext credentials.json with mode 0600.`),this.name=`KeychainUnavailableError`}},jt=class extends Error{constructor(e){super(`Credential storage preflight failed: ${e}`),this.name=`CredentialStorageProbeError`}},Mt=class extends Error{constructor(e){super(`Credential storage is busy. Wait a moment and retry.`),this.name=`CredentialsFileLockedError`,e&&(this.cause=e)}};function Nt(e){let t=Rt(e);if(t)return{value:t,source:`keychain`};let n=Vt(e);return n?{value:n,source:`file`}:{source:`none`}}function Pt(e,t){if(zt(e,t))return Ut(e),`keychain`;if(!Lt())throw new At;return Ht(e,t),`file`}function Ft(){let e=`credential-write-probe:${process.pid}:${i()}`,t=i();if(zt(e,t)){let n=Rt(e);if(!Bt(e))throw new jt(`the OS keychain accepted a test credential but the CLI could not remove it`);if(n!==t)throw new jt(`the OS keychain accepted a test credential but the CLI could not read it back`);return`keychain`}if(!Lt())throw new At;return qt(e),`file`}function It(e){Bt(e),Ut(e)}function Lt(){let e=process.env[Ot];if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function Rt(e){if(process.platform===`darwin`)try{return we(`security`,[`find-generic-password`,`-s`,Et,`-a`,Yt(e),`-w`],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{return}if(process.platform===`linux`)try{return we(`secret-tool`,[`lookup`,`service`,Et,`account`,Yt(e)],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{return}}function zt(e,t){if(process.platform===`darwin`)try{return we(`security`,[`add-generic-password`,`-U`,`-s`,Et,`-a`,Yt(e),`-w`,t],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}if(process.platform===`linux`)try{return we(`secret-tool`,[`store`,`--label=Tangle Sandbox CLI`,`service`,Et,`account`,Yt(e)],{input:t,stdio:[`pipe`,`ignore`,`ignore`]}),!0}catch{return!1}return!1}function Bt(e){if(process.platform===`darwin`)try{return we(`security`,[`delete-generic-password`,`-s`,Et,`-a`,Yt(e)],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}if(process.platform===`linux`)try{return we(`secret-tool`,[`clear`,`service`,Et,`account`,Yt(e)],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}return!1}function Vt(e){return Gt()[e]}function Ht(e,t){Wt(()=>{let n=Gt();n[e]=t,Kt(n)})}function Ut(e){return Wt(()=>{let t;try{t=Gt()}catch(e){if(e instanceof kt)return!1;throw e}return e in t?(delete t[e],Kt(t),Vt(e)===void 0):!0})}function Wt(e){Jt();let t=Date.now()+2e3,n,r;for(;!n;)try{n=Ee(Tt,{realpath:!1,stale:5e3})}catch(e){if(r=e instanceof Error?e:void 0,!e||typeof e!=`object`||!(`code`in e)||e.code!==`ELOCKED`)throw e;if(Date.now()>=t)throw new Mt(r);Atomics.wait(Dt,0,0,20)}try{return e()}finally{n()}}function Gt(){let e;try{e=v.readFileSync(Tt,`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 kt(Tt);let n={};for(let[e,r]of Object.entries(t))typeof r==`string`&&(n[e]=r);return n}catch(e){throw e instanceof kt?e:new kt(Tt,e instanceof Error?e:void 0)}}function Kt(e){if(Jt(),Object.keys(e).length===0){v.existsSync(Tt)&&v.unlinkSync(Tt);return}let t=`${Tt}.${process.pid}.tmp`;v.writeFileSync(t,`${JSON.stringify(e,null,2)}\n`,{mode:384}),v.renameSync(t,Tt)}function qt(e){let t=i(),n=!1,r;try{if(Ht(e,t),n=!0,Vt(e)!==t)throw new jt(`the credentials file did not return the value just written`)}catch(e){r=e}finally{if(n)try{!Ut(e)&&!r&&(r=new jt(`the credentials file accepted a test credential but the CLI could not remove it`))}catch(e){r??=e}}if(r)throw r}function Jt(){if(!v.existsSync(wt)){v.mkdirSync(wt,{mode:448,recursive:!0});return}if(process.platform!==`win32`)try{(v.statSync(wt).mode&511)!=448&&v.chmodSync(wt,448)}catch{}}function Yt(e){return`profile:${e}`}const Xt=b.join(be.homedir(),`.tangle`),Zt=b.join(Xt,`credentials`),Qt=b.join(Xt,`config.json`),$t=`https://id.tangle.tools`,en=`https://solve.tangle.tools/api/solve`,C=`default`;function tn(){return{tangleBaseUrl:process.env.TANGLE_BASE_URL,sandboxBaseUrl:process.env.SANDBOX_BASE_URL,hubUrl:process.env.TANGLE_HUB_URL}}function nn(e,t){let n=un(t??(e===`solve`?`solve`:void 0));if(e===`solve`){if(n!==`solve`)throw Error(`The solve app cannot use profile '${n}'. Use the reserved 'solve' profile.`);return n}if(e===`sandbox`&&!t&&n===`solve`)return C;if(new Set([`solve`]).has(n))throw Error(`The ${e} app cannot use the reserved '${n}' profile. Use the '${e}' profile or choose a custom profile.`);return n}function rn(){v.existsSync(Xt)||v.mkdirSync(Xt,{mode:448,recursive:!0})}function an(e,t){rn();let n=`${e}.${process.pid}.tmp`;v.writeFileSync(n,t,{mode:384}),v.renameSync(n,e)}function on(){try{if(v.existsSync(Zt)){let e=v.readFileSync(Zt,`utf-8`).trim();return sn(e)?e:e.match(/api_key\s*=\s*(\S+)/)?.[1]}}catch{}}function sn(e){return e.startsWith(`sk_`)||e.startsWith(`sk-tan-`)}function cn(){try{v.existsSync(Zt)&&v.unlinkSync(Zt)}catch{}}function w(){return zn(Rn())}function ln(e){let t=Bn(w(),e);an(Qt,`${JSON.stringify(t,null,2)}\n`)}function un(e){return Vn(e||process.env.TANGLE_PROFILE||process.env.SANDBOX_PROFILE||w().activeProfile||C)}function dn(e){ln({activeProfile:Vn(e)})}function fn(){return{token:process.env.TANGLE_LINE_TOKEN,baseUrl:process.env.TANGLE_HUB_URL}}function pn(){return process.env.TANGLE_SANDBOX||w().currentSandbox||void 0}function mn(e){ln({currentSandbox:e})}function hn(){let e=w();delete e.currentSandbox,an(Qt,`${JSON.stringify(e,null,2)}\n`)}function gn(){let e=w().deviceId;if(e&&/^[A-Za-z0-9_.-]{1,64}$/.test(e))return e;let t=be.hostname().replace(/[^A-Za-z0-9_.-]/g,`-`).replace(/^-+|-+$/g,``).slice(0,32),n=r(4).toString(`hex`),i=`${t?`${t}-`:`device-`}${n}`;return ln({deviceId:i}),i}function _n(e){let t=e||pn();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 vn(){let e=w(),t=un(),n=new Set([C,...Object.keys(e.profiles??{})]);return e.activeProfile&&n.add(Vn(e.activeProfile)),[...n].map(e=>{let n=Nt(e),r=e===C?on():void 0,i=n.source===`none`?r?`legacy-file`:`none`:n.source;return{name:e,active:e===t,hasApiKey:n.source!==`none`||!!r,baseUrl:On(void 0,e),apiKeySource:i}}).sort((e,t)=>e.name.localeCompare(t.name))}function yn(e){let t=un(e);return{name:t,active:t===un(),baseUrl:On(void 0,t),credentialSource:Dn(t)}}function bn(e,t){let n=Vn(e),r=w(),i=Ln(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=Pt(n,t.apiKey),n===C&&cn()),ln({profiles:Object.keys(l).length>0?l:{}}),u}function xn(e){let t=un(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]}ln({profiles:n}),It(t),t===C&&cn()}function Sn(){let e=process.env.TANGLE_API_KEY_FILE;if(e){let t=v.readFileSync(e,`utf8`).trim();if(!t.startsWith(`sk-tan-`))throw Error(`Invalid sandbox credential file`);return t}return process.env.TANGLE_API_KEY}function Cn(e,t){let n=nn(`sandbox`,t);if(e)return e;let r=Sn();if(r)return r;let i=Nt(n);if(i.value)return i.value;if(n===C||n===`sandbox`)return on()}function wn(e,t){return e||(process.env.TANGLE_SOLVE_API_KEY?process.env.TANGLE_SOLVE_API_KEY:Nt(nn(`solve`,t)).value)}function Tn(e,t){let n=nn(`sandbox`,t);return e?`flag`:process.env.TANGLE_API_KEY_FILE||process.env.TANGLE_API_KEY?`env`:Dn(n)}function En(e,t){return e?`flag`:process.env.TANGLE_SOLVE_API_KEY?`env`:Nt(nn(`solve`,t)).source}function Dn(e){let t=Nt(e);return t.source===`none`?(e===C||e===`sandbox`)&&on()?`legacy-file`:`none`:t.source}function On(e,t){if(e)return e;let n=process.env.TANGLE_BASE_URL||process.env.SANDBOX_BASE_URL;if(n)return n;let r=un(t),i=w(),a=Ln(r,i);return a.baseUrl?a.baseUrl:(r===C||r===`sandbox`)&&i.baseUrl?i.baseUrl:`https://sandbox.tangle.tools`}function kn(e){if(e)return e.replace(/\/v1\/hub\/?$/,``)}function An(e){return e?.trim().replace(/\/+$/,``)||void 0}function jn(e){return An(e?.flag)??An(kn(An(process.env.TANGLE_HUB_URL)))??An(process.env.TANGLE_PLATFORM_URL)??An(e?.cachedPlatformUrl?.())??$t}function Mn(e){let t=An(e)??An(process.env.TANGLE_SOLVE_API_URL);if(t&&t!==en)throw Error(`Solve credentials may only be sent to ${en}`);return en}function Nn(e){let t=An(e);if(t&&t!==$t)throw Error(`Solve credentials may only be sent to ${$t}`);return $t}function T(e){let t=nn(`sandbox`,e.profile),n=Cn(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:On(e.baseUrl,t),timeout:e.timeout??3e4,profile:t,...Pn(t)}}function Pn(e){let t=w(),n=Ln(un(e),t);return{activeTeamId:n.activeTeamId,activeTeamName:n.activeTeamName}}function Fn(e,t){bn(un(t),{activeTeamId:e.id,activeTeamName:e.name})}function In(e){let t=un(e),n=w(),r={...n.profiles??{}},i={baseUrl:Ln(t,n).baseUrl};i.baseUrl?r[t]=i:delete r[t],ln({profiles:r})}function Ln(e,t=w()){let n=Vn(e);return{...n===C?{baseUrl:t.baseUrl,activeTeamId:t.profiles?.[C]?.activeTeamId,activeTeamName:t.profiles?.[C]?.activeTeamName}:{},...t.profiles?.[n]??{}}}function Rn(){try{if(v.existsSync(Qt)){let e=v.readFileSync(Qt,`utf-8`);return JSON.parse(e)}}catch{}return{}}function zn(e){let t=!1,n={};e.apiKey&&(Pt(C,e.apiKey),cn(),t=!0);for(let[r,i]of Object.entries(e.profiles??{})){i.apiKey&&(Pt(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&&an(Qt,`${JSON.stringify(r,null,2)}\n`),r}function Bn(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 Vn(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 Hn=null,Un=null;function E(e){if(e)return Hn&&Un&&Un.apiKey===e.apiKey&&Un.baseUrl===e.baseUrl&&Un.timeout===e.timeout?Hn:(Hn=new m({apiKey:e.apiKey,baseUrl:e.baseUrl,timeoutMs:e.timeout}),Un=e,Hn);if(Hn)return Hn;let t=T({});return Hn=new m({apiKey:t.apiKey,baseUrl:t.baseUrl,timeoutMs:t.timeout}),Un=t,Hn}function Wn(){Hn=null,Un=null}async function Gn(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 Kn(r,n)}function Kn(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(qn(t,s))}function qn(e,t){let n=t.map(e=>`- ${e.id} (provider: ${e.providerId}, account: ${e.accountDisplay??e.displayName})`).join(`
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{agentInteractiveSessionRunRef as a,canonicalAgentProfileDigest as o,modelProvider as s}from"@tangle-network/agent-interface";import{ALL_BACKEND_TYPES as c,AuthError as l,GPU_LEASE_PROVIDER_NAMES as u,NetworkError as d,NotFoundError as f,PublicTemplatePublishError as p,QuotaError as m,Sandbox as h,SandboxError as g,ServerError as ee,StateError as te,TimeoutError as ne,ValidationError as re,createAgentRunOutcomeTracker as ie,createBatchResultAccumulator as ae,createConfidentialSandbox as oe,generateAttestationNonce as se,parseBackendType as ce,parseSSEStream as le,validateBatchRunRequest as _}from"@tangle-network/sandbox";import v from"chalk";import*as y from"node:fs";import{chmodSync as ue,existsSync as de,mkdirSync as fe,readFileSync as b,renameSync as pe,writeFileSync as me}from"node:fs";import*as x from"node:path";import{basename as he,dirname as ge,extname as _e,join as ve,resolve as ye}from"node:path";import*as be from"node:os";import{homedir as xe,tmpdir as Se}from"node:os";import{execFile as Ce,execFileSync as we,spawn as Te}from"node:child_process";import{lockSync as Ee}from"proper-lockfile";import{HubClient as De,HubSdkError as Oe}from"@tangle-network/hub-sdk";import ke from"ora";import{CONTENT_COMPLETION_KEY as Ae,CONTENT_PROMPT_KEY as je,CONTENT_TOOL_ARGS_KEY as Me,CONTENT_TOOL_NAME_KEY as Ne,CONTENT_TOOL_RESULT_KEY as Pe,TANGLE_SUBJECT_KEY as Fe,asContentField as S,asContentString as Ie}from"@tangle-network/agent-core/telemetry";import*as C from"node:fs/promises";import{open as Le,readFile as Re}from"node:fs/promises";import{createMcpServer as ze}from"@tangle-network/sandbox/agent";import{ensureAgentPreview as Be,publishAgentPreview as Ve,resolveSelfSandbox as He}from"@tangle-network/sandbox/preview";import{fileURLToPath as Ue}from"node:url";import{generatePrivateKey as We,privateKeyToAccount as Ge}from"viem/accounts";import{promisify as Ke}from"node:util";import{createPublicClient as qe,createWalletClient as Je,decodeAbiParameters as Ye,decodeEventLog as Xe,encodeAbiParameters as Ze,getAddress as Qe,http as $e,isAddress as et,keccak256 as tt,parseAbi as nt,parseAbiItem as rt,parseAbiParameters as it,stringToHex as at,toHex as ot}from"viem";import{tempoModerato as st}from"viem/chains";import{Actions as ct,withRelay as lt}from"viem/tempo";import ut from"ws";import{createIntelligenceClient as dt}from"@tangle-network/sandbox/intelligence";function ft(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:he(a)}}let t;try{t=b(e,`utf8`)}catch{throw Error(`cannot read skill/tool "${e}": not a readable file and not a github: ref`)}return{kind:`inline`,name:he(e),content:t}}function pt(e){let t=(e.skills??[]).map(ft),n=(e.tools??[]).map(ft),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 mt(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 St(`https://raw.githubusercontent.com/${i[0]}/${i[1]}/${a}/${i.slice(2).join(`/`)}`)}else t=/^https?:\/\//.test(e)?await St(e):b(e,`utf8`);let n;try{n=JSON.parse(t)}catch{throw Error(`profile at "${e}" is not valid JSON`)}return vt(n,e),n}const ht=[`prompt`,`model`,`permissions`,`tools`,`mcp`,`connections`,`subagents`,`resources`,`hooks`,`modes`,`confidential`,`extensions`],gt=new Set([...ht,`name`,`description`,`version`,`tags`,`metadata`]),_t=[`files`,`tools`,`skills`,`agents`,`commands`];function vt(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=>ht.includes(e)),i=n.includes(`name`)&&n.every(e=>gt.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)`}.`);yt(e,t)}function yt(e,t){let n=e.resources;if(!n||typeof n!=`object`)return;for(let e of _t){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)xt(e===`files`?bt(n):n,t)}}let r=n.instructions;r!==void 0&&typeof r!=`string`&&xt(r,t)}function bt(e){return e&&typeof e==`object`?e.resource:e}function xt(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 St(e){let t=await fetch(e);if(!t.ok)throw Error(`failed to fetch ${e} (${t.status})`);return t.text()}async function Ct(e){let t=e.profileSource?await mt(e.profileSource):void 0,n=pt(e);return t?n?{...t,...n,...n.resources?{resources:{...t.resources,...n.resources}}:{}}:t:n}const wt=x.join(be.homedir(),`.tangle`),Tt=x.join(wt,`credentials.json`),Et=`tangle-sandbox-cli`,Dt=new Int32Array(new SharedArrayBuffer(4)),Ot=`TANGLE_ALLOW_PLAINTEXT_CREDENTIALS`;var kt=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)}},At=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 ${Ot}=1 to opt into a plaintext credentials.json with mode 0600.`),this.name=`KeychainUnavailableError`}},jt=class extends Error{constructor(e){super(`Credential storage preflight failed: ${e}`),this.name=`CredentialStorageProbeError`}},Mt=class extends Error{constructor(e){super(`Credential storage is busy. Wait a moment and retry.`),this.name=`CredentialsFileLockedError`,e&&(this.cause=e)}};function Nt(e){let t=Rt(e);if(t)return{value:t,source:`keychain`};let n=Vt(e);return n?{value:n,source:`file`}:{source:`none`}}function Pt(e,t){if(zt(e,t))return Ut(e),`keychain`;if(!Lt())throw new At;return Ht(e,t),`file`}function Ft(){let e=`credential-write-probe:${process.pid}:${i()}`,t=i();if(zt(e,t)){let n=Rt(e);if(!Bt(e))throw new jt(`the OS keychain accepted a test credential but the CLI could not remove it`);if(n!==t)throw new jt(`the OS keychain accepted a test credential but the CLI could not read it back`);return`keychain`}if(!Lt())throw new At;return qt(e),`file`}function It(e){Bt(e),Ut(e)}function Lt(){let e=process.env[Ot];if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function Rt(e){if(process.platform===`darwin`)try{return we(`security`,[`find-generic-password`,`-s`,Et,`-a`,Yt(e),`-w`],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{return}if(process.platform===`linux`)try{return we(`secret-tool`,[`lookup`,`service`,Et,`account`,Yt(e)],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{return}}function zt(e,t){if(process.platform===`darwin`)try{return we(`security`,[`add-generic-password`,`-U`,`-s`,Et,`-a`,Yt(e),`-w`,t],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}if(process.platform===`linux`)try{return we(`secret-tool`,[`store`,`--label=Tangle Sandbox CLI`,`service`,Et,`account`,Yt(e)],{input:t,stdio:[`pipe`,`ignore`,`ignore`]}),!0}catch{return!1}return!1}function Bt(e){if(process.platform===`darwin`)try{return we(`security`,[`delete-generic-password`,`-s`,Et,`-a`,Yt(e)],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}if(process.platform===`linux`)try{return we(`secret-tool`,[`clear`,`service`,Et,`account`,Yt(e)],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}return!1}function Vt(e){return Gt()[e]}function Ht(e,t){Wt(()=>{let n=Gt();n[e]=t,Kt(n)})}function Ut(e){return Wt(()=>{let t;try{t=Gt()}catch(e){if(e instanceof kt)return!1;throw e}return e in t?(delete t[e],Kt(t),Vt(e)===void 0):!0})}function Wt(e){Jt();let t=Date.now()+2e3,n,r;for(;!n;)try{n=Ee(Tt,{realpath:!1,stale:5e3})}catch(e){if(r=e instanceof Error?e:void 0,!e||typeof e!=`object`||!(`code`in e)||e.code!==`ELOCKED`)throw e;if(Date.now()>=t)throw new Mt(r);Atomics.wait(Dt,0,0,20)}try{return e()}finally{n()}}function Gt(){let e;try{e=y.readFileSync(Tt,`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 kt(Tt);let n={};for(let[e,r]of Object.entries(t))typeof r==`string`&&(n[e]=r);return n}catch(e){throw e instanceof kt?e:new kt(Tt,e instanceof Error?e:void 0)}}function Kt(e){if(Jt(),Object.keys(e).length===0){y.existsSync(Tt)&&y.unlinkSync(Tt);return}let t=`${Tt}.${process.pid}.tmp`;y.writeFileSync(t,`${JSON.stringify(e,null,2)}\n`,{mode:384}),y.renameSync(t,Tt)}function qt(e){let t=i(),n=!1,r;try{if(Ht(e,t),n=!0,Vt(e)!==t)throw new jt(`the credentials file did not return the value just written`)}catch(e){r=e}finally{if(n)try{!Ut(e)&&!r&&(r=new jt(`the credentials file accepted a test credential but the CLI could not remove it`))}catch(e){r??=e}}if(r)throw r}function Jt(){if(!y.existsSync(wt)){y.mkdirSync(wt,{mode:448,recursive:!0});return}if(process.platform!==`win32`)try{(y.statSync(wt).mode&511)!=448&&y.chmodSync(wt,448)}catch{}}function Yt(e){return`profile:${e}`}const Xt=x.join(be.homedir(),`.tangle`),Zt=x.join(Xt,`credentials`),Qt=x.join(Xt,`config.json`),$t=`https://id.tangle.tools`,en=`https://solve.tangle.tools/api/solve`,w=`default`;function tn(){return{tangleBaseUrl:process.env.TANGLE_BASE_URL,sandboxBaseUrl:process.env.SANDBOX_BASE_URL,hubUrl:process.env.TANGLE_HUB_URL}}function nn(e,t){let n=E(t??(e===`solve`?`solve`:void 0));if(e===`solve`){if(n!==`solve`)throw Error(`The solve app cannot use profile '${n}'. Use the reserved 'solve' profile.`);return n}if(e===`sandbox`&&!t&&n===`solve`)return w;if(new Set([`solve`]).has(n))throw Error(`The ${e} app cannot use the reserved '${n}' profile. Use the '${e}' profile or choose a custom profile.`);return n}function rn(){y.existsSync(Xt)||y.mkdirSync(Xt,{mode:448,recursive:!0})}function an(e,t){rn();let n=`${e}.${process.pid}.tmp`;y.writeFileSync(n,t,{mode:384}),y.renameSync(n,e)}function on(){try{if(y.existsSync(Zt)){let e=y.readFileSync(Zt,`utf-8`).trim();return sn(e)?e:e.match(/api_key\s*=\s*(\S+)/)?.[1]}}catch{}}function sn(e){return e.startsWith(`sk_`)||e.startsWith(`sk-tan-`)}function cn(){try{y.existsSync(Zt)&&y.unlinkSync(Zt)}catch{}}function T(){return Rn(Ln())}function ln(e){let t=zn(T(),e);an(Qt,`${JSON.stringify(t,null,2)}\n`)}function E(e){return Bn(e||process.env.TANGLE_PROFILE||process.env.SANDBOX_PROFILE||T().activeProfile||w)}function un(e){ln({activeProfile:Bn(e)})}function dn(){return{token:process.env.TANGLE_LINE_TOKEN,baseUrl:process.env.TANGLE_HUB_URL}}function fn(){return process.env.TANGLE_SANDBOX||T().currentSandbox||void 0}function pn(e){ln({currentSandbox:e})}function mn(){let e=T();delete e.currentSandbox,an(Qt,`${JSON.stringify(e,null,2)}\n`)}function hn(){let e=T().deviceId;if(e&&/^[A-Za-z0-9_.-]{1,64}$/.test(e))return e;let t=be.hostname().replace(/[^A-Za-z0-9_.-]/g,`-`).replace(/^-+|-+$/g,``).slice(0,32),n=r(4).toString(`hex`),i=`${t?`${t}-`:`device-`}${n}`;return ln({deviceId:i}),i}function gn(e){let t=e||fn();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 _n(){let e=T(),t=E(),n=new Set([w,...Object.keys(e.profiles??{})]);return e.activeProfile&&n.add(Bn(e.activeProfile)),[...n].map(e=>{let n=Nt(e),r=e===w?on():void 0,i=n.source===`none`?r?`legacy-file`:`none`:n.source;return{name:e,active:e===t,hasApiKey:n.source!==`none`||!!r,baseUrl:Dn(void 0,e),apiKeySource:i}}).sort((e,t)=>e.name.localeCompare(t.name))}function vn(e){let t=E(e);return{name:t,active:t===E(),baseUrl:Dn(void 0,t),credentialSource:En(t)}}function yn(e,t){let n=Bn(e),r=T(),i=In(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=Pt(n,t.apiKey),n===w&&cn()),ln({profiles:Object.keys(l).length>0?l:{}}),u}function bn(e){let t=E(e),n={...T().profiles??{}},r=n[t];if(r){let e={...r,apiKey:void 0};e.baseUrl||e.activeTeamId||e.activeTeamName?n[t]=e:delete n[t]}ln({profiles:n}),It(t),t===w&&cn()}function xn(){let e=process.env.TANGLE_API_KEY_FILE;if(e){let t=y.readFileSync(e,`utf8`).trim();if(!t.startsWith(`sk-tan-`))throw Error(`Invalid sandbox credential file`);return t}return process.env.TANGLE_API_KEY}function Sn(e,t){let n=nn(`sandbox`,t);if(e)return e;let r=xn();if(r)return r;let i=Nt(n);if(i.value)return i.value;if(n===w||n===`sandbox`)return on()}function Cn(e,t){return e||(process.env.TANGLE_SOLVE_API_KEY?process.env.TANGLE_SOLVE_API_KEY:Nt(nn(`solve`,t)).value)}function wn(e,t){let n=nn(`sandbox`,t);return e?`flag`:process.env.TANGLE_API_KEY_FILE||process.env.TANGLE_API_KEY?`env`:En(n)}function Tn(e,t){return e?`flag`:process.env.TANGLE_SOLVE_API_KEY?`env`:Nt(nn(`solve`,t)).source}function En(e){let t=Nt(e);return t.source===`none`?(e===w||e===`sandbox`)&&on()?`legacy-file`:`none`:t.source}function Dn(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=T(),a=In(r,i);return a.baseUrl?a.baseUrl:(r===w||r===`sandbox`)&&i.baseUrl?i.baseUrl:`https://sandbox.tangle.tools`}function On(e){if(e)return e.replace(/\/v1\/hub\/?$/,``)}function kn(e){return e?.trim().replace(/\/+$/,``)||void 0}function An(e){return kn(e?.flag)??kn(On(kn(process.env.TANGLE_HUB_URL)))??kn(process.env.TANGLE_PLATFORM_URL)??kn(e?.cachedPlatformUrl?.())??$t}function jn(e){let t=kn(e)??kn(process.env.TANGLE_SOLVE_API_URL);if(t&&t!==en)throw Error(`Solve credentials may only be sent to ${en}`);return en}function Mn(e){let t=kn(e);if(t&&t!==$t)throw Error(`Solve credentials may only be sent to ${$t}`);return $t}function D(e){let t=nn(`sandbox`,e.profile),n=Sn(e.apiKey,t);if(!n)throw Error(`No API key found for profile '${t}'. Set TANGLE_API_KEY or run: tangle auth login${t===w?``:` --profile ${t}`}`);return{apiKey:n,baseUrl:Dn(e.baseUrl,t),timeout:e.timeout??3e4,profile:t,...Nn(t)}}function Nn(e){let t=T(),n=In(E(e),t);return{activeTeamId:n.activeTeamId,activeTeamName:n.activeTeamName}}function Pn(e,t){yn(E(t),{activeTeamId:e.id,activeTeamName:e.name})}function Fn(e){let t=E(e),n=T(),r={...n.profiles??{}},i={baseUrl:In(t,n).baseUrl};i.baseUrl?r[t]=i:delete r[t],ln({profiles:r})}function In(e,t=T()){let n=Bn(e);return{...n===w?{baseUrl:t.baseUrl,activeTeamId:t.profiles?.[w]?.activeTeamId,activeTeamName:t.profiles?.[w]?.activeTeamName}:{},...t.profiles?.[n]??{}}}function Ln(){try{if(y.existsSync(Qt)){let e=y.readFileSync(Qt,`utf-8`);return JSON.parse(e)}}catch{}return{}}function Rn(e){let t=!1,n={};e.apiKey&&(Pt(w,e.apiKey),cn(),t=!0);for(let[r,i]of Object.entries(e.profiles??{})){i.apiKey&&(Pt(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&&an(Qt,`${JSON.stringify(r,null,2)}\n`),r}function zn(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 Bn(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 O=null,Vn=null;function k(e){if(e)return O&&Vn&&Vn.apiKey===e.apiKey&&Vn.baseUrl===e.baseUrl&&Vn.timeout===e.timeout?O:(O=new h({apiKey:e.apiKey,baseUrl:e.baseUrl,timeoutMs:e.timeout}),Vn=e,O);if(O)return O;let t=D({});return O=new h({apiKey:t.apiKey,baseUrl:t.baseUrl,timeoutMs:t.timeout}),Vn=t,O}function Hn(){O=null,Vn=null}async function Un(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 Wn(r,n)}function Wn(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(Gn(t,s))}function Gn(e,t){let n=t.map(e=>`- ${e.id} (provider: ${e.providerId}, account: ${e.accountDisplay??e.displayName})`).join(`
2
2
  `);return`Hub connection reference is ambiguous: "${e}" matches ${t.length} connections. Use a connection id or provider:account instead.
3
- `+n}function Jn(e,t){return[...t,e]}async function Yn(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:`${Kn(r,e.ref)}:${e.tail}`)}function Xn(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}})}let Zn=!1;function Qn(e){Zn=e}function $n(...e){Zn?console.error(...e):console.log(...e)}function er(e){return e==null?_.dim(`-`):typeof e==`boolean`?e?_.green(`yes`):_.red(`no`):e instanceof Date?nr(e):typeof e==`string`&&tr(e)?nr(new Date(e)):String(e)}function tr(e){return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)}function nr(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 rr(e){switch(e){case`running`:return _.green(e);case`pending`:case`provisioning`:return _.yellow(e);case`stopped`:return _.gray(e);case`failed`:case`deleted`:return _.red(e);default:return e}}function D(e,t){if(e.length===0){console.log(_.dim(`No items found.`));return}let n=t.map(t=>{let n=t.header.length,r=Math.max(...e.map(e=>er(e[t.key]).length));return t.width??Math.max(n,r)+2}),r=t.map((e,t)=>_.bold(e.header.padEnd(n[t]))).join(``);console.log(r);for(let r of e){let e=t.map((e,t)=>{let i=er(r[e.key]);return e.key===`status`&&(i=rr(String(r[e.key]))),i.padEnd(n[t])}).join(``);console.log(e)}}function O(e){console.log(JSON.stringify(e,null,2))}function k(e){$n(_.green(`✓`),e)}function ir(e){console.error(_.red(`✗`),e)}function A(e){$n(_.yellow(`!`),e)}function j(e){$n(_.blue(`→`),e)}const ar=new Set;function M(e){let t=ke({text:e,color:`cyan`,isSilent:Zn});return ar.add(t),t}function or(){for(let e of ar)e.isSpinning&&e.stop();ar.clear()}function N(e,t=0){let n=` `.repeat(t);for(let[t,r]of Object.entries(e))r!=null&&console.log(`${n}${_.dim(`${t}:`)} ${er(r)}`)}function sr(e){let t=`${e.cpuCores} vCPU / ${e.memoryMB} MB / ${e.diskGB} GB`;return e.pool?`${t} (pool: ${e.pool})`:t}function cr(e){if(console.log(),console.log(_.bold(`Sandbox Details`)),console.log(_.dim(`─`.repeat(40))),N({ID:e.id,Name:e.name,Status:rr(e.status),Resources:e.resources?sr(e.resources):void 0,Created:e.createdAt,Expires:e.expiresAt}),e.connection){if(console.log(),console.log(_.bold(`Connection`)),console.log(_.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}`;N({SSH:process.platform===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN='<token>'; ${r}`:`TANGLE_SSH_PROXY_AUTH_TOKEN='<token>' ${r}`})}e.connection.webTerminalUrl&&N({"Web Terminal":e.connection.webTerminalUrl}),e.connection.runtimeUrl&&N({"API URL":e.connection.runtimeUrl})}console.log()}function lr(e,t){or(),t?O({error:e.message}):ir(e.message),process.exit(1)}function ur(e){O(e)}function P(e,t){if(t.length===0){console.log(_.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)=>_.bold(e.padEnd(n[t]))).join(``));for(let e of t)console.log(e.map((e,t)=>String(e??``).padEnd(n[t])).join(``))}function F(e,t=!1){or(),t&&(O(dr(e)),process.exit(xr(e)));let n=fr(e);console.error(_.red(`Error:`),n),process.exit(xr(e))}function dr(e){return e instanceof Oe?{error:{code:e.code,message:e.message,...typeof e.status==`number`?{status:e.status}:{},...e.details===void 0?{}:{details:e.details}}}:br(e)?{error:{code:e.code,message:e.message,status:e.status,...e.details===void 0?{}:{details:e.details}}}:e instanceof f?{error:{code:e.code,message:e.message,...e.status?{status:e.status}:{},...e.job?{job:e.job}:{}}}:e instanceof h&&!(e instanceof u)?{error:{code:e.code,message:e.message,...typeof e.status==`number`?{status:e.status}:{}}}:{error:{message:fr(e)}}}function fr(e){if(e instanceof l)return`Authentication failed. Run 'tangle auth login' to authenticate.`;if(e instanceof d)return`Resource not found. Check the ID and try again.`;if(e instanceof p)return`Quota exceeded. Upgrade your plan or wait for quota reset.`;if(e instanceof ne)return`Invalid input: ${e.message}`;if(e instanceof ee)return`Invalid state: ${e.message}`;if(e instanceof te)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 u)return pr(e);if(e instanceof Oe){let t=typeof e.status==`number`?` (HTTP ${e.status})`:``;return e.code===`HUB_CONNECTION_MISSING`?hr(e.code,t,e.message,e.details):e.code===`HUB_APPROVAL_REQUIRED`?_r(e.code,t,e.message):e.code===`HUB_UNAUTHENTICATED`?yr(e.code,t,e.message):e.code===`HUB_PROVIDER_REJECTED`?vr(e.code,t,e.message,e.details):`${e.code}${t}: ${e.message}`}return br(e)?e.code===`HUB_CONNECTION_MISSING`?hr(e.code,` (HTTP ${e.status})`,e.message,e.details):e.code===`HUB_APPROVAL_REQUIRED`?_r(e.code,` (HTTP ${e.status})`,e.message):e.code===`HUB_UNAUTHENTICATED`?yr(e.code,` (HTTP ${e.status})`,e.message):e.code===`HUB_PROVIDER_REJECTED`?vr(e.code,` (HTTP ${e.status})`,e.message,e.details):`${e.code} (HTTP ${e.status}): ${e.message}`:e instanceof h&&typeof e.status==`number`?`${e.code} (HTTP ${e.status}): ${e.message}`:e instanceof Error?e.message:String(e)}function pr(e){let t=mr(e.cause),n=t&&!e.message.includes(t)?` (${t})`:``;return`Network error: ${e.message}${n}. No response arrived; check your connection and try again.`}function mr(e){let t,n=e;for(let e=0;n instanceof Error&&e<5;e++){let e=n.code,r=n.message||(n instanceof AggregateError?n.errors.map(e=>e instanceof Error?e.message:String(e)).join(`; `):``);typeof e==`string`?t=r?`${e}: ${r}`:e:r&&(t=r),n=n.cause}return t}function hr(e,t,n,r){let i=gr(r);return`${e}${t}: ${n}${i?`. Run: tangle hub connect ${i}`:``}`}function gr(e){if(!e||typeof e!=`object`)return;let t=e.provider;return typeof t==`string`&&t.length>0?t:void 0}function _r(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 vr(e,t,n,r){let i=typeof r==`object`&&r?r.providerRetryable:void 0;return`${e}${t}: ${n}. ${i===!0?`The provider refused this request, but this refusal can clear — the same call may succeed shortly.`:i===!1?`The provider refused this request — retrying it will not help. Change the request, or check that the account may perform this action.`:`The provider refused this request. Check that the request is valid and that the account may perform this action before retrying.`}`}function yr(e,t,n){return`${e}${t}: ${n}. The CLI auto-mints a short-lived platform 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 or TANGLE_HUB_CAPABILITY_TOKEN (and pass --no-hub-key to skip auto-minting).`}function br(e){if(!(e instanceof Error))return!1;let t=e;return typeof t.code==`string`&&t.code.startsWith(`HUB_`)&&typeof t.status==`number`}function xr(e){return e instanceof ne?2:1}function Sr(e,t){return n(`sha256`).update(`${e}\0${t}`).digest(`hex`).slice(0,32)}function Cr(e){return`${e}:hub`}function wr(e){let{value:t}=Nt(Cr(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 Tr(e,t){try{Pt(Cr(e),JSON.stringify(t))}catch{}}async function Er(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 platform 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(`Platform 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(`Platform key minting returned an unexpected response shape.`);return{key:s.api_key,expiresAt:s.expires_at,platformUrl:s.platform_url}}var Dr=class{cache;fingerprint;constructor(e,t,n,r){this.profile=e,this.sandboxBaseUrl=t,this.sessionToken=n,this.deviceId=r,this.fingerprint=Sr(t,n);let i=wr(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 Er(this.sandboxBaseUrl,this.sessionToken,this.deviceId),sessionFingerprint:this.fingerprint};return this.cache=t,Tr(this.profile,t),t}};function Or(e){if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function kr(e,t){return jn({flag:e.baseUrl,...e.useCachedPlatformUrl?{cachedPlatformUrl:()=>wr(t)?.platformUrl}:{}})}function Ar(e,t){let n=nn(`sandbox`,e.profile),r=Cn(e.apiKey,n),i=Tn(e.apiKey,n),a=e.allowHubCapabilityToken&&process.env.TANGLE_HUB_CAPABILITY_TOKEN?.trim()||void 0;if(a&&i===`env`)throw Error(`Set exactly one of TANGLE_API_KEY or TANGLE_HUB_CAPABILITY_TOKEN, not both`);if(i===`flag`&&r)return{kind:`static`,apiKey:r,baseUrl:kr(e,n)};if(i===`env`&&r)return{kind:`static`,apiKey:a??r,baseUrl:kr(e,n)};if(a)return{kind:`static`,apiKey:a,baseUrl:kr(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 r.startsWith(`sk-tan-`)||t?{kind:`static`,apiKey:r,baseUrl:kr(e,n)}:{kind:`managed`,profile:n,sandboxBaseUrl:On(e.sandboxBaseUrl,n),sessionToken:r,deviceId:gn(),baseUrlOverride:e.baseUrl}}async function jr(e={}){let t=Ar(e,e.hubKey===!1||Or(process.env.TANGLE_SKIP_HUB_KEY));if(t.kind===`static`)return{token:t.apiKey,baseUrl:t.baseUrl,minted:!1};let n=new Dr(t.profile,t.sandboxBaseUrl,t.sessionToken,t.deviceId),r=await n.ensure();return{token:r.key,baseUrl:t.baseUrlOverride??r.platformUrl,refresh:async()=>(await n.ensure(!0)).key,minted:!0}}async function Mr(e,t,n={}){let r=e=>{let r=new Headers(n.headers);return r.set(`Authorization`,`Bearer ${e}`),fetch(t,{...n,headers:r})},i=await r(e.token);return i.status!==401||!e.refresh?i:r(await e.refresh())}async function Nr(e={}){let t;try{t=await jr(e)}catch(e){return{reachable:!1,reason:e instanceof Error?e.message:String(e),refused:!0}}try{let e=await Mr(t,`${t.baseUrl.replace(/\/+$/,``)}/v1/plans/current`);if(e.ok)return{reachable:!0,baseUrl:t.baseUrl};let n=e.status===401||e.status===403;return{reachable:!1,baseUrl:t.baseUrl,reason:n?`the platform refused this credential (HTTP ${e.status})`:`the platform answered HTTP ${e.status}`,refused:n}}catch(e){return{reachable:!1,baseUrl:t.baseUrl,reason:`could not reach ${t.baseUrl}: ${e instanceof Error?e.message:String(e)}`,refused:!1}}}async function Pr(e){let t=Ar(e,e.hubKey===!1||Or(process.env.TANGLE_SKIP_HUB_KEY));if(t.kind===`static`)return!e.apiKey&&process.env.TANGLE_API_KEY_FILE&&!process.env.TANGLE_HUB_CAPABILITY_TOKEN?new De({baseUrl:t.baseUrl,authHeaders:()=>({Authorization:`Bearer ${Sn()}`})}):new De({baseUrl:t.baseUrl,apiKey:t.apiKey});let n=new Dr(t.profile,t.sandboxBaseUrl,t.sessionToken,t.deviceId),r=await n.ensure();return new De({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 Fr(e={}){return Pr(e)}function I(e={}){return Pr({...e,useCachedPlatformUrl:!0,allowHubCapabilityToken:!0})}function Ir(e,t){return`Sandbox name is ambiguous: ${e}. Use a sandbox id instead.\n${t.map(e=>`- ${e.id} (status: ${e.status}, created: ${e.createdAt.toISOString()})`).join(`
4
- `)}`}function Lr(e){return e.activeTeamId?`team:${e.activeTeamId}`:void 0}async function L(e,t,n,r={}){if(!r.nameOnly){let t=await e.get(n);if(t)return t;if(zr(n))throw Error(`Sandbox not found: ${n}`)}let i=(await e.list({scope:Lr(t)})).filter(e=>e.name?.toLowerCase()===n.toLowerCase());if(i.length===0)throw Error(`Sandbox not found: ${n}`);if(i.length>1)throw Error(Ir(n,i));return i[0]}const Rr=/^sandbox-(?:(?:(?:[a-z][a-z0-9-]*)-)?(?:[a-f0-9]{12}|[a-f0-9]{8}-[a-f0-9]{3})|l[0-9a-z]{1,8}-[0-9a-f]{8})(?:-branch-[a-z0-9]+-[0-9]+)*$/;function zr(e){return Rr.test(e)}async function Br(e,t,n,r={}){try{return(await(await L(e,t,n,{nameOnly:r.name})).delete()).outcome}catch(e){if(!(e instanceof Error&&e.message===`Sandbox not found: ${n}`)||r.name||!r.retryCleanup&&!zr(n))throw e}let i=await e.fetch(`/v1/sandboxes/${encodeURIComponent(n)}`,{method:`DELETE`});if(i.ok){let e=await i.json().catch(()=>({}));return e.outcome===`destroyed`||e.outcome===`already_absent`?e.outcome:`unknown`}let a=(await i.text()).trim();throw Error(`Sandbox cleanup failed for ${n} (HTTP ${i.status})${a?`: ${a}`:``}`)}async function R(e,t){if(e.status!==`stopped`)return e;let n=t?.resumeTimeoutMs??12e4;j(`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 Vr=[`anthropic`,`openai`,`vercel-ai`,`mastra`,`mcp-local`,`claude-desktop`,`cursor`,`zed`];function Hr(e,t,n){switch(e){case`anthropic`:return`// pnpm add @anthropic-ai/sdk @tangle-network/sandbox
3
+ `+n}function Kn(e,t){return[...t,e]}async function qn(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:`${Wn(r,e.ref)}:${e.tail}`)}function Jn(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}})}let Yn=!1;function Xn(e){Yn=e}function Zn(...e){Yn?console.error(...e):console.log(...e)}function Qn(e){return e==null?v.dim(`-`):typeof e==`boolean`?e?v.green(`yes`):v.red(`no`):e instanceof Date?er(e):typeof e==`string`&&$n(e)?er(new Date(e)):String(e)}function $n(e){return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)}function er(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 tr(e){switch(e){case`running`:return v.green(e);case`pending`:case`provisioning`:return v.yellow(e);case`stopped`:return v.gray(e);case`failed`:case`deleted`:return v.red(e);default:return e}}function A(e,t){if(e.length===0){console.log(v.dim(`No items found.`));return}let n=t.map(t=>{let n=t.header.length,r=Math.max(...e.map(e=>Qn(e[t.key]).length));return t.width??Math.max(n,r)+2}),r=t.map((e,t)=>v.bold(e.header.padEnd(n[t]))).join(``);console.log(r);for(let r of e){let e=t.map((e,t)=>{let i=Qn(r[e.key]);return e.key===`status`&&(i=tr(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){Zn(v.green(`✓`),e)}function nr(e){console.error(v.red(`✗`),e)}function N(e){Zn(v.yellow(`!`),e)}function P(e){Zn(v.blue(`→`),e)}const rr=new Set;function F(e){let t=ke({text:e,color:`cyan`,isSilent:Yn});return rr.add(t),t}function ir(){for(let e of rr)e.isSpinning&&e.stop();rr.clear()}function I(e,t=0){let n=` `.repeat(t);for(let[t,r]of Object.entries(e))r!=null&&console.log(`${n}${v.dim(`${t}:`)} ${Qn(r)}`)}function ar(e){let t=`${e.cpuCores} vCPU / ${e.memoryMB} MB / ${e.diskGB} GB`;return e.pool?`${t} (pool: ${e.pool})`:t}function or(e){if(console.log(),console.log(v.bold(`Sandbox Details`)),console.log(v.dim(`─`.repeat(40))),I({ID:e.id,Name:e.name,Status:tr(e.status),Resources:e.resources?ar(e.resources):void 0,Created:e.createdAt,Expires:e.expiresAt}),e.connection){if(console.log(),console.log(v.bold(`Connection`)),console.log(v.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 sr(e,t){ir(),t?j({error:e.message}):nr(e.message),process.exit(1)}function cr(e){j(e)}function L(e,t){if(t.length===0){console.log(v.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)=>v.bold(e.padEnd(n[t]))).join(``));for(let e of t)console.log(e.map((e,t)=>String(e??``).padEnd(n[t])).join(``))}function R(e,t=!1){ir(),t&&(j(lr(e)),process.exit(yr(e)));let n=ur(e);console.error(v.red(`Error:`),n),process.exit(yr(e))}function lr(e){return e instanceof Oe?{error:{code:e.code,message:e.message,...typeof e.status==`number`?{status:e.status}:{},...e.details===void 0?{}:{details:e.details}}}:vr(e)?{error:{code:e.code,message:e.message,status:e.status,...e.details===void 0?{}:{details:e.details}}}:e instanceof p?{error:{code:e.code,message:e.message,...e.status?{status:e.status}:{},...e.job?{job:e.job}:{}}}:e instanceof g&&!(e instanceof d)?{error:{code:e.code,message:e.message,...typeof e.status==`number`?{status:e.status}:{}}}:{error:{message:ur(e)}}}function ur(e){if(e instanceof l)return`Authentication failed. Run 'tangle auth login' to authenticate.`;if(e instanceof f)return`Resource not found. Check the ID and try again.`;if(e instanceof m)return`Quota exceeded. Upgrade your plan or wait for quota reset.`;if(e instanceof re)return`Invalid input: ${e.message}`;if(e instanceof te)return`Invalid state: ${e.message}`;if(e instanceof ne)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 d)return dr(e);if(e instanceof Oe){let t=typeof e.status==`number`?` (HTTP ${e.status})`:``;return e.code===`HUB_CONNECTION_MISSING`?pr(e.code,t,e.message,e.details):e.code===`HUB_APPROVAL_REQUIRED`?hr(e.code,t,e.message):e.code===`HUB_UNAUTHENTICATED`?_r(e.code,t,e.message):e.code===`HUB_PROVIDER_REJECTED`?gr(e.code,t,e.message,e.details):`${e.code}${t}: ${e.message}`}return vr(e)?e.code===`HUB_CONNECTION_MISSING`?pr(e.code,` (HTTP ${e.status})`,e.message,e.details):e.code===`HUB_APPROVAL_REQUIRED`?hr(e.code,` (HTTP ${e.status})`,e.message):e.code===`HUB_UNAUTHENTICATED`?_r(e.code,` (HTTP ${e.status})`,e.message):e.code===`HUB_PROVIDER_REJECTED`?gr(e.code,` (HTTP ${e.status})`,e.message,e.details):`${e.code} (HTTP ${e.status}): ${e.message}`:e instanceof g&&typeof e.status==`number`?`${e.code} (HTTP ${e.status}): ${e.message}`:e instanceof Error?e.message:String(e)}function dr(e){let t=fr(e.cause),n=t&&!e.message.includes(t)?` (${t})`:``;return`Network error: ${e.message}${n}. No response arrived; check your connection and try again.`}function fr(e){let t,n=e;for(let e=0;n instanceof Error&&e<5;e++){let e=n.code,r=n.message||(n instanceof AggregateError?n.errors.map(e=>e instanceof Error?e.message:String(e)).join(`; `):``);typeof e==`string`?t=r?`${e}: ${r}`:e:r&&(t=r),n=n.cause}return t}function pr(e,t,n,r){let i=mr(r);return`${e}${t}: ${n}${i?`. Run: tangle hub connect ${i}`:``}`}function mr(e){if(!e||typeof e!=`object`)return;let t=e.provider;return typeof t==`string`&&t.length>0?t:void 0}function hr(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 gr(e,t,n,r){let i=typeof r==`object`&&r?r.providerRetryable:void 0;return`${e}${t}: ${n}. ${i===!0?`The provider refused this request, but this refusal can clear — the same call may succeed shortly.`:i===!1?`The provider refused this request — retrying it will not help. Change the request, or check that the account may perform this action.`:`The provider refused this request. Check that the request is valid and that the account may perform this action before retrying.`}`}function _r(e,t,n){return`${e}${t}: ${n}. The CLI auto-mints a short-lived platform 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 or TANGLE_HUB_CAPABILITY_TOKEN (and pass --no-hub-key to skip auto-minting).`}function vr(e){if(!(e instanceof Error))return!1;let t=e;return typeof t.code==`string`&&t.code.startsWith(`HUB_`)&&typeof t.status==`number`}function yr(e){return e instanceof re?2:1}function br(e,t){return n(`sha256`).update(`${e}\0${t}`).digest(`hex`).slice(0,32)}function xr(e){return`${e}:hub`}function Sr(e){let{value:t}=Nt(xr(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 Cr(e,t){try{Pt(xr(e),JSON.stringify(t))}catch{}}async function wr(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 platform 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(`Platform 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(`Platform key minting returned an unexpected response shape.`);return{key:s.api_key,expiresAt:s.expires_at,platformUrl:s.platform_url}}var Tr=class{cache;fingerprint;constructor(e,t,n,r){this.profile=e,this.sandboxBaseUrl=t,this.sessionToken=n,this.deviceId=r,this.fingerprint=br(t,n);let i=Sr(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 wr(this.sandboxBaseUrl,this.sessionToken,this.deviceId),sessionFingerprint:this.fingerprint};return this.cache=t,Cr(this.profile,t),t}};function Er(e){if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function Dr(e,t){return An({flag:e.baseUrl,...e.useCachedPlatformUrl?{cachedPlatformUrl:()=>Sr(t)?.platformUrl}:{}})}function Or(e,t){let n=nn(`sandbox`,e.profile),r=Sn(e.apiKey,n),i=wn(e.apiKey,n),a=e.allowHubCapabilityToken&&process.env.TANGLE_HUB_CAPABILITY_TOKEN?.trim()||void 0;if(a&&i===`env`)throw Error(`Set exactly one of TANGLE_API_KEY or TANGLE_HUB_CAPABILITY_TOKEN, not both`);if(i===`flag`&&r)return{kind:`static`,apiKey:r,baseUrl:Dr(e,n)};if(i===`env`&&r)return{kind:`static`,apiKey:a??r,baseUrl:Dr(e,n)};if(a)return{kind:`static`,apiKey:a,baseUrl:Dr(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 r.startsWith(`sk-tan-`)||t?{kind:`static`,apiKey:r,baseUrl:Dr(e,n)}:{kind:`managed`,profile:n,sandboxBaseUrl:Dn(e.sandboxBaseUrl,n),sessionToken:r,deviceId:hn(),baseUrlOverride:e.baseUrl}}async function kr(e={}){let t=Or(e,e.hubKey===!1||Er(process.env.TANGLE_SKIP_HUB_KEY));if(t.kind===`static`)return{token:t.apiKey,baseUrl:t.baseUrl,minted:!1};let n=new Tr(t.profile,t.sandboxBaseUrl,t.sessionToken,t.deviceId),r=await n.ensure();return{token:r.key,baseUrl:t.baseUrlOverride??r.platformUrl,refresh:async()=>(await n.ensure(!0)).key,minted:!0}}async function Ar(e,t,n={}){let r=e=>{let r=new Headers(n.headers);return r.set(`Authorization`,`Bearer ${e}`),fetch(t,{...n,headers:r})},i=await r(e.token);return i.status!==401||!e.refresh?i:r(await e.refresh())}async function jr(e={}){let t;try{t=await kr(e)}catch(e){return{reachable:!1,reason:e instanceof Error?e.message:String(e),refused:!0}}try{let e=await Ar(t,`${t.baseUrl.replace(/\/+$/,``)}/v1/plans/current`);if(e.ok)return{reachable:!0,baseUrl:t.baseUrl};let n=e.status===401||e.status===403;return{reachable:!1,baseUrl:t.baseUrl,reason:n?`the platform refused this credential (HTTP ${e.status})`:`the platform answered HTTP ${e.status}`,refused:n}}catch(e){return{reachable:!1,baseUrl:t.baseUrl,reason:`could not reach ${t.baseUrl}: ${e instanceof Error?e.message:String(e)}`,refused:!1}}}async function Mr(e){let t=Or(e,e.hubKey===!1||Er(process.env.TANGLE_SKIP_HUB_KEY));if(t.kind===`static`)return!e.apiKey&&process.env.TANGLE_API_KEY_FILE&&!process.env.TANGLE_HUB_CAPABILITY_TOKEN?new De({baseUrl:t.baseUrl,authHeaders:()=>({Authorization:`Bearer ${xn()}`})}):new De({baseUrl:t.baseUrl,apiKey:t.apiKey});let n=new Tr(t.profile,t.sandboxBaseUrl,t.sessionToken,t.deviceId),r=await n.ensure();return new De({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 Nr(e={}){return Mr(e)}function z(e={}){return Mr({...e,useCachedPlatformUrl:!0,allowHubCapabilityToken:!0})}function Pr(e,t){return`Sandbox name is ambiguous: ${e}. Use a sandbox id instead.\n${t.map(e=>`- ${e.id} (status: ${e.status}, created: ${e.createdAt.toISOString()})`).join(`
4
+ `)}`}function Fr(e){return e.activeTeamId?`team:${e.activeTeamId}`:void 0}async function B(e,t,n,r={}){if(!r.nameOnly){let t=await e.get(n);if(t)return t;if(Lr(n))throw Error(`Sandbox not found: ${n}`)}let i=(await e.list({scope:Fr(t)})).filter(e=>e.name?.toLowerCase()===n.toLowerCase());if(i.length===0)throw Error(`Sandbox not found: ${n}`);if(i.length>1)throw Error(Pr(n,i));return i[0]}const Ir=/^sandbox-(?:(?:(?:[a-z][a-z0-9-]*)-)?(?:[a-f0-9]{12}|[a-f0-9]{8}-[a-f0-9]{3})|l[0-9a-z]{1,8}-[0-9a-f]{8})(?:-branch-[a-z0-9]+-[0-9]+)*$/;function Lr(e){return Ir.test(e)}async function Rr(e,t,n,r={}){try{return(await(await B(e,t,n,{nameOnly:r.name})).delete()).outcome}catch(e){if(!(e instanceof Error&&e.message===`Sandbox not found: ${n}`)||r.name||!r.retryCleanup&&!Lr(n))throw e}let i=await e.fetch(`/v1/sandboxes/${encodeURIComponent(n)}`,{method:`DELETE`});if(i.ok){let e=await i.json().catch(()=>({}));return e.outcome===`destroyed`||e.outcome===`already_absent`?e.outcome:`unknown`}let a=(await i.text()).trim();throw Error(`Sandbox cleanup failed for ${n} (HTTP ${i.status})${a?`: ${a}`:``}`)}async function V(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 zr=[`anthropic`,`openai`,`vercel-ai`,`mastra`,`mcp-local`,`claude-desktop`,`cursor`,`zed`];function Br(e,t,n){switch(e){case`anthropic`:return`// pnpm add @anthropic-ai/sdk @tangle-network/sandbox
5
5
  import Anthropic from "@anthropic-ai/sdk";
6
6
  import { Sandbox } from "@tangle-network/sandbox";
7
7
  import { anthropicTools } from "@tangle-network/sandbox/agent";
@@ -121,30 +121,30 @@ await connect(new StdioServerTransport());`;case`claude-desktop`:return`// Add t
121
121
  }
122
122
  }
123
123
  }
124
- }`}}function Ur(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 Wr(){return new t(`connect`).description(`Print a copy-paste SDK integration snippet for one of: ${Vr.join(`, `)} (to stream a local agent's telemetry to Intelligence, see 'tangle connect')`).argument(`<framework>`,Vr.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)=>{Vr.includes(e)||(console.error(_.red(`unknown framework: ${e}`),`\nsupported: ${Vr.join(`, `)}`),process.exit(2));let n=e;process.stdout.write(_.cyan(`# ${Ur(n)}\n\n`)),process.stdout.write(`${Hr(n,t.sandbox,t.session)}\n`)})}async function Gr(e){let{Writable:t}=await import(`node:stream`),n=await import(`node:readline`),r=!1,i=new t({write(e,t,n){r||process.stderr.write(e,t),n()}}),a=n.createInterface({input:process.stdin,output:i,terminal:!0});return process.stderr.write(e),r=!0,await new Promise(e=>{a.question(``,t=>{r=!1,a.close(),process.stderr.write(`
125
- `),e(t.trim())})})}async function z(e,t){let n=(await import(`node:readline`)).createInterface({input:process.stdin,output:process.stderr}),r=await new Promise(t=>{n.once(`close`,()=>t(void 0)),n.question(e,e=>{t(e.trim().toLowerCase()),n.close()})});if(r===void 0)throw process.stderr.write(`
126
- `),Error(t?`No answer on stdin. Pass ${t} to skip the confirmation.`:`No answer on stdin.`);return r===`y`||r===`yes`}async function Kr(e,t){let n=(await import(`node:readline`)).createInterface({input:process.stdin,output:process.stderr}),r=t?` [${t}]`:``;return await new Promise(t=>{n.question(`${e}${r}: `,e=>{n.close(),t(e.trim())})})||t||``}async function qr(e,t=`secret`){if(process.stdin.isTTY)throw Error(e?`${e} reads ${t} from stdin, but stdin is a terminal; pipe it in`:`Cannot read ${t} from stdin when stdin is a TTY`);let n=[];for await(let e of process.stdin)n.push(Buffer.isBuffer(e)?e:Buffer.from(e));return Buffer.concat(n).toString(`utf8`).replace(/\r?\n$/,``)}function Jr(){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 Kr(`Profile name`,`my-agent`),r=await Kr(`Description (optional)`)||void 0,i=await Kr(`Harness`,`claude-code`)||void 0,a=await Kr(`Model (optional, provider/model)`)||void 0,o=await Kr(`System prompt (optional)`)||void 0,s=await Yr(`Skill ref (local path or github:..., blank to finish)`),c=await Yr(`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=pt({model:a,systemPrompt:o,skills:s,tools:c}),u={...n?{name:n}:{},...r?{description:r}:{},...l??{}};if(t.json){O(u);return}let d=e??`agent-profile.json`;me(d,`${JSON.stringify(u,null,2)}\n`),j(`Wrote ${d}`),j(`Run it: tangle agent prompt <box> --profile ${d}${i?` --harness ${i}`:``}`)}catch(e){F(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{O(await mt(e))}catch(e){F(e,!0)}}),e.command(`validate <source>`).description(`Check a profile loads and is a well-formed object`).action(async e=>{try{let t=await mt(e);j(`OK — "${typeof t.name==`string`?t.name:`(unnamed)`}" loaded as a valid profile object`)}catch(e){F(e)}}),e}async function Yr(e){let t=[];for(;;){let n=await Kr(e);if(!n)break;t.push(n)}return t}function Xr(e){return([process.env.SANDBOX_WEB_URL,process.env.TANGLE_SANDBOX_WEB_URL].map(e=>e?.trim()).find(e=>!!e)??e).replace(/\/+$/,``)}function Zr(e,t){if(process.exitCode=1,e.status===`blocked_on_approval`){console.error(_.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(_.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(<questionId>, { ... }).`);return}if(e.status===`awaiting_interaction`){console.error(_.yellow(`⚠ Agent is awaiting a response.`)),console.error(`Open an interactive session, or answer the canonical interaction through the Sandbox SDK.`);return}if(e.status===`awaiting_plan_decision`){console.error(_.yellow(`⚠ Agent is awaiting a plan decision.`)),console.error(`Approve or reject the pending plan before continuing.`);return}console.error(_.red(`✗ ${e.error&&e.error.length>0?e.error:t}`))}function Qr(e){let t=e.part;if(t?.type===`text`)return t.text??t.content??void 0}function $r(e){return e.finalText??e.response??e.output??e.content??e.text??void 0}function ei(e){if(!e.result.success){Zr(e.result,`Agent run failed`);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(_.green(`✓ Done`),_.dim(`(${r.join(`, `)})`))}async function ti(e,t,n=!0){let r=``,i,a=re(),o=e=>{if(e.startsWith(r)){let t=e.slice(r.length);t&&n&&process.stdout.write(t)}else n&&process.stdout.write(e);r=e};try{for await(let t of e)switch(a.observe(t),t.type){case`token`:{let e=t.data?.value;typeof e==`string`&&(n&&process.stdout.write(e),r+=e);break}case`message.part.updated`:{let e=Qr(t.data);typeof e==`string`&&e.length>0&&o(e);break}case`raw`:break;case`result`:i=t.data;break}}catch(e){a.observe({type:`error`,data:{message:e instanceof Error?e.message:String(e)}})}if(r.length===0&&i){let e=$r(i);typeof e==`string`&&e.length>0&&(n&&process.stdout.write(e),r=e)}return{outcome:{result:a.finish(),startedAt:t,tokenUsage:i?.tokenUsage},resultData:i,printed:r.length,...r.length>0?{response:r}:{}}}function ni(e){let t=Xn(e??[]);if(t.length!==0)return{profile:{connections:t}}}function ri(e,t,n,r,i,s){let c={...r??{},harness:n,...i?{model:{...r?.model??{},default:i}}:{}},l={profile:c,requestedProfileDigest:o(c),initialPrompt:s};return{...l,run:a({provider:`tangle-sandbox`,environmentId:e,sessionId:t,executionId:`interactive-execution-${t}`},l)}}async function ii(e){let t=Xn(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 I({hubKey:e.hubKey});for(let r of t){let t=await n.permissions.allowWrites(r.connectionId);e.json||j(`Allowed ${t.writeActions} write action${t.writeActions===1?``:`s`} for connection ${r.connectionId} (${t.granted} newly granted).`)}e.json||j(`Revert anytime: ${t.map(e=>`tangle hub permissions revert-writes --connection ${e.connectionId}`).join(` · `)}`)}async function ai(e){!e.connection||e.connection.length===0||(e.connection=await Yn(e.connection,()=>I({hubKey:e.hubKey})))}async function oi(e,t){let n=process.stdin,r=process.stdout,i=null,a=!1,o=!1,s,c=new Promise(e=>{s=e}),l=()=>{try{n.setRawMode(!1)}catch{}n.pause()},u=()=>{a||(a=!0,l(),n.off(`data`,p),process.off(`SIGWINCH`,f),process.off(`SIGINT`,d),process.off(`SIGTERM`,d),process.off(`exit`,l),s())},d=e=>{(i?.close()??Promise.resolve()).finally(()=>{u(),process.exit(e===`SIGTERM`?143:130)})},f=()=>{i?.isOpen&&i.resize(r.columns||80,r.rows||24)},p=e=>{if(!i)return;let t=e.indexOf(29);if(t===-1){i.write(e);return}t>0&&i.write(e.subarray(0,t)),i.close().finally(u)};if(i=await e.attach({cols:r.columns||80,rows:r.rows||24,handlers:{onData:e=>{r.write(Buffer.from(e.buffer,e.byteOffset,e.byteLength))},onExit:e=>{o=!0;let t=e.exitCode===void 0?``:` (code ${e.exitCode})`;r.write(`\r\n[interactive session exited${t}]\r\n`),i?.close().finally(u)},onError:e=>{r.write(`\r\n[terminal stream error: ${e.message}]\r\n`)},onClose:()=>u()}}),n.setRawMode(!0),n.resume(),n.on(`data`,p),process.on(`SIGWINCH`,f),process.on(`SIGINT`,d),process.on(`SIGTERM`,d),process.on(`exit`,l),await c,console.log(),o){j(`Interactive session ended.`);return}j(`Detached — the session keeps running.`),N({"Watch & drive":t})}function si(){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>`.",Jn,[]).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,a=t===void 0?_n(n.box):e,o=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),s=E(o),c=await Ct({profileSource:n.profile,systemPrompt:n.systemPrompt,skills:n.skills,tools:n.tools});await ai(n);let l=ni(n.connection);n.allowWrites&&await ii(n);let u=c||l?{...c,...l?.profile}:void 0,d=n.harness,f=u||d||n.model?{...d?{type:d}:{},...u?{profile:u}:{},...n.model?{model:{model:n.model}}:{}}:void 0,p=await L(s,o,a);if(p=await R(p),n.interactive){let e=n.session??`int-${i()}`,t=d??(await p.backend.status()).type,s=ri(a,e,t,u,n.model,r),c=p.session(e).interactive(),l=M(`Starting interactive ${t} session...`);l.start();let f;try{f=await c.start(s)}finally{l.stop()}let m=f.ref.preparationReceipt.harness,h=f.state===`running`?f.streamUrl:void 0,g=`${Xr(o.baseUrl)}/dashboard/sandbox/${encodeURIComponent(a)}?interactive=${encodeURIComponent(f.ref.run.sessionId)}`;if(n.json){O({state:f.state,sessionId:f.ref.run.sessionId,harness:m,...h?{streamUrl:h}:{},webUrl:g});return}if(j(`Interactive ${m} session ${f.state}.`),console.log(),N({...f.state===`running`?{"Watch & drive":g}:{},Session:f.ref.run.sessionId}),console.log(),f.state===`exited`){j(`The initial prompt completed with reason: ${f.reason}.`);return}j(`Open the link to watch the agent and type to take over.`),process.stdin.isTTY===!0&&process.stdout.isTTY===!0&&(console.log(),j(`Attaching to the live session — press Ctrl-] to detach.`),await oi(c,g));return}if(n.stream){n.json||(j(`Streaming response...`),console.log());let e=Date.now(),t=await ti(p.streamPrompt(r,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10),...f?{backend:f}:{}}),e,!n.json);n.json?(O({...t.outcome.result,...t.response?{response:t.response}:{},...t.outcome.tokenUsage?{tokenUsage:t.outcome.tokenUsage}:{},durationMs:Date.now()-e}),t.outcome.result.success||(process.exitCode=1)):(t.printed>0&&console.log(),ei(t.outcome))}else{let e=M(`Processing prompt...`);e.start();let t=await p.prompt(r,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10),...f?{backend:f}:{}});e.stop(),n.json?(O(t),t.success===!1&&(process.exitCode=1)):t.success===!1?Zr(t,`Agent prompt failed`):(console.log(t.response),console.log(),N({Duration:`${t.durationMs}ms`,"Input Tokens":t.usage?.inputTokens,"Output Tokens":t.usage?.outputTokens}))}}catch(e){F(e,n.json)}}),e.addCommand(Wr()),e.addCommand(Jr()),e}async function ci(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 ui(n);throw n.status===401||n.status===403?new l(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 l||e instanceof g||e instanceof te?e:e instanceof Error&&e.name===`AbortError`?new te(t,`Timed out validating credentials against ${n}`):e instanceof Error&&!(e instanceof TypeError)?e:new u(`Failed to reach ${n}`,li(e))}}function li(e){return e instanceof Error?e:void 0}async function ui(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 di(e){if(!pi(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 fi(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=di({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(vi(`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(vi(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(vi(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(vi(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 gi(o.toString());e.onLoginUrl?.({loginUrl:o.toString(),browserOpened:s});let u=await hi({baseUrl:n,grantToken:await mi(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 pi(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 mi(e,t){return await new Promise((n,r)=>{let i=setTimeout(()=>{r(new te(t,`Timed out waiting for browser login to complete`))},t);e.then(e=>{clearTimeout(i),n(e)},e=>{clearTimeout(i),r(e)})})}async function hi(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 u(`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 gi(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 _i(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#39;`)}function vi(e){return`<!doctype html>
124
+ }`}}function Vr(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 Hr(){return new t(`connect`).description(`Print a copy-paste SDK integration snippet for one of: ${zr.join(`, `)} (to stream a local agent's telemetry to Intelligence, see 'tangle connect')`).argument(`<framework>`,zr.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)=>{zr.includes(e)||(console.error(v.red(`unknown framework: ${e}`),`\nsupported: ${zr.join(`, `)}`),process.exit(2));let n=e;process.stdout.write(v.cyan(`# ${Vr(n)}\n\n`)),process.stdout.write(`${Br(n,t.sandbox,t.session)}\n`)})}async function Ur(e){let{Writable:t}=await import(`node:stream`),n=await import(`node:readline`),r=!1,i=new t({write(e,t,n){r||process.stderr.write(e,t),n()}}),a=n.createInterface({input:process.stdin,output:i,terminal:!0});return process.stderr.write(e),r=!0,await new Promise(e=>{a.question(``,t=>{r=!1,a.close(),process.stderr.write(`
125
+ `),e(t.trim())})})}async function H(e,t){let n=(await import(`node:readline`)).createInterface({input:process.stdin,output:process.stderr}),r=await new Promise(t=>{n.once(`close`,()=>t(void 0)),n.question(e,e=>{t(e.trim().toLowerCase()),n.close()})});if(r===void 0)throw process.stderr.write(`
126
+ `),Error(t?`No answer on stdin. Pass ${t} to skip the confirmation.`:`No answer on stdin.`);return r===`y`||r===`yes`}async function Wr(e,t){let n=(await import(`node:readline`)).createInterface({input:process.stdin,output:process.stderr}),r=t?` [${t}]`:``;return await new Promise(t=>{n.question(`${e}${r}: `,e=>{n.close(),t(e.trim())})})||t||``}async function Gr(e,t=`secret`){if(process.stdin.isTTY)throw Error(e?`${e} reads ${t} from stdin, but stdin is a terminal; pipe it in`:`Cannot read ${t} from stdin when stdin is a TTY`);let n=[];for await(let e of process.stdin)n.push(Buffer.isBuffer(e)?e:Buffer.from(e));return Buffer.concat(n).toString(`utf8`).replace(/\r?\n$/,``)}function Kr(){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 Wr(`Profile name`,`my-agent`),r=await Wr(`Description (optional)`)||void 0,i=await Wr(`Harness`,`claude-code`)||void 0,a=await Wr(`Model (optional, provider/model)`)||void 0,o=await Wr(`System prompt (optional)`)||void 0,s=await qr(`Skill ref (local path or github:..., blank to finish)`),c=await qr(`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=pt({model:a,systemPrompt:o,skills:s,tools:c}),u={...n?{name:n}:{},...r?{description:r}:{},...l??{}};if(t.json){j(u);return}let d=e??`agent-profile.json`;me(d,`${JSON.stringify(u,null,2)}\n`),P(`Wrote ${d}`),P(`Run it: tangle agent prompt <box> --profile ${d}${i?` --harness ${i}`:``}`)}catch(e){R(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 mt(e))}catch(e){R(e,!0)}}),e.command(`validate <source>`).description(`Check a profile loads and is a well-formed object`).action(async e=>{try{let t=await mt(e);P(`OK — "${typeof t.name==`string`?t.name:`(unnamed)`}" loaded as a valid profile object`)}catch(e){R(e)}}),e}async function qr(e){let t=[];for(;;){let n=await Wr(e);if(!n)break;t.push(n)}return t}function Jr(e){return([process.env.SANDBOX_WEB_URL,process.env.TANGLE_SANDBOX_WEB_URL].map(e=>e?.trim()).find(e=>!!e)??e).replace(/\/+$/,``)}function Yr(e,t){if(process.exitCode=1,e.status===`blocked_on_approval`){console.error(v.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(v.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(<questionId>, { ... }).`);return}if(e.status===`awaiting_interaction`){console.error(v.yellow(`⚠ Agent is awaiting a response.`)),console.error(`Open an interactive session, or answer the canonical interaction through the Sandbox SDK.`);return}if(e.status===`awaiting_plan_decision`){console.error(v.yellow(`⚠ Agent is awaiting a plan decision.`)),console.error(`Approve or reject the pending plan before continuing.`);return}console.error(v.red(`✗ ${e.error&&e.error.length>0?e.error:t}`))}function Xr(e){let t=e.part;if(t?.type===`text`)return t.text??t.content??void 0}function Zr(e){return e.finalText??e.response??e.output??e.content??e.text??void 0}function Qr(e){if(!e.result.success){Yr(e.result,`Agent run failed`);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(v.green(`✓ Done`),v.dim(`(${r.join(`, `)})`))}async function $r(e,t,n=!0){let r=``,i,a=ie(),o=e=>{if(e.startsWith(r)){let t=e.slice(r.length);t&&n&&process.stdout.write(t)}else n&&process.stdout.write(e);r=e};try{for await(let t of e)switch(a.observe(t),t.type){case`token`:{let e=t.data?.value;typeof e==`string`&&(n&&process.stdout.write(e),r+=e);break}case`message.part.updated`:{let e=Xr(t.data);typeof e==`string`&&e.length>0&&o(e);break}case`raw`:break;case`result`:i=t.data;break}}catch(e){a.observe({type:`error`,data:{message:e instanceof Error?e.message:String(e)}})}if(r.length===0&&i){let e=Zr(i);typeof e==`string`&&e.length>0&&(n&&process.stdout.write(e),r=e)}return{outcome:{result:a.finish(),startedAt:t,tokenUsage:i?.tokenUsage},resultData:i,printed:r.length,...r.length>0?{response:r}:{}}}function ei(e){let t=Jn(e??[]);if(t.length!==0)return{profile:{connections:t}}}function ti(e,t,n,r,i,s){let c={...r??{},harness:n,...i?{model:{...r?.model??{},default:i}}:{}},l={profile:c,requestedProfileDigest:o(c),initialPrompt:s};return{...l,run:a({provider:`tangle-sandbox`,environmentId:e,sessionId:t,executionId:`interactive-execution-${t}`},l)}}async function ni(e){let t=Jn(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 z({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 ri(e){!e.connection||e.connection.length===0||(e.connection=await qn(e.connection,()=>z({hubKey:e.hubKey})))}async function ii(e,t){let n=process.stdin,r=process.stdout,i=null,a=!1,o=!1,s,c=new Promise(e=>{s=e}),l=()=>{try{n.setRawMode(!1)}catch{}n.pause()},u=()=>{a||(a=!0,l(),n.off(`data`,p),process.off(`SIGWINCH`,f),process.off(`SIGINT`,d),process.off(`SIGTERM`,d),process.off(`exit`,l),s())},d=e=>{(i?.close()??Promise.resolve()).finally(()=>{u(),process.exit(e===`SIGTERM`?143:130)})},f=()=>{i?.isOpen&&i.resize(r.columns||80,r.rows||24)},p=e=>{if(!i)return;let t=e.indexOf(29);if(t===-1){i.write(e);return}t>0&&i.write(e.subarray(0,t)),i.close().finally(u)};if(i=await e.attach({cols:r.columns||80,rows:r.rows||24,handlers:{onData:e=>{r.write(Buffer.from(e.buffer,e.byteOffset,e.byteLength))},onExit:e=>{o=!0;let t=e.exitCode===void 0?``:` (code ${e.exitCode})`;r.write(`\r\n[interactive session exited${t}]\r\n`),i?.close().finally(u)},onError:e=>{r.write(`\r\n[terminal stream error: ${e.message}]\r\n`)},onClose:()=>u()}}),n.setRawMode(!0),n.resume(),n.on(`data`,p),process.on(`SIGWINCH`,f),process.on(`SIGINT`,d),process.on(`SIGTERM`,d),process.on(`exit`,l),await c,console.log(),o){P(`Interactive session ended.`);return}P(`Detached — the session keeps running.`),I({"Watch & drive":t})}function ai(){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>`.",Kn,[]).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,a=t===void 0?gn(n.box):e,o=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),s=k(o),c=await Ct({profileSource:n.profile,systemPrompt:n.systemPrompt,skills:n.skills,tools:n.tools});await ri(n);let l=ei(n.connection);n.allowWrites&&await ni(n);let u=c||l?{...c,...l?.profile}:void 0,d=n.harness,f=u||d||n.model?{...d?{type:d}:{},...u?{profile:u}:{},...n.model?{model:{model:n.model}}:{}}:void 0,p=await B(s,o,a);if(p=await V(p),n.interactive){let e=n.session??`int-${i()}`,t=d??(await p.backend.status()).type,s=ti(a,e,t,u,n.model,r),c=p.session(e).interactive(),l=F(`Starting interactive ${t} session...`);l.start();let f;try{f=await c.start(s)}finally{l.stop()}let m=f.ref.preparationReceipt.harness,h=f.state===`running`?f.streamUrl:void 0,g=`${Jr(o.baseUrl)}/dashboard/sandbox/${encodeURIComponent(a)}?interactive=${encodeURIComponent(f.ref.run.sessionId)}`;if(n.json){j({state:f.state,sessionId:f.ref.run.sessionId,harness:m,...h?{streamUrl:h}:{},webUrl:g});return}if(P(`Interactive ${m} session ${f.state}.`),console.log(),I({...f.state===`running`?{"Watch & drive":g}:{},Session:f.ref.run.sessionId}),console.log(),f.state===`exited`){P(`The initial prompt completed with reason: ${f.reason}.`);return}P(`Open the link to watch the agent and type to take over.`),process.stdin.isTTY===!0&&process.stdout.isTTY===!0&&(console.log(),P(`Attaching to the live session — press Ctrl-] to detach.`),await ii(c,g));return}if(n.stream){n.json||(P(`Streaming response...`),console.log());let e=Date.now(),t=await $r(p.streamPrompt(r,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10),...f?{backend:f}:{}}),e,!n.json);n.json?(j({...t.outcome.result,...t.response?{response:t.response}:{},...t.outcome.tokenUsage?{tokenUsage:t.outcome.tokenUsage}:{},durationMs:Date.now()-e}),t.outcome.result.success||(process.exitCode=1)):(t.printed>0&&console.log(),Qr(t.outcome))}else{let e=F(`Processing prompt...`);e.start();let t=await p.prompt(r,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10),...f?{backend:f}:{}});e.stop(),n.json?(j(t),t.success===!1&&(process.exitCode=1)):t.success===!1?Yr(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){R(e,n.json)}}),e.addCommand(Hr()),e.addCommand(Kr()),e}async function oi(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 ci(n);throw n.status===401||n.status===403?new l(e||`Invalid API key`):n.status>=500?new ee(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 l||e instanceof ee||e instanceof ne?e:e instanceof Error&&e.name===`AbortError`?new ne(t,`Timed out validating credentials against ${n}`):e instanceof Error&&!(e instanceof TypeError)?e:new d(`Failed to reach ${n}`,si(e))}}function si(e){return e instanceof Error?e:void 0}async function ci(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 li(e){if(!di(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 ui(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=li({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(gi(`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(gi(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(gi(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(gi(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 mi(o.toString());e.onLoginUrl?.({loginUrl:o.toString(),browserOpened:s});let u=await pi({baseUrl:n,grantToken:await fi(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 di(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 fi(e,t){return await new Promise((n,r)=>{let i=setTimeout(()=>{r(new ne(t,`Timed out waiting for browser login to complete`))},t);e.then(e=>{clearTimeout(i),n(e)},e=>{clearTimeout(i),r(e)})})}async function pi(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 d(`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 mi(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 hi(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#39;`)}function gi(e){return`<!doctype html>
127
127
  <html lang="en">
128
128
  <head>
129
129
  <meta charset="utf-8" />
130
130
  <title>Sandbox CLI Login</title>
131
131
  </head>
132
132
  <body>
133
- <p>${e?`Sandbox CLI login failed: ${_i(e)}`:`Sandbox CLI login complete. You can close this window.`}</p>
133
+ <p>${e?`Sandbox CLI login failed: ${hi(e)}`:`Sandbox CLI login complete. You can close this window.`}</p>
134
134
  </body>
135
- </html>`}const yi=15*6e4,bi=`sandbox`;function xi(e){return Number.isFinite(e)&&e>0?e:yi}async function Si(e){let t=e.timeoutMs??yi,n=Date.now(),r=await Ci({baseUrl:e.baseUrl,app:e.app??bi,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 te(t,`Timed out waiting for device authorization to complete`);let i=await wi({baseUrl:e.baseUrl,app:e.app??bi,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 Ci(e){let t=xi(e.timeoutMs),n=e.app!==bi,r=await fetch(`${Ti(e.baseUrl)}${n?`/cross-site/device/start`:`/auth/cli/device/start`}`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify(n?{app:e.app,...e.provider?{provider:e.provider}:{}}:e.provider?{provider:e.provider}:{}),signal:AbortSignal.timeout(t)}).catch(t=>{throw new u(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),i=await r.json().catch(()=>null);if(!r.ok||!i?.success||!i.data?.device_code)throw Error(i?.error?.message||`Failed to start device login`);return i.data}async function wi(e){let t=xi(e.timeoutMs),n=e.app!==bi,r=await fetch(`${Ti(e.baseUrl)}${n?`/cross-site/device/poll`:`/auth/cli/device/poll`}`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify(n?{app:e.app,device_code:e.deviceCode}:{device_code:e.deviceCode}),signal:AbortSignal.timeout(t)}).catch(t=>{throw new u(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),i=await r.json().catch(()=>null);if(r.status===428&&i?.error?.code===`AUTHORIZATION_PENDING`)return{status:`pending`,intervalSeconds:typeof i.data?.interval==`number`&&i.data.interval>0?i.data.interval:5};if(!r.ok||!i?.success||!i.data?.api_key||!i.data.email)throw Error(i?.error?.message||`Failed to complete device authorization`);return{status:`approved`,data:{apiKey:i.data.api_key,email:i.data.email,name:i.data.name,tier:i.data.tier}}}function Ti(e){return e.replace(/\/$/,``)}function Ei(){let e=new t(`auth`).description(`Manage authentication`);e.command(`login`).description(`Authenticate with browser login, device code, 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(`--app <app>`,`Product to authorize (sandbox or solve)`,`sandbox`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=e.apiKey,n=Mi(e.app),r=Ni(n,e.profile),i=ji(e.provider),a=n===`solve`?Nn(e.baseUrl):On(e.baseUrl,r),o=e.browser!==!1;if(t&&!sn(t)){ir(`Invalid API key format. Keys should start with 'sk_' or 'sk-tan-'.`),process.exit(1);return}if(Ft(),!t){if(o&&n===`sandbox`){let o=M(`Starting browser login...`);o.start();let s=await fi({baseUrl:a,provider:i,onLoginUrl:({loginUrl:e,browserOpened:t})=>{o.stop(),j(t?`Browser login opened.`:`Open this URL to continue browser login:`),console.log(e)}}).finally(()=>{o.stop()});t=s.apiKey,Oi({profile:r,apiKey:t,baseUrl:e.baseUrl?a:void 0,activate:n===`sandbox`}),Wn(),k(`Authenticated`),N({Profile:r,Email:s.email,Tier:s.tier,"Base URL":a}),j(ki);return}let s=M(`Starting device login...`);s.start();let c=await Si({baseUrl:a,app:n,provider:i,onInstructions:({userCode:e,verificationUrl:t,verificationUrlComplete:r})=>{s.stop(),j(`Complete login in a browser on any device:`),N({"Verification URL":t,"Verification URL (prefilled)":r,"Device Code":e}),n===`solve`&&o&&gi(r)}}).finally(()=>{s.stop()});t=c.apiKey,Oi({profile:r,apiKey:t,baseUrl:e.baseUrl?a:void 0,activate:n===`sandbox`}),Wn(),k(`Authenticated`),N({Profile:r,Email:c.email,Tier:c.tier,"Base URL":a}),j(ki);return}t||(ir(`No API key provided.`),process.exit(1));let s=M(`Validating credentials...`);s.start();let c=await ci({apiKey:t,baseUrl:a});s.stop(),Oi({profile:r,apiKey:t,baseUrl:e.baseUrl?a:void 0,activate:n===`sandbox`}),Wn(),k(`Authenticated`),N({Profile:r,Email:c.email,Tier:c.tier,"Base URL":a}),j(ki)}catch(e){F(e)}}),e.command(`logout`).description(`Remove stored credentials`).option(`--profile <name>`,`Profile name`).option(`--app <app>`,`Product credentials to remove (sandbox or solve)`,`sandbox`).action(e=>{try{let t=Ni(Mi(e.app),e.profile);xn(t),Wn(),k(`Logged out successfully.`),j(`Credentials removed for profile '${t}'.`)}catch(e){F(e)}}),e.command(`status`).description(`Show current authentication status`).option(`--json`,`Output as JSON`).option(`--profile <name>`,`Profile name`).option(`--app <app>`,`Product credentials to check (sandbox or solve)`,`sandbox`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=Mi(e.app),n=Ni(t,e.profile),r=t===`solve`?wn(e.apiKey,n):Cn(e.apiKey,n),i=t===`solve`?Nn(e.baseUrl):On(e.baseUrl,n),a=t===`solve`?En(e.apiKey,n):Tn(e.apiKey,n);if(!r){if(e.json){O({authenticated:!1,reason:`missing_credentials`,profile:n,baseUrl:i,credentialSource:null});return}ir(`Not authenticated`),j(`Run 'tangle auth login --profile ${n}' to authenticate.`),process.exit(1)}let o=e.json?null:M(`Checking credentials...`);o?.start();try{let s=await ci({apiKey:r,baseUrl:i}),c=t===`solve`?null:await Nr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.profile===void 0?{}:{profile:e.profile},sandboxBaseUrl:i});o?.stop();let l=c!==null&&!c.reachable&&c.refused,u=!l,d=c!==null&&!c.reachable&&!c.refused;if(e.json){O({authenticated:u,profile:n,baseUrl:i,credentialSource:a,account:s,...c?{sandbox:{authenticated:!0},platform:c}:{}}),u||process.exit(1);return}l?A(`Authenticated for sandbox only`):d?A(`Authenticated — the platform is unreachable right now`):k(`Authenticated`),N({Profile:n,Credentials:`configured`,"Base URL":i,Source:Di(a),Email:s.email,Tier:s.tier,...c?{Platform:c.reachable?`reachable (${c.baseUrl})`:`UNREACHABLE — ${c.reason}`}:{}}),d&&j(`Platform commands (keys, workflows, hub) will not work until the platform answers again. The stored credential is not the cause and does not need replacing.`),u||(j("Platform commands (keys, workflows, hub) will not work until this resolves. Set TANGLE_API_KEY to a key you minted in the console, or run `tangle auth login` again."),process.exit(1))}catch(t){o?.stop(),e.json&&(O({authenticated:!1,profile:n,baseUrl:i,credentialSource:a,error:t instanceof Error?t.message:String(t)}),process.exit(1)),t instanceof l?ir(`Stored credentials are invalid.`):A(`Stored credentials found, but validation could not complete.`),N({Profile:n,Credentials:`configured`,"Base URL":i,Source:Di(a),Error:t instanceof Error?t.message:String(t)}),process.exit(1)}}catch(e){F(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=vn();if(e.json){O(t);return}if(t.length===0){j(`No profiles found.`);return}P([`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){F(e)}}),n.command(`use <name>`).description(`Set the active profile`).action(e=>{try{dn(e);let t=yn(e);k(`Active profile set to '${t.name}'.`),N({"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`})}catch(e){F(e)}}),n.command(`current`).description(`Show the active profile`).option(`--json`,`Output as JSON`).action(e=>{try{let t=yn();if(e.json){O({name:t.name,active:t.active,baseUrl:t.baseUrl,credentialSource:t.credentialSource});return}N({Profile:t.name,"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`,Source:Di(t.credentialSource)})}catch(e){F(e)}}),e.addCommand(n),e}function Di(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 Oi(e){let t=bn(e.profile,{apiKey:e.apiKey,...e.baseUrl?{baseUrl:e.baseUrl}:{}});e.activate!==!1&&dn(e.profile),ln(e.baseUrl&&e.profile===`default`?{baseUrl:e.baseUrl}:{}),ki=Ai(e.profile,t)}let ki=`Credentials updated.`;function Ai(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 ji(e){if(e===void 0||e===`github`||e===`google`||e===`microsoft`)return e;throw Error(`--provider must be one of: github, google, microsoft`)}function Mi(e){if(e===void 0||e===`sandbox`||e===`solve`)return e??`sandbox`;throw Error(`--app must be one of: sandbox, solve`)}function Ni(e,t){return nn(e,t)}function Pi(){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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching backend status...`);i.start();let a=await(await L(r,n,e)).backend.status();i.stop(),t.json?O(a):(j(`Backend Type: ${a.type}`),j(`Status: ${a.status}`),a.version&&j(`Version: ${a.version}`),a.error&&j(`Error: ${a.error}`),a.capabilities&&j(`Capabilities: ${JSON.stringify(a.capabilities)}`))}catch(e){F(e)}}),e.command(`configure <sandboxId-or-name>`).description(`Update backend configuration`).option(`--model <model>`,`Model id (e.g. provider/model)`).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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Updating backend config...`);i.start();let a=await L(r,n,e),o=t.model?{model:t.model}:{};await a.backend.updateConfig(o),i.stop(),k(`Backend configuration updated`),t.json&&O(o)}catch(e){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching MCP status...`);i.start();let a=await(await L(r,n,e)).backend.getMcpStatus();if(i.stop(),t.json)O(a);else{let e=Object.entries(a);e.length===0?j(`No MCP servers configured`):D(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){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Restarting backend...`);i.start(),await(await L(r,n,e)).backend.restart(),i.stop(),k(`Backend restarted`)}catch(e){F(e)}}),e}function Fi(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 Ii(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};if(n.context!==void 0&&(typeof n.context!=`object`||n.context===null||Array.isArray(n.context)))throw Error(`--tasks[${t}].context must be a JSON object`);if(n.context!==void 0&&(a.context=n.context),n.timeoutMs!==void 0&&(!Number.isInteger(n.timeoutMs)||n.timeoutMs<=0))throw Error(`--tasks[${t}].timeoutMs must be a positive integer`);return n.timeoutMs!==void 0&&(a.timeoutMs=n.timeoutMs),a})}function Li(e){let t=e.readFile??(e=>y(e,`utf8`)),n=[];e.file&&n.push(...Ii(t(e.file)));for(let t of e.inline??[])n.push(Fi(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}const Ri=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function zi(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 Bi(e){let t=e.indexOf(`=`);if(t<=0||t===e.length-1)throw Error(`Invalid --backend "${e}": expected format id=type (e.g. primary=opencode)`);let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();if(!Ri.test(n))throw Error(`Invalid backend id "${n}": use 1-128 letters, numbers, dots, underscores, or hyphens, starting with a letter or number`);if(!r||r.includes(`=`))throw Error(`Invalid --backend "${e}": type must be a non-empty backend name`);return{id:n,type:r}}function Vi(e,t){if(!e||e.length===0)throw Error(`No backends provided. Use --backend id=type or --request <file>.`);let n=e.map(Bi),r=new Set;for(let e of n){if(r.has(e.id))throw Error(`Duplicate backend id: ${e.id}`);r.add(e.id)}if(t&&n.length!==1)throw Error(`--model requires exactly one backend; use a profile to configure models for multiple backends`);return t&&(n[0]={...n[0],model:zi(t)}),n}function Hi(e){let t;try{t=JSON.parse(e)}catch(e){throw Error(`--request file is not valid JSON: ${e.message}`)}try{return le(t)}catch(e){throw Error(`--request file is not a valid batch request: ${e.message}`)}}function Ui(e,t,n){return n?`${e} [${t}]`:e}function Wi(e){let t=new Map;for(let n of e)t.set(n.taskId,(t.get(n.taskId)??0)+1);return new Set([...t.entries()].filter(([,e])=>e>1).map(([e])=>e))}function Gi(){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(`--request <file>`,`Path to a complete batch request JSON file`).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>`,`Per-task timeout in milliseconds`,`300000`).option(`--persistent`,`Keep sandboxes alive after completion`,!1).option(`--reuse-key <key>`,`Stable workspace identity required by --persistent`).option(`--idempotency-key <key>`,`Retry identity; keyed runs continue after disconnect`).option(`--backend <id=type>`,`Backend identity and type. Required and repeatable without --request.`,(e,t=[])=>[...t,e],[]).option(`--model <provider/model>`,`Model override when exactly one backend is selected`).option(`--json`,`Output the final result as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{let n=new AbortController,r=!1,i=()=>{r||(r=!0,j(`Cancel requested — stopping stream...`),n.abort())};process.on(`SIGINT`,i),process.on(`SIGTERM`,i);try{let r;if(e.request){let n=[`tasks`,`task`,`backend`,`model`,`timeout`,`persistent`,`reuseKey`].filter(e=>t.getOptionValueSource(e)===`cli`);if(n.length>0){let e={reuseKey:`reuse-key`};throw Error(`--request cannot be combined with ${n.map(t=>`--${e[t]??t}`).join(`, `)}`)}r=Hi(y(e.request,`utf8`))}else{let t=Li({file:e.tasks,inline:e.task}),n=Vi(e.backend,e.model),i=Number(e.timeout);if(!Number.isInteger(i)||i<=0)throw Error(`--timeout must be a positive integer number of milliseconds`);let a=!!e.persistent;if(a&&!e.reuseKey)throw Error(`--persistent requires --reuse-key`);if(!a&&e.reuseKey)throw Error(`--reuse-key requires --persistent`);r=le({tasks:t,timeoutMs:i,backends:n,...a?{persistent:!0,reuseKey:e.reuseKey}:{persistent:!1}})}let{tasks:i,backends:a}=r,o=E(T({apiKey:e.apiKey,baseUrl:e.baseUrl})),s={signal:n.signal,...e.idempotencyKey?{idempotencyKey:e.idempotencyKey}:{}};if(e.stream){let t=e.json?console.error:console.log;j(`Streaming batch of ${i.length} task(s)...`),t();let n=ie(r),c=a.length>1;for await(let e of o.streamBatch(r,s))switch(n.add(e),e.type){case`batch.started`:{let t=e.data;j(`Batch started (${t.taskCount} tasks, ${t.backendCount} backends)`);break}case`task.started`:{let n=e.data;t(_.dim(`→ ${Ui(n.taskId,n.backendId,c)} started`));break}case`task.retry`:{let n=e.data;t(_.yellow(`↻ ${Ui(n.taskId,n.backendId,c)} retry ${n.attempt}: ${n.error}`));break}case`task.completed`:{let n=e.data;t(_.green(`✓ ${Ui(n.taskId,n.backendId,c)} completed in ${n.durationMs}ms`+(n.retries?` (${n.retries} retries)`:``)));break}case`task.failed`:{let n=e.data;t(_.red(`✗ ${Ui(n.taskId,n.backendId,c)} failed: ${n.error}`));break}case`batch.completed`:break}let l=n.finish();t(),e.json?O(l):N({"Total tasks":l.totalTasks,"Total backends":l.totalBackends,"Total executions":l.totalExecutions,Succeeded:l.totalSuccess,Failed:l.totalFailure,"Total retries":l.totalRetries,"Success rate":`${l.successRate.toFixed(1)}%`}),l.totalFailure>0&&(process.exitCode=1)}else{j(`Running batch of ${i.length} task(s)...`);let t=await o.runBatch(r,s);if(e.json)O(t);else if(console.log(),N({"Total tasks":t.totalTasks,"Total backends":t.totalBackends,"Total executions":t.totalExecutions,Succeeded:t.totalSuccess,Failed:t.totalFailure,"Total retries":t.totalRetries,"Success rate":`${t.successRate.toFixed(1)}%`}),t.results.length>0){let e=Wi(t.results);console.log(),console.log(_.bold(`Task Results`)),console.log(_.dim(`─`.repeat(40)));for(let n of t.results){let t=n.success?_.green(`✓`):_.red(`✗`),r=n.success?n.usage.inputTokens+n.usage.outputTokens:0,i=r>0?` • ${r} tokens`:``;console.log(`${t} ${Ui(n.taskId,n.backendId,e.has(n.taskId))} ${_.dim(`(${n.durationMs}ms, ${n.retries} retries${i})`)}`),n.success||console.log(_.red(` ${n.error}`))}}t.totalFailure>0&&(process.exitCode=1)}}catch(e){if(r){console.log(),j(`Batch cancelled.`),process.exitCode=130;return}F(e)}finally{process.off(`SIGINT`,i),process.off(`SIGTERM`,i)}}),e}function Ki(){let e=new t(`branch`).description(`Branch a running sandbox into copy-on-write children`);return e.command(`create <sandbox-id-or-name>`).description(`Branch a running sandbox into N copy-on-write children`).option(`--count <n>`,`Number of children to create`,`1`).option(`--idempotency-key <key>`,`Retry identity: the same key and count replays the first fan-out and creates no second 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=Number.parseInt(t.count,10);if(!Number.isInteger(n)||n<1)throw Error(`--count must be an integer >= 1 (got ${t.count})`);let r=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),i=E(r),a=M(`Branching into ${n} child(ren)...`);a.start();let o=await L(i,r,e),s=await o.fork(n,{...t.idempotencyKey?{idempotencyKey:t.idempotencyKey}:{}}),c=s.children;a.stop(),t.json?O({children:c.map(e=>({sandboxId:e.id})),requestedCount:s.requestedCount,materializedCount:s.materializedCount,complete:s.complete,...s.idempotency?{idempotency:s.idempotency}:{}}):(s.complete?k(`Branched ${c.length} child(ren) from ${o.id}`):A(`Branched ${s.materializedCount} of ${s.requestedCount} requested child(ren) from ${o.id}`),s.idempotency?.outcome===`replayed`&&j(`Replayed an earlier fan-out under this key; created none.`),D(c.map(e=>({sandboxId:e.id})),[{key:`sandboxId`,header:`Child Sandbox`,width:28}]))}catch(e){F(e)}}),e}const qi=[`codex`,`claude-code`,`nanoclaw`,`kimi-code`,`opencode`,`pi`,`openclaw`,`hermes`],Ji=`https://intelligence.tangle.tools/v1/otlp`,Yi=[`codex`,`claude-code`],Xi=[`codex`,`claude-code`,`nanoclaw`],Zi=[`SessionStart`,`UserPromptSubmit`,`PreToolUse`,`PostToolUse`,`Stop`],Qi={codex:{kind:`native`,surface:`codex`,label:`Codex`,buildFiles:da},"claude-code":{kind:`native`,surface:`claude-code`,label:`Claude Code`,buildFiles:fa},nanoclaw:{kind:`native`,surface:`nanoclaw`,label:`NanoClaw`,buildFiles:fa},"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 $i(e){let t=e.split(`,`).map(e=>e.trim()).filter(Boolean).flatMap(e=>ua(e));return t.length===0?[...Yi]:Ta(t)}function ea(e){return Object.hasOwn(Qi,e)}function ta(e=process.cwd()){return he(ye(e))||`agent-workspace`}function na(){return ve(xe(),`.tangle`,`intelligence.json`)}function ra(e=na()){if(!de(e))return null;let t=Sa(e),n=Ea(t,`apiKey`),r=Ea(t,`endpoint`),i=Ea(t,`serviceName`),a=Ea(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 ia(e){let t=ye(e.workspace),n=na(),r=$i(e.selection),i=[],a=[],o=[],s={apiKey:e.apiKey,endpoint:B(e.endpoint),serviceName:e.serviceName,environment:e.environment};e.dryRun||ya(n,s),o.push(n);for(let n of r){let r=Qi[n];if(r.kind===`manual`){a.push({agent:r.surface,label:r.label,reason:r.reason});continue}i.push(r.surface);let s=t=>aa(e.hookCommand,r.surface,t);for(let n of r.buildFiles(s)){let r=ve(t,n.relPath);if(e.dryRun){o.push(r);continue}xa(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 sa({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 aa(e,t,n){return`${e.trim()} --agent ${t} --event ${n} --non-blocking`}function oa(e){let t=BigInt(Date.now())*1000000n,n=Oa(16),r=Oa(8),i=e.sessionId??pa(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`,...ma(e.payload)};return i&&(a[`session.id`]=i,a[`gen_ai.conversation.id`]=i,a[`tangle.sessionId`]=i),{body:{resourceSpans:[{resource:{attributes:[ka(`service.name`,e.serviceName),ka(`deployment.environment`,e.environment),ka(`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])=>ka(e,t)),status:{code:1}}]}]}]},traceId:n}}async function sa(e){let{body:t,traceId:n}=oa(e),r=await fetch(`${B(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 ca(e){return B(e).replace(/\/v1\/otlp$/,``).replace(/\/+$/,``)}async function la(e){let t=`${ca(e.endpoint)}/v1/onboarding/status`,n=await fetch(t,{headers:{Authorization:`Bearer ${e.apiKey}`},signal:e.timeoutMs&&e.timeoutMs>0?AbortSignal.timeout(e.timeoutMs):void 0});if(!n.ok){let e=await n.text().catch(()=>``);throw Error(`onboarding status request failed: ${n.status}${e?` ${e}`:``}`)}let r=await n.json();return{tracesSeen:!!r.tracesSeen,contentSeen:!!r.contentSeen,lastSeenAt:typeof r.lastSeenAt==`string`?r.lastSeenAt:null,windowDays:typeof r.windowDays==`number`?r.windowDays:7,byAgent:r.byAgent&&typeof r.byAgent==`object`?r.byAgent:{}}}function B(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 ua(e){switch(e){case`local`:case`both`:return[...Yi];case`all`:return[...Xi];case`claude`:return[`claude-code`];case`kimi`:return[`kimi-code`];default:if(ea(e))return[e];throw Error(`agent must be one of: local, all, both, ${qi.join(`, `)}`)}}function da(e){let t=Object.fromEntries(Zi.map(t=>[t,[{command:e(t),timeoutMs:3e3,blocking:!1,matcher:`*`}]]));return[{relPath:`.codex/hooks.json`,content:JSON.stringify({hooks:t},null,2)}]}function fa(e){let t=Object.fromEntries(Zi.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 pa(e){return ga(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 ma(e){let t={},n=ha(e,[`tool.name`,`toolName`,`tool_name`,`tool`]),r=ha(e,[`command`,`cmd`,`shell_command`,`shellCommand`]),i=ha(e,[`tool.input`,`toolInput`,`tool_input`,`input`,`arguments`,`args`]),a=ha(e,[`tool.output`,`toolOutput`,`tool_output`,`output`,`result`]),o=ha(e,[`tool.exit_code`,`exitCode`,`exit_code`,`status`]),s=ha(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 ha(e,t){let n=_a(e,t);if(n===void 0)return null;if(typeof n==`string`)return va(n);if(typeof n==`number`||typeof n==`boolean`||typeof n==`bigint`)return String(n);try{return va(JSON.stringify(n))}catch{return null}}function ga(e,t){let n=_a(e,t);return typeof n==`string`&&n.length>0?n:void 0}function _a(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 va(e){return e.length>4096?`${e.slice(0,4093)}...`:e}function ya(e,t){ba(e,`${JSON.stringify(t,null,2)}\n`)}function ba(e,t){fe(ge(e),{mode:448,recursive:!0});let n=`${e}.${process.pid}.tmp`;me(n,t,{mode:384}),pe(n,e)}function xa(e,t,n){fe(ge(e),{recursive:!0});let r=Ca(Sa(e),t);me(e,`${JSON.stringify(r,null,2)}\n`,{mode:n??420})}function Sa(e){if(!de(e))return{};let t=JSON.parse(y(e,`utf8`));if(!Da(t))throw Error(`${e} must contain a JSON object`);return t}function Ca(e,t){let n={...e};for(let[e,r]of Object.entries(t)){let t=n[e];Da(t)&&Da(r)?n[e]=Ca(t,r):Array.isArray(t)&&Array.isArray(r)?n[e]=wa([...t,...r]):n[e]=r}return n}function wa(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 Ta(e){return[...new Set(e)]}function Ea(e,t){let n=e[t];return typeof n==`string`&&n.length>0?n:void 0}function Da(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&(Object.getPrototypeOf(e)===Object.prototype||Object.getPrototypeOf(e)===null)}function Oa(e){return r(e).toString(`hex`)}function ka(e,t){return{key:e,value:{stringValue:t}}}const Aa=`tangle.opencode-exporter`,ja=16384;function Ma(e){return e.length<=ja?e:`${e.slice(0,ja-1)}…`}function V(e,t){return{key:e,value:{stringValue:t}}}function Na(e){if(!e||typeof e!=`object`)return null;let t=e,n=x(t.type);return n?{type:n,properties:t.properties&&typeof t.properties==`object`?t.properties:void 0}:null}function Pa(e,t){let n=[V(`event.name`,e),V(`gen_ai.system`,`opencode`),V(`service.name`,`opencode`)];return t&&(n.push(V(`session.id`,t)),n.push(V(`gen_ai.conversation.id`,t))),n}function Fa(e){if(!e)return null;let t=e.part,n=e.info;return x(t?.sessionID)??x(n?.sessionID)??x(e.sessionID)??null}function Ia(e,t){let n=x(e.role)??x(e.info?.role);if(n)return n.toLowerCase();let r=x(e.messageID),i=t?.(r)??null;return i?i.toLowerCase():null}function La(e,t,n){let r=[],i=Fa(e.properties),a=(n,r)=>({timeUnixNano:t,severityNumber:9,severityText:`INFO`,...n===null?{}:{body:{stringValue:Ma(n)}},attributes:[...Pa(e.type,i),...r]});if(e.type===`message.part.updated`){let t=e.properties?.part;if(!t)return r;let i=x(t.type);if(i===`text`||i===`reasoning`){let e=x(t.text);if(e){let i=Ia(t,n)===`user`?je:Ae;r.push(a(e,[V(i,Ma(e))]))}return r}if(i===`tool`){let e=x(t.tool),n=t.state,i=Ie(n?.input),o=Ie(n?.output),s=x(n?.error)??(typeof n?.error==`object`&&n?.error!==null?Ie(n.error):null);if(e||i){let t=[];e&&t.push(V(Ne,e)),i&&t.push(V(Me,Ma(i))),r.push(a(null,t))}let c=o??s;if(c){let t=[V(Pe,Ma(c))];e&&t.push(V(Ne,e)),r.push(a(c,t))}return r}return r}if(e.type===`session.next.text.delta`||e.type===`session.next.text.ended`){let t=e.properties??{},n=x(t.text)??(e.type===`session.next.text.delta`?x(t.delta):null);return n&&r.push(a(n,[V(Ae,Ma(n))])),r}return r}function Ra(e=process.env.OTEL_RESOURCE_ATTRIBUTES){if(!e)return null;for(let t of e.split(`,`)){let e=t.indexOf(`=`);if(e===-1||t.slice(0,e).trim()!==Fe)continue;let n=t.slice(e+1).trim();if(n.length>0)return n}return null}function za(e,t){if(e.length===0)return null;let n=[V(`service.name`,`opencode`),V(`gen_ai.system`,`opencode`),V(`telemetry.sdk.name`,Aa)];return t&&t.trim().length>0&&n.push(V(Fe,t.trim())),{resourceLogs:[{resource:{attributes:n},scopeLogs:[{scope:{name:Aa,version:`1.0.0`},logRecords:e}]}]}}function Ba(e){return(e??process.env.OPENCODE_BASE_URL??`http://127.0.0.1:4096`).replace(/\/+$/,``)}async function Va(e){let t=B(e.endpoint),n=await(e.fetchImpl??fetch)(`${t}/v1/logs`,{method:`POST`,headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":`application/json`},body:JSON.stringify(e.request),signal:e.timeoutMs&&e.timeoutMs>0?AbortSignal.timeout(e.timeoutMs):void 0});if(!n.ok){let e=await n.text().catch(()=>``);throw Error(`OpenCode OTLP logs ingest failed: ${n.status}${e?` ${e}`:``}`)}}var Ha=class extends Error{partial;constructor(e,t){let n=e instanceof Error?e.message:String(e);super(n),this.name=`OpencodeExporterError`,this.partial=t,e instanceof Error&&(this.cause=e)}};function Ua(){return(BigInt(Date.now())*1000000n).toString()}async function Wa(e){let t=Ba(e.opencodeBaseUrl),n=e.nowUnixNano??Ua,r=e.fetchImpl??fetch,i=e.subjectKey===void 0?Ra():e.subjectKey,a=await r(`${t}/event`,{headers:{Accept:`text/event-stream`},signal:e.signal});if(!a.ok){let e=await a.text().catch(()=>``);throw Error(`OpenCode event subscribe failed: ${a.status} at ${t}/event${e?` ${e}`:``}. Is OpenCode running with 'opencode serve'?`)}if(!a.body)throw Error(`OpenCode event stream at ${t}/event returned no body — cannot subscribe`);let o={eventsSeen:0,contentEventsExported:0,recordsExported:0},s=new Map,c=e=>e?s.get(e)??null:null;try{for await(let t of ce(a.body,{signal:e.signal})){o.eventsSeen++;let a=Na(t.data);if(!a)continue;if(a.type===`message.updated`){let e=a.properties?.info,t=x(e?.id),n=x(e?.role);t&&n&&s.set(t,n);continue}let l=La(a,n(),c),u=za(l,i);u&&(await Va({endpoint:e.endpoint,apiKey:e.apiKey,request:u,timeoutMs:e.postTimeoutMs,fetchImpl:r}),o.contentEventsExported++,o.recordsExported+=l.length,e.onExport?.({eventType:a.type,records:l.length}))}}catch(e){if(e instanceof Error&&(e.name===`AbortError`||e.message.toLowerCase().includes(`abort`)))return o;throw new Ha(e,o)}return o}function H(e,t){let n=Number(e);if(!Number.isSafeInteger(n)||n<=0)throw Error(`${t} must be a positive integer`);return n}const Ga=[`claude-code`,`codex`,`opencode`,`openclaw`,`hermes`,`nanoclaw`],Ka={"claude-code":`Claude Code`,codex:`Codex`,opencode:`OpenCode`,openclaw:`OpenClaw`,hermes:`Hermes`,nanoclaw:`NanoClaw`},qa=`# >>> tangle intelligence (claude-code) >>>`,Ja=`# <<< tangle intelligence (claude-code) <<<`;function Ya(e){return Ga.includes(e)}function Xa(e){let t=e??process.env.TANGLE_INTELLIGENCE_API_KEY??Cn(void 0);if(!t)throw Error(`No Tangle API key found. Pass --api-key, set TANGLE_API_KEY, or run: tangle auth login`);return t}const Za={full:[{key:`OTEL_LOG_USER_PROMPTS`,comment:`the user/task prompt text`},{key:`OTEL_LOG_TOOL_DETAILS`,comment:`tool arguments`},{key:`OTEL_LOG_TOOL_CONTENT`,comment:`full tool input+output bodies`},{key:`OTEL_LOG_RAW_API_BODIES`,comment:`full prompt+completion JSON (richest)`}],prompts:[{key:`OTEL_LOG_USER_PROMPTS`,comment:`the user/task prompt text`},{key:`OTEL_LOG_TOOL_DETAILS`,comment:`tool arguments`}],metadata:[]};function Qa(e,t){return t===`env`?e:/\s/.test(e)?`"${e}"`:e}function $a(e,t){let n=t===`shell`?`export `:t===`dockerfile`?`ENV `:``,r=[];for(let i of e){if(i.kind===`blank`){t===`shell`&&r.push(``);continue}if(i.kind===`comment`){t===`shell`&&r.push(`# ${i.text}`);continue}let e=t===`shell`&&i.comment?` # ${i.comment}`:``;r.push(`${n}${i.key}=${Qa(i.value,t)}${e}`)}return r.join(`
136
- `)}function eo(e){let t=B(e.endpoint),n=e.apiKey??"${TANGLE_API_KEY}",r=e.content??`full`,i=e.format??`shell`,a=[{kind:`comment`,text:`Enable + point Claude Code at Tangle (JSON protocol — matches our adapter)`},{kind:`set`,key:`CLAUDE_CODE_ENABLE_TELEMETRY`,value:`1`},{kind:`set`,key:`OTEL_EXPORTER_OTLP_PROTOCOL`,value:`http/json`},{kind:`set`,key:`OTEL_EXPORTER_OTLP_ENDPOINT`,value:t},{kind:`set`,key:`OTEL_EXPORTER_OTLP_HEADERS`,value:`Authorization=Bearer ${n}`}];e.projectKey?a.push({kind:`blank`},{kind:`comment`,text:`Groups your runs into a project so Tangle can roll up + automate per-project:`},{kind:`set`,key:`OTEL_RESOURCE_ATTRIBUTES`,value:`tangle.subject.key=${e.projectKey}`}):a.push({kind:`blank`},{kind:`comment`,text:`Label this project so Tangle rolls up + automates per-project (pick your own):`},{kind:`comment`,text:` export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=<your project>`}),a.push({kind:`blank`},{kind:`comment`,text:`CONTENT rides LOG EVENTS, so the logs exporter is MANDATORY.`},{kind:`set`,key:`OTEL_LOGS_EXPORTER`,value:`otlp`,comment:`required for prompt/completion/tool content`},{kind:`set`,key:`OTEL_METRICS_EXPORTER`,value:`otlp`,comment:`tokens / cost`},{kind:`set`,key:`OTEL_TRACES_EXPORTER`,value:`otlp`,comment:`spans (beta)`},{kind:`blank`});let o=Za[r];if(o.length===0)a.push({kind:`comment`,text:`Content gates intentionally OFF (metadata-only: tokens, durations, tool names — no prompt/completion/tool bodies).`});else{a.push({kind:`comment`,text:`THE CONTENT GATES (all default OFF):`});for(let e of o)a.push({kind:`set`,key:e.key,value:`1`,comment:e.comment})}return $a(a,i)}function to(e){return[qa,eo(e),Ja].join(`
137
- `)}function no(e,t){let n=e.indexOf(qa);if(n!==-1){let r=e.indexOf(Ja,n);if(r===-1)throw Error(`shell rc has a '${qa}' marker without its closing '${Ja}' — fix it by hand and re-run`);let i=r+43,a=`${e.slice(0,n)}${t}${e.slice(i)}`;return{contents:a,changed:a!==e}}return{contents:`${e.length===0?``:ro(e)}${t}\n`,changed:!0}}function ro(e){return e.endsWith(`
135
+ </html>`}const _i=15*6e4,vi=`sandbox`;function yi(e){return Number.isFinite(e)&&e>0?e:_i}async function bi(e){let t=e.timeoutMs??_i,n=Date.now(),r=await xi({baseUrl:e.baseUrl,app:e.app??vi,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 ne(t,`Timed out waiting for device authorization to complete`);let i=await Si({baseUrl:e.baseUrl,app:e.app??vi,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 xi(e){let t=yi(e.timeoutMs),n=e.app!==vi,r=await fetch(`${Ci(e.baseUrl)}${n?`/cross-site/device/start`:`/auth/cli/device/start`}`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify(n?{app:e.app,...e.provider?{provider:e.provider}:{}}:e.provider?{provider:e.provider}:{}),signal:AbortSignal.timeout(t)}).catch(t=>{throw new d(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),i=await r.json().catch(()=>null);if(!r.ok||!i?.success||!i.data?.device_code)throw Error(i?.error?.message||`Failed to start device login`);return i.data}async function Si(e){let t=yi(e.timeoutMs),n=e.app!==vi,r=await fetch(`${Ci(e.baseUrl)}${n?`/cross-site/device/poll`:`/auth/cli/device/poll`}`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify(n?{app:e.app,device_code:e.deviceCode}:{device_code:e.deviceCode}),signal:AbortSignal.timeout(t)}).catch(t=>{throw new d(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),i=await r.json().catch(()=>null);if(r.status===428&&i?.error?.code===`AUTHORIZATION_PENDING`)return{status:`pending`,intervalSeconds:typeof i.data?.interval==`number`&&i.data.interval>0?i.data.interval:5};if(!r.ok||!i?.success||!i.data?.api_key||!i.data.email)throw Error(i?.error?.message||`Failed to complete device authorization`);return{status:`approved`,data:{apiKey:i.data.api_key,email:i.data.email,name:i.data.name,tier:i.data.tier}}}function Ci(e){return e.replace(/\/$/,``)}function wi(){let e=new t(`auth`).description(`Manage authentication`);e.command(`login`).description(`Authenticate with browser login, device code, 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(`--app <app>`,`Product to authorize (sandbox or solve)`,`sandbox`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=e.apiKey,n=Ai(e.app),r=ji(n,e.profile),i=ki(e.provider),a=n===`solve`?Mn(e.baseUrl):Dn(e.baseUrl,r),o=e.browser!==!1;if(t&&!sn(t)){nr(`Invalid API key format. Keys should start with 'sk_' or 'sk-tan-'.`),process.exit(1);return}if(Ft(),!t){if(o&&n===`sandbox`){let o=F(`Starting browser login...`);o.start();let s=await ui({baseUrl:a,provider:i,onLoginUrl:({loginUrl:e,browserOpened:t})=>{o.stop(),P(t?`Browser login opened.`:`Open this URL to continue browser login:`),console.log(e)}}).finally(()=>{o.stop()});t=s.apiKey,Ei({profile:r,apiKey:t,baseUrl:e.baseUrl?a:void 0,activate:n===`sandbox`}),Hn(),M(`Authenticated`),I({Profile:r,Email:s.email,Tier:s.tier,"Base URL":a}),P(Di);return}let s=F(`Starting device login...`);s.start();let c=await bi({baseUrl:a,app:n,provider:i,onInstructions:({userCode:e,verificationUrl:t,verificationUrlComplete:r})=>{s.stop(),P(`Complete login in a browser on any device:`),I({"Verification URL":t,"Verification URL (prefilled)":r,"Device Code":e}),n===`solve`&&o&&mi(r)}}).finally(()=>{s.stop()});t=c.apiKey,Ei({profile:r,apiKey:t,baseUrl:e.baseUrl?a:void 0,activate:n===`sandbox`}),Hn(),M(`Authenticated`),I({Profile:r,Email:c.email,Tier:c.tier,"Base URL":a}),P(Di);return}t||(nr(`No API key provided.`),process.exit(1));let s=F(`Validating credentials...`);s.start();let c=await oi({apiKey:t,baseUrl:a});s.stop(),Ei({profile:r,apiKey:t,baseUrl:e.baseUrl?a:void 0,activate:n===`sandbox`}),Hn(),M(`Authenticated`),I({Profile:r,Email:c.email,Tier:c.tier,"Base URL":a}),P(Di)}catch(e){R(e)}}),e.command(`logout`).description(`Remove stored credentials`).option(`--profile <name>`,`Profile name`).option(`--app <app>`,`Product credentials to remove (sandbox or solve)`,`sandbox`).action(e=>{try{let t=ji(Ai(e.app),e.profile);bn(t),Hn(),M(`Logged out successfully.`),P(`Credentials removed for profile '${t}'.`)}catch(e){R(e)}}),e.command(`status`).description(`Show current authentication status`).option(`--json`,`Output as JSON`).option(`--profile <name>`,`Profile name`).option(`--app <app>`,`Product credentials to check (sandbox or solve)`,`sandbox`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async e=>{try{let t=Ai(e.app),n=ji(t,e.profile),r=t===`solve`?Cn(e.apiKey,n):Sn(e.apiKey,n),i=t===`solve`?Mn(e.baseUrl):Dn(e.baseUrl,n),a=t===`solve`?Tn(e.apiKey,n):wn(e.apiKey,n);if(!r){if(e.json){j({authenticated:!1,reason:`missing_credentials`,profile:n,baseUrl:i,credentialSource:null});return}nr(`Not authenticated`),P(`Run 'tangle auth login --profile ${n}' to authenticate.`),process.exit(1)}let o=e.json?null:F(`Checking credentials...`);o?.start();try{let s=await oi({apiKey:r,baseUrl:i}),c=t===`solve`?null:await jr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.profile===void 0?{}:{profile:e.profile},sandboxBaseUrl:i});o?.stop();let l=c!==null&&!c.reachable&&c.refused,u=!l,d=c!==null&&!c.reachable&&!c.refused;if(e.json){j({authenticated:u,profile:n,baseUrl:i,credentialSource:a,account:s,...c?{sandbox:{authenticated:!0},platform:c}:{}}),u||process.exit(1);return}l?N(`Authenticated for sandbox only`):d?N(`Authenticated — the platform is unreachable right now`):M(`Authenticated`),I({Profile:n,Credentials:`configured`,"Base URL":i,Source:Ti(a),Email:s.email,Tier:s.tier,...c?{Platform:c.reachable?`reachable (${c.baseUrl})`:`UNREACHABLE — ${c.reason}`}:{}}),d&&P(`Platform commands (keys, workflows, hub) will not work until the platform answers again. The stored credential is not the cause and does not need replacing.`),u||(P("Platform commands (keys, workflows, hub) will not work until this resolves. Set TANGLE_API_KEY to a key you minted in the console, or run `tangle auth login` again."),process.exit(1))}catch(t){o?.stop(),e.json&&(j({authenticated:!1,profile:n,baseUrl:i,credentialSource:a,error:t instanceof Error?t.message:String(t)}),process.exit(1)),t instanceof l?nr(`Stored credentials are invalid.`):N(`Stored credentials found, but validation could not complete.`),I({Profile:n,Credentials:`configured`,"Base URL":i,Source:Ti(a),Error:t instanceof Error?t.message:String(t)}),process.exit(1)}}catch(e){R(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=_n();if(e.json){j(t);return}if(t.length===0){P(`No profiles found.`);return}L([`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){R(e)}}),n.command(`use <name>`).description(`Set the active profile`).action(e=>{try{un(e);let t=vn(e);M(`Active profile set to '${t.name}'.`),I({"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`})}catch(e){R(e)}}),n.command(`current`).description(`Show the active profile`).option(`--json`,`Output as JSON`).action(e=>{try{let t=vn();if(e.json){j({name:t.name,active:t.active,baseUrl:t.baseUrl,credentialSource:t.credentialSource});return}I({Profile:t.name,"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`,Source:Ti(t.credentialSource)})}catch(e){R(e)}}),e.addCommand(n),e}function Ti(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 Ei(e){let t=yn(e.profile,{apiKey:e.apiKey,...e.baseUrl?{baseUrl:e.baseUrl}:{}});e.activate!==!1&&un(e.profile),ln(e.baseUrl&&e.profile===`default`?{baseUrl:e.baseUrl}:{}),Di=Oi(e.profile,t)}let Di=`Credentials updated.`;function Oi(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 ki(e){if(e===void 0||e===`github`||e===`google`||e===`microsoft`)return e;throw Error(`--provider must be one of: github, google, microsoft`)}function Ai(e){if(e===void 0||e===`sandbox`||e===`solve`)return e??`sandbox`;throw Error(`--app must be one of: sandbox, solve`)}function ji(e,t){return nn(e,t)}function Mi(){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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching backend status...`);i.start();let a=await(await B(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.capabilities&&P(`Capabilities: ${JSON.stringify(a.capabilities)}`))}catch(e){R(e)}}),e.command(`configure <sandboxId-or-name>`).description(`Update backend configuration`).option(`--model <model>`,`Model id (e.g. provider/model)`).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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Updating backend config...`);i.start();let a=await B(r,n,e),o=t.model?{model:t.model}:{};await a.backend.updateConfig(o),i.stop(),M(`Backend configuration updated`),t.json&&j(o)}catch(e){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching MCP status...`);i.start();let a=await(await B(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){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Restarting backend...`);i.start(),await(await B(r,n,e)).backend.restart(),i.stop(),M(`Backend restarted`)}catch(e){R(e)}}),e}function Ni(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 Pi(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};if(n.context!==void 0&&(typeof n.context!=`object`||n.context===null||Array.isArray(n.context)))throw Error(`--tasks[${t}].context must be a JSON object`);if(n.context!==void 0&&(a.context=n.context),n.timeoutMs!==void 0&&(!Number.isInteger(n.timeoutMs)||n.timeoutMs<=0))throw Error(`--tasks[${t}].timeoutMs must be a positive integer`);return n.timeoutMs!==void 0&&(a.timeoutMs=n.timeoutMs),a})}function Fi(e){let t=e.readFile??(e=>b(e,`utf8`)),n=[];e.file&&n.push(...Pi(t(e.file)));for(let t of e.inline??[])n.push(Ni(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}const Ii=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function Li(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 Ri(e){let t=e.indexOf(`=`);if(t<=0||t===e.length-1)throw Error(`Invalid --backend "${e}": expected format id=type (e.g. primary=opencode)`);let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();if(!Ii.test(n))throw Error(`Invalid backend id "${n}": use 1-128 letters, numbers, dots, underscores, or hyphens, starting with a letter or number`);if(!r||r.includes(`=`))throw Error(`Invalid --backend "${e}": type must be a non-empty backend name`);return{id:n,type:r}}function zi(e,t){if(!e||e.length===0)throw Error(`No backends provided. Use --backend id=type or --request <file>.`);let n=e.map(Ri),r=new Set;for(let e of n){if(r.has(e.id))throw Error(`Duplicate backend id: ${e.id}`);r.add(e.id)}if(t&&n.length!==1)throw Error(`--model requires exactly one backend; use a profile to configure models for multiple backends`);return t&&(n[0]={...n[0],model:Li(t)}),n}function Bi(e){let t;try{t=JSON.parse(e)}catch(e){throw Error(`--request file is not valid JSON: ${e.message}`)}try{return _(t)}catch(e){throw Error(`--request file is not a valid batch request: ${e.message}`)}}function Vi(e,t,n){return n?`${e} [${t}]`:e}function Hi(e){let t=new Map;for(let n of e)t.set(n.taskId,(t.get(n.taskId)??0)+1);return new Set([...t.entries()].filter(([,e])=>e>1).map(([e])=>e))}function Ui(){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(`--request <file>`,`Path to a complete batch request JSON file`).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>`,`Per-task timeout in milliseconds`,`300000`).option(`--persistent`,`Keep sandboxes alive after completion`,!1).option(`--reuse-key <key>`,`Stable workspace identity required by --persistent`).option(`--idempotency-key <key>`,`Retry identity; keyed runs continue after disconnect`).option(`--backend <id=type>`,`Backend identity and type. Required and repeatable without --request.`,(e,t=[])=>[...t,e],[]).option(`--model <provider/model>`,`Model override when exactly one backend is selected`).option(`--json`,`Output the final result as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{let n=new AbortController,r=!1,i=()=>{r||(r=!0,P(`Cancel requested — stopping stream...`),n.abort())};process.on(`SIGINT`,i),process.on(`SIGTERM`,i);try{let r;if(e.request){let n=[`tasks`,`task`,`backend`,`model`,`timeout`,`persistent`,`reuseKey`].filter(e=>t.getOptionValueSource(e)===`cli`);if(n.length>0){let e={reuseKey:`reuse-key`};throw Error(`--request cannot be combined with ${n.map(t=>`--${e[t]??t}`).join(`, `)}`)}r=Bi(b(e.request,`utf8`))}else{let t=Fi({file:e.tasks,inline:e.task}),n=zi(e.backend,e.model),i=Number(e.timeout);if(!Number.isInteger(i)||i<=0)throw Error(`--timeout must be a positive integer number of milliseconds`);let a=!!e.persistent;if(a&&!e.reuseKey)throw Error(`--persistent requires --reuse-key`);if(!a&&e.reuseKey)throw Error(`--reuse-key requires --persistent`);r=_({tasks:t,timeoutMs:i,backends:n,...a?{persistent:!0,reuseKey:e.reuseKey}:{persistent:!1}})}let{tasks:i,backends:a}=r,o=k(D({apiKey:e.apiKey,baseUrl:e.baseUrl})),s={signal:n.signal,...e.idempotencyKey?{idempotencyKey:e.idempotencyKey}:{}};if(e.stream){let t=e.json?console.error:console.log;P(`Streaming batch of ${i.length} task(s)...`),t();let n=ae(r),c=a.length>1;for await(let e of o.streamBatch(r,s))switch(n.add(e),e.type){case`batch.started`:{let t=e.data;P(`Batch started (${t.taskCount} tasks, ${t.backendCount} backends)`);break}case`task.started`:{let n=e.data;t(v.dim(`→ ${Vi(n.taskId,n.backendId,c)} started`));break}case`task.retry`:{let n=e.data;t(v.yellow(`↻ ${Vi(n.taskId,n.backendId,c)} retry ${n.attempt}: ${n.error}`));break}case`task.completed`:{let n=e.data;t(v.green(`✓ ${Vi(n.taskId,n.backendId,c)} completed in ${n.durationMs}ms`+(n.retries?` (${n.retries} retries)`:``)));break}case`task.failed`:{let n=e.data;t(v.red(`✗ ${Vi(n.taskId,n.backendId,c)} failed: ${n.error}`));break}case`batch.completed`:break}let l=n.finish();t(),e.json?j(l):I({"Total tasks":l.totalTasks,"Total backends":l.totalBackends,"Total executions":l.totalExecutions,Succeeded:l.totalSuccess,Failed:l.totalFailure,"Total retries":l.totalRetries,"Success rate":`${l.successRate.toFixed(1)}%`}),l.totalFailure>0&&(process.exitCode=1)}else{P(`Running batch of ${i.length} task(s)...`);let t=await o.runBatch(r,s);if(e.json)j(t);else if(console.log(),I({"Total tasks":t.totalTasks,"Total backends":t.totalBackends,"Total executions":t.totalExecutions,Succeeded:t.totalSuccess,Failed:t.totalFailure,"Total retries":t.totalRetries,"Success rate":`${t.successRate.toFixed(1)}%`}),t.results.length>0){let e=Hi(t.results);console.log(),console.log(v.bold(`Task Results`)),console.log(v.dim(`─`.repeat(40)));for(let n of t.results){let t=n.success?v.green(`✓`):v.red(`✗`),r=n.success?n.usage.inputTokens+n.usage.outputTokens:0,i=r>0?` • ${r} tokens`:``;console.log(`${t} ${Vi(n.taskId,n.backendId,e.has(n.taskId))} ${v.dim(`(${n.durationMs}ms, ${n.retries} retries${i})`)}`),n.success||console.log(v.red(` ${n.error}`))}}t.totalFailure>0&&(process.exitCode=1)}}catch(e){if(r){console.log(),P(`Batch cancelled.`),process.exitCode=130;return}R(e)}finally{process.off(`SIGINT`,i),process.off(`SIGTERM`,i)}}),e}function Wi(){let e=new t(`branch`).description(`Branch a running sandbox into copy-on-write children`);return e.command(`create <sandbox-id-or-name>`).description(`Branch a running sandbox into N copy-on-write children`).option(`--count <n>`,`Number of children to create`,`1`).option(`--idempotency-key <key>`,`Retry identity: the same key and count replays the first fan-out and creates no second 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=Number.parseInt(t.count,10);if(!Number.isInteger(n)||n<1)throw Error(`--count must be an integer >= 1 (got ${t.count})`);let r=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),i=k(r),a=F(`Branching into ${n} child(ren)...`);a.start();let o=await B(i,r,e),s=await o.fork(n,{...t.idempotencyKey?{idempotencyKey:t.idempotencyKey}:{}}),c=s.children;a.stop(),t.json?j({children:c.map(e=>({sandboxId:e.id})),requestedCount:s.requestedCount,materializedCount:s.materializedCount,complete:s.complete,...s.idempotency?{idempotency:s.idempotency}:{}}):(s.complete?M(`Branched ${c.length} child(ren) from ${o.id}`):N(`Branched ${s.materializedCount} of ${s.requestedCount} requested child(ren) from ${o.id}`),s.idempotency?.outcome===`replayed`&&P(`Replayed an earlier fan-out under this key; created none.`),A(c.map(e=>({sandboxId:e.id})),[{key:`sandboxId`,header:`Child Sandbox`,width:28}]))}catch(e){R(e)}}),e}const Gi=[`codex`,`claude-code`,`nanoclaw`,`kimi-code`,`opencode`,`pi`,`openclaw`,`hermes`],Ki=`https://intelligence.tangle.tools/v1/otlp`,qi=[`codex`,`claude-code`],Ji=[`codex`,`claude-code`,`nanoclaw`],Yi=[`SessionStart`,`UserPromptSubmit`,`PreToolUse`,`PostToolUse`,`Stop`],Xi={codex:{kind:`native`,surface:`codex`,label:`Codex`,buildFiles:la},"claude-code":{kind:`native`,surface:`claude-code`,label:`Claude Code`,buildFiles:ua},nanoclaw:{kind:`native`,surface:`nanoclaw`,label:`NanoClaw`,buildFiles:ua},"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 Zi(e){let t=e.split(`,`).map(e=>e.trim()).filter(Boolean).flatMap(e=>ca(e));return t.length===0?[...qi]:Ca(t)}function Qi(e){return Object.hasOwn(Xi,e)}function $i(e=process.cwd()){return he(ye(e))||`agent-workspace`}function ea(){return ve(xe(),`.tangle`,`intelligence.json`)}function ta(e=ea()){if(!de(e))return null;let t=ba(e),n=wa(t,`apiKey`),r=wa(t,`endpoint`),i=wa(t,`serviceName`),a=wa(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 na(e){let t=ye(e.workspace),n=ea(),r=Zi(e.selection),i=[],a=[],o=[],s={apiKey:e.apiKey,endpoint:U(e.endpoint),serviceName:e.serviceName,environment:e.environment};e.dryRun||_a(n,s),o.push(n);for(let n of r){let r=Xi[n];if(r.kind===`manual`){a.push({agent:r.surface,label:r.label,reason:r.reason});continue}i.push(r.surface);let s=t=>ra(e.hookCommand,r.surface,t);for(let n of r.buildFiles(s)){let r=ve(t,n.relPath);if(e.dryRun){o.push(r);continue}ya(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 aa({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 ra(e,t,n){return`${e.trim()} --agent ${t} --event ${n} --non-blocking`}function ia(e){let t=BigInt(Date.now())*1000000n,n=Ea(16),r=Ea(8),i=e.sessionId??da(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`,...fa(e.payload)};return i&&(a[`session.id`]=i,a[`gen_ai.conversation.id`]=i,a[`tangle.sessionId`]=i),{body:{resourceSpans:[{resource:{attributes:[Da(`service.name`,e.serviceName),Da(`deployment.environment`,e.environment),Da(`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])=>Da(e,t)),status:{code:1}}]}]}]},traceId:n}}async function aa(e){let{body:t,traceId:n}=ia(e),r=await fetch(`${U(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 oa(e){return U(e).replace(/\/v1\/otlp$/,``).replace(/\/+$/,``)}async function sa(e){let t=`${oa(e.endpoint)}/v1/onboarding/status`,n=await fetch(t,{headers:{Authorization:`Bearer ${e.apiKey}`},signal:e.timeoutMs&&e.timeoutMs>0?AbortSignal.timeout(e.timeoutMs):void 0});if(!n.ok){let e=await n.text().catch(()=>``);throw Error(`onboarding status request failed: ${n.status}${e?` ${e}`:``}`)}let r=await n.json();return{tracesSeen:!!r.tracesSeen,contentSeen:!!r.contentSeen,lastSeenAt:typeof r.lastSeenAt==`string`?r.lastSeenAt:null,windowDays:typeof r.windowDays==`number`?r.windowDays:7,byAgent:r.byAgent&&typeof r.byAgent==`object`?r.byAgent:{}}}function U(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 ca(e){switch(e){case`local`:case`both`:return[...qi];case`all`:return[...Ji];case`claude`:return[`claude-code`];case`kimi`:return[`kimi-code`];default:if(Qi(e))return[e];throw Error(`agent must be one of: local, all, both, ${Gi.join(`, `)}`)}}function la(e){let t=Object.fromEntries(Yi.map(t=>[t,[{command:e(t),timeoutMs:3e3,blocking:!1,matcher:`*`}]]));return[{relPath:`.codex/hooks.json`,content:JSON.stringify({hooks:t},null,2)}]}function ua(e){let t=Object.fromEntries(Yi.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 da(e){return ma(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 fa(e){let t={},n=pa(e,[`tool.name`,`toolName`,`tool_name`,`tool`]),r=pa(e,[`command`,`cmd`,`shell_command`,`shellCommand`]),i=pa(e,[`tool.input`,`toolInput`,`tool_input`,`input`,`arguments`,`args`]),a=pa(e,[`tool.output`,`toolOutput`,`tool_output`,`output`,`result`]),o=pa(e,[`tool.exit_code`,`exitCode`,`exit_code`,`status`]),s=pa(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 pa(e,t){let n=ha(e,t);if(n===void 0)return null;if(typeof n==`string`)return ga(n);if(typeof n==`number`||typeof n==`boolean`||typeof n==`bigint`)return String(n);try{return ga(JSON.stringify(n))}catch{return null}}function ma(e,t){let n=ha(e,t);return typeof n==`string`&&n.length>0?n:void 0}function ha(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 ga(e){return e.length>4096?`${e.slice(0,4093)}...`:e}function _a(e,t){va(e,`${JSON.stringify(t,null,2)}\n`)}function va(e,t){fe(ge(e),{mode:448,recursive:!0});let n=`${e}.${process.pid}.tmp`;me(n,t,{mode:384}),pe(n,e)}function ya(e,t,n){fe(ge(e),{recursive:!0});let r=xa(ba(e),t);me(e,`${JSON.stringify(r,null,2)}\n`,{mode:n??420})}function ba(e){if(!de(e))return{};let t=JSON.parse(b(e,`utf8`));if(!Ta(t))throw Error(`${e} must contain a JSON object`);return t}function xa(e,t){let n={...e};for(let[e,r]of Object.entries(t)){let t=n[e];Ta(t)&&Ta(r)?n[e]=xa(t,r):Array.isArray(t)&&Array.isArray(r)?n[e]=Sa([...t,...r]):n[e]=r}return n}function Sa(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 Ca(e){return[...new Set(e)]}function wa(e,t){let n=e[t];return typeof n==`string`&&n.length>0?n:void 0}function Ta(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&(Object.getPrototypeOf(e)===Object.prototype||Object.getPrototypeOf(e)===null)}function Ea(e){return r(e).toString(`hex`)}function Da(e,t){return{key:e,value:{stringValue:t}}}const Oa=`tangle.opencode-exporter`,ka=16384;function Aa(e){return e.length<=ka?e:`${e.slice(0,ka-1)}…`}function W(e,t){return{key:e,value:{stringValue:t}}}function ja(e){if(!e||typeof e!=`object`)return null;let t=e,n=S(t.type);return n?{type:n,properties:t.properties&&typeof t.properties==`object`?t.properties:void 0}:null}function Ma(e,t){let n=[W(`event.name`,e),W(`gen_ai.system`,`opencode`),W(`service.name`,`opencode`)];return t&&(n.push(W(`session.id`,t)),n.push(W(`gen_ai.conversation.id`,t))),n}function Na(e){if(!e)return null;let t=e.part,n=e.info;return S(t?.sessionID)??S(n?.sessionID)??S(e.sessionID)??null}function Pa(e,t){let n=S(e.role)??S(e.info?.role);if(n)return n.toLowerCase();let r=S(e.messageID),i=t?.(r)??null;return i?i.toLowerCase():null}function Fa(e,t,n){let r=[],i=Na(e.properties),a=(n,r)=>({timeUnixNano:t,severityNumber:9,severityText:`INFO`,...n===null?{}:{body:{stringValue:Aa(n)}},attributes:[...Ma(e.type,i),...r]});if(e.type===`message.part.updated`){let t=e.properties?.part;if(!t)return r;let i=S(t.type);if(i===`text`||i===`reasoning`){let e=S(t.text);if(e){let i=Pa(t,n)===`user`?je:Ae;r.push(a(e,[W(i,Aa(e))]))}return r}if(i===`tool`){let e=S(t.tool),n=t.state,i=Ie(n?.input),o=Ie(n?.output),s=S(n?.error)??(typeof n?.error==`object`&&n?.error!==null?Ie(n.error):null);if(e||i){let t=[];e&&t.push(W(Ne,e)),i&&t.push(W(Me,Aa(i))),r.push(a(null,t))}let c=o??s;if(c){let t=[W(Pe,Aa(c))];e&&t.push(W(Ne,e)),r.push(a(c,t))}return r}return r}if(e.type===`session.next.text.delta`||e.type===`session.next.text.ended`){let t=e.properties??{},n=S(t.text)??(e.type===`session.next.text.delta`?S(t.delta):null);return n&&r.push(a(n,[W(Ae,Aa(n))])),r}return r}function Ia(e=process.env.OTEL_RESOURCE_ATTRIBUTES){if(!e)return null;for(let t of e.split(`,`)){let e=t.indexOf(`=`);if(e===-1||t.slice(0,e).trim()!==Fe)continue;let n=t.slice(e+1).trim();if(n.length>0)return n}return null}function La(e,t){if(e.length===0)return null;let n=[W(`service.name`,`opencode`),W(`gen_ai.system`,`opencode`),W(`telemetry.sdk.name`,Oa)];return t&&t.trim().length>0&&n.push(W(Fe,t.trim())),{resourceLogs:[{resource:{attributes:n},scopeLogs:[{scope:{name:Oa,version:`1.0.0`},logRecords:e}]}]}}function Ra(e){return(e??process.env.OPENCODE_BASE_URL??`http://127.0.0.1:4096`).replace(/\/+$/,``)}async function za(e){let t=U(e.endpoint),n=await(e.fetchImpl??fetch)(`${t}/v1/logs`,{method:`POST`,headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":`application/json`},body:JSON.stringify(e.request),signal:e.timeoutMs&&e.timeoutMs>0?AbortSignal.timeout(e.timeoutMs):void 0});if(!n.ok){let e=await n.text().catch(()=>``);throw Error(`OpenCode OTLP logs ingest failed: ${n.status}${e?` ${e}`:``}`)}}var Ba=class extends Error{partial;constructor(e,t){let n=e instanceof Error?e.message:String(e);super(n),this.name=`OpencodeExporterError`,this.partial=t,e instanceof Error&&(this.cause=e)}};function Va(){return(BigInt(Date.now())*1000000n).toString()}async function Ha(e){let t=Ra(e.opencodeBaseUrl),n=e.nowUnixNano??Va,r=e.fetchImpl??fetch,i=e.subjectKey===void 0?Ia():e.subjectKey,a=await r(`${t}/event`,{headers:{Accept:`text/event-stream`},signal:e.signal});if(!a.ok){let e=await a.text().catch(()=>``);throw Error(`OpenCode event subscribe failed: ${a.status} at ${t}/event${e?` ${e}`:``}. Is OpenCode running with 'opencode serve'?`)}if(!a.body)throw Error(`OpenCode event stream at ${t}/event returned no body — cannot subscribe`);let o={eventsSeen:0,contentEventsExported:0,recordsExported:0},s=new Map,c=e=>e?s.get(e)??null:null;try{for await(let t of le(a.body,{signal:e.signal})){o.eventsSeen++;let a=ja(t.data);if(!a)continue;if(a.type===`message.updated`){let e=a.properties?.info,t=S(e?.id),n=S(e?.role);t&&n&&s.set(t,n);continue}let l=Fa(a,n(),c),u=La(l,i);u&&(await za({endpoint:e.endpoint,apiKey:e.apiKey,request:u,timeoutMs:e.postTimeoutMs,fetchImpl:r}),o.contentEventsExported++,o.recordsExported+=l.length,e.onExport?.({eventType:a.type,records:l.length}))}}catch(e){if(e instanceof Error&&(e.name===`AbortError`||e.message.toLowerCase().includes(`abort`)))return o;throw new Ba(e,o)}return o}function Ua(e,t){let n=Number(e);if(!Number.isSafeInteger(n)||n<=0)throw Error(`${t} must be a positive integer`);return n}const Wa=[`claude-code`,`codex`,`opencode`,`openclaw`,`hermes`,`nanoclaw`],Ga={"claude-code":`Claude Code`,codex:`Codex`,opencode:`OpenCode`,openclaw:`OpenClaw`,hermes:`Hermes`,nanoclaw:`NanoClaw`};function Ka(e){return Wa.includes(e)}function qa(e){return de(e)?b(e,`utf8`):``}function Ja(e,t){fe(ge(e),{recursive:!0});let n=`${e}.${process.pid}.tmp`;me(n,t,{mode:384}),ue(n,384),pe(n,e)}const Ya=`# >>> tangle intelligence (claude-code) >>>`,Xa=`# <<< tangle intelligence (claude-code) <<<`,Za={full:[{key:`OTEL_LOG_USER_PROMPTS`,comment:`the user/task prompt text`},{key:`OTEL_LOG_TOOL_DETAILS`,comment:`tool arguments`},{key:`OTEL_LOG_TOOL_CONTENT`,comment:`full tool input+output bodies`},{key:`OTEL_LOG_RAW_API_BODIES`,comment:`full prompt+completion JSON (richest)`}],prompts:[{key:`OTEL_LOG_USER_PROMPTS`,comment:`the user/task prompt text`},{key:`OTEL_LOG_TOOL_DETAILS`,comment:`tool arguments`}],metadata:[]};function Qa(e,t){return t===`env`?e:/\s/.test(e)?`"${e}"`:e}function $a(e,t){let n=t===`shell`?`export `:t===`dockerfile`?`ENV `:``,r=[];for(let i of e){if(i.kind===`blank`){t===`shell`&&r.push(``);continue}if(i.kind===`comment`){t===`shell`&&r.push(`# ${i.text}`);continue}let e=t===`shell`&&i.comment?` # ${i.comment}`:``;r.push(`${n}${i.key}=${Qa(i.value,t)}${e}`)}return r.join(`
136
+ `)}function eo(e){let t=U(e.endpoint),n=e.apiKey??"${TANGLE_API_KEY}",r=e.content??`full`,i=e.format??`shell`,a=[{kind:`comment`,text:`Enable + point Claude Code at Tangle (JSON protocol — matches our adapter)`},{kind:`set`,key:`CLAUDE_CODE_ENABLE_TELEMETRY`,value:`1`},{kind:`set`,key:`OTEL_EXPORTER_OTLP_PROTOCOL`,value:`http/json`},{kind:`set`,key:`OTEL_EXPORTER_OTLP_ENDPOINT`,value:t},{kind:`set`,key:`OTEL_EXPORTER_OTLP_HEADERS`,value:`Authorization=Bearer ${n}`}];e.projectKey?a.push({kind:`blank`},{kind:`comment`,text:`Groups your runs into a project so Tangle can roll up + automate per-project:`},{kind:`set`,key:`OTEL_RESOURCE_ATTRIBUTES`,value:`tangle.subject.key=${e.projectKey}`}):a.push({kind:`blank`},{kind:`comment`,text:`Label this project so Tangle rolls up + automates per-project (pick your own):`},{kind:`comment`,text:` export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=<your project>`}),a.push({kind:`blank`},{kind:`comment`,text:`CONTENT rides LOG EVENTS, so the logs exporter is MANDATORY.`},{kind:`set`,key:`OTEL_LOGS_EXPORTER`,value:`otlp`,comment:`required for prompt/completion/tool content`},{kind:`set`,key:`OTEL_METRICS_EXPORTER`,value:`otlp`,comment:`tokens / cost`},{kind:`set`,key:`OTEL_TRACES_EXPORTER`,value:`otlp`,comment:`spans (beta)`},{kind:`blank`});let o=Za[r];if(o.length===0)a.push({kind:`comment`,text:`Content gates intentionally OFF (metadata-only: tokens, durations, tool names — no prompt/completion/tool bodies).`});else{a.push({kind:`comment`,text:`THE CONTENT GATES (all default OFF):`});for(let e of o)a.push({kind:`set`,key:e.key,value:`1`,comment:e.comment})}return $a(a,i)}function to(e){return[Ya,eo(e),Xa].join(`
137
+ `)}function no(e,t){let n=e.indexOf(Ya);if(n!==-1){let r=e.indexOf(Xa,n);if(r===-1)throw Error(`shell rc has a '${Ya}' marker without its closing '${Xa}' — fix it by hand and re-run`);let i=r+43,a=`${e.slice(0,n)}${t}${e.slice(i)}`;return{contents:a,changed:a!==e}}return{contents:`${e.length===0?``:ro(e)}${t}\n`,changed:!0}}function ro(e){return e.endsWith(`
138
138
 
139
139
  `)?e:e.endsWith(`
140
- `)?`${e}\n`:`${e}\n\n`}function io(e){let t=[],n={header:null,body:[]};for(let r of e.split(`
141
- `))ao(r)?(t.push(n),n={header:r.trim(),body:[]}):n.body.push(r);return t.push(n),t.length>1&&t[0].header===null&&t[0].body.every(e=>e.trim()===``)&&t.shift(),t}function ao(e){let t=e.trim();return t.startsWith(`[`)&&t.endsWith(`]`)&&!t.includes(`=`)||t.startsWith(`[[`)&&t.endsWith(`]]`)}function oo(e){let t=[];for(let n of e)n.header!==null&&t.push(n.header),t.push(...n.body);return t.join(`
142
- `)}function so(e){return[{key:`environment`,line:`environment = "prod"`},{key:`log_user_prompt`,line:`log_user_prompt = true`},{key:`exporter`,line:`exporter = { otlp-http = { endpoint = "${B(e.endpoint)}/v1/logs", protocol = "json", headers = { "Authorization" = "Bearer ${e.apiKey??"${TANGLE_API_KEY}"}" } } }`}]}function co(e){let t=e.trim();if(t===``||t.startsWith(`#`))return null;let n=t.indexOf(`=`);if(n===-1)return null;let r=t.slice(0,n).trim();return/^[A-Za-z0-9_-]+$/.test(r)?r:null}function lo(e,t){let n=so(t),r=new Set(n.map(e=>e.key));if(e.trim()===``)return{contents:`${[`[otel]`,...n.map(e=>e.line)].join(`
143
- `)}\n`,changed:!0};let i=io(e),a=i.find(e=>e.header===`[otel]`);if(!a){let t={header:`[otel]`,body:n.map(e=>e.line)},r=i[i.length-1];r&&!uo(r)&&r.body.push(``),i.push(t);let a=fo(oo(i));return{contents:a,changed:a!==fo(e)}}let o=a.body.filter(e=>{let t=co(e);return t===null||!r.has(t)}),s=[];for(;o.length>0&&o[o.length-1].trim()===``;)s.unshift(o.pop());a.body=[...o,...n.map(e=>e.line),...s];let c=fo(oo(i));return{contents:c,changed:c!==fo(e)}}function uo(e){return e.body.length>0&&e.body[e.body.length-1].trim()===``}function fo(e){return e.endsWith(`
144
- `)?e:`${e}\n`}function po(e){switch(e){case`claude-code`:return`Claude Code: set OTEL_LOGS_EXPORTER=otlp and the four OTEL_LOG_* gates (OTEL_LOG_USER_PROMPTS, OTEL_LOG_TOOL_DETAILS, OTEL_LOG_TOOL_CONTENT, OTEL_LOG_RAW_API_BODIES).`;case`codex`:return`Codex: set log_user_prompt = true in [otel] (default false redacts content).`;case`opencode`:return`OpenCode: a standalone install emits nothing without the tangle-opencode-exporter shim; inside a Tangle sandbox it is already instrumented.`;case`openclaw`:case`hermes`:case`nanoclaw`:return`${Ka[e]}: no native OTLP exporter and no standalone server to subscribe to — run it inside a Tangle sandbox, where the sidecar adapter exports its content with gen_ai.system=${e}. A bare standalone install emits metadata only.`}}function mo(){let e=process.env.SHELL??``;return e.includes(`zsh`)?ve(xe(),`.zshrc`):e.includes(`bash`)?ve(xe(),`.bashrc`):ve(xe(),`.zshrc`)}function ho(e){return de(e)?y(e,`utf8`):``}function go(e,t){fe(ge(e),{recursive:!0});let n=`${e}.${process.pid}.tmp`;me(n,t,{mode:384}),ue(n,384),pe(n,e)}function _o(){return new t(`connect`).description(`Connect a local coding agent's telemetry to Tangle Intelligence, content on (for SDK integration snippets, see 'tangle agent connect')`).argument(`[agent]`,`claude-code | codex | opencode | openclaw | hermes | nanoclaw`).option(`--api-key <key>`,`Tangle API key (or set TANGLE_API_KEY)`).option(`--endpoint <url>`,`OTLP endpoint base`,Ji).option(`-p, --project <key>`,`Project label (tangle.subject.key) to group runs; omit to set it yourself`).option(`--rc <path>`,`Shell rc file to append the Claude Code env block to`).option(`--no-write`,`Print the config instead of writing files (Claude Code / Codex)`).option(`--inline-key`,"Embed the resolved API key literally in the config (default: keep ${TANGLE_API_KEY})").option(`--verify`,`Poll onboarding status and report whether CONTENT is flowing`).option(`--timeout <seconds>`,`Verify poll timeout in seconds`,`120`).option(`--run`,`OpenCode only: run the content exporter against a live OpenCode server until interrupted`).option(`--opencode-url <url>`,`OpenCode server base URL for --run (or set OPENCODE_BASE_URL)`).option(`--format <kind>`,`Claude Code output: shell (export block) | env (.env / docker --env-file) | dockerfile (ENV lines). env/dockerfile are the cron/container path — printed to stdout, no shell-rc edit, no TTY`,`shell`).option(`--content <tier>`,`Claude Code content tier: full (everything) | prompts (task+prompts+tool-args) | metadata (telemetry on, content off)`,`full`).action(async(e,t)=>{try{let n=B(t.endpoint);if(t.run){if((e?yo(e):`opencode`)!==`opencode`)throw Error(`--run is OpenCode-only: it runs the content exporter against a live OpenCode server. Other agents export natively once configured.`);await Do({endpoint:n,apiKey:Xa(t.apiKey),opencodeUrl:t.opencodeUrl});return}if(t.verify){await Oo({endpoint:n,apiKey:Xa(t.apiKey),agent:e?yo(e):void 0,timeoutSeconds:H(t.timeout,`--timeout`)});return}let r=e?yo(e):await So(),i=t.inlineKey?Xa(t.apiKey):void 0;r===`claude-code`?await Co({endpoint:n,apiKey:i,projectKey:t.project,rcPath:t.rc,write:t.write!==!1,content:xo(t.content),format:bo(t.format)}):r===`codex`?wo({endpoint:n,apiKey:i,projectKey:t.project,write:t.write!==!1}):r===`opencode`?To({endpoint:n}):Eo(r,{endpoint:n}),console.log(),j(`Run your agent on a real task, then verify content is flowing: tangle connect ${r} --verify`)}catch(e){F(e)}})}function vo(){return new t(`opencode-exporter`).description(`Export a running OpenCode's content to Tangle Intelligence (standalone shim)`).option(`--api-key <key>`,`Tangle API key (or set TANGLE_API_KEY)`).option(`--endpoint <url>`,`OTLP endpoint base`,Ji).option(`--opencode-url <url>`,`OpenCode server base URL (or set OPENCODE_BASE_URL)`).action(async e=>{try{await Do({endpoint:B(e.endpoint),apiKey:Xa(e.apiKey),opencodeUrl:e.opencodeUrl})}catch(e){F(e)}})}function yo(e){if(Ya(e))return e;throw Error(`Unknown agent '${e}'. Choose one of: ${Ga.join(`, `)}`)}function bo(e){if(e===`shell`||e===`env`||e===`dockerfile`)return e;throw Error(`--format must be one of: shell, env, dockerfile (got '${e}')`)}function xo(e){if(e===`full`||e===`prompts`||e===`metadata`)return e;throw Error(`--content must be one of: full, prompts, metadata (got '${e}')`)}async function So(){if(!process.stdin.isTTY)throw Error(`Specify an agent: tangle connect <${Ga.join(`|`)}>`);console.log(`Which coding agent are you connecting?`),Ga.forEach((e,t)=>{console.log(` ${t+1}) ${Ka[e]} (${e})`)});let e=await Kr(`Enter a number or name`,`1`);return Ga[Number.parseInt(e,10)-1]||yo(e.trim())}async function Co(e){let t=eo({endpoint:e.endpoint,apiKey:e.apiKey,projectKey:e.projectKey,content:e.content,format:e.format});if(console.log(t),e.format!==`shell`){console.log(),j(e.format===`env`?"Cron/container path: feed these to your service env (.env, `docker run --env-file`, k8s envFrom). No shell-rc edit, no TTY needed.":`Dockerfile path: paste these ENV lines into your image. No shell-rc edit, no TTY needed.`);return}if(console.log(),j(`Privacy tiers: --content full ships the whole conversation; --content prompts keeps task, prompts, and tool args only; --content metadata turns content off (telemetry still flows). Secrets are scrubbed server-side regardless.`),!e.write)return;let n=e.rcPath??mo(),r=process.stdin.isTTY?await Kr(`Append this idempotent block to ${n}? (y/N)`,`n`):`n`;if(r.toLowerCase()!==`y`&&r.toLowerCase()!==`yes`){console.log(),j(`Not writing. To append later: tangle connect claude-code --rc ${n}`);return}let i=to({endpoint:e.endpoint,apiKey:e.apiKey,projectKey:e.projectKey,content:e.content,format:e.format}),{contents:a,changed:o}=no(ho(n),i);if(!o){console.log(),k(`Already present in ${n} — nothing to change.`);return}go(n,a),console.log(),k(`Wrote Tangle Intelligence env block to ${n}.`),j(`Reload your shell (e.g. 'source ${n}') before running the agent.`)}function wo(e){let t=ve(xe(),`.codex`,`config.toml`),{contents:n,changed:r}=lo(ho(t),{endpoint:e.endpoint,apiKey:e.apiKey});if(!e.write){console.log(n.trimEnd());return}if(!r){k(`${t} already has the Tangle [otel] block — nothing to change.`);return}go(t,n),k(`Merged the Tangle [otel] block into ${t}.`),j("Codex emits content on the logs signal (codex.* events). Set TANGLE_API_KEY in your env before running if you kept the ${TANGLE_API_KEY} reference."),j(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=${e.projectKey??`<your project>`} before running codex.`)}function To(e){let t=B(e.endpoint);A(`OpenCode has no native OTel exporter, so a standalone install emits nothing without a shim.`),console.log(),N({"Inside a Tangle sandbox":`already instrumented — our adapter exports OpenCode's event-stream content. Nothing to do.`,Standalone:`run 'tangle connect opencode --run' alongside a running OpenCode, exporting to ${t}.`}),console.log(),j(`Start OpenCode in server mode ('opencode serve'), then in another terminal run: tangle connect opencode --run`),j(`The exporter subscribes to OpenCode's SSE event bus and exports content-bearing OTLP (prompt/completion/tool content) to Tangle. Verify with: tangle connect opencode --verify`),j(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=my-project before starting the exporter.`)}function Eo(e,t){let n=B(t.endpoint),r=Ka[e];A(`${r} has no native OTel exporter, so a standalone install emits nothing without instrumentation.`),console.log(),N({"Inside a Tangle sandbox":`already instrumented — the sidecar adapter exports ${r}'s prompt/completion/tool content (gen_ai.system=${e}) to ${n}. Nothing to do.`,Standalone:`${r} exposes no OTLP and no event-bus server; run it inside a Tangle sandbox to capture content.`}),console.log(),j(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=my-project before starting ${r}.`),j(`Verify content is flowing: tangle connect ${e} --verify`)}async function Do(e){let t=Ba(e.opencodeUrl),n=new AbortController,r=()=>n.abort();process.on(`SIGINT`,r),process.on(`SIGTERM`,r),j(`Subscribing to OpenCode at ${t} — exporting content to Tangle.`),j(`Run OpenCode tasks now. Press Ctrl-C to stop.`),console.log();let i=0,a;try{a=await Wa({endpoint:e.endpoint,apiKey:e.apiKey,opencodeBaseUrl:t,signal:n.signal,onExport:({eventType:e,records:t})=>{i+=t,j(`exported ${t} record(s) from ${e} (total ${i})`)}})}catch(e){if(e instanceof Ha){let{recordsExported:t,contentEventsExported:n}=e.partial;console.log(),A(`Exporter failed after exporting ${t} content record(s) from ${n} event(s): ${e.message}`)}throw e}finally{process.off(`SIGINT`,r),process.off(`SIGTERM`,r)}if(console.log(),a.contentEventsExported===0){A(`Saw ${a.eventsSeen} event(s) but none carried content. Run a real OpenCode task (a prompt that produces text or a tool call), then re-run.`);return}k(`Exported ${a.recordsExported} content record(s) from ${a.contentEventsExported} event(s).`),j(`Verify it landed: tangle connect opencode --verify`)}async function Oo(e){let t=Date.now()+e.timeoutSeconds*1e3,n=3e3,r=Math.min(e.timeoutSeconds*1e3,1e4),i=M(`Checking whether content is flowing…`);i.start();let a;try{for(;;){try{a=await la({endpoint:e.endpoint,apiKey:e.apiKey,timeoutMs:r})}catch(e){if(Date.now()>=t)throw e;await Ao(n);continue}if(a.contentSeen||Date.now()>=t)break;await Ao(n)}}finally{i.stop()}if(!a)throw Error(`onboarding status check returned no result`);ko(a,e.agent),a.contentSeen||(process.exitCode=1)}function ko(e,t){if(e.contentSeen){k(`Content flowing — Tangle Intelligence can analyze this feed.`),N({"Last seen":e.lastSeenAt??`just now`,Window:`${e.windowDays}d`});return}if(e.tracesSeen){A(`Metadata-only — traces are arriving but carry no content. You missed a content gate.`);let n=t?[t]:Object.keys(e.byAgent).filter(Ya),r=n.length>0?n:Ga;for(let n of r){let r=e.byAgent[n];(t||!r||r.tracesSeen&&!r.contentSeen)&&j(po(n))}return}A(`No traces yet for your tenant. Run your agent once on a real task, then re-run --verify.`),t&&j(po(t))}function Ao(e){return new Promise(t=>setTimeout(t,e))}function jo(){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=E(T({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=M(`Fetching environments...`);e.json||n.start();let r=await t.environments.list();n.stop(),e.json?O(r):r.length===0?console.log(`No environments found`):P([`ID`,`Description`,`Version`],r.map(e=>[e.id,e.description??``,e.version]))}catch(e){F(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=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=M(`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?O(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){F(e)}}),e}function Mo(){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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(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=M(`Executing: ${a}`);n.json||s.start();let c=await L(i,r,e);c=await R(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?O(l):(l.stdout&&process.stdout.write(l.stdout),l.stderr&&process.stderr.write(l.stderr)),l.exitCode!==0&&(process.exitCode=l.exitCode)}catch(e){if(e instanceof u){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 F(Error(t,{cause:e}))}F(e)}})}const No=[`runpod`,`vast-ai`,`lambda-labs`,`tensordock`,`paperspace`,`aws`,`gcp`,`azure`,`crusoe`,`fluidstack`,`modal`];function Po(e){let t=e.memory?U(e.memory,`--accelerator-memory`):void 0;return{kind:zo(e.kind),count:e.count?U(e.count,`--accelerator-count`):1,...t===void 0?{}:{memoryMB:t}}}function Fo(e,t,n){let r=!!(e.provider||e.image||e.env||e.maxSpendUsd||e.maxLifetime||e.idleTimeout);if(!t&&r)throw Error(n);if(t){if(!e.maxSpendUsd||!e.maxLifetime)throw Error(`--accelerator-kind requires --gpu-max-spend-usd and --gpu-max-lifetime`);return{...e.provider?{provider:Ro(e.provider,`--gpu-provider`)}:{},...e.image?{image:e.image}:{},...e.env?{env:Lo(e.env,`--gpu-env`,`GPU env`)}:{},maxSpendUsd:Bo(e.maxSpendUsd,`--gpu-max-spend-usd`),maxLifetimeSeconds:U(e.maxLifetime,`--gpu-max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:U(e.idleTimeout,`--gpu-idle-timeout`)}:{}}}}function Io(e){return{...e.provider?{provider:Ro(e.provider,`GPU provider`)}:{},accelerator:Po({kind:e.acceleratorKind,count:e.acceleratorCount,memory:e.acceleratorMemory}),...e.image?{image:e.image}:{},...e.env?{env:Lo(e.env,`--env`,`env`)}:{},maxSpendUsd:Bo(e.maxSpendUsd,`--max-spend-usd`),maxLifetimeSeconds:U(e.maxLifetime,`--max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:U(e.idleTimeout,`--idle-timeout`)}:{}}}function Lo(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 U(e,t){if(!/^\d+$/.test(e))throw Error(`${t} must be a positive integer`);let n=Number.parseInt(e,10);if(Number.isNaN(n)||n<1)throw Error(`${t} must be a positive integer`);return n}function Ro(e,t){if(No.includes(e))return e;throw Error(`${t} must be one of ${No.join(`, `)}`)}function zo(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 Bo(e,t){if(!/^(?:\d+|\d+\.\d+|\.\d+)$/.test(e))throw Error(`${t} must be a positive number`);let n=Number.parseFloat(e);if(!Number.isFinite(n)||n<=0)throw Error(`${t} must be a positive number`);return n}const Vo=[`list`,`create`,`delete`,`exec`,`prompt`,`read`,`write`];function Ho(){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(`--environment <environment>`,`Named environment, container image, or built image ID 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(`--accelerator-kind <kind>`,`Accelerator kind per machine, for example nvidia-l4 or nvidia-h100`).option(`--accelerator-count <count>`,`Accelerator devices per machine`).option(`--accelerator-memory <mb>`,`Minimum accelerator memory in MB per machine`).option(`--gpu-provider <provider>`,`GPU cloud provider per machine; omitted picks the cheapest configured provider`).option(`--gpu-worker-image <image>`,`GPU worker image override`).option(`--gpu-env <vars...>`,`Environment variables for each GPU worker (KEY=VALUE)`).option(`--gpu-max-spend-usd <usd>`,`Maximum spend per machine GPU lease`).option(`--gpu-max-lifetime <seconds>`,`Maximum GPU lease lifetime per machine in seconds`).option(`--gpu-idle-timeout <seconds>`,`Destroy each GPU lease after this many idle seconds`).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=E(T({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=M(`Creating fleet...`);n.start();let r=e.coordinator?await t.fleets.createWithCoordinator(Ko(e)):await t.fleets.create(Go(e));n.stop();let i=Xo(r.machines);e.json?O({fleetId:r.fleetId,machines:i}):(k(`Fleet created: ${r.fleetId}`),D(i,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}]))}catch(e){F(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=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=M(`Fetching fleet...`);r.start();let i=await n.fleets.list({fleetId:e,status:t.status});r.stop();let a=Xo(i.machines);t.json?O({fleetId:i.fleetId,machines:a}):D(a,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}])}catch(e){F(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=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=M(`Fetching manifest...`);r.start();let i=await n.fleets.manifest(e);r.stop(),t.json?O(i):(N({"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}),D(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){F(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=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=M(`Deleting fleet...`);r.start(),await n.fleets.delete(e,{continueOnError:t.continueOnError}),r.stop(),t.json?O({success:!0,fleetId:e}):k(`Fleet deleted: ${e}`)}catch(e){F(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=E(T({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=M(`Reaping expired fleets...`);n.start();let r=await t.fleets.reapExpired({dryRun:e.dryRun});n.stop(),e.json?O(r):(N({"Dry run":r.dryRun,Expired:r.expired,Deleted:r.deleted}),D(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){F(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=E(T({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=M(`Reconciling fleets...`);n.start();let r=await t.fleets.reconcile({dryRun:e.dryRun});n.stop(),e.json?O(r):(N({"Dry run":r.dryRun,Checked:r.checked,Orphaned:r.orphaned,Removed:r.removed}),D(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){F(e)}}),e.addCommand(Uo()),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=E(T({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=M(`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)O(a);else{D(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){F(e)}}),e.command(`run [prompt]`).description(`Create a fleet of agents, run one turn on every agent, print each result, then delete the fleet`).requiredOption(`--agents <n|file>`,`Number of agents, or a JSON file with an array of agent specs (agentId, harness, model, profile or { profileId, revision }, task)`).option(`--placement <mode>`,`auto (pack by sandbox memory), dedicated (one sandbox per agent), or a number of agents per sandbox`,`auto`).option(`--model <id>`,`Model every agent runs, e.g. gpt-4.1-mini`).option(`--memory <mb>`,`Memory in MB per sandbox; auto placement packs by it`).option(`--environment <environment>`,`Environment for each sandbox`).option(`--max-spend-usd <usd>`,`Budget for the fleet in USD, enforced by the Platform on the fleet's own key`).option(`--timeout <ms>`,`Per-agent turn timeout in milliseconds`).option(`--fleet-id <id>`,`Stable fleet id (generated when omitted)`).option(`--parent-fleet <id>`,`Fleet that spawns this one; its cap must cover this cap`).option(`--parent-agent <id>`,`Agent of --parent-fleet that spawns this one`).option(`--keep`,`Keep the fleet after the run instead of deleting 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=/^\d+$/.test(t.agents)?Number(t.agents):JSON.parse(y(t.agents,`utf8`));if(!Array.isArray(n)&&e===void 0)throw Error(`A prompt is required unless --agents names a file whose agents carry tasks`);let r=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl}));if(!!t.parentFleet!=!!t.parentAgent)throw Error(`--parent-fleet and --parent-agent go together`);let i=t.placement===`auto`||t.placement===`dedicated`?t.placement:{agentsPerSandbox:Number(t.placement)},a=t.maxSpendUsd?Number(t.maxSpendUsd):void 0,o=M(`Creating fleet...`);o.start();let s=Date.now(),c=await r.fleets.create({fleetId:t.fleetId,agents:n,placement:i,defaults:{...t.environment?{environment:t.environment}:{},...t.memory?{resources:{memoryMB:Number(t.memory)}}:{},...t.model?{backend:{type:`opencode`,model:{model:t.model}}}:{}},...a===void 0?{}:{budgetUsd:a},...t.parentFleet?{parent:{fleetId:t.parentFleet,agentId:t.parentAgent}}:{}}),l=Date.now()-s;o.stop(),t.json||k(`Fleet ${c.fleetId}: ${c.agents.length} agents on ${c.machines.size} sandboxes in ${l} ms`);let u=[],d;try{for await(let n of c.run(e,{timeoutMs:t.timeout?Number(t.timeout):void 0})){if(n.type===`agent.finished`&&!t.json){let e=n.result;console.log(`[${e.agentId}] ${e.harness??`default`}/${e.model??`default`} ${e.status} ${e.durationMs}ms ${e.costUsd===void 0?`no cost reported`:`$${e.costUsd.toFixed(5)}`} ${e.result?.response??e.error??``}`)}n.type===`fleet.finished`&&(u=n.results,d=n.spend)}}finally{t.keep||await c.delete({continueOnError:!0})}t.json?O({fleetId:c.fleetId,createMs:l,sandboxes:c.machines.size,results:u,spend:d,deleted:!t.keep}):N({fleetId:c.fleetId,completed:u.filter(e=>e.status===`completed`).length,agents:u.length,spend:JSON.stringify(d),deleted:!t.keep}),u.some(e=>e.status!==`completed`)&&(process.exitCode=1)}catch(e){F(e)}}),e.command(`cancel <fleet-id>`).description(`Interrupt every agent of a fleet and cancel its child fleets; sandboxes keep running`).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 E(T({apiKey:t.apiKey,baseUrl:t.baseUrl})).fleets.list({fleetId:e})).cancel();t.json?O({fleetId:e,...n}):k(`Fleet ${e}: interrupted ${n.interrupted} agents, cancelled ${n.children} child fleets`)}catch(e){F(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=E(T({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=M(`Fetching capabilities...`);n.start();let r=await t.fleets.capabilities();n.stop(),e.json?O(r):D(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){F(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=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=M(`Fetching usage...`);r.start();let i=await n.fleets.usage(e);if(r.stop(),t.json)O(i);else if(N({"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(`
145
- Recommended actions:`);for(let e of i.insights.recommendedActions)console.log(` - ${e}`)}}catch(e){F(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=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=M(`Estimating cost...`);r.start();let i=await n.fleets.cost(e);r.stop(),t.json?O(i):N({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){F(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 (prompt grants nothing since fleet prompt dispatch was removed)`).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=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=M(`Minting fleet token...`);r.start();let i=await n.fleets.createToken(e,{actions:Zo(t.action),ttlMinutes:t.ttlMinutes?Number(t.ttlMinutes):void 0});r.stop(),t.json?O(i):(N({"Fleet ID":i.fleetId,Token:Qo(i.token),"Expires at":new Date(i.expiresAt).toISOString(),Actions:i.actions.join(`, `)}),console.log(`
146
- Re-run with --json to print the full token value.`))}catch(e){F(e)}}),e}function Uo(){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=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=M(`Creating workspace snapshot...`);r.start();let i=await n.fleets.createWorkspaceSnapshot(e);r.stop(),t.json?O(i):k(`Workspace snapshot created: ${i.snapshotId??i.id}`)}catch(e){F(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=E(T({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=M(`Restoring workspace...`);i.start();let a=await r.fleets.restoreWorkspaceSnapshot(e,t);i.stop(),n.json?O(a):k(`Workspace restored from ${a.snapshotId??t}`)}catch(e){F(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=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=M(`Reconciling workspace...`);r.start();let i=await n.fleets.reconcileWorkspace(e);r.stop(),t.json?O(i):(N({"Fleet ID":i.fleetId,Checked:i.checked,"Orphaned mounts":i.orphanedMounts}),D(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){F(e)}}),e}function Wo(e){if(e.spec){let t=JSON.parse(y(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=qo(e),n=Jo(e,!!t?.accelerator),r={...e.environment?{environment:e.environment}:{},...t?{resources:t}:{},...e.driver?{driver:{type:e.driver}}:{},...n?{gpuLease:n}:{},...e.backend?{backend:{type:e.backend}}:{}},i=Yo(e),a=Math.max(1,Number(e.count)||1),o=Array.from({length:a},(e,t)=>({machineId:`worker-${t+1}`}));return{base:{fleetId:e.fleetId,defaults:Object.keys(r).length>0?r:void 0,policy:i,workspace:{mode:e.workspace}},machines:o}}function Go(e){let{base:t,machines:n}=Wo(e);return{...t,machines:n}}function Ko(e){let{base:t,machines:n}=Wo(e);return{...t,workers:n}}function qo(e){let t={};if(e.cpu&&(t.cpuCores=Number(e.cpu)),e.memory&&(t.memoryMB=Number(e.memory)),e.disk&&(t.diskGB=Number(e.disk)),e.acceleratorKind)t.accelerator=Po({kind:e.acceleratorKind,count:e.acceleratorCount,memory:e.acceleratorMemory});else if(e.acceleratorCount||e.acceleratorMemory)throw Error(`--accelerator-count and --accelerator-memory require --accelerator-kind`);return Object.keys(t).length>0?t:void 0}function Jo(e,t){return Fo({provider:e.gpuProvider,image:e.gpuWorkerImage,env:e.gpuEnv,maxSpendUsd:e.gpuMaxSpendUsd,maxLifetime:e.gpuMaxLifetime,idleTimeout:e.gpuIdleTimeout},t,`Fleet GPU lease flags require --accelerator-kind`)}function Yo(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 Xo(e){return[...e.entries()].map(([e,t])=>({machineId:e,sandboxId:t.id,status:t.status}))}function Zo(e){if(!(!e||e.length===0)){for(let t of e)if(!Vo.includes(t))throw Error(`Invalid token action '${t}'. Allowed: ${Vo.join(`, `)}`);return e}}function Qo(e){return e.length<=12?`****`:`${e.slice(0,6)}...${e.slice(-4)} (masked — use --json for full value)`}function $o(){let e=new t(`fs`).description(`File system operations on sandboxes`);return ns(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}=rs(r),o=await L(a,i,e);if(o=await R(o),!v.existsSync(t))throw Error(`Local file not found: ${t}`);let s=v.statSync(t),c=Date.now();r.json||console.error(`Uploading ${t} to ${n}...`),await o.fs.upload(t,n,{onProgress:e=>{if(r.json)return;let t=e.percentage.toFixed(1);process.stderr.write(`\rProgress: ${t}% (${e.bytesUploaded}/${e.totalBytes} bytes)`)}});let l=Date.now()-c;r.json||console.error(``),r.json?ur({success:!0,localPath:t,remotePath:n,size:s.size,durationMs:l}):console.log(`✓ Uploaded ${s.size} bytes in ${l}ms`)}catch(e){lr(e,r.json)}}),ns(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}=rs(r),o=await L(a,i,e);o=await R(o);let s=Date.now();r.json||console.error(`Downloading ${t} to ${n}...`),await o.fs.download(t,n,{onProgress:e=>{if(r.json)return;let t=e.percentage.toFixed(1);process.stderr.write(`\rProgress: ${t}% (${e.bytesDownloaded}/${e.totalBytes} bytes)`)}});let c=Date.now()-s,l=v.statSync(n);r.json||console.error(``),r.json?ur({success:!0,remotePath:t,localPath:n,size:l.size,durationMs:c}):console.log(`✓ Downloaded ${l.size} bytes in ${c}ms`)}catch(e){lr(e,r.json)}}),ns(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}=rs(n),a=await L(i,r,e);a=await R(a);let o=await a.fs.list(t,{all:n.all,long:n.long});if(n.json)ur(o);else if(n.long)P([`Mode`,`Owner`,`Group`,`Size`,`Modified`,`Name`],o.map(e=>{let t=e.isDir?`d`:e.isSymlink?`l`:`-`,n=es(e.permissions),r=e.isDir?`<DIR>`:ts(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){lr(e,n.json)}}),ns(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}=rs(n),a=await L(i,r,e);a=await R(a);let o=await a.fs.stat(t);n.json?ur(o):(console.log(` File: ${o.name}`),console.log(` Path: ${o.path}`),console.log(` Size: ${ts(o.size)} (${o.size} bytes)`),console.log(` Type: ${o.isDir?`directory`:o.isSymlink?`symlink`:`file`}`),console.log(` Mode: ${es(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){lr(e,n.json)}}),ns(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}=rs(n),a=await L(i,r,e);a=await R(a);let o=await a.read(t);n.json?ur({path:t,content:o}):console.log(o)}catch(e){lr(e,n.json)}}),ns(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}=rs(n),a=await L(i,r,e);a=await R(a),await a.fs.delete(t,{recursive:n.recursive}),n.json?ur({success:!0,path:t,deleted:!0}):console.log(`✓ Deleted: ${t}`)}catch(e){lr(e,n.json)}}),ns(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}=rs(n),a=await L(i,r,e);a=await R(a),await a.fs.mkdir(t,{recursive:n.parents}),n.json?ur({success:!0,path:t,created:!0}):console.log(`✓ Created: ${t}`)}catch(e){lr(e,n.json)}}),ns(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}=rs(n),a=await L(i,r,e);a=await R(a);let o=await a.fs.exists(t);n.json?ur({path:t,exists:o}):(console.log(o?`exists`:`not found`),process.exit(+!o))}catch(e){lr(e,n.json)}}),e}function es(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 ts(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 ns(e){return e.option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`)}function rs(e){let t=T({apiKey:e.apiKey,baseUrl:e.baseUrl});return{context:t,client:E(t)}}function is(){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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching status...`);t.json||i.start();let a=await L(r,n,e);a=await R(a);let o=await a.git.status();if(i.stop(),t.json)O(o);else if(!o.isRepo)console.log(`No git repository in the sandbox workspace.`);else{if(console.log(`Branch: ${o.branch??`unknown`}`),console.log(`HEAD: ${o.head.slice(0,7)||`(no commits)`}`),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){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching log...`);t.json||i.start();let a=await L(r,n,e);a=await R(a);let o=await a.git.log(Number.parseInt(t.limit,10));if(i.stop(),t.json)O(o);else if(o.length===0)console.log(`No commits found`);else for(let e of o)console.log(`${e.shortSha} ${e.message.split(`
147
- `)[0]} (${e.author}, ${e.date.toLocaleDateString()})`)}catch(e){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching diff...`);t.json||i.start();let a=await L(r,n,e);a=await R(a);let o=await a.git.diff(t.ref);i.stop(),t.json?O(o):o.raw?console.log(o.raw):console.log(`${o.additions} additions, ${o.deletions} deletions across ${o.files.length} files`)}catch(e){F(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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=await L(E(r),r,e);i=await R(i),await i.git.add(t),k(`Staged: ${t.join(`, `)}`)}catch(e){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=await L(E(n),n,e);r=await R(r);let i=await r.git.commit(t.message,{amend:t.amend});t.json?O(i):k(`Committed: ${i.shortSha} ${i.message}`)}catch(e){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Pushing...`);i.start();let a=await L(r,n,e);a=await R(a),await a.git.push({force:t.force}),i.stop(),k(`Pushed to remote`)}catch(e){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Pulling...`);i.start();let a=await L(r,n,e);a=await R(a),await a.git.pull({rebase:t.rebase}),i.stop(),k(`Pulled from remote`)}catch(e){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching branches...`);t.json||i.start();let a=await L(r,n,e);a=await R(a);let o=await a.git.branches();i.stop(),t.json?O(o):o.length===0?console.log(`No branches found`):P([`Name`,`Current`,`Remote`],o.map(e=>[e.name,e.current?`* `:` `,e.upstream??`-`]))}catch(e){F(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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=await L(E(r),r,e);i=await R(i),await i.git.checkout(t,{create:n.create}),k(`Checked out: ${t}${n.create?` (new)`:``}`)}catch(e){F(e)}}),e}function as(){let e=new t(`hub`).description(`Discover and run Tangle Hub tools`);e.option(`--json`,`Output as JSON`),e.hook(`preAction`,(e,t)=>{ss(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(`--parameter <key=value>`,`Provider-specific OAuth value. Repeatable.`,Cs,[]).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=ws(t.parameter),r=await(await I(t)).connections.start(e,{cli:!0,connectionParameters:n});if(t.json){O(Es(r));return}Ts(r,t.browser===!1?!1:await gi(r.redirectUrl))}catch(e){W(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 I(e)).connections.list();if(e.json){O(t);return}Ss(t.connections)}catch(t){W(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 I(t),r=await Gn(n,e);if(!t.force&&!await z(`Revoke Hub connection ${r}? `,`--force`)){j(`Revoke cancelled.`);return}let i=await n.connections.revoke(r);if(t.json){O(i);return}j(`Revoked Hub connection ${i.connection.id}.`)}catch(e){W(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 I(e),n=await Gn(t,e.connection),r=await t.permissions.list(n);if(e.json){O(r);return}_s(r.policies)}catch(t){W(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=vs(e.decision),n=await I(e),r=await Gn(n,e.connection),i=await n.permissions.set({connectionId:r,actionPath:e.action,decision:t});if(e.json){O(i);return}_s([i.policy])}catch(t){W(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 I(e),n=await Gn(t,e.connection),r=await t.permissions.revertWrites(n);if(e.json){O(r);return}j(`Reverted ${r.reverted} write permission${r.reverted===1?``:`s`} for connection ${r.connectionId}.`)}catch(t){W(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 I(e)).approvals.list();if(e.json){O(t);return}fs(t.approvals)}catch(t){W(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{ds(e),ps(await(await I(t)).approvals.approve(e),t.json===!0)}catch(e){W(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{ds(e),ps(await(await I(t)).approvals.deny(e),t.json===!0)}catch(e){W(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 I(e)).tools.sources();if(e.json){O(t);return}ys(t.sources)}catch(t){W(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 I(t)).tools.describe(e);if(t.json){O(n);return}bs(n.tool)}catch(e){W(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 I(t)).tools.search(e.join(` `),{provider:t.provider});if(t.json){O(n);return}gs(n.tools)}catch(e){W(e,t)}}),e.addCommand(a),e.addCommand(os(`call`)),e.addCommand(os(`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(ds(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 I(t);ps(t.decline?await n.approvals.deny(e):await n.approvals.approve(e),t.json===!0)}catch(e){W(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 I(e)).status();if(e.json){O(t);return}Ds(t)}catch(t){W(t,e)}}),e}function os(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}=us(e,t),{path:i,input:a}=hs(n),o=await I(t),s=t.connection?await Gn(o,t.connection):void 0;O((await o.tools.invoke(i,a,{connectionId:s,approve:r})).result)}catch(e){W(e,t)}})}function ss(e){if(!cs(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 cs(e,t){return e.options.some(e=>e.attributeName()===t)}function ls(e){return e.json===!0}function W(e,t){return ls(t)?F(e,!0):F(e)}function us(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 ds(e){if(!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`Hub approval ID must contain only letters, numbers, underscores, and dashes.`)}function fs(e){D(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 ps(e,t){if(t){O(ms(e));return}j(`Hub approval ${e.approval.id} ${e.approval.status}.`),e.capabilityToken&&j("Capability token minted. Re-run the original command with `--approve` to execute automatically.")}function ms(e){return{approval:e.approval,...e.capabilityToken?{capabilityToken:{tokenId:e.capabilityToken.tokenId,expiresAt:e.capabilityToken.expiresAt}}:{}}}function hs(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 gs(e){D(e.map(e=>({path:e.path,provider:e.providerId??e.requiredConnectionProviderId,title:e.title,description:e.description,connection:xs(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 _s(e){D(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 vs(e){if(e===`allow`||e===`ask`||e===`deny`)return e;throw Error(`--decision must be one of: allow, ask, deny.`)}function ys(e){D(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 bs(e){N({Path:e.path,Provider:e.providerId??e.requiredConnectionProviderId,Title:e.title,Description:e.description,Connection:xs(e),Policy:e.policyState}),e.inputSchema!==void 0&&(j(`Input schema`),console.log(JSON.stringify(e.inputSchema,null,2))),e.outputSchema!==void 0&&(j(`Output schema`),console.log(JSON.stringify(e.outputSchema,null,2)))}function xs(e){if(e.connectionRequired===!1)return`not required`;if(e.connectionStatus)return e.connectionStatus}function Ss(e){D(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 Cs(e,t){return[...t,e]}function ws(e){if(!e||e.length===0)return;let t={};for(let n of e){let e=n.indexOf(`=`);if(e<=0||e===n.length-1)throw Error(`Invalid --parameter "${n}": expected key=value (for example subdomain=acme)`);let r=n.slice(0,e);if(Object.hasOwn(t,r))throw Error(`Duplicate --parameter key "${r}".`);t[r]=n.slice(e+1)}return t}function Ts(e,t){t?j(`Opened browser to connect ${e.provider}.`):(j(`Open this URL to connect ${e.provider}:`),console.log(e.redirectUrl)),j("Finish authorization in the browser, then rerun `tangle hub status`.")}function Es(e){return{provider:e.provider,redirectUrl:e.redirectUrl,expiresAt:e.expiresAt,scopes:e.scopes,cli:e.cli}}function Ds(e){let{principal:t,connections:n}=e;j(`Hub status`),N({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&&j(`Some providers require reconnect.`)}function Os(){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`,Ji).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`;$i(n);let r=As(t.apiKey),i=await ia({selection:n,workspace:t.workspace,apiKey:r,endpoint:t.endpoint,serviceName:t.serviceName??ta(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){O(a);return}N({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){F(e)}}),e.command(`doctor`).description(`Check whether your agent traces carry CONTENT or are metadata-only`).option(`--api-key <key>`,`Intelligence ingest API key`).option(`--endpoint <url>`,`OTLP endpoint base`,Ji).option(`--json`,`Output as JSON`).action(async e=>{try{let t=ra(),n=await la({endpoint:e.endpoint===`https://intelligence.tangle.tools/v1/otlp`?t?.endpoint??`https://intelligence.tangle.tools/v1/otlp`:e.endpoint,apiKey:As(e.apiKey??t?.apiKey)});e.json?O(n):ks(n),n.contentSeen||(process.exitCode=1)}catch(e){F(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=js(e.agent),n=ra(),r={agent:t,event:e.event,endpoint:e.endpoint??n?.endpoint??`https://intelligence.tangle.tools/v1/otlp`,apiKey:As(e.apiKey??n?.apiKey),serviceName:e.serviceName??n?.serviceName??ta(process.cwd()),environment:e.environment??n?.environment??`local`,sessionId:e.sessionId,payload:e.payload===void 0?await Ns():Ms(e.payload)};if(e.dryRun){let n=oa(r);if(e.json){O(n);return}N({Trace:n.traceId,Agent:t,Event:e.event});return}let i=await sa(r);if(e.json){O({traceId:i});return}N({Trace:i,Agent:t,Event:e.event})}catch(t){if(e.nonBlocking){let n=t instanceof Error?t.message:String(t);e.json?O({ok:!1,error:n}):console.error(`Tangle Intelligence hook skipped: ${n}`);return}F(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 Ps({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 Ps({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 Ps({type:Is(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=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=t.json?null:M(`Fetching intelligence report...`);r?.start();let i=await n.intelligence.getReport(e);if(r?.stop(),t.json){O(i);return}Fs(i)}catch(e){F(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=E(T({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=e.json?null:M(`Fetching intelligence reports...`);n?.start();let r=await t.intelligence.listReports({subjectType:e.subjectType===void 0?void 0:Is(e.subjectType),subjectId:e.subjectId,limit:e.limit===void 0?void 0:zs(e.limit)});if(n?.stop(),e.json){O(r);return}D(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){F(e)}}),e}function ks(e){N({Status:e.contentSeen?`content flowing`:e.tracesSeen?`metadata-only — a content gate is missing`:`no traces yet`,"Traces seen":e.tracesSeen?`yes`:`no`,"Content seen":e.contentSeen?`yes`:`no`,"Last seen":e.lastSeenAt??`never`,Window:`${e.windowDays}d`});let t=Object.entries(e.byAgent);t.length>0&&(console.log(),D(t.map(([e,t])=>({agent:e,traces:t.tracesSeen?`yes`:`no`,content:t.contentSeen?`yes`:`no`})),[{key:`agent`,header:`Agent`,width:18},{key:`traces`,header:`Traces`,width:10},{key:`content`,header:`Content`,width:10}]))}function As(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 js(e){if(ea(e))return e;throw Error(`agent must be a known Tangle Intelligence agent surface`)}function Ms(e){try{return JSON.parse(e)}catch(e){throw Error(`--payload must be JSON: ${e instanceof Error?e.message:String(e)}`)}}async function Ns(){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 Ps(e,t){try{let n=Ls(t.mode),r=Bs(t.metadata),i=t.maxUsd===void 0?void 0:Rs(t.maxUsd);if(n===`agentic`&&i===void 0)throw Error(`Agentic intelligence reports require --max-usd`);let a=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl})),o=t.json?null:M(`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){O(s);return}Fs(s)}catch(e){F(e)}}function Fs(e){N({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(),O(e.result))}function Is(e){if(e===`sandbox`||e===`fleet`)return e;throw Error(`subject type must be sandbox or fleet`)}function Ls(e){if(e===`deterministic`||e===`agentic`)return e;throw Error(`mode must be deterministic or agentic`)}function Rs(e){let t=Number(e);if(!Number.isFinite(t)||t<0)throw Error(`--max-usd must be a non-negative number`);return t}function zs(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function Bs(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 Vs=[`router`,`sandbox`,`blueprint-agent`,`evals`,`agent-builder`];function Hs(e){if(e.minted)throw Error("This command needs a key you minted yourself. A browser login is exchanged for a short-lived key the platform will not accept for key management. Set TANGLE_API_KEY, run `tangle auth login --api-key sk-tan-…`, or mint the key in the web console. `tangle keys list` works from the login alone.")}async function Us(e,t,n={}){let r=new Headers(n.headers);n.body&&!r.has(`content-type`)&&r.set(`content-type`,`application/json`);let i=await Mr(e,t,{...n,headers:r});if(n.expected!==void 0&&i.status!==n.expected)throw Error(await Ws(i,t));return i}async function Ws(e,t){let n=await e.text().catch(()=>``),r;try{let e=JSON.parse(n),t=typeof e?.error==`string`?e.error:e?.error?.message;typeof t==`string`&&t.trim()&&(r=t)}catch{}if(r)return`${r} (HTTP ${e.status})`;let i=n?`: ${n.slice(0,400)}`:``;return`Platform request to ${t} returned ${e.status}${i}`}const Gs=[`ID`,`Prefix`,`Name`,`Product`,`Created`,`Last used`,`Expires`];function Ks(e){return[e.id,e.keyPrefix??``,e.name,e.product??`all`,e.createdAt,e.lastUsedAt??`—`,e.expiresAt??`—`]}function qs(){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=await jr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.platformUrl===void 0?{}:{baseUrl:e.platformUrl},...e.baseUrl===void 0?{}:{sandboxBaseUrl:e.baseUrl}}),n=t.baseUrl,r=await(await Us(t,`${n}/v1/keys`,{expected:200})).json();if(e.json){O(r);return}P(Gs,r.data.map(Ks))}catch(e){F(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 (${Vs.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&&!Vs.includes(t.product))throw Error(`Invalid --product. Expected one of ${Vs.join(`, `)}`);let n=await jr({...t.apiKey===void 0?{}:{apiKey:t.apiKey},...t.platformUrl===void 0?{}:{baseUrl:t.platformUrl},...t.baseUrl===void 0?{}:{sandboxBaseUrl:t.baseUrl}});Hs(n);let r=n.baseUrl,i=t.expiresInDays===void 0?void 0:new Date(Date.now()+Number.parseInt(t.expiresInDays,10)*24*60*60*1e3).toISOString(),a=M(`Creating API key...`);a.start();let o=await Us(n,`${r}/v1/keys`,{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){O(s);return}k(`API key created: ${s.data.prefix}…`),j(`Copy this key now — it will never be shown again:\n${s.data.key}`)}catch(e){F(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=await jr({...t.apiKey===void 0?{}:{apiKey:t.apiKey},...t.platformUrl===void 0?{}:{baseUrl:t.platformUrl},...t.baseUrl===void 0?{}:{sandboxBaseUrl:t.baseUrl}});Hs(n);let r=n.baseUrl;if(!t.yes&&!await z(`Revoke key ${e}? Any service still using it will start to fail.`,`--yes`)){j(`Aborted.`);return}let i=await(await Us(n,`${r}/v1/keys/${encodeURIComponent(e)}`,{method:`DELETE`,expected:200})).json();if(t.json){O(i);return}k(`Revoked ${e}`)}catch(e){F(e)}}),e}function G(e){if(fn().token)throw Error(`A line relay cannot manage numbers or attachments. Use your owner CLI outside the agent box.`);return E(T(e))}function Js(e){if(!e.yes)throw Error(`Review the selected line and use --yes to authorize this change. Attaching enables metered agent work.`)}function Ys(e){if(e===`imessage`||e===`whatsapp`||e===`email`||e===`sms`||e===`voice`||e===`telegram`)return e;throw Error(`--transport must be imessage, whatsapp, email, sms, voice, or telegram`)}function K(e){return e().catch(F)}async function Xs(e){let t=await Le(e,`r`);try{if(!(await t.stat()).isFile())throw Error(`Attachment input must be a regular JSON file`);let e=Buffer.alloc(131073),n=0;for(;n<e.length;){let{bytesRead:r}=await t.read(e,n,e.length-n,null);if(r===0)break;n+=r}if(n===e.length)throw Error(`Attachment JSON exceeds 128 KiB`);let r;try{r=JSON.parse(e.subarray(0,n).toString(`utf8`))}catch{throw Error(`Attachment file is not valid JSON`)}if(!r||typeof r!=`object`||Array.isArray(r))throw Error(`Attachment JSON must be an object`);if(Object.hasOwn(r,`number`))throw Error(`Use the line ID argument, not a number field in the attachment file`);return r}finally{await t.close()}}function Zs(e){e.command(`providers`).description(`List provider transports supported by this Hub deployment`).option(`--json`,`Output JSON`).action(e=>K(async()=>{O(await G(e).lines.providers())})),e.command(`list`).description(`List owned lines, optionally for a saved agent profile or sandbox`).option(`--profile-id <id>`,`Stored profile ID`).option(`--sandbox <id>`,`Existing sandbox ID`).option(`--json`,`Output JSON`).action(e=>K(async()=>{O(await G(e).lines.list({profileId:e.profileId,sandboxId:e.sandbox}))})),e.command(`get`).argument(`<line-id>`).description(`Inspect a line and its current attachment`).option(`--json`,`Output JSON`).action((e,t)=>K(async()=>{O(await G(t).lines.get(e))})),e.command(`numbers`).argument(`<connection-id>`).description(`Discover owned provider numbers; this does not purchase or reserve a number`).option(`--transport <transport>`,`imessage, whatsapp, or sms`,`imessage`).option(`--json`,`Output JSON`).action((e,t)=>K(async()=>{let n=Ys(t.transport);if(n===`email`)throw Error(`Email uses an owned mailbox, not phone inventory`);if(n===`voice`)throw Error(`Voice numbers are listed by ph0ny; provide the owned number ID to lines connect`);if(n===`telegram`)throw Error(`Telegram uses an owned bot, not phone inventory`);O(await G(t).lines.numbers(e,n))})),e.command(`connect`).argument(`<connection-id>`).description(`Bind an owned number or identity through Hub; no provider rental is purchased`).option(`--transport <transport>`,`imessage, whatsapp, sms, email, voice, or telegram`,`imessage`).option(`--number-id <id>`,`Exact owned provider number ID; required for voice, SMS, WhatsApp and Linq iMessage`).option(`--address <email>`,`Owned mailbox on a verified email domain`).requiredOption(`--reference <reference>`,`Stable client reference; keep it unchanged on retry`).option(`--label <label>`,`Line display name`).option(`--yes`,`Authorize provider webhook configuration and line binding`).option(`--json`,`Output JSON`).action((e,t)=>K(async()=>{Js(t);let n=Ys(t.transport);if(n!==`email`&&t.address)throw Error(`--address is email-only`);if((n===`email`||n===`telegram`)&&t.numberId)throw Error(`${n} does not take --number-id`);let r={connectionId:e,label:t.label,clientReference:t.reference},i;if(n===`email`)i={...r,transport:n,address:t.address};else if(n===`telegram`)i={...r,transport:n};else if(n===`imessage`)i={...r,transport:n,phoneNumberId:t.numberId};else{if(!t.numberId)throw Error(`${n} requires --number-id`);i={...r,transport:n,phoneNumberId:t.numberId}}O(await G(t).lines.fromConnection(i))})),e.command(`attach`).argument(`<line-id>`).description(`Attach a saved agent to any sandbox, or use an isolated on-demand member instance`).option(`--file <path>`,`Reviewed native attachment JSON (exclusive with quick-setup flags)`).option(`--profile-id <id>`,`Owner-scoped saved profile; each turn pins its source revision`).option(`--member <address>`,`The one allowed sender: E.164 phone or email`).option(`--sandbox <id>`,`Use an existing sandbox instead of an on-demand instance`).option(`--instance-prefix <prefix>`,`Stable instance namespace; defaults to profile:<profile-id>:`).option(`--tools <mode>`,`chat denies tools; act applies the profile's tools and permissions`).option(`--turns-per-day <count>`,`Per-member daily turn ceiling (default 30)`).option(`--yes`,`Authorize agent execution and spend against your key limits`).option(`--json`,`Output JSON`).action((e,t)=>K(async()=>{Js(t);let n=G(t),r;if(t.file){if(t.profileId||t.member||t.sandbox||t.instancePrefix||t.tools||t.turnsPerDay)throw Error(`Choose --file or quick-setup flags, not both`);r=await Xs(t.file)}else{if(!t.profileId||!t.member)throw Error(`Provide --profile-id and --member, or --file`);if(t.sandbox&&t.instancePrefix)throw Error(`Choose --sandbox or --instance-prefix`);let e=t.tools??`chat`,n=Number(t.turnsPerDay??`30`);if(e!==`chat`&&e!==`act`)throw Error(`--tools must be chat or act`);if(!Number.isSafeInteger(n)||n<1||n>1e4)throw Error(`--turns-per-day must be 1–10000`);if(e===`act`&&t.sandbox)throw Error(`Acting tools require an isolated on-demand instance; omit --sandbox`);r={mode:`personal`,members:[{address:t.member,role:`owner`}],unknownSenders:`reject`,roles:{owner:{context:`own`,tools:e}},respond:{kind:`agent`,profileId:t.profileId,...e===`act`?{rolePolicy:{version:1,roles:{owner:{kind:`general`}},members:{}}}:{}},limits:{turnsPerMemberPerDay:n},...t.sandbox?{sandboxId:t.sandbox}:{instance:{keyPrefix:t.instancePrefix??`profile:${t.profileId}:`,create:{ownerContext:`isolated`,...e===`act`?{egressPolicy:{mode:`strict`,allowDomains:[new URL(jn()).hostname],includeImplicitDomains:!1}}:{}}}}}}if(typeof r.sandboxId==`string`==(r.instance!==void 0))throw Error(`Attachment requires exactly one of sandboxId and instance`);let{sandboxId:i,instance:a,...o}=r,s;if(i){let t=await n.get(i);if(!t)throw Error(`Sandbox not found`);s=await t.lines.attach({...o,number:e})}else{if(!a)throw Error(`Attachment requires an instance`);s=await n.lines.attach({...o,number:e,instance:a})}O(s)}));for(let t of[`detach`,`release`])e.command(t).argument(`<line-id>`).description(t===`detach`?`Stop dispatch; preserve history and provider rental`:`Retire a detached Hub line; does not cancel provider rental`).option(`--yes`,`Authorize this change`).option(`--json`,`Output JSON`).action((e,n)=>K(async()=>{Js(n),O({[t]:await G(n).lines[t](e)})}));e.command(`threads`).argument(`<line-id>`).description(`List this line's separate participant threads`).option(`--json`,`Output JSON`).action((e,t)=>K(async()=>{O(await G(t).lines.threads(e).list())})),e.command(`messages`).argument(`<line-id>`).argument(`<thread-id>`).description(`Read one authorized participant thread`).option(`--json`,`Output JSON`).action((e,t,n)=>K(async()=>{O(await G(n).lines.threads(e).messages(t))}))}async function Qs(e){let{token:t,baseUrl:n}=fn();if(t===void 0)return I(e);if(!t.startsWith(`lrc_`)||!n)throw Error(`The line box needs TANGLE_LINE_TOKEN and TANGLE_HUB_URL`);if(e.apiKey||e.baseUrl&&new URL(e.baseUrl).origin!==new URL(n).origin)throw Error(`A line token cannot be sent to another Hub or combined with an API key`);return new De({baseUrl:n,authHeaders:()=>({Authorization:`Bearer ${t}`})})}async function $s(e,t){if(t)return t;if(!fn().token)throw Error(`Provide --line <line-id>`);return(await e.lines.context()).line.id}function ec(e){return e().catch(F)}function tc(){return new t(`context`).description(`Show live line identity, members, consent, reminders and quotas`).option(`--json`,`Output JSON`).action(e=>ec(async()=>{O(await(await Qs(e)).lines.context())}))}function nc(){let e=new t(`lines`).description(`Connect, manage, message and schedule on a Hub line`);return e.command(`members`).description(`List names, roles and consent on this line`).option(`--line <line-id>`,`Line ID; inferred in a line box`).option(`--json`,`Output JSON`).action(e=>ec(async()=>{let t=await Qs(e);O(await t.lines.members.list(await $s(t,e.line)))})),e.command(`send`).description(`Send to a consenting member through Hub`).argument(`<to-member>`,`Exact member ID for an owner; name, ID, or self in a line box`).argument(`<text>`,`Message text`).option(`--line <line-id>`,`Line ID; inferred in a line box`).option(`--on-behalf-of <member>`,`Verified sender for a member relay`).option(`--not-before <iso-time>`,`Delay delivery until this ISO time`).option(`--idempotency-key <key>`,`Stable key for a retry`).option(`--json`,`Output JSON`).action((e,t,n)=>ec(async()=>{let r=await Qs(n),i=await $s(r,n.line);if(!fn().token){if(n.onBehalfOf)throw Error(`--on-behalf-of is only available inside a line box`);if(!n.idempotencyKey)throw Error(`Owner sends require --idempotency-key so a retry keeps the same message`);if(!(await r.lines.members.list(i)).some(t=>t.id===e))throw Error(`Owner sends require an exact member ID from tangle lines members`);O(await r.lines.send(i,{memberId:e,text:t,idempotencyKey:n.idempotencyKey,...n.notBefore?{notBefore:n.notBefore}:{}}));return}O(await r.lines.send(i,{toMember:e,text:t,...n.onBehalfOf?{onBehalfOf:n.onBehalfOf}:{},...n.notBefore?{notBefore:n.notBefore}:{},...n.idempotencyKey?{idempotencyKey:n.idempotencyKey}:{}}))})),e.command(`remind`).description(`Wake the agent at a future time to write your reminder`).argument(`<text>`,`What to remember`).requiredOption(`--at <iso-time>`,`Future ISO time`).option(`--line <line-id>`,`Line ID; inferred in a line box`).option(`--idempotency-key <key>`,`Stable key for a retry`).option(`--json`,`Output JSON`).action((e,t)=>ec(async()=>{if(!t.at)throw Error(`--at is required`);let r=await Qs(t),i=t.idempotencyKey??n(`sha256`).update(JSON.stringify([e,t.at])).digest(`hex`).slice(0,32);O(await r.lines.remind(await $s(r,t.line),{text:e,notBefore:t.at,idempotencyKey:i}))})),Zs(e),e}function rc(){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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=await L(E(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 ze(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){F(e)}}),e}function ic(){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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching users...`);i.start();let a=await(await L(r,n,e)).permissions.list();i.stop(),t.json?O(a):D(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){F(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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(r),a=M(`Fetching user...`);a.start();let o=await(await L(i,r,e)).permissions.get(t);if(a.stop(),!o)throw Error(`User ${t} not found in sandbox ${e}`);n.json?O(o):(j(`User: ${o.userId}`),j(` Username: ${o.username}`),j(` Role: ${o.role}`),j(` Home: ${o.homeDir}`),j(` SSH Keys: ${o.sshKeys.length}`),j(` Created: ${o.createdAt.toISOString()}`))}catch(e){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Adding user...`);i.start();let a=await(await L(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?O(a):(k(`User ${a.userId} added as ${a.role}`),j(` Username: ${a.username}`),j(` Home: ${a.homeDir}`))}catch(e){F(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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(r),a=M(`Updating user...`);a.start();let o=await(await L(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?O(o):(k(`User ${t} updated`),j(` Role: ${o.role}`),j(` SSH Keys: ${o.sshKeys.length}`))}catch(e){F(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&&!await z(`Remove user ${t} from sandbox? [y/N] `,`--force`)){j(`Cancelled.`);return}let r=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(r),a=M(`Removing user...`);a.start(),await(await L(i,r,e)).permissions.remove(t,{preserveHomeDir:n.preserveHome}),a.stop(),k(`User ${t} removed from sandbox ${e}`)}catch(e){F(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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(r),a=M(`Fetching policies...`);a.start();let o=await(await L(i,r,e)).permissions.getAccessPolicies(t);a.stop(),n.json?O(o):o.length===0?j(`No access policies configured`):D(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){F(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=T({apiKey:i.apiKey,baseUrl:i.baseUrl}),o=E(a),s=M(`Checking access...`);s.start();let c=await(await L(o,a,e)).permissions.checkAccess(t,n,r);s.stop(),c?k(`✓ User ${t} CAN ${r} ${n}`):j(`✗ User ${t} CANNOT ${r} ${n}`)}catch(e){F(e)}}),e}async function ac(e,t){if(t.self&&e)throw Error(`Use --self or an explicit sandbox, not both`);if(!t.self&&!e)throw Error(`Specify a sandbox id/name or --self`);let n=tn(),r=t.baseUrl||n.tangleBaseUrl||n.sandboxBaseUrl,i=n.hubUrl;if(t.self&&!r&&i&&new URL(i).origin!==`https://id.tangle.tools`)throw Error(`This deployment must set SANDBOX_BASE_URL or pass --base-url for self preview access`);let a=t.self?t.apiKey??Sn():t.apiKey;if(t.self&&!a)throw Error(`Self preview access requires the injected sandbox runtime credential; it never reads saved owner credentials`);let o=T({apiKey:a,baseUrl:r}),s=E(o);return t.self?He(s):L(s,o,e)}async function oc(e,t,n){let r=M(e);t||r.start();try{return await n()}finally{r.stop()}}function sc(e){return e.option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key (prefer the environment)`).option(`--base-url <url>`,`API base URL`)}function cc(){let e=new t(`preview`).description(`Manage sandbox preview links`);return sc(e.command(`start`).description(`Start/reuse a managed development server and publish its ready preview`).argument(`[id-or-name]`,`Sandbox ID or name`).option(`--self`,`Use only the sandbox bound to the runtime credential`).option(`--cwd <directory>`,`Project directory in the selected workspace`).option(`--session <session-id>`,`Select the agent's session workspace`).option(`--name <name>`,`App/service label`)).action(async(e,t)=>{try{let n=await ac(e,t),r=await oc(`Starting managed preview...`,t.json,()=>Be(n,{cwd:t.cwd,sessionId:t.session,name:t.name}));t.json?O(r):(k(`Preview ready: ${r.url}`),console.log(`Preview ID: ${r.previewId}`))}catch(e){F(e)}}),sc(e.command(`list`).alias(`ls`).description(`List active preview links for a sandbox`).argument(`[id-or-name]`,`Sandbox ID or name`).option(`--self`,`Use only the sandbox bound to the runtime credential`)).action(async(e,t)=>{try{let n=await ac(e,t),r=await oc(`Fetching preview links...`,t.json,()=>n.previewLinks.list());t.json?O(r):r.length===0?console.log(`No preview links found`):P([`App`,`Preview ID`,`Port`,`URL`,`Status`],r.map(e=>[lc(e.metadata),e.previewId.slice(0,12),String(e.port),e.url,e.status]))}catch(e){F(e)}}),sc(e.command(`publish`).description(`Publish one existing HTTP service; never starts or replaces a process`).argument(`[id-or-name]`,`Sandbox ID or name`).option(`--self`,`Use only the sandbox bound to the runtime credential`).requiredOption(`--port <port>`,`Existing service port`).option(`--name <name>`,`App/service label`)).action(async(e,t)=>{try{if(!t.port||!/^\d+$/.test(t.port))throw Error(`An integer service port is required`);let n=await ac(e,t),r=await oc(`Publishing service...`,t.json,()=>Ve(n,{port:Number(t.port),name:t.name}));t.json?O(r):k(`Preview ready: ${r.url}`)}catch(e){F(e)}}),sc(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`)).action(async(e,t,n)=>{try{if(!/^\d+$/.test(t)||Number(t)<1||Number(t)>65535)throw Error(`Port must be an integer between 1 and 65535`);let r=await ac(e,n),i=await oc(`Creating preview for port ${t}...`,n.json,()=>r.previewLinks.create(Number(t)));n.json?O(i):(k(`Preview created: ${i.url}`),console.log(`Preview ID: ${i.previewId}`))}catch(e){F(e)}}),sc(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')`)).action(async(e,t,n)=>{try{let r=await ac(e,n);await oc(`Removing preview...`,n.json,()=>r.previewLinks.remove(t)),n.json?O({success:!0,previewId:t}):k(`Preview removed: ${t}`)}catch(e){F(e)}}),e}function lc(e){let t=e?.app;if(!t||typeof t!=`object`)return``;let n=`name`in t?t.name:void 0,r=`cwd`in t?t.cwd:void 0;return typeof n==`string`?n:typeof r==`string`?r:``}function uc(){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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(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=M(`Spawning: ${t}`);n.json||o.start();let s=await L(i,r,e);if(s=await R(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?O(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?O({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){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching processes...`);t.json||i.start();let a=await L(r,n,e);a=await R(a);let o=await a.process.list();t.running&&(o=o.filter(e=>e.running)),i.stop(),t.json?O(o):o.length===0?console.log(`No processes found`):P([`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){F(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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(r),a=M(`Fetching process info...`);n.json||a.start();let o=await L(i,r,e);o=await R(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?O(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){F(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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(r),a=M(`Sending ${n.signal} to PID ${t}...`);n.json||a.start();let o=await L(i,r,e);o=await R(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?O({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){F(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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=await L(E(r),r,e);i=await R(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){F(e)}}),e}const dc=[`python`,`node`,`typescript`,`bash`];function fc(e){switch(_e(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 pc(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 Re(ye(e),`utf8`)}async function mc(e,t,n=pc){let r=t?dc.find(e=>e===t)??(()=>{throw Error(`unknown --lang ${t}: must be one of ${dc.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=fc(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 hc(e){return ve(Se(),`tangle-run-images`,e)}function gc(){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: ${dc.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 mc(t,n.lang),a=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),o=await L(E(a),a,e);o=await R(o);let s=M(`Running ${r} (${i.length}b)…`);n.json||s.start();let c=await o.runCode(r,i,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10)});if(s.stop(),n.json){O(c),c.exitCode!==0&&process.exit(c.exitCode);return}c.stdout&&process.stdout.write(c.stdout),c.stderr&&process.stderr.write(c.stderr);let l=0;for(let t of c.results)if(t.type===`image`)if(n.saveImages!==!1){let r=typeof n.saveImages==`string`?n.saveImages:hc(e);fe(r,{recursive:!0});let i=`${r}/${Date.now()}-${l}.${t.format}`;me(i,Buffer.from(t.data,`base64`)),process.stderr.write(_.green(`✓ image → ${i}\n`)),l++}else process.stderr.write(_.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(_.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(_.gray(`… ${t.rows.length-20} more rows\n`))}else t.type===`json`?(process.stderr.write(_.gray(`[json] `)),process.stderr.write(`${JSON.stringify(t.value,null,2)}\n`)):t.type===`html`?process.stderr.write(_.gray(`[html ${t.value.length}b]\n`)):t.type===`error`?(process.stderr.write(_.red(`✗ ${t.name}: ${t.message}\n`)),t.traceback&&process.stderr.write(`${t.traceback}\n`)):t.type===`text`&&process.stderr.write(`${t.value}\n`);c.error&&(process.stderr.write(_.red(`\n✗ ${c.error.name}: ${c.error.message}\n`)),c.error.traceback&&process.stderr.write(`${c.error.traceback}\n`)),c.exitCode!==0&&process.exit(c.exitCode)}catch(e){F(e)}})}function _c(e,t){if(t){O(e);return}if(!e.id){e.kind===`snapshot`&&e.result?.snapshot?k(`Snapshot created: ${e.result.snapshot.snapshotId}`):k(`Sandbox ${e.sandboxId} stopped.`);return}k(`${e.kind===`snapshot`?`Snapshot`:`Stop`} of sandbox ${e.sandboxId} accepted.`),j(`Operation: ${e.id}`),j(`Status: ${e.statusUrl}`)}async function vc(e,t){let n=await jr({apiKey:t.apiKey,baseUrl:t.baseUrl??jn()}),r=await fetch(`${n.baseUrl}/v1/agent-profiles/${encodeURIComponent(e)}`,{headers:{authorization:`Bearer ${n.token}`,accept:`application/json`}});if(!r.ok){let t=await r.text().catch(()=>``);throw r.status===404?Error(`profile '${e}' not found in the platform catalog (it may be a built-in, a stored profile you own, or neither — run 'tangle profile list' to see what is available)`):Error(`platform returned ${r.status}: ${t.slice(0,200)}`)}let i=await r.json();if(!i.definition||typeof i.definition!=`object`)throw Error(`profile '${e}' resolved but has no definition — the catalog entry is malformed`);return i.definition}function yc(e){return`${e.name} (${e.id})`}async function bc(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 q(e,t,n){if(t)return bc(e,t);let r=Pn(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 xc(e,t){Fn({id:e.id,name:e.name},t)}function Sc(e){In(e)}async function Cc(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 qr();if(t.length===0)throw Error(`${e.flagPrefix}-stdin received empty input on stdin`);return t}}function wc(e){if(e.secret===void 0)return;let t=e.backend===`claude-code`?`token`:e.backend===`codex`?`bundle`:void 0;if(!t)throw Error(`--cli-auth needs --backend claude-code or --backend codex`);if(e.apiKeyGiven)throw Error(`--cli-auth cannot be combined with --backend-api-key-env or --backend-api-key-stdin`);return{account:`cli`,secretEnv:e.secret,format:t}}function Tc(e){if(e!==void 0)return e.map(e=>{let t=e.indexOf(`@`);if(t===-1)return e;let n=e.slice(0,t),r=e.slice(t+1),i=r.indexOf(`:`),a=i===-1?r:r.slice(0,i),o=i===-1?void 0:r.slice(i+1);if(!n||!a||o===``)throw Error(`--secret ${e}: expected NAME, NAME@host or NAME@host:Header`);return o===void 0?{name:n,host:a}:{name:n,host:a,header:o}})}function Ec(e,t){let n={};return e.cpu!==void 0&&(n.cpuCores=U(e.cpu,`--cpu`)),e.memory!==void 0&&(n.memoryMB=U(e.memory,`--memory`)),e.disk!==void 0&&(n.diskGB=U(e.disk,`--disk`)),t&&(n.accelerator=t),Object.keys(n).length>0?n:void 0}function Dc(e){let t=e.split(`/`);return t.length>=2?{provider:t[0],model:t.slice(1).join(`/`)}:{model:e}}function Oc(){let e=new t(`sandbox`).description(`Manage sandboxes`);e.command(`create`).description(`Create a new sandbox`).option(`-n, --name <name>`,`Sandbox name`).option(`-e, --environment <environment>`,`Named environment, container image, or built image ID`).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. NAME@host keeps the value out of the sandbox and sends it to that host only (NAME@host:Header for a header other than Authorization)`).option(`--metadata <entries...>`,`Metadata entries (KEY=VALUE or KEY=JSON)`).option(`--cpu <cores>`,"CPU cores (omit for the platform default; see `sandbox shapes`)").option(`--memory <mb>`,`Memory in MB (omit for the platform default)`).option(`--disk <gb>`,`Disk size in GB (omit for the platform default)`).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(`--gpu-provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--gpu-worker-image <image>`,`GPU worker image override`).option(`--gpu-env <vars...>`,`Environment variables for the GPU worker (KEY=VALUE)`).option(`--gpu-max-spend-usd <usd>`,`Maximum customer spend for the create-time GPU lease`).option(`--gpu-max-lifetime <seconds>`,`Maximum create-time GPU lease lifetime in seconds`).option(`--gpu-idle-timeout <seconds>`,`Destroy the create-time GPU lease after this many idle seconds`).option(`--lifetime <seconds>`,`Max wall-clock lifetime before the sandbox is suspended — stopped, not deleted; resume it within the cold window (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(`--billing-owner <userId>`,`Platform user that pays for the sandbox. The API accepts this only from a first-party service key that is listed as a billing delegate, and refuses such a key that names no payer.`).option(`--team <team>`,`Create in a team by id or name`).option(`--personal`,`Create a personal sandbox even when a team is active`).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(`--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(`--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 (${c.join(`, `)})`).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(`--cli-auth <secret>`,"Run --backend claude-code or codex on your own subscription: the stored secret holding a `claude setup-token` token or a Codex auth.json (see `tangle secret create`)").option(`--profile <path>`,`Path to an AgentProfile JSON file to install as the sandbox's backend profile (carries skills, tools, MCP, model). Use with --backend; the profile's inline skills materialize into the harness's native skill directory on first turn`).option(`--profile-stdin`,`Read the AgentProfile JSON from stdin instead of a file (use with --profile)`).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(`--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{let t=await Cc({envVarName:e.gitTokenEnv,fromStdin:e.gitTokenStdin,flagPrefix:`--git-token`}),n=await Cc({envVarName:e.storageSecretAccessKeyEnv,fromStdin:e.storageSecretAccessKeyStdin,flagPrefix:`--storage-secret-access-key`}),r=await Cc({envVarName:e.backendApiKeyEnv,fromStdin:e.backendApiKeyStdin,flagPrefix:`--backend-api-key`}),i=wc({secret:e.cliAuth,backend:e.backend,apiKeyGiven:r!==void 0}),a;if(e.profileStdin){let e=await qr(`--profile-stdin`,`the AgentProfile JSON`);try{a=JSON.parse(e)}catch{F(Error(`--profile-stdin: the input is not valid JSON`));return}}else if(e.profile){let t=String(e.profile);if(t.startsWith(`.`)||t.startsWith(`/`)||t.endsWith(`.json`))try{a=JSON.parse(y(t,`utf8`))}catch(e){F(Error(`--profile ${t}: ${e.message}`));return}else try{a=await vc(t,e)}catch(e){F(Error(`--profile ${t}: ${e.message}`));return}}let o=T({apiKey:e.apiKey,baseUrl:e.baseUrl,timeout:e.timeout?Number.parseInt(e.timeout,10):void 0}),s=E(o),c=M(`Creating sandbox...`);c.start();let l=await Pc({client:s,explicitTeam:e.team,personal:e.personal,activeTeamId:o.activeTeamId}),u={};if(e.env)for(let t of e.env){let[e,...n]=t.split(`=`);e&&n.length>0&&(u[e]=n.join(`=`))}let d=e.metadata?Ac(e.metadata):void 0,f=Mc(e,t),p=Nc(e,n),m=e.acceleratorKind?Po({kind:String(e.acceleratorKind),count:String(e.acceleratorCount),memory:typeof e.acceleratorMemory==`string`?e.acceleratorMemory:void 0}):void 0,h=Fo({provider:typeof e.gpuProvider==`string`?e.gpuProvider:void 0,image:typeof e.gpuWorkerImage==`string`?e.gpuWorkerImage:void 0,env:Array.isArray(e.gpuEnv)?e.gpuEnv:void 0,maxSpendUsd:typeof e.gpuMaxSpendUsd==`string`?e.gpuMaxSpendUsd:void 0,maxLifetime:typeof e.gpuMaxLifetime==`string`?e.gpuMaxLifetime:void 0,idleTimeout:typeof e.gpuIdleTimeout==`string`?e.gpuIdleTimeout:void 0},!!m,`Create-time GPU lease flags require --accelerator-kind`),g=e.driver?{type:e.driver,enableCriu:e.driverCriu||void 0,preferredRegion:e.driverRegion}:void 0,ee=e.backend||e.backendModel||a?{...e.backend?{type:se(e.backend)}:{},...a?{profile:a}:{},model:e.backendModel||r||i?{...e.backendModel?Dc(e.backendModel):{},apiKey:r,...i?{cliAuth:i}:{}}:void 0}:void 0,te=Tc(e.secret),ne=i?[...new Set([...te??[],i.secretEnv])]:te,re=Ec(e,m),ie=[...e.sshKey?[e.sshKey]:[],...(e.sshKeyFile??[]).map(e=>y(e,`utf8`).trim())],oe={name:e.name,environment:e.environment,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(u).length>0?u:void 0,git:f,...re?{resources:re}:{},gpuLease:h,maxLifetimeSeconds:Number.parseInt(e.lifetime,10),idleTimeoutSeconds:Number.parseInt(e.idleTimeout,10),storage:p,fromSnapshot:e.fromSnapshot,publicTemplateId:e.publicTemplate,publicTemplateVersionId:e.publicTemplateVersion,teamId:l,...e.billingOwner?{billingOwnerId:e.billingOwner}:{},secrets:ne,metadata:d,driver:g,backend:ee},ce=e.tee?{tee:e.tee,sealed:e.sealed||void 0,attestationRefresh:e.attestationRefresh||e.attestationNonce===`auto`||void 0}:void 0,le=ce?await ae(s,{...oe,confidential:ce,attestationNonce:e.attestationNonce??(e.attestationRefresh?`auto`:void 0),requireAttestation:e.requireAttestation??!0}):void 0,_=le?.sandbox??await s.create(oe);e.wait&&(c.text=`Waiting for sandbox to start...`,await _.waitFor(`running`,{timeoutMs:12e4}),await _.refresh()),c.stop(),e.json?O({id:_.id,name:_.name,status:_.status,resources:_.resources,createdAt:_.createdAt,expiresAt:_.expiresAt,connection:kc(_.connection),teamId:l,gpuLease:_.gpuLease,confidential:ce,attestation:le?.attestation,attestationNonce:le?.attestationNonce}):(k(`Sandbox created: ${_.id}`),cr({id:_.id,name:_.name,status:_.status,resources:_.resources,createdAt:_.createdAt?.toISOString(),expiresAt:_.expiresAt?.toISOString(),connection:_.connection}),l&&console.log(`Team: ${l}`),_.gpuLease&&(console.log(`GPU lease: ${_.gpuLease.id}`),Lc(_.gpuLease)),ce&&(console.log(`TEE: ${ce.tee}`),console.log(`Attestation: ${le?.attestation?`present`:`not returned`}`),le?.attestationNonce&&console.log(`Attestation nonce: ${le.attestationNonce}`)))}catch(e){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=t.nonce===`auto`?oe():t.nonce,a=M(`Fetching TEE attestation...`);a.start();let o=await(await L(r,n,e)).getTeeAttestation(i?{attestationNonce:i}:void 0);a.stop(),t.json?O(o):(k(`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){F(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=T({apiKey:e.apiKey,baseUrl:e.baseUrl}),n=E(t),r=M(`Fetching sandboxes...`);r.start();let i=await Fc({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?O(a):D(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){F(e)}}),e.command(`get <id-or-name>`).description(`Get sandbox details`).option(`--profile`,`Show the active agent profile provenance (name, hash, skills)`).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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching sandbox...`);i.start();let a=await L(r,n,e);if(i.stop(),t.profile){let e=a.getProfileProvenance?.();e?(j(`Agent profile provenance:`),j(` Base profile: ${e.base.name??`(inline)`} (${e.base.sha256.slice(0,12)}...)`),j(` Effective: ${e.effective.name??`(inline)`} (${e.effective.sha256.slice(0,12)}...)`),j(` Materialized: ${e.materializedAt}`),e.base.sha256!==e.effective.sha256&&j(` ⚠ Profile changed since creation (base ≠ effective)`)):j(`No profile materialized (bare sandbox). Create with --profile <name> to install one.`);return}t.json?O(a):cr({id:a.id,name:a.name,status:a.status,resources:a.resources,createdAt:a.createdAt?.toISOString(),expiresAt:a.expiresAt?.toISOString(),connection:a.connection})}catch(e){F(e)}}),e.command(`shapes`).description(`List the named sandbox sizes, the default, and this account's ceiling`).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 E(T({apiKey:e.apiKey,baseUrl:e.baseUrl})).shapes();if(e.json){O(t);return}let n=e=>e.cpuCores<=t.ceiling.cpuCores&&e.memoryMB<=t.ceiling.memoryMB&&e.diskGB<=t.ceiling.diskGB;D(t.presets.map(e=>({name:e.name===t.default?`${e.name} (default)`:e.name,cpu:e.cpuCores,memory:`${e.memoryMB} MB`,disk:`${e.diskGB} GB`,available:n(e)?`yes`:e.name===t.default?`clamped to ceiling`:`above ceiling`})),[{key:`name`,header:`Shape`,width:18},{key:`cpu`,header:`vCPU`,width:6},{key:`memory`,header:`Memory`,width:10},{key:`disk`,header:`Disk`,width:8},{key:`available`,header:`Available`,width:14}]),j(`Ceiling for this account: ${sr(t.ceiling)}`)}catch(e){F(e)}}),e.command(`delete <id-or-name>`).description(`Delete a sandbox`).option(`-f, --force`,`Skip confirmation`).option(`--name`,`Treat the reference as a sandbox name`).option(`--retry-cleanup`,`Retry server-side cleanup after the sandbox disappeared from get/list`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{if(!t.force&&!await z(`Delete sandbox ${e}? [y/N] `,`--force`)){j(`Cancelled.`);return}let n=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Deleting sandbox...`);i.start();let a=await Br(r,n,e,{retryCleanup:t.retryCleanup,name:t.name});i.stop(),k(a===`already_absent`?`Sandbox ${e} was already gone.`:`Sandbox ${e} deleted.`)}catch(e){F(e)}}),e.command(`stop <id-or-name>`).description(`Stop a running sandbox`).option(`--name`,`Treat the reference as a sandbox name`).option(`--no-wait`,`Return once the stop is accepted and print the operation to poll`).option(`--json`,`With --no-wait, print the operation as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Stopping sandbox...`);i.start();let a=await L(r,n,e,{nameOnly:t.name});if(t.wait===!1){let e=await a.stop({wait:!1});i.stop(),_c(e.info,!!t.json);return}await a.stop(),i.stop(),k(`Sandbox ${e} stopped.`)}catch(e){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl,timeout:n}),i=E(r),a=M(`Resuming sandbox...`);a.start();let o=await L(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(),k(`Sandbox ${o.id} resumed.`)}catch(e){F(e)}});let n=e.command(`gpu`).description(`Manage on-demand GPU leases for a sandbox`);return n.command(`providers <id-or-name>`).description(`List GPU clouds, whether each credential works, and current prices`).option(`--accelerator-kind <kind>`,`Price this GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`).option(`--accelerator-memory <mb>`,`Minimum GPU memory in MB`).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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Checking GPU providers...`);i.start();let a=await(await L(r,n,e)).gpu.providers(t.acceleratorKind?{accelerator:Po({kind:t.acceleratorKind,count:t.acceleratorCount,memory:t.acceleratorMemory})}:{});if(i.stop(),t.json){O(a);return}D(a.statuses.map(e=>({provider:e.provider,state:e.state,gpu:e.estimate?.providerInstanceType??``,usdHr:e.estimate?e.estimate.customerPricePerHourUsd.toFixed(4):``,pricing:e.estimate?.pricingSource??``,needs:e.envVars.join(` `)})),[{key:`provider`,header:`Provider`},{key:`state`,header:`State`},{key:`gpu`,header:`GPU`},{key:`usdHr`,header:`$/hr`},{key:`pricing`,header:`Price`},{key:`needs`,header:`Needs`}]);for(let e of a.statuses){let t=e.state===`credential-invalid`?e.credential?.detail:e.estimateError;t&&j(`${e.provider}: ${t}`)}a.usable.length===0&&j(`No GPU provider is usable on this deployment: set the variables in Needs for one provider on the server.`)}catch(e){F(e)}}),n.command(`attach <id-or-name>`).description(`Attach a temporary GPU worker to a sandbox`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <mb>`,`Minimum GPU memory in MB`).option(`--provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--image <image>`,`GPU worker image override`).option(`--env <vars...>`,`Environment variables for the GPU worker (KEY=VALUE)`).requiredOption(`--max-spend-usd <usd>`,`Maximum customer spend for this lease`).requiredOption(`--max-lifetime <seconds>`,`Maximum lease lifetime in seconds`).option(`--idle-timeout <seconds>`,`Destroy after this many idle seconds`).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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Attaching GPU lease...`);i.start();let a=await(await L(r,n,e)).gpu.attach(Io(t));i.stop(),t.json?O(a):(k(`GPU lease attached: ${a.id}`),Lc(a))}catch(e){F(e)}}),n.command(`run <id-or-name> <command...>`).description(`Attach a temporary GPU, run a command, then destroy it`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <mb>`,`Minimum GPU memory in MB`).option(`--provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--image <image>`,`GPU worker image override`).option(`--env <vars...>`,`Environment variables for the GPU worker and command (KEY=VALUE)`).requiredOption(`--max-spend-usd <usd>`,`Maximum customer spend for this lease`).requiredOption(`--max-lifetime <seconds>`,`Maximum lease lifetime in seconds`).option(`--idle-timeout <seconds>`,`Destroy after this many idle seconds`).option(`--timeout <ms>`,`Command timeout in milliseconds`).option(`--cwd <path>`,`Working directory`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{let r,i,a,o;try{let a=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),o=await L(E(a),a,e),s=M(`Attaching GPU lease...`);s.start(),r=await o.gpu.attach(Io(n)),s.stop();let c=M(`Running GPU command...`);c.start(),i=await o.gpu.exec(r.id,{command:t.join(` `),timeoutMs:n.timeout?U(String(n.timeout),`--timeout`):void 0,cwd:n.cwd,env:n.env?Lo(n.env,`--env`,`env`):void 0}),c.stop(),n.json||Rc(i)}catch(e){a=e}finally{if(r)try{let t=T({apiKey:n.apiKey,baseUrl:n.baseUrl});r=await(await L(E(t),t,e)).gpu.detach(r.id)}catch(e){o=e}}if(a){F(a),o&&F(o);return}if(o){F(o);return}n.json?O({lease:r,result:i}):r&&k(`GPU lease detached: ${r.id}`);let s=i?.result.exitCode;s&&s!==0&&(process.exitCode=s)}),n.command(`list <id-or-name>`).description(`List GPU leases attached to 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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching GPU leases...`);i.start();let a=await(await L(r,n,e)).gpu.list();i.stop(),t.json?O(a):a.length===0?j(`No GPU leases attached.`):D(a.map(e=>({id:e.id,status:e.status,provider:e.provider,accelerator:`${e.accelerator.kind}x${e.accelerator.count}`,customerUsdHr:e.customerPricePerHourUsd??``})),[{key:`id`,header:`ID`,width:28},{key:`status`,header:`Status`,width:12},{key:`provider`,header:`Provider`,width:12},{key:`accelerator`,header:`GPU`,width:24},{key:`customerUsdHr`,header:`$/hr`,width:10}])}catch(e){F(e)}}),n.command(`exec <id-or-name> <lease-id> <command...>`).description(`Run a command on an attached GPU lease`).option(`--timeout <ms>`,`Command timeout in milliseconds`).option(`--cwd <path>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).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=T({apiKey:r.apiKey,baseUrl:r.baseUrl}),a=E(i),o=M(`Running GPU command...`);o.start();let s=await(await L(a,i,e)).gpu.exec(t,{command:n.join(` `),timeoutMs:r.timeout?U(String(r.timeout),`--timeout`):void 0,cwd:r.cwd,env:r.env?Lo(r.env,`--env`,`env`):void 0});o.stop(),r.json?O(s):Rc(s)}catch(e){F(e)}}),n.command(`detach <id-or-name> <lease-id>`).description(`Detach and destroy a GPU lease`).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({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(r),a=M(`Detaching GPU lease...`);a.start();let o=await(await L(i,r,e)).gpu.detach(t);a.stop(),n.json?O(o):(k(`GPU lease detached: ${o.id}`),Lc(o))}catch(e){F(e)}}),e.command(`network <id-or-name>`).description(`Show runtime network state (exposed ports) for a sandbox. Outbound policy is not settable here — see the outbound flags.`).option(`--block-outbound`,`Unenforceable; the server rejects it. Block outbound traffic with an egress policy of mode "blocked"`).option(`--allow-list <cidrs>`,`Unenforceable; the server rejects it. Egress policy allowlists domains, not CIDRs`).option(`--clear`,`Unenforceable; the server rejects it. There is no per-sandbox outbound restriction here to clear`).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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Updating network configuration...`);i.start();let a=await L(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?O(e):(j(`Network Configuration:`),e.ports&&e.ports.length>0?j(` Exposed Ports: ${e.ports.join(`, `)}`):j(` No exposed ports`));return}i.stop();let o=await a.network.getConfig();t.json?O(o):(k(`Network configuration updated.`),o.ports&&o.ports.length>0&&j(` Exposed Ports: ${o.ports.join(`, `)}`))}catch(e){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(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=M(`Exposing port ${i}...`);a.start();let o=await(await L(r,n,e)).network.exposePort(i);a.stop(),t.json?O({port:i,url:o}):(k(`Port ${i} exposed.`),j(` URL: ${o}`))}catch(e){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching exposed URLs...`);i.start();let a=await(await L(r,n,e)).network.listUrls();if(i.stop(),t.json)O(a);else{let e=Object.entries(a);if(e.length===0)j(`No ports exposed.`);else{j(`Exposed Ports:`);for(let[t,n]of e)j(` ${t}: ${n}`)}}}catch(e){F(e)}}),e}function kc(e){return!e||e.authToken===void 0?e:{...e,authToken:`[REDACTED]`}}function Ac(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]=jc(r.join(`=`))}return t}function jc(e){try{return JSON.parse(e)}catch{return e}}function Mc(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`?U(e.gitDepth,`--git-depth`):void 0,sparse:Array.isArray(e.gitSparse)?e.gitSparse:void 0,auth:t?{token:t}:void 0}}}function Nc(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:Ic(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}}}}async function Pc(e){if(e.explicitTeam&&e.personal)throw Error(`--team and --personal cannot be used together`);if(!e.personal)return e.explicitTeam?(await bc(e.client,e.explicitTeam)).id:e.activeTeamId}async function Fc(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 bc(e.client,e.explicitTeam)).id}`;if(e.activeTeamId)return`team:${e.activeTeamId}`}function Ic(e){if(e===`s3`||e===`gcs`||e===`r2`)return e;throw Error(`--storage-type must be one of s3, gcs, or r2`)}function Lc(e){j(` Status: ${e.status}`),j(` Provider: ${e.provider}`),j(` GPU: ${e.accelerator.kind} x ${e.accelerator.count}`),e.customerPricePerHourUsd!==void 0&&j(` Customer price: $${e.customerPricePerHourUsd}/hr`),e.estimatedCustomerCostUsd!==void 0&&j(` Max estimate: $${e.estimatedCustomerCostUsd}`),e.billing&&(j(` Billed seconds: ${e.billing.seconds}`),j(` Customer cost: $${e.billing.customerCostUsd}`))}function Rc(e){e.result.stdout&&process.stdout.write(e.result.stdout),e.result.stderr&&process.stderr.write(e.result.stderr),j(`Exit code: ${e.result.exitCode}`)}function zc(){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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(r),a=M(`Searching...`);n.json||a.start();let o=await L(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){F(e)}})}function Bc(){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=E(T({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=await Vc({value:t,valueStdin:n.valueStdin,prompt:`Enter value for secret '${e}': `}),a=M(`Creating secret...`);a.start();let o=await r.secrets.create(e,i);a.stop(),n.json?O({name:o.name,createdAt:o.createdAt.toISOString(),updatedAt:o.updatedAt.toISOString()}):(k(`Secret created: ${o.name}`),j(`Use --secrets ${o.name} when creating a sandbox to inject it as an environment variable.`))}catch(e){F(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=E(T({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=M(`Fetching secrets...`);n.start();let r=await t.secrets.list();n.stop(),e.json?O(r.map(e=>({name:e.name,createdAt:e.createdAt.toISOString(),updatedAt:e.updatedAt.toISOString()}))):r.length===0?(j(`No secrets found.`),j(`Use 'tangle secret create <name> [value]' to create one.`)):P([`Name`,`Created At`,`Updated At`],r.map(e=>[e.name,e.createdAt.toLocaleString(),e.updatedAt.toLocaleString()]))}catch(e){F(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=E(T({apiKey:t.apiKey,baseUrl:t.baseUrl}));if(!t.force&&!await z(`Are you sure you want to delete secret '${e}'? This cannot be undone. (y/N) `,`--force`)){j(`Cancelled.`);return}let r=M(`Deleting secret...`);r.start(),await n.secrets.delete(e),r.stop(),t.json?O({success:!0,deleted:e}):k(`Secret deleted: ${e}`)}catch(e){F(e)}}),e}async function Vc(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 qr();if(e.length===0)throw Error(`Secret value from stdin cannot be empty`);return e}let t=await Gr(e.prompt);if(t.length===0)throw Error(`Secret value cannot be empty`);return t}function Hc(){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=b.dirname(Ue(import.meta.url)),t=b.resolve(e,`..`,`SKILL.md`);console.log(t)}),e}function Uc(){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(`--no-wait`,`Return once the snapshot is accepted and print the operation to poll`).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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Creating snapshot...`);i.start();let a=await L(r,n,e);if(t.wait===!1){let e=await a.snapshot({tags:t.tags,wait:!1});i.stop(),_c(e.info,!!t.json);return}let o=await a.snapshot({tags:t.tags});i.stop(),t.json?O(o):(k(`Snapshot created: ${o.snapshotId}`),console.log(`Size: ${Wc(o.sizeBytes??0)}`))}catch(e){F(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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching snapshots...`);i.start();let a=await(await L(r,n,e)).listSnapshots();i.stop(),t.json?O(a):D(a.map(e=>({...e,size:Wc(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){F(e)}}),e.command(`restore <sandbox-id> <snapshot-id>`).description(`Create a new sandbox from a snapshot`).option(`--billing-owner <userId>`,`Platform user that pays for the restored sandbox. The API accepts this only from a first-party service key that is listed as a billing delegate, and refuses such a key that names no payer.`).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(T({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=M(`Restoring from snapshot...`);i.start();let a=await r.create({fromSnapshot:t,fromSandboxId:e,...n.billingOwner?{billingOwnerId:n.billingOwner}:{}});await a.waitFor(`running`,{timeoutMs:12e4}),i.stop(),n.json?O({sandboxId:a.id,restoredFrom:t,status:a.status}):(k(`New sandbox created: ${a.id}`),console.log(`Source snapshot: ${t}`))}catch(e){F(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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(r),a=M(`Reverting sandbox to snapshot...`);a.start();let o=await L(i,r,e),s=await o.revertToSnapshot(t);await o.refresh(),a.stop(),n.json?O({sandboxId:o.id,snapshotId:s.snapshotId,status:o.status}):(k(`Sandbox reverted: ${o.id}`),console.log(`Source snapshot: ${s.snapshotId}`))}catch(e){F(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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(r),a=M(`Deleting snapshot...`);a.start();let o=await(await L(i,r,e)).deleteSnapshot(t);a.stop(),n.json?O({success:!0,sandboxId:e,snapshotId:t,outcome:o.outcome}):o.outcome===`already_absent`?k(`Snapshot already gone: ${t}`):k(`Snapshot deleted: ${t}`)}catch(e){F(e)}}),e}function Wc(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]}`}const Gc=`solve:device:secp256k1`,Kc=/^0x[0-9a-f]{64}$/i;function qc(e){return e&&Kc.test(e)?e:void 0}function Jc(){let e=Nt(Gc),t=qc(e.value);if(!(!t||e.source===`none`))return{account:Ge(t),source:e.source}}function Yc(){let e=Jc();if(e)return e;let t=We(),n=Pt(Gc,t);return{account:Ge(t),source:n}}function Xc(e){let t=qc(Nt(Gc).value);if(!t||Ge(t).address!==e.account.address)throw Error(`The local Solve device key changed; it was not retired`);let n=`${Gc}:retired:${e.account.address.toLowerCase()}`;if(Pt(n,t),Nt(n).value!==t)throw Error(`The revoked device key could not be retired safely`);return It(Gc),n}function Zc(e){try{let t=e.create?Yc():Jc();if(!t)throw Error("No Solve device signer found. Run `tangle solve account --create`");e.json?O({address:t.account.address,source:t.source}):N({Address:t.account.address,Source:t.source})}catch(e){F(e)}}const Qc=/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;function $c(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function J(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`${t} must be an object`);return e}function el(e,t,n=2048){if(typeof e!=`string`||!e.trim()||e.length>n)throw Error(`${t} is missing or invalid`);if($c(e))throw Error(`${t} contains control characters`);return e.trim()}function tl(e,t){let n=el(e,t,64).toLowerCase();if(!Qc.test(n))throw Error(`${t} must be a 40 or 64 character Git revision`);return n}function nl(e,t,n=!1){let r=typeof e==`number`&&Number.isSafeInteger(e)?String(e):el(e,t,80);if(!/^\d+$/.test(r)||!n&&r===`0`)throw Error(`${t} must be an unsigned integer`);return BigInt(r).toString()}function rl(e,t){let n=el(e,t,2048),r=new URL(n);if(r.protocol!==`https:`&&!(r.protocol===`http:`&&(r.hostname===`localhost`||r.hostname===`127.0.0.1`)))throw Error(`${t} must use HTTPS outside local development`);return n.replace(/\/$/,``)}function il(e,t){let n=rl(e,t).replace(/\.git$/,``),r=new URL(n),i=r.pathname.split(`/`).filter(Boolean);if(r.hostname!==`github.com`||r.username||r.password||r.search||r.hash||i.length!==2)throw Error(`${t} must be an HTTPS GitHub repository URL`);return`https://github.com/${i.join(`/`)}`}function al(e,t){let n=el(e,t,42);if(!et(n,{strict:!1}))throw Error(`${t} must be an EVM address`);return Qe(n)}function ol(e,t){let n=nl(e,t),r=Number(n);if(!Number.isSafeInteger(r)||r<=0)throw Error(`${t} is out of range`);return r}function Y(...e){for(let t of e)if(typeof t==`string`&&t.trim())return t.trim()}function sl(e){let t=e.trim().replace(/\.git$/,``);return t.startsWith(`git@github.com:`)?`https://github.com/${t.slice(15)}`:t.startsWith(`ssh://git@github.com/`)?`https://github.com/${t.slice(21)}`:t}function cl(e){if(e===void 0)return;let t=el(e,`pull request URL`,2048);if(!/^https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/\d+(?:\/[^\s]*)?$/i.test(t))throw Error(`pull request URL must point to a GitHub pull request`);return t}function ll(e,t){if(!/^https:\/\/[^\s]+$/i.test(e)&&!/^\/(?!\/).*$/.test(e)&&!/^[a-z][a-z0-9+.-]*:[^\s]+$/i.test(e))throw Error(`${t} must be an HTTPS URL or an absolute repository path`);if(e.split(/[?#]/,1)[0].split(`/`).includes(`..`))throw Error(`${t} cannot contain parent-directory segments`);return e}function ul(e){return nn(`solve`,e.profile)}function dl(e){let t=ul(e),n=wn(void 0,t);if(!n)throw Error(`No Solve credential found for profile '${t}'. Run: tangle auth login --provider github --app solve`);return n}async function fl(e){let t=Mn(e.apiUrl),n=await fetch(`${t}${e.path}`,{method:e.method??`GET`,headers:{Accept:`application/json`,...e.body===void 0?{}:{"Content-Type":`application/json`},Authorization:`Bearer ${dl(e)}`},...e.body===void 0?{}:{body:JSON.stringify(e.body)},signal:AbortSignal.timeout(3e4)}),r=await n.json().catch(()=>null);if(!n.ok||!r?.success||r.data===void 0){let e=r?.error?.message??`Solve API request failed with HTTP ${n.status}`;throw Error(r?.error?.code?`${r.error.code}: ${e}`:e)}return r.data}function pl(e){return fl({path:`/v1/wallet/challenges`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.purpose?{purpose:e.purpose}:{}}})}function ml(e){return fl({path:`/v1/devices`,apiUrl:e.apiUrl,profile:e.profile})}function hl(e){return fl({path:`/v1/devices/revoke`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.reason?{reason:e.reason}:{},...e.challengeId&&e.signature?{challengeId:e.challengeId,signature:e.signature}:{}}})}const X={chainId:42431,rpcUrl:`https://rpc.moderato.tempo.xyz`,sponsorUrl:`https://drew-gtr-pro.taild10bfc.ts.net/solve-sponsor`,tangleAddress:`0xff137B9C879c47C28ce389e84501925438AB4cdA`,managerAddress:`0x5271732F893B622ac6793d6DBA5B2626CCa4EA14`,paymentAsset:`0x20C0000000000000000000000000000000000000`,blueprintId:15n,serviceId:9n,competitionId:1n,minStakeWei:0n};function gl(e,t){return e.toLowerCase()===t.toLowerCase()}function _l(e){if(e.chainId!==X.chainId)throw Error(`Solve submissions require Tempo Moderato (chain ${X.chainId}); received ${e.chainId}`);if(e.rpcUrl!==X.rpcUrl)throw Error(`Solve metadata RPC does not match the trusted deployment`);if(e.sponsorUrl!==X.sponsorUrl)throw Error(`Solve metadata sponsor does not match the trusted deployment`);if(!gl(e.tangleAddress,X.tangleAddress))throw Error(`Solve metadata Tangle contract does not match the trusted deployment`);if(!gl(e.managerAddress,X.managerAddress))throw Error(`Solve metadata competition manager does not match the trusted deployment`);if(!gl(e.paymentAsset,X.paymentAsset))throw Error(`Solve metadata payment asset does not match the trusted deployment`);if(e.blueprintId!==X.blueprintId)throw Error(`Solve submissions require blueprint ${X.blueprintId}; received ${e.blueprintId}`);if(e.serviceId!==X.serviceId)throw Error(`Solve submissions require service ${X.serviceId}; received ${e.serviceId}`);if(e.competitionId!==X.competitionId)throw Error(`Solve submissions require competition ${X.competitionId}; received ${e.competitionId}`);if(e.minStakeWei!==X.minStakeWei)throw Error(`Solve submissions require zero stake for the trusted deployment`)}function vl(e,t){let n=J(t.check??e.check,`competition.participation.check`),r=el(n.command,`competition.participation.check.command`,512);if(!Array.isArray(n.args)||n.args.some(e=>typeof e!=`string`))throw Error(`competition.participation.check.args must be an array of strings`);let i=n.args.map(e=>el(e,`competition checker argument`,2048)),a=Y(n.result_file,n.resultFile),o=n.timeout_ms??n.timeoutMs,s=o===void 0?void 0:ol(o,`competition checker timeout`);return{command:r,args:i,...a?{result_file:a}:{},...s?{timeout_ms:s}:{}}}function yl(e){if(e.provenance===void 0)return;let t=J(e.provenance,`competition.participation.provenance`);if(t.mode!==`github_pull_request`)throw Error(`competition.participation.provenance.mode is unsupported`);if(t.required!==void 0&&typeof t.required!=`boolean`)throw Error(`competition.participation.provenance.required must be a boolean`);return{mode:`github_pull_request`,required:t.required===!0}}function bl(e){let t=J(e.chain??e.network??{},`competition.chain`),n=e.rewards&&typeof e.rewards==`object`&&!Array.isArray(e.rewards)?J(e.rewards,`competition.rewards`):{},r=n.minStake&&typeof n.minStake==`object`&&!Array.isArray(n.minStake)?J(n.minStake,`competition.rewards.minStake`).raw:void 0,i=Y(t.minStakeWei,t.min_stake_wei,e.minStakeWei,e.min_stake_wei,r),a=t.chainId??t.chain_id??e.chainId??e.chain_id,o=Y(t.chainName,t.chain_name,e.chainName,e.chain_name)??`Tempo`,s=Y(t.nativeSymbol,t.native_symbol,e.nativeSymbol,e.native_symbol)??`TNT`,c=Y(t.rpcUrl,t.rpc_url,e.rpcUrl,e.rpc_url,process.env.TANGLE_SOLVE_RPC_URL),l=Y(t.sponsorUrl,t.sponsor_url,e.sponsorUrl,e.sponsor_url,process.env.TANGLE_SOLVE_SPONSOR_URL),u=Y(t.tangleAddress,t.tangle_address,t.coreAddress,t.core_address,e.tangleAddress,e.tangle_address,e.coreAddress,e.core_address),d=Y(t.managerAddress,t.manager_address,e.managerAddress,e.manager_address),f=Y(t.paymentAsset,t.payment_asset,t.servicePaymentAsset,t.service_payment_asset,e.paymentAsset,e.payment_asset,e.servicePaymentAsset,e.service_payment_asset),p=Y(t.blueprintId,t.blueprint_id,e.blueprintId,e.blueprint_id),m=Y(t.serviceId,t.service_id,e.serviceId,e.service_id),h=Y(t.competitionId,t.competition_id,e.competitionId,e.competition_id,e.id);if(!c||!l||!u||!d||!p||!m||!h||!i||a===void 0)throw Error(`Solve competition metadata must include complete Tempo chain configuration`);return{chainId:ol(a,`chain.chainId`),chainName:o,nativeSymbol:s,rpcUrl:rl(c,`chain.rpcUrl`),sponsorUrl:rl(l,`chain.sponsorUrl`),tangleAddress:al(u,`chain.tangleAddress`),managerAddress:al(d,`chain.managerAddress`),paymentAsset:al(f??X.paymentAsset,`chain.paymentAsset`),blueprintId:nl(p,`chain.blueprintId`),serviceId:nl(m,`chain.serviceId`),competitionId:nl(h,`chain.competitionId`,!0),minStakeWei:nl(i,`chain.minStakeWei`,!0)}}function xl(e){let t=J(e,`competition`),n=J(t.participation??t.task,`competition.task`),r={...t,participation:{...n,...n.repositoryRevision===void 0&&n.revision!==void 0?{repositoryRevision:n.revision}:{}}},i=r.participation,a=il(Y(r.repository,r.repo_url,i.repository)??``,`competition.repository`),o=tl(Y(r.repositoryRevision,r.repository_revision,i.revision,i.repositoryRevision,i.repository_revision),`competition.repositoryRevision`),s=el(r.slug??r.id,`competition.slug`,128),c=el(r.name??r.title??s,`competition.name`,256),l=vl(r,i),u=yl(i);return{version:1,slug:s,title:c,repository:a,taskRevision:o,checker:l,chain:bl(r),...u?{provenance:u}:{}}}function Sl(e){return{chainId:e.chain.chainId,chainName:e.chain.chainName,nativeSymbol:e.chain.nativeSymbol,rpcUrl:e.chain.rpcUrl,sponsorUrl:e.chain.sponsorUrl,tangleAddress:e.chain.tangleAddress,managerAddress:e.chain.managerAddress,paymentAsset:e.chain.paymentAsset,blueprintId:BigInt(e.chain.blueprintId),serviceId:BigInt(e.chain.serviceId),competitionId:BigInt(e.chain.competitionId),minStakeWei:BigInt(e.chain.minStakeWei)}}async function Cl(e){let t=J(JSON.parse(await S.readFile(b.join(e,`.tangle-solve.json`),`utf8`)),`.tangle-solve.json`);if(t.version!==1)throw Error(`.tangle-solve.json has an unsupported version`);let n=J(t.checker,`.tangle-solve.json.checker`),r=J(t.chain,`.tangle-solve.json.chain`);return xl({slug:t.slug,name:t.title,repository:t.repository,repositoryRevision:t.taskRevision,participation:{check:n,provenance:t.provenance},chain:r,competitionId:r.competitionId})}const wl=Ke(Ce),Tl=`.tangle-solve-run.json`,El=`.tangle-solve.json`,Dl=`tangle.solve.manifestSha256`,Ol=new Set([El,Tl]),kl=`upstream`;async function Al(e,t){let n=await wl(`git`,[`-C`,e,...t],{encoding:`utf8`,maxBuffer:1e6});return String(n.stdout).trim()}async function jl(e,t){let n=b.resolve(t??process.cwd()),r=await Cl(n);if(e&&e!==r.slug&&e!==r.chain.competitionId)throw Error(`This directory contains '${r.slug}', not '${e}'`);return{root:n,manifest:r}}async function Ml(e){let t=b.join(e,El),r;try{r=await S.lstat(t)}catch{throw Error(`${El} is missing`)}if(r.isSymbolicLink()||!r.isFile())throw Error(`${El} must be a regular file`);return n(`sha256`).update(await S.readFile(t)).digest(`hex`)}async function Nl(e){let t=await Ml(e);return await Al(e,[`config`,`--local`,`--replace-all`,Dl,t]),t}async function Pl(e){let t;try{t=await Al(e,[`config`,`--local`,`--get`,Dl])}catch{throw Error(`The local Git metadata has no ${Dl} pin; run tangle solve clone again`)}if(!/^[0-9a-f]{64}$/i.test(t))throw Error(`The local ${Dl} pin is invalid`);if(await Ml(e)!==t.toLowerCase())throw Error(`${El} changed after clone; run tangle solve clone again`)}async function Fl(e,t){try{return await Al(e,[`ls-files`,`--error-unmatch`,`--`,t]),!0}catch{return!1}}async function Il(e){await Pl(e);for(let t of Ol)if(await Fl(e,t))throw Error(`${t} must remain untracked and local to this Solve workspace`);let t=await wl(`git`,[`-C`,e,`status`,`--porcelain=v1`,`--untracked-files=all`,`--ignored=matching`],{encoding:`utf8`,maxBuffer:1e6});if(String(t.stdout).split(/\r?\n/).filter(Boolean).filter(e=>{let t=e.slice(0,2),n=e.slice(3);return!((t===`??`||t===`!!`)&&Ol.has(n))}).length>0)throw Error(`Commit the candidate before running Solve. Only the local manifest and run record may remain uncommitted.`);return tl(await Al(e,[`rev-parse`,`HEAD`]),`submission revision`)}async function Ll(e,t,n,r={}){let i=await Rl(e,t,r);if(i)return{taskRepository:t.repository,taskRevision:t.taskRevision,submissionRepository:i,submissionRevision:n}}async function Rl(e,t,n={}){let r;try{r=sl(await Al(e,[`config`,`--get`,`remote.origin.pushurl`]))}catch{try{r=sl(await Al(e,[`config`,`--get`,`remote.origin.url`]))}catch{if(n.allowMissing)return;throw Error(`Add your GitHub fork as the 'origin' remote before submitting. The task repository is available as '${kl}'.`)}}let i=il(r,`git remote.origin.url`);if(i.toLowerCase()===t.repository.toLowerCase()){if(n.allowMissing)return;throw Error(`The 'origin' remote is the task repository. Add your GitHub fork as 'origin'; keep the task repository as '${kl}' before submitting.`)}return i}function zl(e,t){return!e||!t?!1:e.taskRepository.toLowerCase()===t.taskRepository.toLowerCase()&&e.taskRevision.toLowerCase()===t.taskRevision.toLowerCase()&&e.submissionRepository.toLowerCase()===t.submissionRepository.toLowerCase()&&e.submissionRevision.toLowerCase()===t.submissionRevision.toLowerCase()}function Bl(e,t){return`${e}/commit/${t}`}function Vl(e,t,n,r,i={}){let a=e.evidenceRefs.map(e=>ll(e.trim(),`checker evidence reference`));if(n){if(!t){if(i.allowMissingSource)return{evidence:e.evidence,evidenceRefs:a};throw Error(`Provenance policy requires a submission source`)}let o=cl(r);if(n.required&&(i.requirePullRequest??!0)&&!o)throw Error(`This competition requires a GitHub pull request`);a.push(Bl(t.taskRepository,t.taskRevision),Bl(t.submissionRepository,t.submissionRevision),...o?[o]:[])}return{evidence:e.evidence,evidenceRefs:[...new Set(a)]}}async function Hl(e,t){let n=`${e}.${process.pid}.tmp`;await S.writeFile(n,`${JSON.stringify(t,null,2)}\n`,{mode:384}),await S.rename(n,e)}async function Ul(e){let t=JSON.parse(await S.readFile(b.join(e,Tl),`utf8`));if(t.version!==1||typeof t.competition!=`string`)throw Error(`${Tl} has an unsupported format`);return t}async function Wl(e){let t=cl(e.pullRequest);if(!t)throw Error(`A pull request URL is required`);let n=new URL(t).pathname.split(`/`).filter(Boolean),r=await fetch(`https://api.github.com/repos/${n[0]}/${n[1]}/pulls/${n[3]}`,{headers:{Accept:`application/vnd.github+json`,"User-Agent":`tangle-solve-cli`},signal:AbortSignal.timeout(15e3)}),i=await r.json().catch(()=>null),a=e=>e.replace(/\/$/,``).toLowerCase();if(!r.ok||a(i?.base?.repo?.html_url??``)!==a(e.taskRepository)||i?.head?.sha?.toLowerCase()!==e.submissionRevision.toLowerCase()||a(i?.head?.repo?.html_url??``)!==a(e.submissionRepository))throw Error(`GitHub pull request must target the pinned task repository and contain the current committed submission`)}function Gl(e){return{...e.authorization?{authorization:e.authorization}:{},...e.stake?{stake:e.stake}:{},join:e.join,commit:e.commit,reveal:e.reveal,report:e.report,evaluation:e.evaluation}}const Kl=Ke(Ce);function ql(){return`Task source is '${kl}'. Add your fork as 'origin', commit your candidate, push it, and open a pull request before submitting.`}async function Jl(e,t,n){try{let r=J(await fl({path:`/v1/competitions/${encodeURIComponent(e)}`,apiUrl:n.apiUrl,profile:n.profile}),`competition response`),i=xl(r.competition??r),a=b.resolve(t??i.slug),o=M(`Cloning ${i.slug}…`);n.json||o.start();try{await Kl(`git`,[`clone`,`--no-tags`,`--origin`,kl,i.repository,a],{encoding:`utf8`,maxBuffer:1e6}),await Al(a,[`checkout`,`--detach`,i.taskRevision]);let e=await Al(a,[`rev-parse`,`HEAD`]);if(e.toLowerCase()!==i.taskRevision.toLowerCase())throw Error(`Pinned checkout resolved to ${e}, expected ${i.taskRevision}`);await Hl(b.join(a,`.tangle-solve.json`),i),await Nl(a)}finally{o.stop()}n.json?O({competition:i,directory:a}):(k(`Cloned ${i.slug} at ${i.taskRevision.slice(0,12)}`),i.provenance&&j(ql()),j(`Run the pinned checker with: cd ${a} && tangle solve run`))}catch(e){F(e)}}const Yl=12e4,Xl=rt(`event JobSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint8 jobIndex, address caller, bytes inputs)`),Zl=rt(`event JobCompleted(uint64 indexed serviceId, uint64 indexed callId)`),Ql=rt(`event JobResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, address indexed operator, bytes result)`),$l=rt(`event AggregatedResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint256 signerBitmap, bytes output)`),eu=rt(`event EvaluationAccepted(uint64 indexed serviceId, uint64 indexed competitionId, address indexed researcher, bytes32 candidateId, bytes32 submissionRefHash, bytes32 evaluationDigest, bytes32 metricsHash, bytes32 evidenceRefsHash)`),tu=[...nt([`function submitJob(uint64 serviceId, uint8 jobIndex, bytes inputs) payable returns (uint64 callId)`,`function getJobEventRate(uint64 blueprintId, uint8 jobIndex) view returns (uint256 rate)`,`function getServicePaymentAsset(uint64 serviceId) view returns (address)`,`function isPermittedCaller(uint64 serviceId, address caller) view returns (bool)`]),Xl,Zl,Ql,$l],nu=nt([`function authorizeSelf(uint64 serviceId)`,`function revokeSelf(uint64 serviceId)`,`function isDeviceRevoked(address device) view returns (bool)`,`function postStake(uint64 serviceId, uint64 competitionId) payable`,`function stakes(uint64 serviceId, uint64 competitionId, address researcher) view returns (uint256)`,`function pendingResults(uint64 serviceId, uint64 jobCallId) view returns (uint8 job, bytes32 outputHash, uint256 signerBitmap, bool exists, bool executed)`,`function executePendingResult(uint64 serviceId, uint64 jobCallId, bytes output)`,`function acceptedCandidates(uint64 serviceId, uint64 competitionId, address researcher, bytes32 candidateId) view returns (bool)`]),ru=nt([`function allowance(address owner, address spender) view returns (uint256)`,`function approve(address spender, uint256 amount) returns (bool)`]),iu=it(`uint64 competitionId, uint256 stakeWei`),au=it(`uint64 competitionId, bytes32 commitment`),ou=it(`uint64 competitionId, bytes32 commitment, string artifactRef, bytes32 salt`),su=it(`string artifactRef, bytes32 salt`),cu=it(`uint64 competitionId, bytes32 candidateId, string submissionRef, string evidenceJson, string evidenceRefsJson`),lu=it(`string status, string detail`),uu=/^0x[0-9a-f]{64}$/i;function du(e,t){if(e!==t)throw Error(`Tempo RPC returned chain ${e}; expected ${t}`)}function fu(e,t,n){return{...e,feePayer:!0,nonceKey:t,nonce:n}}function pu(e,t){if(e!==`success`)throw Error(`${t} transaction reverted`)}function mu(e,t,n,r){if(!uu.test(t))throw Error(`${n} transaction hash is invalid`);if(typeof e.transactionHash!=`string`||e.transactionHash.toLowerCase()!==t.toLowerCase())throw Error(`${n} receipt hash does not match the saved transaction`);if(pu(e.status??``,n),typeof e.from!=`string`||e.from.toLowerCase()!==r.from.toLowerCase())throw Error(`${n} receipt sender does not match the Solve device`);if(typeof e.to!=`string`||e.to.toLowerCase()!==r.to.toLowerCase())throw Error(`${n} receipt destination does not match the expected contract`)}function hu(e,t){return e>=t?[]:e>0n?[0n,t]:[t]}function gu(e,t,n=Date.now()){return n>=e+t}function _u(e,t){return e.filter(e=>e.args?.candidateId?.toLowerCase()===t.toLowerCase()).at(-1)?.transactionHash}function vu(e,t,n,r,i){for(let a of e.logs)if(a.address.toLowerCase()===t.tangleAddress.toLowerCase())try{let e=Xe({abi:[Xl],eventName:`JobSubmitted`,data:a.data,topics:a.topics});if(e.args.serviceId===t.serviceId&&e.args.jobIndex===n&&e.args.caller.toLowerCase()===r.toLowerCase()&&(!i||e.args.inputs.toLowerCase()===i.toLowerCase()))return e.args.callId}catch{}throw Error(`Tangle did not emit job ${n} for ${r}`)}function yu(e,t,n,r){for(let i of e.logs)if(i.address.toLowerCase()===t.managerAddress.toLowerCase())try{let e=Xe({abi:[eu],eventName:`EvaluationAccepted`,data:i.data,topics:i.topics}).args;if(e.serviceId===t.serviceId&&e.competitionId===t.competitionId&&e.researcher.toLowerCase()===n.address.toLowerCase()&&e.candidateId.toLowerCase()===r.toLowerCase())return!0}catch{}return!1}function bu(e){if(e.chainId!==st.id)throw Error(`Solve submissions require Tempo Moderato (chain ${st.id}); received ${e.chainId}`);if(!e.sponsorUrl)throw Error(`Solve submissions require a Tempo sponsor relay URL; unsponsored writes are disabled`);return{...st,name:e.chainName,nativeCurrency:{name:e.nativeSymbol,symbol:e.nativeSymbol,decimals:18},rpcUrls:{default:{http:[e.rpcUrl]}}}}async function xu(e,t){_l(e);let n=bu(e),r=qe({chain:n,transport:$e(e.rpcUrl)});return du(await r.getChainId(),e.chainId),await Su({publicClient:r},e),{publicClient:r,walletClient:Je({account:t,chain:n,transport:lt($e(e.rpcUrl),$e(e.sponsorUrl))}),account:t}}async function Su(e,t){let n=await e.publicClient.readContract({address:t.tangleAddress,abi:tu,functionName:`getServicePaymentAsset`,args:[t.serviceId]});if(n.toLowerCase()!==t.paymentAsset.toLowerCase())throw Error(`Tempo service payment asset ${n} does not match the trusted Solve asset ${t.paymentAsset}`)}async function Cu(e,t,n){let[r,i]=await Promise.all([e.publicClient.readContract({address:t.tangleAddress,abi:tu,functionName:`getJobEventRate`,args:[t.blueprintId,n]}),e.publicClient.readContract({address:t.tangleAddress,abi:tu,functionName:`getServicePaymentAsset`,args:[t.serviceId]})]);if(i.toLowerCase()!==t.paymentAsset.toLowerCase())throw Error(`Tempo job payment asset ${i} does not match the trusted Solve asset ${t.paymentAsset}`);return{asset:i,amount:r,value:i===`0x0000000000000000000000000000000000000000`?r:0n}}async function wu(e,t,n){return await e.publicClient.readContract({address:t,abi:ru,functionName:`allowance`,args:[e.account.address,n.tangleAddress]})}async function Tu(e,t,n,r,i,a){let o=Date.now();for(;!gu(o,a);){if((await e.publicClient.getLogs({address:t.tangleAddress,event:Zl,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`})).length>0){let a=(await e.publicClient.getLogs({address:t.tangleAddress,event:Ql,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`}))[0]?.args.result;if(!a)throw Error(`Tangle job ${n} completed without a result`);let[o,s]=Ye(lu,a);if(o!==i)throw Error(`Tangle job ${n} ${o}: ${s}`);return{status:o,detail:s}}await new Promise(e=>setTimeout(e,1e3))}throw Error(`Tangle job ${n} did not complete within 120 seconds`)}async function Eu(e,t,n,r,i){let a=Date.now();for(;!gu(a,i);){let i=(await e.publicClient.getLogs({address:t.tangleAddress,event:$l,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`}))[0]?.args.output;if(i)return i;await new Promise(e=>setTimeout(e,1e3))}throw Error(`Tangle job ${n} did not produce an aggregate within 120 seconds`)}async function Du(e,t,n){return!!await e.publicClient.readContract({address:t.managerAddress,abi:nu,functionName:`acceptedCandidates`,args:[t.serviceId,t.competitionId,e.account.address,n]})}const Ou=BigInt(tt(at(`tangle.solve.v1`)));async function ku(e,t){let n=await ct.nonce.getNonce(e.publicClient,{account:e.account.address,nonceKey:Ou});if(n>BigInt(2**53-1))throw Error(`The Solve transaction nonce exceeds the safe range`);return e.walletClient.writeContract(fu(t,Ou,Number(n)))}async function Au(e,t,n,r){if(!await e.publicClient.readContract({address:t.tangleAddress,abi:tu,functionName:`isPermittedCaller`,args:[t.serviceId,e.account.address]}))try{let i=r??await ku(e,{address:t.managerAddress,abi:nu,functionName:`authorizeSelf`,args:[t.serviceId]});if(r||await n?.(`authorization`,i),mu(await e.publicClient.waitForTransactionReceipt({hash:i}),i,`Authorization`,{from:e.account.address,to:t.managerAddress}),!await e.publicClient.readContract({address:t.tangleAddress,abi:tu,functionName:`isPermittedCaller`,args:[t.serviceId,e.account.address]}))throw Error(`authorization transaction did not add the device`);return i}catch(e){let t=e instanceof Error?e.message:`unknown chain error`;throw Error(`The competition manager did not authorize this device. The deployed manager must expose authorizeSelf(uint64): ${t}`)}}async function ju(e,t){let n=await ku(e,{address:t.managerAddress,abi:nu,functionName:`revokeSelf`,args:[t.serviceId]});return mu(await e.publicClient.waitForTransactionReceipt({hash:n}),n,`Revocation`,{from:e.account.address,to:t.managerAddress}),n}async function Mu(e,t,n,r,i=`allowance`,a={}){if(t.amount===0n||t.asset===`0x0000000000000000000000000000000000000000`)return;let o=await wu(e,t.asset,n);for(let s of hu(o,t.amount)){let o=s===0n?`${i}:reset`:`${i}:approval`,c=a[o];if(c){if(mu(await e.publicClient.waitForTransactionReceipt({hash:c}),c,s===0n?`ERC-20 allowance reset`:`ERC-20 allowance approval`,{from:e.account.address,to:t.asset}),await wu(e,t.asset,n)!==s)throw Error(`${s===0n?`ERC-20 allowance reset`:`ERC-20 allowance approval`} did not set the expected allowance`);continue}let l=await ku(e,{address:t.asset,abi:ru,functionName:`approve`,args:[n.tangleAddress,s]});await r?.(o,l),mu(await e.publicClient.waitForTransactionReceipt({hash:l}),l,s===0n?`ERC-20 allowance reset`:`ERC-20 allowance approval`,{from:e.account.address,to:t.asset})}}async function Nu(e,t,n,r,i,a=`job:${n}`,o={}){let s=await Cu(e,t,n);await Mu(e,s,t,i,`allowance:${a}`,o);let c=o[a],l=c??await ku(e,{address:t.tangleAddress,abi:tu,functionName:`submitJob`,args:[t.serviceId,n,r],value:s.value});c||await i?.(a,l);let u=await e.publicClient.waitForTransactionReceipt({hash:l});return mu(u,l,`Job ${n}`,{from:e.account.address,to:t.tangleAddress}),{hash:l,callId:vu(u,t,n,e.account.address,r),blockNumber:u.blockNumber}}async function Pu(e,t,n,r,i,a,o=`job:${n}`,s={}){let c=await Nu(e,t,n,r,a,o,s),l=await Tu(e,t,c.callId,c.blockNumber,i,Yl);return{...c,acknowledgement:l}}const Z={...X,chainName:`Tempo Moderato`,nativeSymbol:`TNT`},Fu={async read(e){let t=qe({chain:st,transport:$e(Z.rpcUrl,{timeout:15e3})}),n=e=>e.catch(()=>null),r=await Promise.all(e.map(async e=>{let[r,i]=await Promise.all([n(t.readContract({address:Z.tangleAddress,abi:tu,functionName:`isPermittedCaller`,args:[Z.serviceId,e]})),n(t.readContract({address:Z.managerAddress,abi:nu,functionName:`isDeviceRevoked`,args:[e]}))]);return[e.toLowerCase(),{permitted:r,revoked:i}]}));return new Map(r)},async revokeSelf(e){return ju(await xu(Z,e),Z)}},Iu={permitted:null,revoked:null};function Lu(e){return e.revoked?`revoked`:e.permitted===null?`unknown`:e.permitted?`permitted`:`not permitted`}async function Ru(e,t=Fu){try{let{devices:n}=await ml({apiUrl:e.apiUrl,profile:e.profile}),r=Jc()?.account.address.toLowerCase(),i=n.map(e=>({...e,local:e.address===r,status:e.revokedAt?`revoked`:`active`}));r&&!i.some(e=>e.local)&&i.push({address:r,local:!0,status:`unbound`,boundAt:null,lastUsedAt:null,revokedAt:null,revocationMethod:null,revocationReason:null});let a=await t.read(i.map(e=>Qe(e.address))),o=i.map(e=>({...e,onChain:a.get(e.address)??Iu}));if(e.json){O({serviceId:Z.serviceId.toString(),devices:o});return}P([`Address`,`Status`,`Local`,`Service ${Z.serviceId}`,`Last used`,`Revoked`],o.map(e=>[e.address,e.status,e.local?`yes`:``,Lu(e.onChain),e.lastUsedAt??``,e.revokedAt?`${e.revokedAt} (${e.revocationMethod})`:``]))}catch(t){F(t,e.json)}}async function zu(e,t,n=Fu){try{if(!et(e))throw Error(`${e} is not an EVM address`);let r=Qe(e),i=Jc(),a=i?.account.address===r;if(!t.yes){if(!process.stdin.isTTY)throw Error(`Revoking a device is permanent. Re-run with --yes to confirm`);if(!await z(`Permanently revoke Solve device ${r}${a?` (this machine's device)`:``}? [y/N] `,`--yes`)){j(`Revocation cancelled`);return}}let o;if(i&&a){let e=await pl({deviceAddress:r,purpose:`revoke`,apiUrl:t.apiUrl,profile:t.profile});o={challengeId:e.challengeId,signature:await i.account.signMessage({message:e.message})}}let s=await hl({deviceAddress:r,reason:t.reason,...o,apiUrl:t.apiUrl,profile:t.profile}),c=r.toLowerCase(),l=(await n.read([r])).get(c)??Iu,u;if(i&&a&&!l.revoked){try{u=await n.revokeSelf(i.account)}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`The Solve API revoked ${r}, but the on-chain revocation failed and the local key was kept: ${t}. Run the command again to retry`)}l=(await n.read([r])).get(c)??Iu}let d=i&&a&&l.revoked?Xc(i):void 0;if(t.json){O({...s,serviceId:Z.serviceId.toString(),onChain:l,...u?{revocationTransaction:u}:{},localKeyRetired:!!d});return}k(s.alreadyRevoked?`${r} was already revoked in the Solve API`:`Revoked ${r}; the Solve API refuses its signatures`),u&&k(`Revoked on Tempo in ${u}; service ${Z.serviceId} refuses its jobs`),d&&j("The local device key was moved aside because its address may still hold stake or rewards. Run `tangle solve account --create` for a new device"),!a&&l.permitted&&A(`The device can still submit jobs to service ${Z.serviceId}. Only its key, or the Solve blueprint owner, can revoke it on chain`)}catch(e){F(e,t.json)}}function Bu(e,t){return tt(Ze(su,[e.trim(),t]))}function Vu(e){let t=/^submission=(\S+)/.exec(e);if(!t?.[1])throw Error(`COMMIT_CANDIDATE did not return a submission reference`);return t[1]}async function Hu(e,t,n,r,i){let a=i.resumeTransactions?.evaluation;if(a){let n=await e.publicClient.waitForTransactionReceipt({hash:a});if(mu(n,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!yu(n,t,e.account,r))throw Error(`Saved evaluation transaction did not emit EvaluationAccepted for this candidate`);return a}let o=Date.now();for(;!gu(o,Yl);){if(await Du(e,t,r)){let i=_u(await e.publicClient.getLogs({address:t.managerAddress,event:eu,args:{serviceId:t.serviceId,competitionId:t.competitionId,researcher:e.account.address},fromBlock:n.blockNumber,toBlock:`latest`}),r);if(i)return i;throw Error(`Candidate is already accepted, but its EvaluationAccepted transaction is unavailable`)}let[a,o,,s,c]=await e.publicClient.readContract({address:t.managerAddress,abi:nu,functionName:`pendingResults`,args:[t.serviceId,n.callId]});if(s&&a!==4)throw Error(`Manager pending result ${n.callId} has unexpected job ${a}`);if(s&&c)throw Error(`Manager executed the report without EvaluationAccepted`);if(s&&!c){if(o.toLowerCase()!==tt(n.output).toLowerCase())throw Error(`Manager pending report output does not match the aggregate`);let a=await ku(e,{address:t.managerAddress,abi:nu,functionName:`executePendingResult`,args:[t.serviceId,n.callId,n.output]});await i.onTransaction?.(`evaluation`,a);let s=await e.publicClient.waitForTransactionReceipt({hash:a});if(mu(s,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!yu(s,t,e.account,r))throw Error(`Evaluation transaction did not emit EvaluationAccepted for this candidate`);return a}await new Promise(e=>setTimeout(e,1e3))}throw Error(`Manager did not emit EvaluationAccepted within 120 seconds`)}async function Uu(e,t,n,r={}){if(_l(e),!/^0x[0-9a-f]{64}$/i.test(n.salt))throw Error(`Reveal salt must be bytes32`);if(!n.artifactRef.trim())throw Error(`Candidate reference is required`);if(!n.evidenceJson.trim()||n.evidenceRefs.length===0)throw Error(`Checker evidence is required`);let i=await xu(e,t),a=await Au(i,e,r.onTransaction,r.resumeTransactions?.authorization),o,s=await i.publicClient.readContract({address:e.managerAddress,abi:nu,functionName:`stakes`,args:[e.serviceId,e.competitionId,i.account.address]});s<e.minStakeWei&&(o=await ku(i,{address:e.managerAddress,abi:nu,functionName:`postStake`,args:[e.serviceId,e.competitionId],value:e.minStakeWei-s}),await r.onTransaction?.(`stake`,o),mu(await i.publicClient.waitForTransactionReceipt({hash:o}),o,`Stake`,{from:i.account.address,to:e.managerAddress}));let c=Bu(n.artifactRef,n.salt),l=Ze(iu,[e.competitionId,e.minStakeWei]),u=Ze(au,[e.competitionId,c]),d=Ze(ou,[e.competitionId,c,n.artifactRef.trim(),n.salt]),f=await Pu(i,e,1,l,`joined`,r.onTransaction,`join`,r.resumeTransactions),p=await Pu(i,e,2,u,`committed`,r.onTransaction,`commit`,r.resumeTransactions),m=Vu(p.acknowledgement.detail),h=await Pu(i,e,3,d,`revealed`,r.onTransaction,`reveal`,r.resumeTransactions),g=await Nu(i,e,4,Ze(cu,[e.competitionId,c,m,n.evidenceJson,JSON.stringify(n.evidenceRefs)]),r.onTransaction,`report`,r.resumeTransactions),ee=await Eu(i,e,g.callId,g.blockNumber,Yl),te=await Hu(i,e,{callId:g.callId,output:ee,blockNumber:g.blockNumber},c,r);return{address:i.account.address,...a?{authorization:a}:{},...o?{stake:o}:{},join:f.hash,commit:p.hash,reveal:h.hash,report:g.hash,evaluation:te,candidateId:c,submissionRef:m}}const Wu=Ke(Ce),Gu=`/usr/bin/bwrap`,Ku=[`/usr`,`/bin`,`/sbin`,`/lib`,`/lib64`];function qu(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function Ju(e,t){if(!e||e.length>2048||qu(e))throw Error(`${t} contains invalid control characters or is too long`)}function Yu(e,t){let n=t;for(;n<e.length&&/\s/.test(e[n]??``);)n+=1;return n}function Xu(e,t){if(e[t]!==`"`)throw Error(`Checker output must be valid JSON`);let n=t+1;for(;n<e.length;){let t=e[n];if(t===`\\`){n+=2;continue}if(t===`"`)return n+1;if((t?.charCodeAt(0)??0)<32)throw Error(`Checker output must be valid JSON`);n+=1}throw Error(`Checker output must be valid JSON`)}function Zu(e,t,n){let r=new Set,i=Yu(e,t+1);if(e[i]===`}`)return i+1;for(;i<e.length;){let t=Xu(e,i),a=JSON.parse(e.slice(i,t));if(r.has(a))throw Error(`Checker output must not contain duplicate object keys`);if(r.add(a),i=Yu(e,t),e[i]!==`:`)throw Error(`Checker output must be valid JSON`);let o=Yu(e,i+1),s=$u(e,o);if(n?.(a,o,s),i=Yu(e,s),e[i]===`}`)return i+1;if(e[i]!==`,`)throw Error(`Checker output must be valid JSON`);i=Yu(e,i+1)}throw Error(`Checker output must be valid JSON`)}function Qu(e,t){let n=Yu(e,t+1);if(e[n]===`]`)return n+1;for(;n<e.length;){if(n=Yu(e,$u(e,n)),e[n]===`]`)return n+1;if(e[n]!==`,`)throw Error(`Checker output must be valid JSON`);n=Yu(e,n+1)}throw Error(`Checker output must be valid JSON`)}function $u(e,t){if(e[t]===`"`)return Xu(e,t);if(e[t]===`{`)return Zu(e,t);if(e[t]===`[`)return Qu(e,t);let n=t;for(;n<e.length&&!/[\s,\]}]/.test(e[n]??``);)n+=1;return n}function ed(e){let t=e.trim();if(Yu(t,$u(t,0))!==t.length)throw Error(`Checker output must be valid JSON`)}function td(e,t){let n=e.trim();if(n[0]!==`{`)return;let r;return Zu(n,0,(e,i,a)=>{e===t&&(r=n.slice(i,a).trim())}),r}function nd(e,t){let n=e.trim(),r=[];return Zu(n,0,(e,i,a)=>{if(e===`evidence_refs`)return;let o=e===`candidate_ref`?JSON.stringify(t):n.slice(i,a).trim();r.push(`${JSON.stringify(e)}:${o}`)}),`{${r.join(`,`)}}`}function rd(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Checker output must be one JSON object`)}if(ed(e),!t||typeof t!=`object`||Array.isArray(t))throw Error(`Checker output must be a JSON object`);let n=t,r=n.candidate_ref;if(typeof r!=`string`||!r.trim())throw Error(`Checker output must include candidate_ref`);let i=r.trim(),a=n.evidence_refs;if(!Array.isArray(a)||a.length===0||a.some(e=>typeof e!=`string`||!e.trim()))throw Error(`Checker output must include a non-empty evidence_refs array`);Ju(i,`candidate_ref`);for(let e of a)Ju(e.trim(),`evidence_refs`);let o,s;if(n.evidence_json!==void 0){if(!n.evidence_json||typeof n.evidence_json!=`object`||Array.isArray(n.evidence_json))throw Error(`Checker evidence_json must be an object`);o={...n.evidence_json};let t=td(e,`evidence_json`);if(!t)throw Error(`Checker evidence_json source text is missing`);if(s=t,o.candidate_ref!==i)throw Error(`Checker evidence_json candidate_ref must match candidate_ref`)}else{let{evidence_refs:t,...r}=n;o=r,o.candidate_ref=i,s=nd(e,i)}return{candidateRef:i,evidenceRefs:a.map(e=>e.trim()),evidence:o,evidenceJson:s}}async function id(e,t,n){let r=n.trim();if(r.startsWith(`{`)&&r.endsWith(`}`)||!t.result_file)return r;let i=await ud(e),a=b.resolve(i,t.result_file),o=b.relative(i,a);if(o.startsWith(`..`)||b.isAbsolute(o))throw Error(`Checker result_file must stay inside the competition repository`);let s;try{s=await S.lstat(a)}catch{throw Error(`Checker result_file must be an existing regular file inside the competition repository`)}if(s.isSymbolicLink())throw Error(`Checker result_file must not be a symbolic link`);if(!s.isFile())throw Error(`Checker result_file must be an existing regular file inside the competition repository`);let c;try{c=await S.realpath(a)}catch{throw Error(`Checker result_file must resolve to a regular file inside the competition repository`)}let l=b.relative(i,c);if(l.startsWith(`..`)||b.isAbsolute(l))throw Error(`Checker result_file must stay inside the competition repository`);return(await S.readFile(c,`utf8`)).trim()}function ad(e,t){let n=b.relative(e,t);return n===``||!n.startsWith(`..`)&&!b.isAbsolute(n)}function od(e){return Ku.some(t=>ad(t,e))}async function sd(e,t,n){let r=e.includes(`/`)?[b.resolve(t,e)]:(process.env.PATH??``).split(b.delimiter).filter(Boolean).map(t=>b.join(t,e));for(let i of r){let r;try{r=await S.realpath(i),await S.access(r,S.constants.X_OK)}catch{continue}if(!ad(t,r)&&!od(r)&&r!==n)throw Error(`Checker executable '${e}' must resolve inside the competition repository or a trusted runtime directory`);return r}throw Error(`Checker executable '${e}' was not found`)}async function cd(e){let t=[];for(let n of e)try{(await S.stat(n)).isDirectory()&&t.push(n)}catch{}return t}async function ld(e){let t=await S.realpath(be.homedir());if(e===b.parse(e).root||e===t)throw Error(`Solve checker repository must be a dedicated directory, not the filesystem or home root`)}async function ud(e){let t=await S.realpath(e);return await ld(t),t}async function dd(e){let t=b.join(e,`.git`),n;try{n=await S.lstat(t)}catch{return}if(n.isSymbolicLink())throw Error(`Solve checker repository .git must not be a symbolic link`);if(!n.isDirectory()&&!n.isFile())return;let r;try{let t={...process.env};for(let e of[`GIT_DIR`,`GIT_WORK_TREE`,`GIT_INDEX_FILE`,`GIT_OBJECT_DIRECTORY`,`GIT_ALTERNATE_OBJECT_DIRECTORIES`,`GIT_COMMON_DIR`,`GIT_CONFIG_COUNT`,`GIT_CONFIG_PARAMETERS`])delete t[e];let n=await Wu(`/usr/bin/git`,[`-C`,e,`rev-parse`,`--verify`,`HEAD^{commit}`],{encoding:`utf8`,maxBuffer:1e5,env:{...t,GIT_CONFIG_GLOBAL:`/dev/null`,GIT_CONFIG_SYSTEM:`/dev/null`,GIT_CONFIG_NOSYSTEM:`1`,GIT_TERMINAL_PROMPT:`0`}}),i=String(n.stdout).trim();/^[0-9a-f]{40}$/i.test(i)&&(r=i.toLowerCase())}catch{}return{kind:n.isDirectory()?`directory`:`file`,...r?{commit:r}:{}}}async function fd(e,t,n){let r=await ud(e);if(process.platform!==`linux`)throw Error(`Solve checkers require the Linux sandbox runtime (bubblewrap) with network isolation`);try{await S.access(Gu,S.constants.X_OK)}catch{throw Error(`Solve checkers require /usr/bin/bwrap; install bubblewrap or run the checker in a Tangle sandbox`)}let i=await sd(t,r,await S.realpath(process.execPath)),a=await dd(r),o=(await cd(Ku)).flatMap(e=>[`--ro-bind`,e,e]),s=ad(r,i)?`/work/${b.relative(r,i)}`:od(i)?i:`/checker/node`;!ad(r,i)&&!od(i)&&o.push(`--ro-bind`,i,`/checker/node`);let c=a?.kind===`directory`?[`--tmpfs`,`/work/.git`]:a?.kind===`file`?[`--ro-bind`,`/dev/null`,`/work/.git`]:[];return{executable:Gu,args:[`--die-with-parent`,`--new-session`,`--unshare-all`,`--clearenv`,...o,`--proc`,`/proc`,`--dev`,`/dev`,`--tmpfs`,`/tmp`,`--dir`,`/tmp/home`,`--bind`,r,`/work`,...c,`--chdir`,`/work`,`--setenv`,`HOME`,`/tmp/home`,...a?.commit?[`--setenv`,`TANGLE_SOLVE_COMMIT`,a.commit]:[],`--setenv`,`TMPDIR`,`/tmp`,`--setenv`,`PATH`,`/checker:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`,`--setenv`,`LANG`,`C.UTF-8`,`--setenv`,`PYTHONDONTWRITEBYTECODE`,`1`,`--setenv`,`XDG_CONFIG_HOME`,`/tmp/home/.config`,`--setenv`,`XDG_CACHE_HOME`,`/tmp/home/.cache`,`--setenv`,`XDG_DATA_HOME`,`/tmp/home/.local/share`,`--setenv`,`GIT_CONFIG_GLOBAL`,`/dev/null`,`--setenv`,`GIT_CONFIG_SYSTEM`,`/dev/null`,`--setenv`,`NPM_CONFIG_USERCONFIG`,`/dev/null`,s,...n]}}async function pd(e,t){if(!t.command||t.command.includes(`/../`)||qu(t.command))throw Error(`The competition checker command is invalid`);if(!Array.isArray(t.args))throw Error(`The competition checker arguments must be an array`);for(let e of t.args)Ju(e,`Checker argument`);let n=t.timeout_ms??15*6e4;if(!Number.isSafeInteger(n)||n<1e3||n>60*6e4)throw Error(`Checker timeout must be between one second and one hour`);let r=await ud(e),i;try{let e=await fd(r,t.command,t.args);i=await Wu(e.executable,e.args,{cwd:r,timeout:n,maxBuffer:4194304,encoding:`utf8`})}catch(e){let t=e,n=t.stderr?.trim()||t.stdout?.trim()||t.message||`checker failed`;throw Error(`Pinned checker failed: ${n}`)}let a=String(i.stdout),o=String(i.stderr);return{...rd(await id(r,t,a)),stdout:a,stderr:o}}async function md(e,t){try{let{root:n,manifest:a}=await jl(e,t.directory),o=await Il(n),s=a.provenance?await Ll(n,a,o,{allowMissing:!0}):void 0,c=Yc(),l=M(`Running ${a.title} checker…`);t.json||l.start();let u;try{u=await pd(n,a.checker)}finally{l.stop()}let d=Vl(u,s,a.provenance,void 0,{allowMissingSource:!0,requirePullRequest:!1}),f=ot(r(32)),p=Bu(u.candidateRef,f),m={version:1,competition:a.slug,candidateRef:u.candidateRef,evidence:d.evidence,evidenceJson:u.evidenceJson,evidenceRefs:d.evidenceRefs,salt:f,candidateId:p,...s?{source:s}:{},deviceAddress:c.account.address,clientSubmissionId:i(),createdAt:new Date().toISOString()};await Hl(b.join(n,`.tangle-solve-run.json`),m),t.json?O({localRun:m}):(k(`Checker output recorded locally for operator evaluation`),N({Competition:a.slug,Candidate:u.candidateRef,"Device address":c.account.address,"Evidence refs":d.evidenceRefs.length}),j("Commit any changes, then run `tangle solve submit` from this directory."),a.provenance&&!s&&j(`Add your GitHub fork as 'origin' before submitting. The task repository is available as '${kl}'.`))}catch(e){F(e)}}const hd=/^0x[0-9a-f]{64}$/i;async function gd(e){let t=await pl({deviceAddress:e.deviceAddress,apiUrl:e.apiUrl,profile:e.profile}),n=await e.signer.signMessage({message:t.message});return{walletChallengeId:t.challengeId,walletSignature:n}}async function _d(e,t){try{let{root:n,manifest:r}=await jl(e,t.directory);ul({profile:t.profile});let i=await Il(n),a=await Ul(n);if(a.competition!==r.slug)throw Error(`.tangle-solve-run.json does not match this competition`);if(!hd.test(a.salt)||!hd.test(a.candidateId))throw Error("This run predates durable candidate identity. Run `tangle solve run` again");let o=r.provenance?await Ll(n,r,i):void 0;if(r.provenance&&a.source&&!zl(a.source,o))throw Error("The saved run points to a different repository or revision. Keep your fork as 'origin' and run `tangle solve run` again before submitting");let s=Jc();if(!s)throw Error("No Solve device signer found. Run `tangle solve run` first");if(s.account.address.toLowerCase()!==a.deviceAddress.toLowerCase())throw Error("The local Solve device account changed after `tangle solve run`; run the checker again");let c=M(`Checking the committed candidate…`);t.json||c.start();let l;try{l=await pd(n,r.checker)}finally{c.stop()}if(l.candidateRef!==a.candidateRef||l.evidenceJson!==a.evidenceJson)throw Error("The committed checker output changed after `tangle solve run`; run the checker again");if(Bu(l.candidateRef,a.salt).toLowerCase()!==a.candidateId.toLowerCase())throw Error(`The saved candidate identity does not match the checker output; run the checker again`);let u=cl(t.prUrl);if(!r.provenance&&u)throw Error(`This competition does not accept GitHub pull request provenance`);if(u){if(!o)throw Error(`A provenance policy is required for a pull request`);await Wl({pullRequest:u,taskRepository:o.taskRepository,submissionRepository:o.submissionRepository,submissionRevision:i})}let d=Vl(l,o,r.provenance,u,{requirePullRequest:!0}),f={...a,...o?{source:o}:{},chainState:{status:`submitting`,transactions:{...a.chainState?.transactions??{}}}},p=b.join(n,`.tangle-solve-run.json`);await Hl(p,f);let m=M(`Submitting candidate to Tempo…`);t.json||m.start();let h;try{h=await Uu(Sl(r),s.account,{artifactRef:l.candidateRef,salt:a.salt,evidenceJson:l.evidenceJson,evidenceRefs:d.evidenceRefs},{resumeTransactions:f.chainState?.transactions,onTransaction:async(e,t)=>{f={...f,chainState:{status:`submitting`,transactions:{...f.chainState?.transactions??{},[e]:t}}},await Hl(p,f)}})}finally{m.stop()}f={...f,chainReceipt:h,chainState:{status:`accepted`,transactions:{...f.chainState?.transactions??{},...Gl(h)}}},await Hl(p,f);let g=await gd({deviceAddress:h.address,signer:s.account,apiUrl:t.apiUrl,profile:t.profile}),ee=await fl({path:`/v1/submissions`,method:`POST`,apiUrl:t.apiUrl,profile:t.profile,body:{competition:r.slug,candidateRef:l.candidateRef,candidateId:h.candidateId,evidenceJson:l.evidenceJson,evidenceRefs:d.evidenceRefs,deviceAddress:h.address,reportTxHash:h.report,evaluationTxHash:h.evaluation,transactions:Gl(h),...r.provenance&&o?{source:{...o,...u?{pullRequest:u}:{}}}:{},clientSubmissionId:a.clientSubmissionId,...g,...t.model?{model:t.model}:{},...t.note?{note:t.note}:{}}});t.json?O({...ee,transactions:Gl(h),candidateId:h.candidateId}):(k(`Submission accepted on Tempo`),N({Competition:r.slug,Candidate:h.candidateId,"Device address":h.address,"Report transaction":h.report,"Evaluation transaction":h.evaluation,"Submission ID":typeof ee.id==`string`?ee.id:ee.submission?.id}))}catch(e){F(e)}}function vd(){let e=new t(`solve`).description(`Participate in Tangle Solve competitions`);e.command(`clone <competition>`).description(`Clone the pinned competition repository`).argument(`[directory]`,`Destination directory`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).option(`--json`,`Output JSON`).action(Jl),e.command(`run [competition]`).description(`Run the competition checker and record its evidence`).option(`--directory <path>`,`Competition directory (defaults to the current directory)`).option(`--json`,`Output JSON`).action(md),e.command(`submit [competition]`).description(`Submit checker evidence through the device account and Tempo`).option(`--directory <path>`,`Competition directory (defaults to the current directory)`).option(`--pr-url <url>`,`GitHub pull request containing the submission`).option(`--model <name>`,`Model used to produce the submission`).option(`--note <text>`,`Short note shown with the accepted submission`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).option(`--json`,`Output JSON`).action(_d),e.command(`account`).description(`Show the local Solve signing account`).option(`--create`,`Create the account if it does not exist`).option(`--json`,`Output JSON`).action(Zc);let n=e.command(`device`).description(`List and revoke the Solve devices bound to your account`);return n.command(`list`).description(`List your devices and whether each may submit jobs on Tempo`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).option(`--json`,`Output JSON`).action(e=>Ru(e)),n.command(`revoke <address>`).description(`Permanently revoke a device; the local device is revoked with its own key`).option(`--reason <text>`,`Why the device is revoked (shown to the account)`).option(`--yes`,`Confirm the permanent revocation without a prompt`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).option(`--json`,`Output JSON`).action((e,t)=>zu(e,t)),e}function yd(e,t){return`tangle ssh-proxy ${e.replace(/\/+$/,``)}/v1/sidecar-proxy/${t}/ssh`}function bd(e){return/^[A-Za-z0-9_/:=@%+.,-]+$/.test(e)?e:`'${e.replace(/'/g,`'"'"'`)}'`}function xd(e){return`'${e.replace(/'/g,`''`)}'`}function Sd(e){return e===`win32`?`NUL`:`/dev/null`}function Cd(e,t){return t===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN=${xd(`<token>`)}; ssh ${e.map(xd).join(` `)}`:`TANGLE_SSH_PROXY_AUTH_TOKEN=${bd(`<token>`)} ssh ${e.map(bd).join(` `)}`}function wd(e){return e.connection!==void 0&&!e.connection.ssh}function Td(){ir(`SSH is not enabled for this sandbox.`),j(`Create a sandbox with --ssh to enable SSH access.`),process.exit(1)}function Ed(e,t=[],n=process.platform){let r=Sd(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 Dd(){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=T({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=E(r),a=M(`Getting SSH credentials...`);a.start();let o=await L(i,r,e);if(wd(o)){a.stop(),Td();return}o=await R(o);let s=await o.ssh();if(a.stop(),!s){Td();return}let c={...s,proxyCommand:yd(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=Ed(c,[...n.identityFile?[`-i`,n.identityFile,`-o`,`IdentitiesOnly=yes`]:[],...t]);if(n.print){console.log(Cd(l,process.platform));return}j(`Connecting via tunnel...`);let u=Te(`ssh`,l,{stdio:`inherit`,env:{...process.env,TANGLE_SSH_PROXY_AUTH_TOKEN:r.apiKey}});u.on(`error`,e=>{e.code===`ENOENT`&&(ir(`SSH client not found. Please install OpenSSH.`),process.exit(1)),F(e)}),u.on(`exit`,e=>{process.exit(e??0)})}catch(e){F(e)}})}function Od(){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=M(`Fetching SSH keys...`);try{t.start();let n=await E(T(e)).sshKeys.list();t.stop(),e.json?O({sshKeys:n}):n.length===0?j(`No SSH keys found.`):P([`Name`,`Type`,`Fingerprint`,`Created`],n.map(e=>[e.name,e.keyType,e.fingerprint,e.createdAt.toLocaleString()]))}catch(e){t.stop(),F(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=M(`Adding SSH key...`);try{let r=y(t.keyFile,`utf8`).trim();n.start();let i=await E(T(t)).sshKeys.create(e,r);n.stop(),t.json?O({sshKey:i}):k(`Added SSH key ${i.name} (${i.fingerprint})`)}catch(e){n.stop(),F(e)}}),e.command(`delete`).description(`Delete SSH key`).argument(`<name>`,`SSH key name or ID`).action(async(e,t)=>{let n=M(`Deleting SSH key...`);try{n.start(),await E(T(t)).sshKeys.delete(e),n.stop(),k(`Deleted SSH key ${e}`)}catch(e){n.stop(),F(e)}}),e}function kd(e,t=1){process.stderr.write(`${e}\n`),process.exit(t)}function Ad(){return new t(`ssh-proxy`).description(`SSH proxy helper that pipes stdin/stdout to WebSocket`).argument(`<runtime-url>`,`Runtime WebSocket URL`).action(async e=>{let t=process.env.TANGLE_SSH_PROXY_AUTH_TOKEN;t||kd(`TANGLE_SSH_PROXY_AUTH_TOKEN not set`);let n=new ut(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===ut.OPEN&&n.ping()},15e3),r.unref?.(),process.stdin.on(`data`,e=>{n.readyState===ut.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(),kd(`WebSocket error: ${e.message}`)}),n.on(`close`,e=>{i(),process.exit(e===1e3?0:1)}),process.stdin.on(`error`,()=>n.close())})}const jd=[`claude-code`,`opencode`,`codex`,`kimi-code`,`prime`],Md=[`project`,`read-only`],Nd={min:1,max:15},Pd=process.env.TANGLE_ROUTER_URL??`https://router.tangle.tools/v1`;function Fd(e){let t=s(e);if(t)return t;throw Error(`--model '${e}' has no provider. Pass a canonical id, for example 'google/${e}'.`)}function Id(e,t){return{...e,harness:t}}function Ld(e){let t=e.harness??`claude-code`;if(!jd.includes(t))throw Error(`Unknown --harness '${t}'. Supported: ${jd.join(`, `)}.`);let n=e.tokenScope??`project`;if(!Md.includes(n))throw Error(`Unknown --token-scope '${n}'. Supported: ${Md.join(`, `)}.`);let r=Rd(e.maxTokens,2e5,`--max-tokens`),i=Rd(e.maxIterations,50,`--max-iterations`),a=Rd(e.tokenTtl,10,`--token-ttl`);if(a<Nd.min||a>Nd.max)throw Error(`--token-ttl ${a} out of range; the SDK clamps to [${Nd.min}, ${Nd.max}] minutes.`);let o=e.maxWorkers===void 0?void 0:Rd(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 Rd(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 zd(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 Bd(e){let{client:t,scope:n,ttlMinutes:r,onScope:i}=e;return{async create(e){let a=await t.create(Vd(e)),o={scope:n,ttlMinutes:r},s=await a.mintScopedToken(o);return i({id:a.id,scope:s.scope,expiresAt:s.expiresAt,status:`spawned`}),a}}}function Vd(e){if(!e?.env)return e;let{TANGLE_API_KEY:t,...n}=e.env;return{...e,env:n}}function Hd(e){let t=e.spentTotal,n={tokenUsage:{input:t.tokensKnown===!1?null:t.tokens.input,output:t.tokensKnown===!1?null:t.tokens.output},costUsd:t.usdKnown===!1?null:t.usd};if(e.kind===`no-winner`)return{text:``,...n,status:`no-winner (${e.reason})`};let r=e.out;return{text:typeof r==`string`?r:Ud(r)?r.content:JSON.stringify(r),...n,status:`winner`}}function Ud(e){return typeof e==`object`&&!!e&&typeof e.content==`string`}let Wd=null;function Gd(){return Wd??=import(`@tangle-network/agent-runtime/kernel`).catch(e=>{throw Wd=null,e?.code===`ERR_MODULE_NOT_FOUND`?Error("`tangle supervise` needs @tangle-network/agent-runtime, which no longer installs with the CLI. Install it alongside the CLI (for example `npm install @tangle-network/agent-runtime`) and retry.",{cause:e}):e}),Wd}const Kd={makeClient:e=>E(T({apiKey:e.apiKey,baseUrl:e.baseUrl})),resolveRouter:e=>({routerBaseUrl:Pd,routerKey:T({apiKey:e.apiKey}).apiKey}),supervise:async(e,t,n)=>(await Gd()).supervise(e,t,n)};async function qd(e,t,n,r=Kd){let a=r.makeClient({apiKey:n.apiKey,baseUrl:n.baseUrl}),{budget:o,perWorker:s}=zd(t),c=[],l=Bd({client:a,scope:t.tokenScope,ttlMinutes:t.tokenTtl,onScope:e=>{if(c.push(e),!n.json){let n=`ttl ${t.tokenTtl}m`;j(`worker ${e.id} [${e.scope} token ${n}] spawned`)}}}),u=(await Gd()).workerFromBackend({backend:`sandbox`,sandboxClient:l,maxIterations:1}),d=(e,n)=>u(Id(e,t.harness),n),f={name:`supervisor`,harness:`cli-base`,model:{default:t.model??`gemini-2.5-flash-lite`,provider:t.model?Fd(t.model):`google`}},p=r.resolveRouter({apiKey:n.apiKey}),m=Hd(await r.supervise(f,{goal:e},{budget:o,makeWorkerAgent:d,router:p,...s?{perWorker:s}:{},...t.model?{allowedModels:[t.model]}:{},runId:`supervise-${i()}`})),h=m.status===`winner`?`settled`:`failed`;for(let e of c)e.status=h,n.json||j(`worker ${e.id} [${e.scope} token ttl ${t.tokenTtl}m] settled (${e.status})`);return{task:e,result:m.text,workers:c,tokenUsage:m.tokenUsage,costUsd:m.costUsd,status:m.status}}function Jd(){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 (${jd.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 (${Md.join(` | `)})`,`project`).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=Ld({harness:t.harness,model:t.model,maxTokens:t.maxTokens,maxIterations:t.maxIterations,tokenScope:t.tokenScope,tokenTtl:t.tokenTtl,maxWorkers:t.maxWorkers});t.json||(j(`Supervising: ${e}`),j(`harness=${n.harness} budget=${n.maxTokens}tok/${n.maxIterations}it scope=${n.tokenScope} ttl=${n.tokenTtl}m`),console.log());let r=await qd(e,n,{apiKey:t.apiKey,baseUrl:t.baseUrl,json:t.json});if(t.json){O(r),r.status!==`winner`&&(process.exitCode=1);return}if(console.log(),r.result&&(console.log(r.result),console.log()),N({"Input Tokens":r.tokenUsage.input??`Unavailable`,"Output Tokens":r.tokenUsage.output??`Unavailable`,Cost:r.costUsd===null?`Unavailable`:`$${r.costUsd.toFixed(4)}`}),r.status!==`winner`)throw Error(`Supervisor finished without a winner: ${r.status}`)}catch(e){F(e,t.json)}}),e}function Yd(){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=T(e),n=E(t),r=e.json?null:M(`Fetching teams...`);r?.start();let i=await n.teams.list();if(r?.stop(),e.json){O({teams:i,activeTeamId:t.activeTeamId??null});return}D(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){F(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=T(t),r=E(n),i=t.json?null:M(`Creating team...`);i?.start();let a=await r.teams.create({name:e,orgId:t.orgId});if(t.switch&&xc(a,n.profile),i?.stop(),t.json){O({team:a,active:!!t.switch});return}k(`Team created: ${yc(a)}`),t.switch&&k(`Active team set to ${a.name}`)}catch(e){F(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=T(t),r=await bc(E(n),e);if(xc(r,n.profile),t.json){O({team:r,activeTeamId:r.id});return}k(`Active team set to ${yc(r)}`)}catch(e){F(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=Pn(e.profile);if(e.json){O(t.activeTeamId?t:{activeTeamId:null});return}if(!t.activeTeamId){console.log(`No active team.`);return}N({ID:t.activeTeamId,Name:t.activeTeamName})}catch(e){F(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(Sc(e.profile),e.json){O({activeTeamId:null});return}k(`Active team cleared.`)}catch(e){F(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=T(t),r=E(n),i=await q(r,e,n.profile),a=await r.teams.listMembers(i.id);if(t.json){O({team:i,members:a});return}D(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){F(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=T(t),r=E(n),i=await q(r,t.team,n.profile),a=Xd(t.role),o=await r.teams.updateMember(i.id,e,{role:a});if(t.json){O({team:i,member:o});return}k(`Member updated: ${o.customerEmail}`),N({Team:i.name,Role:o.role,Status:o.status})}catch(e){F(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=T(t),r=E(n),i=await q(r,t.team,n.profile),a=Xd(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){O({team:i,invitation:o});return}k(`Invitation created for ${o.email}`),N({Team:i.name,Role:o.role,Expires:o.expiresAt,"Invitation ID":o.id}),k(`Re-run with --json to retrieve the invitation token for sharing.`)}catch(e){F(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=T(t),r=E(n),i=await q(r,e,n.profile);if(!t.force&&!t.json&&!await z(`Leave team '${i.name}'? (y/N) `,`--force`))return;if(await r.teams.leave(i.id),n.activeTeamId===i.id&&Sc(n.profile),t.json){O({success:!0,teamId:i.id});return}k(`Left team: ${i.name}`)}catch(e){F(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=T(n),i=E(r),a=await q(i,t,r.profile);if(!n.force&&!n.json&&!await z(`Transfer ownership of '${a.name}' to ${e}? This cannot be undone without the new owner's cooperation. (y/N) `,`--force`))return;if(await i.teams.transferOwnership(a.id,e),n.json){O({success:!0,teamId:a.id,newOwnerCustomerId:e});return}k(`Ownership transferred for ${a.name}`)}catch(e){F(e)}}),e.addCommand(Zd()),e.addCommand(Qd()),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=T(t),r=E(n),i=await q(r,e,n.profile),a=await r.teams.listInvitations(i.id);if(t.json){O({team:i,invitations:a});return}D(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){F(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=T(t),r=E(n),i=await r.teams.acceptInvitation(e),a=t.switch===!1?null:await r.teams.get(i.teamId);if(a&&xc(a,n.profile),t.json){O({member:i,activeTeamId:a?.id??null});return}k(`Invitation accepted for team ${i.teamId}`),a&&k(`Active team set to ${a.name}`)}catch(e){F(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 E(T(t)).teams.revokeInvitation(e),t.json){O({success:!0,invitationId:e});return}k(`Invitation revoked: ${e}`)}catch(e){F(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=T(t),r=E(n),i=await q(r,t.team,n.profile);if(await r.teams.removeMember(i.id,e),t.json){O({success:!0,teamId:i.id,memberId:e});return}k(`Member removed: ${e}`)}catch(e){F(e)}}),e}function Xd(e){if(e===`admin`||e===`member`||e===`viewer`)return e;throw Error(`Role must be one of: admin, member, viewer`)}function Zd(){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=T(t),r=E(n),i=await q(r,e,n.profile),a=await r.teams.listSecrets(i.id);if(t.json){O({team:i,secrets:a});return}D(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){F(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=T(n),i=E(r),a=await q(i,n.team,r.profile),o=await $d({value:t,valueStdin:n.valueStdin,prompt:`Enter value for team secret '${e}': `}),s=await i.teams.upsertSecret(a.id,e,o);if(n.json){O({team:a,secret:s});return}k(`Team secret saved: ${s.name}`)}catch(e){F(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=T(t),r=E(n),i=await q(r,t.team,n.profile);if(!t.force&&!t.json&&!await z(`Delete team secret '${e}' from '${i.name}'? (y/N) `,`--force`))return;if(await r.teams.deleteSecret(i.id,e),t.json){O({success:!0,teamId:i.id,name:e});return}k(`Team secret deleted: ${e}`)}catch(e){F(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=T(t),r=E(n),i=await q(r,t.team,n.profile),a=await r.teams.revealSecret(i.id,e);if(t.json){O({teamId:i.id,...a});return}console.log(a.value)}catch(e){F(e)}}),e}function Qd(){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=T(t),r=E(n),i=await q(r,e,n.profile),a=await r.teams.listTemplates(i.id);if(t.json){O({team:i,templates:a});return}if(a.length===0){console.log(`No templates yet for ${i.name}.`);return}D(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){F(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=T(n),i=E(r),a=await q(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){O({team:a,template:s});return}k(`Team template created: ${s.name} (${s.id})`)}catch(e){F(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=T(t),r=E(n),i=await q(r,t.team,n.profile);if(!t.force&&!t.json&&!await z(`Delete template '${e}' from '${i.name}'? (y/N) `,`--force`))return;if(await r.teams.deleteTemplate(i.id,e),t.json){O({success:!0,teamId:i.id,templateId:e});return}k(`Team template deleted: ${e}`)}catch(e){F(e)}}),e}async function $d(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 qr();if(e.length===0)throw Error(`Secret value from stdin cannot be empty`);return e}let t=await Gr(e.prompt);if(t.length===0)throw Error(`Secret value cannot be empty`);return t}function ef(e){return{...e.timeout===void 0?{}:{timeoutMs:Number(e.timeout)*1e3},resumeJobId:e.resumeJob,onProgress:e=>{process.stderr.write(`Publication ${e.id}: ${e.status}\n`)}}}function tf(){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=E(T(e)),n=e.featured?await t.publicTemplates.featured():await t.publicTemplates.list({query:e.query,tag:e.tag});if(e.json){O({templates:n});return}D(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(t){F(t,e.json)}}),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 E(T(t)).publicTemplates.get(e);if(t.json){O({template:n});return}O(n)}catch(e){F(e,t.json)}}),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 E(T(t)).publicTemplates.versions(e);if(t.json){O({versions:n});return}D(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){F(e,t.json)}}),e.command(`publish <name> <snapshot-id> <sandbox-id>`).option(`--timeout <seconds>`,`Maximum wait for publication`).option(`--resume-job <id>`,`Resume an accepted publication for this snapshot`).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 E(T({...r,timeout:void 0})).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},ef(r));if(r.json){O({template:i});return}k(`Published template: ${i.slug}`)}catch(e){F(e,r.json)}}),e.command(`publish-version <id-or-slug> <snapshot-id> <sandbox-id>`).option(`--timeout <seconds>`,`Maximum wait for publication`).option(`--resume-job <id>`,`Resume an accepted publication for this snapshot`).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 E(T({...r,timeout:void 0})).publicTemplates.publishVersion(e,{snapshotId:t,sourceSandboxId:n,readmeMarkdown:r.readme,tags:r.tags,releaseNotes:r.releaseNotes},ef(r));if(r.json){O({version:i});return}k(`Published template version: ${i.id}`)}catch(e){F(e,r.json)}}),e}function nf(){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=T({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=E(n),i=M(`Fetching tools...`);t.json||i.start();let a=await(await L(r,n,e)).tools.list();i.stop(),t.json?O(a):a.length===0?console.log(`No tools installed`):P([`Tool`,`Version`,`Active`],a.map(e=>[e.name,e.version,e.active?`yes`:`no`]))}catch(e){F(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=T({apiKey:r.apiKey,baseUrl:r.baseUrl}),a=E(i),o=M(`Installing ${t}@${n}...`);r.json||o.start(),await(await L(a,i,e)).tools.install(t,n),o.stop(),r.json?O({tool:t,version:n,installed:!0}):k(`Installed ${t}@${n}`)}catch(e){F(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=T({apiKey:r.apiKey,baseUrl:r.baseUrl});await(await L(E(i),i,e)).tools.use(t,n),k(`Activated ${t}@${n}`)}catch(e){F(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=T({apiKey:r.apiKey,baseUrl:r.baseUrl}),a=E(i),o=M(`Running ${t} ${n.join(` `)}...`);r.json||o.start();let s=await(await L(a,i,e)).tools.run(t,n);o.stop(),r.json?O(s):(s.stdout&&process.stdout.write(s.stdout),s.stderr&&process.stderr.write(s.stderr),s.exitCode!==0&&process.exit(s.exitCode))}catch(e){F(e)}}),e}function rf(){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:hf(e.status),q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:bf(e.limit)},n=of(e),r=e.json?null:M(`Fetching traces...`);r?.start();let i=await n.listTraces(t);if(r?.stop(),e.json)return O(i);lf(i.items),pf(i.nextCursor)}catch(t){cf(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=of(t);if(t.ndjson){await sf(n,e);return}let r=t.json?null:M(`Fetching trace spans...`);r?.start();let i=await n.getTraceSpans(e,{cursor:t.cursor,limit:t.limit===void 0?void 0:bf(t.limit)});if(r?.stop(),t.json)return O(i);uf(i.items),i.truncated&&N({Spans:`${i.items.length} of ${i.total} (truncated)`}),pf(i.nextCursor)}catch(e){cf(e,t)}}),e.addCommand(af()),e}function af(){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:_f(e.status),gate:e.gate===void 0?void 0:yf(e.gate),label:e.label,from:e.from,to:e.to,q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:bf(e.limit)},n=of(e),r=e.json?null:M(`Fetching runs...`);r?.start();let i=await n.listRuns(t);if(r?.stop(),e.json)return O(i);df(i.items),pf(i.nextCursor)}catch(t){cf(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=of(t),r=t.json?null:M(`Fetching run...`);r?.start();let i=await n.getRun(e);if(r?.stop(),t.json)return O(i);ff(i)}catch(e){cf(e,t)}}),e}function of(e){let t=Cn(e.apiKey);if(!t)throw Error(`No API key found. Set TANGLE_API_KEY or run: tangle auth login`);return dt({apiKey:t,baseUrl:e.baseUrl??process.env.TANGLE_INTELLIGENCE_BASE_URL})}async function sf(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 cf(e,t){return F(e,t.json===!0)}function lf(e){D(e.map(e=>({traceId:e.traceId,root:e.rootName??`-`,model:e.model??`-`,spans:e.spanCount,errors:e.errorCount,durationMs:e.durationMs,cost:mf(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 uf(e){D(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 df(e){D(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 ff(e){N({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 pf(e){e&&N({"Next page":`--cursor ${e}`})}function mf(e){return e===null?`-`:`$${e.toFixed(4)}`}function hf(e){if(e===`ERROR`||e===`OK`)return e;throw Error(`--status must be ERROR or OK`)}const gf=[`started`,`baseline-complete`,`generation-complete`,`gate-decided`,`finished`,`errored`];function _f(e){let t=gf.find(t=>t===e);if(t)return t;throw Error(`--status must be one of ${gf.join(`, `)}`)}const vf=[`ship`,`hold`,`need_more_work`,`model_ceiling`,`arch_ceiling`];function yf(e){let t=vf.find(t=>t===e);if(t)return t;throw Error(`--gate must be one of ${vf.join(`, `)}`)}function bf(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function xf(){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=E(T({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=e.json?null:M(`Fetching usage...`);n?.start();let[r,i]=await Promise.all([t.usage(),t.subscription().catch(()=>null)]);n?.stop(),e.json?O({...r,subscription:i}):(console.log(),console.log(`Account Usage`),console.log(`─`.repeat(40)),N({"Active Sandboxes":r.activeSandboxes,"Total Sandboxes":r.totalSandboxes,"Compute Minutes":Sf(r.computeMinutes),"GPU Seconds":r.gpuSeconds,"GPU Spend":Cf(r.gpuCostUsd)}),i&&(console.log(),console.log(`Subscription`),console.log(`─`.repeat(40)),N({Plan:i.plan,Status:i.status,"Credits Available":Cf(i.creditsAvailableUsd),"Credits Used":Cf(i.creditsUsedUsd),"Monthly Balance":Cf(i.monthlyBalanceUsd)})),console.log(),console.log(`Billing Period`),console.log(`─`.repeat(40)),N({Start:r.periodStart.toLocaleDateString(),End:r.periodEnd.toLocaleDateString()}),console.log())}catch(e){F(e)}})}function Sf(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 Cf(e){return e<0?`-$${(-e).toFixed(2)}`:`$${e.toFixed(2)}`}function wf(){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){hn(),j(`Cleared the active sandbox.`);return}if(e){mn(e),j(`Active sandbox set to ${e}. Commands now default to it; override with --box or TANGLE_SANDBOX.`);return}let n=pn();j(n?`Active sandbox: ${n}`:"No active sandbox. Set one with `tangle use <id>`.")}catch(e){F(e)}})}const Tf=1e3;function Ef(){let e=new t(`workflows`).description(`Create and manage Tangle workflows`);e.option(`--json`,`Output as JSON`),e.hook(`preAction`,(e,t)=>{kf(t)}),e.command(`list`).description(`List your workflows`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async e=>{try{let t=await(await Q(e)).workflows.list();if(e.json)return O(t);jf(t)}catch(t){$(t,e)}}),e.command(`fleet`).description(`Fleet overview: every workflow's run tallies over a trailing window, failing-first`).option(`--window <window>`,`Trailing window: 24h, 7d, or 30d`,`7d`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async e=>{try{let t=await(await Q(e)).workflows.fleetInsights({window:e.window});if(e.json)return O(t);Mf(t)}catch(t){$(t,e)}}),e.command(`get`).description(`Show a workflow's definition and compiled triggers`).argument(`<id>`,`Workflow ID`).option(`--yaml`,`Print only the raw definition YAML (the export path — pipe to a file)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=await(await Q(t)).workflows.get(e);if(t.yaml){if(n.definitionYaml===null)throw Error(`Workflow ${n.id} has no stored definition YAML to export`);process.stdout.write(n.definitionYaml.endsWith(`
148
- `)?n.definitionYaml:`${n.definitionYaml}\n`);return}if(t.json)return O(n);Nf(n)}catch(e){$(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>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=Of(e),r=await(await Q(t)).workflows.create(n);if(t.json)return O(r);j(`Created workflow ${r.id} (${r.name}).`),Nf(r)}catch(e){$(e,t)}}),e.command(`apply`).description(`Create or update a workflow idempotently, matched by the definition's name`).argument(`<file>`,`Path to the workflow YAML`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=Of(e),r=await Q(t),i=await r.workflows.validate(n,{structural:!0});if(!i.valid){if(process.exitCode=1,t.json)return O(i);j(`Invalid workflow:`);for(let e of i.errors)console.log(` ${e.path}: ${e.message}`);return}let a=(await r.workflows.list()).find(e=>e.name===i.name);if(a){let e=await r.workflows.update(a.id,n);if(t.json)return O({action:`updated`,workflow:e});j(`Updated workflow ${e.id} (${e.name}) — matched by name.`),Nf(e);return}let o=await r.workflows.create(n);if(t.json)return O({action:`created`,workflow:o});j(`Created workflow ${o.id} (${o.name}).`),Nf(o)}catch(e){$(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(`--note <note>`,`Revision note recorded on the appended revision (why this change)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=Of(t),i=await(await Q(n)).workflows.update(e,r,{...n.note===void 0?{}:{note:n.note}});if(n.json)return O(i);j(`Updated workflow ${i.id} (${i.name}).`),Nf(i)}catch(e){$(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>`,`Platform control-plane base URL`).action(async(e,t)=>{try{if(!t.force&&!await z(`Delete workflow ${e}? `,`--force`)){j(`Delete cancelled.`);return}if(await(await Q(t)).workflows.delete(e),t.json)return O({deleted:!0,id:e});j(`Deleted workflow ${e}.`)}catch(e){$(e,t)}}),e.command(`validate`).description(`Validate a workflow YAML file without saving it`).argument(`<file>`,`Path to the workflow YAML`).option(`--structural`,`CI mode: compile + capability checks only, no connection resolution — the verdict is the same regardless of connected providers`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=Of(e),r=await(await Q(t)).workflows.validate(n,{...t.structural?{structural:!0}:{}});if(t.json)return O(r);if(r.valid)j(`Valid: ${r.name} (${r.actionCount} action(s), ${r.triggerCount} trigger(s)).`);else{j(`Invalid workflow:`);for(let e of r.errors)console.log(` ${e.path}: ${e.message}`);process.exitCode=1}}catch(e){$(e,t)}}),e.command(`schema`).description(`Print the JSON Schema for the workflow YAML`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async e=>{try{O(await(await Q(e)).workflows.schema())}catch(t){$(t,e)}}),e.command(`run`).description(`Trigger an immediate run of a workflow`).argument(`<id>`,`Workflow ID`).option(`--input <key=value>`,`Trigger input as key=value (e.g. pull_request.number=123). Repeatable.`,Pf,[]).option(`--wait`,`Wait for the run to finish and print its result`).option(`--timeout <ms>`,`With --wait, fail if the run has not finished after this many milliseconds`).option(`--poll-interval <ms>`,`With --wait, how often to poll for completion (default 2000)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=Ff(t.input),r=t.timeout===void 0?void 0:H(t.timeout,`--timeout`),i=t.pollInterval===void 0?void 0:H(t.pollInterval,`--poll-interval`),a=await Q(t),{runId:o}=await a.workflows.run(e,n);if(!t.wait){if(t.json)return O({runId:o});j(`Started run ${o} for workflow ${e}.`),j(`Inspect it with: tangle workflows run-detail ${e} ${o}`);return}let s=t.json?null:M(`Waiting for run ${o} to finish...`).start(),c;try{c=await a.workflows.waitForRun(e,o,{...r===void 0?{}:{timeoutMs:r},...i===void 0?{}:{pollIntervalMs:i}})}finally{s?.stop()}if(c.status===`failed`&&(process.exitCode=1),t.json)return O(c);Lf(c)}catch(e){$(e,t)}}),e.command(`runs`).description(`List a workflow's run history (newest first)`).argument(`<id>`,`Workflow ID`).option(`--limit <n>`,`Runs per page (1-100)`).option(`--cursor <cursor>`,`Pagination cursor from a previous page`).option(`--all`,`Fetch every page, not just the first`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=await Q(t),r=t.limit===void 0?void 0:H(t.limit,`--limit`);if(t.all){let i=[],a=t.cursor,o=0,s=null;for(;;){let c=await n.workflows.listRuns(e,{...r===void 0?{}:{limit:r},...a===void 0?{}:{cursor:a}});if(i.push(...c.runs),o+=1,!c.nextCursor)break;if(o>=Tf){s=c.nextCursor,t.json||j(`Stopped after ${Tf} pages (${i.length} runs); more may exist — resume with --cursor ${c.nextCursor}`);break}a=c.nextCursor}if(t.json)return O({runs:i,nextCursor:s});If(i);return}let i=await n.workflows.listRuns(e,{...r===void 0?{}:{limit:r},...t.cursor===void 0?{}:{cursor:t.cursor}});if(t.json)return O(i);If(i.runs),i.nextCursor&&j(`More runs available — next page: --cursor ${i.nextCursor}`)}catch(e){$(e,t)}}),e.command(`run-detail`).description(`Show a single run's detail (per-action output and errors)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await(await Q(n)).workflows.getRun(e,t);if(n.json)return O(r);Lf(r)}catch(e){$(e,n)}}),e.command(`cancel`).description(`Cancel a queued or in-progress run`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await(await Q(n)).workflows.cancel(e,t);if(n.json)return O(r);Rf(r)}catch(e){$(e,n)}}),e.command(`retry`).description(`Re-run a failed or cancelled run (a fresh run with the same trigger context)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID of the failed/cancelled run to retry`).option(`--wait`,`Wait for the new run to finish and print its result`).option(`--timeout <ms>`,`With --wait, fail if the run has not finished after this many milliseconds`).option(`--poll-interval <ms>`,`With --wait, how often to poll for completion (default 2000)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=n.timeout===void 0?void 0:H(n.timeout,`--timeout`),i=n.pollInterval===void 0?void 0:H(n.pollInterval,`--poll-interval`),a=await Q(n),o=await a.workflows.retryRun(e,t);if(!n.wait){if(n.json)return O(o);j(`Started run ${o.runId} (retry of ${t}).`),j(`Inspect it with: tangle workflows run-detail ${e} ${o.runId}`);return}let s=n.json?null:M(`Waiting for run ${o.runId} to finish...`).start(),c;try{c=await a.workflows.waitForRun(e,o.runId,{...r===void 0?{}:{timeoutMs:r},...i===void 0?{}:{pollIntervalMs:i}})}finally{s?.stop()}if(c.status===`failed`&&(process.exitCode=1),n.json)return O(c);Lf(c)}catch(e){$(e,n)}}),e.command(`events`).description(`Tail a run's live progress events until it finishes`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).option(`--json`,`Emit each event as a JSON line`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await Q(n);for await(let i of r.workflows.watchRun(e,t))n.json?console.log(JSON.stringify(i)):zf(i),i.type===`run.done`&&i.status===`failed`&&(process.exitCode=1)}catch(e){$(e,n)}}),e.command(`enable`).description(`Enable a workflow so its triggers and manual runs fire`).argument(`<id>`,`Workflow ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{await Df(e,!0,t)}),e.command(`disable`).description(`Disable a workflow (pause its triggers and manual runs)`).argument(`<id>`,`Workflow ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{await Df(e,!1,t)}),e.command(`templates`).description(`List the curated starter workflow templates`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async e=>{try{let t=await(await Q(e)).workflows.listTemplates();if(e.json)return O(t);Uf(t)}catch(t){$(t,e)}}),e.command(`init`).description(`Create a workflow from a gallery template and print (or save) its YAML`).argument(`<template-id>`,"Template ID from `workflows templates`").option(`--param <key=value>`,`Template parameter value. Repeatable.`,Pf,[]).option(`--file <out>`,`Write the instantiated workflow YAML to this file instead of stdout`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=Ff(t.param,`param`)??{},r=await(await Q(t)).workflows.instantiateTemplate(e,n);if(t.json)return O(r);if(!r.created){j(`Template ${e} needs provider connections before it can run:`);for(let e of r.connectionRequirements)console.log(` ${e.connected?`✓`:`✗`} ${Wf(e,r.connectionRequirements)}`);process.exitCode=1;return}let{workflow:i}=r;if(i.definitionYaml===null)throw Error(`Workflow ${i.id} was created but the server returned no definition YAML`);if(j(`Created workflow ${i.id} (${i.name}).`),t.file){Hf(t.file,i.definitionYaml),j(`Wrote ${t.file}.`);return}process.stdout.write(i.definitionYaml.endsWith(`
149
- `)?i.definitionYaml:`${i.definitionYaml}\n`)}catch(e){$(e,t)}}),e.command(`revisions`).description(`List a workflow's definition revision history (newest first)`).argument(`<id>`,`Workflow ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=await(await Q(t)).workflows.listRevisions(e);if(t.json)return O(n);Gf(n)}catch(e){$(e,t)}}),e.command(`revision`).description(`Show one revision's metadata and definition YAML`).argument(`<id>`,`Workflow ID`).argument(`<rev>`,`Revision number`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=H(t,`<rev>`),i=await(await Q(n)).workflows.getRevision(e,r);if(n.json)return O(i);N({Revision:i.rev,Created:i.createdAt,"Created by":i.createdBy,Source:i.source,Note:i.note??``}),process.stdout.write(i.yaml.endsWith(`
150
- `)?i.yaml:`${i.yaml}\n`)}catch(e){$(e,n)}}),e.command(`rollback`).description(`Restore a prior revision's definition as a NEW head revision (re-validated)`).argument(`<id>`,`Workflow ID`).argument(`<rev>`,`Revision number to restore`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=H(t,`<rev>`),i=await(await Q(n)).workflows.rollback(e,r);if(n.json)return O(i);j(`Rolled back workflow ${i.id} to rev ${r}.`),Nf(i)}catch(e){$(e,n)}});let n=e.command(`kv`).description(`Read and write a workflow's cross-run KV state`);return n.command(`list`).description(`List every KV entry of a workflow`).argument(`<id>`,`Workflow ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=await(await Q(t)).workflows.listKv(e);if(t.json)return O(n);Kf(n.entries)}catch(e){$(e,t)}}),n.command(`get`).description(`Show one KV entry (value and version)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await(await Q(n)).workflows.getKv(e,t);if(n.json)return O(r);qf(r)}catch(e){$(e,n)}}),n.command(`set`).description(`Write a KV entry from a JSON value`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).argument(`<json>`,`Value as JSON (e.g. '{"cursor":123}' or '"abc"')`).option(`--cas <version>`,`Compare-and-swap: write only if the stored version still equals this`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n,r)=>{try{let i=Vf(n,`<json>`),a=r.cas===void 0?void 0:H(r.cas,`--cas`),o=await Q(r),s=a===void 0?await o.workflows.putKv(e,t,i):await o.workflows.casKv(e,t,a,i);if(r.json)return O(s);qf(s)}catch(e){$(e,r)}}),n.command(`delete`).description(`Delete a KV entry (idempotent)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await(await Q(n)).workflows.deleteKv(e,t);if(n.json)return O(r);j(r.deleted?`Deleted KV entry "${t}" of workflow ${e}.`:`No KV entry "${t}" on workflow ${e}.`)}catch(e){$(e,n)}}),e.command(`artifacts`).description(`List a run's artifact metadata (never the bytes)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await(await Q(n)).workflows.listArtifacts(e,t);if(n.json)return O(r);Jf(r.artifacts)}catch(e){$(e,n)}}),e.command(`artifact-download`).description(`Download one run artifact's bytes to a file`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).argument(`<artifactId>`,`Artifact ID`).option(`--out <file>`,`Destination file (defaults to the artifact ID)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n,r)=>{try{let i=await(await Q(r)).workflows.downloadArtifact(e,t,n),a=r.out??n;try{me(a,i.bytes)}catch(e){throw Error(`Could not write artifact to "${a}": ${e instanceof Error?e.message:String(e)}`)}if(r.json)return O({file:a,contentType:i.contentType,bytes:i.bytes.length});j(`Wrote ${a} (${i.bytes.length} bytes, ${i.contentType}).`)}catch(e){$(e,r)}}),e.command(`decisions`).description(`List a workflow's pending human decisions`).argument(`<id>`,`Workflow ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=(await(await Q(t)).workflows.listPendingDecisions()).decisions.filter(t=>t.workflowId===e);if(t.json)return O({decisions:n});Yf(n)}catch(e){$(e,t)}}),e.command(`decision-resolve`).description(`Answer the decision a run is parked on and resume it`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).requiredOption(`--choice <choice>`,`The option to resolve with (one of the decision's options)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await Q(n),i=await r.workflows.getRunDecision(e,t),a=await r.workflows.resolveRunDecision(e,t,{decisionId:i.id,choice:n.choice});if(n.json)return O(a);if(a.resumed){j(`Resolved decision ${a.decisionId} with "${a.choice}" — run ${a.runId} resumed.`);return}j(`Resolved decision ${a.decisionId} with "${a.choice}", but run ${a.runId} had already finished — nothing to resume.`)}catch(e){$(e,n)}}),e}async function Df(e,t,n){try{let r=await(await Q(n)).workflows.setEnabled(e,t);if(n.json)return O(r);j(`${t?`Enabled`:`Disabled`} workflow ${r.id}.`),Nf(r)}catch(e){$(e,n)}}function Of(e){try{return y(e,`utf8`)}catch(t){throw Error(`Could not read workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function Q(e){return Fr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.baseUrl===void 0?{}:{baseUrl:e.baseUrl}})}function kf(e){if(!Af(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 Af(e,t){return e.options.some(e=>e.attributeName()===t)}function $(e,t){return F(e,t.json===!0)}function jf(e){D(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 Mf(e){let t=e.workflows.filter(e=>e.failed>0).length,n=e.workflows.filter(e=>e.failed===0&&e.waiting>0).length,r=e.workflows.filter(e=>e.failed===0&&e.waiting===0&&e.runsInWindow>0).length;j(`${t} failing · ${n} waiting · ${r} healthy · ${e.workflows.length} total over ${e.window}`),D(e.workflows.map(e=>({id:e.id,name:e.name,enabled:e.enabled?`yes`:`no`,runs:e.runsInWindow,failed:e.failed,waiting:e.waiting,success:e.successRate===null?`—`:`${Math.round(e.successRate*100)}%`,lastRun:e.lastRunStatus??`—`,lastRunAt:e.lastRunAt??`—`})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`enabled`,header:`Enabled`},{key:`runs`,header:`Runs`},{key:`failed`,header:`Failed`},{key:`waiting`,header:`Waiting`},{key:`success`,header:`Success`},{key:`lastRun`,header:`Last Run`},{key:`lastRunAt`,header:`Last Run At`}])}function Nf(e){if(N({ID:e.id,Name:e.name,Description:e.description??``,Enabled:e.enabled?`yes`:`no`,Actions:e.actions.length}),e.triggers&&e.triggers.length>0&&(j(`Triggers`),Bf(e.triggers)),e.validationErrors.length>0){j(`Validation issues`);for(let t of e.validationErrors)console.log(` ${t.path}: ${t.message}`)}}function Pf(e,t){return[...t,e]}function Ff(e,t=`input`){if(!e||e.length===0)return;let n={};for(let r of e){let e=r.indexOf(`=`);if(e<=0)throw Error(`Invalid --${t} "${r}": expected key=value (e.g. pull_request.number=123)`);n[r.slice(0,e)]=r.slice(e+1)}return n}function If(e){D(e.map(e=>({id:e.id,status:e.status,attempts:e.attempts,created:e.createdAt,completed:e.completedAt??``})),[{key:`id`,header:`Run ID`},{key:`status`,header:`Status`},{key:`attempts`,header:`Attempts`},{key:`created`,header:`Created`},{key:`completed`,header:`Completed`}])}function Lf(e){if(N({"Run ID":e.id,Workflow:e.workflowId,Status:e.status,Error:e.error??``,Attempts:e.attempts,Created:e.createdAt,Started:e.startedAt??``,Completed:e.completedAt??``}),e.actionResults.length>0){j(`Actions`);let t=e.actionResults.some(e=>e.nodeId!==void 0||e.visit!==void 0);D(e.actionResults.map(e=>({index:e.index,...t?{node:e.nodeId??``,visit:e.visit??``}:{},kind:e.kind,status:e.status,error:e.error??``,cost:e.costUsd??``})),[{key:`index`,header:`#`},...t?[{key:`node`,header:`Node`},{key:`visit`,header:`Visit`}]:[],{key:`kind`,header:`Kind`},{key:`status`,header:`Status`},{key:`error`,header:`Error`},{key:`cost`,header:`Cost (USD)`}])}e.graph&&(j(`Graph`),N({Nodes:e.graph.nodes.length,Edges:e.graph.edges.length,"Max node visits":e.graph.maxNodeVisits}),D(e.graph.edges.map(e=>({from:e.from,to:e.to,guard:e.when===void 0?``:JSON.stringify(e.when)})),[{key:`from`,header:`From`},{key:`to`,header:`To`},{key:`guard`,header:`Guard`}])),e.edgeVerdicts&&e.edgeVerdicts.length>0&&(j(`Edge verdicts`),D(e.edgeVerdicts.flatMap(e=>Object.entries(e.verdicts).map(([t,n])=>({node:e.nodeId,edge:t,verdict:n?`taken`:`not taken`}))),[{key:`node`,header:`Node`},{key:`edge`,header:`Edge`},{key:`verdict`,header:`Verdict`}]))}function Rf(e){if(e.status===`cancelled`){j(`Cancelled run ${e.runId}.`);return}if(e.signalled){j(`Cancelling run ${e.runId} — signalled the worker; it will stop shortly.`);return}j(`Requested cancellation of run ${e.runId}, but couldn't confirm it — the run may have just finished, or it's running on another instance and will stop on its own.`)}function zf(e){switch(e.type){case`snapshot`:j(`snapshot: ${e.run.status} (${e.run.actionResults.length} action(s))`);break;case`action.started`:console.log(`→ action[${e.index}] ${e.kind} started`);break;case`action.finished`:{let t=e.status===`succeeded`?`✓`:e.status===`skipped`?`⊘`:`✗`;console.log(`${t} action[${e.index}] ${e.kind} ${e.status}${e.error?`: ${e.error}`:``}`);break}case`iteration.started`:console.log(` · action[${e.actionIndex}] iteration ${e.iterationIndex} started`);break;case`iteration.ended`:console.log(` · action[${e.actionIndex}] iteration ${e.iterationIndex} ${e.status}`);break;case`token`:typeof e.delta==`string`&&process.stdout.write(e.delta);break;case`ping`:break;case`run.done`:console.log(`\nrun.done: ${e.status}${e.error?`: ${e.error}`:``}`);break;case`run.waiting`:console.log(`\nrun.waiting: parked on a human decision (${e.decisionId}) — resolve it to resume`);break}}function Bf(e){D(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 Vf(e,t){try{return JSON.parse(e)}catch{throw Error(`Invalid ${t}: not valid JSON`)}}function Hf(e,t){try{me(e,t,`utf8`)}catch(t){throw Error(`Could not write workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function Uf(e){D(e.map(e=>({id:e.id,name:e.name,category:e.category,providers:e.providers.join(`, `),summary:e.summary})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`category`,header:`Category`},{key:`providers`,header:`Providers`},{key:`summary`,header:`Summary`}])}function Wf(e,t){let n=e.kind===`github_app`,r=n?`${e.provider} (App installation)`:e.provider,i=e.connectUrl?` — ${n?`install`:`connect`}: ${e.connectUrl}`:``,a=e.prerequisite;return`${r}${i}${a&&t.some(e=>e.provider===a.provider&&e.kind===a.kind&&!e.connected)?` (after connecting ${a.provider})`:``}`}function Gf(e){D(e.map(e=>({rev:e.rev,created:e.createdAt,by:e.createdBy,source:e.source,note:e.note??``})),[{key:`rev`,header:`Rev`},{key:`created`,header:`Created`},{key:`by`,header:`Created By`},{key:`source`,header:`Source`},{key:`note`,header:`Note`}])}function Kf(e){D(e.map(e=>({key:e.key,version:e.version,updated:e.updatedAt})),[{key:`key`,header:`Key`},{key:`version`,header:`Version`},{key:`updated`,header:`Updated`}])}function qf(e){N({Key:e.key,Version:e.version,Updated:e.updatedAt}),j(`Value`),O(e.value)}function Jf(e){D(e.map(e=>({id:e.id,node:e.nodeId,name:e.name,type:e.contentType,bytes:e.byteSize,created:e.createdAt})),[{key:`id`,header:`ID`},{key:`node`,header:`Node`},{key:`name`,header:`Name`},{key:`type`,header:`Content Type`},{key:`bytes`,header:`Bytes`},{key:`created`,header:`Created`}])}function Yf(e){D(e.map(e=>({id:e.id,run:e.runId,title:e.title,options:e.options.join(`, `),requested:e.requestedAt,expires:e.expiresAt??``})),[{key:`id`,header:`ID`},{key:`run`,header:`Run`},{key:`title`,header:`Title`},{key:`options`,header:`Options`},{key:`requested`,header:`Requested`},{key:`expires`,header:`Expires`}])}function Xf(e){let t={...Zf(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 Zf(e){let t=e;for(;t?.parent;)t=t.parent;return t?t.opts():void 0}const Qf=e(import.meta.url)(`../package.json`);function $f(){let e=new t;return e.name(`tangle`).description(`CLI for Tangle Sandbox operations`).version(Qf.version??`0.0.0`).option(`--api-key <key>`,`API key (or set TANGLE_API_KEY)`).option(`--base-url <url>`,`API base URL`),e.hook(`preAction`,(e,t)=>{Xf(t);let n=t.opts();Qn(n.json===!0||n.ndjson===!0)}),e.addCommand(Ei()),e.addCommand(Oc()),e.addCommand(wf()),e.addCommand(Bc()),e.addCommand(qs()),e.addCommand(tc()),e.addCommand(nc()),e.addCommand(Mo()),e.addCommand(Dd()),e.addCommand(Od()),e.addCommand(Ad()),e.addCommand(si()),e.addCommand(Uc()),e.addCommand(Ho()),e.addCommand(xf()),e.addCommand(Yd()),e.addCommand(tf()),e.addCommand(ic()),e.addCommand(Pi()),e.addCommand(Gi()),e.addCommand(uc()),e.addCommand($o()),e.addCommand(is()),e.addCommand(as()),e.addCommand(Ef()),e.addCommand(jo()),e.addCommand(nf()),e.addCommand(zc()),e.addCommand(vd()),e.addCommand(Hc()),e.addCommand(Ki()),e.addCommand(cc()),e.addCommand(Os()),e.addCommand(_o()),e.addCommand(vo()),e.addCommand(gc()),e.addCommand(rc()),e.addCommand(rf()),e.addCommand(Jd()),e}$f().parseAsync(process.argv).catch(e=>{console.error(`Fatal error:`,e.message),process.exit(1)});export{};
140
+ `)?`${e}\n`:`${e}\n\n`}function io(){let e=process.env.SHELL??``;return e.includes(`zsh`)?ve(xe(),`.zshrc`):e.includes(`bash`)?ve(xe(),`.bashrc`):ve(xe(),`.zshrc`)}function ao(e){if(e===`shell`||e===`env`||e===`dockerfile`)return e;throw Error(`--format must be one of: shell, env, dockerfile (got '${e}')`)}function oo(e){if(e===`full`||e===`prompts`||e===`metadata`)return e;throw Error(`--content must be one of: full, prompts, metadata (got '${e}')`)}async function so(e){let t=eo({endpoint:e.endpoint,apiKey:e.apiKey,projectKey:e.projectKey,content:e.content,format:e.format});if(console.log(t),e.format!==`shell`){console.log(),P(e.format===`env`?"Cron/container path: feed these to your service env (.env, `docker run --env-file`, k8s envFrom). No shell-rc edit, no TTY needed.":`Dockerfile path: paste these ENV lines into your image. No shell-rc edit, no TTY needed.`);return}if(console.log(),P(`Privacy tiers: --content full ships the whole conversation; --content prompts keeps task, prompts, and tool args only; --content metadata turns content off (telemetry still flows). Secrets are scrubbed server-side regardless.`),!e.write)return;let n=e.rcPath??io(),r=process.stdin.isTTY?await Wr(`Append this idempotent block to ${n}? (y/N)`,`n`):`n`;if(r.toLowerCase()!==`y`&&r.toLowerCase()!==`yes`){console.log(),P(`Not writing. To append later: tangle connect claude-code --rc ${n}`);return}let i=to({endpoint:e.endpoint,apiKey:e.apiKey,projectKey:e.projectKey,content:e.content,format:e.format}),{contents:a,changed:o}=no(qa(n),i);if(!o){console.log(),M(`Already present in ${n} — nothing to change.`);return}Ja(n,a),console.log(),M(`Wrote Tangle Intelligence env block to ${n}.`),P(`Reload your shell (e.g. 'source ${n}') before running the agent.`)}function co(e){let t=[],n={header:null,body:[]};for(let r of e.split(`
141
+ `))lo(r)?(t.push(n),n={header:r.trim(),body:[]}):n.body.push(r);return t.push(n),t.length>1&&t[0].header===null&&t[0].body.every(e=>e.trim()===``)&&t.shift(),t}function lo(e){let t=e.trim();return t.startsWith(`[`)&&t.endsWith(`]`)&&!t.includes(`=`)||t.startsWith(`[[`)&&t.endsWith(`]]`)}function uo(e){let t=[];for(let n of e)n.header!==null&&t.push(n.header),t.push(...n.body);return t.join(`
142
+ `)}function fo(e){return[{key:`environment`,line:`environment = "prod"`},{key:`log_user_prompt`,line:`log_user_prompt = true`},{key:`exporter`,line:`exporter = { otlp-http = { endpoint = "${U(e.endpoint)}/v1/logs", protocol = "json", headers = { "Authorization" = "Bearer ${e.apiKey??"${TANGLE_API_KEY}"}" } } }`}]}function po(e){let t=e.trim();if(t===``||t.startsWith(`#`))return null;let n=t.indexOf(`=`);if(n===-1)return null;let r=t.slice(0,n).trim();return/^[A-Za-z0-9_-]+$/.test(r)?r:null}function mo(e,t){let n=fo(t),r=new Set(n.map(e=>e.key));if(e.trim()===``)return{contents:`${[`[otel]`,...n.map(e=>e.line)].join(`
143
+ `)}\n`,changed:!0};let i=co(e),a=i.find(e=>e.header===`[otel]`);if(!a){let t={header:`[otel]`,body:n.map(e=>e.line)},r=i[i.length-1];r&&!ho(r)&&r.body.push(``),i.push(t);let a=go(uo(i));return{contents:a,changed:a!==go(e)}}let o=a.body.filter(e=>{let t=po(e);return t===null||!r.has(t)}),s=[];for(;o.length>0&&o[o.length-1].trim()===``;)s.unshift(o.pop());a.body=[...o,...n.map(e=>e.line),...s];let c=go(uo(i));return{contents:c,changed:c!==go(e)}}function ho(e){return e.body.length>0&&e.body[e.body.length-1].trim()===``}function go(e){return e.endsWith(`
144
+ `)?e:`${e}\n`}function _o(e){let t=ve(xe(),`.codex`,`config.toml`),{contents:n,changed:r}=mo(qa(t),{endpoint:e.endpoint,apiKey:e.apiKey});if(!e.write){console.log(n.trimEnd());return}if(!r){M(`${t} already has the Tangle [otel] block — nothing to change.`);return}Ja(t,n),M(`Merged the Tangle [otel] block into ${t}.`),P("Codex emits content on the logs signal (codex.* events). Set TANGLE_API_KEY in your env before running if you kept the ${TANGLE_API_KEY} reference."),P(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=${e.projectKey??`<your project>`} before running codex.`)}function vo(e){switch(e){case`claude-code`:return`Claude Code: set OTEL_LOGS_EXPORTER=otlp and the four OTEL_LOG_* gates (OTEL_LOG_USER_PROMPTS, OTEL_LOG_TOOL_DETAILS, OTEL_LOG_TOOL_CONTENT, OTEL_LOG_RAW_API_BODIES).`;case`codex`:return`Codex: set log_user_prompt = true in [otel] (default false redacts content).`;case`opencode`:return`OpenCode: a standalone install emits nothing without the tangle-opencode-exporter shim; inside a Tangle sandbox it is already instrumented.`;case`openclaw`:case`hermes`:case`nanoclaw`:return`${Ga[e]}: no native OTLP exporter and no standalone server to subscribe to — run it inside a Tangle sandbox, where the sidecar adapter exports its content with gen_ai.system=${e}. A bare standalone install emits metadata only.`}}async function yo(e){let t=Date.now()+e.timeoutSeconds*1e3,n=3e3,r=Math.min(e.timeoutSeconds*1e3,1e4),i=F(`Checking whether content is flowing…`);i.start();let a;try{for(;;){try{a=await sa({endpoint:e.endpoint,apiKey:e.apiKey,timeoutMs:r})}catch(e){if(Date.now()>=t)throw e;await xo(n);continue}if(a.contentSeen||Date.now()>=t)break;await xo(n)}}finally{i.stop()}if(!a)throw Error(`onboarding status check returned no result`);bo(a,e.agent),a.contentSeen||(process.exitCode=1)}function bo(e,t){if(e.contentSeen){M(`Content flowing — Tangle Intelligence can analyze this feed.`),I({"Last seen":e.lastSeenAt??`just now`,Window:`${e.windowDays}d`});return}if(e.tracesSeen){N(`Metadata-only — traces are arriving but carry no content. You missed a content gate.`);let n=t?[t]:Object.keys(e.byAgent).filter(Ka),r=n.length>0?n:Wa;for(let n of r){let r=e.byAgent[n];(t||!r||r.tracesSeen&&!r.contentSeen)&&P(vo(n))}return}N(`No traces yet for your tenant. Run your agent once on a real task, then re-run --verify.`),t&&P(vo(t))}function xo(e){return new Promise(t=>setTimeout(t,e))}function So(e){let t=e??process.env.TANGLE_INTELLIGENCE_API_KEY??Sn(void 0);if(!t)throw Error(`No Tangle API key found. Pass --api-key, set TANGLE_API_KEY, or run: tangle auth login`);return t}function Co(){return new t(`connect`).description(`Connect a local coding agent's telemetry to Tangle Intelligence, content on (for SDK integration snippets, see 'tangle agent connect')`).argument(`[agent]`,`claude-code | codex | opencode | openclaw | hermes | nanoclaw`).option(`--api-key <key>`,`Tangle API key (or set TANGLE_API_KEY)`).option(`--endpoint <url>`,`OTLP endpoint base`,Ki).option(`-p, --project <key>`,`Project label (tangle.subject.key) to group runs; omit to set it yourself`).option(`--rc <path>`,`Shell rc file to append the Claude Code env block to`).option(`--no-write`,`Print the config instead of writing files (Claude Code / Codex)`).option(`--inline-key`,"Embed the resolved API key literally in the config (default: keep ${TANGLE_API_KEY})").option(`--verify`,`Poll onboarding status and report whether CONTENT is flowing`).option(`--timeout <seconds>`,`Verify poll timeout in seconds`,`120`).option(`--run`,`OpenCode only: run the content exporter against a live OpenCode server until interrupted`).option(`--opencode-url <url>`,`OpenCode server base URL for --run (or set OPENCODE_BASE_URL)`).option(`--format <kind>`,`Claude Code output: shell (export block) | env (.env / docker --env-file) | dockerfile (ENV lines). env/dockerfile are the cron/container path — printed to stdout, no shell-rc edit, no TTY`,`shell`).option(`--content <tier>`,`Claude Code content tier: full (everything) | prompts (task+prompts+tool-args) | metadata (telemetry on, content off)`,`full`).action(async(e,t)=>{try{let n=U(t.endpoint);if(t.run){if((e?To(e):`opencode`)!==`opencode`)throw Error(`--run is OpenCode-only: it runs the content exporter against a live OpenCode server. Other agents export natively once configured.`);await ko({endpoint:n,apiKey:So(t.apiKey),opencodeUrl:t.opencodeUrl});return}if(t.verify){await yo({endpoint:n,apiKey:So(t.apiKey),agent:e?To(e):void 0,timeoutSeconds:Ua(t.timeout,`--timeout`)});return}let r=e?To(e):await Eo(),i=t.inlineKey?So(t.apiKey):void 0;r===`claude-code`?await so({endpoint:n,apiKey:i,projectKey:t.project,rcPath:t.rc,write:t.write!==!1,content:oo(t.content),format:ao(t.format)}):r===`codex`?_o({endpoint:n,apiKey:i,projectKey:t.project,write:t.write!==!1}):r===`opencode`?Do({endpoint:n}):Oo(r,{endpoint:n}),console.log(),P(`Run your agent on a real task, then verify content is flowing: tangle connect ${r} --verify`)}catch(e){R(e)}})}function wo(){return new t(`opencode-exporter`).description(`Export a running OpenCode's content to Tangle Intelligence (standalone shim)`).option(`--api-key <key>`,`Tangle API key (or set TANGLE_API_KEY)`).option(`--endpoint <url>`,`OTLP endpoint base`,Ki).option(`--opencode-url <url>`,`OpenCode server base URL (or set OPENCODE_BASE_URL)`).action(async e=>{try{await ko({endpoint:U(e.endpoint),apiKey:So(e.apiKey),opencodeUrl:e.opencodeUrl})}catch(e){R(e)}})}function To(e){if(Ka(e))return e;throw Error(`Unknown agent '${e}'. Choose one of: ${Wa.join(`, `)}`)}async function Eo(){if(!process.stdin.isTTY)throw Error(`Specify an agent: tangle connect <${Wa.join(`|`)}>`);console.log(`Which coding agent are you connecting?`),Wa.forEach((e,t)=>{console.log(` ${t+1}) ${Ga[e]} (${e})`)});let e=await Wr(`Enter a number or name`,`1`);return Wa[Number.parseInt(e,10)-1]||To(e.trim())}function Do(e){let t=U(e.endpoint);N(`OpenCode has no native OTel exporter, so a standalone install emits nothing without a shim.`),console.log(),I({"Inside a Tangle sandbox":`already instrumented — our adapter exports OpenCode's event-stream content. Nothing to do.`,Standalone:`run 'tangle connect opencode --run' alongside a running OpenCode, exporting to ${t}.`}),console.log(),P(`Start OpenCode in server mode ('opencode serve'), then in another terminal run: tangle connect opencode --run`),P(`The exporter subscribes to OpenCode's SSE event bus and exports content-bearing OTLP (prompt/completion/tool content) to Tangle. Verify with: tangle connect opencode --verify`),P(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=my-project before starting the exporter.`)}function Oo(e,t){let n=U(t.endpoint),r=Ga[e];N(`${r} has no native OTel exporter, so a standalone install emits nothing without instrumentation.`),console.log(),I({"Inside a Tangle sandbox":`already instrumented — the sidecar adapter exports ${r}'s prompt/completion/tool content (gen_ai.system=${e}) to ${n}. Nothing to do.`,Standalone:`${r} exposes no OTLP and no event-bus server; run it inside a Tangle sandbox to capture content.`}),console.log(),P(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=my-project before starting ${r}.`),P(`Verify content is flowing: tangle connect ${e} --verify`)}async function ko(e){let t=Ra(e.opencodeUrl),n=new AbortController,r=()=>n.abort();process.on(`SIGINT`,r),process.on(`SIGTERM`,r),P(`Subscribing to OpenCode at ${t} — exporting content to Tangle.`),P(`Run OpenCode tasks now. Press Ctrl-C to stop.`),console.log();let i=0,a;try{a=await Ha({endpoint:e.endpoint,apiKey:e.apiKey,opencodeBaseUrl:t,signal:n.signal,onExport:({eventType:e,records:t})=>{i+=t,P(`exported ${t} record(s) from ${e} (total ${i})`)}})}catch(e){if(e instanceof Ba){let{recordsExported:t,contentEventsExported:n}=e.partial;console.log(),N(`Exporter failed after exporting ${t} content record(s) from ${n} event(s): ${e.message}`)}throw e}finally{process.off(`SIGINT`,r),process.off(`SIGTERM`,r)}if(console.log(),a.contentEventsExported===0){N(`Saw ${a.eventsSeen} event(s) but none carried content. Run a real OpenCode task (a prompt that produces text or a tool call), then re-run.`);return}M(`Exported ${a.recordsExported} content record(s) from ${a.contentEventsExported} event(s).`),P(`Verify it landed: tangle connect opencode --verify`)}function Ao(){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(D({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`):L([`ID`,`Description`,`Version`],r.map(e=>[e.id,e.description??``,e.version]))}catch(e){R(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(D({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){R(e)}}),e}function jo(){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=D({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 B(i,r,e);c=await V(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.exitCode=l.exitCode)}catch(e){if(e instanceof d){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 R(Error(t,{cause:e}))}R(e)}})}function Mo(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(D({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){R(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(D({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(`
145
+ Recommended actions:`);for(let e of i.insights.recommendedActions)console.log(` - ${e}`)}}catch(e){R(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(D({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){R(e)}})}function No(e){return[...e.entries()].map(([e,t])=>({machineId:e,sandboxId:t.id,status:t.status}))}function Po(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(D({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=No(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){R(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(D({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){R(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(D({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){R(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(D({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){R(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(D({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){R(e)}})}function Fo(e){let t=e.memory?G(e.memory,`--accelerator-memory`):void 0;return{kind:Bo(e.kind),count:e.count?G(e.count,`--accelerator-count`):1,...t===void 0?{}:{memoryMB:t}}}function Io(e,t,n){let r=!!(e.provider||e.image||e.env||e.maxSpendUsd||e.maxLifetime||e.idleTimeout);if(!t&&r)throw Error(n);if(t){if(!e.maxSpendUsd||!e.maxLifetime)throw Error(`--accelerator-kind requires --gpu-max-spend-usd and --gpu-max-lifetime`);return{...e.provider?{provider:zo(e.provider,`--gpu-provider`)}:{},...e.image?{image:e.image}:{},...e.env?{env:Ro(e.env,`--gpu-env`,`GPU env`)}:{},maxSpendUsd:Vo(e.maxSpendUsd,`--gpu-max-spend-usd`),maxLifetimeSeconds:G(e.maxLifetime,`--gpu-max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:G(e.idleTimeout,`--gpu-idle-timeout`)}:{}}}}function Lo(e){return{...e.provider?{provider:zo(e.provider,`GPU provider`)}:{},accelerator:Fo({kind:e.acceleratorKind,count:e.acceleratorCount,memory:e.acceleratorMemory}),...e.image?{image:e.image}:{},...e.env?{env:Ro(e.env,`--env`,`env`)}:{},maxSpendUsd:Vo(e.maxSpendUsd,`--max-spend-usd`),maxLifetimeSeconds:G(e.maxLifetime,`--max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:G(e.idleTimeout,`--idle-timeout`)}:{}}}function Ro(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 G(e,t){if(!/^\d+$/.test(e))throw Error(`${t} must be a positive integer`);let n=Number.parseInt(e,10);if(Number.isNaN(n)||n<1)throw Error(`${t} must be a positive integer`);return n}function zo(e,t){if(u.includes(e))return e;throw Error(`${t} must be one of ${u.join(`, `)}`)}function Bo(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 Vo(e,t){if(!/^(?:\d+|\d+\.\d+|\.\d+)$/.test(e))throw Error(`${t} must be a positive number`);let n=Number.parseFloat(e);if(!Number.isFinite(n)||n<=0)throw Error(`${t} must be a positive number`);return n}function Ho(e){if(e.spec){let t=JSON.parse(b(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=Go(e),n=Ko(e,!!t?.accelerator),r={...e.environment?{environment:e.environment}:{},...t?{resources:t}:{},...e.driver?{driver:{type:e.driver}}:{},...n?{gpuLease:n}:{},...e.backend?{backend:{type:e.backend}}:{}},i=qo(e),a=Math.max(1,Number(e.count)||1),o=Array.from({length:a},(e,t)=>({machineId:`worker-${t+1}`}));return{base:{fleetId:e.fleetId,defaults:Object.keys(r).length>0?r:void 0,policy:i,workspace:{mode:e.workspace}},machines:o}}function Uo(e){let{base:t,machines:n}=Ho(e);return{...t,machines:n}}function Wo(e){let{base:t,machines:n}=Ho(e);return{...t,workers:n}}function Go(e){let t={};if(e.cpu&&(t.cpuCores=Number(e.cpu)),e.memory&&(t.memoryMB=Number(e.memory)),e.disk&&(t.diskGB=Number(e.disk)),e.acceleratorKind)t.accelerator=Fo({kind:e.acceleratorKind,count:e.acceleratorCount,memory:e.acceleratorMemory});else if(e.acceleratorCount||e.acceleratorMemory)throw Error(`--accelerator-count and --accelerator-memory require --accelerator-kind`);return Object.keys(t).length>0?t:void 0}function Ko(e,t){return Io({provider:e.gpuProvider,image:e.gpuWorkerImage,env:e.gpuEnv,maxSpendUsd:e.gpuMaxSpendUsd,maxLifetime:e.gpuMaxLifetime,idleTimeout:e.gpuIdleTimeout},t,`Fleet GPU lease flags require --accelerator-kind`)}function qo(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 Jo(e){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(`--environment <environment>`,`Named environment, container image, or built image ID 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(`--accelerator-kind <kind>`,`Accelerator kind per machine, for example nvidia-l4 or nvidia-h100`).option(`--accelerator-count <count>`,`Accelerator devices per machine`).option(`--accelerator-memory <mb>`,`Minimum accelerator memory in MB per machine`).option(`--gpu-provider <provider>`,`GPU cloud provider per machine; omitted picks the cheapest configured provider`).option(`--gpu-worker-image <image>`,`GPU worker image override`).option(`--gpu-env <vars...>`,`Environment variables for each GPU worker (KEY=VALUE)`).option(`--gpu-max-spend-usd <usd>`,`Maximum spend per machine GPU lease`).option(`--gpu-max-lifetime <seconds>`,`Maximum GPU lease lifetime per machine in seconds`).option(`--gpu-idle-timeout <seconds>`,`Destroy each GPU lease after this many idle seconds`).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(D({apiKey:e.apiKey,baseUrl:e.baseUrl})),n=F(`Creating fleet...`);n.start();let r=e.coordinator?await t.fleets.createWithCoordinator(Wo(e)):await t.fleets.create(Uo(e));n.stop();let i=No(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){R(e)}})}function Yo(e){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(D({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){R(e)}}),e.command(`run [prompt]`).description(`Create a fleet of agents, run one turn on every agent, print each result, then delete the fleet`).requiredOption(`--agents <n|file>`,`Number of agents, or a JSON file with an array of agent specs (agentId, harness, model, profile or { profileId, revision }, task)`).option(`--placement <mode>`,`auto (pack by sandbox memory), dedicated (one sandbox per agent), or a number of agents per sandbox`,`auto`).option(`--model <id>`,`Model every agent runs, e.g. gpt-4.1-mini`).option(`--memory <mb>`,`Memory in MB per sandbox; auto placement packs by it`).option(`--environment <environment>`,`Environment for each sandbox`).option(`--max-spend-usd <usd>`,`Budget for the fleet in USD, enforced by the Platform on the fleet's own key`).option(`--timeout <ms>`,`Per-agent turn timeout in milliseconds`).option(`--fleet-id <id>`,`Stable fleet id (generated when omitted)`).option(`--parent-fleet <id>`,`Fleet that spawns this one; its cap must cover this cap`).option(`--parent-agent <id>`,`Agent of --parent-fleet that spawns this one`).option(`--keep`,`Keep the fleet after the run instead of deleting 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=/^\d+$/.test(t.agents)?Number(t.agents):JSON.parse(b(t.agents,`utf8`));if(!Array.isArray(n)&&e===void 0)throw Error(`A prompt is required unless --agents names a file whose agents carry tasks`);let r=k(D({apiKey:t.apiKey,baseUrl:t.baseUrl}));if(!!t.parentFleet!=!!t.parentAgent)throw Error(`--parent-fleet and --parent-agent go together`);let i=t.placement===`auto`||t.placement===`dedicated`?t.placement:{agentsPerSandbox:Number(t.placement)},a=t.maxSpendUsd?Number(t.maxSpendUsd):void 0,o=F(`Creating fleet...`);o.start();let s=Date.now(),c=await r.fleets.create({fleetId:t.fleetId,agents:n,placement:i,defaults:{...t.environment?{environment:t.environment}:{},...t.memory?{resources:{memoryMB:Number(t.memory)}}:{},...t.model?{backend:{type:`opencode`,model:{model:t.model}}}:{}},...a===void 0?{}:{budgetUsd:a},...t.parentFleet?{parent:{fleetId:t.parentFleet,agentId:t.parentAgent}}:{}}),l=Date.now()-s;o.stop(),t.json||M(`Fleet ${c.fleetId}: ${c.agents.length} agents on ${c.machines.size} sandboxes in ${l} ms`);let u=[],d;try{for await(let n of c.run(e,{timeoutMs:t.timeout?Number(t.timeout):void 0})){if(n.type===`agent.finished`&&!t.json){let e=n.result;console.log(`[${e.agentId}] ${e.harness??`default`}/${e.model??`default`} ${e.status} ${e.durationMs}ms ${e.costUsd===void 0?`no cost reported`:`$${e.costUsd.toFixed(5)}`} ${e.result?.response??e.error??``}`)}n.type===`fleet.finished`&&(u=n.results,d=n.spend)}}finally{t.keep||await c.delete({continueOnError:!0})}t.json?j({fleetId:c.fleetId,createMs:l,sandboxes:c.machines.size,results:u,spend:d,deleted:!t.keep}):I({fleetId:c.fleetId,completed:u.filter(e=>e.status===`completed`).length,agents:u.length,spend:JSON.stringify(d),deleted:!t.keep}),u.some(e=>e.status!==`completed`)&&(process.exitCode=1)}catch(e){R(e)}}),e.command(`cancel <fleet-id>`).description(`Interrupt every agent of a fleet and cancel its child fleets; sandboxes keep running`).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 k(D({apiKey:t.apiKey,baseUrl:t.baseUrl})).fleets.list({fleetId:e})).cancel();t.json?j({fleetId:e,...n}):M(`Fleet ${e}: interrupted ${n.interrupted} agents, cancelled ${n.children} child fleets`)}catch(e){R(e)}})}const Xo=[`list`,`create`,`delete`,`exec`,`prompt`,`read`,`write`];function Zo(e){if(!(!e||e.length===0)){for(let t of e)if(!Xo.includes(t))throw Error(`Invalid token action '${t}'. Allowed: ${Xo.join(`, `)}`);return e}}function Qo(e){return e.length<=12?`****`:`${e.slice(0,6)}...${e.slice(-4)} (masked — use --json for full value)`}function $o(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 (prompt grants nothing since fleet prompt dispatch was removed)`).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(D({apiKey:t.apiKey,baseUrl:t.baseUrl})),r=F(`Minting fleet token...`);r.start();let i=await n.fleets.createToken(e,{actions:Zo(t.action),ttlMinutes:t.ttlMinutes?Number(t.ttlMinutes):void 0});r.stop(),t.json?j(i):(I({"Fleet ID":i.fleetId,Token:Qo(i.token),"Expires at":new Date(i.expiresAt).toISOString(),Actions:i.actions.join(`, `)}),console.log(`
146
+ Re-run with --json to print the full token value.`))}catch(e){R(e)}})}function es(){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(D({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){R(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(D({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){R(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(D({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){R(e)}}),e}function ts(){let e=new t(`fleet`).description(`Manage sandbox fleets`);return Jo(e),Po(e),e.addCommand(es()),Yo(e),Mo(e),$o(e),e}function ns(){let e=new t(`fs`).description(`File system operations on sandboxes`);return as(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}=os(r),o=await B(a,i,e);if(o=await V(o),!y.existsSync(t))throw Error(`Local file not found: ${t}`);let s=y.statSync(t),c=Date.now();r.json||console.error(`Uploading ${t} to ${n}...`),await o.fs.upload(t,n,{onProgress:e=>{if(r.json)return;let t=e.percentage.toFixed(1);process.stderr.write(`\rProgress: ${t}% (${e.bytesUploaded}/${e.totalBytes} bytes)`)}});let l=Date.now()-c;r.json||console.error(``),r.json?cr({success:!0,localPath:t,remotePath:n,size:s.size,durationMs:l}):console.log(`✓ Uploaded ${s.size} bytes in ${l}ms`)}catch(e){sr(e,r.json)}}),as(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}=os(r),o=await B(a,i,e);o=await V(o);let s=Date.now();r.json||console.error(`Downloading ${t} to ${n}...`),await o.fs.download(t,n,{onProgress:e=>{if(r.json)return;let t=e.percentage.toFixed(1);process.stderr.write(`\rProgress: ${t}% (${e.bytesDownloaded}/${e.totalBytes} bytes)`)}});let c=Date.now()-s,l=y.statSync(n);r.json||console.error(``),r.json?cr({success:!0,remotePath:t,localPath:n,size:l.size,durationMs:c}):console.log(`✓ Downloaded ${l.size} bytes in ${c}ms`)}catch(e){sr(e,r.json)}}),as(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}=os(n),a=await B(i,r,e);a=await V(a);let o=await a.fs.list(t,{all:n.all,long:n.long});if(n.json)cr(o);else if(n.long)L([`Mode`,`Owner`,`Group`,`Size`,`Modified`,`Name`],o.map(e=>{let t=e.isDir?`d`:e.isSymlink?`l`:`-`,n=rs(e.permissions),r=e.isDir?`<DIR>`:is(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){sr(e,n.json)}}),as(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}=os(n),a=await B(i,r,e);a=await V(a);let o=await a.fs.stat(t);n.json?cr(o):(console.log(` File: ${o.name}`),console.log(` Path: ${o.path}`),console.log(` Size: ${is(o.size)} (${o.size} bytes)`),console.log(` Type: ${o.isDir?`directory`:o.isSymlink?`symlink`:`file`}`),console.log(` Mode: ${rs(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){sr(e,n.json)}}),as(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}=os(n),a=await B(i,r,e);a=await V(a);let o=await a.read(t);n.json?cr({path:t,content:o}):console.log(o)}catch(e){sr(e,n.json)}}),as(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}=os(n),a=await B(i,r,e);a=await V(a),await a.fs.delete(t,{recursive:n.recursive}),n.json?cr({success:!0,path:t,deleted:!0}):console.log(`✓ Deleted: ${t}`)}catch(e){sr(e,n.json)}}),as(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}=os(n),a=await B(i,r,e);a=await V(a),await a.fs.mkdir(t,{recursive:n.parents}),n.json?cr({success:!0,path:t,created:!0}):console.log(`✓ Created: ${t}`)}catch(e){sr(e,n.json)}}),as(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}=os(n),a=await B(i,r,e);a=await V(a);let o=await a.fs.exists(t);n.json?cr({path:t,exists:o}):(console.log(o?`exists`:`not found`),process.exit(+!o))}catch(e){sr(e,n.json)}}),e}function rs(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 is(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 as(e){return e.option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`)}function os(e){let t=D({apiKey:e.apiKey,baseUrl:e.baseUrl});return{context:t,client:k(t)}}function ss(){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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching status...`);t.json||i.start();let a=await B(r,n,e);a=await V(a);let o=await a.git.status();if(i.stop(),t.json)j(o);else if(!o.isRepo)console.log(`No git repository in the sandbox workspace.`);else{if(console.log(`Branch: ${o.branch??`unknown`}`),console.log(`HEAD: ${o.head.slice(0,7)||`(no commits)`}`),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){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching log...`);t.json||i.start();let a=await B(r,n,e);a=await V(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(`
147
+ `)[0]} (${e.author}, ${e.date.toLocaleDateString()})`)}catch(e){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching diff...`);t.json||i.start();let a=await B(r,n,e);a=await V(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){R(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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=await B(k(r),r,e);i=await V(i),await i.git.add(t),M(`Staged: ${t.join(`, `)}`)}catch(e){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=await B(k(n),n,e);r=await V(r);let i=await r.git.commit(t.message,{amend:t.amend});t.json?j(i):M(`Committed: ${i.shortSha} ${i.message}`)}catch(e){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Pushing...`);i.start();let a=await B(r,n,e);a=await V(a),await a.git.push({force:t.force}),i.stop(),M(`Pushed to remote`)}catch(e){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Pulling...`);i.start();let a=await B(r,n,e);a=await V(a),await a.git.pull({rebase:t.rebase}),i.stop(),M(`Pulled from remote`)}catch(e){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching branches...`);t.json||i.start();let a=await B(r,n,e);a=await V(a);let o=await a.git.branches();i.stop(),t.json?j(o):o.length===0?console.log(`No branches found`):L([`Name`,`Current`,`Remote`],o.map(e=>[e.name,e.current?`* `:` `,e.upstream??`-`]))}catch(e){R(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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=await B(k(r),r,e);i=await V(i),await i.git.checkout(t,{create:n.create}),M(`Checked out: ${t}${n.create?` (new)`:``}`)}catch(e){R(e)}}),e}function cs(){let e=new t(`hub`).description(`Discover and run Tangle Hub tools`);e.option(`--json`,`Output as JSON`),e.hook(`preAction`,(e,t)=>{us(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(`--parameter <key=value>`,`Provider-specific OAuth value. Repeatable.`,Es,[]).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=Ds(t.parameter),r=await(await z(t)).connections.start(e,{cli:!0,connectionParameters:n});if(t.json){j(ks(r));return}Os(r,t.browser===!1?!1:await mi(r.redirectUrl))}catch(e){K(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 z(e)).connections.list();if(e.json){j(t);return}Ts(t.connections)}catch(t){K(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 z(t),r=await Un(n,e);if(!t.force&&!await H(`Revoke Hub connection ${r}? `,`--force`)){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){K(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 z(e),n=await Un(t,e.connection),r=await t.permissions.list(n);if(e.json){j(r);return}bs(r.policies)}catch(t){K(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=xs(e.decision),n=await z(e),r=await Un(n,e.connection),i=await n.permissions.set({connectionId:r,actionPath:e.action,decision:t});if(e.json){j(i);return}bs([i.policy])}catch(t){K(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 z(e),n=await Un(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){K(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 z(e)).approvals.list();if(e.json){j(t);return}hs(t.approvals)}catch(t){K(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{ms(e),gs(await(await z(t)).approvals.approve(e),t.json===!0)}catch(e){K(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{ms(e),gs(await(await z(t)).approvals.deny(e),t.json===!0)}catch(e){K(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 z(e)).tools.sources();if(e.json){j(t);return}Ss(t.sources)}catch(t){K(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 z(t)).tools.describe(e);if(t.json){j(n);return}Cs(n.tool)}catch(e){K(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 z(t)).tools.search(e.join(` `),{provider:t.provider});if(t.json){j(n);return}ys(n.tools)}catch(e){K(e,t)}}),e.addCommand(a),e.addCommand(ls(`call`)),e.addCommand(ls(`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(ms(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 z(t);gs(t.decline?await n.approvals.deny(e):await n.approvals.approve(e),t.json===!0)}catch(e){K(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 z(e)).status();if(e.json){j(t);return}As(t)}catch(t){K(t,e)}}),e}function ls(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}=ps(e,t),{path:i,input:a}=vs(n),o=await z(t),s=t.connection?await Un(o,t.connection):void 0;j((await o.tools.invoke(i,a,{connectionId:s,approve:r})).result)}catch(e){K(e,t)}})}function us(e){if(!ds(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 ds(e,t){return e.options.some(e=>e.attributeName()===t)}function fs(e){return e.json===!0}function K(e,t){return fs(t)?R(e,!0):R(e)}function ps(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 ms(e){if(!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`Hub approval ID must contain only letters, numbers, underscores, and dashes.`)}function hs(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 gs(e,t){if(t){j(_s(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 _s(e){return{approval:e.approval,...e.capabilityToken?{capabilityToken:{tokenId:e.capabilityToken.tokenId,expiresAt:e.capabilityToken.expiresAt}}:{}}}function vs(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 ys(e){A(e.map(e=>({path:e.path,provider:e.providerId??e.requiredConnectionProviderId,title:e.title,description:e.description,connection:ws(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 bs(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 xs(e){if(e===`allow`||e===`ask`||e===`deny`)return e;throw Error(`--decision must be one of: allow, ask, deny.`)}function Ss(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 Cs(e){I({Path:e.path,Provider:e.providerId??e.requiredConnectionProviderId,Title:e.title,Description:e.description,Connection:ws(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 ws(e){if(e.connectionRequired===!1)return`not required`;if(e.connectionStatus)return e.connectionStatus}function Ts(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 Es(e,t){return[...t,e]}function Ds(e){if(!e||e.length===0)return;let t={};for(let n of e){let e=n.indexOf(`=`);if(e<=0||e===n.length-1)throw Error(`Invalid --parameter "${n}": expected key=value (for example subdomain=acme)`);let r=n.slice(0,e);if(Object.hasOwn(t,r))throw Error(`Duplicate --parameter key "${r}".`);t[r]=n.slice(e+1)}return t}function Os(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 ks(e){return{provider:e.provider,redirectUrl:e.redirectUrl,expiresAt:e.expiresAt,scopes:e.scopes,cli:e.cli}}function As(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.`)}function js(){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`,Ki).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`;Zi(n);let r=Ns(t.apiKey),i=await na({selection:n,workspace:t.workspace,apiKey:r,endpoint:t.endpoint,serviceName:t.serviceName??$i(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){R(e)}}),e.command(`doctor`).description(`Check whether your agent traces carry CONTENT or are metadata-only`).option(`--api-key <key>`,`Intelligence ingest API key`).option(`--endpoint <url>`,`OTLP endpoint base`,Ki).option(`--json`,`Output as JSON`).action(async e=>{try{let t=ta(),n=await sa({endpoint:e.endpoint===`https://intelligence.tangle.tools/v1/otlp`?t?.endpoint??`https://intelligence.tangle.tools/v1/otlp`:e.endpoint,apiKey:Ns(e.apiKey??t?.apiKey)});e.json?j(n):Ms(n),n.contentSeen||(process.exitCode=1)}catch(e){R(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=Ps(e.agent),n=ta(),r={agent:t,event:e.event,endpoint:e.endpoint??n?.endpoint??`https://intelligence.tangle.tools/v1/otlp`,apiKey:Ns(e.apiKey??n?.apiKey),serviceName:e.serviceName??n?.serviceName??$i(process.cwd()),environment:e.environment??n?.environment??`local`,sessionId:e.sessionId,payload:e.payload===void 0?await Is():Fs(e.payload)};if(e.dryRun){let n=ia(r);if(e.json){j(n);return}I({Trace:n.traceId,Agent:t,Event:e.event});return}let i=await aa(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}R(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 Ls({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 Ls({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 Ls({type:zs(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(D({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}Rs(i)}catch(e){R(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(D({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:zs(e.subjectType),subjectId:e.subjectId,limit:e.limit===void 0?void 0:Hs(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){R(e)}}),e}function Ms(e){I({Status:e.contentSeen?`content flowing`:e.tracesSeen?`metadata-only — a content gate is missing`:`no traces yet`,"Traces seen":e.tracesSeen?`yes`:`no`,"Content seen":e.contentSeen?`yes`:`no`,"Last seen":e.lastSeenAt??`never`,Window:`${e.windowDays}d`});let t=Object.entries(e.byAgent);t.length>0&&(console.log(),A(t.map(([e,t])=>({agent:e,traces:t.tracesSeen?`yes`:`no`,content:t.contentSeen?`yes`:`no`})),[{key:`agent`,header:`Agent`,width:18},{key:`traces`,header:`Traces`,width:10},{key:`content`,header:`Content`,width:10}]))}function Ns(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 Ps(e){if(Qi(e))return e;throw Error(`agent must be a known Tangle Intelligence agent surface`)}function Fs(e){try{return JSON.parse(e)}catch(e){throw Error(`--payload must be JSON: ${e instanceof Error?e.message:String(e)}`)}}async function Is(){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 Ls(e,t){try{let n=Bs(t.mode),r=Us(t.metadata),i=t.maxUsd===void 0?void 0:Vs(t.maxUsd);if(n===`agentic`&&i===void 0)throw Error(`Agentic intelligence reports require --max-usd`);let a=k(D({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}Rs(s)}catch(e){R(e)}}function Rs(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 zs(e){if(e===`sandbox`||e===`fleet`)return e;throw Error(`subject type must be sandbox or fleet`)}function Bs(e){if(e===`deterministic`||e===`agentic`)return e;throw Error(`mode must be deterministic or agentic`)}function Vs(e){let t=Number(e);if(!Number.isFinite(t)||t<0)throw Error(`--max-usd must be a non-negative number`);return t}function Hs(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function Us(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 Ws=[`router`,`sandbox`,`blueprint-agent`,`evals`,`agent-builder`];function Gs(e){if(e.minted)throw Error("This command needs a key you minted yourself. A browser login is exchanged for a short-lived key the platform will not accept for key management. Set TANGLE_API_KEY, run `tangle auth login --api-key sk-tan-…`, or mint the key in the web console. `tangle keys list` works from the login alone.")}async function Ks(e,t,n={}){let r=new Headers(n.headers);n.body&&!r.has(`content-type`)&&r.set(`content-type`,`application/json`);let i=await Ar(e,t,{...n,headers:r});if(n.expected!==void 0&&i.status!==n.expected)throw Error(await qs(i,t));return i}async function qs(e,t){let n=await e.text().catch(()=>``),r;try{let e=JSON.parse(n),t=typeof e?.error==`string`?e.error:e?.error?.message;typeof t==`string`&&t.trim()&&(r=t)}catch{}if(r)return`${r} (HTTP ${e.status})`;let i=n?`: ${n.slice(0,400)}`:``;return`Platform request to ${t} returned ${e.status}${i}`}const Js=[`ID`,`Prefix`,`Name`,`Product`,`Created`,`Last used`,`Expires`];function Ys(e){return[e.id,e.keyPrefix??``,e.name,e.product??`all`,e.createdAt,e.lastUsedAt??`—`,e.expiresAt??`—`]}function Xs(){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=await kr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.platformUrl===void 0?{}:{baseUrl:e.platformUrl},...e.baseUrl===void 0?{}:{sandboxBaseUrl:e.baseUrl}}),n=t.baseUrl,r=await(await Ks(t,`${n}/v1/keys`,{expected:200})).json();if(e.json){j(r);return}L(Js,r.data.map(Ys))}catch(e){R(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 (${Ws.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&&!Ws.includes(t.product))throw Error(`Invalid --product. Expected one of ${Ws.join(`, `)}`);let n=await kr({...t.apiKey===void 0?{}:{apiKey:t.apiKey},...t.platformUrl===void 0?{}:{baseUrl:t.platformUrl},...t.baseUrl===void 0?{}:{sandboxBaseUrl:t.baseUrl}});Gs(n);let r=n.baseUrl,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 Ks(n,`${r}/v1/keys`,{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){R(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=await kr({...t.apiKey===void 0?{}:{apiKey:t.apiKey},...t.platformUrl===void 0?{}:{baseUrl:t.platformUrl},...t.baseUrl===void 0?{}:{sandboxBaseUrl:t.baseUrl}});Gs(n);let r=n.baseUrl;if(!t.yes&&!await H(`Revoke key ${e}? Any service still using it will start to fail.`,`--yes`)){P(`Aborted.`);return}let i=await(await Ks(n,`${r}/v1/keys/${encodeURIComponent(e)}`,{method:`DELETE`,expected:200})).json();if(t.json){j(i);return}M(`Revoked ${e}`)}catch(e){R(e)}}),e}function Zs(e){if(dn().token)throw Error(`A line relay cannot manage numbers or attachments. Use your owner CLI outside the agent box.`);return k(D(e))}function Qs(e){if(!e.yes)throw Error(`Review the selected line and use --yes to authorize this change. Attaching enables metered agent work.`)}function $s(e){if(e===`imessage`||e===`whatsapp`||e===`email`||e===`sms`||e===`voice`||e===`telegram`)return e;throw Error(`--transport must be imessage, whatsapp, email, sms, voice, or telegram`)}function ec(e){return e().catch(R)}async function tc(e){let t=await Le(e,`r`);try{if(!(await t.stat()).isFile())throw Error(`Attachment input must be a regular JSON file`);let e=Buffer.alloc(131073),n=0;for(;n<e.length;){let{bytesRead:r}=await t.read(e,n,e.length-n,null);if(r===0)break;n+=r}if(n===e.length)throw Error(`Attachment JSON exceeds 128 KiB`);let r;try{r=JSON.parse(e.subarray(0,n).toString(`utf8`))}catch{throw Error(`Attachment file is not valid JSON`)}if(!r||typeof r!=`object`||Array.isArray(r))throw Error(`Attachment JSON must be an object`);if(Object.hasOwn(r,`number`))throw Error(`Use the line ID argument, not a number field in the attachment file`);return r}finally{await t.close()}}function nc(e){e.command(`providers`).description(`List provider transports supported by this Hub deployment`).option(`--json`,`Output JSON`).action(e=>ec(async()=>{j(await Zs(e).lines.providers())})),e.command(`list`).description(`List owned lines, optionally for a saved agent profile or sandbox`).option(`--profile-id <id>`,`Stored profile ID`).option(`--sandbox <id>`,`Existing sandbox ID`).option(`--json`,`Output JSON`).action(e=>ec(async()=>{j(await Zs(e).lines.list({profileId:e.profileId,sandboxId:e.sandbox}))})),e.command(`get`).argument(`<line-id>`).description(`Inspect a line and its current attachment`).option(`--json`,`Output JSON`).action((e,t)=>ec(async()=>{j(await Zs(t).lines.get(e))})),e.command(`numbers`).argument(`<connection-id>`).description(`Discover owned provider numbers; this does not purchase or reserve a number`).option(`--transport <transport>`,`imessage, whatsapp, or sms`,`imessage`).option(`--json`,`Output JSON`).action((e,t)=>ec(async()=>{let n=$s(t.transport);if(n===`email`)throw Error(`Email uses an owned mailbox, not phone inventory`);if(n===`voice`)throw Error(`Voice numbers are listed by ph0ny; provide the owned number ID to lines connect`);if(n===`telegram`)throw Error(`Telegram uses an owned bot, not phone inventory`);j(await Zs(t).lines.numbers(e,n))})),e.command(`connect`).argument(`<connection-id>`).description(`Bind an owned number or identity through Hub; no provider rental is purchased`).option(`--transport <transport>`,`imessage, whatsapp, sms, email, voice, or telegram`,`imessage`).option(`--number-id <id>`,`Exact owned provider number ID; required for voice, SMS, WhatsApp and Linq iMessage`).option(`--address <email>`,`Owned mailbox on a verified email domain`).requiredOption(`--reference <reference>`,`Stable client reference; keep it unchanged on retry`).option(`--label <label>`,`Line display name`).option(`--yes`,`Authorize provider webhook configuration and line binding`).option(`--json`,`Output JSON`).action((e,t)=>ec(async()=>{Qs(t);let n=$s(t.transport);if(n!==`email`&&t.address)throw Error(`--address is email-only`);if((n===`email`||n===`telegram`)&&t.numberId)throw Error(`${n} does not take --number-id`);let r={connectionId:e,label:t.label,clientReference:t.reference},i;if(n===`email`)i={...r,transport:n,address:t.address};else if(n===`telegram`)i={...r,transport:n};else if(n===`imessage`)i={...r,transport:n,phoneNumberId:t.numberId};else{if(!t.numberId)throw Error(`${n} requires --number-id`);i={...r,transport:n,phoneNumberId:t.numberId}}j(await Zs(t).lines.fromConnection(i))})),e.command(`attach`).argument(`<line-id>`).description(`Attach a saved agent to any sandbox, or use an isolated on-demand member instance`).option(`--file <path>`,`Reviewed native attachment JSON (exclusive with quick-setup flags)`).option(`--profile-id <id>`,`Owner-scoped saved profile; each turn pins its source revision`).option(`--member <address>`,`The one allowed sender: E.164 phone or email`).option(`--sandbox <id>`,`Use an existing sandbox instead of an on-demand instance`).option(`--instance-prefix <prefix>`,`Stable instance namespace; defaults to profile:<profile-id>:`).option(`--tools <mode>`,`chat denies tools; act applies the profile's tools and permissions`).option(`--turns-per-day <count>`,`Per-member daily turn ceiling (default 30)`).option(`--yes`,`Authorize agent execution and spend against your key limits`).option(`--json`,`Output JSON`).action((e,t)=>ec(async()=>{Qs(t);let n=Zs(t),r;if(t.file){if(t.profileId||t.member||t.sandbox||t.instancePrefix||t.tools||t.turnsPerDay)throw Error(`Choose --file or quick-setup flags, not both`);r=await tc(t.file)}else{if(!t.profileId||!t.member)throw Error(`Provide --profile-id and --member, or --file`);if(t.sandbox&&t.instancePrefix)throw Error(`Choose --sandbox or --instance-prefix`);let e=t.tools??`chat`,n=Number(t.turnsPerDay??`30`);if(e!==`chat`&&e!==`act`)throw Error(`--tools must be chat or act`);if(!Number.isSafeInteger(n)||n<1||n>1e4)throw Error(`--turns-per-day must be 1–10000`);if(e===`act`&&t.sandbox)throw Error(`Acting tools require an isolated on-demand instance; omit --sandbox`);r={mode:`personal`,members:[{address:t.member,role:`owner`}],unknownSenders:`reject`,roles:{owner:{context:`own`,tools:e}},respond:{kind:`agent`,profileId:t.profileId,...e===`act`?{rolePolicy:{version:1,roles:{owner:{kind:`general`}},members:{}}}:{}},limits:{turnsPerMemberPerDay:n},...t.sandbox?{sandboxId:t.sandbox}:{instance:{keyPrefix:t.instancePrefix??`profile:${t.profileId}:`,create:{ownerContext:`isolated`,...e===`act`?{egressPolicy:{mode:`strict`,allowDomains:[new URL(An()).hostname],includeImplicitDomains:!1}}:{}}}}}}if(typeof r.sandboxId==`string`==(r.instance!==void 0))throw Error(`Attachment requires exactly one of sandboxId and instance`);let{sandboxId:i,instance:a,...o}=r,s;if(i){let t=await n.get(i);if(!t)throw Error(`Sandbox not found`);s=await t.lines.attach({...o,number:e})}else{if(!a)throw Error(`Attachment requires an instance`);s=await n.lines.attach({...o,number:e,instance:a})}j(s)}));for(let t of[`detach`,`release`])e.command(t).argument(`<line-id>`).description(t===`detach`?`Stop dispatch; preserve history and provider rental`:`Retire a detached Hub line; does not cancel provider rental`).option(`--yes`,`Authorize this change`).option(`--json`,`Output JSON`).action((e,n)=>ec(async()=>{Qs(n),j({[t]:await Zs(n).lines[t](e)})}));e.command(`threads`).argument(`<line-id>`).description(`List this line's separate participant threads`).option(`--json`,`Output JSON`).action((e,t)=>ec(async()=>{j(await Zs(t).lines.threads(e).list())})),e.command(`messages`).argument(`<line-id>`).argument(`<thread-id>`).description(`Read one authorized participant thread`).option(`--json`,`Output JSON`).action((e,t,n)=>ec(async()=>{j(await Zs(n).lines.threads(e).messages(t))}))}async function rc(e){let{token:t,baseUrl:n}=dn();if(t===void 0)return z(e);if(!t.startsWith(`lrc_`)||!n)throw Error(`The line box needs TANGLE_LINE_TOKEN and TANGLE_HUB_URL`);if(e.apiKey||e.baseUrl&&new URL(e.baseUrl).origin!==new URL(n).origin)throw Error(`A line token cannot be sent to another Hub or combined with an API key`);return new De({baseUrl:n,authHeaders:()=>({Authorization:`Bearer ${t}`})})}async function ic(e,t){if(t)return t;if(!dn().token)throw Error(`Provide --line <line-id>`);return(await e.lines.context()).line.id}function ac(e){return e().catch(R)}function oc(){return new t(`context`).description(`Show live line identity, members, consent, reminders and quotas`).option(`--json`,`Output JSON`).action(e=>ac(async()=>{j(await(await rc(e)).lines.context())}))}function sc(){let e=new t(`lines`).description(`Connect, manage, message and schedule on a Hub line`);return e.command(`members`).description(`List names, roles and consent on this line`).option(`--line <line-id>`,`Line ID; inferred in a line box`).option(`--json`,`Output JSON`).action(e=>ac(async()=>{let t=await rc(e);j(await t.lines.members.list(await ic(t,e.line)))})),e.command(`send`).description(`Send to a consenting member through Hub`).argument(`<to-member>`,`Exact member ID for an owner; name, ID, or self in a line box`).argument(`<text>`,`Message text`).option(`--line <line-id>`,`Line ID; inferred in a line box`).option(`--on-behalf-of <member>`,`Verified sender for a member relay`).option(`--not-before <iso-time>`,`Delay delivery until this ISO time`).option(`--idempotency-key <key>`,`Stable key for a retry`).option(`--json`,`Output JSON`).action((e,t,n)=>ac(async()=>{let r=await rc(n),i=await ic(r,n.line);if(!dn().token){if(n.onBehalfOf)throw Error(`--on-behalf-of is only available inside a line box`);if(!n.idempotencyKey)throw Error(`Owner sends require --idempotency-key so a retry keeps the same message`);if(!(await r.lines.members.list(i)).some(t=>t.id===e))throw Error(`Owner sends require an exact member ID from tangle lines members`);j(await r.lines.send(i,{memberId:e,text:t,idempotencyKey:n.idempotencyKey,...n.notBefore?{notBefore:n.notBefore}:{}}));return}j(await r.lines.send(i,{toMember:e,text:t,...n.onBehalfOf?{onBehalfOf:n.onBehalfOf}:{},...n.notBefore?{notBefore:n.notBefore}:{},...n.idempotencyKey?{idempotencyKey:n.idempotencyKey}:{}}))})),e.command(`remind`).description(`Wake the agent at a future time to write your reminder`).argument(`<text>`,`What to remember`).requiredOption(`--at <iso-time>`,`Future ISO time`).option(`--line <line-id>`,`Line ID; inferred in a line box`).option(`--idempotency-key <key>`,`Stable key for a retry`).option(`--json`,`Output JSON`).action((e,t)=>ac(async()=>{if(!t.at)throw Error(`--at is required`);let r=await rc(t),i=t.idempotencyKey??n(`sha256`).update(JSON.stringify([e,t.at])).digest(`hex`).slice(0,32);j(await r.lines.remind(await ic(r,t.line),{text:e,notBefore:t.at,idempotencyKey:i}))})),nc(e),e}function cc(){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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=await B(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 ze(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){R(e)}}),e}function lc(){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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching users...`);i.start();let a=await(await B(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){R(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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Fetching user...`);a.start();let o=await(await B(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){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Adding user...`);i.start();let a=await(await B(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){R(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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Updating user...`);a.start();let o=await(await B(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){R(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&&!await H(`Remove user ${t} from sandbox? [y/N] `,`--force`)){P(`Cancelled.`);return}let r=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Removing user...`);a.start(),await(await B(i,r,e)).permissions.remove(t,{preserveHomeDir:n.preserveHome}),a.stop(),M(`User ${t} removed from sandbox ${e}`)}catch(e){R(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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Fetching policies...`);a.start();let o=await(await B(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){R(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=D({apiKey:i.apiKey,baseUrl:i.baseUrl}),o=k(a),s=F(`Checking access...`);s.start();let c=await(await B(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){R(e)}}),e}async function uc(e,t){if(t.self&&e)throw Error(`Use --self or an explicit sandbox, not both`);if(!t.self&&!e)throw Error(`Specify a sandbox id/name or --self`);let n=tn(),r=t.baseUrl||n.tangleBaseUrl||n.sandboxBaseUrl,i=n.hubUrl;if(t.self&&!r&&i&&new URL(i).origin!==`https://id.tangle.tools`)throw Error(`This deployment must set SANDBOX_BASE_URL or pass --base-url for self preview access`);let a=t.self?t.apiKey??xn():t.apiKey;if(t.self&&!a)throw Error(`Self preview access requires the injected sandbox runtime credential; it never reads saved owner credentials`);let o=D({apiKey:a,baseUrl:r}),s=k(o);return t.self?He(s):B(s,o,e)}async function dc(e,t,n){let r=F(e);t||r.start();try{return await n()}finally{r.stop()}}function fc(e){return e.option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key (prefer the environment)`).option(`--base-url <url>`,`API base URL`)}function pc(){let e=new t(`preview`).description(`Manage sandbox preview links`);return fc(e.command(`start`).description(`Start/reuse a managed development server and publish its ready preview`).argument(`[id-or-name]`,`Sandbox ID or name`).option(`--self`,`Use only the sandbox bound to the runtime credential`).option(`--cwd <directory>`,`Project directory in the selected workspace`).option(`--session <session-id>`,`Select the agent's session workspace`).option(`--name <name>`,`App/service label`)).action(async(e,t)=>{try{let n=await uc(e,t),r=await dc(`Starting managed preview...`,t.json,()=>Be(n,{cwd:t.cwd,sessionId:t.session,name:t.name}));t.json?j(r):(M(`Preview ready: ${r.url}`),console.log(`Preview ID: ${r.previewId}`))}catch(e){R(e)}}),fc(e.command(`list`).alias(`ls`).description(`List active preview links for a sandbox`).argument(`[id-or-name]`,`Sandbox ID or name`).option(`--self`,`Use only the sandbox bound to the runtime credential`)).action(async(e,t)=>{try{let n=await uc(e,t),r=await dc(`Fetching preview links...`,t.json,()=>n.previewLinks.list());t.json?j(r):r.length===0?console.log(`No preview links found`):L([`App`,`Preview ID`,`Port`,`URL`,`Status`],r.map(e=>[mc(e.metadata),e.previewId.slice(0,12),String(e.port),e.url,e.status]))}catch(e){R(e)}}),fc(e.command(`publish`).description(`Publish one existing HTTP service; never starts or replaces a process`).argument(`[id-or-name]`,`Sandbox ID or name`).option(`--self`,`Use only the sandbox bound to the runtime credential`).requiredOption(`--port <port>`,`Existing service port`).option(`--name <name>`,`App/service label`)).action(async(e,t)=>{try{if(!t.port||!/^\d+$/.test(t.port))throw Error(`An integer service port is required`);let n=await uc(e,t),r=await dc(`Publishing service...`,t.json,()=>Ve(n,{port:Number(t.port),name:t.name}));t.json?j(r):M(`Preview ready: ${r.url}`)}catch(e){R(e)}}),fc(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`)).action(async(e,t,n)=>{try{if(!/^\d+$/.test(t)||Number(t)<1||Number(t)>65535)throw Error(`Port must be an integer between 1 and 65535`);let r=await uc(e,n),i=await dc(`Creating preview for port ${t}...`,n.json,()=>r.previewLinks.create(Number(t)));n.json?j(i):(M(`Preview created: ${i.url}`),console.log(`Preview ID: ${i.previewId}`))}catch(e){R(e)}}),fc(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')`)).action(async(e,t,n)=>{try{let r=await uc(e,n);await dc(`Removing preview...`,n.json,()=>r.previewLinks.remove(t)),n.json?j({success:!0,previewId:t}):M(`Preview removed: ${t}`)}catch(e){R(e)}}),e}function mc(e){let t=e?.app;if(!t||typeof t!=`object`)return``;let n=`name`in t?t.name:void 0,r=`cwd`in t?t.cwd:void 0;return typeof n==`string`?n:typeof r==`string`?r:``}function hc(){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=D({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 B(i,r,e);if(s=await V(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){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching processes...`);t.json||i.start();let a=await B(r,n,e);a=await V(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`):L([`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){R(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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Fetching process info...`);n.json||a.start();let o=await B(i,r,e);o=await V(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){R(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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Sending ${n.signal} to PID ${t}...`);n.json||a.start();let o=await B(i,r,e);o=await V(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){R(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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=await B(k(r),r,e);i=await V(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){R(e)}}),e}const gc=[`python`,`node`,`typescript`,`bash`];function _c(e){switch(_e(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 vc(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 Re(ye(e),`utf8`)}async function yc(e,t,n=vc){let r=t?gc.find(e=>e===t)??(()=>{throw Error(`unknown --lang ${t}: must be one of ${gc.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=_c(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 bc(e){return ve(Se(),`tangle-run-images`,e)}function xc(){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: ${gc.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 yc(t,n.lang),a=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),o=await B(k(a),a,e);o=await V(o);let s=F(`Running ${r} (${i.length}b)…`);n.json||s.start();let c=await o.runCode(r,i,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10)});if(s.stop(),n.json){j(c),c.exitCode!==0&&process.exit(c.exitCode);return}c.stdout&&process.stdout.write(c.stdout),c.stderr&&process.stderr.write(c.stderr);let l=0;for(let t of c.results)if(t.type===`image`)if(n.saveImages!==!1){let r=typeof n.saveImages==`string`?n.saveImages:bc(e);fe(r,{recursive:!0});let i=`${r}/${Date.now()}-${l}.${t.format}`;me(i,Buffer.from(t.data,`base64`)),process.stderr.write(v.green(`✓ image → ${i}\n`)),l++}else process.stderr.write(v.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(v.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(v.gray(`… ${t.rows.length-20} more rows\n`))}else t.type===`json`?(process.stderr.write(v.gray(`[json] `)),process.stderr.write(`${JSON.stringify(t.value,null,2)}\n`)):t.type===`html`?process.stderr.write(v.gray(`[html ${t.value.length}b]\n`)):t.type===`error`?(process.stderr.write(v.red(`✗ ${t.name}: ${t.message}\n`)),t.traceback&&process.stderr.write(`${t.traceback}\n`)):t.type===`text`&&process.stderr.write(`${t.value}\n`);c.error&&(process.stderr.write(v.red(`\n✗ ${c.error.name}: ${c.error.message}\n`)),c.error.traceback&&process.stderr.write(`${c.error.traceback}\n`)),c.exitCode!==0&&process.exit(c.exitCode)}catch(e){R(e)}})}async function Sc(e,t){let n=await kr({apiKey:t.apiKey,baseUrl:t.baseUrl??An()}),r=await fetch(`${n.baseUrl}/v1/agent-profiles/${encodeURIComponent(e)}`,{headers:{authorization:`Bearer ${n.token}`,accept:`application/json`}});if(!r.ok){let t=await r.text().catch(()=>``);throw r.status===404?Error(`profile '${e}' not found in the platform catalog (it may be a built-in, a stored profile you own, or neither — run 'tangle profile list' to see what is available)`):Error(`platform returned ${r.status}: ${t.slice(0,200)}`)}let i=await r.json();if(!i.definition||typeof i.definition!=`object`)throw Error(`profile '${e}' resolved but has no definition — the catalog entry is malformed`);return i.definition}async function Cc(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 Gr();if(t.length===0)throw Error(`${e.flagPrefix}-stdin received empty input on stdin`);return t}}function wc(e){if(e.secret===void 0)return;let t=e.backend===`claude-code`?`token`:e.backend===`codex`?`bundle`:void 0;if(!t)throw Error(`--cli-auth needs --backend claude-code or --backend codex`);if(e.apiKeyGiven)throw Error(`--cli-auth cannot be combined with --backend-api-key-env or --backend-api-key-stdin`);return{account:`cli`,secretEnv:e.secret,format:t}}function Tc(e){if(e!==void 0)return e.map(e=>{let t=e.indexOf(`@`);if(t===-1)return e;let n=e.slice(0,t),r=e.slice(t+1),i=r.indexOf(`:`),a=i===-1?r:r.slice(0,i),o=i===-1?void 0:r.slice(i+1);if(!n||!a||o===``)throw Error(`--secret ${e}: expected NAME, NAME@host or NAME@host:Header`);return o===void 0?{name:n,host:a}:{name:n,host:a,header:o}})}function Ec(e,t){let n={};return e.cpu!==void 0&&(n.cpuCores=G(e.cpu,`--cpu`)),e.memory!==void 0&&(n.memoryMB=G(e.memory,`--memory`)),e.disk!==void 0&&(n.diskGB=G(e.disk,`--disk`)),t&&(n.accelerator=t),Object.keys(n).length>0?n:void 0}function Dc(e){let t=e.split(`/`);return t.length>=2?{provider:t[0],model:t.slice(1).join(`/`)}:{model:e}}function Oc(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]=kc(r.join(`=`))}return t}function kc(e){try{return JSON.parse(e)}catch{return e}}function Ac(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`?G(e.gitDepth,`--git-depth`):void 0,sparse:Array.isArray(e.gitSparse)?e.gitSparse:void 0,auth:t?{token:t}:void 0}}}function jc(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:Mc(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 Mc(e){if(e===`s3`||e===`gcs`||e===`r2`)return e;throw Error(`--storage-type must be one of s3, gcs, or r2`)}function Nc(e){P(` Status: ${e.status}`),P(` Provider: ${e.provider}`),P(` GPU: ${e.accelerator.kind} x ${e.accelerator.count}`),e.customerPricePerHourUsd!==void 0&&P(` Customer price: $${e.customerPricePerHourUsd}/hr`),e.estimatedCustomerCostUsd!==void 0&&P(` Max estimate: $${e.estimatedCustomerCostUsd}`),e.billing&&(P(` Billed seconds: ${e.billing.seconds}`),P(` Customer cost: $${e.billing.customerCostUsd}`))}function Pc(e){e.result.stdout&&process.stdout.write(e.result.stdout),e.result.stderr&&process.stderr.write(e.result.stderr),P(`Exit code: ${e.result.exitCode}`)}function Fc(e){let t=e.command(`gpu`).description(`Manage on-demand GPU leases for a sandbox`);t.command(`providers <id-or-name>`).description(`List GPU clouds, whether each credential works, and current prices`).option(`--accelerator-kind <kind>`,`Price this GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`).option(`--accelerator-memory <mb>`,`Minimum GPU memory in MB`).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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Checking GPU providers...`);i.start();let a=await(await B(r,n,e)).gpu.providers(t.acceleratorKind?{accelerator:Fo({kind:t.acceleratorKind,count:t.acceleratorCount,memory:t.acceleratorMemory})}:{});if(i.stop(),t.json){j(a);return}A(a.statuses.map(e=>({provider:e.provider,state:e.state,gpu:e.estimate?.providerInstanceType??``,usdHr:e.estimate?e.estimate.customerPricePerHourUsd.toFixed(4):``,pricing:e.estimate?.pricingSource??``,needs:e.envVars.join(` `)})),[{key:`provider`,header:`Provider`},{key:`state`,header:`State`},{key:`gpu`,header:`GPU`},{key:`usdHr`,header:`$/hr`},{key:`pricing`,header:`Price`},{key:`needs`,header:`Needs`}]);for(let e of a.statuses){let t=e.state===`credential-invalid`?e.credential?.detail:e.estimateError;t&&P(`${e.provider}: ${t}`)}a.usable.length===0&&P(`No GPU provider is usable on this deployment: set the variables in Needs for one provider on the server.`)}catch(e){R(e)}}),t.command(`attach <id-or-name>`).description(`Attach a temporary GPU worker to a sandbox`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <mb>`,`Minimum GPU memory in MB`).option(`--provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--image <image>`,`GPU worker image override`).option(`--env <vars...>`,`Environment variables for the GPU worker (KEY=VALUE)`).requiredOption(`--max-spend-usd <usd>`,`Maximum customer spend for this lease`).requiredOption(`--max-lifetime <seconds>`,`Maximum lease lifetime in seconds`).option(`--idle-timeout <seconds>`,`Destroy after this many idle seconds`).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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Attaching GPU lease...`);i.start();let a=await(await B(r,n,e)).gpu.attach(Lo(t));i.stop(),t.json?j(a):(M(`GPU lease attached: ${a.id}`),Nc(a))}catch(e){R(e)}}),t.command(`run <id-or-name> <command...>`).description(`Attach a temporary GPU, run a command, then destroy it`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <mb>`,`Minimum GPU memory in MB`).option(`--provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--image <image>`,`GPU worker image override`).option(`--env <vars...>`,`Environment variables for the GPU worker and command (KEY=VALUE)`).requiredOption(`--max-spend-usd <usd>`,`Maximum customer spend for this lease`).requiredOption(`--max-lifetime <seconds>`,`Maximum lease lifetime in seconds`).option(`--idle-timeout <seconds>`,`Destroy after this many idle seconds`).option(`--timeout <ms>`,`Command timeout in milliseconds`).option(`--cwd <path>`,`Working directory`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t,n)=>{let r,i,a,o;try{let a=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),o=await B(k(a),a,e),s=F(`Attaching GPU lease...`);s.start(),r=await o.gpu.attach(Lo(n)),s.stop();let c=F(`Running GPU command...`);c.start(),i=await o.gpu.exec(r.id,{command:t.join(` `),timeoutMs:n.timeout?G(String(n.timeout),`--timeout`):void 0,cwd:n.cwd,env:n.env?Ro(n.env,`--env`,`env`):void 0}),c.stop(),n.json||Pc(i)}catch(e){a=e}finally{if(r)try{let t=D({apiKey:n.apiKey,baseUrl:n.baseUrl});r=await(await B(k(t),t,e)).gpu.detach(r.id)}catch(e){o=e}}if(a){R(a),o&&R(o);return}if(o){R(o);return}n.json?j({lease:r,result:i}):r&&M(`GPU lease detached: ${r.id}`);let s=i?.result.exitCode;s&&s!==0&&(process.exitCode=s)}),t.command(`list <id-or-name>`).description(`List GPU leases attached to 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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching GPU leases...`);i.start();let a=await(await B(r,n,e)).gpu.list();i.stop(),t.json?j(a):a.length===0?P(`No GPU leases attached.`):A(a.map(e=>({id:e.id,status:e.status,provider:e.provider,accelerator:`${e.accelerator.kind}x${e.accelerator.count}`,customerUsdHr:e.customerPricePerHourUsd??``})),[{key:`id`,header:`ID`,width:28},{key:`status`,header:`Status`,width:12},{key:`provider`,header:`Provider`,width:12},{key:`accelerator`,header:`GPU`,width:24},{key:`customerUsdHr`,header:`$/hr`,width:10}])}catch(e){R(e)}}),t.command(`exec <id-or-name> <lease-id> <command...>`).description(`Run a command on an attached GPU lease`).option(`--timeout <ms>`,`Command timeout in milliseconds`).option(`--cwd <path>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).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=D({apiKey:r.apiKey,baseUrl:r.baseUrl}),a=k(i),o=F(`Running GPU command...`);o.start();let s=await(await B(a,i,e)).gpu.exec(t,{command:n.join(` `),timeoutMs:r.timeout?G(String(r.timeout),`--timeout`):void 0,cwd:r.cwd,env:r.env?Ro(r.env,`--env`,`env`):void 0});o.stop(),r.json?j(s):Pc(s)}catch(e){R(e)}}),t.command(`detach <id-or-name> <lease-id>`).description(`Detach and destroy a GPU lease`).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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Detaching GPU lease...`);a.start();let o=await(await B(i,r,e)).gpu.detach(t);a.stop(),n.json?j(o):(M(`GPU lease detached: ${o.id}`),Nc(o))}catch(e){R(e)}})}function Ic(e,t){if(t){j(e);return}if(!e.id){e.kind===`snapshot`&&e.result?.snapshot?M(`Snapshot created: ${e.result.snapshot.snapshotId}`):M(`Sandbox ${e.sandboxId} stopped.`);return}M(`${e.kind===`snapshot`?`Snapshot`:`Stop`} of sandbox ${e.sandboxId} accepted.`),P(`Operation: ${e.id}`),P(`Status: ${e.statusUrl}`)}function Lc(e){return`${e.name} (${e.id})`}async function Rc(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 q(e,t,n){if(t)return Rc(e,t);let r=Nn(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 zc(e,t){Pn({id:e.id,name:e.name},t)}function Bc(e){Fn(e)}async function Vc(e){if(e.explicitTeam&&e.personal)throw Error(`--team and --personal cannot be used together`);if(!e.personal)return e.explicitTeam?(await Rc(e.client,e.explicitTeam)).id:e.activeTeamId}async function Hc(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 Rc(e.client,e.explicitTeam)).id}`;if(e.activeTeamId)return`team:${e.activeTeamId}`}function Uc(e){return!e||e.authToken===void 0?e:{...e,authToken:`[REDACTED]`}}function Wc(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=t.nonce===`auto`?se():t.nonce,a=F(`Fetching TEE attestation...`);a.start();let o=await(await B(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){R(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=D({apiKey:e.apiKey,baseUrl:e.baseUrl}),n=k(t),r=F(`Fetching sandboxes...`);r.start();let i=await Hc({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){R(e)}}),e.command(`get <id-or-name>`).description(`Get sandbox details`).option(`--profile`,`Show the active agent profile provenance (name, hash, skills)`).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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching sandbox...`);i.start();let a=await B(r,n,e);if(i.stop(),t.profile){let e=a.getProfileProvenance?.();e?(P(`Agent profile provenance:`),P(` Base profile: ${e.base.name??`(inline)`} (${e.base.sha256.slice(0,12)}...)`),P(` Effective: ${e.effective.name??`(inline)`} (${e.effective.sha256.slice(0,12)}...)`),P(` Materialized: ${e.materializedAt}`),e.base.sha256!==e.effective.sha256&&P(` ⚠ Profile changed since creation (base ≠ effective)`)):P(`No profile materialized (bare sandbox). Create with --profile <name> to install one.`);return}t.json?j(a):or({id:a.id,name:a.name,status:a.status,resources:a.resources,createdAt:a.createdAt?.toISOString(),expiresAt:a.expiresAt?.toISOString(),connection:a.connection})}catch(e){R(e)}}),e.command(`shapes`).description(`List the named sandbox sizes, the default, and this account's ceiling`).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 k(D({apiKey:e.apiKey,baseUrl:e.baseUrl})).shapes();if(e.json){j(t);return}let n=e=>e.cpuCores<=t.ceiling.cpuCores&&e.memoryMB<=t.ceiling.memoryMB&&e.diskGB<=t.ceiling.diskGB;A(t.presets.map(e=>({name:e.name===t.default?`${e.name} (default)`:e.name,cpu:e.cpuCores,memory:`${e.memoryMB} MB`,disk:`${e.diskGB} GB`,available:n(e)?`yes`:e.name===t.default?`clamped to ceiling`:`above ceiling`})),[{key:`name`,header:`Shape`,width:18},{key:`cpu`,header:`vCPU`,width:6},{key:`memory`,header:`Memory`,width:10},{key:`disk`,header:`Disk`,width:8},{key:`available`,header:`Available`,width:14}]),P(`Ceiling for this account: ${ar(t.ceiling)}`)}catch(e){R(e)}}),e.command(`delete <id-or-name>`).description(`Delete a sandbox`).option(`-f, --force`,`Skip confirmation`).option(`--name`,`Treat the reference as a sandbox name`).option(`--retry-cleanup`,`Retry server-side cleanup after the sandbox disappeared from get/list`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{if(!t.force&&!await H(`Delete sandbox ${e}? [y/N] `,`--force`)){P(`Cancelled.`);return}let n=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Deleting sandbox...`);i.start();let a=await Rr(r,n,e,{retryCleanup:t.retryCleanup,name:t.name});i.stop(),M(a===`already_absent`?`Sandbox ${e} was already gone.`:`Sandbox ${e} deleted.`)}catch(e){R(e)}}),e.command(`stop <id-or-name>`).description(`Stop a running sandbox`).option(`--name`,`Treat the reference as a sandbox name`).option(`--no-wait`,`Return once the stop is accepted and print the operation to poll`).option(`--json`,`With --no-wait, print the operation as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`API base URL`).action(async(e,t)=>{try{let n=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Stopping sandbox...`);i.start();let a=await B(r,n,e,{nameOnly:t.name});if(t.wait===!1){let e=await a.stop({wait:!1});i.stop(),Ic(e.info,!!t.json);return}await a.stop(),i.stop(),M(`Sandbox ${e} stopped.`)}catch(e){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl,timeout:n}),i=k(r),a=F(`Resuming sandbox...`);a.start();let o=await B(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){R(e)}})}function Gc(e){e.command(`create`).description(`Create a new sandbox`).option(`-n, --name <name>`,`Sandbox name`).option(`-e, --environment <environment>`,`Named environment, container image, or built image ID`).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. NAME@host keeps the value out of the sandbox and sends it to that host only (NAME@host:Header for a header other than Authorization)`).option(`--metadata <entries...>`,`Metadata entries (KEY=VALUE or KEY=JSON)`).option(`--cpu <cores>`,"CPU cores (omit for the platform default; see `sandbox shapes`)").option(`--memory <mb>`,`Memory in MB (omit for the platform default)`).option(`--disk <gb>`,`Disk size in GB (omit for the platform default)`).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(`--gpu-provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--gpu-worker-image <image>`,`GPU worker image override`).option(`--gpu-env <vars...>`,`Environment variables for the GPU worker (KEY=VALUE)`).option(`--gpu-max-spend-usd <usd>`,`Maximum customer spend for the create-time GPU lease`).option(`--gpu-max-lifetime <seconds>`,`Maximum create-time GPU lease lifetime in seconds`).option(`--gpu-idle-timeout <seconds>`,`Destroy the create-time GPU lease after this many idle seconds`).option(`--lifetime <seconds>`,`Max wall-clock lifetime before the sandbox is suspended — stopped, not deleted; resume it within the cold window (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(`--billing-owner <userId>`,`Platform user that pays for the sandbox. The API accepts this only from a first-party service key that is listed as a billing delegate, and refuses such a key that names no payer.`).option(`--team <team>`,`Create in a team by id or name`).option(`--personal`,`Create a personal sandbox even when a team is active`).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(`--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(`--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 (${c.join(`, `)})`).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(`--cli-auth <secret>`,"Run --backend claude-code or codex on your own subscription: the stored secret holding a `claude setup-token` token or a Codex auth.json (see `tangle secret create`)").option(`--profile <path>`,`Path to an AgentProfile JSON file to install as the sandbox's backend profile (carries skills, tools, MCP, model). Use with --backend; the profile's inline skills materialize into the harness's native skill directory on first turn`).option(`--profile-stdin`,`Read the AgentProfile JSON from stdin instead of a file (use with --profile)`).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(`--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{let t=await Cc({envVarName:e.gitTokenEnv,fromStdin:e.gitTokenStdin,flagPrefix:`--git-token`}),n=await Cc({envVarName:e.storageSecretAccessKeyEnv,fromStdin:e.storageSecretAccessKeyStdin,flagPrefix:`--storage-secret-access-key`}),r=await Cc({envVarName:e.backendApiKeyEnv,fromStdin:e.backendApiKeyStdin,flagPrefix:`--backend-api-key`}),i=wc({secret:e.cliAuth,backend:e.backend,apiKeyGiven:r!==void 0}),a;if(e.profileStdin){let e=await Gr(`--profile-stdin`,`the AgentProfile JSON`);try{a=JSON.parse(e)}catch{R(Error(`--profile-stdin: the input is not valid JSON`));return}}else if(e.profile){let t=String(e.profile);if(t.startsWith(`.`)||t.startsWith(`/`)||t.endsWith(`.json`))try{a=JSON.parse(b(t,`utf8`))}catch(e){R(Error(`--profile ${t}: ${e.message}`));return}else try{a=await Sc(t,e)}catch(e){R(Error(`--profile ${t}: ${e.message}`));return}}let o=D({apiKey:e.apiKey,baseUrl:e.baseUrl,timeout:e.timeout?Number.parseInt(e.timeout,10):void 0}),s=k(o),c=F(`Creating sandbox...`);c.start();let l=await Vc({client:s,explicitTeam:e.team,personal:e.personal,activeTeamId:o.activeTeamId}),u={};if(e.env)for(let t of e.env){let[e,...n]=t.split(`=`);e&&n.length>0&&(u[e]=n.join(`=`))}let d=e.metadata?Oc(e.metadata):void 0,f=Ac(e,t),p=jc(e,n),m=e.acceleratorKind?Fo({kind:String(e.acceleratorKind),count:String(e.acceleratorCount),memory:typeof e.acceleratorMemory==`string`?e.acceleratorMemory:void 0}):void 0,h=Io({provider:typeof e.gpuProvider==`string`?e.gpuProvider:void 0,image:typeof e.gpuWorkerImage==`string`?e.gpuWorkerImage:void 0,env:Array.isArray(e.gpuEnv)?e.gpuEnv:void 0,maxSpendUsd:typeof e.gpuMaxSpendUsd==`string`?e.gpuMaxSpendUsd:void 0,maxLifetime:typeof e.gpuMaxLifetime==`string`?e.gpuMaxLifetime:void 0,idleTimeout:typeof e.gpuIdleTimeout==`string`?e.gpuIdleTimeout:void 0},!!m,`Create-time GPU lease flags require --accelerator-kind`),g=e.driver?{type:e.driver,enableCriu:e.driverCriu||void 0,preferredRegion:e.driverRegion}:void 0,ee=e.backend||e.backendModel||a?{...e.backend?{type:ce(e.backend)}:{},...a?{profile:a}:{},model:e.backendModel||r||i?{...e.backendModel?Dc(e.backendModel):{},apiKey:r,...i?{cliAuth:i}:{}}:void 0}:void 0,te=Tc(e.secret),ne=i?[...new Set([...te??[],i.secretEnv])]:te,re=Ec(e,m),ie=[...e.sshKey?[e.sshKey]:[],...(e.sshKeyFile??[]).map(e=>b(e,`utf8`).trim())],ae={name:e.name,environment:e.environment,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(u).length>0?u:void 0,git:f,...re?{resources:re}:{},gpuLease:h,maxLifetimeSeconds:Number.parseInt(e.lifetime,10),idleTimeoutSeconds:Number.parseInt(e.idleTimeout,10),storage:p,fromSnapshot:e.fromSnapshot,publicTemplateId:e.publicTemplate,publicTemplateVersionId:e.publicTemplateVersion,teamId:l,...e.billingOwner?{billingOwnerId:e.billingOwner}:{},secrets:ne,metadata:d,driver:g,backend:ee},se=e.tee?{tee:e.tee,sealed:e.sealed||void 0,attestationRefresh:e.attestationRefresh||e.attestationNonce===`auto`||void 0}:void 0,le=se?await oe(s,{...ae,confidential:se,attestationNonce:e.attestationNonce??(e.attestationRefresh?`auto`:void 0),requireAttestation:e.requireAttestation??!0}):void 0,_=le?.sandbox??await s.create(ae);e.wait&&(c.text=`Waiting for sandbox to start...`,await _.waitFor(`running`,{timeoutMs:12e4}),await _.refresh()),c.stop(),e.json?j({id:_.id,name:_.name,status:_.status,resources:_.resources,createdAt:_.createdAt,expiresAt:_.expiresAt,connection:Uc(_.connection),teamId:l,gpuLease:_.gpuLease,confidential:se,attestation:le?.attestation,attestationNonce:le?.attestationNonce}):(M(`Sandbox created: ${_.id}`),or({id:_.id,name:_.name,status:_.status,resources:_.resources,createdAt:_.createdAt?.toISOString(),expiresAt:_.expiresAt?.toISOString(),connection:_.connection}),l&&console.log(`Team: ${l}`),_.gpuLease&&(console.log(`GPU lease: ${_.gpuLease.id}`),Nc(_.gpuLease)),se&&(console.log(`TEE: ${se.tee}`),console.log(`Attestation: ${le?.attestation?`present`:`not returned`}`),le?.attestationNonce&&console.log(`Attestation nonce: ${le.attestationNonce}`)))}catch(e){R(e)}})}function Kc(e){e.command(`network <id-or-name>`).description(`Show runtime network state (exposed ports) for a sandbox. Outbound policy is not settable here — see the outbound flags.`).option(`--block-outbound`,`Unenforceable; the server rejects it. Block outbound traffic with an egress policy of mode "blocked"`).option(`--allow-list <cidrs>`,`Unenforceable; the server rejects it. Egress policy allowlists domains, not CIDRs`).option(`--clear`,`Unenforceable; the server rejects it. There is no per-sandbox outbound restriction here to clear`).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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Updating network configuration...`);i.start();let a=await B(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.ports&&e.ports.length>0?P(` Exposed Ports: ${e.ports.join(`, `)}`):P(` No exposed ports`));return}i.stop();let o=await a.network.getConfig();t.json?j(o):(M(`Network configuration updated.`),o.ports&&o.ports.length>0&&P(` Exposed Ports: ${o.ports.join(`, `)}`))}catch(e){R(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=D({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 B(r,n,e)).network.exposePort(i);a.stop(),t.json?j({port:i,url:o}):(M(`Port ${i} exposed.`),P(` URL: ${o}`))}catch(e){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching exposed URLs...`);i.start();let a=await(await B(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){R(e)}})}function qc(){let e=new t(`sandbox`).description(`Manage sandboxes`);return Gc(e),Wc(e),Fc(e),Kc(e),e}function Jc(){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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Searching...`);n.json||a.start();let o=await B(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){R(e)}})}function Yc(){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(D({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=await Xc({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){R(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(D({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.`)):L([`Name`,`Created At`,`Updated At`],r.map(e=>[e.name,e.createdAt.toLocaleString(),e.updatedAt.toLocaleString()]))}catch(e){R(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(D({apiKey:t.apiKey,baseUrl:t.baseUrl}));if(!t.force&&!await H(`Are you sure you want to delete secret '${e}'? This cannot be undone. (y/N) `,`--force`)){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){R(e)}}),e}async function Xc(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 Gr();if(e.length===0)throw Error(`Secret value from stdin cannot be empty`);return e}let t=await Ur(e.prompt);if(t.length===0)throw Error(`Secret value cannot be empty`);return t}function Zc(){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=x.dirname(Ue(import.meta.url)),t=x.resolve(e,`..`,`SKILL.md`);console.log(t)}),e}function Qc(){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(`--no-wait`,`Return once the snapshot is accepted and print the operation to poll`).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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Creating snapshot...`);i.start();let a=await B(r,n,e);if(t.wait===!1){let e=await a.snapshot({tags:t.tags,wait:!1});i.stop(),Ic(e.info,!!t.json);return}let o=await a.snapshot({tags:t.tags});i.stop(),t.json?j(o):(M(`Snapshot created: ${o.snapshotId}`),console.log(`Size: ${$c(o.sizeBytes??0)}`))}catch(e){R(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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching snapshots...`);i.start();let a=await(await B(r,n,e)).listSnapshots();i.stop(),t.json?j(a):A(a.map(e=>({...e,size:$c(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){R(e)}}),e.command(`restore <sandbox-id> <snapshot-id>`).description(`Create a new sandbox from a snapshot`).option(`--billing-owner <userId>`,`Platform user that pays for the restored sandbox. The API accepts this only from a first-party service key that is listed as a billing delegate, and refuses such a key that names no payer.`).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(D({apiKey:n.apiKey,baseUrl:n.baseUrl})),i=F(`Restoring from snapshot...`);i.start();let a=await r.create({fromSnapshot:t,fromSandboxId:e,...n.billingOwner?{billingOwnerId:n.billingOwner}:{}});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){R(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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Reverting sandbox to snapshot...`);a.start();let o=await B(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){R(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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Deleting snapshot...`);a.start();let o=await(await B(i,r,e)).deleteSnapshot(t);a.stop(),n.json?j({success:!0,sandboxId:e,snapshotId:t,outcome:o.outcome}):o.outcome===`already_absent`?M(`Snapshot already gone: ${t}`):M(`Snapshot deleted: ${t}`)}catch(e){R(e)}}),e}function $c(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]}`}const el=`solve:device:secp256k1`,tl=/^0x[0-9a-f]{64}$/i;function nl(e){return e&&tl.test(e)?e:void 0}function rl(){let e=Nt(el),t=nl(e.value);if(!(!t||e.source===`none`))return{account:Ge(t),source:e.source}}function il(){let e=rl();if(e)return e;let t=We(),n=Pt(el,t);return{account:Ge(t),source:n}}function al(e){let t=nl(Nt(el).value);if(!t||Ge(t).address!==e.account.address)throw Error(`The local Solve device key changed; it was not retired`);let n=`${el}:retired:${e.account.address.toLowerCase()}`;if(Pt(n,t),Nt(n).value!==t)throw Error(`The revoked device key could not be retired safely`);return It(el),n}function ol(e){try{let t=e.create?il():rl();if(!t)throw Error("No Solve device signer found. Run `tangle solve account --create`");e.json?j({address:t.account.address,source:t.source}):I({Address:t.account.address,Source:t.source})}catch(e){R(e)}}const sl=/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;function cl(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function J(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`${t} must be an object`);return e}function ll(e,t,n=2048){if(typeof e!=`string`||!e.trim()||e.length>n)throw Error(`${t} is missing or invalid`);if(cl(e))throw Error(`${t} contains control characters`);return e.trim()}function ul(e,t){let n=ll(e,t,64).toLowerCase();if(!sl.test(n))throw Error(`${t} must be a 40 or 64 character Git revision`);return n}function dl(e,t,n=!1){let r=typeof e==`number`&&Number.isSafeInteger(e)?String(e):ll(e,t,80);if(!/^\d+$/.test(r)||!n&&r===`0`)throw Error(`${t} must be an unsigned integer`);return BigInt(r).toString()}function fl(e,t){let n=ll(e,t,2048),r=new URL(n);if(r.protocol!==`https:`&&!(r.protocol===`http:`&&(r.hostname===`localhost`||r.hostname===`127.0.0.1`)))throw Error(`${t} must use HTTPS outside local development`);return n.replace(/\/$/,``)}function pl(e,t){let n=fl(e,t).replace(/\.git$/,``),r=new URL(n),i=r.pathname.split(`/`).filter(Boolean);if(r.hostname!==`github.com`||r.username||r.password||r.search||r.hash||i.length!==2)throw Error(`${t} must be an HTTPS GitHub repository URL`);return`https://github.com/${i.join(`/`)}`}function ml(e,t){let n=ll(e,t,42);if(!et(n,{strict:!1}))throw Error(`${t} must be an EVM address`);return Qe(n)}function hl(e,t){let n=dl(e,t),r=Number(n);if(!Number.isSafeInteger(r)||r<=0)throw Error(`${t} is out of range`);return r}function Y(...e){for(let t of e)if(typeof t==`string`&&t.trim())return t.trim()}function gl(e){let t=e.trim().replace(/\.git$/,``);return t.startsWith(`git@github.com:`)?`https://github.com/${t.slice(15)}`:t.startsWith(`ssh://git@github.com/`)?`https://github.com/${t.slice(21)}`:t}function _l(e){if(e===void 0)return;let t=ll(e,`pull request URL`,2048);if(!/^https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/\d+(?:\/[^\s]*)?$/i.test(t))throw Error(`pull request URL must point to a GitHub pull request`);return t}function vl(e,t){if(!/^https:\/\/[^\s]+$/i.test(e)&&!/^\/(?!\/).*$/.test(e)&&!/^[a-z][a-z0-9+.-]*:[^\s]+$/i.test(e))throw Error(`${t} must be an HTTPS URL or an absolute repository path`);if(e.split(/[?#]/,1)[0].split(`/`).includes(`..`))throw Error(`${t} cannot contain parent-directory segments`);return e}function yl(e){return nn(`solve`,e.profile)}function bl(e){let t=yl(e),n=Cn(void 0,t);if(!n)throw Error(`No Solve credential found for profile '${t}'. Run: tangle auth login --provider github --app solve`);return n}async function xl(e){let t=jn(e.apiUrl),n=await fetch(`${t}${e.path}`,{method:e.method??`GET`,headers:{Accept:`application/json`,...e.body===void 0?{}:{"Content-Type":`application/json`},Authorization:`Bearer ${bl(e)}`},...e.body===void 0?{}:{body:JSON.stringify(e.body)},signal:AbortSignal.timeout(3e4)}),r=await n.json().catch(()=>null);if(!n.ok||!r?.success||r.data===void 0){let e=r?.error?.message??`Solve API request failed with HTTP ${n.status}`;throw Error(r?.error?.code?`${r.error.code}: ${e}`:e)}return r.data}function Sl(e){return xl({path:`/v1/wallet/challenges`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.purpose?{purpose:e.purpose}:{}}})}function Cl(e){return xl({path:`/v1/devices`,apiUrl:e.apiUrl,profile:e.profile})}function wl(e){return xl({path:`/v1/devices/revoke`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.reason?{reason:e.reason}:{},...e.challengeId&&e.signature?{challengeId:e.challengeId,signature:e.signature}:{}}})}const X={chainId:42431,rpcUrl:`https://rpc.moderato.tempo.xyz`,sponsorUrl:`https://drew-gtr-pro.taild10bfc.ts.net/solve-sponsor`,tangleAddress:`0xff137B9C879c47C28ce389e84501925438AB4cdA`,managerAddress:`0x5271732F893B622ac6793d6DBA5B2626CCa4EA14`,paymentAsset:`0x20C0000000000000000000000000000000000000`,blueprintId:15n,serviceId:9n,competitionId:1n,minStakeWei:0n};function Tl(e,t){return e.toLowerCase()===t.toLowerCase()}function El(e){if(e.chainId!==X.chainId)throw Error(`Solve submissions require Tempo Moderato (chain ${X.chainId}); received ${e.chainId}`);if(e.rpcUrl!==X.rpcUrl)throw Error(`Solve metadata RPC does not match the trusted deployment`);if(e.sponsorUrl!==X.sponsorUrl)throw Error(`Solve metadata sponsor does not match the trusted deployment`);if(!Tl(e.tangleAddress,X.tangleAddress))throw Error(`Solve metadata Tangle contract does not match the trusted deployment`);if(!Tl(e.managerAddress,X.managerAddress))throw Error(`Solve metadata competition manager does not match the trusted deployment`);if(!Tl(e.paymentAsset,X.paymentAsset))throw Error(`Solve metadata payment asset does not match the trusted deployment`);if(e.blueprintId!==X.blueprintId)throw Error(`Solve submissions require blueprint ${X.blueprintId}; received ${e.blueprintId}`);if(e.serviceId!==X.serviceId)throw Error(`Solve submissions require service ${X.serviceId}; received ${e.serviceId}`);if(e.competitionId!==X.competitionId)throw Error(`Solve submissions require competition ${X.competitionId}; received ${e.competitionId}`);if(e.minStakeWei!==X.minStakeWei)throw Error(`Solve submissions require zero stake for the trusted deployment`)}function Dl(e,t){let n=J(t.check??e.check,`competition.participation.check`),r=ll(n.command,`competition.participation.check.command`,512);if(!Array.isArray(n.args)||n.args.some(e=>typeof e!=`string`))throw Error(`competition.participation.check.args must be an array of strings`);let i=n.args.map(e=>ll(e,`competition checker argument`,2048)),a=Y(n.result_file,n.resultFile),o=n.timeout_ms??n.timeoutMs,s=o===void 0?void 0:hl(o,`competition checker timeout`);return{command:r,args:i,...a?{result_file:a}:{},...s?{timeout_ms:s}:{}}}function Ol(e){if(e.provenance===void 0)return;let t=J(e.provenance,`competition.participation.provenance`);if(t.mode!==`github_pull_request`)throw Error(`competition.participation.provenance.mode is unsupported`);if(t.required!==void 0&&typeof t.required!=`boolean`)throw Error(`competition.participation.provenance.required must be a boolean`);return{mode:`github_pull_request`,required:t.required===!0}}function kl(e){let t=J(e.chain??e.network??{},`competition.chain`),n=e.rewards&&typeof e.rewards==`object`&&!Array.isArray(e.rewards)?J(e.rewards,`competition.rewards`):{},r=n.minStake&&typeof n.minStake==`object`&&!Array.isArray(n.minStake)?J(n.minStake,`competition.rewards.minStake`).raw:void 0,i=Y(t.minStakeWei,t.min_stake_wei,e.minStakeWei,e.min_stake_wei,r),a=t.chainId??t.chain_id??e.chainId??e.chain_id,o=Y(t.chainName,t.chain_name,e.chainName,e.chain_name)??`Tempo`,s=Y(t.nativeSymbol,t.native_symbol,e.nativeSymbol,e.native_symbol)??`TNT`,c=Y(t.rpcUrl,t.rpc_url,e.rpcUrl,e.rpc_url,process.env.TANGLE_SOLVE_RPC_URL),l=Y(t.sponsorUrl,t.sponsor_url,e.sponsorUrl,e.sponsor_url,process.env.TANGLE_SOLVE_SPONSOR_URL),u=Y(t.tangleAddress,t.tangle_address,t.coreAddress,t.core_address,e.tangleAddress,e.tangle_address,e.coreAddress,e.core_address),d=Y(t.managerAddress,t.manager_address,e.managerAddress,e.manager_address),f=Y(t.paymentAsset,t.payment_asset,t.servicePaymentAsset,t.service_payment_asset,e.paymentAsset,e.payment_asset,e.servicePaymentAsset,e.service_payment_asset),p=Y(t.blueprintId,t.blueprint_id,e.blueprintId,e.blueprint_id),m=Y(t.serviceId,t.service_id,e.serviceId,e.service_id),h=Y(t.competitionId,t.competition_id,e.competitionId,e.competition_id,e.id);if(!c||!l||!u||!d||!p||!m||!h||!i||a===void 0)throw Error(`Solve competition metadata must include complete Tempo chain configuration`);return{chainId:hl(a,`chain.chainId`),chainName:o,nativeSymbol:s,rpcUrl:fl(c,`chain.rpcUrl`),sponsorUrl:fl(l,`chain.sponsorUrl`),tangleAddress:ml(u,`chain.tangleAddress`),managerAddress:ml(d,`chain.managerAddress`),paymentAsset:ml(f??X.paymentAsset,`chain.paymentAsset`),blueprintId:dl(p,`chain.blueprintId`),serviceId:dl(m,`chain.serviceId`),competitionId:dl(h,`chain.competitionId`,!0),minStakeWei:dl(i,`chain.minStakeWei`,!0)}}function Al(e){let t=J(e,`competition`),n=J(t.participation??t.task,`competition.task`),r={...t,participation:{...n,...n.repositoryRevision===void 0&&n.revision!==void 0?{repositoryRevision:n.revision}:{}}},i=r.participation,a=pl(Y(r.repository,r.repo_url,i.repository)??``,`competition.repository`),o=ul(Y(r.repositoryRevision,r.repository_revision,i.revision,i.repositoryRevision,i.repository_revision),`competition.repositoryRevision`),s=ll(r.slug??r.id,`competition.slug`,128),c=ll(r.name??r.title??s,`competition.name`,256),l=Dl(r,i),u=Ol(i);return{version:1,slug:s,title:c,repository:a,taskRevision:o,checker:l,chain:kl(r),...u?{provenance:u}:{}}}function jl(e){return{chainId:e.chain.chainId,chainName:e.chain.chainName,nativeSymbol:e.chain.nativeSymbol,rpcUrl:e.chain.rpcUrl,sponsorUrl:e.chain.sponsorUrl,tangleAddress:e.chain.tangleAddress,managerAddress:e.chain.managerAddress,paymentAsset:e.chain.paymentAsset,blueprintId:BigInt(e.chain.blueprintId),serviceId:BigInt(e.chain.serviceId),competitionId:BigInt(e.chain.competitionId),minStakeWei:BigInt(e.chain.minStakeWei)}}async function Ml(e){let t=J(JSON.parse(await C.readFile(x.join(e,`.tangle-solve.json`),`utf8`)),`.tangle-solve.json`);if(t.version!==1)throw Error(`.tangle-solve.json has an unsupported version`);let n=J(t.checker,`.tangle-solve.json.checker`),r=J(t.chain,`.tangle-solve.json.chain`);return Al({slug:t.slug,name:t.title,repository:t.repository,repositoryRevision:t.taskRevision,participation:{check:n,provenance:t.provenance},chain:r,competitionId:r.competitionId})}const Nl=Ke(Ce),Pl=`.tangle-solve-run.json`,Fl=`.tangle-solve.json`,Il=`tangle.solve.manifestSha256`,Ll=new Set([Fl,Pl]),Rl=`upstream`;async function zl(e,t){let n=await Nl(`git`,[`-C`,e,...t],{encoding:`utf8`,maxBuffer:1e6});return String(n.stdout).trim()}async function Bl(e,t){let n=x.resolve(t??process.cwd()),r=await Ml(n);if(e&&e!==r.slug&&e!==r.chain.competitionId)throw Error(`This directory contains '${r.slug}', not '${e}'`);return{root:n,manifest:r}}async function Vl(e){let t=x.join(e,Fl),r;try{r=await C.lstat(t)}catch{throw Error(`${Fl} is missing`)}if(r.isSymbolicLink()||!r.isFile())throw Error(`${Fl} must be a regular file`);return n(`sha256`).update(await C.readFile(t)).digest(`hex`)}async function Hl(e){let t=await Vl(e);return await zl(e,[`config`,`--local`,`--replace-all`,Il,t]),t}async function Ul(e){let t;try{t=await zl(e,[`config`,`--local`,`--get`,Il])}catch{throw Error(`The local Git metadata has no ${Il} pin; run tangle solve clone again`)}if(!/^[0-9a-f]{64}$/i.test(t))throw Error(`The local ${Il} pin is invalid`);if(await Vl(e)!==t.toLowerCase())throw Error(`${Fl} changed after clone; run tangle solve clone again`)}async function Wl(e,t){try{return await zl(e,[`ls-files`,`--error-unmatch`,`--`,t]),!0}catch{return!1}}async function Gl(e){await Ul(e);for(let t of Ll)if(await Wl(e,t))throw Error(`${t} must remain untracked and local to this Solve workspace`);let t=await Nl(`git`,[`-C`,e,`status`,`--porcelain=v1`,`--untracked-files=all`,`--ignored=matching`],{encoding:`utf8`,maxBuffer:1e6});if(String(t.stdout).split(/\r?\n/).filter(Boolean).filter(e=>{let t=e.slice(0,2),n=e.slice(3);return!((t===`??`||t===`!!`)&&Ll.has(n))}).length>0)throw Error(`Commit the candidate before running Solve. Only the local manifest and run record may remain uncommitted.`);return ul(await zl(e,[`rev-parse`,`HEAD`]),`submission revision`)}async function Kl(e,t,n,r={}){let i=await ql(e,t,r);if(i)return{taskRepository:t.repository,taskRevision:t.taskRevision,submissionRepository:i,submissionRevision:n}}async function ql(e,t,n={}){let r;try{r=gl(await zl(e,[`config`,`--get`,`remote.origin.pushurl`]))}catch{try{r=gl(await zl(e,[`config`,`--get`,`remote.origin.url`]))}catch{if(n.allowMissing)return;throw Error(`Add your GitHub fork as the 'origin' remote before submitting. The task repository is available as '${Rl}'.`)}}let i=pl(r,`git remote.origin.url`);if(i.toLowerCase()===t.repository.toLowerCase()){if(n.allowMissing)return;throw Error(`The 'origin' remote is the task repository. Add your GitHub fork as 'origin'; keep the task repository as '${Rl}' before submitting.`)}return i}function Jl(e,t){return!e||!t?!1:e.taskRepository.toLowerCase()===t.taskRepository.toLowerCase()&&e.taskRevision.toLowerCase()===t.taskRevision.toLowerCase()&&e.submissionRepository.toLowerCase()===t.submissionRepository.toLowerCase()&&e.submissionRevision.toLowerCase()===t.submissionRevision.toLowerCase()}function Yl(e,t){return`${e}/commit/${t}`}function Xl(e,t,n,r,i={}){let a=e.evidenceRefs.map(e=>vl(e.trim(),`checker evidence reference`));if(n){if(!t){if(i.allowMissingSource)return{evidence:e.evidence,evidenceRefs:a};throw Error(`Provenance policy requires a submission source`)}let o=_l(r);if(n.required&&(i.requirePullRequest??!0)&&!o)throw Error(`This competition requires a GitHub pull request`);a.push(Yl(t.taskRepository,t.taskRevision),Yl(t.submissionRepository,t.submissionRevision),...o?[o]:[])}return{evidence:e.evidence,evidenceRefs:[...new Set(a)]}}async function Zl(e,t){let n=`${e}.${process.pid}.tmp`;await C.writeFile(n,`${JSON.stringify(t,null,2)}\n`,{mode:384}),await C.rename(n,e)}async function Ql(e){let t=JSON.parse(await C.readFile(x.join(e,Pl),`utf8`));if(t.version!==1||typeof t.competition!=`string`)throw Error(`${Pl} has an unsupported format`);return t}async function $l(e){let t=_l(e.pullRequest);if(!t)throw Error(`A pull request URL is required`);let n=new URL(t).pathname.split(`/`).filter(Boolean),r=await fetch(`https://api.github.com/repos/${n[0]}/${n[1]}/pulls/${n[3]}`,{headers:{Accept:`application/vnd.github+json`,"User-Agent":`tangle-solve-cli`},signal:AbortSignal.timeout(15e3)}),i=await r.json().catch(()=>null),a=e=>e.replace(/\/$/,``).toLowerCase();if(!r.ok||a(i?.base?.repo?.html_url??``)!==a(e.taskRepository)||i?.head?.sha?.toLowerCase()!==e.submissionRevision.toLowerCase()||a(i?.head?.repo?.html_url??``)!==a(e.submissionRepository))throw Error(`GitHub pull request must target the pinned task repository and contain the current committed submission`)}function eu(e){return{...e.authorization?{authorization:e.authorization}:{},...e.stake?{stake:e.stake}:{},join:e.join,commit:e.commit,reveal:e.reveal,report:e.report,evaluation:e.evaluation}}const tu=Ke(Ce);function nu(){return`Task source is '${Rl}'. Add your fork as 'origin', commit your candidate, push it, and open a pull request before submitting.`}async function ru(e,t,n){try{let r=J(await xl({path:`/v1/competitions/${encodeURIComponent(e)}`,apiUrl:n.apiUrl,profile:n.profile}),`competition response`),i=Al(r.competition??r),a=x.resolve(t??i.slug),o=F(`Cloning ${i.slug}…`);n.json||o.start();try{await tu(`git`,[`clone`,`--no-tags`,`--origin`,Rl,i.repository,a],{encoding:`utf8`,maxBuffer:1e6}),await zl(a,[`checkout`,`--detach`,i.taskRevision]);let e=await zl(a,[`rev-parse`,`HEAD`]);if(e.toLowerCase()!==i.taskRevision.toLowerCase())throw Error(`Pinned checkout resolved to ${e}, expected ${i.taskRevision}`);await Zl(x.join(a,`.tangle-solve.json`),i),await Hl(a)}finally{o.stop()}n.json?j({competition:i,directory:a}):(M(`Cloned ${i.slug} at ${i.taskRevision.slice(0,12)}`),i.provenance&&P(nu()),P(`Run the pinned checker with: cd ${a} && tangle solve run`))}catch(e){R(e)}}const iu=12e4,au=rt(`event JobSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint8 jobIndex, address caller, bytes inputs)`),ou=rt(`event JobCompleted(uint64 indexed serviceId, uint64 indexed callId)`),su=rt(`event JobResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, address indexed operator, bytes result)`),cu=rt(`event AggregatedResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint256 signerBitmap, bytes output)`),lu=rt(`event EvaluationAccepted(uint64 indexed serviceId, uint64 indexed competitionId, address indexed researcher, bytes32 candidateId, bytes32 submissionRefHash, bytes32 evaluationDigest, bytes32 metricsHash, bytes32 evidenceRefsHash)`),uu=[...nt([`function submitJob(uint64 serviceId, uint8 jobIndex, bytes inputs) payable returns (uint64 callId)`,`function getJobEventRate(uint64 blueprintId, uint8 jobIndex) view returns (uint256 rate)`,`function getServicePaymentAsset(uint64 serviceId) view returns (address)`,`function isPermittedCaller(uint64 serviceId, address caller) view returns (bool)`]),au,ou,su,cu],du=nt([`function authorizeSelf(uint64 serviceId)`,`function revokeSelf(uint64 serviceId)`,`function isDeviceRevoked(address device) view returns (bool)`,`function postStake(uint64 serviceId, uint64 competitionId) payable`,`function stakes(uint64 serviceId, uint64 competitionId, address researcher) view returns (uint256)`,`function pendingResults(uint64 serviceId, uint64 jobCallId) view returns (uint8 job, bytes32 outputHash, uint256 signerBitmap, bool exists, bool executed)`,`function executePendingResult(uint64 serviceId, uint64 jobCallId, bytes output)`,`function acceptedCandidates(uint64 serviceId, uint64 competitionId, address researcher, bytes32 candidateId) view returns (bool)`]),fu=nt([`function allowance(address owner, address spender) view returns (uint256)`,`function approve(address spender, uint256 amount) returns (bool)`]),pu=it(`uint64 competitionId, uint256 stakeWei`),mu=it(`uint64 competitionId, bytes32 commitment`),hu=it(`uint64 competitionId, bytes32 commitment, string artifactRef, bytes32 salt`),gu=it(`string artifactRef, bytes32 salt`),_u=it(`uint64 competitionId, bytes32 candidateId, string submissionRef, string evidenceJson, string evidenceRefsJson`),vu=it(`string status, string detail`),yu=/^0x[0-9a-f]{64}$/i;function bu(e,t){if(e!==t)throw Error(`Tempo RPC returned chain ${e}; expected ${t}`)}function xu(e,t,n){return{...e,feePayer:!0,nonceKey:t,nonce:n}}function Su(e,t){if(e!==`success`)throw Error(`${t} transaction reverted`)}function Cu(e,t,n,r){if(!yu.test(t))throw Error(`${n} transaction hash is invalid`);if(typeof e.transactionHash!=`string`||e.transactionHash.toLowerCase()!==t.toLowerCase())throw Error(`${n} receipt hash does not match the saved transaction`);if(Su(e.status??``,n),typeof e.from!=`string`||e.from.toLowerCase()!==r.from.toLowerCase())throw Error(`${n} receipt sender does not match the Solve device`);if(typeof e.to!=`string`||e.to.toLowerCase()!==r.to.toLowerCase())throw Error(`${n} receipt destination does not match the expected contract`)}function wu(e,t){return e>=t?[]:e>0n?[0n,t]:[t]}function Tu(e,t,n=Date.now()){return n>=e+t}function Eu(e,t){return e.filter(e=>e.args?.candidateId?.toLowerCase()===t.toLowerCase()).at(-1)?.transactionHash}function Du(e,t,n,r,i){for(let a of e.logs)if(a.address.toLowerCase()===t.tangleAddress.toLowerCase())try{let e=Xe({abi:[au],eventName:`JobSubmitted`,data:a.data,topics:a.topics});if(e.args.serviceId===t.serviceId&&e.args.jobIndex===n&&e.args.caller.toLowerCase()===r.toLowerCase()&&(!i||e.args.inputs.toLowerCase()===i.toLowerCase()))return e.args.callId}catch{}throw Error(`Tangle did not emit job ${n} for ${r}`)}function Ou(e,t,n,r){for(let i of e.logs)if(i.address.toLowerCase()===t.managerAddress.toLowerCase())try{let e=Xe({abi:[lu],eventName:`EvaluationAccepted`,data:i.data,topics:i.topics}).args;if(e.serviceId===t.serviceId&&e.competitionId===t.competitionId&&e.researcher.toLowerCase()===n.address.toLowerCase()&&e.candidateId.toLowerCase()===r.toLowerCase())return!0}catch{}return!1}function ku(e){if(e.chainId!==st.id)throw Error(`Solve submissions require Tempo Moderato (chain ${st.id}); received ${e.chainId}`);if(!e.sponsorUrl)throw Error(`Solve submissions require a Tempo sponsor relay URL; unsponsored writes are disabled`);return{...st,name:e.chainName,nativeCurrency:{name:e.nativeSymbol,symbol:e.nativeSymbol,decimals:18},rpcUrls:{default:{http:[e.rpcUrl]}}}}async function Au(e,t){El(e);let n=ku(e),r=qe({chain:n,transport:$e(e.rpcUrl)});return bu(await r.getChainId(),e.chainId),await ju({publicClient:r},e),{publicClient:r,walletClient:Je({account:t,chain:n,transport:lt($e(e.rpcUrl),$e(e.sponsorUrl))}),account:t}}async function ju(e,t){let n=await e.publicClient.readContract({address:t.tangleAddress,abi:uu,functionName:`getServicePaymentAsset`,args:[t.serviceId]});if(n.toLowerCase()!==t.paymentAsset.toLowerCase())throw Error(`Tempo service payment asset ${n} does not match the trusted Solve asset ${t.paymentAsset}`)}async function Mu(e,t,n){let[r,i]=await Promise.all([e.publicClient.readContract({address:t.tangleAddress,abi:uu,functionName:`getJobEventRate`,args:[t.blueprintId,n]}),e.publicClient.readContract({address:t.tangleAddress,abi:uu,functionName:`getServicePaymentAsset`,args:[t.serviceId]})]);if(i.toLowerCase()!==t.paymentAsset.toLowerCase())throw Error(`Tempo job payment asset ${i} does not match the trusted Solve asset ${t.paymentAsset}`);return{asset:i,amount:r,value:i===`0x0000000000000000000000000000000000000000`?r:0n}}async function Nu(e,t,n){return await e.publicClient.readContract({address:t,abi:fu,functionName:`allowance`,args:[e.account.address,n.tangleAddress]})}async function Pu(e,t,n,r,i,a){let o=Date.now();for(;!Tu(o,a);){if((await e.publicClient.getLogs({address:t.tangleAddress,event:ou,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`})).length>0){let a=(await e.publicClient.getLogs({address:t.tangleAddress,event:su,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`}))[0]?.args.result;if(!a)throw Error(`Tangle job ${n} completed without a result`);let[o,s]=Ye(vu,a);if(o!==i)throw Error(`Tangle job ${n} ${o}: ${s}`);return{status:o,detail:s}}await new Promise(e=>setTimeout(e,1e3))}throw Error(`Tangle job ${n} did not complete within 120 seconds`)}async function Fu(e,t,n,r,i){let a=Date.now();for(;!Tu(a,i);){let i=(await e.publicClient.getLogs({address:t.tangleAddress,event:cu,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`}))[0]?.args.output;if(i)return i;await new Promise(e=>setTimeout(e,1e3))}throw Error(`Tangle job ${n} did not produce an aggregate within 120 seconds`)}async function Iu(e,t,n){return!!await e.publicClient.readContract({address:t.managerAddress,abi:du,functionName:`acceptedCandidates`,args:[t.serviceId,t.competitionId,e.account.address,n]})}const Lu=BigInt(tt(at(`tangle.solve.v1`)));async function Ru(e,t){let n=await ct.nonce.getNonce(e.publicClient,{account:e.account.address,nonceKey:Lu});if(n>BigInt(2**53-1))throw Error(`The Solve transaction nonce exceeds the safe range`);return e.walletClient.writeContract(xu(t,Lu,Number(n)))}async function zu(e,t,n,r){if(!await e.publicClient.readContract({address:t.tangleAddress,abi:uu,functionName:`isPermittedCaller`,args:[t.serviceId,e.account.address]}))try{let i=r??await Ru(e,{address:t.managerAddress,abi:du,functionName:`authorizeSelf`,args:[t.serviceId]});if(r||await n?.(`authorization`,i),Cu(await e.publicClient.waitForTransactionReceipt({hash:i}),i,`Authorization`,{from:e.account.address,to:t.managerAddress}),!await e.publicClient.readContract({address:t.tangleAddress,abi:uu,functionName:`isPermittedCaller`,args:[t.serviceId,e.account.address]}))throw Error(`authorization transaction did not add the device`);return i}catch(e){let t=e instanceof Error?e.message:`unknown chain error`;throw Error(`The competition manager did not authorize this device. The deployed manager must expose authorizeSelf(uint64): ${t}`)}}async function Bu(e,t){let n=await Ru(e,{address:t.managerAddress,abi:du,functionName:`revokeSelf`,args:[t.serviceId]});return Cu(await e.publicClient.waitForTransactionReceipt({hash:n}),n,`Revocation`,{from:e.account.address,to:t.managerAddress}),n}async function Vu(e,t,n,r,i=`allowance`,a={}){if(t.amount===0n||t.asset===`0x0000000000000000000000000000000000000000`)return;let o=await Nu(e,t.asset,n);for(let s of wu(o,t.amount)){let o=s===0n?`${i}:reset`:`${i}:approval`,c=a[o];if(c){if(Cu(await e.publicClient.waitForTransactionReceipt({hash:c}),c,s===0n?`ERC-20 allowance reset`:`ERC-20 allowance approval`,{from:e.account.address,to:t.asset}),await Nu(e,t.asset,n)!==s)throw Error(`${s===0n?`ERC-20 allowance reset`:`ERC-20 allowance approval`} did not set the expected allowance`);continue}let l=await Ru(e,{address:t.asset,abi:fu,functionName:`approve`,args:[n.tangleAddress,s]});await r?.(o,l),Cu(await e.publicClient.waitForTransactionReceipt({hash:l}),l,s===0n?`ERC-20 allowance reset`:`ERC-20 allowance approval`,{from:e.account.address,to:t.asset})}}async function Hu(e,t,n,r,i,a=`job:${n}`,o={}){let s=await Mu(e,t,n);await Vu(e,s,t,i,`allowance:${a}`,o);let c=o[a],l=c??await Ru(e,{address:t.tangleAddress,abi:uu,functionName:`submitJob`,args:[t.serviceId,n,r],value:s.value});c||await i?.(a,l);let u=await e.publicClient.waitForTransactionReceipt({hash:l});return Cu(u,l,`Job ${n}`,{from:e.account.address,to:t.tangleAddress}),{hash:l,callId:Du(u,t,n,e.account.address,r),blockNumber:u.blockNumber}}async function Uu(e,t,n,r,i,a,o=`job:${n}`,s={}){let c=await Hu(e,t,n,r,a,o,s),l=await Pu(e,t,c.callId,c.blockNumber,i,iu);return{...c,acknowledgement:l}}const Z={...X,chainName:`Tempo Moderato`,nativeSymbol:`TNT`},Wu={async read(e){let t=qe({chain:st,transport:$e(Z.rpcUrl,{timeout:15e3})}),n=e=>e.catch(()=>null),r=await Promise.all(e.map(async e=>{let[r,i]=await Promise.all([n(t.readContract({address:Z.tangleAddress,abi:uu,functionName:`isPermittedCaller`,args:[Z.serviceId,e]})),n(t.readContract({address:Z.managerAddress,abi:du,functionName:`isDeviceRevoked`,args:[e]}))]);return[e.toLowerCase(),{permitted:r,revoked:i}]}));return new Map(r)},async revokeSelf(e){return Bu(await Au(Z,e),Z)}},Gu={permitted:null,revoked:null};function Ku(e){return e.revoked?`revoked`:e.permitted===null?`unknown`:e.permitted?`permitted`:`not permitted`}async function qu(e,t=Wu){try{let{devices:n}=await Cl({apiUrl:e.apiUrl,profile:e.profile}),r=rl()?.account.address.toLowerCase(),i=n.map(e=>({...e,local:e.address===r,status:e.revokedAt?`revoked`:`active`}));r&&!i.some(e=>e.local)&&i.push({address:r,local:!0,status:`unbound`,boundAt:null,lastUsedAt:null,revokedAt:null,revocationMethod:null,revocationReason:null});let a=await t.read(i.map(e=>Qe(e.address))),o=i.map(e=>({...e,onChain:a.get(e.address)??Gu}));if(e.json){j({serviceId:Z.serviceId.toString(),devices:o});return}L([`Address`,`Status`,`Local`,`Service ${Z.serviceId}`,`Last used`,`Revoked`],o.map(e=>[e.address,e.status,e.local?`yes`:``,Ku(e.onChain),e.lastUsedAt??``,e.revokedAt?`${e.revokedAt} (${e.revocationMethod})`:``]))}catch(t){R(t,e.json)}}async function Ju(e,t,n=Wu){try{if(!et(e))throw Error(`${e} is not an EVM address`);let r=Qe(e),i=rl(),a=i?.account.address===r;if(!t.yes){if(!process.stdin.isTTY)throw Error(`Revoking a device is permanent. Re-run with --yes to confirm`);if(!await H(`Permanently revoke Solve device ${r}${a?` (this machine's device)`:``}? [y/N] `,`--yes`)){P(`Revocation cancelled`);return}}let o;if(i&&a){let e=await Sl({deviceAddress:r,purpose:`revoke`,apiUrl:t.apiUrl,profile:t.profile});o={challengeId:e.challengeId,signature:await i.account.signMessage({message:e.message})}}let s=await wl({deviceAddress:r,reason:t.reason,...o,apiUrl:t.apiUrl,profile:t.profile}),c=r.toLowerCase(),l=(await n.read([r])).get(c)??Gu,u;if(i&&a&&!l.revoked){try{u=await n.revokeSelf(i.account)}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`The Solve API revoked ${r}, but the on-chain revocation failed and the local key was kept: ${t}. Run the command again to retry`)}l=(await n.read([r])).get(c)??Gu}let d=i&&a&&l.revoked?al(i):void 0;if(t.json){j({...s,serviceId:Z.serviceId.toString(),onChain:l,...u?{revocationTransaction:u}:{},localKeyRetired:!!d});return}M(s.alreadyRevoked?`${r} was already revoked in the Solve API`:`Revoked ${r}; the Solve API refuses its signatures`),u&&M(`Revoked on Tempo in ${u}; service ${Z.serviceId} refuses its jobs`),d&&P("The local device key was moved aside because its address may still hold stake or rewards. Run `tangle solve account --create` for a new device"),!a&&l.permitted&&N(`The device can still submit jobs to service ${Z.serviceId}. Only its key, or the Solve blueprint owner, can revoke it on chain`)}catch(e){R(e,t.json)}}function Yu(e,t){return tt(Ze(gu,[e.trim(),t]))}function Xu(e){let t=/^submission=(\S+)/.exec(e);if(!t?.[1])throw Error(`COMMIT_CANDIDATE did not return a submission reference`);return t[1]}async function Zu(e,t,n,r,i){let a=i.resumeTransactions?.evaluation;if(a){let n=await e.publicClient.waitForTransactionReceipt({hash:a});if(Cu(n,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!Ou(n,t,e.account,r))throw Error(`Saved evaluation transaction did not emit EvaluationAccepted for this candidate`);return a}let o=Date.now();for(;!Tu(o,iu);){if(await Iu(e,t,r)){let i=Eu(await e.publicClient.getLogs({address:t.managerAddress,event:lu,args:{serviceId:t.serviceId,competitionId:t.competitionId,researcher:e.account.address},fromBlock:n.blockNumber,toBlock:`latest`}),r);if(i)return i;throw Error(`Candidate is already accepted, but its EvaluationAccepted transaction is unavailable`)}let[a,o,,s,c]=await e.publicClient.readContract({address:t.managerAddress,abi:du,functionName:`pendingResults`,args:[t.serviceId,n.callId]});if(s&&a!==4)throw Error(`Manager pending result ${n.callId} has unexpected job ${a}`);if(s&&c)throw Error(`Manager executed the report without EvaluationAccepted`);if(s&&!c){if(o.toLowerCase()!==tt(n.output).toLowerCase())throw Error(`Manager pending report output does not match the aggregate`);let a=await Ru(e,{address:t.managerAddress,abi:du,functionName:`executePendingResult`,args:[t.serviceId,n.callId,n.output]});await i.onTransaction?.(`evaluation`,a);let s=await e.publicClient.waitForTransactionReceipt({hash:a});if(Cu(s,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!Ou(s,t,e.account,r))throw Error(`Evaluation transaction did not emit EvaluationAccepted for this candidate`);return a}await new Promise(e=>setTimeout(e,1e3))}throw Error(`Manager did not emit EvaluationAccepted within 120 seconds`)}async function Qu(e,t,n,r={}){if(El(e),!/^0x[0-9a-f]{64}$/i.test(n.salt))throw Error(`Reveal salt must be bytes32`);if(!n.artifactRef.trim())throw Error(`Candidate reference is required`);if(!n.evidenceJson.trim()||n.evidenceRefs.length===0)throw Error(`Checker evidence is required`);let i=await Au(e,t),a=await zu(i,e,r.onTransaction,r.resumeTransactions?.authorization),o,s=await i.publicClient.readContract({address:e.managerAddress,abi:du,functionName:`stakes`,args:[e.serviceId,e.competitionId,i.account.address]});s<e.minStakeWei&&(o=await Ru(i,{address:e.managerAddress,abi:du,functionName:`postStake`,args:[e.serviceId,e.competitionId],value:e.minStakeWei-s}),await r.onTransaction?.(`stake`,o),Cu(await i.publicClient.waitForTransactionReceipt({hash:o}),o,`Stake`,{from:i.account.address,to:e.managerAddress}));let c=Yu(n.artifactRef,n.salt),l=Ze(pu,[e.competitionId,e.minStakeWei]),u=Ze(mu,[e.competitionId,c]),d=Ze(hu,[e.competitionId,c,n.artifactRef.trim(),n.salt]),f=await Uu(i,e,1,l,`joined`,r.onTransaction,`join`,r.resumeTransactions),p=await Uu(i,e,2,u,`committed`,r.onTransaction,`commit`,r.resumeTransactions),m=Xu(p.acknowledgement.detail),h=await Uu(i,e,3,d,`revealed`,r.onTransaction,`reveal`,r.resumeTransactions),g=await Hu(i,e,4,Ze(_u,[e.competitionId,c,m,n.evidenceJson,JSON.stringify(n.evidenceRefs)]),r.onTransaction,`report`,r.resumeTransactions),ee=await Fu(i,e,g.callId,g.blockNumber,iu),te=await Zu(i,e,{callId:g.callId,output:ee,blockNumber:g.blockNumber},c,r);return{address:i.account.address,...a?{authorization:a}:{},...o?{stake:o}:{},join:f.hash,commit:p.hash,reveal:h.hash,report:g.hash,evaluation:te,candidateId:c,submissionRef:m}}const $u=Ke(Ce),ed=`/usr/bin/bwrap`,td=[`/usr`,`/bin`,`/sbin`,`/lib`,`/lib64`];function nd(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function rd(e,t){if(!e||e.length>2048||nd(e))throw Error(`${t} contains invalid control characters or is too long`)}function id(e,t){let n=t;for(;n<e.length&&/\s/.test(e[n]??``);)n+=1;return n}function ad(e,t){if(e[t]!==`"`)throw Error(`Checker output must be valid JSON`);let n=t+1;for(;n<e.length;){let t=e[n];if(t===`\\`){n+=2;continue}if(t===`"`)return n+1;if((t?.charCodeAt(0)??0)<32)throw Error(`Checker output must be valid JSON`);n+=1}throw Error(`Checker output must be valid JSON`)}function od(e,t,n){let r=new Set,i=id(e,t+1);if(e[i]===`}`)return i+1;for(;i<e.length;){let t=ad(e,i),a=JSON.parse(e.slice(i,t));if(r.has(a))throw Error(`Checker output must not contain duplicate object keys`);if(r.add(a),i=id(e,t),e[i]!==`:`)throw Error(`Checker output must be valid JSON`);let o=id(e,i+1),s=cd(e,o);if(n?.(a,o,s),i=id(e,s),e[i]===`}`)return i+1;if(e[i]!==`,`)throw Error(`Checker output must be valid JSON`);i=id(e,i+1)}throw Error(`Checker output must be valid JSON`)}function sd(e,t){let n=id(e,t+1);if(e[n]===`]`)return n+1;for(;n<e.length;){if(n=id(e,cd(e,n)),e[n]===`]`)return n+1;if(e[n]!==`,`)throw Error(`Checker output must be valid JSON`);n=id(e,n+1)}throw Error(`Checker output must be valid JSON`)}function cd(e,t){if(e[t]===`"`)return ad(e,t);if(e[t]===`{`)return od(e,t);if(e[t]===`[`)return sd(e,t);let n=t;for(;n<e.length&&!/[\s,\]}]/.test(e[n]??``);)n+=1;return n}function ld(e){let t=e.trim();if(id(t,cd(t,0))!==t.length)throw Error(`Checker output must be valid JSON`)}function ud(e,t){let n=e.trim();if(n[0]!==`{`)return;let r;return od(n,0,(e,i,a)=>{e===t&&(r=n.slice(i,a).trim())}),r}function dd(e,t){let n=e.trim(),r=[];return od(n,0,(e,i,a)=>{if(e===`evidence_refs`)return;let o=e===`candidate_ref`?JSON.stringify(t):n.slice(i,a).trim();r.push(`${JSON.stringify(e)}:${o}`)}),`{${r.join(`,`)}}`}function fd(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Checker output must be one JSON object`)}if(ld(e),!t||typeof t!=`object`||Array.isArray(t))throw Error(`Checker output must be a JSON object`);let n=t,r=n.candidate_ref;if(typeof r!=`string`||!r.trim())throw Error(`Checker output must include candidate_ref`);let i=r.trim(),a=n.evidence_refs;if(!Array.isArray(a)||a.length===0||a.some(e=>typeof e!=`string`||!e.trim()))throw Error(`Checker output must include a non-empty evidence_refs array`);rd(i,`candidate_ref`);for(let e of a)rd(e.trim(),`evidence_refs`);let o,s;if(n.evidence_json!==void 0){if(!n.evidence_json||typeof n.evidence_json!=`object`||Array.isArray(n.evidence_json))throw Error(`Checker evidence_json must be an object`);o={...n.evidence_json};let t=ud(e,`evidence_json`);if(!t)throw Error(`Checker evidence_json source text is missing`);if(s=t,o.candidate_ref!==i)throw Error(`Checker evidence_json candidate_ref must match candidate_ref`)}else{let{evidence_refs:t,...r}=n;o=r,o.candidate_ref=i,s=dd(e,i)}return{candidateRef:i,evidenceRefs:a.map(e=>e.trim()),evidence:o,evidenceJson:s}}async function pd(e,t,n){let r=n.trim();if(r.startsWith(`{`)&&r.endsWith(`}`)||!t.result_file)return r;let i=await yd(e),a=x.resolve(i,t.result_file),o=x.relative(i,a);if(o.startsWith(`..`)||x.isAbsolute(o))throw Error(`Checker result_file must stay inside the competition repository`);let s;try{s=await C.lstat(a)}catch{throw Error(`Checker result_file must be an existing regular file inside the competition repository`)}if(s.isSymbolicLink())throw Error(`Checker result_file must not be a symbolic link`);if(!s.isFile())throw Error(`Checker result_file must be an existing regular file inside the competition repository`);let c;try{c=await C.realpath(a)}catch{throw Error(`Checker result_file must resolve to a regular file inside the competition repository`)}let l=x.relative(i,c);if(l.startsWith(`..`)||x.isAbsolute(l))throw Error(`Checker result_file must stay inside the competition repository`);return(await C.readFile(c,`utf8`)).trim()}function md(e,t){let n=x.relative(e,t);return n===``||!n.startsWith(`..`)&&!x.isAbsolute(n)}function hd(e){return td.some(t=>md(t,e))}async function gd(e,t,n){let r=e.includes(`/`)?[x.resolve(t,e)]:(process.env.PATH??``).split(x.delimiter).filter(Boolean).map(t=>x.join(t,e));for(let i of r){let r;try{r=await C.realpath(i),await C.access(r,C.constants.X_OK)}catch{continue}if(!md(t,r)&&!hd(r)&&r!==n)throw Error(`Checker executable '${e}' must resolve inside the competition repository or a trusted runtime directory`);return r}throw Error(`Checker executable '${e}' was not found`)}async function _d(e){let t=[];for(let n of e)try{(await C.stat(n)).isDirectory()&&t.push(n)}catch{}return t}async function vd(e){let t=await C.realpath(be.homedir());if(e===x.parse(e).root||e===t)throw Error(`Solve checker repository must be a dedicated directory, not the filesystem or home root`)}async function yd(e){let t=await C.realpath(e);return await vd(t),t}async function bd(e){let t=x.join(e,`.git`),n;try{n=await C.lstat(t)}catch{return}if(n.isSymbolicLink())throw Error(`Solve checker repository .git must not be a symbolic link`);if(!n.isDirectory()&&!n.isFile())return;let r;try{let t={...process.env};for(let e of[`GIT_DIR`,`GIT_WORK_TREE`,`GIT_INDEX_FILE`,`GIT_OBJECT_DIRECTORY`,`GIT_ALTERNATE_OBJECT_DIRECTORIES`,`GIT_COMMON_DIR`,`GIT_CONFIG_COUNT`,`GIT_CONFIG_PARAMETERS`])delete t[e];let n=await $u(`/usr/bin/git`,[`-C`,e,`rev-parse`,`--verify`,`HEAD^{commit}`],{encoding:`utf8`,maxBuffer:1e5,env:{...t,GIT_CONFIG_GLOBAL:`/dev/null`,GIT_CONFIG_SYSTEM:`/dev/null`,GIT_CONFIG_NOSYSTEM:`1`,GIT_TERMINAL_PROMPT:`0`}}),i=String(n.stdout).trim();/^[0-9a-f]{40}$/i.test(i)&&(r=i.toLowerCase())}catch{}return{kind:n.isDirectory()?`directory`:`file`,...r?{commit:r}:{}}}async function xd(e,t,n){let r=await yd(e);if(process.platform!==`linux`)throw Error(`Solve checkers require the Linux sandbox runtime (bubblewrap) with network isolation`);try{await C.access(ed,C.constants.X_OK)}catch{throw Error(`Solve checkers require /usr/bin/bwrap; install bubblewrap or run the checker in a Tangle sandbox`)}let i=await gd(t,r,await C.realpath(process.execPath)),a=await bd(r),o=(await _d(td)).flatMap(e=>[`--ro-bind`,e,e]),s=md(r,i)?`/work/${x.relative(r,i)}`:hd(i)?i:`/checker/node`;!md(r,i)&&!hd(i)&&o.push(`--ro-bind`,i,`/checker/node`);let c=a?.kind===`directory`?[`--tmpfs`,`/work/.git`]:a?.kind===`file`?[`--ro-bind`,`/dev/null`,`/work/.git`]:[];return{executable:ed,args:[`--die-with-parent`,`--new-session`,`--unshare-all`,`--clearenv`,...o,`--proc`,`/proc`,`--dev`,`/dev`,`--tmpfs`,`/tmp`,`--dir`,`/tmp/home`,`--bind`,r,`/work`,...c,`--chdir`,`/work`,`--setenv`,`HOME`,`/tmp/home`,...a?.commit?[`--setenv`,`TANGLE_SOLVE_COMMIT`,a.commit]:[],`--setenv`,`TMPDIR`,`/tmp`,`--setenv`,`PATH`,`/checker:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`,`--setenv`,`LANG`,`C.UTF-8`,`--setenv`,`PYTHONDONTWRITEBYTECODE`,`1`,`--setenv`,`XDG_CONFIG_HOME`,`/tmp/home/.config`,`--setenv`,`XDG_CACHE_HOME`,`/tmp/home/.cache`,`--setenv`,`XDG_DATA_HOME`,`/tmp/home/.local/share`,`--setenv`,`GIT_CONFIG_GLOBAL`,`/dev/null`,`--setenv`,`GIT_CONFIG_SYSTEM`,`/dev/null`,`--setenv`,`NPM_CONFIG_USERCONFIG`,`/dev/null`,s,...n]}}async function Sd(e,t){if(!t.command||t.command.includes(`/../`)||nd(t.command))throw Error(`The competition checker command is invalid`);if(!Array.isArray(t.args))throw Error(`The competition checker arguments must be an array`);for(let e of t.args)rd(e,`Checker argument`);let n=t.timeout_ms??15*6e4;if(!Number.isSafeInteger(n)||n<1e3||n>60*6e4)throw Error(`Checker timeout must be between one second and one hour`);let r=await yd(e),i;try{let e=await xd(r,t.command,t.args);i=await $u(e.executable,e.args,{cwd:r,timeout:n,maxBuffer:4194304,encoding:`utf8`})}catch(e){let t=e,n=t.stderr?.trim()||t.stdout?.trim()||t.message||`checker failed`;throw Error(`Pinned checker failed: ${n}`)}let a=String(i.stdout),o=String(i.stderr);return{...fd(await pd(r,t,a)),stdout:a,stderr:o}}async function Cd(e,t){try{let{root:n,manifest:a}=await Bl(e,t.directory),o=await Gl(n),s=a.provenance?await Kl(n,a,o,{allowMissing:!0}):void 0,c=il(),l=F(`Running ${a.title} checker…`);t.json||l.start();let u;try{u=await Sd(n,a.checker)}finally{l.stop()}let d=Xl(u,s,a.provenance,void 0,{allowMissingSource:!0,requirePullRequest:!1}),f=ot(r(32)),p=Yu(u.candidateRef,f),m={version:1,competition:a.slug,candidateRef:u.candidateRef,evidence:d.evidence,evidenceJson:u.evidenceJson,evidenceRefs:d.evidenceRefs,salt:f,candidateId:p,...s?{source:s}:{},deviceAddress:c.account.address,clientSubmissionId:i(),createdAt:new Date().toISOString()};await Zl(x.join(n,`.tangle-solve-run.json`),m),t.json?j({localRun:m}):(M(`Checker output recorded locally for operator evaluation`),I({Competition:a.slug,Candidate:u.candidateRef,"Device address":c.account.address,"Evidence refs":d.evidenceRefs.length}),P("Commit any changes, then run `tangle solve submit` from this directory."),a.provenance&&!s&&P(`Add your GitHub fork as 'origin' before submitting. The task repository is available as '${Rl}'.`))}catch(e){R(e)}}const wd=/^0x[0-9a-f]{64}$/i;async function Td(e){let t=await Sl({deviceAddress:e.deviceAddress,apiUrl:e.apiUrl,profile:e.profile}),n=await e.signer.signMessage({message:t.message});return{walletChallengeId:t.challengeId,walletSignature:n}}async function Ed(e,t){try{let{root:n,manifest:r}=await Bl(e,t.directory);yl({profile:t.profile});let i=await Gl(n),a=await Ql(n);if(a.competition!==r.slug)throw Error(`.tangle-solve-run.json does not match this competition`);if(!wd.test(a.salt)||!wd.test(a.candidateId))throw Error("This run predates durable candidate identity. Run `tangle solve run` again");let o=r.provenance?await Kl(n,r,i):void 0;if(r.provenance&&a.source&&!Jl(a.source,o))throw Error("The saved run points to a different repository or revision. Keep your fork as 'origin' and run `tangle solve run` again before submitting");let s=rl();if(!s)throw Error("No Solve device signer found. Run `tangle solve run` first");if(s.account.address.toLowerCase()!==a.deviceAddress.toLowerCase())throw Error("The local Solve device account changed after `tangle solve run`; run the checker again");let c=F(`Checking the committed candidate…`);t.json||c.start();let l;try{l=await Sd(n,r.checker)}finally{c.stop()}if(l.candidateRef!==a.candidateRef||l.evidenceJson!==a.evidenceJson)throw Error("The committed checker output changed after `tangle solve run`; run the checker again");if(Yu(l.candidateRef,a.salt).toLowerCase()!==a.candidateId.toLowerCase())throw Error(`The saved candidate identity does not match the checker output; run the checker again`);let u=_l(t.prUrl);if(!r.provenance&&u)throw Error(`This competition does not accept GitHub pull request provenance`);if(u){if(!o)throw Error(`A provenance policy is required for a pull request`);await $l({pullRequest:u,taskRepository:o.taskRepository,submissionRepository:o.submissionRepository,submissionRevision:i})}let d=Xl(l,o,r.provenance,u,{requirePullRequest:!0}),f={...a,...o?{source:o}:{},chainState:{status:`submitting`,transactions:{...a.chainState?.transactions??{}}}},p=x.join(n,`.tangle-solve-run.json`);await Zl(p,f);let m=F(`Submitting candidate to Tempo…`);t.json||m.start();let h;try{h=await Qu(jl(r),s.account,{artifactRef:l.candidateRef,salt:a.salt,evidenceJson:l.evidenceJson,evidenceRefs:d.evidenceRefs},{resumeTransactions:f.chainState?.transactions,onTransaction:async(e,t)=>{f={...f,chainState:{status:`submitting`,transactions:{...f.chainState?.transactions??{},[e]:t}}},await Zl(p,f)}})}finally{m.stop()}f={...f,chainReceipt:h,chainState:{status:`accepted`,transactions:{...f.chainState?.transactions??{},...eu(h)}}},await Zl(p,f);let g=await Td({deviceAddress:h.address,signer:s.account,apiUrl:t.apiUrl,profile:t.profile}),ee=await xl({path:`/v1/submissions`,method:`POST`,apiUrl:t.apiUrl,profile:t.profile,body:{competition:r.slug,candidateRef:l.candidateRef,candidateId:h.candidateId,evidenceJson:l.evidenceJson,evidenceRefs:d.evidenceRefs,deviceAddress:h.address,reportTxHash:h.report,evaluationTxHash:h.evaluation,transactions:eu(h),...r.provenance&&o?{source:{...o,...u?{pullRequest:u}:{}}}:{},clientSubmissionId:a.clientSubmissionId,...g,...t.model?{model:t.model}:{},...t.note?{note:t.note}:{}}});t.json?j({...ee,transactions:eu(h),candidateId:h.candidateId}):(M(`Submission accepted on Tempo`),I({Competition:r.slug,Candidate:h.candidateId,"Device address":h.address,"Report transaction":h.report,"Evaluation transaction":h.evaluation,"Submission ID":typeof ee.id==`string`?ee.id:ee.submission?.id}))}catch(e){R(e)}}function Dd(){let e=new t(`solve`).description(`Participate in Tangle Solve competitions`);e.command(`clone <competition>`).description(`Clone the pinned competition repository`).argument(`[directory]`,`Destination directory`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).option(`--json`,`Output JSON`).action(ru),e.command(`run [competition]`).description(`Run the competition checker and record its evidence`).option(`--directory <path>`,`Competition directory (defaults to the current directory)`).option(`--json`,`Output JSON`).action(Cd),e.command(`submit [competition]`).description(`Submit checker evidence through the device account and Tempo`).option(`--directory <path>`,`Competition directory (defaults to the current directory)`).option(`--pr-url <url>`,`GitHub pull request containing the submission`).option(`--model <name>`,`Model used to produce the submission`).option(`--note <text>`,`Short note shown with the accepted submission`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).option(`--json`,`Output JSON`).action(Ed),e.command(`account`).description(`Show the local Solve signing account`).option(`--create`,`Create the account if it does not exist`).option(`--json`,`Output JSON`).action(ol);let n=e.command(`device`).description(`List and revoke the Solve devices bound to your account`);return n.command(`list`).description(`List your devices and whether each may submit jobs on Tempo`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).option(`--json`,`Output JSON`).action(e=>qu(e)),n.command(`revoke <address>`).description(`Permanently revoke a device; the local device is revoked with its own key`).option(`--reason <text>`,`Why the device is revoked (shown to the account)`).option(`--yes`,`Confirm the permanent revocation without a prompt`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).option(`--json`,`Output JSON`).action((e,t)=>Ju(e,t)),e}function Od(e,t){return`tangle ssh-proxy ${e.replace(/\/+$/,``)}/v1/sidecar-proxy/${t}/ssh`}function kd(e){return/^[A-Za-z0-9_/:=@%+.,-]+$/.test(e)?e:`'${e.replace(/'/g,`'"'"'`)}'`}function Ad(e){return`'${e.replace(/'/g,`''`)}'`}function jd(e){return e===`win32`?`NUL`:`/dev/null`}function Md(e,t){return t===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN=${Ad(`<token>`)}; ssh ${e.map(Ad).join(` `)}`:`TANGLE_SSH_PROXY_AUTH_TOKEN=${kd(`<token>`)} ssh ${e.map(kd).join(` `)}`}function Nd(e){return e.connection!==void 0&&!e.connection.ssh}function Pd(){nr(`SSH is not enabled for this sandbox.`),P(`Create a sandbox with --ssh to enable SSH access.`),process.exit(1)}function Fd(e,t=[],n=process.platform){let r=jd(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 Id(){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=D({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=k(r),a=F(`Getting SSH credentials...`);a.start();let o=await B(i,r,e);if(Nd(o)){a.stop(),Pd();return}o=await V(o);let s=await o.ssh();if(a.stop(),!s){Pd();return}let c={...s,proxyCommand:Od(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=Fd(c,[...n.identityFile?[`-i`,n.identityFile,`-o`,`IdentitiesOnly=yes`]:[],...t]);if(n.print){console.log(Md(l,process.platform));return}P(`Connecting via tunnel...`);let u=Te(`ssh`,l,{stdio:`inherit`,env:{...process.env,TANGLE_SSH_PROXY_AUTH_TOKEN:r.apiKey}});u.on(`error`,e=>{e.code===`ENOENT`&&(nr(`SSH client not found. Please install OpenSSH.`),process.exit(1)),R(e)}),u.on(`exit`,e=>{process.exit(e??0)})}catch(e){R(e)}})}function Ld(){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(D(e)).sshKeys.list();t.stop(),e.json?j({sshKeys:n}):n.length===0?P(`No SSH keys found.`):L([`Name`,`Type`,`Fingerprint`,`Created`],n.map(e=>[e.name,e.keyType,e.fingerprint,e.createdAt.toLocaleString()]))}catch(e){t.stop(),R(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=b(t.keyFile,`utf8`).trim();n.start();let i=await k(D(t)).sshKeys.create(e,r);n.stop(),t.json?j({sshKey:i}):M(`Added SSH key ${i.name} (${i.fingerprint})`)}catch(e){n.stop(),R(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(D(t)).sshKeys.delete(e),n.stop(),M(`Deleted SSH key ${e}`)}catch(e){n.stop(),R(e)}}),e}function Rd(e,t=1){process.stderr.write(`${e}\n`),process.exit(t)}function zd(){return new t(`ssh-proxy`).description(`SSH proxy helper that pipes stdin/stdout to WebSocket`).argument(`<runtime-url>`,`Runtime WebSocket URL`).action(async e=>{let t=process.env.TANGLE_SSH_PROXY_AUTH_TOKEN;t||Rd(`TANGLE_SSH_PROXY_AUTH_TOKEN not set`);let n=new ut(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===ut.OPEN&&n.ping()},15e3),r.unref?.(),process.stdin.on(`data`,e=>{n.readyState===ut.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(),Rd(`WebSocket error: ${e.message}`)}),n.on(`close`,e=>{i(),process.exit(e===1e3?0:1)}),process.stdin.on(`error`,()=>n.close())})}const Bd=[`claude-code`,`opencode`,`codex`,`kimi-code`,`prime`],Vd=[`project`,`read-only`],Hd={min:1,max:15},Ud=process.env.TANGLE_ROUTER_URL??`https://router.tangle.tools/v1`;function Wd(e){let t=s(e);if(t)return t;throw Error(`--model '${e}' has no provider. Pass a canonical id, for example 'google/${e}'.`)}function Gd(e,t){return{...e,harness:t}}function Kd(e){let t=e.harness??`claude-code`;if(!Bd.includes(t))throw Error(`Unknown --harness '${t}'. Supported: ${Bd.join(`, `)}.`);let n=e.tokenScope??`project`;if(!Vd.includes(n))throw Error(`Unknown --token-scope '${n}'. Supported: ${Vd.join(`, `)}.`);let r=qd(e.maxTokens,2e5,`--max-tokens`),i=qd(e.maxIterations,50,`--max-iterations`),a=qd(e.tokenTtl,10,`--token-ttl`);if(a<Hd.min||a>Hd.max)throw Error(`--token-ttl ${a} out of range; the SDK clamps to [${Hd.min}, ${Hd.max}] minutes.`);let o=e.maxWorkers===void 0?void 0:qd(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 qd(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 Jd(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 Yd(e){let{client:t,scope:n,ttlMinutes:r,onScope:i}=e;return{async create(e){let a=await t.create(Xd(e)),o={scope:n,ttlMinutes:r},s=await a.mintScopedToken(o);return i({id:a.id,scope:s.scope,expiresAt:s.expiresAt,status:`spawned`}),a}}}function Xd(e){if(!e?.env)return e;let{TANGLE_API_KEY:t,...n}=e.env;return{...e,env:n}}function Zd(e){let t=e.spentTotal,n={tokenUsage:{input:t.tokensKnown===!1?null:t.tokens.input,output:t.tokensKnown===!1?null:t.tokens.output},costUsd:t.usdKnown===!1?null:t.usd};if(e.kind===`no-winner`)return{text:``,...n,status:`no-winner (${e.reason})`};let r=e.out;return{text:typeof r==`string`?r:Qd(r)?r.content:JSON.stringify(r),...n,status:`winner`}}function Qd(e){return typeof e==`object`&&!!e&&typeof e.content==`string`}let $d=null;function ef(){return $d??=import(`@tangle-network/agent-runtime/kernel`).catch(e=>{throw $d=null,e?.code===`ERR_MODULE_NOT_FOUND`?Error("`tangle supervise` needs @tangle-network/agent-runtime, which no longer installs with the CLI. Install it alongside the CLI (for example `npm install @tangle-network/agent-runtime`) and retry.",{cause:e}):e}),$d}const tf={makeClient:e=>k(D({apiKey:e.apiKey,baseUrl:e.baseUrl})),resolveRouter:e=>({routerBaseUrl:Ud,routerKey:D({apiKey:e.apiKey}).apiKey}),supervise:async(e,t,n)=>(await ef()).supervise(e,t,n)};async function nf(e,t,n,r=tf){let a=r.makeClient({apiKey:n.apiKey,baseUrl:n.baseUrl}),{budget:o,perWorker:s}=Jd(t),c=[],l=Yd({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=(await ef()).workerFromBackend({backend:`sandbox`,sandboxClient:l,maxIterations:1}),d=(e,n)=>u(Gd(e,t.harness),n),f={name:`supervisor`,harness:`cli-base`,model:{default:t.model??`gemini-2.5-flash-lite`,provider:t.model?Wd(t.model):`google`}},p=r.resolveRouter({apiKey:n.apiKey}),m=Zd(await r.supervise(f,{goal:e},{budget:o,makeWorkerAgent:d,router:p,...s?{perWorker:s}:{},...t.model?{allowedModels:[t.model]}:{},runId:`supervise-${i()}`})),h=m.status===`winner`?`settled`:`failed`;for(let e of c)e.status=h,n.json||P(`worker ${e.id} [${e.scope} token ttl ${t.tokenTtl}m] settled (${e.status})`);return{task:e,result:m.text,workers:c,tokenUsage:m.tokenUsage,costUsd:m.costUsd,status:m.status}}function rf(){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 (${Bd.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 (${Vd.join(` | `)})`,`project`).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=Kd({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 nf(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.result&&(console.log(r.result),console.log()),I({"Input Tokens":r.tokenUsage.input??`Unavailable`,"Output Tokens":r.tokenUsage.output??`Unavailable`,Cost:r.costUsd===null?`Unavailable`:`$${r.costUsd.toFixed(4)}`}),r.status!==`winner`)throw Error(`Supervisor finished without a winner: ${r.status}`)}catch(e){R(e,t.json)}}),e}function af(){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=D(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){R(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=D(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&&zc(a,n.profile),i?.stop(),t.json){j({team:a,active:!!t.switch});return}M(`Team created: ${Lc(a)}`),t.switch&&M(`Active team set to ${a.name}`)}catch(e){R(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=D(t),r=await Rc(k(n),e);if(zc(r,n.profile),t.json){j({team:r,activeTeamId:r.id});return}M(`Active team set to ${Lc(r)}`)}catch(e){R(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=Nn(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){R(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(Bc(e.profile),e.json){j({activeTeamId:null});return}M(`Active team cleared.`)}catch(e){R(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=D(t),r=k(n),i=await q(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){R(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=D(t),r=k(n),i=await q(r,t.team,n.profile),a=of(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){R(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=D(t),r=k(n),i=await q(r,t.team,n.profile),a=of(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){R(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=D(t),r=k(n),i=await q(r,e,n.profile);if(!t.force&&!t.json&&!await H(`Leave team '${i.name}'? (y/N) `,`--force`))return;if(await r.teams.leave(i.id),n.activeTeamId===i.id&&Bc(n.profile),t.json){j({success:!0,teamId:i.id});return}M(`Left team: ${i.name}`)}catch(e){R(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=D(n),i=k(r),a=await q(i,t,r.profile);if(!n.force&&!n.json&&!await H(`Transfer ownership of '${a.name}' to ${e}? This cannot be undone without the new owner's cooperation. (y/N) `,`--force`))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){R(e)}}),e.addCommand(sf()),e.addCommand(cf()),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=D(t),r=k(n),i=await q(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){R(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=D(t),r=k(n),i=await r.teams.acceptInvitation(e),a=t.switch===!1?null:await r.teams.get(i.teamId);if(a&&zc(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){R(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(D(t)).teams.revokeInvitation(e),t.json){j({success:!0,invitationId:e});return}M(`Invitation revoked: ${e}`)}catch(e){R(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=D(t),r=k(n),i=await q(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){R(e)}}),e}function of(e){if(e===`admin`||e===`member`||e===`viewer`)return e;throw Error(`Role must be one of: admin, member, viewer`)}function sf(){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=D(t),r=k(n),i=await q(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){R(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=D(n),i=k(r),a=await q(i,n.team,r.profile),o=await lf({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){R(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=D(t),r=k(n),i=await q(r,t.team,n.profile);if(!t.force&&!t.json&&!await H(`Delete team secret '${e}' from '${i.name}'? (y/N) `,`--force`))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){R(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=D(t),r=k(n),i=await q(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){R(e)}}),e}function cf(){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=D(t),r=k(n),i=await q(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){R(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=D(n),i=k(r),a=await q(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){R(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=D(t),r=k(n),i=await q(r,t.team,n.profile);if(!t.force&&!t.json&&!await H(`Delete template '${e}' from '${i.name}'? (y/N) `,`--force`))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){R(e)}}),e}async function lf(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 Gr();if(e.length===0)throw Error(`Secret value from stdin cannot be empty`);return e}let t=await Ur(e.prompt);if(t.length===0)throw Error(`Secret value cannot be empty`);return t}async function uf(e,t){let n=new AbortController,r=()=>n.abort();try{let i=k(D({...e,timeout:void 0}));process.once(`SIGINT`,r),process.once(`SIGTERM`,r);let a=await t(i,{...e.timeout===void 0?{}:{timeoutMs:Number(e.timeout)*1e3},resumeJobId:e.resumeJob,signal:n.signal,onProgress:e=>{process.stderr.write(`Publication ${e.id}: ${e.status}\n`)}}).finally(()=>{process.off(`SIGINT`,r),process.off(`SIGTERM`,r)});e.json?j(a):M(`template`in a?`Published template: ${a.template.slug}`:`Published template version: ${a.version.id}`)}catch(t){R(t,e.json)}}function df(){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(D(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(t){R(t,e.json)}}),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(D(t)).publicTemplates.get(e);if(t.json){j({template:n});return}j(n)}catch(e){R(e,t.json)}}),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(D(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){R(e,t.json)}}),e.command(`publish <name> <snapshot-id> <sandbox-id>`).option(`--timeout <seconds>`,`Maximum wait for publication`).option(`--resume-job <id>`,`Resume an accepted publication for this snapshot`).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((e,t,n,r)=>uf(r,async(i,a)=>({template:await i.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},a)}))),e.command(`publish-version <id-or-slug> <snapshot-id> <sandbox-id>`).option(`--timeout <seconds>`,`Maximum wait for publication`).option(`--resume-job <id>`,`Resume an accepted publication for this snapshot`).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((e,t,n,r)=>uf(r,async(i,a)=>({version:await i.publicTemplates.publishVersion(e,{snapshotId:t,sourceSandboxId:n,readmeMarkdown:r.readme,tags:r.tags,releaseNotes:r.releaseNotes},a)}))),e}function ff(){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=D({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=k(n),i=F(`Fetching tools...`);t.json||i.start();let a=await(await B(r,n,e)).tools.list();i.stop(),t.json?j(a):a.length===0?console.log(`No tools installed`):L([`Tool`,`Version`,`Active`],a.map(e=>[e.name,e.version,e.active?`yes`:`no`]))}catch(e){R(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=D({apiKey:r.apiKey,baseUrl:r.baseUrl}),a=k(i),o=F(`Installing ${t}@${n}...`);r.json||o.start(),await(await B(a,i,e)).tools.install(t,n),o.stop(),r.json?j({tool:t,version:n,installed:!0}):M(`Installed ${t}@${n}`)}catch(e){R(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=D({apiKey:r.apiKey,baseUrl:r.baseUrl});await(await B(k(i),i,e)).tools.use(t,n),M(`Activated ${t}@${n}`)}catch(e){R(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=D({apiKey:r.apiKey,baseUrl:r.baseUrl}),a=k(i),o=F(`Running ${t} ${n.join(` `)}...`);r.json||o.start();let s=await(await B(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){R(e)}}),e}function pf(){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:wf(e.status),q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:kf(e.limit)},n=hf(e),r=e.json?null:F(`Fetching traces...`);r?.start();let i=await n.listTraces(t);if(r?.stop(),e.json)return j(i);vf(i.items),Sf(i.nextCursor)}catch(t){_f(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=hf(t);if(t.ndjson){await gf(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:kf(t.limit)});if(r?.stop(),t.json)return j(i);yf(i.items),i.truncated&&I({Spans:`${i.items.length} of ${i.total} (truncated)`}),Sf(i.nextCursor)}catch(e){_f(e,t)}}),e.addCommand(mf()),e}function mf(){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:Ef(e.status),gate:e.gate===void 0?void 0:Of(e.gate),label:e.label,from:e.from,to:e.to,q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:kf(e.limit)},n=hf(e),r=e.json?null:F(`Fetching runs...`);r?.start();let i=await n.listRuns(t);if(r?.stop(),e.json)return j(i);bf(i.items),Sf(i.nextCursor)}catch(t){_f(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=hf(t),r=t.json?null:F(`Fetching run...`);r?.start();let i=await n.getRun(e);if(r?.stop(),t.json)return j(i);xf(i)}catch(e){_f(e,t)}}),e}function hf(e){let t=Sn(e.apiKey);if(!t)throw Error(`No API key found. Set TANGLE_API_KEY or run: tangle auth login`);return dt({apiKey:t,baseUrl:e.baseUrl??process.env.TANGLE_INTELLIGENCE_BASE_URL})}async function gf(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 _f(e,t){return R(e,t.json===!0)}function vf(e){A(e.map(e=>({traceId:e.traceId,root:e.rootName??`-`,model:e.model??`-`,spans:e.spanCount,errors:e.errorCount,durationMs:e.durationMs,cost:Cf(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 yf(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 bf(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 xf(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 Sf(e){e&&I({"Next page":`--cursor ${e}`})}function Cf(e){return e===null?`-`:`$${e.toFixed(4)}`}function wf(e){if(e===`ERROR`||e===`OK`)return e;throw Error(`--status must be ERROR or OK`)}const Tf=[`started`,`baseline-complete`,`generation-complete`,`gate-decided`,`finished`,`errored`];function Ef(e){let t=Tf.find(t=>t===e);if(t)return t;throw Error(`--status must be one of ${Tf.join(`, `)}`)}const Df=[`ship`,`hold`,`need_more_work`,`model_ceiling`,`arch_ceiling`];function Of(e){let t=Df.find(t=>t===e);if(t)return t;throw Error(`--gate must be one of ${Df.join(`, `)}`)}function kf(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function Af(){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(D({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":jf(r.computeMinutes),"GPU Seconds":r.gpuSeconds,"GPU Spend":Mf(r.gpuCostUsd)}),i&&(console.log(),console.log(`Subscription`),console.log(`─`.repeat(40)),I({Plan:i.plan,Status:i.status,"Credits Available":Mf(i.creditsAvailableUsd),"Credits Used":Mf(i.creditsUsedUsd),"Monthly Balance":Mf(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){R(e)}})}function jf(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 Mf(e){return e<0?`-$${(-e).toFixed(2)}`:`$${e.toFixed(2)}`}function Nf(){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){mn(),P(`Cleared the active sandbox.`);return}if(e){pn(e),P(`Active sandbox set to ${e}. Commands now default to it; override with --box or TANGLE_SANDBOX.`);return}let n=fn();P(n?`Active sandbox: ${n}`:"No active sandbox. Set one with `tangle use <id>`.")}catch(e){R(e)}})}function Q(e){return Nr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.baseUrl===void 0?{}:{baseUrl:e.baseUrl}})}function Pf(e){if(!Ff(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 Ff(e,t){return e.options.some(e=>e.attributeName()===t)}function $(e,t){return R(e,t.json===!0)}function If(e){A(e.map(e=>({id:e.id,node:e.nodeId,name:e.name,type:e.contentType,bytes:e.byteSize,created:e.createdAt})),[{key:`id`,header:`ID`},{key:`node`,header:`Node`},{key:`name`,header:`Name`},{key:`type`,header:`Content Type`},{key:`bytes`,header:`Bytes`},{key:`created`,header:`Created`}])}function Lf(e){e.command(`artifacts`).description(`List a run's artifact metadata (never the bytes)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await(await Q(n)).workflows.listArtifacts(e,t);if(n.json)return j(r);If(r.artifacts)}catch(e){$(e,n)}}),e.command(`artifact-download`).description(`Download one run artifact's bytes to a file`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).argument(`<artifactId>`,`Artifact ID`).option(`--out <file>`,`Destination file (defaults to the artifact ID)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n,r)=>{try{let i=await(await Q(r)).workflows.downloadArtifact(e,t,n),a=r.out??n;try{me(a,i.bytes)}catch(e){throw Error(`Could not write artifact to "${a}": ${e instanceof Error?e.message:String(e)}`)}if(r.json)return j({file:a,contentType:i.contentType,bytes:i.bytes.length});P(`Wrote ${a} (${i.bytes.length} bytes, ${i.contentType}).`)}catch(e){$(e,r)}})}function Rf(e){A(e.map(e=>({id:e.id,run:e.runId,title:e.title,options:e.options.join(`, `),requested:e.requestedAt,expires:e.expiresAt??``})),[{key:`id`,header:`ID`},{key:`run`,header:`Run`},{key:`title`,header:`Title`},{key:`options`,header:`Options`},{key:`requested`,header:`Requested`},{key:`expires`,header:`Expires`}])}function zf(e){e.command(`decisions`).description(`List a workflow's pending human decisions`).argument(`<id>`,`Workflow ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=(await(await Q(t)).workflows.listPendingDecisions()).decisions.filter(t=>t.workflowId===e);if(t.json)return j({decisions:n});Rf(n)}catch(e){$(e,t)}}),e.command(`decision-resolve`).description(`Answer the decision a run is parked on and resume it`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).requiredOption(`--choice <choice>`,`The option to resolve with (one of the decision's options)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await Q(n),i=await r.workflows.getRunDecision(e,t),a=await r.workflows.resolveRunDecision(e,t,{decisionId:i.id,choice:n.choice});if(n.json)return j(a);if(a.resumed){P(`Resolved decision ${a.decisionId} with "${a.choice}" — run ${a.runId} resumed.`);return}P(`Resolved decision ${a.decisionId} with "${a.choice}", but run ${a.runId} had already finished — nothing to resume.`)}catch(e){$(e,n)}})}function Bf(e){try{return b(e,`utf8`)}catch(t){throw Error(`Could not read workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function Vf(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 Hf(e){let t=e.workflows.filter(e=>e.failed>0).length,n=e.workflows.filter(e=>e.failed===0&&e.waiting>0).length,r=e.workflows.filter(e=>e.failed===0&&e.waiting===0&&e.runsInWindow>0).length;P(`${t} failing · ${n} waiting · ${r} healthy · ${e.workflows.length} total over ${e.window}`),A(e.workflows.map(e=>({id:e.id,name:e.name,enabled:e.enabled?`yes`:`no`,runs:e.runsInWindow,failed:e.failed,waiting:e.waiting,success:e.successRate===null?`—`:`${Math.round(e.successRate*100)}%`,lastRun:e.lastRunStatus??`—`,lastRunAt:e.lastRunAt??`—`})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`enabled`,header:`Enabled`},{key:`runs`,header:`Runs`},{key:`failed`,header:`Failed`},{key:`waiting`,header:`Waiting`},{key:`success`,header:`Success`},{key:`lastRun`,header:`Last Run`},{key:`lastRunAt`,header:`Last Run At`}])}function Uf(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`),Wf(e.triggers)),e.validationErrors.length>0){P(`Validation issues`);for(let t of e.validationErrors)console.log(` ${t.path}: ${t.message}`)}}function Wf(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 Gf(e){e.command(`list`).description(`List your workflows`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async e=>{try{let t=await(await Q(e)).workflows.list();if(e.json)return j(t);Vf(t)}catch(t){$(t,e)}}),e.command(`fleet`).description(`Fleet overview: every workflow's run tallies over a trailing window, failing-first`).option(`--window <window>`,`Trailing window: 24h, 7d, or 30d`,`7d`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async e=>{try{let t=await(await Q(e)).workflows.fleetInsights({window:e.window});if(e.json)return j(t);Hf(t)}catch(t){$(t,e)}}),e.command(`get`).description(`Show a workflow's definition and compiled triggers`).argument(`<id>`,`Workflow ID`).option(`--yaml`,`Print only the raw definition YAML (the export path — pipe to a file)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=await(await Q(t)).workflows.get(e);if(t.yaml){if(n.definitionYaml===null)throw Error(`Workflow ${n.id} has no stored definition YAML to export`);process.stdout.write(n.definitionYaml.endsWith(`
148
+ `)?n.definitionYaml:`${n.definitionYaml}\n`);return}if(t.json)return j(n);Uf(n)}catch(e){$(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>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=Bf(e),r=await(await Q(t)).workflows.create(n);if(t.json)return j(r);P(`Created workflow ${r.id} (${r.name}).`),Uf(r)}catch(e){$(e,t)}}),e.command(`apply`).description(`Create or update a workflow idempotently, matched by the definition's name`).argument(`<file>`,`Path to the workflow YAML`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=Bf(e),r=await Q(t),i=await r.workflows.validate(n,{structural:!0});if(!i.valid){if(process.exitCode=1,t.json)return j(i);P(`Invalid workflow:`);for(let e of i.errors)console.log(` ${e.path}: ${e.message}`);return}let a=(await r.workflows.list()).find(e=>e.name===i.name);if(a){let e=await r.workflows.update(a.id,n);if(t.json)return j({action:`updated`,workflow:e});P(`Updated workflow ${e.id} (${e.name}) — matched by name.`),Uf(e);return}let o=await r.workflows.create(n);if(t.json)return j({action:`created`,workflow:o});P(`Created workflow ${o.id} (${o.name}).`),Uf(o)}catch(e){$(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(`--note <note>`,`Revision note recorded on the appended revision (why this change)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=Bf(t),i=await(await Q(n)).workflows.update(e,r,{...n.note===void 0?{}:{note:n.note}});if(n.json)return j(i);P(`Updated workflow ${i.id} (${i.name}).`),Uf(i)}catch(e){$(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>`,`Platform control-plane base URL`).action(async(e,t)=>{try{if(!t.force&&!await H(`Delete workflow ${e}? `,`--force`)){P(`Delete cancelled.`);return}if(await(await Q(t)).workflows.delete(e),t.json)return j({deleted:!0,id:e});P(`Deleted workflow ${e}.`)}catch(e){$(e,t)}}),e.command(`validate`).description(`Validate a workflow YAML file without saving it`).argument(`<file>`,`Path to the workflow YAML`).option(`--structural`,`CI mode: compile + capability checks only, no connection resolution — the verdict is the same regardless of connected providers`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=Bf(e),r=await(await Q(t)).workflows.validate(n,{...t.structural?{structural:!0}:{}});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){$(e,t)}}),e.command(`schema`).description(`Print the JSON Schema for the workflow YAML`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async e=>{try{j(await(await Q(e)).workflows.schema())}catch(t){$(t,e)}})}const Kf=1e3;function qf(e,t){return[...t,e]}function Jf(e,t=`input`){if(!e||e.length===0)return;let n={};for(let r of e){let e=r.indexOf(`=`);if(e<=0)throw Error(`Invalid --${t} "${r}": expected key=value (e.g. pull_request.number=123)`);n[r.slice(0,e)]=r.slice(e+1)}return n}function Yf(e){A(e.map(e=>({id:e.id,status:e.status,attempts:e.attempts,created:e.createdAt,completed:e.completedAt??``})),[{key:`id`,header:`Run ID`},{key:`status`,header:`Status`},{key:`attempts`,header:`Attempts`},{key:`created`,header:`Created`},{key:`completed`,header:`Completed`}])}function Xf(e){if(I({"Run ID":e.id,Workflow:e.workflowId,Status:e.status,Error:e.error??``,Attempts:e.attempts,Created:e.createdAt,Started:e.startedAt??``,Completed:e.completedAt??``}),e.actionResults.length>0){P(`Actions`);let t=e.actionResults.some(e=>e.nodeId!==void 0||e.visit!==void 0);A(e.actionResults.map(e=>({index:e.index,...t?{node:e.nodeId??``,visit:e.visit??``}:{},kind:e.kind,status:e.status,error:e.error??``,cost:e.costUsd??``})),[{key:`index`,header:`#`},...t?[{key:`node`,header:`Node`},{key:`visit`,header:`Visit`}]:[],{key:`kind`,header:`Kind`},{key:`status`,header:`Status`},{key:`error`,header:`Error`},{key:`cost`,header:`Cost (USD)`}])}e.graph&&(P(`Graph`),I({Nodes:e.graph.nodes.length,Edges:e.graph.edges.length,"Max node visits":e.graph.maxNodeVisits}),A(e.graph.edges.map(e=>({from:e.from,to:e.to,guard:e.when===void 0?``:JSON.stringify(e.when)})),[{key:`from`,header:`From`},{key:`to`,header:`To`},{key:`guard`,header:`Guard`}])),e.edgeVerdicts&&e.edgeVerdicts.length>0&&(P(`Edge verdicts`),A(e.edgeVerdicts.flatMap(e=>Object.entries(e.verdicts).map(([t,n])=>({node:e.nodeId,edge:t,verdict:n?`taken`:`not taken`}))),[{key:`node`,header:`Node`},{key:`edge`,header:`Edge`},{key:`verdict`,header:`Verdict`}]))}function Zf(e){if(e.status===`cancelled`){P(`Cancelled run ${e.runId}.`);return}if(e.signalled){P(`Cancelling run ${e.runId} — signalled the worker; it will stop shortly.`);return}P(`Requested cancellation of run ${e.runId}, but couldn't confirm it — the run may have just finished, or it's running on another instance and will stop on its own.`)}function Qf(e){switch(e.type){case`snapshot`:P(`snapshot: ${e.run.status} (${e.run.actionResults.length} action(s))`);break;case`action.started`:console.log(`→ action[${e.index}] ${e.kind} started`);break;case`action.finished`:{let t=e.status===`succeeded`?`✓`:e.status===`skipped`?`⊘`:`✗`;console.log(`${t} action[${e.index}] ${e.kind} ${e.status}${e.error?`: ${e.error}`:``}`);break}case`iteration.started`:console.log(` · action[${e.actionIndex}] iteration ${e.iterationIndex} started`);break;case`iteration.ended`:console.log(` · action[${e.actionIndex}] iteration ${e.iterationIndex} ${e.status}`);break;case`token`:typeof e.delta==`string`&&process.stdout.write(e.delta);break;case`ping`:break;case`run.done`:console.log(`\nrun.done: ${e.status}${e.error?`: ${e.error}`:``}`);break;case`run.waiting`:console.log(`\nrun.waiting: parked on a human decision (${e.decisionId}) — resolve it to resume`);break}}function $f(e){e.command(`run`).description(`Trigger an immediate run of a workflow`).argument(`<id>`,`Workflow ID`).option(`--input <key=value>`,`Trigger input as key=value (e.g. pull_request.number=123). Repeatable.`,qf,[]).option(`--wait`,`Wait for the run to finish and print its result`).option(`--timeout <ms>`,`With --wait, fail if the run has not finished after this many milliseconds`).option(`--poll-interval <ms>`,`With --wait, how often to poll for completion (default 2000)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=Jf(t.input),r=t.timeout===void 0?void 0:Ua(t.timeout,`--timeout`),i=t.pollInterval===void 0?void 0:Ua(t.pollInterval,`--poll-interval`),a=await Q(t),{runId:o}=await a.workflows.run(e,n);if(!t.wait){if(t.json)return j({runId:o});P(`Started run ${o} for workflow ${e}.`),P(`Inspect it with: tangle workflows run-detail ${e} ${o}`);return}let s=t.json?null:F(`Waiting for run ${o} to finish...`).start(),c;try{c=await a.workflows.waitForRun(e,o,{...r===void 0?{}:{timeoutMs:r},...i===void 0?{}:{pollIntervalMs:i}})}finally{s?.stop()}if(c.status===`failed`&&(process.exitCode=1),t.json)return j(c);Xf(c)}catch(e){$(e,t)}}),e.command(`runs`).description(`List a workflow's run history (newest first)`).argument(`<id>`,`Workflow ID`).option(`--limit <n>`,`Runs per page (1-100)`).option(`--cursor <cursor>`,`Pagination cursor from a previous page`).option(`--all`,`Fetch every page, not just the first`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=await Q(t),r=t.limit===void 0?void 0:Ua(t.limit,`--limit`);if(t.all){let i=[],a=t.cursor,o=0,s=null;for(;;){let c=await n.workflows.listRuns(e,{...r===void 0?{}:{limit:r},...a===void 0?{}:{cursor:a}});if(i.push(...c.runs),o+=1,!c.nextCursor)break;if(o>=Kf){s=c.nextCursor,t.json||P(`Stopped after ${Kf} pages (${i.length} runs); more may exist — resume with --cursor ${c.nextCursor}`);break}a=c.nextCursor}if(t.json)return j({runs:i,nextCursor:s});Yf(i);return}let i=await n.workflows.listRuns(e,{...r===void 0?{}:{limit:r},...t.cursor===void 0?{}:{cursor:t.cursor}});if(t.json)return j(i);Yf(i.runs),i.nextCursor&&P(`More runs available — next page: --cursor ${i.nextCursor}`)}catch(e){$(e,t)}}),e.command(`run-detail`).description(`Show a single run's detail (per-action output and errors)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await(await Q(n)).workflows.getRun(e,t);if(n.json)return j(r);Xf(r)}catch(e){$(e,n)}}),e.command(`cancel`).description(`Cancel a queued or in-progress run`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await(await Q(n)).workflows.cancel(e,t);if(n.json)return j(r);Zf(r)}catch(e){$(e,n)}}),e.command(`retry`).description(`Re-run a failed or cancelled run (a fresh run with the same trigger context)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID of the failed/cancelled run to retry`).option(`--wait`,`Wait for the new run to finish and print its result`).option(`--timeout <ms>`,`With --wait, fail if the run has not finished after this many milliseconds`).option(`--poll-interval <ms>`,`With --wait, how often to poll for completion (default 2000)`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=n.timeout===void 0?void 0:Ua(n.timeout,`--timeout`),i=n.pollInterval===void 0?void 0:Ua(n.pollInterval,`--poll-interval`),a=await Q(n),o=await a.workflows.retryRun(e,t);if(!n.wait){if(n.json)return j(o);P(`Started run ${o.runId} (retry of ${t}).`),P(`Inspect it with: tangle workflows run-detail ${e} ${o.runId}`);return}let s=n.json?null:F(`Waiting for run ${o.runId} to finish...`).start(),c;try{c=await a.workflows.waitForRun(e,o.runId,{...r===void 0?{}:{timeoutMs:r},...i===void 0?{}:{pollIntervalMs:i}})}finally{s?.stop()}if(c.status===`failed`&&(process.exitCode=1),n.json)return j(c);Xf(c)}catch(e){$(e,n)}}),e.command(`events`).description(`Tail a run's live progress events until it finishes`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).option(`--json`,`Emit each event as a JSON line`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await Q(n);for await(let i of r.workflows.watchRun(e,t))n.json?console.log(JSON.stringify(i)):Qf(i),i.type===`run.done`&&i.status===`failed`&&(process.exitCode=1)}catch(e){$(e,n)}})}async function ep(e,t,n){try{let r=await(await Q(n)).workflows.setEnabled(e,t);if(n.json)return j(r);P(`${t?`Enabled`:`Disabled`} workflow ${r.id}.`),Uf(r)}catch(e){$(e,n)}}function tp(e,t){try{return JSON.parse(e)}catch{throw Error(`Invalid ${t}: not valid JSON`)}}function np(e,t){try{me(e,t,`utf8`)}catch(t){throw Error(`Could not write workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function rp(e){A(e.map(e=>({id:e.id,name:e.name,category:e.category,providers:e.providers.join(`, `),summary:e.summary})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`category`,header:`Category`},{key:`providers`,header:`Providers`},{key:`summary`,header:`Summary`}])}function ip(e,t){let n=e.kind===`github_app`,r=n?`${e.provider} (App installation)`:e.provider,i=e.connectUrl?` — ${n?`install`:`connect`}: ${e.connectUrl}`:``,a=e.prerequisite;return`${r}${i}${a&&t.some(e=>e.provider===a.provider&&e.kind===a.kind&&!e.connected)?` (after connecting ${a.provider})`:``}`}function ap(e){e.command(`enable`).description(`Enable a workflow so its triggers and manual runs fire`).argument(`<id>`,`Workflow ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{await ep(e,!0,t)}),e.command(`disable`).description(`Disable a workflow (pause its triggers and manual runs)`).argument(`<id>`,`Workflow ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{await ep(e,!1,t)}),e.command(`templates`).description(`List the curated starter workflow templates`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async e=>{try{let t=await(await Q(e)).workflows.listTemplates();if(e.json)return j(t);rp(t)}catch(t){$(t,e)}}),e.command(`init`).description(`Create a workflow from a gallery template and print (or save) its YAML`).argument(`<template-id>`,"Template ID from `workflows templates`").option(`--param <key=value>`,`Template parameter value. Repeatable.`,qf,[]).option(`--file <out>`,`Write the instantiated workflow YAML to this file instead of stdout`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=Jf(t.param,`param`)??{},r=await(await Q(t)).workflows.instantiateTemplate(e,n);if(t.json)return j(r);if(!r.created){P(`Template ${e} needs provider connections before it can run:`);for(let e of r.connectionRequirements)console.log(` ${e.connected?`✓`:`✗`} ${ip(e,r.connectionRequirements)}`);process.exitCode=1;return}let{workflow:i}=r;if(i.definitionYaml===null)throw Error(`Workflow ${i.id} was created but the server returned no definition YAML`);if(P(`Created workflow ${i.id} (${i.name}).`),t.file){np(t.file,i.definitionYaml),P(`Wrote ${t.file}.`);return}process.stdout.write(i.definitionYaml.endsWith(`
149
+ `)?i.definitionYaml:`${i.definitionYaml}\n`)}catch(e){$(e,t)}})}function op(e){A(e.map(e=>({key:e.key,version:e.version,updated:e.updatedAt})),[{key:`key`,header:`Key`},{key:`version`,header:`Version`},{key:`updated`,header:`Updated`}])}function sp(e){I({Key:e.key,Version:e.version,Updated:e.updatedAt}),P(`Value`),j(e.value)}function cp(e){let t=e.command(`kv`).description(`Read and write a workflow's cross-run KV state`);t.command(`list`).description(`List every KV entry of a workflow`).argument(`<id>`,`Workflow ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=await(await Q(t)).workflows.listKv(e);if(t.json)return j(n);op(n.entries)}catch(e){$(e,t)}}),t.command(`get`).description(`Show one KV entry (value and version)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await(await Q(n)).workflows.getKv(e,t);if(n.json)return j(r);sp(r)}catch(e){$(e,n)}}),t.command(`set`).description(`Write a KV entry from a JSON value`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).argument(`<json>`,`Value as JSON (e.g. '{"cursor":123}' or '"abc"')`).option(`--cas <version>`,`Compare-and-swap: write only if the stored version still equals this`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n,r)=>{try{let i=tp(n,`<json>`),a=r.cas===void 0?void 0:Ua(r.cas,`--cas`),o=await Q(r),s=a===void 0?await o.workflows.putKv(e,t,i):await o.workflows.casKv(e,t,a,i);if(r.json)return j(s);sp(s)}catch(e){$(e,r)}}),t.command(`delete`).description(`Delete a KV entry (idempotent)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=await(await Q(n)).workflows.deleteKv(e,t);if(n.json)return j(r);P(r.deleted?`Deleted KV entry "${t}" of workflow ${e}.`:`No KV entry "${t}" on workflow ${e}.`)}catch(e){$(e,n)}})}function lp(e){A(e.map(e=>({rev:e.rev,created:e.createdAt,by:e.createdBy,source:e.source,note:e.note??``})),[{key:`rev`,header:`Rev`},{key:`created`,header:`Created`},{key:`by`,header:`Created By`},{key:`source`,header:`Source`},{key:`note`,header:`Note`}])}function up(e){e.command(`revisions`).description(`List a workflow's definition revision history (newest first)`).argument(`<id>`,`Workflow ID`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t)=>{try{let n=await(await Q(t)).workflows.listRevisions(e);if(t.json)return j(n);lp(n)}catch(e){$(e,t)}}),e.command(`revision`).description(`Show one revision's metadata and definition YAML`).argument(`<id>`,`Workflow ID`).argument(`<rev>`,`Revision number`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=Ua(t,`<rev>`),i=await(await Q(n)).workflows.getRevision(e,r);if(n.json)return j(i);I({Revision:i.rev,Created:i.createdAt,"Created by":i.createdBy,Source:i.source,Note:i.note??``}),process.stdout.write(i.yaml.endsWith(`
150
+ `)?i.yaml:`${i.yaml}\n`)}catch(e){$(e,n)}}),e.command(`rollback`).description(`Restore a prior revision's definition as a NEW head revision (re-validated)`).argument(`<id>`,`Workflow ID`).argument(`<rev>`,`Revision number to restore`).option(`--json`,`Output as JSON`).option(`--api-key <key>`,`API key`).option(`--base-url <url>`,`Platform control-plane base URL`).action(async(e,t,n)=>{try{let r=Ua(t,`<rev>`),i=await(await Q(n)).workflows.rollback(e,r);if(n.json)return j(i);P(`Rolled back workflow ${i.id} to rev ${r}.`),Uf(i)}catch(e){$(e,n)}})}function dp(){let e=new t(`workflows`).description(`Create and manage Tangle workflows`);return e.option(`--json`,`Output as JSON`),e.hook(`preAction`,(e,t)=>{Pf(t)}),Gf(e),$f(e),ap(e),up(e),cp(e),Lf(e),zf(e),e}function fp(e){let t={...pp(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 pp(e){let t=e;for(;t?.parent;)t=t.parent;return t?t.opts():void 0}const mp=e(import.meta.url)(`../package.json`);function hp(){let e=new t;return e.name(`tangle`).description(`CLI for Tangle Sandbox operations`).version(mp.version??`0.0.0`).option(`--api-key <key>`,`API key (or set TANGLE_API_KEY)`).option(`--base-url <url>`,`API base URL`),e.hook(`preAction`,(e,t)=>{fp(t);let n=t.opts();Xn(n.json===!0||n.ndjson===!0)}),e.addCommand(wi()),e.addCommand(qc()),e.addCommand(Nf()),e.addCommand(Yc()),e.addCommand(Xs()),e.addCommand(oc()),e.addCommand(sc()),e.addCommand(jo()),e.addCommand(Id()),e.addCommand(Ld()),e.addCommand(zd()),e.addCommand(ai()),e.addCommand(Qc()),e.addCommand(ts()),e.addCommand(Af()),e.addCommand(af()),e.addCommand(df()),e.addCommand(lc()),e.addCommand(Mi()),e.addCommand(Ui()),e.addCommand(hc()),e.addCommand(ns()),e.addCommand(ss()),e.addCommand(cs()),e.addCommand(dp()),e.addCommand(Ao()),e.addCommand(ff()),e.addCommand(Jc()),e.addCommand(Dd()),e.addCommand(Zc()),e.addCommand(Wi()),e.addCommand(pc()),e.addCommand(js()),e.addCommand(Co()),e.addCommand(wo()),e.addCommand(xc()),e.addCommand(cc()),e.addCommand(pf()),e.addCommand(rf()),e}hp().parseAsync(process.argv).catch(e=>{console.error(`Fatal error:`,e.message),process.exit(1)});export{};