@tangle-network/sandbox-cli 0.21.17 → 0.21.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +22 -21
- 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{ALL_BACKEND_TYPES as t,AuthError as n,GPU_LEASE_PROVIDER_NAMES as r,NetworkError as i,NotFoundError as a,PublicTemplatePublishError as o,QuotaError as s,Sandbox as c,ServerError as l,StateError as u,TimeoutError as d,ValidationError as f,createAgentRunOutcomeTracker as p,createBatchResultAccumulator as m,createConfidentialSandbox as h,generateAttestationNonce as g,parseBackendType as _,parseSSEStream as v,validateBatchRunRequest as ee}from"@tangle-network/sandbox";import y from"chalk";import te from"ora";import{Command as b}from"commander";import{createHash as ne,randomBytes as re,randomUUID as ie}from"node:crypto";import{agentInteractiveSessionRunRef as ae,agentProfileSchema as x,canonicalAgentProfileDigest as oe,modelProvider as se,parseSeatSpec as ce}from"@tangle-network/agent-interface";import*as S from"node:fs";import{chmodSync as le,constants as ue,existsSync as de,mkdirSync as fe,readFileSync as C,renameSync as pe,writeFileSync as me}from"node:fs";import*as w from"node:path";import{basename as he,dirname as ge,extname as _e,isAbsolute as ve,join as T,relative as ye,resolve as be,sep as xe}from"node:path";import*as Se from"node:os";import{homedir as Ce,tmpdir as we}from"node:os";import{execFile as Te,execFileSync as Ee,spawn as De}from"node:child_process";import{lockSync as Oe}from"proper-lockfile";import{HubClient as ke}from"@tangle-network/hub-sdk";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 E,asContentString as Ie}from"@tangle-network/agent-core/telemetry";import*as D from"node:fs/promises";import{mkdir as Le,open as Re,readFile as ze,realpath as Be}from"node:fs/promises";import{fileURLToPath as Ve}from"node:url";import{AsyncLocalStorage as He}from"node:async_hooks";import{listLocalModels as Ue,loadConfig as We}from"cli-bridge";import{createMcpServer as Ge}from"@tangle-network/sandbox/agent";import{ensureAgentPreview as Ke,publishAgentPreview as qe,resolveSelfSandbox as Je}from"@tangle-network/sandbox/preview";import{generatePrivateKey as Ye,privateKeyToAccount as Xe}from"viem/accounts";import{promisify as Ze}from"node:util";import{createPublicClient as Qe,createWalletClient as $e,decodeAbiParameters as et,decodeEventLog as tt,encodeAbiParameters as nt,getAddress as rt,http as it,isAddress as at,keccak256 as ot,parseAbi as st,parseAbiItem as ct,parseAbiParameters as lt,stringToHex as ut,toHex as dt}from"viem";import{tempoModerato as ft}from"viem/chains";import{Actions as pt,withRelay as mt}from"viem/tempo";import ht from"ws";import{createIntelligenceClient as gt}from"@tangle-network/sandbox/intelligence";let _t=!1;function vt(e){_t=e}function yt(...e){_t?console.error(...e):console.log(...e)}function bt(e){return e==null?y.dim(`-`):typeof e==`boolean`?e?y.green(`yes`):y.red(`no`):e instanceof Date?St(e):typeof e==`string`&&xt(e)?St(new Date(e)):String(e)}function xt(e){return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)}function St(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 Ct(e){switch(e){case`running`:return y.green(e);case`pending`:case`provisioning`:return y.yellow(e);case`stopped`:return y.gray(e);case`failed`:case`deleted`:return y.red(e);default:return e}}function O(e,t){if(e.length===0){console.log(y.dim(`No items found.`));return}let n=t.map(t=>{let n=t.header.length,r=Math.max(...e.map(e=>bt(e[t.key]).length));return t.width??Math.max(n,r)+2}),r=t.map((e,t)=>y.bold(e.header.padEnd(n[t]))).join(``);console.log(r);for(let r of e){let e=t.map((e,t)=>{let i=bt(r[e.key]);return e.key===`status`&&(i=Ct(String(r[e.key]))),i.padEnd(n[t])}).join(``);console.log(e)}}function k(e){console.log(JSON.stringify(e,null,2))}function A(e){yt(y.green(`✓`),e)}function wt(e){console.error(y.red(`✗`),e)}function Tt(e){yt(y.yellow(`!`),e)}function j(e){yt(y.blue(`→`),e)}const Et=new Set;function M(e){let t=te({text:e,color:`cyan`,isSilent:_t});return Et.add(t),t}function Dt(){for(let e of Et)e.isSpinning&&e.stop();Et.clear()}function N(e,t=0){let n=` `.repeat(t);for(let[t,r]of Object.entries(e))r!=null&&console.log(`${n}${y.dim(`${t}:`)} ${bt(r)}`)}function Ot(e){let t=`${e.cpuCores} vCPU / ${e.memoryMB} MB / ${e.diskGB} GB`;return e.pool?`${t} (pool: ${e.pool})`:t}function kt(e){if(console.log(),console.log(y.bold(`Sandbox Details`)),console.log(y.dim(`─`.repeat(40))),N({ID:e.id,Name:e.name,Status:Ct(e.status),Resources:e.resources?Ot(e.resources):void 0,Created:e.createdAt,Expires:e.expiresAt}),e.connection){if(console.log(),console.log(y.bold(`Connection`)),console.log(y.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 At(e){k(e)}function jt(e,t){if(t.length===0){console.log(y.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)=>y.bold(e.padEnd(n[t]))).join(``));for(let e of t)console.log(e.map((e,t)=>String(e??``).padEnd(n[t])).join(``))}var P=class extends Error{constructor(e,t,n,r){super(t),this.code=e,this.cause=n,this.fix=r,this.name=`ActionableCliError`}};const Mt=new Set([`AUTH_EXPIRED`,`AUTH_WRONG_AUDIENCE`,`SEAT_NONE_DETECTED`,`SEAT_NOT_LOGGED_IN`,`SEAT_NOT_ENROLLED`,`HUB_NOT_CONNECTED`,`HUB_RECONNECT`,`HUB_APP_NOT_INSTALLED`,`HUB_APPROVAL_REQUIRED`]),Nt=new Set([`GRAPH_INVALID`,`STEP_REF`,`PROFILE_INVALID`,`UNKNOWN_HARNESS`,`HUB_TOOL_UNKNOWN`,`TRIGGER_INVALID`,`WORKFLOW_INPUT_FILE_INVALID`,`VALIDATION_ERROR`]),Pt=new Set([`UNKNOWN_COMMAND`,`GRAPH_PARAM_MISSING`,`GRAPH_PARAM_UNKNOWN`,`SEAT_SYNTAX`,`HUB_PROVIDER_UNKNOWN`,`USAGE_INVALID`]),Ft=new Set([`SUBSCRIPTION_REQUIRED`,`MODEL_NOT_FOUND`,`MODEL_PROVIDER_MISMATCH`,`MCP_BLOCKED`,`CLOUD_SEAT_UNSUPPORTED`,`SCHEDULE_AUTHORITY`]);function It(e){return typeof e==`object`&&e?e:{}}function F(e){return typeof e==`string`&&e.length>0?e:void 0}function Lt(e){let t=F(e);return t&&/^[a-z0-9][a-z0-9_-]*$/i.test(t)?t:void 0}function Rt(e){let t,n=e;for(let e=0;n instanceof Error&&e<5;e++,n=n.cause){let e=n.message||(n instanceof AggregateError?n.errors.map(e=>e instanceof Error?e.message:String(e)).join(`; `):``),r=F(It(n).code);(e||r)&&(t=r?`${r}${e?`: ${e}`:``}`:e)}return t}function zt(e){return e.code===`credential-refused`&&e.owner===`caller`&&e.providerCode===`subscription_required`?It(e.remediation):{}}function Bt(e){let t=It(e),r=Array.isArray(t.runtimeFailures)?t.runtimeFailures.map(It):[],c=r.find(e=>F(zt(It(e.failure)).fix))??r[0],l=It(c?.failure??t.runtimeFailure),p=zt(l),m=It(t.details),h=Lt(t.provider??m.provider??m.providerId),g=It(t.fix??m.fix),_=F(t.code)??`CLI_ERROR`,v=F(t.message)??String(e),ee=F(l.cause)??F(t.cause)??F(m.reason)??v,y=`tangle --help`,te=typeof m.providerRetryable==`boolean`?m.providerRetryable:typeof t.retryable==`boolean`?t.retryable:null;if(e instanceof n||_===`HUB_UNAUTHENTICATED`||t.status===401)_=`AUTH_EXPIRED`,v=`Authentication failed`,y=`tangle auth login`;else if([`HUB_CONNECTION_MISSING`,`HUB_CONNECTION_REVOKED`,`HUB_CONNECTION_UNHEALTHY`,`HUB_RECONNECT_REQUIRED`,`CONNECTION_REQUIRED`].includes(_))_=[`HUB_CONNECTION_MISSING`,`CONNECTION_REQUIRED`].includes(_)?`HUB_NOT_CONNECTED`:`HUB_RECONNECT`,y=h?`tangle hub connect ${h}`:`tangle hub connections --json`;else if(_===`HUB_APPROVAL_REQUIRED`){let e=Lt(It(m.approval).id);y=e?`tangle hub approvals approve ${e}`:`tangle hub approvals list --json`}else _===`HUB_PROVIDER_REJECTED`?(y=`tangle hub status --json`,m.providerRetryable===!1&&(ee+=`. Change the request before retrying`)):_===`provider_quota_exhausted`||_===`SEAT_LIMIT`?(_=`SEAT_LIMIT`,y=`tangle auth status`,te=!0):e instanceof s?y=`tangle usage --json`:e instanceof i?(_=`NETWORK_UNAVAILABLE`,v=`Network error: ${v}`,ee=Rt(e.cause)??`No response arrived`,y=`tangle auth status --json`,te=!0):e instanceof d?(_=`TIMEOUT`,y=`tangle sandbox list --json`,te=!0):e instanceof f?(_=`VALIDATION_ERROR`,v=`Invalid input`):e instanceof a||e instanceof u?y=`tangle sandbox list --json`:_===`commander.unknownCommand`?(_=`UNKNOWN_COMMAND`,y=v.includes(`'graph'`)?`npm install -g @tangle-network/sandbox-cli@latest`:`tangle --help`):_.startsWith(`commander.`)?_=`USAGE_INVALID`:(_===`ENOENT`||_===`EACCES`)&&(_=`INPUT_UNAVAILABLE`);e instanceof P&&(y=e.fix,te=!1),F(p.fix)&&(_=p.cause===`not_authenticated`?`SEAT_NOT_LOGGED_IN`:`SUBSCRIPTION_REQUIRED`),e instanceof o&&y===`tangle --help`&&(y=`tangle template publish --help`),y=F(p.fix)??F(g.command)??(_===`HUB_NOT_CONNECTED`?void 0:F(t.fixCommand))??y,Mt.has(_)&&y===`tangle --help`&&(y=`tangle auth login`);let b=It(t.subject??m.subject??{node:c?.node??t.node,seat:t.seat??p.harness}),ne=F(t.resumeAt??m.resumeAt??m.resetAt);return{code:_,subject:{...F(b.node)?{node:String(b.node)}:{},...F(b.seat)?{seat:String(b.seat)}:{}},what:v,cause:ee,fix:{command:y,...Array.isArray(g.alternatives)&&g.alternatives.every(e=>typeof e==`string`)?{alternatives:g.alternatives}:{},...g.edit===void 0?{}:{edit:g.edit},...F(g.url)?{url:String(g.url)}:{}},retryable:te,...ne&&Number.isFinite(Date.parse(ne))?{resumeAt:ne}:{},...F(t.runId)?{runId:String(t.runId)}:{},...F(t.requestId)?{requestId:String(t.requestId)}:{},...typeof t.status==`number`?{status:t.status}:{},...e instanceof o&&e.job?{job:e.job}:{}}}function Vt(e){let t=[e.subject.node&&`node ${e.subject.node}`,e.subject.seat].filter(Boolean).join(` · `);return`✗ ${`${t?`${t}: `:``}${e.what}${e.status?` (HTTP ${e.status})`:``}`}${e.cause===e.what?``:` — ${e.cause}`}\n → run: ${e.fix.command}`+(e.fix.alternatives?.map(e=>`\n or: ${e}`).join(``)??``)+(e.resumeAt?`\n resumes ${e.resumeAt}${e.subject.seat?` on ${e.subject.seat}`:``}`:``)}function Ht(e){return Vt(Bt(e))}function I(e,t=!1){Dt();let n=Bt(e);t?k({ok:!1,error:n}):console.error(y.red(Vt(n)));let r=1;Mt.has(n.code)?r=77:Nt.has(n.code)?r=65:Pt.has(n.code)?r=64:Ft.has(n.code)?r=78:[`SEAT_LIMIT`,`RATE_LIMITED`].includes(n.code)?r=75:[`HARNESS_NOT_INSTALLED`,`MCP_UNREACHABLE`,`NETWORK_UNAVAILABLE`].includes(n.code)?r=69:n.code===`RUN_STOPPED`&&(r=130),process.exit(r)}function Ut(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=C(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 Wt(e){let t=(e.skills??[]).map(Ut),n=(e.tools??[]).map(Ut),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 Gt(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 qt(`https://raw.githubusercontent.com/${i[0]}/${i[1]}/${a}/${i.slice(2).join(`/`)}`)}else t=/^https?:\/\//.test(e)?await qt(e):C(e,`utf8`);let n;try{n=JSON.parse(t)}catch{throw new P(`PROFILE_INVALID`,`Profile '${e}' is invalid`,`Expected a JSON AgentProfile`,`tangle agent profile create --name my-agent --json`)}return Kt(n,e)}function Kt(e,t){let n=x.safeParse(e);if(!n.success)throw new P(`PROFILE_INVALID`,`Profile '${t}' is invalid`,n.error.issues.map(e=>`${e.path.join(`.`)||`(root)`}: ${e.message}`).join(`; `),`tangle agent profile create --name my-agent --json`);return e}async function qt(e){let t=await fetch(e);if(!t.ok)throw Error(`failed to fetch ${e} (${t.status})`);return t.text()}async function Jt(e){let t=e.profileSource?await Gt(e.profileSource):void 0,n=Wt(e);return t?n?{...t,...n,...n.resources?{resources:{...t.resources,...n.resources}}:{}}:t:n}const Yt=w.join(Se.homedir(),`.tangle`),Xt=w.join(Yt,`credentials.json`),Zt=`tangle-sandbox-cli`,Qt=new Int32Array(new SharedArrayBuffer(4)),$t=`TANGLE_ALLOW_PLAINTEXT_CREDENTIALS`;var en=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)}},tn=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 ${$t}=1 to opt into a plaintext credentials.json with mode 0600.`),this.name=`KeychainUnavailableError`}},nn=class extends Error{constructor(e){super(`Credential storage preflight failed: ${e}`),this.name=`CredentialStorageProbeError`}},rn=class extends Error{constructor(e){super(`Credential storage is busy. Wait a moment and retry.`),this.name=`CredentialsFileLockedError`,e&&(this.cause=e)}};function an(e){let t=un(e);if(t)return{value:t,source:`keychain`};let n=pn(e);return n?{value:n,source:`file`}:{source:`none`}}function on(e,t){if(dn(e,t))return hn(e),`keychain`;if(!ln())throw new tn;return mn(e,t),`file`}function sn(){let e=`credential-write-probe:${process.pid}:${ie()}`,t=ie();if(dn(e,t)){let n=un(e);if(!fn(e))throw new nn(`the OS keychain accepted a test credential but the CLI could not remove it`);if(n!==t)throw new nn(`the OS keychain accepted a test credential but the CLI could not read it back`);return`keychain`}if(!ln())throw new tn;return yn(e),`file`}function cn(e){fn(e),hn(e)}function ln(){let e=process.env[$t];if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function un(e){if(process.platform===`darwin`)try{return Ee(`security`,[`find-generic-password`,`-s`,Zt,`-a`,xn(e),`-w`],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{return}if(process.platform===`linux`)try{return Ee(`secret-tool`,[`lookup`,`service`,Zt,`account`,xn(e)],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{return}}function dn(e,t){if(process.platform===`darwin`)try{return Ee(`security`,[`add-generic-password`,`-U`,`-s`,Zt,`-a`,xn(e),`-w`,t],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}if(process.platform===`linux`)try{return Ee(`secret-tool`,[`store`,`--label=Tangle Sandbox CLI`,`service`,Zt,`account`,xn(e)],{input:t,stdio:[`pipe`,`ignore`,`ignore`]}),!0}catch{return!1}return!1}function fn(e){if(process.platform===`darwin`)try{return Ee(`security`,[`delete-generic-password`,`-s`,Zt,`-a`,xn(e)],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}if(process.platform===`linux`)try{return Ee(`secret-tool`,[`clear`,`service`,Zt,`account`,xn(e)],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}return!1}function pn(e){return _n()[e]}function mn(e,t){gn(()=>{let n=_n();n[e]=t,vn(n)})}function hn(e){return gn(()=>{let t;try{t=_n()}catch(e){if(e instanceof en)return!1;throw e}return e in t?(delete t[e],vn(t),pn(e)===void 0):!0})}function gn(e){bn();let t=Date.now()+2e3,n,r;for(;!n;)try{n=Oe(Xt,{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 rn(r);Atomics.wait(Qt,0,0,20)}try{return e()}finally{n()}}function _n(){let e;try{e=S.readFileSync(Xt,`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 en(Xt);let n={};for(let[e,r]of Object.entries(t))typeof r==`string`&&(n[e]=r);return n}catch(e){throw e instanceof en?e:new en(Xt,e instanceof Error?e:void 0)}}function vn(e){if(bn(),Object.keys(e).length===0){S.existsSync(Xt)&&S.unlinkSync(Xt);return}let t=`${Xt}.${process.pid}.tmp`;S.writeFileSync(t,`${JSON.stringify(e,null,2)}\n`,{mode:384}),S.renameSync(t,Xt)}function yn(e){let t=ie(),n=!1,r;try{if(mn(e,t),n=!0,pn(e)!==t)throw new nn(`the credentials file did not return the value just written`)}catch(e){r=e}finally{if(n)try{!hn(e)&&!r&&(r=new nn(`the credentials file accepted a test credential but the CLI could not remove it`))}catch(e){r??=e}}if(r)throw r}function bn(){if(!S.existsSync(Yt)){S.mkdirSync(Yt,{mode:448,recursive:!0});return}if(process.platform!==`win32`)try{(S.statSync(Yt).mode&511)!=448&&S.chmodSync(Yt,448)}catch{}}function xn(e){return`profile:${e}`}const Sn=w.join(Se.homedir(),`.tangle`),Cn=w.join(Sn,`credentials`),wn=w.join(Sn,`config.json`),Tn=`https://id.tangle.tools`,En=`https://solve.tangle.tools/api/solve`,L=`default`;function Dn(){return{tangleBaseUrl:process.env.TANGLE_BASE_URL,sandboxBaseUrl:process.env.SANDBOX_BASE_URL,hubUrl:process.env.TANGLE_HUB_URL}}function On(e,t){let n=Fn(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 L;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 kn(){S.existsSync(Sn)||S.mkdirSync(Sn,{mode:448,recursive:!0})}function An(e,t){kn();let n=`${e}.${process.pid}.tmp`;S.writeFileSync(n,t,{mode:384}),S.renameSync(n,e)}function jn(){try{if(S.existsSync(Cn)){let e=S.readFileSync(Cn,`utf-8`).trim();return Mn(e)?e:e.match(/api_key\s*=\s*(\S+)/)?.[1]}}catch{}}function Mn(e){return e.startsWith(`sk_`)||e.startsWith(`sk-tan-`)}function Nn(){try{S.existsSync(Cn)&&S.unlinkSync(Cn)}catch{}}function R(){return ur(lr())}function Pn(e){let t=dr(R(),e);An(wn,`${JSON.stringify(t,null,2)}\n`)}function Fn(e){return fr(e||process.env.TANGLE_PROFILE||process.env.SANDBOX_PROFILE||R().activeProfile||L)}function In(e){Pn({activeProfile:fr(e)})}function Ln(){return{token:process.env.TANGLE_LINE_TOKEN,baseUrl:process.env.TANGLE_HUB_URL}}function Rn(){return process.env.TANGLE_SANDBOX||R().currentSandbox||void 0}function zn(e){Pn({currentSandbox:e})}function Bn(){let e=R();delete e.currentSandbox,An(wn,`${JSON.stringify(e,null,2)}\n`)}function Vn(){let e=R().deviceId;if(e&&/^[A-Za-z0-9_.-]{1,64}$/.test(e))return e;let t=Se.hostname().replace(/[^A-Za-z0-9_.-]/g,`-`).replace(/^-+|-+$/g,``).slice(0,32),n=re(4).toString(`hex`),r=`${t?`${t}-`:`device-`}${n}`;return Pn({deviceId:r}),r}function Hn(e){let t=e||Rn();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 Un(){let e=R(),t=Fn(),n=new Set([L,...Object.keys(e.profiles??{})]);return e.activeProfile&&n.add(fr(e.activeProfile)),[...n].map(e=>{let n=an(e),r=e===L?jn():void 0,i=n.source===`none`?r?`legacy-file`:`none`:n.source;return{name:e,active:e===t,hasApiKey:n.source!==`none`||!!r,baseUrl:$n(void 0,e),apiKeySource:i}}).sort((e,t)=>e.name.localeCompare(t.name))}function Wn(e){let t=Fn(e);return{name:t,active:t===Fn(),baseUrl:$n(void 0,t),credentialSource:Qn(t)}}function Gn(e,t){let n=fr(e),r=R(),i=cr(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=on(n,t.apiKey),n===L&&Nn()),Pn({profiles:Object.keys(l).length>0?l:{}}),u}function Kn(e){let t=Fn(e),n={...R().profiles??{}},r=n[t];if(r){let e={...r,apiKey:void 0};e.baseUrl||e.activeTeamId||e.activeTeamName?n[t]=e:delete n[t]}Pn({profiles:n}),cn(t),t===L&&Nn()}function qn(){let e=process.env.TANGLE_API_KEY_FILE;if(e){let t=S.readFileSync(e,`utf8`).trim();if(!t.startsWith(`sk-tan-`))throw Error(`Invalid sandbox credential file`);return t}return process.env.TANGLE_API_KEY}function Jn(e,t){let n=On(`sandbox`,t);if(e)return e;let r=qn();if(r)return r;let i=an(n);if(i.value)return i.value;if(n===L||n===`sandbox`)return jn()}function Yn(e,t){return e||(process.env.TANGLE_SOLVE_API_KEY?process.env.TANGLE_SOLVE_API_KEY:an(On(`solve`,t)).value)}function Xn(e,t){let n=On(`sandbox`,t);return e?`flag`:process.env.TANGLE_API_KEY_FILE||process.env.TANGLE_API_KEY?`env`:Qn(n)}function Zn(e,t){return e?`flag`:process.env.TANGLE_SOLVE_API_KEY?`env`:an(On(`solve`,t)).source}function Qn(e){let t=an(e);return t.source===`none`?(e===L||e===`sandbox`)&&jn()?`legacy-file`:`none`:t.source}function $n(e,t){if(e)return e;let n=process.env.TANGLE_BASE_URL||process.env.SANDBOX_BASE_URL;if(n)return n;let r=Fn(t),i=R(),a=cr(r,i);return a.baseUrl?a.baseUrl:(r===L||r===`sandbox`)&&i.baseUrl?i.baseUrl:`https://sandbox.tangle.tools`}function er(e){if(e)return e.replace(/\/v1\/hub\/?$/,``)}function tr(e){return e?.trim().replace(/\/+$/,``)||void 0}function nr(e){return tr(e?.flag)??tr(er(tr(process.env.TANGLE_HUB_URL)))??tr(process.env.TANGLE_PLATFORM_URL)??tr(e?.cachedPlatformUrl?.())??Tn}function rr(e){let t=tr(e)??tr(process.env.TANGLE_SOLVE_API_URL);if(t&&t!==En)throw Error(`Solve credentials may only be sent to ${En}`);return En}function ir(e){let t=tr(e);if(t&&t!==Tn)throw Error(`Solve credentials may only be sent to ${Tn}`);return Tn}function z(e){let t=On(`sandbox`,e.profile),n=Jn(e.apiKey,t);if(!n)throw Error(`No API key found for profile '${t}'. Set TANGLE_API_KEY or run: tangle auth login${t===L?``:` --profile ${t}`}`);return{apiKey:n,baseUrl:$n(e.baseUrl,t),timeout:e.timeout??3e4,profile:t,...ar(t)}}function ar(e){let t=R(),n=cr(Fn(e),t);return{activeTeamId:n.activeTeamId,activeTeamName:n.activeTeamName}}function or(e,t){Gn(Fn(t),{activeTeamId:e.id,activeTeamName:e.name})}function sr(e){let t=Fn(e),n=R(),r={...n.profiles??{}},i={baseUrl:cr(t,n).baseUrl};i.baseUrl?r[t]=i:delete r[t],Pn({profiles:r})}function cr(e,t=R()){let n=fr(e);return{...n===L?{baseUrl:t.baseUrl,activeTeamId:t.profiles?.[L]?.activeTeamId,activeTeamName:t.profiles?.[L]?.activeTeamName}:{},...t.profiles?.[n]??{}}}function lr(){try{if(S.existsSync(wn)){let e=S.readFileSync(wn,`utf-8`);return JSON.parse(e)}}catch{}return{}}function ur(e){let t=!1,n={};e.apiKey&&(on(L,e.apiKey),Nn(),t=!0);for(let[r,i]of Object.entries(e.profiles??{})){i.apiKey&&(on(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(wn,`${JSON.stringify(r,null,2)}\n`),r}function dr(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 fr(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 pr=null,mr=null;function B(e){if(e)return pr&&mr&&mr.apiKey===e.apiKey&&mr.baseUrl===e.baseUrl&&mr.timeout===e.timeout?pr:(pr=new c({apiKey:e.apiKey,baseUrl:e.baseUrl,timeoutMs:e.timeout}),mr=e,pr);if(pr)return pr;let t=z({});return pr=new c({apiKey:t.apiKey,baseUrl:t.baseUrl,timeoutMs:t.timeout}),mr=t,pr}function hr(){pr=null,mr=null}async function gr(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 _r(r,n)}function _r(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(vr(t,s))}function vr(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{ALL_BACKEND_TYPES as t,AuthError as n,GPU_LEASE_PROVIDER_NAMES as r,NetworkError as i,NotFoundError as a,PublicTemplatePublishError as o,QuotaError as s,Sandbox as c,SandboxError as l,ServerError as u,StateError as d,TimeoutError as f,ValidationError as p,createAgentRunOutcomeTracker as m,createBatchResultAccumulator as h,createConfidentialSandbox as g,generateAttestationNonce as _,parseBackendType as v,parseSSEStream as ee,validateBatchRunRequest as y}from"@tangle-network/sandbox";import b from"chalk";import te from"ora";import{Command as x}from"commander";import{createHash as ne,randomBytes as re,randomUUID as S}from"node:crypto";import{agentInteractiveSessionRunRef as C,agentProfileSchema as ie,canonicalAgentProfileDigest as ae,modelProvider as oe,parseSeatSpec as se}from"@tangle-network/agent-interface";import*as w from"node:fs";import{chmodSync as ce,constants as le,existsSync as ue,mkdirSync as de,readFileSync as T,renameSync as fe,writeFileSync as pe}from"node:fs";import*as E from"node:path";import{basename as me,dirname as he,extname as ge,isAbsolute as _e,join as D,relative as ve,resolve as ye,sep as be}from"node:path";import*as xe from"node:os";import{homedir as Se,tmpdir as Ce}from"node:os";import{execFile as we,execFileSync as Te,spawn as Ee}from"node:child_process";import{lockSync as De}from"proper-lockfile";import{HubClient as Oe}from"@tangle-network/hub-sdk";import{createInterface as ke}from"node:readline";import{Writable as Ae}from"node:stream";import{buffer as je}from"node:stream/consumers";import{CONTENT_COMPLETION_KEY as Me,CONTENT_PROMPT_KEY as Ne,CONTENT_TOOL_ARGS_KEY as Pe,CONTENT_TOOL_NAME_KEY as Fe,CONTENT_TOOL_RESULT_KEY as Ie,TANGLE_SUBJECT_KEY as Le,asContentField as O,asContentString as Re}from"@tangle-network/agent-core/telemetry";import*as k from"node:fs/promises";import{mkdir as ze,open as Be,readFile as Ve,realpath as He}from"node:fs/promises";import{shellQuote as Ue,spawnCliProcess as We}from"@tangle-network/sdk-cli-runner";import{listLocalModels as Ge,loadConfig as Ke}from"cli-bridge";import{setImmediate as qe}from"node:timers/promises";import{promisify as Je,stripVTControlCharacters as Ye}from"node:util";import{cliAuthReferenceSchema as Xe}from"@tangle-network/sandbox/auth";import{createMcpServer as Ze}from"@tangle-network/sandbox/agent";import{ensureAgentPreview as Qe,publishAgentPreview as $e,resolveSelfSandbox as et}from"@tangle-network/sandbox/preview";import{fileURLToPath as tt}from"node:url";import{generatePrivateKey as nt,privateKeyToAccount as rt}from"viem/accounts";import{createPublicClient as it,createWalletClient as at,decodeAbiParameters as ot,decodeEventLog as st,encodeAbiParameters as ct,getAddress as lt,http as ut,isAddress as dt,keccak256 as ft,parseAbi as pt,parseAbiItem as mt,parseAbiParameters as ht,stringToHex as gt,toHex as _t}from"viem";import{tempoModerato as vt}from"viem/chains";import{Actions as yt,withRelay as bt}from"viem/tempo";import xt from"ws";import{createIntelligenceClient as St}from"@tangle-network/sandbox/intelligence";let Ct=!1;function wt(e){Ct=e}function Tt(...e){Ct?console.error(...e):console.log(...e)}function Et(e){return e==null?b.dim(`-`):typeof e==`boolean`?e?b.green(`yes`):b.red(`no`):e instanceof Date?Ot(e):typeof e==`string`&&Dt(e)?Ot(new Date(e)):String(e)}function Dt(e){return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)}function Ot(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 kt(e){switch(e){case`running`:return b.green(e);case`pending`:case`provisioning`:return b.yellow(e);case`stopped`:return b.gray(e);case`failed`:case`deleted`:return b.red(e);default:return e}}function A(e,t){if(e.length===0){console.log(b.dim(`No items found.`));return}let n=t.map(t=>{let n=t.header.length,r=Math.max(...e.map(e=>Et(e[t.key]).length));return t.width??Math.max(n,r)+2}),r=t.map((e,t)=>b.bold(e.header.padEnd(n[t]))).join(``);console.log(r);for(let r of e){let e=t.map((e,t)=>{let i=Et(r[e.key]);return e.key===`status`&&(i=kt(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){Tt(b.green(`✓`),e)}function At(e){console.error(b.red(`✗`),e)}function jt(e){Tt(b.yellow(`!`),e)}function N(e){Tt(b.blue(`→`),e)}const Mt=new Set;function P(e){let t=te({text:e,color:`cyan`,isSilent:Ct});return Mt.add(t),t}function Nt(){for(let e of Mt)e.isSpinning&&e.stop();Mt.clear()}function F(e,t=0){let n=` `.repeat(t);for(let[t,r]of Object.entries(e))r!=null&&console.log(`${n}${b.dim(`${t}:`)} ${Et(r)}`)}function Pt(e){let t=`${e.cpuCores} vCPU / ${e.memoryMB} MB / ${e.diskGB} GB`;return e.pool?`${t} (pool: ${e.pool})`:t}function Ft(e){if(console.log(),console.log(b.bold(`Sandbox Details`)),console.log(b.dim(`─`.repeat(40))),F({ID:e.id,Name:e.name,Status:kt(e.status),Resources:e.resources?Pt(e.resources):void 0,Created:e.createdAt,Expires:e.expiresAt}),e.connection){if(console.log(),console.log(b.bold(`Connection`)),console.log(b.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}`;F({SSH:process.platform===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN='<token>'; ${r}`:`TANGLE_SSH_PROXY_AUTH_TOKEN='<token>' ${r}`})}e.connection.webTerminalUrl&&F({"Web Terminal":e.connection.webTerminalUrl}),e.connection.runtimeUrl&&F({"API URL":e.connection.runtimeUrl})}console.log()}function It(e){j(e)}function Lt(e,t){if(t.length===0){console.log(b.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)=>b.bold(e.padEnd(n[t]))).join(``));for(let e of t)console.log(e.map((e,t)=>String(e??``).padEnd(n[t])).join(``))}var I=class extends Error{constructor(e,t,n,r){super(t),this.code=e,this.cause=n,this.fix=r,this.name=`ActionableCliError`}};const Rt=new Set([`AUTH_EXPIRED`,`AUTH_WRONG_AUDIENCE`,`SEAT_NONE_DETECTED`,`SEAT_NOT_LOGGED_IN`,`SEAT_NOT_ENROLLED`,`HUB_NOT_CONNECTED`,`HUB_RECONNECT`,`HUB_APP_NOT_INSTALLED`,`HUB_APPROVAL_REQUIRED`]),zt=new Set([`GRAPH_INVALID`,`STEP_REF`,`PROFILE_INVALID`,`UNKNOWN_HARNESS`,`HUB_TOOL_UNKNOWN`,`TRIGGER_INVALID`,`WORKFLOW_INPUT_FILE_INVALID`,`VALIDATION_ERROR`]),Bt=new Set([`UNKNOWN_COMMAND`,`GRAPH_PARAM_MISSING`,`GRAPH_PARAM_UNKNOWN`,`SEAT_SYNTAX`,`HUB_PROVIDER_UNKNOWN`,`USAGE_INVALID`]),Vt=new Set([`SUBSCRIPTION_REQUIRED`,`MODEL_NOT_FOUND`,`MODEL_PROVIDER_MISMATCH`,`MCP_BLOCKED`,`CLOUD_SEAT_UNSUPPORTED`,`SCHEDULE_AUTHORITY`]);function Ht(e){return typeof e==`object`&&e?e:{}}function L(e){return typeof e==`string`&&e.length>0?e:void 0}function Ut(e){let t=L(e);return t&&/^[a-z0-9][a-z0-9_-]*$/i.test(t)?t:void 0}function Wt(e){let t,n=e;for(let e=0;n instanceof Error&&e<5;e++,n=n.cause){let e=n.message||(n instanceof AggregateError?n.errors.map(e=>e instanceof Error?e.message:String(e)).join(`; `):``),r=L(Ht(n).code);(e||r)&&(t=r?`${r}${e?`: ${e}`:``}`:e)}return t}function Gt(e){return e.code===`credential-refused`&&e.owner===`caller`&&e.providerCode===`subscription_required`?Ht(e.remediation):{}}function Kt(e){let t=Ht(e),r=Array.isArray(t.runtimeFailures)?t.runtimeFailures.map(Ht):[],c=r.find(e=>L(Gt(Ht(e.failure)).fix))??r[0],l=Ht(c?.failure??t.runtimeFailure),u=Gt(l),m=Ht(t.details),h=Ut(t.provider??m.provider??m.providerId),g=Ht(t.fix??m.fix),_=L(t.code)??`CLI_ERROR`,v=L(t.message)??String(e),ee=L(l.cause)??L(t.cause)??L(m.reason)??v,y=`tangle --help`,b=typeof m.providerRetryable==`boolean`?m.providerRetryable:typeof t.retryable==`boolean`?t.retryable:null;if(e instanceof n||_===`HUB_UNAUTHENTICATED`||t.status===401)_=`AUTH_EXPIRED`,v=`Authentication failed`,y=`tangle auth login`;else if([`HUB_CONNECTION_MISSING`,`HUB_CONNECTION_REVOKED`,`HUB_CONNECTION_UNHEALTHY`,`HUB_RECONNECT_REQUIRED`,`CONNECTION_REQUIRED`].includes(_))_=[`HUB_CONNECTION_MISSING`,`CONNECTION_REQUIRED`].includes(_)?`HUB_NOT_CONNECTED`:`HUB_RECONNECT`,y=h?`tangle hub connect ${h}`:`tangle hub connections --json`;else if(_===`HUB_APPROVAL_REQUIRED`){let e=Ut(Ht(m.approval).id);y=e?`tangle hub approvals approve ${e}`:`tangle hub approvals list --json`}else _===`HUB_PROVIDER_REJECTED`?(y=`tangle hub status --json`,m.providerRetryable===!1&&(ee+=`. Change the request before retrying`)):_===`provider_quota_exhausted`||_===`SEAT_LIMIT`?(_=`SEAT_LIMIT`,y=`tangle auth status`,b=!0):e instanceof s?y=`tangle usage --json`:e instanceof i?(_=`NETWORK_UNAVAILABLE`,v=`Network error: ${v}`,ee=Wt(e.cause)??`No response arrived`,y=`tangle auth status --json`,b=!0):e instanceof f?(_=`TIMEOUT`,y=`tangle sandbox list --json`,b=!0):e instanceof p?(_=`VALIDATION_ERROR`,v=`Invalid input`):e instanceof a||e instanceof d?y=`tangle sandbox list --json`:_===`commander.unknownCommand`?(_=`UNKNOWN_COMMAND`,y=v.includes(`'graph'`)?`npm install -g @tangle-network/sandbox-cli@latest`:`tangle --help`):_.startsWith(`commander.`)?_=`USAGE_INVALID`:(_===`ENOENT`||_===`EACCES`)&&(_=`INPUT_UNAVAILABLE`);e instanceof I&&(y=e.fix,b=!1),L(u.fix)&&(_=u.cause===`not_authenticated`?`SEAT_NOT_LOGGED_IN`:`SUBSCRIPTION_REQUIRED`),e instanceof o&&y===`tangle --help`&&(y=`tangle template publish --help`),y=L(u.fix)??L(g.command)??(_===`HUB_NOT_CONNECTED`?void 0:L(t.fixCommand))??y,Rt.has(_)&&y===`tangle --help`&&(y=`tangle auth login`);let te=Ht(t.subject??m.subject??{node:c?.node??t.node,seat:t.seat??u.harness}),x=L(t.resumeAt??m.resumeAt??m.resetAt);return{code:_,subject:{...L(te.node)?{node:String(te.node)}:{},...L(te.seat)?{seat:String(te.seat)}:{}},what:v,cause:ee,fix:{command:y,...Array.isArray(g.alternatives)&&g.alternatives.every(e=>typeof e==`string`)?{alternatives:g.alternatives}:{},...g.edit===void 0?{}:{edit:g.edit},...L(g.url)?{url:String(g.url)}:{}},retryable:b,...x&&Number.isFinite(Date.parse(x))?{resumeAt:x}:{},...L(t.runId)?{runId:String(t.runId)}:{},...L(t.requestId)?{requestId:String(t.requestId)}:{},...typeof t.status==`number`?{status:t.status}:{},...e instanceof o&&e.job?{job:e.job}:{}}}function qt(e){let t=[e.subject.node&&`node ${e.subject.node}`,e.subject.seat].filter(Boolean).join(` · `);return`✗ ${`${t?`${t}: `:``}${e.what}${e.status?` (HTTP ${e.status})`:``}`}${e.cause===e.what?``:` — ${e.cause}`}\n → run: ${e.fix.command}`+(e.fix.alternatives?.map(e=>`\n or: ${e}`).join(``)??``)+(e.resumeAt?`\n resumes ${e.resumeAt}${e.subject.seat?` on ${e.subject.seat}`:``}`:``)}function Jt(e){return qt(Kt(e))}function R(e,t=!1){Nt();let n=Kt(e);t?j({ok:!1,error:n}):console.error(b.red(qt(n)));let r=1;Rt.has(n.code)?r=77:zt.has(n.code)?r=65:Bt.has(n.code)?r=64:Vt.has(n.code)?r=78:[`SEAT_LIMIT`,`RATE_LIMITED`].includes(n.code)?r=75:[`HARNESS_NOT_INSTALLED`,`MCP_UNREACHABLE`,`NETWORK_UNAVAILABLE`].includes(n.code)?r=69:n.code===`RUN_STOPPED`&&(r=130),process.exit(r)}function Yt(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:me(a)}}let t;try{t=T(e,`utf8`)}catch{throw Error(`cannot read skill/tool "${e}": not a readable file and not a github: ref`)}return{kind:`inline`,name:me(e),content:t}}function Xt(e){let t=(e.skills??[]).map(Yt),n=(e.tools??[]).map(Yt),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 Zt(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 $t(`https://raw.githubusercontent.com/${i[0]}/${i[1]}/${a}/${i.slice(2).join(`/`)}`)}else t=/^https?:\/\//.test(e)?await $t(e):T(e,`utf8`);let n;try{n=JSON.parse(t)}catch{throw new I(`PROFILE_INVALID`,`Profile '${e}' is invalid`,`Expected a JSON AgentProfile`,`tangle agent profile create --name my-agent --json`)}return Qt(n,e)}function Qt(e,t){let n=ie.safeParse(e);if(!n.success)throw new I(`PROFILE_INVALID`,`Profile '${t}' is invalid`,n.error.issues.map(e=>`${e.path.join(`.`)||`(root)`}: ${e.message}`).join(`; `),`tangle agent profile create --name my-agent --json`);return e}async function $t(e){let t=await fetch(e);if(!t.ok)throw Error(`failed to fetch ${e} (${t.status})`);return t.text()}async function en(e){let t=e.profileSource?await Zt(e.profileSource):void 0,n=Xt(e);return t?n?{...t,...n,...n.resources?{resources:{...t.resources,...n.resources}}:{}}:t:n}const tn=E.join(xe.homedir(),`.tangle`),nn=E.join(tn,`credentials.json`),rn=`tangle-sandbox-cli`,an=new Int32Array(new SharedArrayBuffer(4)),on=`TANGLE_ALLOW_PLAINTEXT_CREDENTIALS`;var sn=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)}},cn=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 ${on}=1 to opt into a plaintext credentials.json with mode 0600.`),this.name=`KeychainUnavailableError`}},ln=class extends Error{constructor(e){super(`Credential storage preflight failed: ${e}`),this.name=`CredentialStorageProbeError`}},un=class extends Error{constructor(e){super(`Credential storage is busy. Wait a moment and retry.`),this.name=`CredentialsFileLockedError`,e&&(this.cause=e)}};function dn(e){let t=gn(e);if(t)return{value:t,source:`keychain`};let n=yn(e);return n?{value:n,source:`file`}:{source:`none`}}function fn(e,t){if(_n(e,t))return xn(e),`keychain`;if(!hn())throw new cn;return bn(e,t),`file`}function pn(){let e=`credential-write-probe:${process.pid}:${S()}`,t=S();if(_n(e,t)){let n=gn(e);if(!vn(e))throw new ln(`the OS keychain accepted a test credential but the CLI could not remove it`);if(n!==t)throw new ln(`the OS keychain accepted a test credential but the CLI could not read it back`);return`keychain`}if(!hn())throw new cn;return Tn(e),`file`}function mn(e){vn(e),xn(e)}function hn(){let e=process.env[on];if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function gn(e){if(process.platform===`darwin`)try{return Te(`security`,[`find-generic-password`,`-s`,rn,`-a`,Dn(e),`-w`],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{return}if(process.platform===`linux`)try{return Te(`secret-tool`,[`lookup`,`service`,rn,`account`,Dn(e)],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{return}}function _n(e,t){if(process.platform===`darwin`)try{return Te(`security`,[`add-generic-password`,`-U`,`-s`,rn,`-a`,Dn(e),`-w`,t],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}if(process.platform===`linux`)try{return Te(`secret-tool`,[`store`,`--label=Tangle Sandbox CLI`,`service`,rn,`account`,Dn(e)],{input:t,stdio:[`pipe`,`ignore`,`ignore`]}),!0}catch{return!1}return!1}function vn(e){if(process.platform===`darwin`)try{return Te(`security`,[`delete-generic-password`,`-s`,rn,`-a`,Dn(e)],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}if(process.platform===`linux`)try{return Te(`secret-tool`,[`clear`,`service`,rn,`account`,Dn(e)],{stdio:[`ignore`,`ignore`,`ignore`]}),!0}catch{return!1}return!1}function yn(e){return Cn()[e]}function bn(e,t){Sn(()=>{let n=Cn();n[e]=t,wn(n)})}function xn(e){return Sn(()=>{let t;try{t=Cn()}catch(e){if(e instanceof sn)return!1;throw e}return e in t?(delete t[e],wn(t),yn(e)===void 0):!0})}function Sn(e){En();let t=Date.now()+2e3,n,r;for(;!n;)try{n=De(nn,{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 un(r);Atomics.wait(an,0,0,20)}try{return e()}finally{n()}}function Cn(){let e;try{e=w.readFileSync(nn,`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 sn(nn);let n={};for(let[e,r]of Object.entries(t))typeof r==`string`&&(n[e]=r);return n}catch(e){throw e instanceof sn?e:new sn(nn,e instanceof Error?e:void 0)}}function wn(e){if(En(),Object.keys(e).length===0){w.existsSync(nn)&&w.unlinkSync(nn);return}let t=`${nn}.${process.pid}.tmp`;w.writeFileSync(t,`${JSON.stringify(e,null,2)}\n`,{mode:384}),w.renameSync(t,nn)}function Tn(e){let t=S(),n=!1,r;try{if(bn(e,t),n=!0,yn(e)!==t)throw new ln(`the credentials file did not return the value just written`)}catch(e){r=e}finally{if(n)try{!xn(e)&&!r&&(r=new ln(`the credentials file accepted a test credential but the CLI could not remove it`))}catch(e){r??=e}}if(r)throw r}function En(){if(!w.existsSync(tn)){w.mkdirSync(tn,{mode:448,recursive:!0});return}if(process.platform!==`win32`)try{(w.statSync(tn).mode&511)!=448&&w.chmodSync(tn,448)}catch{}}function Dn(e){return`profile:${e}`}const On=E.join(xe.homedir(),`.tangle`),kn=E.join(On,`credentials`),An=E.join(On,`config.json`),jn=`https://id.tangle.tools`,Mn=`https://solve.tangle.tools/api/solve`,z=`default`;function Nn(){return{tangleBaseUrl:process.env.TANGLE_BASE_URL,sandboxBaseUrl:process.env.SANDBOX_BASE_URL,hubUrl:process.env.TANGLE_HUB_URL}}function Pn(e,t){let n=Vn(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 z;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 Fn(){w.existsSync(On)||w.mkdirSync(On,{mode:448,recursive:!0})}function In(e,t){Fn();let n=`${e}.${process.pid}.tmp`;w.writeFileSync(n,t,{mode:384}),w.renameSync(n,e)}function Ln(){try{if(w.existsSync(kn)){let e=w.readFileSync(kn,`utf-8`).trim();return Rn(e)?e:e.match(/api_key\s*=\s*(\S+)/)?.[1]}}catch{}}function Rn(e){return e.startsWith(`sk_`)||e.startsWith(`sk-tan-`)}function zn(){try{w.existsSync(kn)&&w.unlinkSync(kn)}catch{}}function B(){return gr(hr())}function Bn(e){let t=_r(B(),e);In(An,`${JSON.stringify(t,null,2)}\n`)}function Vn(e){return vr(e||process.env.TANGLE_PROFILE||process.env.SANDBOX_PROFILE||B().activeProfile||z)}function Hn(e){Bn({activeProfile:vr(e)})}function Un(){return{token:process.env.TANGLE_LINE_TOKEN,baseUrl:process.env.TANGLE_HUB_URL}}function Wn(){return process.env.TANGLE_SANDBOX||B().currentSandbox||void 0}function Gn(e){Bn({currentSandbox:e})}function Kn(){let e=B();delete e.currentSandbox,In(An,`${JSON.stringify(e,null,2)}\n`)}function qn(){let e=B().deviceId;if(e&&/^[A-Za-z0-9_.-]{1,64}$/.test(e))return e;let t=xe.hostname().replace(/[^A-Za-z0-9_.-]/g,`-`).replace(/^-+|-+$/g,``).slice(0,32),n=re(4).toString(`hex`),r=`${t?`${t}-`:`device-`}${n}`;return Bn({deviceId:r}),r}function Jn(e){let t=e||Wn();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 Yn(){let e=B(),t=Vn(),n=new Set([z,...Object.keys(e.profiles??{})]);return e.activeProfile&&n.add(vr(e.activeProfile)),[...n].map(e=>{let n=dn(e),r=e===z?Ln():void 0,i=n.source===`none`?r?`legacy-file`:`none`:n.source;return{name:e,active:e===t,hasApiKey:n.source!==`none`||!!r,baseUrl:ar(void 0,e),apiKeySource:i}}).sort((e,t)=>e.name.localeCompare(t.name))}function Xn(e){let t=Vn(e);return{name:t,active:t===Vn(),baseUrl:ar(void 0,t),credentialSource:ir(t)}}function Zn(e,t){let n=vr(e),r=B(),i=mr(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=fn(n,t.apiKey),n===z&&zn()),Bn({profiles:Object.keys(l).length>0?l:{}}),u}function Qn(e){let t=Vn(e),n={...B().profiles??{}},r=n[t];if(r){let e={...r,apiKey:void 0};e.baseUrl||e.activeTeamId||e.activeTeamName?n[t]=e:delete n[t]}Bn({profiles:n}),mn(t),t===z&&zn()}function $n(){let e=process.env.TANGLE_API_KEY_FILE;if(e){let t=w.readFileSync(e,`utf8`).trim();if(!t.startsWith(`sk-tan-`))throw Error(`Invalid sandbox credential file`);return t}return process.env.TANGLE_API_KEY}function er(e,t){let n=Pn(`sandbox`,t);if(e)return e;let r=$n();if(r)return r;let i=dn(n);if(i.value)return i.value;if(n===z||n===`sandbox`)return Ln()}function tr(e,t){return e||(process.env.TANGLE_SOLVE_API_KEY?process.env.TANGLE_SOLVE_API_KEY:dn(Pn(`solve`,t)).value)}function nr(e,t){let n=Pn(`sandbox`,t);return e?`flag`:process.env.TANGLE_API_KEY_FILE||process.env.TANGLE_API_KEY?`env`:ir(n)}function rr(e,t){return e?`flag`:process.env.TANGLE_SOLVE_API_KEY?`env`:dn(Pn(`solve`,t)).source}function ir(e){let t=dn(e);return t.source===`none`?(e===z||e===`sandbox`)&&Ln()?`legacy-file`:`none`:t.source}function ar(e,t){if(e)return e;let n=process.env.TANGLE_BASE_URL||process.env.SANDBOX_BASE_URL;if(n)return n;let r=Vn(t),i=B(),a=mr(r,i);return a.baseUrl?a.baseUrl:(r===z||r===`sandbox`)&&i.baseUrl?i.baseUrl:`https://sandbox.tangle.tools`}function or(e){if(e)return e.replace(/\/v1\/hub\/?$/,``)}function sr(e){return e?.trim().replace(/\/+$/,``)||void 0}function cr(e){return sr(e?.flag)??sr(or(sr(process.env.TANGLE_HUB_URL)))??sr(process.env.TANGLE_PLATFORM_URL)??sr(e?.cachedPlatformUrl?.())??jn}function lr(e){let t=sr(e)??sr(process.env.TANGLE_SOLVE_API_URL);if(t&&t!==Mn)throw Error(`Solve credentials may only be sent to ${Mn}`);return Mn}function ur(e){let t=sr(e);if(t&&t!==jn)throw Error(`Solve credentials may only be sent to ${jn}`);return jn}function V(e){let t=Pn(`sandbox`,e.profile),n=er(e.apiKey,t);if(!n)throw Error(`No API key found for profile '${t}'. Set TANGLE_API_KEY or run: tangle auth login${t===z?``:` --profile ${t}`}`);return{apiKey:n,baseUrl:ar(e.baseUrl,t),timeout:e.timeout??3e4,profile:t,...dr(t)}}function dr(e){let t=B(),n=mr(Vn(e),t);return{activeTeamId:n.activeTeamId,activeTeamName:n.activeTeamName}}function fr(e,t){Zn(Vn(t),{activeTeamId:e.id,activeTeamName:e.name})}function pr(e){let t=Vn(e),n=B(),r={...n.profiles??{}},i={baseUrl:mr(t,n).baseUrl};i.baseUrl?r[t]=i:delete r[t],Bn({profiles:r})}function mr(e,t=B()){let n=vr(e);return{...n===z?{baseUrl:t.baseUrl,activeTeamId:t.profiles?.[z]?.activeTeamId,activeTeamName:t.profiles?.[z]?.activeTeamName}:{},...t.profiles?.[n]??{}}}function hr(){try{if(w.existsSync(An)){let e=w.readFileSync(An,`utf-8`);return JSON.parse(e)}}catch{}return{}}function gr(e){let t=!1,n={};e.apiKey&&(fn(z,e.apiKey),zn(),t=!0);for(let[r,i]of Object.entries(e.profiles??{})){i.apiKey&&(fn(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&&In(An,`${JSON.stringify(r,null,2)}\n`),r}function _r(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 vr(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 yr=null,br=null;function H(e){if(!e&&yr)return yr;let t=e??V({});return(!yr||!br||br.apiKey!==t.apiKey||br.baseUrl!==t.baseUrl||br.timeout!==t.timeout)&&(yr=new c({apiKey:t.apiKey,baseUrl:t.baseUrl,timeoutMs:t.timeout}),br=t),yr}function xr(){yr=null,br=null}function U(e){let t=V({apiKey:e.apiKey,baseUrl:e.baseUrl});return{context:t,client:H(t)}}async function Sr(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 Cr(r,n)}function Cr(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(wr(t,s))}function wr(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
|
|
4
|
-
`)}`}function
|
|
3
|
+
`+n}function Tr(e,t){return[...t,e]}async function Er(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:`${Cr(r,e.ref)}:${e.tail}`)}function Dr(e){let t=new Map,n=[];for(let r of e){let e=r.trim(),i=e.indexOf(`:`);if(i===-1)throw Error(`Invalid --connection "${r}": expected <connectionId>:<capability>[,<capability>]. List connection ids with \`tangle hub connections\` and capability paths with \`tangle hub tools search <keyword>\`.`);let a=e.slice(0,i).trim();if(a.length===0)throw Error(`Invalid --connection "${r}": connection id is empty. Use <connectionId>:<capability> — list ids with \`tangle hub connections\`.`);let o=e.slice(i+1).split(`,`).map(e=>e.trim()).filter(e=>e.length>0);if(o.length===0)throw Error(`Invalid --connection "${r}": grant at least one capability, e.g. ${a}:gmail.messages.list. Discover paths with \`tangle hub tools search <keyword>\`.`);if(o.includes(`*`)&&o.length>1)throw Error(`Invalid --connection "${r}": "*" grants all capabilities and can't be combined with specific paths. Use <connectionId>:* alone, or list explicit paths.`);if(a===`*`&&!(o.length===1&&o[0]===`*`))throw Error(`Invalid --connection "${r}": a "*" connection is only valid as "*:*" (all connections, all capabilities). Name a connection id for specific paths.`);let s=t.get(a);s===void 0&&(s=new Set,t.set(a,s),n.push(a));for(let e of o)s.add(e)}return n.map(e=>{let n=t.get(e),r=n?[...n]:[];if(r.includes(`*`)&&r.length>1)throw Error(`Invalid --connection for "${e}": "*" can't be combined with specific capability paths across repeated --connection flags.`);return{connectionId:e,capabilities:r}})}function Or(e,t){return ne(`sha256`).update(`${e}\0${t}`).digest(`hex`).slice(0,32)}function kr(e){return`${e}:hub`}function Ar(e){let{value:t}=dn(kr(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 jr(e,t){try{fn(kr(e),JSON.stringify(t))}catch{}}async function Mr(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 Nr=class{cache;fingerprint;constructor(e,t,n,r){this.profile=e,this.sandboxBaseUrl=t,this.sessionToken=n,this.deviceId=r,this.fingerprint=Or(t,n);let i=Ar(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 Mr(this.sandboxBaseUrl,this.sessionToken,this.deviceId),sessionFingerprint:this.fingerprint};return this.cache=t,jr(this.profile,t),t}};function Pr(e){if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function Fr(e,t){return cr({flag:e.baseUrl,...e.useCachedPlatformUrl?{cachedPlatformUrl:()=>Ar(t)?.platformUrl}:{}})}function Ir(e,t){let n=Pn(`sandbox`,e.profile),r=er(e.apiKey,n),i=nr(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:Fr(e,n)};if(i===`env`&&r)return{kind:`static`,apiKey:a??r,baseUrl:Fr(e,n)};if(a)return{kind:`static`,apiKey:a,baseUrl:Fr(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:Fr(e,n)}:{kind:`managed`,profile:n,sandboxBaseUrl:ar(e.sandboxBaseUrl,n),sessionToken:r,deviceId:qn(),baseUrlOverride:e.baseUrl}}async function Lr(e={}){let t=Ir(e,e.hubKey===!1||Pr(process.env.TANGLE_SKIP_HUB_KEY));if(t.kind===`static`)return{token:t.apiKey,baseUrl:t.baseUrl,minted:!1};let n=new Nr(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 Rr(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 zr(e={}){let t;try{t=await Lr(e)}catch(e){return{reachable:!1,reason:e instanceof Error?e.message:String(e),refused:!0}}try{let e=await Rr(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 Br(e){let t=Ir(e,e.hubKey===!1||Pr(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 Oe({baseUrl:t.baseUrl,authHeaders:()=>({Authorization:`Bearer ${$n()}`})}):new Oe({baseUrl:t.baseUrl,apiKey:t.apiKey});let n=new Nr(t.profile,t.sandboxBaseUrl,t.sessionToken,t.deviceId),r=await n.ensure();return new Oe({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 Vr(e={}){return Br(e)}function W(e={}){return Br({...e,useCachedPlatformUrl:!0,allowHubCapabilityToken:!0})}function Hr(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 Ur(e){return e.activeTeamId?`team:${e.activeTeamId}`:void 0}async function G(e,t,n,r={}){if(!r.nameOnly){let t=await e.get(n);if(t)return t;if(Gr(n))throw Error(`Sandbox not found: ${n}`)}let i=(await e.list({scope:Ur(t)})).filter(e=>e.name?.toLowerCase()===n.toLowerCase());if(i.length===0)throw Error(`Sandbox not found: ${n}`);if(i.length>1)throw Error(Hr(n,i));return i[0]}const Wr=/^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 Gr(e){return Wr.test(e)}async function Kr(e,t,n,r={}){try{return(await(await G(e,t,n,{nameOnly:r.name})).delete()).outcome}catch(e){if(!(e instanceof Error&&e.message===`Sandbox not found: ${n}`)||r.name||!r.retryCleanup&&!Gr(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 K(e,t){if(e.status!==`stopped`)return e;let n=t?.resumeTimeoutMs??12e4;N(`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 qr=[`anthropic`,`openai`,`vercel-ai`,`mastra`,`mcp-local`,`claude-desktop`,`cursor`,`zed`];function Jr(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,31 @@ await connect(new StdioServerTransport());`;case`claude-desktop`:return`// Add t
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
-
}`}}function
|
|
125
|
-
`)
|
|
126
|
-
`),Error(t?`No answer on stdin. Pass ${t} to skip the confirmation.`:`No answer on stdin.`);return r===`y`||r===`yes`}async function Jr(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 Yr(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 Xr(){let e=new b(`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`).action(async(e,t)=>{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 Jr(`Profile name`,`my-agent`),r=await Jr(`Description (optional)`)||void 0,i=await Jr(`Harness`,`claude-code`)||void 0,a=await Jr(`Model (optional, provider/model)`)||void 0,o=await Jr(`System prompt (optional)`)||void 0,s=await Zr(`Skill ref (local path or github:..., blank to finish)`),c=await Zr(`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=Wt({model:a,systemPrompt:o,skills:s,tools:c}),u=Kt({...n?{name:n}:{},...r?{description:r}:{},...l??{},...i?{harness:i}:{}},`new profile`);if(t.json){k(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}`:``}`)}),e.command(`show <source>`).description(`Load and print a profile (local path, https URL, or github:owner/repo/path[@ref])`).action(async e=>{try{k(await Gt(e))}catch(e){I(e,!0)}}),e.command(`validate <source>`).description(`Validate a profile against the canonical AgentProfile schema`).action(async(e,t)=>{let n=await Gt(e),r=typeof n.name==`string`?n.name:`(unnamed)`;t.json?k({ok:!0,name:r}):j(`Profile valid: "${r}"`)}),e}async function Zr(e){let t=[];for(;;){let n=await Jr(e);if(!n)break;t.push(n)}return t}function Qr(e){return([process.env.SANDBOX_WEB_URL,process.env.TANGLE_SANDBOX_WEB_URL].map(e=>e?.trim()).find(e=>!!e)??e).replace(/\/+$/,``)}function $r(e,t){if(process.exitCode=1,e.status===`blocked_on_approval`){console.error(y.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(y.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(y.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(y.yellow(`⚠ Agent is awaiting a plan decision.`)),console.error(`Approve or reject the pending plan before continuing.`);return}console.error(y.red(`✗ ${e.error&&e.error.length>0?e.error:t}`))}function ei(e){let t=e.part;if(t?.type===`text`)return t.text??t.content??void 0}function ti(e){return e.finalText??e.response??e.output??e.content??e.text??void 0}function ni(e){if(!e.result.success){$r(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(y.green(`✓ Done`),y.dim(`(${r.join(`, `)})`))}async function ri(e,t,n=!0){let r=``,i,a=p(),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=ei(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=ti(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 ii(e){let t=xr(e??[]);if(t.length!==0)return{profile:{connections:t}}}function ai(e,t,n,r,i,a){let o={...r??{},harness:n,...i?{model:{...r?.model??{},default:i}}:{}},s={profile:o,requestedProfileDigest:oe(o),initialPrompt:a};return{...s,run:ae({provider:`tangle-sandbox`,environmentId:e,sessionId:t,executionId:`interactive-execution-${t}`},s)}}async function oi(e){let t=xr(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 H({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 si(e){!e.connection||e.connection.length===0||(e.connection=await br(e.connection,()=>H({hubKey:e.hubKey})))}async function ci(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 li(){let e=new b(`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>`.",yr,[]).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`).action(async(e,t,n)=>{let r=t===void 0?e:t,i=t===void 0?Hn(n.box):e,a=V(n),o=B(a),s=await Jt({profileSource:n.profile,systemPrompt:n.systemPrompt,skills:n.skills,tools:n.tools});await si(n);let c=ii(n.connection);n.allowWrites&&await oi(n);let l=s||c?{...s,...c?.profile}:void 0,u=n.harness,d=l||u||n.model?{...u?{type:u}:{},...l?{profile:l}:{},...n.model?{model:{model:n.model}}:{}}:void 0,f=await U(o,a,i);if(f=await W(f),n.interactive){let e=n.session??`int-${ie()}`,t=u??(await f.backend.status()).type,o=ai(i,e,t,l,n.model,r),s=f.session(e).interactive(),c=M(`Starting interactive ${t} session...`);c.start();let d;try{d=await s.start(o)}finally{c.stop()}let p=d.ref.preparationReceipt.harness,m=d.state===`running`?d.streamUrl:void 0,h=`${Qr(a.baseUrl)}/dashboard/sandbox/${encodeURIComponent(i)}?interactive=${encodeURIComponent(d.ref.run.sessionId)}`;if(n.json){k({state:d.state,sessionId:d.ref.run.sessionId,harness:p,...m?{streamUrl:m}:{},webUrl:h});return}if(j(`Interactive ${p} session ${d.state}.`),console.log(),N({...d.state===`running`?{"Watch & drive":h}:{},Session:d.ref.run.sessionId}),console.log(),d.state===`exited`){j(`The initial prompt completed with reason: ${d.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 ci(s,h));return}if(n.stream){n.json||(j(`Streaming response...`),console.log());let e=Date.now(),t=await ri(f.streamPrompt(r,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10),...d?{backend:d}:{}}),e,!n.json);n.json?(k({...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(),ni(t.outcome))}else{let e=M(`Processing prompt...`);e.start();let t=await f.prompt(r,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10),...d?{backend:d}:{}});e.stop(),n.json?(k(t),t.success===!1&&(process.exitCode=1)):t.success===!1?$r(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}))}}),e.addCommand(Gr()),e.addCommand(Xr()),e}async function ui(e){let t=e.timeoutMs??1e4,r=e.baseUrl.replace(/\/$/,``),a=`${r}/v1/account/me`;try{let r=await fetch(a,{headers:{Accept:`application/json`,Authorization:`Bearer ${e.apiKey}`},signal:AbortSignal.timeout(t)});if(!r.ok){let e=await fi(r);throw r.status===401||r.status===403?new n(e||`Invalid API key`):r.status>=500?new l(e||`Sandbox API returned an unexpected error`,r.status):Error(e||`Credential validation failed with status ${r.status}`)}let i=await r.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 n||e instanceof l||e instanceof d?e:e instanceof Error&&e.name===`AbortError`?new d(t,`Timed out validating credentials against ${r}`):e instanceof Error&&!(e instanceof TypeError)?e:new i(`Failed to reach ${r}`,di(e))}}function di(e){return e instanceof Error?e:void 0}async function fi(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 pi(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`).replace(/'/g,`'`)}function mi(e){if(!gi(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 hi(e){let t=e.timeoutMs??12e4,n=e.baseUrl.replace(/\/$/,``),r=await import(`node:http`),i=re(32).toString(`hex`),a=null,o=null,s=new Promise((e,t)=>{a=e,o=t}),c=r.createServer((e,t)=>{try{let n=mi({hostHeader:e.headers.host,requestUrl:e.url,expectedState:i});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(bi(`State mismatch — refusing login`)),o?.(Error(`Browser login state mismatch — refusing potentially hijacked callback`));return;case`error`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(bi(n.reason)),o?.(Error(`Browser login failed: ${n.reason}`));return;case`missing-token`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(bi(null)),o?.(Error(`Browser login did not return a grant token`));return;case`ok`:t.writeHead(200,{"content-type":`text/html; charset=utf-8`}),t.end(bi(null)),a?.(n.token);return}}catch(e){o?.(e instanceof Error?e:Error(`Browser login callback failed`))}});await new Promise((e,t)=>{c.once(`error`,t),c.listen(0,`127.0.0.1`,()=>e())});try{let r=c.address();if(!r||typeof r==`string`)throw Error(`Failed to bind local callback server`);let a=new URL(`http://127.0.0.1:${r.port}/callback`);a.searchParams.set(`state`,i);let o=new URL(`${n}/auth/cli/login`);o.searchParams.set(`callback_url`,a.toString()),e.provider&&o.searchParams.set(`provider`,e.provider);let l=await yi(o.toString());e.onLoginUrl?.({loginUrl:o.toString(),browserOpened:l});let u=await vi({baseUrl:n,grantToken:await _i(s,t),timeoutMs:t});return{apiKey:u.apiKey,email:u.email,name:u.name,tier:u.tier}}finally{await new Promise((e,t)=>{c.close(n=>{if(n){t(n);return}e()})}).catch(()=>void 0)}}function gi(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 _i(e,t){return await new Promise((n,r)=>{let i=setTimeout(()=>{r(new d(t,`Timed out waiting for browser login to complete`))},t);e.then(e=>{clearTimeout(i),n(e)},e=>{clearTimeout(i),r(e)})})}async function vi(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 i(`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 yi(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 bi(e){return`<!doctype html>
|
|
124
|
+
}`}}function Yr(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 Xr(){return new x(`connect`).description(`Print a copy-paste SDK integration snippet for one of: ${qr.join(`, `)} (to stream a local agent's telemetry to Intelligence, see 'tangle connect')`).argument(`<framework>`,qr.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)=>{qr.includes(e)||(console.error(b.red(`unknown framework: ${e}`),`\nsupported: ${qr.join(`, `)}`),process.exit(2));let n=e;process.stdout.write(b.cyan(`# ${Yr(n)}\n\n`)),process.stdout.write(`${Jr(n,t.sandbox,t.session)}\n`)})}async function Zr(e,t=!1){let n=t?new Ae({write(e,t,n){n()}}):process.stderr,r=ke({input:process.stdin,output:n,...t?{terminal:!0}:{}});t&&process.stderr.write(e);try{return await new Promise(n=>{r.once(`close`,()=>n(void 0)),r.question(t?``:e,e=>{n(e.trim()),r.close()})})}finally{r.close(),t&&process.stderr.write(`
|
|
125
|
+
`)}}async function Qr(e){let t=await Zr(e,!0);if(t===void 0)throw Error(`No answer on stdin.`);return t}async function $r(e,t){let n=await Zr(e);if(n===void 0)throw process.stderr.write(`
|
|
126
|
+
`),Error(t?`No answer on stdin. Pass ${t} to skip the confirmation.`:`No answer on stdin.`);return[`y`,`yes`].includes(n.toLowerCase())}async function ei(e,t){let n=await Zr(`${e}${t?` [${t}]`:``}: `);if(n===void 0)throw Error(`No answer on stdin.`);return n||t||``}async function ti(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`);return(await je(process.stdin)).toString(`utf8`).replace(/\r?\n$/,``)}function ni(){let e=new x(`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`).action(async(e,t)=>{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 ei(`Profile name`,`my-agent`),r=await ei(`Description (optional)`)||void 0,i=await ei(`Harness`,`claude-code`)||void 0,a=await ei(`Model (optional, provider/model)`)||void 0,o=await ei(`System prompt (optional)`)||void 0,s=await ri(`Skill ref (local path or github:..., blank to finish)`),c=await ri(`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=Xt({model:a,systemPrompt:o,skills:s,tools:c}),u=Qt({...n?{name:n}:{},...r?{description:r}:{},...l??{},...i?{harness:i}:{}},`new profile`);if(t.json){j(u);return}let d=e??`agent-profile.json`;pe(d,`${JSON.stringify(u,null,2)}\n`),N(`Wrote ${d}`),N(`Run it: tangle agent prompt <box> --profile ${d}${i?` --harness ${i}`:``}`)}),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 Zt(e))}catch(e){R(e,!0)}}),e.command(`validate <source>`).description(`Validate a profile against the canonical AgentProfile schema`).action(async(e,t)=>{let n=await Zt(e),r=typeof n.name==`string`?n.name:`(unnamed)`;t.json?j({ok:!0,name:r}):N(`Profile valid: "${r}"`)}),e}async function ri(e){let t=[];for(;;){let n=await ei(e);if(!n)break;t.push(n)}return t}function ii(e){return([process.env.SANDBOX_WEB_URL,process.env.TANGLE_SANDBOX_WEB_URL].map(e=>e?.trim()).find(e=>!!e)??e).replace(/\/+$/,``)}function ai(e,t){if(process.exitCode=1,e.status===`blocked_on_approval`){console.error(b.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(b.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(b.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(b.yellow(`⚠ Agent is awaiting a plan decision.`)),console.error(`Approve or reject the pending plan before continuing.`);return}console.error(b.red(`✗ ${e.error&&e.error.length>0?e.error:t}`))}function oi(e){let t=e.part;if(t?.type===`text`)return t.text??t.content??void 0}function si(e){return e.finalText??e.response??e.output??e.content??e.text??void 0}function ci(e){if(!e.result.success){ai(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(b.green(`✓ Done`),b.dim(`(${r.join(`, `)})`))}async function li(e,t,n=!0){let r=``,i,a=m(),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=oi(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=si(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 ui(e){let t=Dr(e??[]);if(t.length!==0)return{profile:{connections:t}}}function di(e,t,n,r,i,a){let o={...r??{},harness:n,...i?{model:{...r?.model??{},default:i}}:{}},s={profile:o,requestedProfileDigest:ae(o),initialPrompt:a};return{...s,run:C({provider:`tangle-sandbox`,environmentId:e,sessionId:t,executionId:`interactive-execution-${t}`},s)}}async function fi(e){let t=Dr(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 W({hubKey:e.hubKey});for(let r of t){let t=await n.permissions.allowWrites(r.connectionId);e.json||N(`Allowed ${t.writeActions} write action${t.writeActions===1?``:`s`} for connection ${r.connectionId} (${t.granted} newly granted).`)}e.json||N(`Revert anytime: ${t.map(e=>`tangle hub permissions revert-writes --connection ${e.connectionId}`).join(` · `)}`)}async function pi(e){!e.connection||e.connection.length===0||(e.connection=await Er(e.connection,()=>W({hubKey:e.hubKey})))}async function mi(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){N(`Interactive session ended.`);return}N(`Detached — the session keeps running.`),F({"Watch & drive":t})}function hi(){let e=new x(`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>`.",Tr,[]).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`).action(async(e,t,n)=>{let r=t===void 0?e:t,i=t===void 0?Jn(n.box):e,{context:a,client:o}=U(n),s=await en({profileSource:n.profile,systemPrompt:n.systemPrompt,skills:n.skills,tools:n.tools});await pi(n);let c=ui(n.connection);n.allowWrites&&await fi(n);let l=s||c?{...s,...c?.profile}:void 0,u=n.harness,d=l||u||n.model?{...u?{type:u}:{},...l?{profile:l}:{},...n.model?{model:{model:n.model}}:{}}:void 0,f=await G(o,a,i);if(f=await K(f),n.interactive){let e=n.session??`int-${S()}`,t=u??(await f.backend.status()).type,o=di(i,e,t,l,n.model,r),s=f.session(e).interactive(),c=P(`Starting interactive ${t} session...`);c.start();let d;try{d=await s.start(o)}finally{c.stop()}let p=d.ref.preparationReceipt.harness,m=d.state===`running`?d.streamUrl:void 0,h=`${ii(a.baseUrl)}/dashboard/sandbox/${encodeURIComponent(i)}?interactive=${encodeURIComponent(d.ref.run.sessionId)}`;if(n.json){j({state:d.state,sessionId:d.ref.run.sessionId,harness:p,...m?{streamUrl:m}:{},webUrl:h});return}if(N(`Interactive ${p} session ${d.state}.`),console.log(),F({...d.state===`running`?{"Watch & drive":h}:{},Session:d.ref.run.sessionId}),console.log(),d.state===`exited`){N(`The initial prompt completed with reason: ${d.reason}.`);return}N(`Open the link to watch the agent and type to take over.`),process.stdin.isTTY===!0&&process.stdout.isTTY===!0&&(console.log(),N(`Attaching to the live session — press Ctrl-] to detach.`),await mi(s,h));return}if(n.stream){n.json||(N(`Streaming response...`),console.log());let e=Date.now(),t=await li(f.streamPrompt(r,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10),...d?{backend:d}:{}}),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(),ci(t.outcome))}else{let e=P(`Processing prompt...`);e.start();let t=await f.prompt(r,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10),...d?{backend:d}:{}});e.stop(),n.json?(j(t),t.success===!1&&(process.exitCode=1)):t.success===!1?ai(t,`Agent prompt failed`):(console.log(t.response),console.log(),F({Duration:`${t.durationMs}ms`,"Input Tokens":t.usage?.inputTokens,"Output Tokens":t.usage?.outputTokens}))}}),e.addCommand(Xr()),e.addCommand(ni()),e}async function gi(e){let t=e.timeoutMs??1e4,r=e.baseUrl.replace(/\/$/,``),a=`${r}/v1/account/me`;try{let r=await fetch(a,{headers:{Accept:`application/json`,Authorization:`Bearer ${e.apiKey}`},signal:AbortSignal.timeout(t)});if(!r.ok){let e=await vi(r);throw r.status===401||r.status===403?new n(e||`Invalid API key`):r.status>=500?new u(e||`Sandbox API returned an unexpected error`,r.status):Error(e||`Credential validation failed with status ${r.status}`)}let i=await r.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 n||e instanceof u||e instanceof f?e:e instanceof Error&&e.name===`AbortError`?new f(t,`Timed out validating credentials against ${r}`):e instanceof Error&&!(e instanceof TypeError)?e:new i(`Failed to reach ${r}`,_i(e))}}function _i(e){return e instanceof Error?e:void 0}async function vi(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 yi(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`).replace(/'/g,`'`)}function bi(e){if(!Si(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 xi(e){let t=e.timeoutMs??12e4,n=e.baseUrl.replace(/\/$/,``),r=await import(`node:http`),i=re(32).toString(`hex`),a=null,o=null,s=new Promise((e,t)=>{a=e,o=t}),c=r.createServer((e,t)=>{try{let n=bi({hostHeader:e.headers.host,requestUrl:e.url,expectedState:i});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(Ei(`State mismatch — refusing login`)),o?.(Error(`Browser login state mismatch — refusing potentially hijacked callback`));return;case`error`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Ei(n.reason)),o?.(Error(`Browser login failed: ${n.reason}`));return;case`missing-token`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Ei(null)),o?.(Error(`Browser login did not return a grant token`));return;case`ok`:t.writeHead(200,{"content-type":`text/html; charset=utf-8`}),t.end(Ei(null)),a?.(n.token);return}}catch(e){o?.(e instanceof Error?e:Error(`Browser login callback failed`))}});await new Promise((e,t)=>{c.once(`error`,t),c.listen(0,`127.0.0.1`,()=>e())});try{let r=c.address();if(!r||typeof r==`string`)throw Error(`Failed to bind local callback server`);let a=new URL(`http://127.0.0.1:${r.port}/callback`);a.searchParams.set(`state`,i);let o=new URL(`${n}/auth/cli/login`);o.searchParams.set(`callback_url`,a.toString()),e.provider&&o.searchParams.set(`provider`,e.provider);let l=await Ti(o.toString());e.onLoginUrl?.({loginUrl:o.toString(),browserOpened:l});let u=await wi({baseUrl:n,grantToken:await Ci(s,t),timeoutMs:t});return{apiKey:u.apiKey,email:u.email,name:u.name,tier:u.tier}}finally{await new Promise((e,t)=>{c.close(n=>{if(n){t(n);return}e()})}).catch(()=>void 0)}}function Si(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 Ci(e,t){return await new Promise((n,r)=>{let i=setTimeout(()=>{r(new f(t,`Timed out waiting for browser login to complete`))},t);e.then(e=>{clearTimeout(i),n(e)},e=>{clearTimeout(i),r(e)})})}async function wi(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 i(`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 Ti(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 Ei(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: ${
|
|
133
|
+
<p>${e?`Sandbox CLI login failed: ${yi(e)}`:`Sandbox CLI login complete. You can close this window.`}</p>
|
|
134
134
|
</body>
|
|
135
|
-
</html>`}const xi=15*6e4,Si=`sandbox`;function Ci(e){return Number.isFinite(e)&&e>0?e:xi}async function wi(e){let t=e.timeoutMs??xi,n=Date.now(),r=await Ti({baseUrl:e.baseUrl,app:e.app??Si,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 d(t,`Timed out waiting for device authorization to complete`);let i=await Ei({baseUrl:e.baseUrl,app:e.app??Si,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 Ti(e){let t=Ci(e.timeoutMs),n=e.app!==Si,r=await fetch(`${Di(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 i(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),a=await r.json().catch(()=>null);if(!r.ok||!a?.success||!a.data?.device_code)throw Error(a?.error?.message||`Failed to start device login`);return a.data}async function Ei(e){let t=Ci(e.timeoutMs),n=e.app!==Si,r=await fetch(`${Di(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 i(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),a=await r.json().catch(()=>null);if(r.status===428&&a?.error?.code===`AUTHORIZATION_PENDING`)return{status:`pending`,intervalSeconds:typeof a.data?.interval==`number`&&a.data.interval>0?a.data.interval:5};if(!r.ok||!a?.success||!a.data?.api_key||!a.data.email)throw Error(a?.error?.message||`Failed to complete device authorization`);return{status:`approved`,data:{apiKey:a.data.api_key,email:a.data.email,name:a.data.name,tier:a.data.tier}}}function Di(e){return e.replace(/\/$/,``)}function Oi(){let e=new b(`auth`).description(`Manage authentication`);e.command(`login`).description(`Authenticate with browser login, device code, or an 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`).action(async e=>{let t=e.apiKey,n=Pi(e.app),r=Fi(n,e.profile),i=Ni(e.provider),a=n===`solve`?ir(e.baseUrl):$n(e.baseUrl,r),o=e.browser!==!1,s=(t,i)=>{Ai({profile:r,apiKey:t,baseUrl:e.baseUrl?a:void 0,activate:n===`sandbox`}),hr(),A(`Authenticated`),N({Profile:r,Email:i.email,Tier:i.tier,"Base URL":a}),j(ji)};if(t&&!Mn(t)){wt(`Invalid API key format. Keys should start with 'sk_' or 'sk-tan-'.`),process.exit(1);return}if(sn(),!t){if(o&&n===`sandbox`){let e=M(`Starting browser login...`);e.start();let t=await hi({baseUrl:a,provider:i,onLoginUrl:({loginUrl:t,browserOpened:n})=>{e.stop(),j(n?`Browser login opened.`:`Open this URL to continue browser login:`),console.log(t)}}).finally(()=>{e.stop()});s(t.apiKey,t);return}let e=M(`Starting device login...`);e.start();let t=await wi({baseUrl:a,app:n,provider:i,onInstructions:({userCode:t,verificationUrl:r,verificationUrlComplete:i})=>{e.stop(),j(`Complete login in a browser on any device:`),N({"Verification URL":r,"Verification URL (prefilled)":i,"Device Code":t}),n===`solve`&&o&&yi(i)}}).finally(()=>{e.stop()});s(t.apiKey,t);return}t||(wt(`No API key provided.`),process.exit(1));let c=M(`Validating credentials...`);c.start();let l=await ui({apiKey:t,baseUrl:a});c.stop(),s(t,l)}),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=>{let t=Fi(Pi(e.app),e.profile);Kn(t),hr(),A(`Logged out successfully.`),j(`Credentials removed for profile '${t}'.`)}),e.command(`status`).description(`Show current authentication status`).option(`--profile <name>`,`Profile name`).option(`--app <app>`,`Product credentials to check (sandbox or solve)`,`sandbox`).action(async e=>{let t=Pi(e.app),r=Fi(t,e.profile),i=t===`solve`?Yn(e.apiKey,r):Jn(e.apiKey,r),a=t===`solve`?ir(e.baseUrl):$n(e.baseUrl,r),o=t===`solve`?Zn(e.apiKey,r):Xn(e.apiKey,r);if(!i){if(e.json){k({authenticated:!1,reason:`missing_credentials`,profile:r,baseUrl:a,credentialSource:null});return}wt(`Not authenticated`),j(`Run 'tangle auth login --profile ${r}' to authenticate.`),process.exit(1)}let s=e.json?null:M(`Checking credentials...`);s?.start();try{let n=await ui({apiKey:i,baseUrl:a}),c=t===`solve`?null:await Pr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.profile===void 0?{}:{profile:e.profile},sandboxBaseUrl:a});s?.stop();let l=c!==null&&!c.reachable&&c.refused,u=!l,d=c!==null&&!c.reachable&&!c.refused;if(e.json){k({authenticated:u,profile:r,baseUrl:a,credentialSource:o,account:n,...c?{sandbox:{authenticated:!0},platform:c}:{}}),u||process.exit(1);return}l?Tt(`Authenticated for sandbox only`):d?Tt(`Authenticated — the platform is unreachable right now`):A(`Authenticated`),N({Profile:r,Credentials:`configured`,"Base URL":a,Source:ki(o),Email:n.email,Tier:n.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){s?.stop(),e.json&&(k({authenticated:!1,profile:r,baseUrl:a,credentialSource:o,error:t instanceof Error?t.message:String(t)}),process.exit(1)),t instanceof n?wt(`Stored credentials are invalid.`):Tt(`Stored credentials found, but validation could not complete.`),N({Profile:r,Credentials:`configured`,"Base URL":a,Source:ki(o),Error:t instanceof Error?t.message:String(t)}),process.exit(1)}});let t=new b(`profiles`).description(`Manage CLI profiles`);return t.command(`list`).description(`List configured profiles`).action(e=>{let t=Un();if(e.json){k(t);return}if(t.length===0){j(`No profiles found.`);return}jt([`Profile`,`Active`,`Base URL`,`Credentials`,`Source`],t.map(e=>[e.name,e.active?`yes`:`no`,e.baseUrl,e.hasApiKey?`configured`:`none`,e.apiKeySource]))}),t.command(`use <name>`).description(`Set the active profile`).action(e=>{In(e);let t=Wn(e);A(`Active profile set to '${t.name}'.`),N({"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`})}),t.command(`current`).description(`Show the active profile`).action(e=>{let t=Wn();if(e.json){k({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:ki(t.credentialSource)})}),e.addCommand(t),e}function ki(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 Ai(e){let t=Gn(e.profile,{apiKey:e.apiKey,...e.baseUrl?{baseUrl:e.baseUrl}:{}});e.activate!==!1&&In(e.profile),Pn(e.baseUrl&&e.profile===`default`?{baseUrl:e.baseUrl}:{}),ji=Mi(e.profile,t)}let ji=`Credentials updated.`;function Mi(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 Ni(e){if(e===void 0||e===`github`||e===`google`||e===`microsoft`)return e;throw Error(`--provider must be one of: github, google, microsoft`)}function Pi(e){if(e===void 0||e===`sandbox`||e===`solve`)return e??`sandbox`;throw Error(`--app must be one of: sandbox, solve`)}function Fi(e,t){return On(e,t)}function Ii(){let e=new b(`backend`).description(`Manage sandbox AI agent backend`);return e.command(`status <sandboxId-or-name>`).description(`Get backend agent status`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Fetching backend status...`);i.start();let a=await(await U(r,n,e)).backend.status();i.stop(),t.json?k(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)}`))}),e.command(`configure <sandboxId-or-name>`).description(`Update backend configuration`).option(`--model <model>`,`Model id (e.g. provider/model)`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Updating backend config...`);i.start();let a=await U(r,n,e),o=t.model?{model:t.model}:{};await a.backend.updateConfig(o),i.stop(),A(`Backend configuration updated`),t.json&&k(o)}),e.command(`mcp-status <sandboxId-or-name>`).description(`Get status of MCP servers`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Fetching MCP status...`);i.start();let a=await(await U(r,n,e)).backend.getMcpStatus();if(i.stop(),t.json)k(a);else{let e=Object.entries(a);e.length===0?j(`No MCP servers configured`):O(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}])}}),e.command(`restart <sandboxId-or-name>`).description(`Restart the backend agent`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Restarting backend...`);i.start(),await(await U(r,n,e)).backend.restart(),i.stop(),A(`Backend restarted`)}),e}function Li(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 Ri(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 zi(e){let t=e.readFile??(e=>C(e,`utf8`)),n=[];e.file&&n.push(...Ri(t(e.file)));for(let t of e.inline??[])n.push(Li(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 Bi=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function Vi(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 Hi(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(!Bi.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 Ui(e,t){if(!e||e.length===0)throw Error(`No backends provided. Use --backend id=type or --request <file>.`);let n=e.map(Hi),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:Vi(t)}),n}function Wi(e){let t;try{t=JSON.parse(e)}catch(e){throw Error(`--request file is not valid JSON: ${e.message}`)}try{return ee(t)}catch(e){throw Error(`--request file is not a valid batch request: ${e.message}`)}}function Gi(e,t,n){return n?`${e} [${t}]`:e}function Ki(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 qi(){let e=new b(`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`).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=Wi(C(e.request,`utf8`))}else{let t=zi({file:e.tasks,inline:e.task}),n=Ui(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=ee({tasks:t,timeoutMs:i,backends:n,...a?{persistent:!0,reuseKey:e.reuseKey}:{persistent:!1}})}let{tasks:i,backends:a}=r,o=B(V(e)),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=m(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(y.dim(`→ ${Gi(n.taskId,n.backendId,c)} started`));break}case`task.retry`:{let n=e.data;t(y.yellow(`↻ ${Gi(n.taskId,n.backendId,c)} retry ${n.attempt}: ${n.error}`));break}case`task.completed`:{let n=e.data;t(y.green(`✓ ${Gi(n.taskId,n.backendId,c)} completed in ${n.durationMs}ms`+(n.retries?` (${n.retries} retries)`:``)));break}case`task.failed`:{let n=e.data;t(y.red(`✗ ${Gi(n.taskId,n.backendId,c)} failed: ${n.error}`));break}case`batch.completed`:break}let l=n.finish();t(),e.json?k(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)k(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=Ki(t.results);console.log(),console.log(y.bold(`Task Results`)),console.log(y.dim(`─`.repeat(40)));for(let n of t.results){let t=n.success?y.green(`✓`):y.red(`✗`),r=n.success?n.usage.inputTokens+n.usage.outputTokens:0,i=r>0?` • ${r} tokens`:``;console.log(`${t} ${Gi(n.taskId,n.backendId,e.has(n.taskId))} ${y.dim(`(${n.durationMs}ms, ${n.retries} retries${i})`)}`),n.success||console.log(y.red(` ${n.error}`))}}t.totalFailure>0&&(process.exitCode=1)}}catch(e){if(r){console.log(),j(`Batch cancelled.`),process.exitCode=130;return}I(e)}finally{process.off(`SIGINT`,i),process.off(`SIGTERM`,i)}}),e}function Ji(){let e=new b(`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`).action(async(e,t)=>{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=V(t),i=B(r),a=M(`Branching into ${n} child(ren)...`);a.start();let o=await U(i,r,e),s=await o.fork(n,{...t.idempotencyKey?{idempotencyKey:t.idempotencyKey}:{}}),c=s.children;a.stop(),t.json?k({children:c.map(e=>({sandboxId:e.id})),requestedCount:s.requestedCount,materializedCount:s.materializedCount,complete:s.complete,...s.idempotency?{idempotency:s.idempotency}:{}}):(s.complete?A(`Branched ${c.length} child(ren) from ${o.id}`):Tt(`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.`),O(c.map(e=>({sandboxId:e.id})),[{key:`sandboxId`,header:`Child Sandbox`,width:28}]))}),e}const Yi=[`codex`,`claude-code`,`nanoclaw`,`kimi-code`,`opencode`,`pi`,`openclaw`,`hermes`],Xi=`https://intelligence.tangle.tools/v1/otlp`,Zi=[`codex`,`claude-code`],Qi=[`codex`,`claude-code`,`nanoclaw`],$i=[`SessionStart`,`UserPromptSubmit`,`PreToolUse`,`PostToolUse`,`Stop`],ea={codex:{kind:`native`,surface:`codex`,label:`Codex`,buildFiles:ma},"claude-code":{kind:`native`,surface:`claude-code`,label:`Claude Code`,buildFiles:ha},nanoclaw:{kind:`native`,surface:`nanoclaw`,label:`NanoClaw`,buildFiles:ha},"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 ta(e){let t=e.split(`,`).map(e=>e.trim()).filter(Boolean).flatMap(e=>pa(e));return t.length===0?[...Zi]:Oa(t)}function na(e){return Object.hasOwn(ea,e)}function ra(e=process.cwd()){return he(be(e))||`agent-workspace`}function ia(){return T(Ce(),`.tangle`,`intelligence.json`)}function aa(e=ia()){if(!de(e))return null;let t=Ta(e),n=ka(t,`apiKey`),r=ka(t,`endpoint`),i=ka(t,`serviceName`),a=ka(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 oa(e){let t=be(e.workspace),n=ia(),r=ta(e.selection),i=[],a=[],o=[],s={apiKey:e.apiKey,endpoint:fa(e.endpoint),serviceName:e.serviceName,environment:e.environment};e.dryRun||Sa(n,s),o.push(n);for(let n of r){let r=ea[n];if(r.kind===`manual`){a.push({agent:r.surface,label:r.label,reason:r.reason});continue}i.push(r.surface);let s=t=>sa(e.hookCommand,r.surface,t);for(let n of r.buildFiles(s)){let r=T(t,n.relPath);if(e.dryRun){o.push(r);continue}wa(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 la({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 sa(e,t,n){return`${e.trim()} --agent ${t} --event ${n} --non-blocking`}function ca(e){let t=BigInt(Date.now())*1000000n,n=ja(16),r=ja(8),i=e.sessionId??ga(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`,..._a(e.payload)};return i&&(a[`session.id`]=i,a[`gen_ai.conversation.id`]=i,a[`tangle.sessionId`]=i),{body:{resourceSpans:[{resource:{attributes:[Ma(`service.name`,e.serviceName),Ma(`deployment.environment`,e.environment),Ma(`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])=>Ma(e,t)),status:{code:1}}]}]}]},traceId:n}}async function la(e){let{body:t,traceId:n}=ca(e),r=await fetch(`${fa(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 ua(e){return fa(e).replace(/\/v1\/otlp$/,``).replace(/\/+$/,``)}async function da(e){let t=`${ua(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 fa(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 pa(e){switch(e){case`local`:case`both`:return[...Zi];case`all`:return[...Qi];case`claude`:return[`claude-code`];case`kimi`:return[`kimi-code`];default:if(na(e))return[e];throw Error(`agent must be one of: local, all, both, ${Yi.join(`, `)}`)}}function ma(e){let t=Object.fromEntries($i.map(t=>[t,[{command:e(t),timeoutMs:3e3,blocking:!1,matcher:`*`}]]));return[{relPath:`.codex/hooks.json`,content:JSON.stringify({hooks:t},null,2)}]}function ha(e){let t=Object.fromEntries($i.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 ga(e){return ya(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 _a(e){let t={},n=va(e,[`tool.name`,`toolName`,`tool_name`,`tool`]),r=va(e,[`command`,`cmd`,`shell_command`,`shellCommand`]),i=va(e,[`tool.input`,`toolInput`,`tool_input`,`input`,`arguments`,`args`]),a=va(e,[`tool.output`,`toolOutput`,`tool_output`,`output`,`result`]),o=va(e,[`tool.exit_code`,`exitCode`,`exit_code`,`status`]),s=va(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 va(e,t){let n=ba(e,t);if(n===void 0)return null;if(typeof n==`string`)return xa(n);if(typeof n==`number`||typeof n==`boolean`||typeof n==`bigint`)return String(n);try{return xa(JSON.stringify(n))}catch{return null}}function ya(e,t){let n=ba(e,t);return typeof n==`string`&&n.length>0?n:void 0}function ba(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 xa(e){return e.length>4096?`${e.slice(0,4093)}...`:e}function Sa(e,t){Ca(e,`${JSON.stringify(t,null,2)}\n`)}function Ca(e,t){fe(ge(e),{mode:448,recursive:!0});let n=`${e}.${process.pid}.tmp`;me(n,t,{mode:384}),pe(n,e)}function wa(e,t,n){fe(ge(e),{recursive:!0});let r=Ea(Ta(e),t);me(e,`${JSON.stringify(r,null,2)}\n`,{mode:n??420})}function Ta(e){if(!de(e))return{};let t=JSON.parse(C(e,`utf8`));if(!Aa(t))throw Error(`${e} must contain a JSON object`);return t}function Ea(e,t){let n={...e};for(let[e,r]of Object.entries(t)){let t=n[e];Aa(t)&&Aa(r)?n[e]=Ea(t,r):Array.isArray(t)&&Array.isArray(r)?n[e]=Da([...t,...r]):n[e]=r}return n}function Da(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 Oa(e){return[...new Set(e)]}function ka(e,t){let n=e[t];return typeof n==`string`&&n.length>0?n:void 0}function Aa(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&(Object.getPrototypeOf(e)===Object.prototype||Object.getPrototypeOf(e)===null)}function ja(e){return re(e).toString(`hex`)}function Ma(e,t){return{key:e,value:{stringValue:t}}}const Na=`tangle.opencode-exporter`,Pa=16384;function Fa(e){return e.length<=Pa?e:`${e.slice(0,Pa-1)}…`}function G(e,t){return{key:e,value:{stringValue:t}}}function Ia(e){if(!e||typeof e!=`object`)return null;let t=e,n=E(t.type);return n?{type:n,properties:t.properties&&typeof t.properties==`object`?t.properties:void 0}:null}function La(e,t){let n=[G(`event.name`,e),G(`gen_ai.system`,`opencode`),G(`service.name`,`opencode`)];return t&&(n.push(G(`session.id`,t)),n.push(G(`gen_ai.conversation.id`,t))),n}function Ra(e){if(!e)return null;let t=e.part,n=e.info;return E(t?.sessionID)??E(n?.sessionID)??E(e.sessionID)??null}function za(e,t){let n=E(e.role)??E(e.info?.role);if(n)return n.toLowerCase();let r=E(e.messageID),i=t?.(r)??null;return i?i.toLowerCase():null}function Ba(e,t,n){let r=[],i=Ra(e.properties),a=(n,r)=>({timeUnixNano:t,severityNumber:9,severityText:`INFO`,...n===null?{}:{body:{stringValue:Fa(n)}},attributes:[...La(e.type,i),...r]});if(e.type===`message.part.updated`){let t=e.properties?.part;if(!t)return r;let i=E(t.type);if(i===`text`||i===`reasoning`){let e=E(t.text);if(e){let i=za(t,n)===`user`?je:Ae;r.push(a(e,[G(i,Fa(e))]))}return r}if(i===`tool`){let e=E(t.tool),n=t.state,i=Ie(n?.input),o=Ie(n?.output),s=E(n?.error)??(typeof n?.error==`object`&&n?.error!==null?Ie(n.error):null);if(e||i){let t=[];e&&t.push(G(Ne,e)),i&&t.push(G(Me,Fa(i))),r.push(a(null,t))}let c=o??s;if(c){let t=[G(Pe,Fa(c))];e&&t.push(G(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=E(t.text)??(e.type===`session.next.text.delta`?E(t.delta):null);return n&&r.push(a(n,[G(Ae,Fa(n))])),r}return r}function Va(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 Ha(e,t){if(e.length===0)return null;let n=[G(`service.name`,`opencode`),G(`gen_ai.system`,`opencode`),G(`telemetry.sdk.name`,Na)];return t&&t.trim().length>0&&n.push(G(Fe,t.trim())),{resourceLogs:[{resource:{attributes:n},scopeLogs:[{scope:{name:Na,version:`1.0.0`},logRecords:e}]}]}}function Ua(e){return(e??process.env.OPENCODE_BASE_URL??`http://127.0.0.1:4096`).replace(/\/+$/,``)}async function Wa(e){let t=fa(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 Ga=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 Ka(){return(BigInt(Date.now())*1000000n).toString()}async function qa(e){let t=Ua(e.opencodeBaseUrl),n=e.nowUnixNano??Ka,r=e.fetchImpl??fetch,i=e.subjectKey===void 0?Va():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 v(a.body,{signal:e.signal})){o.eventsSeen++;let a=Ia(t.data);if(!a)continue;if(a.type===`message.updated`){let e=a.properties?.info,t=E(e?.id),n=E(e?.role);t&&n&&s.set(t,n);continue}let l=Ba(a,n(),c),u=Ha(l,i);u&&(await Wa({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 Ga(e,o)}return o}function Ja(e,t){let n=Number(e);if(!Number.isSafeInteger(n)||n<=0)throw Error(`${t} must be a positive integer`);return n}const Ya=[`claude-code`,`codex`,`opencode`,`openclaw`,`hermes`,`nanoclaw`],Xa={"claude-code":`Claude Code`,codex:`Codex`,opencode:`OpenCode`,openclaw:`OpenClaw`,hermes:`Hermes`,nanoclaw:`NanoClaw`};function Za(e){return Ya.includes(e)}function Qa(e){return de(e)?C(e,`utf8`):``}function $a(e,t){fe(ge(e),{recursive:!0});let n=`${e}.${process.pid}.tmp`;me(n,t,{mode:384}),le(n,384),pe(n,e)}const eo=`# >>> tangle intelligence (claude-code) >>>`,to=`# <<< tangle intelligence (claude-code) <<<`,no={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 ro(e,t){return t===`env`?e:/\s/.test(e)?`"${e}"`:e}function io(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}=${ro(i.value,t)}${e}`)}return r.join(`
|
|
136
|
-
`)}function
|
|
137
|
-
`)}function
|
|
135
|
+
</html>`}const Di=15*6e4,Oi=`sandbox`;function ki(e){return Number.isFinite(e)&&e>0?e:Di}async function Ai(e){let t=e.timeoutMs??Di,n=Date.now(),r=await ji({baseUrl:e.baseUrl,app:e.app??Oi,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 f(t,`Timed out waiting for device authorization to complete`);let i=await Mi({baseUrl:e.baseUrl,app:e.app??Oi,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 ji(e){let t=ki(e.timeoutMs),n=e.app!==Oi,r=await fetch(`${Ni(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 i(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),a=await r.json().catch(()=>null);if(!r.ok||!a?.success||!a.data?.device_code)throw Error(a?.error?.message||`Failed to start device login`);return a.data}async function Mi(e){let t=ki(e.timeoutMs),n=e.app!==Oi,r=await fetch(`${Ni(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 i(`Failed to reach ${e.baseUrl}`,t instanceof Error?t:void 0)}),a=await r.json().catch(()=>null);if(r.status===428&&a?.error?.code===`AUTHORIZATION_PENDING`)return{status:`pending`,intervalSeconds:typeof a.data?.interval==`number`&&a.data.interval>0?a.data.interval:5};if(!r.ok||!a?.success||!a.data?.api_key||!a.data.email)throw Error(a?.error?.message||`Failed to complete device authorization`);return{status:`approved`,data:{apiKey:a.data.api_key,email:a.data.email,name:a.data.name,tier:a.data.tier}}}function Ni(e){return e.replace(/\/$/,``)}function Pi(){let e=new x(`auth`).description(`Manage authentication`);e.command(`login`).description(`Authenticate with browser login, device code, or an 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`).action(async e=>{let t=e.apiKey,n=Bi(e.app),r=Vi(n,e.profile),i=zi(e.provider),a=n===`solve`?ur(e.baseUrl):ar(e.baseUrl,r),o=e.browser!==!1,s=(t,i)=>{Ii({profile:r,apiKey:t,baseUrl:e.baseUrl?a:void 0,activate:n===`sandbox`}),xr(),M(`Authenticated`),F({Profile:r,Email:i.email,Tier:i.tier,"Base URL":a}),N(Li)};if(t&&!Rn(t)){At(`Invalid API key format. Keys should start with 'sk_' or 'sk-tan-'.`),process.exit(1);return}if(pn(),!t){if(o&&n===`sandbox`){let e=P(`Starting browser login...`);e.start();let t=await xi({baseUrl:a,provider:i,onLoginUrl:({loginUrl:t,browserOpened:n})=>{e.stop(),N(n?`Browser login opened.`:`Open this URL to continue browser login:`),console.log(t)}}).finally(()=>{e.stop()});s(t.apiKey,t);return}let e=P(`Starting device login...`);e.start();let t=await Ai({baseUrl:a,app:n,provider:i,onInstructions:({userCode:t,verificationUrl:r,verificationUrlComplete:i})=>{e.stop(),N(`Complete login in a browser on any device:`),F({"Verification URL":r,"Verification URL (prefilled)":i,"Device Code":t}),n===`solve`&&o&&Ti(i)}}).finally(()=>{e.stop()});s(t.apiKey,t);return}t||(At(`No API key provided.`),process.exit(1));let c=P(`Validating credentials...`);c.start();let l=await gi({apiKey:t,baseUrl:a});c.stop(),s(t,l)}),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=>{let t=Vi(Bi(e.app),e.profile);Qn(t),xr(),M(`Logged out successfully.`),N(`Credentials removed for profile '${t}'.`)}),e.command(`status`).description(`Show current authentication status`).option(`--profile <name>`,`Profile name`).option(`--app <app>`,`Product credentials to check (sandbox or solve)`,`sandbox`).action(async e=>{let t=Bi(e.app),r=Vi(t,e.profile),i=t===`solve`?tr(e.apiKey,r):er(e.apiKey,r),a=t===`solve`?ur(e.baseUrl):ar(e.baseUrl,r),o=t===`solve`?rr(e.apiKey,r):nr(e.apiKey,r);if(!i){if(e.json){j({authenticated:!1,reason:`missing_credentials`,profile:r,baseUrl:a,credentialSource:null});return}At(`Not authenticated`),N(`Run 'tangle auth login --profile ${r}' to authenticate.`),process.exit(1)}let s=e.json?null:P(`Checking credentials...`);s?.start();try{let n=await gi({apiKey:i,baseUrl:a}),c=t===`solve`?null:await zr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.profile===void 0?{}:{profile:e.profile},sandboxBaseUrl:a});s?.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:r,baseUrl:a,credentialSource:o,account:n,...c?{sandbox:{authenticated:!0},platform:c}:{}}),u||process.exit(1);return}l?jt(`Authenticated for sandbox only`):d?jt(`Authenticated — the platform is unreachable right now`):M(`Authenticated`),F({Profile:r,Credentials:`configured`,"Base URL":a,Source:Fi(o),Email:n.email,Tier:n.tier,...c?{Platform:c.reachable?`reachable (${c.baseUrl})`:`UNREACHABLE — ${c.reason}`}:{}}),d&&N(`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||(N("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){s?.stop(),e.json&&(j({authenticated:!1,profile:r,baseUrl:a,credentialSource:o,error:t instanceof Error?t.message:String(t)}),process.exit(1)),t instanceof n?At(`Stored credentials are invalid.`):jt(`Stored credentials found, but validation could not complete.`),F({Profile:r,Credentials:`configured`,"Base URL":a,Source:Fi(o),Error:t instanceof Error?t.message:String(t)}),process.exit(1)}});let t=new x(`profiles`).description(`Manage CLI profiles`);return t.command(`list`).description(`List configured profiles`).action(e=>{let t=Yn();if(e.json){j(t);return}if(t.length===0){N(`No profiles found.`);return}Lt([`Profile`,`Active`,`Base URL`,`Credentials`,`Source`],t.map(e=>[e.name,e.active?`yes`:`no`,e.baseUrl,e.hasApiKey?`configured`:`none`,e.apiKeySource]))}),t.command(`use <name>`).description(`Set the active profile`).action(e=>{Hn(e);let t=Xn(e);M(`Active profile set to '${t.name}'.`),F({"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`})}),t.command(`current`).description(`Show the active profile`).action(e=>{let t=Xn();if(e.json){j({name:t.name,active:t.active,baseUrl:t.baseUrl,credentialSource:t.credentialSource});return}F({Profile:t.name,"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`,Source:Fi(t.credentialSource)})}),e.addCommand(t),e}function Fi(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 Ii(e){let t=Zn(e.profile,{apiKey:e.apiKey,...e.baseUrl?{baseUrl:e.baseUrl}:{}});e.activate!==!1&&Hn(e.profile),Bn(e.baseUrl&&e.profile===`default`?{baseUrl:e.baseUrl}:{}),Li=Ri(e.profile,t)}let Li=`Credentials updated.`;function Ri(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 zi(e){if(e===void 0||e===`github`||e===`google`||e===`microsoft`)return e;throw Error(`--provider must be one of: github, google, microsoft`)}function Bi(e){if(e===void 0||e===`sandbox`||e===`solve`)return e??`sandbox`;throw Error(`--app must be one of: sandbox, solve`)}function Vi(e,t){return Pn(e,t)}function Hi(){let e=new x(`backend`).description(`Manage sandbox AI agent backend`);return e.command(`status <sandboxId-or-name>`).description(`Get backend agent status`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching backend status...`);i.start();let a=await(await G(r,n,e)).backend.status();i.stop(),t.json?j(a):(N(`Backend Type: ${a.type}`),N(`Status: ${a.status}`),a.version&&N(`Version: ${a.version}`),a.error&&N(`Error: ${a.error}`),a.capabilities&&N(`Capabilities: ${JSON.stringify(a.capabilities)}`))}),e.command(`configure <sandboxId-or-name>`).description(`Update backend configuration`).option(`--model <model>`,`Model id (e.g. provider/model)`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Updating backend config...`);i.start();let a=await G(r,n,e),o=t.model?{model:t.model}:{};await a.backend.updateConfig(o),i.stop(),M(`Backend configuration updated`),t.json&&j(o)}),e.command(`mcp-status <sandboxId-or-name>`).description(`Get status of MCP servers`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching MCP status...`);i.start();let a=await(await G(r,n,e)).backend.getMcpStatus();if(i.stop(),t.json)j(a);else{let e=Object.entries(a);e.length===0?N(`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}])}}),e.command(`restart <sandboxId-or-name>`).description(`Restart the backend agent`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Restarting backend...`);i.start(),await(await G(r,n,e)).backend.restart(),i.stop(),M(`Backend restarted`)}),e}function Ui(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 Wi(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 Gi(e){let t=e.readFile??(e=>T(e,`utf8`)),n=[];e.file&&n.push(...Wi(t(e.file)));for(let t of e.inline??[])n.push(Ui(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 Ki=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function qi(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 Ji(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(!Ki.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 Yi(e,t){if(!e||e.length===0)throw Error(`No backends provided. Use --backend id=type or --request <file>.`);let n=e.map(Ji),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:qi(t)}),n}function Xi(e){let t;try{t=JSON.parse(e)}catch(e){throw Error(`--request file is not valid JSON: ${e.message}`)}try{return y(t)}catch(e){throw Error(`--request file is not a valid batch request: ${e.message}`)}}function Zi(e,t,n){return n?`${e} [${t}]`:e}function Qi(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 $i(){let e=new x(`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`).action(async(e,t)=>{let n=new AbortController,r=!1,i=()=>{r||(r=!0,N(`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=Xi(T(e.request,`utf8`))}else{let t=Gi({file:e.tasks,inline:e.task}),n=Yi(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=y({tasks:t,timeoutMs:i,backends:n,...a?{persistent:!0,reuseKey:e.reuseKey}:{persistent:!1}})}let{tasks:i,backends:a}=r,{client:o}=U(e),s={signal:n.signal,...e.idempotencyKey?{idempotencyKey:e.idempotencyKey}:{}};if(e.stream){let t=e.json?console.error:console.log;N(`Streaming batch of ${i.length} task(s)...`),t();let n=h(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;N(`Batch started (${t.taskCount} tasks, ${t.backendCount} backends)`);break}case`task.started`:{let n=e.data;t(b.dim(`→ ${Zi(n.taskId,n.backendId,c)} started`));break}case`task.retry`:{let n=e.data;t(b.yellow(`↻ ${Zi(n.taskId,n.backendId,c)} retry ${n.attempt}: ${n.error}`));break}case`task.completed`:{let n=e.data;t(b.green(`✓ ${Zi(n.taskId,n.backendId,c)} completed in ${n.durationMs}ms`+(n.retries?` (${n.retries} retries)`:``)));break}case`task.failed`:{let n=e.data;t(b.red(`✗ ${Zi(n.taskId,n.backendId,c)} failed: ${n.error}`));break}case`batch.completed`:break}let l=n.finish();t(),e.json?j(l):F({"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{N(`Running batch of ${i.length} task(s)...`);let t=await o.runBatch(r,s);if(e.json)j(t);else if(console.log(),F({"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=Qi(t.results);console.log(),console.log(b.bold(`Task Results`)),console.log(b.dim(`─`.repeat(40)));for(let n of t.results){let t=n.success?b.green(`✓`):b.red(`✗`),r=n.success?n.usage.inputTokens+n.usage.outputTokens:0,i=r>0?` • ${r} tokens`:``;console.log(`${t} ${Zi(n.taskId,n.backendId,e.has(n.taskId))} ${b.dim(`(${n.durationMs}ms, ${n.retries} retries${i})`)}`),n.success||console.log(b.red(` ${n.error}`))}}t.totalFailure>0&&(process.exitCode=1)}}catch(e){if(r){console.log(),N(`Batch cancelled.`),process.exitCode=130;return}R(e)}finally{process.off(`SIGINT`,i),process.off(`SIGTERM`,i)}}),e}function ea(){let e=new x(`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`).action(async(e,t)=>{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{context:r,client:i}=U(t),a=P(`Branching into ${n} child(ren)...`);a.start();let o=await G(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}`):jt(`Branched ${s.materializedCount} of ${s.requestedCount} requested child(ren) from ${o.id}`),s.idempotency?.outcome===`replayed`&&N(`Replayed an earlier fan-out under this key; created none.`),A(c.map(e=>({sandboxId:e.id})),[{key:`sandboxId`,header:`Child Sandbox`,width:28}]))}),e}const ta=[`codex`,`claude-code`,`nanoclaw`,`kimi-code`,`opencode`,`pi`,`openclaw`,`hermes`],na=`https://intelligence.tangle.tools/v1/otlp`,ra=[`codex`,`claude-code`],ia=[`codex`,`claude-code`,`nanoclaw`],aa=[`SessionStart`,`UserPromptSubmit`,`PreToolUse`,`PostToolUse`,`Stop`],oa={codex:{kind:`native`,surface:`codex`,label:`Codex`,buildFiles:ba},"claude-code":{kind:`native`,surface:`claude-code`,label:`Claude Code`,buildFiles:xa},nanoclaw:{kind:`native`,surface:`nanoclaw`,label:`NanoClaw`,buildFiles:xa},"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 sa(e){let t=e.split(`,`).map(e=>e.trim()).filter(Boolean).flatMap(e=>ya(e));return t.length===0?[...ra]:Pa(t)}function ca(e){return Object.hasOwn(oa,e)}function la(e=process.cwd()){return me(ye(e))||`agent-workspace`}function ua(){return D(Se(),`.tangle`,`intelligence.json`)}function da(e=ua()){if(!ue(e))return null;let t=ja(e),n=Fa(t,`apiKey`),r=Fa(t,`endpoint`),i=Fa(t,`serviceName`),a=Fa(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 fa(e){let t=ye(e.workspace),n=ua(),r=sa(e.selection),i=[],a=[],o=[],s={apiKey:e.apiKey,endpoint:va(e.endpoint),serviceName:e.serviceName,environment:e.environment};e.dryRun||Oa(n,s),o.push(n);for(let n of r){let r=oa[n];if(r.kind===`manual`){a.push({agent:r.surface,label:r.label,reason:r.reason});continue}i.push(r.surface);let s=t=>pa(e.hookCommand,r.surface,t);for(let n of r.buildFiles(s)){let r=D(t,n.relPath);if(e.dryRun){o.push(r);continue}Aa(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 ha({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 pa(e,t,n){return`${e.trim()} --agent ${t} --event ${n} --non-blocking`}function ma(e){let t=BigInt(Date.now())*1000000n,n=La(16),r=La(8),i=e.sessionId??Sa(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`,...Ca(e.payload)};return i&&(a[`session.id`]=i,a[`gen_ai.conversation.id`]=i,a[`tangle.sessionId`]=i),{body:{resourceSpans:[{resource:{attributes:[Ra(`service.name`,e.serviceName),Ra(`deployment.environment`,e.environment),Ra(`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])=>Ra(e,t)),status:{code:1}}]}]}]},traceId:n}}async function ha(e){let{body:t,traceId:n}=ma(e),r=await fetch(`${va(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 ga(e){return va(e).replace(/\/v1\/otlp$/,``).replace(/\/+$/,``)}async function _a(e){let t=`${ga(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 va(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 ya(e){switch(e){case`local`:case`both`:return[...ra];case`all`:return[...ia];case`claude`:return[`claude-code`];case`kimi`:return[`kimi-code`];default:if(ca(e))return[e];throw Error(`agent must be one of: local, all, both, ${ta.join(`, `)}`)}}function ba(e){let t=Object.fromEntries(aa.map(t=>[t,[{command:e(t),timeoutMs:3e3,blocking:!1,matcher:`*`}]]));return[{relPath:`.codex/hooks.json`,content:JSON.stringify({hooks:t},null,2)}]}function xa(e){let t=Object.fromEntries(aa.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 Sa(e){return Ta(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 Ca(e){let t={},n=wa(e,[`tool.name`,`toolName`,`tool_name`,`tool`]),r=wa(e,[`command`,`cmd`,`shell_command`,`shellCommand`]),i=wa(e,[`tool.input`,`toolInput`,`tool_input`,`input`,`arguments`,`args`]),a=wa(e,[`tool.output`,`toolOutput`,`tool_output`,`output`,`result`]),o=wa(e,[`tool.exit_code`,`exitCode`,`exit_code`,`status`]),s=wa(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 wa(e,t){let n=Ea(e,t);if(n===void 0)return null;if(typeof n==`string`)return Da(n);if(typeof n==`number`||typeof n==`boolean`||typeof n==`bigint`)return String(n);try{return Da(JSON.stringify(n))}catch{return null}}function Ta(e,t){let n=Ea(e,t);return typeof n==`string`&&n.length>0?n:void 0}function Ea(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 Da(e){return e.length>4096?`${e.slice(0,4093)}...`:e}function Oa(e,t){ka(e,`${JSON.stringify(t,null,2)}\n`)}function ka(e,t){de(he(e),{mode:448,recursive:!0});let n=`${e}.${process.pid}.tmp`;pe(n,t,{mode:384}),fe(n,e)}function Aa(e,t,n){de(he(e),{recursive:!0});let r=Ma(ja(e),t);pe(e,`${JSON.stringify(r,null,2)}\n`,{mode:n??420})}function ja(e){if(!ue(e))return{};let t=JSON.parse(T(e,`utf8`));if(!Ia(t))throw Error(`${e} must contain a JSON object`);return t}function Ma(e,t){let n={...e};for(let[e,r]of Object.entries(t)){let t=n[e];Ia(t)&&Ia(r)?n[e]=Ma(t,r):Array.isArray(t)&&Array.isArray(r)?n[e]=Na([...t,...r]):n[e]=r}return n}function Na(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 Pa(e){return[...new Set(e)]}function Fa(e,t){let n=e[t];return typeof n==`string`&&n.length>0?n:void 0}function Ia(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&(Object.getPrototypeOf(e)===Object.prototype||Object.getPrototypeOf(e)===null)}function La(e){return re(e).toString(`hex`)}function Ra(e,t){return{key:e,value:{stringValue:t}}}const za=`tangle.opencode-exporter`,Ba=16384;function Va(e){return e.length<=Ba?e:`${e.slice(0,Ba-1)}…`}function q(e,t){return{key:e,value:{stringValue:t}}}function Ha(e){if(!e||typeof e!=`object`)return null;let t=e,n=O(t.type);return n?{type:n,properties:t.properties&&typeof t.properties==`object`?t.properties:void 0}:null}function Ua(e,t){let n=[q(`event.name`,e),q(`gen_ai.system`,`opencode`),q(`service.name`,`opencode`)];return t&&(n.push(q(`session.id`,t)),n.push(q(`gen_ai.conversation.id`,t))),n}function Wa(e){if(!e)return null;let t=e.part,n=e.info;return O(t?.sessionID)??O(n?.sessionID)??O(e.sessionID)??null}function Ga(e,t){let n=O(e.role)??O(e.info?.role);if(n)return n.toLowerCase();let r=O(e.messageID),i=t?.(r)??null;return i?i.toLowerCase():null}function Ka(e,t,n){let r=[],i=Wa(e.properties),a=(n,r)=>({timeUnixNano:t,severityNumber:9,severityText:`INFO`,...n===null?{}:{body:{stringValue:Va(n)}},attributes:[...Ua(e.type,i),...r]});if(e.type===`message.part.updated`){let t=e.properties?.part;if(!t)return r;let i=O(t.type);if(i===`text`||i===`reasoning`){let e=O(t.text);if(e){let i=Ga(t,n)===`user`?Ne:Me;r.push(a(e,[q(i,Va(e))]))}return r}if(i===`tool`){let e=O(t.tool),n=t.state,i=Re(n?.input),o=Re(n?.output),s=O(n?.error)??(typeof n?.error==`object`&&n?.error!==null?Re(n.error):null);if(e||i){let t=[];e&&t.push(q(Fe,e)),i&&t.push(q(Pe,Va(i))),r.push(a(null,t))}let c=o??s;if(c){let t=[q(Ie,Va(c))];e&&t.push(q(Fe,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=O(t.text)??(e.type===`session.next.text.delta`?O(t.delta):null);return n&&r.push(a(n,[q(Me,Va(n))])),r}return r}function qa(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()!==Le)continue;let n=t.slice(e+1).trim();if(n.length>0)return n}return null}function Ja(e,t){if(e.length===0)return null;let n=[q(`service.name`,`opencode`),q(`gen_ai.system`,`opencode`),q(`telemetry.sdk.name`,za)];return t&&t.trim().length>0&&n.push(q(Le,t.trim())),{resourceLogs:[{resource:{attributes:n},scopeLogs:[{scope:{name:za,version:`1.0.0`},logRecords:e}]}]}}function Ya(e){return(e??process.env.OPENCODE_BASE_URL??`http://127.0.0.1:4096`).replace(/\/+$/,``)}async function Xa(e){let t=va(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 Za=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 Qa(){return(BigInt(Date.now())*1000000n).toString()}async function $a(e){let t=Ya(e.opencodeBaseUrl),n=e.nowUnixNano??Qa,r=e.fetchImpl??fetch,i=e.subjectKey===void 0?qa():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 ee(a.body,{signal:e.signal})){o.eventsSeen++;let a=Ha(t.data);if(!a)continue;if(a.type===`message.updated`){let e=a.properties?.info,t=O(e?.id),n=O(e?.role);t&&n&&s.set(t,n);continue}let l=Ka(a,n(),c),u=Ja(l,i);u&&(await Xa({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 Za(e,o)}return o}function eo(e,t){let n=Number(e);if(!Number.isSafeInteger(n)||n<=0)throw Error(`${t} must be a positive integer`);return n}const to=[`claude-code`,`codex`,`opencode`,`openclaw`,`hermes`,`nanoclaw`],no={"claude-code":`Claude Code`,codex:`Codex`,opencode:`OpenCode`,openclaw:`OpenClaw`,hermes:`Hermes`,nanoclaw:`NanoClaw`};function ro(e){return to.includes(e)}function io(e){return ue(e)?T(e,`utf8`):``}function ao(e,t){de(he(e),{recursive:!0});let n=`${e}.${process.pid}.tmp`;pe(n,t,{mode:384}),ce(n,384),fe(n,e)}const oo=`# >>> tangle intelligence (claude-code) >>>`,so=`# <<< tangle intelligence (claude-code) <<<`,co={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 lo(e,t){return t===`env`?e:/\s/.test(e)?`"${e}"`:e}function uo(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}=${lo(i.value,t)}${e}`)}return r.join(`
|
|
136
|
+
`)}function fo(e){let t=va(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=co[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 uo(a,i)}function po(e){return[oo,fo(e),so].join(`
|
|
137
|
+
`)}function mo(e,t){let n=e.indexOf(oo);if(n!==-1){let r=e.indexOf(so,n);if(r===-1)throw Error(`shell rc has a '${oo}' marker without its closing '${so}' — 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?``:ho(e)}${t}\n`,changed:!0}}function ho(e){return e.endsWith(`
|
|
138
138
|
|
|
139
139
|
`)?e:e.endsWith(`
|
|
140
|
-
`)?`${e}\n`:`${e}\n\n`}function
|
|
141
|
-
`))
|
|
142
|
-
`)}function
|
|
143
|
-
`)}\n`,changed:!0};let i=
|
|
144
|
-
`)?e:`${e}\n`}function So(e){let t=T(Ce(),`.codex`,`config.toml`),{contents:n,changed:r}=yo(Qa(t),{endpoint:e.endpoint,apiKey:e.apiKey});if(!e.write){console.log(n.trimEnd());return}if(!r){A(`${t} already has the Tangle [otel] block — nothing to change.`);return}$a(t,n),A(`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 Co(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`${Xa[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 wo(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 da({endpoint:e.endpoint,apiKey:e.apiKey,timeoutMs:r})}catch(e){if(Date.now()>=t)throw e;await Eo(n);continue}if(a.contentSeen||Date.now()>=t)break;await Eo(n)}}finally{i.stop()}if(!a)throw Error(`onboarding status check returned no result`);To(a,e.agent),a.contentSeen||(process.exitCode=1)}function To(e,t){if(e.contentSeen){A(`Content flowing — Tangle Intelligence can analyze this feed.`),N({"Last seen":e.lastSeenAt??`just now`,Window:`${e.windowDays}d`});return}if(e.tracesSeen){Tt(`Metadata-only — traces are arriving but carry no content. You missed a content gate.`);let n=t?[t]:Object.keys(e.byAgent).filter(Za),r=n.length>0?n:Ya;for(let n of r){let r=e.byAgent[n];(t||!r||r.tracesSeen&&!r.contentSeen)&&j(Co(n))}return}Tt(`No traces yet for your tenant. Run your agent once on a real task, then re-run --verify.`),t&&j(Co(t))}function Eo(e){return new Promise(t=>setTimeout(t,e))}function Do(e){let t=e??process.env.TANGLE_INTELLIGENCE_API_KEY??Jn(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 Oo(){return new b(`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(`--endpoint <url>`,`OTLP endpoint base`,Xi).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)=>{let n=fa(t.endpoint);if(t.run){if((e?Ao(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 Po({endpoint:n,apiKey:Do(t.apiKey),opencodeUrl:t.opencodeUrl});return}if(t.verify){await wo({endpoint:n,apiKey:Do(t.apiKey),agent:e?Ao(e):void 0,timeoutSeconds:Ja(t.timeout,`--timeout`)});return}let r=e?Ao(e):await jo(),i=t.inlineKey?Do(t.apiKey):void 0;r===`claude-code`?await po({endpoint:n,apiKey:i,projectKey:t.project,rcPath:t.rc,write:t.write!==!1,content:fo(t.content),format:uo(t.format)}):r===`codex`?So({endpoint:n,apiKey:i,projectKey:t.project,write:t.write!==!1}):r===`opencode`?Mo({endpoint:n}):No(r,{endpoint:n}),console.log(),j(`Run your agent on a real task, then verify content is flowing: tangle connect ${r} --verify`)})}function ko(){return new b(`opencode-exporter`).description(`Export a running OpenCode's content to Tangle Intelligence (standalone shim)`).option(`--endpoint <url>`,`OTLP endpoint base`,Xi).option(`--opencode-url <url>`,`OpenCode server base URL (or set OPENCODE_BASE_URL)`).action(async e=>{await Po({endpoint:fa(e.endpoint),apiKey:Do(e.apiKey),opencodeUrl:e.opencodeUrl})})}function Ao(e){if(Za(e))return e;throw Error(`Unknown agent '${e}'. Choose one of: ${Ya.join(`, `)}`)}async function jo(){if(!process.stdin.isTTY)throw Error(`Specify an agent: tangle connect <${Ya.join(`|`)}>`);console.log(`Which coding agent are you connecting?`),Ya.forEach((e,t)=>{console.log(` ${t+1}) ${Xa[e]} (${e})`)});let e=await Jr(`Enter a number or name`,`1`);return Ya[Number.parseInt(e,10)-1]||Ao(e.trim())}function Mo(e){let t=fa(e.endpoint);Tt(`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 No(e,t){let n=fa(t.endpoint),r=Xa[e];Tt(`${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 Po(e){let t=Ua(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 qa({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 Ga){let{recordsExported:t,contentEventsExported:n}=e.partial;console.log(),Tt(`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){Tt(`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}A(`Exported ${a.recordsExported} content record(s) from ${a.contentEventsExported} event(s).`),j(`Verify it landed: tangle connect opencode --verify`)}function Fo(){let e=new b(`environments`).alias(`env`).description(`Manage sandbox environments`);return e.command(`list`).alias(`ls`).description(`List available environments`).action(async e=>{let t=B(V(e)),n=M(`Fetching environments...`);e.json||n.start();let r=await t.environments.list();n.stop(),e.json?k(r):r.length===0?console.log(`No environments found`):jt([`ID`,`Description`,`Version`],r.map(e=>[e.id,e.description??``,e.version]))}),e.command(`get`).description(`Get environment details`).argument(`<id>`,`Environment ID`).action(async(e,t)=>{let n=B(V(t)),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?k(i):(console.log(`ID: ${i.id}`),console.log(`Description: ${i.description??`-`}`),console.log(`Version: ${i.version}`),i.base&&console.log(`Base: ${i.base}`))}),e}function Io(){return new b(`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`).action(async(e,t,n)=>{try{let r=V(n),i=B(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 U(i,r,e);c=await W(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?k(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 i){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 I(Error(t,{cause:e}))}I(e)}})}function Lo(e){e.command(`capabilities`).description(`List fleet drivers and their supported features`).action(async e=>{let t=B(V(e)),n=M(`Fetching capabilities...`);n.start();let r=await t.fleets.capabilities();n.stop(),e.json?k(r):O(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}])}),e.command(`usage <fleet-id>`).description(`Show fleet usage and reliability insights`).action(async(e,t)=>{let n=B(V(t)),r=M(`Fetching usage...`);r.start();let i=await n.fleets.usage(e);if(r.stop(),t.json)k(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}`)}}),e.command(`cost <fleet-id>`).description(`Show the fleet's cost estimate`).action(async(e,t)=>{let n=B(V(t)),r=M(`Estimating cost...`);r.start();let i=await n.fleets.cost(e);r.stop(),t.json?k(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})})}function Ro(e){return[...e.entries()].map(([e,t])=>({machineId:e,sandboxId:t.id,status:t.status}))}function zo(e){e.command(`list <fleet-id>`).description(`List the machines of one fleet (fleet id is required)`).option(`--status <status>`,`Filter machines by status`).action(async(e,t)=>{let n=B(V(t)),r=M(`Fetching fleet...`);r.start();let i=await n.fleets.list({fleetId:e,status:t.status});r.stop();let a=Ro(i.machines);t.json?k({fleetId:i.fleetId,machines:a}):O(a,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}])}),e.command(`get <fleet-id>`).description(`Show one fleet's manifest (server record)`).action(async(e,t)=>{let n=B(V(t)),r=M(`Fetching manifest...`);r.start();let i=await n.fleets.manifest(e);r.stop(),t.json?k(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}),O(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}]))}),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`).action(async(e,t)=>{let n=B(V(t)),r=M(`Deleting fleet...`);r.start(),await n.fleets.delete(e,{continueOnError:t.continueOnError}),r.stop(),t.json?k({success:!0,fleetId:e}):A(`Fleet deleted: ${e}`)}),e.command(`reap`).description(`TTL cleanup of all expired fleets (fleet-wide)`).option(`--dry-run`,`Report what would be reaped without deleting`).action(async e=>{let t=B(V(e)),n=M(`Reaping expired fleets...`);n.start();let r=await t.fleets.reapExpired({dryRun:e.dryRun});n.stop(),e.json?k(r):(N({"Dry run":r.dryRun,Expired:r.expired,Deleted:r.deleted}),O(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}]))}),e.command(`reconcile`).description(`Drop fleet records whose underlying sandboxes vanished`).option(`--dry-run`,`Report orphans without removing them`).action(async e=>{let t=B(V(e)),n=M(`Reconciling fleets...`);n.start();let r=await t.fleets.reconcile({dryRun:e.dryRun});n.stop(),e.json?k(r):(N({"Dry run":r.dryRun,Checked:r.checked,Orphaned:r.orphaned,Removed:r.removed}),O(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}]))})}function Bo(e){let t=e.memory?Wo(e.memory,`--accelerator-memory`):void 0;return{kind:Ko(e.kind),count:e.count?Wo(e.count,`--accelerator-count`):1,...t===void 0?{}:{memoryMB:t}}}function Vo(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:Go(e.provider,`--gpu-provider`)}:{},...e.image?{image:e.image}:{},...e.env?{env:Uo(e.env,`--gpu-env`,`GPU env`)}:{},maxSpendUsd:qo(e.maxSpendUsd,`--gpu-max-spend-usd`),maxLifetimeSeconds:Wo(e.maxLifetime,`--gpu-max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:Wo(e.idleTimeout,`--gpu-idle-timeout`)}:{}}}}function Ho(e){return{...e.provider?{provider:Go(e.provider,`GPU provider`)}:{},accelerator:Bo({kind:e.acceleratorKind,count:e.acceleratorCount,memory:e.acceleratorMemory}),...e.image?{image:e.image}:{},...e.env?{env:Uo(e.env,`--env`,`env`)}:{},maxSpendUsd:qo(e.maxSpendUsd,`--max-spend-usd`),maxLifetimeSeconds:Wo(e.maxLifetime,`--max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:Wo(e.idleTimeout,`--idle-timeout`)}:{}}}function Uo(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 Wo(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 Go(e,t){if(r.includes(e))return e;throw Error(`${t} must be one of ${r.join(`, `)}`)}function Ko(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 qo(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 Jo(e){if(e.spec){let t=JSON.parse(C(e.spec,`utf8`));return{base:{fleetId:e.fleetId,defaults:t.defaults,policy:t.policy,workspace:t.workspace,metadata:t.metadata},machines:t.machines??[]}}let t=Zo(e),n=Qo(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=$o(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 Yo(e){let{base:t,machines:n}=Jo(e);return{...t,machines:n}}function Xo(e){let{base:t,machines:n}=Jo(e);return{...t,workers:n}}function Zo(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=Bo({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 Qo(e,t){return Vo({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 $o(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 es(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)`).action(async e=>{let t=B(V(e)),n=M(`Creating fleet...`);n.start();let r=e.coordinator?await t.fleets.createWithCoordinator(Xo(e)):await t.fleets.create(Yo(e));n.stop();let i=Ro(r.machines);e.json?k({fleetId:r.fleetId,machines:i}):(A(`Fleet created: ${r.fleetId}`),O(i,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}]))})}function ts(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`).action(async(e,t,n)=>{let r=B(V(n)),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)k(a);else{O(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)}),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`).action(async(e,t)=>{let n=/^\d+$/.test(t.agents)?Number(t.agents):JSON.parse(C(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=B(V(t));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||A(`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?k({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)}),e.command(`cancel <fleet-id>`).description(`Interrupt every agent of a fleet and cancel its child fleets; sandboxes keep running`).action(async(e,t)=>{let n=await(await B(V(t)).fleets.list({fleetId:e})).cancel();t.json?k({fleetId:e,...n}):A(`Fleet ${e}: interrupted ${n.interrupted} agents, cancelled ${n.children} child fleets`)})}const ns=[`list`,`create`,`delete`,`exec`,`prompt`,`read`,`write`];function rs(e){if(!(!e||e.length===0)){for(let t of e)if(!ns.includes(t))throw Error(`Invalid token action '${t}'. Allowed: ${ns.join(`, `)}`);return e}}function is(e){return e.length<=12?`****`:`${e.slice(0,6)}...${e.slice(-4)} (masked — use --json for full value)`}function as(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`).action(async(e,t)=>{let n=B(V(t)),r=M(`Minting fleet token...`);r.start();let i=await n.fleets.createToken(e,{actions:rs(t.action),ttlMinutes:t.ttlMinutes?Number(t.ttlMinutes):void 0});r.stop(),t.json?k(i):(N({"Fleet ID":i.fleetId,Token:is(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.`))})}function
|
|
147
|
-
`)[0]} (${e.author}, ${e.date.toLocaleDateString()})`)}),e.command(`diff`).description(`Show diff`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--ref <ref>`,`Ref to diff against`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Fetching diff...`);t.json||i.start();let a=await U(r,n,e);a=await W(a);let o=await a.git.diff(t.ref);i.stop(),t.json?k(o):o.raw?console.log(o.raw):console.log(`${o.additions} additions, ${o.deletions} deletions across ${o.files.length} files`)}),e.command(`add`).description(`Stage files`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<paths...>`,`Paths to stage`).action(async(e,t,n)=>{let r=V(n),i=await U(B(r),r,e);i=await W(i),await i.git.add(t),A(`Staged: ${t.join(`, `)}`)}),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`).action(async(e,t)=>{let n=V(t),r=await U(B(n),n,e);r=await W(r);let i=await r.git.commit(t.message,{amend:t.amend});t.json?k(i):A(`Committed: ${i.shortSha} ${i.message}`)}),e.command(`push`).description(`Push to remote`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--force`,`Force push`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Pushing...`);i.start();let a=await U(r,n,e);a=await W(a),await a.git.push({force:t.force}),i.stop(),A(`Pushed to remote`)}),e.command(`pull`).description(`Pull from remote`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--rebase`,`Rebase instead of merge`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Pulling...`);i.start();let a=await U(r,n,e);a=await W(a),await a.git.pull({rebase:t.rebase}),i.stop(),A(`Pulled from remote`)}),e.command(`branches`).description(`List branches`).argument(`<id-or-name>`,`Sandbox ID or name`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Fetching branches...`);t.json||i.start();let a=await U(r,n,e);a=await W(a);let o=await a.git.branches();i.stop(),t.json?k(o):o.length===0?console.log(`No branches found`):jt([`Name`,`Current`,`Remote`],o.map(e=>[e.name,e.current?`* `:` `,e.upstream??`-`]))}),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`).action(async(e,t,n)=>{let r=V(n),i=await U(B(r),r,e);i=await W(i),await i.git.checkout(t,{create:n.create}),A(`Checked out: ${t}${n.create?` (new)`:``}`)}),e}ue.O_WRONLY|ue.O_APPEND|ue.O_CREAT|ue.O_NOFOLLOW;const ms=Symbol.for(`tangle.sdk-cli-runner.raw-capture-writers`),hs=globalThis,gs=hs[ms]??{liveWriters:new Map,generations:new Map,losses:new Map,trims:new Map};hs[ms]=gs;const{liveWriters:_s,generations:vs}=gs;gs.losses??=new Map,gs.losses,gs.trims??=new Map,gs.trims,gs.retained??=new Set,gs.retained,new He;function ys(e){return`'${e.replace(/'/g,`'"'"'`)}'`}const bs=`claude,codex,kimi,opencode,gemini,pi`;function xs(e,t){let n;return async(r,{node:i,lastCandidate:a})=>{t.throwIfAborted();let o;try{o=r===void 0?void 0:ce(r)}catch(e){throw e instanceof Error&&Object.assign(e,{node:i,seat:r,fixCommand:`tangle graph run --help`}),e}n??=Ue({cwd:e,signal:t,config:We({...process.env,BRIDGE_BACKENDS:bs,BRIDGE_SUBSCRIPTIONS_ONLY:`1`})});let s=await n;t.throwIfAborted();let c=e=>e.authentication?.status===`authenticated`&&e.authentication.authMode===`subscription`,l=o?.harness??s.find(e=>e.provider&&c(e))?.backend,u=s.filter(e=>e.backend===l),d=u.filter(c),f=o?u.find(e=>e.id===`${o.harness}/${o.model}`)??d.find(e=>e.provider===o.provider):d.find(e=>e.default)??d.find(e=>e.recommended)??d[0];if(!f||!c(f)){if(a===!1)return;let e=f?.authentication??u[0]?.authentication??(o?void 0:s.find(e=>e.authentication?.fix)?.authentication);throw Object.assign(new P(o?`SEAT_NOT_LOGGED_IN`:`SEAT_NONE_DETECTED`,`Node '${i}' has no available subscription${o?` for ${o.harness}`:``}`,e?`Selected provider: ${e.status} (${e.authMode})`:`No authenticated subscription route was detected`,e?.fix??`tangle graph run --help`),{node:i,seat:r})}let p=o?.harness??ce(f.id).harness,m=o?.provider??f.provider,h=o?.model??f.id.slice(p.length+1);if(!m||!h)throw new P(`MODEL_PROVIDER_MISMATCH`,`Node '${i}' has an unresolved model provider`,`Bridge has no configured provider for ${r??p}`,`tangle graph run --help`);return{harness:p,provider:m,model:h,selector:{kind:`all-eligible`},...o?.reasoningEffort===void 0?{}:{reasoningEffort:o.reasoningEffort}}}}const Ss=e=>ne(`sha256`).update(e).digest(`hex`);function K(e){throw new P(`GRAPH_INVALID`,`Graph creation failed`,e,`tangle graph new --help`)}function Cs(e){return typeof e==`string`&&/^[a-z0-9][a-z0-9-]{0,62}$/i.test(e)}const ws={maxBarren:2,failures:`verbatim`,panel:`off`,bar:`on`,profile:{id:`graph-new-v1`,opening:`The graph has not passed its outside check.`,plan:`Repair the concrete diagnostics with write_graph, run the saved file and submit the actual evidence.`,rules:`Completion requires a successful host run and unchanged YAML. Retain working graph content when blocked.`,headings:{failures:`Failures`,protected:`Passing checks`,changed:`Changes`,findings:`Findings`,bar:`Acceptance`,plan:`Next`,rules:`Rules`}}};var Ts=class{owned;lastFailure;pending=Promise.resolve();revision=0;sealed=!1;constructor(e,t,n){this.directory=e,this.options=t,this.cwd=n}async digest(e=this.owned){e||K(`No graph file was saved`);let t=await Re(e.file,ue.O_RDONLY|ue.O_NOFOLLOW);try{let[n,r]=await Promise.all([t.stat(),e.handle.stat()]);return(!n.isFile()||n.dev!==r.dev||n.ino!==r.ino)&&K(`The owned graph file was replaced`),Ss(await t.readFile())}finally{await t.close()}}enqueue(e){let t=++this.revision,n=this.pending.then(()=>e(t));return this.pending=n.then(()=>void 0,()=>void 0),n}check=()=>this.enqueue(async e=>{let t=this.owned;if(!t?.result)return!1;let{digest:n,result:r}=t,i=await this.digest(t),a=this.revision===e&&this.owned===t&&t.digest===n&&t.result===r&&i===n;return a&&(this.sealed=!0),a});receipt(){this.owned?.result||K(`No successful graph run was recorded`);let{file:e,digest:t,result:n}=this.owned;return{file:e,digest:t,result:n}}invoke(e,t){return this.sealed&&K(`The graph is accepted; submit its recorded successful run`),this.enqueue(()=>this.write(e,t)).catch(e=>(this.lastFailure=e,{ok:!1,diagnostic:Ht(e)}))}async write(e,t){t.throwIfAborted(),this.lastFailure=void 0;let n=e;(!n||!Cs(n.name)||typeof n.source!=`string`||typeof n.run!=`boolean`||Object.keys(n).some(e=>![`name`,`source`,`run`].includes(e)))&&K(`Expected only name, source and boolean run`),this.options.name!==void 0&&n.name!==this.options.name&&K(`The graph name must match --name`),this.owned&&(this.owned.result=void 0);let r=T(this.directory,`${n.name}.yaml`);if(this.owned&&this.owned.file!==r&&K(`This invocation owns one named graph file`),!this.owned)try{this.owned={file:r,handle:await Re(r,ue.O_RDWR|ue.O_CREAT|ue.O_EXCL|ue.O_NOFOLLOW,384),digest:Ss(``)}}catch(e){throw e.code===`EEXIST`&&K(`Graph already exists: ${r}; choose another --name`),e}let i=this.owned;await this.digest()!==i.digest&&K(`The owned graph was changed`);let a=Buffer.from(n.source);for(let e=0;e<a.length;){let{bytesWritten:t}=await i.handle.write(a,e,a.length-e,e);if(!t)throw Error(`Graph file write made no progress`);e+=t}await i.handle.truncate(a.length),await i.handle.sync(),i.digest=Ss(a);let o={seat:this.options.seat,param:[]},s={cwd:this.cwd,signal:t,source:n.source},c=await tc(r,{...o,dryRun:!0},s);if(`graph`in c||K(`No canonical graph was returned`),c.graph.deliverable.checkRef===`command`&&K(`Host command checks need a jailed verifier node`),await this.digest()!==i.digest&&K(`Graph changed during validation`),!n.run)return{file:r,graphDigest:c.graph.digest,validated:!0};let l=await tc(r,o,{...s,graphDigest:c.graph.digest});return(!(`status`in l)||l.status!==`winner`||l.graphDigest!==c.graph.digest||await this.digest()!==i.digest)&&K(`The graph must succeed with unchanged YAML`),i.result=l,this.receipt()}async close(){await this.pending,await this.owned?.handle.close()}};async function Es(e,t,n){let{runId:r,runDir:i,cwd:a,bridgeUrl:o,bridgeBearer:s,signal:c}=e,l=T(await Be(T(Ce(),`.tangle`)),`graphs`),u=(e,t)=>{let n=ye(e,t);return n!==`..`&&!n.startsWith(`..${xe}`)&&!ve(n)};(u(a,l)||u(l,a))&&K(`The graph store must be outside the agent workspace; choose another working directory`);try{await Le(l,{mode:448})}catch(e){if(e.code!==`EEXIST`)throw e}await Be(l)!==l&&K(`The graph store redirects outside its canonical location`);let d=n.seat??R().seat,f=await xs(a,c)(d,{node:`graph-designer`,cwd:a,signal:c,lastCandidate:!0});f||K(`No authenticated native subscription is available`);let{graphDesignerProfile:p}=await import(`@tangle-network/agent-runtime/profiles`),{supervisePursuit:m}=await import(`@tangle-network/agent-runtime/durable`),h=p({profile:{name:`graph-designer`,harness:f.harness,model:{provider:f.provider,default:f.model,...f.reasoningEffort===void 0?{}:{reasoningEffort:f.reasoningEffort}},prompt:{instructions:[`You are the sole graph designer. Author a canonical YAML graph for the requested intent, then qualify and run it using write_graph. Its nodes are complete AgentProfiles with a real independent verifier and declarative route/data outside check. Command checks execute on the host and are refused here; put executable verification in the verifier node's normal native tools. Read the supplied skills and preserve the user's task and authority.`,`Call write_graph with name, complete YAML source and run:false to validate; repair its concrete diagnostics, then call it with the identical source and run:true. The graph schema and executor are owned by the installed loader. Supply defaults for parameters needed by the first run. Only a real successful host run of the unchanged saved file passes. Submit that evidence using submit_result; explain concrete blockers using report_blocked.`]},tools:{agent_runtime_coordination_write_graph:!0,agent_runtime_coordination_submit_result:!0,agent_runtime_coordination_read_continuation:!0,agent_runtime_coordination_report_blocked:!0}}}),g=oe(h),_=new Ts(l,{...n,seat:d},a),v={maxIterations:6,maxTokens:3e4,deadlineMs:3e5};try{let e=await m(h,{intent:t,name:n.name},{pursuitId:r,runId:r,runDir:i,signal:c,backend:{backend:`bridge`,bridgeUrl:o,bridgeBearer:s,cwd:a,timeoutMs:v.deadlineMs},budget:v,maxDepth:0,coordination:{authentication:!0,requestTimeoutMs:v.deadlineMs},deliverable:{describe:`The saved graph succeeds with unchanged YAML`,check:_.check,checkState:_.check},continuation:ws,resolveSupervisorTools:e=>e.runId!==r||e.nodeId!==r||e.depth!==0||e.identity.profileDigest!==g?[]:[{name:`write_graph`,description:`Save, validate and run this graph.`,inputSchema:{type:`object`,properties:{name:{type:`string`},source:{type:`string`},run:{type:`boolean`}},required:[`name`,`source`,`run`],additionalProperties:!1},handler:(t,n)=>((n.nodeId!==e.nodeId||n.ownerId!==e.ownerId||n.runId!==e.runId)&&K(`Wrong graph tool owner`),_.invoke(t,n.signal))}]});if(e.result.kind===`no-winner`||!await _.check()){if(_.lastFailure)throw _.lastFailure;let t=e.result.kind===`no-winner`?e.result.error?.message??e.result.reason:`The graph file changed after its successful run`;throw Object.assign(new P(`GRAPH_DESIGN_FAILED`,`Graph design did not finish`,t,`tangle graph new --help`),{runId:r,node:`graph-designer`})}return _.receipt()}finally{await _.close()}}function Ds(e){e.command(`new <intent>`).description(`Design, validate and run one portable graph`).option(`--seat <seat>`,`Use harness/model@effort for the designer and graph`).option(`--name <name>`,`Save this graph name`).action(async(e,t)=>{process.env.BRIDGE_JAIL_RW_PATHS?.trim()&&K(`Remove BRIDGE_JAIL_RW_PATHS before graph new; extra native write roots cannot contain its host store`),t.name!==void 0&&!Cs(t.name)&&K(`Use letters, numbers and hyphens in --name`);let n=await ec({},n=>Es(n,e,t));t.json?k(n):j(`Created ${n.file} · run ${n.result.runId}`)})}const Os=[`claude-code`,`opencode`,`codex`,`kimi-code`,`prime`],ks=process.env.TANGLE_ROUTER_URL??`https://router.tangle.tools/v1`;function As(e){let t=se(e);if(t)return t;throw Error(`--model '${e}' has no provider. Pass a canonical id, for example 'google/${e}'.`)}function js(e,t){return{...e,harness:t}}function Ms(e){let t=e.harness??`claude-code`;if(!Os.includes(t))throw Error(`Unknown --harness '${t}'. Supported: ${Os.join(`, `)}.`);let n=Ns(e.maxTokens,2e5,`--max-tokens`),r=Ns(e.maxIterations,50,`--max-iterations`),i=e.maxWorkers===void 0?void 0:Ns(e.maxWorkers,0,`--max-workers`);return{harness:t,...e.model?{model:e.model}:{},maxTokens:n,maxIterations:r,...i===void 0?{}:{maxWorkers:i}}}function Ns(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 Ps(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 Fs(e){return{async create(t){let n=await e.client.create(Is(t));return e.onCreate({id:n.id,status:`spawned`}),n}}}function Is(e){if(!e?.env)return e;let{TANGLE_API_KEY:t,...n}=e.env;return{...e,env:n}}function Ls(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:Rs(r)?r.content:JSON.stringify(r),...n,status:`winner`}}function Rs(e){return typeof e==`object`&&!!e&&typeof e.content==`string`}let zs=null;function Bs(){return zs??=import(`@tangle-network/agent-runtime/kernel`).catch(e=>{throw zs=null,e?.code===`ERR_MODULE_NOT_FOUND`?new P(`RUNTIME_UNAVAILABLE`,`Agent Runtime could not be loaded`,e.message,`npm install -g @tangle-network/sandbox-cli@latest`):e}),zs}async function Vs(e,t,n){let r=z({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=B(r),{budget:a,perWorker:o}=Ps(t),s=[],c=Fs({client:i,onCreate:e=>{s.push(e),n.json||j(`worker ${e.id} spawned`)}}),l=await Bs(),u=l.workerFromBackend({backend:`sandbox`,sandboxClient:c,maxIterations:1}),d=(e,n)=>u(js(e,t.harness),n),f={name:`supervisor`,harness:`cli-base`,model:{default:t.model??`gemini-2.5-flash-lite`,provider:t.model?As(t.model):`google`},tools:{agent_runtime_coordination_spawn_worker:!0,agent_runtime_coordination_observe_agent:!0}},p={routerBaseUrl:ks,routerKey:r.apiKey},m=Ls(await l.supervise(f,{goal:e},{budget:a,makeWorkerAgent:d,router:p,...o?{perWorker:o}:{},...t.model?{allowedModels:[t.model]}:{},runId:`supervise-${ie()}`})),h=m.status===`winner`?`settled`:`failed`;for(let e of s)e.status=h,n.json||j(`worker ${e.id} settled (${e.status})`);return{task:e,result:m.text,workers:s,tokenUsage:m.tokenUsage,costUsd:m.costUsd,status:m.status}}function Hs(){let e=new b(`supervise`);return e.description(`Run a budget-conserving supervisor that spawns isolated sandbox workers to deliver a task.`).argument(`<task>`,`What the supervisor should accomplish`).option(`--harness <name>`,`Worker harness (${Os.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(`--max-workers <n>`,`Bound the fanout; each worker reserves floor(max-tokens / n) tokens and floor(max-iterations / n) iterations`).action(async(e,t)=>{let n=Ms({harness:t.harness,model:t.model,maxTokens:t.maxTokens,maxIterations:t.maxIterations,maxWorkers:t.maxWorkers});t.json||(j(`Supervising: ${e}`),j(`harness=${n.harness} budget=${n.maxTokens}tok/${n.maxIterations}it`),console.log());let r=await Vs(e,n,{apiKey:t.apiKey,baseUrl:t.baseUrl,json:t.json});if(t.json){k(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}`)}),e}function q(e){return Ir({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.baseUrl===void 0?{}:{baseUrl:e.baseUrl}})}function J(e,t){return I(e,t.json===!0)}const Us=1e3;function Ws(e,t){return[...t,e]}function Gs(e,t=`input`,n){if(n===void 0&&!e?.length)return;let r={};if(n!==void 0)try{if(r=JSON.parse(C(n,`utf8`)),!r||typeof r!=`object`||Array.isArray(r)||Object.entries(r).some(([e,t])=>!e.length||typeof t!=`string`))throw Error(`Invalid input map`)}catch{throw new P(`WORKFLOW_INPUT_FILE_INVALID`,`Could not load --input-file '${n}'`,`Expected a readable JSON object with nonempty keys and string values`,`tangle workflows run --help`)}let i=Object.entries(r);for(let n of e??[]){let e=n.indexOf(`=`);if(e<=0)throw Error(`Invalid --${t} "${n}": expected key=value (e.g. pull_request.number=123)`);i.push([n.slice(0,e),n.slice(e+1)])}return Object.fromEntries(i)}function Ks(e){O(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 qs(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);O(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}),O(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`),O(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 Js(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 Ys(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 Xs(e){e.command(`run`).description(`Trigger an immediate run of a workflow`).argument(`<id>`,`Workflow ID`).option(`--input-file <file>`,`Trigger inputs from a flat JSON string map; --input overrides its keys`).option(`--input <key=value>`,`Trigger input as key=value (e.g. pull_request.number=123). Repeatable.`,Ws,[]).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)`).action(async(e,t)=>{try{let n=Gs(t.input,`input`,t.inputFile),r=t.timeout===void 0?void 0:Ja(t.timeout,`--timeout`),i=t.pollInterval===void 0?void 0:Ja(t.pollInterval,`--poll-interval`),a=await q(t),{runId:o}=await a.workflows.run(e,n);if(!t.wait){if(t.json)return k({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 k(c);qs(c)}catch(e){J(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`).action(async(e,t)=>{try{let n=await q(t),r=t.limit===void 0?void 0:Ja(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>=Us){s=c.nextCursor,t.json||j(`Stopped after ${Us} pages (${i.length} runs); more may exist — resume with --cursor ${c.nextCursor}`);break}a=c.nextCursor}if(t.json)return k({runs:i,nextCursor:s});Ks(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 k(i);Ks(i.runs),i.nextCursor&&j(`More runs available — next page: --cursor ${i.nextCursor}`)}catch(e){J(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`).action(async(e,t,n)=>{try{let r=await(await q(n)).workflows.getRun(e,t);if(n.json)return k(r);qs(r)}catch(e){J(e,n)}}),e.command(`cancel`).description(`Cancel a queued or in-progress run`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{try{let r=await(await q(n)).workflows.cancel(e,t);if(n.json)return k(r);Js(r)}catch(e){J(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)`).action(async(e,t,n)=>{try{let r=n.timeout===void 0?void 0:Ja(n.timeout,`--timeout`),i=n.pollInterval===void 0?void 0:Ja(n.pollInterval,`--poll-interval`),a=await q(n),o=await a.workflows.retryRun(e,t);if(!n.wait){if(n.json)return k(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 k(c);qs(c)}catch(e){J(e,n)}}),e.command(`events`).description(`Tail a run's live progress events until it finishes`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).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)):Ys(i),i.type===`run.done`&&i.status===`failed`&&(process.exitCode=1)}catch(e){J(e,n)}})}function Zs(e,t){let n=ye(e,t);return n!==`..`&&!n.startsWith(`..${xe}`)&&!ve(n)}function Qs(e,t){if(/[\\/]/.test(e)||/\.(yaml|yml|json)$/.test(e))return be(t,e);let n=t;for(;!de(T(n,`.git`))&&ge(n)!==n;)n=ge(n);de(T(n,`.git`))||(n=t);let r=[T(n,`.tangle`,`graphs`,`${e}.yaml`),T(Ce(),`.tangle`,`graphs`,`${e}.yaml`)],i=r.find(de);if(i)return i;throw new P(`GRAPH_NOT_FOUND`,`Graph '${e}' was not found`,`Looked in ${r.join(` and `)}`,`tangle graph --help`)}async function $s(e,t){let n=new AbortController,r=e??n.signal,i=()=>n.abort();e||(process.once(`SIGINT`,i),process.once(`SIGTERM`,i));try{return r.throwIfAborted(),await t(r)}catch(e){if(!r.aborted||e instanceof P&&e.code===`RUN_STOPPED`)throw e;let t=new P(`RUN_STOPPED`,`Graph execution interrupted`,`A stop request ended this execution`,`tangle graph --help`);throw e instanceof Error&&`runId`in e&&typeof e.runId==`string`&&Object.assign(t,{runId:e.runId}),t}finally{e||(process.off(`SIGINT`,i),process.off(`SIGTERM`,i))}}async function ec(e,t){return $s(e.signal,async n=>{let r=ie(),i;try{let a=T(Ce(),`.tangle`,`runs`,r);await Le(a,{recursive:!0,mode:448});let o=await Be(T(Ce(),`.tangle`)),s=await Be(e.cwd??process.cwd()),c=[`runs`,`graph-registry`,`graphs`].some(e=>Zs(s,T(o,e))||Zs(T(o,e),s))?T(Ce(),`.tangle`,`workspaces`,r):s;await Le(c,{recursive:!0,mode:448});let l=re(32).toString(`hex`),{loadConfig:u,startServer:d}=await import(`cli-bridge`);return i=await d({cwd:c,config:{...u({...process.env,BRIDGE_HOST:`127.0.0.1`,BRIDGE_PORT:`3344`,BRIDGE_BEARER:l,BRIDGE_DATA_DIR:T(a,`bridge`),BRIDGE_BACKENDS:bs,BRIDGE_JAIL_MODE:`fs-jail`,BRIDGE_JAIL_FALLBACK:`deny`,BRIDGE_SUBSCRIPTIONS_ONLY:`1`}),port:0},handleSignals:!1,quiet:!0}),await t({runId:r,runDir:a,cwd:c,bridgeUrl:i.url,bridgeBearer:l,signal:n})}catch(e){throw e instanceof Error&&Object.assign(e,{runId:r}),e}finally{await i?.close()}})}async function tc(e,t,n={}){try{return await $s(n.signal,async r=>{let i=await Bs();r.throwIfAborted();let a=Qs(e,n.cwd??process.cwd()),o=async e=>{r.throwIfAborted();let o=await i.loadGraphFile(a,{source:n.source,seat:t.seat??R().seat,resolveSeat:xs(e,r),params:Gs(t.param,`param`),cwd:e,signal:r});if(r.throwIfAborted(),n.graphDigest&&o.graph.digest!==n.graphDigest)throw new P(`GRAPH_CHANGED`,`The validated graph changed before execution`,`Its compiled graph digest no longer matches validation`,`tangle graph run --help`);return o};return t.dryRun?o(n.cwd??process.cwd()):ec({...n,signal:r},async({runId:e,runDir:t,cwd:n,bridgeUrl:s,bridgeBearer:c})=>{let l=await o(n),{superviseGraphPursuit:u}=await import(`@tangle-network/agent-runtime/durable`),d=i.graphRegistry(T(Ce(),`.tangle`,`graph-registry`));await i.recordStoredGraphRun(d,l.graph);let f=new Date().toISOString(),p=new Map;j(`Run ${e} · ${he(a)} · ${n}`);let m=await u(i.graphFromStored(l.graph),{pursuitId:l.graph.digest,runDir:t,runId:e,backend:{backend:`bridge`,bridgeUrl:s,bridgeBearer:c,cwd:n},signal:r,hooks:{onEvent:e=>{let t=e.payload;e.target===`agent.spawn`&&t?.childId&&typeof t.label==`string`&&p.set(t.childId,t.label);let n=p.get(t?.childId??e.parentId??``);process.stderr.write(`${n?`${JSON.stringify(n)} `:``}${e.target} ${JSON.stringify(t?.status??e.phase)}\n`)}}}),h={runId:e,graphDigest:l.graph.digest,...Ls(m.result.result)},g=m.result.result;if(await i.recordStoredGraphRun(d,l.graph,{graphDigest:l.graph.digest,taskDigest:i.taskShapeDigest({graph:he(a),params:l.params}),startedAt:f,finishedAt:new Date().toISOString(),outcome:g.kind===`no-winner`?{kind:`no-winner`,reason:g.reason}:{kind:`delivered`,summary:h.text},cost:{iterations:g.spentTotal.iterations,ms:g.spentTotal.ms,...h.tokenUsage.input===null?{}:{inputTokens:h.tokenUsage.input},...h.tokenUsage.output===null?{}:{outputTokens:h.tokenUsage.output},...h.costUsd===null?{}:{usd:h.costUsd}},traversals:m.result.ledger.length,exhaustedEdges:m.result.exhaustedEdges,source:{kind:`tangle-cli-graph`,id:e}}),g.kind===`no-winner`)throw Object.assign(new P(`GRAPH_RUN_FAILED`,`Graph '${he(a)}' finished without a result`,g.reason,`tangle graph run --help`),{runId:e,runtimeFailures:g.tree.nodes.filter(e=>e.failure).map(e=>({node:e.label,failure:e.failure}))});return h})})}catch(n){throw n instanceof P&&n.code===`RUN_STOPPED`&&Object.assign(n,{fix:[`tangle graph run`,ys(e),...t.dryRun?[`--dry-run`]:[],...t.seat?[`--seat`,ys(t.seat)]:[],...t.param.flatMap(e=>[`--param`,ys(e)])].join(` `)}),n}}function nc(){let e=new b(`graph`).description(`Build and run portable agent graphs`);return Ds(e),e.command(`run <name-or-file>`).description(`Run a saved graph over local subscriptions`).option(`--seat <seat>`,`Use harness/model@effort for every node`).option(`--param <key=value>`,`Graph parameter; repeatable`,(e,t)=>[...t,e],[]).option(`--dry-run`,`Validate and print the graph without starting agents`).action(async(e,t)=>{let n=await tc(e,t);t.json||t.dryRun?k(n):`status`in n&&(j(`${n.status} · ${n.runId}`),n.text&&console.log(n.text))}),e}function rc(){let e=new b(`hub`).description(`Discover and run Tangle Hub tools`);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.`,yc,[]).action(async(e,t)=>{try{let n=bc(t.parameter),r=await(await H(t)).connections.start(e,{cli:!0,connectionParameters:n});if(t.json){k(Sc(r));return}xc(r,t.browser===!1?!1:await yi(r.redirectUrl))}catch(e){Y(e,t)}});let t=new b(`connections`).description(`List Hub provider connections`).action(async e=>{try{let t=await(await H(e)).connections.list();if(e.json){k(t);return}vc(t.connections)}catch(t){Y(t,e)}});t.command(`revoke <connection-id>`).description(`Revoke a Hub provider connection`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{try{let n=await H(t),r=await gr(n,e);if(!t.force&&!await qr(`Revoke Hub connection ${r}? `,`--force`)){j(`Revoke cancelled.`);return}let i=await n.connections.revoke(r);if(t.json){k(i);return}j(`Revoked Hub connection ${i.connection.id}.`)}catch(e){Y(e,t)}}),e.addCommand(t);let n=new b(`permissions`).description(`Manage Hub action permissions`);n.command(`list`).description(`List Hub permissions for a connection`).requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).action(async e=>{try{if(!e.connection)throw Error(`--connection is required.`);let t=await H(e),n=await gr(t,e.connection),r=await t.permissions.list(n);if(e.json){k(r);return}pc(r.policies)}catch(t){Y(t,e)}}),n.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`).action(async e=>{try{if(!e.connection)throw Error(`--connection is required.`);if(!e.action)throw Error(`--action is required.`);let t=mc(e.decision),n=await H(e),r=await gr(n,e.connection),i=await n.permissions.set({connectionId:r,actionPath:e.action,decision:t});if(e.json){k(i);return}pc([i.policy])}catch(t){Y(t,e)}}),n.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]`).action(async e=>{try{if(!e.connection)throw Error(`--connection is required.`);let t=await H(e),n=await gr(t,e.connection),r=await t.permissions.revertWrites(n);if(e.json){k(r);return}j(`Reverted ${r.reverted} write permission${r.reverted===1?``:`s`} for connection ${r.connectionId}.`)}catch(t){Y(t,e)}}),e.addCommand(n);let r=new b(`approvals`).description(`List and resolve Hub execution approvals`);r.command(`list`).description(`List pending Hub execution approvals`).action(async e=>{try{let t=await(await H(e)).approvals.list();if(e.json){k(t);return}cc(t.approvals)}catch(t){Y(t,e)}}),r.command(`approve`).description(`Approve a pending Hub execution approval`).argument(`approval-id`,`Hub approval ID`).action(async(e,t)=>{try{sc(e),lc(await(await H(t)).approvals.approve(e),t.json===!0)}catch(e){Y(e,t)}}),r.command(`deny`).description(`Deny a pending Hub execution approval`).argument(`approval-id`,`Hub approval ID`).action(async(e,t)=>{try{sc(e),lc(await(await H(t)).approvals.deny(e),t.json===!0)}catch(e){Y(e,t)}}),e.addCommand(r);let i=new b(`tools`).description(`Discover Hub tools`);return i.command(`sources`).description(`List Hub tool sources`).action(async e=>{try{let t=await(await H(e)).tools.sources();if(e.json){k(t);return}hc(t.sources)}catch(t){Y(t,e)}}),i.command(`describe`).description(`Describe a Hub tool`).argument(`path`,`Executor tool path`).action(async(e,t)=>{try{let n=await(await H(t)).tools.describe(e);if(t.json){k(n);return}gc(n.tool)}catch(e){Y(e,t)}}),i.command(`search`).description(`Search Hub tools`).argument(`<query...>`,`Search query`).option(`--provider <provider>`,`Filter by provider/source ID`).action(async(e,t)=>{try{let n=await(await H(t)).tools.search(e.join(` `),{provider:t.provider});if(t.json){k(n);return}fc(n.tools)}catch(e){Y(e,t)}}),e.addCommand(i),e.addCommand(ic(`call`)),e.addCommand(ic(`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`).action(async(e,t)=>{try{if(sc(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 H(t);lc(t.decline?await n.approvals.deny(e):await n.approvals.approve(e),t.json===!0)}catch(e){Y(e,t)}}),e.command(`status`).description(`Show Hub auth and connection status`).action(async e=>{try{let t=await(await H(e)).status();if(e.json){k(t);return}Cc(t)}catch(t){Y(t,e)}}),e}function ic(e){return new b(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`).action(async(e,t)=>{try{let{args:n,approve:r}=oc(e,t),{path:i,input:a}=dc(n),o=await H(t),s=t.connection?await gr(o,t.connection):void 0;k((await o.tools.invoke(i,a,{connectionId:s,approve:r})).result)}catch(e){Y(e,t)}})}function ac(e){return e.json===!0}function Y(e,t){return ac(t)?I(e,!0):I(e)}function oc(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 sc(e){if(!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`Hub approval ID must contain only letters, numbers, underscores, and dashes.`)}function cc(e){O(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 lc(e,t){if(t){k(uc(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 uc(e){return{approval:e.approval,...e.capabilityToken?{capabilityToken:{tokenId:e.capabilityToken.tokenId,expiresAt:e.capabilityToken.expiresAt}}:{}}}function dc(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 fc(e){O(e.map(e=>({path:e.path,provider:e.providerId??e.requiredConnectionProviderId,title:e.title,description:e.description,connection:_c(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 pc(e){O(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 mc(e){if(e===`allow`||e===`ask`||e===`deny`)return e;throw Error(`--decision must be one of: allow, ask, deny.`)}function hc(e){O(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 gc(e){N({Path:e.path,Provider:e.providerId??e.requiredConnectionProviderId,Title:e.title,Description:e.description,Connection:_c(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 _c(e){if(e.connectionRequired===!1)return`not required`;if(e.connectionStatus)return e.connectionStatus}function vc(e){O(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 yc(e,t){return[...t,e]}function bc(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 xc(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 Sc(e){return{provider:e.provider,redirectUrl:e.redirectUrl,expiresAt:e.expiresAt,scopes:e.scopes,cli:e.cli}}function Cc(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 wc(){let e=new b(`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(`--endpoint <url>`,`OTLP endpoint base`,Xi).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`).action(async(e,t)=>{let n=e??`local`;ta(n);let r=Ec(t.apiKey),i=await oa({selection:n,workspace:t.workspace,apiKey:r,endpoint:t.endpoint,serviceName:t.serviceName??ra(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){k(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})}),e.command(`doctor`).description(`Check whether your agent traces carry CONTENT or are metadata-only`).option(`--endpoint <url>`,`OTLP endpoint base`,Xi).action(async e=>{let t=aa(),n=await da({endpoint:e.endpoint===`https://intelligence.tangle.tools/v1/otlp`?t?.endpoint??`https://intelligence.tangle.tools/v1/otlp`:e.endpoint,apiKey:Ec(e.apiKey??t?.apiKey)});e.json?k(n):Tc(n),n.contentSeen||(process.exitCode=1)}),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(`--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`).action(async e=>{try{let t=Dc(e.agent),n=aa(),r={agent:t,event:e.event,endpoint:e.endpoint??n?.endpoint??`https://intelligence.tangle.tools/v1/otlp`,apiKey:Ec(e.apiKey??n?.apiKey),serviceName:e.serviceName??n?.serviceName??ra(process.cwd()),environment:e.environment??n?.environment??`local`,sessionId:e.sessionId,payload:e.payload===void 0?await kc():Oc(e.payload)};if(e.dryRun){let n=ca(r);if(e.json){k(n);return}N({Trace:n.traceId,Agent:t,Event:e.event});return}let i=await la(r);if(e.json){k({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?k({ok:!1,error:n}):console.error(`Tangle Intelligence hook skipped: ${n}`);return}I(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`).action(async(e,t)=>{await Ac({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`).action(async(e,t)=>{await Ac({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`).action(async e=>{await Ac({type:Mc(e.subjectType),id:e.subjectId},e)}),e.command(`get <job-id>`).description(`Get an intelligence report`).action(async(e,t)=>{let n=B(V(t)),r=t.json?null:M(`Fetching intelligence report...`);r?.start();let i=await n.intelligence.getReport(e);if(r?.stop(),t.json){k(i);return}jc(i)}),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`).action(async e=>{let t=B(V(e)),n=e.json?null:M(`Fetching intelligence reports...`);n?.start();let r=await t.intelligence.listReports({subjectType:e.subjectType===void 0?void 0:Mc(e.subjectType),subjectId:e.subjectId,limit:e.limit===void 0?void 0:Fc(e.limit)});if(n?.stop(),e.json){k(r);return}O(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}])}),e}function Tc(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(),O(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 Ec(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 Dc(e){if(na(e))return e;throw Error(`agent must be a known Tangle Intelligence agent surface`)}function Oc(e){try{return JSON.parse(e)}catch(e){throw Error(`--payload must be JSON: ${e instanceof Error?e.message:String(e)}`)}}async function kc(){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 Ac(e,t){try{let n=Nc(t.mode),r=Ic(t.metadata),i=t.maxUsd===void 0?void 0:Pc(t.maxUsd);if(n===`agentic`&&i===void 0)throw Error(`Agentic intelligence reports require --max-usd`);let a=B(V(t)),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){k(s);return}jc(s)}catch(e){I(e)}}function jc(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(),k(e.result))}function Mc(e){if(e===`sandbox`||e===`fleet`)return e;throw Error(`subject type must be sandbox or fleet`)}function Nc(e){if(e===`deterministic`||e===`agentic`)return e;throw Error(`mode must be deterministic or agentic`)}function Pc(e){let t=Number(e);if(!Number.isFinite(t)||t<0)throw Error(`--max-usd must be a non-negative number`);return t}function Fc(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function Ic(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 Lc=[`router`,`sandbox`,`blueprint-agent`,`evals`,`agent-builder`];async function Rc(e,t){let n=await Mr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.platformUrl===void 0?{}:{baseUrl:e.platformUrl},...e.baseUrl===void 0?{}:{sandboxBaseUrl:e.baseUrl}});if(!t||!n.minted)return n;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 zc(e,t,n={}){let r=new Headers(n.headers);n.body&&!r.has(`content-type`)&&r.set(`content-type`,`application/json`);let i=await Nr(e,t,{...n,headers:r});if(n.expected!==void 0&&i.status!==n.expected)throw Error(await Bc(i,t));return i}async function Bc(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 Vc=[`ID`,`Prefix`,`Name`,`Product`,`Created`,`Last used`,`Expires`];function Hc(e){return[e.id,e.keyPrefix??``,e.name,e.product??`all`,e.createdAt,e.lastUsedAt??`—`,e.expiresAt??`—`]}function Uc(){let e=new b(`keys`).description(`Manage sk-tan-* API keys on id.tangle.tools`);return e.command(`list`).description(`List your active API keys`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async e=>{let t=await Rc(e,!1),n=t.baseUrl,r=await(await zc(t,`${n}/v1/keys`,{expected:200})).json();if(e.json){k(r);return}jt(Vc,r.data.map(Hc))}),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 (${Lc.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(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{if(t.product!==void 0&&!Lc.includes(t.product))throw Error(`Invalid --product. Expected one of ${Lc.join(`, `)}`);let n=await Rc(t,!0),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 zc(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){k(s);return}A(`API key created: ${s.data.prefix}…`),j(`Copy this key now — it will never be shown again:\n${s.data.key}`)}),e.command(`revoke`).description(`Revoke an API key`).argument(`<keyId>`,"Key ID (from `tcloud keys list`)").option(`--yes`,`Skip the confirmation prompt`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{let n=await Rc(t,!0),r=n.baseUrl;if(!t.yes&&!await qr(`Revoke key ${e}? Any service still using it will start to fail.`,`--yes`)){j(`Aborted.`);return}let i=await(await zc(n,`${r}/v1/keys/${encodeURIComponent(e)}`,{method:`DELETE`,expected:200})).json();if(t.json){k(i);return}A(`Revoked ${e}`)}),e}function Wc(e){if(Ln().token)throw Error(`A line relay cannot manage numbers or attachments. Use your owner CLI outside the agent box.`);return B(z(e))}function Gc(e){if(!e.yes)throw Error(`Review the selected line and use --yes to authorize this change. Attaching enables metered agent work.`)}function Kc(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 qc(e){return e().catch(I)}async function Jc(e){let t=await Re(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 Yc(e){e.command(`providers`).description(`List provider transports supported by this Hub deployment`).action(e=>qc(async()=>{k(await Wc(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`).action(e=>qc(async()=>{k(await Wc(e).lines.list({profileId:e.profileId,sandboxId:e.sandbox}))})),e.command(`get`).argument(`<line-id>`).description(`Inspect a line and its current attachment`).action((e,t)=>qc(async()=>{k(await Wc(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`).action((e,t)=>qc(async()=>{let n=Kc(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`);k(await Wc(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`).action((e,t)=>qc(async()=>{Gc(t);let n=Kc(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}}k(await Wc(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`).action((e,t)=>qc(async()=>{Gc(t);let n=Wc(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 Jc(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(nr()).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})}k(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`).action((e,n)=>qc(async()=>{Gc(n),k({[t]:await Wc(n).lines[t](e)})}));e.command(`threads`).argument(`<line-id>`).description(`List this line's separate participant threads`).action((e,t)=>qc(async()=>{k(await Wc(t).lines.threads(e).list())})),e.command(`messages`).argument(`<line-id>`).argument(`<thread-id>`).description(`Read one authorized participant thread`).action((e,t,n)=>qc(async()=>{k(await Wc(n).lines.threads(e).messages(t))}))}async function Xc(e){let{token:t,baseUrl:n}=Ln();if(t===void 0)return H(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 ke({baseUrl:n,authHeaders:()=>({Authorization:`Bearer ${t}`})})}async function Zc(e,t){if(t)return t;if(!Ln().token)throw Error(`Provide --line <line-id>`);return(await e.lines.context()).line.id}function Qc(e){return e().catch(I)}function $c(){return new b(`context`).description(`Show live line identity, members, consent, reminders and quotas`).action(e=>Qc(async()=>{k(await(await Xc(e)).lines.context())}))}function el(){let e=new b(`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`).action(e=>Qc(async()=>{let t=await Xc(e);k(await t.lines.members.list(await Zc(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`).action((e,t,n)=>Qc(async()=>{let r=await Xc(n),i=await Zc(r,n.line);if(!Ln().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`);k(await r.lines.send(i,{memberId:e,text:t,idempotencyKey:n.idempotencyKey,...n.notBefore?{notBefore:n.notBefore}:{}}));return}k(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`).action((e,t)=>Qc(async()=>{if(!t.at)throw Error(`--at is required`);let n=await Xc(t),r=t.idempotencyKey??ne(`sha256`).update(JSON.stringify([e,t.at])).digest(`hex`).slice(0,32);k(await n.lines.remind(await Zc(n,t.line),{text:e,notBefore:t.at,idempotencyKey:r}))})),Yc(e),e}function tl(){let e=new b(`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)=>{let n=z({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=await U(B(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 Ge(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))})}),e}async function nl(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=Dn(),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??qn():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=z({apiKey:a,baseUrl:r}),s=B(o);return t.self?Je(s):U(s,o,e)}async function rl(e,t,n){let r=M(e);t||r.start();try{return await n()}finally{r.stop()}}function il(e){return e}function al(){let e=new b(`preview`).description(`Manage sandbox preview links`);return il(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)=>{let n=await nl(e,t),r=await rl(`Starting managed preview...`,t.json,()=>Ke(n,{cwd:t.cwd,sessionId:t.session,name:t.name}));t.json?k(r):(A(`Preview ready: ${r.url}`),console.log(`Preview ID: ${r.previewId}`))}),il(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)=>{let n=await nl(e,t),r=await rl(`Fetching preview links...`,t.json,()=>n.previewLinks.list());t.json?k(r):r.length===0?console.log(`No preview links found`):jt([`App`,`Preview ID`,`Port`,`URL`,`Status`],r.map(e=>[ol(e.metadata),e.previewId.slice(0,12),String(e.port),e.url,e.status]))}),il(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)=>{if(!t.port||!/^\d+$/.test(t.port))throw Error(`An integer service port is required`);let n=await nl(e,t),r=await rl(`Publishing service...`,t.json,()=>qe(n,{port:Number(t.port),name:t.name}));t.json?k(r):A(`Preview ready: ${r.url}`)}),il(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)=>{if(!/^\d+$/.test(t)||Number(t)<1||Number(t)>65535)throw Error(`Port must be an integer between 1 and 65535`);let r=await nl(e,n),i=await rl(`Creating preview for port ${t}...`,n.json,()=>r.previewLinks.create(Number(t)));n.json?k(i):(A(`Preview created: ${i.url}`),console.log(`Preview ID: ${i.previewId}`))}),il(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)=>{let r=await nl(e,n);await rl(`Removing preview...`,n.json,()=>r.previewLinks.remove(t)),n.json?k({success:!0,previewId:t}):A(`Preview removed: ${t}`)}),e}function ol(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 sl(){let e=new b(`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)`).action(async(e,t,n)=>{let r=V(n),i=B(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 U(i,r,e);if(s=await W(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?k(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?k({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`))}}),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`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Fetching processes...`);t.json||i.start();let a=await U(r,n,e);a=await W(a);let o=await a.process.list();t.running&&(o=o.filter(e=>e.running)),i.stop(),t.json?k(o):o.length===0?console.log(`No processes found`):jt([`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()]))}),e.command(`get`).description(`Get detailed info about a process`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).action(async(e,t,n)=>{let r=V(n),i=B(r),a=M(`Fetching process info...`);n.json||a.start();let o=await U(i,r,e);o=await W(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?k(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()}`))}),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`).action(async(e,t,n)=>{let r=V(n),i=B(r),a=M(`Sending ${n.signal} to PID ${t}...`);n.json||a.start();let o=await U(i,r,e);o=await W(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?k({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}`)}),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`).action(async(e,t,n)=>{let r=V(n),i=await U(B(r),r,e);i=await W(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))}),e}const cl=[`python`,`node`,`typescript`,`bash`];function ll(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 ul(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 ze(be(e),`utf8`)}async function dl(e,t,n=ul){let r=t?cl.find(e=>e===t)??(()=>{throw Error(`unknown --lang ${t}: must be one of ${cl.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=ll(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 fl(e){return T(we(),`tangle-run-images`,e)}function pl(){return new b(`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: ${cl.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`).action(async(e,t,n)=>{let{language:r,source:i}=await dl(t,n.lang),a=V(n),o=await U(B(a),a,e);o=await W(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){k(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:fl(e);fe(r,{recursive:!0});let i=`${r}/${Date.now()}-${l}.${t.format}`;me(i,Buffer.from(t.data,`base64`)),process.stderr.write(y.green(`✓ image → ${i}\n`)),l++}else process.stderr.write(y.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(y.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(y.gray(`… ${t.rows.length-20} more rows\n`))}else t.type===`json`?(process.stderr.write(y.gray(`[json] `)),process.stderr.write(`${JSON.stringify(t.value,null,2)}\n`)):t.type===`html`?process.stderr.write(y.gray(`[html ${t.value.length}b]\n`)):t.type===`error`?(process.stderr.write(y.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(y.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)})}async function ml(e,t){let n=await Mr({apiKey:t.apiKey,baseUrl:t.baseUrl??nr()}),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 hl(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 Yr();if(t.length===0)throw Error(`${e.flagPrefix}-stdin received empty input on stdin`);return t}}function gl(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 _l(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 vl(e,t){let n={};return e.cpu!==void 0&&(n.cpuCores=Wo(e.cpu,`--cpu`)),e.memory!==void 0&&(n.memoryMB=Wo(e.memory,`--memory`)),e.disk!==void 0&&(n.diskGB=Wo(e.disk,`--disk`)),t&&(n.accelerator=t),Object.keys(n).length>0?n:void 0}function yl(e){let t=e.split(`/`);return t.length>=2?{provider:t[0],model:t.slice(1).join(`/`)}:{model:e}}function bl(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]=xl(r.join(`=`))}return t}function xl(e){try{return JSON.parse(e)}catch{return e}}function Sl(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`?Wo(e.gitDepth,`--git-depth`):void 0,sparse:Array.isArray(e.gitSparse)?e.gitSparse:void 0,auth:t?{token:t}:void 0}}}function Cl(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:wl(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 wl(e){if(e===`s3`||e===`gcs`||e===`r2`)return e;throw Error(`--storage-type must be one of s3, gcs, or r2`)}function Tl(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 El(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 Dl(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`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Checking GPU providers...`);i.start();let a=await(await U(r,n,e)).gpu.providers(t.acceleratorKind?{accelerator:Bo({kind:t.acceleratorKind,count:t.acceleratorCount,memory:t.acceleratorMemory})}:{});if(i.stop(),t.json){k(a);return}O(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.`)}),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`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Attaching GPU lease...`);i.start();let a=await(await U(r,n,e)).gpu.attach(Ho(t));i.stop(),t.json?k(a):(A(`GPU lease attached: ${a.id}`),Tl(a))}),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`).action(async(e,t,n)=>{let r,i,a,o;try{let a=V(n),o=await U(B(a),a,e),s=M(`Attaching GPU lease...`);s.start(),r=await o.gpu.attach(Ho(n)),s.stop();let c=M(`Running GPU command...`);c.start(),i=await o.gpu.exec(r.id,{command:t.join(` `),timeoutMs:n.timeout?Wo(String(n.timeout),`--timeout`):void 0,cwd:n.cwd,env:n.env?Uo(n.env,`--env`,`env`):void 0}),c.stop(),n.json||El(i)}catch(e){a=e}finally{if(r)try{let t=V(n);r=await(await U(B(t),t,e)).gpu.detach(r.id)}catch(e){o=e}}if(a){I(a),o&&I(o);return}if(o){I(o);return}n.json?k({lease:r,result:i}):r&&A(`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`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Fetching GPU leases...`);i.start();let a=await(await U(r,n,e)).gpu.list();i.stop(),t.json?k(a):a.length===0?j(`No GPU leases attached.`):O(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}])}),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)`).action(async(e,t,n,r)=>{let i=V(r),a=B(i),o=M(`Running GPU command...`);o.start();let s=await(await U(a,i,e)).gpu.exec(t,{command:n.join(` `),timeoutMs:r.timeout?Wo(String(r.timeout),`--timeout`):void 0,cwd:r.cwd,env:r.env?Uo(r.env,`--env`,`env`):void 0});o.stop(),r.json?k(s):El(s)}),t.command(`detach <id-or-name> <lease-id>`).description(`Detach and destroy a GPU lease`).action(async(e,t,n)=>{let r=V(n),i=B(r),a=M(`Detaching GPU lease...`);a.start();let o=await(await U(i,r,e)).gpu.detach(t);a.stop(),n.json?k(o):(A(`GPU lease detached: ${o.id}`),Tl(o))})}function Ol(e,t){if(t){k(e);return}if(!e.id){e.kind===`snapshot`&&e.result?.snapshot?A(`Snapshot created: ${e.result.snapshot.snapshotId}`):A(`Sandbox ${e.sandboxId} stopped.`);return}A(`${e.kind===`snapshot`?`Snapshot`:`Stop`} of sandbox ${e.sandboxId} accepted.`),j(`Operation: ${e.id}`),j(`Status: ${e.statusUrl}`)}function kl(e){return`${e.name} (${e.id})`}async function Al(e,t){if(t.startsWith(`team_`))return e.teams.get(t);let n=(await e.teams.list()).filter(e=>e.name.toLowerCase()===t.toLowerCase());if(n.length===0)throw Error(`Team not found: ${t}`);if(n.length>1)throw Error(`Team name is ambiguous: ${t}. Use a team id instead.`);return n[0]}async function X(e,t,n){if(t)return Al(e,t);let r=ar(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 jl(e,t){or({id:e.id,name:e.name},t)}function Ml(e){sr(e)}async function Nl(e){if(e.explicitTeam&&e.personal)throw Error(`--team and --personal cannot be used together`);if(!e.personal)return e.explicitTeam?(await Al(e.client,e.explicitTeam)).id:e.activeTeamId}async function Pl(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 Al(e.client,e.explicitTeam)).id}`;if(e.activeTeamId)return`team:${e.activeTeamId}`}function Fl(e){return!e||e.authToken===void 0?e:{...e,authToken:`[REDACTED]`}}function Il(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`).action(async(e,t)=>{let n=V(t),r=B(n),i=t.nonce===`auto`?g():t.nonce,a=M(`Fetching TEE attestation...`);a.start();let o=await(await U(r,n,e)).getTeeAttestation(i?{attestationNonce:i}:void 0);a.stop(),t.json?k(o):(A(`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}`))}),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`).action(async e=>{let t=V(e),n=B(t),r=M(`Fetching sandboxes...`);r.start();let i=await Pl({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?k(a):O(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}])}),e.command(`get <id-or-name>`).description(`Get sandbox details`).option(`--profile`,`Show the active agent profile provenance (name, hash, skills)`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Fetching sandbox...`);i.start();let a=await U(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?k(a):kt({id:a.id,name:a.name,status:a.status,resources:a.resources,createdAt:a.createdAt?.toISOString(),expiresAt:a.expiresAt?.toISOString(),connection:a.connection})}),e.command(`shapes`).description(`List the named sandbox sizes, the default, and this account's ceiling`).action(async e=>{let t=await B(V(e)).shapes();if(e.json){k(t);return}let n=e=>e.cpuCores<=t.ceiling.cpuCores&&e.memoryMB<=t.ceiling.memoryMB&&e.diskGB<=t.ceiling.diskGB;O(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: ${Ot(t.ceiling)}`)}),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`).action(async(e,t)=>{if(!t.force&&!await qr(`Delete sandbox ${e}? [y/N] `,`--force`)){j(`Cancelled.`);return}let n=V(t),r=B(n),i=M(`Deleting sandbox...`);i.start();let a=await Vr(r,n,e,{retryCleanup:t.retryCleanup,name:t.name});i.stop(),A(a===`already_absent`?`Sandbox ${e} was already gone.`:`Sandbox ${e} deleted.`)}),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`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Stopping sandbox...`);i.start();let a=await U(r,n,e,{nameOnly:t.name});if(t.wait===!1){let e=await a.stop({wait:!1});i.stop(),Ol(e.info,!!t.json);return}await a.stop(),i.stop(),A(`Sandbox ${e} stopped.`)}),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`).action(async(e,t)=>{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=z({apiKey:t.apiKey,baseUrl:t.baseUrl,timeout:n}),i=B(r),a=M(`Resuming sandbox...`);a.start();let o=await U(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(),A(`Sandbox ${o.id} resumed.`)})}function Ll(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 (${t.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`).action(async e=>{let t=await hl({envVarName:e.gitTokenEnv,fromStdin:e.gitTokenStdin,flagPrefix:`--git-token`}),n=await hl({envVarName:e.storageSecretAccessKeyEnv,fromStdin:e.storageSecretAccessKeyStdin,flagPrefix:`--storage-secret-access-key`}),r=await hl({envVarName:e.backendApiKeyEnv,fromStdin:e.backendApiKeyStdin,flagPrefix:`--backend-api-key`}),i=gl({secret:e.cliAuth,backend:e.backend,apiKeyGiven:r!==void 0}),a;if(e.profileStdin){let e=await Yr(`--profile-stdin`,`the AgentProfile JSON`);try{a=JSON.parse(e)}catch{I(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(C(t,`utf8`))}catch(e){I(Error(`--profile ${t}: ${e.message}`));return}else try{a=await ml(t,e)}catch(e){I(Error(`--profile ${t}: ${e.message}`));return}}let o=z({apiKey:e.apiKey,baseUrl:e.baseUrl,timeout:e.timeout?Number.parseInt(e.timeout,10):void 0}),s=B(o),c=M(`Creating sandbox...`);c.start();let l=await Nl({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?bl(e.metadata):void 0,f=Sl(e,t),p=Cl(e,n),m=e.acceleratorKind?Bo({kind:String(e.acceleratorKind),count:String(e.acceleratorCount),memory:typeof e.acceleratorMemory==`string`?e.acceleratorMemory:void 0}):void 0,g=Vo({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`),v=e.driver?{type:e.driver,enableCriu:e.driverCriu||void 0,preferredRegion:e.driverRegion}:void 0,ee=e.backend||e.backendModel||a?{...e.backend?{type:_(e.backend)}:{},...a?{profile:a}:{},model:e.backendModel||r||i?{...e.backendModel?yl(e.backendModel):{},apiKey:r,...i?{cliAuth:i}:{}}:void 0}:void 0,y=_l(e.secret),te=i?[...new Set([...y??[],i.secretEnv])]:y,b=vl(e,m),ne=[...e.sshKey?[e.sshKey]:[],...(e.sshKeyFile??[]).map(e=>C(e,`utf8`).trim())],re={name:e.name,environment:e.environment,bare:e.bare||void 0,sshEnabled:e.ssh||!!e.sshKey||ne.length>0||!!e.sshKeys?.length,sshPublicKeys:ne.length>0?ne:void 0,sshKeyIds:e.sshKeys,webTerminalEnabled:e.webTerminal,env:Object.keys(u).length>0?u:void 0,git:f,...b?{resources:b}:{},gpuLease:g,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:te,metadata:d,driver:v,backend:ee},ie=e.tee?{tee:e.tee,sealed:e.sealed||void 0,attestationRefresh:e.attestationRefresh||e.attestationNonce===`auto`||void 0}:void 0,ae=ie?await h(s,{...re,confidential:ie,attestationNonce:e.attestationNonce??(e.attestationRefresh?`auto`:void 0),requireAttestation:e.requireAttestation??!0}):void 0,x=ae?.sandbox??await s.create(re);e.wait&&(c.text=`Waiting for sandbox to start...`,await x.waitFor(`running`,{timeoutMs:12e4}),await x.refresh()),c.stop(),e.json?k({id:x.id,name:x.name,status:x.status,resources:x.resources,createdAt:x.createdAt,expiresAt:x.expiresAt,connection:Fl(x.connection),teamId:l,gpuLease:x.gpuLease,confidential:ie,attestation:ae?.attestation,attestationNonce:ae?.attestationNonce}):(A(`Sandbox created: ${x.id}`),kt({id:x.id,name:x.name,status:x.status,resources:x.resources,createdAt:x.createdAt?.toISOString(),expiresAt:x.expiresAt?.toISOString(),connection:x.connection}),l&&console.log(`Team: ${l}`),x.gpuLease&&(console.log(`GPU lease: ${x.gpuLease.id}`),Tl(x.gpuLease)),ie&&(console.log(`TEE: ${ie.tee}`),console.log(`Attestation: ${ae?.attestation?`present`:`not returned`}`),ae?.attestationNonce&&console.log(`Attestation nonce: ${ae.attestationNonce}`)))})}function Rl(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`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Updating network configuration...`);i.start();let a=await U(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?k(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?k(o):(A(`Network configuration updated.`),o.ports&&o.ports.length>0&&j(` Exposed Ports: ${o.ports.join(`, `)}`))}),e.command(`expose <id-or-name>`).description(`Expose a port and get a public URL`).option(`-p, --port <port>`,`Port to expose`,`8000`).action(async(e,t)=>{let n=V(t),r=B(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 U(r,n,e)).network.exposePort(i);a.stop(),t.json?k({port:i,url:o}):(A(`Port ${i} exposed.`),j(` URL: ${o}`))}),e.command(`urls <id-or-name>`).description(`List exposed port URLs for a sandbox`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Fetching exposed URLs...`);i.start();let a=await(await U(r,n,e)).network.listUrls();if(i.stop(),t.json)k(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}`)}}})}function zl(){let e=new b(`sandbox`).description(`Manage sandboxes`);return Ll(e),Il(e),Dl(e),Rl(e),e}function Bl(){return new b(`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`).action(async(e,t,n)=>{let r=V(n),i=B(r),a=M(`Searching...`);n.json||a.start();let o=await U(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`)})}function Vl(){let e=new b(`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`).action(async(e,t,n)=>{let r=B(V(n)),i=await Hl({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?k({name:o.name,createdAt:o.createdAt.toISOString(),updatedAt:o.updatedAt.toISOString()}):(A(`Secret created: ${o.name}`),j(`Use --secrets ${o.name} when creating a sandbox to inject it as an environment variable.`))}),e.command(`list`).description(`List all secrets`).action(async e=>{let t=B(V(e)),n=M(`Fetching secrets...`);n.start();let r=await t.secrets.list();n.stop(),e.json?k(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.`)):jt([`Name`,`Created At`,`Updated At`],r.map(e=>[e.name,e.createdAt.toLocaleString(),e.updatedAt.toLocaleString()]))}),e.command(`delete`).description(`Delete a secret`).argument(`<name>`,`Secret name`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=B(V(t));if(!t.force&&!await qr(`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?k({success:!0,deleted:e}):A(`Secret deleted: ${e}`)}),e}async function Hl(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 Yr();if(e.length===0)throw Error(`Secret value from stdin cannot be empty`);return e}let t=await Kr(e.prompt);if(t.length===0)throw Error(`Secret value cannot be empty`);return t}function Ul(){let e=new b(`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=w.dirname(Ve(import.meta.url)),t=w.resolve(e,`..`,`SKILL.md`);console.log(t)}),e}function Wl(){let e=new b(`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`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Creating snapshot...`);i.start();let a=await U(r,n,e);if(t.wait===!1){let e=await a.snapshot({tags:t.tags,wait:!1});i.stop(),Ol(e.info,!!t.json);return}let o=await a.snapshot({tags:t.tags});i.stop(),t.json?k(o):(A(`Snapshot created: ${o.snapshotId}`),console.log(`Size: ${Gl(o.sizeBytes??0)}`))}),e.command(`list <sandbox-id-or-name>`).description(`List snapshots for a sandbox`).action(async(e,t)=>{let n=V(t),r=B(n),i=M(`Fetching snapshots...`);i.start();let a=await(await U(r,n,e)).listSnapshots();i.stop(),t.json?k(a):O(a.map(e=>({...e,size:Gl(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}])}),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.`).action(async(e,t,n)=>{let r=B(V(n)),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?k({sandboxId:a.id,restoredFrom:t,status:a.status}):(A(`New sandbox created: ${a.id}`),console.log(`Source snapshot: ${t}`))}),e.command(`revert <sandbox-id-or-name> <snapshot-id>`).description(`Revert an existing sandbox to a snapshot`).action(async(e,t,n)=>{let r=V(n),i=B(r),a=M(`Reverting sandbox to snapshot...`);a.start();let o=await U(i,r,e),s=await o.revertToSnapshot(t);await o.refresh(),a.stop(),n.json?k({sandboxId:o.id,snapshotId:s.snapshotId,status:o.status}):(A(`Sandbox reverted: ${o.id}`),console.log(`Source snapshot: ${s.snapshotId}`))}),e.command(`delete <sandbox-id-or-name> <snapshot-id>`).description(`Delete a sandbox snapshot`).action(async(e,t,n)=>{let r=V(n),i=B(r),a=M(`Deleting snapshot...`);a.start();let o=await(await U(i,r,e)).deleteSnapshot(t);a.stop(),n.json?k({success:!0,sandboxId:e,snapshotId:t,outcome:o.outcome}):o.outcome===`already_absent`?A(`Snapshot already gone: ${t}`):A(`Snapshot deleted: ${t}`)}),e}function Gl(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 Kl=`solve:device:secp256k1`,ql=/^0x[0-9a-f]{64}$/i;function Jl(e){return e&&ql.test(e)?e:void 0}function Yl(){let e=an(Kl),t=Jl(e.value);if(!(!t||e.source===`none`))return{account:Xe(t),source:e.source}}function Xl(){let e=Yl();if(e)return e;let t=Ye(),n=on(Kl,t);return{account:Xe(t),source:n}}function Zl(e){let t=Jl(an(Kl).value);if(!t||Xe(t).address!==e.account.address)throw Error(`The local Solve device key changed; it was not retired`);let n=`${Kl}:retired:${e.account.address.toLowerCase()}`;if(on(n,t),an(n).value!==t)throw Error(`The revoked device key could not be retired safely`);return cn(Kl),n}function Ql(e){try{let t=e.create?Xl():Yl();if(!t)throw Error("No Solve device signer found. Run `tangle solve account --create`");e.json?k({address:t.account.address,source:t.source}):N({Address:t.account.address,Source:t.source})}catch(e){I(e)}}const $l=/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;function eu(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function tu(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`${t} must be an object`);return e}function nu(e,t,n=2048){if(typeof e!=`string`||!e.trim()||e.length>n)throw Error(`${t} is missing or invalid`);if(eu(e))throw Error(`${t} contains control characters`);return e.trim()}function ru(e,t){let n=nu(e,t,64).toLowerCase();if(!$l.test(n))throw Error(`${t} must be a 40 or 64 character Git revision`);return n}function iu(e,t,n=!1){let r=typeof e==`number`&&Number.isSafeInteger(e)?String(e):nu(e,t,80);if(!/^\d+$/.test(r)||!n&&r===`0`)throw Error(`${t} must be an unsigned integer`);return BigInt(r).toString()}function au(e,t){let n=nu(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 ou(e,t){let n=au(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 su(e,t){let n=nu(e,t,42);if(!at(n,{strict:!1}))throw Error(`${t} must be an EVM address`);return rt(n)}function cu(e,t){let n=iu(e,t),r=Number(n);if(!Number.isSafeInteger(r)||r<=0)throw Error(`${t} is out of range`);return r}function Z(...e){for(let t of e)if(typeof t==`string`&&t.trim())return t.trim()}function lu(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 uu(e){if(e===void 0)return;let t=nu(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 du(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 fu(e){return On(`solve`,e.profile)}function pu(e){let t=fu(e),n=Yn(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 mu(e){let t=rr(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 ${pu(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 hu(e){return mu({path:`/v1/wallet/challenges`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.purpose?{purpose:e.purpose}:{}}})}function gu(e){return mu({path:`/v1/devices`,apiUrl:e.apiUrl,profile:e.profile})}function _u(e){return mu({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 Q={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 vu(e,t){return e.toLowerCase()===t.toLowerCase()}function yu(e){if(e.chainId!==Q.chainId)throw Error(`Solve submissions require Tempo Moderato (chain ${Q.chainId}); received ${e.chainId}`);if(e.rpcUrl!==Q.rpcUrl)throw Error(`Solve metadata RPC does not match the trusted deployment`);if(e.sponsorUrl!==Q.sponsorUrl)throw Error(`Solve metadata sponsor does not match the trusted deployment`);if(!vu(e.tangleAddress,Q.tangleAddress))throw Error(`Solve metadata Tangle contract does not match the trusted deployment`);if(!vu(e.managerAddress,Q.managerAddress))throw Error(`Solve metadata competition manager does not match the trusted deployment`);if(!vu(e.paymentAsset,Q.paymentAsset))throw Error(`Solve metadata payment asset does not match the trusted deployment`);if(e.blueprintId!==Q.blueprintId)throw Error(`Solve submissions require blueprint ${Q.blueprintId}; received ${e.blueprintId}`);if(e.serviceId!==Q.serviceId)throw Error(`Solve submissions require service ${Q.serviceId}; received ${e.serviceId}`);if(e.competitionId!==Q.competitionId)throw Error(`Solve submissions require competition ${Q.competitionId}; received ${e.competitionId}`);if(e.minStakeWei!==Q.minStakeWei)throw Error(`Solve submissions require zero stake for the trusted deployment`)}function bu(e,t){let n=tu(t.check??e.check,`competition.participation.check`),r=nu(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=>nu(e,`competition checker argument`,2048)),a=Z(n.result_file,n.resultFile),o=n.timeout_ms??n.timeoutMs,s=o===void 0?void 0:cu(o,`competition checker timeout`);return{command:r,args:i,...a?{result_file:a}:{},...s?{timeout_ms:s}:{}}}function xu(e){if(e.provenance===void 0)return;let t=tu(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 Su(e){let t=tu(e.chain??e.network??{},`competition.chain`),n=e.rewards&&typeof e.rewards==`object`&&!Array.isArray(e.rewards)?tu(e.rewards,`competition.rewards`):{},r=n.minStake&&typeof n.minStake==`object`&&!Array.isArray(n.minStake)?tu(n.minStake,`competition.rewards.minStake`).raw:void 0,i=Z(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=Z(t.chainName,t.chain_name,e.chainName,e.chain_name)??`Tempo`,s=Z(t.nativeSymbol,t.native_symbol,e.nativeSymbol,e.native_symbol)??`TNT`,c=Z(t.rpcUrl,t.rpc_url,e.rpcUrl,e.rpc_url,process.env.TANGLE_SOLVE_RPC_URL),l=Z(t.sponsorUrl,t.sponsor_url,e.sponsorUrl,e.sponsor_url,process.env.TANGLE_SOLVE_SPONSOR_URL),u=Z(t.tangleAddress,t.tangle_address,t.coreAddress,t.core_address,e.tangleAddress,e.tangle_address,e.coreAddress,e.core_address),d=Z(t.managerAddress,t.manager_address,e.managerAddress,e.manager_address),f=Z(t.paymentAsset,t.payment_asset,t.servicePaymentAsset,t.service_payment_asset,e.paymentAsset,e.payment_asset,e.servicePaymentAsset,e.service_payment_asset),p=Z(t.blueprintId,t.blueprint_id,e.blueprintId,e.blueprint_id),m=Z(t.serviceId,t.service_id,e.serviceId,e.service_id),h=Z(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:cu(a,`chain.chainId`),chainName:o,nativeSymbol:s,rpcUrl:au(c,`chain.rpcUrl`),sponsorUrl:au(l,`chain.sponsorUrl`),tangleAddress:su(u,`chain.tangleAddress`),managerAddress:su(d,`chain.managerAddress`),paymentAsset:su(f??Q.paymentAsset,`chain.paymentAsset`),blueprintId:iu(p,`chain.blueprintId`),serviceId:iu(m,`chain.serviceId`),competitionId:iu(h,`chain.competitionId`,!0),minStakeWei:iu(i,`chain.minStakeWei`,!0)}}function Cu(e){let t=tu(e,`competition`),n=tu(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=ou(Z(r.repository,r.repo_url,i.repository)??``,`competition.repository`),o=ru(Z(r.repositoryRevision,r.repository_revision,i.revision,i.repositoryRevision,i.repository_revision),`competition.repositoryRevision`),s=nu(r.slug??r.id,`competition.slug`,128),c=nu(r.name??r.title??s,`competition.name`,256),l=bu(r,i),u=xu(i);return{version:1,slug:s,title:c,repository:a,taskRevision:o,checker:l,chain:Su(r),...u?{provenance:u}:{}}}function wu(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 Tu(e){let t=tu(JSON.parse(await D.readFile(w.join(e,`.tangle-solve.json`),`utf8`)),`.tangle-solve.json`);if(t.version!==1)throw Error(`.tangle-solve.json has an unsupported version`);let n=tu(t.checker,`.tangle-solve.json.checker`),r=tu(t.chain,`.tangle-solve.json.chain`);return Cu({slug:t.slug,name:t.title,repository:t.repository,repositoryRevision:t.taskRevision,participation:{check:n,provenance:t.provenance},chain:r,competitionId:r.competitionId})}const Eu=Ze(Te),Du=`.tangle-solve-run.json`,Ou=`.tangle-solve.json`,ku=`tangle.solve.manifestSha256`,Au=new Set([Ou,Du]),ju=`upstream`;async function Mu(e,t){let n=await Eu(`git`,[`-C`,e,...t],{encoding:`utf8`,maxBuffer:1e6});return String(n.stdout).trim()}async function Nu(e,t){let n=w.resolve(t??process.cwd()),r=await Tu(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 Pu(e){let t=w.join(e,Ou),n;try{n=await D.lstat(t)}catch{throw Error(`${Ou} is missing`)}if(n.isSymbolicLink()||!n.isFile())throw Error(`${Ou} must be a regular file`);return ne(`sha256`).update(await D.readFile(t)).digest(`hex`)}async function Fu(e){let t=await Pu(e);return await Mu(e,[`config`,`--local`,`--replace-all`,ku,t]),t}async function Iu(e){let t;try{t=await Mu(e,[`config`,`--local`,`--get`,ku])}catch{throw Error(`The local Git metadata has no ${ku} pin; run tangle solve clone again`)}if(!/^[0-9a-f]{64}$/i.test(t))throw Error(`The local ${ku} pin is invalid`);if(await Pu(e)!==t.toLowerCase())throw Error(`${Ou} changed after clone; run tangle solve clone again`)}async function Lu(e,t){try{return await Mu(e,[`ls-files`,`--error-unmatch`,`--`,t]),!0}catch{return!1}}async function Ru(e){await Iu(e);for(let t of Au)if(await Lu(e,t))throw Error(`${t} must remain untracked and local to this Solve workspace`);let t=await Eu(`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===`!!`)&&Au.has(n))}).length>0)throw Error(`Commit the candidate before running Solve. Only the local manifest and run record may remain uncommitted.`);return ru(await Mu(e,[`rev-parse`,`HEAD`]),`submission revision`)}async function zu(e,t,n,r={}){let i=await Bu(e,t,r);if(i)return{taskRepository:t.repository,taskRevision:t.taskRevision,submissionRepository:i,submissionRevision:n}}async function Bu(e,t,n={}){let r;try{r=lu(await Mu(e,[`config`,`--get`,`remote.origin.pushurl`]))}catch{try{r=lu(await Mu(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 '${ju}'.`)}}let i=ou(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 '${ju}' before submitting.`)}return i}function Vu(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 Hu(e,t){return`${e}/commit/${t}`}function Uu(e,t,n,r,i={}){let a=e.evidenceRefs.map(e=>du(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=uu(r);if(n.required&&(i.requirePullRequest??!0)&&!o)throw Error(`This competition requires a GitHub pull request`);a.push(Hu(t.taskRepository,t.taskRevision),Hu(t.submissionRepository,t.submissionRevision),...o?[o]:[])}return{evidence:e.evidence,evidenceRefs:[...new Set(a)]}}async function Wu(e,t){let n=`${e}.${process.pid}.tmp`;await D.writeFile(n,`${JSON.stringify(t,null,2)}\n`,{mode:384}),await D.rename(n,e)}async function Gu(e){let t=JSON.parse(await D.readFile(w.join(e,Du),`utf8`));if(t.version!==1||typeof t.competition!=`string`)throw Error(`${Du} has an unsupported format`);return t}async function Ku(e){let t=uu(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 qu(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 Ju=Ze(Te);function Yu(){return`Task source is '${ju}'. Add your fork as 'origin', commit your candidate, push it, and open a pull request before submitting.`}async function Xu(e,t,n){try{let r=tu(await mu({path:`/v1/competitions/${encodeURIComponent(e)}`,apiUrl:n.apiUrl,profile:n.profile}),`competition response`),i=Cu(r.competition??r),a=w.resolve(t??i.slug),o=M(`Cloning ${i.slug}…`);n.json||o.start();try{await Ju(`git`,[`clone`,`--no-tags`,`--origin`,ju,i.repository,a],{encoding:`utf8`,maxBuffer:1e6}),await Mu(a,[`checkout`,`--detach`,i.taskRevision]);let e=await Mu(a,[`rev-parse`,`HEAD`]);if(e.toLowerCase()!==i.taskRevision.toLowerCase())throw Error(`Pinned checkout resolved to ${e}, expected ${i.taskRevision}`);await Wu(w.join(a,`.tangle-solve.json`),i),await Fu(a)}finally{o.stop()}n.json?k({competition:i,directory:a}):(A(`Cloned ${i.slug} at ${i.taskRevision.slice(0,12)}`),i.provenance&&j(Yu()),j(`Run the pinned checker with: cd ${a} && tangle solve run`))}catch(e){I(e)}}const Zu=12e4,Qu=ct(`event JobSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint8 jobIndex, address caller, bytes inputs)`),$u=ct(`event JobCompleted(uint64 indexed serviceId, uint64 indexed callId)`),ed=ct(`event JobResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, address indexed operator, bytes result)`),td=ct(`event AggregatedResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint256 signerBitmap, bytes output)`),nd=ct(`event EvaluationAccepted(uint64 indexed serviceId, uint64 indexed competitionId, address indexed researcher, bytes32 candidateId, bytes32 submissionRefHash, bytes32 evaluationDigest, bytes32 metricsHash, bytes32 evidenceRefsHash)`),rd=[...st([`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)`]),Qu,$u,ed,td],id=st([`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)`]),ad=st([`function allowance(address owner, address spender) view returns (uint256)`,`function approve(address spender, uint256 amount) returns (bool)`]),od=lt(`uint64 competitionId, uint256 stakeWei`),sd=lt(`uint64 competitionId, bytes32 commitment`),cd=lt(`uint64 competitionId, bytes32 commitment, string artifactRef, bytes32 salt`),ld=lt(`string artifactRef, bytes32 salt`),ud=lt(`uint64 competitionId, bytes32 candidateId, string submissionRef, string evidenceJson, string evidenceRefsJson`),dd=lt(`string status, string detail`),fd=/^0x[0-9a-f]{64}$/i;function pd(e,t){if(e!==t)throw Error(`Tempo RPC returned chain ${e}; expected ${t}`)}function md(e,t,n){return{...e,feePayer:!0,nonceKey:t,nonce:n}}function hd(e,t){if(e!==`success`)throw Error(`${t} transaction reverted`)}function gd(e,t,n,r){if(!fd.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(hd(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 _d(e,t){return e>=t?[]:e>0n?[0n,t]:[t]}function vd(e,t,n=Date.now()){return n>=e+t}function yd(e,t){return e.filter(e=>e.args?.candidateId?.toLowerCase()===t.toLowerCase()).at(-1)?.transactionHash}function bd(e,t,n,r,i){for(let a of e.logs)if(a.address.toLowerCase()===t.tangleAddress.toLowerCase())try{let e=tt({abi:[Qu],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 xd(e,t,n,r){for(let i of e.logs)if(i.address.toLowerCase()===t.managerAddress.toLowerCase())try{let e=tt({abi:[nd],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 Sd(e){if(e.chainId!==ft.id)throw Error(`Solve submissions require Tempo Moderato (chain ${ft.id}); received ${e.chainId}`);if(!e.sponsorUrl)throw Error(`Solve submissions require a Tempo sponsor relay URL; unsponsored writes are disabled`);return{...ft,name:e.chainName,nativeCurrency:{name:e.nativeSymbol,symbol:e.nativeSymbol,decimals:18},rpcUrls:{default:{http:[e.rpcUrl]}}}}async function Cd(e,t){yu(e);let n=Sd(e),r=Qe({chain:n,transport:it(e.rpcUrl)});return pd(await r.getChainId(),e.chainId),await wd({publicClient:r},e),{publicClient:r,walletClient:$e({account:t,chain:n,transport:mt(it(e.rpcUrl),it(e.sponsorUrl))}),account:t}}async function wd(e,t){let n=await e.publicClient.readContract({address:t.tangleAddress,abi:rd,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 Td(e,t,n){let[r,i]=await Promise.all([e.publicClient.readContract({address:t.tangleAddress,abi:rd,functionName:`getJobEventRate`,args:[t.blueprintId,n]}),e.publicClient.readContract({address:t.tangleAddress,abi:rd,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 Ed(e,t,n){return await e.publicClient.readContract({address:t,abi:ad,functionName:`allowance`,args:[e.account.address,n.tangleAddress]})}async function Dd(e,t,n,r,i,a){let o=Date.now();for(;!vd(o,a);){if((await e.publicClient.getLogs({address:t.tangleAddress,event:$u,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`})).length>0){let a=(await e.publicClient.getLogs({address:t.tangleAddress,event:ed,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]=et(dd,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 Od(e,t,n,r,i){let a=Date.now();for(;!vd(a,i);){let i=(await e.publicClient.getLogs({address:t.tangleAddress,event:td,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 kd(e,t,n){return!!await e.publicClient.readContract({address:t.managerAddress,abi:id,functionName:`acceptedCandidates`,args:[t.serviceId,t.competitionId,e.account.address,n]})}const Ad=BigInt(ot(ut(`tangle.solve.v1`)));async function jd(e,t){let n=await pt.nonce.getNonce(e.publicClient,{account:e.account.address,nonceKey:Ad});if(n>BigInt(2**53-1))throw Error(`The Solve transaction nonce exceeds the safe range`);return e.walletClient.writeContract(md(t,Ad,Number(n)))}async function Md(e,t,n,r){if(!await e.publicClient.readContract({address:t.tangleAddress,abi:rd,functionName:`isPermittedCaller`,args:[t.serviceId,e.account.address]}))try{let i=r??await jd(e,{address:t.managerAddress,abi:id,functionName:`authorizeSelf`,args:[t.serviceId]});if(r||await n?.(`authorization`,i),gd(await e.publicClient.waitForTransactionReceipt({hash:i}),i,`Authorization`,{from:e.account.address,to:t.managerAddress}),!await e.publicClient.readContract({address:t.tangleAddress,abi:rd,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 Nd(e,t){let n=await jd(e,{address:t.managerAddress,abi:id,functionName:`revokeSelf`,args:[t.serviceId]});return gd(await e.publicClient.waitForTransactionReceipt({hash:n}),n,`Revocation`,{from:e.account.address,to:t.managerAddress}),n}async function Pd(e,t,n,r,i=`allowance`,a={}){if(t.amount===0n||t.asset===`0x0000000000000000000000000000000000000000`)return;let o=await Ed(e,t.asset,n);for(let s of _d(o,t.amount)){let o=s===0n?`${i}:reset`:`${i}:approval`,c=a[o];if(c){if(gd(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 Ed(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 jd(e,{address:t.asset,abi:ad,functionName:`approve`,args:[n.tangleAddress,s]});await r?.(o,l),gd(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 Fd(e,t,n,r,i,a=`job:${n}`,o={}){let s=await Td(e,t,n);await Pd(e,s,t,i,`allowance:${a}`,o);let c=o[a],l=c??await jd(e,{address:t.tangleAddress,abi:rd,functionName:`submitJob`,args:[t.serviceId,n,r],value:s.value});c||await i?.(a,l);let u=await e.publicClient.waitForTransactionReceipt({hash:l});return gd(u,l,`Job ${n}`,{from:e.account.address,to:t.tangleAddress}),{hash:l,callId:bd(u,t,n,e.account.address,r),blockNumber:u.blockNumber}}async function Id(e,t,n,r,i,a,o=`job:${n}`,s={}){let c=await Fd(e,t,n,r,a,o,s),l=await Dd(e,t,c.callId,c.blockNumber,i,Zu);return{...c,acknowledgement:l}}const Ld={...Q,chainName:`Tempo Moderato`,nativeSymbol:`TNT`},Rd={async read(e){let t=Qe({chain:ft,transport:it(Ld.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:Ld.tangleAddress,abi:rd,functionName:`isPermittedCaller`,args:[Ld.serviceId,e]})),n(t.readContract({address:Ld.managerAddress,abi:id,functionName:`isDeviceRevoked`,args:[e]}))]);return[e.toLowerCase(),{permitted:r,revoked:i}]}));return new Map(r)},async revokeSelf(e){return Nd(await Cd(Ld,e),Ld)}},zd={permitted:null,revoked:null};function Bd(e){return e.revoked?`revoked`:e.permitted===null?`unknown`:e.permitted?`permitted`:`not permitted`}async function Vd(e,t=Rd){try{let{devices:n}=await gu({apiUrl:e.apiUrl,profile:e.profile}),r=Yl()?.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=>rt(e.address))),o=i.map(e=>({...e,onChain:a.get(e.address)??zd}));if(e.json){k({serviceId:Ld.serviceId.toString(),devices:o});return}jt([`Address`,`Status`,`Local`,`Service ${Ld.serviceId}`,`Last used`,`Revoked`],o.map(e=>[e.address,e.status,e.local?`yes`:``,Bd(e.onChain),e.lastUsedAt??``,e.revokedAt?`${e.revokedAt} (${e.revocationMethod})`:``]))}catch(t){I(t,e.json)}}async function Hd(e,t,n=Rd){try{if(!at(e))throw Error(`${e} is not an EVM address`);let r=rt(e),i=Yl(),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 qr(`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 hu({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 _u({deviceAddress:r,reason:t.reason,...o,apiUrl:t.apiUrl,profile:t.profile}),c=r.toLowerCase(),l=(await n.read([r])).get(c)??zd,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)??zd}let d=i&&a&&l.revoked?Zl(i):void 0;if(t.json){k({...s,serviceId:Ld.serviceId.toString(),onChain:l,...u?{revocationTransaction:u}:{},localKeyRetired:!!d});return}A(s.alreadyRevoked?`${r} was already revoked in the Solve API`:`Revoked ${r}; the Solve API refuses its signatures`),u&&A(`Revoked on Tempo in ${u}; service ${Ld.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&&Tt(`The device can still submit jobs to service ${Ld.serviceId}. Only its key, or the Solve blueprint owner, can revoke it on chain`)}catch(e){I(e,t.json)}}function Ud(e,t){return ot(nt(ld,[e.trim(),t]))}function Wd(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 Gd(e,t,n,r,i){let a=i.resumeTransactions?.evaluation;if(a){let n=await e.publicClient.waitForTransactionReceipt({hash:a});if(gd(n,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!xd(n,t,e.account,r))throw Error(`Saved evaluation transaction did not emit EvaluationAccepted for this candidate`);return a}let o=Date.now();for(;!vd(o,Zu);){if(await kd(e,t,r)){let i=yd(await e.publicClient.getLogs({address:t.managerAddress,event:nd,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:id,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()!==ot(n.output).toLowerCase())throw Error(`Manager pending report output does not match the aggregate`);let a=await jd(e,{address:t.managerAddress,abi:id,functionName:`executePendingResult`,args:[t.serviceId,n.callId,n.output]});await i.onTransaction?.(`evaluation`,a);let s=await e.publicClient.waitForTransactionReceipt({hash:a});if(gd(s,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!xd(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 Kd(e,t,n,r={}){if(yu(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 Cd(e,t),a=await Md(i,e,r.onTransaction,r.resumeTransactions?.authorization),o,s=await i.publicClient.readContract({address:e.managerAddress,abi:id,functionName:`stakes`,args:[e.serviceId,e.competitionId,i.account.address]});s<e.minStakeWei&&(o=await jd(i,{address:e.managerAddress,abi:id,functionName:`postStake`,args:[e.serviceId,e.competitionId],value:e.minStakeWei-s}),await r.onTransaction?.(`stake`,o),gd(await i.publicClient.waitForTransactionReceipt({hash:o}),o,`Stake`,{from:i.account.address,to:e.managerAddress}));let c=Ud(n.artifactRef,n.salt),l=nt(od,[e.competitionId,e.minStakeWei]),u=nt(sd,[e.competitionId,c]),d=nt(cd,[e.competitionId,c,n.artifactRef.trim(),n.salt]),f=await Id(i,e,1,l,`joined`,r.onTransaction,`join`,r.resumeTransactions),p=await Id(i,e,2,u,`committed`,r.onTransaction,`commit`,r.resumeTransactions),m=Wd(p.acknowledgement.detail),h=await Id(i,e,3,d,`revealed`,r.onTransaction,`reveal`,r.resumeTransactions),g=await Fd(i,e,4,nt(ud,[e.competitionId,c,m,n.evidenceJson,JSON.stringify(n.evidenceRefs)]),r.onTransaction,`report`,r.resumeTransactions),_=await Od(i,e,g.callId,g.blockNumber,Zu),v=await Gd(i,e,{callId:g.callId,output:_,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:v,candidateId:c,submissionRef:m}}const qd=Ze(Te),Jd=`/usr/bin/bwrap`,Yd=[`/usr`,`/bin`,`/sbin`,`/lib`,`/lib64`];function Xd(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function Zd(e,t){if(!e||e.length>2048||Xd(e))throw Error(`${t} contains invalid control characters or is too long`)}function Qd(e,t){let n=t;for(;n<e.length&&/\s/.test(e[n]??``);)n+=1;return n}function $d(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 ef(e,t,n){let r=new Set,i=Qd(e,t+1);if(e[i]===`}`)return i+1;for(;i<e.length;){let t=$d(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=Qd(e,t),e[i]!==`:`)throw Error(`Checker output must be valid JSON`);let o=Qd(e,i+1),s=nf(e,o);if(n?.(a,o,s),i=Qd(e,s),e[i]===`}`)return i+1;if(e[i]!==`,`)throw Error(`Checker output must be valid JSON`);i=Qd(e,i+1)}throw Error(`Checker output must be valid JSON`)}function tf(e,t){let n=Qd(e,t+1);if(e[n]===`]`)return n+1;for(;n<e.length;){if(n=Qd(e,nf(e,n)),e[n]===`]`)return n+1;if(e[n]!==`,`)throw Error(`Checker output must be valid JSON`);n=Qd(e,n+1)}throw Error(`Checker output must be valid JSON`)}function nf(e,t){if(e[t]===`"`)return $d(e,t);if(e[t]===`{`)return ef(e,t);if(e[t]===`[`)return tf(e,t);let n=t;for(;n<e.length&&!/[\s,\]}]/.test(e[n]??``);)n+=1;return n}function rf(e){let t=e.trim();if(Qd(t,nf(t,0))!==t.length)throw Error(`Checker output must be valid JSON`)}function af(e,t){let n=e.trim();if(n[0]!==`{`)return;let r;return ef(n,0,(e,i,a)=>{e===t&&(r=n.slice(i,a).trim())}),r}function of(e,t){let n=e.trim(),r=[];return ef(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 sf(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Checker output must be one JSON object`)}if(rf(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`);Zd(i,`candidate_ref`);for(let e of a)Zd(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=af(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=of(e,i)}return{candidateRef:i,evidenceRefs:a.map(e=>e.trim()),evidence:o,evidenceJson:s}}async function cf(e,t,n){let r=n.trim();if(r.startsWith(`{`)&&r.endsWith(`}`)||!t.result_file)return r;let i=await mf(e),a=w.resolve(i,t.result_file),o=w.relative(i,a);if(o.startsWith(`..`)||w.isAbsolute(o))throw Error(`Checker result_file must stay inside the competition repository`);let s;try{s=await D.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 D.realpath(a)}catch{throw Error(`Checker result_file must resolve to a regular file inside the competition repository`)}let l=w.relative(i,c);if(l.startsWith(`..`)||w.isAbsolute(l))throw Error(`Checker result_file must stay inside the competition repository`);return(await D.readFile(c,`utf8`)).trim()}function lf(e,t){let n=w.relative(e,t);return n===``||!n.startsWith(`..`)&&!w.isAbsolute(n)}function uf(e){return Yd.some(t=>lf(t,e))}async function df(e,t,n){let r=e.includes(`/`)?[w.resolve(t,e)]:(process.env.PATH??``).split(w.delimiter).filter(Boolean).map(t=>w.join(t,e));for(let i of r){let r;try{r=await D.realpath(i),await D.access(r,D.constants.X_OK)}catch{continue}if(!lf(t,r)&&!uf(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 ff(e){let t=[];for(let n of e)try{(await D.stat(n)).isDirectory()&&t.push(n)}catch{}return t}async function pf(e){let t=await D.realpath(Se.homedir());if(e===w.parse(e).root||e===t)throw Error(`Solve checker repository must be a dedicated directory, not the filesystem or home root`)}async function mf(e){let t=await D.realpath(e);return await pf(t),t}async function hf(e){let t=w.join(e,`.git`),n;try{n=await D.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 qd(`/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 gf(e,t,n){let r=await mf(e);if(process.platform!==`linux`)throw Error(`Solve checkers require the Linux sandbox runtime (bubblewrap) with network isolation`);try{await D.access(Jd,D.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 df(t,r,await D.realpath(process.execPath)),a=await hf(r),o=(await ff(Yd)).flatMap(e=>[`--ro-bind`,e,e]),s=lf(r,i)?`/work/${w.relative(r,i)}`:uf(i)?i:`/checker/node`;!lf(r,i)&&!uf(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:Jd,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 _f(e,t){if(!t.command||t.command.includes(`/../`)||Xd(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)Zd(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 mf(e),i;try{let e=await gf(r,t.command,t.args);i=await qd(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{...sf(await cf(r,t,a)),stdout:a,stderr:o}}async function vf(e,t){try{let{root:n,manifest:r}=await Nu(e,t.directory),i=await Ru(n),a=r.provenance?await zu(n,r,i,{allowMissing:!0}):void 0,o=Xl(),s=M(`Running ${r.title} checker…`);t.json||s.start();let c;try{c=await _f(n,r.checker)}finally{s.stop()}let l=Uu(c,a,r.provenance,void 0,{allowMissingSource:!0,requirePullRequest:!1}),u=dt(re(32)),d=Ud(c.candidateRef,u),f={version:1,competition:r.slug,candidateRef:c.candidateRef,evidence:l.evidence,evidenceJson:c.evidenceJson,evidenceRefs:l.evidenceRefs,salt:u,candidateId:d,...a?{source:a}:{},deviceAddress:o.account.address,clientSubmissionId:ie(),createdAt:new Date().toISOString()};await Wu(w.join(n,`.tangle-solve-run.json`),f),t.json?k({localRun:f}):(A(`Checker output recorded locally for operator evaluation`),N({Competition:r.slug,Candidate:c.candidateRef,"Device address":o.account.address,"Evidence refs":l.evidenceRefs.length}),j("Commit any changes, then run `tangle solve submit` from this directory."),r.provenance&&!a&&j(`Add your GitHub fork as 'origin' before submitting. The task repository is available as '${ju}'.`))}catch(e){I(e)}}const yf=/^0x[0-9a-f]{64}$/i;async function bf(e){let t=await hu({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 xf(e,t){try{let{root:n,manifest:r}=await Nu(e,t.directory);fu({profile:t.profile});let i=await Ru(n),a=await Gu(n);if(a.competition!==r.slug)throw Error(`.tangle-solve-run.json does not match this competition`);if(!yf.test(a.salt)||!yf.test(a.candidateId))throw Error("This run predates durable candidate identity. Run `tangle solve run` again");let o=r.provenance?await zu(n,r,i):void 0;if(r.provenance&&a.source&&!Vu(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=Yl();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 _f(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(Ud(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=uu(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 Ku({pullRequest:u,taskRepository:o.taskRepository,submissionRepository:o.submissionRepository,submissionRevision:i})}let d=Uu(l,o,r.provenance,u,{requirePullRequest:!0}),f={...a,...o?{source:o}:{},chainState:{status:`submitting`,transactions:{...a.chainState?.transactions??{}}}},p=w.join(n,`.tangle-solve-run.json`);await Wu(p,f);let m=M(`Submitting candidate to Tempo…`);t.json||m.start();let h;try{h=await Kd(wu(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 Wu(p,f)}})}finally{m.stop()}f={...f,chainReceipt:h,chainState:{status:`accepted`,transactions:{...f.chainState?.transactions??{},...qu(h)}}},await Wu(p,f);let g=await bf({deviceAddress:h.address,signer:s.account,apiUrl:t.apiUrl,profile:t.profile}),_=await mu({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:qu(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?k({..._,transactions:qu(h),candidateId:h.candidateId}):(A(`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 _.id==`string`?_.id:_.submission?.id}))}catch(e){I(e)}}function Sf(){let e=new b(`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`).action(Xu),e.command(`run [competition]`).description(`Run the competition checker and record its evidence`).option(`--directory <path>`,`Competition directory (defaults to the current directory)`).action(vf),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`).action(xf),e.command(`account`).description(`Show the local Solve signing account`).option(`--create`,`Create the account if it does not exist`).action(Ql);let t=e.command(`device`).description(`List and revoke the Solve devices bound to your account`);return t.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`).action(e=>Vd(e)),t.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`).action((e,t)=>Hd(e,t)),e}function Cf(e,t){return`tangle ssh-proxy ${e.replace(/\/+$/,``)}/v1/sidecar-proxy/${t}/ssh`}function wf(e){return/^[A-Za-z0-9_/:=@%+.,-]+$/.test(e)?e:`'${e.replace(/'/g,`'"'"'`)}'`}function Tf(e){return`'${e.replace(/'/g,`''`)}'`}function Ef(e){return e===`win32`?`NUL`:`/dev/null`}function Df(e,t){return t===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN=${Tf(`<token>`)}; ssh ${e.map(Tf).join(` `)}`:`TANGLE_SSH_PROXY_AUTH_TOKEN=${wf(`<token>`)} ssh ${e.map(wf).join(` `)}`}function Of(e){return e.connection!==void 0&&!e.connection.ssh}function kf(){wt(`SSH is not enabled for this sandbox.`),j(`Create a sandbox with --ssh to enable SSH access.`),process.exit(1)}function Af(e,t=[],n=process.platform){let r=Ef(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 jf(){return new b(`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`).allowUnknownOption(!0).action(async(e,t,n)=>{let r=V(n),i=B(r),a=M(`Getting SSH credentials...`);a.start();let o=await U(i,r,e);if(Of(o)){a.stop(),kf();return}o=await W(o);let s=await o.ssh();if(a.stop(),!s){kf();return}let c={...s,proxyCommand:Cf(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=Af(c,[...n.identityFile?[`-i`,n.identityFile,`-o`,`IdentitiesOnly=yes`]:[],...t]);if(n.print){console.log(Df(l,process.platform));return}j(`Connecting via tunnel...`);let u=De(`ssh`,l,{stdio:`inherit`,env:{...process.env,TANGLE_SSH_PROXY_AUTH_TOKEN:r.apiKey}});u.on(`error`,e=>{e.code===`ENOENT`&&(wt(`SSH client not found. Please install OpenSSH.`),process.exit(1)),I(e)}),u.on(`exit`,e=>{process.exit(e??0)})})}function Mf(){let e=new b(`ssh-keys`).description(`Manage SSH keys`);return e.command(`list`).description(`List SSH keys`).action(async e=>{let t=M(`Fetching SSH keys...`);try{t.start();let n=await B(z(e)).sshKeys.list();t.stop(),e.json?k({sshKeys:n}):n.length===0?j(`No SSH keys found.`):jt([`Name`,`Type`,`Fingerprint`,`Created`],n.map(e=>[e.name,e.keyType,e.fingerprint,e.createdAt.toLocaleString()]))}catch(e){t.stop(),I(e)}}),e.command(`add`).description(`Add SSH key`).argument(`<name>`,`SSH key name`).requiredOption(`--key-file <path>`,`Public key file path`).action(async(e,t)=>{let n=M(`Adding SSH key...`);try{let r=C(t.keyFile,`utf8`).trim();n.start();let i=await B(z(t)).sshKeys.create(e,r);n.stop(),t.json?k({sshKey:i}):A(`Added SSH key ${i.name} (${i.fingerprint})`)}catch(e){n.stop(),I(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 B(z(t)).sshKeys.delete(e),n.stop(),A(`Deleted SSH key ${e}`)}catch(e){n.stop(),I(e)}}),e}function Nf(e,t=1){process.stderr.write(`${e}\n`),process.exit(t)}function Pf(){return new b(`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||Nf(`TANGLE_SSH_PROXY_AUTH_TOKEN not set`);let n=new ht(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===ht.OPEN&&n.ping()},15e3),r.unref?.(),process.stdin.on(`data`,e=>{n.readyState===ht.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(),Nf(`WebSocket error: ${e.message}`)}),n.on(`close`,e=>{i(),process.exit(e===1e3?0:1)}),process.stdin.on(`error`,()=>n.close())})}function Ff(){let e=new b(`team`).description(`Manage teams`);return $(e,`list`).description(`List teams for the current account`).action(async e=>{let t=z(e),n=B(t),r=e.json?null:M(`Fetching teams...`);r?.start();let i=await n.teams.list();if(r?.stop(),e.json){k({teams:i,activeTeamId:t.activeTeamId??null});return}O(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}])}),$(e,`create <name>`).description(`Create a team`).option(`--org-id <id>`,`External organization id`).option(`--no-switch`,`Do not set the new team as active`).action(async(e,t)=>{let n=z(t),r=B(n),i=t.json?null:M(`Creating team...`);i?.start();let a=await r.teams.create({name:e,orgId:t.orgId});if(t.switch&&jl(a,n.profile),i?.stop(),t.json){k({team:a,active:!!t.switch});return}A(`Team created: ${kl(a)}`),t.switch&&A(`Active team set to ${a.name}`)}),$(e,`switch <team>`).description(`Set the active team for the current profile`).action(async(e,t)=>{let n=z(t),r=await Al(B(n),e);if(jl(r,n.profile),t.json){k({team:r,activeTeamId:r.id});return}A(`Active team set to ${kl(r)}`)}),e.command(`current`).description(`Show the active team for the current profile`).option(`--profile <profile>`,`Credential profile`).action(e=>{let t=ar(e.profile);if(e.json){k(t.activeTeamId?t:{activeTeamId:null});return}if(!t.activeTeamId){console.log(`No active team.`);return}N({ID:t.activeTeamId,Name:t.activeTeamName})}),e.command(`clear`).description(`Clear the active team for the current profile`).option(`--profile <profile>`,`Credential profile`).action(e=>{if(Ml(e.profile),e.json){k({activeTeamId:null});return}A(`Active team cleared.`)}),$(e,`members [team]`).description(`List team members`).action(async(e,t)=>{let n=z(t),r=B(n),i=await X(r,e,n.profile),a=await r.teams.listMembers(i.id);if(t.json){k({team:i,members:a});return}O(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}])}),$(e,`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`).action(async(e,t)=>{let n=z(t),r=B(n),i=await X(r,t.team,n.profile),a=If(t.role),o=await r.teams.updateMember(i.id,e,{role:a});if(t.json){k({team:i,member:o});return}A(`Member updated: ${o.customerEmail}`),N({Team:i.name,Role:o.role,Status:o.status})}),$(e,`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`).action(async(e,t)=>{let n=z(t),r=B(n),i=await X(r,t.team,n.profile),a=If(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){k({team:i,invitation:o});return}A(`Invitation created for ${o.email}`),N({Team:i.name,Role:o.role,Expires:o.expiresAt,"Invitation ID":o.id}),A(`Re-run with --json to retrieve the invitation token for sharing.`)}),$(e,`leave [team]`).description(`Leave a team as the current user`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=z(t),r=B(n),i=await X(r,e,n.profile);if(!(!t.force&&!t.json&&!await qr(`Leave team '${i.name}'? (y/N) `,`--force`))){if(await r.teams.leave(i.id),n.activeTeamId===i.id&&Ml(n.profile),t.json){k({success:!0,teamId:i.id});return}A(`Left team: ${i.name}`)}}),$(e,`transfer <new-owner-customer-id> [team]`).description(`Transfer team ownership to another active member`).option(`--force`,`Skip confirmation prompt`).action(async(e,t,n)=>{let r=z(n),i=B(r),a=await X(i,t,r.profile);if(!(!n.force&&!n.json&&!await qr(`Transfer ownership of '${a.name}' to ${e}? This cannot be undone without the new owner's cooperation. (y/N) `,`--force`))){if(await i.teams.transferOwnership(a.id,e),n.json){k({success:!0,teamId:a.id,newOwnerCustomerId:e});return}A(`Ownership transferred for ${a.name}`)}}),e.addCommand(Lf()),e.addCommand(Rf()),$(e,`invitations [team]`).description(`List pending and historical team invitations`).action(async(e,t)=>{let n=z(t),r=B(n),i=await X(r,e,n.profile),a=await r.teams.listInvitations(i.id);if(t.json){k({team:i,invitations:a});return}O(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}])}),$(e,`accept <token>`).description(`Accept a team invitation`).option(`--no-switch`,`Do not set the accepted team as active`).action(async(e,t)=>{let n=z(t),r=B(n),i=await r.teams.acceptInvitation(e),a=t.switch===!1?null:await r.teams.get(i.teamId);if(a&&jl(a,n.profile),t.json){k({member:i,activeTeamId:a?.id??null});return}A(`Invitation accepted for team ${i.teamId}`),a&&A(`Active team set to ${a.name}`)}),$(e,`revoke-invitation <invitation-id>`).description(`Revoke a pending team invitation`).action(async(e,t)=>{if(await B(z(t)).teams.revokeInvitation(e),t.json){k({success:!0,invitationId:e});return}A(`Invitation revoked: ${e}`)}),$(e,`remove-member <member-id>`).description(`Remove a member from a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).action(async(e,t)=>{let n=z(t),r=B(n),i=await X(r,t.team,n.profile);if(await r.teams.removeMember(i.id,e),t.json){k({success:!0,teamId:i.id,memberId:e});return}A(`Member removed: ${e}`)}),e}function If(e){if(e===`admin`||e===`member`||e===`viewer`)return e;throw Error(`Role must be one of: admin, member, viewer`)}function Lf(){let e=new b(`secret`).description(`Manage team secrets`);return $(e,`list [team]`).description(`List team secret names`).action(async(e,t)=>{let n=z(t),r=B(n),i=await X(r,e,n.profile),a=await r.teams.listSecrets(i.id);if(t.json){k({team:i,secrets:a});return}O(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}])}),$(e,`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`).action(async(e,t,n)=>{let r=z(n),i=B(r),a=await X(i,n.team,r.profile),o=await Hl({value:t,valueStdin:n.valueStdin,prompt:`Enter value for team secret '${e}': `}),s=await i.teams.upsertSecret(a.id,e,o);if(n.json){k({team:a,secret:s});return}A(`Team secret saved: ${s.name}`)}),$(e,`delete <name>`).description(`Delete a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=z(t),r=B(n),i=await X(r,t.team,n.profile);if(!(!t.force&&!t.json&&!await qr(`Delete team secret '${e}' from '${i.name}'? (y/N) `,`--force`))){if(await r.teams.deleteSecret(i.id,e),t.json){k({success:!0,teamId:i.id,name:e});return}A(`Team secret deleted: ${e}`)}}),$(e,`reveal <name>`).description(`Reveal a team secret value`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).action(async(e,t)=>{let n=z(t),r=B(n),i=await X(r,t.team,n.profile),a=await r.teams.revealSecret(i.id,e);if(t.json){k({teamId:i.id,...a});return}console.log(a.value)}),e}function Rf(){let e=new b(`templates`).description(`Manage team golden-path templates`);return $(e,`list [team]`).description(`List a team's golden-path templates`).action(async(e,t)=>{let n=z(t),r=B(n),i=await X(r,e,n.profile),a=await r.teams.listTemplates(i.id);if(t.json){k({team:i,templates:a});return}if(a.length===0){console.log(`No templates yet for ${i.name}.`);return}O(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}])}),$(e,`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`).action(async(e,t,n)=>{let r=z(n),i=B(r),a=await X(i,n.team,r.profile),o;if(n.config)try{let e=JSON.parse(n.config);if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`--config must be a JSON object`);o=e}catch(e){throw Error(`--config is not valid JSON: ${e instanceof Error?e.message:String(e)}`)}let s=await i.teams.createTemplate(a.id,{name:e,snapshotId:t,description:n.description,environment:n.environment,config:o});if(n.json){k({team:a,template:s});return}A(`Team template created: ${s.name} (${s.id})`)}),$(e,`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`).action(async(e,t)=>{let n=z(t),r=B(n),i=await X(r,t.team,n.profile);if(!(!t.force&&!t.json&&!await qr(`Delete template '${e}' from '${i.name}'? (y/N) `,`--force`))){if(await r.teams.deleteTemplate(i.id,e),t.json){k({success:!0,teamId:i.id,templateId:e});return}A(`Team template deleted: ${e}`)}}),e}function $(e,t){return e.command(t).option(`--profile <profile>`,`Credential profile`)}async function zf(e,t,n){let r=new AbortController,i=()=>r.abort();try{let n=B(z({...e,timeout:void 0}));process.once(`SIGINT`,i),process.once(`SIGTERM`,i);let a=await t(n,{...e.timeout===void 0?{}:{timeoutMs:Number(e.timeout)*1e3},resumeJobId:e.resumeJob,signal:r.signal,onProgress:e=>{process.stderr.write(`Publication ${e.id}: ${e.status}\n`)}}).finally(()=>{process.off(`SIGINT`,i),process.off(`SIGTERM`,i)});e.json?k(a):A(`template`in a?`Published template: ${a.template.slug}`:`Published template version: ${a.version.id}`)}catch(t){if(t instanceof o&&t.status!==401&&t.job&&[`pending`,`scanning`,`ready`].includes(t.job.status)){let e=[`tangle`,`template`,...n,`--resume-job`,t.job.id].map(ys).join(` `);Object.assign(t,{fix:{command:e}})}I(t,e.json)}}function Bf(){let e=new b(`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`).action(async e=>{let t=B(z(e)),n=e.featured?await t.publicTemplates.featured():await t.publicTemplates.list({query:e.query,tag:e.tag});if(e.json){k({templates:n});return}O(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}])}),e.command(`get <id-or-slug>`).action(async(e,t)=>{let n=await B(z(t)).publicTemplates.get(e);if(t.json){k({template:n});return}k(n)}),e.command(`versions <id-or-slug>`).action(async(e,t)=>{let n=await B(z(t)).publicTemplates.versions(e);if(t.json){k({versions:n});return}O(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}])}),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`).action((e,t,n,r)=>zf(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)}),[`publish`,e,t,n])),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`).action((e,t,n,r)=>zf(r,async(i,a)=>({version:await i.publicTemplates.publishVersion(e,{snapshotId:t,sourceSandboxId:n,readmeMarkdown:r.readme,tags:r.tags,releaseNotes:r.releaseNotes},a)}),[`publish-version`,e,t,n])),e}function Vf(){let e=new b(`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])`).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:Qf(e.status),q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:rp(e.limit)},n=Uf(e),r=e.json?null:M(`Fetching traces...`);r?.start();let i=await n.listTraces(t);if(r?.stop(),e.json)return k(i);Kf(i.items),Xf(i.nextCursor)}catch(t){Gf(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`).action(async(e,t)=>{try{let n=Uf(t);if(t.ndjson){await Wf(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:rp(t.limit)});if(r?.stop(),t.json)return k(i);qf(i.items),i.truncated&&N({Spans:`${i.items.length} of ${i.total} (truncated)`}),Xf(i.nextCursor)}catch(e){Gf(e,t)}}),e.addCommand(Hf()),e}function Hf(){let e=new b(`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`).action(async e=>{try{let t={status:e.status===void 0?void 0:ep(e.status),gate:e.gate===void 0?void 0:np(e.gate),label:e.label,from:e.from,to:e.to,q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:rp(e.limit)},n=Uf(e),r=e.json?null:M(`Fetching runs...`);r?.start();let i=await n.listRuns(t);if(r?.stop(),e.json)return k(i);Jf(i.items),Xf(i.nextCursor)}catch(t){Gf(t,e)}}),e.command(`get <runId>`).description(`Show a single eval-run`).action(async(e,t)=>{try{let n=Uf(t),r=t.json?null:M(`Fetching run...`);r?.start();let i=await n.getRun(e);if(r?.stop(),t.json)return k(i);Yf(i)}catch(e){Gf(e,t)}}),e}function Uf(e){let t=Jn(e.apiKey);if(!t)throw Error(`No API key found. Set TANGLE_API_KEY or run: tangle auth login`);return gt({apiKey:t,baseUrl:e.baseUrl??process.env.TANGLE_INTELLIGENCE_BASE_URL})}async function Wf(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 Gf(e,t){return I(e,t.json===!0)}function Kf(e){O(e.map(e=>({traceId:e.traceId,root:e.rootName??`-`,model:e.model??`-`,spans:e.spanCount,errors:e.errorCount,durationMs:e.durationMs,cost:Zf(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 qf(e){O(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 Jf(e){O(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 Yf(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 Xf(e){e&&N({"Next page":`--cursor ${e}`})}function Zf(e){return e===null?`-`:`$${e.toFixed(4)}`}function Qf(e){if(e===`ERROR`||e===`OK`)return e;throw Error(`--status must be ERROR or OK`)}const $f=[`started`,`baseline-complete`,`generation-complete`,`gate-decided`,`finished`,`errored`];function ep(e){let t=$f.find(t=>t===e);if(t)return t;throw Error(`--status must be one of ${$f.join(`, `)}`)}const tp=[`ship`,`hold`,`need_more_work`,`model_ceiling`,`arch_ceiling`];function np(e){let t=tp.find(t=>t===e);if(t)return t;throw Error(`--gate must be one of ${tp.join(`, `)}`)}function rp(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function ip(){return new b(`usage`).description(`Show account usage and billing information`).action(async e=>{let t=B(V(e)),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?k({...r,subscription:i}):(console.log(),console.log(`Account Usage`),console.log(`─`.repeat(40)),N({"Active Sandboxes":r.activeSandboxes,"Total Sandboxes":r.totalSandboxes,"Compute Minutes":ap(r.computeMinutes),"GPU Seconds":r.gpuSeconds,"GPU Spend":op(r.gpuCostUsd)}),i&&(console.log(),console.log(`Subscription`),console.log(`─`.repeat(40)),N({Plan:i.plan,Status:i.status,"Credits Available":op(i.creditsAvailableUsd),"Credits Used":op(i.creditsUsedUsd),"Monthly Balance":op(i.monthlyBalanceUsd)})),console.log(),console.log(`Billing Period`),console.log(`─`.repeat(40)),N({Start:r.periodStart.toLocaleDateString(),End:r.periodEnd.toLocaleDateString()}),console.log())})}function ap(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 op(e){return e<0?`-$${(-e).toFixed(2)}`:`$${e.toFixed(2)}`}function sp(){return new b(`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)=>{if(t.clear){Bn(),j(`Cleared the active sandbox.`);return}if(e){zn(e),j(`Active sandbox set to ${e}. Commands now default to it; override with --box or TANGLE_SANDBOX.`);return}let n=Rn();j(n?`Active sandbox: ${n}`:"No active sandbox. Set one with `tangle use <id>`.")})}function cp(e){O(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 lp(e){e.command(`artifacts`).description(`List a run's artifact metadata (never the bytes)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{try{let r=await(await q(n)).workflows.listArtifacts(e,t);if(n.json)return k(r);cp(r.artifacts)}catch(e){J(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)`).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 k({file:a,contentType:i.contentType,bytes:i.bytes.length});j(`Wrote ${a} (${i.bytes.length} bytes, ${i.contentType}).`)}catch(e){J(e,r)}})}function up(e){O(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 dp(e){e.command(`decisions`).description(`List a workflow's pending human decisions`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{try{let n=(await(await q(t)).workflows.listPendingDecisions()).decisions.filter(t=>t.workflowId===e);if(t.json)return k({decisions:n});up(n)}catch(e){J(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)`).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 k(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){J(e,n)}})}function fp(e){try{return C(e,`utf8`)}catch(t){throw Error(`Could not read workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function pp(e){O(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 mp(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}`),O(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 hp(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`),gp(e.triggers)),e.validationErrors.length>0){j(`Validation issues`);for(let t of e.validationErrors)console.log(` ${t.path}: ${t.message}`)}}function gp(e){O(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 _p(e){e.command(`list`).description(`List your workflows`).action(async e=>{try{let t=await(await q(e)).workflows.list();if(e.json)return k(t);pp(t)}catch(t){J(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`).action(async e=>{try{let t=await(await q(e)).workflows.fleetInsights({window:e.window});if(e.json)return k(t);mp(t)}catch(t){J(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)`).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 k(n);hp(n)}catch(e){J(e,t)}}),e.command(`create`).description(`Create a workflow from a YAML file`).argument(`<file>`,`Path to the workflow YAML`).action(async(e,t)=>{try{let n=fp(e),r=await(await q(t)).workflows.create(n);if(t.json)return k(r);j(`Created workflow ${r.id} (${r.name}).`),hp(r)}catch(e){J(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`).action(async(e,t)=>{try{let n=fp(e),r=await q(t),i=await r.workflows.validate(n,{structural:!0});if(!i.valid){if(process.exitCode=1,t.json)return k(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 k({action:`updated`,workflow:e});j(`Updated workflow ${e.id} (${e.name}) — matched by name.`),hp(e);return}let o=await r.workflows.create(n);if(t.json)return k({action:`created`,workflow:o});j(`Created workflow ${o.id} (${o.name}).`),hp(o)}catch(e){J(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)`).action(async(e,t,n)=>{try{let r=fp(t),i=await(await q(n)).workflows.update(e,r,{...n.note===void 0?{}:{note:n.note}});if(n.json)return k(i);j(`Updated workflow ${i.id} (${i.name}).`),hp(i)}catch(e){J(e,n)}}),e.command(`delete`).description(`Delete a workflow and its triggers`).argument(`<id>`,`Workflow ID`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{try{if(!t.force&&!await qr(`Delete workflow ${e}? `,`--force`)){j(`Delete cancelled.`);return}if(await(await q(t)).workflows.delete(e),t.json)return k({deleted:!0,id:e});j(`Deleted workflow ${e}.`)}catch(e){J(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`).action(async(e,t)=>{try{let n=fp(e),r=await(await q(t)).workflows.validate(n,{...t.structural?{structural:!0}:{}});if(t.json)return k(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){J(e,t)}}),e.command(`schema`).description(`Print the JSON Schema for the workflow YAML`).action(async e=>{try{k(await(await q(e)).workflows.schema())}catch(t){J(t,e)}})}async function vp(e,t,n){try{let r=await(await q(n)).workflows.setEnabled(e,t);if(n.json)return k(r);j(`${t?`Enabled`:`Disabled`} workflow ${r.id}.`),hp(r)}catch(e){J(e,n)}}function yp(e,t){try{return JSON.parse(e)}catch{throw Error(`Invalid ${t}: not valid JSON`)}}function bp(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 xp(e){O(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 Sp(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 Cp(e){e.command(`enable`).description(`Enable a workflow so its triggers and manual runs fire`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{await vp(e,!0,t)}),e.command(`disable`).description(`Disable a workflow (pause its triggers and manual runs)`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{await vp(e,!1,t)}),e.command(`templates`).description(`List the curated starter workflow templates`).action(async e=>{try{let t=await(await q(e)).workflows.listTemplates();if(e.json)return k(t);xp(t)}catch(t){J(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.`,Ws,[]).option(`--file <out>`,`Write the instantiated workflow YAML to this file instead of stdout`).action(async(e,t)=>{try{let n=Gs(t.param,`param`)??{},r=await(await q(t)).workflows.instantiateTemplate(e,n);if(t.json)return k(r);if(!r.created){j(`Template ${e} needs provider connections before it can run:`);for(let e of r.connectionRequirements)console.log(` ${e.connected?`✓`:`✗`} ${Sp(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){bp(t.file,i.definitionYaml),j(`Wrote ${t.file}.`);return}process.stdout.write(i.definitionYaml.endsWith(`
|
|
149
|
-
`)?
|
|
150
|
-
`)?i.
|
|
140
|
+
`)?`${e}\n`:`${e}\n\n`}function go(){let e=process.env.SHELL??``;return e.includes(`zsh`)?D(Se(),`.zshrc`):e.includes(`bash`)?D(Se(),`.bashrc`):D(Se(),`.zshrc`)}function _o(e){if(e===`shell`||e===`env`||e===`dockerfile`)return e;throw Error(`--format must be one of: shell, env, dockerfile (got '${e}')`)}function vo(e){if(e===`full`||e===`prompts`||e===`metadata`)return e;throw Error(`--content must be one of: full, prompts, metadata (got '${e}')`)}async function yo(e){let t=fo({endpoint:e.endpoint,apiKey:e.apiKey,projectKey:e.projectKey,content:e.content,format:e.format});if(console.log(t),e.format!==`shell`){console.log(),N(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(),N(`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??go(),r=process.stdin.isTTY?await ei(`Append this idempotent block to ${n}? (y/N)`,`n`):`n`;if(r.toLowerCase()!==`y`&&r.toLowerCase()!==`yes`){console.log(),N(`Not writing. To append later: tangle connect claude-code --rc ${n}`);return}let i=po({endpoint:e.endpoint,apiKey:e.apiKey,projectKey:e.projectKey,content:e.content,format:e.format}),{contents:a,changed:o}=mo(io(n),i);if(!o){console.log(),M(`Already present in ${n} — nothing to change.`);return}ao(n,a),console.log(),M(`Wrote Tangle Intelligence env block to ${n}.`),N(`Reload your shell (e.g. 'source ${n}') before running the agent.`)}function bo(e){let t=[],n={header:null,body:[]};for(let r of e.split(`
|
|
141
|
+
`))xo(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 xo(e){let t=e.trim();return t.startsWith(`[`)&&t.endsWith(`]`)&&!t.includes(`=`)||t.startsWith(`[[`)&&t.endsWith(`]]`)}function So(e){let t=[];for(let n of e)n.header!==null&&t.push(n.header),t.push(...n.body);return t.join(`
|
|
142
|
+
`)}function Co(e){return[{key:`environment`,line:`environment = "prod"`},{key:`log_user_prompt`,line:`log_user_prompt = true`},{key:`exporter`,line:`exporter = { otlp-http = { endpoint = "${va(e.endpoint)}/v1/logs", protocol = "json", headers = { "Authorization" = "Bearer ${e.apiKey??"${TANGLE_API_KEY}"}" } } }`}]}function wo(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 To(e,t){let n=Co(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=bo(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&&!Eo(r)&&r.body.push(``),i.push(t);let a=Do(So(i));return{contents:a,changed:a!==Do(e)}}let o=a.body.filter(e=>{let t=wo(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=Do(So(i));return{contents:c,changed:c!==Do(e)}}function Eo(e){return e.body.length>0&&e.body[e.body.length-1].trim()===``}function Do(e){return e.endsWith(`
|
|
144
|
+
`)?e:`${e}\n`}function Oo(e){let t=D(Se(),`.codex`,`config.toml`),{contents:n,changed:r}=To(io(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}ao(t,n),M(`Merged the Tangle [otel] block into ${t}.`),N("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."),N(`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 ko(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`${no[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 Ao(e){let t=Date.now()+e.timeoutSeconds*1e3,n=3e3,r=Math.min(e.timeoutSeconds*1e3,1e4),i=P(`Checking whether content is flowing…`);i.start();let a;try{for(;;){try{a=await _a({endpoint:e.endpoint,apiKey:e.apiKey,timeoutMs:r})}catch(e){if(Date.now()>=t)throw e;await Mo(n);continue}if(a.contentSeen||Date.now()>=t)break;await Mo(n)}}finally{i.stop()}if(!a)throw Error(`onboarding status check returned no result`);jo(a,e.agent),a.contentSeen||(process.exitCode=1)}function jo(e,t){if(e.contentSeen){M(`Content flowing — Tangle Intelligence can analyze this feed.`),F({"Last seen":e.lastSeenAt??`just now`,Window:`${e.windowDays}d`});return}if(e.tracesSeen){jt(`Metadata-only — traces are arriving but carry no content. You missed a content gate.`);let n=t?[t]:Object.keys(e.byAgent).filter(ro),r=n.length>0?n:to;for(let n of r){let r=e.byAgent[n];(t||!r||r.tracesSeen&&!r.contentSeen)&&N(ko(n))}return}jt(`No traces yet for your tenant. Run your agent once on a real task, then re-run --verify.`),t&&N(ko(t))}function Mo(e){return new Promise(t=>setTimeout(t,e))}function No(e){let t=e??process.env.TANGLE_INTELLIGENCE_API_KEY??er(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 Po(){return new x(`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(`--endpoint <url>`,`OTLP endpoint base`,na).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)=>{let n=va(t.endpoint);if(t.run){if((e?Io(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 Bo({endpoint:n,apiKey:No(t.apiKey),opencodeUrl:t.opencodeUrl});return}if(t.verify){await Ao({endpoint:n,apiKey:No(t.apiKey),agent:e?Io(e):void 0,timeoutSeconds:eo(t.timeout,`--timeout`)});return}let r=e?Io(e):await Lo(),i=t.inlineKey?No(t.apiKey):void 0;r===`claude-code`?await yo({endpoint:n,apiKey:i,projectKey:t.project,rcPath:t.rc,write:t.write!==!1,content:vo(t.content),format:_o(t.format)}):r===`codex`?Oo({endpoint:n,apiKey:i,projectKey:t.project,write:t.write!==!1}):r===`opencode`?Ro({endpoint:n}):zo(r,{endpoint:n}),console.log(),N(`Run your agent on a real task, then verify content is flowing: tangle connect ${r} --verify`)})}function Fo(){return new x(`opencode-exporter`).description(`Export a running OpenCode's content to Tangle Intelligence (standalone shim)`).option(`--endpoint <url>`,`OTLP endpoint base`,na).option(`--opencode-url <url>`,`OpenCode server base URL (or set OPENCODE_BASE_URL)`).action(async e=>{await Bo({endpoint:va(e.endpoint),apiKey:No(e.apiKey),opencodeUrl:e.opencodeUrl})})}function Io(e){if(ro(e))return e;throw Error(`Unknown agent '${e}'. Choose one of: ${to.join(`, `)}`)}async function Lo(){if(!process.stdin.isTTY)throw Error(`Specify an agent: tangle connect <${to.join(`|`)}>`);console.log(`Which coding agent are you connecting?`),to.forEach((e,t)=>{console.log(` ${t+1}) ${no[e]} (${e})`)});let e=await ei(`Enter a number or name`,`1`);return to[Number.parseInt(e,10)-1]||Io(e.trim())}function Ro(e){let t=va(e.endpoint);jt(`OpenCode has no native OTel exporter, so a standalone install emits nothing without a shim.`),console.log(),F({"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(),N(`Start OpenCode in server mode ('opencode serve'), then in another terminal run: tangle connect opencode --run`),N(`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`),N(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=my-project before starting the exporter.`)}function zo(e,t){let n=va(t.endpoint),r=no[e];jt(`${r} has no native OTel exporter, so a standalone install emits nothing without instrumentation.`),console.log(),F({"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(),N(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=my-project before starting ${r}.`),N(`Verify content is flowing: tangle connect ${e} --verify`)}async function Bo(e){let t=Ya(e.opencodeUrl),n=new AbortController,r=()=>n.abort();process.on(`SIGINT`,r),process.on(`SIGTERM`,r),N(`Subscribing to OpenCode at ${t} — exporting content to Tangle.`),N(`Run OpenCode tasks now. Press Ctrl-C to stop.`),console.log();let i=0,a;try{a=await $a({endpoint:e.endpoint,apiKey:e.apiKey,opencodeBaseUrl:t,signal:n.signal,onExport:({eventType:e,records:t})=>{i+=t,N(`exported ${t} record(s) from ${e} (total ${i})`)}})}catch(e){if(e instanceof Za){let{recordsExported:t,contentEventsExported:n}=e.partial;console.log(),jt(`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){jt(`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).`),N(`Verify it landed: tangle connect opencode --verify`)}function Vo(){let e=new x(`environments`).alias(`env`).description(`Manage sandbox environments`);return e.command(`list`).alias(`ls`).description(`List available environments`).action(async e=>{let{client:t}=U(e),n=P(`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`):Lt([`ID`,`Description`,`Version`],r.map(e=>[e.id,e.description??``,e.version]))}),e.command(`get`).description(`Get environment details`).argument(`<id>`,`Environment ID`).action(async(e,t)=>{let{client:n}=U(t),r=P(`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}`))}),e}function Ho(){return new x(`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`).action(async(e,t,n)=>{try{let{context:r,client:i}=U(n),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=P(`Executing: ${a}`);n.json||s.start();let c=await G(i,r,e);c=await K(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 i){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 Uo(e){e.command(`capabilities`).description(`List fleet drivers and their supported features`).action(async e=>{let{client:t}=U(e),n=P(`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}])}),e.command(`usage <fleet-id>`).description(`Show fleet usage and reliability insights`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Fetching usage...`);r.start();let i=await n.fleets.usage(e);if(r.stop(),t.json)j(i);else if(F({"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}`)}}),e.command(`cost <fleet-id>`).description(`Show the fleet's cost estimate`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Estimating cost...`);r.start();let i=await n.fleets.cost(e);r.stop(),t.json?j(i):F({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})})}function Wo(e){return[...e.entries()].map(([e,t])=>({machineId:e,sandboxId:t.id,status:t.status}))}function Go(e){e.command(`list <fleet-id>`).description(`List the machines of one fleet (fleet id is required)`).option(`--status <status>`,`Filter machines by status`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Fetching fleet...`);r.start();let i=await n.fleets.list({fleetId:e,status:t.status});r.stop();let a=Wo(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}])}),e.command(`get <fleet-id>`).description(`Show one fleet's manifest (server record)`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Fetching manifest...`);r.start();let i=await n.fleets.manifest(e);r.stop(),t.json?j(i):(F({"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}]))}),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`).action(async(e,t)=>{let{client:n}=U(t),r=P(`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}`)}),e.command(`reap`).description(`TTL cleanup of all expired fleets (fleet-wide)`).option(`--dry-run`,`Report what would be reaped without deleting`).action(async e=>{let{client:t}=U(e),n=P(`Reaping expired fleets...`);n.start();let r=await t.fleets.reapExpired({dryRun:e.dryRun});n.stop(),e.json?j(r):(F({"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}]))}),e.command(`reconcile`).description(`Drop fleet records whose underlying sandboxes vanished`).option(`--dry-run`,`Report orphans without removing them`).action(async e=>{let{client:t}=U(e),n=P(`Reconciling fleets...`);n.start();let r=await t.fleets.reconcile({dryRun:e.dryRun});n.stop(),e.json?j(r):(F({"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}]))})}function Ko(e){let t=e.memory?Xo(e.memory,`--accelerator-memory`):void 0;return{kind:Qo(e.kind),count:e.count?Xo(e.count,`--accelerator-count`):1,...t===void 0?{}:{memoryMB:t}}}function qo(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:Yo(e.env,`--gpu-env`,`GPU env`)}:{},maxSpendUsd:$o(e.maxSpendUsd,`--gpu-max-spend-usd`),maxLifetimeSeconds:Xo(e.maxLifetime,`--gpu-max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:Xo(e.idleTimeout,`--gpu-idle-timeout`)}:{}}}}function Jo(e){return{...e.provider?{provider:Zo(e.provider,`GPU provider`)}:{},accelerator:Ko({kind:e.acceleratorKind,count:e.acceleratorCount,memory:e.acceleratorMemory}),...e.image?{image:e.image}:{},...e.env?{env:Yo(e.env,`--env`,`env`)}:{},maxSpendUsd:$o(e.maxSpendUsd,`--max-spend-usd`),maxLifetimeSeconds:Xo(e.maxLifetime,`--max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:Xo(e.idleTimeout,`--idle-timeout`)}:{}}}function Yo(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 Xo(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(r.includes(e))return e;throw Error(`${t} must be one of ${r.join(`, `)}`)}function Qo(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 $o(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 es(e){if(e.spec){let t=JSON.parse(T(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=rs(e),n=is(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=as(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 ts(e){let{base:t,machines:n}=es(e);return{...t,machines:n}}function ns(e){let{base:t,machines:n}=es(e);return{...t,workers:n}}function rs(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=Ko({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 is(e,t){return qo({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 as(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 os(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)`).action(async e=>{let{client:t}=U(e),n=P(`Creating fleet...`);n.start();let r=e.coordinator?await t.fleets.createWithCoordinator(ns(e)):await t.fleets.create(ts(e));n.stop();let i=Wo(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}]))})}function ss(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`).action(async(e,t,n)=>{let{client:r}=U(n),i=P(`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)}),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`).action(async(e,t)=>{let n=/^\d+$/.test(t.agents)?Number(t.agents):JSON.parse(T(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{client:r}=U(t);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=P(`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}):F({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)}),e.command(`cancel <fleet-id>`).description(`Interrupt every agent of a fleet and cancel its child fleets; sandboxes keep running`).action(async(e,t)=>{let{client:n}=U(t),r=await(await n.fleets.list({fleetId:e})).cancel();t.json?j({fleetId:e,...r}):M(`Fleet ${e}: interrupted ${r.interrupted} agents, cancelled ${r.children} child fleets`)})}const cs=[`list`,`create`,`delete`,`exec`,`prompt`,`read`,`write`];function ls(e){if(!(!e||e.length===0)){for(let t of e)if(!cs.includes(t))throw Error(`Invalid token action '${t}'. Allowed: ${cs.join(`, `)}`);return e}}function us(e){return e.length<=12?`****`:`${e.slice(0,6)}...${e.slice(-4)} (masked — use --json for full value)`}function ds(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`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Minting fleet token...`);r.start();let i=await n.fleets.createToken(e,{actions:ls(t.action),ttlMinutes:t.ttlMinutes?Number(t.ttlMinutes):void 0});r.stop(),t.json?j(i):(F({"Fleet ID":i.fleetId,Token:us(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.`))})}function fs(){let e=new x(`workspace`).description(`Manage a fleet's shared workspace`);return e.command(`snapshot <fleet-id>`).description(`Snapshot the fleet's shared workspace`).action(async(e,t)=>{let{client:n}=U(t),r=P(`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}`)}),e.command(`restore <fleet-id> <snapshot-id>`).description(`Restore the fleet's shared workspace from a snapshot`).action(async(e,t,n)=>{let{client:r}=U(n),i=P(`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}`)}),e.command(`reconcile <fleet-id>`).description(`Re-mount the shared workspace on all fleet machines`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Reconciling workspace...`);r.start();let i=await n.fleets.reconcileWorkspace(e);r.stop(),t.json?j(i):(F({"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}]))}),e}function ps(){let e=new x(`fleet`).description(`Manage sandbox fleets`);return os(e),Go(e),e.addCommand(fs()),ss(e),Uo(e),ds(e),e}function ms(){let e=new x(`fs`).description(`File system operations on sandboxes`);return 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`).action(async(e,t,n,r)=>{let{context:i,client:a}=U(r),o=await G(a,i,e);if(o=await K(o),!w.existsSync(t))throw Error(`Local file not found: ${t}`);let s=w.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?It({success:!0,localPath:t,remotePath:n,size:s.size,durationMs:l}):console.log(`✓ Uploaded ${s.size} bytes in ${l}ms`)}),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`).action(async(e,t,n,r)=>{let{context:i,client:a}=U(r),o=await G(a,i,e);o=await K(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=w.statSync(n);r.json||console.error(``),r.json?It({success:!0,remotePath:t,localPath:n,size:l.size,durationMs:c}):console.log(`✓ Downloaded ${l.size} bytes in ${c}ms`)}),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`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a);let o=await a.fs.list(t,{all:n.all,long:n.long});if(n.json)It(o);else if(n.long)Lt([`Mode`,`Owner`,`Group`,`Size`,`Modified`,`Name`],o.map(e=>{let t=e.isDir?`d`:e.isSymlink?`l`:`-`,n=hs(e.permissions),r=e.isDir?`<DIR>`:gs(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(` `))}}),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`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a);let o=await a.fs.stat(t);n.json?It(o):(console.log(` File: ${o.name}`),console.log(` Path: ${o.path}`),console.log(` Size: ${gs(o.size)} (${o.size} bytes)`),console.log(` Type: ${o.isDir?`directory`:o.isSymlink?`symlink`:`file`}`),console.log(` Mode: ${hs(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()}`))}),e.command(`cat`).description(`Print file contents`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to file`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a);let o=await a.read(t);n.json?It({path:t,content:o}):console.log(o)}),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`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a),await a.fs.delete(t,{recursive:n.recursive}),n.json?It({success:!0,path:t,deleted:!0}):console.log(`✓ Deleted: ${t}`)}),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`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a),await a.fs.mkdir(t,{recursive:n.parents}),n.json?It({success:!0,path:t,created:!0}):console.log(`✓ Created: ${t}`)}),e.command(`exists`).description(`Check if a path exists`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to check`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a);let o=await a.fs.exists(t);n.json?It({path:t,exists:o}):(console.log(o?`exists`:`not found`),process.exit(+!o))}),e}function hs(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 gs(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 _s(){let e=new x(`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`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching status...`);t.json||i.start();let a=await G(r,n,e);a=await K(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}`)}}}),e.command(`log`).description(`Show commit log`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`-n, --limit <count>`,`Max commits to show`,`10`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching log...`);t.json||i.start();let a=await G(r,n,e);a=await K(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()})`)}),e.command(`diff`).description(`Show diff`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--ref <ref>`,`Ref to diff against`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching diff...`);t.json||i.start();let a=await G(r,n,e);a=await K(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`)}),e.command(`add`).description(`Stage files`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<paths...>`,`Paths to stage`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a),await a.git.add(t),M(`Staged: ${t.join(`, `)}`)}),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`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=await G(r,n,e);i=await K(i);let a=await i.git.commit(t.message,{amend:t.amend});t.json?j(a):M(`Committed: ${a.shortSha} ${a.message}`)}),e.command(`push`).description(`Push to remote`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--force`,`Force push`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Pushing...`);i.start();let a=await G(r,n,e);a=await K(a),await a.git.push({force:t.force}),i.stop(),M(`Pushed to remote`)}),e.command(`pull`).description(`Pull from remote`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--rebase`,`Rebase instead of merge`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Pulling...`);i.start();let a=await G(r,n,e);a=await K(a),await a.git.pull({rebase:t.rebase}),i.stop(),M(`Pulled from remote`)}),e.command(`branches`).description(`List branches`).argument(`<id-or-name>`,`Sandbox ID or name`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching branches...`);t.json||i.start();let a=await G(r,n,e);a=await K(a);let o=await a.git.branches();i.stop(),t.json?j(o):o.length===0?console.log(`No branches found`):Lt([`Name`,`Current`,`Remote`],o.map(e=>[e.name,e.current?`* `:` `,e.upstream??`-`]))}),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`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a),await a.git.checkout(t,{create:n.create}),M(`Checked out: ${t}${n.create?` (new)`:``}`)}),e}async function vs(e,t,n=`tangle --help`){let r=new AbortController,i=e??r.signal,a=()=>{r.abort(),process.stderr.write(`Stopping…
|
|
148
|
+
`)};e||(process.once(`SIGINT`,a),process.once(`SIGTERM`,a));try{return i.throwIfAborted(),await t(i)}catch(e){if(!i.aborted||e instanceof I&&e.code===`RUN_STOPPED`)throw e;let t=new I(`RUN_STOPPED`,`Command interrupted`,`A stop request ended this execution`,n);throw e instanceof Error&&`runId`in e&&typeof e.runId==`string`&&Object.assign(t,{runId:e.runId}),t}finally{e||(process.off(`SIGINT`,a),process.off(`SIGTERM`,a))}}const ys=`claude,codex,kimi,opencode,gemini,pi`;function bs(e,t){let n;return async(r,{node:i,lastCandidate:a})=>{t.throwIfAborted();let o;try{o=r===void 0?void 0:se(r)}catch(e){throw e instanceof Error&&Object.assign(e,{node:i,seat:r,fixCommand:`tangle graph run --help`}),e}n??=Ge({cwd:e,signal:t,config:Ke({...process.env,BRIDGE_BACKENDS:ys,BRIDGE_SUBSCRIPTIONS_ONLY:`1`})});let s=await n;t.throwIfAborted();let c=e=>e.authentication?.status===`authenticated`&&e.authentication.authMode===`subscription`,l=o?.harness??s.find(e=>e.provider&&c(e))?.backend,u=s.filter(e=>e.backend===l),d=u.filter(c),f=o?u.find(e=>e.id===`${o.harness}/${o.model}`)??d.find(e=>e.provider===o.provider):d.find(e=>e.default)??d.find(e=>e.recommended)??d[0];if(!f||!c(f)){if(a===!1)return;let e=f?.authentication??u[0]?.authentication??(o?void 0:s.find(e=>e.authentication?.fix)?.authentication);throw Object.assign(new I(o?`SEAT_NOT_LOGGED_IN`:`SEAT_NONE_DETECTED`,`Node '${i}' has no available subscription${o?` for ${o.harness}`:``}`,e?`Selected provider: ${e.status} (${e.authMode})`:`No authenticated subscription route was detected`,e?.fix??`tangle graph run --help`),{node:i,seat:r})}let p=o?.harness??se(f.id).harness,m=o?.provider??f.provider,h=o?.model??f.id.slice(p.length+1);if(!m||!h)throw new I(`MODEL_PROVIDER_MISMATCH`,`Node '${i}' has an unresolved model provider`,`Bridge has no configured provider for ${r??p}`,`tangle graph run --help`);return{harness:p,provider:m,model:h,selector:{kind:`all-eligible`},...o?.reasoningEffort===void 0?{}:{reasoningEffort:o.reasoningEffort}}}}async function xs(e,t,n){let r=`tangle secret create ${Ue(t)} --from-login claude`,i=(e,t=r)=>new I(`NATIVE_CREDENTIAL_GRANT_FAILED`,`Claude subscription enrollment failed`,e,t),a;try{a=new URL(e.getBaseUrl())}catch{throw i(`The Sandbox API URL is invalid`,`tangle auth login`)}if(a.protocol!==`https:`||a.username||a.password||a.search||a.hash)throw i(`Native credentials require a credential-free HTTPS Sandbox API URL`,`tangle auth login`);if(!Xe.safeParse({account:`cli`,secretEnv:t,format:`token`}).success)throw i(`The secret name is not valid for a native credential reference`,`tangle secret create --help`);return process.stderr.write(`Authorize Claude in its native browser. Store the token as ${t} at ${a.href}. The token stays out of terminal output.\n`),vs(n,async n=>{let r=await Ss(n,i);n.throwIfAborted();let a=await e.secrets.create(t,r).catch(e=>{if(n.aborted)return;let t=e instanceof l?e.status:void 0;throw i(t?`Sandbox secret storage returned HTTP ${t}; enrollment is unconfirmed`:`Sandbox secret storage did not confirm enrollment`,t===401||t===403?`tangle auth login`:`tangle secret list --json`)});if(await qe(),n.aborted)throw new I(`RUN_STOPPED`,`Native enrollment interrupted`,`Secret upload may already have completed`,`tangle secret list --json`);if(!a||a.name!==t)throw i(`The Sandbox API did not confirm the requested secret name`);return a},r)}async function Ss(e,t){let n=new AbortController,r=We({command:`claude`,args:[`setup-token`],cwd:process.cwd(),signal:AbortSignal.any([e,n.signal]),timeoutMs:12e4,spawnOptions:{stdio:[process.stdin,`pipe`,`pipe`],detached:!1},env:{ANTHROPIC_API_KEY:void 0,ANTHROPIC_AUTH_TOKEN:void 0,CLAUDE_CODE_OAUTH_TOKEN:void 0,ANTHROPIC_BASE_URL:void 0}}),i=``,a=!1,o=new Set,s=e=>{if(!a){if(Buffer.byteLength(i)+e.length>65536){a=!0,i=``,n.abort();return}i+=e.toString(`utf8`);for(let e of i.split(`\x1B]8;;`).slice(1)){let t=Math.min(...[e.indexOf(`\x07`),e.indexOf(`\x1B\\`)].filter(e=>e>=0));if(!Number.isFinite(t))continue;let n=e.slice(0,t);if(!URL.canParse(n))continue;let r=new URL(n);![`https://platform.claude.com/oauth/authorize`,`https://claude.com/cai/oauth/authorize`].includes(`${r.origin}${r.pathname}`)||r.username||r.password||r.hash||/sk-ant-|(?:access_token|refresh_token|id_token|code|key)=/.test(r.href)||![`client_id`,`state`,`redirect_uri`,`code_challenge`].every(e=>r.searchParams.has(e))||o.has(r.href)||(o.add(r.href),process.stderr.write(`Open to authorize Claude:\n${r.href}\n`))}Ye(i).includes(`Paste code here`)&&!o.has(`code`)&&(o.add(`code`),process.stderr.write(`Paste the code shown in your browser into this terminal and press Enter: `))}};r.process.stdout?.on(`data`,s),r.process.stderr?.on(`data`,s);let c=await r.exitPromise;if(e.throwIfAborted(),!c.success||a)throw t(a?`Native consent output exceeded its private capture bound`:c.timedOut?`Native browser consent timed out`:c.spawnError?`The native claude command could not start`:`Native consent exited ${c.code??c.signal??`without a result`}`);let l=[...new Set([...Ye(i).matchAll(/Your OAuth token \(valid for[^\n]*\):\s+([\s\S]*?)\s+Store this token securely/g)].map(e=>e[1].replace(/\s/g,``)))];if(i=``,l.length!==1||!/^sk-ant-oat\d+-[A-Za-z0-9_-]+$/.test(l[0]))throw t(`Native consent returned no unambiguous subscription token`);return l[0]}async function Cs(e,t,n){let r=new Map;for(let e of new Set(t)){if(e!==`claude-code`&&e!==`codex`)throw new I(`NATIVE_CREDENTIAL_UNSUPPORTED`,`Cloud subscription grant for ${e} is unavailable`,`This Sandbox native credential channel supports Claude Code and Codex`,`tangle graph run --help`);r.set(e,{account:`cli`,secretEnv:e===`claude-code`?`CLAUDE_TOKEN`:`CODEX_AUTH`,format:e===`claude-code`?`token`:`bundle`})}let i=await e.secrets.list();for(let[t,a]of r)if(n.throwIfAborted(),!i.some(e=>e.name===a.secretEnv)){if(t!==`claude-code`)throw new I(`NATIVE_CREDENTIAL_NOT_ENROLLED`,`Codex cloud credential is not enrolled`,`A local Codex login does not grant the Sandbox API a stored credential reference`,`tangle secret create CODEX_AUTH --value-stdin`);await xs(e,a.secretEnv,n)}return r}function J(e){throw new I(`GRAPH_INVALID`,`Graph creation failed`,e,`tangle graph new --help`)}function ws(e){return typeof e==`string`&&/^[a-z0-9][a-z0-9-]{0,62}$/i.test(e)}const Ts={maxBarren:2,failures:`verbatim`,panel:`off`,bar:`on`,profile:{id:`graph-new-v1`,opening:`The graph has not passed its outside check.`,plan:`Repair the concrete diagnostics with write_graph, run the saved file and submit the actual evidence.`,rules:`Completion requires a successful host run and unchanged YAML. Retain working graph content when blocked.`,headings:{failures:`Failures`,protected:`Passing checks`,changed:`Changes`,findings:`Findings`,bar:`Acceptance`,plan:`Next`,rules:`Rules`}}};var Es=class{owned;lastFailure;pending=Promise.resolve();revision=0;sealed=!1;constructor(e,t,n){this.directory=e,this.options=t,this.cwd=n}async digest(e=this.owned){e||J(`No graph file was saved`);let t=await Be(e.file,le.O_RDONLY|le.O_NOFOLLOW);try{let[n,r]=await Promise.all([t.stat(),e.handle.stat()]);return(!n.isFile()||n.dev!==r.dev||n.ino!==r.ino)&&J(`The owned graph file was replaced`),Qs(await t.readFile())}finally{await t.close()}}enqueue(e){let t=++this.revision,n=this.pending.then(()=>e(t));return this.pending=n.then(()=>void 0,()=>void 0),n}check=()=>this.enqueue(async e=>{let t=this.owned;if(!t?.result)return!1;let{digest:n,result:r}=t,i=await this.digest(t),a=this.revision===e&&this.owned===t&&t.digest===n&&t.result===r&&i===n;return a&&(this.sealed=!0),a});receipt(){this.owned?.result||J(`No successful graph run was recorded`);let{file:e,digest:t,result:n}=this.owned;return{file:e,digest:t,result:n}}invoke(e,t){return this.sealed&&J(`The graph is accepted; submit its recorded successful run`),this.enqueue(()=>this.write(e,t)).catch(e=>(this.lastFailure=e,{ok:!1,diagnostic:Jt(e)}))}async write(e,t){t.throwIfAborted(),this.lastFailure=void 0;let n=e;(!n||!ws(n.name)||typeof n.source!=`string`||typeof n.run!=`boolean`||Object.keys(n).some(e=>![`name`,`source`,`run`].includes(e)))&&J(`Expected only name, source and boolean run`),this.options.name!==void 0&&n.name!==this.options.name&&J(`The graph name must match --name`),this.owned&&(this.owned.result=void 0);let r=D(this.directory,`${n.name}.yaml`);if(this.owned&&this.owned.file!==r&&J(`This invocation owns one named graph file`),!this.owned)try{this.owned={file:r,handle:await Be(r,le.O_RDWR|le.O_CREAT|le.O_EXCL|le.O_NOFOLLOW,384),digest:Qs(``)}}catch(e){throw e.code===`EEXIST`&&J(`Graph already exists: ${r}; choose another --name`),e}let i=this.owned;await this.digest()!==i.digest&&J(`The owned graph was changed`);let a=Buffer.from(n.source);for(let e=0;e<a.length;){let{bytesWritten:t}=await i.handle.write(a,e,a.length-e,e);if(!t)throw Error(`Graph file write made no progress`);e+=t}await i.handle.truncate(a.length),await i.handle.sync(),i.digest=Qs(a);let o={seat:this.options.seat,param:[]},s={cwd:this.cwd,signal:t,source:n.source},c=await ac(r,{...o,dryRun:!0},s);if(`graph`in c||J(`No canonical graph was returned`),c.graph.deliverable.checkRef===`command`&&J(`Host command checks need a jailed verifier node`),await this.digest()!==i.digest&&J(`Graph changed during validation`),!n.run)return{file:r,graphDigest:c.graph.digest,validated:!0};let l=await ac(r,o,{...s,graphDigest:c.graph.digest});return(!(`status`in l)||l.status!==`winner`||l.graphDigest!==c.graph.digest||await this.digest()!==i.digest)&&J(`The graph must succeed with unchanged YAML`),i.result=l,this.receipt()}async close(){await this.pending,await this.owned?.handle.close()}};async function Ds(e,t,n){let{runId:r,runDir:i,cwd:a,bridge:o,signal:s}=e,c=await o(),l=D(await He(D(Se(),`.tangle`)),`graphs`);($s(a,l)||$s(l,a))&&J(`The graph store must be outside the agent workspace; choose another working directory`);try{await ze(l,{mode:448})}catch(e){if(e.code!==`EEXIST`)throw e}await He(l)!==l&&J(`The graph store redirects outside its canonical location`);let u=n.seat??B().seat,d=await bs(a,s)(u,{node:`graph-designer`,cwd:a,signal:s,lastCandidate:!0});d||J(`No authenticated native subscription is available`);let{graphDesignerProfile:f}=await import(`@tangle-network/agent-runtime/profiles`),{supervisePursuit:p}=await import(`@tangle-network/agent-runtime/durable`),m=f({profile:{name:`graph-designer`,harness:d.harness,model:{provider:d.provider,default:d.model,...d.reasoningEffort===void 0?{}:{reasoningEffort:d.reasoningEffort}},prompt:{instructions:[`You are the sole graph designer. Author a canonical YAML graph for the requested intent, then qualify and run it using write_graph. Its nodes are complete AgentProfiles with a real independent verifier and declarative route/data outside check. Command checks execute on the host and are refused here; put executable verification in the verifier node's normal native tools. Read the supplied skills and preserve the user's task and authority.`,`Call write_graph with name, complete YAML source and run:false to validate; repair its concrete diagnostics, then call it with the identical source and run:true. The graph schema and executor are owned by the installed loader. Supply defaults for parameters needed by the first run. Only a real successful host run of the unchanged saved file passes. Submit that evidence using submit_result; explain concrete blockers using report_blocked.`]},tools:{agent_runtime_coordination_write_graph:!0,agent_runtime_coordination_submit_result:!0,agent_runtime_coordination_read_continuation:!0,agent_runtime_coordination_report_blocked:!0}}}),h=ae(m),g=new Es(l,{...n,seat:u},a),_={maxIterations:6,maxTokens:3e4,deadlineMs:3e5};try{let e=await p(m,{intent:t,name:n.name},{pursuitId:r,runId:r,runDir:i,signal:s,backend:{...c,timeoutMs:_.deadlineMs},budget:_,maxDepth:0,coordination:{authentication:!0,requestTimeoutMs:_.deadlineMs},deliverable:{describe:`The saved graph succeeds with unchanged YAML`,check:g.check,checkState:g.check},continuation:Ts,resolveSupervisorTools:e=>e.runId!==r||e.nodeId!==r||e.depth!==0||e.identity.profileDigest!==h?[]:[{name:`write_graph`,description:`Save, validate and run this graph.`,inputSchema:{type:`object`,properties:{name:{type:`string`},source:{type:`string`},run:{type:`boolean`}},required:[`name`,`source`,`run`],additionalProperties:!1},handler:(t,n)=>((n.nodeId!==e.nodeId||n.ownerId!==e.ownerId||n.runId!==e.runId)&&J(`Wrong graph tool owner`),g.invoke(t,n.signal))}]});if(e.result.kind===`no-winner`||!await g.check()){if(g.lastFailure)throw g.lastFailure;let t=e.result.kind===`no-winner`?e.result.error?.message??e.result.reason:`The graph file changed after its successful run`;throw Object.assign(new I(`GRAPH_DESIGN_FAILED`,`Graph design did not finish`,t,`tangle graph new --help`),{runId:r,node:`graph-designer`})}return g.receipt()}finally{await g.close()}}function Os(e){e.command(`new <intent>`).description(`Design, validate and run one portable graph`).option(`--seat <seat>`,`Use harness/model@effort for the designer and graph`).option(`--name <name>`,`Save this graph name`).action(async(e,t)=>{process.env.BRIDGE_JAIL_RW_PATHS?.trim()&&J(`Remove BRIDGE_JAIL_RW_PATHS before graph new; extra native write roots cannot contain its host store`),t.name!==void 0&&!ws(t.name)&&J(`Use letters, numbers and hyphens in --name`);let n=await tc({},n=>Ds(n,e,t));t.json?j(n):N(`Created ${n.file} · run ${n.result.runId}`)})}const ks=[`claude-code`,`opencode`,`codex`,`kimi-code`,`prime`],As=process.env.TANGLE_ROUTER_URL??`https://router.tangle.tools/v1`;function js(e){let t=oe(e);if(t)return t;throw Error(`--model '${e}' has no provider. Pass a canonical id, for example 'google/${e}'.`)}function Ms(e,t){return{...e,harness:t}}function Ns(e){let t=e.harness??`claude-code`;if(!ks.includes(t))throw Error(`Unknown --harness '${t}'. Supported: ${ks.join(`, `)}.`);let n=Ps(e.maxTokens,2e5,`--max-tokens`),r=Ps(e.maxIterations,50,`--max-iterations`),i=e.maxWorkers===void 0?void 0:Ps(e.maxWorkers,0,`--max-workers`);return{harness:t,...e.model?{model:e.model}:{},maxTokens:n,maxIterations:r,...i===void 0?{}:{maxWorkers:i}}}function Ps(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 Fs(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 Is(e){return{async create(t){let n=await e.client.create(Ls(t));return e.onCreate({id:n.id,status:`spawned`}),n}}}function Ls(e){if(!e?.env)return e;let{TANGLE_API_KEY:t,...n}=e.env;return{...e,env:n}}function Rs(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:zs(r)?r.content:JSON.stringify(r),...n,status:`winner`}}function zs(e){return typeof e==`object`&&!!e&&typeof e.content==`string`}let Bs=null;function Vs(){return Bs??=import(`@tangle-network/agent-runtime/kernel`).catch(e=>{throw Bs=null,e?.code===`ERR_MODULE_NOT_FOUND`?new I(`RUNTIME_UNAVAILABLE`,`Agent Runtime could not be loaded`,e.message,`npm install -g @tangle-network/sandbox-cli@latest`):e}),Bs}async function Hs(e,t,n){let r=V({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=H(r),{budget:a,perWorker:o}=Fs(t),s=[],c=Is({client:i,onCreate:e=>{s.push(e),n.json||N(`worker ${e.id} spawned`)}}),l=await Vs(),u=l.workerFromBackend({backend:`sandbox`,sandboxClient:c,maxIterations:1}),d=(e,n)=>u(Ms(e,t.harness),n),f={name:`supervisor`,harness:`cli-base`,model:{default:t.model??`gemini-2.5-flash-lite`,provider:t.model?js(t.model):`google`},tools:{agent_runtime_coordination_spawn_worker:!0,agent_runtime_coordination_observe_agent:!0}},p={routerBaseUrl:As,routerKey:r.apiKey},m=Rs(await l.supervise(f,{goal:e},{budget:a,makeWorkerAgent:d,router:p,...o?{perWorker:o}:{},...t.model?{allowedModels:[t.model]}:{},runId:`supervise-${S()}`})),h=m.status===`winner`?`settled`:`failed`;for(let e of s)e.status=h,n.json||N(`worker ${e.id} settled (${e.status})`);return{task:e,result:m.text,workers:s,tokenUsage:m.tokenUsage,costUsd:m.costUsd,status:m.status}}function Us(){let e=new x(`supervise`);return e.description(`Run a budget-conserving supervisor that spawns isolated sandbox workers to deliver a task.`).argument(`<task>`,`What the supervisor should accomplish`).option(`--harness <name>`,`Worker harness (${ks.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(`--max-workers <n>`,`Bound the fanout; each worker reserves floor(max-tokens / n) tokens and floor(max-iterations / n) iterations`).action(async(e,t)=>{let n=Ns({harness:t.harness,model:t.model,maxTokens:t.maxTokens,maxIterations:t.maxIterations,maxWorkers:t.maxWorkers});t.json||(N(`Supervising: ${e}`),N(`harness=${n.harness} budget=${n.maxTokens}tok/${n.maxIterations}it`),console.log());let r=await Hs(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()),F({"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}`)}),e}function Y(e){return Vr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.baseUrl===void 0?{}:{baseUrl:e.baseUrl}})}const Ws=1e3;function Gs(e,t){return[...t,e]}function Ks(e,t=`input`,n){if(n===void 0&&!e?.length)return;let r={};if(n!==void 0)try{if(r=JSON.parse(T(n,`utf8`)),!r||typeof r!=`object`||Array.isArray(r)||Object.entries(r).some(([e,t])=>!e.length||typeof t!=`string`))throw Error(`Invalid input map`)}catch{throw new I(`WORKFLOW_INPUT_FILE_INVALID`,`Could not load --input-file '${n}'`,`Expected a readable JSON object with nonempty keys and string values`,`tangle workflows run --help`)}let i=Object.entries(r);for(let n of e??[]){let e=n.indexOf(`=`);if(e<=0)throw Error(`Invalid --${t} "${n}": expected key=value (e.g. pull_request.number=123)`);i.push([n.slice(0,e),n.slice(e+1)])}return Object.fromEntries(i)}function qs(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 Js(e){if(F({"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){N(`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&&(N(`Graph`),F({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&&(N(`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 Ys(e){if(e.status===`cancelled`){N(`Cancelled run ${e.runId}.`);return}if(e.signalled){N(`Cancelling run ${e.runId} — signalled the worker; it will stop shortly.`);return}N(`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 Xs(e){switch(e.type){case`snapshot`:N(`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 Zs(e){e.command(`run`).description(`Trigger an immediate run of a workflow`).argument(`<id>`,`Workflow ID`).option(`--input-file <file>`,`Trigger inputs from a flat JSON string map; --input overrides its keys`).option(`--input <key=value>`,`Trigger input as key=value (e.g. pull_request.number=123). Repeatable.`,Gs,[]).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)`).action(async(e,t)=>{let n=Ks(t.input,`input`,t.inputFile),r=t.timeout===void 0?void 0:eo(t.timeout,`--timeout`),i=t.pollInterval===void 0?void 0:eo(t.pollInterval,`--poll-interval`),a=await Y(t),{runId:o}=await a.workflows.run(e,n);if(!t.wait){if(t.json)return j({runId:o});N(`Started run ${o} for workflow ${e}.`),N(`Inspect it with: tangle workflows run-detail ${e} ${o}`);return}let s=t.json?null:P(`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);Js(c)}),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`).action(async(e,t)=>{let n=await Y(t),r=t.limit===void 0?void 0:eo(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>=Ws){s=c.nextCursor,t.json||N(`Stopped after ${Ws} 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});qs(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);qs(i.runs),i.nextCursor&&N(`More runs available — next page: --cursor ${i.nextCursor}`)}),e.command(`run-detail`).description(`Show a single run's detail (per-action output and errors)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.getRun(e,t);if(n.json)return j(r);Js(r)}),e.command(`cancel`).description(`Cancel a queued or in-progress run`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.cancel(e,t);if(n.json)return j(r);Ys(r)}),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)`).action(async(e,t,n)=>{let r=n.timeout===void 0?void 0:eo(n.timeout,`--timeout`),i=n.pollInterval===void 0?void 0:eo(n.pollInterval,`--poll-interval`),a=await Y(n),o=await a.workflows.retryRun(e,t);if(!n.wait){if(n.json)return j(o);N(`Started run ${o.runId} (retry of ${t}).`),N(`Inspect it with: tangle workflows run-detail ${e} ${o.runId}`);return}let s=n.json?null:P(`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);Js(c)}),e.command(`events`).description(`Tail a run's live progress events until it finishes`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await Y(n);for await(let i of r.workflows.watchRun(e,t))n.json?console.log(JSON.stringify(i)):Xs(i),i.type===`run.done`&&i.status===`failed`&&(process.exitCode=1)})}const Qs=e=>ne(`sha256`).update(e).digest(`hex`);function $s(e,t){let n=ve(e,t);return n!==`..`&&!n.startsWith(`..${be}`)&&!_e(n)}function ec(e,t){if(/[\\/]/.test(e)||/\.(yaml|yml|json)$/.test(e))return ye(t,e);let n=t;for(;!ue(D(n,`.git`))&&he(n)!==n;)n=he(n);ue(D(n,`.git`))||(n=t);let r=[D(n,`.tangle`,`graphs`,`${e}.yaml`),D(Se(),`.tangle`,`graphs`,`${e}.yaml`)],i=r.find(ue);if(i)return i;throw new I(`GRAPH_NOT_FOUND`,`Graph '${e}' was not found`,`Looked in ${r.join(` and `)}`,`tangle graph --help`)}async function tc(e,t){return vs(e.signal,async n=>{let r=S(),i;try{let a=D(Se(),`.tangle`,`runs`,r);await ze(a,{recursive:!0,mode:448});let o=await He(D(Se(),`.tangle`)),s=await He(e.cwd??process.cwd()),c=[`runs`,`graph-registry`,`graphs`].some(e=>$s(s,D(o,e))||$s(D(o,e),s))?D(Se(),`.tangle`,`workspaces`,r):s;await ze(c,{recursive:!0,mode:448});let l;return await t({runId:r,runDir:a,cwd:c,bridge:()=>l??=(async()=>{n.throwIfAborted();let e=re(32).toString(`hex`),{loadConfig:t,startServer:r}=await import(`cli-bridge`);return i=await r({cwd:c,config:{...t({...process.env,BRIDGE_HOST:`127.0.0.1`,BRIDGE_PORT:`3344`,BRIDGE_BEARER:e,BRIDGE_DATA_DIR:D(a,`bridge`),BRIDGE_BACKENDS:ys,BRIDGE_JAIL_MODE:`fs-jail`,BRIDGE_JAIL_FALLBACK:`deny`,BRIDGE_SUBSCRIPTIONS_ONLY:`1`}),port:0},handleSignals:!1,quiet:!0}),{backend:`bridge`,bridgeUrl:i.url,bridgeBearer:e,cwd:c}})(),signal:n})}catch(e){throw e instanceof Error&&Object.assign(e,{runId:r}),e}finally{await i?.close()}},`tangle graph --help`)}function nc(e){throw new I(`GRAPH_CLOUD_UNAVAILABLE`,`Cloud subscription execution was refused`,e,`tangle graph run --help`)}function rc(e){(e.observed||!e.entry||e.deliverable.checkRef===`command`)&&nc(`Cloud needs an executable flow and portable outside check; root coordination and host checks are unsupported`);let{digest:t,...n}=e;return{...n,nodes:e.nodes.map(({id:e,profile:t})=>{t.seats&&nc(`Node '${e}' has an account-selection chain; direct single-account execution cannot drop it`);let n=t.model?.metadata?.credentialSource;return n!==void 0&&n!==`subscription`&&nc(`Node '${e}' declares a non-subscription credential source`),{id:e,profile:ie.parse({...t,model:{...t.model,metadata:{...t.model?.metadata,credentialSource:`subscription`}}})}})}}async function ic(e,t,n){let r=[...new Set(e.nodes.map(({profile:e})=>e.harness))];(r.length!==1||!r[0])&&nc(`Direct cloud execution currently needs one concrete harness across nodes`);let i=U(t).client,a=(await Cs(i,[r[0]],n)).get(r[0]);a||nc(`No enrolled native reference for ${r[0]}`);let{createTangleProvider:o}=await import(`@tangle-network/agent-provider-tangle`);return{backend:`provider`,provider:o({client:i,modelCredentials:{cliAuth:a},requireNativeSessionCapture:!0}),destroyOnSettle:!0,requireTerminalEvent:!0}}async function ac(e,t,n={}){try{return await vs(n.signal,async r=>{let i=await Vs();r.throwIfAborted();let a=ec(e,n.cwd??process.cwd()),o=n.source??(t.cloud?await Ve(a,`utf8`):void 0),s=o===void 0?void 0:Qs(o),c=async e=>{r.throwIfAborted();let c=await i.loadGraphFile(a,{source:o,seat:t.seat??B().seat,resolveSeat:bs(e,r),params:Ks(t.param,`param`),cwd:e,signal:r});if(r.throwIfAborted(),n.graphDigest&&c.graph.digest!==n.graphDigest)throw new I(`GRAPH_CHANGED`,`The validated graph changed before execution`,`Its compiled graph digest no longer matches validation`,`tangle graph run --help`);if(!t.cloud)return c;let l=rc(c.graph);return{...c,sourceGraph:c.graph,sourceDigest:s,graph:{...l,digest:i.graphDigest(l)}}};return t.dryRun?c(n.cwd??process.cwd()):tc({...n,signal:r},async({runId:e,runDir:n,cwd:o,bridge:l})=>{let u=await c(o),{superviseGraphPursuit:d}=await import(`@tangle-network/agent-runtime/durable`),f=i.graphRegistry(D(Se(),`.tangle`,`graph-registry`)),p=`sourceGraph`in u?u.sourceGraph:u.graph;t.cloud&&await i.recordStoredGraphRun(f,p);let m=await i.recordStoredGraphRun(f,u.graph),h=t.cloud?await ic(m,t,r):await l(),g=new Date().toISOString(),_=new Map;N(`Run ${e} · ${me(a)} · ${o}`);let v=await d(i.graphFromStored(m),{pursuitId:m.digest,runDir:n,runId:e,backend:h,signal:r,hooks:{onEvent:e=>{let t=e.payload;e.target===`agent.spawn`&&t?.childId&&typeof t.label==`string`&&_.set(t.childId,t.label);let n=_.get(t?.childId??e.parentId??``);process.stderr.write(`${n?`${JSON.stringify(n)} `:``}${e.target} ${JSON.stringify(t?.status??e.phase)}\n`)}}}),ee={runId:e,graphDigest:m.digest,...t.cloud?{authoredGraphDigest:p.digest,sourceDigest:s}:{},...Rs(v.result.result)},y=v.result.result;if(await i.recordStoredGraphRun(f,m,{graphDigest:m.digest,...t.cloud?{evidence:[{kind:`authored-graph`,url:`urn:sha256:${p.digest}`},{kind:`authored-yaml`,url:`urn:sha256:${s}`}]}:{},taskDigest:i.taskShapeDigest({graph:me(a),params:u.params}),startedAt:g,finishedAt:new Date().toISOString(),outcome:y.kind===`no-winner`?{kind:`no-winner`,reason:y.reason}:{kind:`delivered`,summary:ee.text},cost:{iterations:y.spentTotal.iterations,ms:y.spentTotal.ms,...Object.fromEntries(Object.entries({inputTokens:ee.tokenUsage.input,outputTokens:ee.tokenUsage.output,usd:ee.costUsd}).filter(([,e])=>e!==null))},traversals:v.result.ledger.length,exhaustedEdges:v.result.exhaustedEdges,source:{kind:`tangle-cli-graph`,id:e}}),y.kind===`no-winner`)throw Object.assign(new I(`GRAPH_RUN_FAILED`,`Graph '${me(a)}' finished without a result`,y.reason,`tangle graph run --help`),{runId:e,runtimeFailures:y.tree.nodes.filter(e=>e.failure).map(e=>({node:e.label,failure:e.failure}))});return ee})},`tangle graph --help`)}catch(n){throw n instanceof I&&n.code===`RUN_STOPPED`&&Object.assign(n,{fix:[`tangle graph run`,Ue(e),...t.dryRun?[`--dry-run`]:[],...t.cloud?[`--cloud`]:[],...t.seat?[`--seat`,Ue(t.seat)]:[],...t.param.flatMap(e=>[`--param`,Ue(e)])].join(` `)}),n}}function oc(){let e=new x(`graph`).description(`Build and run portable agent graphs`);return Os(e),e.command(`run <name-or-file>`).description(`Run a saved graph over native subscriptions`).option(`--cloud`,`Run each node in a Tangle sandbox using your subscription`).option(`--seat <seat>`,`Use harness/model@effort for every node`).option(`--param <key=value>`,`Graph parameter; repeatable`,(e,t)=>[...t,e],[]).option(`--dry-run`,`Validate and print the graph without starting agents`).action(async(e,t)=>{let n=await ac(e,t);t.json||t.dryRun?j(n):`status`in n&&(N(`${n.status} · ${n.runId}`),n.text&&console.log(n.text))}),e}function sc(){let e=new x(`hub`).description(`Discover and run Tangle Hub tools`);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.`,Sc,[]).action(async(e,t)=>{let n=Cc(t.parameter),r=await(await W(t)).connections.start(e,{cli:!0,connectionParameters:n});if(t.json){j(Tc(r));return}wc(r,t.browser===!1?!1:await Ti(r.redirectUrl))});let t=new x(`connections`).description(`List Hub provider connections`).action(async e=>{let t=await(await W(e)).connections.list();if(e.json){j(t);return}xc(t.connections)});t.command(`revoke <connection-id>`).description(`Revoke a Hub provider connection`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=await W(t),r=await Sr(n,e);if(!t.force&&!await $r(`Revoke Hub connection ${r}? `,`--force`)){N(`Revoke cancelled.`);return}let i=await n.connections.revoke(r);if(t.json){j(i);return}N(`Revoked Hub connection ${i.connection.id}.`)}),e.addCommand(t);let n=new x(`permissions`).description(`Manage Hub action permissions`);n.command(`list`).description(`List Hub permissions for a connection`).requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);let t=await W(e),n=await Sr(t,e.connection),r=await t.permissions.list(n);if(e.json){j(r);return}gc(r.policies)}),n.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`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);if(!e.action)throw Error(`--action is required.`);let t=_c(e.decision),n=await W(e),r=await Sr(n,e.connection),i=await n.permissions.set({connectionId:r,actionPath:e.action,decision:t});if(e.json){j(i);return}gc([i.policy])}),n.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]`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);let t=await W(e),n=await Sr(t,e.connection),r=await t.permissions.revertWrites(n);if(e.json){j(r);return}N(`Reverted ${r.reverted} write permission${r.reverted===1?``:`s`} for connection ${r.connectionId}.`)}),e.addCommand(n);let r=new x(`approvals`).description(`List and resolve Hub execution approvals`);r.command(`list`).description(`List pending Hub execution approvals`).action(async e=>{let t=await(await W(e)).approvals.list();if(e.json){j(t);return}dc(t.approvals)}),r.command(`approve`).description(`Approve a pending Hub execution approval`).argument(`approval-id`,`Hub approval ID`).action(async(e,t)=>{uc(e),fc(await(await W(t)).approvals.approve(e),t.json===!0)}),r.command(`deny`).description(`Deny a pending Hub execution approval`).argument(`approval-id`,`Hub approval ID`).action(async(e,t)=>{uc(e),fc(await(await W(t)).approvals.deny(e),t.json===!0)}),e.addCommand(r);let i=new x(`tools`).description(`Discover Hub tools`);return i.command(`sources`).description(`List Hub tool sources`).action(async e=>{let t=await(await W(e)).tools.sources();if(e.json){j(t);return}vc(t.sources)}),i.command(`describe`).description(`Describe a Hub tool`).argument(`path`,`Executor tool path`).action(async(e,t)=>{let n=await(await W(t)).tools.describe(e);if(t.json){j(n);return}yc(n.tool)}),i.command(`search`).description(`Search Hub tools`).argument(`<query...>`,`Search query`).option(`--provider <provider>`,`Filter by provider/source ID`).action(async(e,t)=>{let n=await(await W(t)).tools.search(e.join(` `),{provider:t.provider});if(t.json){j(n);return}hc(n.tools)}),e.addCommand(i),e.addCommand(cc(`call`)),e.addCommand(cc(`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`).action(async(e,t)=>{if(uc(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 W(t);fc(t.decline?await n.approvals.deny(e):await n.approvals.approve(e),t.json===!0)}),e.command(`status`).description(`Show Hub auth and connection status`).action(async e=>{let t=await(await W(e)).status();if(e.json){j(t);return}Ec(t)}),e}function cc(e){return new x(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`).action(async(e,t)=>{let{args:n,approve:r}=lc(e,t),{path:i,input:a}=mc(n),o=await W(t),s=t.connection?await Sr(o,t.connection):void 0;j((await o.tools.invoke(i,a,{connectionId:s,approve:r})).result)})}function lc(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 uc(e){if(!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`Hub approval ID must contain only letters, numbers, underscores, and dashes.`)}function dc(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 fc(e,t){if(t){j(pc(e));return}N(`Hub approval ${e.approval.id} ${e.approval.status}.`),e.capabilityToken&&N("Capability token minted. Re-run the original command with `--approve` to execute automatically.")}function pc(e){return{approval:e.approval,...e.capabilityToken?{capabilityToken:{tokenId:e.capabilityToken.tokenId,expiresAt:e.capabilityToken.expiresAt}}:{}}}function mc(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 hc(e){A(e.map(e=>({path:e.path,provider:e.providerId??e.requiredConnectionProviderId,title:e.title,description:e.description,connection:bc(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 gc(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 _c(e){if(e===`allow`||e===`ask`||e===`deny`)return e;throw Error(`--decision must be one of: allow, ask, deny.`)}function vc(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 yc(e){F({Path:e.path,Provider:e.providerId??e.requiredConnectionProviderId,Title:e.title,Description:e.description,Connection:bc(e),Policy:e.policyState}),e.inputSchema!==void 0&&(N(`Input schema`),console.log(JSON.stringify(e.inputSchema,null,2))),e.outputSchema!==void 0&&(N(`Output schema`),console.log(JSON.stringify(e.outputSchema,null,2)))}function bc(e){if(e.connectionRequired===!1)return`not required`;if(e.connectionStatus)return e.connectionStatus}function xc(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 Sc(e,t){return[...t,e]}function Cc(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 wc(e,t){t?N(`Opened browser to connect ${e.provider}.`):(N(`Open this URL to connect ${e.provider}:`),console.log(e.redirectUrl)),N("Finish authorization in the browser, then rerun `tangle hub status`.")}function Tc(e){return{provider:e.provider,redirectUrl:e.redirectUrl,expiresAt:e.expiresAt,scopes:e.scopes,cli:e.cli}}function Ec(e){let{principal:t,connections:n}=e;N(`Hub status`),F({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&&N(`Some providers require reconnect.`)}function Dc(){let e=new x(`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(`--endpoint <url>`,`OTLP endpoint base`,na).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`).action(async(e,t)=>{let n=e??`local`;sa(n);let r=kc(t.apiKey),i=await fa({selection:n,workspace:t.workspace,apiKey:r,endpoint:t.endpoint,serviceName:t.serviceName??la(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}F({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})}),e.command(`doctor`).description(`Check whether your agent traces carry CONTENT or are metadata-only`).option(`--endpoint <url>`,`OTLP endpoint base`,na).action(async e=>{let t=da(),n=await _a({endpoint:e.endpoint===`https://intelligence.tangle.tools/v1/otlp`?t?.endpoint??`https://intelligence.tangle.tools/v1/otlp`:e.endpoint,apiKey:kc(e.apiKey??t?.apiKey)});e.json?j(n):Oc(n),n.contentSeen||(process.exitCode=1)}),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(`--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`).action(async e=>{try{let t=Ac(e.agent),n=da(),r={agent:t,event:e.event,endpoint:e.endpoint??n?.endpoint??`https://intelligence.tangle.tools/v1/otlp`,apiKey:kc(e.apiKey??n?.apiKey),serviceName:e.serviceName??n?.serviceName??la(process.cwd()),environment:e.environment??n?.environment??`local`,sessionId:e.sessionId,payload:e.payload===void 0?await Mc():jc(e.payload)};if(e.dryRun){let n=ma(r);if(e.json){j(n);return}F({Trace:n.traceId,Agent:t,Event:e.event});return}let i=await ha(r);if(e.json){j({traceId:i});return}F({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`).action(async(e,t)=>{await Nc({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`).action(async(e,t)=>{await Nc({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`).action(async e=>{await Nc({type:Fc(e.subjectType),id:e.subjectId},e)}),e.command(`get <job-id>`).description(`Get an intelligence report`).action(async(e,t)=>{let{client:n}=U(t),r=t.json?null:P(`Fetching intelligence report...`);r?.start();let i=await n.intelligence.getReport(e);if(r?.stop(),t.json){j(i);return}Pc(i)}),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`).action(async e=>{let{client:t}=U(e),n=e.json?null:P(`Fetching intelligence reports...`);n?.start();let r=await t.intelligence.listReports({subjectType:e.subjectType===void 0?void 0:Fc(e.subjectType),subjectId:e.subjectId,limit:e.limit===void 0?void 0:Rc(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}])}),e}function Oc(e){F({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 kc(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 Ac(e){if(ca(e))return e;throw Error(`agent must be a known Tangle Intelligence agent surface`)}function jc(e){try{return JSON.parse(e)}catch(e){throw Error(`--payload must be JSON: ${e instanceof Error?e.message:String(e)}`)}}async function Mc(){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 Nc(e,t){let n=Ic(t.mode),r=zc(t.metadata),i=t.maxUsd===void 0?void 0:Lc(t.maxUsd);if(n===`agentic`&&i===void 0)throw Error(`Agentic intelligence reports require --max-usd`);let{client:a}=U(t),o=t.json?null:P(`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}Pc(s)}function Pc(e){F({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 Fc(e){if(e===`sandbox`||e===`fleet`)return e;throw Error(`subject type must be sandbox or fleet`)}function Ic(e){if(e===`deterministic`||e===`agentic`)return e;throw Error(`mode must be deterministic or agentic`)}function Lc(e){let t=Number(e);if(!Number.isFinite(t)||t<0)throw Error(`--max-usd must be a non-negative number`);return t}function Rc(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function zc(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 Bc=[`router`,`sandbox`,`blueprint-agent`,`evals`,`agent-builder`];async function Vc(e,t){let n=await Lr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.platformUrl===void 0?{}:{baseUrl:e.platformUrl},...e.baseUrl===void 0?{}:{sandboxBaseUrl:e.baseUrl}});if(!t||!n.minted)return n;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 Hc(e,t,n={}){let r=new Headers(n.headers);n.body&&!r.has(`content-type`)&&r.set(`content-type`,`application/json`);let i=await Rr(e,t,{...n,headers:r});if(n.expected!==void 0&&i.status!==n.expected)throw Error(await Uc(i,t));return i}async function Uc(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 Wc=[`ID`,`Prefix`,`Name`,`Product`,`Created`,`Last used`,`Expires`];function Gc(e){return[e.id,e.keyPrefix??``,e.name,e.product??`all`,e.createdAt,e.lastUsedAt??`—`,e.expiresAt??`—`]}function Kc(){let e=new x(`keys`).description(`Manage sk-tan-* API keys on id.tangle.tools`);return e.command(`list`).description(`List your active API keys`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async e=>{let t=await Vc(e,!1),n=t.baseUrl,r=await(await Hc(t,`${n}/v1/keys`,{expected:200})).json();if(e.json){j(r);return}Lt(Wc,r.data.map(Gc))}),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 (${Bc.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(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{if(t.product!==void 0&&!Bc.includes(t.product))throw Error(`Invalid --product. Expected one of ${Bc.join(`, `)}`);let n=await Vc(t,!0),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=P(`Creating API key...`);a.start();let o=await Hc(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}…`),N(`Copy this key now — it will never be shown again:\n${s.data.key}`)}),e.command(`revoke`).description(`Revoke an API key`).argument(`<keyId>`,"Key ID (from `tcloud keys list`)").option(`--yes`,`Skip the confirmation prompt`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{let n=await Vc(t,!0),r=n.baseUrl;if(!t.yes&&!await $r(`Revoke key ${e}? Any service still using it will start to fail.`,`--yes`)){N(`Aborted.`);return}let i=await(await Hc(n,`${r}/v1/keys/${encodeURIComponent(e)}`,{method:`DELETE`,expected:200})).json();if(t.json){j(i);return}M(`Revoked ${e}`)}),e}function qc(e){if(Un().token)throw Error(`A line relay cannot manage numbers or attachments. Use your owner CLI outside the agent box.`);return H(V(e))}function Jc(e){if(!e.yes)throw Error(`Review the selected line and use --yes to authorize this change. Attaching enables metered agent work.`)}function Yc(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 Xc(e){return e().catch(R)}async function Zc(e){let t=await Be(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 Qc(e){e.command(`providers`).description(`List provider transports supported by this Hub deployment`).action(e=>Xc(async()=>{j(await qc(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`).action(e=>Xc(async()=>{j(await qc(e).lines.list({profileId:e.profileId,sandboxId:e.sandbox}))})),e.command(`get`).argument(`<line-id>`).description(`Inspect a line and its current attachment`).action((e,t)=>Xc(async()=>{j(await qc(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`).action((e,t)=>Xc(async()=>{let n=Yc(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 qc(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`).action((e,t)=>Xc(async()=>{Jc(t);let n=Yc(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 qc(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`).action((e,t)=>Xc(async()=>{Jc(t);let n=qc(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 Zc(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(cr()).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`).action((e,n)=>Xc(async()=>{Jc(n),j({[t]:await qc(n).lines[t](e)})}));e.command(`threads`).argument(`<line-id>`).description(`List this line's separate participant threads`).action((e,t)=>Xc(async()=>{j(await qc(t).lines.threads(e).list())})),e.command(`messages`).argument(`<line-id>`).argument(`<thread-id>`).description(`Read one authorized participant thread`).action((e,t,n)=>Xc(async()=>{j(await qc(n).lines.threads(e).messages(t))}))}async function $c(e){let{token:t,baseUrl:n}=Un();if(t===void 0)return W(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 Oe({baseUrl:n,authHeaders:()=>({Authorization:`Bearer ${t}`})})}async function el(e,t){if(t)return t;if(!Un().token)throw Error(`Provide --line <line-id>`);return(await e.lines.context()).line.id}function tl(e){return e().catch(R)}function nl(){return new x(`context`).description(`Show live line identity, members, consent, reminders and quotas`).action(e=>tl(async()=>{j(await(await $c(e)).lines.context())}))}function rl(){let e=new x(`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`).action(e=>tl(async()=>{let t=await $c(e);j(await t.lines.members.list(await el(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`).action((e,t,n)=>tl(async()=>{let r=await $c(n),i=await el(r,n.line);if(!Un().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`).action((e,t)=>tl(async()=>{if(!t.at)throw Error(`--at is required`);let n=await $c(t),r=t.idempotencyKey??ne(`sha256`).update(JSON.stringify([e,t.at])).digest(`hex`).slice(0,32);j(await n.lines.remind(await el(n,t.line),{text:e,notBefore:t.at,idempotencyKey:r}))})),Qc(e),e}function il(){let e=new x(`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)=>{let n=V({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=await G(H(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))})}),e}async function al(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=Nn(),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??$n():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=V({apiKey:a,baseUrl:r}),s=H(o);return t.self?et(s):G(s,o,e)}async function ol(e,t,n){let r=P(e);t||r.start();try{return await n()}finally{r.stop()}}function sl(e){return e}function cl(){let e=new x(`preview`).description(`Manage sandbox preview links`);return sl(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)=>{let n=await al(e,t),r=await ol(`Starting managed preview...`,t.json,()=>Qe(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}`))}),sl(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)=>{let n=await al(e,t),r=await ol(`Fetching preview links...`,t.json,()=>n.previewLinks.list());t.json?j(r):r.length===0?console.log(`No preview links found`):Lt([`App`,`Preview ID`,`Port`,`URL`,`Status`],r.map(e=>[ll(e.metadata),e.previewId.slice(0,12),String(e.port),e.url,e.status]))}),sl(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)=>{if(!t.port||!/^\d+$/.test(t.port))throw Error(`An integer service port is required`);let n=await al(e,t),r=await ol(`Publishing service...`,t.json,()=>$e(n,{port:Number(t.port),name:t.name}));t.json?j(r):M(`Preview ready: ${r.url}`)}),sl(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)=>{if(!/^\d+$/.test(t)||Number(t)<1||Number(t)>65535)throw Error(`Port must be an integer between 1 and 65535`);let r=await al(e,n),i=await ol(`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}`))}),sl(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)=>{let r=await al(e,n);await ol(`Removing preview...`,n.json,()=>r.previewLinks.remove(t)),n.json?j({success:!0,previewId:t}):M(`Preview removed: ${t}`)}),e}function ll(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 ul(){let e=new x(`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)`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),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=P(`Spawning: ${t}`);n.json||o.start();let s=await G(i,r,e);if(s=await K(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`))}}),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`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching processes...`);t.json||i.start();let a=await G(r,n,e);a=await K(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`):Lt([`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()]))}),e.command(`get`).description(`Get detailed info about a process`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Fetching process info...`);n.json||a.start();let o=await G(i,r,e);o=await K(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()}`))}),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`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Sending ${n.signal} to PID ${t}...`);n.json||a.start();let o=await G(i,r,e);o=await K(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}`)}),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`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a);let o=await a.process.get(Number.parseInt(t,10));if(!o){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}for await(let e of o.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))}),e}const dl=[`python`,`node`,`typescript`,`bash`];function fl(e){switch(ge(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 pl(e){if(e===`-`){let e=[];for await(let t of process.stdin)e.push(typeof t==`string`?Buffer.from(t):t);return Buffer.concat(e).toString(`utf8`)}return await Ve(ye(e),`utf8`)}async function ml(e,t,n=pl){let r=t?dl.find(e=>e===t)??(()=>{throw Error(`unknown --lang ${t}: must be one of ${dl.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=fl(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 hl(e){return D(Ce(),`tangle-run-images`,e)}function gl(){return new x(`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: ${dl.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`).action(async(e,t,n)=>{let{language:r,source:i}=await ml(t,n.lang),{context:a,client:o}=U(n),s=await G(o,a,e);s=await K(s);let c=P(`Running ${r} (${i.length}b)…`);n.json||c.start();let l=await s.runCode(r,i,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10)});if(c.stop(),n.json){j(l),l.exitCode!==0&&process.exit(l.exitCode);return}l.stdout&&process.stdout.write(l.stdout),l.stderr&&process.stderr.write(l.stderr);let u=0;for(let t of l.results)if(t.type===`image`)if(n.saveImages!==!1){let r=typeof n.saveImages==`string`?n.saveImages:hl(e);de(r,{recursive:!0});let i=`${r}/${Date.now()}-${u}.${t.format}`;pe(i,Buffer.from(t.data,`base64`)),process.stderr.write(b.green(`✓ image → ${i}\n`)),u++}else process.stderr.write(b.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(b.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(b.gray(`… ${t.rows.length-20} more rows\n`))}else t.type===`json`?(process.stderr.write(b.gray(`[json] `)),process.stderr.write(`${JSON.stringify(t.value,null,2)}\n`)):t.type===`html`?process.stderr.write(b.gray(`[html ${t.value.length}b]\n`)):t.type===`error`?(process.stderr.write(b.red(`✗ ${t.name}: ${t.message}\n`)),t.traceback&&process.stderr.write(`${t.traceback}\n`)):t.type===`text`&&process.stderr.write(`${t.value}\n`);l.error&&(process.stderr.write(b.red(`\n✗ ${l.error.name}: ${l.error.message}\n`)),l.error.traceback&&process.stderr.write(`${l.error.traceback}\n`)),l.exitCode!==0&&process.exit(l.exitCode)})}async function _l(e,t){let n=await Lr({apiKey:t.apiKey,baseUrl:t.baseUrl??cr()}),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 vl(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 ti();if(t.length===0)throw Error(`${e.flagPrefix}-stdin received empty input on stdin`);return t}}function yl(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 bl(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 xl(e,t){let n={};return e.cpu!==void 0&&(n.cpuCores=Xo(e.cpu,`--cpu`)),e.memory!==void 0&&(n.memoryMB=Xo(e.memory,`--memory`)),e.disk!==void 0&&(n.diskGB=Xo(e.disk,`--disk`)),t&&(n.accelerator=t),Object.keys(n).length>0?n:void 0}function Sl(e){let t=e.split(`/`);return t.length>=2?{provider:t[0],model:t.slice(1).join(`/`)}:{model:e}}function Cl(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]=wl(r.join(`=`))}return t}function wl(e){try{return JSON.parse(e)}catch{return e}}function Tl(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`?Xo(e.gitDepth,`--git-depth`):void 0,sparse:Array.isArray(e.gitSparse)?e.gitSparse:void 0,auth:t?{token:t}:void 0}}}function El(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:Dl(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 Dl(e){if(e===`s3`||e===`gcs`||e===`r2`)return e;throw Error(`--storage-type must be one of s3, gcs, or r2`)}function Ol(e){N(` Status: ${e.status}`),N(` Provider: ${e.provider}`),N(` GPU: ${e.accelerator.kind} x ${e.accelerator.count}`),e.customerPricePerHourUsd!==void 0&&N(` Customer price: $${e.customerPricePerHourUsd}/hr`),e.estimatedCustomerCostUsd!==void 0&&N(` Max estimate: $${e.estimatedCustomerCostUsd}`),e.billing&&(N(` Billed seconds: ${e.billing.seconds}`),N(` Customer cost: $${e.billing.customerCostUsd}`))}function kl(e){e.result.stdout&&process.stdout.write(e.result.stdout),e.result.stderr&&process.stderr.write(e.result.stderr),N(`Exit code: ${e.result.exitCode}`)}function Al(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`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Checking GPU providers...`);i.start();let a=await(await G(r,n,e)).gpu.providers(t.acceleratorKind?{accelerator:Ko({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&&N(`${e.provider}: ${t}`)}a.usable.length===0&&N(`No GPU provider is usable on this deployment: set the variables in Needs for one provider on the server.`)}),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`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Attaching GPU lease...`);i.start();let a=await(await G(r,n,e)).gpu.attach(Jo(t));i.stop(),t.json?j(a):(M(`GPU lease attached: ${a.id}`),Ol(a))}),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`).action(async(e,t,n)=>{let r,i,a,o;try{let{context:a,client:o}=U(n),s=await G(o,a,e),c=P(`Attaching GPU lease...`);c.start(),r=await s.gpu.attach(Jo(n)),c.stop();let l=P(`Running GPU command...`);l.start(),i=await s.gpu.exec(r.id,{command:t.join(` `),timeoutMs:n.timeout?Xo(String(n.timeout),`--timeout`):void 0,cwd:n.cwd,env:n.env?Yo(n.env,`--env`,`env`):void 0}),l.stop(),n.json||kl(i)}catch(e){a=e}finally{if(r)try{let{context:t,client:i}=U(n);r=await(await G(i,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`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching GPU leases...`);i.start();let a=await(await G(r,n,e)).gpu.list();i.stop(),t.json?j(a):a.length===0?N(`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}])}),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)`).action(async(e,t,n,r)=>{let{context:i,client:a}=U(r),o=P(`Running GPU command...`);o.start();let s=await(await G(a,i,e)).gpu.exec(t,{command:n.join(` `),timeoutMs:r.timeout?Xo(String(r.timeout),`--timeout`):void 0,cwd:r.cwd,env:r.env?Yo(r.env,`--env`,`env`):void 0});o.stop(),r.json?j(s):kl(s)}),t.command(`detach <id-or-name> <lease-id>`).description(`Detach and destroy a GPU lease`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Detaching GPU lease...`);a.start();let o=await(await G(i,r,e)).gpu.detach(t);a.stop(),n.json?j(o):(M(`GPU lease detached: ${o.id}`),Ol(o))})}function jl(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.`),N(`Operation: ${e.id}`),N(`Status: ${e.statusUrl}`)}function Ml(e){return`${e.name} (${e.id})`}async function Nl(e,t){if(t.startsWith(`team_`))return e.teams.get(t);let n=(await e.teams.list()).filter(e=>e.name.toLowerCase()===t.toLowerCase());if(n.length===0)throw Error(`Team not found: ${t}`);if(n.length>1)throw Error(`Team name is ambiguous: ${t}. Use a team id instead.`);return n[0]}async function X(e,t,n){if(t)return Nl(e,t);let r=dr(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 Pl(e,t){fr({id:e.id,name:e.name},t)}function Fl(e){pr(e)}async function Il(e){if(e.explicitTeam&&e.personal)throw Error(`--team and --personal cannot be used together`);if(!e.personal)return e.explicitTeam?(await Nl(e.client,e.explicitTeam)).id:e.activeTeamId}async function Ll(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 Nl(e.client,e.explicitTeam)).id}`;if(e.activeTeamId)return`team:${e.activeTeamId}`}function Rl(e){return!e||e.authToken===void 0?e:{...e,authToken:`[REDACTED]`}}function zl(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`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=t.nonce===`auto`?_():t.nonce,a=P(`Fetching TEE attestation...`);a.start();let o=await(await G(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}`))}),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`).action(async e=>{let{context:t,client:n}=U(e),r=P(`Fetching sandboxes...`);r.start();let i=await Ll({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}])}),e.command(`get <id-or-name>`).description(`Get sandbox details`).option(`--profile`,`Show the active agent profile provenance (name, hash, skills)`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching sandbox...`);i.start();let a=await G(r,n,e);if(i.stop(),t.profile){let e=a.getProfileProvenance?.();e?(N(`Agent profile provenance:`),N(` Base profile: ${e.base.name??`(inline)`} (${e.base.sha256.slice(0,12)}...)`),N(` Effective: ${e.effective.name??`(inline)`} (${e.effective.sha256.slice(0,12)}...)`),N(` Materialized: ${e.materializedAt}`),e.base.sha256!==e.effective.sha256&&N(` ⚠ Profile changed since creation (base ≠ effective)`)):N(`No profile materialized (bare sandbox). Create with --profile <name> to install one.`);return}t.json?j(a):Ft({id:a.id,name:a.name,status:a.status,resources:a.resources,createdAt:a.createdAt?.toISOString(),expiresAt:a.expiresAt?.toISOString(),connection:a.connection})}),e.command(`shapes`).description(`List the named sandbox sizes, the default, and this account's ceiling`).action(async e=>{let{client:t}=U(e),n=await t.shapes();if(e.json){j(n);return}let r=e=>e.cpuCores<=n.ceiling.cpuCores&&e.memoryMB<=n.ceiling.memoryMB&&e.diskGB<=n.ceiling.diskGB;A(n.presets.map(e=>({name:e.name===n.default?`${e.name} (default)`:e.name,cpu:e.cpuCores,memory:`${e.memoryMB} MB`,disk:`${e.diskGB} GB`,available:r(e)?`yes`:e.name===n.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}]),N(`Ceiling for this account: ${Pt(n.ceiling)}`)}),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`).action(async(e,t)=>{if(!t.force&&!await $r(`Delete sandbox ${e}? [y/N] `,`--force`)){N(`Cancelled.`);return}let{context:n,client:r}=U(t),i=P(`Deleting sandbox...`);i.start();let a=await Kr(r,n,e,{retryCleanup:t.retryCleanup,name:t.name});i.stop(),M(a===`already_absent`?`Sandbox ${e} was already gone.`:`Sandbox ${e} deleted.`)}),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`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Stopping sandbox...`);i.start();let a=await G(r,n,e,{nameOnly:t.name});if(t.wait===!1){let e=await a.stop({wait:!1});i.stop(),jl(e.info,!!t.json);return}await a.stop(),i.stop(),M(`Sandbox ${e} stopped.`)}),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`).action(async(e,t)=>{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=V({apiKey:t.apiKey,baseUrl:t.baseUrl,timeout:n}),i=H(r),a=P(`Resuming sandbox...`);a.start();let o=await G(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.`)})}function Bl(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 (${t.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`).action(async e=>{let t=await vl({envVarName:e.gitTokenEnv,fromStdin:e.gitTokenStdin,flagPrefix:`--git-token`}),n=await vl({envVarName:e.storageSecretAccessKeyEnv,fromStdin:e.storageSecretAccessKeyStdin,flagPrefix:`--storage-secret-access-key`}),r=await vl({envVarName:e.backendApiKeyEnv,fromStdin:e.backendApiKeyStdin,flagPrefix:`--backend-api-key`}),i=yl({secret:e.cliAuth,backend:e.backend,apiKeyGiven:r!==void 0}),a;if(e.profileStdin){let e=await ti(`--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(T(t,`utf8`))}catch(e){R(Error(`--profile ${t}: ${e.message}`));return}else try{a=await _l(t,e)}catch(e){R(Error(`--profile ${t}: ${e.message}`));return}}let o=V({apiKey:e.apiKey,baseUrl:e.baseUrl,timeout:e.timeout?Number.parseInt(e.timeout,10):void 0}),s=H(o),c=P(`Creating sandbox...`);c.start();let l=await Il({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?Cl(e.metadata):void 0,f=Tl(e,t),p=El(e,n),m=e.acceleratorKind?Ko({kind:String(e.acceleratorKind),count:String(e.acceleratorCount),memory:typeof e.acceleratorMemory==`string`?e.acceleratorMemory:void 0}):void 0,h=qo({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`),_=e.driver?{type:e.driver,enableCriu:e.driverCriu||void 0,preferredRegion:e.driverRegion}:void 0,ee=e.backend||e.backendModel||a?{...e.backend?{type:v(e.backend)}:{},...a?{profile:a}:{},model:e.backendModel||r||i?{...e.backendModel?Sl(e.backendModel):{},apiKey:r,...i?{cliAuth:i}:{}}:void 0}:void 0,y=bl(e.secret),b=i?[...new Set([...y??[],i.secretEnv])]:y,te=xl(e,m),x=[...e.sshKey?[e.sshKey]:[],...(e.sshKeyFile??[]).map(e=>T(e,`utf8`).trim())],ne={name:e.name,environment:e.environment,bare:e.bare||void 0,sshEnabled:e.ssh||!!e.sshKey||x.length>0||!!e.sshKeys?.length,sshPublicKeys:x.length>0?x:void 0,sshKeyIds:e.sshKeys,webTerminalEnabled:e.webTerminal,env:Object.keys(u).length>0?u:void 0,git:f,...te?{resources:te}:{},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:b,metadata:d,driver:_,backend:ee},re=e.tee?{tee:e.tee,sealed:e.sealed||void 0,attestationRefresh:e.attestationRefresh||e.attestationNonce===`auto`||void 0}:void 0,S=re?await g(s,{...ne,confidential:re,attestationNonce:e.attestationNonce??(e.attestationRefresh?`auto`:void 0),requireAttestation:e.requireAttestation??!0}):void 0,C=S?.sandbox??await s.create(ne);e.wait&&(c.text=`Waiting for sandbox to start...`,await C.waitFor(`running`,{timeoutMs:12e4}),await C.refresh()),c.stop(),e.json?j({id:C.id,name:C.name,status:C.status,resources:C.resources,createdAt:C.createdAt,expiresAt:C.expiresAt,connection:Rl(C.connection),teamId:l,gpuLease:C.gpuLease,confidential:re,attestation:S?.attestation,attestationNonce:S?.attestationNonce}):(M(`Sandbox created: ${C.id}`),Ft({id:C.id,name:C.name,status:C.status,resources:C.resources,createdAt:C.createdAt?.toISOString(),expiresAt:C.expiresAt?.toISOString(),connection:C.connection}),l&&console.log(`Team: ${l}`),C.gpuLease&&(console.log(`GPU lease: ${C.gpuLease.id}`),Ol(C.gpuLease)),re&&(console.log(`TEE: ${re.tee}`),console.log(`Attestation: ${S?.attestation?`present`:`not returned`}`),S?.attestationNonce&&console.log(`Attestation nonce: ${S.attestationNonce}`)))})}function Vl(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`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Updating network configuration...`);i.start();let a=await G(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):(N(`Network Configuration:`),e.ports&&e.ports.length>0?N(` Exposed Ports: ${e.ports.join(`, `)}`):N(` 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&&N(` Exposed Ports: ${o.ports.join(`, `)}`))}),e.command(`expose <id-or-name>`).description(`Expose a port and get a public URL`).option(`-p, --port <port>`,`Port to expose`,`8000`).action(async(e,t)=>{let{context:n,client:r}=U(t),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=P(`Exposing port ${i}...`);a.start();let o=await(await G(r,n,e)).network.exposePort(i);a.stop(),t.json?j({port:i,url:o}):(M(`Port ${i} exposed.`),N(` URL: ${o}`))}),e.command(`urls <id-or-name>`).description(`List exposed port URLs for a sandbox`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching exposed URLs...`);i.start();let a=await(await G(r,n,e)).network.listUrls();if(i.stop(),t.json)j(a);else{let e=Object.entries(a);if(e.length===0)N(`No ports exposed.`);else{N(`Exposed Ports:`);for(let[t,n]of e)N(` ${t}: ${n}`)}}})}function Hl(){let e=new x(`sandbox`).description(`Manage sandboxes`);return Bl(e),zl(e),Al(e),Vl(e),e}function Ul(){return new x(`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`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Searching...`);n.json||a.start();let o=await G(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`)})}function Wl(){let e=new x(`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(`--from-login <harness>`,`Authorize Claude in its native browser and store its token privately`).action(async(e,t,n)=>{if(n.fromLogin!==void 0&&(n.fromLogin!==`claude`||t!==void 0||n.valueStdin))throw new I(`NATIVE_CREDENTIAL_ARGUMENTS`,`Native enrollment arguments are invalid`,`Use --from-login claude without a value argument or --value-stdin`,`tangle secret create --help`);let r=U(n).client,i=n.fromLogin===void 0?await r.secrets.create(e,await Gl({value:t,valueStdin:n.valueStdin,prompt:`Enter value for secret '${e}': `})):await xs(r,e);n.json?j(i):(M(`Secret created: ${i.name}`),N(`Use --secrets ${i.name} when creating a sandbox to inject it as an environment variable.`))}),e.command(`list`).description(`List all secrets`).action(async e=>{let t=await U(e).client.secrets.list();e.json?j(t):t.length===0?(N(`No secrets found.`),N(`Use 'tangle secret create <name> [value]' to create one.`)):Lt([`Name`,`Created At`,`Updated At`],t.map(e=>[e.name,e.createdAt.toLocaleString(),e.updatedAt.toLocaleString()]))}),e.command(`delete`).description(`Delete a secret`).argument(`<name>`,`Secret name`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=U(t).client;if(!t.force&&!await $r(`Are you sure you want to delete secret '${e}'? This cannot be undone. (y/N) `,`--force`)){N(`Cancelled.`);return}await n.secrets.delete(e),t.json?j({success:!0,deleted:e}):M(`Secret deleted: ${e}`)}),e}async function Gl(e){if(e.value!==void 0&&e.valueStdin)throw Error(`Provide either a secret value argument or --value-stdin, not both`);let t=e.value??(e.valueStdin?await ti():await Qr(e.prompt));if(!t.length)throw Error(e.valueStdin?`Secret value from stdin cannot be empty`:`Secret value cannot be empty`);return t}function Kl(){let e=new x(`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=E.dirname(tt(import.meta.url)),t=E.resolve(e,`..`,`SKILL.md`);console.log(t)}),e}function ql(){let e=new x(`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`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Creating snapshot...`);i.start();let a=await G(r,n,e);if(t.wait===!1){let e=await a.snapshot({tags:t.tags,wait:!1});i.stop(),jl(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: ${Jl(o.sizeBytes??0)}`))}),e.command(`list <sandbox-id-or-name>`).description(`List snapshots for a sandbox`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching snapshots...`);i.start();let a=await(await G(r,n,e)).listSnapshots();i.stop(),t.json?j(a):A(a.map(e=>({...e,size:Jl(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}])}),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.`).action(async(e,t,n)=>{let{client:r}=U(n),i=P(`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}`))}),e.command(`revert <sandbox-id-or-name> <snapshot-id>`).description(`Revert an existing sandbox to a snapshot`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Reverting sandbox to snapshot...`);a.start();let o=await G(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}`))}),e.command(`delete <sandbox-id-or-name> <snapshot-id>`).description(`Delete a sandbox snapshot`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Deleting snapshot...`);a.start();let o=await(await G(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}`)}),e}function Jl(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 Yl=`solve:device:secp256k1`,Xl=/^0x[0-9a-f]{64}$/i;function Zl(e){return e&&Xl.test(e)?e:void 0}function Ql(){let e=dn(Yl),t=Zl(e.value);if(!(!t||e.source===`none`))return{account:rt(t),source:e.source}}function $l(){let e=Ql();if(e)return e;let t=nt(),n=fn(Yl,t);return{account:rt(t),source:n}}function eu(e){let t=Zl(dn(Yl).value);if(!t||rt(t).address!==e.account.address)throw Error(`The local Solve device key changed; it was not retired`);let n=`${Yl}:retired:${e.account.address.toLowerCase()}`;if(fn(n,t),dn(n).value!==t)throw Error(`The revoked device key could not be retired safely`);return mn(Yl),n}function tu(e){let t=e.create?$l():Ql();if(!t)throw Error("No Solve device signer found. Run `tangle solve account --create`");e.json?j({address:t.account.address,source:t.source}):F({Address:t.account.address,Source:t.source})}const nu=/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;function ru(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function iu(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`${t} must be an object`);return e}function au(e,t,n=2048){if(typeof e!=`string`||!e.trim()||e.length>n)throw Error(`${t} is missing or invalid`);if(ru(e))throw Error(`${t} contains control characters`);return e.trim()}function ou(e,t){let n=au(e,t,64).toLowerCase();if(!nu.test(n))throw Error(`${t} must be a 40 or 64 character Git revision`);return n}function su(e,t,n=!1){let r=typeof e==`number`&&Number.isSafeInteger(e)?String(e):au(e,t,80);if(!/^\d+$/.test(r)||!n&&r===`0`)throw Error(`${t} must be an unsigned integer`);return BigInt(r).toString()}function cu(e,t){let n=au(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 lu(e,t){let n=cu(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 uu(e,t){let n=au(e,t,42);if(!dt(n,{strict:!1}))throw Error(`${t} must be an EVM address`);return lt(n)}function du(e,t){let n=su(e,t),r=Number(n);if(!Number.isSafeInteger(r)||r<=0)throw Error(`${t} is out of range`);return r}function Z(...e){for(let t of e)if(typeof t==`string`&&t.trim())return t.trim()}function fu(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 pu(e){if(e===void 0)return;let t=au(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 mu(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 hu(e){return Pn(`solve`,e.profile)}function gu(e){let t=hu(e),n=tr(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 _u(e){let t=lr(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 ${gu(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 vu(e){return _u({path:`/v1/wallet/challenges`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.purpose?{purpose:e.purpose}:{}}})}function yu(e){return _u({path:`/v1/devices`,apiUrl:e.apiUrl,profile:e.profile})}function bu(e){return _u({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 Q={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 xu(e,t){return e.toLowerCase()===t.toLowerCase()}function Su(e){if(e.chainId!==Q.chainId)throw Error(`Solve submissions require Tempo Moderato (chain ${Q.chainId}); received ${e.chainId}`);if(e.rpcUrl!==Q.rpcUrl)throw Error(`Solve metadata RPC does not match the trusted deployment`);if(e.sponsorUrl!==Q.sponsorUrl)throw Error(`Solve metadata sponsor does not match the trusted deployment`);if(!xu(e.tangleAddress,Q.tangleAddress))throw Error(`Solve metadata Tangle contract does not match the trusted deployment`);if(!xu(e.managerAddress,Q.managerAddress))throw Error(`Solve metadata competition manager does not match the trusted deployment`);if(!xu(e.paymentAsset,Q.paymentAsset))throw Error(`Solve metadata payment asset does not match the trusted deployment`);if(e.blueprintId!==Q.blueprintId)throw Error(`Solve submissions require blueprint ${Q.blueprintId}; received ${e.blueprintId}`);if(e.serviceId!==Q.serviceId)throw Error(`Solve submissions require service ${Q.serviceId}; received ${e.serviceId}`);if(e.competitionId!==Q.competitionId)throw Error(`Solve submissions require competition ${Q.competitionId}; received ${e.competitionId}`);if(e.minStakeWei!==Q.minStakeWei)throw Error(`Solve submissions require zero stake for the trusted deployment`)}function Cu(e,t){let n=iu(t.check??e.check,`competition.participation.check`),r=au(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=>au(e,`competition checker argument`,2048)),a=Z(n.result_file,n.resultFile),o=n.timeout_ms??n.timeoutMs,s=o===void 0?void 0:du(o,`competition checker timeout`);return{command:r,args:i,...a?{result_file:a}:{},...s?{timeout_ms:s}:{}}}function wu(e){if(e.provenance===void 0)return;let t=iu(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 Tu(e){let t=iu(e.chain??e.network??{},`competition.chain`),n=e.rewards&&typeof e.rewards==`object`&&!Array.isArray(e.rewards)?iu(e.rewards,`competition.rewards`):{},r=n.minStake&&typeof n.minStake==`object`&&!Array.isArray(n.minStake)?iu(n.minStake,`competition.rewards.minStake`).raw:void 0,i=Z(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=Z(t.chainName,t.chain_name,e.chainName,e.chain_name)??`Tempo`,s=Z(t.nativeSymbol,t.native_symbol,e.nativeSymbol,e.native_symbol)??`TNT`,c=Z(t.rpcUrl,t.rpc_url,e.rpcUrl,e.rpc_url,process.env.TANGLE_SOLVE_RPC_URL),l=Z(t.sponsorUrl,t.sponsor_url,e.sponsorUrl,e.sponsor_url,process.env.TANGLE_SOLVE_SPONSOR_URL),u=Z(t.tangleAddress,t.tangle_address,t.coreAddress,t.core_address,e.tangleAddress,e.tangle_address,e.coreAddress,e.core_address),d=Z(t.managerAddress,t.manager_address,e.managerAddress,e.manager_address),f=Z(t.paymentAsset,t.payment_asset,t.servicePaymentAsset,t.service_payment_asset,e.paymentAsset,e.payment_asset,e.servicePaymentAsset,e.service_payment_asset),p=Z(t.blueprintId,t.blueprint_id,e.blueprintId,e.blueprint_id),m=Z(t.serviceId,t.service_id,e.serviceId,e.service_id),h=Z(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:du(a,`chain.chainId`),chainName:o,nativeSymbol:s,rpcUrl:cu(c,`chain.rpcUrl`),sponsorUrl:cu(l,`chain.sponsorUrl`),tangleAddress:uu(u,`chain.tangleAddress`),managerAddress:uu(d,`chain.managerAddress`),paymentAsset:uu(f??Q.paymentAsset,`chain.paymentAsset`),blueprintId:su(p,`chain.blueprintId`),serviceId:su(m,`chain.serviceId`),competitionId:su(h,`chain.competitionId`,!0),minStakeWei:su(i,`chain.minStakeWei`,!0)}}function Eu(e){let t=iu(e,`competition`),n=iu(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=lu(Z(r.repository,r.repo_url,i.repository)??``,`competition.repository`),o=ou(Z(r.repositoryRevision,r.repository_revision,i.revision,i.repositoryRevision,i.repository_revision),`competition.repositoryRevision`),s=au(r.slug??r.id,`competition.slug`,128),c=au(r.name??r.title??s,`competition.name`,256),l=Cu(r,i),u=wu(i);return{version:1,slug:s,title:c,repository:a,taskRevision:o,checker:l,chain:Tu(r),...u?{provenance:u}:{}}}function Du(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 Ou(e){let t=iu(JSON.parse(await k.readFile(E.join(e,`.tangle-solve.json`),`utf8`)),`.tangle-solve.json`);if(t.version!==1)throw Error(`.tangle-solve.json has an unsupported version`);let n=iu(t.checker,`.tangle-solve.json.checker`),r=iu(t.chain,`.tangle-solve.json.chain`);return Eu({slug:t.slug,name:t.title,repository:t.repository,repositoryRevision:t.taskRevision,participation:{check:n,provenance:t.provenance},chain:r,competitionId:r.competitionId})}const ku=Je(we),Au=`.tangle-solve-run.json`,ju=`.tangle-solve.json`,Mu=`tangle.solve.manifestSha256`,Nu=new Set([ju,Au]),Pu=`upstream`;async function Fu(e,t){let n=await ku(`git`,[`-C`,e,...t],{encoding:`utf8`,maxBuffer:1e6});return String(n.stdout).trim()}async function Iu(e,t){let n=E.resolve(t??process.cwd()),r=await Ou(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 Lu(e){let t=E.join(e,ju),n;try{n=await k.lstat(t)}catch{throw Error(`${ju} is missing`)}if(n.isSymbolicLink()||!n.isFile())throw Error(`${ju} must be a regular file`);return ne(`sha256`).update(await k.readFile(t)).digest(`hex`)}async function Ru(e){let t=await Lu(e);return await Fu(e,[`config`,`--local`,`--replace-all`,Mu,t]),t}async function zu(e){let t;try{t=await Fu(e,[`config`,`--local`,`--get`,Mu])}catch{throw Error(`The local Git metadata has no ${Mu} pin; run tangle solve clone again`)}if(!/^[0-9a-f]{64}$/i.test(t))throw Error(`The local ${Mu} pin is invalid`);if(await Lu(e)!==t.toLowerCase())throw Error(`${ju} changed after clone; run tangle solve clone again`)}async function Bu(e,t){try{return await Fu(e,[`ls-files`,`--error-unmatch`,`--`,t]),!0}catch{return!1}}async function Vu(e){await zu(e);for(let t of Nu)if(await Bu(e,t))throw Error(`${t} must remain untracked and local to this Solve workspace`);let t=await ku(`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===`!!`)&&Nu.has(n))}).length>0)throw Error(`Commit the candidate before running Solve. Only the local manifest and run record may remain uncommitted.`);return ou(await Fu(e,[`rev-parse`,`HEAD`]),`submission revision`)}async function Hu(e,t,n,r={}){let i=await Uu(e,t,r);if(i)return{taskRepository:t.repository,taskRevision:t.taskRevision,submissionRepository:i,submissionRevision:n}}async function Uu(e,t,n={}){let r;try{r=fu(await Fu(e,[`config`,`--get`,`remote.origin.pushurl`]))}catch{try{r=fu(await Fu(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 '${Pu}'.`)}}let i=lu(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 '${Pu}' before submitting.`)}return i}function Wu(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 Gu(e,t){return`${e}/commit/${t}`}function Ku(e,t,n,r,i={}){let a=e.evidenceRefs.map(e=>mu(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=pu(r);if(n.required&&(i.requirePullRequest??!0)&&!o)throw Error(`This competition requires a GitHub pull request`);a.push(Gu(t.taskRepository,t.taskRevision),Gu(t.submissionRepository,t.submissionRevision),...o?[o]:[])}return{evidence:e.evidence,evidenceRefs:[...new Set(a)]}}async function qu(e,t){let n=`${e}.${process.pid}.tmp`;await k.writeFile(n,`${JSON.stringify(t,null,2)}\n`,{mode:384}),await k.rename(n,e)}async function Ju(e){let t=JSON.parse(await k.readFile(E.join(e,Au),`utf8`));if(t.version!==1||typeof t.competition!=`string`)throw Error(`${Au} has an unsupported format`);return t}async function Yu(e){let t=pu(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 Xu(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 Zu=Je(we);function Qu(){return`Task source is '${Pu}'. Add your fork as 'origin', commit your candidate, push it, and open a pull request before submitting.`}async function $u(e,t,n){try{let r=iu(await _u({path:`/v1/competitions/${encodeURIComponent(e)}`,apiUrl:n.apiUrl,profile:n.profile}),`competition response`),i=Eu(r.competition??r),a=E.resolve(t??i.slug),o=P(`Cloning ${i.slug}…`);n.json||o.start();try{await Zu(`git`,[`clone`,`--no-tags`,`--origin`,Pu,i.repository,a],{encoding:`utf8`,maxBuffer:1e6}),await Fu(a,[`checkout`,`--detach`,i.taskRevision]);let e=await Fu(a,[`rev-parse`,`HEAD`]);if(e.toLowerCase()!==i.taskRevision.toLowerCase())throw Error(`Pinned checkout resolved to ${e}, expected ${i.taskRevision}`);await qu(E.join(a,`.tangle-solve.json`),i),await Ru(a)}finally{o.stop()}n.json?j({competition:i,directory:a}):(M(`Cloned ${i.slug} at ${i.taskRevision.slice(0,12)}`),i.provenance&&N(Qu()),N(`Run the pinned checker with: cd ${a} && tangle solve run`))}catch(e){R(e)}}const ed=12e4,td=mt(`event JobSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint8 jobIndex, address caller, bytes inputs)`),nd=mt(`event JobCompleted(uint64 indexed serviceId, uint64 indexed callId)`),rd=mt(`event JobResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, address indexed operator, bytes result)`),id=mt(`event AggregatedResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint256 signerBitmap, bytes output)`),ad=mt(`event EvaluationAccepted(uint64 indexed serviceId, uint64 indexed competitionId, address indexed researcher, bytes32 candidateId, bytes32 submissionRefHash, bytes32 evaluationDigest, bytes32 metricsHash, bytes32 evidenceRefsHash)`),od=[...pt([`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)`]),td,nd,rd,id],sd=pt([`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)`]),cd=pt([`function allowance(address owner, address spender) view returns (uint256)`,`function approve(address spender, uint256 amount) returns (bool)`]),ld=ht(`uint64 competitionId, uint256 stakeWei`),ud=ht(`uint64 competitionId, bytes32 commitment`),dd=ht(`uint64 competitionId, bytes32 commitment, string artifactRef, bytes32 salt`),fd=ht(`string artifactRef, bytes32 salt`),pd=ht(`uint64 competitionId, bytes32 candidateId, string submissionRef, string evidenceJson, string evidenceRefsJson`),md=ht(`string status, string detail`),hd=/^0x[0-9a-f]{64}$/i;function gd(e,t){if(e!==t)throw Error(`Tempo RPC returned chain ${e}; expected ${t}`)}function _d(e,t,n){return{...e,feePayer:!0,nonceKey:t,nonce:n}}function vd(e,t){if(e!==`success`)throw Error(`${t} transaction reverted`)}function yd(e,t,n,r){if(!hd.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(vd(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 bd(e,t){return e>=t?[]:e>0n?[0n,t]:[t]}function xd(e,t,n=Date.now()){return n>=e+t}function Sd(e,t){return e.filter(e=>e.args?.candidateId?.toLowerCase()===t.toLowerCase()).at(-1)?.transactionHash}function Cd(e,t,n,r,i){for(let a of e.logs)if(a.address.toLowerCase()===t.tangleAddress.toLowerCase())try{let e=st({abi:[td],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 wd(e,t,n,r){for(let i of e.logs)if(i.address.toLowerCase()===t.managerAddress.toLowerCase())try{let e=st({abi:[ad],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 Td(e){if(e.chainId!==vt.id)throw Error(`Solve submissions require Tempo Moderato (chain ${vt.id}); received ${e.chainId}`);if(!e.sponsorUrl)throw Error(`Solve submissions require a Tempo sponsor relay URL; unsponsored writes are disabled`);return{...vt,name:e.chainName,nativeCurrency:{name:e.nativeSymbol,symbol:e.nativeSymbol,decimals:18},rpcUrls:{default:{http:[e.rpcUrl]}}}}async function Ed(e,t){Su(e);let n=Td(e),r=it({chain:n,transport:ut(e.rpcUrl)});return gd(await r.getChainId(),e.chainId),await Dd({publicClient:r},e),{publicClient:r,walletClient:at({account:t,chain:n,transport:bt(ut(e.rpcUrl),ut(e.sponsorUrl))}),account:t}}async function Dd(e,t){let n=await e.publicClient.readContract({address:t.tangleAddress,abi:od,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 Od(e,t,n){let[r,i]=await Promise.all([e.publicClient.readContract({address:t.tangleAddress,abi:od,functionName:`getJobEventRate`,args:[t.blueprintId,n]}),e.publicClient.readContract({address:t.tangleAddress,abi:od,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 kd(e,t,n){return await e.publicClient.readContract({address:t,abi:cd,functionName:`allowance`,args:[e.account.address,n.tangleAddress]})}async function Ad(e,t,n,r,i,a){let o=Date.now();for(;!xd(o,a);){if((await e.publicClient.getLogs({address:t.tangleAddress,event:nd,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`})).length>0){let a=(await e.publicClient.getLogs({address:t.tangleAddress,event:rd,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]=ot(md,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 jd(e,t,n,r,i){let a=Date.now();for(;!xd(a,i);){let i=(await e.publicClient.getLogs({address:t.tangleAddress,event:id,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 Md(e,t,n){return!!await e.publicClient.readContract({address:t.managerAddress,abi:sd,functionName:`acceptedCandidates`,args:[t.serviceId,t.competitionId,e.account.address,n]})}const Nd=BigInt(ft(gt(`tangle.solve.v1`)));async function Pd(e,t){let n=await yt.nonce.getNonce(e.publicClient,{account:e.account.address,nonceKey:Nd});if(n>BigInt(2**53-1))throw Error(`The Solve transaction nonce exceeds the safe range`);return e.walletClient.writeContract(_d(t,Nd,Number(n)))}async function Fd(e,t,n,r){if(!await e.publicClient.readContract({address:t.tangleAddress,abi:od,functionName:`isPermittedCaller`,args:[t.serviceId,e.account.address]}))try{let i=r??await Pd(e,{address:t.managerAddress,abi:sd,functionName:`authorizeSelf`,args:[t.serviceId]});if(r||await n?.(`authorization`,i),yd(await e.publicClient.waitForTransactionReceipt({hash:i}),i,`Authorization`,{from:e.account.address,to:t.managerAddress}),!await e.publicClient.readContract({address:t.tangleAddress,abi:od,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 Id(e,t){let n=await Pd(e,{address:t.managerAddress,abi:sd,functionName:`revokeSelf`,args:[t.serviceId]});return yd(await e.publicClient.waitForTransactionReceipt({hash:n}),n,`Revocation`,{from:e.account.address,to:t.managerAddress}),n}async function Ld(e,t,n,r,i=`allowance`,a={}){if(t.amount===0n||t.asset===`0x0000000000000000000000000000000000000000`)return;let o=await kd(e,t.asset,n);for(let s of bd(o,t.amount)){let o=s===0n?`${i}:reset`:`${i}:approval`,c=a[o];if(c){if(yd(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 kd(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 Pd(e,{address:t.asset,abi:cd,functionName:`approve`,args:[n.tangleAddress,s]});await r?.(o,l),yd(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 Rd(e,t,n,r,i,a=`job:${n}`,o={}){let s=await Od(e,t,n);await Ld(e,s,t,i,`allowance:${a}`,o);let c=o[a],l=c??await Pd(e,{address:t.tangleAddress,abi:od,functionName:`submitJob`,args:[t.serviceId,n,r],value:s.value});c||await i?.(a,l);let u=await e.publicClient.waitForTransactionReceipt({hash:l});return yd(u,l,`Job ${n}`,{from:e.account.address,to:t.tangleAddress}),{hash:l,callId:Cd(u,t,n,e.account.address,r),blockNumber:u.blockNumber}}async function zd(e,t,n,r,i,a,o=`job:${n}`,s={}){let c=await Rd(e,t,n,r,a,o,s),l=await Ad(e,t,c.callId,c.blockNumber,i,ed);return{...c,acknowledgement:l}}const Bd={...Q,chainName:`Tempo Moderato`,nativeSymbol:`TNT`},Vd={async read(e){let t=it({chain:vt,transport:ut(Bd.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:Bd.tangleAddress,abi:od,functionName:`isPermittedCaller`,args:[Bd.serviceId,e]})),n(t.readContract({address:Bd.managerAddress,abi:sd,functionName:`isDeviceRevoked`,args:[e]}))]);return[e.toLowerCase(),{permitted:r,revoked:i}]}));return new Map(r)},async revokeSelf(e){return Id(await Ed(Bd,e),Bd)}},Hd={permitted:null,revoked:null};function Ud(e){return e.revoked?`revoked`:e.permitted===null?`unknown`:e.permitted?`permitted`:`not permitted`}async function Wd(e,t=Vd){try{let{devices:n}=await yu({apiUrl:e.apiUrl,profile:e.profile}),r=Ql()?.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=>lt(e.address))),o=i.map(e=>({...e,onChain:a.get(e.address)??Hd}));if(e.json){j({serviceId:Bd.serviceId.toString(),devices:o});return}Lt([`Address`,`Status`,`Local`,`Service ${Bd.serviceId}`,`Last used`,`Revoked`],o.map(e=>[e.address,e.status,e.local?`yes`:``,Ud(e.onChain),e.lastUsedAt??``,e.revokedAt?`${e.revokedAt} (${e.revocationMethod})`:``]))}catch(t){R(t,e.json)}}async function Gd(e,t,n=Vd){try{if(!dt(e))throw Error(`${e} is not an EVM address`);let r=lt(e),i=Ql(),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 $r(`Permanently revoke Solve device ${r}${a?` (this machine's device)`:``}? [y/N] `,`--yes`)){N(`Revocation cancelled`);return}}let o;if(i&&a){let e=await vu({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 bu({deviceAddress:r,reason:t.reason,...o,apiUrl:t.apiUrl,profile:t.profile}),c=r.toLowerCase(),l=(await n.read([r])).get(c)??Hd,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)??Hd}let d=i&&a&&l.revoked?eu(i):void 0;if(t.json){j({...s,serviceId:Bd.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 ${Bd.serviceId} refuses its jobs`),d&&N("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&&jt(`The device can still submit jobs to service ${Bd.serviceId}. Only its key, or the Solve blueprint owner, can revoke it on chain`)}catch(e){R(e,t.json)}}function Kd(e,t){return ft(ct(fd,[e.trim(),t]))}function qd(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 Jd(e,t,n,r,i){let a=i.resumeTransactions?.evaluation;if(a){let n=await e.publicClient.waitForTransactionReceipt({hash:a});if(yd(n,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!wd(n,t,e.account,r))throw Error(`Saved evaluation transaction did not emit EvaluationAccepted for this candidate`);return a}let o=Date.now();for(;!xd(o,ed);){if(await Md(e,t,r)){let i=Sd(await e.publicClient.getLogs({address:t.managerAddress,event:ad,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:sd,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()!==ft(n.output).toLowerCase())throw Error(`Manager pending report output does not match the aggregate`);let a=await Pd(e,{address:t.managerAddress,abi:sd,functionName:`executePendingResult`,args:[t.serviceId,n.callId,n.output]});await i.onTransaction?.(`evaluation`,a);let s=await e.publicClient.waitForTransactionReceipt({hash:a});if(yd(s,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!wd(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 Yd(e,t,n,r={}){if(Su(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 Ed(e,t),a=await Fd(i,e,r.onTransaction,r.resumeTransactions?.authorization),o,s=await i.publicClient.readContract({address:e.managerAddress,abi:sd,functionName:`stakes`,args:[e.serviceId,e.competitionId,i.account.address]});s<e.minStakeWei&&(o=await Pd(i,{address:e.managerAddress,abi:sd,functionName:`postStake`,args:[e.serviceId,e.competitionId],value:e.minStakeWei-s}),await r.onTransaction?.(`stake`,o),yd(await i.publicClient.waitForTransactionReceipt({hash:o}),o,`Stake`,{from:i.account.address,to:e.managerAddress}));let c=Kd(n.artifactRef,n.salt),l=ct(ld,[e.competitionId,e.minStakeWei]),u=ct(ud,[e.competitionId,c]),d=ct(dd,[e.competitionId,c,n.artifactRef.trim(),n.salt]),f=await zd(i,e,1,l,`joined`,r.onTransaction,`join`,r.resumeTransactions),p=await zd(i,e,2,u,`committed`,r.onTransaction,`commit`,r.resumeTransactions),m=qd(p.acknowledgement.detail),h=await zd(i,e,3,d,`revealed`,r.onTransaction,`reveal`,r.resumeTransactions),g=await Rd(i,e,4,ct(pd,[e.competitionId,c,m,n.evidenceJson,JSON.stringify(n.evidenceRefs)]),r.onTransaction,`report`,r.resumeTransactions),_=await jd(i,e,g.callId,g.blockNumber,ed),v=await Jd(i,e,{callId:g.callId,output:_,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:v,candidateId:c,submissionRef:m}}const Xd=Je(we),Zd=`/usr/bin/bwrap`,Qd=[`/usr`,`/bin`,`/sbin`,`/lib`,`/lib64`];function $d(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function ef(e,t){if(!e||e.length>2048||$d(e))throw Error(`${t} contains invalid control characters or is too long`)}function tf(e,t){let n=t;for(;n<e.length&&/\s/.test(e[n]??``);)n+=1;return n}function nf(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 rf(e,t,n){let r=new Set,i=tf(e,t+1);if(e[i]===`}`)return i+1;for(;i<e.length;){let t=nf(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=tf(e,t),e[i]!==`:`)throw Error(`Checker output must be valid JSON`);let o=tf(e,i+1),s=of(e,o);if(n?.(a,o,s),i=tf(e,s),e[i]===`}`)return i+1;if(e[i]!==`,`)throw Error(`Checker output must be valid JSON`);i=tf(e,i+1)}throw Error(`Checker output must be valid JSON`)}function af(e,t){let n=tf(e,t+1);if(e[n]===`]`)return n+1;for(;n<e.length;){if(n=tf(e,of(e,n)),e[n]===`]`)return n+1;if(e[n]!==`,`)throw Error(`Checker output must be valid JSON`);n=tf(e,n+1)}throw Error(`Checker output must be valid JSON`)}function of(e,t){if(e[t]===`"`)return nf(e,t);if(e[t]===`{`)return rf(e,t);if(e[t]===`[`)return af(e,t);let n=t;for(;n<e.length&&!/[\s,\]}]/.test(e[n]??``);)n+=1;return n}function sf(e){let t=e.trim();if(tf(t,of(t,0))!==t.length)throw Error(`Checker output must be valid JSON`)}function cf(e,t){let n=e.trim();if(n[0]!==`{`)return;let r;return rf(n,0,(e,i,a)=>{e===t&&(r=n.slice(i,a).trim())}),r}function lf(e,t){let n=e.trim(),r=[];return rf(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 uf(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Checker output must be one JSON object`)}if(sf(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`);ef(i,`candidate_ref`);for(let e of a)ef(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=cf(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=lf(e,i)}return{candidateRef:i,evidenceRefs:a.map(e=>e.trim()),evidence:o,evidenceJson:s}}async function df(e,t,n){let r=n.trim();if(r.startsWith(`{`)&&r.endsWith(`}`)||!t.result_file)return r;let i=await _f(e),a=E.resolve(i,t.result_file),o=E.relative(i,a);if(o.startsWith(`..`)||E.isAbsolute(o))throw Error(`Checker result_file must stay inside the competition repository`);let s;try{s=await k.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 k.realpath(a)}catch{throw Error(`Checker result_file must resolve to a regular file inside the competition repository`)}let l=E.relative(i,c);if(l.startsWith(`..`)||E.isAbsolute(l))throw Error(`Checker result_file must stay inside the competition repository`);return(await k.readFile(c,`utf8`)).trim()}function ff(e,t){let n=E.relative(e,t);return n===``||!n.startsWith(`..`)&&!E.isAbsolute(n)}function pf(e){return Qd.some(t=>ff(t,e))}async function mf(e,t,n){let r=e.includes(`/`)?[E.resolve(t,e)]:(process.env.PATH??``).split(E.delimiter).filter(Boolean).map(t=>E.join(t,e));for(let i of r){let r;try{r=await k.realpath(i),await k.access(r,k.constants.X_OK)}catch{continue}if(!ff(t,r)&&!pf(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 hf(e){let t=[];for(let n of e)try{(await k.stat(n)).isDirectory()&&t.push(n)}catch{}return t}async function gf(e){let t=await k.realpath(xe.homedir());if(e===E.parse(e).root||e===t)throw Error(`Solve checker repository must be a dedicated directory, not the filesystem or home root`)}async function _f(e){let t=await k.realpath(e);return await gf(t),t}async function vf(e){let t=E.join(e,`.git`),n;try{n=await k.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 Xd(`/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 yf(e,t,n){let r=await _f(e);if(process.platform!==`linux`)throw Error(`Solve checkers require the Linux sandbox runtime (bubblewrap) with network isolation`);try{await k.access(Zd,k.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 mf(t,r,await k.realpath(process.execPath)),a=await vf(r),o=(await hf(Qd)).flatMap(e=>[`--ro-bind`,e,e]),s=ff(r,i)?`/work/${E.relative(r,i)}`:pf(i)?i:`/checker/node`;!ff(r,i)&&!pf(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:Zd,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 bf(e,t){if(!t.command||t.command.includes(`/../`)||$d(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)ef(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 _f(e),i;try{let e=await yf(r,t.command,t.args);i=await Xd(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{...uf(await df(r,t,a)),stdout:a,stderr:o}}async function xf(e,t){try{let{root:n,manifest:r}=await Iu(e,t.directory),i=await Vu(n),a=r.provenance?await Hu(n,r,i,{allowMissing:!0}):void 0,o=$l(),s=P(`Running ${r.title} checker…`);t.json||s.start();let c;try{c=await bf(n,r.checker)}finally{s.stop()}let l=Ku(c,a,r.provenance,void 0,{allowMissingSource:!0,requirePullRequest:!1}),u=_t(re(32)),d=Kd(c.candidateRef,u),f={version:1,competition:r.slug,candidateRef:c.candidateRef,evidence:l.evidence,evidenceJson:c.evidenceJson,evidenceRefs:l.evidenceRefs,salt:u,candidateId:d,...a?{source:a}:{},deviceAddress:o.account.address,clientSubmissionId:S(),createdAt:new Date().toISOString()};await qu(E.join(n,`.tangle-solve-run.json`),f),t.json?j({localRun:f}):(M(`Checker output recorded locally for operator evaluation`),F({Competition:r.slug,Candidate:c.candidateRef,"Device address":o.account.address,"Evidence refs":l.evidenceRefs.length}),N("Commit any changes, then run `tangle solve submit` from this directory."),r.provenance&&!a&&N(`Add your GitHub fork as 'origin' before submitting. The task repository is available as '${Pu}'.`))}catch(e){R(e)}}const Sf=/^0x[0-9a-f]{64}$/i;async function Cf(e){let t=await vu({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 wf(e,t){try{let{root:n,manifest:r}=await Iu(e,t.directory);hu({profile:t.profile});let i=await Vu(n),a=await Ju(n);if(a.competition!==r.slug)throw Error(`.tangle-solve-run.json does not match this competition`);if(!Sf.test(a.salt)||!Sf.test(a.candidateId))throw Error("This run predates durable candidate identity. Run `tangle solve run` again");let o=r.provenance?await Hu(n,r,i):void 0;if(r.provenance&&a.source&&!Wu(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=Ql();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=P(`Checking the committed candidate…`);t.json||c.start();let l;try{l=await bf(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(Kd(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=pu(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 Yu({pullRequest:u,taskRepository:o.taskRepository,submissionRepository:o.submissionRepository,submissionRevision:i})}let d=Ku(l,o,r.provenance,u,{requirePullRequest:!0}),f={...a,...o?{source:o}:{},chainState:{status:`submitting`,transactions:{...a.chainState?.transactions??{}}}},p=E.join(n,`.tangle-solve-run.json`);await qu(p,f);let m=P(`Submitting candidate to Tempo…`);t.json||m.start();let h;try{h=await Yd(Du(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 qu(p,f)}})}finally{m.stop()}f={...f,chainReceipt:h,chainState:{status:`accepted`,transactions:{...f.chainState?.transactions??{},...Xu(h)}}},await qu(p,f);let g=await Cf({deviceAddress:h.address,signer:s.account,apiUrl:t.apiUrl,profile:t.profile}),_=await _u({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:Xu(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({..._,transactions:Xu(h),candidateId:h.candidateId}):(M(`Submission accepted on Tempo`),F({Competition:r.slug,Candidate:h.candidateId,"Device address":h.address,"Report transaction":h.report,"Evaluation transaction":h.evaluation,"Submission ID":typeof _.id==`string`?_.id:_.submission?.id}))}catch(e){R(e)}}function Tf(){let e=new x(`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`).action($u),e.command(`run [competition]`).description(`Run the competition checker and record its evidence`).option(`--directory <path>`,`Competition directory (defaults to the current directory)`).action(xf),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`).action(wf),e.command(`account`).description(`Show the local Solve signing account`).option(`--create`,`Create the account if it does not exist`).action(tu);let t=e.command(`device`).description(`List and revoke the Solve devices bound to your account`);return t.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`).action(e=>Wd(e)),t.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`).action((e,t)=>Gd(e,t)),e}function Ef(e,t){return`tangle ssh-proxy ${e.replace(/\/+$/,``)}/v1/sidecar-proxy/${t}/ssh`}function Df(e){return/^[A-Za-z0-9_/:=@%+.,-]+$/.test(e)?e:`'${e.replace(/'/g,`'"'"'`)}'`}function Of(e){return`'${e.replace(/'/g,`''`)}'`}function kf(e){return e===`win32`?`NUL`:`/dev/null`}function Af(e,t){return t===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN=${Of(`<token>`)}; ssh ${e.map(Of).join(` `)}`:`TANGLE_SSH_PROXY_AUTH_TOKEN=${Df(`<token>`)} ssh ${e.map(Df).join(` `)}`}function jf(e){return e.connection!==void 0&&!e.connection.ssh}function Mf(){At(`SSH is not enabled for this sandbox.`),N(`Create a sandbox with --ssh to enable SSH access.`),process.exit(1)}function Nf(e,t=[],n=process.platform){let r=kf(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 Pf(){return new x(`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`).allowUnknownOption(!0).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Getting SSH credentials...`);a.start();let o=await G(i,r,e);if(jf(o)){a.stop(),Mf();return}o=await K(o);let s=await o.ssh();if(a.stop(),!s){Mf();return}let c={...s,proxyCommand:Ef(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=Nf(c,[...n.identityFile?[`-i`,n.identityFile,`-o`,`IdentitiesOnly=yes`]:[],...t]);if(n.print){console.log(Af(l,process.platform));return}N(`Connecting via tunnel...`);let u=Ee(`ssh`,l,{stdio:`inherit`,env:{...process.env,TANGLE_SSH_PROXY_AUTH_TOKEN:r.apiKey}});u.on(`error`,e=>{e.code===`ENOENT`&&(At(`SSH client not found. Please install OpenSSH.`),process.exit(1)),R(e)}),u.on(`exit`,e=>{process.exit(e??0)})})}function Ff(){let e=new x(`ssh-keys`).description(`Manage SSH keys`);return e.command(`list`).description(`List SSH keys`).action(async e=>{let t=P(`Fetching SSH keys...`);try{t.start();let n=await H(V(e)).sshKeys.list();t.stop(),e.json?j({sshKeys:n}):n.length===0?N(`No SSH keys found.`):Lt([`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`).action(async(e,t)=>{let n=P(`Adding SSH key...`);try{let r=T(t.keyFile,`utf8`).trim();n.start();let i=await H(V(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=P(`Deleting SSH key...`);try{n.start(),await H(V(t)).sshKeys.delete(e),n.stop(),M(`Deleted SSH key ${e}`)}catch(e){n.stop(),R(e)}}),e}function If(e,t=1){process.stderr.write(`${e}\n`),process.exit(t)}function Lf(){return new x(`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||If(`TANGLE_SSH_PROXY_AUTH_TOKEN not set`);let n=new xt(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===xt.OPEN&&n.ping()},15e3),r.unref?.(),process.stdin.on(`data`,e=>{n.readyState===xt.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(),If(`WebSocket error: ${e.message}`)}),n.on(`close`,e=>{i(),process.exit(e===1e3?0:1)}),process.stdin.on(`error`,()=>n.close())})}function Rf(){let e=new x(`team`).description(`Manage teams`);return $(e,`list`).description(`List teams for the current account`).action(async e=>{let t=V(e),n=H(t),r=e.json?null:P(`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}])}),$(e,`create <name>`).description(`Create a team`).option(`--org-id <id>`,`External organization id`).option(`--no-switch`,`Do not set the new team as active`).action(async(e,t)=>{let n=V(t),r=H(n),i=t.json?null:P(`Creating team...`);i?.start();let a=await r.teams.create({name:e,orgId:t.orgId});if(t.switch&&Pl(a,n.profile),i?.stop(),t.json){j({team:a,active:!!t.switch});return}M(`Team created: ${Ml(a)}`),t.switch&&M(`Active team set to ${a.name}`)}),$(e,`switch <team>`).description(`Set the active team for the current profile`).action(async(e,t)=>{let n=V(t),r=await Nl(H(n),e);if(Pl(r,n.profile),t.json){j({team:r,activeTeamId:r.id});return}M(`Active team set to ${Ml(r)}`)}),e.command(`current`).description(`Show the active team for the current profile`).option(`--profile <profile>`,`Credential profile`).action(e=>{let t=dr(e.profile);if(e.json){j(t.activeTeamId?t:{activeTeamId:null});return}if(!t.activeTeamId){console.log(`No active team.`);return}F({ID:t.activeTeamId,Name:t.activeTeamName})}),e.command(`clear`).description(`Clear the active team for the current profile`).option(`--profile <profile>`,`Credential profile`).action(e=>{if(Fl(e.profile),e.json){j({activeTeamId:null});return}M(`Active team cleared.`)}),$(e,`members [team]`).description(`List team members`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile),a=await r.teams.listMembers(i.id);if(t.json){j({team:i,members:a});return}A(a.map(e=>({id:e.id,email:e.customerEmail,role:e.role,status:e.status,joinedAt:e.joinedAt})),[{key:`id`,header:`ID`,width:36},{key:`email`,header:`Email`,width:28},{key:`role`,header:`Role`,width:10},{key:`status`,header:`Status`,width:10},{key:`joinedAt`,header:`Joined`,width:16}])}),$(e,`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`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile),a=zf(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}`),F({Team:i.name,Role:o.role,Status:o.status})}),$(e,`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`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile),a=zf(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}`),F({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.`)}),$(e,`leave [team]`).description(`Leave a team as the current user`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile);if(!(!t.force&&!t.json&&!await $r(`Leave team '${i.name}'? (y/N) `,`--force`))){if(await r.teams.leave(i.id),n.activeTeamId===i.id&&Fl(n.profile),t.json){j({success:!0,teamId:i.id});return}M(`Left team: ${i.name}`)}}),$(e,`transfer <new-owner-customer-id> [team]`).description(`Transfer team ownership to another active member`).option(`--force`,`Skip confirmation prompt`).action(async(e,t,n)=>{let r=V(n),i=H(r),a=await X(i,t,r.profile);if(!(!n.force&&!n.json&&!await $r(`Transfer ownership of '${a.name}' to ${e}? This cannot be undone without the new owner's cooperation. (y/N) `,`--force`))){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}`)}}),e.addCommand(Bf()),e.addCommand(Vf()),$(e,`invitations [team]`).description(`List pending and historical team invitations`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile),a=await r.teams.listInvitations(i.id);if(t.json){j({team:i,invitations:a});return}A(a.map(e=>({id:e.id,email:e.email,role:e.role,status:e.status,expiresAt:e.expiresAt})),[{key:`id`,header:`ID`,width:38},{key:`email`,header:`Email`,width:28},{key:`role`,header:`Role`,width:10},{key:`status`,header:`Status`,width:12},{key:`expiresAt`,header:`Expires`,width:16}])}),$(e,`accept <token>`).description(`Accept a team invitation`).option(`--no-switch`,`Do not set the accepted team as active`).action(async(e,t)=>{let n=V(t),r=H(n),i=await r.teams.acceptInvitation(e),a=t.switch===!1?null:await r.teams.get(i.teamId);if(a&&Pl(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}`)}),$(e,`revoke-invitation <invitation-id>`).description(`Revoke a pending team invitation`).action(async(e,t)=>{if(await H(V(t)).teams.revokeInvitation(e),t.json){j({success:!0,invitationId:e});return}M(`Invitation revoked: ${e}`)}),$(e,`remove-member <member-id>`).description(`Remove a member from a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile);if(await r.teams.removeMember(i.id,e),t.json){j({success:!0,teamId:i.id,memberId:e});return}M(`Member removed: ${e}`)}),e}function zf(e){if(e===`admin`||e===`member`||e===`viewer`)return e;throw Error(`Role must be one of: admin, member, viewer`)}function Bf(){let e=new x(`secret`).description(`Manage team secrets`);return $(e,`list [team]`).description(`List team secret names`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile),a=await r.teams.listSecrets(i.id);if(t.json){j({team:i,secrets:a});return}A(a.map(e=>({name:e.name,updatedAt:e.updatedAt,updatedBy:e.updatedBy})),[{key:`name`,header:`Name`,width:28},{key:`updatedAt`,header:`Updated`,width:24},{key:`updatedBy`,header:`Updated By`,width:28}])}),$(e,`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`).action(async(e,t,n)=>{let r=V(n),i=H(r),a=await X(i,n.team,r.profile),o=await Gl({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}`)}),$(e,`delete <name>`).description(`Delete a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile);if(!(!t.force&&!t.json&&!await $r(`Delete team secret '${e}' from '${i.name}'? (y/N) `,`--force`))){if(await r.teams.deleteSecret(i.id,e),t.json){j({success:!0,teamId:i.id,name:e});return}M(`Team secret deleted: ${e}`)}}),$(e,`reveal <name>`).description(`Reveal a team secret value`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile),a=await r.teams.revealSecret(i.id,e);if(t.json){j({teamId:i.id,...a});return}console.log(a.value)}),e}function Vf(){let e=new x(`templates`).description(`Manage team golden-path templates`);return $(e,`list [team]`).description(`List a team's golden-path templates`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile),a=await r.teams.listTemplates(i.id);if(t.json){j({team:i,templates:a});return}if(a.length===0){console.log(`No templates yet for ${i.name}.`);return}A(a.map(e=>({id:e.id,name:e.name,environment:e.environment,snapshot:`${e.snapshotId.slice(0,12)}…`,updated:e.updatedAt})),[{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:28},{key:`environment`,header:`Env`,width:14},{key:`snapshot`,header:`Snapshot`,width:16},{key:`updated`,header:`Updated`,width:24}])}),$(e,`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`).action(async(e,t,n)=>{let r=V(n),i=H(r),a=await X(i,n.team,r.profile),o;if(n.config)try{let e=JSON.parse(n.config);if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`--config must be a JSON object`);o=e}catch(e){throw Error(`--config is not valid JSON: ${e instanceof Error?e.message:String(e)}`)}let s=await i.teams.createTemplate(a.id,{name:e,snapshotId:t,description:n.description,environment:n.environment,config:o});if(n.json){j({team:a,template:s});return}M(`Team template created: ${s.name} (${s.id})`)}),$(e,`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`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile);if(!(!t.force&&!t.json&&!await $r(`Delete template '${e}' from '${i.name}'? (y/N) `,`--force`))){if(await r.teams.deleteTemplate(i.id,e),t.json){j({success:!0,teamId:i.id,templateId:e});return}M(`Team template deleted: ${e}`)}}),e}function $(e,t){return e.command(t).option(`--profile <profile>`,`Credential profile`)}async function Hf(e,t,n){let r=new AbortController,i=()=>r.abort();try{let n=H(V({...e,timeout:void 0}));process.once(`SIGINT`,i),process.once(`SIGTERM`,i);let a=await t(n,{...e.timeout===void 0?{}:{timeoutMs:Number(e.timeout)*1e3},resumeJobId:e.resumeJob,signal:r.signal,onProgress:e=>{process.stderr.write(`Publication ${e.id}: ${e.status}\n`)}}).finally(()=>{process.off(`SIGINT`,i),process.off(`SIGTERM`,i)});e.json?j(a):M(`template`in a?`Published template: ${a.template.slug}`:`Published template version: ${a.version.id}`)}catch(t){if(t instanceof o&&t.status!==401&&t.job&&[`pending`,`scanning`,`ready`].includes(t.job.status)){let e=[`tangle`,`template`,...n,`--resume-job`,t.job.id].map(Ue).join(` `);Object.assign(t,{fix:{command:e}})}R(t,e.json)}}function Uf(){let e=new x(`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`).action(async e=>{let t=H(V(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}])}),e.command(`get <id-or-slug>`).action(async(e,t)=>{let n=await H(V(t)).publicTemplates.get(e);if(t.json){j({template:n});return}j(n)}),e.command(`versions <id-or-slug>`).action(async(e,t)=>{let n=await H(V(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}])}),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`).action((e,t,n,r)=>Hf(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)}),[`publish`,e,t,n])),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`).action((e,t,n,r)=>Hf(r,async(i,a)=>({version:await i.publicTemplates.publishVersion(e,{snapshotId:t,sourceSandboxId:n,readmeMarkdown:r.readme,tags:r.tags,releaseNotes:r.releaseNotes},a)}),[`publish-version`,e,t,n])),e}function Wf(){let e=new x(`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])`).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:tp(e.status),q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:op(e.limit)},n=Kf(e),r=e.json?null:P(`Fetching traces...`);r?.start();let i=await n.listTraces(t);if(r?.stop(),e.json)return j(i);Yf(i.items),$f(i.nextCursor)}catch(t){Jf(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`).action(async(e,t)=>{try{let n=Kf(t);if(t.ndjson){await qf(n,e);return}let r=t.json?null:P(`Fetching trace spans...`);r?.start();let i=await n.getTraceSpans(e,{cursor:t.cursor,limit:t.limit===void 0?void 0:op(t.limit)});if(r?.stop(),t.json)return j(i);Xf(i.items),i.truncated&&F({Spans:`${i.items.length} of ${i.total} (truncated)`}),$f(i.nextCursor)}catch(e){Jf(e,t)}}),e.addCommand(Gf()),e}function Gf(){let e=new x(`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`).action(async e=>{try{let t={status:e.status===void 0?void 0:rp(e.status),gate:e.gate===void 0?void 0:ap(e.gate),label:e.label,from:e.from,to:e.to,q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:op(e.limit)},n=Kf(e),r=e.json?null:P(`Fetching runs...`);r?.start();let i=await n.listRuns(t);if(r?.stop(),e.json)return j(i);Zf(i.items),$f(i.nextCursor)}catch(t){Jf(t,e)}}),e.command(`get <runId>`).description(`Show a single eval-run`).action(async(e,t)=>{try{let n=Kf(t),r=t.json?null:P(`Fetching run...`);r?.start();let i=await n.getRun(e);if(r?.stop(),t.json)return j(i);Qf(i)}catch(e){Jf(e,t)}}),e}function Kf(e){let t=er(e.apiKey);if(!t)throw Error(`No API key found. Set TANGLE_API_KEY or run: tangle auth login`);return St({apiKey:t,baseUrl:e.baseUrl??process.env.TANGLE_INTELLIGENCE_BASE_URL})}async function qf(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 Jf(e,t){return R(e,t.json===!0)}function Yf(e){A(e.map(e=>({traceId:e.traceId,root:e.rootName??`-`,model:e.model??`-`,spans:e.spanCount,errors:e.errorCount,durationMs:e.durationMs,cost:ep(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 Xf(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 Zf(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 Qf(e){F({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 $f(e){e&&F({"Next page":`--cursor ${e}`})}function ep(e){return e===null?`-`:`$${e.toFixed(4)}`}function tp(e){if(e===`ERROR`||e===`OK`)return e;throw Error(`--status must be ERROR or OK`)}const np=[`started`,`baseline-complete`,`generation-complete`,`gate-decided`,`finished`,`errored`];function rp(e){let t=np.find(t=>t===e);if(t)return t;throw Error(`--status must be one of ${np.join(`, `)}`)}const ip=[`ship`,`hold`,`need_more_work`,`model_ceiling`,`arch_ceiling`];function ap(e){let t=ip.find(t=>t===e);if(t)return t;throw Error(`--gate must be one of ${ip.join(`, `)}`)}function op(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function sp(){return new x(`usage`).description(`Show account usage and billing information`).action(async e=>{let{client:t}=U(e),n=e.json?null:P(`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)),F({"Active Sandboxes":r.activeSandboxes,"Total Sandboxes":r.totalSandboxes,"Compute Minutes":cp(r.computeMinutes),"GPU Seconds":r.gpuSeconds,"GPU Spend":lp(r.gpuCostUsd)}),i&&(console.log(),console.log(`Subscription`),console.log(`─`.repeat(40)),F({Plan:i.plan,Status:i.status,"Credits Available":lp(i.creditsAvailableUsd),"Credits Used":lp(i.creditsUsedUsd),"Monthly Balance":lp(i.monthlyBalanceUsd)})),console.log(),console.log(`Billing Period`),console.log(`─`.repeat(40)),F({Start:r.periodStart.toLocaleDateString(),End:r.periodEnd.toLocaleDateString()}),console.log())})}function cp(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 lp(e){return e<0?`-$${(-e).toFixed(2)}`:`$${e.toFixed(2)}`}function up(){return new x(`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)=>{if(t.clear){Kn(),N(`Cleared the active sandbox.`);return}if(e){Gn(e),N(`Active sandbox set to ${e}. Commands now default to it; override with --box or TANGLE_SANDBOX.`);return}let n=Wn();N(n?`Active sandbox: ${n}`:"No active sandbox. Set one with `tangle use <id>`.")})}function dp(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 fp(e){e.command(`artifacts`).description(`List a run's artifact metadata (never the bytes)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.listArtifacts(e,t);if(n.json)return j(r);dp(r.artifacts)}),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)`).action(async(e,t,n,r)=>{let i=await(await Y(r)).workflows.downloadArtifact(e,t,n),a=r.out??n;try{pe(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});N(`Wrote ${a} (${i.bytes.length} bytes, ${i.contentType}).`)})}function pp(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 mp(e){e.command(`decisions`).description(`List a workflow's pending human decisions`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=(await(await Y(t)).workflows.listPendingDecisions()).decisions.filter(t=>t.workflowId===e);if(t.json)return j({decisions:n});pp(n)}),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)`).action(async(e,t,n)=>{let r=await Y(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){N(`Resolved decision ${a.decisionId} with "${a.choice}" — run ${a.runId} resumed.`);return}N(`Resolved decision ${a.decisionId} with "${a.choice}", but run ${a.runId} had already finished — nothing to resume.`)})}function hp(e){try{return T(e,`utf8`)}catch(t){throw Error(`Could not read workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function gp(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 _p(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;N(`${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 vp(e){if(F({ID:e.id,Name:e.name,Description:e.description??``,Enabled:e.enabled?`yes`:`no`,Actions:e.actions.length}),e.triggers&&e.triggers.length>0&&(N(`Triggers`),yp(e.triggers)),e.validationErrors.length>0){N(`Validation issues`);for(let t of e.validationErrors)console.log(` ${t.path}: ${t.message}`)}}function yp(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 bp(e){e.command(`list`).description(`List your workflows`).action(async e=>{let t=await(await Y(e)).workflows.list();if(e.json)return j(t);gp(t)}),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`).action(async e=>{let t=await(await Y(e)).workflows.fleetInsights({window:e.window});if(e.json)return j(t);_p(t)}),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)`).action(async(e,t)=>{let n=await(await Y(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(`
|
|
149
|
+
`)?n.definitionYaml:`${n.definitionYaml}\n`);return}if(t.json)return j(n);vp(n)}),e.command(`create`).description(`Create a workflow from a YAML file`).argument(`<file>`,`Path to the workflow YAML`).action(async(e,t)=>{let n=hp(e),r=await(await Y(t)).workflows.create(n);if(t.json)return j(r);N(`Created workflow ${r.id} (${r.name}).`),vp(r)}),e.command(`apply`).description(`Create or update a workflow idempotently, matched by the definition's name`).argument(`<file>`,`Path to the workflow YAML`).action(async(e,t)=>{let n=hp(e),r=await Y(t),i=await r.workflows.validate(n,{structural:!0});if(!i.valid){if(process.exitCode=1,t.json)return j(i);N(`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});N(`Updated workflow ${e.id} (${e.name}) — matched by name.`),vp(e);return}let o=await r.workflows.create(n);if(t.json)return j({action:`created`,workflow:o});N(`Created workflow ${o.id} (${o.name}).`),vp(o)}),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)`).action(async(e,t,n)=>{let r=hp(t),i=await(await Y(n)).workflows.update(e,r,{...n.note===void 0?{}:{note:n.note}});if(n.json)return j(i);N(`Updated workflow ${i.id} (${i.name}).`),vp(i)}),e.command(`delete`).description(`Delete a workflow and its triggers`).argument(`<id>`,`Workflow ID`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{if(!t.force&&!await $r(`Delete workflow ${e}? `,`--force`)){N(`Delete cancelled.`);return}if(await(await Y(t)).workflows.delete(e),t.json)return j({deleted:!0,id:e});N(`Deleted workflow ${e}.`)}),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`).action(async(e,t)=>{let n=hp(e),r=await(await Y(t)).workflows.validate(n,{...t.structural?{structural:!0}:{}});if(t.json)return j(r);if(r.valid)N(`Valid: ${r.name} (${r.actionCount} action(s), ${r.triggerCount} trigger(s)).`);else{N(`Invalid workflow:`);for(let e of r.errors)console.log(` ${e.path}: ${e.message}`);process.exitCode=1}}),e.command(`schema`).description(`Print the JSON Schema for the workflow YAML`).action(async e=>{j(await(await Y(e)).workflows.schema())})}async function xp(e,t,n){let r=await(await Y(n)).workflows.setEnabled(e,t);if(n.json)return j(r);N(`${t?`Enabled`:`Disabled`} workflow ${r.id}.`),vp(r)}function Sp(e,t){try{return JSON.parse(e)}catch{throw Error(`Invalid ${t}: not valid JSON`)}}function Cp(e,t){try{pe(e,t,`utf8`)}catch(t){throw Error(`Could not write workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function wp(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 Tp(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 Ep(e){e.command(`enable`).description(`Enable a workflow so its triggers and manual runs fire`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{await xp(e,!0,t)}),e.command(`disable`).description(`Disable a workflow (pause its triggers and manual runs)`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{await xp(e,!1,t)}),e.command(`templates`).description(`List the curated starter workflow templates`).action(async e=>{let t=await(await Y(e)).workflows.listTemplates();if(e.json)return j(t);wp(t)}),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.`,Gs,[]).option(`--file <out>`,`Write the instantiated workflow YAML to this file instead of stdout`).action(async(e,t)=>{let n=Ks(t.param,`param`)??{},r=await(await Y(t)).workflows.instantiateTemplate(e,n);if(t.json)return j(r);if(!r.created){N(`Template ${e} needs provider connections before it can run:`);for(let e of r.connectionRequirements)console.log(` ${e.connected?`✓`:`✗`} ${Tp(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(N(`Created workflow ${i.id} (${i.name}).`),t.file){Cp(t.file,i.definitionYaml),N(`Wrote ${t.file}.`);return}process.stdout.write(i.definitionYaml.endsWith(`
|
|
150
|
+
`)?i.definitionYaml:`${i.definitionYaml}\n`)})}function Dp(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 Op(e){F({Key:e.key,Version:e.version,Updated:e.updatedAt}),N(`Value`),j(e.value)}function kp(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`).action(async(e,t)=>{let n=await(await Y(t)).workflows.listKv(e);if(t.json)return j(n);Dp(n.entries)}),t.command(`get`).description(`Show one KV entry (value and version)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.getKv(e,t);if(n.json)return j(r);Op(r)}),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`).action(async(e,t,n,r)=>{let i=Sp(n,`<json>`),a=r.cas===void 0?void 0:eo(r.cas,`--cas`),o=await Y(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);Op(s)}),t.command(`delete`).description(`Delete a KV entry (idempotent)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.deleteKv(e,t);if(n.json)return j(r);N(r.deleted?`Deleted KV entry "${t}" of workflow ${e}.`:`No KV entry "${t}" on workflow ${e}.`)})}function Ap(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 jp(e){e.command(`revisions`).description(`List a workflow's definition revision history (newest first)`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=await(await Y(t)).workflows.listRevisions(e);if(t.json)return j(n);Ap(n)}),e.command(`revision`).description(`Show one revision's metadata and definition YAML`).argument(`<id>`,`Workflow ID`).argument(`<rev>`,`Revision number`).action(async(e,t,n)=>{let r=eo(t,`<rev>`),i=await(await Y(n)).workflows.getRevision(e,r);if(n.json)return j(i);F({Revision:i.rev,Created:i.createdAt,"Created by":i.createdBy,Source:i.source,Note:i.note??``}),process.stdout.write(i.yaml.endsWith(`
|
|
151
|
+
`)?i.yaml:`${i.yaml}\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`).action(async(e,t,n)=>{let r=eo(t,`<rev>`),i=await(await Y(n)).workflows.rollback(e,r);if(n.json)return j(i);N(`Rolled back workflow ${i.id} to rev ${r}.`),vp(i)})}function Mp(){let e=new x(`workflows`).description(`Create and manage Tangle workflows`);return bp(e),Zs(e),Ep(e),jp(e),kp(e),fp(e),mp(e),e}function Np(e){for(let[t,n]of Object.entries(e.optsWithGlobals()))e.getOptionValue(t)===void 0&&n!==void 0&&e.setOptionValue(t,n)}const Pp=e(import.meta.url)(`../package.json`);function Fp(){let e=new x;e.name(`tangle`).description(`CLI for Tangle Sandbox operations`).version(Pp.version??`0.0.0`).option(`--json`,`Output JSON where supported, including errors`).option(`--api-key <key>`,`API key (or set TANGLE_API_KEY)`).option(`--base-url <url>`,`API base URL`),e.hook(`preAction`,(e,t)=>{Np(t);let n=t.opts();wt(n.json===!0||n.ndjson===!0)}),e.addCommand(Pi()),e.addCommand(Hl()),e.addCommand(up()),e.addCommand(Wl()),e.addCommand(Kc()),e.addCommand(nl()),e.addCommand(rl()),e.addCommand(Ho()),e.addCommand(Pf()),e.addCommand(Ff()),e.addCommand(Lf()),e.addCommand(hi()),e.addCommand(ql()),e.addCommand(ps()),e.addCommand(sp()),e.addCommand(Rf()),e.addCommand(Uf()),e.addCommand(Hi()),e.addCommand($i()),e.addCommand(ul()),e.addCommand(ms()),e.addCommand(_s()),e.addCommand(oc()),e.addCommand(sc()),e.addCommand(Mp()),e.addCommand(Vo()),e.addCommand(Ul()),e.addCommand(Tf()),e.addCommand(Kl()),e.addCommand(ea()),e.addCommand(cl()),e.addCommand(Dc()),e.addCommand(Po()),e.addCommand(Fo()),e.addCommand(gl()),e.addCommand(il()),e.addCommand(Wf()),e.addCommand(Us());function t(e){e.configureHelp({showGlobalOptions:!0}),e.configureOutput({writeErr:()=>{}}),e.exitOverride(t=>{t.exitCode===0&&process.exit(0),R(t,e.optsWithGlobals().json===!0)});for(let n of e.commands)t(n)}return t(e),e}const Ip=Fp();Ip.parseAsync(process.argv).catch(e=>{R(e,Ip.opts().json===!0)});export{};
|