@tangle-network/sandbox-cli 0.22.27 → 0.22.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +1 -1
  2. package/package.json +4 -4
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
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 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 ne,canonicalAgentProfileDigest as re,canonicalCandidateDigest as ie,modelProvider as ae,parseSeatSpec as oe}from"@tangle-network/agent-interface";import*as O from"node:fs";import{chmodSync as se,constants as ce,existsSync as le,mkdirSync as ue,readFileSync as k,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,writeFile as Ke}from"node:fs/promises";import{listLocalModels as qe,loadConfig as Je}from"cli-bridge";import{promisify as Ye,stripVTControlCharacters as Xe}from"node:util";import{gunzipSync as Ze}from"node:zlib";import{SearchEnvironmentFault as Qe}from"@tangle-network/agent-runtime";import{fileURLToPath as $e,pathToFileURL as et}from"node:url";import{parseDocument as tt}from"yaml";import{createMcpServer as nt}from"@tangle-network/sandbox/agent";import{ensureAgentPreview as rt,publishAgentPreview as it,resolveSelfSandbox as at}from"@tangle-network/sandbox/preview";import{generatePrivateKey as ot,privateKeyToAccount as st}from"viem/accounts";import{createPublicClient as ct,createWalletClient as lt,decodeAbiParameters as ut,decodeEventLog as dt,encodeAbiParameters as ft,getAddress as pt,http as mt,isAddress as ht,keccak256 as gt,parseAbi as _t,parseAbiItem as vt,parseAbiParameters as yt,stringToHex as bt,toHex as xt}from"viem";import{tempoModerato as St}from"viem/chains";import{Actions as Ct,withRelay as wt}from"viem/tempo";import Tt from"ws";import{createIntelligenceClient as Et}from"@tangle-network/sandbox/intelligence";let Dt=!1;function Ot(e){Dt=e}function kt(...e){Dt?console.error(...e):console.log(...e)}function At(e){return e==null?b.dim(`-`):typeof e==`boolean`?e?b.green(`yes`):b.red(`no`):e instanceof Date?Mt(e):typeof e==`string`&&jt(e)?Mt(new Date(e)):String(e)}function jt(e){return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)}function Mt(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 Nt(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=>At(e[t.key]).length));return t.width??Math.max(n,r)+2}),r=e.map(e=>t.map(t=>t.key===`status`?Nt(String(e[t.key])):At(e[t.key])));Bt(t.map(e=>e.header),r,n)}function I(e){console.log(JSON.stringify(e,null,2))}function L(e){kt(b.green(`✓`),e)}function Pt(e){console.error(b.red(`✗`),e)}function Ft(e){kt(b.yellow(`!`),e)}function R(e){kt(b.blue(`→`),e)}const It=new Set;function z(e){let t=ee({text:e,color:`cyan`,isSilent:Dt});return It.add(t),t}function Lt(){for(let e of It)e.isSpinning&&e.stop();It.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}:`)} ${At(r)}`)}function Rt(e){let t=`${e.cpuCores} vCPU / ${e.memoryMB} MB / ${e.diskGB} GB`;return e.pool?`${t} (pool: ${e.pool})`:t}function zt(e){if(console.log(),console.log(b.bold(`Sandbox Details`)),console.log(b.dim(`─`.repeat(40))),B({ID:e.id,Name:e.name,Status:Nt(e.status),Resources:e.resources?Rt(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 Bt(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 Vt=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`]),Ht=new Set([`GRAPH_INVALID`,`STEP_REF`,`PROFILE_INVALID`,`UNKNOWN_HARNESS`,`HUB_TOOL_UNKNOWN`,`TRIGGER_INVALID`,`WORKFLOW_INPUT_FILE_INVALID`,`VALIDATION_ERROR`]),Ut=new Set([`UNKNOWN_COMMAND`,`GRAPH_PARAM_MISSING`,`GRAPH_PARAM_UNKNOWN`,`SEAT_SYNTAX`,`HUB_PROVIDER_UNKNOWN`,`USAGE_INVALID`]),Wt=new Set([`SUBSCRIPTION_REQUIRED`,`MODEL_NOT_FOUND`,`MODEL_PROVIDER_MISMATCH`,`MCP_BLOCKED`,`CLOUD_SEAT_UNSUPPORTED`,`SCHEDULE_AUTHORITY`]);function Gt(e){return typeof e==`object`&&e?e:{}}function H(e){return typeof e==`string`&&e.length>0?e:void 0}function Kt(e){let t=H(e);return t&&/^[a-z0-9][a-z0-9_-]*$/i.test(t)?t:void 0}function qt(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(Gt(n).code);(e||r)&&(t=r?`${r}${e?`: ${e}`:``}`:e)}return t}function Jt(e){return e.code===`credential-refused`&&e.owner===`caller`&&e.providerCode===`subscription_required`?Gt(e.remediation):{}}function Yt(e){let t=Gt(e),n=Array.isArray(t.runtimeFailures)?t.runtimeFailures.map(Gt):[],c=n.find(e=>H(Jt(Gt(e.failure)).fix))??n[0],l=Gt(c?.failure??t.runtimeFailure),u=Jt(l),m=Gt(t.details),h=Kt(t.provider??m.provider??m.providerId),g=Gt(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=Kt(Gt(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=qt(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,Vt.has(_)&&b===`tangle --help`&&(b=`tangle auth login`);let x=Gt(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 Xt(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 Zt(e){return Xt(Yt(e))}function U(e,t=!1){Lt();let n=Yt(e);t?I({ok:!1,error:n}):console.error(b.red(Xt(n)));let r=1;Vt.has(n.code)?r=77:Ht.has(n.code)?r=65:Ut.has(n.code)?r=64:Wt.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 Qt(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=k(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 $t(e){let t=(e.skills??[]).map(Qt),n=(e.tools??[]).map(Qt),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 en(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 nn(`https://raw.githubusercontent.com/${i[0]}/${i[1]}/${a}/${i.slice(2).join(`/`)}`)}else t=/^https?:\/\//.test(e)?await nn(e):k(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 tn(n,e)}function tn(e,t){let n=ne.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 nn(e){let t=await fetch(e);if(!t.ok)throw Error(`failed to fetch ${e} (${t.status})`);return t.text()}async function rn(e){let t=e.profileSource?await en(e.profileSource):void 0,n=$t(e);return t?n?{...t,...n,...n.resources?{resources:{...t.resources,...n.resources}}:{}}:t:n}const an=A.join(be.homedir(),`.tangle`),on=A.join(an,`credentials.json`),sn=`tangle-sandbox-cli`,cn=new Int32Array(new SharedArrayBuffer(4)),ln=`TANGLE_ALLOW_PLAINTEXT_CREDENTIALS`;var un=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)}},dn=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 ${ln}=1 to opt into a plaintext credentials.json with mode 0600.`),this.name=`KeychainUnavailableError`}},fn=class extends Error{constructor(e){super(`Credential storage preflight failed: ${e}`),this.name=`CredentialStorageProbeError`}},pn=class extends Error{constructor(e){super(`Credential storage is busy. Wait a moment and retry.`),this.name=`CredentialsFileLockedError`,e&&(this.cause=e)}};function mn(e){let t=bn(e);if(t)return{value:t,source:`keychain`};let n=Cn(e);return n?{value:n,source:`file`}:{source:`none`}}function hn(e,t){if(xn(e,t))return Tn(e),`keychain`;if(!vn())throw new dn;return wn(e,t),`file`}function gn(){let e=`credential-write-probe:${process.pid}:${w()}`,t=w();if(xn(e,t)){let n=bn(e);if(!Sn(e))throw new fn(`the OS keychain accepted a test credential but the CLI could not remove it`);if(n!==t)throw new fn(`the OS keychain accepted a test credential but the CLI could not read it back`);return`keychain`}if(!vn())throw new dn;return kn(e),`file`}function _n(e){Sn(e),Tn(e)}function vn(){let e=process.env[ln];if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function yn(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 bn(e){let t=jn(e);return yn({darwin:[`find-generic-password`,`-s`,sn,`-a`,t,`-w`],linux:[`lookup`,`service`,sn,`account`,t]})}function xn(e,t){let n=jn(e),r=[`add-generic-password`,`-U`,`-s`,sn,`-a`],i=[`store`,`--label=Tangle Sandbox CLI`,`service`];return yn({darwin:[...r,n,`-w`,t],linux:[...i,sn,`account`,n]},process.platform===`linux`?t:void 0)!==void 0}function Sn(e){let t=jn(e);return yn({darwin:[`delete-generic-password`,`-s`,sn,`-a`,t],linux:[`clear`,`service`,sn,`account`,t]})!==void 0}function Cn(e){return Dn()[e]}function wn(e,t){En(()=>{let n=Dn();n[e]=t,On(n)})}function Tn(e){return En(()=>{let t;try{t=Dn()}catch(e){if(e instanceof un)return!1;throw e}return e in t?(delete t[e],On(t),Cn(e)===void 0):!0})}function En(e){An();let t=Date.now()+2e3,n,r;for(;!n;)try{n=Te(on,{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 pn(r);Atomics.wait(cn,0,0,20)}try{return e()}finally{n()}}function Dn(){let e;try{e=O.readFileSync(on,`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 un(on);let n={};for(let[e,r]of Object.entries(t))typeof r==`string`&&(n[e]=r);return n}catch(e){throw e instanceof un?e:new un(on,e instanceof Error?e:void 0)}}function On(e){if(An(),Object.keys(e).length===0){O.existsSync(on)&&O.unlinkSync(on);return}let t=`${on}.${process.pid}.tmp`;O.writeFileSync(t,`${JSON.stringify(e,null,2)}\n`,{mode:384}),O.renameSync(t,on)}function kn(e){let t=w(),n=!1,r;try{if(wn(e,t),n=!0,Cn(e)!==t)throw new fn(`the credentials file did not return the value just written`)}catch(e){r=e}finally{if(n)try{!Tn(e)&&!r&&(r=new fn(`the credentials file accepted a test credential but the CLI could not remove it`))}catch(e){r??=e}}if(r)throw r}function An(){if(!O.existsSync(an)){O.mkdirSync(an,{mode:448,recursive:!0});return}if(process.platform!==`win32`)try{(O.statSync(an).mode&511)!=448&&O.chmodSync(an,448)}catch{}}function jn(e){return`profile:${e}`}const Mn=A.join(be.homedir(),`.tangle`),Nn=A.join(Mn,`config.json`),Pn=`https://id.tangle.tools`,Fn=`https://solve.tangle.tools/api/solve`,In=`default`;function Ln(){return{tangleBaseUrl:process.env.TANGLE_BASE_URL,sandboxBaseUrl:process.env.SANDBOX_BASE_URL,hubUrl:process.env.TANGLE_HUB_URL}}function Rn(e,t){let n=Wn(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 In;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 zn(){O.existsSync(Mn)||O.mkdirSync(Mn,{mode:448,recursive:!0})}function Bn(e,t){zn();let n=`${e}.${process.pid}.tmp`;O.writeFileSync(n,t,{mode:384}),O.renameSync(n,e)}function Vn(e){return e.startsWith(`sk_`)||e.startsWith(`sk-tan-`)}function Hn(){try{if(O.existsSync(Nn))return JSON.parse(O.readFileSync(Nn,`utf-8`))}catch{}return{}}function Un(e){let t=_r(Hn(),e);Bn(Nn,`${JSON.stringify(t,null,2)}\n`)}function Wn(e){return vr(e||process.env.TANGLE_PROFILE||process.env.SANDBOX_PROFILE||Hn().activeProfile||In)}function Gn(e){Un({activeProfile:vr(e)})}function Kn(){return{token:process.env.TANGLE_LINE_TOKEN,baseUrl:process.env.TANGLE_HUB_URL}}function qn(){return process.env.TANGLE_SANDBOX||Hn().currentSandbox||void 0}function Jn(e){Un({currentSandbox:e})}function Yn(){let e=Hn();delete e.currentSandbox,Bn(Nn,`${JSON.stringify(e,null,2)}\n`)}function Xn(){let e=Hn().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 Un({deviceId:r}),r}function Zn(e){let t=e||qn();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 Qn(){let e=Hn(),t=Wn(),n=new Set([In,...Object.keys(e.profiles??{})]);return e.activeProfile&&n.add(vr(e.activeProfile)),[...n].map(e=>{let n=mn(e).source;return{name:e,active:e===t,hasApiKey:n!==`none`,baseUrl:sr(void 0,e),apiKeySource:n}}).sort((e,t)=>e.name.localeCompare(t.name))}function $n(e){let t=Wn(e);return{name:t,active:t===Wn(),baseUrl:sr(void 0,t),credentialSource:mn(t).source}}function er(e,t){let n=vr(e),r=Hn(),i=gr(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=hn(n,t.apiKey)),Un({profiles:Object.keys(l).length>0?l:{}}),u}function tr(e){let t=Wn(e),n={...Hn().profiles??{}},r=n[t];if(r){let e={...r};e.baseUrl||e.activeTeamId||e.activeTeamName?n[t]=e:delete n[t]}Un({profiles:n}),_n(t)}function nr(){let e=process.env.TANGLE_API_KEY_FILE;if(e){let t=O.readFileSync(e,`utf8`).trim();if(!t.startsWith(`sk-tan-`))throw Error(`Invalid sandbox credential file`);return t}return process.env.TANGLE_API_KEY}function rr(e,t){let n=Rn(`sandbox`,t);return e||nr()||mn(n).value}function ir(e,t){return e||(process.env.TANGLE_SOLVE_API_KEY?process.env.TANGLE_SOLVE_API_KEY:mn(Rn(`solve`,t)).value)}function ar(e,t){let n=Rn(`sandbox`,t);return e?`flag`:process.env.TANGLE_API_KEY_FILE||process.env.TANGLE_API_KEY?`env`:mn(n).source}function or(e,t){return e?`flag`:process.env.TANGLE_SOLVE_API_KEY?`env`:mn(Rn(`solve`,t)).source}function sr(e,t){if(e)return e;let n=process.env.TANGLE_BASE_URL||process.env.SANDBOX_BASE_URL;if(n)return n;let r=Wn(t),i=Hn(),a=gr(r,i);return a.baseUrl?a.baseUrl:(r===In||r===`sandbox`)&&i.baseUrl?i.baseUrl:`https://sandbox.tangle.tools`}function cr(e){if(e)return e.replace(/\/v1\/hub\/?$/,``)}function lr(e){return e?.trim().replace(/\/+$/,``)||void 0}function ur(e){return lr(e?.flag)??lr(cr(lr(process.env.TANGLE_HUB_URL)))??lr(process.env.TANGLE_PLATFORM_URL)??lr(e?.cachedPlatformUrl?.())??Pn}function dr(e){let t=lr(e)??lr(process.env.TANGLE_SOLVE_API_URL);if(t&&t!==Fn)throw Error(`Solve credentials may only be sent to ${Fn}`);return Fn}function fr(e){let t=lr(e);if(t&&t!==Pn)throw Error(`Solve credentials may only be sent to ${Pn}`);return Pn}function W(e){let t=Rn(`sandbox`,e.profile),n=rr(e.apiKey,t);if(!n)throw Error(`No API key found for profile '${t}'. Set TANGLE_API_KEY or run: tangle auth login${t===In?``:` --profile ${t}`}`);return{apiKey:n,baseUrl:sr(e.baseUrl,t),timeout:e.timeout??3e4,profile:t,...pr(t)}}function pr(e){let t=Hn(),n=gr(Wn(e),t);return{activeTeamId:n.activeTeamId,activeTeamName:n.activeTeamName}}function mr(e,t){er(Wn(t),{activeTeamId:e.id,activeTeamName:e.name})}function hr(e){let t=Wn(e),n=Hn(),r={...n.profiles??{}},i={baseUrl:gr(t,n).baseUrl};i.baseUrl?r[t]=i:delete r[t],Un({profiles:r})}function gr(e,t=Hn()){let n=vr(e);return{...n===In?{baseUrl:t.baseUrl,activeTeamId:t.profiles?.[In]?.activeTeamId,activeTeamName:t.profiles?.[In]?.activeTeamName}:{},...t.profiles?.[n]??{}}}function _r(e,t){let n=t.profiles===void 0?{...e.profiles??{}}:Object.fromEntries(Object.entries(t.profiles).filter(([,e])=>!!(e.apiKey||e.baseUrl||e.activeTeamId||e.activeTeamName)));return{...e,...t,profiles:Object.keys(n).length>0?n:void 0}}function vr(e){let t=e.trim().toLowerCase();if(!t)throw Error(`Profile name cannot be empty`);if(!/^[a-z0-9][a-z0-9._-]*$/.test(t))throw Error(`Profile names may only contain lowercase letters, numbers, dots, underscores, and hyphens`);return t}let yr=null,br=null;function G(e){if(!e&&yr)return yr;let t=e??W({});return(!yr||!br||br.apiKey!==t.apiKey||br.baseUrl!==t.baseUrl||br.timeout!==t.timeout)&&(yr=new l({apiKey:t.apiKey,baseUrl:t.baseUrl,timeoutMs:t.timeout}),br=t),yr}function xr(){yr=null,br=null}function K(e){let t=W({apiKey:e.apiKey,baseUrl:e.baseUrl});return{context:t,client:G(t)}}async function Sr(e,t){let n=t.trim();if(n.length===0)throw Error(`Connection reference is empty.`);if(n.startsWith(`hubconn_`))return n;let{connections:r}=await e.connections.list();return Cr(r,n)}function Cr(e,t){let n=t.trim();if(n.length===0)throw Error(`Connection reference is empty.`);let r=e.find(e=>e.id===n);if(r)return r.id;let i=n.indexOf(`:`),a=(i===-1?n:n.slice(0,i)).trim().toLowerCase(),o=i===-1?null:n.slice(i+1).trim(),s=e.filter(e=>e.status!==`revoked`&&e.providerId.toLowerCase()===a);if(o&&o.length>0){let e=o.toLowerCase();s=s.filter(t=>(t.accountDisplay??``).toLowerCase()===e||t.displayName.toLowerCase()===e)}if(s.length===1)return s[0].id;throw s.length===0?Error(`No hub connection matches "${t}". List your connections with \`tangle hub connections\`.`):Error(wr(t,s))}function wr(e,t){let n=t.map(e=>`- ${e.id} (provider: ${e.providerId}, account: ${e.accountDisplay??e.displayName})`).join(`
2
2
  `);return`Hub connection reference is ambiguous: "${e}" matches ${t.length} connections. Use a connection id or provider:account instead.
3
3
  `+n}function Tr(e,t){return[...t,e]}async function Er(e,t){let n=e.map(e=>{let t=e.trim(),n=t.indexOf(`:`);return n===-1?{raw:e,ref:null,tail:null}:{raw:e,ref:t.slice(0,n).trim(),tail:t.slice(n+1)}});if(!n.some(e=>e.ref!==null&&e.ref!==`*`&&!e.ref.startsWith(`hubconn_`)))return[...e];let{connections:r}=await(await t()).connections.list();return n.map(e=>e.ref===null||e.ref===`*`||e.ref.startsWith(`hubconn_`)?e.raw:`${Cr(r,e.ref)}:${e.tail}`)}function Dr(e){let t=new Map,n=[];for(let r of e){let e=r.trim(),i=e.indexOf(`:`);if(i===-1)throw Error(`Invalid --connection "${r}": expected <connectionId>:<capability>[,<capability>]. List connection ids with \`tangle hub connections\` and capability paths with \`tangle hub tools search <keyword>\`.`);let a=e.slice(0,i).trim();if(a.length===0)throw Error(`Invalid --connection "${r}": connection id is empty. Use <connectionId>:<capability> — list ids with \`tangle hub connections\`.`);let o=e.slice(i+1).split(`,`).map(e=>e.trim()).filter(e=>e.length>0);if(o.length===0)throw Error(`Invalid --connection "${r}": grant at least one capability, e.g. ${a}:gmail.messages.list. Discover paths with \`tangle hub tools search <keyword>\`.`);if(o.includes(`*`)&&o.length>1)throw Error(`Invalid --connection "${r}": "*" grants all capabilities and can't be combined with specific paths. Use <connectionId>:* alone, or list explicit paths.`);if(a===`*`&&!(o.length===1&&o[0]===`*`))throw Error(`Invalid --connection "${r}": a "*" connection is only valid as "*:*" (all connections, all capabilities). Name a connection id for specific paths.`);let s=t.get(a);s===void 0&&(s=new Set,t.set(a,s),n.push(a));for(let e of o)s.add(e)}return n.map(e=>{let n=t.get(e),r=n?[...n]:[];if(r.includes(`*`)&&r.length>1)throw Error(`Invalid --connection for "${e}": "*" can't be combined with specific capability paths across repeated --connection flags.`);return{connectionId:e,capabilities:r}})}function Or(e,t){return C(`sha256`).update(`${e}\0${t}`).digest(`hex`).slice(0,32)}function kr(e){return`${e}:hub`}function Ar(e){let{value:t}=mn(kr(e));if(!t)return null;try{let e=JSON.parse(t);if(typeof e.key==`string`&&typeof e.expiresAt==`string`&&typeof e.platformUrl==`string`&&typeof e.sessionFingerprint==`string`)return{key:e.key,expiresAt:e.expiresAt,platformUrl:e.platformUrl,sessionFingerprint:e.sessionFingerprint}}catch{}return null}function jr(e,t){try{hn(kr(e),JSON.stringify(t))}catch{}}async function Mr(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 Nr=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=Or(t,n);let a=Ar(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 Mr(this.sandboxBaseUrl,this.sessionToken,this.deviceId,this.signal),sessionFingerprint:this.fingerprint};return this.cache=t,jr(this.profile,t),t}};function Pr(e){if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function Fr(e,t){return ur({flag:e.baseUrl,...e.useCachedPlatformUrl?{cachedPlatformUrl:()=>Ar(t)?.platformUrl}:{}})}function Ir(e,t){let n=Rn(`sandbox`,e.profile),r=rr(e.apiKey,n),i=ar(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:Fr(e,n)}:{kind:`managed`,profile:n,sandboxBaseUrl:sr(e.sandboxBaseUrl,n),sessionToken:o,deviceId:Xn(),baseUrlOverride:e.baseUrl}}async function Lr(e={}){let t=Ir(e,e.hubKey===!1||Pr(process.env.TANGLE_SKIP_HUB_KEY));if(t.kind===`static`)return{token:t.apiKey,baseUrl:t.baseUrl,minted:!1};let n=new Nr(t.profile,t.sandboxBaseUrl,t.sessionToken,t.deviceId,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 Rr(e,t,n={}){let r=e=>{let r=new Headers(n.headers);return r.set(`Authorization`,`Bearer ${e}`),fetch(t,{...n,headers:r})},i=await r(e.token);return i.status!==401||!e.refresh?i:r(await e.refresh())}async function zr(e={}){let t;try{t=await Lr(e)}catch(e){return{reachable:!1,reason:e instanceof Error?e.message:String(e),refused:!0}}try{let e=await Rr(t,`${t.baseUrl.replace(/\/+$/,``)}/v1/plans/current`);if(e.ok)return{reachable:!0,baseUrl:t.baseUrl};let n=e.status===401||e.status===403;return{reachable:!1,baseUrl:t.baseUrl,reason:n?`the platform refused this credential (HTTP ${e.status})`:`the platform answered HTTP ${e.status}`,refused:n}}catch(e){return{reachable:!1,baseUrl:t.baseUrl,reason:`could not reach ${t.baseUrl}: ${e instanceof Error?e.message:String(e)}`,refused:!1}}}async function Br(e){let t=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=Ir(e,e.hubKey===!1||Pr(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?nr():r.apiKey}`})})}let i=new Nr(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 Vr(e={}){return Br(e)}function q(e={}){return Br({...e,useCachedPlatformUrl:!0,allowHubCapabilityToken:!0})}function Hr(e,t){return`Sandbox name is ambiguous: ${e}. Use a sandbox id instead.\n${t.map(e=>`- ${e.id} (status: ${e.status}, created: ${e.createdAt.toISOString()})`).join(`
4
- `)}`}function Ur(e){return e.activeTeamId?`team:${e.activeTeamId}`:void 0}async function J(e,t,n,r={}){if(!r.nameOnly){let t=await e.get(n);if(t)return t;if(Gr(n))throw Error(`Sandbox not found: ${n}`)}let i=(await e.list({scope:Ur(t)})).filter(e=>e.name?.toLowerCase()===n.toLowerCase());if(i.length===0)throw Error(`Sandbox not found: ${n}`);if(i.length>1)throw Error(Hr(n,i));return i[0]}const Wr=/^sandbox-(?:(?:(?:[a-z][a-z0-9-]*)-)?(?:[a-f0-9]{12}|[a-f0-9]{8}-[a-f0-9]{3})|l[0-9a-z]{1,8}-[0-9a-f]{8})(?:-branch-[a-z0-9]+-[0-9]+)*$/;function Gr(e){return Wr.test(e)}async function Kr(e,t,n,r={}){try{return(await(await 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&&!Gr(n))throw e}let i=await e.fetch(`/v1/sandboxes/${encodeURIComponent(n)}`,{method:`DELETE`});if(i.ok){let e=await i.json().catch(()=>({}));return e.outcome===`destroyed`||e.outcome===`already_absent`?e.outcome:`unknown`}let a=(await i.text()).trim();throw Error(`Sandbox cleanup failed for ${n} (HTTP ${i.status})${a?`: ${a}`:``}`)}async function 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 qr=[`anthropic`,`openai`,`vercel-ai`,`mastra`,`mcp-local`,`claude-desktop`,`cursor`,`zed`];function Jr(e,t,n){switch(e){case`anthropic`:return`// pnpm add @anthropic-ai/sdk @tangle-network/sandbox
4
+ `)}`}function Ur(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(Gr(n))throw Error(`Sandbox not found: ${n}`)}let i=(await e.list({scope:Ur(t)})).filter(e=>e.name?.toLowerCase()===n.toLowerCase());if(i.length===0)throw Error(`Sandbox not found: ${n}`);if(i.length>1)throw Error(Hr(n,i));return i[0]}const Wr=/^sandbox-(?:(?:(?:[a-z][a-z0-9-]*)-)?(?:[a-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 Gr(e){return Wr.test(e)}async function Kr(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&&!Gr(n))throw e}let i=await e.fetch(`/v1/sandboxes/${encodeURIComponent(n)}`,{method:`DELETE`});if(i.ok){let e=await i.json().catch(()=>({}));return e.outcome===`destroyed`||e.outcome===`already_absent`?e.outcome:`unknown`}let a=(await i.text()).trim();throw Error(`Sandbox cleanup failed for ${n} (HTTP ${i.status})${a?`: ${a}`:``}`)}async function 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 qr=[`anthropic`,`openai`,`vercel-ai`,`mastra`,`mcp-local`,`claude-desktop`,`cursor`,`zed`];function Jr(e,t,n){switch(e){case`anthropic`:return`// pnpm add @anthropic-ai/sdk @tangle-network/sandbox
5
5
  import Anthropic from "@anthropic-ai/sdk";
6
6
  import { Sandbox } from "@tangle-network/sandbox";
7
7
  import { anthropicTools } from "@tangle-network/sandbox/agent";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-cli",
3
- "version": "0.22.27",
3
+ "version": "0.22.29",
4
4
  "description": "CLI for Tangle Sandbox operations",
5
5
  "type": "module",
6
6
  "engines": {
@@ -25,7 +25,7 @@
25
25
  "@tangle-network/agent-runtime": "^9.0.0",
26
26
  "@tangle-network/harness-sessions": "^1.0.2",
27
27
  "@tangle-network/hub-sdk": "1.0.21",
28
- "@tangle-network/sandbox": "^1.0.297",
28
+ "@tangle-network/sandbox": "^1.0.298",
29
29
  "@tangle-network/sdk-cli-runner": "^0.3.10",
30
30
  "chalk": "^5.6.2",
31
31
  "cli-bridge": "https://github.com/drewstone/cli-bridge/archive/5798fd5297b8705f367f95ab966df7d8e2f875d2.tar.gz",
@@ -78,8 +78,8 @@
78
78
  "author": "Tangle Network",
79
79
  "license": "MIT",
80
80
  "tangleRelease": {
81
- "sourceSha": "9ff0d22e59a8fb189851e1afca4014e3d59adf29",
82
- "mergedAt": "2026-11-07T23:23:48-08:00"
81
+ "sourceSha": "394b827894c712ebe845d13970bd754729cdd9d8",
82
+ "mergedAt": "2026-11-08T00:17:41-08:00"
83
83
  },
84
84
  "scripts": {
85
85
  "build": "tsdown",