@tangle-network/sandbox-cli 0.22.70 → 0.22.71
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 +1 -1
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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 ee from"ora";import{Command as x,Option as S}from"commander";import{createHash as C,randomBytes as te,randomUUID as w}from"node:crypto";import{ProxySecretsSchema as T,REASONING_EFFORTS as E,agentInteractiveSessionRunRef as D,agentProfileSchema as O,canonicalAgentProfileDigest as ne,canonicalCandidateDigest as re,modelProvider as ie,parseSeatSpec as ae}from"@tangle-network/agent-interface";import*as k from"node:fs";import{chmodSync as oe,constants as se,existsSync as ce,mkdirSync as le,readFileSync as ue,renameSync as de,writeFileSync as fe}from"node:fs";import*as A from"node:path";import{basename as pe,dirname as me,extname as he,isAbsolute as ge,join as j,relative as _e,resolve as ve,sep as ye}from"node:path";import*as be from"node:os";import{homedir as M,tmpdir as xe}from"node:os";import{execFile as Se,execFileSync as Ce,spawn as we}from"node:child_process";import{lockSync as Te}from"proper-lockfile";import{HubClient as Ee}from"@tangle-network/hub-sdk";import{createInterface as De}from"node:readline";import{Writable as Oe}from"node:stream";import{buffer as ke}from"node:stream/consumers";import{setTimeout as Ae}from"node:timers/promises";import{CONTENT_COMPLETION_KEY as je,CONTENT_PROMPT_KEY as Me,CONTENT_TOOL_ARGS_KEY as Ne,CONTENT_TOOL_NAME_KEY as Pe,CONTENT_TOOL_RESULT_KEY as Fe,TANGLE_SUBJECT_KEY as Ie,asContentField as Le,asContentString as Re}from"@tangle-network/agent-core/telemetry";import{z as N}from"zod";import{execCli as ze,shellQuote as Be}from"@tangle-network/sdk-cli-runner";import*as P from"node:fs/promises";import{mkdir as Ve,mkdtemp as He,open as Ue,readFile as We,realpath as Ge,rm as Ke,writeFile as qe}from"node:fs/promises";import{listLocalModels as Je,loadConfig as Ye}from"cli-bridge";import{promisify as Xe,stripVTControlCharacters as Ze}from"node:util";import{createCliBridgeProvider as Qe}from"@tangle-network/agent-provider-cli-bridge";import{gunzipSync as $e}from"node:zlib";import{SearchEnvironmentFault as et}from"@tangle-network/agent-runtime";import{fileURLToPath as tt,pathToFileURL as nt}from"node:url";import{parseDocument as rt}from"yaml";import{createMcpServer as it}from"@tangle-network/sandbox/agent";import{ensureAgentPreview as at,publishAgentPreview as ot,resolveSelfSandbox as st}from"@tangle-network/sandbox/preview";import{generatePrivateKey as ct,privateKeyToAccount as lt}from"viem/accounts";import{createPublicClient as ut,createWalletClient as dt,decodeAbiParameters as ft,decodeEventLog as pt,encodeAbiParameters as mt,getAddress as ht,http as gt,isAddress as _t,keccak256 as vt,parseAbi as yt,parseAbiItem as bt,parseAbiParameters as xt,stringToHex as St,toHex as Ct}from"viem";import{tempoModerato as wt}from"viem/chains";import{Actions as Tt,withRelay as Et}from"viem/tempo";import Dt from"ws";import{createIntelligenceClient as Ot}from"@tangle-network/sandbox/intelligence";let kt=!1;function At(e){kt=e}function jt(...e){kt?console.error(...e):console.log(...e)}function Mt(e){return e==null?b.dim(`-`):typeof e==`boolean`?e?b.green(`yes`):b.red(`no`):e instanceof Date?Pt(e):typeof e==`string`&&Nt(e)?Pt(new Date(e)):String(e)}function Nt(e){return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)}function Pt(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 Ft(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 F(e,t){let n=t.map(t=>{let n=t.header.length,r=Math.max(...e.map(e=>Mt(e[t.key]).length));return t.width??Math.max(n,r)+2}),r=e.map(e=>t.map(t=>t.key===`status`?Ft(String(e[t.key])):Mt(e[t.key])));Ht(t.map(e=>e.header),r,n)}function I(e){console.log(JSON.stringify(e,null,2))}function L(e){jt(b.green(`✓`),e)}function It(e){console.error(b.red(`✗`),e)}function Lt(e){jt(b.yellow(`!`),e)}function R(e){jt(b.blue(`→`),e)}const Rt=new Set;function z(e){let t=ee({text:e,color:`cyan`,isSilent:kt});return Rt.add(t),t}function zt(){for(let e of Rt)e.isSpinning&&e.stop();Rt.clear()}function B(e,t=0){let n=` `.repeat(t);for(let[t,r]of Object.entries(e))r!=null&&console.log(`${n}${b.dim(`${t}:`)} ${Mt(r)}`)}function Bt(e){let t=`${e.cpuCores} vCPU / ${e.memoryMB} MB / ${e.diskGB} GB`;return e.pool?`${t} (pool: ${e.pool})`:t}function Vt(e){if(console.log(),console.log(b.bold(`Sandbox Details`)),console.log(b.dim(`─`.repeat(40))),B({ID:e.id,Name:e.name,Status:Ft(e.status),Resources:e.resources?Bt(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}`;B({SSH:process.platform===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN='<token>'; ${r}`:`TANGLE_SSH_PROXY_AUTH_TOKEN='<token>' ${r}`})}e.connection.webTerminalUrl&&B({"Web Terminal":e.connection.webTerminalUrl}),e.connection.runtimeUrl&&B({"API URL":e.connection.runtimeUrl})}console.log()}function Ht(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 V=class extends Error{constructor(e,t,n,r){super(t),this.code=e,this.cause=n,this.fix=r,this.name=`ActionableCliError`}};const Ut=new Set([`AUTH_EXPIRED`,`AUTH_WRONG_AUDIENCE`,`SEAT_NONE_DETECTED`,`SEAT_NOT_LOGGED_IN`,`SEAT_NOT_ENROLLED`,`HUB_NOT_CONNECTED`,`HUB_RECONNECT`,`HUB_APP_NOT_INSTALLED`,`HUB_APPROVAL_REQUIRED`]),Wt=new Set([`GRAPH_INVALID`,`STEP_REF`,`PROFILE_INVALID`,`UNKNOWN_HARNESS`,`HUB_TOOL_UNKNOWN`,`TRIGGER_INVALID`,`WORKFLOW_INPUT_FILE_INVALID`,`VALIDATION_ERROR`]),Gt=new Set([`UNKNOWN_COMMAND`,`GRAPH_PARAM_MISSING`,`GRAPH_PARAM_UNKNOWN`,`SEAT_SYNTAX`,`HUB_PROVIDER_UNKNOWN`,`USAGE_INVALID`]),Kt=new Set([`SUBSCRIPTION_REQUIRED`,`MODEL_NOT_FOUND`,`MODEL_PROVIDER_MISMATCH`,`MCP_BLOCKED`,`CLOUD_SEAT_UNSUPPORTED`,`SCHEDULE_AUTHORITY`]);function qt(e){return typeof e==`object`&&e?e:{}}function H(e){return typeof e==`string`&&e.length>0?e:void 0}function Jt(e){let t=H(e);return t&&/^[a-z0-9][a-z0-9_-]*$/i.test(t)?t:void 0}function Yt(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=H(qt(n).code);(e||r)&&(t=r?`${r}${e?`: ${e}`:``}`:e)}return t}function Xt(e){return e.code===`credential-refused`&&e.owner===`caller`&&e.providerCode===`subscription_required`?qt(e.remediation):{}}function Zt(e){let t=qt(e),n=Array.isArray(t.runtimeFailures)?t.runtimeFailures.map(qt):[],c=n.find(e=>H(Xt(qt(e.failure)).fix))??n[0],l=qt(c?.failure??t.runtimeFailure),u=Xt(l),m=qt(t.details),h=Jt(t.provider??m.provider??m.providerId),g=qt(t.fix??m.fix),_=H(t.code)??`CLI_ERROR`,v=H(t.message)??String(e),y=H(l.cause)??H(t.cause)??H(m.reason)??v,b=`tangle --help`,ee=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([`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=Jt(qt(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`,ee=!0):e instanceof s?b=`tangle usage --json`:e instanceof i?(_=`NETWORK_UNAVAILABLE`,v=`Network error: ${v}`,y=Yt(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 V&&(b=e.fix,ee=!1),H(u.fix)&&(_=u.cause===`not_authenticated`?`SEAT_NOT_LOGGED_IN`:`SUBSCRIPTION_REQUIRED`),e instanceof o&&b===`tangle --help`&&(b=`tangle template publish --help`),b=H(u.fix)??H(g.command)??(_===`HUB_NOT_CONNECTED`?void 0:H(t.fixCommand))??b,Ut.has(_)&&b===`tangle --help`&&(b=`tangle auth login`);let x=qt(t.subject??m.subject??{node:c?.node??t.node,seat:t.seat??u.harness}),S=e instanceof i||e instanceof Error&&`batchCustody`in e?t.batchCustody:void 0;S&&(y=`Batch acceptance: ${S.acceptance}; retirement receipt ${S.cleanup?.mode===`release`&&S.cleanup.isComplete?`proved`:`unproved`}.`,ee=!1,b=`tangle batch run --help`);let C=H(t.resumeAt??m.resumeAt??m.resetAt);return{code:_,...S?{batchCustody:S}:{},catalogCode:H(t.catalogCode),message:H(t.nextStep)&&H(t.message),nextStep:H(t.nextStep),subject:{...H(x.node)?{node:String(x.node)}:{},...H(x.seat)?{seat:String(x.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},...H(g.url)?{url:String(g.url)}:{}},retryable:ee,...C&&Number.isFinite(Date.parse(C))?{resumeAt:C}:{},...H(t.runId)?{runId:String(t.runId)}:{},...H(t.requestId)?{requestId:String(t.requestId)}:{},...typeof t.status==`number`?{status:t.status}:{},...H(l.code)&&H(l.owner)?{runtimeFailure:{code:String(l.code),owner:String(l.owner),cause:typeof l.cause==`string`?l.cause:y,...H(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 Qt(e){let t=[e.subject.node&&`node ${e.subject.node}`,e.subject.seat].filter(Boolean).join(` · `);return`✗ ${`${t?`${t}: `:``}${e.what}${e.status?` (HTTP ${e.status})`:``}`}${e.cause===e.what?``:` — ${e.cause}`}${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 $t(e){return Qt(Zt(e))}function U(e,t=!1){zt();let n=Zt(e);t?I({ok:!1,error:n}):console.error(b.red(Qt(n)));let r=1;Ut.has(n.code)?r=77:Wt.has(n.code)?r=65:Gt.has(n.code)?r=64:Kt.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 en(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:pe(a)}}let t;try{t=ue(e,`utf8`)}catch{throw Error(`cannot read skill/tool "${e}": not a readable file and not a github: ref`)}return{kind:`inline`,name:pe(e),content:t}}function tn(e){let t=(e.skills??[]).map(en),n=(e.tools??[]).map(en),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 nn(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 an(`https://raw.githubusercontent.com/${i[0]}/${i[1]}/${a}/${i.slice(2).join(`/`)}`)}else t=/^https?:\/\//.test(e)?await an(e):ue(e,`utf8`);let n;try{n=JSON.parse(t)}catch{throw new V(`PROFILE_INVALID`,`Profile '${e}' is invalid`,`Expected a JSON AgentProfile`,`tangle agent profile create --name my-agent --json`)}return rn(n,e)}function rn(e,t){let n=O.safeParse(e);if(!n.success)throw new V(`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 an(e){let t=await fetch(e);if(!t.ok)throw Error(`failed to fetch ${e} (${t.status})`);return t.text()}async function on(e){let t=e.profileSource?await nn(e.profileSource):void 0,n=tn(e);return t?n?{...t,...n,...n.resources?{resources:{...t.resources,...n.resources}}:{}}:t:n}const sn=A.join(be.homedir(),`.tangle`),cn=A.join(sn,`credentials.json`),ln=`tangle-sandbox-cli`,un=new Int32Array(new SharedArrayBuffer(4)),dn=`TANGLE_ALLOW_PLAINTEXT_CREDENTIALS`;var fn=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)}},pn=class extends Error{constructor(){super(`Could not store credential in the OS keychain, and the plaintext fallback is not enabled. Install a keychain provider (macOS Keychain or libsecret/secret-tool on Linux), or set ${dn}=1 to opt into a plaintext credentials.json with mode 0600.`),this.name=`KeychainUnavailableError`}},mn=class extends Error{constructor(e){super(`Credential storage preflight failed: ${e}`),this.name=`CredentialStorageProbeError`}},hn=class extends Error{constructor(e){super(`Credential storage is busy. Wait a moment and retry.`),this.name=`CredentialsFileLockedError`,e&&(this.cause=e)}};function gn(e){let t=Sn(e);if(t)return{value:t,source:`keychain`};let n=Tn(e);return n?{value:n,source:`file`}:{source:`none`}}function _n(e,t){if(Cn(e,t))return Dn(e),`keychain`;if(!bn())throw new pn;return En(e,t),`file`}function vn(){let e=`credential-write-probe:${process.pid}:${w()}`,t=w();if(Cn(e,t)){let n=Sn(e);if(!wn(e))throw new mn(`the OS keychain accepted a test credential but the CLI could not remove it`);if(n!==t)throw new mn(`the OS keychain accepted a test credential but the CLI could not read it back`);return`keychain`}if(!bn())throw new pn;return jn(e),`file`}function yn(e){wn(e),Dn(e)}function bn(){let e=process.env[dn];if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function xn(e,t){let n=process.platform;if(n!==`darwin`&&n!==`linux`)return;let r=n===`darwin`?`security`:`secret-tool`;try{return Ce(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 Sn(e){let t=Nn(e);return xn({darwin:[`find-generic-password`,`-s`,ln,`-a`,t,`-w`],linux:[`lookup`,`service`,ln,`account`,t]})}function Cn(e,t){let n=Nn(e),r=[`add-generic-password`,`-U`,`-s`,ln,`-a`],i=[`store`,`--label=Tangle Sandbox CLI`,`service`];return xn({darwin:[...r,n,`-w`,t],linux:[...i,ln,`account`,n]},process.platform===`linux`?t:void 0)!==void 0}function wn(e){let t=Nn(e);return xn({darwin:[`delete-generic-password`,`-s`,ln,`-a`,t],linux:[`clear`,`service`,ln,`account`,t]})!==void 0}function Tn(e){return kn()[e]}function En(e,t){On(()=>{let n=kn();n[e]=t,An(n)})}function Dn(e){return On(()=>{let t;try{t=kn()}catch(e){if(e instanceof fn)return!1;throw e}return e in t?(delete t[e],An(t),Tn(e)===void 0):!0})}function On(e){Mn();let t=Date.now()+2e3,n,r;for(;!n;)try{n=Te(cn,{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 hn(r);Atomics.wait(un,0,0,20)}try{return e()}finally{n()}}function kn(){let e;try{e=k.readFileSync(cn,`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 fn(cn);let n={};for(let[e,r]of Object.entries(t))typeof r==`string`&&(n[e]=r);return n}catch(e){throw e instanceof fn?e:new fn(cn,e instanceof Error?e:void 0)}}function An(e){if(Mn(),Object.keys(e).length===0){k.existsSync(cn)&&k.unlinkSync(cn);return}let t=`${cn}.${process.pid}.tmp`;k.writeFileSync(t,`${JSON.stringify(e,null,2)}\n`,{mode:384}),k.renameSync(t,cn)}function jn(e){let t=w(),n=!1,r;try{if(En(e,t),n=!0,Tn(e)!==t)throw new mn(`the credentials file did not return the value just written`)}catch(e){r=e}finally{if(n)try{!Dn(e)&&!r&&(r=new mn(`the credentials file accepted a test credential but the CLI could not remove it`))}catch(e){r??=e}}if(r)throw r}function Mn(){if(!k.existsSync(sn)){k.mkdirSync(sn,{mode:448,recursive:!0});return}if(process.platform!==`win32`)try{(k.statSync(sn).mode&511)!=448&&k.chmodSync(sn,448)}catch{}}function Nn(e){return`profile:${e}`}const Pn=A.join(be.homedir(),`.tangle`),Fn=A.join(Pn,`config.json`),In=`https://id.tangle.tools`,Ln=`https://solve.tangle.tools/api/solve`,Rn=`default`;function zn(){return{tangleBaseUrl:process.env.TANGLE_BASE_URL,sandboxBaseUrl:process.env.SANDBOX_BASE_URL,hubUrl:process.env.TANGLE_HUB_URL}}function Bn(e,t){let n=Kn(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 Rn;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 Vn(){k.existsSync(Pn)||k.mkdirSync(Pn,{mode:448,recursive:!0})}function Hn(e,t){Vn();let n=`${e}.${process.pid}.tmp`;k.writeFileSync(n,t,{mode:384}),k.renameSync(n,e)}function Un(e){return e.startsWith(`sk_`)||e.startsWith(`sk-tan-`)}function Wn(){try{if(k.existsSync(Fn))return JSON.parse(k.readFileSync(Fn,`utf-8`))}catch{}return{}}function Gn(e){let t=yr(Wn(),e);Hn(Fn,`${JSON.stringify(t,null,2)}\n`)}function Kn(e){return br(e||process.env.TANGLE_PROFILE||process.env.SANDBOX_PROFILE||Wn().activeProfile||Rn)}function qn(e){Gn({activeProfile:br(e)})}function Jn(){return{token:process.env.TANGLE_LINE_TOKEN,baseUrl:process.env.TANGLE_HUB_URL}}function Yn(){return process.env.TANGLE_SANDBOX||Wn().currentSandbox||void 0}function Xn(e){Gn({currentSandbox:e})}function Zn(){let e=Wn();delete e.currentSandbox,Hn(Fn,`${JSON.stringify(e,null,2)}\n`)}function Qn(){let e=Wn().deviceId;if(e&&/^[A-Za-z0-9_.-]{1,64}$/.test(e))return e;let t=be.hostname().replace(/[^A-Za-z0-9_.-]/g,`-`).replace(/^-+|-+$/g,``).slice(0,32),n=te(4).toString(`hex`),r=`${t?`${t}-`:`device-`}${n}`;return Gn({deviceId:r}),r}function $n(e){let t=e||Yn();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 er(){let e=Wn(),t=Kn(),n=new Set([Rn,...Object.keys(e.profiles??{})]);return e.activeProfile&&n.add(br(e.activeProfile)),[...n].map(e=>{let n=gn(e).source;return{name:e,active:e===t,hasApiKey:n!==`none`,baseUrl:lr(void 0,e),apiKeySource:n}}).sort((e,t)=>e.name.localeCompare(t.name))}function tr(e){let t=Kn(e);return{name:t,active:t===Kn(),baseUrl:lr(void 0,t),credentialSource:gn(t).source}}function nr(e,t){let n=br(e),r=Wn(),i=vr(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=_n(n,t.apiKey)),Gn({profiles:Object.keys(l).length>0?l:{}}),u}function rr(e){let t=Kn(e),n={...Wn().profiles??{}},r=n[t];if(r){let e={...r};e.baseUrl||e.activeTeamId||e.activeTeamName?n[t]=e:delete n[t]}Gn({profiles:n}),yn(t)}function ir(){let e=process.env.TANGLE_API_KEY_FILE;if(e){let t=k.readFileSync(e,`utf8`).trim();if(!t.startsWith(`sk-tan-`))throw Error(`Invalid sandbox credential file`);return t}return process.env.TANGLE_API_KEY}function ar(e,t){let n=Bn(`sandbox`,t);return e||ir()||gn(n).value}function or(e,t){return e||(process.env.TANGLE_SOLVE_API_KEY?process.env.TANGLE_SOLVE_API_KEY:gn(Bn(`solve`,t)).value)}function sr(e,t){let n=Bn(`sandbox`,t);return e?`flag`:process.env.TANGLE_API_KEY_FILE||process.env.TANGLE_API_KEY?`env`:gn(n).source}function cr(e,t){return e?`flag`:process.env.TANGLE_SOLVE_API_KEY?`env`:gn(Bn(`solve`,t)).source}function lr(e,t){if(e)return e;let n=process.env.TANGLE_BASE_URL||process.env.SANDBOX_BASE_URL;if(n)return n;let r=Kn(t),i=Wn(),a=vr(r,i);return a.baseUrl?a.baseUrl:(r===Rn||r===`sandbox`)&&i.baseUrl?i.baseUrl:`https://sandbox.tangle.tools`}function ur(e){if(e)return e.replace(/\/v1\/hub\/?$/,``)}function dr(e){return e?.trim().replace(/\/+$/,``)||void 0}function fr(e){return dr(e?.flag)??dr(ur(dr(process.env.TANGLE_HUB_URL)))??dr(process.env.TANGLE_PLATFORM_URL)??dr(e?.cachedPlatformUrl?.())??In}function pr(e){let t=dr(e)??dr(process.env.TANGLE_SOLVE_API_URL);if(t&&t!==Ln)throw Error(`Solve credentials may only be sent to ${Ln}`);return Ln}function mr(e){let t=dr(e);if(t&&t!==In)throw Error(`Solve credentials may only be sent to ${In}`);return In}function W(e){let t=Bn(`sandbox`,e.profile),n=ar(e.apiKey,t);if(!n)throw Error(`No API key found for profile '${t}'. Set TANGLE_API_KEY or run: tangle auth login${t===Rn?``:` --profile ${t}`}`);return{apiKey:n,baseUrl:lr(e.baseUrl,t),timeout:e.timeout??3e4,profile:t,...hr(t)}}function hr(e){let t=Wn(),n=vr(Kn(e),t);return{activeTeamId:n.activeTeamId,activeTeamName:n.activeTeamName}}function gr(e,t){nr(Kn(t),{activeTeamId:e.id,activeTeamName:e.name})}function _r(e){let t=Kn(e),n=Wn(),r={...n.profiles??{}},i={baseUrl:vr(t,n).baseUrl};i.baseUrl?r[t]=i:delete r[t],Gn({profiles:r})}function vr(e,t=Wn()){let n=br(e);return{...n===Rn?{baseUrl:t.baseUrl,activeTeamId:t.profiles?.[Rn]?.activeTeamId,activeTeamName:t.profiles?.[Rn]?.activeTeamName}:{},...t.profiles?.[n]??{}}}function yr(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 br(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 xr=null,Sr=null;function G(e){if(!e&&xr)return xr;let t=e??W({});return(!xr||!Sr||Sr.apiKey!==t.apiKey||Sr.baseUrl!==t.baseUrl||Sr.timeout!==t.timeout)&&(xr=new l({apiKey:t.apiKey,baseUrl:t.baseUrl,timeoutMs:t.timeout}),Sr=t),xr}function Cr(){xr=null,Sr=null}function K(e){let t=W({apiKey:e.apiKey,baseUrl:e.baseUrl});return{context:t,client:G(t)}}async function wr(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 Tr(r,n)}function Tr(e,t){let n=t.trim();if(n.length===0)throw Error(`Connection reference is empty.`);let r=e.find(e=>e.id===n);if(r)return r.id;let i=n.indexOf(`:`),a=(i===-1?n:n.slice(0,i)).trim().toLowerCase(),o=i===-1?null:n.slice(i+1).trim(),s=e.filter(e=>e.status!==`revoked`&&e.providerId.toLowerCase()===a);if(o&&o.length>0){let e=o.toLowerCase();s=s.filter(t=>(t.accountDisplay??``).toLowerCase()===e||t.displayName.toLowerCase()===e)}if(s.length===1)return s[0].id;throw s.length===0?Error(`No hub connection matches "${t}". List your connections with \`tangle hub connections\`.`):Error(Er(t,s))}function Er(e,t){let n=t.map(e=>`- ${e.id} (provider: ${e.providerId}, account: ${e.accountDisplay??e.displayName})`).join(`
|
|
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 ee from"ora";import{Command as x,Option as S}from"commander";import{createHash as C,randomBytes as te,randomUUID as w}from"node:crypto";import{ProxySecretsSchema as T,REASONING_EFFORTS as E,agentInteractiveSessionRunRef as D,agentProfileSchema as O,canonicalAgentProfileDigest as ne,canonicalCandidateDigest as re,modelProvider as ie,parseSeatSpec as ae}from"@tangle-network/agent-interface";import*as k from"node:fs";import{chmodSync as oe,constants as se,existsSync as ce,mkdirSync as le,readFileSync as ue,renameSync as de,writeFileSync as fe}from"node:fs";import*as A from"node:path";import{basename as pe,dirname as me,extname as he,isAbsolute as ge,join as j,relative as _e,resolve as ve,sep as ye}from"node:path";import*as be from"node:os";import{homedir as M,tmpdir as xe}from"node:os";import{execFile as Se,execFileSync as Ce,spawn as we}from"node:child_process";import{lockSync as Te}from"proper-lockfile";import{HubClient as Ee}from"@tangle-network/hub-sdk";import{createInterface as De}from"node:readline";import{Writable as Oe}from"node:stream";import{buffer as ke}from"node:stream/consumers";import{setTimeout as Ae}from"node:timers/promises";import{CONTENT_COMPLETION_KEY as je,CONTENT_PROMPT_KEY as Me,CONTENT_TOOL_ARGS_KEY as Ne,CONTENT_TOOL_NAME_KEY as Pe,CONTENT_TOOL_RESULT_KEY as Fe,TANGLE_SUBJECT_KEY as Ie,asContentField as Le,asContentString as Re}from"@tangle-network/agent-core/telemetry";import{z as N}from"zod";import{execCli as ze,shellQuote as Be}from"@tangle-network/sdk-cli-runner";import*as P from"node:fs/promises";import{mkdir as Ve,mkdtemp as He,open as Ue,readFile as We,realpath as Ge,rm as Ke,writeFile as qe}from"node:fs/promises";import{listLocalModels as Je,loadConfig as Ye}from"cli-bridge";import{promisify as Xe,stripVTControlCharacters as Ze}from"node:util";import{createCliBridgeProvider as Qe}from"@tangle-network/agent-provider-cli-bridge";import{gunzipSync as $e}from"node:zlib";import{SearchEnvironmentFault as et}from"@tangle-network/agent-runtime";import{fileURLToPath as tt,pathToFileURL as nt}from"node:url";import{parseDocument as rt}from"yaml";import{createMcpServer as it}from"@tangle-network/sandbox/agent";import{ensureAgentPreview as at,publishAgentPreview as ot,resolveSelfSandbox as st}from"@tangle-network/sandbox/preview";import{generatePrivateKey as ct,privateKeyToAccount as lt}from"viem/accounts";import{createPublicClient as ut,createWalletClient as dt,decodeAbiParameters as ft,decodeEventLog as pt,encodeAbiParameters as mt,getAddress as ht,http as gt,isAddress as _t,keccak256 as vt,parseAbi as yt,parseAbiItem as bt,parseAbiParameters as xt,stringToHex as St,toHex as Ct}from"viem";import{tempoModerato as wt}from"viem/chains";import{Actions as Tt,withRelay as Et}from"viem/tempo";import Dt from"ws";import{createIntelligenceClient as Ot}from"@tangle-network/sandbox/intelligence";let kt=!1;function At(e){kt=e}function jt(...e){kt?console.error(...e):console.log(...e)}function Mt(e){return e==null?b.dim(`-`):typeof e==`boolean`?e?b.green(`yes`):b.red(`no`):e instanceof Date?Pt(e):typeof e==`string`&&Nt(e)?Pt(new Date(e)):String(e)}function Nt(e){return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)}function Pt(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 Ft(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 F(e,t){let n=t.map(t=>{let n=t.header.length,r=Math.max(...e.map(e=>Mt(e[t.key]).length));return t.width??Math.max(n,r)+2}),r=e.map(e=>t.map(t=>t.key===`status`?Ft(String(e[t.key])):Mt(e[t.key])));Ht(t.map(e=>e.header),r,n)}function I(e){console.log(JSON.stringify(e,null,2))}function L(e){jt(b.green(`✓`),e)}function It(e){console.error(b.red(`✗`),e)}function Lt(e){jt(b.yellow(`!`),e)}function R(e){jt(b.blue(`→`),e)}const Rt=new Set;function z(e){let t=ee({text:e,color:`cyan`,isSilent:kt});return Rt.add(t),t}function zt(){for(let e of Rt)e.isSpinning&&e.stop();Rt.clear()}function B(e,t=0){let n=` `.repeat(t);for(let[t,r]of Object.entries(e))r!=null&&console.log(`${n}${b.dim(`${t}:`)} ${Mt(r)}`)}function Bt(e){let t=`${e.cpuCores} vCPU / ${e.memoryMB} MB / ${e.diskGB} GB`;return e.pool?`${t} (pool: ${e.pool})`:t}function Vt(e){if(console.log(),console.log(b.bold(`Sandbox Details`)),console.log(b.dim(`─`.repeat(40))),B({ID:e.id,Name:e.name,Status:Ft(e.status),Resources:e.resources?Bt(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}`;B({SSH:process.platform===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN='<token>'; ${r}`:`TANGLE_SSH_PROXY_AUTH_TOKEN='<token>' ${r}`})}e.connection.webTerminalUrl&&B({"Web Terminal":e.connection.webTerminalUrl}),e.connection.runtimeUrl&&B({"API URL":e.connection.runtimeUrl})}console.log()}function Ht(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 V=class extends Error{constructor(e,t,n,r){super(t),this.code=e,this.cause=n,this.fix=r,this.name=`ActionableCliError`}};const Ut=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`]),Wt=new Set([`GRAPH_INVALID`,`STEP_REF`,`PROFILE_INVALID`,`UNKNOWN_HARNESS`,`HUB_TOOL_UNKNOWN`,`TRIGGER_INVALID`,`WORKFLOW_INPUT_FILE_INVALID`,`VALIDATION_ERROR`]),Gt=new Set([`UNKNOWN_COMMAND`,`GRAPH_PARAM_MISSING`,`GRAPH_PARAM_UNKNOWN`,`SEAT_SYNTAX`,`HUB_PROVIDER_UNKNOWN`,`USAGE_INVALID`]),Kt=new Set([`SUBSCRIPTION_REQUIRED`,`MODEL_NOT_FOUND`,`MODEL_PROVIDER_MISMATCH`,`MCP_BLOCKED`,`CLOUD_SEAT_UNSUPPORTED`,`SCHEDULE_AUTHORITY`]);function qt(e){return typeof e==`object`&&e?e:{}}function H(e){return typeof e==`string`&&e.length>0?e:void 0}function Jt(e){let t=H(e);return t&&/^[a-z0-9][a-z0-9_-]*$/i.test(t)?t:void 0}function Yt(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=H(qt(n).code);(e||r)&&(t=r?`${r}${e?`: ${e}`:``}`:e)}return t}function Xt(e){return e.code===`credential-refused`&&e.owner===`caller`&&e.providerCode===`subscription_required`?qt(e.remediation):{}}function Zt(e){let t=qt(e),n=Array.isArray(t.runtimeFailures)?t.runtimeFailures.map(qt):[],c=n.find(e=>H(Xt(qt(e.failure)).fix))??n[0],l=qt(c?.failure??t.runtimeFailure),u=Xt(l),m=qt(t.details),h=Jt(t.provider??m.provider??m.providerId),g=qt(t.fix??m.fix),_=H(t.code)??`CLI_ERROR`,v=H(t.message)??String(e),y=H(l.cause)??H(t.cause)??H(m.reason)??v,b=`tangle --help`,ee=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=Jt(qt(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`,ee=!0):e instanceof s?b=`tangle usage --json`:e instanceof i?(_=`NETWORK_UNAVAILABLE`,v=`Network error: ${v}`,y=Yt(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 V&&(b=e.fix,ee=!1),H(u.fix)&&(_=u.cause===`not_authenticated`?`SEAT_NOT_LOGGED_IN`:`SUBSCRIPTION_REQUIRED`),e instanceof o&&b===`tangle --help`&&(b=`tangle template publish --help`),b=H(u.fix)??H(g.command)??(_===`HUB_NOT_CONNECTED`?void 0:H(t.fixCommand))??b,Ut.has(_)&&b===`tangle --help`&&(b=`tangle auth login`);let x=qt(t.subject??m.subject??{node:c?.node??t.node,seat:t.seat??u.harness}),S=e instanceof i||e instanceof Error&&`batchCustody`in e?t.batchCustody:void 0;S&&(y=`Batch acceptance: ${S.acceptance}; retirement receipt ${S.cleanup?.mode===`release`&&S.cleanup.isComplete?`proved`:`unproved`}.`,ee=!1,b=`tangle batch run --help`);let C=H(t.resumeAt??m.resumeAt??m.resetAt);return{code:_,...S?{batchCustody:S}:{},catalogCode:H(t.catalogCode),message:H(t.nextStep)&&H(t.message),nextStep:H(t.nextStep),subject:{...H(x.node)?{node:String(x.node)}:{},...H(x.seat)?{seat:String(x.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},...H(g.url)?{url:String(g.url)}:{}},retryable:ee,...C&&Number.isFinite(Date.parse(C))?{resumeAt:C}:{},...H(t.runId)?{runId:String(t.runId)}:{},...H(t.requestId)?{requestId:String(t.requestId)}:{},...typeof t.status==`number`?{status:t.status}:{},...H(l.code)&&H(l.owner)?{runtimeFailure:{code:String(l.code),owner:String(l.owner),cause:typeof l.cause==`string`?l.cause:y,...H(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 Qt(e){let t=[e.subject.node&&`node ${e.subject.node}`,e.subject.seat].filter(Boolean).join(` · `);return`✗ ${`${t?`${t}: `:``}${e.what}${e.status?` (HTTP ${e.status})`:``}`}${e.cause===e.what?``:` — ${e.cause}`}${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 $t(e){return Qt(Zt(e))}function U(e,t=!1){zt();let n=Zt(e);t?I({ok:!1,error:n}):console.error(b.red(Qt(n)));let r=1;Ut.has(n.code)?r=77:Wt.has(n.code)?r=65:Gt.has(n.code)?r=64:Kt.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 en(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:pe(a)}}let t;try{t=ue(e,`utf8`)}catch{throw Error(`cannot read skill/tool "${e}": not a readable file and not a github: ref`)}return{kind:`inline`,name:pe(e),content:t}}function tn(e){let t=(e.skills??[]).map(en),n=(e.tools??[]).map(en),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 nn(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 an(`https://raw.githubusercontent.com/${i[0]}/${i[1]}/${a}/${i.slice(2).join(`/`)}`)}else t=/^https?:\/\//.test(e)?await an(e):ue(e,`utf8`);let n;try{n=JSON.parse(t)}catch{throw new V(`PROFILE_INVALID`,`Profile '${e}' is invalid`,`Expected a JSON AgentProfile`,`tangle agent profile create --name my-agent --json`)}return rn(n,e)}function rn(e,t){let n=O.safeParse(e);if(!n.success)throw new V(`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 an(e){let t=await fetch(e);if(!t.ok)throw Error(`failed to fetch ${e} (${t.status})`);return t.text()}async function on(e){let t=e.profileSource?await nn(e.profileSource):void 0,n=tn(e);return t?n?{...t,...n,...n.resources?{resources:{...t.resources,...n.resources}}:{}}:t:n}const sn=A.join(be.homedir(),`.tangle`),cn=A.join(sn,`credentials.json`),ln=`tangle-sandbox-cli`,un=new Int32Array(new SharedArrayBuffer(4)),dn=`TANGLE_ALLOW_PLAINTEXT_CREDENTIALS`;var fn=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)}},pn=class extends Error{constructor(){super(`Could not store credential in the OS keychain, and the plaintext fallback is not enabled. Install a keychain provider (macOS Keychain or libsecret/secret-tool on Linux), or set ${dn}=1 to opt into a plaintext credentials.json with mode 0600.`),this.name=`KeychainUnavailableError`}},mn=class extends Error{constructor(e){super(`Credential storage preflight failed: ${e}`),this.name=`CredentialStorageProbeError`}},hn=class extends Error{constructor(e){super(`Credential storage is busy. Wait a moment and retry.`),this.name=`CredentialsFileLockedError`,e&&(this.cause=e)}};function gn(e){let t=Sn(e);if(t)return{value:t,source:`keychain`};let n=Tn(e);return n?{value:n,source:`file`}:{source:`none`}}function _n(e,t){if(Cn(e,t))return Dn(e),`keychain`;if(!bn())throw new pn;return En(e,t),`file`}function vn(){let e=`credential-write-probe:${process.pid}:${w()}`,t=w();if(Cn(e,t)){let n=Sn(e);if(!wn(e))throw new mn(`the OS keychain accepted a test credential but the CLI could not remove it`);if(n!==t)throw new mn(`the OS keychain accepted a test credential but the CLI could not read it back`);return`keychain`}if(!bn())throw new pn;return jn(e),`file`}function yn(e){wn(e),Dn(e)}function bn(){let e=process.env[dn];if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function xn(e,t){let n=process.platform;if(n!==`darwin`&&n!==`linux`)return;let r=n===`darwin`?`security`:`secret-tool`;try{return Ce(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 Sn(e){let t=Nn(e);return xn({darwin:[`find-generic-password`,`-s`,ln,`-a`,t,`-w`],linux:[`lookup`,`service`,ln,`account`,t]})}function Cn(e,t){let n=Nn(e),r=[`add-generic-password`,`-U`,`-s`,ln,`-a`],i=[`store`,`--label=Tangle Sandbox CLI`,`service`];return xn({darwin:[...r,n,`-w`,t],linux:[...i,ln,`account`,n]},process.platform===`linux`?t:void 0)!==void 0}function wn(e){let t=Nn(e);return xn({darwin:[`delete-generic-password`,`-s`,ln,`-a`,t],linux:[`clear`,`service`,ln,`account`,t]})!==void 0}function Tn(e){return kn()[e]}function En(e,t){On(()=>{let n=kn();n[e]=t,An(n)})}function Dn(e){return On(()=>{let t;try{t=kn()}catch(e){if(e instanceof fn)return!1;throw e}return e in t?(delete t[e],An(t),Tn(e)===void 0):!0})}function On(e){Mn();let t=Date.now()+2e3,n,r;for(;!n;)try{n=Te(cn,{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 hn(r);Atomics.wait(un,0,0,20)}try{return e()}finally{n()}}function kn(){let e;try{e=k.readFileSync(cn,`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 fn(cn);let n={};for(let[e,r]of Object.entries(t))typeof r==`string`&&(n[e]=r);return n}catch(e){throw e instanceof fn?e:new fn(cn,e instanceof Error?e:void 0)}}function An(e){if(Mn(),Object.keys(e).length===0){k.existsSync(cn)&&k.unlinkSync(cn);return}let t=`${cn}.${process.pid}.tmp`;k.writeFileSync(t,`${JSON.stringify(e,null,2)}\n`,{mode:384}),k.renameSync(t,cn)}function jn(e){let t=w(),n=!1,r;try{if(En(e,t),n=!0,Tn(e)!==t)throw new mn(`the credentials file did not return the value just written`)}catch(e){r=e}finally{if(n)try{!Dn(e)&&!r&&(r=new mn(`the credentials file accepted a test credential but the CLI could not remove it`))}catch(e){r??=e}}if(r)throw r}function Mn(){if(!k.existsSync(sn)){k.mkdirSync(sn,{mode:448,recursive:!0});return}if(process.platform!==`win32`)try{(k.statSync(sn).mode&511)!=448&&k.chmodSync(sn,448)}catch{}}function Nn(e){return`profile:${e}`}const Pn=A.join(be.homedir(),`.tangle`),Fn=A.join(Pn,`config.json`),In=`https://id.tangle.tools`,Ln=`https://solve.tangle.tools/api/solve`,Rn=`default`;function zn(){return{tangleBaseUrl:process.env.TANGLE_BASE_URL,sandboxBaseUrl:process.env.SANDBOX_BASE_URL,hubUrl:process.env.TANGLE_HUB_URL}}function Bn(e,t){let n=Kn(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 Rn;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 Vn(){k.existsSync(Pn)||k.mkdirSync(Pn,{mode:448,recursive:!0})}function Hn(e,t){Vn();let n=`${e}.${process.pid}.tmp`;k.writeFileSync(n,t,{mode:384}),k.renameSync(n,e)}function Un(e){return e.startsWith(`sk_`)||e.startsWith(`sk-tan-`)}function Wn(){try{if(k.existsSync(Fn))return JSON.parse(k.readFileSync(Fn,`utf-8`))}catch{}return{}}function Gn(e){let t=yr(Wn(),e);Hn(Fn,`${JSON.stringify(t,null,2)}\n`)}function Kn(e){return br(e||process.env.TANGLE_PROFILE||process.env.SANDBOX_PROFILE||Wn().activeProfile||Rn)}function qn(e){Gn({activeProfile:br(e)})}function Jn(){return{token:process.env.TANGLE_LINE_TOKEN,baseUrl:process.env.TANGLE_HUB_URL}}function Yn(){return process.env.TANGLE_SANDBOX||Wn().currentSandbox||void 0}function Xn(e){Gn({currentSandbox:e})}function Zn(){let e=Wn();delete e.currentSandbox,Hn(Fn,`${JSON.stringify(e,null,2)}\n`)}function Qn(){let e=Wn().deviceId;if(e&&/^[A-Za-z0-9_.-]{1,64}$/.test(e))return e;let t=be.hostname().replace(/[^A-Za-z0-9_.-]/g,`-`).replace(/^-+|-+$/g,``).slice(0,32),n=te(4).toString(`hex`),r=`${t?`${t}-`:`device-`}${n}`;return Gn({deviceId:r}),r}function $n(e){let t=e||Yn();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 er(){let e=Wn(),t=Kn(),n=new Set([Rn,...Object.keys(e.profiles??{})]);return e.activeProfile&&n.add(br(e.activeProfile)),[...n].map(e=>{let n=gn(e).source;return{name:e,active:e===t,hasApiKey:n!==`none`,baseUrl:lr(void 0,e),apiKeySource:n}}).sort((e,t)=>e.name.localeCompare(t.name))}function tr(e){let t=Kn(e);return{name:t,active:t===Kn(),baseUrl:lr(void 0,t),credentialSource:gn(t).source}}function nr(e,t){let n=br(e),r=Wn(),i=vr(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=_n(n,t.apiKey)),Gn({profiles:Object.keys(l).length>0?l:{}}),u}function rr(e){let t=Kn(e),n={...Wn().profiles??{}},r=n[t];if(r){let e={...r};e.baseUrl||e.activeTeamId||e.activeTeamName?n[t]=e:delete n[t]}Gn({profiles:n}),yn(t)}function ir(){let e=process.env.TANGLE_API_KEY_FILE;if(e){let t=k.readFileSync(e,`utf8`).trim();if(!t.startsWith(`sk-tan-`))throw Error(`Invalid sandbox credential file`);return t}return process.env.TANGLE_API_KEY}function ar(e,t){let n=Bn(`sandbox`,t);return e||ir()||gn(n).value}function or(e,t){return e||(process.env.TANGLE_SOLVE_API_KEY?process.env.TANGLE_SOLVE_API_KEY:gn(Bn(`solve`,t)).value)}function sr(e,t){let n=Bn(`sandbox`,t);return e?`flag`:process.env.TANGLE_API_KEY_FILE||process.env.TANGLE_API_KEY?`env`:gn(n).source}function cr(e,t){return e?`flag`:process.env.TANGLE_SOLVE_API_KEY?`env`:gn(Bn(`solve`,t)).source}function lr(e,t){if(e)return e;let n=process.env.TANGLE_BASE_URL||process.env.SANDBOX_BASE_URL;if(n)return n;let r=Kn(t),i=Wn(),a=vr(r,i);return a.baseUrl?a.baseUrl:(r===Rn||r===`sandbox`)&&i.baseUrl?i.baseUrl:`https://sandbox.tangle.tools`}function ur(e){if(e)return e.replace(/\/v1\/hub\/?$/,``)}function dr(e){return e?.trim().replace(/\/+$/,``)||void 0}function fr(e){return dr(e?.flag)??dr(ur(dr(process.env.TANGLE_HUB_URL)))??dr(process.env.TANGLE_PLATFORM_URL)??dr(e?.cachedPlatformUrl?.())??In}function pr(e){let t=dr(e)??dr(process.env.TANGLE_SOLVE_API_URL);if(t&&t!==Ln)throw Error(`Solve credentials may only be sent to ${Ln}`);return Ln}function mr(e){let t=dr(e);if(t&&t!==In)throw Error(`Solve credentials may only be sent to ${In}`);return In}function W(e){let t=Bn(`sandbox`,e.profile),n=ar(e.apiKey,t);if(!n)throw Error(`No API key found for profile '${t}'. Set TANGLE_API_KEY or run: tangle auth login${t===Rn?``:` --profile ${t}`}`);return{apiKey:n,baseUrl:lr(e.baseUrl,t),timeout:e.timeout??3e4,profile:t,...hr(t)}}function hr(e){let t=Wn(),n=vr(Kn(e),t);return{activeTeamId:n.activeTeamId,activeTeamName:n.activeTeamName}}function gr(e,t){nr(Kn(t),{activeTeamId:e.id,activeTeamName:e.name})}function _r(e){let t=Kn(e),n=Wn(),r={...n.profiles??{}},i={baseUrl:vr(t,n).baseUrl};i.baseUrl?r[t]=i:delete r[t],Gn({profiles:r})}function vr(e,t=Wn()){let n=br(e);return{...n===Rn?{baseUrl:t.baseUrl,activeTeamId:t.profiles?.[Rn]?.activeTeamId,activeTeamName:t.profiles?.[Rn]?.activeTeamName}:{},...t.profiles?.[n]??{}}}function yr(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 br(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 xr=null,Sr=null;function G(e){if(!e&&xr)return xr;let t=e??W({});return(!xr||!Sr||Sr.apiKey!==t.apiKey||Sr.baseUrl!==t.baseUrl||Sr.timeout!==t.timeout)&&(xr=new l({apiKey:t.apiKey,baseUrl:t.baseUrl,timeoutMs:t.timeout}),Sr=t),xr}function Cr(){xr=null,Sr=null}function K(e){let t=W({apiKey:e.apiKey,baseUrl:e.baseUrl});return{context:t,client:G(t)}}async function wr(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 Tr(r,n)}function Tr(e,t){let n=t.trim();if(n.length===0)throw Error(`Connection reference is empty.`);let r=e.find(e=>e.id===n);if(r)return r.id;let i=n.indexOf(`:`),a=(i===-1?n:n.slice(0,i)).trim().toLowerCase(),o=i===-1?null:n.slice(i+1).trim(),s=e.filter(e=>e.status!==`revoked`&&e.providerId.toLowerCase()===a);if(o&&o.length>0){let e=o.toLowerCase();s=s.filter(t=>(t.accountDisplay??``).toLowerCase()===e||t.displayName.toLowerCase()===e)}if(s.length===1)return s[0].id;throw s.length===0?Error(`No hub connection matches "${t}". List your connections with \`tangle hub connections\`.`):Error(Er(t,s))}function Er(e,t){let n=t.map(e=>`- ${e.id} (provider: ${e.providerId}, account: ${e.accountDisplay??e.displayName})`).join(`
|
|
2
2
|
`);return`Hub connection reference is ambiguous: "${e}" matches ${t.length} connections. Use a connection id or provider:account instead.
|
|
3
3
|
`+n}function Dr(e,t){return[...t,e]}async function Or(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:`${Tr(r,e.ref)}:${e.tail}`)}function kr(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 Ar(e,t){return C(`sha256`).update(`${e}\0${t}`).digest(`hex`).slice(0,32)}function jr(e){return`${e}:hub`}function Mr(e){let{value:t}=gn(jr(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 Nr(e,t){try{_n(jr(e),JSON.stringify(t))}catch{}}async function Pr(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 Fr=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=Ar(t,n);let a=Mr(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 Pr(this.sandboxBaseUrl,this.sessionToken,this.deviceId,this.signal),sessionFingerprint:this.fingerprint};return this.cache=t,Nr(this.profile,t),t}};function Ir(e){if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function Lr(e,t){return fr({flag:e.baseUrl,...e.useCachedPlatformUrl?{cachedPlatformUrl:()=>Mr(t)?.platformUrl}:{}})}function Rr(e,t){let n=Bn(`sandbox`,e.profile),r=ar(e.apiKey,n),i=sr(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:Lr(e,n)}:{kind:`managed`,profile:n,sandboxBaseUrl:lr(e.sandboxBaseUrl,n),sessionToken:o,deviceId:Qn(),baseUrlOverride:e.baseUrl}}async function zr(e={}){let t=Rr(e,e.hubKey===!1||Ir(process.env.TANGLE_SKIP_HUB_KEY));if(t.kind===`static`)return{token:t.apiKey,baseUrl:t.baseUrl,minted:!1};let n=new Fr(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 Br(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 Vr(e={}){let t;try{t=await zr(e)}catch(e){return{reachable:!1,reason:e instanceof Error?e.message:String(e),refused:!0}}try{let e=await Br(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 Hr(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=Rr(e,e.hubKey===!1||Ir(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 Ee({baseUrl:r.baseUrl,fetch:n,authHeaders:()=>({Authorization:`Bearer ${t?ir():r.apiKey}`})})}let i=new Fr(r.profile,r.sandboxBaseUrl,r.sessionToken,r.deviceId,e.signal),a=await i.ensure();return new Ee({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 Ur(e={}){return Hr(e)}function q(e={}){return Hr({...e,useCachedPlatformUrl:!0,allowHubCapabilityToken:!0})}function Wr(e,t){return`Sandbox name is ambiguous: ${e}. Use a sandbox id instead.\n${t.map(e=>`- ${e.id} (status: ${e.status}, created: ${e.createdAt.toISOString()})`).join(`
|
|
4
4
|
`)}`}function Gr(e){return e.activeTeamId?`team:${e.activeTeamId}`:void 0}async function J(e,t,n,r={}){if(!r.nameOnly){let t=await e.get(n);if(t)return t;if(qr(n))throw Error(`Sandbox not found: ${n}`)}let i=(await e.list({scope:Gr(t)})).filter(e=>e.name?.toLowerCase()===n.toLowerCase());if(i.length===0)throw Error(`Sandbox not found: ${n}`);if(i.length>1)throw Error(Wr(n,i));return i[0]}const Kr=/^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 qr(e){return Kr.test(e)}async function Jr(e,t,n,r={}){try{return(await(await J(e,t,n,{nameOnly:r.name})).delete()).outcome}catch(e){if(!(e instanceof Error&&e.message===`Sandbox not found: ${n}`)||r.name||!r.retryCleanup&&!qr(n))throw e}let i=await e.fetch(`/v1/sandboxes/${encodeURIComponent(n)}`,{method:`DELETE`});if(i.ok){let e=await i.json().catch(()=>({}));return e.outcome===`destroyed`||e.outcome===`already_absent`?e.outcome:`unknown`}let a=(await i.text()).trim();throw Error(`Sandbox cleanup failed for ${n} (HTTP ${i.status})${a?`: ${a}`:``}`)}async function Y(e,t){if(e.status!==`stopped`)return e;let n=t?.resumeTimeoutMs??12e4;R(`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 Yr=[`anthropic`,`openai`,`vercel-ai`,`mastra`,`mcp-local`,`claude-desktop`,`cursor`,`zed`];function Xr(e,t,n){switch(e){case`anthropic`:return`// pnpm add @anthropic-ai/sdk @tangle-network/sandbox
|
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.71",
|
|
4
4
|
"description": "CLI for Tangle Sandbox operations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"tsx": "^4.23.15",
|
|
60
60
|
"typescript": "^6.0.3",
|
|
61
61
|
"vitest": "^4.1.12",
|
|
62
|
-
"@
|
|
63
|
-
"@
|
|
62
|
+
"@tangle-network/runtime-contracts": "0.20.0",
|
|
63
|
+
"@repo/shared": "0.0.0"
|
|
64
64
|
},
|
|
65
65
|
"publishConfig": {
|
|
66
66
|
"access": "public",
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
"author": "Tangle Network",
|
|
81
81
|
"license": "MIT",
|
|
82
82
|
"tangleRelease": {
|
|
83
|
-
"sourceSha": "
|
|
84
|
-
"mergedAt": "2026-11-
|
|
83
|
+
"sourceSha": "e0b6f9a9353f7397c3204131110ebc4913e248ef",
|
|
84
|
+
"mergedAt": "2026-11-09T13:40:16-08:00"
|
|
85
85
|
},
|
|
86
86
|
"scripts": {
|
|
87
87
|
"build": "tsdown",
|