@tangle-network/sandbox-cli 0.22.105 → 0.22.106
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 +2 -2
- package/package.json +6 -6
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{createRequire as e,findPackageJSON as t}from"node:module";import"dotenv/config";import{ALL_BACKEND_TYPES as n,AuthError as r,NetworkError as i,NotFoundError as a,PublicTemplatePublishError as o,QuotaError as s,SANDBOX_RUNTIMES as c,Sandbox as l,ServerError as u,StateError as d,TimeoutError as f,ValidationError as p,createAgentRunOutcomeTracker as m,createConfidentialSandbox as h,generateAttestationNonce as g,parseBackendType as _,parseSSEStream as v,validateBatchRunRequest as y}from"@tangle-network/sandbox";import b from"chalk";import x from"ora";import{Command as S,Option as C}from"commander";import{createHash as w,randomBytes as T,randomUUID as E}from"node:crypto";import{ProxySecretsSchema as D,REASONING_EFFORTS as O,agentCandidateArtifactRefSchema as k,agentCandidateWorkspaceSnapshotEvidenceSchema as ee,agentInteractiveSessionRunRef as te,agentProfileSchema as ne,canonicalAgentProfileDigest as re,canonicalCandidateDigest as A,modelProvider as ie,parseSeatSpec as ae,validateAgentProfileSecurity as oe}from"@tangle-network/agent-interface";import*as se from"node:fs";import{chmodSync as ce,constants as le,existsSync as ue,mkdirSync as de,readFileSync as fe,renameSync as pe,writeFileSync as me}from"node:fs";import*as j from"node:path";import{basename as he,dirname as ge,extname as _e,isAbsolute as ve,join as M,relative as ye,resolve as be,sep as xe}from"node:path";import*as Se from"node:os";import{homedir as N,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,graphMcpPolicySchema as ke,graphMcpPolicySchema as Ae,graphProfileSecurity as je,resolveConnectionReferenceFrom as Me,resolveConnectionReferenceFrom as Ne}from"@tangle-network/hub-sdk";import{createInterface as Pe}from"node:readline";import{Writable as Fe}from"node:stream";import{buffer as Ie}from"node:stream/consumers";import{setTimeout as Le}from"node:timers/promises";import{CONTENT_COMPLETION_KEY as Re,CONTENT_PROMPT_KEY as ze,CONTENT_TOOL_ARGS_KEY as Be,CONTENT_TOOL_NAME_KEY as Ve,CONTENT_TOOL_RESULT_KEY as He,TANGLE_SUBJECT_KEY as Ue,asContentField as We,asContentString as Ge}from"@tangle-network/agent-core/telemetry";import{z as P}from"zod";import{execCli as Ke,shellQuote as qe}from"@tangle-network/sdk-cli-runner";import*as Je from"node:fs/promises";import Ye,{lstat as Xe,mkdir as Ze,mkdtemp as Qe,open as $e,readFile as F,readdir as et,realpath as I,rename as tt,rm as nt,writeFile as L}from"node:fs/promises";import{KnowledgeImprovementCandidateRefSchema as rt,assertKnowledgeRetrievalMatchesVisibilityArtifact as it,createKnowledgeTools as at,createRunScopedStores as ot,decodeKnowledgeVisibilitySnapshot as st,encodeKnowledgeVisibilitySnapshot as ct,hashKnowledgeBase as lt,loadSourceRegistry as ut,parseKnowledgeWriteBlocks as dt,promoteKnowledgeCandidate as ft,restoreKnowledgeCandidateBaseline as pt,verifyKnowledgeRetrievalReceipt as mt}from"@tangle-network/agent-knowledge";import{acquireSingleRunLock as ht,incumbent as gt,parseSearchLedgerLine as _t,replaySearchLedgerText as vt,uniform as yt}from"@tangle-network/agent-eval/campaign";import{captureAgentWorkspaceSnapshot as bt,materializeAgentWorkspaceSnapshot as xt}from"@tangle-network/agent-runtime/candidate-execution";import{createBudgetPool as St,createPrivateCasArtifactPort as Ct,readGraphStrings as wt,setGraphStrings as Tt}from"@tangle-network/agent-runtime/kernel";import{listLocalModels as Et,loadConfig as Dt}from"cli-bridge";import{promisify as Ot,stripVTControlCharacters as kt}from"node:util";import{createCliBridgeProvider as At}from"@tangle-network/agent-provider-cli-bridge";import{parse as jt,parseDocument as Mt}from"yaml";import{SearchEnvironmentFault as Nt,improve as Pt,officialGepa as Ft,reflectiveProfileProposer as It,searchMethod as Lt,subscriptionLane as Rt}from"@tangle-network/agent-runtime";import{readSettleRecord as zt,runEvidence as Bt}from"@tangle-network/agent-runtime/durable";import{runtimeRunRolloutLines as Vt}from"@tangle-network/agent-eval/supervisor-run";import{paretoFrontier as Ht}from"@tangle-network/agent-eval";import{gunzipSync as Ut}from"node:zlib";import{fileURLToPath as Wt,pathToFileURL as Gt}from"node:url";import{createMcpServer as Kt}from"@tangle-network/sandbox/agent";import{ensureAgentPreview as qt,publishAgentPreview as Jt,resolveSelfSandbox as Yt}from"@tangle-network/sandbox/preview";import{generatePrivateKey as Xt,privateKeyToAccount as Zt}from"viem/accounts";import{createPublicClient as Qt,createWalletClient as $t,decodeAbiParameters as en,decodeEventLog as tn,encodeAbiParameters as nn,getAddress as rn,http as an,isAddress as on,keccak256 as sn,parseAbi as cn,parseAbiItem as ln,parseAbiParameters as un,stringToHex as dn,toHex as fn}from"viem";import{tempoModerato as pn}from"viem/chains";import{Actions as mn,withRelay as hn}from"viem/tempo";import gn from"ws";import{createIntelligenceClient as _n}from"@tangle-network/sandbox/intelligence";let vn=!1;function yn(e){vn=e}function bn(...e){vn?console.error(...e):console.log(...e)}function xn(e){return e==null?b.dim(`-`):typeof e==`boolean`?e?b.green(`yes`):b.red(`no`):e instanceof Date?Cn(e):typeof e==`string`&&Sn(e)?Cn(new Date(e)):String(e)}function Sn(e){return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)}function Cn(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 wn(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 R(e,t){let n=t.map(t=>{let n=t.header.length,r=Math.max(...e.map(e=>xn(e[t.key]).length));return t.width??Math.max(n,r)+2}),r=e.map(e=>t.map(t=>t.key===`status`?wn(String(e[t.key])):xn(e[t.key])));jn(t.map(e=>e.header),r,n)}function z(e){console.log(JSON.stringify(e,null,2))}function B(e){bn(b.green(`✓`),e)}function Tn(e){console.error(b.red(`✗`),e)}function En(e){bn(b.yellow(`!`),e)}function V(e){bn(b.blue(`→`),e)}const Dn=new Set;function H(e){let t=x({text:e,color:`cyan`,isSilent:vn});return Dn.add(t),t}function On(){for(let e of Dn)e.isSpinning&&e.stop();Dn.clear()}function U(e,t=0){let n=` `.repeat(t);for(let[t,r]of Object.entries(e))r!=null&&console.log(`${n}${b.dim(`${t}:`)} ${xn(r)}`)}function kn(e){let t=`${e.cpuCores} vCPU / ${e.memoryMB} MB / ${e.diskGB} GB`;return e.pool?`${t} (pool: ${e.pool})`:t}function An(e){if(console.log(),console.log(b.bold(`Sandbox Details`)),console.log(b.dim(`─`.repeat(40))),U({ID:e.id,Name:e.name,Status:wn(e.status),Resources:e.resources?kn(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}`;U({SSH:process.platform===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN='<token>'; ${r}`:`TANGLE_SSH_PROXY_AUTH_TOKEN='<token>' ${r}`})}e.connection.webTerminalUrl&&U({"Web Terminal":e.connection.webTerminalUrl}),e.connection.runtimeUrl&&U({"API URL":e.connection.runtimeUrl})}console.log()}function jn(e,t,n){if(t.length===0){console.log(b.dim(`No items found.`));return}let r=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(r[t]))).join(``));for(let e of t)console.log(e.map((e,t)=>String(e??``).padEnd(r[t])).join(``))}var W=class extends Error{constructor(e,t,n,r){super(t),this.code=e,this.cause=n,this.fix=r,this.name=`ActionableCliError`}};const Mn=new Set([`AUTH_EXPIRED`,`SANDBOX_CREDENTIAL_REFUSED`,`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`]),Nn=new Set([`GRAPH_INVALID`,`STEP_REF`,`PROFILE_INVALID`,`UNKNOWN_HARNESS`,`HUB_TOOL_UNKNOWN`,`TRIGGER_INVALID`,`WORKFLOW_INPUT_FILE_INVALID`,`VALIDATION_ERROR`]),Pn=new Set([`UNKNOWN_COMMAND`,`GRAPH_PARAM_MISSING`,`GRAPH_PARAM_UNKNOWN`,`SEAT_SYNTAX`,`HUB_PROVIDER_UNKNOWN`,`USAGE_INVALID`]),Fn=new Set([`SUBSCRIPTION_REQUIRED`,`MODEL_NOT_FOUND`,`MODEL_PROVIDER_MISMATCH`,`MCP_BLOCKED`,`CLOUD_SEAT_UNSUPPORTED`,`SCHEDULE_AUTHORITY`]);function In(e){return typeof e==`object`&&e?e:{}}function Ln(e){return typeof e==`string`&&e.length>0?e:void 0}function Rn(e){let t=Ln(e);return t&&/^[a-z0-9][a-z0-9_-]*$/i.test(t)?t:void 0}function zn(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=Ln(In(n).code);(e||r)&&(t=r?`${r}${e?`: ${e}`:``}`:e)}return t}function Bn(e){return e.code===`credential-refused`&&e.owner===`caller`&&e.providerCode===`subscription_required`?In(e.remediation):{}}function Vn(e){let t=In(e),n=Array.isArray(t.runtimeFailures)?t.runtimeFailures.map(In):[],c=n.find(e=>Ln(Bn(In(e.failure)).fix))??n[0],l=In(c?.failure??t.runtimeFailure),u=Bn(l),m=In(t.details),h=Rn(t.provider??m.provider??m.providerId),g=In(t.fix??m.fix),_=Ln(t.code)??`CLI_ERROR`,v=Ln(t.message)??String(e),y=Ln(l.cause)??Ln(t.cause)??Ln(m.reason)??v,b=`tangle --help`,x=typeof m.providerRetryable==`boolean`?m.providerRetryable:typeof t.retryable==`boolean`?t.retryable:null;if(e instanceof r||_===`HUB_UNAUTHENTICATED`||t.status===401)_=`AUTH_EXPIRED`,v=`Authentication failed`,b=`tangle auth login`;else if(t.status===403&&v.startsWith(`Sandbox runtime creden`))_=`SANDBOX_CREDENTIAL_REFUSED`,v=`This sandbox's own TANGLE_API_KEY may call Hub endpoints only`,b=`export TANGLE_API_KEY=<owner or workspace sk-tan- key> (or pass --api-key), or run outside the sandbox`;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`,b=h?`tangle hub connect ${h}`:`tangle hub connections --json`;else if(_===`HUB_APPROVAL_REQUIRED`){let e=Rn(In(m.approval).id);b=e?`tangle hub approvals approve ${e}`:`tangle hub approvals list --json`}else _===`HUB_PROVIDER_REJECTED`?(b=`tangle hub status --json`,m.providerRetryable===!1&&(y+=`. Change the request before retrying`)):_===`provider_quota_exhausted`||_===`SEAT_LIMIT`?(_=`SEAT_LIMIT`,b=`tangle auth status`,x=!0):e instanceof s?b=`tangle usage --json`:e instanceof i?(_=`NETWORK_UNAVAILABLE`,v=`Network error: ${v}`,y=zn(e.cause)??`No response arrived`,b=`tangle auth status --json`):e instanceof f?(_=`TIMEOUT`,b=`tangle sandbox list --json`):e instanceof p?(_=`VALIDATION_ERROR`,v=`Invalid input`):e instanceof a||e instanceof d?b=`tangle sandbox list --json`:_===`commander.unknownCommand`?(_=`UNKNOWN_COMMAND`,b=v.includes(`'graph'`)?`npm install -g @tangle-network/sandbox-cli@latest`:`tangle --help`):_.startsWith(`commander.`)?_=`USAGE_INVALID`:(_===`ENOENT`||_===`EACCES`)&&(_=`INPUT_UNAVAILABLE`);e instanceof W&&(b=e.fix,x=!1),Ln(u.fix)&&(_=u.cause===`not_authenticated`?`SEAT_NOT_LOGGED_IN`:`SUBSCRIPTION_REQUIRED`),e instanceof o&&b===`tangle --help`&&(b=`tangle template publish --help`),b=Ln(u.fix)??Ln(g.command)??(_===`HUB_NOT_CONNECTED`?void 0:Ln(t.fixCommand))??b,Mn.has(_)&&b===`tangle --help`&&(b=`tangle auth login`);let S=In(t.subject??m.subject??{node:c?.node??t.node,seat:t.seat??u.harness}),C=e instanceof i||e instanceof Error&&`batchCustody`in e?t.batchCustody:void 0;C&&(y=`Batch acceptance: ${C.acceptance}; retirement receipt ${C.cleanup?.mode===`release`&&C.cleanup.isComplete?`proved`:`unproved`}.`,x=!1,b=`tangle batch run --help`);let w=Ln(t.resumeAt??m.resumeAt??m.resetAt);return{code:_,...C?{batchCustody:C}:{},catalogCode:Ln(t.catalogCode),message:Ln(t.nextStep)&&Ln(t.message),nextStep:Ln(t.nextStep),subject:{...Ln(S.node)?{node:String(S.node)}:{},...Ln(S.seat)?{seat:String(S.seat)}:{}},what:v,cause:y,fix:{command:b,...Array.isArray(g.alternatives)&&g.alternatives.every(e=>typeof e==`string`)?{alternatives:g.alternatives}:{},...g.edit===void 0?{}:{edit:g.edit},...Ln(g.url)?{url:String(g.url)}:{}},retryable:x,...w&&Number.isFinite(Date.parse(w))?{resumeAt:w}:{},...Ln(t.runId)?{runId:String(t.runId)}:{},...Ln(t.requestId)?{requestId:String(t.requestId)}:{},...typeof t.status==`number`?{status:t.status}:{},...Ln(l.code)&&Ln(l.owner)?{runtimeFailure:{code:String(l.code),owner:String(l.owner),cause:typeof l.cause==`string`?l.cause:y,...Ln(l.providerCode)?{providerCode:String(l.providerCode)}:{},...typeof l.providerStatus==`number`?{providerStatus:l.providerStatus}:{},...typeof l.retryAfterMs==`number`?{retryAfterMs:l.retryAfterMs}:{},...Object.keys(u).length?{remediation:u}:{}}}:{},...e instanceof o&&e.job?{job:e.job}:{}}}function Hn(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}`}${e.nextStep?`\n → next: ${e.nextStep}`:``}\n → run: ${e.fix.command}`+(e.runtimeFailure?`\n runtime: ${e.runtimeFailure.code} · ${e.runtimeFailure.owner}${e.runtimeFailure.providerCode?` · ${e.runtimeFailure.providerCode}`:``}${e.runtimeFailure.providerStatus===void 0?``:` · HTTP ${e.runtimeFailure.providerStatus}`}${e.runtimeFailure.retryAfterMs===void 0?``:` · retry-after ${e.runtimeFailure.retryAfterMs} ms`}`:``)+(e.fix.alternatives?.map(e=>`\n or: ${e}`).join(``)??``)+(e.resumeAt?`\n resumes ${e.resumeAt}${e.subject.seat?` on ${e.subject.seat}`:``}`:``)}function Un(e){return Hn(Vn(e))}function G(e,t=!1){On();let n=Vn(e);t?z({ok:!1,error:n}):console.error(b.red(Hn(n)));let r=1;Mn.has(n.code)?r=77:Nn.has(n.code)?r=65:Pn.has(n.code)?r=64:Fn.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 Wn(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=fe(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 Gn(e){let t=(e.skills??[]).map(Wn),n=(e.tools??[]).map(Wn),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 Kn(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 Jn(`https://raw.githubusercontent.com/${i[0]}/${i[1]}/${a}/${i.slice(2).join(`/`)}`)}else t=/^https?:\/\//.test(e)?await Jn(e):fe(e,`utf8`);let n;try{n=JSON.parse(t)}catch{throw new W(`PROFILE_INVALID`,`Profile '${e}' is invalid`,`Expected a JSON AgentProfile`,`tangle agent profile create --name my-agent --json`)}return qn(n,e)}function qn(e,t){let n=ne.safeParse(e);if(!n.success)throw new W(`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 Jn(e){let t=await fetch(e);if(!t.ok)throw Error(`failed to fetch ${e} (${t.status})`);return t.text()}async function Yn(e){let t=e.profileSource?await Kn(e.profileSource):void 0,n=Gn(e);return t?n?{...t,...n,...n.resources?{resources:{...t.resources,...n.resources}}:{}}:t:n}const Xn=j.join(Se.homedir(),`.tangle`),Zn=j.join(Xn,`credentials.json`),Qn=`tangle-sandbox-cli`,$n=new Int32Array(new SharedArrayBuffer(4));var er=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)}},tr=class extends Error{constructor(e){super(`Credential storage preflight failed: ${e}`),this.name=`CredentialStorageProbeError`}},nr=class extends Error{constructor(e){super(`Credential storage is busy. Wait a moment and retry.`),this.name=`CredentialsFileLockedError`,e&&(this.cause=e)}};function rr(e){let t=cr(e);if(t)return{value:t,source:`keychain`};let n=dr(e);return n?{value:n,source:`file`}:{source:`none`}}function ir(e,t){return lr(e,t)?(pr(e),`keychain`):(fr(e,t),`file`)}function ar(){let e=`credential-write-probe:${process.pid}:${E()}`,t=E();if(lr(e,t)){let n=cr(e);if(!ur(e))throw new tr(`the OS keychain accepted a test credential but the CLI could not remove it`);if(n!==t)throw new tr(`the OS keychain accepted a test credential but the CLI could not read it back`);return`keychain`}return _r(e),`file`}function or(e){ur(e),pr(e)}function sr(e,t){let n=process.platform;if(n!==`darwin`&&n!==`linux`)return;let r=n===`darwin`?`security`:`secret-tool`;try{return Te(r,e[n],{encoding:`utf8`,input:t,stdio:[t===void 0?`ignore`:`pipe`,`pipe`,`ignore`],timeout:n===`linux`?1e4:void 0}).trim()}catch{return}}function cr(e){let t=yr(e);return sr({darwin:[`find-generic-password`,`-s`,Qn,`-a`,t,`-w`],linux:[`lookup`,`service`,Qn,`account`,t]})}function lr(e,t){let n=yr(e),r=[`add-generic-password`,`-U`,`-s`,Qn,`-a`],i=[`store`,`--label=Tangle Sandbox CLI`,`service`];return sr({darwin:[...r,n,`-w`,t],linux:[...i,Qn,`account`,n]},process.platform===`linux`?t:void 0)!==void 0}function ur(e){let t=yr(e);return sr({darwin:[`delete-generic-password`,`-s`,Qn,`-a`,t],linux:[`clear`,`service`,Qn,`account`,t]})!==void 0}function dr(e){return hr()[e]}function fr(e,t){mr(()=>{let n=hr();n[e]=t,gr(n)})}function pr(e){return mr(()=>{let t;try{t=hr()}catch(e){if(e instanceof er)return!1;throw e}return e in t?(delete t[e],gr(t),dr(e)===void 0):!0})}function mr(e){vr();let t=Date.now()+2e3,n,r;for(;!n;)try{n=De(Zn,{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 nr(r);Atomics.wait($n,0,0,20)}try{return e()}finally{n()}}function hr(){let e;try{e=se.readFileSync(Zn,`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 er(Zn);let n={};for(let[e,r]of Object.entries(t))typeof r==`string`&&(n[e]=r);return n}catch(e){throw e instanceof er?e:new er(Zn,e instanceof Error?e:void 0)}}function gr(e){if(vr(),Object.keys(e).length===0){se.existsSync(Zn)&&se.unlinkSync(Zn);return}let t=`${Zn}.${process.pid}.tmp`;se.writeFileSync(t,`${JSON.stringify(e,null,2)}\n`,{mode:384}),se.renameSync(t,Zn)}function _r(e){let t=E(),n=!1,r;try{if(fr(e,t),n=!0,dr(e)!==t)throw new tr(`the credentials file did not return the value just written`)}catch(e){r=e}finally{if(n)try{!pr(e)&&!r&&(r=new tr(`the credentials file accepted a test credential but the CLI could not remove it`))}catch(e){r??=e}}if(r)throw r}function vr(){if(!se.existsSync(Xn)){se.mkdirSync(Xn,{mode:448,recursive:!0});return}if(process.platform!==`win32`)try{(se.statSync(Xn).mode&511)!=448&&se.chmodSync(Xn,448)}catch{}}function yr(e){return`profile:${e}`}const br=j.join(Se.homedir(),`.tangle`),xr=j.join(br,`config.json`),Sr=`https://id.tangle.tools`,Cr=`https://solve.tangle.tools/api/solve`,wr=`default`;function Tr(){return{tangleBaseUrl:process.env.TANGLE_BASE_URL,sandboxBaseUrl:process.env.SANDBOX_BASE_URL,hubUrl:process.env.TANGLE_HUB_URL}}function Er(e,t){let n=Mr(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 wr;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 Dr(){se.existsSync(br)||se.mkdirSync(br,{mode:448,recursive:!0})}function Or(e,t){Dr();let n=`${e}.${process.pid}.tmp`;se.writeFileSync(n,t,{mode:384}),se.renameSync(n,e)}function kr(e){return e.startsWith(`sk_`)||e.startsWith(`sk-tan-`)}function Ar(){try{if(se.existsSync(xr))return JSON.parse(se.readFileSync(xr,`utf-8`))}catch{}return{}}function jr(e){let t=ai(Ar(),e);Or(xr,`${JSON.stringify(t,null,2)}\n`)}function Mr(e){return oi(e||process.env.TANGLE_PROFILE||process.env.SANDBOX_PROFILE||Ar().activeProfile||wr)}function Nr(e){jr({activeProfile:oi(e)})}function Pr(){return{token:process.env.TANGLE_LINE_TOKEN,baseUrl:process.env.TANGLE_HUB_URL}}function Fr(){return process.env.TANGLE_SANDBOX||Ar().currentSandbox||void 0}function Ir(e){jr({currentSandbox:e})}function Lr(){let e=Ar();delete e.currentSandbox,Or(xr,`${JSON.stringify(e,null,2)}\n`)}function Rr(){let e=Ar().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=T(4).toString(`hex`),r=`${t?`${t}-`:`device-`}${n}`;return jr({deviceId:r}),r}function zr(e){let t=e||Fr();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 Br(){let e=Ar(),t=Mr(),n=new Set([wr,...Object.keys(e.profiles??{})]);return e.activeProfile&&n.add(oi(e.activeProfile)),[...n].map(e=>{let n=rr(e).source;return{name:e,active:e===t,hasApiKey:n!==`none`,baseUrl:Yr(void 0,e),apiKeySource:n}}).sort((e,t)=>e.name.localeCompare(t.name))}function Vr(e){let t=Mr(e);return{name:t,active:t===Mr(),baseUrl:Yr(void 0,t),credentialSource:rr(t).source}}function Hr(e,t){let n=oi(e),r=Ar(),i=ii(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=ir(n,t.apiKey)),jr({profiles:Object.keys(l).length>0?l:{}}),u}function Ur(e){let t=Mr(e),n={...Ar().profiles??{}},r=n[t];if(r){let e={...r};e.baseUrl||e.activeTeamId||e.activeTeamName?n[t]=e:delete n[t]}jr({profiles:n}),or(t)}function Wr(){let e=process.env.TANGLE_API_KEY_FILE;if(e){let t=se.readFileSync(e,`utf8`).trim();if(!t.startsWith(`sk-tan-`))throw Error(`Invalid sandbox credential file`);return t}return process.env.TANGLE_API_KEY}function Gr(e,t){let n=Er(`sandbox`,t);return e||Wr()||rr(n).value}function Kr(e,t){return e||(process.env.TANGLE_SOLVE_API_KEY?process.env.TANGLE_SOLVE_API_KEY:rr(Er(`solve`,t)).value)}function qr(e,t){let n=Er(`sandbox`,t);return e?`flag`:process.env.TANGLE_API_KEY_FILE||process.env.TANGLE_API_KEY?`env`:rr(n).source}function Jr(e,t){return e?`flag`:process.env.TANGLE_SOLVE_API_KEY?`env`:rr(Er(`solve`,t)).source}function Yr(e,t){if(e)return e;let n=process.env.TANGLE_BASE_URL||process.env.SANDBOX_BASE_URL;if(n)return n;let r=Mr(t),i=Ar(),a=ii(r,i);return a.baseUrl?a.baseUrl:(r===wr||r===`sandbox`)&&i.baseUrl?i.baseUrl:`https://sandbox.tangle.tools`}function Xr(e){if(e)return e.replace(/\/v1\/hub\/?$/,``)}function Zr(e){return e?.trim().replace(/\/+$/,``)||void 0}function Qr(e){return Zr(e?.flag)??Zr(Xr(Zr(process.env.TANGLE_HUB_URL)))??Zr(process.env.TANGLE_PLATFORM_URL)??Zr(e?.cachedPlatformUrl?.())??Sr}function $r(e){let t=Zr(e)??Zr(process.env.TANGLE_SOLVE_API_URL);if(t&&t!==Cr)throw Error(`Solve credentials may only be sent to ${Cr}`);return Cr}function ei(e){let t=Zr(e);if(t&&t!==Sr)throw Error(`Solve credentials may only be sent to ${Sr}`);return Sr}function K(e){let t=Er(`sandbox`,e.profile),n=Gr(e.apiKey,t);if(!n)throw Error(`No API key found for profile '${t}'. Set TANGLE_API_KEY or run: tangle auth login${t===wr?``:` --profile ${t}`}`);return{apiKey:n,baseUrl:Yr(e.baseUrl,t),timeout:e.timeout??3e4,profile:t,...ti(t)}}function ti(e){let t=Ar(),n=ii(Mr(e),t);return{activeTeamId:n.activeTeamId,activeTeamName:n.activeTeamName}}function ni(e,t){Hr(Mr(t),{activeTeamId:e.id,activeTeamName:e.name})}function ri(e){let t=Mr(e),n=Ar(),r={...n.profiles??{}},i={baseUrl:ii(t,n).baseUrl};i.baseUrl?r[t]=i:delete r[t],jr({profiles:r})}function ii(e,t=Ar()){let n=oi(e);return{...n===wr?{baseUrl:t.baseUrl,activeTeamId:t.profiles?.[wr]?.activeTeamId,activeTeamName:t.profiles?.[wr]?.activeTeamName}:{},...t.profiles?.[n]??{}}}function ai(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 oi(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 si=null,ci=null;function q(e){if(!e&&si)return si;let t=e??K({});return(!si||!ci||ci.apiKey!==t.apiKey||ci.baseUrl!==t.baseUrl||ci.timeout!==t.timeout)&&(si=new l({apiKey:t.apiKey,baseUrl:t.baseUrl,timeoutMs:t.timeout}),ci=t),si}function li(){si=null,ci=null}function J(e){let t=K({apiKey:e.apiKey,baseUrl:e.baseUrl});return{context:t,client:q(t)}}async function ui(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 Me(r,n)}function di(e,t){return[...t,e]}async function fi(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:`${Ne(r,e.ref)}:${e.tail}`)}function pi(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 mi(e,t){return w(`sha256`).update(`${e}\0${t}`).digest(`hex`).slice(0,32)}function hi(e){return`${e}:hub`}function gi(e){let{value:t}=rr(hi(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 _i(e,t){try{ir(hi(e),JSON.stringify(t))}catch{}}async function vi(e,t,n,r){let i=`${e.replace(/\/+$/,``)}/auth/cli/hub-key`,a;try{a=await fetch(i,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${t}`},body:JSON.stringify({device_id:n}),signal:r})}catch(e){throw Error(`Could not reach ${i} to mint a platform key: ${e instanceof Error?e.message:String(e)}`)}let o=await a.text(),s;try{s=JSON.parse(o)}catch{s=null}if(!a.ok||!s?.success){let e=typeof s?.error?.message==`string`?s.error.message:`HTTP ${a.status}`;throw Error(`Platform key minting failed: ${e}. Your sandbox session may have expired — run \`tangle auth login\`.`)}let c=s.data;if(typeof c?.api_key!=`string`||typeof c?.expires_at!=`string`||typeof c?.platform_url!=`string`)throw Error(`Platform key minting returned an unexpected response shape.`);return{key:c.api_key,expiresAt:c.expires_at,platformUrl:c.platform_url}}var yi=class{cache;fingerprint;constructor(e,t,n,r,i){this.profile=e,this.sandboxBaseUrl=t,this.sessionToken=n,this.deviceId=r,this.signal=i,this.fingerprint=mi(t,n);let a=gi(e);this.cache=a&&a.sessionFingerprint===this.fingerprint?a:null}isFresh(e){return e!==null&&Date.parse(e.expiresAt)-Date.now()>6e4}async ensure(e=!1){if(this.signal?.throwIfAborted(),!e&&this.isFresh(this.cache))return this.cache;let t={...await vi(this.sandboxBaseUrl,this.sessionToken,this.deviceId,this.signal),sessionFingerprint:this.fingerprint};return this.cache=t,_i(this.profile,t),t}};function bi(e){if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function xi(e,t){return Qr({flag:e.baseUrl,...e.useCachedPlatformUrl?{cachedPlatformUrl:()=>gi(t)?.platformUrl}:{}})}function Si(e,t){let n=Er(`sandbox`,e.profile),r=Gr(e.apiKey,n),i=qr(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`);let o=i===`flag`&&r?r:a??r;if(!o)throw Error(`No API key found for profile '${n}'. Set TANGLE_API_KEY or run: tangle auth login${n===`default`?``:` --profile ${n}`}`);return(i===`flag`||i===`env`)&&r||a||o.startsWith(`sk-tan-`)||t?{kind:`static`,apiKey:o,baseUrl:xi(e,n)}:{kind:`managed`,profile:n,sandboxBaseUrl:Yr(e.sandboxBaseUrl,n),sessionToken:o,deviceId:Rr(),baseUrlOverride:e.baseUrl}}async function Ci(e={}){let t=Si(e,e.hubKey===!1||bi(process.env.TANGLE_SKIP_HUB_KEY));if(t.kind===`static`)return{token:t.apiKey,baseUrl:t.baseUrl,minted:!1};let n=new yi(t.profile,t.sandboxBaseUrl,t.sessionToken,t.deviceId,e.signal),r=await n.ensure();return{token:r.key,baseUrl:t.baseUrlOverride??r.platformUrl,refresh:async()=>(await n.ensure(!0)).key,minted:!0}}async function wi(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 Ti(e={}){let t;try{t=await Ci(e)}catch(e){return{reachable:!1,reason:e instanceof Error?e.message:String(e),refused:!0}}try{let e=await wi(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 Ei(e){let t=e.signal,n=t?(e,n)=>{let r=n?.signal??(e instanceof Request?e.signal:void 0);return fetch(e,{...n,signal:r?AbortSignal.any([r,t]):t})}:fetch.bind(globalThis),r=Si(e,e.hubKey===!1||bi(process.env.TANGLE_SKIP_HUB_KEY));if(r.kind===`static`){let t=!e.apiKey&&process.env.TANGLE_API_KEY_FILE&&!process.env.TANGLE_HUB_CAPABILITY_TOKEN;return new Oe({baseUrl:r.baseUrl,fetch:n,authHeaders:()=>({Authorization:`Bearer ${t?Wr():r.apiKey}`})})}let i=new yi(r.profile,r.sandboxBaseUrl,r.sessionToken,r.deviceId,e.signal),a=await i.ensure();return new Oe({baseUrl:r.baseUrlOverride??a.platformUrl,authHeaders:async()=>({Authorization:`Bearer ${(await i.ensure()).key}`}),fetch:async(e,t)=>{let r=await n(e,t);if(r.status!==401)return r;let a=await i.ensure(!0),o=new Headers(t?.headers);return o.set(`Authorization`,`Bearer ${a.key}`),n(e,{...t,headers:o})}})}function Di(e={}){return Ei(e)}function Oi(e={}){return Ei({...e,useCachedPlatformUrl:!0,allowHubCapabilityToken:!0})}function ki(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(`
|
|
2
|
-
`)}`}function Ai(e){return e.activeTeamId?`team:${e.activeTeamId}`:void 0}async function Y(e,t,n,r={}){if(!r.nameOnly){let t=await e.get(n);if(t)return t;if(Mi(n))throw Error(`Sandbox not found: ${n}`)}let i=(await e.list({scope:Ai(t)})).filter(e=>e.name?.toLowerCase()===n.toLowerCase());if(i.length===0)throw Error(`Sandbox not found: ${n}`);if(i.length>1)throw Error(ki(n,i));return i[0]}const ji=/^sandbox-(?:(?:(?:[a-z][a-z0-9-]*)-)?(?:[a-v0-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 Mi(e){return ji.test(e)}async function Ni(e,t,n,r={}){try{
|
|
2
|
+
`)}`}function Ai(e){return e.activeTeamId?`team:${e.activeTeamId}`:void 0}async function Y(e,t,n,r={}){if(!r.nameOnly){let t=await e.get(n);if(t)return t;if(Mi(n))throw Error(`Sandbox not found: ${n}`)}let i=(await e.list({scope:Ai(t)})).filter(e=>e.name?.toLowerCase()===n.toLowerCase());if(i.length===0)throw Error(`Sandbox not found: ${n}`);if(i.length>1)throw Error(ki(n,i));return i[0]}const ji=/^sandbox-(?:(?:(?:[a-z][a-z0-9-]*)-)?(?:[a-v0-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 Mi(e){return ji.test(e)}async function Ni(e,t,n,r={}){let i=n;try{i=(await Y(e,t,n,{nameOnly:r.name})).id}catch(e){if(!(e instanceof Error&&e.message===`Sandbox not found: ${n}`)||r.name||!r.retryCleanup&&!Mi(n))throw e}let a=await e.delete(i,{until:r.until});if(r.until===`removed`&&a.removal!==`complete`)throw Error(`Sandbox removal is unconfirmed for ${i}: ${a.removal??`unknown`}`);return a.outcome}async function X(e,t){if(e.status!==`stopped`)return e;let n=t?.resumeTimeoutMs??12e4;V(`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 Pi=[`anthropic`,`openai`,`vercel-ai`,`mastra`,`mcp-local`,`claude-desktop`,`cursor`,`zed`];function Fi(e,t,n){switch(e){case`anthropic`:return`// pnpm add @anthropic-ai/sdk @tangle-network/sandbox
|
|
3
3
|
import Anthropic from "@anthropic-ai/sdk";
|
|
4
4
|
import { Sandbox } from "@tangle-network/sandbox";
|
|
5
5
|
import { anthropicTools } from "@tangle-network/sandbox/agent";
|
|
@@ -141,7 +141,7 @@ await connect(new StdioServerTransport());`;case`claude-desktop`:return`// Add t
|
|
|
141
141
|
`)}\n`,changed:!0};let i=us(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&&!gs(r)&&r.body.push(``),i.push(t);let a=_s(fs(i));return{contents:a,changed:a!==_s(e)}}let o=a.body.filter(e=>{let t=ms(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=_s(fs(i));return{contents:c,changed:c!==_s(e)}}function gs(e){return e.body.length>0&&e.body[e.body.length-1].trim()===``}function _s(e){return e.endsWith(`
|
|
142
142
|
`)?e:`${e}\n`}function vs(e){let t=M(N(),`.codex`,`config.toml`),{contents:n,changed:r}=hs(Yo(t),{endpoint:e.endpoint,apiKey:e.apiKey});if(!e.write){console.log(n.trimEnd());return}if(!r){B(`${t} already has the Tangle [otel] block — nothing to change.`);return}Xo(t,n),B(`Merged the Tangle [otel] block into ${t}.`),V("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."),V(`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 ys(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`${qo[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 bs(e){let t=Date.now()+e.timeoutSeconds*1e3,n=3e3,r=Math.min(e.timeoutSeconds*1e3,1e4),i=H(`Checking whether content is flowing…`);i.start();let a;try{for(;;){try{a=await oo({endpoint:e.endpoint,apiKey:e.apiKey,timeoutMs:r})}catch(e){if(Date.now()>=t)throw e;await Le(n);continue}if(a.contentSeen||Date.now()>=t)break;await Le(n)}}finally{i.stop()}if(!a)throw Error(`onboarding status check returned no result`);xs(a,e.agent),a.contentSeen||(process.exitCode=1)}function xs(e,t){if(e.contentSeen){B(`Content flowing — Tangle Intelligence can analyze this feed.`),U({"Last seen":e.lastSeenAt??`just now`,Window:`${e.windowDays}d`});return}if(e.tracesSeen){En(`Metadata-only — traces are arriving but carry no content. You missed a content gate.`);let n=t?[t]:Object.keys(e.byAgent).filter(Jo),r=n.length>0?n:Ko;for(let n of r){let r=e.byAgent[n];(t||!r||r.tracesSeen&&!r.contentSeen)&&V(ys(n))}return}En(`No traces yet for your tenant. Run your agent once on a real task, then re-run --verify.`),t&&V(ys(t))}function Ss(e){let t=e??process.env.TANGLE_INTELLIGENCE_API_KEY??Gr(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 Cs(){return new S(`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`,Ga).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=so(t.endpoint);if(t.run){if((e?Ts(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 ks({endpoint:n,apiKey:Ss(t.apiKey),opencodeUrl:t.opencodeUrl});return}if(t.verify){await bs({endpoint:n,apiKey:Ss(t.apiKey),agent:e?Ts(e):void 0,timeoutSeconds:Go(t.timeout,`--timeout`)});return}let r=e?Ts(e):await Es(),i=t.inlineKey?Ss(t.apiKey):void 0;r===`claude-code`?await ls({endpoint:n,apiKey:i,projectKey:t.project,rcPath:t.rc,write:t.write!==!1,content:cs(t.content),format:ss(t.format)}):r===`codex`?vs({endpoint:n,apiKey:i,projectKey:t.project,write:t.write!==!1}):r===`opencode`?Ds({endpoint:n}):Os(r,{endpoint:n}),console.log(),V(`Run your agent on a real task, then verify content is flowing: tangle connect ${r} --verify`)})}function ws(){return new S(`opencode-exporter`).description(`Export a running OpenCode's content to Tangle Intelligence (standalone shim)`).option(`--endpoint <url>`,`OTLP endpoint base`,Ga).option(`--opencode-url <url>`,`OpenCode server base URL (or set OPENCODE_BASE_URL)`).action(async e=>{await ks({endpoint:so(e.endpoint),apiKey:Ss(e.apiKey),opencodeUrl:e.opencodeUrl})})}function Ts(e){if(Jo(e))return e;throw Error(`Unknown agent '${e}'. Choose one of: ${Ko.join(`, `)}`)}async function Es(){if(!process.stdin.isTTY)throw Error(`Specify an agent: tangle connect <${Ko.join(`|`)}>`);console.log(`Which coding agent are you connecting?`),Ko.forEach((e,t)=>{console.log(` ${t+1}) ${qo[e]} (${e})`)});let e=await Vi(`Enter a number or name`,`1`);return Ko[Number.parseInt(e,10)-1]||Ts(e.trim())}function Ds(e){let t=so(e.endpoint);En(`OpenCode has no native OTel exporter, so a standalone install emits nothing without a shim.`),console.log(),U({"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(),V(`Start OpenCode in server mode ('opencode serve'), then in another terminal run: tangle connect opencode --run`),V(`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`),V(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=my-project before starting the exporter.`)}function Os(e,t){let n=so(t.endpoint),r=qo[e];En(`${r} has no native OTel exporter, so a standalone install emits nothing without instrumentation.`),console.log(),U({"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(),V(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=my-project before starting ${r}.`),V(`Verify content is flowing: tangle connect ${e} --verify`)}async function ks(e){let t=Bo(e.opencodeUrl),n=new AbortController,r=()=>n.abort();process.on(`SIGINT`,r),process.on(`SIGTERM`,r),V(`Subscribing to OpenCode at ${t} — exporting content to Tangle.`),V(`Run OpenCode tasks now. Press Ctrl-C to stop.`),console.log();let i=0,a;try{a=await Wo({endpoint:e.endpoint,apiKey:e.apiKey,opencodeBaseUrl:t,signal:n.signal,onExport:({eventType:e,records:t})=>{i+=t,V(`exported ${t} record(s) from ${e} (total ${i})`)}})}catch(e){if(e instanceof Ho){let{recordsExported:t,contentEventsExported:n}=e.partial;console.log(),En(`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){En(`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}B(`Exported ${a.recordsExported} content record(s) from ${a.contentEventsExported} event(s).`),V(`Verify it landed: tangle connect opencode --verify`)}function As(){let e=new S(`environments`).alias(`env`).description(`Manage sandbox environments`);return e.command(`list`).alias(`ls`).description(`List available environments`).action(async e=>{let{client:t}=J(e),n=H(`Fetching environments...`);e.json||n.start();let r=await t.environments.list();n.stop(),e.json?z(r):r.length===0?console.log(`No environments found`):jn([`ID`,`Description`,`Version`,`Runtimes`],r.map(e=>[e.id,e.description??``,e.version,e.runtimes.join(`, `)]))}),e.command(`get`).description(`Get environment details`).argument(`<id>`,`Environment ID`).action(async(e,t)=>{let{client:n}=J(t),r=H(`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?z(i):(console.log(`ID: ${i.id}`),console.log(`Description: ${i.description??`-`}`),console.log(`Version: ${i.version}`),console.log(`Runtimes: ${i.runtimes.join(`, `)}`),i.base&&console.log(`Base: ${i.base}`))}),e}const js=P.string().trim().toLowerCase().min(1).max(64).regex(/^[a-z][a-z0-9-]*$/),Ms=P.string().trim().toLowerCase().min(1).max(128).regex(/^[a-z0-9][a-z0-9._-]*$/),Ns=P.object({kind:Ms,count:P.number().int().positive().default(1),vramGb:P.number().positive().optional()}).strict();P.object({command:P.string().min(1).max(8192),timeoutMs:P.number().int().positive().max(2147453647).optional(),env:P.record(P.string(),P.string()).optional(),cwd:P.string().min(1).max(2048).optional()}).strict(),P.object({refresh:P.enum([`true`,`false`]).optional(),acceleratorKind:Ms.optional(),acceleratorCount:P.coerce.number().pipe(Ns.shape.count.unwrap()).optional(),acceleratorVramGb:P.coerce.number().positive().optional()}).strict(),P.object({maxSpendUsd:P.number().positive().max(1e4).optional(),maxLifetimeSeconds:P.number().int().positive().max(1440*60).optional()}).strict().refine(e=>e.maxSpendUsd!==void 0||e.maxLifetimeSeconds!==void 0,`Renewal requires a lifetime or spend cap`);const Ps=P.object({provider:js.optional(),image:P.string().min(1).max(512).optional(),env:P.record(P.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/),P.string()).optional(),diskGb:P.number().int().positive().optional(),volumeGb:P.number().int().nonnegative().optional(),volumeMountPath:P.string().startsWith(`/`).max(2048).optional(),region:P.string().min(1).max(128).optional(),manifest:P.record(P.string(),P.unknown()).optional(),command:P.array(P.string().max(8192)).min(1).max(256).optional(),ports:P.array(P.number().int().min(1).max(65535)).max(32).optional(),endpoint:P.object({port:P.number().int().min(1).max(65535),healthPath:P.string().regex(/^\/(?![/\\])/).refine(e=>![`\r`,`
|
|
143
143
|
`,` `].some(t=>e.includes(t))).max(2048).optional()}).strict().optional(),allowSpot:P.boolean().optional(),maxHourlyUsd:P.number().positive().optional(),weights:P.object({manifestSha:P.string().regex(/^[a-f0-9]{64}$/),sizeBytes:P.number().int().positive().safe()}).strict().optional(),arms:P.array(P.unknown()).min(1).max(256).optional(),maxSpendUsd:P.number().positive().max(1e4),maxLifetimeSeconds:P.number().int().positive().max(1440*60),idleTimeoutSeconds:P.number().int().positive().optional()}).strict();Ps.extend({accelerator:Ns});const Fs=Ns,Is=js;P.object({...Ps.omit({env:!0}).shape,id:P.string(),projectRef:P.string(),ownerUserId:P.string(),productId:P.string().optional(),provider:Is,providerLeaseId:P.string().optional(),providerInstanceType:P.string().optional(),endpointUrl:P.string().optional(),status:P.enum([`provisioning`,`ready`,`detaching`,`destroyed`,`failed`]),accelerator:Fs,providerCostPerHourUsd:P.number().optional(),customerPricePerHourUsd:P.number().optional(),estimatedProviderCostUsd:P.number().optional(),estimatedCustomerCostUsd:P.number().optional(),providerSelection:P.object({strategy:P.enum([`explicit`,`cheapest`,`ranked`]),selectedProvider:Is,requestedProvider:Is.optional(),candidates:P.array(P.object({provider:Is,accelerator:Fs,providerInstanceType:P.string().optional(),region:P.string().optional(),pricingSource:P.enum([`live`,`configured`]).optional(),providerCostPerHourUsd:P.number(),customerPricePerHourUsd:P.number(),maxLifetimeSeconds:P.number(),estimatedProviderCostUsd:P.number(),estimatedCustomerCostUsd:P.number()})),rejected:P.array(P.object({provider:Is,error:P.string()}))}).optional(),createdAt:P.string(),updatedAt:P.string(),readyAt:P.string().optional(),startedAt:P.string().optional(),lastUsedAt:P.string().optional(),destroyedAt:P.string().optional(),failure:P.string().optional(),billing:P.object({seconds:P.number(),providerCostUsd:P.number(),customerCostUsd:P.number(),providerCostPerHourUsd:P.number(),customerPricePerHourUsd:P.number(),startedAt:P.string(),stoppedAt:P.string()}).optional()});function Ls(e){return{kind:Gs(e.kind),count:e.count?Ws(e.count,`--accelerator-count`):1,...e.memory?{vramGb:qs(e.memory,`--accelerator-memory`)}:{}}}function Rs(e,t,n){if(!t&&Object.values(e).some(Boolean))throw Error(n);return t?Bs(e,`--gpu-`):void 0}function zs(e){return{...Bs(e,`--`),accelerator:Ls({kind:e.acceleratorKind,count:e.acceleratorCount,memory:e.acceleratorMemory})}}function Bs(e,t){let{provider:n,image:r,env:i,maxSpendUsd:a,maxLifetime:o,idleTimeout:s}=e;if(!a||!o)throw Error(`--accelerator-kind requires ${t}max-spend-usd and ${t}max-lifetime`);return{...n?{provider:Ks(n,`${t}provider`)}:{},...r?{image:r}:{},...i?{env:Us(i,`${t}env`,`env`)}:{},maxSpendUsd:qs(a,`${t}max-spend-usd`),maxLifetimeSeconds:Ws(o,`${t}max-lifetime`),...s?{idleTimeoutSeconds:Ws(s,`${t}idle-timeout`)}:{}}}function Vs(e){return e.length===1?e[0]:e.map(qe).join(` `)}function Hs(e){return{timeoutMs:e.timeout?Ws(String(e.timeout),`--timeout`):void 0,env:e.env?Us(e.env,`--env`,`env`):void 0}}function Us(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 Ws(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 Gs(e){let t=Ms.safeParse(e);if(t.success)return t.data;throw Error(`--accelerator-kind must contain only letters, numbers, dots, underscores, or hyphens`)}function Ks(e,t){let n=js.safeParse(e);if(n.success)return n.data;throw Error(`${t} must start with a letter and contain only letters, numbers, or hyphens`)}function qs(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 Js(){return new S(`exec`).description(`Execute a command in a sandbox`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<command...>`,`Command and arguments, or one shell script`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`,`60000`).allowUnknownOption(!0).action(async(e,t,n)=>{try{let{context:r,client:i}=J(n),a=Vs(t),o=Us(n.env??[],`--env`,`env`),s=H(`Executing: ${a}`);n.json||s.start();let c=await Y(i,r,e);c=await X(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?z(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 G(Error(t,{cause:e}))}G(e)}})}function Ys(e){e.command(`capabilities`).description(`List fleet drivers and their supported features`).action(async e=>{let{client:t}=J(e),n=H(`Fetching capabilities...`);n.start();let r=await t.fleets.capabilities();n.stop(),e.json?z(r):R(r.drivers,[{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}=J(t),r=H(`Fetching usage...`);r.start();let i=await n.fleets.usage(e);if(r.stop(),t.json)z(i);else if(U({"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(`
|
|
144
|
-
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}=J(t),r=H(`Estimating cost...`);r.start();let i=await n.fleets.cost(e);r.stop(),t.json?z(i):U({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 Xs(e){return[...e.entries()].map(([e,t])=>({machineId:e,sandboxId:t.id,status:t.status}))}function Zs(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}=J(t),r=H(`Fetching fleet...`);r.start();let i=await n.fleets.list({fleetId:e,status:t.status});r.stop();let a=Xs(i.machines);t.json?z({fleetId:i.fleetId,machines:a}):R(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}=J(t),r=H(`Fetching manifest...`);r.start();let i=await n.fleets.manifest(e);r.stop(),t.json?z(i):(U({"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}),R(i.machines,[{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}=J(t),r=H(`Deleting fleet...`);r.start(),await n.fleets.delete(e,{continueOnError:t.continueOnError}),r.stop(),t.json?z({success:!0,fleetId:e}):B(`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}=J(e),n=H(`Reaping expired fleets...`);n.start();let r=await t.fleets.reapExpired({dryRun:e.dryRun});n.stop(),e.json?z(r):(U({"Dry run":r.dryRun,Expired:r.expired,Deleted:r.deleted}),R(r.fleets,[{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}=J(e),n=H(`Reconciling fleets...`);n.start();let r=await t.fleets.reconcile({dryRun:e.dryRun});n.stop(),e.json?z(r):(U({"Dry run":r.dryRun,Checked:r.checked,Orphaned:r.orphaned,Removed:r.removed}),R(r.machines,[{key:`fleetId`,header:`Fleet`,width:24},{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`removed`,header:`Removed`,width:10}]))})}async function Qs(e,t){let n=await Ci({apiKey:t.apiKey,baseUrl:t.baseUrl??Qr()}),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 $s(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 Hi();if(t.length===0)throw Error(`${e.flagPrefix}-stdin received empty input on stdin`);return t}}function ec(e){if(e.secret===void 0)return;let t=e.backend===`claude-code`?`token`:e.backend===`codex`?`bundle`:void 0;if(!t)throw Error(`--cli-auth needs --backend claude-code or --backend codex`);if(e.apiKeyGiven)throw Error(`--cli-auth cannot be combined with --backend-api-key-env or --backend-api-key-stdin`);return{account:`cli`,secretEnv:e.secret,format:t}}function tc(e){if(e!==void 0)return e.map(e=>{if(e.includes(`@`)||e.includes(`:`))throw Error(`--secret ${e}: bare secret names only (box delivery). For proxy custody use --proxy-secret with a canonical binding`);return e})}function nc(e,t){let n={};return e.cpu!==void 0&&(n.cpuCores=Ws(e.cpu,`--cpu`)),e.memory!==void 0&&(n.memoryMB=Ws(e.memory,`--memory`)),e.disk!==void 0&&(n.diskGB=Ws(e.disk,`--disk`)),t&&(n.accelerator=t),Object.keys(n).length>0?n:void 0}function rc(e){let t=e.split(`/`);return t.length>=2?{provider:t[0],model:t.slice(1).join(`/`)}:{model:e}}function ic(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]=ac(r.join(`=`))}return t}function ac(e){try{return JSON.parse(e)}catch{return e}}function oc(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`?Ws(e.gitDepth,`--git-depth`):void 0,sparse:Array.isArray(e.gitSparse)?e.gitSparse:void 0,auth:t?{token:t}:void 0}}}function sc(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:cc(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 cc(e){if(e===`s3`||e===`gcs`||e===`r2`)return e;throw Error(`--storage-type must be one of s3, gcs, or r2`)}function lc(e){if(e===void 0)return;let t=[];for(let n of e){let e=n,r=`--proxy-secret <json>`;if(n.startsWith(`@`)){let t=n.slice(1);r=`--proxy-secret @${t}`;try{e=fe(t,`utf8`)}catch{throw Error(`${r}: file could not be read`)}}let i;try{i=JSON.parse(e)}catch(e){throw Error(`${r}: not valid JSON (${e instanceof Error?e.message:String(e)})`)}if(Array.isArray(i))t.push(...i);else if(typeof i==`object`&&i)t.push(i);else throw Error(`${r}: expected a binding object or an array of bindings`)}let n=D.parse(t);return n.length>0?n:void 0}function uc(e){V(` Status: ${e.status}`),V(` Provider: ${e.provider}`),V(` GPU: ${e.accelerator.kind} x ${e.accelerator.count}`),e.customerPricePerHourUsd!==void 0&&V(` Customer price: $${e.customerPricePerHourUsd}/hr`),e.estimatedCustomerCostUsd!==void 0&&V(` Max estimate: $${e.estimatedCustomerCostUsd}`),e.billing&&(V(` Billed seconds: ${e.billing.seconds}`),V(` Customer cost: $${e.billing.customerCostUsd}`))}function dc(e){e.result.stdout&&process.stdout.write(e.result.stdout),e.result.stderr&&process.stderr.write(e.result.stderr),V(`Exit code: ${e.result.exitCode}`)}function fc(e){let t=e.command(`gpu`).description(`Manage on-demand GPU leases for a sandbox`);t.command(`providers <id-or-name>`).description(`List GPU clouds, whether each credential works, and current prices`).option(`--accelerator-kind <kind>`,`Price this GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).action(async(e,t)=>{let{context:n,client:r}=J(t),i=H(`Checking GPU providers...`);i.start();let a=await(await Y(r,n,e)).gpu.providers(t.acceleratorKind?{accelerator:Ls({kind:t.acceleratorKind,count:t.acceleratorCount,memory:t.acceleratorMemory})}:{});if(i.stop(),t.json){z(a);return}R(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&&V(`${e.provider}: ${t}`)}a.usable.length===0&&V(`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 <gb>`,`Minimum memory per GPU in decimal GB`).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}=J(t),i=H(`Attaching GPU lease...`);i.start();let a=await(await Y(r,n,e)).gpu.attach(zs(t));i.stop(),t.json?z(a):(B(`GPU lease attached: ${a.id}`),uc(a))}),t.command(`run <id-or-name> <command...>`).description(`Attach a GPU, run a command or script, then destroy it`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).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}=J(n),s=await Y(o,a,e),c=H(`Attaching GPU lease...`);c.start(),r=await s.gpu.attach(zs(n)),c.stop();let l=H(`Running GPU command...`);l.start(),i=await s.gpu.exec(r.id,{command:Vs(t),...Hs(n),cwd:n.cwd}),l.stop(),n.json||dc(i)}catch(e){a=e}finally{if(r)try{let{context:t,client:i}=J(n);r=await(await Y(i,t,e)).gpu.detach(r.id)}catch(e){o=e}}if(a){G(a),o&&G(o);return}if(o){G(o);return}n.json?z({lease:r,result:i}):r&&B(`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}=J(t),i=H(`Fetching GPU leases...`);i.start();let a=await(await Y(r,n,e)).gpu.list();i.stop(),t.json?z(a):a.length===0?V(`No GPU leases attached.`):R(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 or script 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}=J(r),o=H(`Running GPU command...`);o.start();let s=await(await Y(a,i,e)).gpu.exec(t,{command:Vs(n),...Hs(r),cwd:r.cwd});o.stop(),r.json?z(s):dc(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}=J(n),a=H(`Detaching GPU lease...`);a.start();let o=await(await Y(i,r,e)).gpu.detach(t);a.stop(),n.json?z(o):(B(`GPU lease detached: ${o.id}`),uc(o))})}function pc(e,t){if(t){z(e);return}if(!e.id){e.kind===`snapshot`&&e.result?.snapshot?B(`Snapshot created: ${e.result.snapshot.snapshotId}`):B(`Sandbox ${e.sandboxId} stopped.`);return}B(`${e.kind===`snapshot`?`Snapshot`:`Stop`} of sandbox ${e.sandboxId} accepted.`),V(`Operation: ${e.id}`),V(`Status: ${e.statusUrl}`)}function mc(e){return`${e.name} (${e.id})`}async function hc(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 gc(e,t,n){if(t)return hc(e,t);let r=ti(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 _c(e,t){ni({id:e.id,name:e.name},t)}function vc(e){ri(e)}async function yc(e){if(e.explicitTeam&&e.personal)throw Error(`--team and --personal cannot be used together`);if(!e.personal)return e.explicitTeam?(await hc(e.client,e.explicitTeam)).id:e.activeTeamId}async function bc(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 hc(e.client,e.explicitTeam)).id}`;if(e.activeTeamId)return`team:${e.activeTeamId}`}function xc(e){if(!e)return e;let t={...e};for(let e of[`authToken`,`execToken`])t[e]!==void 0&&(t[e]=`[REDACTED]`);return t}function Sc(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}=J(t),i=t.nonce===`auto`?g():t.nonce,a=H(`Fetching TEE attestation...`);a.start();let o=await(await Y(r,n,e)).getTeeAttestation(i?{attestationNonce:i}:void 0);a.stop(),t.json?z(o):(B(`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}=J(e),r=H(`Fetching sandboxes...`);r.start();let i=await bc({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?z(a):R(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}=J(t),i=H(`Fetching sandbox...`);i.start();let a=await Y(r,n,e);if(i.stop(),t.profile){let e=a.getProfileProvenance?.();e?(V(`Agent profile provenance:`),V(` Base profile: ${e.base.name??`(inline)`} (${e.base.sha256.slice(0,12)}...)`),V(` Effective: ${e.effective.name??`(inline)`} (${e.effective.sha256.slice(0,12)}...)`),V(` Materialized: ${e.materializedAt}`),e.base.sha256!==e.effective.sha256&&V(` ⚠ Profile changed since creation (base ≠ effective)`)):V(`No profile materialized (bare sandbox). Create with --profile <name> to install one.`);return}t.json?z(a):An({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}=J(e),n=await t.shapes();if(e.json){z(n);return}let r=e=>e.cpuCores<=n.ceiling.cpuCores&&e.memoryMB<=n.ceiling.memoryMB&&e.diskGB<=n.ceiling.diskGB;R(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}]),V(`Ceiling for this account: ${kn(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 Bi(`Delete sandbox ${e}? [y/N] `,`--force`)){V(`Cancelled.`);return}let{context:n,client:r}=J(t),i=H(`Deleting sandbox...`);i.start();let a=await Ni(r,n,e,{retryCleanup:t.retryCleanup,name:t.name});i.stop(),B(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}=J(t),i=H(`Stopping sandbox...`);i.start();let a=await Y(r,n,e,{nameOnly:t.name});if(t.wait===!1){let e=await a.stop({wait:!1});i.stop(),pc(e.info,!!t.json);return}await a.stop(),i.stop(),B(`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=K({apiKey:t.apiKey,baseUrl:t.baseUrl,timeout:n}),i=q(r),a=H(`Resuming sandbox...`);a.start();let o=await Y(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(),B(`Sandbox ${o.id} resumed.`)})}function Cc(e){e.command(`create`).description(`Create a new sandbox`).option(`-n, --name <name>`,`Sandbox name`).option(`-e, --environment <environment>`,wc).addOption(Tc()).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 selected by bare name for box delivery (value in the sandbox env). For proxy custody use --proxy-secret`).option(`--proxy-secret <bindings...>`,`Canonical proxy custody binding(s): one binding as inline JSON, or @file with a JSON array. The value stays at the egress proxy and is redeemed only within the binding's scope (hosts/methods/paths/TTL); the box reads a placeholder. Repeatable`).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 <gb>`,`Minimum memory per GPU in decimal GB`).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`).addOption(new C(`--driver <type>`,`Run on Tangle network operators instead of the platform's hosts (--tee needs it)`).choices([`tangle`])).option(`--backend <type>`,`Backend agent type (${n.join(`, `)})`).option(`--backend-model <model>`,`Model override (format: provider/model)`).addOption(new C(`--reasoning-effort <level>`,`Reasoning effort for the backend's model; overrides the profile's model.reasoningEffort`).choices(O)).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 $s({envVarName:e.gitTokenEnv,fromStdin:e.gitTokenStdin,flagPrefix:`--git-token`}),n=await $s({envVarName:e.storageSecretAccessKeyEnv,fromStdin:e.storageSecretAccessKeyStdin,flagPrefix:`--storage-secret-access-key`}),r=await $s({envVarName:e.backendApiKeyEnv,fromStdin:e.backendApiKeyStdin,flagPrefix:`--backend-api-key`}),i=ec({secret:e.cliAuth,backend:e.backend,apiKeyGiven:r!==void 0}),a;if(e.profileStdin){let e=await Hi(`--profile-stdin`,`the AgentProfile JSON`);try{a=JSON.parse(e)}catch{G(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(fe(t,`utf8`))}catch(e){G(Error(`--profile ${t}: ${e.message}`));return}else try{a=await Qs(t,e)}catch(e){G(Error(`--profile ${t}: ${e.message}`));return}}a=Dc(a,e.reasoningEffort);let o=K({apiKey:e.apiKey,baseUrl:e.baseUrl,timeout:e.timeout?Number.parseInt(e.timeout,10):void 0}),s=q(o),c=H(`Creating sandbox...`);c.start();let l=await yc({client:s,explicitTeam:e.team,personal:e.personal,activeTeamId:o.activeTeamId}),u=Us(e.env??[],`--env`,`env`),d=e.metadata?ic(e.metadata):void 0,f=oc(e,t),p=sc(e,n),m=e.acceleratorKind?Ls({kind:String(e.acceleratorKind),count:String(e.acceleratorCount),memory:typeof e.acceleratorMemory==`string`?e.acceleratorMemory:void 0}):void 0,g=Rs({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:`tangle`}:void 0,y=e.backend||e.backendModel||a?{...e.backend?{type:_(e.backend)}:{},...a?{profile:a}:{},model:e.backendModel||r||i?{...e.backendModel?rc(e.backendModel):{},apiKey:r,...i?{cliAuth:i}:{}}:void 0}:void 0,b=tc(e.secret),x=i?[...new Set([...b??[],i.secretEnv])]:b,S=lc(e.proxySecret),C=nc(e,m),w=e.sshKeyFile??(e.ssh&&!e.sshKey&&!e.sshKeys?.length?[Ec()]:[]),T=[...e.sshKey?[e.sshKey]:[],...w.map(e=>fe(e,`utf8`).trim())],E={name:e.name,environment:e.environment,runtime:e.runtime,bare:e.bare||void 0,sshEnabled:e.ssh||!!e.sshKey||T.length>0||!!e.sshKeys?.length,sshPublicKeys:T.length>0?T:void 0,sshKeyIds:e.sshKeys,webTerminalEnabled:e.webTerminal,env:Object.keys(u).length>0?u:void 0,git:f,...C?{resources:C}:{},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:x,...S?{proxySecrets:S}:{},metadata:d,driver:v,backend:y},D=e.tee?{tee:e.tee,sealed:e.sealed||void 0,attestationRefresh:e.attestationRefresh||e.attestationNonce===`auto`||void 0}:void 0,O=D?await h(s,{...E,confidential:D,attestationNonce:e.attestationNonce??(e.attestationRefresh?`auto`:void 0),requireAttestation:e.requireAttestation??!0}):void 0,k=O?.sandbox??await s.create(E);e.wait&&(c.text=`Waiting for sandbox to start...`,await k.waitFor(`running`,{timeoutMs:12e4}),await k.refresh()),c.stop(),e.json?z({id:k.id,name:k.name,status:k.status,resources:k.resources,createdAt:k.createdAt,expiresAt:k.expiresAt,connection:xc(k.connection),teamId:l,gpuLease:k.gpuLease,confidential:D,attestation:O?.attestation,attestationNonce:O?.attestationNonce}):(B(`Sandbox created: ${k.id}`),An({id:k.id,name:k.name,status:k.status,resources:k.resources,createdAt:k.createdAt?.toISOString(),expiresAt:k.expiresAt?.toISOString(),connection:k.connection}),l&&console.log(`Team: ${l}`),k.gpuLease&&(console.log(`GPU lease: ${k.gpuLease.id}`),uc(k.gpuLease)),D&&(console.log(`TEE: ${D.tee}`),console.log(`Attestation: ${O?.attestation?`present`:`not returned`}`),O?.attestationNonce&&console.log(`Attestation nonce: ${O.attestationNonce}`)))})}const wc="A catalog environment, a container image reference, or a built image ID. Firecracker runs only images pinned by repository@sha256 that the cell's Firecracker hosts carry; `environments list` shows each image's runtimes";function Tc(){return new C(`--runtime <runtime>`,`Isolation on the platform's hosts: docker runs a container on the host kernel, firecracker a microVM with its own kernel. Omit for the platform default`).choices(c)}function Ec(){let e=[`id_ed25519`,`id_ecdsa`,`id_rsa`].map(e=>`${N()}/.ssh/${e}.pub`),t=e.find(e=>ue(e));if(!t)throw Error(`--ssh needs a public key and found none at ${e.join(`, `)}. Run ssh-keygen -t ed25519, or pass --ssh-key-file.`);return t}function Dc(e,t){if(!t)return e;let n=e?.model??{};return{...e,model:{...n,reasoningEffort:t}}}function Oc(e){if(e.spec){let t=JSON.parse(fe(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=jc(e),n=Mc(e,!!t?.accelerator),r={...e.environment?{environment:e.environment}:{},...t?{resources:t}:{},...e.runtime?{runtime:e.runtime}:{},...n?{gpuLease:n}:{},...e.backend?{backend:{type:e.backend}}:{}},i=Nc(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 kc(e){let{base:t,machines:n}=Oc(e);return{...t,machines:n}}function Ac(e){let{base:t,machines:n}=Oc(e);return{...t,workers:n}}function jc(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=Ls({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 Mc(e,t){return Rs({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 Nc(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 Pc(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>`,wc).addOption(Tc()).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 <gb>`,`Minimum memory per GPU in decimal GB`).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(`--backend <id>`,`Agent backend type`).option(`--workspace <mode>`,`Workspace mode: isolated (no driver supports shared yet)`,`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}=J(e),n=H(`Creating fleet...`);n.start();let r=e.coordinator?await t.fleets.createWithCoordinator(Ac(e)):await t.fleets.create(kc(e));n.stop();let i=Xs(r.machines);e.json?z({fleetId:r.fleetId,machines:i}):(B(`Fleet created: ${r.fleetId}`),R(i,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}]))})}function Fc(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}=J(n),i=H(`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)z(a);else{R(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(fe(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}=J(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=H(`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||B(`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?z({fleetId:c.fleetId,createMs:l,sandboxes:c.machines.size,results:u,spend:d,deleted:!t.keep}):U({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}=J(t),r=await(await n.fleets.list({fleetId:e})).cancel();t.json?z({fleetId:e,...r}):B(`Fleet ${e}: interrupted ${r.interrupted} agents, cancelled ${r.children} child fleets`)})}const Ic=[`list`,`create`,`delete`,`exec`,`prompt`,`read`,`write`];function Lc(e){if(!(!e||e.length===0)){for(let t of e)if(!Ic.includes(t))throw Error(`Invalid token action '${t}'. Allowed: ${Ic.join(`, `)}`);return e}}function Rc(e){return e.length<=12?`****`:`${e.slice(0,6)}...${e.slice(-4)} (masked — use --json for full value)`}function zc(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}=J(t),r=H(`Minting fleet token...`);r.start();let i=await n.fleets.createToken(e,{actions:Lc(t.action),ttlMinutes:t.ttlMinutes?Number(t.ttlMinutes):void 0});r.stop(),t.json?z(i):(U({"Fleet ID":i.fleetId,Token:Rc(i.token),"Expires at":new Date(i.expiresAt).toISOString(),Actions:i.actions.join(`, `)}),console.log(`
|
|
144
|
+
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}=J(t),r=H(`Estimating cost...`);r.start();let i=await n.fleets.cost(e);r.stop(),t.json?z(i):U({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 Xs(e){return[...e.entries()].map(([e,t])=>({machineId:e,sandboxId:t.id,status:t.status}))}function Zs(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}=J(t),r=H(`Fetching fleet...`);r.start();let i=await n.fleets.list({fleetId:e,status:t.status});r.stop();let a=Xs(i.machines);t.json?z({fleetId:i.fleetId,machines:a}):R(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}=J(t),r=H(`Fetching manifest...`);r.start();let i=await n.fleets.manifest(e);r.stop(),t.json?z(i):(U({"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}),R(i.machines,[{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}=J(t),r=H(`Deleting fleet...`);r.start(),await n.fleets.delete(e,{continueOnError:t.continueOnError}),r.stop(),t.json?z({success:!0,fleetId:e}):B(`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}=J(e),n=H(`Reaping expired fleets...`);n.start();let r=await t.fleets.reapExpired({dryRun:e.dryRun});n.stop(),e.json?z(r):(U({"Dry run":r.dryRun,Expired:r.expired,Deleted:r.deleted}),R(r.fleets,[{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}=J(e),n=H(`Reconciling fleets...`);n.start();let r=await t.fleets.reconcile({dryRun:e.dryRun});n.stop(),e.json?z(r):(U({"Dry run":r.dryRun,Checked:r.checked,Orphaned:r.orphaned,Removed:r.removed}),R(r.machines,[{key:`fleetId`,header:`Fleet`,width:24},{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`removed`,header:`Removed`,width:10}]))})}async function Qs(e,t){let n=await Ci({apiKey:t.apiKey,baseUrl:t.baseUrl??Qr()}),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 $s(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 Hi();if(t.length===0)throw Error(`${e.flagPrefix}-stdin received empty input on stdin`);return t}}function ec(e){if(e.secret===void 0)return;let t=e.backend===`claude-code`?`token`:e.backend===`codex`?`bundle`:void 0;if(!t)throw Error(`--cli-auth needs --backend claude-code or --backend codex`);if(e.apiKeyGiven)throw Error(`--cli-auth cannot be combined with --backend-api-key-env or --backend-api-key-stdin`);return{account:`cli`,secretEnv:e.secret,format:t}}function tc(e){if(e!==void 0)return e.map(e=>{if(e.includes(`@`)||e.includes(`:`))throw Error(`--secret ${e}: bare secret names only (box delivery). For proxy custody use --proxy-secret with a canonical binding`);return e})}function nc(e,t){let n={};return e.cpu!==void 0&&(n.cpuCores=Ws(e.cpu,`--cpu`)),e.memory!==void 0&&(n.memoryMB=Ws(e.memory,`--memory`)),e.disk!==void 0&&(n.diskGB=Ws(e.disk,`--disk`)),t&&(n.accelerator=t),Object.keys(n).length>0?n:void 0}function rc(e){let t=e.split(`/`);return t.length>=2?{provider:t[0],model:t.slice(1).join(`/`)}:{model:e}}function ic(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]=ac(r.join(`=`))}return t}function ac(e){try{return JSON.parse(e)}catch{return e}}function oc(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`?Ws(e.gitDepth,`--git-depth`):void 0,sparse:Array.isArray(e.gitSparse)?e.gitSparse:void 0,auth:t?{token:t}:void 0}}}function sc(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:cc(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 cc(e){if(e===`s3`||e===`gcs`||e===`r2`)return e;throw Error(`--storage-type must be one of s3, gcs, or r2`)}function lc(e){if(e===void 0)return;let t=[];for(let n of e){let e=n,r=`--proxy-secret <json>`;if(n.startsWith(`@`)){let t=n.slice(1);r=`--proxy-secret @${t}`;try{e=fe(t,`utf8`)}catch{throw Error(`${r}: file could not be read`)}}let i;try{i=JSON.parse(e)}catch(e){throw Error(`${r}: not valid JSON (${e instanceof Error?e.message:String(e)})`)}if(Array.isArray(i))t.push(...i);else if(typeof i==`object`&&i)t.push(i);else throw Error(`${r}: expected a binding object or an array of bindings`)}let n=D.parse(t);return n.length>0?n:void 0}function uc(e){V(` Status: ${e.status}`),V(` Provider: ${e.provider}`),V(` GPU: ${e.accelerator.kind} x ${e.accelerator.count}`),e.customerPricePerHourUsd!==void 0&&V(` Customer price: $${e.customerPricePerHourUsd}/hr`),e.estimatedCustomerCostUsd!==void 0&&V(` Max estimate: $${e.estimatedCustomerCostUsd}`),e.billing&&(V(` Billed seconds: ${e.billing.seconds}`),V(` Customer cost: $${e.billing.customerCostUsd}`))}function dc(e){e.result.stdout&&process.stdout.write(e.result.stdout),e.result.stderr&&process.stderr.write(e.result.stderr),V(`Exit code: ${e.result.exitCode}`)}function fc(e){let t=e.command(`gpu`).description(`Manage on-demand GPU leases for a sandbox`);t.command(`providers <id-or-name>`).description(`List GPU clouds, whether each credential works, and current prices`).option(`--accelerator-kind <kind>`,`Price this GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).action(async(e,t)=>{let{context:n,client:r}=J(t),i=H(`Checking GPU providers...`);i.start();let a=await(await Y(r,n,e)).gpu.providers(t.acceleratorKind?{accelerator:Ls({kind:t.acceleratorKind,count:t.acceleratorCount,memory:t.acceleratorMemory})}:{});if(i.stop(),t.json){z(a);return}R(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&&V(`${e.provider}: ${t}`)}a.usable.length===0&&V(`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 <gb>`,`Minimum memory per GPU in decimal GB`).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}=J(t),i=H(`Attaching GPU lease...`);i.start();let a=await(await Y(r,n,e)).gpu.attach(zs(t));i.stop(),t.json?z(a):(B(`GPU lease attached: ${a.id}`),uc(a))}),t.command(`run <id-or-name> <command...>`).description(`Attach a GPU, run a command or script, then destroy it`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).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}=J(n),s=await Y(o,a,e),c=H(`Attaching GPU lease...`);c.start(),r=await s.gpu.attach(zs(n)),c.stop();let l=H(`Running GPU command...`);l.start(),i=await s.gpu.exec(r.id,{command:Vs(t),...Hs(n),cwd:n.cwd}),l.stop(),n.json||dc(i)}catch(e){a=e}finally{if(r)try{let{context:t,client:i}=J(n);r=await(await Y(i,t,e)).gpu.detach(r.id)}catch(e){o=e}}if(a){G(a),o&&G(o);return}if(o){G(o);return}n.json?z({lease:r,result:i}):r&&B(`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}=J(t),i=H(`Fetching GPU leases...`);i.start();let a=await(await Y(r,n,e)).gpu.list();i.stop(),t.json?z(a):a.length===0?V(`No GPU leases attached.`):R(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 or script 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}=J(r),o=H(`Running GPU command...`);o.start();let s=await(await Y(a,i,e)).gpu.exec(t,{command:Vs(n),...Hs(r),cwd:r.cwd});o.stop(),r.json?z(s):dc(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}=J(n),a=H(`Detaching GPU lease...`);a.start();let o=await(await Y(i,r,e)).gpu.detach(t);a.stop(),n.json?z(o):(B(`GPU lease detached: ${o.id}`),uc(o))})}function pc(e,t){if(t){z(e);return}if(!e.id){e.kind===`snapshot`&&e.result?.snapshot?B(`Snapshot created: ${e.result.snapshot.snapshotId}`):B(`Sandbox ${e.sandboxId} stopped.`);return}B(`${e.kind===`snapshot`?`Snapshot`:`Stop`} of sandbox ${e.sandboxId} accepted.`),V(`Operation: ${e.id}`),V(`Status: ${e.statusUrl}`)}function mc(e){return`${e.name} (${e.id})`}async function hc(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 gc(e,t,n){if(t)return hc(e,t);let r=ti(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 _c(e,t){ni({id:e.id,name:e.name},t)}function vc(e){ri(e)}async function yc(e){if(e.explicitTeam&&e.personal)throw Error(`--team and --personal cannot be used together`);if(!e.personal)return e.explicitTeam?(await hc(e.client,e.explicitTeam)).id:e.activeTeamId}async function bc(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 hc(e.client,e.explicitTeam)).id}`;if(e.activeTeamId)return`team:${e.activeTeamId}`}function xc(e){if(!e)return e;let t={...e};for(let e of[`authToken`,`execToken`])t[e]!==void 0&&(t[e]=`[REDACTED]`);return t}function Sc(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}=J(t),i=t.nonce===`auto`?g():t.nonce,a=H(`Fetching TEE attestation...`);a.start();let o=await(await Y(r,n,e)).getTeeAttestation(i?{attestationNonce:i}:void 0);a.stop(),t.json?z(o):(B(`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}=J(e),r=H(`Fetching sandboxes...`);r.start();let i=await bc({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?z(a):R(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}=J(t),i=H(`Fetching sandbox...`);i.start();let a=await Y(r,n,e);if(i.stop(),t.profile){let e=a.getProfileProvenance?.();e?(V(`Agent profile provenance:`),V(` Base profile: ${e.base.name??`(inline)`} (${e.base.sha256.slice(0,12)}...)`),V(` Effective: ${e.effective.name??`(inline)`} (${e.effective.sha256.slice(0,12)}...)`),V(` Materialized: ${e.materializedAt}`),e.base.sha256!==e.effective.sha256&&V(` ⚠ Profile changed since creation (base ≠ effective)`)):V(`No profile materialized (bare sandbox). Create with --profile <name> to install one.`);return}t.json?z(a):An({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}=J(e),n=await t.shapes();if(e.json){z(n);return}let r=e=>e.cpuCores<=n.ceiling.cpuCores&&e.memoryMB<=n.ceiling.memoryMB&&e.diskGB<=n.ceiling.diskGB;R(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}]),V(`Ceiling for this account: ${kn(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`).addOption(new C(`--until <state>`,`Wait for physical removal`).choices([`removed`])).option(`--retry-cleanup`,`Retry server-side cleanup after the sandbox disappeared from get/list`).action(async(e,t)=>{if(!t.force&&!await Bi(`Delete sandbox ${e}? [y/N] `,`--force`)){V(`Cancelled.`);return}let{context:n,client:r}=J(t),i=H(`Deleting sandbox...`);i.start();let a=await Ni(r,n,e,{retryCleanup:t.retryCleanup,name:t.name,until:t.until});i.stop(),B(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}=J(t),i=H(`Stopping sandbox...`);i.start();let a=await Y(r,n,e,{nameOnly:t.name});if(t.wait===!1){let e=await a.stop({wait:!1});i.stop(),pc(e.info,!!t.json);return}await a.stop(),i.stop(),B(`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=K({apiKey:t.apiKey,baseUrl:t.baseUrl,timeout:n}),i=q(r),a=H(`Resuming sandbox...`);a.start();let o=await Y(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(),B(`Sandbox ${o.id} resumed.`)})}function Cc(e){e.command(`create`).option(`--cpu-features <flags>`,`Required Linux CPU flags, comma-separated`).description(`Create a new sandbox`).option(`-n, --name <name>`,`Sandbox name`).option(`-e, --environment <environment>`,wc).addOption(Tc()).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 selected by bare name for box delivery (value in the sandbox env). For proxy custody use --proxy-secret`).option(`--proxy-secret <bindings...>`,`Canonical proxy custody binding(s): one binding as inline JSON, or @file with a JSON array. The value stays at the egress proxy and is redeemed only within the binding's scope (hosts/methods/paths/TTL); the box reads a placeholder. Repeatable`).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 <gb>`,`Minimum memory per GPU in decimal GB`).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`).addOption(new C(`--driver <type>`,`Run on Tangle network operators instead of the platform's hosts (--tee needs it)`).choices([`tangle`])).option(`--backend <type>`,`Backend agent type (${n.join(`, `)})`).option(`--backend-model <model>`,`Model override (format: provider/model)`).addOption(new C(`--reasoning-effort <level>`,`Reasoning effort for the backend's model; overrides the profile's model.reasoningEffort`).choices(O)).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 $s({envVarName:e.gitTokenEnv,fromStdin:e.gitTokenStdin,flagPrefix:`--git-token`}),n=await $s({envVarName:e.storageSecretAccessKeyEnv,fromStdin:e.storageSecretAccessKeyStdin,flagPrefix:`--storage-secret-access-key`}),r=await $s({envVarName:e.backendApiKeyEnv,fromStdin:e.backendApiKeyStdin,flagPrefix:`--backend-api-key`}),i=ec({secret:e.cliAuth,backend:e.backend,apiKeyGiven:r!==void 0}),a;if(e.profileStdin){let e=await Hi(`--profile-stdin`,`the AgentProfile JSON`);try{a=JSON.parse(e)}catch{G(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(fe(t,`utf8`))}catch(e){G(Error(`--profile ${t}: ${e.message}`));return}else try{a=await Qs(t,e)}catch(e){G(Error(`--profile ${t}: ${e.message}`));return}}a=Dc(a,e.reasoningEffort);let o=K({apiKey:e.apiKey,baseUrl:e.baseUrl,timeout:e.timeout?Number.parseInt(e.timeout,10):void 0}),s=q(o),c=H(`Creating sandbox...`);c.start();let l=await yc({client:s,explicitTeam:e.team,personal:e.personal,activeTeamId:o.activeTeamId}),u=Us(e.env??[],`--env`,`env`),d=e.metadata?ic(e.metadata):void 0,f=oc(e,t),p=sc(e,n),m=e.acceleratorKind?Ls({kind:String(e.acceleratorKind),count:String(e.acceleratorCount),memory:typeof e.acceleratorMemory==`string`?e.acceleratorMemory:void 0}):void 0,g=Rs({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:`tangle`}:void 0,y=e.backend||e.backendModel||a?{...e.backend?{type:_(e.backend)}:{},...a?{profile:a}:{},model:e.backendModel||r||i?{...e.backendModel?rc(e.backendModel):{},apiKey:r,...i?{cliAuth:i}:{}}:void 0}:void 0,b=tc(e.secret),x=i?[...new Set([...b??[],i.secretEnv])]:b,S=lc(e.proxySecret),C=nc(e,m),w=e.sshKeyFile??(e.ssh&&!e.sshKey&&!e.sshKeys?.length?[Ec()]:[]),T=[...e.sshKey?[e.sshKey]:[],...w.map(e=>fe(e,`utf8`).trim())],E={name:e.name,environment:e.environment,runtime:e.runtime,cpuFeatures:e.cpuFeatures?.split(`,`).map(e=>e.trim()),bare:e.bare||void 0,sshEnabled:e.ssh||!!e.sshKey||T.length>0||!!e.sshKeys?.length,sshPublicKeys:T.length>0?T:void 0,sshKeyIds:e.sshKeys,webTerminalEnabled:e.webTerminal,env:Object.keys(u).length>0?u:void 0,git:f,...C?{resources:C}:{},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:x,...S?{proxySecrets:S}:{},metadata:d,driver:v,backend:y},D=e.tee?{tee:e.tee,sealed:e.sealed||void 0,attestationRefresh:e.attestationRefresh||e.attestationNonce===`auto`||void 0}:void 0,O=D?await h(s,{...E,confidential:D,attestationNonce:e.attestationNonce??(e.attestationRefresh?`auto`:void 0),requireAttestation:e.requireAttestation??!0}):void 0,k=O?.sandbox??await s.create(E);e.wait&&(c.text=`Waiting for sandbox to start...`,await k.waitFor(`running`,{timeoutMs:12e4}),await k.refresh()),c.stop(),e.json?z({id:k.id,name:k.name,status:k.status,resources:k.resources,createdAt:k.createdAt,expiresAt:k.expiresAt,connection:xc(k.connection),teamId:l,gpuLease:k.gpuLease,confidential:D,attestation:O?.attestation,attestationNonce:O?.attestationNonce}):(B(`Sandbox created: ${k.id}`),An({id:k.id,name:k.name,status:k.status,resources:k.resources,createdAt:k.createdAt?.toISOString(),expiresAt:k.expiresAt?.toISOString(),connection:k.connection}),l&&console.log(`Team: ${l}`),k.gpuLease&&(console.log(`GPU lease: ${k.gpuLease.id}`),uc(k.gpuLease)),D&&(console.log(`TEE: ${D.tee}`),console.log(`Attestation: ${O?.attestation?`present`:`not returned`}`),O?.attestationNonce&&console.log(`Attestation nonce: ${O.attestationNonce}`)))})}const wc="A catalog environment, a container image reference, or a built image ID. Firecracker runs only images pinned by repository@sha256 that the cell's Firecracker hosts carry; `environments list` shows each image's runtimes";function Tc(){return new C(`--runtime <runtime>`,`Isolation on the platform's hosts: docker runs a container on the host kernel, firecracker a microVM with its own kernel. Omit for the platform default`).choices(c)}function Ec(){let e=[`id_ed25519`,`id_ecdsa`,`id_rsa`].map(e=>`${N()}/.ssh/${e}.pub`),t=e.find(e=>ue(e));if(!t)throw Error(`--ssh needs a public key and found none at ${e.join(`, `)}. Run ssh-keygen -t ed25519, or pass --ssh-key-file.`);return t}function Dc(e,t){if(!t)return e;let n=e?.model??{};return{...e,model:{...n,reasoningEffort:t}}}function Oc(e){if(e.spec){let t=JSON.parse(fe(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=jc(e),n=Mc(e,!!t?.accelerator),r={...e.environment?{environment:e.environment}:{},...t?{resources:t}:{},...e.runtime?{runtime:e.runtime}:{},...n?{gpuLease:n}:{},...e.backend?{backend:{type:e.backend}}:{}},i=Nc(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 kc(e){let{base:t,machines:n}=Oc(e);return{...t,machines:n}}function Ac(e){let{base:t,machines:n}=Oc(e);return{...t,workers:n}}function jc(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=Ls({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 Mc(e,t){return Rs({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 Nc(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 Pc(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>`,wc).addOption(Tc()).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 <gb>`,`Minimum memory per GPU in decimal GB`).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(`--backend <id>`,`Agent backend type`).option(`--workspace <mode>`,`Workspace mode: isolated (no driver supports shared yet)`,`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}=J(e),n=H(`Creating fleet...`);n.start();let r=e.coordinator?await t.fleets.createWithCoordinator(Ac(e)):await t.fleets.create(kc(e));n.stop();let i=Xs(r.machines);e.json?z({fleetId:r.fleetId,machines:i}):(B(`Fleet created: ${r.fleetId}`),R(i,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}]))})}function Fc(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}=J(n),i=H(`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)z(a);else{R(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(fe(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}=J(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=H(`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||B(`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?z({fleetId:c.fleetId,createMs:l,sandboxes:c.machines.size,results:u,spend:d,deleted:!t.keep}):U({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}=J(t),r=await(await n.fleets.list({fleetId:e})).cancel();t.json?z({fleetId:e,...r}):B(`Fleet ${e}: interrupted ${r.interrupted} agents, cancelled ${r.children} child fleets`)})}const Ic=[`list`,`create`,`delete`,`exec`,`prompt`,`read`,`write`];function Lc(e){if(!(!e||e.length===0)){for(let t of e)if(!Ic.includes(t))throw Error(`Invalid token action '${t}'. Allowed: ${Ic.join(`, `)}`);return e}}function Rc(e){return e.length<=12?`****`:`${e.slice(0,6)}...${e.slice(-4)} (masked — use --json for full value)`}function zc(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}=J(t),r=H(`Minting fleet token...`);r.start();let i=await n.fleets.createToken(e,{actions:Lc(t.action),ttlMinutes:t.ttlMinutes?Number(t.ttlMinutes):void 0});r.stop(),t.json?z(i):(U({"Fleet ID":i.fleetId,Token:Rc(i.token),"Expires at":new Date(i.expiresAt).toISOString(),Actions:i.actions.join(`, `)}),console.log(`
|
|
145
145
|
Re-run with --json to print the full token value.`))})}function Bc(){let e=new S(`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}=J(t),r=H(`Creating workspace snapshot...`);r.start();let i=await n.fleets.createWorkspaceSnapshot(e);r.stop(),t.json?z(i):B(`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}=J(n),i=H(`Restoring workspace...`);i.start();let a=await r.fleets.restoreWorkspaceSnapshot(e,t);i.stop(),n.json?z(a):B(`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}=J(t),r=H(`Reconciling workspace...`);r.start();let i=await n.fleets.reconcileWorkspace(e);r.stop(),t.json?z(i):(U({"Fleet ID":i.fleetId,Checked:i.checked,"Orphaned mounts":i.orphanedMounts}),R(i.machines,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`mounted`,header:`Mounted`,width:10}]))}),e}function Vc(){let e=new S(`fleet`).description(`Manage sandbox fleets`);return Pc(e),Zs(e),e.addCommand(Bc()),Fc(e),Ys(e),zc(e),e}function Hc(){let e=new S(`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}=J(r),o=await Y(a,i,e);if(o=await X(o),!se.existsSync(t))throw Error(`Local file not found: ${t}`);let s=se.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?z({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}=J(r),o=await Y(a,i,e);o=await X(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=se.statSync(n);r.json||console.error(``),r.json?z({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}=J(n),a=await Y(i,r,e);a=await X(a);let o=await a.fs.list(t,{all:n.all,long:n.long});if(n.json)z(o);else if(n.long)jn([`Mode`,`Owner`,`Group`,`Size`,`Modified`,`Name`],o.map(e=>{let t=e.isDir?`d`:e.isSymlink?`l`:`-`,n=Uc(e.permissions),r=e.isDir?`<DIR>`:Wc(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}=J(n),a=await Y(i,r,e);a=await X(a);let o=await a.fs.stat(t);n.json?z(o):(console.log(` File: ${o.name}`),console.log(` Path: ${o.path}`),console.log(` Size: ${Wc(o.size)} (${o.size} bytes)`),console.log(` Type: ${o.isDir?`directory`:o.isSymlink?`symlink`:`file`}`),console.log(` Mode: ${Uc(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}=J(n),a=await Y(i,r,e);a=await X(a);let o=await a.read(t);n.json?z({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}=J(n),a=await Y(i,r,e);a=await X(a),await a.fs.delete(t,{recursive:n.recursive}),n.json?z({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}=J(n),a=await Y(i,r,e);a=await X(a),await a.fs.mkdir(t,{recursive:n.parents}),n.json?z({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}=J(n),a=await Y(i,r,e);a=await X(a);let o=await a.fs.exists(t);n.json?z({path:t,exists:o}):(console.log(o?`exists`:`not found`),process.exit(+!o))}),e}function Uc(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 Wc(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 Gc(){let e=new S(`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}=J(t),i=H(`Fetching status...`);t.json||i.start();let a=await Y(r,n,e);a=await X(a);let o=await a.git.status();if(i.stop(),t.json)z(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}=J(t),i=H(`Fetching log...`);t.json||i.start();let a=await Y(r,n,e);a=await X(a);let o=await a.git.log(Number.parseInt(t.limit,10));if(i.stop(),t.json)z(o);else if(o.length===0)console.log(`No commits found`);else for(let e of o)console.log(`${e.shortSha} ${e.message.split(`
|
|
146
146
|
`)[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}=J(t),i=H(`Fetching diff...`);t.json||i.start();let a=await Y(r,n,e);a=await X(a);let o=await a.git.diff(t.ref);i.stop(),t.json?z(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}=J(n),a=await Y(i,r,e);a=await X(a),await a.git.add(t),B(`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}=J(t),i=await Y(r,n,e);i=await X(i);let a=await i.git.commit(t.message,{amend:t.amend});t.json?z(a):B(`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}=J(t),i=H(`Pushing...`);i.start();let a=await Y(r,n,e);a=await X(a),await a.git.push({force:t.force}),i.stop(),B(`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}=J(t),i=H(`Pulling...`);i.start();let a=await Y(r,n,e);a=await X(a),await a.git.pull({rebase:t.rebase}),i.stop(),B(`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}=J(t),i=H(`Fetching branches...`);t.json||i.start();let a=await Y(r,n,e);a=await X(a);let o=await a.git.branches();i.stop(),t.json?z(o):o.length===0?console.log(`No branches found`):jn([`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}=J(n),a=await Y(i,r,e);a=await X(a),await a.git.checkout(t,{create:n.create}),B(`Checked out: ${t}${n.create?` (new)`:``}`)}),e}function Kc(e,t=16){if(!Number.isInteger(t)||t<=0||t>64)throw TypeError(`stableHashHex: lengthHex must be in [1, 64] (got ${t})`);let n=typeof e==`string`?e:JSON.stringify(e,(e,t)=>{if(t&&typeof t==`object`&&!Array.isArray(t)){let e={},n=t;for(let t of Object.keys(n).sort())e[t]=n[t];return e}return t});return w(`sha256`).update(n).digest(`hex`).slice(0,t)}Object.freeze([`HS256`]),Object.freeze([`RS256`]);async function qc(e,t,n=`tangle --help`){let r=new AbortController,i=e??r.signal,a=()=>{r.abort(),process.stderr.write(`Stopping…
|
|
147
147
|
`)};e||(process.once(`SIGINT`,a),process.once(`SIGTERM`,a));try{return i.throwIfAborted(),await t(i)}catch(e){if(!i.aborted||e instanceof W&&e.code===`RUN_STOPPED`)throw e;let t=new W(`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))}}function Jc(e,t){for(let[n,r]of Object.entries(t)){let t=e.gates?.find(e=>e.id===n);if(!t||!t.choices.includes(r))throw new W(`GATE_CHOICE_INVALID`,`Invalid choice for gate '${n}'`,t?`Choose one of: ${t.choices.join(`, `)}`:`The graph does not declare this gate`,`tangle graph run --help`)}}function Yc(e,t){let n=t.signal;return async r=>{let i=Object.hasOwn(e,r.gate)?e[r.gate]:void 0,a=`--param ${qe(`gate.${r.gate}=<choice>`)}`,o=`${r.question} Choose one of: ${r.choices.join(`, `)}`,s=()=>new W(`GATE_ANSWER_REQUIRED`,`Gate '${r.gate}' needs an answer. ${o}. Pass ${a}`,o,`tangle graph run <graph> ${a}`);if(i!==void 0)return{kind:`choose`,choice:i,by:`cli:param`};if(t.json||!process.stdin.isTTY)throw s();let c;try{c=await Vi(`${r.question} [${r.choices.join(` / `)}]`,void 0,n)}catch{if(n.aborted)return{kind:`stop`,reason:`Gate input interrupted or timed out`,by:`cli:terminal`};throw s()}if(!r.choices.includes(c))throw s();return{kind:`choose`,choice:c,by:`cli:terminal`}}}const Xc=P.strictObject({sourceId:P.string().min(1),generation:P.string().regex(/^kg_[a-f0-9]{64}$/)}),Zc=P.discriminatedUnion(`kind`,[P.strictObject({kind:P.literal(`local`),root:P.string().refine(ve),sourceDigest:P.string().regex(/^sha256:[a-f0-9]{64}$/)}),P.strictObject({kind:P.literal(`hub`),references:P.array(Xc).min(1)})]);async function Qc(e){let t=await I(e);return{kind:`local`,root:t,sourceDigest:`sha256:${await lt(t)}`}}function $c(e){throw Object.assign(Error(e),{code:`KNOWLEDGE_BACKEND_UNSUPPORTED`})}const el=P.strictObject({question:P.string().trim().min(1).max(16e3),limit:P.number().int().min(1).max(20).default(5)}),tl=P.object({results:P.array(P.object({sourceId:P.string().min(1),generation:P.string().regex(/^kg_[a-f0-9]{64}$/),hits:P.array(P.object({id:P.string(),snippet:P.string()}).passthrough()),evidence:P.object({receipt:P.unknown(),visibility:P.unknown(),sources:P.array(P.object({id:P.string(),uri:P.string(),contentHash:P.string()}))})}).passthrough()),failures:P.array(P.unknown()),partial:P.boolean()}).passthrough();let nl;function rl(){return nl??=(async()=>{let e=t(`@tangle-network/agent-knowledge`,import.meta.url);if(!e)throw Error(`Cannot identify the installed Knowledge retriever`);return JSON.parse(await F(e,`utf8`)).version})(),nl}async function il(e){let t=Zc.parse(e.binding),n=Object.freeze({...e.context});if(t.kind===`hub`){let r=e.queryHub;return r||$c(`This backend has no owner-authorized Hub knowledge query binding`),[{name:`knowledge_search`,description:`Search the graph's exact owner-authorized knowledge generations and retain retrieval evidence.`,inputSchema:el,inputSchemaJson:P.toJSONSchema(el),handler:async i=>{let a=el.parse(i),o=await r({query:a.question,limit:a.limit,expectedReferences:t.references,context:n},e.signal),s=tl.parse(o);if(!s.partial&&(s.results.length!==t.references.length||t.references.some(e=>s.results.filter(t=>t.sourceId===e.sourceId&&t.generation===e.generation).length!==1)))throw Error(`Hub knowledge omitted or duplicated a selected source generation`);let c=[],l=[];for(let r of s.results){let i=mt(r.evidence.receipt),o=r.evidence.visibility,s=ct(o);if(i.runId!==n.runId||i.actorId!==n.nodeId||i.profileDigest!==n.profileDigest||i.query!==a.question)throw Error(`Hub knowledge receipt does not match the trusted graph invocation`);if(i.attributes.sourceId!==r.sourceId||i.attributes.generation!==r.generation||!t.references.some(e=>e.sourceId===r.sourceId&&e.generation===r.generation))throw Error(`Hub knowledge receipt does not match an exact selected source generation`);if(r.hits.length!==i.results.length||r.hits.some((e,t)=>e.id!==i.results[t]?.pageId||e.snippet!==i.results[t]?.snippet))throw Error(`Hub knowledge hits do not match their retrieval receipt`);await it(i,()=>s),c.push(await e.record({context:n,binding:t,receipt:i,visibility:o,sources:r.evidence.sources})),l.push({sourceId:r.sourceId,generation:r.generation,hits:r.hits,retrievalReceiptDigest:i.receiptDigest})}return{partial:s.partial,failures:s.failures,results:l,retainedEvidence:c}}},{name:`knowledge_record`,description:`Retain an isolated knowledge proposal; it does not alter published source generations.`,inputSchema:P.strictObject({proposal:P.string().min(1)}),inputSchemaJson:{type:`object`,properties:{proposal:{type:`string`}},required:[`proposal`],additionalProperties:!1},handler:async r=>{let{proposal:i}=P.strictObject({proposal:P.string().min(1)}).parse(r);return dt(i),{isolated:!0,evaluated:!1,artifact:await e.recordProposal({context:n,binding:t,proposal:i,digest:A({context:n,binding:t,proposal:i})}),activation:`unsupported-for-hub-generations`}}}]}let r=async()=>{if(`sha256:${await lt(t.root)}`!==t.sourceDigest)throw Error(`The graph's pinned local knowledge changed`)};if(await r(),!e.storeRoot)throw Error(`Local graph Knowledge needs its private run-store root`);let i=await I(t.root),a=be(e.storeRoot),o=(e,t)=>{let n=ye(e,t);return n===``||!n.startsWith(`..`)&&!ve(n)};if(o(i,a)||o(a,i))throw Error(`Knowledge run stores must be separate from the curated corpus`);let s=ot({root:a,sharedRoot:i});await s.init(n.runId);let c=new Map;return at({stores:s,runId:n.runId,actorId:n.nodeId,retrieverVersion:await rl(),retainHistory:!0,recordRetrieval:async i=>{if(await r(),!i.visibility.artifact)throw Error(`Knowledge did not retain the visibility snapshot`);let a=await F(new URL(i.visibility.artifact.uri));await it(i,()=>a);let o=st(a),s=await ut(t.root),l=new Set(o.entries.flatMap(e=>e.sourceIds)),u=Object.values(s.sources).filter(e=>l.has(e.id)).map(({id:e,uri:t,contentHash:n})=>({id:e,uri:t,contentHash:n}));c.set(i.receiptDigest,await e.record({context:n,binding:t,receipt:i,visibility:o,sources:u}))}}).map(t=>({...t,handler:async(n,i)=>{e.signal?.throwIfAborted(),await r();let a=await t.handler(n,i);return await r(),a&&typeof a==`object`&&`retrievalReceiptDigest`in a?{...a,retainedEvidence:c.get(String(a.retrievalReceiptDigest))}:a}}))}function al(e){return async t=>{if(!Object.entries(t.profile.tools??{}).some(([e,t])=>t===!0&&/_knowledge_(search|read|record|resolve)$/.test(e)))return[];if(!t.identity.profileDigest)throw Error(`Knowledge tools require Runtime's exact profile identity`);return(await il({...e,...e.storeRoot?{storeRoot:M(e.storeRoot,t.nodeId)}:{},context:{runId:t.runId,nodeId:t.nodeId,profileDigest:t.identity.profileDigest}})).map(e=>{if(!e.inputSchemaJson)throw Error(`Knowledge tool lacks its wire input schema`);return{name:e.name,description:e.description,inputSchema:e.inputSchemaJson,handler:t=>e.handler(t,{})}})}}async function ol(e,t,n){let r=Zc.parse(e);r.kind!==`local`&&$c(`Measured file-backed Knowledge candidates cannot activate Hub generations; use the source generation owner's publication path`);let i=rt.parse(t);if(`sha256:${i.baseHash}`!==r.sourceDigest)throw Error(`Knowledge candidate does not match the graph's pinned baseline`);return n===`promote`?ft({root:r.root,candidate:i}):pt({root:r.root,candidate:i})}function sl(e,t,n,r){if(e==null)return;let i=Zc.parse(e);if(i.kind!==`local`)throw Error(`A local graph needs a pinned local Knowledge binding; Hub generations require the hosted workflow owner`);return al({binding:i,storeRoot:M(t,`knowledge`),signal:r,record:async e=>n.put({executionId:e.context.nodeId,purpose:`executor-native-evidence`,bytes:Buffer.from(JSON.stringify(e))}),recordProposal:async e=>n.put({executionId:e.context.nodeId,purpose:`task-output`,bytes:Buffer.from(JSON.stringify(e))})})}function cl(e){let t=e.command(`knowledge`).description(`Exact measured Knowledge candidate transitions`);t.command(`bind <root>`).description(`Identify exact bytes of an existing local Knowledge store`).action(async e=>z(await Qc(e)));for(let e of[`promote`,`restore`])t.command(`${e} <binding> <candidate>`).description(`${e} the exact measured local Knowledge candidate through its owner`).action(async(t,n)=>{let r=Zc.parse(JSON.parse(await F(t,`utf8`))),i=await ol(r,JSON.parse(await F(n,`utf8`)),e);z({...i,nextBinding:{...r,sourceDigest:`sha256:${i.mutation.afterHash}`}})})}const ll=()=>new C(`--mcp-secret <key=variable>`,`Private local MCP secret reference binding; repeatable, values are never recorded`).argParser((e,t)=>[...t,e]).default([]);function ul(e=[]){let t=new Map;for(let n of e){let e=n.indexOf(`=`),r=n.slice(0,e).trim(),i=n.slice(e+1).trim();if(e<1||!r||!/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)||t.has(r)&&t.get(r)!==i)throw new W(`GRAPH_MCP_SECRET_BINDING`,`Invalid private MCP credential binding`,`Use one unambiguous key=ENVIRONMENT_VARIABLE per declared secret reference`,`tangle graph run --help`);t.set(r,i)}return Object.fromEntries(t)}async function dl(e){try{return ke.parse(JSON.parse(await F(e,`utf8`)))}catch(e){throw new W(`GRAPH_MCP_POLICY_INVALID`,`The graph MCP policy is invalid`,e instanceof Error?e.message:String(e),`tangle graph run --help`)}}const fl=[`claude-code`,`opencode`,`codex`,`kimi-code`,`prime`],pl=process.env.TANGLE_ROUTER_URL??`https://router.tangle.tools/v1`;function ml(e){let t=ie(e);if(t)return t;throw Error(`--model '${e}' has no provider. Pass a canonical id, for example 'google/${e}'.`)}function hl(e){let t=e.harness??`claude-code`;if(!fl.includes(t))throw Error(`Unknown --harness '${t}'. Supported: ${fl.join(`, `)}.`);let n=gl(e.maxTokens,2e5,`--max-tokens`),r=gl(e.maxIterations,50,`--max-iterations`),i=e.maxWorkers===void 0?void 0:gl(e.maxWorkers,0,`--max-workers`);return{harness:t,...e.model?{model:e.model}:{},maxTokens:n,maxIterations:r,...i===void 0?{}:{maxWorkers:i}}}function gl(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 _l(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 vl(e){let t=e.spentTotal,n=e.kind===`no-winner`?``:e.out;return{text:typeof n==`string`?n:typeof n==`object`&&n&&`content`in n&&typeof n.content==`string`?n.content:JSON.stringify(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,status:e.kind===`no-winner`?`no-winner (${e.reason})`:`winner`}}let yl=null;function bl(){return yl??=import(`@tangle-network/agent-runtime/kernel`).catch(e=>{throw yl=null,e?.code===`ERR_MODULE_NOT_FOUND`?new W(`RUNTIME_UNAVAILABLE`,`Agent Runtime could not be loaded`,e.message,`npm install -g @tangle-network/sandbox-cli@latest`):e}),yl}async function xl(e,t,n){let r=K({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=q(r),{budget:a,perWorker:o}=_l(t),s=[],c={async create(e){let{TANGLE_API_KEY:t,...r}=e?.env??{},a=await i.create(e?.env?{...e,env:r}:e);return s.push({id:a.id,status:`spawned`}),n.json||V(`worker ${a.id} spawned`),a}},l=await bl(),u=l.workerFromBackend({backend:`sandbox`,sandboxClient:c,maxIterations:1}),d=(e,n)=>u({...e,harness:t.harness},n),f={name:`supervisor`,harness:`cli-base`,model:{default:t.model??`gemini-3.5-flash-lite`,provider:t.model?ml(t.model):`google`},tools:{agent_runtime_coordination_spawn_worker:!0,agent_runtime_coordination_observe_agent:!0}},p={routerBaseUrl:pl,routerKey:r.apiKey},m=vl(await l.supervise(f,{goal:e},{budget:a,makeWorkerAgent:d,router:p,...o?{perWorker:o}:{},...t.model?{allowedModels:[t.model]}:{},runId:`supervise-${E()}`})),h=m.status===`winner`?`settled`:`failed`;for(let e of s)e.status=h,n.json||V(`worker ${e.id} settled (${e.status})`);return{task:e,result:m.text,workers:s,tokenUsage:m.tokenUsage,costUsd:m.costUsd,status:m.status}}function Sl(){let e=new S(`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 (${fl.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=hl({harness:t.harness,model:t.model,maxTokens:t.maxTokens,maxIterations:t.maxIterations,maxWorkers:t.maxWorkers});t.json||(V(`Supervising: ${e}`),V(`harness=${n.harness} budget=${n.maxTokens}tok/${n.maxIterations}it`),console.log());let r=await xl(e,n,{apiKey:t.apiKey,baseUrl:t.baseUrl,json:t.json});if(t.json){z(r),r.status!==`winner`&&(process.exitCode=1);return}if(console.log(),r.result&&(console.log(r.result),console.log()),U({"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 Cl(e,t){let n=ye(e,t);return n!==`..`&&!n.startsWith(`..${xe}`)&&!ve(n)}const wl=`graph-task-workspaces`,Tl=P.number().int().positive().max(2**53-1),El=P.strictObject({maxArchiveBytes:Tl.optional(),maxEmbeddedArtifactBytes:Tl.optional(),maxFiles:Tl.optional(),maxFileBytes:Tl.optional(),maxTotalFileBytes:Tl.optional(),maxPathBytes:Tl.optional(),maxRepositoryBundleBytes:Tl.optional()}),Dl=ee.shape,Ol=P.strictObject({snapshot:P.strictObject({kind:Dl.kind,digest:Dl.digest,manifest:k,archive:k}).superRefine((e,t)=>{(e.digest!==e.manifest.sha256||!e.manifest.byteLength||!e.archive.byteLength)&&t.addIssue({code:`custom`,message:`The canonical workspace manifest, digest and archive must agree`})}),capture:P.strictObject({mode:P.literal(`git-working-tree`),runtimeVersion:P.string().min(1),limits:El}),gaps:P.tuple([P.literal(`environment-and-toolchain-not-snapshotted`),P.literal(`git-ignored-files-excluded`)])}),kl=e=>A(Ol.parse(e));function Al(e){for(let t of[e.snapshot.manifest,e.snapshot.archive])if(t.locator.kind!==`private-cas`||t.locator.namespace!==wl)throw Error(`Task workspace artifacts require their original local private CAS; cross-backend activation is unsupported`)}async function jl(){let e=M(N(),`.tangle`);return await Ze(e,{recursive:!0,mode:448}),I(e)}const Ml=e=>Ct(M(e,`artifacts`),wl);async function Nl(e){let t=await $e(be(e),le.O_RDONLY|le.O_NOFOLLOW);try{if(!(await t.stat()).isFile())throw Error(`Task workspace reference must be a regular file`);let e=Ol.parse(JSON.parse(await t.readFile(`utf8`)));return Al(e),e}finally{await t.close()}}async function Pl(e,n={}){n.signal?.throwIfAborted();let r=be(e),i=await Xe(r);if(!i.isDirectory()||i.isSymbolicLink())throw Error(`Task workspace must be one real repository root`);let a=await I(r),o=await I(N()),s=await jl();if(a===o||a===ge(a)||Cl(s,a)||Cl(a,s))throw Error(`Task workspace capture cannot include the home, filesystem or private evidence root`);let{release:c}=ht({lockPath:`${a}.graph-workspace.lock`});try{let e=El.parse(n.limits??{}),r=await bt(a,{includeRepository:!0,repositoryContents:`working-tree`,limits:e,artifactPersistence:{executionId:E(),outputArtifacts:Ml(s),signal:n.signal}}),i=t(`@tangle-network/agent-runtime`,import.meta.url);if(!i)throw Error(`Cannot identify the Runtime workspace archive owner`);let o=JSON.parse(await F(i,`utf8`));return Ol.parse({snapshot:r,capture:{mode:`git-working-tree`,runtimeVersion:o.version,limits:e},gaps:[`environment-and-toolchain-not-snapshotted`,`git-ignored-files-excluded`]})}finally{c()}}async function Fl(e,t){let n=P.uuid().parse(t.runId),r=Ol.parse(e);Al(r);let i=await jl(),a=M(i,`workspaces`);if(await Ze(a,{recursive:!0,mode:448}),await I(a)!==a)throw Error(`Task workspace allocation root redirects elsewhere`);let o=M(a,n),{release:s}=ht({lockPath:`${o}.lock`});try{t.signal?.throwIfAborted();let e=`${o}.task-workspace.json`,a;try{a=JSON.parse(await F(e,`utf8`))}catch(e){if(e.code!==`ENOENT`)throw e}let c=kl(r);if(a!==void 0){let e=P.strictObject({runId:P.uuid(),identity:P.string()}).parse(a);if(e.runId!==n||e.identity!==c||t.resumeCwd!==void 0&&be(t.resumeCwd)!==o||await I(o)!==o||!(await Xe(o)).isDirectory())throw Error(`The retained task workspace no longer names this exact native run allocation`)}else{if(t.resumeCwd!==void 0)throw Error(`The retained task workspace allocation receipt is missing`);await xt({snapshot:r.snapshot,artifacts:Ml(i),destination:o,limits:r.capture.limits,signal:t.signal}),await L(e,JSON.stringify({runId:n,identity:c}),{flag:`wx`,mode:384,flush:!0})}if(!t.validationOnly||a!==void 0)return{cwd:o,release:s};let l=await Promise.all([Xe(o,{bigint:!0}),Xe(e,{bigint:!0})]);return{cwd:o,release:async()=>{try{for(let[t,r]of[o,e].entries()){let e=await Xe(r,{bigint:!0});if(!(t===0?e.isDirectory():e.isFile())||e.dev!==l[t]?.dev||e.ino!==l[t]?.ino||await I(r)!==r)throw Error(`Validation allocation ${n} changed; retained`)}if(A(JSON.parse(await F(e,`utf8`)))!==A({runId:n,identity:c}))throw Error(`Validation allocation ${n} receipt changed; retained`);try{throw await Xe(M(i,`runs`,n)),Error(`Validation allocation ${n} has run state; retained`)}catch(e){if(e.code!==`ENOENT`)throw e}await nt(o,{recursive:!0}),await nt(e)}finally{s()}}}}catch(e){throw s(),e}}function Il(e){e.command(`workspace`).description(`Capture immutable local task files for graph replay`).command(`capture <repository>`).description(`Capture Git HEAD, index, tracked and unignored files into private local artifacts`).requiredOption(`--output <file>`,`New reference file outside the source repository`).option(`--limits <file>`,`JSON overrides for the maintained Runtime archive limits`).action(async(e,t)=>{let n=await I(be(e)),r=M(await I(ge(be(t.output))),he(be(t.output)));if(Cl(n,r))throw Error(`The task reference must be written outside the original workspace`);try{throw await Xe(r),Error(`Task workspace reference already exists; choose a new output file`)}catch(e){if(e.code!==`ENOENT`)throw e}let i=await Pl(n,{limits:t.limits?El.parse(JSON.parse(await F(t.limits,`utf8`))):void 0});await L(r,JSON.stringify(i),{flag:`wx`,mode:384,flush:!0}),z(i)})}const Ll=P.string().regex(/^[a-f0-9]{64}$/),Rl=P.strictObject({version:P.literal(1),runId:P.uuid(),file:P.string().refine(ve),cwd:P.string().refine(ve),sourceDigest:Ll,source:P.string().optional(),graphDigest:Ll,params:P.record(P.string(),P.unknown()),trigger:P.record(P.string(),P.unknown()).optional(),gateChoices:P.record(P.string(),P.string()).optional(),startedAt:P.iso.datetime(),seat:P.string().optional(),mcpPolicy:Ae.optional(),taskWorkspace:Ol.optional()});async function zl(e){let t=await bl(),n=t.graphRegistry(M(N(),`.tangle`,`graph-registry`)),r=await t.loadGraph(n,e.graphDigest);if(!r)throw Error(`Retained execution graph is unavailable; configuration is unknown`);let i=t.validateStoredGraph(r);if(i.digest!==e.graphDigest)throw Error(`Retained execution graph changed its identity`);return A({mcpPolicy:Ae.parse(e.mcpPolicy??{}),nodes:i.nodes.map(({id:e,profile:t})=>({id:e,harness:t.harness??null,model:t.model??null,seats:t.seats??null,connections:t.connections??null}))})}function Z(e){throw new W(`GRAPH_RESUME_REFUSED`,`The graph run cannot be resumed`,e,`tangle graph run --help`)}async function Bl(e){P.uuid().safeParse(e).success||Z(`Use a recorded graph run ID`);let t;try{let n=M(await I(M(N(),`.tangle`)),`runs`,e);await I(n)!==n&&Z(`The run directory redirects elsewhere`),t=await $e(M(n,`input.json`),le.O_RDONLY|le.O_NOFOLLOW),(await t.stat()).isFile()||Z(`The run input is not a regular file`);let r=Rl.parse(JSON.parse(await t.readFile(`utf8`)));return r.runId!==e&&Z(`The recorded run identity changed`),r.source!==void 0&&Hl(r,r.source),r}catch(e){if(e instanceof W)throw e;return Z(`The private recorded run input is missing or invalid`)}finally{await t?.close()}}async function Vl(e,t){let n=t.source??await F(t.file,`utf8`);Hl(t,n),await L(M(e,`input.json`),JSON.stringify({...t,source:n}),{flag:`wx`,mode:384,flush:!0})}function Hl(e,t){return w(`sha256`).update(t).digest(`hex`)!==e.sourceDigest&&Z(`The retained graph source does not match this run`),t}async function Ul(e){return Hl(e,e.source??await F(e.file,`utf8`))}function Wl(e,t,n,r,i={}){e.sourceDigest!==n&&Z(`The authored graph source changed`),t.cloud&&Z(`A local run cannot move to cloud execution`),Object.entries(r).some(([t,n])=>!Object.hasOwn(e.params,t)||A(n)!==A(e.params[t]))&&Z(`A recorded graph parameter changed`),Object.entries(i).some(([t,n])=>e.gateChoices?.[t]!==n)&&Z(`A recorded gate choice changed`),t.seat!==void 0&&t.seat!==e.seat&&Z(`The recorded graph seat override changed`),t.mcpPolicy!==void 0&&(e.mcpPolicy===void 0||A(t.mcpPolicy)!==A(e.mcpPolicy))&&Z(`The recorded graph MCP policy changed`)}const Gl=e=>Object.entries(e).map(([e,t])=>`${e}=${typeof t==`string`?t:JSON.stringify(t)}`),Kl=`claude,codex,kimi,opencode,gemini,pi`;function ql(e,t){let n;return async(r,{node:i,lastCandidate:a})=>{t.throwIfAborted();let o;try{o=r===void 0?void 0:ae(r)}catch(e){throw e instanceof Error&&Object.assign(e,{node:i,seat:r,fixCommand:`tangle graph run --help`}),e}n??=Et({cwd:e,signal:t,config:Dt({...process.env,BRIDGE_BACKENDS:Kl,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 W(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??ae(f.id).harness,m=o?.provider??f.provider,h=o?.model??f.id.slice(p.length+1);if(!m||!h)throw new W(`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 Jl=Ot(we);function Yl(e,t,n=`tangle graph run --help`){throw new W(`SEAT_NONE_DETECTED`,e,t,n)}function Xl(e){let t=[];for(let n of e.nodes)for(let e of n.check?.egress??[]){let n=e.trim().toLowerCase();if(n){if(/[\s*]|\/|:\/\//u.test(n))throw new W(`GRAPH_EGRESS_HOST`,`Graph egress host "${e.trim()}" is not a DNS hostname`,`A check egress entry has whitespace, a wildcard, or a URL`,`tangle graph run --help`);t.includes(n)||t.push(n)}}return t.length>0?t.join(`,`):void 0}function Zl(e){return e.some(e=>(e.profile?.seats?.length??0)>0)}function Ql(e){let t=e?.trim();if(t)return/\s/u.test(t)&&Yl(`A seat account, command, or credential must be a single token`,`The seat command is an executable path, not a shell line`),t}function $l(e){let t=Ql(e.seatAccount),n=Ql(e.seatCommand),r=Ql(e.seatCredential);return r&&!n&&!t&&Yl(`A seat credential needs a seat command`,`The credential is an argument to the configured command`,`tangle graph run --seat-command <program>`),{...t?{account:t}:{},...n?{command:n}:{},...r?{credential:r}:{}}}async function eu(e,t,n){if(e.account)return e.account;e.command||Yl(`This graph needs a seat account or a seat command`,`No account was authored and no seat command is configured`,`tangle graph run --seat-account <account>`);let r=``;try{r=(await Jl(e.command,[t,...e.credential?[e.credential]:[]],{timeout:3e4,maxBuffer:4096,signal:n,encoding:`utf8`})).stdout}catch(e){n.throwIfAborted();let t=e.code===`ENOENT`;Yl(t?`The seat command was not found`:`The seat command failed`,t?`The configured executable is not on PATH`:`The seat command exited without an account id`)}let i=r.trim();return(!i||/\s/u.test(i))&&Yl(`The seat command did not print an account id`,`The command must print one account id and nothing else`),i}function tu(e,t,n){let r=new Map;return async i=>{n.throwIfAborted();let a=i.stage.harness,o=i.stage.selector.kind===`seat`?i.stage.selector.id.trim():``,s=`${a}\0${t.credential??``}`,c=o||t.account||r.get(s)||await eu(t,a,n);return!o&&!t.account&&r.set(s,c),(!c||/\s/u.test(c)||i.resumeSeatId!==void 0&&i.resumeSeatId!==c)&&Yl(`Node '${i.nodeId}' has no seat account`,`The authored seat, account flag, or seat command did not yield one`),{seat:c,backend:{backend:`provider`,provider:At({baseUrl:e.bridgeUrl,bearerToken:e.bridgeBearer}),defaults:{workspace:{cwd:{base:`host`,path:e.cwd}}},runtime:`cli`,outputFormat:`json`,destroyOnSettle:!0,requireTerminalEvent:!0}}}}function Q(e){return Di({signal:e.signal,...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.baseUrl===void 0?{}:{baseUrl:e.baseUrl}})}const nu=P.object({version:P.literal(1),type:P.enum([`state`,`ack`,`error`,`event`]),requestId:P.string().optional(),operationId:P.string().optional(),command:P.string().optional(),code:P.string().optional(),message:P.string().optional(),result:P.unknown().optional()}).passthrough(),ru=P.object({state:P.object({runConfiguration:P.unknown()}),view:P.object({capabilities:P.record(P.string(),P.object({available:P.boolean(),reason:P.string().optional()}))})}),iu=P.object({status:P.enum([`completed`,`failed`,`cancelled`]),analysis:P.object({id:P.string().min(1)}).passthrough(),source:P.object({runtimeRun:P.unknown()}).passthrough()}).passthrough(),au=`TANGLE_GRAPH_ANALYSIS_SOURCE`;async function ou(e,t,n){if(!e.startsWith(`wfrun_`)){let t=M(await I(M(N(),`.tangle`)),`runs`,e);if(await I(t)!==t)throw new W(`RUN_NOT_FOUND`,`The run directory redirects elsewhere`,`Use the recorded local run directory`,`tangle graph inspect --help`);return{source:`runtime:${e}@${t}`,env:{},schema:P.object({runId:P.literal(e),runDir:P.literal(t)})}}let r={signal:n,...t.apiKey===void 0?{}:{apiKey:t.apiKey},...t.baseUrl===void 0?{}:{baseUrl:t.baseUrl}},i=await Q(r),a=P.object({id:P.literal(e),workflowId:P.string(),revUsed:P.number().int(),execution:P.object({kind:P.literal(`graph`),sourceSha:P.string(),authoredGraphDigest:P.string(),graphDigest:P.string()}),runtime:P.object({snapshot:P.object({supervisors:P.tuple([P.object({id:P.string()})])})})}).parse(await i.workflows.getRun(e,{signal:n})),o=a.runtime.snapshot.supervisors[0];if(!o)throw new W(`BRAID_RPC_FAILED`,`The cloud run has no retained Runtime root`,`Wait for execution evidence before analysis`,`tangle graph inspect ${e}`);let s=await Ci(r);if(new URL(s.baseUrl.replace(/\/+$/,``)).href!==new URL(i.baseUrl.replace(/\/+$/,``)).href)throw new W(`AUTH_REQUIRED`,`The analysis source origin changed`,`Use the same authenticated platform origin`,`tangle auth status --json`);return{source:`runtime:${e}@${au}`,env:{[au]:JSON.stringify({url:`${s.baseUrl.replace(/\/+$/,``)}/v1/workflows/runs/${encodeURIComponent(e)}`,headers:{Authorization:`Bearer ${s.token}`}})},schema:P.object({runId:P.literal(e),remoteEndpointEnv:P.literal(au),checkpoint:P.object({workflowId:P.literal(a.workflowId),runtimeRunId:P.literal(o.id),revUsed:P.literal(a.revUsed),sourceSha:P.literal(a.execution.sourceSha),authoredGraphDigest:P.literal(a.execution.authoredGraphDigest),graphDigest:P.literal(a.execution.graphDigest)})})}}async function su(e,t){if(!e.startsWith(`wfrun_`)&&!P.uuid().safeParse(e).success)throw new W(`RUN_NOT_FOUND`,`Use a recorded graph run ID`,`The run identifier is invalid`,`tangle graph inspect --help`);if(!Number.isSafeInteger(t.timeout)||t.timeout<1)throw new W(`INVALID_TIMEOUT`,`Use a positive analysis timeout`,`The timeout must be an integer number of milliseconds`,`tangle graph analyze --help`);let n=t.profile;if(!n?.trim())throw new W(`USAGE_INVALID`,`Select the canonical analysis profile`,`Graph analysis requires an existing canonical AgentProfile reference`,`tangle graph analyze `+e+` --profile <name|path>`);let r=/^(?:\.\.?)[/\\]/.test(n)?be(process.cwd(),n):n;return qc(t.signal,async n=>{let i=await ou(e,t,n),a=i.source;return wf({signal:n,errorRunId:e},async n=>{let o=await n.bridge(),s=await Qe(M(n.runDir,`analysis-`)),c=M(s,`config.json`),l=M(s,`database.key`),u=M(s,`state.sqlite`),d=`connection-owned-graph-bridge`,f=new Date().toISOString();await L(l,T(32),{mode:384,flag:`wx`}),await L(c,JSON.stringify({format:`braid-startup-config`,schemaVersion:2,profile:r,connectionId:d,connections:[{id:d,name:`Graph analysis`,kind:`cli-bridge`,endpoint:o.bridgeUrl,providerOptions:{transport:`local`},createdAt:f,updatedAt:f,lastHealth:{status:`unknown`}}]}),{mode:384,flag:`wx`});let p=n.signal,m=`op-${E()}`,h=`op-${E()}`,g=`${m}:initialize`,_=`${m}:analyze`,v=`${m}:shutdown`,y={version:1,requestId:g,command:`initialize`,params:{workspace:n.cwd,subscribe:!1}},b={version:1,requestId:_,operationId:m,command:`analyze`,params:{source:a,recipe:`all`,totalTimeoutMs:t.timeout}},x={version:1,requestId:v,operationId:h,command:`shutdown`,params:{mode:`wait`}},S,C,w,D,O={transform:e=>{let t=nu.parse(e);return t.type===`error`||t.type===`state`&&t.requestId===g||t.type===`ack`&&[_,v].includes(t.requestId??``)?t:null},onError:e=>{D??=e},onEvent:e=>{e.type===`error`&&(D??=new W(e.code??`BRAID_RPC_FAILED`,`Braid refused graph analysis`,e.message??`The RPC response omitted its cause`,`tangle graph analyze --help`)),e.requestId===g&&e.type===`state`&&(S??=e),e.requestId===_&&e.type===`ack`&&(C??=e),e.requestId===v&&e.type===`ack`&&(w??=e)}},k=await Ke({command:process.env.BRAID_BIN??`braid`,args:[`rpc`,`--workspace`,n.cwd,`--config`,c,`--profile`,r,`--database-key-file`,l],cwd:n.cwd,env:{...i.env,BRAID_STATE_PATH:u,BRAID_CLI_BRIDGE_ENDPOINT:o.bridgeUrl,BRAID_CLI_BRIDGE_AUTH:o.bridgeBearer},timeoutMs:t.timeout,signal:p,ownProcessGroup:!0},O,{stdin:[y,...t.dryRun?[]:[b],x].map(e=>JSON.stringify(e)).join(`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/sandbox-cli",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.106",
|
|
4
4
|
"description": "CLI for Tangle Sandbox operations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@tangle-network/agent-runtime": "^9.0.10",
|
|
27
27
|
"@tangle-network/harness-sessions": "^1.0.2",
|
|
28
28
|
"@tangle-network/hub-sdk": "1.0.30",
|
|
29
|
-
"@tangle-network/sandbox": "^1.0.
|
|
29
|
+
"@tangle-network/sandbox": "^1.0.391",
|
|
30
30
|
"@tangle-network/sdk-cli-runner": "^0.3.12",
|
|
31
31
|
"chalk": "^5.6.2",
|
|
32
32
|
"cli-bridge": "https://codeload.github.com/drewstone/cli-bridge/tar.gz/3f8b6f8777d04509641109f8b16ae450621f844b",
|
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
"typescript": "^6.0.3",
|
|
62
62
|
"vitest": "^4.1.12",
|
|
63
63
|
"@repo/shared": "0.0.0",
|
|
64
|
-
"@repo/knowledge-host": "0.0.0",
|
|
65
64
|
"@tangle-network/runtime-contracts": "0.20.0",
|
|
66
|
-
"@tangle-network/sdk-session-persistence": "0.7.0"
|
|
65
|
+
"@tangle-network/sdk-session-persistence": "0.7.0",
|
|
66
|
+
"@repo/knowledge-host": "0.0.0"
|
|
67
67
|
},
|
|
68
68
|
"publishConfig": {
|
|
69
69
|
"access": "public",
|
|
@@ -87,8 +87,8 @@
|
|
|
87
87
|
"author": "Tangle Network",
|
|
88
88
|
"license": "MIT",
|
|
89
89
|
"tangleRelease": {
|
|
90
|
-
"sourceSha": "
|
|
91
|
-
"mergedAt": "2026-11-
|
|
90
|
+
"sourceSha": "53768203a96a0136acc02bf251a9a59dda933f3a",
|
|
91
|
+
"mergedAt": "2026-11-12T16:05:32-08:00"
|
|
92
92
|
},
|
|
93
93
|
"scripts": {
|
|
94
94
|
"build": "tsdown",
|