@tangle-network/sandbox-cli 0.22.31 → 0.22.33

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 +33 -33
  2. package/package.json +8 -6
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
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(`
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 ne,agentInteractiveSessionRunRef as E,agentProfileSchema as D,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{createCliBridgeProvider as Ze}from"@tangle-network/agent-provider-cli-bridge";import{gunzipSync as Qe}from"node:zlib";import{SearchEnvironmentFault as $e}from"@tangle-network/agent-runtime";import{fileURLToPath as et,pathToFileURL as tt}from"node:url";import{parseDocument as nt}from"yaml";import{createMcpServer as rt}from"@tangle-network/sandbox/agent";import{ensureAgentPreview as it,publishAgentPreview as at,resolveSelfSandbox as ot}from"@tangle-network/sandbox/preview";import{generatePrivateKey as st,privateKeyToAccount as ct}from"viem/accounts";import{createPublicClient as lt,createWalletClient as ut,decodeAbiParameters as dt,decodeEventLog as ft,encodeAbiParameters as pt,getAddress as mt,http as ht,isAddress as gt,keccak256 as _t,parseAbi as vt,parseAbiItem as yt,parseAbiParameters as bt,stringToHex as xt,toHex as St}from"viem";import{tempoModerato as Ct}from"viem/chains";import{Actions as wt,withRelay as Tt}from"viem/tempo";import Et from"ws";import{createIntelligenceClient as Dt}from"@tangle-network/sandbox/intelligence";let Ot=!1;function kt(e){Ot=e}function At(...e){Ot?console.error(...e):console.log(...e)}function jt(e){return e==null?b.dim(`-`):typeof e==`boolean`?e?b.green(`yes`):b.red(`no`):e instanceof Date?Nt(e):typeof e==`string`&&Mt(e)?Nt(new Date(e)):String(e)}function Mt(e){return/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)}function Nt(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 Pt(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=>jt(e[t.key]).length));return t.width??Math.max(n,r)+2}),r=e.map(e=>t.map(t=>t.key===`status`?Pt(String(e[t.key])):jt(e[t.key])));Vt(t.map(e=>e.header),r,n)}function I(e){console.log(JSON.stringify(e,null,2))}function L(e){At(b.green(`✓`),e)}function Ft(e){console.error(b.red(`✗`),e)}function It(e){At(b.yellow(`!`),e)}function R(e){At(b.blue(`→`),e)}const Lt=new Set;function z(e){let t=ee({text:e,color:`cyan`,isSilent:Ot});return Lt.add(t),t}function Rt(){for(let e of Lt)e.isSpinning&&e.stop();Lt.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}:`)} ${jt(r)}`)}function zt(e){let t=`${e.cpuCores} vCPU / ${e.memoryMB} MB / ${e.diskGB} GB`;return e.pool?`${t} (pool: ${e.pool})`:t}function Bt(e){if(console.log(),console.log(b.bold(`Sandbox Details`)),console.log(b.dim(`─`.repeat(40))),B({ID:e.id,Name:e.name,Status:Pt(e.status),Resources:e.resources?zt(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 Vt(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 Ht=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`]),Ut=new Set([`GRAPH_INVALID`,`STEP_REF`,`PROFILE_INVALID`,`UNKNOWN_HARNESS`,`HUB_TOOL_UNKNOWN`,`TRIGGER_INVALID`,`WORKFLOW_INPUT_FILE_INVALID`,`VALIDATION_ERROR`]),Wt=new Set([`UNKNOWN_COMMAND`,`GRAPH_PARAM_MISSING`,`GRAPH_PARAM_UNKNOWN`,`SEAT_SYNTAX`,`HUB_PROVIDER_UNKNOWN`,`USAGE_INVALID`]),Gt=new Set([`SUBSCRIPTION_REQUIRED`,`MODEL_NOT_FOUND`,`MODEL_PROVIDER_MISMATCH`,`MCP_BLOCKED`,`CLOUD_SEAT_UNSUPPORTED`,`SCHEDULE_AUTHORITY`]);function Kt(e){return typeof e==`object`&&e?e:{}}function H(e){return typeof e==`string`&&e.length>0?e:void 0}function qt(e){let t=H(e);return t&&/^[a-z0-9][a-z0-9_-]*$/i.test(t)?t:void 0}function Jt(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(Kt(n).code);(e||r)&&(t=r?`${r}${e?`: ${e}`:``}`:e)}return t}function Yt(e){return e.code===`credential-refused`&&e.owner===`caller`&&e.providerCode===`subscription_required`?Kt(e.remediation):{}}function Xt(e){let t=Kt(e),n=Array.isArray(t.runtimeFailures)?t.runtimeFailures.map(Kt):[],c=n.find(e=>H(Yt(Kt(e.failure)).fix))??n[0],l=Kt(c?.failure??t.runtimeFailure),u=Yt(l),m=Kt(t.details),h=qt(t.provider??m.provider??m.providerId),g=Kt(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=qt(Kt(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=Jt(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,Ht.has(_)&&b===`tangle --help`&&(b=`tangle auth login`);let x=Kt(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 Zt(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 Qt(e){return Zt(Xt(e))}function U(e,t=!1){Rt();let n=Xt(e);t?I({ok:!1,error:n}):console.error(b.red(Zt(n)));let r=1;Ht.has(n.code)?r=77:Ut.has(n.code)?r=65:Wt.has(n.code)?r=64:Gt.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 $t(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 en(e){let t=(e.skills??[]).map($t),n=(e.tools??[]).map($t),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 tn(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 rn(`https://raw.githubusercontent.com/${i[0]}/${i[1]}/${a}/${i.slice(2).join(`/`)}`)}else t=/^https?:\/\//.test(e)?await rn(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 nn(n,e)}function nn(e,t){let n=D.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 rn(e){let t=await fetch(e);if(!t.ok)throw Error(`failed to fetch ${e} (${t.status})`);return t.text()}async function an(e){let t=e.profileSource?await tn(e.profileSource):void 0,n=en(e);return t?n?{...t,...n,...n.resources?{resources:{...t.resources,...n.resources}}:{}}:t:n}const on=A.join(be.homedir(),`.tangle`),sn=A.join(on,`credentials.json`),cn=`tangle-sandbox-cli`,ln=new Int32Array(new SharedArrayBuffer(4)),un=`TANGLE_ALLOW_PLAINTEXT_CREDENTIALS`;var dn=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)}},fn=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 ${un}=1 to opt into a plaintext credentials.json with mode 0600.`),this.name=`KeychainUnavailableError`}},pn=class extends Error{constructor(e){super(`Credential storage preflight failed: ${e}`),this.name=`CredentialStorageProbeError`}},mn=class extends Error{constructor(e){super(`Credential storage is busy. Wait a moment and retry.`),this.name=`CredentialsFileLockedError`,e&&(this.cause=e)}};function hn(e){let t=xn(e);if(t)return{value:t,source:`keychain`};let n=wn(e);return n?{value:n,source:`file`}:{source:`none`}}function gn(e,t){if(Sn(e,t))return En(e),`keychain`;if(!yn())throw new fn;return Tn(e,t),`file`}function _n(){let e=`credential-write-probe:${process.pid}:${w()}`,t=w();if(Sn(e,t)){let n=xn(e);if(!Cn(e))throw new pn(`the OS keychain accepted a test credential but the CLI could not remove it`);if(n!==t)throw new pn(`the OS keychain accepted a test credential but the CLI could not read it back`);return`keychain`}if(!yn())throw new fn;return An(e),`file`}function vn(e){Cn(e),En(e)}function yn(){let e=process.env[un];if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function bn(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 xn(e){let t=Mn(e);return bn({darwin:[`find-generic-password`,`-s`,cn,`-a`,t,`-w`],linux:[`lookup`,`service`,cn,`account`,t]})}function Sn(e,t){let n=Mn(e),r=[`add-generic-password`,`-U`,`-s`,cn,`-a`],i=[`store`,`--label=Tangle Sandbox CLI`,`service`];return bn({darwin:[...r,n,`-w`,t],linux:[...i,cn,`account`,n]},process.platform===`linux`?t:void 0)!==void 0}function Cn(e){let t=Mn(e);return bn({darwin:[`delete-generic-password`,`-s`,cn,`-a`,t],linux:[`clear`,`service`,cn,`account`,t]})!==void 0}function wn(e){return On()[e]}function Tn(e,t){Dn(()=>{let n=On();n[e]=t,kn(n)})}function En(e){return Dn(()=>{let t;try{t=On()}catch(e){if(e instanceof dn)return!1;throw e}return e in t?(delete t[e],kn(t),wn(e)===void 0):!0})}function Dn(e){jn();let t=Date.now()+2e3,n,r;for(;!n;)try{n=Te(sn,{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 mn(r);Atomics.wait(ln,0,0,20)}try{return e()}finally{n()}}function On(){let e;try{e=O.readFileSync(sn,`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 dn(sn);let n={};for(let[e,r]of Object.entries(t))typeof r==`string`&&(n[e]=r);return n}catch(e){throw e instanceof dn?e:new dn(sn,e instanceof Error?e:void 0)}}function kn(e){if(jn(),Object.keys(e).length===0){O.existsSync(sn)&&O.unlinkSync(sn);return}let t=`${sn}.${process.pid}.tmp`;O.writeFileSync(t,`${JSON.stringify(e,null,2)}\n`,{mode:384}),O.renameSync(t,sn)}function An(e){let t=w(),n=!1,r;try{if(Tn(e,t),n=!0,wn(e)!==t)throw new pn(`the credentials file did not return the value just written`)}catch(e){r=e}finally{if(n)try{!En(e)&&!r&&(r=new pn(`the credentials file accepted a test credential but the CLI could not remove it`))}catch(e){r??=e}}if(r)throw r}function jn(){if(!O.existsSync(on)){O.mkdirSync(on,{mode:448,recursive:!0});return}if(process.platform!==`win32`)try{(O.statSync(on).mode&511)!=448&&O.chmodSync(on,448)}catch{}}function Mn(e){return`profile:${e}`}const Nn=A.join(be.homedir(),`.tangle`),Pn=A.join(Nn,`config.json`),Fn=`https://id.tangle.tools`,In=`https://solve.tangle.tools/api/solve`,Ln=`default`;function Rn(){return{tangleBaseUrl:process.env.TANGLE_BASE_URL,sandboxBaseUrl:process.env.SANDBOX_BASE_URL,hubUrl:process.env.TANGLE_HUB_URL}}function zn(e,t){let n=Gn(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 Ln;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 Bn(){O.existsSync(Nn)||O.mkdirSync(Nn,{mode:448,recursive:!0})}function Vn(e,t){Bn();let n=`${e}.${process.pid}.tmp`;O.writeFileSync(n,t,{mode:384}),O.renameSync(n,e)}function Hn(e){return e.startsWith(`sk_`)||e.startsWith(`sk-tan-`)}function Un(){try{if(O.existsSync(Pn))return JSON.parse(O.readFileSync(Pn,`utf-8`))}catch{}return{}}function Wn(e){let t=vr(Un(),e);Vn(Pn,`${JSON.stringify(t,null,2)}\n`)}function Gn(e){return yr(e||process.env.TANGLE_PROFILE||process.env.SANDBOX_PROFILE||Un().activeProfile||Ln)}function Kn(e){Wn({activeProfile:yr(e)})}function qn(){return{token:process.env.TANGLE_LINE_TOKEN,baseUrl:process.env.TANGLE_HUB_URL}}function Jn(){return process.env.TANGLE_SANDBOX||Un().currentSandbox||void 0}function Yn(e){Wn({currentSandbox:e})}function Xn(){let e=Un();delete e.currentSandbox,Vn(Pn,`${JSON.stringify(e,null,2)}\n`)}function Zn(){let e=Un().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 Wn({deviceId:r}),r}function Qn(e){let t=e||Jn();if(!t)throw Error("No sandbox specified. Pass it positionally, set a default with `tangle use <id>`, pass `--box <id>`, or set TANGLE_SANDBOX.");return t}function $n(){let e=Un(),t=Gn(),n=new Set([Ln,...Object.keys(e.profiles??{})]);return e.activeProfile&&n.add(yr(e.activeProfile)),[...n].map(e=>{let n=hn(e).source;return{name:e,active:e===t,hasApiKey:n!==`none`,baseUrl:cr(void 0,e),apiKeySource:n}}).sort((e,t)=>e.name.localeCompare(t.name))}function er(e){let t=Gn(e);return{name:t,active:t===Gn(),baseUrl:cr(void 0,t),credentialSource:hn(t).source}}function tr(e,t){let n=yr(e),r=Un(),i=_r(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=gn(n,t.apiKey)),Wn({profiles:Object.keys(l).length>0?l:{}}),u}function nr(e){let t=Gn(e),n={...Un().profiles??{}},r=n[t];if(r){let e={...r};e.baseUrl||e.activeTeamId||e.activeTeamName?n[t]=e:delete n[t]}Wn({profiles:n}),vn(t)}function rr(){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 ir(e,t){let n=zn(`sandbox`,t);return e||rr()||hn(n).value}function ar(e,t){return e||(process.env.TANGLE_SOLVE_API_KEY?process.env.TANGLE_SOLVE_API_KEY:hn(zn(`solve`,t)).value)}function or(e,t){let n=zn(`sandbox`,t);return e?`flag`:process.env.TANGLE_API_KEY_FILE||process.env.TANGLE_API_KEY?`env`:hn(n).source}function sr(e,t){return e?`flag`:process.env.TANGLE_SOLVE_API_KEY?`env`:hn(zn(`solve`,t)).source}function cr(e,t){if(e)return e;let n=process.env.TANGLE_BASE_URL||process.env.SANDBOX_BASE_URL;if(n)return n;let r=Gn(t),i=Un(),a=_r(r,i);return a.baseUrl?a.baseUrl:(r===Ln||r===`sandbox`)&&i.baseUrl?i.baseUrl:`https://sandbox.tangle.tools`}function lr(e){if(e)return e.replace(/\/v1\/hub\/?$/,``)}function ur(e){return e?.trim().replace(/\/+$/,``)||void 0}function dr(e){return ur(e?.flag)??ur(lr(ur(process.env.TANGLE_HUB_URL)))??ur(process.env.TANGLE_PLATFORM_URL)??ur(e?.cachedPlatformUrl?.())??Fn}function fr(e){let t=ur(e)??ur(process.env.TANGLE_SOLVE_API_URL);if(t&&t!==In)throw Error(`Solve credentials may only be sent to ${In}`);return In}function pr(e){let t=ur(e);if(t&&t!==Fn)throw Error(`Solve credentials may only be sent to ${Fn}`);return Fn}function W(e){let t=zn(`sandbox`,e.profile),n=ir(e.apiKey,t);if(!n)throw Error(`No API key found for profile '${t}'. Set TANGLE_API_KEY or run: tangle auth login${t===Ln?``:` --profile ${t}`}`);return{apiKey:n,baseUrl:cr(e.baseUrl,t),timeout:e.timeout??3e4,profile:t,...mr(t)}}function mr(e){let t=Un(),n=_r(Gn(e),t);return{activeTeamId:n.activeTeamId,activeTeamName:n.activeTeamName}}function hr(e,t){tr(Gn(t),{activeTeamId:e.id,activeTeamName:e.name})}function gr(e){let t=Gn(e),n=Un(),r={...n.profiles??{}},i={baseUrl:_r(t,n).baseUrl};i.baseUrl?r[t]=i:delete r[t],Wn({profiles:r})}function _r(e,t=Un()){let n=yr(e);return{...n===Ln?{baseUrl:t.baseUrl,activeTeamId:t.profiles?.[Ln]?.activeTeamId,activeTeamName:t.profiles?.[Ln]?.activeTeamName}:{},...t.profiles?.[n]??{}}}function vr(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 yr(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 br=null,xr=null;function G(e){if(!e&&br)return br;let t=e??W({});return(!br||!xr||xr.apiKey!==t.apiKey||xr.baseUrl!==t.baseUrl||xr.timeout!==t.timeout)&&(br=new l({apiKey:t.apiKey,baseUrl:t.baseUrl,timeoutMs:t.timeout}),xr=t),br}function Sr(){br=null,xr=null}function K(e){let t=W({apiKey:e.apiKey,baseUrl:e.baseUrl});return{context:t,client:G(t)}}async function Cr(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 wr(r,n)}function wr(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(Tr(t,s))}function Tr(e,t){let n=t.map(e=>`- ${e.id} (provider: ${e.providerId}, account: ${e.accountDisplay??e.displayName})`).join(`
2
2
  `);return`Hub connection reference is ambiguous: "${e}" matches ${t.length} connections. Use a connection id or provider:account instead.
3
- `+n}function 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-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
3
+ `+n}function Er(e,t){return[...t,e]}async function Dr(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:`${wr(r,e.ref)}:${e.tail}`)}function Or(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 kr(e,t){return C(`sha256`).update(`${e}\0${t}`).digest(`hex`).slice(0,32)}function Ar(e){return`${e}:hub`}function jr(e){let{value:t}=hn(Ar(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 Mr(e,t){try{gn(Ar(e),JSON.stringify(t))}catch{}}async function Nr(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 Pr=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=kr(t,n);let a=jr(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 Nr(this.sandboxBaseUrl,this.sessionToken,this.deviceId,this.signal),sessionFingerprint:this.fingerprint};return this.cache=t,Mr(this.profile,t),t}};function Fr(e){if(!e)return!1;let t=e.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}function Ir(e,t){return dr({flag:e.baseUrl,...e.useCachedPlatformUrl?{cachedPlatformUrl:()=>jr(t)?.platformUrl}:{}})}function Lr(e,t){let n=zn(`sandbox`,e.profile),r=ir(e.apiKey,n),i=or(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:Ir(e,n)}:{kind:`managed`,profile:n,sandboxBaseUrl:cr(e.sandboxBaseUrl,n),sessionToken:o,deviceId:Zn(),baseUrlOverride:e.baseUrl}}async function Rr(e={}){let t=Lr(e,e.hubKey===!1||Fr(process.env.TANGLE_SKIP_HUB_KEY));if(t.kind===`static`)return{token:t.apiKey,baseUrl:t.baseUrl,minted:!1};let n=new Pr(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 zr(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 Br(e={}){let t;try{t=await Rr(e)}catch(e){return{reachable:!1,reason:e instanceof Error?e.message:String(e),refused:!0}}try{let e=await zr(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 Vr(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=Lr(e,e.hubKey===!1||Fr(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?rr():r.apiKey}`})})}let i=new Pr(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 Hr(e={}){return Vr(e)}function q(e={}){return Vr({...e,useCachedPlatformUrl:!0,allowHubCapabilityToken:!0})}function Ur(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 Wr(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(Kr(n))throw Error(`Sandbox not found: ${n}`)}let i=(await e.list({scope:Wr(t)})).filter(e=>e.name?.toLowerCase()===n.toLowerCase());if(i.length===0)throw Error(`Sandbox not found: ${n}`);if(i.length>1)throw Error(Ur(n,i));return i[0]}const Gr=/^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 Kr(e){return Gr.test(e)}async function qr(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&&!Kr(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 Jr=[`anthropic`,`openai`,`vercel-ai`,`mastra`,`mcp-local`,`claude-desktop`,`cursor`,`zed`];function Yr(e,t,n){switch(e){case`anthropic`:return`// pnpm add @anthropic-ai/sdk @tangle-network/sandbox
5
5
  import Anthropic from "@anthropic-ai/sdk";
6
6
  import { Sandbox } from "@tangle-network/sandbox";
7
7
  import { anthropicTools } from "@tangle-network/sandbox/agent";
@@ -121,37 +121,37 @@ await connect(new StdioServerTransport());`;case`claude-desktop`:return`// Add t
121
121
  }
122
122
  }
123
123
  }
124
- }`}}function Yr(e){return{anthropic:`Anthropic Messages API (Claude)`,openai:`OpenAI Chat Completions (function calling)`,"vercel-ai":`Vercel AI SDK (generateText / streamText)`,mastra:`Mastra agent framework`,"mcp-local":`Local MCP server bridge (stdio)`,"claude-desktop":`Claude Desktop config (uses local MCP)`,cursor:`Cursor config (uses local MCP)`,zed:`Zed config (uses local MCP)`}[e]}function Xr(){return new x(`connect`).description(`Print a copy-paste SDK integration snippet for one of: ${qr.join(`, `)} (to stream a local agent's telemetry to Intelligence, see 'tangle connect')`).argument(`<framework>`,qr.join(` | `)).option(`-i, --sandbox <id>`,`Sandbox ID to embed in the snippet`,`<SANDBOX_ID>`).option(`-s, --session <id>`,`Session ID to embed in the snippet`,`default`).action((e,t)=>{qr.includes(e)||(console.error(b.red(`unknown framework: ${e}`),`\nsupported: ${qr.join(`, `)}`),process.exit(2));let n=e;process.stdout.write(b.cyan(`# ${Yr(n)}\n\n`)),process.stdout.write(`${Jr(n,t.sandbox,t.session)}\n`)})}async function Zr(e,t=!1,n){n?.throwIfAborted();let r=t?new Oe({write(e,t,n){n()}}):process.stderr,i=De({input:process.stdin,signal:n,output:r,...t?{terminal:!0}:{}});n&&i.once(`SIGINT`,()=>{process.emit(`SIGINT`),i.close()}),t&&process.stderr.write(e);try{return await new Promise(n=>{i.once(`close`,()=>n(void 0)),i.question(t?``:e,e=>{n(e.trim()),i.close()})})}finally{i.close(),t&&process.stderr.write(`
125
- `)}}async function Qr(e){let t=await Zr(e,!0);if(t===void 0)throw Error(`No answer on stdin.`);return t}async function $r(e,t){let n=await Zr(e);if(n===void 0)throw process.stderr.write(`
126
- `),Error(t?`No answer on stdin. Pass ${t} to skip the confirmation.`:`No answer on stdin.`);return[`y`,`yes`].includes(n.toLowerCase())}async function ei(e,t,n){let r=await Zr(`${e}${t?` [${t}]`:``}: `,!1,n);if(r===void 0)throw Error(`No answer on stdin.`);return r||t||``}async function ti(e,t=`secret`){if(process.stdin.isTTY)throw Error(e?`${e} reads ${t} from stdin, but stdin is a terminal; pipe it in`:`Cannot read ${t} from stdin when stdin is a TTY`);return(await ke(process.stdin)).toString(`utf8`).replace(/\r?\n$/,``)}function ni(){let e=new x(`profile`).description(`Create, inspect, and validate portable agent profiles`);return e.command(`create [output]`).description(`Create a profile — interactively (a wizard), or fully via flags`).option(`--name <name>`,`Profile name (when set, skips the wizard)`).option(`--description <text>`,`Profile description`).option(`--model <model>`,`Model (provider/model)`).option(`--system-prompt <text>`,`System prompt`).option(`--skills <ref...>`,`Skill refs: local path or github:<owner>/<repo>/<path>[@<ref>]`).option(`--tools <ref...>`,`Tool refs: local path or github:<owner>/<repo>/<path>[@<ref>]`).option(`--harness <name>`,`Harness hint shown in the run command`).action(async(e,t)=>{let n=t.name,r=t.description,i=t.harness,a=t.model,o=t.systemPrompt,s=t.skills??[],c=t.tools??[];if(!n&&process.stdin.isTTY&&(n=await ei(`Profile name`,`my-agent`),r=await ei(`Description (optional)`)||void 0,i=await ei(`Harness`,`claude-code`)||void 0,a=await ei(`Model (optional, provider/model)`)||void 0,o=await ei(`System prompt (optional)`)||void 0,s=await ri(`Skill ref (local path or github:..., blank to finish)`),c=await ri(`Tool ref (blank to finish)`)),!n)throw Error(process.stdin.isTTY?`Profile name is required.`:"`agent profile create` needs at least --name in a non-interactive shell (no TTY to prompt). Pass --name <name> (and optionally --model/--skills/--tools/--system-prompt).");let l=$t({model:a,systemPrompt:o,skills:s,tools:c}),u=tn({...n?{name:n}:{},...r?{description:r}:{},...l??{},...i?{harness:i}:{}},`new profile`);if(t.json){I(u);return}let d=e??`agent-profile.json`;fe(d,`${JSON.stringify(u,null,2)}\n`),R(`Wrote ${d}`),R(`Run it: tangle agent prompt <box> --profile ${d}${i?` --harness ${i}`:``}`)}),e.command(`show <source>`).description(`Load and print a profile (local path, https URL, or github:owner/repo/path[@ref])`).action(async e=>{try{I(await en(e))}catch(e){U(e,!0)}}),e.command(`validate <source>`).description(`Validate a profile against the canonical AgentProfile schema`).action(async(e,t)=>{let n=await en(e),r=typeof n.name==`string`?n.name:`(unnamed)`;t.json?I({ok:!0,name:r}):R(`Profile valid: "${r}"`)}),e}async function ri(e){let t=[];for(;;){let n=await ei(e);if(!n)break;t.push(n)}return t}function ii(e){return(process.env.TANGLE_SANDBOX_WEB_URL?.trim()||e).replace(/\/+$/,``)}function ai(e,t){if(process.exitCode=1,e.status===`blocked_on_approval`){console.error(b.yellow(`⚠ Blocked on a hub approval.`));let t=e.approval?.approvalId;console.error(t?`Approve it: tangle hub approvals approve ${t}`:"Approve the pending request (`tangle hub approvals`), then re-run.");return}if(e.status===`awaiting_question`){console.error(b.yellow(`⚠ Agent is awaiting an answer to a question.`)),console.error(`Re-run with --interactive to answer it, or answer programmatically via box.session(<id>).answer(<questionId>, { ... }).`);return}if(e.status===`awaiting_interaction`){console.error(b.yellow(`⚠ Agent is awaiting a response.`)),console.error(`Open an interactive session, or answer the canonical interaction through the Sandbox SDK.`);return}if(e.status===`awaiting_plan_decision`){console.error(b.yellow(`⚠ Agent is awaiting a plan decision.`)),console.error(`Approve or reject the pending plan before continuing.`);return}console.error(b.red(`✗ ${e.error&&e.error.length>0?e.error:t}`))}function oi(e){let t=e.part;if(t?.type===`text`)return t.text??t.content??void 0}function si(e){return e.finalText??e.response??e.output??e.content??e.text??void 0}function ci(e){if(!e.result.success){ai(e.result,`Agent run failed`);return}let t=Date.now()-e.startedAt,n=e.tokenUsage,r=[`${t}ms`,n?.inputTokens===void 0?void 0:`${n.inputTokens} in`,n?.outputTokens===void 0?void 0:`${n.outputTokens} out`].filter(e=>!!e);console.log(b.green(`✓ Done`),b.dim(`(${r.join(`, `)})`))}async function li(e,t,n=!0){let r=``,i,a=m(),o=e=>{if(e.startsWith(r)){let t=e.slice(r.length);t&&n&&process.stdout.write(t)}else n&&process.stdout.write(e);r=e};try{for await(let t of e)switch(a.observe(t),t.type){case`token`:{let e=t.data?.value;typeof e==`string`&&(n&&process.stdout.write(e),r+=e);break}case`message.part.updated`:{let e=oi(t.data);typeof e==`string`&&e.length>0&&o(e);break}case`raw`:break;case`result`:i=t.data;break}}catch(e){a.observe({type:`error`,data:{message:e instanceof Error?e.message:String(e)}})}if(r.length===0&&i){let e=si(i);typeof e==`string`&&e.length>0&&(n&&process.stdout.write(e),r=e)}return{outcome:{result:a.finish(),startedAt:t,tokenUsage:i?.tokenUsage},resultData:i,printed:r.length,...r.length>0?{response:r}:{}}}function ui(e){let t=Dr(e??[]);if(t.length!==0)return{profile:{connections:t}}}function di(e,t,n,r,i,a){let o={...r??{},harness:n,...i?{model:{...r?.model??{},default:i}}:{}},s={profile:o,requestedProfileDigest:re(o),initialPrompt:a};return{...s,run:D({provider:`tangle-sandbox`,environmentId:e,sessionId:t,executionId:`interactive-execution-${t}`},s)}}async function fi(e){let t=Dr(e.connection??[]);if(t.length===0)throw Error(`--allow-writes needs at least one --connection to grant writes for.`);if(t.some(e=>e.connectionId===`*`))throw Error("--allow-writes needs explicit --connection ids; the `*:*` wildcard can't be bulk-granted. Grant per connection, e.g. --connection conn_x:* --allow-writes.");let n=await q({hubKey:e.hubKey});for(let r of t){let t=await n.permissions.allowWrites(r.connectionId);e.json||R(`Allowed ${t.writeActions} write action${t.writeActions===1?``:`s`} for connection ${r.connectionId} (${t.granted} newly granted).`)}e.json||R(`Revert anytime: ${t.map(e=>`tangle hub permissions revert-writes --connection ${e.connectionId}`).join(` · `)}`)}async function pi(e){!e.connection||e.connection.length===0||(e.connection=await Er(e.connection,()=>q({hubKey:e.hubKey})))}async function mi(e,t){let n=process.stdin,r=process.stdout,i=null,a=!1,o=!1,s,c=new Promise(e=>{s=e}),l=()=>{try{n.setRawMode(!1)}catch{}n.pause()},u=()=>{a||(a=!0,l(),n.off(`data`,p),process.off(`SIGWINCH`,f),process.off(`SIGINT`,d),process.off(`SIGTERM`,d),process.off(`exit`,l),s())},d=e=>{(i?.close()??Promise.resolve()).finally(()=>{u(),process.exit(e===`SIGTERM`?143:130)})},f=()=>{i?.isOpen&&i.resize(r.columns||80,r.rows||24)},p=e=>{if(!i)return;let t=e.indexOf(29);if(t===-1){i.write(e);return}t>0&&i.write(e.subarray(0,t)),i.close().finally(u)};if(i=await e.attach({cols:r.columns||80,rows:r.rows||24,handlers:{onData:e=>{r.write(Buffer.from(e.buffer,e.byteOffset,e.byteLength))},onExit:e=>{o=!0;let t=e.exitCode===void 0?``:` (code ${e.exitCode})`;r.write(`\r\n[interactive session exited${t}]\r\n`),i?.close().finally(u)},onError:e=>{r.write(`\r\n[terminal stream error: ${e.message}]\r\n`)},onClose:()=>u()}}),n.setRawMode(!0),n.resume(),n.on(`data`,p),process.on(`SIGWINCH`,f),process.on(`SIGINT`,d),process.on(`SIGTERM`,d),process.on(`exit`,l),await c,console.log(),o){R(`Interactive session ended.`);return}R(`Detached — the session keeps running.`),B({"Watch & drive":t})}function hi(){let e=new x(`agent`).description(`Interact with AI agent`);return e.command(`prompt <idOrMessage> [message]`).description("Send a single prompt to the agent. With one arg it's the prompt and the box comes from `tangle use` / --box / TANGLE_SANDBOX; with two it's <id> <message>.").option(`--box <id>`,`Target sandbox (overrides the active one)`).option(`--session <id>`,`Continue existing session`).option(`--model <model>`,`Model to use`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`,`300000`).option(`--stream`,`Stream response in real-time`).option(`--interactive`,`Spawn the harness's interactive TUI in the sandbox, inject this prompt, and print a link to watch + drive the live session in the browser (omit for the default headless run)`).option(`--harness <name>`,`Harness that executes this run (claude-code, codex, kimi-code, opencode, pi, amp, hermes). Defaults to the sandbox's configured backend. The box ships all harnesses, so this is a per-run choice.`).option(`--profile <source>`,`Agent profile to run: a local JSON path, an https URL, or github:<owner>/<repo>/<path>[@<ref>]`).option(`--skills <ref...>`,`Attach skills (repeatable): a local file path, or github:<owner>/<repo>/<path>[@<ref>] to pull from a repo`).option(`--tools <ref...>`,`Attach tools (repeatable): a local file path, or github:<owner>/<repo>/<path>[@<ref>]`).option(`--system-prompt <text>`,`Override the agent's system prompt for this run`).option(`--connection <spec>`,"Grant a hub connection to the agent as MCP tools (repeatable). The connection is a connection id or a provider name. Modes: <connection>:<cap1>,<cap2> (least privilege, recommended), <connection>:* (all of one connection), or *:* (all connections). List connections with `tangle hub connections`; paths with `tangle hub tools search <keyword>`.",Tr,[]).option(`--allow-writes`,"Pre-approve every WRITE action of each granted --connection so the agent can write unattended (reads are already allowed; destructive actions still prompt). Revert with `tangle hub permissions revert-writes`.").option(`--no-hub-key`,`Do not auto-mint a platform Hub key for --allow-writes; use the stored credential as-is`).action(async(e,t,n)=>{let r=t===void 0?e:t,i=t===void 0?Zn(n.box):e,{context:a,client:o}=K(n),s=await rn({profileSource:n.profile,systemPrompt:n.systemPrompt,skills:n.skills,tools:n.tools});await pi(n);let c=ui(n.connection);n.allowWrites&&await fi(n);let l=s||c?{...s,...c?.profile}:void 0,u=n.harness,d=l||u||n.model?{...u?{type:u}:{},...l?{profile:l}:{},...n.model?{model:{model:n.model}}:{}}:void 0,f=await J(o,a,i);if(f=await Y(f),n.interactive){let e=n.session??`int-${w()}`,t=u??(await f.backend.status()).type,o=di(i,e,t,l,n.model,r),s=f.session(e).interactive(),c=z(`Starting interactive ${t} session...`);c.start();let d;try{d=await s.start(o)}finally{c.stop()}let p=d.ref.preparationReceipt.harness,m=d.state===`running`?d.streamUrl:void 0,h=`${ii(a.baseUrl)}/dashboard/sandbox/${encodeURIComponent(i)}?interactive=${encodeURIComponent(d.ref.run.sessionId)}`;if(n.json){I({state:d.state,sessionId:d.ref.run.sessionId,harness:p,...m?{streamUrl:m}:{},webUrl:h});return}if(R(`Interactive ${p} session ${d.state}.`),console.log(),B({...d.state===`running`?{"Watch & drive":h}:{},Session:d.ref.run.sessionId}),console.log(),d.state===`exited`){R(`The initial prompt completed with reason: ${d.reason}.`);return}R(`Open the link to watch the agent and type to take over.`),process.stdin.isTTY===!0&&process.stdout.isTTY===!0&&(console.log(),R(`Attaching to the live session — press Ctrl-] to detach.`),await mi(s,h));return}if(n.stream){n.json||(R(`Streaming response...`),console.log());let e=Date.now(),t=await li(f.streamPrompt(r,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10),...d?{backend:d}:{}}),e,!n.json);n.json?(I({...t.outcome.result,...t.response?{response:t.response}:{},...t.outcome.tokenUsage?{tokenUsage:t.outcome.tokenUsage}:{},durationMs:Date.now()-e}),t.outcome.result.success||(process.exitCode=1)):(t.printed>0&&console.log(),ci(t.outcome))}else{let e=z(`Processing prompt...`);e.start();let t=await f.prompt(r,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10),...d?{backend:d}:{}});e.stop(),n.json?(I(t),t.success===!1&&(process.exitCode=1)):t.success===!1?ai(t,`Agent prompt failed`):(console.log(t.response),console.log(),B({Duration:`${t.durationMs}ms`,"Input Tokens":t.usage?.inputTokens,"Output Tokens":t.usage?.outputTokens}))}}),e.addCommand(Xr()),e.addCommand(ni()),e}async function gi(e){let t=e.timeoutMs??1e4,n=e.baseUrl.replace(/\/$/,``),a=`${n}/v1/account/me`;try{let n=await fetch(a,{headers:{Accept:`application/json`,Authorization:`Bearer ${e.apiKey}`},signal:AbortSignal.timeout(t)});if(!n.ok){let e=await vi(n);throw n.status===401||n.status===403?new r(e||`Invalid API key`):n.status>=500?new u(e||`Sandbox API returned an unexpected error`,{status:n.status}):Error(e||`Credential validation failed with status ${n.status}`)}let i=await n.json();if(!i.success||!i.data)throw Error(`Sandbox API returned an invalid account response`);return{customerId:i.data.customer_id,billingOwnerId:typeof i.data.billing_owner_id==`string`?i.data.billing_owner_id:void 0,apiKeyId:typeof i.data.api_key_id==`string`||i.data.api_key_id===null?i.data.api_key_id:void 0,billingDelegationAuthorized:typeof i.data.billing_delegation_authorized==`boolean`?i.data.billing_delegation_authorized:void 0,email:i.data.email,name:i.data.name,tier:i.data.tier,createdAt:i.data.created_at}}catch(e){throw e instanceof r||e instanceof u||e instanceof f?e:e instanceof Error&&e.name===`AbortError`?new f(`Timed out validating credentials against ${n}`,{timeoutMs:t}):e instanceof Error&&!(e instanceof TypeError)?e:new i(`Failed to reach ${n}`,{cause:_i(e)})}}function _i(e){return e instanceof Error?e:void 0}async function vi(e){let t=await e.text();if(t)try{let e=JSON.parse(t);return e.error?.message??e.message??t}catch{return t}}function yi(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#39;`)}function bi(e){if(!Si(e.hostHeader))return{kind:`host-mismatch`};let t;try{t=new URL(e.requestUrl??`/`,`http://127.0.0.1`)}catch{return{kind:`not-found`}}if(t.pathname!==`/callback`)return{kind:`not-found`};if(t.searchParams.get(`state`)!==e.expectedState)return{kind:`state-mismatch`};let n=t.searchParams.get(`error`);if(n)return{kind:`error`,reason:n};let r=t.searchParams.get(`grant_token`);return r?{kind:`ok`,token:r}:{kind:`missing-token`}}async function xi(e){e.signal?.throwIfAborted();let t=e.timeoutMs??12e4,n=e.baseUrl.replace(/\/$/,``),r=await import(`node:http`),i=te(32).toString(`hex`),a=null,o=null,s=new Promise((e,t)=>{a=e,o=t}),c=r.createServer((e,t)=>{try{let n=bi({hostHeader:e.headers.host,requestUrl:e.url,expectedState:i});switch(n.kind){case`host-mismatch`:t.writeHead(421,{"content-type":`text/plain; charset=utf-8`}),t.end(`Misdirected request`);return;case`not-found`:t.writeHead(404,{"content-type":`text/plain; charset=utf-8`}),t.end(`Not found`);return;case`state-mismatch`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Ei(`State mismatch — refusing login`)),o?.(Error(`Browser login state mismatch — refusing potentially hijacked callback`));return;case`error`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Ei(n.reason)),o?.(Error(`Browser login failed: ${n.reason}`));return;case`missing-token`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Ei(null)),o?.(Error(`Browser login did not return a grant token`));return;case`ok`:t.writeHead(200,{"content-type":`text/html; charset=utf-8`}),t.end(Ei(null)),a?.(n.token);return}}catch(e){o?.(e instanceof Error?e:Error(`Browser login callback failed`))}});await new Promise((e,t)=>{c.once(`error`,t),c.listen(0,`127.0.0.1`,()=>e())});try{let r=c.address();if(!r||typeof r==`string`)throw Error(`Failed to bind local callback server`);let a=new URL(`http://127.0.0.1:${r.port}/callback`);a.searchParams.set(`state`,i);let o=new URL(`${n}/auth/cli/login`);o.searchParams.set(`callback_url`,a.toString()),e.provider&&o.searchParams.set(`provider`,e.provider);let l=await Ti(o.toString());e.onLoginUrl?.({loginUrl:o.toString(),browserOpened:l});let u=await wi({baseUrl:n,grantToken:await Ci(s,t,e.signal),timeoutMs:t,signal:e.signal});return{apiKey:u.apiKey,email:u.email,name:u.name,tier:u.tier}}finally{e.signal?.aborted&&c.closeAllConnections(),await new Promise((e,t)=>{c.close(n=>{if(n){t(n);return}e()})}).catch(()=>void 0)}}function Si(e){if(!e)return!1;let t=e.toLowerCase().match(/^(\[[^\]]+\]|[^:]+)(?::\d+)?$/);if(!t)return!1;let n=t[1];return n===`127.0.0.1`||n===`localhost`||n===`[::1]`}async function Ci(e,t,n){let r=new AbortController;try{return await Promise.race([e,Ae(t,void 0,{signal:AbortSignal.any([r.signal,...n?[n]:[]])}).then(()=>{throw new f(`Timed out waiting for browser login to complete`,{timeoutMs:t})})])}finally{r.abort()}}async function wi(e){let t=await fetch(`${e.baseUrl}/auth/cli/exchange`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify({grant_token:e.grantToken}),signal:AbortSignal.any([AbortSignal.timeout(e.timeoutMs),...e.signal?[e.signal]:[]])}).catch(t=>{throw new i(`Failed to reach ${e.baseUrl}`,{cause:t instanceof Error?t:void 0})}),n=await t.json().catch(()=>null);if(!t.ok||!n?.success||!n.data?.api_key)throw Error(n?.error?.message||`Failed to exchange browser login grant`);return{apiKey:n.data.api_key,email:n.data.email,name:n.data.name,tier:n.data.tier}}async function Ti(e){let{spawn:t}=await import(`node:child_process`),n=process.platform===`darwin`?[`open`,e]:process.platform===`win32`?[`cmd`,`/c`,`start`,``,e]:[`xdg-open`,e];return await new Promise(e=>{let r=t(n[0],n.slice(1),{detached:!0,stdio:`ignore`});r.once(`error`,()=>e(!1)),r.once(`spawn`,()=>{r.unref(),e(!0)})})}function Ei(e){return`<!doctype html>
124
+ }`}}function Xr(e){return{anthropic:`Anthropic Messages API (Claude)`,openai:`OpenAI Chat Completions (function calling)`,"vercel-ai":`Vercel AI SDK (generateText / streamText)`,mastra:`Mastra agent framework`,"mcp-local":`Local MCP server bridge (stdio)`,"claude-desktop":`Claude Desktop config (uses local MCP)`,cursor:`Cursor config (uses local MCP)`,zed:`Zed config (uses local MCP)`}[e]}function Zr(){return new x(`connect`).description(`Print a copy-paste SDK integration snippet for one of: ${Jr.join(`, `)} (to stream a local agent's telemetry to Intelligence, see 'tangle connect')`).argument(`<framework>`,Jr.join(` | `)).option(`-i, --sandbox <id>`,`Sandbox ID to embed in the snippet`,`<SANDBOX_ID>`).option(`-s, --session <id>`,`Session ID to embed in the snippet`,`default`).action((e,t)=>{Jr.includes(e)||(console.error(b.red(`unknown framework: ${e}`),`\nsupported: ${Jr.join(`, `)}`),process.exit(2));let n=e;process.stdout.write(b.cyan(`# ${Xr(n)}\n\n`)),process.stdout.write(`${Yr(n,t.sandbox,t.session)}\n`)})}async function Qr(e,t=!1,n){n?.throwIfAborted();let r=t?new Oe({write(e,t,n){n()}}):process.stderr,i=De({input:process.stdin,signal:n,output:r,...t?{terminal:!0}:{}});n&&i.once(`SIGINT`,()=>{process.emit(`SIGINT`),i.close()}),t&&process.stderr.write(e);try{return await new Promise(n=>{i.once(`close`,()=>n(void 0)),i.question(t?``:e,e=>{n(e.trim()),i.close()})})}finally{i.close(),t&&process.stderr.write(`
125
+ `)}}async function $r(e){let t=await Qr(e,!0);if(t===void 0)throw Error(`No answer on stdin.`);return t}async function ei(e,t){let n=await Qr(e);if(n===void 0)throw process.stderr.write(`
126
+ `),Error(t?`No answer on stdin. Pass ${t} to skip the confirmation.`:`No answer on stdin.`);return[`y`,`yes`].includes(n.toLowerCase())}async function ti(e,t,n){let r=await Qr(`${e}${t?` [${t}]`:``}: `,!1,n);if(r===void 0)throw Error(`No answer on stdin.`);return r||t||``}async function ni(e,t=`secret`){if(process.stdin.isTTY)throw Error(e?`${e} reads ${t} from stdin, but stdin is a terminal; pipe it in`:`Cannot read ${t} from stdin when stdin is a TTY`);return(await ke(process.stdin)).toString(`utf8`).replace(/\r?\n$/,``)}function ri(){let e=new x(`profile`).description(`Create, inspect, and validate portable agent profiles`);return e.command(`create [output]`).description(`Create a profile — interactively (a wizard), or fully via flags`).option(`--name <name>`,`Profile name (when set, skips the wizard)`).option(`--description <text>`,`Profile description`).option(`--model <model>`,`Model (provider/model)`).option(`--system-prompt <text>`,`System prompt`).option(`--skills <ref...>`,`Skill refs: local path or github:<owner>/<repo>/<path>[@<ref>]`).option(`--tools <ref...>`,`Tool refs: local path or github:<owner>/<repo>/<path>[@<ref>]`).option(`--harness <name>`,`Harness hint shown in the run command`).action(async(e,t)=>{let n=t.name,r=t.description,i=t.harness,a=t.model,o=t.systemPrompt,s=t.skills??[],c=t.tools??[];if(!n&&process.stdin.isTTY&&(n=await ti(`Profile name`,`my-agent`),r=await ti(`Description (optional)`)||void 0,i=await ti(`Harness`,`claude-code`)||void 0,a=await ti(`Model (optional, provider/model)`)||void 0,o=await ti(`System prompt (optional)`)||void 0,s=await ii(`Skill ref (local path or github:..., blank to finish)`),c=await ii(`Tool ref (blank to finish)`)),!n)throw Error(process.stdin.isTTY?`Profile name is required.`:"`agent profile create` needs at least --name in a non-interactive shell (no TTY to prompt). Pass --name <name> (and optionally --model/--skills/--tools/--system-prompt).");let l=en({model:a,systemPrompt:o,skills:s,tools:c}),u=nn({...n?{name:n}:{},...r?{description:r}:{},...l??{},...i?{harness:i}:{}},`new profile`);if(t.json){I(u);return}let d=e??`agent-profile.json`;fe(d,`${JSON.stringify(u,null,2)}\n`),R(`Wrote ${d}`),R(`Run it: tangle agent prompt <box> --profile ${d}${i?` --harness ${i}`:``}`)}),e.command(`show <source>`).description(`Load and print a profile (local path, https URL, or github:owner/repo/path[@ref])`).action(async e=>{try{I(await tn(e))}catch(e){U(e,!0)}}),e.command(`validate <source>`).description(`Validate a profile against the canonical AgentProfile schema`).action(async(e,t)=>{let n=await tn(e),r=typeof n.name==`string`?n.name:`(unnamed)`;t.json?I({ok:!0,name:r}):R(`Profile valid: "${r}"`)}),e}async function ii(e){let t=[];for(;;){let n=await ti(e);if(!n)break;t.push(n)}return t}function ai(e){return(process.env.TANGLE_SANDBOX_WEB_URL?.trim()||e).replace(/\/+$/,``)}function oi(e,t){if(process.exitCode=1,e.status===`blocked_on_approval`){console.error(b.yellow(`⚠ Blocked on a hub approval.`));let t=e.approval?.approvalId;console.error(t?`Approve it: tangle hub approvals approve ${t}`:"Approve the pending request (`tangle hub approvals`), then re-run.");return}if(e.status===`awaiting_question`){console.error(b.yellow(`⚠ Agent is awaiting an answer to a question.`)),console.error(`Re-run with --interactive to answer it, or answer programmatically via box.session(<id>).answer(<questionId>, { ... }).`);return}if(e.status===`awaiting_interaction`){console.error(b.yellow(`⚠ Agent is awaiting a response.`)),console.error(`Open an interactive session, or answer the canonical interaction through the Sandbox SDK.`);return}if(e.status===`awaiting_plan_decision`){console.error(b.yellow(`⚠ Agent is awaiting a plan decision.`)),console.error(`Approve or reject the pending plan before continuing.`);return}console.error(b.red(`✗ ${e.error&&e.error.length>0?e.error:t}`))}function si(e){let t=e.part;if(t?.type===`text`)return t.text??t.content??void 0}function ci(e){return e.finalText??e.response??e.output??e.content??e.text??void 0}function li(e){if(!e.result.success){oi(e.result,`Agent run failed`);return}let t=Date.now()-e.startedAt,n=e.tokenUsage,r=[`${t}ms`,n?.inputTokens===void 0?void 0:`${n.inputTokens} in`,n?.outputTokens===void 0?void 0:`${n.outputTokens} out`].filter(e=>!!e);console.log(b.green(`✓ Done`),b.dim(`(${r.join(`, `)})`))}async function ui(e,t,n=!0){let r=``,i,a=m(),o=e=>{if(e.startsWith(r)){let t=e.slice(r.length);t&&n&&process.stdout.write(t)}else n&&process.stdout.write(e);r=e};try{for await(let t of e)switch(a.observe(t),t.type){case`token`:{let e=t.data?.value;typeof e==`string`&&(n&&process.stdout.write(e),r+=e);break}case`message.part.updated`:{let e=si(t.data);typeof e==`string`&&e.length>0&&o(e);break}case`raw`:break;case`result`:i=t.data;break}}catch(e){a.observe({type:`error`,data:{message:e instanceof Error?e.message:String(e)}})}if(r.length===0&&i){let e=ci(i);typeof e==`string`&&e.length>0&&(n&&process.stdout.write(e),r=e)}return{outcome:{result:a.finish(),startedAt:t,tokenUsage:i?.tokenUsage},resultData:i,printed:r.length,...r.length>0?{response:r}:{}}}function di(e){let t=Or(e??[]);if(t.length!==0)return{profile:{connections:t}}}function fi(e,t,n,r,i,a){let o={...r??{},harness:n,...i?{model:{...r?.model??{},default:i}}:{}},s={profile:o,requestedProfileDigest:re(o),initialPrompt:a};return{...s,run:E({provider:`tangle-sandbox`,environmentId:e,sessionId:t,executionId:`interactive-execution-${t}`},s)}}async function pi(e){let t=Or(e.connection??[]);if(t.length===0)throw Error(`--allow-writes needs at least one --connection to grant writes for.`);if(t.some(e=>e.connectionId===`*`))throw Error("--allow-writes needs explicit --connection ids; the `*:*` wildcard can't be bulk-granted. Grant per connection, e.g. --connection conn_x:* --allow-writes.");let n=await q({hubKey:e.hubKey});for(let r of t){let t=await n.permissions.allowWrites(r.connectionId);e.json||R(`Allowed ${t.writeActions} write action${t.writeActions===1?``:`s`} for connection ${r.connectionId} (${t.granted} newly granted).`)}e.json||R(`Revert anytime: ${t.map(e=>`tangle hub permissions revert-writes --connection ${e.connectionId}`).join(` · `)}`)}async function mi(e){!e.connection||e.connection.length===0||(e.connection=await Dr(e.connection,()=>q({hubKey:e.hubKey})))}async function hi(e,t){let n=process.stdin,r=process.stdout,i=null,a=!1,o=!1,s,c=new Promise(e=>{s=e}),l=()=>{try{n.setRawMode(!1)}catch{}n.pause()},u=()=>{a||(a=!0,l(),n.off(`data`,p),process.off(`SIGWINCH`,f),process.off(`SIGINT`,d),process.off(`SIGTERM`,d),process.off(`exit`,l),s())},d=e=>{(i?.close()??Promise.resolve()).finally(()=>{u(),process.exit(e===`SIGTERM`?143:130)})},f=()=>{i?.isOpen&&i.resize(r.columns||80,r.rows||24)},p=e=>{if(!i)return;let t=e.indexOf(29);if(t===-1){i.write(e);return}t>0&&i.write(e.subarray(0,t)),i.close().finally(u)};if(i=await e.attach({cols:r.columns||80,rows:r.rows||24,handlers:{onData:e=>{r.write(Buffer.from(e.buffer,e.byteOffset,e.byteLength))},onExit:e=>{o=!0;let t=e.exitCode===void 0?``:` (code ${e.exitCode})`;r.write(`\r\n[interactive session exited${t}]\r\n`),i?.close().finally(u)},onError:e=>{r.write(`\r\n[terminal stream error: ${e.message}]\r\n`)},onClose:()=>u()}}),n.setRawMode(!0),n.resume(),n.on(`data`,p),process.on(`SIGWINCH`,f),process.on(`SIGINT`,d),process.on(`SIGTERM`,d),process.on(`exit`,l),await c,console.log(),o){R(`Interactive session ended.`);return}R(`Detached — the session keeps running.`),B({"Watch & drive":t})}function gi(){let e=new x(`agent`).description(`Interact with AI agent`);return e.command(`prompt <idOrMessage> [message]`).description("Send a single prompt to the agent. With one arg it's the prompt and the box comes from `tangle use` / --box / TANGLE_SANDBOX; with two it's <id> <message>.").option(`--box <id>`,`Target sandbox (overrides the active one)`).option(`--session <id>`,`Continue existing session`).option(`--model <model>`,`Model to use`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`,`300000`).option(`--stream`,`Stream response in real-time`).option(`--interactive`,`Spawn the harness's interactive TUI in the sandbox, inject this prompt, and print a link to watch + drive the live session in the browser (omit for the default headless run)`).option(`--harness <name>`,`Harness that executes this run (claude-code, codex, kimi-code, opencode, pi, amp, hermes). Defaults to the sandbox's configured backend. The box ships all harnesses, so this is a per-run choice.`).option(`--profile <source>`,`Agent profile to run: a local JSON path, an https URL, or github:<owner>/<repo>/<path>[@<ref>]`).option(`--skills <ref...>`,`Attach skills (repeatable): a local file path, or github:<owner>/<repo>/<path>[@<ref>] to pull from a repo`).option(`--tools <ref...>`,`Attach tools (repeatable): a local file path, or github:<owner>/<repo>/<path>[@<ref>]`).option(`--system-prompt <text>`,`Override the agent's system prompt for this run`).option(`--connection <spec>`,"Grant a hub connection to the agent as MCP tools (repeatable). The connection is a connection id or a provider name. Modes: <connection>:<cap1>,<cap2> (least privilege, recommended), <connection>:* (all of one connection), or *:* (all connections). List connections with `tangle hub connections`; paths with `tangle hub tools search <keyword>`.",Er,[]).option(`--allow-writes`,"Pre-approve every WRITE action of each granted --connection so the agent can write unattended (reads are already allowed; destructive actions still prompt). Revert with `tangle hub permissions revert-writes`.").option(`--no-hub-key`,`Do not auto-mint a platform Hub key for --allow-writes; use the stored credential as-is`).action(async(e,t,n)=>{let r=t===void 0?e:t,i=t===void 0?Qn(n.box):e,{context:a,client:o}=K(n),s=await an({profileSource:n.profile,systemPrompt:n.systemPrompt,skills:n.skills,tools:n.tools});await mi(n);let c=di(n.connection);n.allowWrites&&await pi(n);let l=s||c?{...s,...c?.profile}:void 0,u=n.harness,d=l||u||n.model?{...u?{type:u}:{},...l?{profile:l}:{},...n.model?{model:{model:n.model}}:{}}:void 0,f=await J(o,a,i);if(f=await Y(f),n.interactive){let e=n.session??`int-${w()}`,t=u??(await f.backend.status()).type,o=fi(i,e,t,l,n.model,r),s=f.session(e).interactive(),c=z(`Starting interactive ${t} session...`);c.start();let d;try{d=await s.start(o)}finally{c.stop()}let p=d.ref.preparationReceipt.harness,m=d.state===`running`?d.streamUrl:void 0,h=`${ai(a.baseUrl)}/dashboard/sandbox/${encodeURIComponent(i)}?interactive=${encodeURIComponent(d.ref.run.sessionId)}`;if(n.json){I({state:d.state,sessionId:d.ref.run.sessionId,harness:p,...m?{streamUrl:m}:{},webUrl:h});return}if(R(`Interactive ${p} session ${d.state}.`),console.log(),B({...d.state===`running`?{"Watch & drive":h}:{},Session:d.ref.run.sessionId}),console.log(),d.state===`exited`){R(`The initial prompt completed with reason: ${d.reason}.`);return}R(`Open the link to watch the agent and type to take over.`),process.stdin.isTTY===!0&&process.stdout.isTTY===!0&&(console.log(),R(`Attaching to the live session — press Ctrl-] to detach.`),await hi(s,h));return}if(n.stream){n.json||(R(`Streaming response...`),console.log());let e=Date.now(),t=await ui(f.streamPrompt(r,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10),...d?{backend:d}:{}}),e,!n.json);n.json?(I({...t.outcome.result,...t.response?{response:t.response}:{},...t.outcome.tokenUsage?{tokenUsage:t.outcome.tokenUsage}:{},durationMs:Date.now()-e}),t.outcome.result.success||(process.exitCode=1)):(t.printed>0&&console.log(),li(t.outcome))}else{let e=z(`Processing prompt...`);e.start();let t=await f.prompt(r,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10),...d?{backend:d}:{}});e.stop(),n.json?(I(t),t.success===!1&&(process.exitCode=1)):t.success===!1?oi(t,`Agent prompt failed`):(console.log(t.response),console.log(),B({Duration:`${t.durationMs}ms`,"Input Tokens":t.usage?.inputTokens,"Output Tokens":t.usage?.outputTokens}))}}),e.addCommand(Zr()),e.addCommand(ri()),e}async function _i(e){let t=e.timeoutMs??1e4,n=e.baseUrl.replace(/\/$/,``),a=`${n}/v1/account/me`;try{let n=await fetch(a,{headers:{Accept:`application/json`,Authorization:`Bearer ${e.apiKey}`},signal:AbortSignal.timeout(t)});if(!n.ok){let e=await yi(n);throw n.status===401||n.status===403?new r(e||`Invalid API key`):n.status>=500?new u(e||`Sandbox API returned an unexpected error`,{status:n.status}):Error(e||`Credential validation failed with status ${n.status}`)}let i=await n.json();if(!i.success||!i.data)throw Error(`Sandbox API returned an invalid account response`);return{customerId:i.data.customer_id,billingOwnerId:typeof i.data.billing_owner_id==`string`?i.data.billing_owner_id:void 0,apiKeyId:typeof i.data.api_key_id==`string`||i.data.api_key_id===null?i.data.api_key_id:void 0,billingDelegationAuthorized:typeof i.data.billing_delegation_authorized==`boolean`?i.data.billing_delegation_authorized:void 0,email:i.data.email,name:i.data.name,tier:i.data.tier,createdAt:i.data.created_at}}catch(e){throw e instanceof r||e instanceof u||e instanceof f?e:e instanceof Error&&e.name===`AbortError`?new f(`Timed out validating credentials against ${n}`,{timeoutMs:t}):e instanceof Error&&!(e instanceof TypeError)?e:new i(`Failed to reach ${n}`,{cause:vi(e)})}}function vi(e){return e instanceof Error?e:void 0}async function yi(e){let t=await e.text();if(t)try{let e=JSON.parse(t);return e.error?.message??e.message??t}catch{return t}}function bi(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#39;`)}function xi(e){if(!Ci(e.hostHeader))return{kind:`host-mismatch`};let t;try{t=new URL(e.requestUrl??`/`,`http://127.0.0.1`)}catch{return{kind:`not-found`}}if(t.pathname!==`/callback`)return{kind:`not-found`};if(t.searchParams.get(`state`)!==e.expectedState)return{kind:`state-mismatch`};let n=t.searchParams.get(`error`);if(n)return{kind:`error`,reason:n};let r=t.searchParams.get(`grant_token`);return r?{kind:`ok`,token:r}:{kind:`missing-token`}}async function Si(e){e.signal?.throwIfAborted();let t=e.timeoutMs??12e4,n=e.baseUrl.replace(/\/$/,``),r=await import(`node:http`),i=te(32).toString(`hex`),a=null,o=null,s=new Promise((e,t)=>{a=e,o=t}),c=r.createServer((e,t)=>{try{let n=xi({hostHeader:e.headers.host,requestUrl:e.url,expectedState:i});switch(n.kind){case`host-mismatch`:t.writeHead(421,{"content-type":`text/plain; charset=utf-8`}),t.end(`Misdirected request`);return;case`not-found`:t.writeHead(404,{"content-type":`text/plain; charset=utf-8`}),t.end(`Not found`);return;case`state-mismatch`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Di(`State mismatch — refusing login`)),o?.(Error(`Browser login state mismatch — refusing potentially hijacked callback`));return;case`error`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Di(n.reason)),o?.(Error(`Browser login failed: ${n.reason}`));return;case`missing-token`:t.writeHead(400,{"content-type":`text/html; charset=utf-8`}),t.end(Di(null)),o?.(Error(`Browser login did not return a grant token`));return;case`ok`:t.writeHead(200,{"content-type":`text/html; charset=utf-8`}),t.end(Di(null)),a?.(n.token);return}}catch(e){o?.(e instanceof Error?e:Error(`Browser login callback failed`))}});await new Promise((e,t)=>{c.once(`error`,t),c.listen(0,`127.0.0.1`,()=>e())});try{let r=c.address();if(!r||typeof r==`string`)throw Error(`Failed to bind local callback server`);let a=new URL(`http://127.0.0.1:${r.port}/callback`);a.searchParams.set(`state`,i);let o=new URL(`${n}/auth/cli/login`);o.searchParams.set(`callback_url`,a.toString()),e.provider&&o.searchParams.set(`provider`,e.provider);let l=await Ei(o.toString());e.onLoginUrl?.({loginUrl:o.toString(),browserOpened:l});let u=await Ti({baseUrl:n,grantToken:await wi(s,t,e.signal),timeoutMs:t,signal:e.signal});return{apiKey:u.apiKey,email:u.email,name:u.name,tier:u.tier}}finally{e.signal?.aborted&&c.closeAllConnections(),await new Promise((e,t)=>{c.close(n=>{if(n){t(n);return}e()})}).catch(()=>void 0)}}function Ci(e){if(!e)return!1;let t=e.toLowerCase().match(/^(\[[^\]]+\]|[^:]+)(?::\d+)?$/);if(!t)return!1;let n=t[1];return n===`127.0.0.1`||n===`localhost`||n===`[::1]`}async function wi(e,t,n){let r=new AbortController;try{return await Promise.race([e,Ae(t,void 0,{signal:AbortSignal.any([r.signal,...n?[n]:[]])}).then(()=>{throw new f(`Timed out waiting for browser login to complete`,{timeoutMs:t})})])}finally{r.abort()}}async function Ti(e){let t=await fetch(`${e.baseUrl}/auth/cli/exchange`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify({grant_token:e.grantToken}),signal:AbortSignal.any([AbortSignal.timeout(e.timeoutMs),...e.signal?[e.signal]:[]])}).catch(t=>{throw new i(`Failed to reach ${e.baseUrl}`,{cause:t instanceof Error?t:void 0})}),n=await t.json().catch(()=>null);if(!t.ok||!n?.success||!n.data?.api_key)throw Error(n?.error?.message||`Failed to exchange browser login grant`);return{apiKey:n.data.api_key,email:n.data.email,name:n.data.name,tier:n.data.tier}}async function Ei(e){let{spawn:t}=await import(`node:child_process`),n=process.platform===`darwin`?[`open`,e]:process.platform===`win32`?[`cmd`,`/c`,`start`,``,e]:[`xdg-open`,e];return await new Promise(e=>{let r=t(n[0],n.slice(1),{detached:!0,stdio:`ignore`});r.once(`error`,()=>e(!1)),r.once(`spawn`,()=>{r.unref(),e(!0)})})}function Di(e){return`<!doctype html>
127
127
  <html lang="en">
128
128
  <head>
129
129
  <meta charset="utf-8" />
130
130
  <title>Sandbox CLI Login</title>
131
131
  </head>
132
132
  <body>
133
- <p>${e?`Sandbox CLI login failed: ${yi(e)}`:`Sandbox CLI login complete. You can close this window.`}</p>
133
+ <p>${e?`Sandbox CLI login failed: ${bi(e)}`:`Sandbox CLI login complete. You can close this window.`}</p>
134
134
  </body>
135
- </html>`}const Di=15*6e4,Oi=`sandbox`;function ki(e){return Number.isFinite(e)&&e>0?e:Di}async function Ai(e){let t=e.timeoutMs??Di,n=Date.now(),r=await ji({baseUrl:e.baseUrl,app:e.app??Oi,timeoutMs:t,provider:e.provider});for(e.onInstructions?.({userCode:r.user_code,verificationUrl:r.verification_uri,verificationUrlComplete:r.verification_uri_complete,expiresIn:r.expires_in,intervalSeconds:r.interval});;){if(Date.now()-n>t)throw new f(`Timed out waiting for device authorization to complete`,{timeoutMs:t});let i=await Mi({baseUrl:e.baseUrl,app:e.app??Oi,deviceCode:r.device_code,timeoutMs:t});if(i.status===`approved`)return i.data;let a=i.intervalSeconds*1e3;await new Promise(e=>setTimeout(e,a))}}async function ji(e){let t=ki(e.timeoutMs),n=e.app!==Oi,r=await fetch(`${Ni(e.baseUrl)}${n?`/cross-site/device/start`:`/auth/cli/device/start`}`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify(n?{app:e.app,...e.provider?{provider:e.provider}:{}}:e.provider?{provider:e.provider}:{}),signal:AbortSignal.timeout(t)}).catch(t=>{throw new i(`Failed to reach ${e.baseUrl}`,{cause:t instanceof Error?t:void 0})}),a=await r.json().catch(()=>null);if(!r.ok||!a?.success||!a.data?.device_code)throw Error(a?.error?.message||`Failed to start device login`);return a.data}async function Mi(e){let t=ki(e.timeoutMs),n=e.app!==Oi,r=await fetch(`${Ni(e.baseUrl)}${n?`/cross-site/device/poll`:`/auth/cli/device/poll`}`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify(n?{app:e.app,device_code:e.deviceCode}:{device_code:e.deviceCode}),signal:AbortSignal.timeout(t)}).catch(t=>{throw new i(`Failed to reach ${e.baseUrl}`,{cause:t instanceof Error?t:void 0})}),a=await r.json().catch(()=>null);if(r.status===428&&a?.error?.code===`AUTHORIZATION_PENDING`)return{status:`pending`,intervalSeconds:typeof a.data?.interval==`number`&&a.data.interval>0?a.data.interval:5};if(!r.ok||!a?.success||!a.data?.api_key||!a.data.email)throw Error(a?.error?.message||`Failed to complete device authorization`);return{status:`approved`,data:{apiKey:a.data.api_key,email:a.data.email,name:a.data.name,tier:a.data.tier}}}function Ni(e){return e.replace(/\/$/,``)}async function Pi(e){let t=e.apiKey,n=Hi(e.app??`sandbox`),r=Ui(n,e.profile),i=Vi(e.provider),a=n===`solve`?fr(e.baseUrl):sr(e.baseUrl,r),o=e.browser!==!1,s=(t,i)=>{Ri({profile:r,apiKey:t,baseUrl:e.baseUrl?a:void 0,activate:n===`sandbox`}),xr(),L(`Authenticated`),B({Profile:r,Email:i.email,Tier:i.tier,"Base URL":a}),R(zi)};if(t&&!Vn(t)){Pt(`Invalid API key format. Keys should start with 'sk_' or 'sk-tan-'.`),process.exit(1);return}if(gn(),!t){let t=o&&n===`sandbox`,r=z(t?`Starting browser login...`:`Starting device login...`);r.start();let c;try{c=t?await xi({baseUrl:a,provider:i,signal:e.signal,onLoginUrl:({loginUrl:e,browserOpened:t})=>{r.stop(),R(t?`Browser login opened.`:`Open this URL to continue browser login:`),console.log(e)}}):await Ai({baseUrl:a,app:n,provider:i,onInstructions:({userCode:e,verificationUrl:t,verificationUrlComplete:i})=>{r.stop(),R(`Complete login in a browser on any device:`),B({"Verification URL":t,"Verification URL (prefilled)":i,"Device Code":e}),n===`solve`&&o&&Ti(i)}})}finally{r.stop()}s(c.apiKey,c);return}let c=z(`Validating credentials...`);c.start();let l=await gi({apiKey:t,baseUrl:a});c.stop(),s(t,l)}function Fi(){let e=new x(`auth`).description(`Manage authentication`);return e.command(`login`).description(`Authenticate with browser login, device code, or an API key`).option(`--no-browser`,`Use device-code login instead of opening a browser`).option(`--profile <name>`,`Profile name`).option(`--provider <provider>`,`Identity provider (github, google, microsoft)`).option(`--app <app>`,`Product to authorize (sandbox or solve)`,`sandbox`).action(Pi),e.command(`logout`).description(`Remove stored credentials`).option(`--profile <name>`,`Profile name`).option(`--app <app>`,`Product credentials to remove (sandbox or solve)`,`sandbox`).action(e=>{let t=Ui(Hi(e.app),e.profile);tr(t),xr(),L(`Logged out successfully.`),R(`Credentials removed for profile '${t}'.`)}),e.command(`status`).description(`Show current authentication status`).option(`--profile <name>`,`Profile name`).option(`--app <app>`,`Product credentials to check (sandbox or solve)`,`sandbox`).action(async e=>{let t=Hi(e.app),n=Ui(t,e.profile),i=t===`solve`?ir(e.apiKey,n):rr(e.apiKey,n),a=t===`solve`?fr(e.baseUrl):sr(e.baseUrl,n),o=t===`solve`?or(e.apiKey,n):ar(e.apiKey,n);if(!i){if(e.json){I({authenticated:!1,reason:`missing_credentials`,profile:n,baseUrl:a,credentialSource:null});return}Pt(`Not authenticated`),R(`Run 'tangle auth login --profile ${n}' to authenticate.`),process.exit(1)}let s=e.json?null:z(`Checking credentials...`);s?.start();try{let r=await gi({apiKey:i,baseUrl:a}),c=t===`solve`?null:await zr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.profile===void 0?{}:{profile:e.profile},sandboxBaseUrl:a});s?.stop();let l=c!==null&&!c.reachable&&c.refused,u=!l,d=c!==null&&!c.reachable&&!c.refused;if(e.json){I({authenticated:u,profile:n,baseUrl:a,credentialSource:o,account:r,...c?{sandbox:{authenticated:!0},platform:c}:{}}),u||process.exit(1);return}l?Ft(`Authenticated for sandbox only`):d?Ft(`Authenticated — the platform is unreachable right now`):L(`Authenticated`),B({Profile:n,Credentials:`configured`,"Base URL":a,Source:Li(o),Email:r.email,Tier:r.tier,...c?{Platform:c.reachable?`reachable (${c.baseUrl})`:`UNREACHABLE — ${c.reason}`}:{}}),d&&R(`Platform commands (keys, workflows, hub) will not work until the platform answers again. The stored credential is not the cause and does not need replacing.`),u||(R("Platform commands (keys, workflows, hub) will not work until this resolves. Set TANGLE_API_KEY to a key you minted in the console, or run `tangle auth login` again."),process.exit(1))}catch(t){s?.stop(),e.json&&(I({authenticated:!1,profile:n,baseUrl:a,credentialSource:o,error:t instanceof Error?t.message:String(t)}),process.exit(1)),t instanceof r?Pt(`Stored credentials are invalid.`):Ft(`Stored credentials found, but validation could not complete.`),B({Profile:n,Credentials:`configured`,"Base URL":a,Source:Li(o),Error:t instanceof Error?t.message:String(t)}),process.exit(1)}}),e.addCommand(Ii()),e}function Ii(){let e=new x(`profiles`).description(`Manage CLI profiles`);return e.command(`list`).description(`List configured profiles`).action(e=>{let t=Qn();if(e.json){I(t);return}if(t.length===0){R(`No profiles found.`);return}Bt([`Profile`,`Active`,`Base URL`,`Credentials`,`Source`],t.map(e=>[e.name,e.active?`yes`:`no`,e.baseUrl,e.hasApiKey?`configured`:`none`,e.apiKeySource]))}),e.command(`use <name>`).description(`Set the active profile`).action(e=>{Gn(e);let t=$n(e);L(`Active profile set to '${t.name}'.`),B({"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`})}),e.command(`current`).description(`Show the active profile`).action(e=>{let t=$n();if(e.json){I({name:t.name,active:t.active,baseUrl:t.baseUrl,credentialSource:t.credentialSource});return}B({Profile:t.name,"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`,Source:Li(t.credentialSource)})}),e}function Li(e){switch(e){case`flag`:return`command flag`;case`env`:return`environment`;case`keychain`:return`OS keychain`;case`file`:return`credentials file`;default:return`unknown`}}function Ri(e){let t=er(e.profile,{apiKey:e.apiKey,...e.baseUrl?{baseUrl:e.baseUrl}:{}});e.activate!==!1&&Gn(e.profile),Un(e.baseUrl&&e.profile===`default`?{baseUrl:e.baseUrl}:{}),zi=Bi(e.profile,t)}let zi=`Credentials updated.`;function Bi(e,t){return t===`keychain`?e===`default`?`API key saved to the OS keychain for the default profile`:`API key saved to the OS keychain for profile '${e}'`:t===`file`?e===`default`?`API key saved to ~/.tangle/credentials.json for the default profile`:`API key saved to ~/.tangle/credentials.json for profile '${e}'`:`Profile '${e}' updated.`}function Vi(e){if(e===void 0||e===`github`||e===`google`||e===`microsoft`)return e;throw Error(`--provider must be one of: github, google, microsoft`)}function Hi(e){if(e===void 0||e===`sandbox`||e===`solve`)return e??`sandbox`;throw Error(`--app must be one of: sandbox, solve`)}function Ui(e,t){return Rn(e,t)}function Wi(){let e=new x(`backend`).description(`Manage sandbox AI agent backend`);return e.command(`status <sandboxId-or-name>`).description(`Get backend agent status`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching backend status...`);i.start();let a=await(await J(r,n,e)).backend.status();i.stop(),t.json?I(a):(R(`Backend Type: ${a.type}`),R(`Status: ${a.status}`),a.version&&R(`Version: ${a.version}`),a.error&&R(`Error: ${a.error}`),a.capabilities&&R(`Capabilities: ${JSON.stringify(a.capabilities)}`))}),e.command(`configure <sandboxId-or-name>`).description(`Update backend configuration`).option(`--model <model>`,`Model id (e.g. provider/model)`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Updating backend config...`);i.start();let a=await J(r,n,e),o=t.model?{model:t.model}:{};await a.backend.updateConfig(o),i.stop(),L(`Backend configuration updated`),t.json&&I(o)}),e.command(`mcp-status <sandboxId-or-name>`).description(`Get status of MCP servers`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching MCP status...`);i.start();let a=await(await J(r,n,e)).backend.getMcpStatus();if(i.stop(),t.json)I(a);else{let e=Object.entries(a);e.length===0?R(`No MCP servers configured`):F(e.map(([e,t])=>{let n=t;return{name:e,status:n.status,error:n.error??``}}),[{key:`name`,header:`Name`,width:24},{key:`status`,header:`Status`,width:12},{key:`error`,header:`Error`,width:40}])}}),e.command(`restart <sandboxId-or-name>`).description(`Restart the backend agent`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Restarting backend...`);i.start(),await(await J(r,n,e)).backend.restart(),i.stop(),L(`Backend restarted`)}),e}function Gi(e){let t=e.indexOf(`=`);if(t<=0)throw Error(`Invalid --task "${e}": expected format id=message (e.g. t1=summarize README)`);let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();if(!n||!r)throw Error(`Invalid --task "${e}": id and message must be non-empty`);return{id:n,message:r}}function Ki(e){let t;try{t=JSON.parse(e)}catch(e){throw Error(`--tasks file is not valid JSON: ${e.message}`)}let n=Array.isArray(t)?t:t?.tasks;if(!Array.isArray(n))throw Error(`--tasks file must contain an array or an object with a "tasks" array`);return n.map((e,t)=>{if(!e||typeof e!=`object`)throw Error(`--tasks[${t}] must be an object`);let n=e,r=typeof n.id==`string`?n.id.trim():``,i=typeof n.message==`string`?n.message:``;if(!r)throw Error(`--tasks[${t}].id must be a non-empty string`);if(!i.trim())throw Error(`--tasks[${t}].message must be a non-empty string`);let a={id:r,message:i};if(n.context!==void 0&&(typeof n.context!=`object`||n.context===null||Array.isArray(n.context)))throw Error(`--tasks[${t}].context must be a JSON object`);if(n.context!==void 0&&(a.context=n.context),n.timeoutMs!==void 0&&(!Number.isInteger(n.timeoutMs)||n.timeoutMs<=0))throw Error(`--tasks[${t}].timeoutMs must be a positive integer`);return n.timeoutMs!==void 0&&(a.timeoutMs=n.timeoutMs),a})}function qi(e){let t=e.readFile??(e=>k(e,`utf8`)),n=[];e.file&&n.push(...Ki(t(e.file)));for(let t of e.inline??[])n.push(Gi(t));if(n.length===0)throw Error(`No tasks provided. Use --tasks <file> and/or --task id=message.`);let r=new Set;for(let e of n){if(r.has(e.id))throw Error(`Duplicate task id: ${e.id}`);r.add(e.id)}return n}const Ji=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function Yi(e){let t=e.trim(),n=t.indexOf(`/`);if(n<=0||n===t.length-1)throw Error(`--model must be in the form provider/model (got "${e}")`);return{provider:t.slice(0,n),model:t.slice(n+1)}}function Xi(e){let t=e.indexOf(`=`);if(t<=0||t===e.length-1)throw Error(`Invalid --backend "${e}": expected format id=type (e.g. primary=opencode)`);let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();if(!Ji.test(n))throw Error(`Invalid backend id "${n}": use 1-128 letters, numbers, dots, underscores, or hyphens, starting with a letter or number`);if(!r||r.includes(`=`))throw Error(`Invalid --backend "${e}": type must be a non-empty backend name`);return{id:n,type:r}}function Zi(e,t){if(!e||e.length===0)throw Error(`No backends provided. Use --backend id=type or --request <file>.`);let n=e.map(Xi),r=new Set;for(let e of n){if(r.has(e.id))throw Error(`Duplicate backend id: ${e.id}`);r.add(e.id)}if(t&&n.length!==1)throw Error(`--model requires exactly one backend; use a profile to configure models for multiple backends`);return t&&(n[0]={...n[0],model:Yi(t)}),n}function Qi(e){let t;try{t=JSON.parse(e)}catch(e){throw Error(`--request file is not valid JSON: ${e.message}`)}try{return y(t)}catch(e){throw Error(`--request file is not a valid batch request: ${e.message}`)}}function $i(e,t,n){return n?`${e} [${t}]`:e}function ea(e){let t=new Map;for(let n of e)t.set(n.taskId,(t.get(n.taskId)??0)+1);return new Set([...t.entries()].filter(([,e])=>e>1).map(([e])=>e))}function ta(){let e=new x(`batch`).description(`Run multiple agent tasks in parallel across sandboxes`);return e.command(`run`).description(`Execute a batch of tasks. Provide tasks via --tasks <file.json> and/or repeated --task id=message flags.`).option(`--tasks <file>`,`Path to a JSON file with an array of tasks (or {tasks: [...]})`).option(`--request <file>`,`Path to a complete batch request JSON file`).option(`--task <id=message>`,`Inline task, id=message. Repeatable.`,(e,t=[])=>[...t,e],[]).option(`--stream`,`Stream per-task events as they arrive`).option(`-t, --timeout <ms>`,`Per-task timeout in milliseconds`,`300000`).option(`--persistent`,`Keep sandboxes alive after completion`,!1).option(`--reuse-key <key>`,`Stable workspace identity required by --persistent`).option(`--replay-only`,`Rejoin existing keyed work; refuse missing custody`).option(`--idempotency-key <key>`,`Retry identity; keyed runs continue after disconnect`).option(`--backend <id=type>`,`Backend identity and type. Required and repeatable without --request.`,(e,t=[])=>[...t,e],[]).option(`--model <provider/model>`,`Model override when exactly one backend is selected`).action(async(e,t)=>{let n=new AbortController,r=!1,i=()=>{r||(r=!0,R(`Cancel requested — stopping stream...`),n.abort())};process.on(`SIGINT`,i),process.on(`SIGTERM`,i);try{let r;if(e.request){let n=[`tasks`,`task`,`backend`,`model`,`timeout`,`persistent`,`reuseKey`].filter(e=>t.getOptionValueSource(e)===`cli`);if(n.length>0){let e={reuseKey:`reuse-key`};throw Error(`--request cannot be combined with ${n.map(t=>`--${e[t]??t}`).join(`, `)}`)}r=Qi(k(e.request,`utf8`))}else{let t=qi({file:e.tasks,inline:e.task}),n=Zi(e.backend,e.model),i=Number(e.timeout);if(!Number.isInteger(i)||i<=0)throw Error(`--timeout must be a positive integer number of milliseconds`);let a=!!e.persistent;if(a&&!e.reuseKey)throw Error(`--persistent requires --reuse-key`);if(!a&&e.reuseKey)throw Error(`--reuse-key requires --persistent`);r=y({tasks:t,timeoutMs:i,backends:n,...a?{persistent:!0,reuseKey:e.reuseKey}:{persistent:!1}})}let{tasks:i,backends:a}=r,{client:o}=K(e),s={signal:n.signal,replayOnly:!!e.replayOnly,...e.idempotencyKey?{idempotencyKey:e.idempotencyKey}:{}},c;if(e.stream){let t=e.json?console.error:console.log;R(`Streaming batch of ${i.length} task(s)...`),t();let n=o.streamBatch(r,s),l=a.length>1;for(;;){let e=await n.next();if(e.done){c=e.value;break}let r=e.value;switch(r.type){case`batch.started`:{let e=r.data;R(`Batch started (${e.taskCount} tasks, ${e.backendCount} backends)`);break}case`task.started`:{let e=r.data;t(b.dim(`→ ${$i(e.taskId,e.backendId,l)} started`));break}case`task.retry`:{let e=r.data;t(b.yellow(`↻ ${$i(e.taskId,e.backendId,l)} retry ${e.attempt}: ${e.error}`));break}case`task.completed`:{let e=r.data;t(b.green(`✓ ${$i(e.taskId,e.backendId,l)} completed in ${e.durationMs}ms`+(e.retries?` (${e.retries} retries)`:``)));break}case`task.failed`:{let e=r.data;t(b.red(`✗ ${$i(e.taskId,e.backendId,l)} failed: ${e.error}`));break}}}t()}else R(`Running batch of ${i.length} task(s)...`),c=await o.runBatch(r,s),e.json||console.log();if(e.json)I(c);else if(B({"Total tasks":c.totalTasks,"Total backends":c.totalBackends,"Total executions":c.totalExecutions,Succeeded:c.totalSuccess,Failed:c.totalFailure,"Total retries":c.totalRetries,"Success rate":`${c.successRate.toFixed(1)}%`}),!e.stream&&c.results.length>0){let e=ea(c.results);console.log(),console.log(b.bold(`Task Results`)),console.log(b.dim(`─`.repeat(40)));for(let t of c.results){let n=t.success?b.green(`✓`):b.red(`✗`),r=t.success?t.usage.inputTokens+t.usage.outputTokens:0,i=r>0?` • ${r} tokens`:``;console.log(`${n} ${$i(t.taskId,t.backendId,e.has(t.taskId))} ${b.dim(`(${t.durationMs}ms, ${t.retries} retries${i})`)}`),t.success||console.log(b.red(` ${t.error}`))}}c.totalFailure>0&&(process.exitCode=1)}catch(t){let n=t instanceof Error&&`batchCustody`in t?t.batchCustody:void 0;if(n?.acceptance===`accepted`&&!(n.cleanup?.mode===`release`&&n.cleanup.isComplete)&&R(`Batch accepted; retirement receipt unproved.`),r){console.log(),R(`Batch cancelled.`),e.json&&t instanceof Error&&`batchCustody`in t&&I({ok:!1,batchCustody:t.batchCustody}),process.exitCode=130;return}U(t,e.json)}finally{process.off(`SIGINT`,i),process.off(`SIGTERM`,i)}}),e}function na(){let e=new x(`branch`).description(`Branch a running sandbox into copy-on-write children`);return e.command(`create <sandbox-id-or-name>`).description(`Branch a running sandbox into N copy-on-write children`).option(`--count <n>`,`Number of children to create`,`1`).option(`--idempotency-key <key>`,`Retry identity: the same key and count replays the first fan-out and creates no second one`).action(async(e,t)=>{let n=Number.parseInt(t.count,10);if(!Number.isInteger(n)||n<1)throw Error(`--count must be an integer >= 1 (got ${t.count})`);let{context:r,client:i}=K(t),a=z(`Branching into ${n} child(ren)...`);a.start();let o=await J(i,r,e),s=await o.fork(n,{...t.idempotencyKey?{idempotencyKey:t.idempotencyKey}:{}}),c=s.children;a.stop(),t.json?I({children:c.map(e=>({sandboxId:e.id})),requestedCount:s.requestedCount,materializedCount:s.materializedCount,complete:s.complete,...s.idempotency?{idempotency:s.idempotency}:{}}):(s.complete?L(`Branched ${c.length} child(ren) from ${o.id}`):Ft(`Branched ${s.materializedCount} of ${s.requestedCount} requested child(ren) from ${o.id}`),s.idempotency?.outcome===`replayed`&&R(`Replayed an earlier fan-out under this key; created none.`),F(c.map(e=>({sandboxId:e.id})),[{key:`sandboxId`,header:`Child Sandbox`,width:28}]))}),e}const ra=[`codex`,`claude-code`,`nanoclaw`,`kimi-code`,`opencode`,`pi`,`openclaw`,`hermes`],ia=`https://intelligence.tangle.tools/v1/otlp`,aa=[`codex`,`claude-code`],oa=[`codex`,`claude-code`,`nanoclaw`],sa=[`SessionStart`,`UserPromptSubmit`,`PreToolUse`,`PostToolUse`,`Stop`],ca={codex:{kind:`native`,surface:`codex`,label:`Codex`,buildFiles:Sa},"claude-code":{kind:`native`,surface:`claude-code`,label:`Claude Code`,buildFiles:Ca},nanoclaw:{kind:`native`,surface:`nanoclaw`,label:`NanoClaw`,buildFiles:Ca},"kimi-code":{kind:`manual`,surface:`kimi-code`,label:`Kimi Code`,reason:`Kimi Code loads hooks through an explicit config file, so use standard OTLP env wiring until the native config adapter is verified.`},opencode:{kind:`manual`,surface:`opencode`,label:`OpenCode`,reason:`OpenCode hooks run as plugins; use standard OTLP env wiring until the native plugin adapter is verified.`},pi:{kind:`manual`,surface:`pi`,label:`Pi`,reason:`Pi hooks run through TypeScript extensions; use standard OTLP env wiring until the native extension adapter is verified.`},openclaw:{kind:`manual`,surface:`openclaw`,label:`OpenClaw`,reason:`OpenClaw project hooks require user opt-in; use standard OTLP env wiring until the hook toggle and adapter are verified.`},hermes:{kind:`manual`,surface:`hermes`,label:`Hermes`,reason:`Hermes project plugins require explicit enablement; use standard OTLP env wiring until the plugin adapter is verified.`}};function la(e){let t=e.split(`,`).map(e=>e.trim()).filter(Boolean).flatMap(e=>xa(e));return t.length===0?[...aa]:Ia(t)}function ua(e){return Object.hasOwn(ca,e)}function da(e=process.cwd()){return pe(ve(e))||`agent-workspace`}function fa(){return j(M(),`.tangle`,`intelligence.json`)}function pa(e=fa()){if(!le(e))return null;let t=Na(e),n=La(t,`apiKey`),r=La(t,`endpoint`),i=La(t,`serviceName`),a=La(t,`environment`);if(!n||!r||!i||!a)throw Error(`${e} is missing apiKey, endpoint, serviceName, or environment`);return{apiKey:n,endpoint:r,serviceName:i,environment:a}}async function ma(e){let t=ve(e.workspace),n=fa(),r=la(e.selection),i=[],a=[],o=[],s={apiKey:e.apiKey,endpoint:ba(e.endpoint),serviceName:e.serviceName,environment:e.environment};e.dryRun||Aa(n,s),o.push(n);for(let n of r){let r=ca[n];if(r.kind===`manual`){a.push({agent:r.surface,label:r.label,reason:r.reason});continue}i.push(r.surface);let s=t=>ha(e.hookCommand,r.surface,t);for(let n of r.buildFiles(s)){let r=j(t,n.relPath);if(e.dryRun){o.push(r);continue}Ma(r,JSON.parse(n.content),n.mode),o.push(r)}}return!e.smoke||e.dryRun?{configPath:n,written:o,agents:r,nativeAgents:i,manual:a}:{configPath:n,written:o,agents:r,nativeAgents:i,manual:a,smokeTraceId:await _a({agent:i[0]??r[0]??`codex`,event:`install.smoke`,endpoint:s.endpoint,apiKey:s.apiKey,serviceName:s.serviceName,environment:s.environment,sessionId:`install-smoke-${Date.now()}`,payload:{source:`tangle intelligence connect`}})}}function ha(e,t,n){return`${e.trim()} --agent ${t} --event ${n} --non-blocking`}function ga(e){let t=BigInt(Date.now())*1000000n,n=za(16),r=za(8),i=e.sessionId??wa(e.payload),a={"service.name":e.serviceName,"deployment.environment":e.environment,"tangle.agent.surface":e.agent,"tangle.agent.hook.event":e.event,"tangle.agent.hook.source":`local-hook`,...Ta(e.payload)};return i&&(a[`session.id`]=i,a[`gen_ai.conversation.id`]=i,a[`tangle.sessionId`]=i),{body:{resourceSpans:[{resource:{attributes:[Ba(`service.name`,e.serviceName),Ba(`deployment.environment`,e.environment),Ba(`tangle.agent.surface`,e.agent)]},scopeSpans:[{scope:{name:`tangle.intelligence.agent-hook`,version:`1.0.0`},spans:[{traceId:n,spanId:r,name:`agent.${e.agent}.${e.event}`,kind:1,startTimeUnixNano:t.toString(),endTimeUnixNano:(t+1000000n).toString(),attributes:Object.entries(a).map(([e,t])=>Ba(e,t)),status:{code:1}}]}]}]},traceId:n}}async function _a(e){let{body:t,traceId:n}=ga(e),r=await fetch(`${ba(e.endpoint)}/v1/traces`,{method:`POST`,headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":`application/json`},body:JSON.stringify(t)});if(!r.ok){let e=await r.text().catch(()=>``);throw Error(`OTLP smoke ingest failed: ${r.status}${e?` ${e}`:``}`)}return n}function va(e){return ba(e).replace(/\/v1\/otlp$/,``).replace(/\/+$/,``)}async function ya(e){let t=`${va(e.endpoint)}/v1/onboarding/status`,n=await fetch(t,{headers:{Authorization:`Bearer ${e.apiKey}`},signal:e.timeoutMs&&e.timeoutMs>0?AbortSignal.timeout(e.timeoutMs):void 0});if(!n.ok){let e=await n.text().catch(()=>``);throw Error(`onboarding status request failed: ${n.status}${e?` ${e}`:``}`)}let r=await n.json();return{tracesSeen:!!r.tracesSeen,contentSeen:!!r.contentSeen,lastSeenAt:typeof r.lastSeenAt==`string`?r.lastSeenAt:null,windowDays:typeof r.windowDays==`number`?r.windowDays:7,byAgent:r.byAgent&&typeof r.byAgent==`object`?r.byAgent:{}}}function ba(e){let t=e.trim().replace(/\/+$/,``);return t.endsWith(`/v1/traces`)?t.slice(0,-10):t.endsWith(`/v1/logs`)?t.slice(0,-8):t}function xa(e){switch(e){case`local`:case`both`:return[...aa];case`all`:return[...oa];case`claude`:return[`claude-code`];case`kimi`:return[`kimi-code`];default:if(ua(e))return[e];throw Error(`agent must be one of: local, all, both, ${ra.join(`, `)}`)}}function Sa(e){let t=Object.fromEntries(sa.map(t=>[t,[{command:e(t),timeoutMs:3e3,blocking:!1,matcher:`*`}]]));return[{relPath:`.codex/hooks.json`,content:JSON.stringify({hooks:t},null,2)}]}function Ca(e){let t=Object.fromEntries(sa.map(t=>[t,[{matcher:`*`,hooks:[{type:`command`,command:e(t),timeout:3}]}]]));return[{relPath:`.claude/settings.json`,content:JSON.stringify({hooks:t},null,2)}]}function wa(e){return Da(e,[`session.id`,`sessionId`,`session_id`,`conversationId`,`conversation_id`,`threadId`,`thread_id`,`transcriptId`,`transcript_id`])||process.env.TANGLE_SESSION_ID||process.env.CODEX_THREAD_ID||process.env.CLAUDE_SESSION_ID||process.env.OPENCODE_SESSION_ID}function Ta(e){let t={},n=Ea(e,[`tool.name`,`toolName`,`tool_name`,`tool`]),r=Ea(e,[`command`,`cmd`,`shell_command`,`shellCommand`]),i=Ea(e,[`tool.input`,`toolInput`,`tool_input`,`input`,`arguments`,`args`]),a=Ea(e,[`tool.output`,`toolOutput`,`tool_output`,`output`,`result`]),o=Ea(e,[`tool.exit_code`,`exitCode`,`exit_code`,`status`]),s=Ea(e,[`tool.error.message`,`errorMessage`,`error_message`,`error`]);return n&&(t[`tool.name`]=n),r&&(t[`process.command`]=r),i&&(t[`tool.input.summary`]=i),a&&(t[`tool.output.summary`]=a),o&&(t[`tool.exit_code`]=o),s&&(t[`tool.error.message`]=s),t}function Ea(e,t){let n=Oa(e,t);if(n===void 0)return null;if(typeof n==`string`)return ka(n);if(typeof n==`number`||typeof n==`boolean`||typeof n==`bigint`)return String(n);try{return ka(JSON.stringify(n))}catch{return null}}function Da(e,t){let n=Oa(e,t);return typeof n==`string`&&n.length>0?n:void 0}function Oa(e,t){if(typeof e!=`object`||!e)return;let n=[e],r=new Set;for(;n.length;){let e=n.pop();if(typeof e!=`object`||!e||r.has(e))continue;r.add(e);let i=e;for(let e of t){let t=i[e];if(t!=null&&t!==``)return t}for(let e of Object.values(i))typeof e==`object`&&e&&n.push(e)}}function ka(e){return e.length>4096?`${e.slice(0,4093)}...`:e}function Aa(e,t){ja(e,`${JSON.stringify(t,null,2)}\n`)}function ja(e,t){ue(me(e),{mode:448,recursive:!0});let n=`${e}.${process.pid}.tmp`;fe(n,t,{mode:384}),de(n,e)}function Ma(e,t,n){ue(me(e),{recursive:!0});let r=Pa(Na(e),t);fe(e,`${JSON.stringify(r,null,2)}\n`,{mode:n??420})}function Na(e){if(!le(e))return{};let t=JSON.parse(k(e,`utf8`));if(!Ra(t))throw Error(`${e} must contain a JSON object`);return t}function Pa(e,t){let n={...e};for(let[e,r]of Object.entries(t)){let t=n[e];Ra(t)&&Ra(r)?n[e]=Pa(t,r):Array.isArray(t)&&Array.isArray(r)?n[e]=Fa([...t,...r]):n[e]=r}return n}function Fa(e){let t=new Set,n=[];for(let r of e){let e=JSON.stringify(r);t.has(e)||(t.add(e),n.push(r))}return n}function Ia(e){return[...new Set(e)]}function La(e,t){let n=e[t];return typeof n==`string`&&n.length>0?n:void 0}function Ra(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&(Object.getPrototypeOf(e)===Object.prototype||Object.getPrototypeOf(e)===null)}function za(e){return te(e).toString(`hex`)}function Ba(e,t){return{key:e,value:{stringValue:t}}}const Va=`tangle.opencode-exporter`,Ha=16384;function Ua(e){return e.length<=Ha?e:`${e.slice(0,Ha-1)}…`}function Wa(e,t){return{key:e,value:{stringValue:t}}}function Ga(e){if(!e||typeof e!=`object`)return null;let t=e,n=Le(t.type);return n?{type:n,properties:t.properties&&typeof t.properties==`object`?t.properties:void 0}:null}function Ka(e,t){let n=[Wa(`event.name`,e),Wa(`gen_ai.system`,`opencode`),Wa(`service.name`,`opencode`)];return t&&(n.push(Wa(`session.id`,t)),n.push(Wa(`gen_ai.conversation.id`,t))),n}function qa(e){if(!e)return null;let t=e.part,n=e.info;return Le(t?.sessionID)??Le(n?.sessionID)??Le(e.sessionID)??null}function Ja(e,t){let n=Le(e.role)??Le(e.info?.role);if(n)return n.toLowerCase();let r=Le(e.messageID),i=t?.(r)??null;return i?i.toLowerCase():null}function Ya(e,t,n){let r=[],i=qa(e.properties),a=(n,r)=>({timeUnixNano:t,severityNumber:9,severityText:`INFO`,...n===null?{}:{body:{stringValue:Ua(n)}},attributes:[...Ka(e.type,i),...r]});if(e.type===`message.part.updated`){let t=e.properties?.part;if(!t)return r;let i=Le(t.type);if(i===`text`||i===`reasoning`){let e=Le(t.text);if(e){let i=Ja(t,n)===`user`?Me:je;r.push(a(e,[Wa(i,Ua(e))]))}return r}if(i===`tool`){let e=Le(t.tool),n=t.state,i=Re(n?.input),o=Re(n?.output),s=Le(n?.error)??(typeof n?.error==`object`&&n?.error!==null?Re(n.error):null);if(e||i){let t=[];e&&t.push(Wa(Pe,e)),i&&t.push(Wa(Ne,Ua(i))),r.push(a(null,t))}let c=o??s;if(c){let t=[Wa(Fe,Ua(c))];e&&t.push(Wa(Pe,e)),r.push(a(c,t))}return r}return r}if(e.type===`session.next.text.delta`||e.type===`session.next.text.ended`){let t=e.properties??{},n=Le(t.text)??(e.type===`session.next.text.delta`?Le(t.delta):null);return n&&r.push(a(n,[Wa(je,Ua(n))])),r}return r}function Xa(e=process.env.OTEL_RESOURCE_ATTRIBUTES){if(!e)return null;for(let t of e.split(`,`)){let e=t.indexOf(`=`);if(e===-1||t.slice(0,e).trim()!==Ie)continue;let n=t.slice(e+1).trim();if(n.length>0)return n}return null}function Za(e,t){if(e.length===0)return null;let n=[Wa(`service.name`,`opencode`),Wa(`gen_ai.system`,`opencode`),Wa(`telemetry.sdk.name`,Va)];return t&&t.trim().length>0&&n.push(Wa(Ie,t.trim())),{resourceLogs:[{resource:{attributes:n},scopeLogs:[{scope:{name:Va,version:`1.0.0`},logRecords:e}]}]}}function Qa(e){return(e??process.env.OPENCODE_BASE_URL??`http://127.0.0.1:4096`).replace(/\/+$/,``)}async function $a(e){let t=ba(e.endpoint),n=await(e.fetchImpl??fetch)(`${t}/v1/logs`,{method:`POST`,headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":`application/json`},body:JSON.stringify(e.request),signal:e.timeoutMs&&e.timeoutMs>0?AbortSignal.timeout(e.timeoutMs):void 0});if(!n.ok){let e=await n.text().catch(()=>``);throw Error(`OpenCode OTLP logs ingest failed: ${n.status}${e?` ${e}`:``}`)}}var eo=class extends Error{partial;constructor(e,t){let n=e instanceof Error?e.message:String(e);super(n),this.name=`OpencodeExporterError`,this.partial=t,e instanceof Error&&(this.cause=e)}};function to(){return(BigInt(Date.now())*1000000n).toString()}async function no(e){let t=Qa(e.opencodeBaseUrl),n=e.nowUnixNano??to,r=e.fetchImpl??fetch,i=e.subjectKey===void 0?Xa():e.subjectKey,a=await r(`${t}/event`,{headers:{Accept:`text/event-stream`},signal:e.signal});if(!a.ok){let e=await a.text().catch(()=>``);throw Error(`OpenCode event subscribe failed: ${a.status} at ${t}/event${e?` ${e}`:``}. Is OpenCode running with 'opencode serve'?`)}if(!a.body)throw Error(`OpenCode event stream at ${t}/event returned no body — cannot subscribe`);let o={eventsSeen:0,contentEventsExported:0,recordsExported:0},s=new Map,c=e=>e?s.get(e)??null:null;try{for await(let t of v(a.body,{signal:e.signal})){o.eventsSeen++;let a=Ga(t.data);if(!a)continue;if(a.type===`message.updated`){let e=a.properties?.info,t=Le(e?.id),n=Le(e?.role);t&&n&&s.set(t,n);continue}let l=Ya(a,n(),c),u=Za(l,i);u&&(await $a({endpoint:e.endpoint,apiKey:e.apiKey,request:u,timeoutMs:e.postTimeoutMs,fetchImpl:r}),o.contentEventsExported++,o.recordsExported+=l.length,e.onExport?.({eventType:a.type,records:l.length}))}}catch(e){if(e instanceof Error&&(e.name===`AbortError`||e.message.toLowerCase().includes(`abort`)))return o;throw new eo(e,o)}return o}function ro(e,t){let n=Number(e);if(!Number.isSafeInteger(n)||n<=0)throw Error(`${t} must be a positive integer`);return n}const io=[`claude-code`,`codex`,`opencode`,`openclaw`,`hermes`,`nanoclaw`],ao={"claude-code":`Claude Code`,codex:`Codex`,opencode:`OpenCode`,openclaw:`OpenClaw`,hermes:`Hermes`,nanoclaw:`NanoClaw`};function oo(e){return io.includes(e)}function so(e){return le(e)?k(e,`utf8`):``}function co(e,t){ue(me(e),{recursive:!0});let n=`${e}.${process.pid}.tmp`;fe(n,t,{mode:384}),se(n,384),de(n,e)}const lo=`# >>> tangle intelligence (claude-code) >>>`,uo=`# <<< tangle intelligence (claude-code) <<<`,fo={full:[{key:`OTEL_LOG_USER_PROMPTS`,comment:`the user/task prompt text`},{key:`OTEL_LOG_TOOL_DETAILS`,comment:`tool arguments`},{key:`OTEL_LOG_TOOL_CONTENT`,comment:`full tool input+output bodies`},{key:`OTEL_LOG_RAW_API_BODIES`,comment:`full prompt+completion JSON (richest)`}],prompts:[{key:`OTEL_LOG_USER_PROMPTS`,comment:`the user/task prompt text`},{key:`OTEL_LOG_TOOL_DETAILS`,comment:`tool arguments`}],metadata:[]};function po(e,t){return t===`env`?e:/\s/.test(e)?`"${e}"`:e}function mo(e,t){let n=t===`shell`?`export `:t===`dockerfile`?`ENV `:``,r=[];for(let i of e){if(i.kind===`blank`){t===`shell`&&r.push(``);continue}if(i.kind===`comment`){t===`shell`&&r.push(`# ${i.text}`);continue}let e=t===`shell`&&i.comment?` # ${i.comment}`:``;r.push(`${n}${i.key}=${po(i.value,t)}${e}`)}return r.join(`
136
- `)}function ho(e){let t=ba(e.endpoint),n=e.apiKey??"${TANGLE_API_KEY}",r=e.content??`full`,i=e.format??`shell`,a=[{kind:`comment`,text:`Enable + point Claude Code at Tangle (JSON protocol — matches our adapter)`},{kind:`set`,key:`CLAUDE_CODE_ENABLE_TELEMETRY`,value:`1`},{kind:`set`,key:`OTEL_EXPORTER_OTLP_PROTOCOL`,value:`http/json`},{kind:`set`,key:`OTEL_EXPORTER_OTLP_ENDPOINT`,value:t},{kind:`set`,key:`OTEL_EXPORTER_OTLP_HEADERS`,value:`Authorization=Bearer ${n}`}];e.projectKey?a.push({kind:`blank`},{kind:`comment`,text:`Groups your runs into a project so Tangle can roll up + automate per-project:`},{kind:`set`,key:`OTEL_RESOURCE_ATTRIBUTES`,value:`tangle.subject.key=${e.projectKey}`}):a.push({kind:`blank`},{kind:`comment`,text:`Label this project so Tangle rolls up + automates per-project (pick your own):`},{kind:`comment`,text:` export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=<your project>`}),a.push({kind:`blank`},{kind:`comment`,text:`CONTENT rides LOG EVENTS, so the logs exporter is MANDATORY.`},{kind:`set`,key:`OTEL_LOGS_EXPORTER`,value:`otlp`,comment:`required for prompt/completion/tool content`},{kind:`set`,key:`OTEL_METRICS_EXPORTER`,value:`otlp`,comment:`tokens / cost`},{kind:`set`,key:`OTEL_TRACES_EXPORTER`,value:`otlp`,comment:`spans (beta)`},{kind:`blank`});let o=fo[r];if(o.length===0)a.push({kind:`comment`,text:`Content gates intentionally OFF (metadata-only: tokens, durations, tool names — no prompt/completion/tool bodies).`});else{a.push({kind:`comment`,text:`THE CONTENT GATES (all default OFF):`});for(let e of o)a.push({kind:`set`,key:e.key,value:`1`,comment:e.comment})}return mo(a,i)}function go(e){return[lo,ho(e),uo].join(`
137
- `)}function _o(e,t){let n=e.indexOf(lo);if(n!==-1){let r=e.indexOf(uo,n);if(r===-1)throw Error(`shell rc has a '${lo}' marker without its closing '${uo}' — fix it by hand and re-run`);let i=r+43,a=`${e.slice(0,n)}${t}${e.slice(i)}`;return{contents:a,changed:a!==e}}return{contents:`${e.length===0?``:vo(e)}${t}\n`,changed:!0}}function vo(e){return e.endsWith(`
135
+ </html>`}const Oi=15*6e4,ki=`sandbox`;function Ai(e){return Number.isFinite(e)&&e>0?e:Oi}async function ji(e){let t=e.timeoutMs??Oi,n=Date.now(),r=await Mi({baseUrl:e.baseUrl,app:e.app??ki,timeoutMs:t,provider:e.provider});for(e.onInstructions?.({userCode:r.user_code,verificationUrl:r.verification_uri,verificationUrlComplete:r.verification_uri_complete,expiresIn:r.expires_in,intervalSeconds:r.interval});;){if(Date.now()-n>t)throw new f(`Timed out waiting for device authorization to complete`,{timeoutMs:t});let i=await Ni({baseUrl:e.baseUrl,app:e.app??ki,deviceCode:r.device_code,timeoutMs:t});if(i.status===`approved`)return i.data;let a=i.intervalSeconds*1e3;await new Promise(e=>setTimeout(e,a))}}async function Mi(e){let t=Ai(e.timeoutMs),n=e.app!==ki,r=await fetch(`${Pi(e.baseUrl)}${n?`/cross-site/device/start`:`/auth/cli/device/start`}`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify(n?{app:e.app,...e.provider?{provider:e.provider}:{}}:e.provider?{provider:e.provider}:{}),signal:AbortSignal.timeout(t)}).catch(t=>{throw new i(`Failed to reach ${e.baseUrl}`,{cause:t instanceof Error?t:void 0})}),a=await r.json().catch(()=>null);if(!r.ok||!a?.success||!a.data?.device_code)throw Error(a?.error?.message||`Failed to start device login`);return a.data}async function Ni(e){let t=Ai(e.timeoutMs),n=e.app!==ki,r=await fetch(`${Pi(e.baseUrl)}${n?`/cross-site/device/poll`:`/auth/cli/device/poll`}`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`},body:JSON.stringify(n?{app:e.app,device_code:e.deviceCode}:{device_code:e.deviceCode}),signal:AbortSignal.timeout(t)}).catch(t=>{throw new i(`Failed to reach ${e.baseUrl}`,{cause:t instanceof Error?t:void 0})}),a=await r.json().catch(()=>null);if(r.status===428&&a?.error?.code===`AUTHORIZATION_PENDING`)return{status:`pending`,intervalSeconds:typeof a.data?.interval==`number`&&a.data.interval>0?a.data.interval:5};if(!r.ok||!a?.success||!a.data?.api_key||!a.data.email)throw Error(a?.error?.message||`Failed to complete device authorization`);return{status:`approved`,data:{apiKey:a.data.api_key,email:a.data.email,name:a.data.name,tier:a.data.tier}}}function Pi(e){return e.replace(/\/$/,``)}async function Fi(e){let t=e.apiKey,n=Ui(e.app??`sandbox`),r=Wi(n,e.profile),i=Hi(e.provider),a=n===`solve`?pr(e.baseUrl):cr(e.baseUrl,r),o=e.browser!==!1,s=(t,i)=>{zi({profile:r,apiKey:t,baseUrl:e.baseUrl?a:void 0,activate:n===`sandbox`}),Sr(),L(`Authenticated`),B({Profile:r,Email:i.email,Tier:i.tier,"Base URL":a}),R(Bi)};if(t&&!Hn(t)){Ft(`Invalid API key format. Keys should start with 'sk_' or 'sk-tan-'.`),process.exit(1);return}if(_n(),!t){let t=o&&n===`sandbox`,r=z(t?`Starting browser login...`:`Starting device login...`);r.start();let c;try{c=t?await Si({baseUrl:a,provider:i,signal:e.signal,onLoginUrl:({loginUrl:e,browserOpened:t})=>{r.stop(),R(t?`Browser login opened.`:`Open this URL to continue browser login:`),console.log(e)}}):await ji({baseUrl:a,app:n,provider:i,onInstructions:({userCode:e,verificationUrl:t,verificationUrlComplete:i})=>{r.stop(),R(`Complete login in a browser on any device:`),B({"Verification URL":t,"Verification URL (prefilled)":i,"Device Code":e}),n===`solve`&&o&&Ei(i)}})}finally{r.stop()}s(c.apiKey,c);return}let c=z(`Validating credentials...`);c.start();let l=await _i({apiKey:t,baseUrl:a});c.stop(),s(t,l)}function Ii(){let e=new x(`auth`).description(`Manage authentication`);return e.command(`login`).description(`Authenticate with browser login, device code, or an API key`).option(`--no-browser`,`Use device-code login instead of opening a browser`).option(`--profile <name>`,`Profile name`).option(`--provider <provider>`,`Identity provider (github, google, microsoft)`).option(`--app <app>`,`Product to authorize (sandbox or solve)`,`sandbox`).action(Fi),e.command(`logout`).description(`Remove stored credentials`).option(`--profile <name>`,`Profile name`).option(`--app <app>`,`Product credentials to remove (sandbox or solve)`,`sandbox`).action(e=>{let t=Wi(Ui(e.app),e.profile);nr(t),Sr(),L(`Logged out successfully.`),R(`Credentials removed for profile '${t}'.`)}),e.command(`status`).description(`Show current authentication status`).option(`--profile <name>`,`Profile name`).option(`--app <app>`,`Product credentials to check (sandbox or solve)`,`sandbox`).action(async e=>{let t=Ui(e.app),n=Wi(t,e.profile),i=t===`solve`?ar(e.apiKey,n):ir(e.apiKey,n),a=t===`solve`?pr(e.baseUrl):cr(e.baseUrl,n),o=t===`solve`?sr(e.apiKey,n):or(e.apiKey,n);if(!i){if(e.json){I({authenticated:!1,reason:`missing_credentials`,profile:n,baseUrl:a,credentialSource:null});return}Ft(`Not authenticated`),R(`Run 'tangle auth login --profile ${n}' to authenticate.`),process.exit(1)}let s=e.json?null:z(`Checking credentials...`);s?.start();try{let r=await _i({apiKey:i,baseUrl:a}),c=t===`solve`?null:await Br({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.profile===void 0?{}:{profile:e.profile},sandboxBaseUrl:a});s?.stop();let l=c!==null&&!c.reachable&&c.refused,u=!l,d=c!==null&&!c.reachable&&!c.refused;if(e.json){I({authenticated:u,profile:n,baseUrl:a,credentialSource:o,account:r,...c?{sandbox:{authenticated:!0},platform:c}:{}}),u||process.exit(1);return}l?It(`Authenticated for sandbox only`):d?It(`Authenticated — the platform is unreachable right now`):L(`Authenticated`),B({Profile:n,Credentials:`configured`,"Base URL":a,Source:Ri(o),Email:r.email,Tier:r.tier,...c?{Platform:c.reachable?`reachable (${c.baseUrl})`:`UNREACHABLE — ${c.reason}`}:{}}),d&&R(`Platform commands (keys, workflows, hub) will not work until the platform answers again. The stored credential is not the cause and does not need replacing.`),u||(R("Platform commands (keys, workflows, hub) will not work until this resolves. Set TANGLE_API_KEY to a key you minted in the console, or run `tangle auth login` again."),process.exit(1))}catch(t){s?.stop(),e.json&&(I({authenticated:!1,profile:n,baseUrl:a,credentialSource:o,error:t instanceof Error?t.message:String(t)}),process.exit(1)),t instanceof r?Ft(`Stored credentials are invalid.`):It(`Stored credentials found, but validation could not complete.`),B({Profile:n,Credentials:`configured`,"Base URL":a,Source:Ri(o),Error:t instanceof Error?t.message:String(t)}),process.exit(1)}}),e.addCommand(Li()),e}function Li(){let e=new x(`profiles`).description(`Manage CLI profiles`);return e.command(`list`).description(`List configured profiles`).action(e=>{let t=$n();if(e.json){I(t);return}if(t.length===0){R(`No profiles found.`);return}Vt([`Profile`,`Active`,`Base URL`,`Credentials`,`Source`],t.map(e=>[e.name,e.active?`yes`:`no`,e.baseUrl,e.hasApiKey?`configured`:`none`,e.apiKeySource]))}),e.command(`use <name>`).description(`Set the active profile`).action(e=>{Kn(e);let t=er(e);L(`Active profile set to '${t.name}'.`),B({"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`})}),e.command(`current`).description(`Show the active profile`).action(e=>{let t=er();if(e.json){I({name:t.name,active:t.active,baseUrl:t.baseUrl,credentialSource:t.credentialSource});return}B({Profile:t.name,"Base URL":t.baseUrl,Credentials:t.credentialSource===`none`?`missing`:`configured`,Source:Ri(t.credentialSource)})}),e}function Ri(e){switch(e){case`flag`:return`command flag`;case`env`:return`environment`;case`keychain`:return`OS keychain`;case`file`:return`credentials file`;default:return`unknown`}}function zi(e){let t=tr(e.profile,{apiKey:e.apiKey,...e.baseUrl?{baseUrl:e.baseUrl}:{}});e.activate!==!1&&Kn(e.profile),Wn(e.baseUrl&&e.profile===`default`?{baseUrl:e.baseUrl}:{}),Bi=Vi(e.profile,t)}let Bi=`Credentials updated.`;function Vi(e,t){return t===`keychain`?e===`default`?`API key saved to the OS keychain for the default profile`:`API key saved to the OS keychain for profile '${e}'`:t===`file`?e===`default`?`API key saved to ~/.tangle/credentials.json for the default profile`:`API key saved to ~/.tangle/credentials.json for profile '${e}'`:`Profile '${e}' updated.`}function Hi(e){if(e===void 0||e===`github`||e===`google`||e===`microsoft`)return e;throw Error(`--provider must be one of: github, google, microsoft`)}function Ui(e){if(e===void 0||e===`sandbox`||e===`solve`)return e??`sandbox`;throw Error(`--app must be one of: sandbox, solve`)}function Wi(e,t){return zn(e,t)}function Gi(){let e=new x(`backend`).description(`Manage sandbox AI agent backend`);return e.command(`status <sandboxId-or-name>`).description(`Get backend agent status`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching backend status...`);i.start();let a=await(await J(r,n,e)).backend.status();i.stop(),t.json?I(a):(R(`Backend Type: ${a.type}`),R(`Status: ${a.status}`),a.version&&R(`Version: ${a.version}`),a.error&&R(`Error: ${a.error}`),a.capabilities&&R(`Capabilities: ${JSON.stringify(a.capabilities)}`))}),e.command(`configure <sandboxId-or-name>`).description(`Update backend configuration`).option(`--model <model>`,`Model id (e.g. provider/model)`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Updating backend config...`);i.start();let a=await J(r,n,e),o=t.model?{model:t.model}:{};await a.backend.updateConfig(o),i.stop(),L(`Backend configuration updated`),t.json&&I(o)}),e.command(`mcp-status <sandboxId-or-name>`).description(`Get status of MCP servers`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching MCP status...`);i.start();let a=await(await J(r,n,e)).backend.getMcpStatus();if(i.stop(),t.json)I(a);else{let e=Object.entries(a);e.length===0?R(`No MCP servers configured`):F(e.map(([e,t])=>{let n=t;return{name:e,status:n.status,error:n.error??``}}),[{key:`name`,header:`Name`,width:24},{key:`status`,header:`Status`,width:12},{key:`error`,header:`Error`,width:40}])}}),e.command(`restart <sandboxId-or-name>`).description(`Restart the backend agent`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Restarting backend...`);i.start(),await(await J(r,n,e)).backend.restart(),i.stop(),L(`Backend restarted`)}),e}function Ki(e){let t=e.indexOf(`=`);if(t<=0)throw Error(`Invalid --task "${e}": expected format id=message (e.g. t1=summarize README)`);let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();if(!n||!r)throw Error(`Invalid --task "${e}": id and message must be non-empty`);return{id:n,message:r}}function qi(e){let t;try{t=JSON.parse(e)}catch(e){throw Error(`--tasks file is not valid JSON: ${e.message}`)}let n=Array.isArray(t)?t:t?.tasks;if(!Array.isArray(n))throw Error(`--tasks file must contain an array or an object with a "tasks" array`);return n.map((e,t)=>{if(!e||typeof e!=`object`)throw Error(`--tasks[${t}] must be an object`);let n=e,r=typeof n.id==`string`?n.id.trim():``,i=typeof n.message==`string`?n.message:``;if(!r)throw Error(`--tasks[${t}].id must be a non-empty string`);if(!i.trim())throw Error(`--tasks[${t}].message must be a non-empty string`);let a={id:r,message:i};if(n.context!==void 0&&(typeof n.context!=`object`||n.context===null||Array.isArray(n.context)))throw Error(`--tasks[${t}].context must be a JSON object`);if(n.context!==void 0&&(a.context=n.context),n.timeoutMs!==void 0&&(!Number.isInteger(n.timeoutMs)||n.timeoutMs<=0))throw Error(`--tasks[${t}].timeoutMs must be a positive integer`);return n.timeoutMs!==void 0&&(a.timeoutMs=n.timeoutMs),a})}function Ji(e){let t=e.readFile??(e=>k(e,`utf8`)),n=[];e.file&&n.push(...qi(t(e.file)));for(let t of e.inline??[])n.push(Ki(t));if(n.length===0)throw Error(`No tasks provided. Use --tasks <file> and/or --task id=message.`);let r=new Set;for(let e of n){if(r.has(e.id))throw Error(`Duplicate task id: ${e.id}`);r.add(e.id)}return n}const Yi=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function Xi(e){let t=e.trim(),n=t.indexOf(`/`);if(n<=0||n===t.length-1)throw Error(`--model must be in the form provider/model (got "${e}")`);return{provider:t.slice(0,n),model:t.slice(n+1)}}function Zi(e){let t=e.indexOf(`=`);if(t<=0||t===e.length-1)throw Error(`Invalid --backend "${e}": expected format id=type (e.g. primary=opencode)`);let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();if(!Yi.test(n))throw Error(`Invalid backend id "${n}": use 1-128 letters, numbers, dots, underscores, or hyphens, starting with a letter or number`);if(!r||r.includes(`=`))throw Error(`Invalid --backend "${e}": type must be a non-empty backend name`);return{id:n,type:r}}function Qi(e,t){if(!e||e.length===0)throw Error(`No backends provided. Use --backend id=type or --request <file>.`);let n=e.map(Zi),r=new Set;for(let e of n){if(r.has(e.id))throw Error(`Duplicate backend id: ${e.id}`);r.add(e.id)}if(t&&n.length!==1)throw Error(`--model requires exactly one backend; use a profile to configure models for multiple backends`);return t&&(n[0]={...n[0],model:Xi(t)}),n}function $i(e){let t;try{t=JSON.parse(e)}catch(e){throw Error(`--request file is not valid JSON: ${e.message}`)}try{return y(t)}catch(e){throw Error(`--request file is not a valid batch request: ${e.message}`)}}function ea(e,t,n){return n?`${e} [${t}]`:e}function ta(e){let t=new Map;for(let n of e)t.set(n.taskId,(t.get(n.taskId)??0)+1);return new Set([...t.entries()].filter(([,e])=>e>1).map(([e])=>e))}function na(){let e=new x(`batch`).description(`Run multiple agent tasks in parallel across sandboxes`);return e.command(`run`).description(`Execute a batch of tasks. Provide tasks via --tasks <file.json> and/or repeated --task id=message flags.`).option(`--tasks <file>`,`Path to a JSON file with an array of tasks (or {tasks: [...]})`).option(`--request <file>`,`Path to a complete batch request JSON file`).option(`--task <id=message>`,`Inline task, id=message. Repeatable.`,(e,t=[])=>[...t,e],[]).option(`--stream`,`Stream per-task events as they arrive`).option(`-t, --timeout <ms>`,`Per-task timeout in milliseconds`,`300000`).option(`--persistent`,`Keep sandboxes alive after completion`,!1).option(`--reuse-key <key>`,`Stable workspace identity required by --persistent`).option(`--replay-only`,`Rejoin existing keyed work; refuse missing custody`).option(`--idempotency-key <key>`,`Retry identity; keyed runs continue after disconnect`).option(`--backend <id=type>`,`Backend identity and type. Required and repeatable without --request.`,(e,t=[])=>[...t,e],[]).option(`--model <provider/model>`,`Model override when exactly one backend is selected`).action(async(e,t)=>{let n=new AbortController,r=!1,i=()=>{r||(r=!0,R(`Cancel requested — stopping stream...`),n.abort())};process.on(`SIGINT`,i),process.on(`SIGTERM`,i);try{let r;if(e.request){let n=[`tasks`,`task`,`backend`,`model`,`timeout`,`persistent`,`reuseKey`].filter(e=>t.getOptionValueSource(e)===`cli`);if(n.length>0){let e={reuseKey:`reuse-key`};throw Error(`--request cannot be combined with ${n.map(t=>`--${e[t]??t}`).join(`, `)}`)}r=$i(k(e.request,`utf8`))}else{let t=Ji({file:e.tasks,inline:e.task}),n=Qi(e.backend,e.model),i=Number(e.timeout);if(!Number.isInteger(i)||i<=0)throw Error(`--timeout must be a positive integer number of milliseconds`);let a=!!e.persistent;if(a&&!e.reuseKey)throw Error(`--persistent requires --reuse-key`);if(!a&&e.reuseKey)throw Error(`--reuse-key requires --persistent`);r=y({tasks:t,timeoutMs:i,backends:n,...a?{persistent:!0,reuseKey:e.reuseKey}:{persistent:!1}})}let{tasks:i,backends:a}=r,{client:o}=K(e),s={signal:n.signal,replayOnly:!!e.replayOnly,...e.idempotencyKey?{idempotencyKey:e.idempotencyKey}:{}},c;if(e.stream){let t=e.json?console.error:console.log;R(`Streaming batch of ${i.length} task(s)...`),t();let n=o.streamBatch(r,s),l=a.length>1;for(;;){let e=await n.next();if(e.done){c=e.value;break}let r=e.value;switch(r.type){case`batch.started`:{let e=r.data;R(`Batch started (${e.taskCount} tasks, ${e.backendCount} backends)`);break}case`task.started`:{let e=r.data;t(b.dim(`→ ${ea(e.taskId,e.backendId,l)} started`));break}case`task.retry`:{let e=r.data;t(b.yellow(`↻ ${ea(e.taskId,e.backendId,l)} retry ${e.attempt}: ${e.error}`));break}case`task.completed`:{let e=r.data;t(b.green(`✓ ${ea(e.taskId,e.backendId,l)} completed in ${e.durationMs}ms`+(e.retries?` (${e.retries} retries)`:``)));break}case`task.failed`:{let e=r.data;t(b.red(`✗ ${ea(e.taskId,e.backendId,l)} failed: ${e.error}`));break}}}t()}else R(`Running batch of ${i.length} task(s)...`),c=await o.runBatch(r,s),e.json||console.log();if(e.json)I(c);else if(B({"Total tasks":c.totalTasks,"Total backends":c.totalBackends,"Total executions":c.totalExecutions,Succeeded:c.totalSuccess,Failed:c.totalFailure,"Total retries":c.totalRetries,"Success rate":`${c.successRate.toFixed(1)}%`}),!e.stream&&c.results.length>0){let e=ta(c.results);console.log(),console.log(b.bold(`Task Results`)),console.log(b.dim(`─`.repeat(40)));for(let t of c.results){let n=t.success?b.green(`✓`):b.red(`✗`),r=t.success?t.usage.inputTokens+t.usage.outputTokens:0,i=r>0?` • ${r} tokens`:``;console.log(`${n} ${ea(t.taskId,t.backendId,e.has(t.taskId))} ${b.dim(`(${t.durationMs}ms, ${t.retries} retries${i})`)}`),t.success||console.log(b.red(` ${t.error}`))}}c.totalFailure>0&&(process.exitCode=1)}catch(t){let n=t instanceof Error&&`batchCustody`in t?t.batchCustody:void 0;if(n?.acceptance===`accepted`&&!(n.cleanup?.mode===`release`&&n.cleanup.isComplete)&&R(`Batch accepted; retirement receipt unproved.`),r){console.log(),R(`Batch cancelled.`),e.json&&t instanceof Error&&`batchCustody`in t&&I({ok:!1,batchCustody:t.batchCustody}),process.exitCode=130;return}U(t,e.json)}finally{process.off(`SIGINT`,i),process.off(`SIGTERM`,i)}}),e}function ra(){let e=new x(`branch`).description(`Branch a running sandbox into copy-on-write children`);return e.command(`create <sandbox-id-or-name>`).description(`Branch a running sandbox into N copy-on-write children`).option(`--count <n>`,`Number of children to create`,`1`).option(`--idempotency-key <key>`,`Retry identity: the same key and count replays the first fan-out and creates no second one`).action(async(e,t)=>{let n=Number.parseInt(t.count,10);if(!Number.isInteger(n)||n<1)throw Error(`--count must be an integer >= 1 (got ${t.count})`);let{context:r,client:i}=K(t),a=z(`Branching into ${n} child(ren)...`);a.start();let o=await J(i,r,e),s=await o.fork(n,{...t.idempotencyKey?{idempotencyKey:t.idempotencyKey}:{}}),c=s.children;a.stop(),t.json?I({children:c.map(e=>({sandboxId:e.id})),requestedCount:s.requestedCount,materializedCount:s.materializedCount,complete:s.complete,...s.idempotency?{idempotency:s.idempotency}:{}}):(s.complete?L(`Branched ${c.length} child(ren) from ${o.id}`):It(`Branched ${s.materializedCount} of ${s.requestedCount} requested child(ren) from ${o.id}`),s.idempotency?.outcome===`replayed`&&R(`Replayed an earlier fan-out under this key; created none.`),F(c.map(e=>({sandboxId:e.id})),[{key:`sandboxId`,header:`Child Sandbox`,width:28}]))}),e}const ia=[`codex`,`claude-code`,`nanoclaw`,`kimi-code`,`opencode`,`pi`,`openclaw`,`hermes`],aa=`https://intelligence.tangle.tools/v1/otlp`,oa=[`codex`,`claude-code`],sa=[`codex`,`claude-code`,`nanoclaw`],ca=[`SessionStart`,`UserPromptSubmit`,`PreToolUse`,`PostToolUse`,`Stop`],la={codex:{kind:`native`,surface:`codex`,label:`Codex`,buildFiles:Ca},"claude-code":{kind:`native`,surface:`claude-code`,label:`Claude Code`,buildFiles:wa},nanoclaw:{kind:`native`,surface:`nanoclaw`,label:`NanoClaw`,buildFiles:wa},"kimi-code":{kind:`manual`,surface:`kimi-code`,label:`Kimi Code`,reason:`Kimi Code loads hooks through an explicit config file, so use standard OTLP env wiring until the native config adapter is verified.`},opencode:{kind:`manual`,surface:`opencode`,label:`OpenCode`,reason:`OpenCode hooks run as plugins; use standard OTLP env wiring until the native plugin adapter is verified.`},pi:{kind:`manual`,surface:`pi`,label:`Pi`,reason:`Pi hooks run through TypeScript extensions; use standard OTLP env wiring until the native extension adapter is verified.`},openclaw:{kind:`manual`,surface:`openclaw`,label:`OpenClaw`,reason:`OpenClaw project hooks require user opt-in; use standard OTLP env wiring until the hook toggle and adapter are verified.`},hermes:{kind:`manual`,surface:`hermes`,label:`Hermes`,reason:`Hermes project plugins require explicit enablement; use standard OTLP env wiring until the plugin adapter is verified.`}};function ua(e){let t=e.split(`,`).map(e=>e.trim()).filter(Boolean).flatMap(e=>Sa(e));return t.length===0?[...oa]:La(t)}function da(e){return Object.hasOwn(la,e)}function fa(e=process.cwd()){return pe(ve(e))||`agent-workspace`}function pa(){return j(M(),`.tangle`,`intelligence.json`)}function ma(e=pa()){if(!le(e))return null;let t=Pa(e),n=Ra(t,`apiKey`),r=Ra(t,`endpoint`),i=Ra(t,`serviceName`),a=Ra(t,`environment`);if(!n||!r||!i||!a)throw Error(`${e} is missing apiKey, endpoint, serviceName, or environment`);return{apiKey:n,endpoint:r,serviceName:i,environment:a}}async function ha(e){let t=ve(e.workspace),n=pa(),r=ua(e.selection),i=[],a=[],o=[],s={apiKey:e.apiKey,endpoint:xa(e.endpoint),serviceName:e.serviceName,environment:e.environment};e.dryRun||ja(n,s),o.push(n);for(let n of r){let r=la[n];if(r.kind===`manual`){a.push({agent:r.surface,label:r.label,reason:r.reason});continue}i.push(r.surface);let s=t=>ga(e.hookCommand,r.surface,t);for(let n of r.buildFiles(s)){let r=j(t,n.relPath);if(e.dryRun){o.push(r);continue}Na(r,JSON.parse(n.content),n.mode),o.push(r)}}return!e.smoke||e.dryRun?{configPath:n,written:o,agents:r,nativeAgents:i,manual:a}:{configPath:n,written:o,agents:r,nativeAgents:i,manual:a,smokeTraceId:await va({agent:i[0]??r[0]??`codex`,event:`install.smoke`,endpoint:s.endpoint,apiKey:s.apiKey,serviceName:s.serviceName,environment:s.environment,sessionId:`install-smoke-${Date.now()}`,payload:{source:`tangle intelligence connect`}})}}function ga(e,t,n){return`${e.trim()} --agent ${t} --event ${n} --non-blocking`}function _a(e){let t=BigInt(Date.now())*1000000n,n=Ba(16),r=Ba(8),i=e.sessionId??Ta(e.payload),a={"service.name":e.serviceName,"deployment.environment":e.environment,"tangle.agent.surface":e.agent,"tangle.agent.hook.event":e.event,"tangle.agent.hook.source":`local-hook`,...Ea(e.payload)};return i&&(a[`session.id`]=i,a[`gen_ai.conversation.id`]=i,a[`tangle.sessionId`]=i),{body:{resourceSpans:[{resource:{attributes:[Va(`service.name`,e.serviceName),Va(`deployment.environment`,e.environment),Va(`tangle.agent.surface`,e.agent)]},scopeSpans:[{scope:{name:`tangle.intelligence.agent-hook`,version:`1.0.0`},spans:[{traceId:n,spanId:r,name:`agent.${e.agent}.${e.event}`,kind:1,startTimeUnixNano:t.toString(),endTimeUnixNano:(t+1000000n).toString(),attributes:Object.entries(a).map(([e,t])=>Va(e,t)),status:{code:1}}]}]}]},traceId:n}}async function va(e){let{body:t,traceId:n}=_a(e),r=await fetch(`${xa(e.endpoint)}/v1/traces`,{method:`POST`,headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":`application/json`},body:JSON.stringify(t)});if(!r.ok){let e=await r.text().catch(()=>``);throw Error(`OTLP smoke ingest failed: ${r.status}${e?` ${e}`:``}`)}return n}function ya(e){return xa(e).replace(/\/v1\/otlp$/,``).replace(/\/+$/,``)}async function ba(e){let t=`${ya(e.endpoint)}/v1/onboarding/status`,n=await fetch(t,{headers:{Authorization:`Bearer ${e.apiKey}`},signal:e.timeoutMs&&e.timeoutMs>0?AbortSignal.timeout(e.timeoutMs):void 0});if(!n.ok){let e=await n.text().catch(()=>``);throw Error(`onboarding status request failed: ${n.status}${e?` ${e}`:``}`)}let r=await n.json();return{tracesSeen:!!r.tracesSeen,contentSeen:!!r.contentSeen,lastSeenAt:typeof r.lastSeenAt==`string`?r.lastSeenAt:null,windowDays:typeof r.windowDays==`number`?r.windowDays:7,byAgent:r.byAgent&&typeof r.byAgent==`object`?r.byAgent:{}}}function xa(e){let t=e.trim().replace(/\/+$/,``);return t.endsWith(`/v1/traces`)?t.slice(0,-10):t.endsWith(`/v1/logs`)?t.slice(0,-8):t}function Sa(e){switch(e){case`local`:case`both`:return[...oa];case`all`:return[...sa];case`claude`:return[`claude-code`];case`kimi`:return[`kimi-code`];default:if(da(e))return[e];throw Error(`agent must be one of: local, all, both, ${ia.join(`, `)}`)}}function Ca(e){let t=Object.fromEntries(ca.map(t=>[t,[{command:e(t),timeoutMs:3e3,blocking:!1,matcher:`*`}]]));return[{relPath:`.codex/hooks.json`,content:JSON.stringify({hooks:t},null,2)}]}function wa(e){let t=Object.fromEntries(ca.map(t=>[t,[{matcher:`*`,hooks:[{type:`command`,command:e(t),timeout:3}]}]]));return[{relPath:`.claude/settings.json`,content:JSON.stringify({hooks:t},null,2)}]}function Ta(e){return Oa(e,[`session.id`,`sessionId`,`session_id`,`conversationId`,`conversation_id`,`threadId`,`thread_id`,`transcriptId`,`transcript_id`])||process.env.TANGLE_SESSION_ID||process.env.CODEX_THREAD_ID||process.env.CLAUDE_SESSION_ID||process.env.OPENCODE_SESSION_ID}function Ea(e){let t={},n=Da(e,[`tool.name`,`toolName`,`tool_name`,`tool`]),r=Da(e,[`command`,`cmd`,`shell_command`,`shellCommand`]),i=Da(e,[`tool.input`,`toolInput`,`tool_input`,`input`,`arguments`,`args`]),a=Da(e,[`tool.output`,`toolOutput`,`tool_output`,`output`,`result`]),o=Da(e,[`tool.exit_code`,`exitCode`,`exit_code`,`status`]),s=Da(e,[`tool.error.message`,`errorMessage`,`error_message`,`error`]);return n&&(t[`tool.name`]=n),r&&(t[`process.command`]=r),i&&(t[`tool.input.summary`]=i),a&&(t[`tool.output.summary`]=a),o&&(t[`tool.exit_code`]=o),s&&(t[`tool.error.message`]=s),t}function Da(e,t){let n=ka(e,t);if(n===void 0)return null;if(typeof n==`string`)return Aa(n);if(typeof n==`number`||typeof n==`boolean`||typeof n==`bigint`)return String(n);try{return Aa(JSON.stringify(n))}catch{return null}}function Oa(e,t){let n=ka(e,t);return typeof n==`string`&&n.length>0?n:void 0}function ka(e,t){if(typeof e!=`object`||!e)return;let n=[e],r=new Set;for(;n.length;){let e=n.pop();if(typeof e!=`object`||!e||r.has(e))continue;r.add(e);let i=e;for(let e of t){let t=i[e];if(t!=null&&t!==``)return t}for(let e of Object.values(i))typeof e==`object`&&e&&n.push(e)}}function Aa(e){return e.length>4096?`${e.slice(0,4093)}...`:e}function ja(e,t){Ma(e,`${JSON.stringify(t,null,2)}\n`)}function Ma(e,t){ue(me(e),{mode:448,recursive:!0});let n=`${e}.${process.pid}.tmp`;fe(n,t,{mode:384}),de(n,e)}function Na(e,t,n){ue(me(e),{recursive:!0});let r=Fa(Pa(e),t);fe(e,`${JSON.stringify(r,null,2)}\n`,{mode:n??420})}function Pa(e){if(!le(e))return{};let t=JSON.parse(k(e,`utf8`));if(!za(t))throw Error(`${e} must contain a JSON object`);return t}function Fa(e,t){let n={...e};for(let[e,r]of Object.entries(t)){let t=n[e];za(t)&&za(r)?n[e]=Fa(t,r):Array.isArray(t)&&Array.isArray(r)?n[e]=Ia([...t,...r]):n[e]=r}return n}function Ia(e){let t=new Set,n=[];for(let r of e){let e=JSON.stringify(r);t.has(e)||(t.add(e),n.push(r))}return n}function La(e){return[...new Set(e)]}function Ra(e,t){let n=e[t];return typeof n==`string`&&n.length>0?n:void 0}function za(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&(Object.getPrototypeOf(e)===Object.prototype||Object.getPrototypeOf(e)===null)}function Ba(e){return te(e).toString(`hex`)}function Va(e,t){return{key:e,value:{stringValue:t}}}const Ha=`tangle.opencode-exporter`,Ua=16384;function Wa(e){return e.length<=Ua?e:`${e.slice(0,Ua-1)}…`}function Ga(e,t){return{key:e,value:{stringValue:t}}}function Ka(e){if(!e||typeof e!=`object`)return null;let t=e,n=Le(t.type);return n?{type:n,properties:t.properties&&typeof t.properties==`object`?t.properties:void 0}:null}function qa(e,t){let n=[Ga(`event.name`,e),Ga(`gen_ai.system`,`opencode`),Ga(`service.name`,`opencode`)];return t&&(n.push(Ga(`session.id`,t)),n.push(Ga(`gen_ai.conversation.id`,t))),n}function Ja(e){if(!e)return null;let t=e.part,n=e.info;return Le(t?.sessionID)??Le(n?.sessionID)??Le(e.sessionID)??null}function Ya(e,t){let n=Le(e.role)??Le(e.info?.role);if(n)return n.toLowerCase();let r=Le(e.messageID),i=t?.(r)??null;return i?i.toLowerCase():null}function Xa(e,t,n){let r=[],i=Ja(e.properties),a=(n,r)=>({timeUnixNano:t,severityNumber:9,severityText:`INFO`,...n===null?{}:{body:{stringValue:Wa(n)}},attributes:[...qa(e.type,i),...r]});if(e.type===`message.part.updated`){let t=e.properties?.part;if(!t)return r;let i=Le(t.type);if(i===`text`||i===`reasoning`){let e=Le(t.text);if(e){let i=Ya(t,n)===`user`?Me:je;r.push(a(e,[Ga(i,Wa(e))]))}return r}if(i===`tool`){let e=Le(t.tool),n=t.state,i=Re(n?.input),o=Re(n?.output),s=Le(n?.error)??(typeof n?.error==`object`&&n?.error!==null?Re(n.error):null);if(e||i){let t=[];e&&t.push(Ga(Pe,e)),i&&t.push(Ga(Ne,Wa(i))),r.push(a(null,t))}let c=o??s;if(c){let t=[Ga(Fe,Wa(c))];e&&t.push(Ga(Pe,e)),r.push(a(c,t))}return r}return r}if(e.type===`session.next.text.delta`||e.type===`session.next.text.ended`){let t=e.properties??{},n=Le(t.text)??(e.type===`session.next.text.delta`?Le(t.delta):null);return n&&r.push(a(n,[Ga(je,Wa(n))])),r}return r}function Za(e=process.env.OTEL_RESOURCE_ATTRIBUTES){if(!e)return null;for(let t of e.split(`,`)){let e=t.indexOf(`=`);if(e===-1||t.slice(0,e).trim()!==Ie)continue;let n=t.slice(e+1).trim();if(n.length>0)return n}return null}function Qa(e,t){if(e.length===0)return null;let n=[Ga(`service.name`,`opencode`),Ga(`gen_ai.system`,`opencode`),Ga(`telemetry.sdk.name`,Ha)];return t&&t.trim().length>0&&n.push(Ga(Ie,t.trim())),{resourceLogs:[{resource:{attributes:n},scopeLogs:[{scope:{name:Ha,version:`1.0.0`},logRecords:e}]}]}}function $a(e){return(e??process.env.OPENCODE_BASE_URL??`http://127.0.0.1:4096`).replace(/\/+$/,``)}async function eo(e){let t=xa(e.endpoint),n=await(e.fetchImpl??fetch)(`${t}/v1/logs`,{method:`POST`,headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":`application/json`},body:JSON.stringify(e.request),signal:e.timeoutMs&&e.timeoutMs>0?AbortSignal.timeout(e.timeoutMs):void 0});if(!n.ok){let e=await n.text().catch(()=>``);throw Error(`OpenCode OTLP logs ingest failed: ${n.status}${e?` ${e}`:``}`)}}var to=class extends Error{partial;constructor(e,t){let n=e instanceof Error?e.message:String(e);super(n),this.name=`OpencodeExporterError`,this.partial=t,e instanceof Error&&(this.cause=e)}};function no(){return(BigInt(Date.now())*1000000n).toString()}async function ro(e){let t=$a(e.opencodeBaseUrl),n=e.nowUnixNano??no,r=e.fetchImpl??fetch,i=e.subjectKey===void 0?Za():e.subjectKey,a=await r(`${t}/event`,{headers:{Accept:`text/event-stream`},signal:e.signal});if(!a.ok){let e=await a.text().catch(()=>``);throw Error(`OpenCode event subscribe failed: ${a.status} at ${t}/event${e?` ${e}`:``}. Is OpenCode running with 'opencode serve'?`)}if(!a.body)throw Error(`OpenCode event stream at ${t}/event returned no body — cannot subscribe`);let o={eventsSeen:0,contentEventsExported:0,recordsExported:0},s=new Map,c=e=>e?s.get(e)??null:null;try{for await(let t of v(a.body,{signal:e.signal})){o.eventsSeen++;let a=Ka(t.data);if(!a)continue;if(a.type===`message.updated`){let e=a.properties?.info,t=Le(e?.id),n=Le(e?.role);t&&n&&s.set(t,n);continue}let l=Xa(a,n(),c),u=Qa(l,i);u&&(await eo({endpoint:e.endpoint,apiKey:e.apiKey,request:u,timeoutMs:e.postTimeoutMs,fetchImpl:r}),o.contentEventsExported++,o.recordsExported+=l.length,e.onExport?.({eventType:a.type,records:l.length}))}}catch(e){if(e instanceof Error&&(e.name===`AbortError`||e.message.toLowerCase().includes(`abort`)))return o;throw new to(e,o)}return o}function io(e,t){let n=Number(e);if(!Number.isSafeInteger(n)||n<=0)throw Error(`${t} must be a positive integer`);return n}const ao=[`claude-code`,`codex`,`opencode`,`openclaw`,`hermes`,`nanoclaw`],oo={"claude-code":`Claude Code`,codex:`Codex`,opencode:`OpenCode`,openclaw:`OpenClaw`,hermes:`Hermes`,nanoclaw:`NanoClaw`};function so(e){return ao.includes(e)}function co(e){return le(e)?k(e,`utf8`):``}function lo(e,t){ue(me(e),{recursive:!0});let n=`${e}.${process.pid}.tmp`;fe(n,t,{mode:384}),se(n,384),de(n,e)}const uo=`# >>> tangle intelligence (claude-code) >>>`,fo=`# <<< tangle intelligence (claude-code) <<<`,po={full:[{key:`OTEL_LOG_USER_PROMPTS`,comment:`the user/task prompt text`},{key:`OTEL_LOG_TOOL_DETAILS`,comment:`tool arguments`},{key:`OTEL_LOG_TOOL_CONTENT`,comment:`full tool input+output bodies`},{key:`OTEL_LOG_RAW_API_BODIES`,comment:`full prompt+completion JSON (richest)`}],prompts:[{key:`OTEL_LOG_USER_PROMPTS`,comment:`the user/task prompt text`},{key:`OTEL_LOG_TOOL_DETAILS`,comment:`tool arguments`}],metadata:[]};function mo(e,t){return t===`env`?e:/\s/.test(e)?`"${e}"`:e}function ho(e,t){let n=t===`shell`?`export `:t===`dockerfile`?`ENV `:``,r=[];for(let i of e){if(i.kind===`blank`){t===`shell`&&r.push(``);continue}if(i.kind===`comment`){t===`shell`&&r.push(`# ${i.text}`);continue}let e=t===`shell`&&i.comment?` # ${i.comment}`:``;r.push(`${n}${i.key}=${mo(i.value,t)}${e}`)}return r.join(`
136
+ `)}function go(e){let t=xa(e.endpoint),n=e.apiKey??"${TANGLE_API_KEY}",r=e.content??`full`,i=e.format??`shell`,a=[{kind:`comment`,text:`Enable + point Claude Code at Tangle (JSON protocol — matches our adapter)`},{kind:`set`,key:`CLAUDE_CODE_ENABLE_TELEMETRY`,value:`1`},{kind:`set`,key:`OTEL_EXPORTER_OTLP_PROTOCOL`,value:`http/json`},{kind:`set`,key:`OTEL_EXPORTER_OTLP_ENDPOINT`,value:t},{kind:`set`,key:`OTEL_EXPORTER_OTLP_HEADERS`,value:`Authorization=Bearer ${n}`}];e.projectKey?a.push({kind:`blank`},{kind:`comment`,text:`Groups your runs into a project so Tangle can roll up + automate per-project:`},{kind:`set`,key:`OTEL_RESOURCE_ATTRIBUTES`,value:`tangle.subject.key=${e.projectKey}`}):a.push({kind:`blank`},{kind:`comment`,text:`Label this project so Tangle rolls up + automates per-project (pick your own):`},{kind:`comment`,text:` export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=<your project>`}),a.push({kind:`blank`},{kind:`comment`,text:`CONTENT rides LOG EVENTS, so the logs exporter is MANDATORY.`},{kind:`set`,key:`OTEL_LOGS_EXPORTER`,value:`otlp`,comment:`required for prompt/completion/tool content`},{kind:`set`,key:`OTEL_METRICS_EXPORTER`,value:`otlp`,comment:`tokens / cost`},{kind:`set`,key:`OTEL_TRACES_EXPORTER`,value:`otlp`,comment:`spans (beta)`},{kind:`blank`});let o=po[r];if(o.length===0)a.push({kind:`comment`,text:`Content gates intentionally OFF (metadata-only: tokens, durations, tool names — no prompt/completion/tool bodies).`});else{a.push({kind:`comment`,text:`THE CONTENT GATES (all default OFF):`});for(let e of o)a.push({kind:`set`,key:e.key,value:`1`,comment:e.comment})}return ho(a,i)}function _o(e){return[uo,go(e),fo].join(`
137
+ `)}function vo(e,t){let n=e.indexOf(uo);if(n!==-1){let r=e.indexOf(fo,n);if(r===-1)throw Error(`shell rc has a '${uo}' marker without its closing '${fo}' — fix it by hand and re-run`);let i=r+43,a=`${e.slice(0,n)}${t}${e.slice(i)}`;return{contents:a,changed:a!==e}}return{contents:`${e.length===0?``:yo(e)}${t}\n`,changed:!0}}function yo(e){return e.endsWith(`
138
138
 
139
139
  `)?e:e.endsWith(`
140
- `)?`${e}\n`:`${e}\n\n`}function yo(){let e=process.env.SHELL??``;return e.includes(`zsh`)?j(M(),`.zshrc`):e.includes(`bash`)?j(M(),`.bashrc`):j(M(),`.zshrc`)}function bo(e){if(e===`shell`||e===`env`||e===`dockerfile`)return e;throw Error(`--format must be one of: shell, env, dockerfile (got '${e}')`)}function xo(e){if(e===`full`||e===`prompts`||e===`metadata`)return e;throw Error(`--content must be one of: full, prompts, metadata (got '${e}')`)}async function So(e){let t=ho({endpoint:e.endpoint,apiKey:e.apiKey,projectKey:e.projectKey,content:e.content,format:e.format});if(console.log(t),e.format!==`shell`){console.log(),R(e.format===`env`?"Cron/container path: feed these to your service env (.env, `docker run --env-file`, k8s envFrom). No shell-rc edit, no TTY needed.":`Dockerfile path: paste these ENV lines into your image. No shell-rc edit, no TTY needed.`);return}if(console.log(),R(`Privacy tiers: --content full ships the whole conversation; --content prompts keeps task, prompts, and tool args only; --content metadata turns content off (telemetry still flows). Secrets are scrubbed server-side regardless.`),!e.write)return;let n=e.rcPath??yo(),r=process.stdin.isTTY?await ei(`Append this idempotent block to ${n}? (y/N)`,`n`):`n`;if(r.toLowerCase()!==`y`&&r.toLowerCase()!==`yes`){console.log(),R(`Not writing. To append later: tangle connect claude-code --rc ${n}`);return}let i=go({endpoint:e.endpoint,apiKey:e.apiKey,projectKey:e.projectKey,content:e.content,format:e.format}),{contents:a,changed:o}=_o(so(n),i);if(!o){console.log(),L(`Already present in ${n} — nothing to change.`);return}co(n,a),console.log(),L(`Wrote Tangle Intelligence env block to ${n}.`),R(`Reload your shell (e.g. 'source ${n}') before running the agent.`)}function Co(e){let t=[],n={header:null,body:[]};for(let r of e.split(`
141
- `))wo(r)?(t.push(n),n={header:r.trim(),body:[]}):n.body.push(r);return t.push(n),t.length>1&&t[0].header===null&&t[0].body.every(e=>e.trim()===``)&&t.shift(),t}function wo(e){let t=e.trim();return t.startsWith(`[`)&&t.endsWith(`]`)&&!t.includes(`=`)||t.startsWith(`[[`)&&t.endsWith(`]]`)}function To(e){let t=[];for(let n of e)n.header!==null&&t.push(n.header),t.push(...n.body);return t.join(`
142
- `)}function Eo(e){return[{key:`environment`,line:`environment = "prod"`},{key:`log_user_prompt`,line:`log_user_prompt = true`},{key:`exporter`,line:`exporter = { otlp-http = { endpoint = "${ba(e.endpoint)}/v1/logs", protocol = "json", headers = { "Authorization" = "Bearer ${e.apiKey??"${TANGLE_API_KEY}"}" } } }`}]}function Do(e){let t=e.trim();if(t===``||t.startsWith(`#`))return null;let n=t.indexOf(`=`);if(n===-1)return null;let r=t.slice(0,n).trim();return/^[A-Za-z0-9_-]+$/.test(r)?r:null}function Oo(e,t){let n=Eo(t),r=new Set(n.map(e=>e.key));if(e.trim()===``)return{contents:`${[`[otel]`,...n.map(e=>e.line)].join(`
143
- `)}\n`,changed:!0};let i=Co(e),a=i.find(e=>e.header===`[otel]`);if(!a){let t={header:`[otel]`,body:n.map(e=>e.line)},r=i[i.length-1];r&&!ko(r)&&r.body.push(``),i.push(t);let a=Ao(To(i));return{contents:a,changed:a!==Ao(e)}}let o=a.body.filter(e=>{let t=Do(e);return t===null||!r.has(t)}),s=[];for(;o.length>0&&o[o.length-1].trim()===``;)s.unshift(o.pop());a.body=[...o,...n.map(e=>e.line),...s];let c=Ao(To(i));return{contents:c,changed:c!==Ao(e)}}function ko(e){return e.body.length>0&&e.body[e.body.length-1].trim()===``}function Ao(e){return e.endsWith(`
144
- `)?e:`${e}\n`}function jo(e){let t=j(M(),`.codex`,`config.toml`),{contents:n,changed:r}=Oo(so(t),{endpoint:e.endpoint,apiKey:e.apiKey});if(!e.write){console.log(n.trimEnd());return}if(!r){L(`${t} already has the Tangle [otel] block — nothing to change.`);return}co(t,n),L(`Merged the Tangle [otel] block into ${t}.`),R("Codex emits content on the logs signal (codex.* events). Set TANGLE_API_KEY in your env before running if you kept the ${TANGLE_API_KEY} reference."),R(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=${e.projectKey??`<your project>`} before running codex.`)}function Mo(e){switch(e){case`claude-code`:return`Claude Code: set OTEL_LOGS_EXPORTER=otlp and the four OTEL_LOG_* gates (OTEL_LOG_USER_PROMPTS, OTEL_LOG_TOOL_DETAILS, OTEL_LOG_TOOL_CONTENT, OTEL_LOG_RAW_API_BODIES).`;case`codex`:return`Codex: set log_user_prompt = true in [otel] (default false redacts content).`;case`opencode`:return`OpenCode: a standalone install emits nothing without the tangle-opencode-exporter shim; inside a Tangle sandbox it is already instrumented.`;case`openclaw`:case`hermes`:case`nanoclaw`:return`${ao[e]}: no native OTLP exporter and no standalone server to subscribe to — run it inside a Tangle sandbox, where the sidecar adapter exports its content with gen_ai.system=${e}. A bare standalone install emits metadata only.`}}async function No(e){let t=Date.now()+e.timeoutSeconds*1e3,n=3e3,r=Math.min(e.timeoutSeconds*1e3,1e4),i=z(`Checking whether content is flowing…`);i.start();let a;try{for(;;){try{a=await ya({endpoint:e.endpoint,apiKey:e.apiKey,timeoutMs:r})}catch(e){if(Date.now()>=t)throw e;await Ae(n);continue}if(a.contentSeen||Date.now()>=t)break;await Ae(n)}}finally{i.stop()}if(!a)throw Error(`onboarding status check returned no result`);Po(a,e.agent),a.contentSeen||(process.exitCode=1)}function Po(e,t){if(e.contentSeen){L(`Content flowing — Tangle Intelligence can analyze this feed.`),B({"Last seen":e.lastSeenAt??`just now`,Window:`${e.windowDays}d`});return}if(e.tracesSeen){Ft(`Metadata-only — traces are arriving but carry no content. You missed a content gate.`);let n=t?[t]:Object.keys(e.byAgent).filter(oo),r=n.length>0?n:io;for(let n of r){let r=e.byAgent[n];(t||!r||r.tracesSeen&&!r.contentSeen)&&R(Mo(n))}return}Ft(`No traces yet for your tenant. Run your agent once on a real task, then re-run --verify.`),t&&R(Mo(t))}function Fo(e){let t=e??process.env.TANGLE_INTELLIGENCE_API_KEY??rr(void 0);if(!t)throw Error(`No Tangle API key found. Pass --api-key, set TANGLE_API_KEY, or run: tangle auth login`);return t}function Io(){return new x(`connect`).description(`Connect a local coding agent's telemetry to Tangle Intelligence, content on (for SDK integration snippets, see 'tangle agent connect')`).argument(`[agent]`,`claude-code | codex | opencode | openclaw | hermes | nanoclaw`).option(`--endpoint <url>`,`OTLP endpoint base`,ia).option(`-p, --project <key>`,`Project label (tangle.subject.key) to group runs; omit to set it yourself`).option(`--rc <path>`,`Shell rc file to append the Claude Code env block to`).option(`--no-write`,`Print the config instead of writing files (Claude Code / Codex)`).option(`--inline-key`,"Embed the resolved API key literally in the config (default: keep ${TANGLE_API_KEY})").option(`--verify`,`Poll onboarding status and report whether CONTENT is flowing`).option(`--timeout <seconds>`,`Verify poll timeout in seconds`,`120`).option(`--run`,`OpenCode only: run the content exporter against a live OpenCode server until interrupted`).option(`--opencode-url <url>`,`OpenCode server base URL for --run (or set OPENCODE_BASE_URL)`).option(`--format <kind>`,`Claude Code output: shell (export block) | env (.env / docker --env-file) | dockerfile (ENV lines). env/dockerfile are the cron/container path — printed to stdout, no shell-rc edit, no TTY`,`shell`).option(`--content <tier>`,`Claude Code content tier: full (everything) | prompts (task+prompts+tool-args) | metadata (telemetry on, content off)`,`full`).action(async(e,t)=>{let n=ba(t.endpoint);if(t.run){if((e?Ro(e):`opencode`)!==`opencode`)throw Error(`--run is OpenCode-only: it runs the content exporter against a live OpenCode server. Other agents export natively once configured.`);await Ho({endpoint:n,apiKey:Fo(t.apiKey),opencodeUrl:t.opencodeUrl});return}if(t.verify){await No({endpoint:n,apiKey:Fo(t.apiKey),agent:e?Ro(e):void 0,timeoutSeconds:ro(t.timeout,`--timeout`)});return}let r=e?Ro(e):await zo(),i=t.inlineKey?Fo(t.apiKey):void 0;r===`claude-code`?await So({endpoint:n,apiKey:i,projectKey:t.project,rcPath:t.rc,write:t.write!==!1,content:xo(t.content),format:bo(t.format)}):r===`codex`?jo({endpoint:n,apiKey:i,projectKey:t.project,write:t.write!==!1}):r===`opencode`?Bo({endpoint:n}):Vo(r,{endpoint:n}),console.log(),R(`Run your agent on a real task, then verify content is flowing: tangle connect ${r} --verify`)})}function Lo(){return new x(`opencode-exporter`).description(`Export a running OpenCode's content to Tangle Intelligence (standalone shim)`).option(`--endpoint <url>`,`OTLP endpoint base`,ia).option(`--opencode-url <url>`,`OpenCode server base URL (or set OPENCODE_BASE_URL)`).action(async e=>{await Ho({endpoint:ba(e.endpoint),apiKey:Fo(e.apiKey),opencodeUrl:e.opencodeUrl})})}function Ro(e){if(oo(e))return e;throw Error(`Unknown agent '${e}'. Choose one of: ${io.join(`, `)}`)}async function zo(){if(!process.stdin.isTTY)throw Error(`Specify an agent: tangle connect <${io.join(`|`)}>`);console.log(`Which coding agent are you connecting?`),io.forEach((e,t)=>{console.log(` ${t+1}) ${ao[e]} (${e})`)});let e=await ei(`Enter a number or name`,`1`);return io[Number.parseInt(e,10)-1]||Ro(e.trim())}function Bo(e){let t=ba(e.endpoint);Ft(`OpenCode has no native OTel exporter, so a standalone install emits nothing without a shim.`),console.log(),B({"Inside a Tangle sandbox":`already instrumented — our adapter exports OpenCode's event-stream content. Nothing to do.`,Standalone:`run 'tangle connect opencode --run' alongside a running OpenCode, exporting to ${t}.`}),console.log(),R(`Start OpenCode in server mode ('opencode serve'), then in another terminal run: tangle connect opencode --run`),R(`The exporter subscribes to OpenCode's SSE event bus and exports content-bearing OTLP (prompt/completion/tool content) to Tangle. Verify with: tangle connect opencode --verify`),R(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=my-project before starting the exporter.`)}function Vo(e,t){let n=ba(t.endpoint),r=ao[e];Ft(`${r} has no native OTel exporter, so a standalone install emits nothing without instrumentation.`),console.log(),B({"Inside a Tangle sandbox":`already instrumented — the sidecar adapter exports ${r}'s prompt/completion/tool content (gen_ai.system=${e}) to ${n}. Nothing to do.`,Standalone:`${r} exposes no OTLP and no event-bus server; run it inside a Tangle sandbox to capture content.`}),console.log(),R(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=my-project before starting ${r}.`),R(`Verify content is flowing: tangle connect ${e} --verify`)}async function Ho(e){let t=Qa(e.opencodeUrl),n=new AbortController,r=()=>n.abort();process.on(`SIGINT`,r),process.on(`SIGTERM`,r),R(`Subscribing to OpenCode at ${t} — exporting content to Tangle.`),R(`Run OpenCode tasks now. Press Ctrl-C to stop.`),console.log();let i=0,a;try{a=await no({endpoint:e.endpoint,apiKey:e.apiKey,opencodeBaseUrl:t,signal:n.signal,onExport:({eventType:e,records:t})=>{i+=t,R(`exported ${t} record(s) from ${e} (total ${i})`)}})}catch(e){if(e instanceof eo){let{recordsExported:t,contentEventsExported:n}=e.partial;console.log(),Ft(`Exporter failed after exporting ${t} content record(s) from ${n} event(s): ${e.message}`)}throw e}finally{process.off(`SIGINT`,r),process.off(`SIGTERM`,r)}if(console.log(),a.contentEventsExported===0){Ft(`Saw ${a.eventsSeen} event(s) but none carried content. Run a real OpenCode task (a prompt that produces text or a tool call), then re-run.`);return}L(`Exported ${a.recordsExported} content record(s) from ${a.contentEventsExported} event(s).`),R(`Verify it landed: tangle connect opencode --verify`)}function Uo(){let e=new x(`environments`).alias(`env`).description(`Manage sandbox environments`);return e.command(`list`).alias(`ls`).description(`List available environments`).action(async e=>{let{client:t}=K(e),n=z(`Fetching environments...`);e.json||n.start();let r=await t.environments.list();n.stop(),e.json?I(r):r.length===0?console.log(`No environments found`):Bt([`ID`,`Description`,`Version`,`Runtimes`],r.map(e=>[e.id,e.description??``,e.version,e.runtimes.join(`, `)]))}),e.command(`get`).description(`Get environment details`).argument(`<id>`,`Environment ID`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Fetching environment...`);t.json||r.start();let i=await n.environments.get(e);if(r.stop(),!i){console.error(`Environment not found: ${e}`),process.exit(1);return}t.json?I(i):(console.log(`ID: ${i.id}`),console.log(`Description: ${i.description??`-`}`),console.log(`Version: ${i.version}`),console.log(`Runtimes: ${i.runtimes.join(`, `)}`),i.base&&console.log(`Base: ${i.base}`))}),e}const Wo=N.string().trim().toLowerCase().min(1).max(64).regex(/^[a-z][a-z0-9-]*$/),Go=N.string().trim().toLowerCase().min(1).max(128).regex(/^[a-z0-9][a-z0-9._-]*$/),Ko=N.object({kind:Go,count:N.number().int().positive().default(1),vramGb:N.number().positive().optional()}).strict();N.object({command:N.string().min(1).max(8192),timeoutMs:N.number().int().positive().max(2147453647).optional(),env:N.record(N.string(),N.string()).optional(),cwd:N.string().min(1).max(2048).optional()}).strict(),N.object({refresh:N.enum([`true`,`false`]).optional(),acceleratorKind:Go.optional(),acceleratorCount:N.coerce.number().pipe(Ko.shape.count.unwrap()).optional(),acceleratorVramGb:N.coerce.number().positive().optional()}).strict(),N.object({maxSpendUsd:N.number().positive().max(1e4).optional(),maxLifetimeSeconds:N.number().int().positive().max(1440*60).optional()}).strict().refine(e=>e.maxSpendUsd!==void 0||e.maxLifetimeSeconds!==void 0,`Renewal requires a lifetime or spend cap`);const qo=N.object({provider:Wo.optional(),image:N.string().min(1).max(512).optional(),env:N.record(N.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/),N.string()).optional(),diskGb:N.number().int().positive().optional(),volumeGb:N.number().int().nonnegative().optional(),volumeMountPath:N.string().startsWith(`/`).max(2048).optional(),region:N.string().min(1).max(128).optional(),manifest:N.record(N.string(),N.unknown()).optional(),command:N.array(N.string().max(8192)).min(1).max(256).optional(),ports:N.array(N.number().int().min(1).max(65535)).max(32).optional(),endpoint:N.object({port:N.number().int().min(1).max(65535),healthPath:N.string().regex(/^\/(?![/\\])/).refine(e=>![`\r`,`
145
- `,` `].some(t=>e.includes(t))).max(2048).optional()}).strict().optional(),allowSpot:N.boolean().optional(),maxHourlyUsd:N.number().positive().optional(),weights:N.object({manifestSha:N.string().regex(/^[a-f0-9]{64}$/),sizeBytes:N.number().int().positive().safe()}).strict().optional(),arms:N.array(N.unknown()).min(1).max(256).optional(),maxSpendUsd:N.number().positive().max(1e4),maxLifetimeSeconds:N.number().int().positive().max(1440*60),idleTimeoutSeconds:N.number().int().positive().optional()}).strict();qo.extend({accelerator:Ko});const Jo=Ko,Yo=Wo;N.object({...qo.omit({env:!0}).shape,id:N.string(),projectRef:N.string(),ownerUserId:N.string(),productId:N.string().optional(),provider:Yo,providerLeaseId:N.string().optional(),providerInstanceType:N.string().optional(),workerUrl:N.string().optional(),endpointUrl:N.string().optional(),status:N.enum([`provisioning`,`ready`,`detaching`,`destroyed`,`failed`]),accelerator:Jo,providerCostPerHourUsd:N.number().optional(),customerPricePerHourUsd:N.number().optional(),estimatedProviderCostUsd:N.number().optional(),estimatedCustomerCostUsd:N.number().optional(),providerSelection:N.object({strategy:N.enum([`explicit`,`cheapest`,`ranked`]),selectedProvider:Yo,requestedProvider:Yo.optional(),candidates:N.array(N.object({provider:Yo,accelerator:Jo,providerInstanceType:N.string().optional(),region:N.string().optional(),pricingSource:N.enum([`live`,`configured`]).optional(),providerCostPerHourUsd:N.number(),customerPricePerHourUsd:N.number(),maxLifetimeSeconds:N.number(),estimatedProviderCostUsd:N.number(),estimatedCustomerCostUsd:N.number()})),rejected:N.array(N.object({provider:Yo,error:N.string()}))}).optional(),createdAt:N.string(),updatedAt:N.string(),readyAt:N.string().optional(),startedAt:N.string().optional(),lastUsedAt:N.string().optional(),destroyedAt:N.string().optional(),failure:N.string().optional(),billing:N.object({seconds:N.number(),providerCostUsd:N.number(),customerCostUsd:N.number(),providerCostPerHourUsd:N.number(),customerPricePerHourUsd:N.number(),startedAt:N.string(),stoppedAt:N.string()}).optional()});function Xo(e){return Ko.parse({kind:e.kind,count:e.count===void 0?void 0:Number(e.count),...e.memory===void 0?{}:{vramGb:Number(e.memory)}})}function Zo(e,t,n){let r=!!(e.provider||e.image||e.env||e.maxSpendUsd||e.maxLifetime||e.idleTimeout);if(!t&&r)throw Error(n);if(t){if(!e.maxSpendUsd||!e.maxLifetime)throw Error(`--accelerator-kind requires --gpu-max-spend-usd and --gpu-max-lifetime`);return{...e.provider?{provider:Wo.parse(e.provider)}:{},...e.image?{image:e.image}:{},...e.env?{env:ts(e.env,`--gpu-env`,`GPU env`)}:{},maxSpendUsd:rs(e.maxSpendUsd,`--gpu-max-spend-usd`),maxLifetimeSeconds:ns(e.maxLifetime,`--gpu-max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:ns(e.idleTimeout,`--gpu-idle-timeout`)}:{}}}}function Qo(e){return{...e.provider?{provider:Wo.parse(e.provider)}:{},accelerator:Xo({kind:e.acceleratorKind,count:e.acceleratorCount,memory:e.acceleratorMemory}),...e.image?{image:e.image}:{},...e.env?{env:ts(e.env,`--env`,`env`)}:{},maxSpendUsd:rs(e.maxSpendUsd,`--max-spend-usd`),maxLifetimeSeconds:ns(e.maxLifetime,`--max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:ns(e.idleTimeout,`--idle-timeout`)}:{}}}function $o(e){return e.length===1?e[0]:e.map(Be).join(` `)}function es(e){return{timeoutMs:e.timeout?ns(String(e.timeout),`--timeout`):void 0,env:e.env?ts(e.env,`--env`,`env`):void 0}}function ts(e,t,n){let r={};for(let i of e){let[e,...a]=i.split(`=`);if(!e||a.length===0)throw Error(`${t} expects ${n} values in KEY=VALUE format`);r[e]=a.join(`=`)}return r}function ns(e,t){if(!/^\d+$/.test(e))throw Error(`${t} must be a positive integer`);let n=Number.parseInt(e,10);if(Number.isNaN(n)||n<1)throw Error(`${t} must be a positive integer`);return n}function rs(e,t){if(!/^(?:\d+|\d+\.\d+|\.\d+)$/.test(e))throw Error(`${t} must be a positive number`);let n=Number.parseFloat(e);if(!Number.isFinite(n)||n<=0)throw Error(`${t} must be a positive number`);return n}function is(){return new x(`exec`).description(`Execute a command in a sandbox`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<command...>`,`Command and arguments, or one shell script`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`,`60000`).allowUnknownOption(!0).action(async(e,t,n)=>{try{let{context:r,client:i}=K(n),a=$o(t),o=ts(n.env??[],`--env`,`env`),s=z(`Executing: ${a}`);n.json||s.start();let c=await J(i,r,e);c=await Y(c);let l=await c.exec(a,{cwd:n.cwd,env:Object.keys(o).length>0?o:void 0,timeoutMs:Number.parseInt(n.timeout,10)});s.stop(),n.json?I(l):(l.stdout&&process.stdout.write(l.stdout),l.stderr&&process.stderr.write(l.stderr)),l.exitCode!==0&&(process.exitCode=l.exitCode)}catch(e){if(e instanceof i){let t=`Exec transport lost before command status was confirmed. Remote command status is unknown. Original error: ${e.message}. For long-running commands, use \`tangle process spawn\`, \`tangle process logs\`, and \`tangle process kill --tree\`.`;return U(Error(t,{cause:e}))}U(e)}})}function as(e){e.command(`capabilities`).description(`List fleet drivers and their supported features`).action(async e=>{let{client:t}=K(e),n=z(`Fetching capabilities...`);n.start();let r=await t.fleets.capabilities();n.stop(),e.json?I(r):F(r.drivers,[{key:`driverType`,header:`Driver`,width:16},{key:`sharedWorkspace`,header:`Shared WS`,width:12},{key:`accelerators`,header:`Accel`,width:8},{key:`queueTimings`,header:`Queue`,width:8}])}),e.command(`usage <fleet-id>`).description(`Show fleet usage and reliability insights`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Fetching usage...`);r.start();let i=await n.fleets.usage(e);if(r.stop(),t.json)I(i);else if(B({"Fleet ID":i.usage.fleetId,Status:i.usage.status,Machines:i.usage.machineCount,Running:i.usage.runningMachines,Failed:i.usage.failedMachines,"Runtime (ms)":i.usage.meteredUsage?.runtimeMs,"Reliability score":i.insights.reliabilityScore,"Failure rate":i.insights.failureRate}),i.insights.recommendedActions.length>0){console.log(`
146
- Recommended actions:`);for(let e of i.insights.recommendedActions)console.log(` - ${e}`)}}),e.command(`cost <fleet-id>`).description(`Show the fleet's cost estimate`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Estimating cost...`);r.start();let i=await n.fleets.cost(e);r.stop(),t.json?I(i):B({Plan:i.plan,Currency:i.currency,"Hourly (USD)":i.hourlyUsd,"Max lifetime (s)":i.maxLifetimeSeconds,"Estimated max lifetime (USD)":i.estimatedMaxLifetimeUsd,Machines:i.requestedResources.machines,"Total CPU":i.requestedResources.totalCpu,"Total memory (MB)":i.requestedResources.totalMemoryMb})})}function os(e){return[...e.entries()].map(([e,t])=>({machineId:e,sandboxId:t.id,status:t.status}))}function ss(e){e.command(`list <fleet-id>`).description(`List the machines of one fleet (fleet id is required)`).option(`--status <status>`,`Filter machines by status`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Fetching fleet...`);r.start();let i=await n.fleets.list({fleetId:e,status:t.status});r.stop();let a=os(i.machines);t.json?I({fleetId:i.fleetId,machines:a}):F(a,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}])}),e.command(`get <fleet-id>`).description(`Show one fleet's manifest (server record)`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Fetching manifest...`);r.start();let i=await n.fleets.manifest(e);r.stop(),t.json?I(i):(B({"Fleet ID":i.fleetId??i.id,Machines:i.machines.length,"Workspace mode":i.workspace?.mode,"Workspace status":i.workspace?.status,"Max lifetime (s)":i.policy?.maxLifetimeSeconds,"Max spend (USD)":i.policy?.maxSpendUsd,Created:i.createdAt,Updated:i.updatedAt}),F(i.machines,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`role`,header:`Role`,width:14},{key:`status`,header:`Status`,width:14}]))}),e.command(`delete <fleet-id>`).description(`Delete a fleet's machine sandboxes and its record`).option(`--continue-on-error`,`Keep deleting remaining machines if one delete fails`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Deleting fleet...`);r.start(),await n.fleets.delete(e,{continueOnError:t.continueOnError}),r.stop(),t.json?I({success:!0,fleetId:e}):L(`Fleet deleted: ${e}`)}),e.command(`reap`).description(`TTL cleanup of all expired fleets (fleet-wide)`).option(`--dry-run`,`Report what would be reaped without deleting`).action(async e=>{let{client:t}=K(e),n=z(`Reaping expired fleets...`);n.start();let r=await t.fleets.reapExpired({dryRun:e.dryRun});n.stop(),e.json?I(r):(B({"Dry run":r.dryRun,Expired:r.expired,Deleted:r.deleted}),F(r.fleets,[{key:`fleetId`,header:`Fleet`,width:24},{key:`expiredAt`,header:`Expired`,width:18},{key:`deleted`,header:`Deleted`,width:10}]))}),e.command(`reconcile`).description(`Drop fleet records whose underlying sandboxes vanished`).option(`--dry-run`,`Report orphans without removing them`).action(async e=>{let{client:t}=K(e),n=z(`Reconciling fleets...`);n.start();let r=await t.fleets.reconcile({dryRun:e.dryRun});n.stop(),e.json?I(r):(B({"Dry run":r.dryRun,Checked:r.checked,Orphaned:r.orphaned,Removed:r.removed}),F(r.machines,[{key:`fleetId`,header:`Fleet`,width:24},{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`removed`,header:`Removed`,width:10}]))})}async function cs(e,t){let n=await Lr({apiKey:t.apiKey,baseUrl:t.baseUrl??ur()}),r=await fetch(`${n.baseUrl}/v1/agent-profiles/${encodeURIComponent(e)}`,{headers:{authorization:`Bearer ${n.token}`,accept:`application/json`}});if(!r.ok){let t=await r.text().catch(()=>``);throw r.status===404?Error(`profile '${e}' not found in the platform catalog (it may be a built-in, a stored profile you own, or neither — run 'tangle profile list' to see what is available)`):Error(`platform returned ${r.status}: ${t.slice(0,200)}`)}let i=await r.json();if(!i.definition||typeof i.definition!=`object`)throw Error(`profile '${e}' resolved but has no definition — the catalog entry is malformed`);return i.definition}async function ls(e){let t=typeof e.envVarName==`string`&&e.envVarName.length>0?e.envVarName:null,n=!!e.fromStdin;if(t&&n)throw Error(`Pass either ${e.flagPrefix}-env or ${e.flagPrefix}-stdin, not both`);if(t){let n=process.env[t];if(!n||n.length===0)throw Error(`${e.flagPrefix}-env points at ${t}, but that environment variable is empty or unset`);return n}if(n){let t=await ti();if(t.length===0)throw Error(`${e.flagPrefix}-stdin received empty input on stdin`);return t}}function us(e){if(e.secret===void 0)return;let t=e.backend===`claude-code`?`token`:e.backend===`codex`?`bundle`:void 0;if(!t)throw Error(`--cli-auth needs --backend claude-code or --backend codex`);if(e.apiKeyGiven)throw Error(`--cli-auth cannot be combined with --backend-api-key-env or --backend-api-key-stdin`);return{account:`cli`,secretEnv:e.secret,format:t}}function ds(e){if(e!==void 0)return e.map(e=>{if(e.includes(`@`)||e.includes(`:`))throw Error(`--secret ${e}: bare secret names only (box delivery). For proxy custody use --proxy-secret with a canonical binding`);return e})}function fs(e,t){let n={};return e.cpu!==void 0&&(n.cpuCores=ns(e.cpu,`--cpu`)),e.memory!==void 0&&(n.memoryMB=ns(e.memory,`--memory`)),e.disk!==void 0&&(n.diskGB=ns(e.disk,`--disk`)),t&&(n.accelerator=t),Object.keys(n).length>0?n:void 0}function ps(e){let t=e.split(`/`);return t.length>=2?{provider:t[0],model:t.slice(1).join(`/`)}:{model:e}}function ms(e){let t={};for(let n of e){let[e,...r]=n.split(`=`);if(!e||r.length===0)throw Error(`--metadata expects values in KEY=VALUE or KEY=JSON format`);t[e]=hs(r.join(`=`))}return t}function hs(e){try{return JSON.parse(e)}catch{return e}}function gs(e,t){if(!(!e.gitUrl&&!e.gitRef&&!e.gitDepth&&!e.gitSparse&&!t)){if(!e.gitUrl||typeof e.gitUrl!=`string`)throw Error(`--git-url is required when using git provisioning options`);return{url:e.gitUrl,ref:typeof e.gitRef==`string`?e.gitRef:void 0,depth:typeof e.gitDepth==`string`?ns(e.gitDepth,`--git-depth`):void 0,sparse:Array.isArray(e.gitSparse)?e.gitSparse:void 0,auth:t?{token:t}:void 0}}}function _s(e,t){if(!(!e.storageType&&!e.storageBucket&&!e.storageEndpoint&&!e.storageRegion&&!e.storagePrefix&&!e.storageAccessKeyId&&!t)){if(typeof e.storageType!=`string`||typeof e.storageBucket!=`string`||typeof e.storageAccessKeyId!=`string`||!t)throw Error(`Storage config requires --storage-type, --storage-bucket, --storage-access-key-id, and one of --storage-secret-access-key-env / --storage-secret-access-key-stdin`);return{type:vs(e.storageType),bucket:e.storageBucket,endpoint:typeof e.storageEndpoint==`string`?e.storageEndpoint:void 0,region:typeof e.storageRegion==`string`?e.storageRegion:void 0,prefix:typeof e.storagePrefix==`string`?e.storagePrefix:void 0,credentials:{accessKeyId:e.storageAccessKeyId,secretAccessKey:t}}}}function vs(e){if(e===`s3`||e===`gcs`||e===`r2`)return e;throw Error(`--storage-type must be one of s3, gcs, or r2`)}function ys(e){if(e===void 0)return;let t=[];for(let n of e){let e=n,r=`--proxy-secret <json>`;if(n.startsWith(`@`)){let t=n.slice(1);r=`--proxy-secret @${t}`;try{e=k(t,`utf8`)}catch{throw Error(`${r}: file could not be read`)}}let i;try{i=JSON.parse(e)}catch(e){throw Error(`${r}: not valid JSON (${e instanceof Error?e.message:String(e)})`)}if(Array.isArray(i))t.push(...i);else if(typeof i==`object`&&i)t.push(i);else throw Error(`${r}: expected a binding object or an array of bindings`)}let n=T.parse(t);return n.length>0?n:void 0}function bs(e){R(` Status: ${e.status}`),R(` Provider: ${e.provider}`),R(` GPU: ${e.accelerator.kind} x ${e.accelerator.count}`),e.customerPricePerHourUsd!==void 0&&R(` Customer price: $${e.customerPricePerHourUsd}/hr`),e.estimatedCustomerCostUsd!==void 0&&R(` Max estimate: $${e.estimatedCustomerCostUsd}`),e.billing&&(R(` Billed seconds: ${e.billing.seconds}`),R(` Customer cost: $${e.billing.customerCostUsd}`))}function xs(e){e.result.stdout&&process.stdout.write(e.result.stdout),e.result.stderr&&process.stderr.write(e.result.stderr),R(`Exit code: ${e.result.exitCode}`)}function Ss(e){let t=e.command(`gpu`).description(`Manage on-demand GPU leases for a sandbox`);t.command(`providers <id-or-name>`).description(`List GPU clouds, whether each credential works, and current prices`).option(`--accelerator-kind <kind>`,`Price this GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Checking GPU providers...`);i.start();let a=await(await J(r,n,e)).gpu.providers(t.acceleratorKind?{accelerator:Xo({kind:t.acceleratorKind,count:t.acceleratorCount,memory:t.acceleratorMemory})}:{});if(i.stop(),t.json){I(a);return}F(a.statuses.map(e=>({provider:e.provider,state:e.state,gpu:e.estimate?.providerInstanceType??``,usdHr:e.estimate?e.estimate.customerPricePerHourUsd.toFixed(4):``,pricing:e.estimate?.pricingSource??``,needs:e.envVars.join(` `)})),[{key:`provider`,header:`Provider`},{key:`state`,header:`State`},{key:`gpu`,header:`GPU`},{key:`usdHr`,header:`$/hr`},{key:`pricing`,header:`Price`},{key:`needs`,header:`Needs`}]);for(let e of a.statuses){let t=e.state===`credential-invalid`?e.credential?.detail:e.estimateError;t&&R(`${e.provider}: ${t}`)}a.usable.length===0&&R(`No GPU provider is usable on this deployment: set the variables in Needs for one provider on the server.`)}),t.command(`attach <id-or-name>`).description(`Attach a temporary GPU worker to a sandbox`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).option(`--provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--image <image>`,`GPU worker image override`).option(`--env <vars...>`,`Environment variables for the GPU worker (KEY=VALUE)`).requiredOption(`--max-spend-usd <usd>`,`Maximum customer spend for this lease`).requiredOption(`--max-lifetime <seconds>`,`Maximum lease lifetime in seconds`).option(`--idle-timeout <seconds>`,`Destroy after this many idle seconds`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Attaching GPU lease...`);i.start();let a=await(await J(r,n,e)).gpu.attach(Qo(t));i.stop(),t.json?I(a):(L(`GPU lease attached: ${a.id}`),bs(a))}),t.command(`run <id-or-name> <command...>`).description(`Attach a GPU, run a command or script, then destroy it`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).option(`--provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--image <image>`,`GPU worker image override`).option(`--env <vars...>`,`Environment variables for the GPU worker and command (KEY=VALUE)`).requiredOption(`--max-spend-usd <usd>`,`Maximum customer spend for this lease`).requiredOption(`--max-lifetime <seconds>`,`Maximum lease lifetime in seconds`).option(`--idle-timeout <seconds>`,`Destroy after this many idle seconds`).option(`--timeout <ms>`,`Command timeout in milliseconds`).option(`--cwd <path>`,`Working directory`).action(async(e,t,n)=>{let r,i,a,o;try{let{context:a,client:o}=K(n),s=await J(o,a,e),c=z(`Attaching GPU lease...`);c.start(),r=await s.gpu.attach(Qo(n)),c.stop();let l=z(`Running GPU command...`);l.start(),i=await s.gpu.exec(r.id,{command:$o(t),...es(n),cwd:n.cwd}),l.stop(),n.json||xs(i)}catch(e){a=e}finally{if(r)try{let{context:t,client:i}=K(n);r=await(await J(i,t,e)).gpu.detach(r.id)}catch(e){o=e}}if(a){U(a),o&&U(o);return}if(o){U(o);return}n.json?I({lease:r,result:i}):r&&L(`GPU lease detached: ${r.id}`);let s=i?.result.exitCode;s&&s!==0&&(process.exitCode=s)}),t.command(`list <id-or-name>`).description(`List GPU leases attached to a sandbox`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching GPU leases...`);i.start();let a=await(await J(r,n,e)).gpu.list();i.stop(),t.json?I(a):a.length===0?R(`No GPU leases attached.`):F(a.map(e=>({id:e.id,status:e.status,provider:e.provider,accelerator:`${e.accelerator.kind}x${e.accelerator.count}`,customerUsdHr:e.customerPricePerHourUsd??``})),[{key:`id`,header:`ID`,width:28},{key:`status`,header:`Status`,width:12},{key:`provider`,header:`Provider`,width:12},{key:`accelerator`,header:`GPU`,width:24},{key:`customerUsdHr`,header:`$/hr`,width:10}])}),t.command(`exec <id-or-name> <lease-id> <command...>`).description(`Run a command or script on an attached GPU lease`).option(`--timeout <ms>`,`Command timeout in milliseconds`).option(`--cwd <path>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).action(async(e,t,n,r)=>{let{context:i,client:a}=K(r),o=z(`Running GPU command...`);o.start();let s=await(await J(a,i,e)).gpu.exec(t,{command:$o(n),...es(r),cwd:r.cwd});o.stop(),r.json?I(s):xs(s)}),t.command(`detach <id-or-name> <lease-id>`).description(`Detach and destroy a GPU lease`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Detaching GPU lease...`);a.start();let o=await(await J(i,r,e)).gpu.detach(t);a.stop(),n.json?I(o):(L(`GPU lease detached: ${o.id}`),bs(o))})}function Cs(e,t){if(t){I(e);return}if(!e.id){e.kind===`snapshot`&&e.result?.snapshot?L(`Snapshot created: ${e.result.snapshot.snapshotId}`):L(`Sandbox ${e.sandboxId} stopped.`);return}L(`${e.kind===`snapshot`?`Snapshot`:`Stop`} of sandbox ${e.sandboxId} accepted.`),R(`Operation: ${e.id}`),R(`Status: ${e.statusUrl}`)}function ws(e){return`${e.name} (${e.id})`}async function Ts(e,t){if(t.startsWith(`team_`))return e.teams.get(t);let n=(await e.teams.list()).filter(e=>e.name.toLowerCase()===t.toLowerCase());if(n.length===0)throw Error(`Team not found: ${t}`);if(n.length>1)throw Error(`Team name is ambiguous: ${t}. Use a team id instead.`);return n[0]}async function Es(e,t,n){if(t)return Ts(e,t);let r=pr(n);if(!r.activeTeamId)throw Error("No active team. Run `tangle team switch <team>` or pass `--team <team>`.");return e.teams.get(r.activeTeamId)}function Ds(e,t){mr({id:e.id,name:e.name},t)}function Os(e){hr(e)}async function ks(e){if(e.explicitTeam&&e.personal)throw Error(`--team and --personal cannot be used together`);if(!e.personal)return e.explicitTeam?(await Ts(e.client,e.explicitTeam)).id:e.activeTeamId}async function As(e){if([!!e.explicitTeam,!!e.personal,!!e.allScopes].filter(Boolean).length>1)throw Error(`--team, --personal, and --all-scopes are mutually exclusive`);if(e.allScopes)return`all`;if(e.personal)return`personal`;if(e.explicitTeam)return`team:${(await Ts(e.client,e.explicitTeam)).id}`;if(e.activeTeamId)return`team:${e.activeTeamId}`}function js(e){if(!e)return e;let t={...e};for(let e of[`authToken`,`execToken`])t[e]!==void 0&&(t[e]=`[REDACTED]`);return t}function Ms(e){e.command(`attestation <id-or-name>`).description(`Fetch TEE attestation evidence for a sandbox`).option(`--nonce <hex|auto>`,`Nonce to bind into a fresh attestation report; use auto to generate one`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=t.nonce===`auto`?g():t.nonce,a=z(`Fetching TEE attestation...`);a.start();let o=await(await J(r,n,e)).getTeeAttestation(i?{attestationNonce:i}:void 0);a.stop(),t.json?I(o):(L(`Attestation fetched for ${e}`),console.log(`TEE type: ${o.attestation.tee_type}`),console.log(`Evidence bytes: ${o.attestation.evidence.length}`),console.log(`Measurement bytes: ${o.attestation.measurement.length}`),console.log(`Timestamp: ${o.attestation.timestamp}`),o.attestationNonce&&console.log(`Nonce: ${o.attestationNonce}`))}),e.command(`list`).description(`List all sandboxes`).option(`-s, --status <status>`,`Filter by status (running, stopped, all)`).option(`-l, --limit <n>`,`Limit results`,`50`).option(`--team <team>`,`List sandboxes for a team by id or name`).option(`--personal`,`List personal sandboxes`).option(`--all-scopes`,`List personal and team sandboxes`).action(async e=>{let{context:t,client:n}=K(e),r=z(`Fetching sandboxes...`);r.start();let i=await As({client:n,explicitTeam:e.team,personal:e.personal,allScopes:e.allScopes,activeTeamId:t.activeTeamId}),a=await n.list({status:e.status===`all`?void 0:e.status,limit:Number.parseInt(e.limit,10),scope:i});r.stop(),e.json?I(a):F(a.map(e=>({id:e.id,status:e.status,createdAt:e.createdAt,name:e.name??``})),[{key:`id`,header:`ID`,width:24},{key:`status`,header:`Status`,width:14},{key:`createdAt`,header:`Created`,width:16},{key:`name`,header:`Name`,width:20}])}),e.command(`get <id-or-name>`).description(`Get sandbox details`).option(`--profile`,`Show the active agent profile provenance (name, hash, skills)`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching sandbox...`);i.start();let a=await J(r,n,e);if(i.stop(),t.profile){let e=a.getProfileProvenance?.();e?(R(`Agent profile provenance:`),R(` Base profile: ${e.base.name??`(inline)`} (${e.base.sha256.slice(0,12)}...)`),R(` Effective: ${e.effective.name??`(inline)`} (${e.effective.sha256.slice(0,12)}...)`),R(` Materialized: ${e.materializedAt}`),e.base.sha256!==e.effective.sha256&&R(` ⚠ Profile changed since creation (base ≠ effective)`)):R(`No profile materialized (bare sandbox). Create with --profile <name> to install one.`);return}t.json?I(a):zt({id:a.id,name:a.name,status:a.status,resources:a.resources,createdAt:a.createdAt?.toISOString(),expiresAt:a.expiresAt?.toISOString(),connection:a.connection})}),e.command(`shapes`).description(`List the named sandbox sizes, the default, and this account's ceiling`).action(async e=>{let{client:t}=K(e),n=await t.shapes();if(e.json){I(n);return}let r=e=>e.cpuCores<=n.ceiling.cpuCores&&e.memoryMB<=n.ceiling.memoryMB&&e.diskGB<=n.ceiling.diskGB;F(n.presets.map(e=>({name:e.name===n.default?`${e.name} (default)`:e.name,cpu:e.cpuCores,memory:`${e.memoryMB} MB`,disk:`${e.diskGB} GB`,available:r(e)?`yes`:e.name===n.default?`clamped to ceiling`:`above ceiling`})),[{key:`name`,header:`Shape`,width:18},{key:`cpu`,header:`vCPU`,width:6},{key:`memory`,header:`Memory`,width:10},{key:`disk`,header:`Disk`,width:8},{key:`available`,header:`Available`,width:14}]),R(`Ceiling for this account: ${Rt(n.ceiling)}`)}),e.command(`delete <id-or-name>`).description(`Delete a sandbox`).option(`-f, --force`,`Skip confirmation`).option(`--name`,`Treat the reference as a sandbox name`).option(`--retry-cleanup`,`Retry server-side cleanup after the sandbox disappeared from get/list`).action(async(e,t)=>{if(!t.force&&!await $r(`Delete sandbox ${e}? [y/N] `,`--force`)){R(`Cancelled.`);return}let{context:n,client:r}=K(t),i=z(`Deleting sandbox...`);i.start();let a=await Kr(r,n,e,{retryCleanup:t.retryCleanup,name:t.name});i.stop(),L(a===`already_absent`?`Sandbox ${e} was already gone.`:`Sandbox ${e} deleted.`)}),e.command(`stop <id-or-name>`).description(`Stop a running sandbox`).option(`--name`,`Treat the reference as a sandbox name`).option(`--no-wait`,`Return once the stop is accepted and print the operation to poll`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Stopping sandbox...`);i.start();let a=await J(r,n,e,{nameOnly:t.name});if(t.wait===!1){let e=await a.stop({wait:!1});i.stop(),Cs(e.info,!!t.json);return}await a.stop(),i.stop(),L(`Sandbox ${e} stopped.`)}),e.command(`resume <id-or-name>`).description(`Resume a stopped sandbox`).option(`--wait`,`Wait for sandbox to be running`,!0).option(`-t, --timeout <ms>`,`Resume timeout in milliseconds; a cold resume re-provisions the sandbox, so this defaults higher than other commands (default 120000)`,`120000`).action(async(e,t)=>{let n=Number.parseInt(t.timeout,10);if(!Number.isFinite(n)||n<=0)throw Error(`--timeout must be a positive number of milliseconds`);let r=W({apiKey:t.apiKey,baseUrl:t.baseUrl,timeout:n}),i=G(r),a=z(`Resuming sandbox...`);a.start();let o=await J(i,r,e);await o.resume({timeoutMs:n}),t.wait&&(a.text=`Waiting for sandbox to start...`,await o.waitFor(`running`,{timeoutMs:n})),a.stop(),L(`Sandbox ${o.id} resumed.`)})}function Ns(e){e.command(`create`).description(`Create a new sandbox`).option(`-n, --name <name>`,`Sandbox name`).option(`-e, --environment <environment>`,Ps).addOption(Fs()).option(`--bare`,`Create a bare sandbox without the agent runtime`).option(`--ssh`,`Enable SSH access`).option(`--ssh-key <key>`,`SSH public key for authentication`).option(`--ssh-keys <names...>`,`Stored SSH key names or IDs for authentication`).option(`--ssh-key-file <paths...>`,`SSH public key file paths for authentication`).option(`--web-terminal`,`Enable web terminal`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`--secret <names...>`,`Secrets selected by bare name for box delivery (value in the sandbox env). For proxy custody use --proxy-secret`).option(`--proxy-secret <bindings...>`,`Canonical proxy custody binding(s): one binding as inline JSON, or @file with a JSON array. The value stays at the egress proxy and is redeemed only within the binding's scope (hosts/methods/paths/TTL); the box reads a placeholder. Repeatable`).option(`--metadata <entries...>`,`Metadata entries (KEY=VALUE or KEY=JSON)`).option(`--cpu <cores>`,"CPU cores (omit for the platform default; see `sandbox shapes`)").option(`--memory <mb>`,`Memory in MB (omit for the platform default)`).option(`--disk <gb>`,`Disk size in GB (omit for the platform default)`).option(`--accelerator-kind <kind>`,`Accelerator kind, for example nvidia-h100 or amd-mi300x`).option(`--accelerator-count <count>`,`Accelerator device count`,`1`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).option(`--gpu-provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--gpu-worker-image <image>`,`GPU worker image override`).option(`--gpu-env <vars...>`,`Environment variables for the GPU worker (KEY=VALUE)`).option(`--gpu-max-spend-usd <usd>`,`Maximum customer spend for the create-time GPU lease`).option(`--gpu-max-lifetime <seconds>`,`Maximum create-time GPU lease lifetime in seconds`).option(`--gpu-idle-timeout <seconds>`,`Destroy the create-time GPU lease after this many idle seconds`).option(`--lifetime <seconds>`,`Max wall-clock lifetime before the sandbox is suspended — stopped, not deleted; resume it within the cold window (default 3600 = 1h). Raise it for long sessions, e.g. --lifetime 7200`,`3600`).option(`--idle-timeout <seconds>`,"Idle time before the sandbox is stopped — not deleted (default 900 = 15m). Resume it later with `tangle sandbox resume <id-or-name>`, or it auto-resumes on next use. Raise it for demos, e.g. --idle-timeout 3600",`900`).option(`--from-snapshot <id>`,`Create the sandbox from a snapshot`).option(`--public-template <id-or-slug>`,`Create the sandbox from a published public template`).option(`--public-template-version <id>`,`Pin creation to a specific published public-template version`).option(`--billing-owner <userId>`,`Platform user that pays for the sandbox. The API accepts this only from a first-party service key that is listed as a billing delegate, and refuses such a key that names no payer.`).option(`--team <team>`,`Create in a team by id or name`).option(`--personal`,`Create a personal sandbox even when a team is active`).option(`--git-url <url>`,`Git repository URL to clone during provisioning`).option(`--git-ref <ref>`,`Git branch, tag, or commit to checkout`).option(`--git-depth <depth>`,`Git clone depth`).option(`--git-sparse <paths...>`,`Sparse checkout paths`).option(`--git-token-env <name>`,`Name of an environment variable containing the Git HTTPS auth token`).option(`--git-token-stdin`,`Read the Git HTTPS auth token from stdin`).option(`--storage-type <type>`,`BYOS3 storage type (s3, gcs, r2)`).option(`--storage-bucket <name>`,`BYOS3 bucket name`).option(`--storage-endpoint <url>`,`BYOS3 endpoint URL`).option(`--storage-region <region>`,`BYOS3 region`).option(`--storage-prefix <prefix>`,`BYOS3 path prefix`).option(`--storage-access-key-id <id>`,`BYOS3 access key ID`).option(`--storage-secret-access-key-env <name>`,`Name of an environment variable containing the BYOS3 secret access key`).option(`--storage-secret-access-key-stdin`,`Read the BYOS3 secret access key from stdin`).addOption(new S(`--driver <type>`,`Run on Tangle network operators instead of the platform's hosts (--tee needs it)`).choices([`tangle`])).option(`--backend <type>`,`Backend agent type (${n.join(`, `)})`).option(`--backend-model <model>`,`Model override (format: provider/model)`).addOption(new S(`--reasoning-effort <level>`,`Reasoning effort for the backend's model; overrides the profile's model.reasoningEffort`).choices(E)).option(`--backend-api-key-env <name>`,`Name of an environment variable containing the BYOK backend API key`).option(`--backend-api-key-stdin`,`Read the BYOK backend API key from stdin`).option(`--cli-auth <secret>`,"Run --backend claude-code or codex on your own subscription: the stored secret holding a `claude setup-token` token or a Codex auth.json (see `tangle secret create`)").option(`--profile <path>`,`Path to an AgentProfile JSON file to install as the sandbox's backend profile (carries skills, tools, MCP, model). Use with --backend; the profile's inline skills materialize into the harness's native skill directory on first turn`).option(`--profile-stdin`,`Read the AgentProfile JSON from stdin instead of a file (use with --profile)`).option(`--tee <type>`,`Require a TEE backend (any, tdx, nitro, sev-snp, phala-dstack)`).option(`--sealed`,`Request TEE sealed-secret support`).option(`--attestation-nonce <hex|auto>`,`Deploy-time attestation nonce; use auto to generate one`).option(`--attestation-refresh`,`Generate a fresh deploy-time attestation nonce when --tee is set`).option(`--require-attestation`,`Fail unless TEE attestation evidence is returned`).option(`--wait`,`Wait for sandbox to be running`,!0).option(`--timeout <ms>`,`HTTP timeout in milliseconds`,`30000`).action(async e=>{let t=await ls({envVarName:e.gitTokenEnv,fromStdin:e.gitTokenStdin,flagPrefix:`--git-token`}),n=await ls({envVarName:e.storageSecretAccessKeyEnv,fromStdin:e.storageSecretAccessKeyStdin,flagPrefix:`--storage-secret-access-key`}),r=await ls({envVarName:e.backendApiKeyEnv,fromStdin:e.backendApiKeyStdin,flagPrefix:`--backend-api-key`}),i=us({secret:e.cliAuth,backend:e.backend,apiKeyGiven:r!==void 0}),a;if(e.profileStdin){let e=await ti(`--profile-stdin`,`the AgentProfile JSON`);try{a=JSON.parse(e)}catch{U(Error(`--profile-stdin: the input is not valid JSON`));return}}else if(e.profile){let t=String(e.profile);if(t.startsWith(`.`)||t.startsWith(`/`)||t.endsWith(`.json`))try{a=JSON.parse(k(t,`utf8`))}catch(e){U(Error(`--profile ${t}: ${e.message}`));return}else try{a=await cs(t,e)}catch(e){U(Error(`--profile ${t}: ${e.message}`));return}}a=Ls(a,e.reasoningEffort);let o=W({apiKey:e.apiKey,baseUrl:e.baseUrl,timeout:e.timeout?Number.parseInt(e.timeout,10):void 0}),s=G(o),c=z(`Creating sandbox...`);c.start();let l=await ks({client:s,explicitTeam:e.team,personal:e.personal,activeTeamId:o.activeTeamId}),u=ts(e.env??[],`--env`,`env`),d=e.metadata?ms(e.metadata):void 0,f=gs(e,t),p=_s(e,n),m=e.acceleratorKind?Xo({kind:String(e.acceleratorKind),count:String(e.acceleratorCount),memory:typeof e.acceleratorMemory==`string`?e.acceleratorMemory:void 0}):void 0,g=Zo({provider:typeof e.gpuProvider==`string`?e.gpuProvider:void 0,image:typeof e.gpuWorkerImage==`string`?e.gpuWorkerImage:void 0,env:Array.isArray(e.gpuEnv)?e.gpuEnv:void 0,maxSpendUsd:typeof e.gpuMaxSpendUsd==`string`?e.gpuMaxSpendUsd:void 0,maxLifetime:typeof e.gpuMaxLifetime==`string`?e.gpuMaxLifetime:void 0,idleTimeout:typeof e.gpuIdleTimeout==`string`?e.gpuIdleTimeout:void 0},!!m,`Create-time GPU lease flags require --accelerator-kind`),v=e.driver?{type:`tangle`}:void 0,y=e.backend||e.backendModel||a?{...e.backend?{type:_(e.backend)}:{},...a?{profile:a}:{},model:e.backendModel||r||i?{...e.backendModel?ps(e.backendModel):{},apiKey:r,...i?{cliAuth:i}:{}}:void 0}:void 0,b=ds(e.secret),ee=i?[...new Set([...b??[],i.secretEnv])]:b,x=ys(e.proxySecret),S=fs(e,m),C=e.sshKeyFile??(e.ssh&&!e.sshKey&&!e.sshKeys?.length?[Is()]:[]),te=[...e.sshKey?[e.sshKey]:[],...C.map(e=>k(e,`utf8`).trim())],w={name:e.name,environment:e.environment,runtime:e.runtime,bare:e.bare||void 0,sshEnabled:e.ssh||!!e.sshKey||te.length>0||!!e.sshKeys?.length,sshPublicKeys:te.length>0?te:void 0,sshKeyIds:e.sshKeys,webTerminalEnabled:e.webTerminal,env:Object.keys(u).length>0?u:void 0,git:f,...S?{resources:S}:{},gpuLease:g,maxLifetimeSeconds:Number.parseInt(e.lifetime,10),idleTimeoutSeconds:Number.parseInt(e.idleTimeout,10),storage:p,fromSnapshot:e.fromSnapshot,publicTemplateId:e.publicTemplate,publicTemplateVersionId:e.publicTemplateVersion,teamId:l,...e.billingOwner?{billingOwnerId:e.billingOwner}:{},secrets:ee,...x?{proxySecrets:x}:{},metadata:d,driver:v,backend:y},T=e.tee?{tee:e.tee,sealed:e.sealed||void 0,attestationRefresh:e.attestationRefresh||e.attestationNonce===`auto`||void 0}:void 0,E=T?await h(s,{...w,confidential:T,attestationNonce:e.attestationNonce??(e.attestationRefresh?`auto`:void 0),requireAttestation:e.requireAttestation??!0}):void 0,D=E?.sandbox??await s.create(w);e.wait&&(c.text=`Waiting for sandbox to start...`,await D.waitFor(`running`,{timeoutMs:12e4}),await D.refresh()),c.stop(),e.json?I({id:D.id,name:D.name,status:D.status,resources:D.resources,createdAt:D.createdAt,expiresAt:D.expiresAt,connection:js(D.connection),teamId:l,gpuLease:D.gpuLease,confidential:T,attestation:E?.attestation,attestationNonce:E?.attestationNonce}):(L(`Sandbox created: ${D.id}`),zt({id:D.id,name:D.name,status:D.status,resources:D.resources,createdAt:D.createdAt?.toISOString(),expiresAt:D.expiresAt?.toISOString(),connection:D.connection}),l&&console.log(`Team: ${l}`),D.gpuLease&&(console.log(`GPU lease: ${D.gpuLease.id}`),bs(D.gpuLease)),T&&(console.log(`TEE: ${T.tee}`),console.log(`Attestation: ${E?.attestation?`present`:`not returned`}`),E?.attestationNonce&&console.log(`Attestation nonce: ${E.attestationNonce}`)))})}const Ps="A catalog environment, a container image reference, or a built image ID. Firecracker runs only images pinned by repository@sha256 that the cell's Firecracker hosts carry; `environments list` shows each image's runtimes";function Fs(){return new S(`--runtime <runtime>`,`Isolation on the platform's hosts: docker runs a container on the host kernel, firecracker a microVM with its own kernel. Omit for the platform default`).choices(c)}function Is(){let e=[`id_ed25519`,`id_ecdsa`,`id_rsa`].map(e=>`${M()}/.ssh/${e}.pub`),t=e.find(e=>le(e));if(!t)throw Error(`--ssh needs a public key and found none at ${e.join(`, `)}. Run ssh-keygen -t ed25519, or pass --ssh-key-file.`);return t}function Ls(e,t){if(!t)return e;let n=e?.model??{};return{...e,model:{...n,reasoningEffort:t}}}function Rs(e){if(e.spec){let t=JSON.parse(k(e.spec,`utf8`));return{base:{fleetId:e.fleetId,defaults:t.defaults,policy:t.policy,workspace:t.workspace,metadata:t.metadata},machines:t.machines??[]}}let t=Vs(e),n=Hs(e,!!t?.accelerator),r={...e.environment?{environment:e.environment}:{},...t?{resources:t}:{},...e.runtime?{runtime:e.runtime}:{},...n?{gpuLease:n}:{},...e.backend?{backend:{type:e.backend}}:{}},i=Us(e),a=Math.max(1,Number(e.count)||1),o=Array.from({length:a},(e,t)=>({machineId:`worker-${t+1}`}));return{base:{fleetId:e.fleetId,defaults:Object.keys(r).length>0?r:void 0,policy:i,workspace:{mode:e.workspace}},machines:o}}function zs(e){let{base:t,machines:n}=Rs(e);return{...t,machines:n}}function Bs(e){let{base:t,machines:n}=Rs(e);return{...t,workers:n}}function Vs(e){let t={};if(e.cpu&&(t.cpuCores=Number(e.cpu)),e.memory&&(t.memoryMB=Number(e.memory)),e.disk&&(t.diskGB=Number(e.disk)),e.acceleratorKind)t.accelerator=Xo({kind:e.acceleratorKind,count:e.acceleratorCount,memory:e.acceleratorMemory});else if(e.acceleratorCount||e.acceleratorMemory)throw Error(`--accelerator-count and --accelerator-memory require --accelerator-kind`);return Object.keys(t).length>0?t:void 0}function Hs(e,t){return Zo({provider:e.gpuProvider,image:e.gpuWorkerImage,env:e.gpuEnv,maxSpendUsd:e.gpuMaxSpendUsd,maxLifetime:e.gpuMaxLifetime,idleTimeout:e.gpuIdleTimeout},t,`Fleet GPU lease flags require --accelerator-kind`)}function Us(e){let t={};return e.maxSpendUsd&&(t.maxSpendUsd=Number(e.maxSpendUsd)),e.maxLifetime&&(t.maxLifetimeSeconds=Number(e.maxLifetime)),Object.keys(t).length>0?t:void 0}function Ws(e){e.command(`create`).description(`Create a sandbox fleet`).option(`--fleet-id <id>`,`Stable fleet id (generated when omitted)`).option(`--count <n>`,`Number of worker machines`,`1`).option(`--environment <environment>`,Ps).addOption(Fs()).option(`--cpu <cores>`,`CPU cores per machine`).option(`--memory <mb>`,`Memory in MB per machine`).option(`--disk <gb>`,`Disk in GB per machine`).option(`--accelerator-kind <kind>`,`Accelerator kind per machine, for example nvidia-l4 or nvidia-h100`).option(`--accelerator-count <count>`,`Accelerator devices per machine`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).option(`--gpu-provider <provider>`,`GPU cloud provider per machine; omitted picks the cheapest configured provider`).option(`--gpu-worker-image <image>`,`GPU worker image override`).option(`--gpu-env <vars...>`,`Environment variables for each GPU worker (KEY=VALUE)`).option(`--gpu-max-spend-usd <usd>`,`Maximum spend per machine GPU lease`).option(`--gpu-max-lifetime <seconds>`,`Maximum GPU lease lifetime per machine in seconds`).option(`--gpu-idle-timeout <seconds>`,`Destroy each GPU lease after this many idle seconds`).option(`--backend <id>`,`Agent backend type`).option(`--workspace <mode>`,`Workspace mode: isolated (no driver supports shared yet)`,`isolated`).option(`--max-spend-usd <n>`,`Fleet spend cap in USD (policy)`).option(`--max-lifetime <s>`,`Max machine lifetime in seconds (policy)`).option(`--spec <file.json>`,`Path to a JSON file describing the fleet (overrides synthesized machines)`).option(`--coordinator`,`Create a coordinator + workers fleet (routes to createWithCoordinator)`).action(async e=>{let{client:t}=K(e),n=z(`Creating fleet...`);n.start();let r=e.coordinator?await t.fleets.createWithCoordinator(Bs(e)):await t.fleets.create(zs(e));n.stop();let i=os(r.machines);e.json?I({fleetId:r.fleetId,machines:i}):(L(`Fleet created: ${r.fleetId}`),F(i,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}]))})}function Gs(e){e.command(`exec <fleet-id> <command>`).description(`Run a shell command across the fleet's machines`).option(`--machine <id...>`,`Restrict to a subset of machine ids (default: all)`).option(`--cwd <dir>`,`Working directory for the command`).option(`--timeout <ms>`,`Per-machine timeout in milliseconds`).option(`--max-concurrent <n>`,`Max concurrent dispatches`).action(async(e,t,n)=>{let{client:r}=K(n),i=z(`Dispatching command...`);i.start();let a=await(await r.fleets.list({fleetId:e})).dispatchExecDetailed(t,{machines:n.machine,cwd:n.cwd,timeoutMs:n.timeout?Number(n.timeout):void 0,maxConcurrent:n.maxConcurrent?Number(n.maxConcurrent):void 0});if(i.stop(),n.json)I(a);else{F(a.results.map(e=>({machineId:e.machineId,ok:e.ok,exitCode:e.result?.exitCode,durationMs:e.durationMs})),[{key:`machineId`,header:`Machine`,width:20},{key:`ok`,header:`OK`,width:6},{key:`exitCode`,header:`Exit`,width:8},{key:`durationMs`,header:`Duration(ms)`,width:14}]);for(let e of a.results){let t=e.result?.stdout,n=e.result?.stderr;t&&(console.log(`\n[${e.machineId}] stdout:`),console.log(t)),n&&(console.log(`\n[${e.machineId}] stderr:`),console.log(n)),e.error&&console.log(`\n[${e.machineId}] error: ${e.error.message}`)}}a.results.some(e=>e.ok===!1)&&(process.exitCode=1)}),e.command(`run [prompt]`).description(`Create a fleet of agents, run one turn on every agent, print each result, then delete the fleet`).requiredOption(`--agents <n|file>`,`Number of agents, or a JSON file with an array of agent specs (agentId, harness, model, profile or { profileId, revision }, task)`).option(`--placement <mode>`,`auto (pack by sandbox memory), dedicated (one sandbox per agent), or a number of agents per sandbox`,`auto`).option(`--model <id>`,`Model every agent runs, e.g. gpt-4.1-mini`).option(`--memory <mb>`,`Memory in MB per sandbox; auto placement packs by it`).option(`--environment <environment>`,`Environment for each sandbox`).option(`--max-spend-usd <usd>`,`Budget for the fleet in USD, enforced by the Platform on the fleet's own key`).option(`--timeout <ms>`,`Per-agent turn timeout in milliseconds`).option(`--fleet-id <id>`,`Stable fleet id (generated when omitted)`).option(`--parent-fleet <id>`,`Fleet that spawns this one; its cap must cover this cap`).option(`--parent-agent <id>`,`Agent of --parent-fleet that spawns this one`).option(`--keep`,`Keep the fleet after the run instead of deleting it`).action(async(e,t)=>{let n=/^\d+$/.test(t.agents)?Number(t.agents):JSON.parse(k(t.agents,`utf8`));if(!Array.isArray(n)&&e===void 0)throw Error(`A prompt is required unless --agents names a file whose agents carry tasks`);let{client:r}=K(t);if(!!t.parentFleet!=!!t.parentAgent)throw Error(`--parent-fleet and --parent-agent go together`);let i=t.placement===`auto`||t.placement===`dedicated`?t.placement:{agentsPerSandbox:Number(t.placement)},a=t.maxSpendUsd?Number(t.maxSpendUsd):void 0,o=z(`Creating fleet...`);o.start();let s=Date.now(),c=await r.fleets.create({fleetId:t.fleetId,agents:n,placement:i,defaults:{...t.environment?{environment:t.environment}:{},...t.memory?{resources:{memoryMB:Number(t.memory)}}:{},...t.model?{backend:{type:`opencode`,model:{model:t.model}}}:{}},...a===void 0?{}:{budgetUsd:a},...t.parentFleet?{parent:{fleetId:t.parentFleet,agentId:t.parentAgent}}:{}}),l=Date.now()-s;o.stop(),t.json||L(`Fleet ${c.fleetId}: ${c.agents.length} agents on ${c.machines.size} sandboxes in ${l} ms`);let u=[],d;try{for await(let n of c.run(e,{timeoutMs:t.timeout?Number(t.timeout):void 0})){if(n.type===`agent.finished`&&!t.json){let e=n.result;console.log(`[${e.agentId}] ${e.harness??`default`}/${e.model??`default`} ${e.status} ${e.durationMs}ms ${e.costUsd===void 0?`no cost reported`:`$${e.costUsd.toFixed(5)}`} ${e.result?.response??e.error??``}`)}n.type===`fleet.finished`&&(u=n.results,d=n.spend)}}finally{t.keep||await c.delete({continueOnError:!0})}t.json?I({fleetId:c.fleetId,createMs:l,sandboxes:c.machines.size,results:u,spend:d,deleted:!t.keep}):B({fleetId:c.fleetId,completed:u.filter(e=>e.status===`completed`).length,agents:u.length,spend:JSON.stringify(d),deleted:!t.keep}),u.some(e=>e.status!==`completed`)&&(process.exitCode=1)}),e.command(`cancel <fleet-id>`).description(`Interrupt every agent of a fleet and cancel its child fleets; sandboxes keep running`).action(async(e,t)=>{let{client:n}=K(t),r=await(await n.fleets.list({fleetId:e})).cancel();t.json?I({fleetId:e,...r}):L(`Fleet ${e}: interrupted ${r.interrupted} agents, cancelled ${r.children} child fleets`)})}const Ks=[`list`,`create`,`delete`,`exec`,`prompt`,`read`,`write`];function qs(e){if(!(!e||e.length===0)){for(let t of e)if(!Ks.includes(t))throw Error(`Invalid token action '${t}'. Allowed: ${Ks.join(`, `)}`);return e}}function Js(e){return e.length<=12?`****`:`${e.slice(0,6)}...${e.slice(-4)} (masked — use --json for full value)`}function Ys(e){e.command(`token <fleet-id>`).description(`Mint a scoped fleet bearer token (treated as a secret)`).option(`--action <a...>`,`Allowed actions: list create delete exec prompt read write (prompt grants nothing since fleet prompt dispatch was removed)`).option(`--ttl-minutes <n>`,`Token lifetime in minutes`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Minting fleet token...`);r.start();let i=await n.fleets.createToken(e,{actions:qs(t.action),ttlMinutes:t.ttlMinutes?Number(t.ttlMinutes):void 0});r.stop(),t.json?I(i):(B({"Fleet ID":i.fleetId,Token:Js(i.token),"Expires at":new Date(i.expiresAt).toISOString(),Actions:i.actions.join(`, `)}),console.log(`
147
- Re-run with --json to print the full token value.`))})}function Xs(){let e=new x(`workspace`).description(`Manage a fleet's shared workspace`);return e.command(`snapshot <fleet-id>`).description(`Snapshot the fleet's shared workspace`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Creating workspace snapshot...`);r.start();let i=await n.fleets.createWorkspaceSnapshot(e);r.stop(),t.json?I(i):L(`Workspace snapshot created: ${i.snapshotId??i.id}`)}),e.command(`restore <fleet-id> <snapshot-id>`).description(`Restore the fleet's shared workspace from a snapshot`).action(async(e,t,n)=>{let{client:r}=K(n),i=z(`Restoring workspace...`);i.start();let a=await r.fleets.restoreWorkspaceSnapshot(e,t);i.stop(),n.json?I(a):L(`Workspace restored from ${a.snapshotId??t}`)}),e.command(`reconcile <fleet-id>`).description(`Re-mount the shared workspace on all fleet machines`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Reconciling workspace...`);r.start();let i=await n.fleets.reconcileWorkspace(e);r.stop(),t.json?I(i):(B({"Fleet ID":i.fleetId,Checked:i.checked,"Orphaned mounts":i.orphanedMounts}),F(i.machines,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`mounted`,header:`Mounted`,width:10}]))}),e}function Zs(){let e=new x(`fleet`).description(`Manage sandbox fleets`);return Ws(e),ss(e),e.addCommand(Xs()),Gs(e),as(e),Ys(e),e}function Qs(){let e=new x(`fs`).description(`File system operations on sandboxes`);return e.command(`upload`).description(`Upload a file to a sandbox`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<local-path>`,`Local file path`).argument(`<remote-path>`,`Remote destination path`).action(async(e,t,n,r)=>{let{context:i,client:a}=K(r),o=await J(a,i,e);if(o=await Y(o),!O.existsSync(t))throw Error(`Local file not found: ${t}`);let s=O.statSync(t),c=Date.now();r.json||console.error(`Uploading ${t} to ${n}...`),await o.fs.upload(t,n,{onProgress:e=>{if(r.json)return;let t=e.percentage.toFixed(1);process.stderr.write(`\rProgress: ${t}% (${e.bytesUploaded}/${e.totalBytes} bytes)`)}});let l=Date.now()-c;r.json||console.error(``),r.json?I({success:!0,localPath:t,remotePath:n,size:s.size,durationMs:l}):console.log(`✓ Uploaded ${s.size} bytes in ${l}ms`)}),e.command(`download`).description(`Download a file from a sandbox`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<remote-path>`,`Remote file path`).argument(`<local-path>`,`Local destination path`).action(async(e,t,n,r)=>{let{context:i,client:a}=K(r),o=await J(a,i,e);o=await Y(o);let s=Date.now();r.json||console.error(`Downloading ${t} to ${n}...`),await o.fs.download(t,n,{onProgress:e=>{if(r.json)return;let t=e.percentage.toFixed(1);process.stderr.write(`\rProgress: ${t}% (${e.bytesDownloaded}/${e.totalBytes} bytes)`)}});let c=Date.now()-s,l=O.statSync(n);r.json||console.error(``),r.json?I({success:!0,remotePath:t,localPath:n,size:l.size,durationMs:c}):console.log(`✓ Downloaded ${l.size} bytes in ${c}ms`)}),e.command(`ls`).description(`List directory contents`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`[path]`,`Directory path`,`.`).option(`-l, --long`,`Show detailed information`).option(`-a, --all`,`Include hidden files`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a);let o=await a.fs.list(t,{all:n.all,long:n.long});if(n.json)I(o);else if(n.long)Bt([`Mode`,`Owner`,`Group`,`Size`,`Modified`,`Name`],o.map(e=>{let t=e.isDir?`d`:e.isSymlink?`l`:`-`,n=$s(e.permissions),r=e.isDir?`<DIR>`:ec(e.size),i=e.modTime.toLocaleDateString();return[t+n,e.owner,e.group,r,i,e.name]}));else{let e=o.map(e=>e.isDir?`${e.name}/`:e.name);console.log(e.join(` `))}}),e.command(`stat`).description(`Get file or directory information`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to file or directory`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a);let o=await a.fs.stat(t);n.json?I(o):(console.log(` File: ${o.name}`),console.log(` Path: ${o.path}`),console.log(` Size: ${ec(o.size)} (${o.size} bytes)`),console.log(` Type: ${o.isDir?`directory`:o.isSymlink?`symlink`:`file`}`),console.log(` Mode: ${$s(o.permissions)} (${o.permissions.toString(8)})`),console.log(` Owner: ${o.owner}`),console.log(` Group: ${o.group}`),console.log(` Modified: ${o.modTime.toISOString()}`),console.log(` Accessed: ${o.accessTime.toISOString()}`))}),e.command(`cat`).description(`Print file contents`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to file`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a);let o=await a.read(t);n.json?I({path:t,content:o}):console.log(o)}),e.command(`rm`).description(`Delete a file or directory`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to delete`).option(`-r, --recursive`,`Delete directories recursively`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a),await a.fs.delete(t,{recursive:n.recursive}),n.json?I({success:!0,path:t,deleted:!0}):console.log(`✓ Deleted: ${t}`)}),e.command(`mkdir`).description(`Create a directory`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Directory path to create`).option(`-p, --parents`,`Create parent directories as needed`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a),await a.fs.mkdir(t,{recursive:n.parents}),n.json?I({success:!0,path:t,created:!0}):console.log(`✓ Created: ${t}`)}),e.command(`exists`).description(`Check if a path exists`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to check`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a);let o=await a.fs.exists(t);n.json?I({path:t,exists:o}):(console.log(o?`exists`:`not found`),process.exit(+!o))}),e}function $s(e){let t=[`r`,`w`,`x`],n=``;for(let r=2;r>=0;r--){let i=r*3;for(let r=0;r<3;r++)n+=e>>i+(2-r)&1?t[r]:`-`}return n}function ec(e){let t=[`B`,`KB`,`MB`,`GB`,`TB`],n=e,r=0;for(;n>=1024&&r<t.length-1;)n/=1024,r++;return r===0?`${n}${t[r]}`:`${n.toFixed(1)}${t[r]}`}function tc(){let e=new x(`git`).description(`Git operations in a sandbox workspace`);return e.command(`status`).description(`Show git repository status`).argument(`<id-or-name>`,`Sandbox ID or name`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching status...`);t.json||i.start();let a=await J(r,n,e);a=await Y(a);let o=await a.git.status();if(i.stop(),t.json)I(o);else if(!o.isRepo)console.log(`No git repository in the sandbox workspace.`);else{if(console.log(`Branch: ${o.branch??`unknown`}`),console.log(`HEAD: ${o.head.slice(0,7)||`(no commits)`}`),console.log(`Dirty: ${o.isDirty?`yes`:`no`}`),o.ahead&&console.log(`Ahead: ${o.ahead}`),o.behind&&console.log(`Behind: ${o.behind}`),o.staged.length>0){console.log(`\nStaged (${o.staged.length}):`);for(let e of o.staged)console.log(` + ${e}`)}if(o.modified.length>0){console.log(`\nModified (${o.modified.length}):`);for(let e of o.modified)console.log(` M ${e}`)}if(o.untracked.length>0){console.log(`\nUntracked (${o.untracked.length}):`);for(let e of o.untracked)console.log(` ? ${e}`)}}}),e.command(`log`).description(`Show commit log`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`-n, --limit <count>`,`Max commits to show`,`10`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching log...`);t.json||i.start();let a=await J(r,n,e);a=await Y(a);let o=await a.git.log(Number.parseInt(t.limit,10));if(i.stop(),t.json)I(o);else if(o.length===0)console.log(`No commits found`);else for(let e of o)console.log(`${e.shortSha} ${e.message.split(`
148
- `)[0]} (${e.author}, ${e.date.toLocaleDateString()})`)}),e.command(`diff`).description(`Show diff`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--ref <ref>`,`Ref to diff against`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching diff...`);t.json||i.start();let a=await J(r,n,e);a=await Y(a);let o=await a.git.diff(t.ref);i.stop(),t.json?I(o):o.raw?console.log(o.raw):console.log(`${o.additions} additions, ${o.deletions} deletions across ${o.files.length} files`)}),e.command(`add`).description(`Stage files`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<paths...>`,`Paths to stage`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a),await a.git.add(t),L(`Staged: ${t.join(`, `)}`)}),e.command(`commit`).description(`Create a commit`).argument(`<id-or-name>`,`Sandbox ID or name`).requiredOption(`-m, --message <msg>`,`Commit message`).option(`--amend`,`Amend the previous commit`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=await J(r,n,e);i=await Y(i);let a=await i.git.commit(t.message,{amend:t.amend});t.json?I(a):L(`Committed: ${a.shortSha} ${a.message}`)}),e.command(`push`).description(`Push to remote`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--force`,`Force push`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Pushing...`);i.start();let a=await J(r,n,e);a=await Y(a),await a.git.push({force:t.force}),i.stop(),L(`Pushed to remote`)}),e.command(`pull`).description(`Pull from remote`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--rebase`,`Rebase instead of merge`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Pulling...`);i.start();let a=await J(r,n,e);a=await Y(a),await a.git.pull({rebase:t.rebase}),i.stop(),L(`Pulled from remote`)}),e.command(`branches`).description(`List branches`).argument(`<id-or-name>`,`Sandbox ID or name`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching branches...`);t.json||i.start();let a=await J(r,n,e);a=await Y(a);let o=await a.git.branches();i.stop(),t.json?I(o):o.length===0?console.log(`No branches found`):Bt([`Name`,`Current`,`Remote`],o.map(e=>[e.name,e.current?`* `:` `,e.upstream??`-`]))}),e.command(`checkout`).description(`Checkout a branch or ref`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<ref>`,`Branch name or ref`).option(`-b, --create`,`Create a new branch`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a),await a.git.checkout(t,{create:n.create}),L(`Checked out: ${t}${n.create?` (new)`:``}`)}),e}function nc(e,t=16){if(!Number.isInteger(t)||t<=0||t>64)throw TypeError(`stableHashHex: lengthHex must be in [1, 64] (got ${t})`);let n=typeof e==`string`?e:JSON.stringify(e,(e,t)=>{if(t&&typeof t==`object`&&!Array.isArray(t)){let e={},n=t;for(let t of Object.keys(n).sort())e[t]=n[t];return e}return t});return C(`sha256`).update(n).digest(`hex`).slice(0,t)}Object.freeze([`HS256`]),Object.freeze([`RS256`]);async function rc(e,t,n=`tangle --help`){let r=new AbortController,i=e??r.signal,a=()=>{r.abort(),process.stderr.write(`Stopping…
149
- `)};e||(process.once(`SIGINT`,a),process.once(`SIGTERM`,a));try{return i.throwIfAborted(),await t(i)}catch(e){if(!i.aborted||e instanceof V&&e.code===`RUN_STOPPED`)throw e;let t=new V(`RUN_STOPPED`,`Command interrupted`,`A stop request ended this execution`,n);throw e instanceof Error&&`runId`in e&&typeof e.runId==`string`&&Object.assign(t,{runId:e.runId}),t}finally{e||(process.off(`SIGINT`,a),process.off(`SIGTERM`,a))}}function ic(e,t){for(let[n,r]of Object.entries(t)){let t=e.gates?.find(e=>e.id===n);if(!t||!t.choices.includes(r))throw new V(`GATE_CHOICE_INVALID`,`Invalid choice for gate '${n}'`,t?`Choose one of: ${t.choices.join(`, `)}`:`The graph does not declare this gate`,`tangle graph run --help`)}}function ac(e,t){let n=t.signal;return async r=>{let i=Object.hasOwn(e,r.gate)?e[r.gate]:void 0,a=`--param ${Be(`gate.${r.gate}=<choice>`)}`,o=`${r.question} Choose one of: ${r.choices.join(`, `)}`,s=()=>new V(`GATE_ANSWER_REQUIRED`,`Gate '${r.gate}' needs an answer. ${o}. Pass ${a}`,o,`tangle graph run <graph> ${a}`);if(i!==void 0)return{kind:`choose`,choice:i,by:`cli:param`};if(t.json||!process.stdin.isTTY)throw s();let c;try{c=await ei(`${r.question} [${r.choices.join(` / `)}]`,void 0,n)}catch{if(n.aborted)return{kind:`stop`,reason:`Gate input interrupted or timed out`,by:`cli:terminal`};throw s()}if(!r.choices.includes(c))throw s();return{kind:`choose`,choice:c,by:`cli:terminal`}}}const oc=N.string().regex(/^[a-f0-9]{64}$/),sc=N.strictObject({version:N.literal(1),runId:N.uuid(),file:N.string().refine(ge),cwd:N.string().refine(ge),sourceDigest:oc,graphDigest:oc,params:N.record(N.string(),N.unknown()),gateChoices:N.record(N.string(),N.string()).optional(),startedAt:N.iso.datetime(),seat:N.string().optional()});function X(e){throw new V(`GRAPH_RESUME_REFUSED`,`The graph run cannot be resumed`,e,`tangle graph run --help`)}async function cc(e){N.uuid().safeParse(e).success||X(`Use a recorded graph run ID`);let t;try{let n=j(await Ge(j(M(),`.tangle`)),`runs`,e);await Ge(n)!==n&&X(`The run directory redirects elsewhere`),t=await Ue(j(n,`input.json`),ce.O_RDONLY|ce.O_NOFOLLOW),(await t.stat()).isFile()||X(`The run input is not a regular file`);let r=sc.parse(JSON.parse(await t.readFile(`utf8`)));return(r.runId!==e||await Ge(r.cwd)!==r.cwd)&&X(`The recorded run or workspace identity changed`),r}catch(e){if(e instanceof V)throw e;return X(`The private recorded run input is missing or invalid`)}finally{await t?.close()}}async function lc(e,t){await Ke(j(e,`input.json`),JSON.stringify(t),{flag:`wx`,mode:384,flush:!0})}function uc(e,t,n,r,i={}){e.sourceDigest!==n&&X(`The authored graph source changed`),t.cloud&&X(`A local run cannot move to cloud execution`),Object.entries(r).some(([t,n])=>!Object.hasOwn(e.params,t)||ie(n)!==ie(e.params[t]))&&X(`A recorded graph parameter changed`),Object.entries(i).some(([t,n])=>e.gateChoices?.[t]!==n)&&X(`A recorded gate choice changed`),t.seat!==void 0&&t.seat!==e.seat&&X(`The recorded graph seat override changed`)}const dc=`claude,codex,kimi,opencode,gemini,pi`;function fc(e,t){let n;return async(r,{node:i,lastCandidate:a})=>{t.throwIfAborted();let o;try{o=r===void 0?void 0:oe(r)}catch(e){throw e instanceof Error&&Object.assign(e,{node:i,seat:r,fixCommand:`tangle graph run --help`}),e}n??=qe({cwd:e,signal:t,config:Je({...process.env,BRIDGE_BACKENDS:dc,BRIDGE_SUBSCRIPTIONS_ONLY:`1`})});let s=await n;t.throwIfAborted();let c=e=>e.authentication?.status===`authenticated`&&e.authentication.authMode===`subscription`,l=o?.harness??s.find(e=>e.provider&&c(e))?.backend,u=s.filter(e=>e.backend===l),d=u.filter(c),f=o?u.find(e=>e.id===`${o.harness}/${o.model}`)??d.find(e=>e.provider===o.provider):d.find(e=>e.default)??d.find(e=>e.recommended)??d[0];if(!f||!c(f)){if(a===!1)return;let e=f?.authentication??u[0]?.authentication??(o?void 0:s.find(e=>e.authentication?.fix)?.authentication);throw Object.assign(new V(o?`SEAT_NOT_LOGGED_IN`:`SEAT_NONE_DETECTED`,`Node '${i}' has no available subscription${o?` for ${o.harness}`:``}`,e?`Selected provider: ${e.status} (${e.authMode})`:`No authenticated subscription route was detected`,e?.fix??`tangle graph run --help`),{node:i,seat:r})}let p=o?.harness??oe(f.id).harness,m=o?.provider??f.provider,h=o?.model??f.id.slice(p.length+1);if(!m||!h)throw new V(`MODEL_PROVIDER_MISMATCH`,`Node '${i}' has an unresolved model provider`,`Bridge has no configured provider for ${r??p}`,`tangle graph run --help`);return{harness:p,provider:m,model:h,selector:{kind:`all-eligible`},...o?.reasoningEffort===void 0?{}:{reasoningEffort:o.reasoningEffort}}}}function Z(e){return Vr({signal:e.signal,...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.baseUrl===void 0?{}:{baseUrl:e.baseUrl}})}const pc=N.object({version:N.literal(1),type:N.enum([`state`,`ack`,`error`,`event`]),requestId:N.string().optional(),operationId:N.string().optional(),command:N.string().optional(),code:N.string().optional(),message:N.string().optional(),result:N.unknown().optional()}).passthrough(),mc=N.object({state:N.object({runConfiguration:N.unknown()}),view:N.object({capabilities:N.record(N.string(),N.object({available:N.boolean(),reason:N.string().optional()}))})}),hc=N.object({status:N.enum([`completed`,`failed`,`cancelled`]),analysis:N.object({id:N.string().min(1)}).passthrough(),source:N.object({runtimeRun:N.unknown()}).passthrough()}).passthrough(),gc=`TANGLE_GRAPH_ANALYSIS_SOURCE`;async function _c(e,t,n){if(!e.startsWith(`wfrun_`)){let t=j(await Ge(j(M(),`.tangle`)),`runs`,e);if(await Ge(t)!==t)throw new V(`RUN_NOT_FOUND`,`The run directory redirects elsewhere`,`Use the recorded local run directory`,`tangle graph inspect --help`);return{source:`runtime:${e}@${t}`,env:{},schema:N.object({runId:N.literal(e),runDir:N.literal(t)})}}let r={signal:n,...t.apiKey===void 0?{}:{apiKey:t.apiKey},...t.baseUrl===void 0?{}:{baseUrl:t.baseUrl}},i=await Z(r),a=N.object({id:N.literal(e),workflowId:N.string(),revUsed:N.number().int(),execution:N.object({kind:N.literal(`graph`),sourceSha:N.string(),authoredGraphDigest:N.string(),graphDigest:N.string()}),runtime:N.object({snapshot:N.object({supervisors:N.tuple([N.object({id:N.string()})])})})}).parse(await i.workflows.getRun(e,{signal:n})),o=a.runtime.snapshot.supervisors[0];if(!o)throw new V(`BRAID_RPC_FAILED`,`The cloud run has no retained Runtime root`,`Wait for execution evidence before analysis`,`tangle graph inspect ${e}`);let s=await Lr(r);if(new URL(s.baseUrl.replace(/\/+$/,``)).href!==new URL(i.baseUrl.replace(/\/+$/,``)).href)throw new V(`AUTH_REQUIRED`,`The analysis source origin changed`,`Use the same authenticated platform origin`,`tangle auth status --json`);return{source:`runtime:${e}@${gc}`,env:{[gc]:JSON.stringify({url:`${s.baseUrl.replace(/\/+$/,``)}/v1/workflows/runs/${encodeURIComponent(e)}`,headers:{Authorization:`Bearer ${s.token}`}})},schema:N.object({runId:N.literal(e),remoteEndpointEnv:N.literal(gc),checkpoint:N.object({workflowId:N.literal(a.workflowId),runtimeRunId:N.literal(o.id),revUsed:N.literal(a.revUsed),sourceSha:N.literal(a.execution.sourceSha),authoredGraphDigest:N.literal(a.execution.authoredGraphDigest),graphDigest:N.literal(a.execution.graphDigest)})})}}async function vc(e,t){if(!e.startsWith(`wfrun_`)&&!N.uuid().safeParse(e).success)throw new V(`RUN_NOT_FOUND`,`Use a recorded graph run ID`,`The run identifier is invalid`,`tangle graph inspect --help`);if(!Number.isSafeInteger(t.timeout)||t.timeout<1)throw new V(`INVALID_TIMEOUT`,`Use a positive analysis timeout`,`The timeout must be an integer number of milliseconds`,`tangle graph analyze --help`);let n=t.profile;if(!n?.trim())throw new V(`USAGE_INVALID`,`Select the canonical analysis profile`,`Graph analysis requires an existing canonical AgentProfile reference`,`tangle graph analyze `+e+` --profile <name|path>`);let r=/^(?:\.\.?)[/\\]/.test(n)?ve(process.cwd(),n):n;return rc(t.signal,async n=>{let i=await _c(e,t,n),a=i.source;return Ll({signal:n,errorRunId:e},async n=>{let o=await n.bridge(),s=await He(j(n.runDir,`analysis-`)),c=j(s,`config.json`),l=j(s,`database.key`),u=j(s,`state.sqlite`),d=`connection-owned-graph-bridge`,f=new Date().toISOString();await Ke(l,te(32),{mode:384,flag:`wx`}),await Ke(c,JSON.stringify({format:`braid-startup-config`,schemaVersion:2,profile:r,connectionId:d,connections:[{id:d,name:`Graph analysis`,kind:`cli-bridge`,endpoint:o.bridgeUrl,providerOptions:{transport:`local`},createdAt:f,updatedAt:f,lastHealth:{status:`unknown`}}]}),{mode:384,flag:`wx`});let p=n.signal,m=`op-${w()}`,h=`op-${w()}`,g=`${m}:initialize`,_=`${m}:analyze`,v=`${m}:shutdown`,y={version:1,requestId:g,command:`initialize`,params:{workspace:n.cwd,subscribe:!1}},b={version:1,requestId:_,operationId:m,command:`analyze`,params:{source:a,recipe:`all`,totalTimeoutMs:t.timeout}},ee={version:1,requestId:v,operationId:h,command:`shutdown`,params:{mode:`wait`}},x,S,C,T,E={transform:e=>{let t=pc.parse(e);return t.type===`error`||t.type===`state`&&t.requestId===g||t.type===`ack`&&[_,v].includes(t.requestId??``)?t:null},onError:e=>{T??=e},onEvent:e=>{e.type===`error`&&(T??=new V(e.code??`BRAID_RPC_FAILED`,`Braid refused graph analysis`,e.message??`The RPC response omitted its cause`,`tangle graph analyze --help`)),e.requestId===g&&e.type===`state`&&(x??=e),e.requestId===_&&e.type===`ack`&&(S??=e),e.requestId===v&&e.type===`ack`&&(C??=e)}},D=await ze({command:process.env.BRAID_BIN??`braid`,args:[`rpc`,`--workspace`,n.cwd,`--config`,c,`--profile`,r,`--database-key-file`,l],cwd:n.cwd,env:{...i.env,BRAID_STATE_PATH:u,BRAID_CLI_BRIDGE_ENDPOINT:o.bridgeUrl,BRAID_CLI_BRIDGE_AUTH:o.bridgeBearer},timeoutMs:t.timeout,signal:p,ownProcessGroup:!0},E,{stdin:[y,...t.dryRun?[]:[b],ee].map(e=>JSON.stringify(e)).join(`
140
+ `)?`${e}\n`:`${e}\n\n`}function bo(){let e=process.env.SHELL??``;return e.includes(`zsh`)?j(M(),`.zshrc`):e.includes(`bash`)?j(M(),`.bashrc`):j(M(),`.zshrc`)}function xo(e){if(e===`shell`||e===`env`||e===`dockerfile`)return e;throw Error(`--format must be one of: shell, env, dockerfile (got '${e}')`)}function So(e){if(e===`full`||e===`prompts`||e===`metadata`)return e;throw Error(`--content must be one of: full, prompts, metadata (got '${e}')`)}async function Co(e){let t=go({endpoint:e.endpoint,apiKey:e.apiKey,projectKey:e.projectKey,content:e.content,format:e.format});if(console.log(t),e.format!==`shell`){console.log(),R(e.format===`env`?"Cron/container path: feed these to your service env (.env, `docker run --env-file`, k8s envFrom). No shell-rc edit, no TTY needed.":`Dockerfile path: paste these ENV lines into your image. No shell-rc edit, no TTY needed.`);return}if(console.log(),R(`Privacy tiers: --content full ships the whole conversation; --content prompts keeps task, prompts, and tool args only; --content metadata turns content off (telemetry still flows). Secrets are scrubbed server-side regardless.`),!e.write)return;let n=e.rcPath??bo(),r=process.stdin.isTTY?await ti(`Append this idempotent block to ${n}? (y/N)`,`n`):`n`;if(r.toLowerCase()!==`y`&&r.toLowerCase()!==`yes`){console.log(),R(`Not writing. To append later: tangle connect claude-code --rc ${n}`);return}let i=_o({endpoint:e.endpoint,apiKey:e.apiKey,projectKey:e.projectKey,content:e.content,format:e.format}),{contents:a,changed:o}=vo(co(n),i);if(!o){console.log(),L(`Already present in ${n} — nothing to change.`);return}lo(n,a),console.log(),L(`Wrote Tangle Intelligence env block to ${n}.`),R(`Reload your shell (e.g. 'source ${n}') before running the agent.`)}function wo(e){let t=[],n={header:null,body:[]};for(let r of e.split(`
141
+ `))To(r)?(t.push(n),n={header:r.trim(),body:[]}):n.body.push(r);return t.push(n),t.length>1&&t[0].header===null&&t[0].body.every(e=>e.trim()===``)&&t.shift(),t}function To(e){let t=e.trim();return t.startsWith(`[`)&&t.endsWith(`]`)&&!t.includes(`=`)||t.startsWith(`[[`)&&t.endsWith(`]]`)}function Eo(e){let t=[];for(let n of e)n.header!==null&&t.push(n.header),t.push(...n.body);return t.join(`
142
+ `)}function Do(e){return[{key:`environment`,line:`environment = "prod"`},{key:`log_user_prompt`,line:`log_user_prompt = true`},{key:`exporter`,line:`exporter = { otlp-http = { endpoint = "${xa(e.endpoint)}/v1/logs", protocol = "json", headers = { "Authorization" = "Bearer ${e.apiKey??"${TANGLE_API_KEY}"}" } } }`}]}function Oo(e){let t=e.trim();if(t===``||t.startsWith(`#`))return null;let n=t.indexOf(`=`);if(n===-1)return null;let r=t.slice(0,n).trim();return/^[A-Za-z0-9_-]+$/.test(r)?r:null}function ko(e,t){let n=Do(t),r=new Set(n.map(e=>e.key));if(e.trim()===``)return{contents:`${[`[otel]`,...n.map(e=>e.line)].join(`
143
+ `)}\n`,changed:!0};let i=wo(e),a=i.find(e=>e.header===`[otel]`);if(!a){let t={header:`[otel]`,body:n.map(e=>e.line)},r=i[i.length-1];r&&!Ao(r)&&r.body.push(``),i.push(t);let a=jo(Eo(i));return{contents:a,changed:a!==jo(e)}}let o=a.body.filter(e=>{let t=Oo(e);return t===null||!r.has(t)}),s=[];for(;o.length>0&&o[o.length-1].trim()===``;)s.unshift(o.pop());a.body=[...o,...n.map(e=>e.line),...s];let c=jo(Eo(i));return{contents:c,changed:c!==jo(e)}}function Ao(e){return e.body.length>0&&e.body[e.body.length-1].trim()===``}function jo(e){return e.endsWith(`
144
+ `)?e:`${e}\n`}function Mo(e){let t=j(M(),`.codex`,`config.toml`),{contents:n,changed:r}=ko(co(t),{endpoint:e.endpoint,apiKey:e.apiKey});if(!e.write){console.log(n.trimEnd());return}if(!r){L(`${t} already has the Tangle [otel] block — nothing to change.`);return}lo(t,n),L(`Merged the Tangle [otel] block into ${t}.`),R("Codex emits content on the logs signal (codex.* events). Set TANGLE_API_KEY in your env before running if you kept the ${TANGLE_API_KEY} reference."),R(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=${e.projectKey??`<your project>`} before running codex.`)}function No(e){switch(e){case`claude-code`:return`Claude Code: set OTEL_LOGS_EXPORTER=otlp and the four OTEL_LOG_* gates (OTEL_LOG_USER_PROMPTS, OTEL_LOG_TOOL_DETAILS, OTEL_LOG_TOOL_CONTENT, OTEL_LOG_RAW_API_BODIES).`;case`codex`:return`Codex: set log_user_prompt = true in [otel] (default false redacts content).`;case`opencode`:return`OpenCode: a standalone install emits nothing without the tangle-opencode-exporter shim; inside a Tangle sandbox it is already instrumented.`;case`openclaw`:case`hermes`:case`nanoclaw`:return`${oo[e]}: no native OTLP exporter and no standalone server to subscribe to — run it inside a Tangle sandbox, where the sidecar adapter exports its content with gen_ai.system=${e}. A bare standalone install emits metadata only.`}}async function Po(e){let t=Date.now()+e.timeoutSeconds*1e3,n=3e3,r=Math.min(e.timeoutSeconds*1e3,1e4),i=z(`Checking whether content is flowing…`);i.start();let a;try{for(;;){try{a=await ba({endpoint:e.endpoint,apiKey:e.apiKey,timeoutMs:r})}catch(e){if(Date.now()>=t)throw e;await Ae(n);continue}if(a.contentSeen||Date.now()>=t)break;await Ae(n)}}finally{i.stop()}if(!a)throw Error(`onboarding status check returned no result`);Fo(a,e.agent),a.contentSeen||(process.exitCode=1)}function Fo(e,t){if(e.contentSeen){L(`Content flowing — Tangle Intelligence can analyze this feed.`),B({"Last seen":e.lastSeenAt??`just now`,Window:`${e.windowDays}d`});return}if(e.tracesSeen){It(`Metadata-only — traces are arriving but carry no content. You missed a content gate.`);let n=t?[t]:Object.keys(e.byAgent).filter(so),r=n.length>0?n:ao;for(let n of r){let r=e.byAgent[n];(t||!r||r.tracesSeen&&!r.contentSeen)&&R(No(n))}return}It(`No traces yet for your tenant. Run your agent once on a real task, then re-run --verify.`),t&&R(No(t))}function Io(e){let t=e??process.env.TANGLE_INTELLIGENCE_API_KEY??ir(void 0);if(!t)throw Error(`No Tangle API key found. Pass --api-key, set TANGLE_API_KEY, or run: tangle auth login`);return t}function Lo(){return new x(`connect`).description(`Connect a local coding agent's telemetry to Tangle Intelligence, content on (for SDK integration snippets, see 'tangle agent connect')`).argument(`[agent]`,`claude-code | codex | opencode | openclaw | hermes | nanoclaw`).option(`--endpoint <url>`,`OTLP endpoint base`,aa).option(`-p, --project <key>`,`Project label (tangle.subject.key) to group runs; omit to set it yourself`).option(`--rc <path>`,`Shell rc file to append the Claude Code env block to`).option(`--no-write`,`Print the config instead of writing files (Claude Code / Codex)`).option(`--inline-key`,"Embed the resolved API key literally in the config (default: keep ${TANGLE_API_KEY})").option(`--verify`,`Poll onboarding status and report whether CONTENT is flowing`).option(`--timeout <seconds>`,`Verify poll timeout in seconds`,`120`).option(`--run`,`OpenCode only: run the content exporter against a live OpenCode server until interrupted`).option(`--opencode-url <url>`,`OpenCode server base URL for --run (or set OPENCODE_BASE_URL)`).option(`--format <kind>`,`Claude Code output: shell (export block) | env (.env / docker --env-file) | dockerfile (ENV lines). env/dockerfile are the cron/container path — printed to stdout, no shell-rc edit, no TTY`,`shell`).option(`--content <tier>`,`Claude Code content tier: full (everything) | prompts (task+prompts+tool-args) | metadata (telemetry on, content off)`,`full`).action(async(e,t)=>{let n=xa(t.endpoint);if(t.run){if((e?zo(e):`opencode`)!==`opencode`)throw Error(`--run is OpenCode-only: it runs the content exporter against a live OpenCode server. Other agents export natively once configured.`);await Uo({endpoint:n,apiKey:Io(t.apiKey),opencodeUrl:t.opencodeUrl});return}if(t.verify){await Po({endpoint:n,apiKey:Io(t.apiKey),agent:e?zo(e):void 0,timeoutSeconds:io(t.timeout,`--timeout`)});return}let r=e?zo(e):await Bo(),i=t.inlineKey?Io(t.apiKey):void 0;r===`claude-code`?await Co({endpoint:n,apiKey:i,projectKey:t.project,rcPath:t.rc,write:t.write!==!1,content:So(t.content),format:xo(t.format)}):r===`codex`?Mo({endpoint:n,apiKey:i,projectKey:t.project,write:t.write!==!1}):r===`opencode`?Vo({endpoint:n}):Ho(r,{endpoint:n}),console.log(),R(`Run your agent on a real task, then verify content is flowing: tangle connect ${r} --verify`)})}function Ro(){return new x(`opencode-exporter`).description(`Export a running OpenCode's content to Tangle Intelligence (standalone shim)`).option(`--endpoint <url>`,`OTLP endpoint base`,aa).option(`--opencode-url <url>`,`OpenCode server base URL (or set OPENCODE_BASE_URL)`).action(async e=>{await Uo({endpoint:xa(e.endpoint),apiKey:Io(e.apiKey),opencodeUrl:e.opencodeUrl})})}function zo(e){if(so(e))return e;throw Error(`Unknown agent '${e}'. Choose one of: ${ao.join(`, `)}`)}async function Bo(){if(!process.stdin.isTTY)throw Error(`Specify an agent: tangle connect <${ao.join(`|`)}>`);console.log(`Which coding agent are you connecting?`),ao.forEach((e,t)=>{console.log(` ${t+1}) ${oo[e]} (${e})`)});let e=await ti(`Enter a number or name`,`1`);return ao[Number.parseInt(e,10)-1]||zo(e.trim())}function Vo(e){let t=xa(e.endpoint);It(`OpenCode has no native OTel exporter, so a standalone install emits nothing without a shim.`),console.log(),B({"Inside a Tangle sandbox":`already instrumented — our adapter exports OpenCode's event-stream content. Nothing to do.`,Standalone:`run 'tangle connect opencode --run' alongside a running OpenCode, exporting to ${t}.`}),console.log(),R(`Start OpenCode in server mode ('opencode serve'), then in another terminal run: tangle connect opencode --run`),R(`The exporter subscribes to OpenCode's SSE event bus and exports content-bearing OTLP (prompt/completion/tool content) to Tangle. Verify with: tangle connect opencode --verify`),R(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=my-project before starting the exporter.`)}function Ho(e,t){let n=xa(t.endpoint),r=oo[e];It(`${r} has no native OTel exporter, so a standalone install emits nothing without instrumentation.`),console.log(),B({"Inside a Tangle sandbox":`already instrumented — the sidecar adapter exports ${r}'s prompt/completion/tool content (gen_ai.system=${e}) to ${n}. Nothing to do.`,Standalone:`${r} exposes no OTLP and no event-bus server; run it inside a Tangle sandbox to capture content.`}),console.log(),R(`Label this project so Tangle rolls up + automates per-project: export OTEL_RESOURCE_ATTRIBUTES=tangle.subject.key=my-project before starting ${r}.`),R(`Verify content is flowing: tangle connect ${e} --verify`)}async function Uo(e){let t=$a(e.opencodeUrl),n=new AbortController,r=()=>n.abort();process.on(`SIGINT`,r),process.on(`SIGTERM`,r),R(`Subscribing to OpenCode at ${t} — exporting content to Tangle.`),R(`Run OpenCode tasks now. Press Ctrl-C to stop.`),console.log();let i=0,a;try{a=await ro({endpoint:e.endpoint,apiKey:e.apiKey,opencodeBaseUrl:t,signal:n.signal,onExport:({eventType:e,records:t})=>{i+=t,R(`exported ${t} record(s) from ${e} (total ${i})`)}})}catch(e){if(e instanceof to){let{recordsExported:t,contentEventsExported:n}=e.partial;console.log(),It(`Exporter failed after exporting ${t} content record(s) from ${n} event(s): ${e.message}`)}throw e}finally{process.off(`SIGINT`,r),process.off(`SIGTERM`,r)}if(console.log(),a.contentEventsExported===0){It(`Saw ${a.eventsSeen} event(s) but none carried content. Run a real OpenCode task (a prompt that produces text or a tool call), then re-run.`);return}L(`Exported ${a.recordsExported} content record(s) from ${a.contentEventsExported} event(s).`),R(`Verify it landed: tangle connect opencode --verify`)}function Wo(){let e=new x(`environments`).alias(`env`).description(`Manage sandbox environments`);return e.command(`list`).alias(`ls`).description(`List available environments`).action(async e=>{let{client:t}=K(e),n=z(`Fetching environments...`);e.json||n.start();let r=await t.environments.list();n.stop(),e.json?I(r):r.length===0?console.log(`No environments found`):Vt([`ID`,`Description`,`Version`,`Runtimes`],r.map(e=>[e.id,e.description??``,e.version,e.runtimes.join(`, `)]))}),e.command(`get`).description(`Get environment details`).argument(`<id>`,`Environment ID`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Fetching environment...`);t.json||r.start();let i=await n.environments.get(e);if(r.stop(),!i){console.error(`Environment not found: ${e}`),process.exit(1);return}t.json?I(i):(console.log(`ID: ${i.id}`),console.log(`Description: ${i.description??`-`}`),console.log(`Version: ${i.version}`),console.log(`Runtimes: ${i.runtimes.join(`, `)}`),i.base&&console.log(`Base: ${i.base}`))}),e}const Go=N.string().trim().toLowerCase().min(1).max(64).regex(/^[a-z][a-z0-9-]*$/),Ko=N.string().trim().toLowerCase().min(1).max(128).regex(/^[a-z0-9][a-z0-9._-]*$/),qo=N.object({kind:Ko,count:N.number().int().positive().default(1),vramGb:N.number().positive().optional()}).strict();N.object({command:N.string().min(1).max(8192),timeoutMs:N.number().int().positive().max(2147453647).optional(),env:N.record(N.string(),N.string()).optional(),cwd:N.string().min(1).max(2048).optional()}).strict(),N.object({refresh:N.enum([`true`,`false`]).optional(),acceleratorKind:Ko.optional(),acceleratorCount:N.coerce.number().pipe(qo.shape.count.unwrap()).optional(),acceleratorVramGb:N.coerce.number().positive().optional()}).strict(),N.object({maxSpendUsd:N.number().positive().max(1e4).optional(),maxLifetimeSeconds:N.number().int().positive().max(1440*60).optional()}).strict().refine(e=>e.maxSpendUsd!==void 0||e.maxLifetimeSeconds!==void 0,`Renewal requires a lifetime or spend cap`);const Jo=N.object({provider:Go.optional(),image:N.string().min(1).max(512).optional(),env:N.record(N.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/),N.string()).optional(),diskGb:N.number().int().positive().optional(),volumeGb:N.number().int().nonnegative().optional(),volumeMountPath:N.string().startsWith(`/`).max(2048).optional(),region:N.string().min(1).max(128).optional(),manifest:N.record(N.string(),N.unknown()).optional(),command:N.array(N.string().max(8192)).min(1).max(256).optional(),ports:N.array(N.number().int().min(1).max(65535)).max(32).optional(),endpoint:N.object({port:N.number().int().min(1).max(65535),healthPath:N.string().regex(/^\/(?![/\\])/).refine(e=>![`\r`,`
145
+ `,` `].some(t=>e.includes(t))).max(2048).optional()}).strict().optional(),allowSpot:N.boolean().optional(),maxHourlyUsd:N.number().positive().optional(),weights:N.object({manifestSha:N.string().regex(/^[a-f0-9]{64}$/),sizeBytes:N.number().int().positive().safe()}).strict().optional(),arms:N.array(N.unknown()).min(1).max(256).optional(),maxSpendUsd:N.number().positive().max(1e4),maxLifetimeSeconds:N.number().int().positive().max(1440*60),idleTimeoutSeconds:N.number().int().positive().optional()}).strict();Jo.extend({accelerator:qo});const Yo=qo,Xo=Go;N.object({...Jo.omit({env:!0}).shape,id:N.string(),projectRef:N.string(),ownerUserId:N.string(),productId:N.string().optional(),provider:Xo,providerLeaseId:N.string().optional(),providerInstanceType:N.string().optional(),workerUrl:N.string().optional(),endpointUrl:N.string().optional(),status:N.enum([`provisioning`,`ready`,`detaching`,`destroyed`,`failed`]),accelerator:Yo,providerCostPerHourUsd:N.number().optional(),customerPricePerHourUsd:N.number().optional(),estimatedProviderCostUsd:N.number().optional(),estimatedCustomerCostUsd:N.number().optional(),providerSelection:N.object({strategy:N.enum([`explicit`,`cheapest`,`ranked`]),selectedProvider:Xo,requestedProvider:Xo.optional(),candidates:N.array(N.object({provider:Xo,accelerator:Yo,providerInstanceType:N.string().optional(),region:N.string().optional(),pricingSource:N.enum([`live`,`configured`]).optional(),providerCostPerHourUsd:N.number(),customerPricePerHourUsd:N.number(),maxLifetimeSeconds:N.number(),estimatedProviderCostUsd:N.number(),estimatedCustomerCostUsd:N.number()})),rejected:N.array(N.object({provider:Xo,error:N.string()}))}).optional(),createdAt:N.string(),updatedAt:N.string(),readyAt:N.string().optional(),startedAt:N.string().optional(),lastUsedAt:N.string().optional(),destroyedAt:N.string().optional(),failure:N.string().optional(),billing:N.object({seconds:N.number(),providerCostUsd:N.number(),customerCostUsd:N.number(),providerCostPerHourUsd:N.number(),customerPricePerHourUsd:N.number(),startedAt:N.string(),stoppedAt:N.string()}).optional()});function Zo(e){return qo.parse({kind:e.kind,count:e.count===void 0?void 0:Number(e.count),...e.memory===void 0?{}:{vramGb:Number(e.memory)}})}function Qo(e,t,n){let r=!!(e.provider||e.image||e.env||e.maxSpendUsd||e.maxLifetime||e.idleTimeout);if(!t&&r)throw Error(n);if(t){if(!e.maxSpendUsd||!e.maxLifetime)throw Error(`--accelerator-kind requires --gpu-max-spend-usd and --gpu-max-lifetime`);return{...e.provider?{provider:Go.parse(e.provider)}:{},...e.image?{image:e.image}:{},...e.env?{env:ns(e.env,`--gpu-env`,`GPU env`)}:{},maxSpendUsd:is(e.maxSpendUsd,`--gpu-max-spend-usd`),maxLifetimeSeconds:rs(e.maxLifetime,`--gpu-max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:rs(e.idleTimeout,`--gpu-idle-timeout`)}:{}}}}function $o(e){return{...e.provider?{provider:Go.parse(e.provider)}:{},accelerator:Zo({kind:e.acceleratorKind,count:e.acceleratorCount,memory:e.acceleratorMemory}),...e.image?{image:e.image}:{},...e.env?{env:ns(e.env,`--env`,`env`)}:{},maxSpendUsd:is(e.maxSpendUsd,`--max-spend-usd`),maxLifetimeSeconds:rs(e.maxLifetime,`--max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:rs(e.idleTimeout,`--idle-timeout`)}:{}}}function es(e){return e.length===1?e[0]:e.map(Be).join(` `)}function ts(e){return{timeoutMs:e.timeout?rs(String(e.timeout),`--timeout`):void 0,env:e.env?ns(e.env,`--env`,`env`):void 0}}function ns(e,t,n){let r={};for(let i of e){let[e,...a]=i.split(`=`);if(!e||a.length===0)throw Error(`${t} expects ${n} values in KEY=VALUE format`);r[e]=a.join(`=`)}return r}function rs(e,t){if(!/^\d+$/.test(e))throw Error(`${t} must be a positive integer`);let n=Number.parseInt(e,10);if(Number.isNaN(n)||n<1)throw Error(`${t} must be a positive integer`);return n}function is(e,t){if(!/^(?:\d+|\d+\.\d+|\.\d+)$/.test(e))throw Error(`${t} must be a positive number`);let n=Number.parseFloat(e);if(!Number.isFinite(n)||n<=0)throw Error(`${t} must be a positive number`);return n}function as(){return new x(`exec`).description(`Execute a command in a sandbox`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<command...>`,`Command and arguments, or one shell script`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`,`60000`).allowUnknownOption(!0).action(async(e,t,n)=>{try{let{context:r,client:i}=K(n),a=es(t),o=ns(n.env??[],`--env`,`env`),s=z(`Executing: ${a}`);n.json||s.start();let c=await J(i,r,e);c=await Y(c);let l=await c.exec(a,{cwd:n.cwd,env:Object.keys(o).length>0?o:void 0,timeoutMs:Number.parseInt(n.timeout,10)});s.stop(),n.json?I(l):(l.stdout&&process.stdout.write(l.stdout),l.stderr&&process.stderr.write(l.stderr)),l.exitCode!==0&&(process.exitCode=l.exitCode)}catch(e){if(e instanceof i){let t=`Exec transport lost before command status was confirmed. Remote command status is unknown. Original error: ${e.message}. For long-running commands, use \`tangle process spawn\`, \`tangle process logs\`, and \`tangle process kill --tree\`.`;return U(Error(t,{cause:e}))}U(e)}})}function os(e){e.command(`capabilities`).description(`List fleet drivers and their supported features`).action(async e=>{let{client:t}=K(e),n=z(`Fetching capabilities...`);n.start();let r=await t.fleets.capabilities();n.stop(),e.json?I(r):F(r.drivers,[{key:`driverType`,header:`Driver`,width:16},{key:`sharedWorkspace`,header:`Shared WS`,width:12},{key:`accelerators`,header:`Accel`,width:8},{key:`queueTimings`,header:`Queue`,width:8}])}),e.command(`usage <fleet-id>`).description(`Show fleet usage and reliability insights`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Fetching usage...`);r.start();let i=await n.fleets.usage(e);if(r.stop(),t.json)I(i);else if(B({"Fleet ID":i.usage.fleetId,Status:i.usage.status,Machines:i.usage.machineCount,Running:i.usage.runningMachines,Failed:i.usage.failedMachines,"Runtime (ms)":i.usage.meteredUsage?.runtimeMs,"Reliability score":i.insights.reliabilityScore,"Failure rate":i.insights.failureRate}),i.insights.recommendedActions.length>0){console.log(`
146
+ Recommended actions:`);for(let e of i.insights.recommendedActions)console.log(` - ${e}`)}}),e.command(`cost <fleet-id>`).description(`Show the fleet's cost estimate`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Estimating cost...`);r.start();let i=await n.fleets.cost(e);r.stop(),t.json?I(i):B({Plan:i.plan,Currency:i.currency,"Hourly (USD)":i.hourlyUsd,"Max lifetime (s)":i.maxLifetimeSeconds,"Estimated max lifetime (USD)":i.estimatedMaxLifetimeUsd,Machines:i.requestedResources.machines,"Total CPU":i.requestedResources.totalCpu,"Total memory (MB)":i.requestedResources.totalMemoryMb})})}function ss(e){return[...e.entries()].map(([e,t])=>({machineId:e,sandboxId:t.id,status:t.status}))}function cs(e){e.command(`list <fleet-id>`).description(`List the machines of one fleet (fleet id is required)`).option(`--status <status>`,`Filter machines by status`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Fetching fleet...`);r.start();let i=await n.fleets.list({fleetId:e,status:t.status});r.stop();let a=ss(i.machines);t.json?I({fleetId:i.fleetId,machines:a}):F(a,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}])}),e.command(`get <fleet-id>`).description(`Show one fleet's manifest (server record)`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Fetching manifest...`);r.start();let i=await n.fleets.manifest(e);r.stop(),t.json?I(i):(B({"Fleet ID":i.fleetId??i.id,Machines:i.machines.length,"Workspace mode":i.workspace?.mode,"Workspace status":i.workspace?.status,"Max lifetime (s)":i.policy?.maxLifetimeSeconds,"Max spend (USD)":i.policy?.maxSpendUsd,Created:i.createdAt,Updated:i.updatedAt}),F(i.machines,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`role`,header:`Role`,width:14},{key:`status`,header:`Status`,width:14}]))}),e.command(`delete <fleet-id>`).description(`Delete a fleet's machine sandboxes and its record`).option(`--continue-on-error`,`Keep deleting remaining machines if one delete fails`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Deleting fleet...`);r.start(),await n.fleets.delete(e,{continueOnError:t.continueOnError}),r.stop(),t.json?I({success:!0,fleetId:e}):L(`Fleet deleted: ${e}`)}),e.command(`reap`).description(`TTL cleanup of all expired fleets (fleet-wide)`).option(`--dry-run`,`Report what would be reaped without deleting`).action(async e=>{let{client:t}=K(e),n=z(`Reaping expired fleets...`);n.start();let r=await t.fleets.reapExpired({dryRun:e.dryRun});n.stop(),e.json?I(r):(B({"Dry run":r.dryRun,Expired:r.expired,Deleted:r.deleted}),F(r.fleets,[{key:`fleetId`,header:`Fleet`,width:24},{key:`expiredAt`,header:`Expired`,width:18},{key:`deleted`,header:`Deleted`,width:10}]))}),e.command(`reconcile`).description(`Drop fleet records whose underlying sandboxes vanished`).option(`--dry-run`,`Report orphans without removing them`).action(async e=>{let{client:t}=K(e),n=z(`Reconciling fleets...`);n.start();let r=await t.fleets.reconcile({dryRun:e.dryRun});n.stop(),e.json?I(r):(B({"Dry run":r.dryRun,Checked:r.checked,Orphaned:r.orphaned,Removed:r.removed}),F(r.machines,[{key:`fleetId`,header:`Fleet`,width:24},{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`removed`,header:`Removed`,width:10}]))})}async function ls(e,t){let n=await Rr({apiKey:t.apiKey,baseUrl:t.baseUrl??dr()}),r=await fetch(`${n.baseUrl}/v1/agent-profiles/${encodeURIComponent(e)}`,{headers:{authorization:`Bearer ${n.token}`,accept:`application/json`}});if(!r.ok){let t=await r.text().catch(()=>``);throw r.status===404?Error(`profile '${e}' not found in the platform catalog (it may be a built-in, a stored profile you own, or neither — run 'tangle profile list' to see what is available)`):Error(`platform returned ${r.status}: ${t.slice(0,200)}`)}let i=await r.json();if(!i.definition||typeof i.definition!=`object`)throw Error(`profile '${e}' resolved but has no definition — the catalog entry is malformed`);return i.definition}async function us(e){let t=typeof e.envVarName==`string`&&e.envVarName.length>0?e.envVarName:null,n=!!e.fromStdin;if(t&&n)throw Error(`Pass either ${e.flagPrefix}-env or ${e.flagPrefix}-stdin, not both`);if(t){let n=process.env[t];if(!n||n.length===0)throw Error(`${e.flagPrefix}-env points at ${t}, but that environment variable is empty or unset`);return n}if(n){let t=await ni();if(t.length===0)throw Error(`${e.flagPrefix}-stdin received empty input on stdin`);return t}}function ds(e){if(e.secret===void 0)return;let t=e.backend===`claude-code`?`token`:e.backend===`codex`?`bundle`:void 0;if(!t)throw Error(`--cli-auth needs --backend claude-code or --backend codex`);if(e.apiKeyGiven)throw Error(`--cli-auth cannot be combined with --backend-api-key-env or --backend-api-key-stdin`);return{account:`cli`,secretEnv:e.secret,format:t}}function fs(e){if(e!==void 0)return e.map(e=>{if(e.includes(`@`)||e.includes(`:`))throw Error(`--secret ${e}: bare secret names only (box delivery). For proxy custody use --proxy-secret with a canonical binding`);return e})}function ps(e,t){let n={};return e.cpu!==void 0&&(n.cpuCores=rs(e.cpu,`--cpu`)),e.memory!==void 0&&(n.memoryMB=rs(e.memory,`--memory`)),e.disk!==void 0&&(n.diskGB=rs(e.disk,`--disk`)),t&&(n.accelerator=t),Object.keys(n).length>0?n:void 0}function ms(e){let t=e.split(`/`);return t.length>=2?{provider:t[0],model:t.slice(1).join(`/`)}:{model:e}}function hs(e){let t={};for(let n of e){let[e,...r]=n.split(`=`);if(!e||r.length===0)throw Error(`--metadata expects values in KEY=VALUE or KEY=JSON format`);t[e]=gs(r.join(`=`))}return t}function gs(e){try{return JSON.parse(e)}catch{return e}}function _s(e,t){if(!(!e.gitUrl&&!e.gitRef&&!e.gitDepth&&!e.gitSparse&&!t)){if(!e.gitUrl||typeof e.gitUrl!=`string`)throw Error(`--git-url is required when using git provisioning options`);return{url:e.gitUrl,ref:typeof e.gitRef==`string`?e.gitRef:void 0,depth:typeof e.gitDepth==`string`?rs(e.gitDepth,`--git-depth`):void 0,sparse:Array.isArray(e.gitSparse)?e.gitSparse:void 0,auth:t?{token:t}:void 0}}}function vs(e,t){if(!(!e.storageType&&!e.storageBucket&&!e.storageEndpoint&&!e.storageRegion&&!e.storagePrefix&&!e.storageAccessKeyId&&!t)){if(typeof e.storageType!=`string`||typeof e.storageBucket!=`string`||typeof e.storageAccessKeyId!=`string`||!t)throw Error(`Storage config requires --storage-type, --storage-bucket, --storage-access-key-id, and one of --storage-secret-access-key-env / --storage-secret-access-key-stdin`);return{type:ys(e.storageType),bucket:e.storageBucket,endpoint:typeof e.storageEndpoint==`string`?e.storageEndpoint:void 0,region:typeof e.storageRegion==`string`?e.storageRegion:void 0,prefix:typeof e.storagePrefix==`string`?e.storagePrefix:void 0,credentials:{accessKeyId:e.storageAccessKeyId,secretAccessKey:t}}}}function ys(e){if(e===`s3`||e===`gcs`||e===`r2`)return e;throw Error(`--storage-type must be one of s3, gcs, or r2`)}function bs(e){if(e===void 0)return;let t=[];for(let n of e){let e=n,r=`--proxy-secret <json>`;if(n.startsWith(`@`)){let t=n.slice(1);r=`--proxy-secret @${t}`;try{e=k(t,`utf8`)}catch{throw Error(`${r}: file could not be read`)}}let i;try{i=JSON.parse(e)}catch(e){throw Error(`${r}: not valid JSON (${e instanceof Error?e.message:String(e)})`)}if(Array.isArray(i))t.push(...i);else if(typeof i==`object`&&i)t.push(i);else throw Error(`${r}: expected a binding object or an array of bindings`)}let n=T.parse(t);return n.length>0?n:void 0}function xs(e){R(` Status: ${e.status}`),R(` Provider: ${e.provider}`),R(` GPU: ${e.accelerator.kind} x ${e.accelerator.count}`),e.customerPricePerHourUsd!==void 0&&R(` Customer price: $${e.customerPricePerHourUsd}/hr`),e.estimatedCustomerCostUsd!==void 0&&R(` Max estimate: $${e.estimatedCustomerCostUsd}`),e.billing&&(R(` Billed seconds: ${e.billing.seconds}`),R(` Customer cost: $${e.billing.customerCostUsd}`))}function Ss(e){e.result.stdout&&process.stdout.write(e.result.stdout),e.result.stderr&&process.stderr.write(e.result.stderr),R(`Exit code: ${e.result.exitCode}`)}function Cs(e){let t=e.command(`gpu`).description(`Manage on-demand GPU leases for a sandbox`);t.command(`providers <id-or-name>`).description(`List GPU clouds, whether each credential works, and current prices`).option(`--accelerator-kind <kind>`,`Price this GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Checking GPU providers...`);i.start();let a=await(await J(r,n,e)).gpu.providers(t.acceleratorKind?{accelerator:Zo({kind:t.acceleratorKind,count:t.acceleratorCount,memory:t.acceleratorMemory})}:{});if(i.stop(),t.json){I(a);return}F(a.statuses.map(e=>({provider:e.provider,state:e.state,gpu:e.estimate?.providerInstanceType??``,usdHr:e.estimate?e.estimate.customerPricePerHourUsd.toFixed(4):``,pricing:e.estimate?.pricingSource??``,needs:e.envVars.join(` `)})),[{key:`provider`,header:`Provider`},{key:`state`,header:`State`},{key:`gpu`,header:`GPU`},{key:`usdHr`,header:`$/hr`},{key:`pricing`,header:`Price`},{key:`needs`,header:`Needs`}]);for(let e of a.statuses){let t=e.state===`credential-invalid`?e.credential?.detail:e.estimateError;t&&R(`${e.provider}: ${t}`)}a.usable.length===0&&R(`No GPU provider is usable on this deployment: set the variables in Needs for one provider on the server.`)}),t.command(`attach <id-or-name>`).description(`Attach a temporary GPU worker to a sandbox`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).option(`--provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--image <image>`,`GPU worker image override`).option(`--env <vars...>`,`Environment variables for the GPU worker (KEY=VALUE)`).requiredOption(`--max-spend-usd <usd>`,`Maximum customer spend for this lease`).requiredOption(`--max-lifetime <seconds>`,`Maximum lease lifetime in seconds`).option(`--idle-timeout <seconds>`,`Destroy after this many idle seconds`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Attaching GPU lease...`);i.start();let a=await(await J(r,n,e)).gpu.attach($o(t));i.stop(),t.json?I(a):(L(`GPU lease attached: ${a.id}`),xs(a))}),t.command(`run <id-or-name> <command...>`).description(`Attach a GPU, run a command or script, then destroy it`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).option(`--provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--image <image>`,`GPU worker image override`).option(`--env <vars...>`,`Environment variables for the GPU worker and command (KEY=VALUE)`).requiredOption(`--max-spend-usd <usd>`,`Maximum customer spend for this lease`).requiredOption(`--max-lifetime <seconds>`,`Maximum lease lifetime in seconds`).option(`--idle-timeout <seconds>`,`Destroy after this many idle seconds`).option(`--timeout <ms>`,`Command timeout in milliseconds`).option(`--cwd <path>`,`Working directory`).action(async(e,t,n)=>{let r,i,a,o;try{let{context:a,client:o}=K(n),s=await J(o,a,e),c=z(`Attaching GPU lease...`);c.start(),r=await s.gpu.attach($o(n)),c.stop();let l=z(`Running GPU command...`);l.start(),i=await s.gpu.exec(r.id,{command:es(t),...ts(n),cwd:n.cwd}),l.stop(),n.json||Ss(i)}catch(e){a=e}finally{if(r)try{let{context:t,client:i}=K(n);r=await(await J(i,t,e)).gpu.detach(r.id)}catch(e){o=e}}if(a){U(a),o&&U(o);return}if(o){U(o);return}n.json?I({lease:r,result:i}):r&&L(`GPU lease detached: ${r.id}`);let s=i?.result.exitCode;s&&s!==0&&(process.exitCode=s)}),t.command(`list <id-or-name>`).description(`List GPU leases attached to a sandbox`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching GPU leases...`);i.start();let a=await(await J(r,n,e)).gpu.list();i.stop(),t.json?I(a):a.length===0?R(`No GPU leases attached.`):F(a.map(e=>({id:e.id,status:e.status,provider:e.provider,accelerator:`${e.accelerator.kind}x${e.accelerator.count}`,customerUsdHr:e.customerPricePerHourUsd??``})),[{key:`id`,header:`ID`,width:28},{key:`status`,header:`Status`,width:12},{key:`provider`,header:`Provider`,width:12},{key:`accelerator`,header:`GPU`,width:24},{key:`customerUsdHr`,header:`$/hr`,width:10}])}),t.command(`exec <id-or-name> <lease-id> <command...>`).description(`Run a command or script on an attached GPU lease`).option(`--timeout <ms>`,`Command timeout in milliseconds`).option(`--cwd <path>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).action(async(e,t,n,r)=>{let{context:i,client:a}=K(r),o=z(`Running GPU command...`);o.start();let s=await(await J(a,i,e)).gpu.exec(t,{command:es(n),...ts(r),cwd:r.cwd});o.stop(),r.json?I(s):Ss(s)}),t.command(`detach <id-or-name> <lease-id>`).description(`Detach and destroy a GPU lease`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Detaching GPU lease...`);a.start();let o=await(await J(i,r,e)).gpu.detach(t);a.stop(),n.json?I(o):(L(`GPU lease detached: ${o.id}`),xs(o))})}function ws(e,t){if(t){I(e);return}if(!e.id){e.kind===`snapshot`&&e.result?.snapshot?L(`Snapshot created: ${e.result.snapshot.snapshotId}`):L(`Sandbox ${e.sandboxId} stopped.`);return}L(`${e.kind===`snapshot`?`Snapshot`:`Stop`} of sandbox ${e.sandboxId} accepted.`),R(`Operation: ${e.id}`),R(`Status: ${e.statusUrl}`)}function Ts(e){return`${e.name} (${e.id})`}async function Es(e,t){if(t.startsWith(`team_`))return e.teams.get(t);let n=(await e.teams.list()).filter(e=>e.name.toLowerCase()===t.toLowerCase());if(n.length===0)throw Error(`Team not found: ${t}`);if(n.length>1)throw Error(`Team name is ambiguous: ${t}. Use a team id instead.`);return n[0]}async function Ds(e,t,n){if(t)return Es(e,t);let r=mr(n);if(!r.activeTeamId)throw Error("No active team. Run `tangle team switch <team>` or pass `--team <team>`.");return e.teams.get(r.activeTeamId)}function Os(e,t){hr({id:e.id,name:e.name},t)}function ks(e){gr(e)}async function As(e){if(e.explicitTeam&&e.personal)throw Error(`--team and --personal cannot be used together`);if(!e.personal)return e.explicitTeam?(await Es(e.client,e.explicitTeam)).id:e.activeTeamId}async function js(e){if([!!e.explicitTeam,!!e.personal,!!e.allScopes].filter(Boolean).length>1)throw Error(`--team, --personal, and --all-scopes are mutually exclusive`);if(e.allScopes)return`all`;if(e.personal)return`personal`;if(e.explicitTeam)return`team:${(await Es(e.client,e.explicitTeam)).id}`;if(e.activeTeamId)return`team:${e.activeTeamId}`}function Ms(e){if(!e)return e;let t={...e};for(let e of[`authToken`,`execToken`])t[e]!==void 0&&(t[e]=`[REDACTED]`);return t}function Ns(e){e.command(`attestation <id-or-name>`).description(`Fetch TEE attestation evidence for a sandbox`).option(`--nonce <hex|auto>`,`Nonce to bind into a fresh attestation report; use auto to generate one`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=t.nonce===`auto`?g():t.nonce,a=z(`Fetching TEE attestation...`);a.start();let o=await(await J(r,n,e)).getTeeAttestation(i?{attestationNonce:i}:void 0);a.stop(),t.json?I(o):(L(`Attestation fetched for ${e}`),console.log(`TEE type: ${o.attestation.tee_type}`),console.log(`Evidence bytes: ${o.attestation.evidence.length}`),console.log(`Measurement bytes: ${o.attestation.measurement.length}`),console.log(`Timestamp: ${o.attestation.timestamp}`),o.attestationNonce&&console.log(`Nonce: ${o.attestationNonce}`))}),e.command(`list`).description(`List all sandboxes`).option(`-s, --status <status>`,`Filter by status (running, stopped, all)`).option(`-l, --limit <n>`,`Limit results`,`50`).option(`--team <team>`,`List sandboxes for a team by id or name`).option(`--personal`,`List personal sandboxes`).option(`--all-scopes`,`List personal and team sandboxes`).action(async e=>{let{context:t,client:n}=K(e),r=z(`Fetching sandboxes...`);r.start();let i=await js({client:n,explicitTeam:e.team,personal:e.personal,allScopes:e.allScopes,activeTeamId:t.activeTeamId}),a=await n.list({status:e.status===`all`?void 0:e.status,limit:Number.parseInt(e.limit,10),scope:i});r.stop(),e.json?I(a):F(a.map(e=>({id:e.id,status:e.status,createdAt:e.createdAt,name:e.name??``})),[{key:`id`,header:`ID`,width:24},{key:`status`,header:`Status`,width:14},{key:`createdAt`,header:`Created`,width:16},{key:`name`,header:`Name`,width:20}])}),e.command(`get <id-or-name>`).description(`Get sandbox details`).option(`--profile`,`Show the active agent profile provenance (name, hash, skills)`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching sandbox...`);i.start();let a=await J(r,n,e);if(i.stop(),t.profile){let e=a.getProfileProvenance?.();e?(R(`Agent profile provenance:`),R(` Base profile: ${e.base.name??`(inline)`} (${e.base.sha256.slice(0,12)}...)`),R(` Effective: ${e.effective.name??`(inline)`} (${e.effective.sha256.slice(0,12)}...)`),R(` Materialized: ${e.materializedAt}`),e.base.sha256!==e.effective.sha256&&R(` ⚠ Profile changed since creation (base ≠ effective)`)):R(`No profile materialized (bare sandbox). Create with --profile <name> to install one.`);return}t.json?I(a):Bt({id:a.id,name:a.name,status:a.status,resources:a.resources,createdAt:a.createdAt?.toISOString(),expiresAt:a.expiresAt?.toISOString(),connection:a.connection})}),e.command(`shapes`).description(`List the named sandbox sizes, the default, and this account's ceiling`).action(async e=>{let{client:t}=K(e),n=await t.shapes();if(e.json){I(n);return}let r=e=>e.cpuCores<=n.ceiling.cpuCores&&e.memoryMB<=n.ceiling.memoryMB&&e.diskGB<=n.ceiling.diskGB;F(n.presets.map(e=>({name:e.name===n.default?`${e.name} (default)`:e.name,cpu:e.cpuCores,memory:`${e.memoryMB} MB`,disk:`${e.diskGB} GB`,available:r(e)?`yes`:e.name===n.default?`clamped to ceiling`:`above ceiling`})),[{key:`name`,header:`Shape`,width:18},{key:`cpu`,header:`vCPU`,width:6},{key:`memory`,header:`Memory`,width:10},{key:`disk`,header:`Disk`,width:8},{key:`available`,header:`Available`,width:14}]),R(`Ceiling for this account: ${zt(n.ceiling)}`)}),e.command(`delete <id-or-name>`).description(`Delete a sandbox`).option(`-f, --force`,`Skip confirmation`).option(`--name`,`Treat the reference as a sandbox name`).option(`--retry-cleanup`,`Retry server-side cleanup after the sandbox disappeared from get/list`).action(async(e,t)=>{if(!t.force&&!await ei(`Delete sandbox ${e}? [y/N] `,`--force`)){R(`Cancelled.`);return}let{context:n,client:r}=K(t),i=z(`Deleting sandbox...`);i.start();let a=await qr(r,n,e,{retryCleanup:t.retryCleanup,name:t.name});i.stop(),L(a===`already_absent`?`Sandbox ${e} was already gone.`:`Sandbox ${e} deleted.`)}),e.command(`stop <id-or-name>`).description(`Stop a running sandbox`).option(`--name`,`Treat the reference as a sandbox name`).option(`--no-wait`,`Return once the stop is accepted and print the operation to poll`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Stopping sandbox...`);i.start();let a=await J(r,n,e,{nameOnly:t.name});if(t.wait===!1){let e=await a.stop({wait:!1});i.stop(),ws(e.info,!!t.json);return}await a.stop(),i.stop(),L(`Sandbox ${e} stopped.`)}),e.command(`resume <id-or-name>`).description(`Resume a stopped sandbox`).option(`--wait`,`Wait for sandbox to be running`,!0).option(`-t, --timeout <ms>`,`Resume timeout in milliseconds; a cold resume re-provisions the sandbox, so this defaults higher than other commands (default 120000)`,`120000`).action(async(e,t)=>{let n=Number.parseInt(t.timeout,10);if(!Number.isFinite(n)||n<=0)throw Error(`--timeout must be a positive number of milliseconds`);let r=W({apiKey:t.apiKey,baseUrl:t.baseUrl,timeout:n}),i=G(r),a=z(`Resuming sandbox...`);a.start();let o=await J(i,r,e);await o.resume({timeoutMs:n}),t.wait&&(a.text=`Waiting for sandbox to start...`,await o.waitFor(`running`,{timeoutMs:n})),a.stop(),L(`Sandbox ${o.id} resumed.`)})}function Ps(e){e.command(`create`).description(`Create a new sandbox`).option(`-n, --name <name>`,`Sandbox name`).option(`-e, --environment <environment>`,Fs).addOption(Is()).option(`--bare`,`Create a bare sandbox without the agent runtime`).option(`--ssh`,`Enable SSH access`).option(`--ssh-key <key>`,`SSH public key for authentication`).option(`--ssh-keys <names...>`,`Stored SSH key names or IDs for authentication`).option(`--ssh-key-file <paths...>`,`SSH public key file paths for authentication`).option(`--web-terminal`,`Enable web terminal`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`--secret <names...>`,`Secrets selected by bare name for box delivery (value in the sandbox env). For proxy custody use --proxy-secret`).option(`--proxy-secret <bindings...>`,`Canonical proxy custody binding(s): one binding as inline JSON, or @file with a JSON array. The value stays at the egress proxy and is redeemed only within the binding's scope (hosts/methods/paths/TTL); the box reads a placeholder. Repeatable`).option(`--metadata <entries...>`,`Metadata entries (KEY=VALUE or KEY=JSON)`).option(`--cpu <cores>`,"CPU cores (omit for the platform default; see `sandbox shapes`)").option(`--memory <mb>`,`Memory in MB (omit for the platform default)`).option(`--disk <gb>`,`Disk size in GB (omit for the platform default)`).option(`--accelerator-kind <kind>`,`Accelerator kind, for example nvidia-h100 or amd-mi300x`).option(`--accelerator-count <count>`,`Accelerator device count`,`1`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).option(`--gpu-provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--gpu-worker-image <image>`,`GPU worker image override`).option(`--gpu-env <vars...>`,`Environment variables for the GPU worker (KEY=VALUE)`).option(`--gpu-max-spend-usd <usd>`,`Maximum customer spend for the create-time GPU lease`).option(`--gpu-max-lifetime <seconds>`,`Maximum create-time GPU lease lifetime in seconds`).option(`--gpu-idle-timeout <seconds>`,`Destroy the create-time GPU lease after this many idle seconds`).option(`--lifetime <seconds>`,`Max wall-clock lifetime before the sandbox is suspended — stopped, not deleted; resume it within the cold window (default 3600 = 1h). Raise it for long sessions, e.g. --lifetime 7200`,`3600`).option(`--idle-timeout <seconds>`,"Idle time before the sandbox is stopped — not deleted (default 900 = 15m). Resume it later with `tangle sandbox resume <id-or-name>`, or it auto-resumes on next use. Raise it for demos, e.g. --idle-timeout 3600",`900`).option(`--from-snapshot <id>`,`Create the sandbox from a snapshot`).option(`--public-template <id-or-slug>`,`Create the sandbox from a published public template`).option(`--public-template-version <id>`,`Pin creation to a specific published public-template version`).option(`--billing-owner <userId>`,`Platform user that pays for the sandbox. The API accepts this only from a first-party service key that is listed as a billing delegate, and refuses such a key that names no payer.`).option(`--team <team>`,`Create in a team by id or name`).option(`--personal`,`Create a personal sandbox even when a team is active`).option(`--git-url <url>`,`Git repository URL to clone during provisioning`).option(`--git-ref <ref>`,`Git branch, tag, or commit to checkout`).option(`--git-depth <depth>`,`Git clone depth`).option(`--git-sparse <paths...>`,`Sparse checkout paths`).option(`--git-token-env <name>`,`Name of an environment variable containing the Git HTTPS auth token`).option(`--git-token-stdin`,`Read the Git HTTPS auth token from stdin`).option(`--storage-type <type>`,`BYOS3 storage type (s3, gcs, r2)`).option(`--storage-bucket <name>`,`BYOS3 bucket name`).option(`--storage-endpoint <url>`,`BYOS3 endpoint URL`).option(`--storage-region <region>`,`BYOS3 region`).option(`--storage-prefix <prefix>`,`BYOS3 path prefix`).option(`--storage-access-key-id <id>`,`BYOS3 access key ID`).option(`--storage-secret-access-key-env <name>`,`Name of an environment variable containing the BYOS3 secret access key`).option(`--storage-secret-access-key-stdin`,`Read the BYOS3 secret access key from stdin`).addOption(new S(`--driver <type>`,`Run on Tangle network operators instead of the platform's hosts (--tee needs it)`).choices([`tangle`])).option(`--backend <type>`,`Backend agent type (${n.join(`, `)})`).option(`--backend-model <model>`,`Model override (format: provider/model)`).addOption(new S(`--reasoning-effort <level>`,`Reasoning effort for the backend's model; overrides the profile's model.reasoningEffort`).choices(ne)).option(`--backend-api-key-env <name>`,`Name of an environment variable containing the BYOK backend API key`).option(`--backend-api-key-stdin`,`Read the BYOK backend API key from stdin`).option(`--cli-auth <secret>`,"Run --backend claude-code or codex on your own subscription: the stored secret holding a `claude setup-token` token or a Codex auth.json (see `tangle secret create`)").option(`--profile <path>`,`Path to an AgentProfile JSON file to install as the sandbox's backend profile (carries skills, tools, MCP, model). Use with --backend; the profile's inline skills materialize into the harness's native skill directory on first turn`).option(`--profile-stdin`,`Read the AgentProfile JSON from stdin instead of a file (use with --profile)`).option(`--tee <type>`,`Require a TEE backend (any, tdx, nitro, sev-snp, phala-dstack)`).option(`--sealed`,`Request TEE sealed-secret support`).option(`--attestation-nonce <hex|auto>`,`Deploy-time attestation nonce; use auto to generate one`).option(`--attestation-refresh`,`Generate a fresh deploy-time attestation nonce when --tee is set`).option(`--require-attestation`,`Fail unless TEE attestation evidence is returned`).option(`--wait`,`Wait for sandbox to be running`,!0).option(`--timeout <ms>`,`HTTP timeout in milliseconds`,`30000`).action(async e=>{let t=await us({envVarName:e.gitTokenEnv,fromStdin:e.gitTokenStdin,flagPrefix:`--git-token`}),n=await us({envVarName:e.storageSecretAccessKeyEnv,fromStdin:e.storageSecretAccessKeyStdin,flagPrefix:`--storage-secret-access-key`}),r=await us({envVarName:e.backendApiKeyEnv,fromStdin:e.backendApiKeyStdin,flagPrefix:`--backend-api-key`}),i=ds({secret:e.cliAuth,backend:e.backend,apiKeyGiven:r!==void 0}),a;if(e.profileStdin){let e=await ni(`--profile-stdin`,`the AgentProfile JSON`);try{a=JSON.parse(e)}catch{U(Error(`--profile-stdin: the input is not valid JSON`));return}}else if(e.profile){let t=String(e.profile);if(t.startsWith(`.`)||t.startsWith(`/`)||t.endsWith(`.json`))try{a=JSON.parse(k(t,`utf8`))}catch(e){U(Error(`--profile ${t}: ${e.message}`));return}else try{a=await ls(t,e)}catch(e){U(Error(`--profile ${t}: ${e.message}`));return}}a=Rs(a,e.reasoningEffort);let o=W({apiKey:e.apiKey,baseUrl:e.baseUrl,timeout:e.timeout?Number.parseInt(e.timeout,10):void 0}),s=G(o),c=z(`Creating sandbox...`);c.start();let l=await As({client:s,explicitTeam:e.team,personal:e.personal,activeTeamId:o.activeTeamId}),u=ns(e.env??[],`--env`,`env`),d=e.metadata?hs(e.metadata):void 0,f=_s(e,t),p=vs(e,n),m=e.acceleratorKind?Zo({kind:String(e.acceleratorKind),count:String(e.acceleratorCount),memory:typeof e.acceleratorMemory==`string`?e.acceleratorMemory:void 0}):void 0,g=Qo({provider:typeof e.gpuProvider==`string`?e.gpuProvider:void 0,image:typeof e.gpuWorkerImage==`string`?e.gpuWorkerImage:void 0,env:Array.isArray(e.gpuEnv)?e.gpuEnv:void 0,maxSpendUsd:typeof e.gpuMaxSpendUsd==`string`?e.gpuMaxSpendUsd:void 0,maxLifetime:typeof e.gpuMaxLifetime==`string`?e.gpuMaxLifetime:void 0,idleTimeout:typeof e.gpuIdleTimeout==`string`?e.gpuIdleTimeout:void 0},!!m,`Create-time GPU lease flags require --accelerator-kind`),v=e.driver?{type:`tangle`}:void 0,y=e.backend||e.backendModel||a?{...e.backend?{type:_(e.backend)}:{},...a?{profile:a}:{},model:e.backendModel||r||i?{...e.backendModel?ms(e.backendModel):{},apiKey:r,...i?{cliAuth:i}:{}}:void 0}:void 0,b=fs(e.secret),ee=i?[...new Set([...b??[],i.secretEnv])]:b,x=bs(e.proxySecret),S=ps(e,m),C=e.sshKeyFile??(e.ssh&&!e.sshKey&&!e.sshKeys?.length?[Ls()]:[]),te=[...e.sshKey?[e.sshKey]:[],...C.map(e=>k(e,`utf8`).trim())],w={name:e.name,environment:e.environment,runtime:e.runtime,bare:e.bare||void 0,sshEnabled:e.ssh||!!e.sshKey||te.length>0||!!e.sshKeys?.length,sshPublicKeys:te.length>0?te:void 0,sshKeyIds:e.sshKeys,webTerminalEnabled:e.webTerminal,env:Object.keys(u).length>0?u:void 0,git:f,...S?{resources:S}:{},gpuLease:g,maxLifetimeSeconds:Number.parseInt(e.lifetime,10),idleTimeoutSeconds:Number.parseInt(e.idleTimeout,10),storage:p,fromSnapshot:e.fromSnapshot,publicTemplateId:e.publicTemplate,publicTemplateVersionId:e.publicTemplateVersion,teamId:l,...e.billingOwner?{billingOwnerId:e.billingOwner}:{},secrets:ee,...x?{proxySecrets:x}:{},metadata:d,driver:v,backend:y},T=e.tee?{tee:e.tee,sealed:e.sealed||void 0,attestationRefresh:e.attestationRefresh||e.attestationNonce===`auto`||void 0}:void 0,ne=T?await h(s,{...w,confidential:T,attestationNonce:e.attestationNonce??(e.attestationRefresh?`auto`:void 0),requireAttestation:e.requireAttestation??!0}):void 0,E=ne?.sandbox??await s.create(w);e.wait&&(c.text=`Waiting for sandbox to start...`,await E.waitFor(`running`,{timeoutMs:12e4}),await E.refresh()),c.stop(),e.json?I({id:E.id,name:E.name,status:E.status,resources:E.resources,createdAt:E.createdAt,expiresAt:E.expiresAt,connection:Ms(E.connection),teamId:l,gpuLease:E.gpuLease,confidential:T,attestation:ne?.attestation,attestationNonce:ne?.attestationNonce}):(L(`Sandbox created: ${E.id}`),Bt({id:E.id,name:E.name,status:E.status,resources:E.resources,createdAt:E.createdAt?.toISOString(),expiresAt:E.expiresAt?.toISOString(),connection:E.connection}),l&&console.log(`Team: ${l}`),E.gpuLease&&(console.log(`GPU lease: ${E.gpuLease.id}`),xs(E.gpuLease)),T&&(console.log(`TEE: ${T.tee}`),console.log(`Attestation: ${ne?.attestation?`present`:`not returned`}`),ne?.attestationNonce&&console.log(`Attestation nonce: ${ne.attestationNonce}`)))})}const Fs="A catalog environment, a container image reference, or a built image ID. Firecracker runs only images pinned by repository@sha256 that the cell's Firecracker hosts carry; `environments list` shows each image's runtimes";function Is(){return new S(`--runtime <runtime>`,`Isolation on the platform's hosts: docker runs a container on the host kernel, firecracker a microVM with its own kernel. Omit for the platform default`).choices(c)}function Ls(){let e=[`id_ed25519`,`id_ecdsa`,`id_rsa`].map(e=>`${M()}/.ssh/${e}.pub`),t=e.find(e=>le(e));if(!t)throw Error(`--ssh needs a public key and found none at ${e.join(`, `)}. Run ssh-keygen -t ed25519, or pass --ssh-key-file.`);return t}function Rs(e,t){if(!t)return e;let n=e?.model??{};return{...e,model:{...n,reasoningEffort:t}}}function zs(e){if(e.spec){let t=JSON.parse(k(e.spec,`utf8`));return{base:{fleetId:e.fleetId,defaults:t.defaults,policy:t.policy,workspace:t.workspace,metadata:t.metadata},machines:t.machines??[]}}let t=Hs(e),n=Us(e,!!t?.accelerator),r={...e.environment?{environment:e.environment}:{},...t?{resources:t}:{},...e.runtime?{runtime:e.runtime}:{},...n?{gpuLease:n}:{},...e.backend?{backend:{type:e.backend}}:{}},i=Ws(e),a=Math.max(1,Number(e.count)||1),o=Array.from({length:a},(e,t)=>({machineId:`worker-${t+1}`}));return{base:{fleetId:e.fleetId,defaults:Object.keys(r).length>0?r:void 0,policy:i,workspace:{mode:e.workspace}},machines:o}}function Bs(e){let{base:t,machines:n}=zs(e);return{...t,machines:n}}function Vs(e){let{base:t,machines:n}=zs(e);return{...t,workers:n}}function Hs(e){let t={};if(e.cpu&&(t.cpuCores=Number(e.cpu)),e.memory&&(t.memoryMB=Number(e.memory)),e.disk&&(t.diskGB=Number(e.disk)),e.acceleratorKind)t.accelerator=Zo({kind:e.acceleratorKind,count:e.acceleratorCount,memory:e.acceleratorMemory});else if(e.acceleratorCount||e.acceleratorMemory)throw Error(`--accelerator-count and --accelerator-memory require --accelerator-kind`);return Object.keys(t).length>0?t:void 0}function Us(e,t){return Qo({provider:e.gpuProvider,image:e.gpuWorkerImage,env:e.gpuEnv,maxSpendUsd:e.gpuMaxSpendUsd,maxLifetime:e.gpuMaxLifetime,idleTimeout:e.gpuIdleTimeout},t,`Fleet GPU lease flags require --accelerator-kind`)}function Ws(e){let t={};return e.maxSpendUsd&&(t.maxSpendUsd=Number(e.maxSpendUsd)),e.maxLifetime&&(t.maxLifetimeSeconds=Number(e.maxLifetime)),Object.keys(t).length>0?t:void 0}function Gs(e){e.command(`create`).description(`Create a sandbox fleet`).option(`--fleet-id <id>`,`Stable fleet id (generated when omitted)`).option(`--count <n>`,`Number of worker machines`,`1`).option(`--environment <environment>`,Fs).addOption(Is()).option(`--cpu <cores>`,`CPU cores per machine`).option(`--memory <mb>`,`Memory in MB per machine`).option(`--disk <gb>`,`Disk in GB per machine`).option(`--accelerator-kind <kind>`,`Accelerator kind per machine, for example nvidia-l4 or nvidia-h100`).option(`--accelerator-count <count>`,`Accelerator devices per machine`).option(`--accelerator-memory <gb>`,`Minimum memory per GPU in decimal GB`).option(`--gpu-provider <provider>`,`GPU cloud provider per machine; omitted picks the cheapest configured provider`).option(`--gpu-worker-image <image>`,`GPU worker image override`).option(`--gpu-env <vars...>`,`Environment variables for each GPU worker (KEY=VALUE)`).option(`--gpu-max-spend-usd <usd>`,`Maximum spend per machine GPU lease`).option(`--gpu-max-lifetime <seconds>`,`Maximum GPU lease lifetime per machine in seconds`).option(`--gpu-idle-timeout <seconds>`,`Destroy each GPU lease after this many idle seconds`).option(`--backend <id>`,`Agent backend type`).option(`--workspace <mode>`,`Workspace mode: isolated (no driver supports shared yet)`,`isolated`).option(`--max-spend-usd <n>`,`Fleet spend cap in USD (policy)`).option(`--max-lifetime <s>`,`Max machine lifetime in seconds (policy)`).option(`--spec <file.json>`,`Path to a JSON file describing the fleet (overrides synthesized machines)`).option(`--coordinator`,`Create a coordinator + workers fleet (routes to createWithCoordinator)`).action(async e=>{let{client:t}=K(e),n=z(`Creating fleet...`);n.start();let r=e.coordinator?await t.fleets.createWithCoordinator(Vs(e)):await t.fleets.create(Bs(e));n.stop();let i=ss(r.machines);e.json?I({fleetId:r.fleetId,machines:i}):(L(`Fleet created: ${r.fleetId}`),F(i,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}]))})}function Ks(e){e.command(`exec <fleet-id> <command>`).description(`Run a shell command across the fleet's machines`).option(`--machine <id...>`,`Restrict to a subset of machine ids (default: all)`).option(`--cwd <dir>`,`Working directory for the command`).option(`--timeout <ms>`,`Per-machine timeout in milliseconds`).option(`--max-concurrent <n>`,`Max concurrent dispatches`).action(async(e,t,n)=>{let{client:r}=K(n),i=z(`Dispatching command...`);i.start();let a=await(await r.fleets.list({fleetId:e})).dispatchExecDetailed(t,{machines:n.machine,cwd:n.cwd,timeoutMs:n.timeout?Number(n.timeout):void 0,maxConcurrent:n.maxConcurrent?Number(n.maxConcurrent):void 0});if(i.stop(),n.json)I(a);else{F(a.results.map(e=>({machineId:e.machineId,ok:e.ok,exitCode:e.result?.exitCode,durationMs:e.durationMs})),[{key:`machineId`,header:`Machine`,width:20},{key:`ok`,header:`OK`,width:6},{key:`exitCode`,header:`Exit`,width:8},{key:`durationMs`,header:`Duration(ms)`,width:14}]);for(let e of a.results){let t=e.result?.stdout,n=e.result?.stderr;t&&(console.log(`\n[${e.machineId}] stdout:`),console.log(t)),n&&(console.log(`\n[${e.machineId}] stderr:`),console.log(n)),e.error&&console.log(`\n[${e.machineId}] error: ${e.error.message}`)}}a.results.some(e=>e.ok===!1)&&(process.exitCode=1)}),e.command(`run [prompt]`).description(`Create a fleet of agents, run one turn on every agent, print each result, then delete the fleet`).requiredOption(`--agents <n|file>`,`Number of agents, or a JSON file with an array of agent specs (agentId, harness, model, profile or { profileId, revision }, task)`).option(`--placement <mode>`,`auto (pack by sandbox memory), dedicated (one sandbox per agent), or a number of agents per sandbox`,`auto`).option(`--model <id>`,`Model every agent runs, e.g. gpt-4.1-mini`).option(`--memory <mb>`,`Memory in MB per sandbox; auto placement packs by it`).option(`--environment <environment>`,`Environment for each sandbox`).option(`--max-spend-usd <usd>`,`Budget for the fleet in USD, enforced by the Platform on the fleet's own key`).option(`--timeout <ms>`,`Per-agent turn timeout in milliseconds`).option(`--fleet-id <id>`,`Stable fleet id (generated when omitted)`).option(`--parent-fleet <id>`,`Fleet that spawns this one; its cap must cover this cap`).option(`--parent-agent <id>`,`Agent of --parent-fleet that spawns this one`).option(`--keep`,`Keep the fleet after the run instead of deleting it`).action(async(e,t)=>{let n=/^\d+$/.test(t.agents)?Number(t.agents):JSON.parse(k(t.agents,`utf8`));if(!Array.isArray(n)&&e===void 0)throw Error(`A prompt is required unless --agents names a file whose agents carry tasks`);let{client:r}=K(t);if(!!t.parentFleet!=!!t.parentAgent)throw Error(`--parent-fleet and --parent-agent go together`);let i=t.placement===`auto`||t.placement===`dedicated`?t.placement:{agentsPerSandbox:Number(t.placement)},a=t.maxSpendUsd?Number(t.maxSpendUsd):void 0,o=z(`Creating fleet...`);o.start();let s=Date.now(),c=await r.fleets.create({fleetId:t.fleetId,agents:n,placement:i,defaults:{...t.environment?{environment:t.environment}:{},...t.memory?{resources:{memoryMB:Number(t.memory)}}:{},...t.model?{backend:{type:`opencode`,model:{model:t.model}}}:{}},...a===void 0?{}:{budgetUsd:a},...t.parentFleet?{parent:{fleetId:t.parentFleet,agentId:t.parentAgent}}:{}}),l=Date.now()-s;o.stop(),t.json||L(`Fleet ${c.fleetId}: ${c.agents.length} agents on ${c.machines.size} sandboxes in ${l} ms`);let u=[],d;try{for await(let n of c.run(e,{timeoutMs:t.timeout?Number(t.timeout):void 0})){if(n.type===`agent.finished`&&!t.json){let e=n.result;console.log(`[${e.agentId}] ${e.harness??`default`}/${e.model??`default`} ${e.status} ${e.durationMs}ms ${e.costUsd===void 0?`no cost reported`:`$${e.costUsd.toFixed(5)}`} ${e.result?.response??e.error??``}`)}n.type===`fleet.finished`&&(u=n.results,d=n.spend)}}finally{t.keep||await c.delete({continueOnError:!0})}t.json?I({fleetId:c.fleetId,createMs:l,sandboxes:c.machines.size,results:u,spend:d,deleted:!t.keep}):B({fleetId:c.fleetId,completed:u.filter(e=>e.status===`completed`).length,agents:u.length,spend:JSON.stringify(d),deleted:!t.keep}),u.some(e=>e.status!==`completed`)&&(process.exitCode=1)}),e.command(`cancel <fleet-id>`).description(`Interrupt every agent of a fleet and cancel its child fleets; sandboxes keep running`).action(async(e,t)=>{let{client:n}=K(t),r=await(await n.fleets.list({fleetId:e})).cancel();t.json?I({fleetId:e,...r}):L(`Fleet ${e}: interrupted ${r.interrupted} agents, cancelled ${r.children} child fleets`)})}const qs=[`list`,`create`,`delete`,`exec`,`prompt`,`read`,`write`];function Js(e){if(!(!e||e.length===0)){for(let t of e)if(!qs.includes(t))throw Error(`Invalid token action '${t}'. Allowed: ${qs.join(`, `)}`);return e}}function Ys(e){return e.length<=12?`****`:`${e.slice(0,6)}...${e.slice(-4)} (masked — use --json for full value)`}function Xs(e){e.command(`token <fleet-id>`).description(`Mint a scoped fleet bearer token (treated as a secret)`).option(`--action <a...>`,`Allowed actions: list create delete exec prompt read write (prompt grants nothing since fleet prompt dispatch was removed)`).option(`--ttl-minutes <n>`,`Token lifetime in minutes`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Minting fleet token...`);r.start();let i=await n.fleets.createToken(e,{actions:Js(t.action),ttlMinutes:t.ttlMinutes?Number(t.ttlMinutes):void 0});r.stop(),t.json?I(i):(B({"Fleet ID":i.fleetId,Token:Ys(i.token),"Expires at":new Date(i.expiresAt).toISOString(),Actions:i.actions.join(`, `)}),console.log(`
147
+ Re-run with --json to print the full token value.`))})}function Zs(){let e=new x(`workspace`).description(`Manage a fleet's shared workspace`);return e.command(`snapshot <fleet-id>`).description(`Snapshot the fleet's shared workspace`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Creating workspace snapshot...`);r.start();let i=await n.fleets.createWorkspaceSnapshot(e);r.stop(),t.json?I(i):L(`Workspace snapshot created: ${i.snapshotId??i.id}`)}),e.command(`restore <fleet-id> <snapshot-id>`).description(`Restore the fleet's shared workspace from a snapshot`).action(async(e,t,n)=>{let{client:r}=K(n),i=z(`Restoring workspace...`);i.start();let a=await r.fleets.restoreWorkspaceSnapshot(e,t);i.stop(),n.json?I(a):L(`Workspace restored from ${a.snapshotId??t}`)}),e.command(`reconcile <fleet-id>`).description(`Re-mount the shared workspace on all fleet machines`).action(async(e,t)=>{let{client:n}=K(t),r=z(`Reconciling workspace...`);r.start();let i=await n.fleets.reconcileWorkspace(e);r.stop(),t.json?I(i):(B({"Fleet ID":i.fleetId,Checked:i.checked,"Orphaned mounts":i.orphanedMounts}),F(i.machines,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`mounted`,header:`Mounted`,width:10}]))}),e}function Qs(){let e=new x(`fleet`).description(`Manage sandbox fleets`);return Gs(e),cs(e),e.addCommand(Zs()),Ks(e),os(e),Xs(e),e}function $s(){let e=new x(`fs`).description(`File system operations on sandboxes`);return e.command(`upload`).description(`Upload a file to a sandbox`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<local-path>`,`Local file path`).argument(`<remote-path>`,`Remote destination path`).action(async(e,t,n,r)=>{let{context:i,client:a}=K(r),o=await J(a,i,e);if(o=await Y(o),!O.existsSync(t))throw Error(`Local file not found: ${t}`);let s=O.statSync(t),c=Date.now();r.json||console.error(`Uploading ${t} to ${n}...`),await o.fs.upload(t,n,{onProgress:e=>{if(r.json)return;let t=e.percentage.toFixed(1);process.stderr.write(`\rProgress: ${t}% (${e.bytesUploaded}/${e.totalBytes} bytes)`)}});let l=Date.now()-c;r.json||console.error(``),r.json?I({success:!0,localPath:t,remotePath:n,size:s.size,durationMs:l}):console.log(`✓ Uploaded ${s.size} bytes in ${l}ms`)}),e.command(`download`).description(`Download a file from a sandbox`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<remote-path>`,`Remote file path`).argument(`<local-path>`,`Local destination path`).action(async(e,t,n,r)=>{let{context:i,client:a}=K(r),o=await J(a,i,e);o=await Y(o);let s=Date.now();r.json||console.error(`Downloading ${t} to ${n}...`),await o.fs.download(t,n,{onProgress:e=>{if(r.json)return;let t=e.percentage.toFixed(1);process.stderr.write(`\rProgress: ${t}% (${e.bytesDownloaded}/${e.totalBytes} bytes)`)}});let c=Date.now()-s,l=O.statSync(n);r.json||console.error(``),r.json?I({success:!0,remotePath:t,localPath:n,size:l.size,durationMs:c}):console.log(`✓ Downloaded ${l.size} bytes in ${c}ms`)}),e.command(`ls`).description(`List directory contents`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`[path]`,`Directory path`,`.`).option(`-l, --long`,`Show detailed information`).option(`-a, --all`,`Include hidden files`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a);let o=await a.fs.list(t,{all:n.all,long:n.long});if(n.json)I(o);else if(n.long)Vt([`Mode`,`Owner`,`Group`,`Size`,`Modified`,`Name`],o.map(e=>{let t=e.isDir?`d`:e.isSymlink?`l`:`-`,n=ec(e.permissions),r=e.isDir?`<DIR>`:tc(e.size),i=e.modTime.toLocaleDateString();return[t+n,e.owner,e.group,r,i,e.name]}));else{let e=o.map(e=>e.isDir?`${e.name}/`:e.name);console.log(e.join(` `))}}),e.command(`stat`).description(`Get file or directory information`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to file or directory`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a);let o=await a.fs.stat(t);n.json?I(o):(console.log(` File: ${o.name}`),console.log(` Path: ${o.path}`),console.log(` Size: ${tc(o.size)} (${o.size} bytes)`),console.log(` Type: ${o.isDir?`directory`:o.isSymlink?`symlink`:`file`}`),console.log(` Mode: ${ec(o.permissions)} (${o.permissions.toString(8)})`),console.log(` Owner: ${o.owner}`),console.log(` Group: ${o.group}`),console.log(` Modified: ${o.modTime.toISOString()}`),console.log(` Accessed: ${o.accessTime.toISOString()}`))}),e.command(`cat`).description(`Print file contents`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to file`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a);let o=await a.read(t);n.json?I({path:t,content:o}):console.log(o)}),e.command(`rm`).description(`Delete a file or directory`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to delete`).option(`-r, --recursive`,`Delete directories recursively`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a),await a.fs.delete(t,{recursive:n.recursive}),n.json?I({success:!0,path:t,deleted:!0}):console.log(`✓ Deleted: ${t}`)}),e.command(`mkdir`).description(`Create a directory`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Directory path to create`).option(`-p, --parents`,`Create parent directories as needed`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a),await a.fs.mkdir(t,{recursive:n.parents}),n.json?I({success:!0,path:t,created:!0}):console.log(`✓ Created: ${t}`)}),e.command(`exists`).description(`Check if a path exists`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to check`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a);let o=await a.fs.exists(t);n.json?I({path:t,exists:o}):(console.log(o?`exists`:`not found`),process.exit(+!o))}),e}function ec(e){let t=[`r`,`w`,`x`],n=``;for(let r=2;r>=0;r--){let i=r*3;for(let r=0;r<3;r++)n+=e>>i+(2-r)&1?t[r]:`-`}return n}function tc(e){let t=[`B`,`KB`,`MB`,`GB`,`TB`],n=e,r=0;for(;n>=1024&&r<t.length-1;)n/=1024,r++;return r===0?`${n}${t[r]}`:`${n.toFixed(1)}${t[r]}`}function nc(){let e=new x(`git`).description(`Git operations in a sandbox workspace`);return e.command(`status`).description(`Show git repository status`).argument(`<id-or-name>`,`Sandbox ID or name`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching status...`);t.json||i.start();let a=await J(r,n,e);a=await Y(a);let o=await a.git.status();if(i.stop(),t.json)I(o);else if(!o.isRepo)console.log(`No git repository in the sandbox workspace.`);else{if(console.log(`Branch: ${o.branch??`unknown`}`),console.log(`HEAD: ${o.head.slice(0,7)||`(no commits)`}`),console.log(`Dirty: ${o.isDirty?`yes`:`no`}`),o.ahead&&console.log(`Ahead: ${o.ahead}`),o.behind&&console.log(`Behind: ${o.behind}`),o.staged.length>0){console.log(`\nStaged (${o.staged.length}):`);for(let e of o.staged)console.log(` + ${e}`)}if(o.modified.length>0){console.log(`\nModified (${o.modified.length}):`);for(let e of o.modified)console.log(` M ${e}`)}if(o.untracked.length>0){console.log(`\nUntracked (${o.untracked.length}):`);for(let e of o.untracked)console.log(` ? ${e}`)}}}),e.command(`log`).description(`Show commit log`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`-n, --limit <count>`,`Max commits to show`,`10`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching log...`);t.json||i.start();let a=await J(r,n,e);a=await Y(a);let o=await a.git.log(Number.parseInt(t.limit,10));if(i.stop(),t.json)I(o);else if(o.length===0)console.log(`No commits found`);else for(let e of o)console.log(`${e.shortSha} ${e.message.split(`
148
+ `)[0]} (${e.author}, ${e.date.toLocaleDateString()})`)}),e.command(`diff`).description(`Show diff`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--ref <ref>`,`Ref to diff against`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching diff...`);t.json||i.start();let a=await J(r,n,e);a=await Y(a);let o=await a.git.diff(t.ref);i.stop(),t.json?I(o):o.raw?console.log(o.raw):console.log(`${o.additions} additions, ${o.deletions} deletions across ${o.files.length} files`)}),e.command(`add`).description(`Stage files`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<paths...>`,`Paths to stage`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a),await a.git.add(t),L(`Staged: ${t.join(`, `)}`)}),e.command(`commit`).description(`Create a commit`).argument(`<id-or-name>`,`Sandbox ID or name`).requiredOption(`-m, --message <msg>`,`Commit message`).option(`--amend`,`Amend the previous commit`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=await J(r,n,e);i=await Y(i);let a=await i.git.commit(t.message,{amend:t.amend});t.json?I(a):L(`Committed: ${a.shortSha} ${a.message}`)}),e.command(`push`).description(`Push to remote`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--force`,`Force push`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Pushing...`);i.start();let a=await J(r,n,e);a=await Y(a),await a.git.push({force:t.force}),i.stop(),L(`Pushed to remote`)}),e.command(`pull`).description(`Pull from remote`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--rebase`,`Rebase instead of merge`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Pulling...`);i.start();let a=await J(r,n,e);a=await Y(a),await a.git.pull({rebase:t.rebase}),i.stop(),L(`Pulled from remote`)}),e.command(`branches`).description(`List branches`).argument(`<id-or-name>`,`Sandbox ID or name`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching branches...`);t.json||i.start();let a=await J(r,n,e);a=await Y(a);let o=await a.git.branches();i.stop(),t.json?I(o):o.length===0?console.log(`No branches found`):Vt([`Name`,`Current`,`Remote`],o.map(e=>[e.name,e.current?`* `:` `,e.upstream??`-`]))}),e.command(`checkout`).description(`Checkout a branch or ref`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<ref>`,`Branch name or ref`).option(`-b, --create`,`Create a new branch`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a),await a.git.checkout(t,{create:n.create}),L(`Checked out: ${t}${n.create?` (new)`:``}`)}),e}function rc(e,t=16){if(!Number.isInteger(t)||t<=0||t>64)throw TypeError(`stableHashHex: lengthHex must be in [1, 64] (got ${t})`);let n=typeof e==`string`?e:JSON.stringify(e,(e,t)=>{if(t&&typeof t==`object`&&!Array.isArray(t)){let e={},n=t;for(let t of Object.keys(n).sort())e[t]=n[t];return e}return t});return C(`sha256`).update(n).digest(`hex`).slice(0,t)}Object.freeze([`HS256`]),Object.freeze([`RS256`]);async function ic(e,t,n=`tangle --help`){let r=new AbortController,i=e??r.signal,a=()=>{r.abort(),process.stderr.write(`Stopping…
149
+ `)};e||(process.once(`SIGINT`,a),process.once(`SIGTERM`,a));try{return i.throwIfAborted(),await t(i)}catch(e){if(!i.aborted||e instanceof V&&e.code===`RUN_STOPPED`)throw e;let t=new V(`RUN_STOPPED`,`Command interrupted`,`A stop request ended this execution`,n);throw e instanceof Error&&`runId`in e&&typeof e.runId==`string`&&Object.assign(t,{runId:e.runId}),t}finally{e||(process.off(`SIGINT`,a),process.off(`SIGTERM`,a))}}function ac(e,t){for(let[n,r]of Object.entries(t)){let t=e.gates?.find(e=>e.id===n);if(!t||!t.choices.includes(r))throw new V(`GATE_CHOICE_INVALID`,`Invalid choice for gate '${n}'`,t?`Choose one of: ${t.choices.join(`, `)}`:`The graph does not declare this gate`,`tangle graph run --help`)}}function oc(e,t){let n=t.signal;return async r=>{let i=Object.hasOwn(e,r.gate)?e[r.gate]:void 0,a=`--param ${Be(`gate.${r.gate}=<choice>`)}`,o=`${r.question} Choose one of: ${r.choices.join(`, `)}`,s=()=>new V(`GATE_ANSWER_REQUIRED`,`Gate '${r.gate}' needs an answer. ${o}. Pass ${a}`,o,`tangle graph run <graph> ${a}`);if(i!==void 0)return{kind:`choose`,choice:i,by:`cli:param`};if(t.json||!process.stdin.isTTY)throw s();let c;try{c=await ti(`${r.question} [${r.choices.join(` / `)}]`,void 0,n)}catch{if(n.aborted)return{kind:`stop`,reason:`Gate input interrupted or timed out`,by:`cli:terminal`};throw s()}if(!r.choices.includes(c))throw s();return{kind:`choose`,choice:c,by:`cli:terminal`}}}const sc=N.string().regex(/^[a-f0-9]{64}$/),cc=N.strictObject({version:N.literal(1),runId:N.uuid(),file:N.string().refine(ge),cwd:N.string().refine(ge),sourceDigest:sc,graphDigest:sc,params:N.record(N.string(),N.unknown()),gateChoices:N.record(N.string(),N.string()).optional(),startedAt:N.iso.datetime(),seat:N.string().optional()});function X(e){throw new V(`GRAPH_RESUME_REFUSED`,`The graph run cannot be resumed`,e,`tangle graph run --help`)}async function lc(e){N.uuid().safeParse(e).success||X(`Use a recorded graph run ID`);let t;try{let n=j(await Ge(j(M(),`.tangle`)),`runs`,e);await Ge(n)!==n&&X(`The run directory redirects elsewhere`),t=await Ue(j(n,`input.json`),ce.O_RDONLY|ce.O_NOFOLLOW),(await t.stat()).isFile()||X(`The run input is not a regular file`);let r=cc.parse(JSON.parse(await t.readFile(`utf8`)));return(r.runId!==e||await Ge(r.cwd)!==r.cwd)&&X(`The recorded run or workspace identity changed`),r}catch(e){if(e instanceof V)throw e;return X(`The private recorded run input is missing or invalid`)}finally{await t?.close()}}async function uc(e,t){await Ke(j(e,`input.json`),JSON.stringify(t),{flag:`wx`,mode:384,flush:!0})}function dc(e,t,n,r,i={}){e.sourceDigest!==n&&X(`The authored graph source changed`),t.cloud&&X(`A local run cannot move to cloud execution`),Object.entries(r).some(([t,n])=>!Object.hasOwn(e.params,t)||ie(n)!==ie(e.params[t]))&&X(`A recorded graph parameter changed`),Object.entries(i).some(([t,n])=>e.gateChoices?.[t]!==n)&&X(`A recorded gate choice changed`),t.seat!==void 0&&t.seat!==e.seat&&X(`The recorded graph seat override changed`)}const fc=`claude,codex,kimi,opencode,gemini,pi`;function pc(e,t){let n;return async(r,{node:i,lastCandidate:a})=>{t.throwIfAborted();let o;try{o=r===void 0?void 0:oe(r)}catch(e){throw e instanceof Error&&Object.assign(e,{node:i,seat:r,fixCommand:`tangle graph run --help`}),e}n??=qe({cwd:e,signal:t,config:Je({...process.env,BRIDGE_BACKENDS:fc,BRIDGE_SUBSCRIPTIONS_ONLY:`1`})});let s=await n;t.throwIfAborted();let c=e=>e.authentication?.status===`authenticated`&&e.authentication.authMode===`subscription`,l=o?.harness??s.find(e=>e.provider&&c(e))?.backend,u=s.filter(e=>e.backend===l),d=u.filter(c),f=o?u.find(e=>e.id===`${o.harness}/${o.model}`)??d.find(e=>e.provider===o.provider):d.find(e=>e.default)??d.find(e=>e.recommended)??d[0];if(!f||!c(f)){if(a===!1)return;let e=f?.authentication??u[0]?.authentication??(o?void 0:s.find(e=>e.authentication?.fix)?.authentication);throw Object.assign(new V(o?`SEAT_NOT_LOGGED_IN`:`SEAT_NONE_DETECTED`,`Node '${i}' has no available subscription${o?` for ${o.harness}`:``}`,e?`Selected provider: ${e.status} (${e.authMode})`:`No authenticated subscription route was detected`,e?.fix??`tangle graph run --help`),{node:i,seat:r})}let p=o?.harness??oe(f.id).harness,m=o?.provider??f.provider,h=o?.model??f.id.slice(p.length+1);if(!m||!h)throw new V(`MODEL_PROVIDER_MISMATCH`,`Node '${i}' has an unresolved model provider`,`Bridge has no configured provider for ${r??p}`,`tangle graph run --help`);return{harness:p,provider:m,model:h,selector:{kind:`all-eligible`},...o?.reasoningEffort===void 0?{}:{reasoningEffort:o.reasoningEffort}}}}const mc=Ye(Se);function hc(e,t,n=`tangle graph run --help`){throw new V(`SEAT_NONE_DETECTED`,e,t,n)}function gc(e){let t=[];for(let n of e.nodes)for(let e of n.check?.egress??[]){let n=e.trim().toLowerCase();if(n){if(/[\s*]|\/|:\/\//u.test(n))throw new V(`GRAPH_EGRESS_HOST`,`Graph egress host "${e.trim()}" is not a DNS hostname`,`A check egress entry has whitespace, a wildcard, or a URL`,`tangle graph run --help`);t.includes(n)||t.push(n)}}return t.length>0?t.join(`,`):void 0}function _c(e){return e.some(e=>(e.profile?.seats?.length??0)>0)}function vc(e){let t=e?.trim();if(t)return/\s/u.test(t)&&hc(`A seat account, command, or credential must be a single token`,`The seat command is an executable path, not a shell line`),t}function yc(e){let t=vc(e.seatAccount),n=vc(e.seatCommand),r=vc(e.seatCredential);return r&&!n&&!t&&hc(`A seat credential needs a seat command`,`The credential is an argument to the configured command`,`tangle graph run --seat-command <program>`),{...t?{account:t}:{},...n?{command:n}:{},...r?{credential:r}:{}}}function bc(e){if(e.seats===void 0)return e;let{seats:t,...n}=e;return n}async function xc(e,t,n){if(e.account)return e.account;e.command||hc(`This graph needs a seat account or a seat command`,`No account was authored and no seat command is configured`,`tangle graph run --seat-account <account>`);let r=``;try{r=(await mc(e.command,[t,...e.credential?[e.credential]:[]],{timeout:3e4,maxBuffer:4096,signal:n,encoding:`utf8`})).stdout}catch(e){n.throwIfAborted();let t=e.code===`ENOENT`;hc(t?`The seat command was not found`:`The seat command failed`,t?`The configured executable is not on PATH`:`The seat command exited without an account id`)}let i=r.trim();return(!i||/\s/u.test(i))&&hc(`The seat command did not print an account id`,`The command must print one account id and nothing else`),i}function Sc(e,t,n){let r=new Map;return async i=>{n.throwIfAborted();let a=i.stage.harness,o=i.stage.selector.kind===`seat`?i.stage.selector.id.trim():``,s=`${a}\0${t.credential??``}`,c=o||t.account||r.get(s)||await xc(t,a,n);return!o&&!t.account&&r.set(s,c),(!c||/\s/u.test(c)||i.resumeSeatId!==void 0&&i.resumeSeatId!==c)&&hc(`Node '${i.nodeId}' has no seat account`,`The authored seat, account flag, or seat command did not yield one`),{seat:c,backend:{backend:`provider`,provider:Ze({baseUrl:e.bridgeUrl,bearerToken:e.bridgeBearer}),runtime:`cli`,outputFormat:`json`,destroyOnSettle:!0,requireTerminalEvent:!0,profileForCreate:bc}}}}function Z(e){return Hr({signal:e.signal,...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.baseUrl===void 0?{}:{baseUrl:e.baseUrl}})}const Cc=N.object({version:N.literal(1),type:N.enum([`state`,`ack`,`error`,`event`]),requestId:N.string().optional(),operationId:N.string().optional(),command:N.string().optional(),code:N.string().optional(),message:N.string().optional(),result:N.unknown().optional()}).passthrough(),wc=N.object({state:N.object({runConfiguration:N.unknown()}),view:N.object({capabilities:N.record(N.string(),N.object({available:N.boolean(),reason:N.string().optional()}))})}),Tc=N.object({status:N.enum([`completed`,`failed`,`cancelled`]),analysis:N.object({id:N.string().min(1)}).passthrough(),source:N.object({runtimeRun:N.unknown()}).passthrough()}).passthrough(),Ec=`TANGLE_GRAPH_ANALYSIS_SOURCE`;async function Dc(e,t,n){if(!e.startsWith(`wfrun_`)){let t=j(await Ge(j(M(),`.tangle`)),`runs`,e);if(await Ge(t)!==t)throw new V(`RUN_NOT_FOUND`,`The run directory redirects elsewhere`,`Use the recorded local run directory`,`tangle graph inspect --help`);return{source:`runtime:${e}@${t}`,env:{},schema:N.object({runId:N.literal(e),runDir:N.literal(t)})}}let r={signal:n,...t.apiKey===void 0?{}:{apiKey:t.apiKey},...t.baseUrl===void 0?{}:{baseUrl:t.baseUrl}},i=await Z(r),a=N.object({id:N.literal(e),workflowId:N.string(),revUsed:N.number().int(),execution:N.object({kind:N.literal(`graph`),sourceSha:N.string(),authoredGraphDigest:N.string(),graphDigest:N.string()}),runtime:N.object({snapshot:N.object({supervisors:N.tuple([N.object({id:N.string()})])})})}).parse(await i.workflows.getRun(e,{signal:n})),o=a.runtime.snapshot.supervisors[0];if(!o)throw new V(`BRAID_RPC_FAILED`,`The cloud run has no retained Runtime root`,`Wait for execution evidence before analysis`,`tangle graph inspect ${e}`);let s=await Rr(r);if(new URL(s.baseUrl.replace(/\/+$/,``)).href!==new URL(i.baseUrl.replace(/\/+$/,``)).href)throw new V(`AUTH_REQUIRED`,`The analysis source origin changed`,`Use the same authenticated platform origin`,`tangle auth status --json`);return{source:`runtime:${e}@${Ec}`,env:{[Ec]:JSON.stringify({url:`${s.baseUrl.replace(/\/+$/,``)}/v1/workflows/runs/${encodeURIComponent(e)}`,headers:{Authorization:`Bearer ${s.token}`}})},schema:N.object({runId:N.literal(e),remoteEndpointEnv:N.literal(Ec),checkpoint:N.object({workflowId:N.literal(a.workflowId),runtimeRunId:N.literal(o.id),revUsed:N.literal(a.revUsed),sourceSha:N.literal(a.execution.sourceSha),authoredGraphDigest:N.literal(a.execution.authoredGraphDigest),graphDigest:N.literal(a.execution.graphDigest)})})}}async function Oc(e,t){if(!e.startsWith(`wfrun_`)&&!N.uuid().safeParse(e).success)throw new V(`RUN_NOT_FOUND`,`Use a recorded graph run ID`,`The run identifier is invalid`,`tangle graph inspect --help`);if(!Number.isSafeInteger(t.timeout)||t.timeout<1)throw new V(`INVALID_TIMEOUT`,`Use a positive analysis timeout`,`The timeout must be an integer number of milliseconds`,`tangle graph analyze --help`);let n=t.profile;if(!n?.trim())throw new V(`USAGE_INVALID`,`Select the canonical analysis profile`,`Graph analysis requires an existing canonical AgentProfile reference`,`tangle graph analyze `+e+` --profile <name|path>`);let r=/^(?:\.\.?)[/\\]/.test(n)?ve(process.cwd(),n):n;return ic(t.signal,async n=>{let i=await Dc(e,t,n),a=i.source;return ql({signal:n,errorRunId:e},async n=>{let o=await n.bridge(),s=await He(j(n.runDir,`analysis-`)),c=j(s,`config.json`),l=j(s,`database.key`),u=j(s,`state.sqlite`),d=`connection-owned-graph-bridge`,f=new Date().toISOString();await Ke(l,te(32),{mode:384,flag:`wx`}),await Ke(c,JSON.stringify({format:`braid-startup-config`,schemaVersion:2,profile:r,connectionId:d,connections:[{id:d,name:`Graph analysis`,kind:`cli-bridge`,endpoint:o.bridgeUrl,providerOptions:{transport:`local`},createdAt:f,updatedAt:f,lastHealth:{status:`unknown`}}]}),{mode:384,flag:`wx`});let p=n.signal,m=`op-${w()}`,h=`op-${w()}`,g=`${m}:initialize`,_=`${m}:analyze`,v=`${m}:shutdown`,y={version:1,requestId:g,command:`initialize`,params:{workspace:n.cwd,subscribe:!1}},b={version:1,requestId:_,operationId:m,command:`analyze`,params:{source:a,recipe:`all`,totalTimeoutMs:t.timeout}},ee={version:1,requestId:v,operationId:h,command:`shutdown`,params:{mode:`wait`}},x,S,C,T,ne={transform:e=>{let t=Cc.parse(e);return t.type===`error`||t.type===`state`&&t.requestId===g||t.type===`ack`&&[_,v].includes(t.requestId??``)?t:null},onError:e=>{T??=e},onEvent:e=>{e.type===`error`&&(T??=new V(e.code??`BRAID_RPC_FAILED`,`Braid refused graph analysis`,e.message??`The RPC response omitted its cause`,`tangle graph analyze --help`)),e.requestId===g&&e.type===`state`&&(x??=e),e.requestId===_&&e.type===`ack`&&(S??=e),e.requestId===v&&e.type===`ack`&&(C??=e)}},E=await ze({command:process.env.BRAID_BIN??`braid`,args:[`rpc`,`--workspace`,n.cwd,`--config`,c,`--profile`,r,`--database-key-file`,l],cwd:n.cwd,env:{...i.env,BRAID_STATE_PATH:u,BRAID_CLI_BRIDGE_ENDPOINT:o.bridgeUrl,BRAID_CLI_BRIDGE_AUTH:o.bridgeBearer},timeoutMs:t.timeout,signal:p,ownProcessGroup:!0},ne,{stdin:[y,...t.dryRun?[]:[b],ee].map(e=>JSON.stringify(e)).join(`
150
150
  `)+`
151
- `});if(T)throw T;let ne=D.exit;if(!ne.success||!x||!C||C.operationId!==h||C.command!==`shutdown`)throw new V(`BRAID_RPC_FAILED`,`Braid graph analysis did not finish`,ne.spawnError??ne.timeoutDiagnostic??ne.stdinError??ne.processGroupError??ne.captureError??ne.terminateError??(D.stderr||`Exit ${ne.code}, signal ${ne.signal}; complete shutdown acknowledgement: ${!!C}`),`npm install --global @tangle-network/braid`);let re=mc.parse(x),ie=re.view.capabilities[`analysis.recipe`];if(t.dryRun)return{source:a,statePath:u,configuration:re.state.runConfiguration,capability:ie};if(!S||S.operationId!==m||S.command!==`analyze`)throw Error(`Braid did not acknowledge this analysis operation`);let ae=hc.parse(S.result);if(!i.schema.safeParse(ae.source.runtimeRun).success)throw new V(`BRAID_RPC_FAILED`,`Braid returned analysis of another source`,`Its saved run or immutable checkpoint identity does not match this request`,`tangle graph inspect ${e}`);return{...ae,statePath:u}})},`tangle graph analyze ${e}`)}function yc(e){e.command(`analyze <run>`).description(`Analyze retained graph evidence through Braid`).addHelpText(`after`,`
151
+ `});if(T)throw T;let D=E.exit;if(!D.success||!x||!C||C.operationId!==h||C.command!==`shutdown`)throw new V(`BRAID_RPC_FAILED`,`Braid graph analysis did not finish`,D.spawnError??D.timeoutDiagnostic??D.stdinError??D.processGroupError??D.captureError??D.terminateError??(E.stderr||`Exit ${D.code}, signal ${D.signal}; complete shutdown acknowledgement: ${!!C}`),`npm install --global @tangle-network/braid`);let re=wc.parse(x),ie=re.view.capabilities[`analysis.recipe`];if(t.dryRun)return{source:a,statePath:u,configuration:re.state.runConfiguration,capability:ie};if(!S||S.operationId!==m||S.command!==`analyze`)throw Error(`Braid did not acknowledge this analysis operation`);let ae=Tc.parse(S.result);if(!i.schema.safeParse(ae.source.runtimeRun).success)throw new V(`BRAID_RPC_FAILED`,`Braid returned analysis of another source`,`Its saved run or immutable checkpoint identity does not match this request`,`tangle graph inspect ${e}`);return{...ae,statePath:u}})},`tangle graph analyze ${e}`)}function kc(e){e.command(`analyze <run>`).description(`Analyze retained graph evidence through Braid`).addHelpText(`after`,`
152
152
  Requires the Braid companion CLI: npm install --global @tangle-network/braid.
153
153
  BRAID_BIN may select its installed executable. Select an existing canonical AgentProfile with --profile. Analysis uses the owned subscription-only Bridge.
154
- `).requiredOption(`--profile <name|path>`,`Use a canonical analysis AgentProfile, distinct from the Tangle account profile`).option(`--dry-run`,`Inspect Braid's selected analysis configuration without dispatch`).option(`--timeout <ms>`,`Bound the analysis process in milliseconds`,Number,3e5).action(async(e,t)=>{let n=await vc(e,t);I(n),`status`in n&&n.status!==`completed`&&(process.exitCode=1)})}const bc=1e3;function xc(e,t){return[...t,e]}function Sc(e,t=`input`,n){if(n===void 0&&!e?.length)return;let r={};if(n!==void 0)try{if(r=JSON.parse(k(n,`utf8`)),!r||typeof r!=`object`||Array.isArray(r)||Object.entries(r).some(([e,t])=>!e.length||typeof t!=`string`))throw Error(`Invalid input map`)}catch{throw new V(`WORKFLOW_INPUT_FILE_INVALID`,`Could not load --input-file '${n}'`,`Expected a readable JSON object with nonempty keys and string values`,`tangle workflows run --help`)}let i=Object.entries(r);for(let n of e??[]){let e=n.indexOf(`=`);if(e<=0)throw Error(`Invalid --${t} "${n}": expected key=value (e.g. pull_request.number=123)`);i.push([n.slice(0,e),n.slice(e+1)])}return Object.fromEntries(i)}function Cc(e){F(e.map(e=>({id:e.id,status:e.status,attempts:e.attempts,created:e.createdAt,completed:e.completedAt??``})),[{key:`id`,header:`Run ID`},{key:`status`,header:`Status`},{key:`attempts`,header:`Attempts`},{key:`created`,header:`Created`},{key:`completed`,header:`Completed`}])}function wc(e){if(B({"Run ID":e.id,Workflow:e.workflowId,Status:e.status,Error:e.error??``,Attempts:e.attempts,Created:e.createdAt,Started:e.startedAt??``,Completed:e.completedAt??``}),e.actionResults.length>0){R(`Actions`);let t=e.actionResults.some(e=>e.nodeId!==void 0||e.visit!==void 0);F(e.actionResults.map(e=>({index:e.index,...t?{node:e.nodeId??``,visit:e.visit??``}:{},kind:e.kind,status:e.status,error:e.error??``,cost:e.costUsd??``})),[{key:`index`,header:`#`},...t?[{key:`node`,header:`Node`},{key:`visit`,header:`Visit`}]:[],{key:`kind`,header:`Kind`},{key:`status`,header:`Status`},{key:`error`,header:`Error`},{key:`cost`,header:`Cost (USD)`}])}e.graph&&(R(`Graph`),B({Nodes:e.graph.nodes.length,Edges:e.graph.edges.length,"Max node visits":e.graph.maxNodeVisits}),F(e.graph.edges.map(e=>({from:e.from,to:e.to,guard:e.when===void 0?``:JSON.stringify(e.when)})),[{key:`from`,header:`From`},{key:`to`,header:`To`},{key:`guard`,header:`Guard`}])),e.edgeVerdicts&&e.edgeVerdicts.length>0&&(R(`Edge verdicts`),F(e.edgeVerdicts.flatMap(e=>Object.entries(e.verdicts).map(([t,n])=>({node:e.nodeId,edge:t,verdict:n?`taken`:`not taken`}))),[{key:`node`,header:`Node`},{key:`edge`,header:`Edge`},{key:`verdict`,header:`Verdict`}]))}function Tc(e){if(e.status===`cancelled`){R(`Cancelled run ${e.runId}.`);return}if(e.signalled){R(`Cancelling run ${e.runId} — signalled the worker; it will stop shortly.`);return}R(`Requested cancellation of run ${e.runId}, but couldn't confirm it — the run may have just finished, or it's running on another instance and will stop on its own.`)}function Ec(e){switch(e.type){case`snapshot`:R(`snapshot: ${e.run.status} (${e.run.actionResults.length} action(s))`);break;case`action.started`:console.log(`→ action[${e.index}] ${e.kind} started`);break;case`action.finished`:{let t=e.status===`succeeded`?`✓`:e.status===`skipped`?`⊘`:`✗`;console.log(`${t} action[${e.index}] ${e.kind} ${e.status}${e.error?`: ${e.error}`:``}`);break}case`iteration.started`:console.log(` · action[${e.actionIndex}] iteration ${e.iterationIndex} started`);break;case`iteration.ended`:console.log(` · action[${e.actionIndex}] iteration ${e.iterationIndex} ${e.status}`);break;case`token`:typeof e.delta==`string`&&process.stdout.write(e.delta);break;case`ping`:break;case`run.done`:console.log(`\nrun.done: ${e.status}${e.error?`: ${e.error}`:``}`);break;case`run.waiting`:console.log(`\nrun.waiting: parked on a human decision (${e.decisionId}) — resolve it to resume`);break}}function Dc(e){e.command(`run`).description(`Trigger an immediate run of a workflow`).argument(`<id>`,`Workflow ID`).option(`--input-file <file>`,`Trigger inputs from a flat JSON string map; --input overrides its keys`).option(`--input <key=value>`,`Trigger input as key=value (e.g. pull_request.number=123). Repeatable.`,xc,[]).option(`--wait`,`Wait for the run to finish and print its result`).option(`--timeout <ms>`,`With --wait, fail if the run has not finished after this many milliseconds`).option(`--poll-interval <ms>`,`With --wait, how often to poll for completion (default 2000)`).action(async(e,t)=>{let n=Sc(t.input,`input`,t.inputFile),r=t.timeout===void 0?void 0:ro(t.timeout,`--timeout`),i=t.pollInterval===void 0?void 0:ro(t.pollInterval,`--poll-interval`),a=await Z(t),{runId:o}=await a.workflows.run(e,n);if(!t.wait){if(t.json)return I({runId:o});R(`Started run ${o} for workflow ${e}.`),R(`Inspect it with: tangle workflows run-detail ${e} ${o}`);return}let s=t.json?null:z(`Waiting for run ${o} to finish...`).start(),c;try{c=await a.workflows.waitForRun(e,o,{...r===void 0?{}:{timeoutMs:r},...i===void 0?{}:{pollIntervalMs:i}})}finally{s?.stop()}if(c.status===`failed`&&(process.exitCode=1),t.json)return I(c);wc(c)}),e.command(`runs`).description(`List a workflow's run history (newest first)`).argument(`<id>`,`Workflow ID`).option(`--limit <n>`,`Runs per page (1-100)`).option(`--cursor <cursor>`,`Pagination cursor from a previous page`).option(`--all`,`Fetch every page, not just the first`).action(async(e,t)=>{let n=await Z(t),r=t.limit===void 0?void 0:ro(t.limit,`--limit`);if(t.all){let i=[],a=t.cursor,o=0,s=null;for(;;){let c=await n.workflows.listRuns(e,{...r===void 0?{}:{limit:r},...a===void 0?{}:{cursor:a}});if(i.push(...c.runs),o+=1,!c.nextCursor)break;if(o>=bc){s=c.nextCursor,t.json||R(`Stopped after ${bc} pages (${i.length} runs); more may exist — resume with --cursor ${c.nextCursor}`);break}a=c.nextCursor}if(t.json)return I({runs:i,nextCursor:s});Cc(i);return}let i=await n.workflows.listRuns(e,{...r===void 0?{}:{limit:r},...t.cursor===void 0?{}:{cursor:t.cursor}});if(t.json)return I(i);Cc(i.runs),i.nextCursor&&R(`More runs available — next page: --cursor ${i.nextCursor}`)}),e.command(`run-detail`).description(`Show a single run's detail (per-action output and errors)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Z(n)).workflows.getRun(e,t);if(n.json)return I(r);wc(r)}),e.command(`cancel`).description(`Cancel a queued or in-progress run`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Z(n)).workflows.cancel(e,t);if(n.json)return I(r);Tc(r)}),e.command(`retry`).description(`Re-run a failed or cancelled run (a fresh run with the same trigger context)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID of the failed/cancelled run to retry`).option(`--wait`,`Wait for the new run to finish and print its result`).option(`--timeout <ms>`,`With --wait, fail if the run has not finished after this many milliseconds`).option(`--poll-interval <ms>`,`With --wait, how often to poll for completion (default 2000)`).action(async(e,t,n)=>{let r=n.timeout===void 0?void 0:ro(n.timeout,`--timeout`),i=n.pollInterval===void 0?void 0:ro(n.pollInterval,`--poll-interval`),a=await Z(n),o=await a.workflows.retryRun(e,t);if(!n.wait){if(n.json)return I(o);R(`Started run ${o.runId} (retry of ${t}).`),R(`Inspect it with: tangle workflows run-detail ${e} ${o.runId}`);return}let s=n.json?null:z(`Waiting for run ${o.runId} to finish...`).start(),c;try{c=await a.workflows.waitForRun(e,o.runId,{...r===void 0?{}:{timeoutMs:r},...i===void 0?{}:{pollIntervalMs:i}})}finally{s?.stop()}if(c.status===`failed`&&(process.exitCode=1),n.json)return I(c);wc(c)}),e.command(`events`).description(`Tail a run's live progress events until it finishes`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await Z(n);for await(let i of r.workflows.watchRun(e,t))n.json?console.log(JSON.stringify(i)):Ec(i),i.type===`run.done`&&i.status===`failed`&&(process.exitCode=1)})}async function Oc(e,t,n,r){let i=await Z({...n,signal:r}),a=Pl(t),o=Sc(n.param,`param`),s={name:pe(e).replace(/(\.graph)?\.(yaml|yml|json)$/i,``),...o?{params:o}:{},...n.seat?{seat:n.seat}:{}},c,l;if(n.resume){let e=await i.workflows.getRun(n.resume,{signal:r});e.id!==n.resume&&X(`The cloud owner returned another run identity`);let t=e.execution;if((t?.kind!==`graph`||t.sourceSha!==a)&&X(`The authored cloud graph source changed`),Object.entries(o??{}).some(([e,n])=>!Object.hasOwn(t.params,e)||ie(t.params[e])!==ie(n))&&X(`A recorded cloud graph parameter changed`),n.seat!==void 0&&n.seat!==t.deploy.seat&&X(`The recorded cloud seat override changed`),n.dryRun)return{run:e};if((e.status===`cancelled`||e.status===`failed`)&&X(`The cloud run is terminal: ${e.status}`),e.status===`succeeded`)return e.graphResult||X(`The settled cloud run has no retained Runtime result`),{workflowId:e.workflowId,runId:e.id,sourceDigest:a,result:e.graphResult,replayed:!0,viewerUrl:`${i.baseUrl}/app/workflows/${encodeURIComponent(e.workflowId)}/runs/${encodeURIComponent(e.id)}`};if(e.recovery?.state===`running`)return{workflowId:e.workflowId,runId:e.id,sourceDigest:a,run:e,attached:!0,viewerUrl:`${i.baseUrl}/app/workflows/${encodeURIComponent(e.workflowId)}/runs/${encodeURIComponent(e.id)}`};e.recovery?.state!==`queued`&&e.recovery?.state!==`recoverable`&&X(`The owner has not confirmed recovery eligibility`),c=e.workflowId,l=e.revUsed??X(`The captured cloud revision is unavailable`)}else{if(n.dryRun)return i.workflows.validate(t,{format:`graph`,deploy:s});let e=await i.workflows.create(t,{format:`graph`,deploy:s});c=e.id,l=e.headRev??X(`The cloud workflow has no retained revision`)}r.throwIfAborted();let u=await i.workflows.run(c,void 0,{signal:r,sourceSha:a,expectedRev:l,...n.resume?{resumeRunId:n.resume}:{}});return n.resume&&u.runId!==n.resume&&X(`The cloud owner recovered another run identity`),{...u,workflowId:c,sourceDigest:a,viewerUrl:`${i.baseUrl}/app/workflows/${encodeURIComponent(c)}/runs/${encodeURIComponent(u.runId)}`}}const kc=[`claude-code`,`opencode`,`codex`,`kimi-code`,`prime`],Ac=process.env.TANGLE_ROUTER_URL??`https://router.tangle.tools/v1`;function jc(e){let t=ae(e);if(t)return t;throw Error(`--model '${e}' has no provider. Pass a canonical id, for example 'google/${e}'.`)}function Mc(e){let t=e.harness??`claude-code`;if(!kc.includes(t))throw Error(`Unknown --harness '${t}'. Supported: ${kc.join(`, `)}.`);let n=Nc(e.maxTokens,2e5,`--max-tokens`),r=Nc(e.maxIterations,50,`--max-iterations`),i=e.maxWorkers===void 0?void 0:Nc(e.maxWorkers,0,`--max-workers`);return{harness:t,...e.model?{model:e.model}:{},maxTokens:n,maxIterations:r,...i===void 0?{}:{maxWorkers:i}}}function Nc(e,t,n){if(e===void 0)return t;let r=Number.parseInt(e,10);if(!Number.isFinite(r)||r<=0)throw Error(`${n} must be a positive integer, got '${e}'.`);return r}function Pc(e){let t={maxTokens:e.maxTokens,maxIterations:e.maxIterations};return e.maxWorkers===void 0?{budget:t}:{budget:t,perWorker:{maxTokens:Math.max(1,Math.floor(e.maxTokens/e.maxWorkers)),maxIterations:Math.max(1,Math.floor(e.maxIterations/e.maxWorkers))}}}function Fc(e){let t=e.spentTotal,n=e.kind===`no-winner`?``:e.out;return{text:typeof n==`string`?n:typeof n==`object`&&n&&`content`in n&&typeof n.content==`string`?n.content:JSON.stringify(n),tokenUsage:{input:t.tokensKnown===!1?null:t.tokens.input,output:t.tokensKnown===!1?null:t.tokens.output},costUsd:t.usdKnown===!1?null:t.usd,status:e.kind===`no-winner`?`no-winner (${e.reason})`:`winner`}}let Ic=null;function Lc(){return Ic??=import(`@tangle-network/agent-runtime/kernel`).catch(e=>{throw Ic=null,e?.code===`ERR_MODULE_NOT_FOUND`?new V(`RUNTIME_UNAVAILABLE`,`Agent Runtime could not be loaded`,e.message,`npm install -g @tangle-network/sandbox-cli@latest`):e}),Ic}async function Rc(e,t,n){let r=W({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=G(r),{budget:a,perWorker:o}=Pc(t),s=[],c={async create(e){let{TANGLE_API_KEY:t,...r}=e?.env??{},a=await i.create(e?.env?{...e,env:r}:e);return s.push({id:a.id,status:`spawned`}),n.json||R(`worker ${a.id} spawned`),a}},l=await Lc(),u=l.workerFromBackend({backend:`sandbox`,sandboxClient:c,maxIterations:1}),d=(e,n)=>u({...e,harness:t.harness},n),f={name:`supervisor`,harness:`cli-base`,model:{default:t.model??`gemini-3.5-flash-lite`,provider:t.model?jc(t.model):`google`},tools:{agent_runtime_coordination_spawn_worker:!0,agent_runtime_coordination_observe_agent:!0}},p={routerBaseUrl:Ac,routerKey:r.apiKey},m=Fc(await l.supervise(f,{goal:e},{budget:a,makeWorkerAgent:d,router:p,...o?{perWorker:o}:{},...t.model?{allowedModels:[t.model]}:{},runId:`supervise-${w()}`})),h=m.status===`winner`?`settled`:`failed`;for(let e of s)e.status=h,n.json||R(`worker ${e.id} settled (${e.status})`);return{task:e,result:m.text,workers:s,tokenUsage:m.tokenUsage,costUsd:m.costUsd,status:m.status}}function zc(){let e=new x(`supervise`);return e.description(`Run a budget-conserving supervisor that spawns isolated sandbox workers to deliver a task.`).argument(`<task>`,`What the supervisor should accomplish`).option(`--harness <name>`,`Worker harness (${kc.join(` | `)})`,`claude-code`).option(`--model <id>`,`Model for the supervisor + workers`).option(`--max-tokens <n>`,`Conserved token budget for the whole run`,`200000`).option(`--max-iterations <n>`,`Conserved iteration budget for the whole run`,`50`).option(`--max-workers <n>`,`Bound the fanout; each worker reserves floor(max-tokens / n) tokens and floor(max-iterations / n) iterations`).action(async(e,t)=>{let n=Mc({harness:t.harness,model:t.model,maxTokens:t.maxTokens,maxIterations:t.maxIterations,maxWorkers:t.maxWorkers});t.json||(R(`Supervising: ${e}`),R(`harness=${n.harness} budget=${n.maxTokens}tok/${n.maxIterations}it`),console.log());let r=await Rc(e,n,{apiKey:t.apiKey,baseUrl:t.baseUrl,json:t.json});if(t.json){I(r),r.status!==`winner`&&(process.exitCode=1);return}if(console.log(),r.result&&(console.log(r.result),console.log()),B({"Input Tokens":r.tokenUsage.input??`Unavailable`,"Output Tokens":r.tokenUsage.output??`Unavailable`,Cost:r.costUsd===null?`Unavailable`:`$${r.costUsd.toFixed(4)}`}),r.status!==`winner`)throw Error(`Supervisor finished without a winner: ${r.status}`)}),e}const Bc=Ye(Se),Vc=async(e,...t)=>{let n={maxBuffer:1<<28};return(await Bc(`bash`,[`-ec`,e,`graph-improve`,...t],n)).stdout.trim()},Hc=j(M(),`.tangle`,`graph-improve`,`v5`),Uc=j(M(),`.tangle`,`workspaces`),Wc=e=>!!e&&e.owner!==`work`&&e.code!==`budget-exhausted`;async function Gc(e){await Ve(j(e,`bin`)),await Ve(j(e,`remotes`));let t=`#!/bin/sh
154
+ `).requiredOption(`--profile <name|path>`,`Use a canonical analysis AgentProfile, distinct from the Tangle account profile`).option(`--dry-run`,`Inspect Braid's selected analysis configuration without dispatch`).option(`--timeout <ms>`,`Bound the analysis process in milliseconds`,Number,3e5).action(async(e,t)=>{let n=await Oc(e,t);I(n),`status`in n&&n.status!==`completed`&&(process.exitCode=1)})}const Ac=1e3;function jc(e,t){return[...t,e]}function Mc(e,t=`input`,n){if(n===void 0&&!e?.length)return;let r={};if(n!==void 0)try{if(r=JSON.parse(k(n,`utf8`)),!r||typeof r!=`object`||Array.isArray(r)||Object.entries(r).some(([e,t])=>!e.length||typeof t!=`string`))throw Error(`Invalid input map`)}catch{throw new V(`WORKFLOW_INPUT_FILE_INVALID`,`Could not load --input-file '${n}'`,`Expected a readable JSON object with nonempty keys and string values`,`tangle workflows run --help`)}let i=Object.entries(r);for(let n of e??[]){let e=n.indexOf(`=`);if(e<=0)throw Error(`Invalid --${t} "${n}": expected key=value (e.g. pull_request.number=123)`);i.push([n.slice(0,e),n.slice(e+1)])}return Object.fromEntries(i)}function Nc(e){F(e.map(e=>({id:e.id,status:e.status,attempts:e.attempts,created:e.createdAt,completed:e.completedAt??``})),[{key:`id`,header:`Run ID`},{key:`status`,header:`Status`},{key:`attempts`,header:`Attempts`},{key:`created`,header:`Created`},{key:`completed`,header:`Completed`}])}function Pc(e){if(B({"Run ID":e.id,Workflow:e.workflowId,Status:e.status,Error:e.error??``,Attempts:e.attempts,Created:e.createdAt,Started:e.startedAt??``,Completed:e.completedAt??``}),e.actionResults.length>0){R(`Actions`);let t=e.actionResults.some(e=>e.nodeId!==void 0||e.visit!==void 0);F(e.actionResults.map(e=>({index:e.index,...t?{node:e.nodeId??``,visit:e.visit??``}:{},kind:e.kind,status:e.status,error:e.error??``,cost:e.costUsd??``})),[{key:`index`,header:`#`},...t?[{key:`node`,header:`Node`},{key:`visit`,header:`Visit`}]:[],{key:`kind`,header:`Kind`},{key:`status`,header:`Status`},{key:`error`,header:`Error`},{key:`cost`,header:`Cost (USD)`}])}e.graph&&(R(`Graph`),B({Nodes:e.graph.nodes.length,Edges:e.graph.edges.length,"Max node visits":e.graph.maxNodeVisits}),F(e.graph.edges.map(e=>({from:e.from,to:e.to,guard:e.when===void 0?``:JSON.stringify(e.when)})),[{key:`from`,header:`From`},{key:`to`,header:`To`},{key:`guard`,header:`Guard`}])),e.edgeVerdicts&&e.edgeVerdicts.length>0&&(R(`Edge verdicts`),F(e.edgeVerdicts.flatMap(e=>Object.entries(e.verdicts).map(([t,n])=>({node:e.nodeId,edge:t,verdict:n?`taken`:`not taken`}))),[{key:`node`,header:`Node`},{key:`edge`,header:`Edge`},{key:`verdict`,header:`Verdict`}]))}function Fc(e){if(e.status===`cancelled`){R(`Cancelled run ${e.runId}.`);return}if(e.signalled){R(`Cancelling run ${e.runId} — signalled the worker; it will stop shortly.`);return}R(`Requested cancellation of run ${e.runId}, but couldn't confirm it — the run may have just finished, or it's running on another instance and will stop on its own.`)}function Ic(e){switch(e.type){case`snapshot`:R(`snapshot: ${e.run.status} (${e.run.actionResults.length} action(s))`);break;case`action.started`:console.log(`→ action[${e.index}] ${e.kind} started`);break;case`action.finished`:{let t=e.status===`succeeded`?`✓`:e.status===`skipped`?`⊘`:`✗`;console.log(`${t} action[${e.index}] ${e.kind} ${e.status}${e.error?`: ${e.error}`:``}`);break}case`iteration.started`:console.log(` · action[${e.actionIndex}] iteration ${e.iterationIndex} started`);break;case`iteration.ended`:console.log(` · action[${e.actionIndex}] iteration ${e.iterationIndex} ${e.status}`);break;case`token`:typeof e.delta==`string`&&process.stdout.write(e.delta);break;case`ping`:break;case`run.done`:console.log(`\nrun.done: ${e.status}${e.error?`: ${e.error}`:``}`);break;case`run.waiting`:console.log(`\nrun.waiting: parked on a human decision (${e.decisionId}) — resolve it to resume`);break}}function Lc(e){e.command(`run`).description(`Trigger an immediate run of a workflow`).argument(`<id>`,`Workflow ID`).option(`--input-file <file>`,`Trigger inputs from a flat JSON string map; --input overrides its keys`).option(`--input <key=value>`,`Trigger input as key=value (e.g. pull_request.number=123). Repeatable.`,jc,[]).option(`--wait`,`Wait for the run to finish and print its result`).option(`--timeout <ms>`,`With --wait, fail if the run has not finished after this many milliseconds`).option(`--poll-interval <ms>`,`With --wait, how often to poll for completion (default 2000)`).action(async(e,t)=>{let n=Mc(t.input,`input`,t.inputFile),r=t.timeout===void 0?void 0:io(t.timeout,`--timeout`),i=t.pollInterval===void 0?void 0:io(t.pollInterval,`--poll-interval`),a=await Z(t),{runId:o}=await a.workflows.run(e,n);if(!t.wait){if(t.json)return I({runId:o});R(`Started run ${o} for workflow ${e}.`),R(`Inspect it with: tangle workflows run-detail ${e} ${o}`);return}let s=t.json?null:z(`Waiting for run ${o} to finish...`).start(),c;try{c=await a.workflows.waitForRun(e,o,{...r===void 0?{}:{timeoutMs:r},...i===void 0?{}:{pollIntervalMs:i}})}finally{s?.stop()}if(c.status===`failed`&&(process.exitCode=1),t.json)return I(c);Pc(c)}),e.command(`runs`).description(`List a workflow's run history (newest first)`).argument(`<id>`,`Workflow ID`).option(`--limit <n>`,`Runs per page (1-100)`).option(`--cursor <cursor>`,`Pagination cursor from a previous page`).option(`--all`,`Fetch every page, not just the first`).action(async(e,t)=>{let n=await Z(t),r=t.limit===void 0?void 0:io(t.limit,`--limit`);if(t.all){let i=[],a=t.cursor,o=0,s=null;for(;;){let c=await n.workflows.listRuns(e,{...r===void 0?{}:{limit:r},...a===void 0?{}:{cursor:a}});if(i.push(...c.runs),o+=1,!c.nextCursor)break;if(o>=Ac){s=c.nextCursor,t.json||R(`Stopped after ${Ac} pages (${i.length} runs); more may exist — resume with --cursor ${c.nextCursor}`);break}a=c.nextCursor}if(t.json)return I({runs:i,nextCursor:s});Nc(i);return}let i=await n.workflows.listRuns(e,{...r===void 0?{}:{limit:r},...t.cursor===void 0?{}:{cursor:t.cursor}});if(t.json)return I(i);Nc(i.runs),i.nextCursor&&R(`More runs available — next page: --cursor ${i.nextCursor}`)}),e.command(`run-detail`).description(`Show a single run's detail (per-action output and errors)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Z(n)).workflows.getRun(e,t);if(n.json)return I(r);Pc(r)}),e.command(`cancel`).description(`Cancel a queued or in-progress run`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Z(n)).workflows.cancel(e,t);if(n.json)return I(r);Fc(r)}),e.command(`retry`).description(`Re-run a failed or cancelled run (a fresh run with the same trigger context)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID of the failed/cancelled run to retry`).option(`--wait`,`Wait for the new run to finish and print its result`).option(`--timeout <ms>`,`With --wait, fail if the run has not finished after this many milliseconds`).option(`--poll-interval <ms>`,`With --wait, how often to poll for completion (default 2000)`).action(async(e,t,n)=>{let r=n.timeout===void 0?void 0:io(n.timeout,`--timeout`),i=n.pollInterval===void 0?void 0:io(n.pollInterval,`--poll-interval`),a=await Z(n),o=await a.workflows.retryRun(e,t);if(!n.wait){if(n.json)return I(o);R(`Started run ${o.runId} (retry of ${t}).`),R(`Inspect it with: tangle workflows run-detail ${e} ${o.runId}`);return}let s=n.json?null:z(`Waiting for run ${o.runId} to finish...`).start(),c;try{c=await a.workflows.waitForRun(e,o.runId,{...r===void 0?{}:{timeoutMs:r},...i===void 0?{}:{pollIntervalMs:i}})}finally{s?.stop()}if(c.status===`failed`&&(process.exitCode=1),n.json)return I(c);Pc(c)}),e.command(`events`).description(`Tail a run's live progress events until it finishes`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await Z(n);for await(let i of r.workflows.watchRun(e,t))n.json?console.log(JSON.stringify(i)):Ic(i),i.type===`run.done`&&i.status===`failed`&&(process.exitCode=1)})}async function Rc(e,t,n,r){let i=await Z({...n,signal:r}),a=Wl(t),o=Mc(n.param,`param`),s={name:pe(e).replace(/(\.graph)?\.(yaml|yml|json)$/i,``),...o?{params:o}:{},...n.seat?{seat:n.seat}:{}},c,l;if(n.resume){let e=await i.workflows.getRun(n.resume,{signal:r});e.id!==n.resume&&X(`The cloud owner returned another run identity`);let t=e.execution;if((t?.kind!==`graph`||t.sourceSha!==a)&&X(`The authored cloud graph source changed`),Object.entries(o??{}).some(([e,n])=>!Object.hasOwn(t.params,e)||ie(t.params[e])!==ie(n))&&X(`A recorded cloud graph parameter changed`),n.seat!==void 0&&n.seat!==t.deploy.seat&&X(`The recorded cloud seat override changed`),n.dryRun)return{run:e};if((e.status===`cancelled`||e.status===`failed`)&&X(`The cloud run is terminal: ${e.status}`),e.status===`succeeded`)return e.graphResult||X(`The settled cloud run has no retained Runtime result`),{workflowId:e.workflowId,runId:e.id,sourceDigest:a,result:e.graphResult,replayed:!0,viewerUrl:`${i.baseUrl}/app/workflows/${encodeURIComponent(e.workflowId)}/runs/${encodeURIComponent(e.id)}`};if(e.recovery?.state===`running`)return{workflowId:e.workflowId,runId:e.id,sourceDigest:a,run:e,attached:!0,viewerUrl:`${i.baseUrl}/app/workflows/${encodeURIComponent(e.workflowId)}/runs/${encodeURIComponent(e.id)}`};e.recovery?.state!==`queued`&&e.recovery?.state!==`recoverable`&&X(`The owner has not confirmed recovery eligibility`),c=e.workflowId,l=e.revUsed??X(`The captured cloud revision is unavailable`)}else{if(n.dryRun)return i.workflows.validate(t,{format:`graph`,deploy:s});let e=await i.workflows.create(t,{format:`graph`,deploy:s});c=e.id,l=e.headRev??X(`The cloud workflow has no retained revision`)}r.throwIfAborted();let u=await i.workflows.run(c,void 0,{signal:r,sourceSha:a,expectedRev:l,...n.resume?{resumeRunId:n.resume}:{}});return n.resume&&u.runId!==n.resume&&X(`The cloud owner recovered another run identity`),{...u,workflowId:c,sourceDigest:a,viewerUrl:`${i.baseUrl}/app/workflows/${encodeURIComponent(c)}/runs/${encodeURIComponent(u.runId)}`}}const zc=[`claude-code`,`opencode`,`codex`,`kimi-code`,`prime`],Bc=process.env.TANGLE_ROUTER_URL??`https://router.tangle.tools/v1`;function Vc(e){let t=ae(e);if(t)return t;throw Error(`--model '${e}' has no provider. Pass a canonical id, for example 'google/${e}'.`)}function Hc(e){let t=e.harness??`claude-code`;if(!zc.includes(t))throw Error(`Unknown --harness '${t}'. Supported: ${zc.join(`, `)}.`);let n=Uc(e.maxTokens,2e5,`--max-tokens`),r=Uc(e.maxIterations,50,`--max-iterations`),i=e.maxWorkers===void 0?void 0:Uc(e.maxWorkers,0,`--max-workers`);return{harness:t,...e.model?{model:e.model}:{},maxTokens:n,maxIterations:r,...i===void 0?{}:{maxWorkers:i}}}function Uc(e,t,n){if(e===void 0)return t;let r=Number.parseInt(e,10);if(!Number.isFinite(r)||r<=0)throw Error(`${n} must be a positive integer, got '${e}'.`);return r}function Wc(e){let t={maxTokens:e.maxTokens,maxIterations:e.maxIterations};return e.maxWorkers===void 0?{budget:t}:{budget:t,perWorker:{maxTokens:Math.max(1,Math.floor(e.maxTokens/e.maxWorkers)),maxIterations:Math.max(1,Math.floor(e.maxIterations/e.maxWorkers))}}}function Gc(e){let t=e.spentTotal,n=e.kind===`no-winner`?``:e.out;return{text:typeof n==`string`?n:typeof n==`object`&&n&&`content`in n&&typeof n.content==`string`?n.content:JSON.stringify(n),tokenUsage:{input:t.tokensKnown===!1?null:t.tokens.input,output:t.tokensKnown===!1?null:t.tokens.output},costUsd:t.usdKnown===!1?null:t.usd,status:e.kind===`no-winner`?`no-winner (${e.reason})`:`winner`}}let Kc=null;function qc(){return Kc??=import(`@tangle-network/agent-runtime/kernel`).catch(e=>{throw Kc=null,e?.code===`ERR_MODULE_NOT_FOUND`?new V(`RUNTIME_UNAVAILABLE`,`Agent Runtime could not be loaded`,e.message,`npm install -g @tangle-network/sandbox-cli@latest`):e}),Kc}async function Jc(e,t,n){let r=W({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=G(r),{budget:a,perWorker:o}=Wc(t),s=[],c={async create(e){let{TANGLE_API_KEY:t,...r}=e?.env??{},a=await i.create(e?.env?{...e,env:r}:e);return s.push({id:a.id,status:`spawned`}),n.json||R(`worker ${a.id} spawned`),a}},l=await qc(),u=l.workerFromBackend({backend:`sandbox`,sandboxClient:c,maxIterations:1}),d=(e,n)=>u({...e,harness:t.harness},n),f={name:`supervisor`,harness:`cli-base`,model:{default:t.model??`gemini-3.5-flash-lite`,provider:t.model?Vc(t.model):`google`},tools:{agent_runtime_coordination_spawn_worker:!0,agent_runtime_coordination_observe_agent:!0}},p={routerBaseUrl:Bc,routerKey:r.apiKey},m=Gc(await l.supervise(f,{goal:e},{budget:a,makeWorkerAgent:d,router:p,...o?{perWorker:o}:{},...t.model?{allowedModels:[t.model]}:{},runId:`supervise-${w()}`})),h=m.status===`winner`?`settled`:`failed`;for(let e of s)e.status=h,n.json||R(`worker ${e.id} settled (${e.status})`);return{task:e,result:m.text,workers:s,tokenUsage:m.tokenUsage,costUsd:m.costUsd,status:m.status}}function Yc(){let e=new x(`supervise`);return e.description(`Run a budget-conserving supervisor that spawns isolated sandbox workers to deliver a task.`).argument(`<task>`,`What the supervisor should accomplish`).option(`--harness <name>`,`Worker harness (${zc.join(` | `)})`,`claude-code`).option(`--model <id>`,`Model for the supervisor + workers`).option(`--max-tokens <n>`,`Conserved token budget for the whole run`,`200000`).option(`--max-iterations <n>`,`Conserved iteration budget for the whole run`,`50`).option(`--max-workers <n>`,`Bound the fanout; each worker reserves floor(max-tokens / n) tokens and floor(max-iterations / n) iterations`).action(async(e,t)=>{let n=Hc({harness:t.harness,model:t.model,maxTokens:t.maxTokens,maxIterations:t.maxIterations,maxWorkers:t.maxWorkers});t.json||(R(`Supervising: ${e}`),R(`harness=${n.harness} budget=${n.maxTokens}tok/${n.maxIterations}it`),console.log());let r=await Jc(e,n,{apiKey:t.apiKey,baseUrl:t.baseUrl,json:t.json});if(t.json){I(r),r.status!==`winner`&&(process.exitCode=1);return}if(console.log(),r.result&&(console.log(r.result),console.log()),B({"Input Tokens":r.tokenUsage.input??`Unavailable`,"Output Tokens":r.tokenUsage.output??`Unavailable`,Cost:r.costUsd===null?`Unavailable`:`$${r.costUsd.toFixed(4)}`}),r.status!==`winner`)throw Error(`Supervisor finished without a winner: ${r.status}`)}),e}const Xc=Ye(Se),Zc=async(e,...t)=>{let n={maxBuffer:1<<28};return(await Xc(`bash`,[`-ec`,e,`graph-improve`,...t],n)).stdout.trim()},Qc=j(M(),`.tangle`,`graph-improve`,`v5`),$c=j(M(),`.tangle`,`workspaces`),el=e=>!!e&&e.owner!==`work`&&e.code!==`budget-exhausted`;async function tl(e){await Ve(j(e,`bin`)),await Ve(j(e,`remotes`));let t=`#!/bin/sh
155
155
  [ "$1 $2" = "issue view" ] || { echo "gh: offline replay; only 'gh issue view <n>' answers" >&2; exit 1; }
156
156
  shift 2; n=; repo=; prev=
157
157
  for a; do
@@ -160,8 +160,8 @@ for a; do
160
160
  prev=$a
161
161
  done
162
162
  exec cat "${e}/remotes/$repo.git/tangle-issue-$n.json"
163
- `;for(let n of[`gh`,`gh-drew`])await Ke(j(e,`bin`,n),t,{mode:493});let n=`[url "${e}/remotes/"]\n\tinsteadOf = https://github.com/\n[user]\n\tname = graph-improve\n\temail = gi@local\n`;await Ke(j(e,`bin`,`gitconfig`),n);for(let e of Object.keys(process.env))/(^|_)(GH|GITHUB)\w*_(TOKEN|PAT)$|_PAT$/i.test(e)&&delete process.env[e];Object.assign(process.env,{GITHUB_TOKEN:`replay-placeholder`,PATH:`${j(e,`bin`)}:${process.env.PATH}`,GIT_CONFIG_GLOBAL:j(e,`bin`,`gitconfig`),GIT_CONFIG_NOSYSTEM:`1`,BRIDGE_JAIL_RW_PATHS:j(e,`remotes`),BRIDGE_JAIL_RO_PATHS:j(e,`bin`)})}async function Kc(e,t,n){let{runCampaign:r,wilson:i}=await import(`@tangle-network/agent-eval`),a=await import(`@tangle-network/agent-eval/benchmarks`),{durableRunToolSpans:o,readSettleRecord:s}=await import(`@tangle-network/agent-runtime/durable`),c=await We(j(t,`cases.jsonl.gz`)),l=Ze(c).toString().trim().split(`
164
- `).map(e=>JSON.parse(e)),u=new Map(l.map(e=>[e.id,e])),d=e=>u.get(e.split(`:`).pop()??e),f=e=>`graph-improve-js::${d(e).upstream}`,p=e=>a.deterministicSplit(f(e),`agent-eval-v1`,[.32,.38]),m=(e,t)=>[`issue=https://github.com/${e.upstream}/issues/${e.issue}`,...[`deliver=branch`,`base=main`,`test=${e.test}`],`verify_image=${t}`,`agent_tools={"websearch":false,"webfetch":false}`],h=await Rl(e,{param:m(l[0],`none`),dryRun:!0});if(!(`graph`in h))throw Error(`${e} did not load locally`);let g=h.graph.nodes.filter(({check:e,profile:{tools:t}})=>!e&&(t?.websearch!==!1||t?.webfetch!==!1));if(g.length)throw Error(`${g.map(e=>e.id)} can use web tools; refusing`);let _=h.graph.budget?.maxTokens;if(!_)throw Error(`${e} sets no budget.maxTokens to book at`);let v=await He(j(xe(),`tangle-graph-improve-`));await Gc(v);let y=new Map,b=(e,t)=>y.set(e,(y.get(e)??0)+t),ee=()=>[...y].flatMap(([e,t])=>t>0?[e]:[]),x=e=>Vc(`busy=" $2 " list=$(mktemp); trap 'rm -f "$list"' EXIT; mkdir -p "$3"
163
+ `;for(let n of[`gh`,`gh-drew`])await Ke(j(e,`bin`,n),t,{mode:493});let n=`[url "${e}/remotes/"]\n\tinsteadOf = https://github.com/\n[user]\n\tname = graph-improve\n\temail = gi@local\n`;await Ke(j(e,`bin`,`gitconfig`),n);for(let e of Object.keys(process.env))/(^|_)(GH|GITHUB)\w*_(TOKEN|PAT)$|_PAT$/i.test(e)&&delete process.env[e];Object.assign(process.env,{GITHUB_TOKEN:`replay-placeholder`,PATH:`${j(e,`bin`)}:${process.env.PATH}`,GIT_CONFIG_GLOBAL:j(e,`bin`,`gitconfig`),GIT_CONFIG_NOSYSTEM:`1`,BRIDGE_JAIL_RW_PATHS:j(e,`remotes`),BRIDGE_JAIL_RO_PATHS:j(e,`bin`)})}async function nl(e,t,n){let{runCampaign:r,wilson:i}=await import(`@tangle-network/agent-eval`),a=await import(`@tangle-network/agent-eval/benchmarks`),{durableRunToolSpans:o,readSettleRecord:s}=await import(`@tangle-network/agent-runtime/durable`),c=await We(j(t,`cases.jsonl.gz`)),l=Qe(c).toString().trim().split(`
164
+ `).map(e=>JSON.parse(e)),u=new Map(l.map(e=>[e.id,e])),d=e=>u.get(e.split(`:`).pop()??e),f=e=>`graph-improve-js::${d(e).upstream}`,p=e=>a.deterministicSplit(f(e),`agent-eval-v1`,[.32,.38]),m=(e,t)=>[`issue=https://github.com/${e.upstream}/issues/${e.issue}`,...[`deliver=branch`,`base=main`,`test=${e.test}`],`verify_image=${t}`,`agent_tools={"websearch":false,"webfetch":false}`],h=await Yl(e,{param:m(l[0],`none`),dryRun:!0});if(!(`graph`in h))throw Error(`${e} did not load locally`);let g=h.graph.nodes.filter(({check:e,profile:{tools:t}})=>!e&&(t?.websearch!==!1||t?.webfetch!==!1));if(g.length)throw Error(`${g.map(e=>e.id)} can use web tools; refusing`);let _=h.graph.budget?.maxTokens;if(!_)throw Error(`${e} sets no budget.maxTokens to book at`);let v=await He(j(xe(),`tangle-graph-improve-`));await tl(v);let y=new Map,b=(e,t)=>y.set(e,(y.get(e)??0)+t),ee=()=>[...y].flatMap(([e,t])=>t>0?[e]:[]),x=e=>Zc(`busy=" $2 " list=$(mktemp); trap 'rm -f "$list"' EXIT; mkdir -p "$3"
165
165
  ids=" $(docker images -q --filter label=tangle.graph-improve=v5 | tr '\\n' ' ') "
166
166
  docker system df -v --format '{{json .Images}}' | jq -r '.[] | "\\(.ID[7:19]) \\(.Repository):\\(.Tag) \\(.UniqueSize)"' |
167
167
  while read -r id t u; do
@@ -174,22 +174,22 @@ while read -r _ size t; do
174
174
  case "$busy" in *" $t "*) continue ;; esac
175
175
  docker image rm "$t" >/dev/null && total=$((total - size))
176
176
  done < "$list"
177
- echo "$total"`,`${e}`,ee().join(` `),j(Hc,`used`)),S=[...u.keys()].filter(e=>p(e)===`search`),C=a.createHarborBenchmarkAdapter({id:`graph-improve-js`,datasetDir:t,tasks:S.sort(),source:{name:`js-issues`,revision:Pl(c).slice(0,12)},assignSplit:p,grade:a.gradeHarborPatch({jobsDir:j(Hc,`jobs`)})}),te=async({payload:{taskDir:e,dir:t}})=>{let n=await We(j(e,`environment/Dockerfile`));return`tangle-graph-improve/${t.toLowerCase()}:${Pl(n).slice(0,16)}`},w=[...n.seat],T=new AbortController,E=async(t,n)=>{let r=await te(t),i=j(Hc,`remotes`,`${t.id}.git`);b(r,1),await x(25*2**30),await Vc(`docker image inspect "$2" >/dev/null 2>&1 || docker build -q -t "$2" "$1/environment" >/dev/null
177
+ echo "$total"`,`${e}`,ee().join(` `),j(Qc,`used`)),S=[...u.keys()].filter(e=>p(e)===`search`),C=a.createHarborBenchmarkAdapter({id:`graph-improve-js`,datasetDir:t,tasks:S.sort(),source:{name:`js-issues`,revision:Wl(c).slice(0,12)},assignSplit:p,grade:a.gradeHarborPatch({jobsDir:j(Qc,`jobs`)})}),te=async({payload:{taskDir:e,dir:t}})=>{let n=await We(j(e,`environment/Dockerfile`));return`tangle-graph-improve/${t.toLowerCase()}:${Wl(n).slice(0,16)}`},w=[...n.seat],T=new AbortController,ne=async(t,n)=>{let r=await te(t),i=j(Qc,`remotes`,`${t.id}.git`);b(r,1),await x(25*2**30),await Zc(`docker image inspect "$2" >/dev/null 2>&1 || docker build -q -t "$2" "$1/environment" >/dev/null
178
178
  sed -i '/^docker_image = /d' "$1/task.toml"
179
179
  sed -i 's|^\\[environment\\]$|&\\ndocker_image = "'"$2"'"|' "$1/task.toml" && grep -q '^docker_image' "$1/task.toml"
180
180
  [ -d "$3/refs" ] && exit; g=$(mktemp -d); trap 'rm -rf "$g"' EXIT
181
181
  docker run --rm --network none "$2" tar -C /app/.git -c . | tar -x -C "$g"
182
182
  c=$(git -c user.name=graph-improve -c user.email=gi@local --git-dir "$g" commit-tree 'HEAD^{tree}' -m Base)
183
183
  git init -q --bare -b main "$3.partial" && git --git-dir "$g" push -q "$3.partial" "$c:refs/heads/main"
184
- mv "$3.partial" "$3"`,t.payload.taskDir,r,i);let a=d(t.id),c=j(v,`remotes`,`${a.upstream}.git`),l=w.shift(),{issueTitle:u,issueBodyClean:f}=a,p=`https://github.com/${a.upstream}/issues/${a.issue}`,h=JSON.stringify({title:u,body:f,url:p,state:`OPEN`}),g,y;try{await Vc(`rm -rf "$2" && git clone -q --bare "$1" "$2" && printf %s "$4" > "$2/tangle-issue-$3.json"`,i,c,`${a.issue}`,h);try{let t=await Rl(e,{param:m(a,r),json:!0,...l&&{seat:l}},{signal:n});g=`runId`in t?t.runId:void 0;let i=JSON.parse(`text`in t?t.text:`{}`);y=Object.values(i).find(e=>e?.json?.branch)?.json?.branch}catch(e){let n=e;if(n.code!==`GRAPH_RUN_FAILED`)throw e;if(e.runtimeFailures?.some(({failure:e})=>Wc(e)))throw new Qe(t.id,{cause:e});g=n.runId}let u=j(M(),`.tangle`,`runs`,`${g}`),d=(await o(u)).map(e=>e.toolName).find(e=>/web.?(search|fetch)/i.test(e));if(d)throw T.abort(Error(`Replay ${g} called ${d}: not offline`)),T.signal.reason;let f=y?await Vc(`b=$(git --git-dir "$1" rev-parse main); git --git-dir "$2" diff --binary "$b" "$3"`,i,c,y):``,p=await s(u),v=p&&Fc(p).tokenUsage,b=v?.input!=null&&v.output!=null,ee=b?{input:v.input??0,output:v.output??0,known:b}:{input:0,output:_,known:b};return{patch:f&&`${f}\n`,tokens:ee,...g&&{runId:g}}}finally{l&&w.push(l),await Vc(`rm -rf "$1"; case "$2" in "$3"/*) rm -rf "$2" ;; esac`,c,`${g&&(await cc(g)).cwd}`,Uc)}},D=await a.benchmarkScenarios(C,[`search`]),ne=e=>Pl(`rerun::${e}`),re=D.map(e=>e.id).sort(),ie=new Set(re.sort((e,t)=>ne(e)<ne(t)?-1:1).slice(0,40)),ae=new Set(D.slice(0,n.probe).map(e=>e.id)),oe=new Map,O=`${h.graph.digest}:${n.seat.join(`,`)}`,se=await r({scenarios:D,judges:[a.benchmarkJudge(C)],reps:2,cellFilter:({scenario:{id:e},rep:t})=>t===0?ae.has(e):!n.probe&&ie.has(e),maxConcurrency:3,dispatchTimeoutMs:4*36e5,signal:T.signal,resumable:!0,dispatchRef:O,runDir:j(Hc,`base`,Pl(`${t}:${O}`)),onCellSettled:async(e,{item:t})=>{let n=await te(t);e.cached||b(n,-1),await Ke(j(Hc,`used`,n.replace(/[/:]/g,`_`)),``)},dispatch:(e,t)=>{let n=d(e.id).upstream,r=(oe.get(n)??Promise.resolve()).catch(()=>{}).then(()=>E(e.item,t.signal));return oe.set(n,r),r}});if(T.signal.aborted)throw T.signal.reason;let ce=se.cells.filter(e=>!e.error),le=e=>Object.values(e.judgeScores)[0]?.composite??0,ue=ce.filter(e=>e.rep===0),k=ue.filter(e=>le(e)>=1).length,de=ce.map(e=>e.artifact.tokens),fe=de.filter(e=>e.known),A=se.cells.filter(e=>e.error);I({resolved:k,n:ue.length,wilson95:i(k,ue.length),unmeasured:A.map(e=>`${e.cellId}: ${e.error}`),measuredTokens:fe.reduce((e,t)=>e+t.input+t.output,0),tokensBookedAtCap:(de.length-fe.length+A.length)*_,replayHours:se.cells.reduce((e,t)=>e+t.durationMs,0)/36e5,imageBytes:Number(await x(2**53-1)),cacheBytes:Number(await Vc(`du -sb "$1" | cut -f1`,Hc)),replays:ce.map(({scenarioId:e,rep:t,artifact:n,durationMs:r},i)=>({case:e,rep:t,runId:n.runId,...n.tokens,reward:le(ce[i]),seconds:r/1e3})),runDir:se.runDir})}function qc(e){e.command(`improve <graph> [dataset]`).description(`Measure a graph's base rate on js-issues by offline replay`).option(`--probe <n>`,`Stop after the first n train cases`,Number).option(`--seat <seat>`,`Replay seat; repeatable, one per replay`,(e,t)=>[...t,e],[]).action((e,t,n)=>Kc(e,t??j(Hc,`js-issues`),n))}const Jc=1e5;function Q(e){throw new V(`GRAPH_INVALID`,`Graph creation failed`,e,`tangle graph new --help`)}function Yc(e){return typeof e==`string`&&/^[a-z0-9][a-z0-9-]{0,62}$/i.test(e)}const Xc={maxBarren:2,failures:`verbatim`,panel:`off`,bar:`on`,profile:{id:`graph-new-v1`,opening:`The graph has not passed its outside check.`,plan:`Repair the concrete diagnostics with write_graph, run the saved file and submit the actual evidence.`,rules:`Completion requires a successful host run and unchanged YAML. Retain working graph content when blocked.`,headings:{failures:`Failures`,protected:`Passing checks`,changed:`Changes`,findings:`Findings`,bar:`Acceptance`,plan:`Next`,rules:`Rules`}}};var Zc=class{owned;lastFailure;pending=Promise.resolve();revision=0;sealed=!1;constructor(e,t,n){this.directory=e,this.options=t,this.cwd=n}async digest(e=this.owned){e||Q(`No graph file was saved`);let t=await Ue(e.file,ce.O_RDONLY|ce.O_NOFOLLOW);try{let[n,r]=await Promise.all([t.stat(),e.handle.stat()]);return(!n.isFile()||n.dev!==r.dev||n.ino!==r.ino)&&Q(`The owned graph file was replaced`),Pl(await t.readFile())}finally{await t.close()}}enqueue(e){let t=++this.revision,n=this.pending.then(()=>e(t));return this.pending=n.then(()=>void 0,()=>void 0),n}check=()=>this.enqueue(async e=>{let t=this.owned;if(!t?.result)return!1;let{digest:n,result:r}=t,i=await this.digest(t),a=this.revision===e&&this.owned===t&&t.digest===n&&t.result===r&&i===n;return a&&(this.sealed=!0),a});receipt(){this.owned?.result||Q(`No successful graph run was recorded`);let{file:e,digest:t,result:n}=this.owned;return{file:e,digest:t,result:n}}invoke(e,t){return this.sealed&&Q(`The graph is accepted; submit its recorded successful run`),this.enqueue(()=>this.write(e,t)).catch(e=>(this.lastFailure=e,{ok:!1,diagnostic:Zt(e)}))}async write(e,t){t.throwIfAborted(),this.lastFailure=void 0;let n=e;(!n||!Yc(n.name)||typeof n.source!=`string`||typeof n.run!=`boolean`||Object.keys(n).some(e=>![`name`,`source`,`run`].includes(e)))&&Q(`Expected only name, source and boolean run`),this.options.name!==void 0&&n.name!==this.options.name&&Q(`The graph name must match --name`),this.owned&&(this.owned.result=void 0);let r=j(this.directory,`${n.name}.yaml`);if(this.owned&&this.owned.file!==r&&Q(`This invocation owns one named graph file`),!this.owned)try{this.owned={file:r,handle:await Ue(r,ce.O_RDWR|ce.O_CREAT|ce.O_EXCL|ce.O_NOFOLLOW,384),digest:Pl(``)}}catch(e){throw e.code===`EEXIST`&&Q(`Graph already exists: ${r}; choose another --name`),e}let i=this.owned;await this.digest()!==i.digest&&Q(`The owned graph was changed`);let a=Buffer.from(n.source);for(let e=0;e<a.length;){let{bytesWritten:t}=await i.handle.write(a,e,a.length-e,e);if(!t)throw Error(`Graph file write made no progress`);e+=t}await i.handle.truncate(a.length),await i.handle.sync(),i.digest=Pl(a);let o={...this.options,param:[]},s={cwd:this.cwd,signal:t,source:n.source},c=await Rl(r,{...o,dryRun:!0},{...s,connectNeeds:!0});`graph`in c||Q(`No canonical graph was returned`),c.graph.deliverable.checkRef===`command`&&Q(`Host command checks need a jailed verifier node`);let{nodes:l,edges:u,budget:d}=c.graph,f=u.reduce((e,t)=>e+(`maxTraversals`in t?(t.maxTraversals??1)-1:0),l.length),p=(f+1)*Jc;if(d?.maxTokens!==void 0&&d.maxTokens<p&&Q(`budget.maxTokens ${d.maxTokens} is below ${p}: ${f} agent spawns plus one reservation at ${Jc} tokens per native turn`),await this.digest()!==i.digest&&Q(`Graph changed during validation`),!n.run)return{file:r,graphDigest:c.graph.digest,validated:!0};let m=await Rl(r,o,{...s,graphDigest:c.graph.digest});return(!(`status`in m)||m.status!==`winner`||m.graphDigest!==c.graph.digest||await this.digest()!==i.digest)&&Q(`The graph must succeed with unchanged YAML`),i.result=m,this.receipt()}async close(){await this.pending,await this.owned?.handle.close()}};async function Qc(e,t,n){let{runId:r,runDir:i,cwd:a,bridge:o,signal:s}=e,c=await o(),l=j(await Ge(j(M(),`.tangle`)),`graphs`);(Fl(a,l)||Fl(l,a))&&Q(`The graph store must be outside the agent workspace; choose another working directory`);try{await Ve(l,{mode:448})}catch(e){if(e.code!==`EEXIST`)throw e}await Ge(l)!==l&&Q(`The graph store redirects outside its canonical location`);let u=n.seat??Hn().seat,d=await fc(a,s)(u,{node:`graph-designer`,cwd:a,signal:s,lastCandidate:!0});d||Q(`No authenticated native subscription is available`);let{graphDesignerProfile:f}=await import(`@tangle-network/agent-runtime/profiles`),{supervisePursuit:p}=await import(`@tangle-network/agent-runtime/durable`),m=f({profile:{name:`graph-designer`,harness:d.harness,model:{provider:d.provider,default:d.model,...d.reasoningEffort===void 0?{}:{reasoningEffort:d.reasoningEffort}},prompt:{instructions:[`You are the sole graph designer. Author a canonical YAML graph for the requested intent, then qualify and run it using write_graph. Its nodes are complete AgentProfiles with a real independent verifier and declarative route/data outside check. Command checks execute on the host and are refused here; put executable verification in the verifier node's normal native tools. Read the supplied skills and preserve the user's task and authority.`,`Call write_graph with name, complete YAML source and run:false to validate; repair its concrete diagnostics, then call it with the identical source and run:true. The graph schema and executor are owned by the installed loader. Supply defaults for parameters needed by the first run. Only a real successful host run of the unchanged saved file passes. Submit that evidence using submit_result; explain concrete blockers using report_blocked.`]},tools:{agent_runtime_coordination_write_graph:!0,agent_runtime_coordination_submit_result:!0,agent_runtime_coordination_read_continuation:!0,agent_runtime_coordination_report_blocked:!0}}}),h=re(m),g=new Zc(l,{...n,seat:u},a),_={maxIterations:6,maxTokens:2e6,deadlineMs:9e5};try{let e=await p(m,{intent:t,name:n.name},{pursuitId:r,runId:r,runDir:i,signal:s,backend:{...c,timeoutMs:_.deadlineMs},budget:_,maxDepth:0,coordination:{authentication:!0,requestTimeoutMs:_.deadlineMs},deliverable:{describe:`The saved graph succeeds with unchanged YAML`,check:g.check,checkState:g.check},continuation:Xc,resolveSupervisorTools:e=>e.runId!==r||e.nodeId!==r||e.depth!==0||e.identity.profileDigest!==h?[]:[{name:`write_graph`,description:`Save, validate and run this graph.`,inputSchema:{type:`object`,properties:{name:{type:`string`},source:{type:`string`},run:{type:`boolean`}},required:[`name`,`source`,`run`],additionalProperties:!1},handler:(t,n)=>((n.nodeId!==e.nodeId||n.ownerId!==e.ownerId||n.runId!==e.runId)&&Q(`Wrong graph tool owner`),g.invoke(t,n.signal))}]});if(e.result.kind===`no-winner`||!await g.check()){if(g.lastFailure)throw g.lastFailure;let t=e.result.kind===`no-winner`?e.result.error?.message??e.result.reason:`The graph file changed after its successful run`;throw Object.assign(new V(`GRAPH_DESIGN_FAILED`,`Graph design did not finish`,t,`tangle graph new --help`),{runId:r,node:`graph-designer`})}return g.receipt()}finally{await g.close()}}function $c(e){e.command(`new <intent>`).description(`Design, validate and run one portable graph`).option(`--seat <seat>`,`Use harness/model@effort for the designer and graph`).option(`--name <name>`,`Save this graph name`).action(async(e,t)=>{process.env.BRIDGE_JAIL_RW_PATHS?.trim()&&Q(`Remove BRIDGE_JAIL_RW_PATHS before graph new; extra native write roots cannot contain its host store`),t.name!==void 0&&!Yc(t.name)&&Q(`Use letters, numbers and hyphens in --name`);let n=await Ll({},n=>Qc(n,e,t));t.json?I(n):R(`Created ${n.file} · run ${n.result.runId}`)})}const el=e=>e===void 0?[]:(Array.isArray(e)?e:[e]).map(String),tl=(e=``)=>{let t=e.replace(/\s+/g,` `).trim(),n=t.match(/^.+?[.!?](?=\s|$)/)?.[0]??t;return n.length>90?`${n.slice(0,89)}…`:n},nl=e=>e&&(e.all??[e]).map(e=>{let t=`equals`in e?`= ${JSON.stringify(e.equals)}`:`in`in e?`∈ ${JSON.stringify(e.in)}`:e.exists===!1?`absent`:`exists`;return`${e.node??``}${e.pointer||`/`} ${t}`}).join(` and `);function rl(e,t){try{let n=tt(t,{uniqueKeys:!0,strict:!0}),r=[...n.errors,...n.warnings][0];if(r)throw r;let i=he(e)===`.json`?JSON.parse(t):n.toJS();if(Array.isArray(i?.nodes)&&Array.isArray(i.edges))return i;throw Error(`A graph needs nodes and edges lists`)}catch(t){throw new V(`GRAPH_INVALID`,`Graph file ${e} cannot be read`,t.message,`tangle graph show --help`)}}function il(e,t){let n=rl(e,t),r=e=>{let t=String(e).match(/^\$\{params\.([\w-]+)\}$/)?.[1];return t?`${n.params?.[t]?.default??`?`} (params.${t})`:e},i=n.nodes.map(e=>{if(e.check){let t=String(e.check.command??``),n=t.match(RegExp(`#\\s*${e.id}:\\s*(.+)`))?.[1],r=t.split(`
185
- `).find(e=>e.trim()&&!/^\s*#/.test(e));return{id:e.id,kind:`check`,detail:tl(n??`$ ${r}`)}}let t=[e.profile?.harness,e.profile?.model?.default],n=el(e.seat).join(` › `)||t.filter(Boolean).join(` · `),r=tl(e.profile?.prompt?.systemPrompt),i=[n||`default seat`,r].filter(Boolean).join(`
186
- `);return{id:e.id,kind:`agent`,detail:i}});for(let e of n.gates??[]){let t=el(e.choices).join(` | `);i.push({id:e.id,kind:`gate`,detail:`${t}\n${e.question}`})}let a=el(n.entry?.map(e=>e.node??e)),o=[];if(a.length){i.unshift({id:`start`,kind:`start`,detail:``});let e=a.length>1?`fork`:``;o.push({from:[`start`],to:a,label:e,loop:!1})}for(let e of n.edges){let t=e.to?.finish===void 0?`stop`:`finish`,a=e.to?.[t]===void 0?void 0:`${t}:${e.to[t]}`,s=a===void 0?el(e.to??e.join):[a];a&&!i.some(e=>e.id===a)&&i.push({id:a,kind:t,detail:``});let c=el(e.kind===`analyzes`?e.over:e.from),l=n.edges.some(t=>!e.when&&t.when&&el(t.from).join()===c.join()),u=e.maxTraversals!==void 0,d=[nl(e.when)??(l?`otherwise`:e.kind?.replace(`routes`,``)),c.length>1&&`join`,s.length>1&&`fork`,u&&`↺ loop ≤${r(e.maxTraversals)}`];o.push({from:c,to:s,label:d.filter(Boolean).join(` · `),loop:u})}let s=n.check??{},c=[[`params`,Object.entries(n.params??{}).map(([e,t])=>`${e}${`default`in t?`=${JSON.stringify(t.default)}`:` (required)`}`).join(`, `)],[`workspace`,n.workspace],[`done when`,s.command?.command??s.command??nl(s.all||s.pointer?s:void 0)],[``,s.describe]];return{name:n.graph??e.replace(/^.*\/|(\.graph)?\.(ya?ml|json)$/g,``),describe:n.describe?.trim(),facts:c.filter(e=>e[1]),nodes:i,edges:o}}const al={start:[`▶`,b.green],agent:[`●`,b.cyan.bold],check:[`▣`,b.yellow.bold],gate:[`◇`,b.magenta.bold],finish:[`✓`,b.green.bold],stop:[`■`,b.red.bold]};function ol(e){let t=t=>e.nodes.find(e=>e.id===t)?.kind??`agent`,n=e=>{let[n,r]=al[t(e)];return r(`${n} ${e.replace(/^(finish|stop):/,``)}`)},r=Math.max(...e.nodes.map(e=>e.id.length))+4,i=[`${b.bold(`◆ ${e.name}`)}`,...e.describe?[` ${e.describe}`]:[],``];for(let[t,n]of e.facts)i.push(` ${b.dim(t.padEnd(10))} ${n}`);i.push(``,b.bold(`NODES`));for(let t of e.nodes.filter(e=>[`agent`,`check`,`gate`].includes(e.kind))){let[e,...a]=t.detail.split(`
184
+ mv "$3.partial" "$3"`,t.payload.taskDir,r,i);let a=d(t.id),c=j(v,`remotes`,`${a.upstream}.git`),l=w.shift(),{issueTitle:u,issueBodyClean:f}=a,p=`https://github.com/${a.upstream}/issues/${a.issue}`,h=JSON.stringify({title:u,body:f,url:p,state:`OPEN`}),g,y;try{await Zc(`rm -rf "$2" && git clone -q --bare "$1" "$2" && printf %s "$4" > "$2/tangle-issue-$3.json"`,i,c,`${a.issue}`,h);try{let t=await Yl(e,{param:m(a,r),json:!0,...l&&{seat:l}},{signal:n});g=`runId`in t?t.runId:void 0;let i=JSON.parse(`text`in t?t.text:`{}`);y=Object.values(i).find(e=>e?.json?.branch)?.json?.branch}catch(e){let n=e;if(n.code!==`GRAPH_RUN_FAILED`)throw e;if(e.runtimeFailures?.some(({failure:e})=>el(e)))throw new $e(t.id,{cause:e});g=n.runId}let u=j(M(),`.tangle`,`runs`,`${g}`),d=(await o(u)).map(e=>e.toolName).find(e=>/web.?(search|fetch)/i.test(e));if(d)throw T.abort(Error(`Replay ${g} called ${d}: not offline`)),T.signal.reason;let f=y?await Zc(`b=$(git --git-dir "$1" rev-parse main); git --git-dir "$2" diff --binary "$b" "$3"`,i,c,y):``,p=await s(u),v=p&&Gc(p).tokenUsage,b=v?.input!=null&&v.output!=null,ee=b?{input:v.input??0,output:v.output??0,known:b}:{input:0,output:_,known:b};return{patch:f&&`${f}\n`,tokens:ee,...g&&{runId:g}}}finally{l&&w.push(l),await Zc(`rm -rf "$1"; case "$2" in "$3"/*) rm -rf "$2" ;; esac`,c,`${g&&(await lc(g)).cwd}`,$c)}},E=await a.benchmarkScenarios(C,[`search`]),D=e=>Wl(`rerun::${e}`),re=E.map(e=>e.id).sort(),ie=new Set(re.sort((e,t)=>D(e)<D(t)?-1:1).slice(0,40)),ae=new Set(E.slice(0,n.probe).map(e=>e.id)),oe=new Map,O=`${h.graph.digest}:${n.seat.join(`,`)}`,se=await r({scenarios:E,judges:[a.benchmarkJudge(C)],reps:2,cellFilter:({scenario:{id:e},rep:t})=>t===0?ae.has(e):!n.probe&&ie.has(e),maxConcurrency:3,dispatchTimeoutMs:4*36e5,signal:T.signal,resumable:!0,dispatchRef:O,runDir:j(Qc,`base`,Wl(`${t}:${O}`)),onCellSettled:async(e,{item:t})=>{let n=await te(t);e.cached||b(n,-1),await Ke(j(Qc,`used`,n.replace(/[/:]/g,`_`)),``)},dispatch:(e,t)=>{let n=d(e.id).upstream,r=(oe.get(n)??Promise.resolve()).catch(()=>{}).then(()=>ne(e.item,t.signal));return oe.set(n,r),r}});if(T.signal.aborted)throw T.signal.reason;let ce=se.cells.filter(e=>!e.error),le=e=>Object.values(e.judgeScores)[0]?.composite??0,ue=ce.filter(e=>e.rep===0),k=ue.filter(e=>le(e)>=1).length,de=ce.map(e=>e.artifact.tokens),fe=de.filter(e=>e.known),A=se.cells.filter(e=>e.error);I({resolved:k,n:ue.length,wilson95:i(k,ue.length),unmeasured:A.map(e=>`${e.cellId}: ${e.error}`),measuredTokens:fe.reduce((e,t)=>e+t.input+t.output,0),tokensBookedAtCap:(de.length-fe.length+A.length)*_,replayHours:se.cells.reduce((e,t)=>e+t.durationMs,0)/36e5,imageBytes:Number(await x(2**53-1)),cacheBytes:Number(await Zc(`du -sb "$1" | cut -f1`,Qc)),replays:ce.map(({scenarioId:e,rep:t,artifact:n,durationMs:r},i)=>({case:e,rep:t,runId:n.runId,...n.tokens,reward:le(ce[i]),seconds:r/1e3})),runDir:se.runDir})}function rl(e){e.command(`improve <graph> [dataset]`).description(`Measure a graph's base rate on js-issues by offline replay`).option(`--probe <n>`,`Stop after the first n train cases`,Number).option(`--seat <seat>`,`Replay seat; repeatable, one per replay`,(e,t)=>[...t,e],[]).action((e,t,n)=>nl(e,t??j(Qc,`js-issues`),n))}const il=1e5;function Q(e){throw new V(`GRAPH_INVALID`,`Graph creation failed`,e,`tangle graph new --help`)}function al(e){return typeof e==`string`&&/^[a-z0-9][a-z0-9-]{0,62}$/i.test(e)}const ol={maxBarren:2,failures:`verbatim`,panel:`off`,bar:`on`,profile:{id:`graph-new-v1`,opening:`The graph has not passed its outside check.`,plan:`Repair the concrete diagnostics with write_graph, run the saved file and submit the actual evidence.`,rules:`Completion requires a successful host run and unchanged YAML. Retain working graph content when blocked.`,headings:{failures:`Failures`,protected:`Passing checks`,changed:`Changes`,findings:`Findings`,bar:`Acceptance`,plan:`Next`,rules:`Rules`}}};var sl=class{owned;lastFailure;pending=Promise.resolve();revision=0;sealed=!1;constructor(e,t,n){this.directory=e,this.options=t,this.cwd=n}async digest(e=this.owned){e||Q(`No graph file was saved`);let t=await Ue(e.file,ce.O_RDONLY|ce.O_NOFOLLOW);try{let[n,r]=await Promise.all([t.stat(),e.handle.stat()]);return(!n.isFile()||n.dev!==r.dev||n.ino!==r.ino)&&Q(`The owned graph file was replaced`),Wl(await t.readFile())}finally{await t.close()}}enqueue(e){let t=++this.revision,n=this.pending.then(()=>e(t));return this.pending=n.then(()=>void 0,()=>void 0),n}check=()=>this.enqueue(async e=>{let t=this.owned;if(!t?.result)return!1;let{digest:n,result:r}=t,i=await this.digest(t),a=this.revision===e&&this.owned===t&&t.digest===n&&t.result===r&&i===n;return a&&(this.sealed=!0),a});receipt(){this.owned?.result||Q(`No successful graph run was recorded`);let{file:e,digest:t,result:n}=this.owned;return{file:e,digest:t,result:n}}invoke(e,t){return this.sealed&&Q(`The graph is accepted; submit its recorded successful run`),this.enqueue(()=>this.write(e,t)).catch(e=>(this.lastFailure=e,{ok:!1,diagnostic:Qt(e)}))}async write(e,t){t.throwIfAborted(),this.lastFailure=void 0;let n=e;(!n||!al(n.name)||typeof n.source!=`string`||typeof n.run!=`boolean`||Object.keys(n).some(e=>![`name`,`source`,`run`].includes(e)))&&Q(`Expected only name, source and boolean run`),this.options.name!==void 0&&n.name!==this.options.name&&Q(`The graph name must match --name`),this.owned&&(this.owned.result=void 0);let r=j(this.directory,`${n.name}.yaml`);if(this.owned&&this.owned.file!==r&&Q(`This invocation owns one named graph file`),!this.owned)try{this.owned={file:r,handle:await Ue(r,ce.O_RDWR|ce.O_CREAT|ce.O_EXCL|ce.O_NOFOLLOW,384),digest:Wl(``)}}catch(e){throw e.code===`EEXIST`&&Q(`Graph already exists: ${r}; choose another --name`),e}let i=this.owned;await this.digest()!==i.digest&&Q(`The owned graph was changed`);let a=Buffer.from(n.source);for(let e=0;e<a.length;){let{bytesWritten:t}=await i.handle.write(a,e,a.length-e,e);if(!t)throw Error(`Graph file write made no progress`);e+=t}await i.handle.truncate(a.length),await i.handle.sync(),i.digest=Wl(a);let o={...this.options,param:[]},s={cwd:this.cwd,signal:t,source:n.source},c=await Yl(r,{...o,dryRun:!0},{...s,connectNeeds:!0});`graph`in c||Q(`No canonical graph was returned`),c.graph.deliverable.checkRef===`command`&&Q(`Host command checks need a jailed verifier node`);let{nodes:l,edges:u,budget:d}=c.graph,f=u.reduce((e,t)=>e+(`maxTraversals`in t?(t.maxTraversals??1)-1:0),l.length),p=(f+1)*il;if(d?.maxTokens!==void 0&&d.maxTokens<p&&Q(`budget.maxTokens ${d.maxTokens} is below ${p}: ${f} agent spawns plus one reservation at ${il} tokens per native turn`),await this.digest()!==i.digest&&Q(`Graph changed during validation`),!n.run)return{file:r,graphDigest:c.graph.digest,validated:!0};let m=await Yl(r,o,{...s,graphDigest:c.graph.digest});return(!(`status`in m)||m.status!==`winner`||m.graphDigest!==c.graph.digest||await this.digest()!==i.digest)&&Q(`The graph must succeed with unchanged YAML`),i.result=m,this.receipt()}async close(){await this.pending,await this.owned?.handle.close()}};async function cl(e,t,n){let{runId:r,runDir:i,cwd:a,bridge:o,signal:s}=e,c=await o(),l=j(await Ge(j(M(),`.tangle`)),`graphs`);(Gl(a,l)||Gl(l,a))&&Q(`The graph store must be outside the agent workspace; choose another working directory`);try{await Ve(l,{mode:448})}catch(e){if(e.code!==`EEXIST`)throw e}await Ge(l)!==l&&Q(`The graph store redirects outside its canonical location`);let u=n.seat??Un().seat,d=await pc(a,s)(u,{node:`graph-designer`,cwd:a,signal:s,lastCandidate:!0});d||Q(`No authenticated native subscription is available`);let{graphDesignerProfile:f}=await import(`@tangle-network/agent-runtime/profiles`),{supervisePursuit:p}=await import(`@tangle-network/agent-runtime/durable`),m=f({profile:{name:`graph-designer`,harness:d.harness,model:{provider:d.provider,default:d.model,...d.reasoningEffort===void 0?{}:{reasoningEffort:d.reasoningEffort}},prompt:{instructions:[`You are the sole graph designer. Author a canonical YAML graph for the requested intent, then qualify and run it using write_graph. Its nodes are complete AgentProfiles with a real independent verifier and declarative route/data outside check. Command checks execute on the host and are refused here; put executable verification in the verifier node's normal native tools. Read the supplied skills and preserve the user's task and authority.`,`Call write_graph with name, complete YAML source and run:false to validate; repair its concrete diagnostics, then call it with the identical source and run:true. The graph schema and executor are owned by the installed loader. Supply defaults for parameters needed by the first run. Only a real successful host run of the unchanged saved file passes. Submit that evidence using submit_result; explain concrete blockers using report_blocked.`]},tools:{agent_runtime_coordination_write_graph:!0,agent_runtime_coordination_submit_result:!0,agent_runtime_coordination_read_continuation:!0,agent_runtime_coordination_report_blocked:!0}}}),h=re(m),g=new sl(l,{...n,seat:u},a),_={maxIterations:6,maxTokens:2e6,deadlineMs:9e5};try{let e=await p(m,{intent:t,name:n.name},{pursuitId:r,runId:r,runDir:i,signal:s,backend:{...c,timeoutMs:_.deadlineMs},budget:_,maxDepth:0,coordination:{authentication:!0,requestTimeoutMs:_.deadlineMs},deliverable:{describe:`The saved graph succeeds with unchanged YAML`,check:g.check,checkState:g.check},continuation:ol,resolveSupervisorTools:e=>e.runId!==r||e.nodeId!==r||e.depth!==0||e.identity.profileDigest!==h?[]:[{name:`write_graph`,description:`Save, validate and run this graph.`,inputSchema:{type:`object`,properties:{name:{type:`string`},source:{type:`string`},run:{type:`boolean`}},required:[`name`,`source`,`run`],additionalProperties:!1},handler:(t,n)=>((n.nodeId!==e.nodeId||n.ownerId!==e.ownerId||n.runId!==e.runId)&&Q(`Wrong graph tool owner`),g.invoke(t,n.signal))}]});if(e.result.kind===`no-winner`||!await g.check()){if(g.lastFailure)throw g.lastFailure;let t=e.result.kind===`no-winner`?e.result.error?.message??e.result.reason:`The graph file changed after its successful run`;throw Object.assign(new V(`GRAPH_DESIGN_FAILED`,`Graph design did not finish`,t,`tangle graph new --help`),{runId:r,node:`graph-designer`})}return g.receipt()}finally{await g.close()}}function ll(e){e.command(`new <intent>`).description(`Design, validate and run one portable graph`).option(`--seat <seat>`,`Use harness/model@effort for the designer and graph`).option(`--name <name>`,`Save this graph name`).action(async(e,t)=>{process.env.BRIDGE_JAIL_RW_PATHS?.trim()&&Q(`Remove BRIDGE_JAIL_RW_PATHS before graph new; extra native write roots cannot contain its host store`),t.name!==void 0&&!al(t.name)&&Q(`Use letters, numbers and hyphens in --name`);let n=await ql({},n=>cl(n,e,t));t.json?I(n):R(`Created ${n.file} · run ${n.result.runId}`)})}const ul=e=>e===void 0?[]:(Array.isArray(e)?e:[e]).map(String),dl=(e=``)=>{let t=e.replace(/\s+/g,` `).trim(),n=t.match(/^.+?[.!?](?=\s|$)/)?.[0]??t;return n.length>90?`${n.slice(0,89)}…`:n},fl=e=>e&&(e.all??[e]).map(e=>{let t=`equals`in e?`= ${JSON.stringify(e.equals)}`:`in`in e?`∈ ${JSON.stringify(e.in)}`:e.exists===!1?`absent`:`exists`;return`${e.node??``}${e.pointer||`/`} ${t}`}).join(` and `);function pl(e,t){try{let n=nt(t,{uniqueKeys:!0,strict:!0}),r=[...n.errors,...n.warnings][0];if(r)throw r;let i=he(e)===`.json`?JSON.parse(t):n.toJS();if(Array.isArray(i?.nodes)&&Array.isArray(i.edges))return i;throw Error(`A graph needs nodes and edges lists`)}catch(t){throw new V(`GRAPH_INVALID`,`Graph file ${e} cannot be read`,t.message,`tangle graph show --help`)}}function ml(e,t){let n=pl(e,t),r=e=>{let t=String(e).match(/^\$\{params\.([\w-]+)\}$/)?.[1];return t?`${n.params?.[t]?.default??`?`} (params.${t})`:e},i=n.nodes.map(e=>{if(e.check){let t=String(e.check.command??``),n=t.match(RegExp(`#\\s*${e.id}:\\s*(.+)`))?.[1],r=t.split(`
185
+ `).find(e=>e.trim()&&!/^\s*#/.test(e));return{id:e.id,kind:`check`,detail:dl(n??`$ ${r}`)}}let t=[e.profile?.harness,e.profile?.model?.default],n=ul(e.seat).join(` › `)||t.filter(Boolean).join(` · `),r=dl(e.profile?.prompt?.systemPrompt),i=[n||`default seat`,r].filter(Boolean).join(`
186
+ `);return{id:e.id,kind:`agent`,detail:i}});for(let e of n.gates??[]){let t=ul(e.choices).join(` | `);i.push({id:e.id,kind:`gate`,detail:`${t}\n${e.question}`})}let a=ul(n.entry?.map(e=>e.node??e)),o=[];if(a.length){i.unshift({id:`start`,kind:`start`,detail:``});let e=a.length>1?`fork`:``;o.push({from:[`start`],to:a,label:e,loop:!1})}for(let e of n.edges){let t=e.to?.finish===void 0?`stop`:`finish`,a=e.to?.[t]===void 0?void 0:`${t}:${e.to[t]}`,s=a===void 0?ul(e.to??e.join):[a];a&&!i.some(e=>e.id===a)&&i.push({id:a,kind:t,detail:``});let c=ul(e.kind===`analyzes`?e.over:e.from),l=n.edges.some(t=>!e.when&&t.when&&ul(t.from).join()===c.join()),u=e.maxTraversals!==void 0,d=[fl(e.when)??(l?`otherwise`:e.kind?.replace(`routes`,``)),c.length>1&&`join`,s.length>1&&`fork`,u&&`↺ loop ≤${r(e.maxTraversals)}`];o.push({from:c,to:s,label:d.filter(Boolean).join(` · `),loop:u})}let s=n.check??{},c=[[`params`,Object.entries(n.params??{}).map(([e,t])=>`${e}${`default`in t?`=${JSON.stringify(t.default)}`:` (required)`}`).join(`, `)],[`workspace`,n.workspace],[`done when`,s.command?.command??s.command??fl(s.all||s.pointer?s:void 0)],[``,s.describe]];return{name:n.graph??e.replace(/^.*\/|(\.graph)?\.(ya?ml|json)$/g,``),describe:n.describe?.trim(),facts:c.filter(e=>e[1]),nodes:i,edges:o}}const hl={start:[`▶`,b.green],agent:[`●`,b.cyan.bold],check:[`▣`,b.yellow.bold],gate:[`◇`,b.magenta.bold],finish:[`✓`,b.green.bold],stop:[`■`,b.red.bold]};function gl(e){let t=t=>e.nodes.find(e=>e.id===t)?.kind??`agent`,n=e=>{let[n,r]=hl[t(e)];return r(`${n} ${e.replace(/^(finish|stop):/,``)}`)},r=Math.max(...e.nodes.map(e=>e.id.length))+4,i=[`${b.bold(`◆ ${e.name}`)}`,...e.describe?[` ${e.describe}`]:[],``];for(let[t,n]of e.facts)i.push(` ${b.dim(t.padEnd(10))} ${n}`);i.push(``,b.bold(`NODES`));for(let t of e.nodes.filter(e=>[`agent`,`check`,`gate`].includes(e.kind))){let[e,...a]=t.detail.split(`
187
187
  `);i.push(` ${n(t.id)}${` `.repeat(Math.max(1,r-t.id.length))}${e}`);for(let e of a)i.push(`${` `.repeat(r+4)}${b.dim(e)}`)}i.push(``,b.bold(`FLOW`));for(let t of e.edges){let e=` ${t.from.map(n).join(b.dim(` + `))} ${b.dim(`─▶`)} ${t.to.map(n).join(b.dim(` ∥ `))}`,r=t.loop?b.magenta(t.label):b.blue(t.label);i.push(...t.label.length+Xe(e).length>100?[e,` ${r}`]:[`${e} ${r}`])}return i.join(`
188
- `)}async function sl(e,t){let n=j(t,`dist`,`graph-show`),[r,i]=await Promise.all([`viewer.iife.js`,`styles.css`].map(e=>We(j(n,e),`utf8`))),a=(e=``)=>e.replace(/<\/(script)/gi,`<\\/$1`).replace(/<!--/g,`<\\!--`),o=e.name.replace(/[^\w.-]+/g,`-`),s=`<!doctype html><html lang="en"><head><meta charset="utf-8"><title>${o} · tangle graph</title>
188
+ `)}async function _l(e,t){let n=j(t,`dist`,`graph-show`),[r,i]=await Promise.all([`viewer.iife.js`,`styles.css`].map(e=>We(j(n,e),`utf8`))),a=(e=``)=>e.replace(/<\/(script)/gi,`<\\/$1`).replace(/<!--/g,`<\\!--`),o=e.name.replace(/[^\w.-]+/g,`-`),s=`<!doctype html><html lang="en"><head><meta charset="utf-8"><title>${o} · tangle graph</title>
189
189
  <meta name="description" content="${(e.describe??o).replace(/[&<>"]/g,``)}">
190
190
  <style>${i}html,body,#root{margin:0;height:100%;font-family:ui-sans-serif,system-ui,sans-serif}</style></head>
191
191
  <body><div id="root"></div><script id="graph" type="application/json">${JSON.stringify(e).replace(/</g,`\\u003c`)}<\/script>
192
- <script>${a(r)}<\/script></body></html>`,c=j(await He(j(xe(),`tangle-graph-`)),`${o}.html`);return await Ke(c,s,{mode:384}),c}function cl(e,t,n){e.command(`show <name-or-file>`).description(`Draw a graph file: labelled nodes, routes, loops and stops`).option(`--open`,`Write one offline page and open it in the browser`).action(async(e,r)=>{let i=await Ge(t(e,process.cwd())),a=il(i,await We(i,`utf8`));if(r.json)return I(a);if(!r.open)return console.log(ol(a));let o=await sl(a,n);R(await Ti(et(o).href)?`Opened ${o}`:`Open ${o}`)})}async function ll(e){if(!rr(e.apiKey)){if(e.json||e.dryRun||!process.stdin.isTTY)return;await Pi({baseUrl:e.sandboxBaseUrl,signal:e.signal})}return q(e)}async function ul(e,t,n){let r=Ol(t.parameter),i=n??await ll(t);if(!i)throw new V(`AUTH_REQUIRED`,`Hub authentication is required`,`No Tangle credential is configured`,`tangle auth login`);let a=await i.connections.start(e,{cli:!0,connectionParameters:r});return t.json?(I(Al(a)),a):(kl(a,t.browser===!1?!1:await Ti(a.redirectUrl),t.wait),a)}async function dl(e,t,n){let r=async()=>{n.signal?.throwIfAborted();let{connections:r}=await e.connections.list(),i=r.filter(e=>e.status===`active`&&e.providerId.toLowerCase()===t.trim().toLowerCase());return i.length?Cr(i,t):void 0},i=await r();if(i||n.json||n.dryRun||!process.stdin.isTTY)return i;let a=await ul(t,{...n,wait:!0},e);for(;!i&&Date.now()<Date.parse(a.expiresAt);)await Ae(1e3,void 0,{signal:n.signal}),i=await r();return i}function fl(){let e=new x(`hub`).description(`Discover and run Tangle Hub tools`);e.command(`connect`).description(`Connect a provider account`).argument(`provider`,`Provider to connect`).option(`--no-browser`,`Print the authorization URL instead of opening it`).option(`--parameter <key=value>`,`Provider-specific OAuth value. Repeatable.`,(e,t)=>[...t,e],[]).action(async(e,t)=>{await ul(e,t)});let t=new x(`connections`).description(`List Hub provider connections`).action(async e=>{let t=await(await q(e)).connections.list();if(e.json){I(t);return}Dl(t.connections)});t.command(`revoke <connection-id>`).description(`Revoke a Hub provider connection`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=await q(t),r=await Sr(n,e);if(!t.force&&!await $r(`Revoke Hub connection ${r}? `,`--force`)){R(`Revoke cancelled.`);return}let i=await n.connections.revoke(r);if(t.json){I(i);return}R(`Revoked Hub connection ${i.connection.id}.`)}),e.addCommand(t);let n=new x(`permissions`).description(`Manage Hub action permissions`);n.command(`list`).description(`List Hub permissions for a connection`).requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);let t=await q(e),n=await Sr(t,e.connection),r=await t.permissions.list(n);if(e.json){I(r);return}Sl(r.policies)}),n.command(`set`).description(`Set Hub permission for one action`).requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).requiredOption(`--action <path>`,`Executor action path`).requiredOption(`--decision <allow|ask|deny>`,`Permission decision`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);if(!e.action)throw Error(`--action is required.`);let t=Cl(e.decision),n=await q(e),r=await Sr(n,e.connection),i=await n.permissions.set({connectionId:r,actionPath:e.action,decision:t});if(e.json){I(i);return}Sl([i.policy])}),n.command(`revert-writes`).description("Revoke a bulk `--allow-writes` grant for a connection (deletes only the auto-granted write rows; manual permissions are untouched)").requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);let t=await q(e),n=await Sr(t,e.connection),r=await t.permissions.revertWrites(n);if(e.json){I(r);return}R(`Reverted ${r.reverted} write permission${r.reverted===1?``:`s`} for connection ${r.connectionId}.`)}),e.addCommand(n),e.addCommand(ml());let r=new x(`tools`).description(`Discover Hub tools`);return r.command(`sources`).description(`List Hub tool sources`).action(async e=>{let t=await(await q(e)).tools.sources();if(e.json){I(t);return}wl(t.sources)}),r.command(`describe`).description(`Describe a Hub tool`).argument(`path`,`Executor tool path`).action(async(e,t)=>{let n=await(await q(t)).tools.describe(e);if(t.json){I(n);return}Tl(n.tool)}),r.command(`search`).description(`Search Hub tools`).argument(`<query...>`,`Search query`).option(`--provider <provider>`,`Filter by provider/source ID`).action(async(e,t)=>{let n=await(await q(t)).tools.search(e.join(` `),{provider:t.provider});if(t.json){I(n);return}xl(n.tools)}),e.addCommand(r),e.addCommand(pl(`call`)),e.addCommand(pl(`exec`)),e.command(`resume`).description(`Resolve a Hub approval created by a paused execution`).argument(`approval-id`,`Hub approval ID from HUB_APPROVAL_REQUIRED`).option(`--accept`,`Approve the execution approval`).option(`--decline`,`Deny the execution approval`).option(`--cancel`,`Unsupported for approval-backed Hub resume`).action(async(e,t)=>{if(gl(e),t.cancel)throw Error(`Hub approval resume does not support --cancel. Use --decline to deny the approval.`);if(t.accept&&t.decline)throw Error(`Choose only one of --accept or --decline.`);if(!t.accept&&!t.decline)throw Error(`Choose --accept to approve or --decline to deny the Hub approval.`);let n=await q(t);vl(t.decline?await n.approvals.deny(e):await n.approvals.approve(e),t.json===!0)}),e.command(`status`).description(`Show Hub auth and connection status`).action(async e=>{let t=await(await q(e)).status();if(e.json){I(t);return}jl(t)}),e}function pl(e){return new x(e).description(`Execute a Hub tool`).argument(`<args...>`,`Tool path tokens followed by JSON input`).option(`--connection <ref>`,`Hub connection id, or provider[:account]`).option(`--auto-approve`,`Approve a HUB_APPROVAL_REQUIRED execution and retry once`).option(`--approve`,`Alias for --auto-approve`).option(`--no-hub-key`,`Do not auto-mint a platform Hub key; use the stored credential as-is`).action(async(e,t)=>{let{args:n,approve:r}=hl(e,t),{path:i,input:a}=bl(n),o=await q(t),s=t.connection?await Sr(o,t.connection):void 0;I((await o.tools.invoke(i,a,{connectionId:s,approve:r})).result)})}function ml(){let e=new x(`approvals`).description(`List and resolve Hub execution approvals`);e.command(`list`).description(`List pending Hub execution approvals`).action(async e=>{let t=await(await q(e)).approvals.list();if(e.json){I(t);return}_l(t.approvals)});for(let t of[`approve`,`deny`])e.command(t).description(`${t===`approve`?`Approve`:`Deny`} a pending Hub execution approval`).argument(`approval-id`,`Hub approval ID`).action(async(e,n)=>{gl(e),vl(await(await q(n)).approvals[t](e),n.json===!0)});return e}function hl(e,t){let n=t.autoApprove;return{args:e.filter(e=>e!==`--approve`&&e!==`--auto-approve`),approve:t.approve===!0||n===!0||e.includes(`--approve`)||e.includes(`--auto-approve`)}}function gl(e){if(!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`Hub approval ID must contain only letters, numbers, underscores, and dashes.`)}function _l(e){F(e,[{key:`id`,header:`ID`},{key:`providerId`,header:`Provider`},{key:`actionPath`,header:`Action`},{key:`connectionId`,header:`Connection`},{key:`status`,header:`Status`},{key:`expiresAt`,header:`Expires`}])}function vl(e,t){if(t){I(yl(e));return}R(`Hub approval ${e.approval.id} ${e.approval.status}.`),e.capabilityToken&&R("Capability token minted. Re-run the original command with `--approve` to execute automatically.")}function yl(e){return{approval:e.approval,...e.capabilityToken?{capabilityToken:{tokenId:e.capabilityToken.tokenId,expiresAt:e.capabilityToken.expiresAt}}:{}}}function bl(e){if(e.length<2)throw Error(`Usage: tangle hub call <path> <json-input>`);let t=e[e.length-1];try{return{path:e.slice(0,-1).join(`.`),input:JSON.parse(t)}}catch{throw Error(`Hub call input must be valid JSON.`)}}function xl(e){F(e.map(e=>({...e,provider:e.providerId??e.requiredConnectionProviderId,connection:El(e)})),[{key:`path`,header:`Path`},{key:`provider`,header:`Provider`},{key:`title`,header:`Title`},{key:`description`,header:`Description`},{key:`connection`,header:`Connection`},{key:`policyState`,header:`Policy`}])}function Sl(e){F(e,[{key:`connectionId`,header:`Connection`},{key:`providerId`,header:`Provider`},{key:`actionPath`,header:`Action`},{key:`decision`,header:`Decision`},{key:`updatedAt`,header:`Updated`}])}function Cl(e){if(e===`allow`||e===`ask`||e===`deny`)return e;throw Error(`--decision must be one of: allow, ask, deny.`)}function wl(e){F(e,[{key:`sourceId`,header:`Source`},{key:`displayName`,header:`Provider`},{key:`toolCount`,header:`Tools`},{key:`connectionStatus`,header:`Connection`},{key:`health`,header:`Health`},{key:`configured`,header:`Configured`}])}function Tl(e){B({Path:e.path,Provider:e.providerId??e.requiredConnectionProviderId,Title:e.title,Description:e.description,Connection:El(e),Policy:e.policyState}),e.inputSchema!==void 0&&(R(`Input schema`),console.log(JSON.stringify(e.inputSchema,null,2))),e.outputSchema!==void 0&&(R(`Output schema`),console.log(JSON.stringify(e.outputSchema,null,2)))}function El(e){if(e.connectionRequired===!1)return`not required`;if(e.connectionStatus)return e.connectionStatus}function Dl(e){F(e.map(e=>({...e,account:e.accountDisplay??e.displayName,scopes:e.scopes.join(`, `)})),[{key:`id`,header:`ID`},{key:`providerId`,header:`Provider`},{key:`account`,header:`Account`},{key:`scopes`,header:`Scopes`},{key:`status`,header:`Status`},{key:`health`,header:`Health`},{key:`lastUsedAt`,header:`Last Used`}])}function Ol(e){if(!e||e.length===0)return;let t={};for(let n of e){let e=n.indexOf(`=`);if(e<=0||e===n.length-1)throw Error(`Invalid --parameter "${n}": expected key=value (for example subdomain=acme)`);let r=n.slice(0,e);if(Object.hasOwn(t,r))throw Error(`Duplicate --parameter key "${r}".`);t[r]=n.slice(e+1)}return t}function kl(e,t,n=!1){t?R(`Opened browser to connect ${e.provider}.`):(R(`Open this URL to connect ${e.provider}:`),console.log(e.redirectUrl)),R(n?`Finish authorization in the browser; this run resumes when connected.`:"Finish authorization in the browser, then rerun `tangle hub status`.")}function Al(e){return{provider:e.provider,redirectUrl:e.redirectUrl,expiresAt:e.expiresAt,scopes:e.scopes,cli:e.cli}}function jl(e){let{principal:t,connections:n}=e;R(`Hub status`),B({Principal:t.kind,"User ID":t.userId,"API Key ID":t.apiKeyId,"Sandbox ID":t.sandboxId,"Connected Providers":n.connectedProviderCount,"Unhealthy Providers":n.unhealthyProviderCount}),n.unhealthyProviderCount>0&&R(`Some providers require reconnect.`)}const Ml=t(import.meta.url);if(!Ml)throw Error(`Tangle CLI package metadata was not found`);const Nl=me(Ml),Pl=e=>C(`sha256`).update(e).digest(`hex`);function Fl(e,t){let n=_e(e,t);return n!==`..`&&!n.startsWith(`..${ye}`)&&!ge(n)}function Il(e,t){if(/[\\/]/.test(e)||/\.(yaml|yml|json)$/.test(e))return ve(t,e);let n=t;for(;!le(j(n,`.git`))&&me(n)!==n;)n=me(n);le(j(n,`.git`))||(n=t);let r=[`yaml`,`yml`,`json`].flatMap(e=>[`graph.${e}`,e]),i=[n,M()].flatMap(t=>r.map(n=>j(t,`.tangle/graphs/${e}.${n}`))),a=i.find(le);if(a)return a;throw new V(`GRAPH_NOT_FOUND`,`Graph '${e}' was not found`,`Looked in ${i.join(`, `)}`,`tangle graph --help`)}async function Ll(e,t){return rc(e.signal,async n=>{let r=e.runId??w(),i;try{let a=j(M(),`.tangle`,`runs`,r);await Ve(a,{recursive:!0,mode:448});let o=await Ge(j(M(),`.tangle`)),s=await Ge(e.cwd??process.cwd()),c=[`runs`,`graph-registry`,`graphs`].some(e=>Fl(s,j(o,e))||Fl(j(o,e),s))?j(M(),`.tangle`,`workspaces`,r):s;await Ve(c,{recursive:!0,mode:448});let l;return await t({runId:r,runDir:a,cwd:c,bridge:e=>l??=(async()=>{n.throwIfAborted();let t=te(32).toString(`hex`),{loadConfig:r,startServer:o}=await import(`cli-bridge`),s=j(Nl,`dist`,`stdio.mjs`),l=r({...process.env,BRIDGE_HOST:`127.0.0.1`,BRIDGE_BEARER:t,BRIDGE_DATA_DIR:j(a,`bridge`),BRIDGE_BACKENDS:dc,BRIDGE_JAIL_MODE:`fs-jail`,BRIDGE_JAIL_FALLBACK:`deny`,BRIDGE_JAIL_NETWORK:`relay`,BRIDGE_SUBSCRIPTIONS_ONLY:`1`});e&&l.jailReadablePaths.push(s),i=await o({cwd:c,config:{...l,port:0},handleSignals:!1,quiet:!0,hub:e?{client:e,hash:nc,serverForGrant:e=>{if(!i)throw Error(`Hub host is not ready`);return{transport:`stdio`,command:process.execPath,args:[{kind:`public`,value:s}],env:{TANGLE_HUB_MCP_ENDPOINT:{kind:`public`,value:`${i.url}/hub/mcp/grants/${e}`}}}}}:void 0});let{graphNativeCapture:u}=await import(`./graph-native-af-gs1TS.mjs`);return{harnessTranscript:u({bridgeUrl:i.url,bridgeBearer:t,cwd:c}),backend:`bridge`,bridgeUrl:i.url,bridgeBearer:t,cwd:c}})(),signal:n})}catch(t){throw t instanceof Error&&Object.assign(t,{runId:e.errorRunId??r}),t}finally{await i?.close()}},e.fix??`tangle graph --help`)}async function Rl(e,t,n={}){let r=[`tangle graph run`,Be(e),...t.dryRun?[`--dry-run`]:[],...t.cloud?[`--cloud`]:[],...t.resume?[`--resume`,Be(t.resume)]:[],...t.seat?[`--seat`,Be(t.seat)]:[],...t.param.flatMap(e=>[`--param`,Be(e)])].join(` `);return await rc(n.signal,async i=>{i.throwIfAborted();let a=await Ge(Il(e,n.cwd??process.cwd())),o=n.source??await We(a,`utf8`);if(!t.resume&&t.cloud||t.resume?.startsWith(`wfrun_`))return Oc(a,o,t,i);let s=await Lc(),c=Pl(o),l=Object.entries(Sc(t.param,`param`)??{}),u=Object.fromEntries(l.filter(([e])=>!e.startsWith(`gate.`))),d=Object.fromEntries(l.filter(([e])=>e.startsWith(`gate.`)).map(([e,t])=>[e.slice(5),t])),f=t.resume?await cc(t.resume):void 0,p=s.graphRegistry(j(M(),`.tangle`,`graph-registry`)),m;if(f){f.file!==a&&X(`The recorded graph source path changed`);let e=await s.loadGraph(p,f.graphDigest);e||X(`The recorded executable graph is unavailable`),m=s.validateStoredGraph(e),uc(f,t,c,u,d)}let h={apiKey:t.apiKey,sandboxBaseUrl:t.baseUrl,signal:i,json:t.json,dryRun:t.dryRun&&!n.connectNeeds},g,_=()=>g??=ll(h),v=new Map,y=e=>{let t=e.trim().toLowerCase(),n=v.get(t)??(async()=>{let e=await _(),n=e&&await dl(e,t,h);return n?{connectionId:n,capabilities:[`*`]}:void 0})();return v.set(t,n),n},b=async e=>{if(i.throwIfAborted(),f&&m)return ic(m,f.gateChoices??{}),{graph:m,params:f.params};let r=await s.loadGraphFile(a,{source:o,seat:t.seat??Hn().seat,resolveSeat:fc(e,i),resolveNeed:y,params:u,cwd:e,signal:i});if(i.throwIfAborted(),ic(r.graph,d),n.graphDigest&&r.graph.digest!==n.graphDigest)throw new V(`GRAPH_CHANGED`,`The validated graph changed before execution`,`Its compiled graph digest no longer matches validation`,`tangle graph run --help`);return r},ee=n.cwd??process.cwd(),x=await b(f?.cwd??ee);if(t.dryRun)return x;let S=f?.runId??n.runId??w(),C=f?.cwd??await s.graphWorkspace(x.graph,{cwd:ee,runId:S});return Ll({...n,runId:S,cwd:C,signal:i,fix:r},async({runId:e,runDir:n,cwd:r,bridge:o})=>{let{superviseGraphPursuit:l,readSettleRecord:u}=await import(`@tangle-network/agent-runtime/durable`),m=await s.recordStoredGraphRun(p,x.graph),h=f??{version:1,runId:e,cwd:r,file:a,graphDigest:m.digest,sourceDigest:c,params:x.params,...Object.keys(d).length?{gateChoices:d}:{},startedAt:new Date().toISOString(),...t.seat===void 0?{}:{seat:t.seat}};f||await lc(n,h);let g=f?await u(n):void 0;if(g&&g.tree.root!==e&&X(`The settlement names another run`),g?.kind===`no-winner`&&X(`The local run is terminal: ${g.reason}`),g)return{runId:e,graphDigest:m.digest,sourceDigest:c,...Fc(g),replayed:!0};let v=s.graphFromStored(m),y=m.nodes.some(e=>e.profile.connections?.length),b=y?await _():void 0;if(y&&!b)throw new V(`AUTH_REQUIRED`,`Hub authentication is required`,`No Tangle credential is configured for this local graph`,`tangle auth login`);let ee=await o(b),S=h.startedAt;R(`Run ${e} · ${pe(a)} · ${r}`);let C=await zl(n);R(`Viewer ${C.url}`);let te=new AbortController,w=await l(v,{pursuitId:m.digest,runDir:n,runId:e,backend:ee,...v.entry===void 0?{driverBackend:ee}:{},...m.gates?.length?{decideGate:ac(h.gateChoices??{},{json:t.json,signal:AbortSignal.any([i,te.signal])})}:{},resume:!!f,signal:i,profileSecurity:{allowConnections:y,allowLocalMcp:!1,allowHooks:!1,allowedMcpHosts:[]}}).finally(async()=>{te.abort(),await C.close()}),T={runId:e,graphDigest:m.digest,sourceDigest:c,...Fc(w.result.result)},E=w.result.result,{tokens:D,tokensKnown:ne,iterations:re,ms:ie}=E.spentTotal;if(await s.recordStoredGraphRun(p,m,{graphDigest:m.digest,evidence:[{kind:`authored-graph`,url:`urn:sha256:${m.digest}`},{kind:`authored-yaml`,url:`urn:sha256:${c}`}],taskDigest:s.taskShapeDigest({graph:pe(a),params:x.params}),startedAt:S,finishedAt:new Date().toISOString(),outcome:E.kind===`no-winner`?{kind:`no-winner`,reason:E.reason}:{kind:`delivered`,summary:T.text},cost:{iterations:re,ms:ie,...ne===!1?{}:{tokens:D.input+D.output},...T.costUsd===null?{}:{usd:T.costUsd}},traversals:w.result.ledger.length,exhaustedEdges:w.result.exhaustedEdges,source:{kind:`tangle-cli-graph`,id:e}}),E.kind===`no-winner`)throw Object.assign(new V(`GRAPH_RUN_FAILED`,`Graph '${pe(a)}' finished without a result`,w.result.stopped?.reason||w.result.ledger.filter(e=>e.outcome===`unpropagated`&&e.reason).pop()?.reason||E.reason,`tangle graph inspect ${e}`),{runId:e,runtimeFailures:[...E.tree.nodes.filter(e=>e.failure).map(e=>({node:e.label,failure:e.failure})),...E.reason===`driver-failed`&&E.error.failure?[{node:`root`,failure:E.error.failure}]:[]]});return T})},r)}async function zl(e){let{serveTopWeb:t}=await import(`@tangle-network/agent-runtime/tui`),{readGraphSessions:n}=await import(`./graph-native-af-gs1TS.mjs`);return t({roots:[e],assets:j(Nl,`dist`,`graph-viewer`),readSessions:n})}async function Bl(e,t){if(e.startsWith(`wfrun_`)){let n=await Z(t),r=await n.workflows.getRun(e);return t.json?I(r):R(`Run ${e} · ${n.baseUrl}/app/workflows/${encodeURIComponent(r.workflowId)}/runs/${encodeURIComponent(e)}`)}let n=j(M(),`.tangle`,`runs`,e);if(!/^[a-f0-9-]{36}$/i.test(e)||!le(n))throw new V(`RUN_NOT_FOUND`,`Run '${e}' was not found`,`Use a run ID printed by tangle graph run`,`tangle graph inspect --help`);let{loadTopSnapshot:r}=await import(`@tangle-network/agent-runtime/tui`);if(t.json)return I(await r(process.cwd(),{runDir:n}));R(`Run ${e} · ${(await zl(n)).url}`)}function Vl(){let e=new x(`graph`).description(`Build and run portable agent graphs`);return $c(e),yc(e),qc(e),cl(e,Il,Nl),e.command(`inspect <run>`).description(`Inspect a live or retained graph run`).action(Bl),e.command(`run <name-or-file>`).description(`Run a saved graph over native subscriptions`).option(`--cloud`,`Run through Tangle's durable cloud workflow owner`).option(`--resume <run>`,`Resume this run's saved graph and durable execution`).option(`--seat <seat>`,`Use harness/model@effort for every node`).option(`--param <key=value>`,`Graph parameter or gate.<id>=<choice>; repeatable`,(e,t)=>[...t,e],[]).option(`--dry-run`,`Validate and print the graph without starting agents`).action(async(e,t)=>{let n=await Rl(e,t);t.json||t.dryRun?I(n):`status`in n?(R(`${n.status} · ${n.runId}`),n.text&&console.log(n.text)):`viewerUrl`in n&&R(`Run ${n.runId} · ${n.viewerUrl}`)}),e}function Hl(){let e=new x(`intelligence`).description(`Create and inspect trace intelligence reports`);return e.command(`connect [agent]`).alias(`connect-agent`).description(`Connect local agent CLIs to Tangle Intelligence`).option(`--endpoint <url>`,`OTLP endpoint base`,ia).option(`--workspace <path>`,`Workspace to write hook files into`,`.`).option(`--service-name <name>`,`OTel service.name label`).option(`--environment <name>`,`OTel deployment.environment label`,`local`).option(`--dry-run`,`Print planned writes without changing files`).option(`--hook-command <command>`,`Command native hooks should run`,`tangle intelligence hook`).option(`--no-smoke`,`Skip the install smoke trace`).action(async(e,t)=>{let n=e??`local`;la(n);let r=Wl(t.apiKey),i=await ma({selection:n,workspace:t.workspace,apiKey:r,endpoint:t.endpoint,serviceName:t.serviceName??da(t.workspace),environment:t.environment,smoke:t.smoke,dryRun:!!t.dryRun,hookCommand:t.hookCommand}),a={configPath:i.configPath,agents:i.agents,nativeAgents:i.nativeAgents,manual:i.manual,written:i.written,smokeTraceId:i.smokeTraceId};if(t.json){I(a);return}B({Config:i.configPath,Agents:i.agents.join(`, `),"Native Hooks":i.nativeAgents.join(`, `)||void 0,"Manual Setup":i.manual.length?i.manual.map(e=>`${e.label}: ${e.reason}`).join(` `):void 0,Files:i.written.join(`, `),"Smoke Trace":i.smokeTraceId})}),e.command(`doctor`).description(`Check whether your agent traces carry CONTENT or are metadata-only`).option(`--endpoint <url>`,`OTLP endpoint base`,ia).action(async e=>{let t=pa(),n=await ya({endpoint:e.endpoint===`https://intelligence.tangle.tools/v1/otlp`?t?.endpoint??`https://intelligence.tangle.tools/v1/otlp`:e.endpoint,apiKey:Wl(e.apiKey??t?.apiKey)});e.json?I(n):Ul(n),n.contentSeen||(process.exitCode=1)}),e.command(`hook`).description(`Emit one local agent hook event to Tangle Intelligence`).requiredOption(`--agent <agent>`,`Agent surface`).requiredOption(`--event <event>`,`Hook event name`).option(`--payload <json>`,`Hook payload JSON`).option(`--endpoint <url>`,`OTLP endpoint base`).option(`--service-name <name>`,`OTel service.name label`).option(`--environment <name>`,`OTel deployment.environment label`).option(`--session-id <id>`,`Session id override`).option(`--dry-run`,`Build the OTLP request without sending it`).option(`--non-blocking`,`Do not fail the parent agent process`).action(async e=>{try{let t=Gl(e.agent),n=pa(),r={agent:t,event:e.event,endpoint:e.endpoint??n?.endpoint??`https://intelligence.tangle.tools/v1/otlp`,apiKey:Wl(e.apiKey??n?.apiKey),serviceName:e.serviceName??n?.serviceName??da(process.cwd()),environment:e.environment??n?.environment??`local`,sessionId:e.sessionId,payload:e.payload===void 0?await ql():Kl(e.payload)};if(e.dryRun){let n=ga(r);if(e.json){I(n);return}B({Trace:n.traceId,Agent:t,Event:e.event});return}let i=await _a(r);if(e.json){I({traceId:i});return}B({Trace:i,Agent:t,Event:e.event})}catch(t){if(e.nonBlocking){let n=t instanceof Error?t.message:String(t);e.json?I({ok:!1,error:n}):console.error(`Tangle Intelligence hook skipped: ${n}`);return}U(t)}}),e.command(`sandbox <sandbox-id>`).description(`Create an intelligence report for one sandbox`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).action(async(e,t)=>{await Jl({type:`sandbox`,id:e},t)}),e.command(`fleet <fleet-id>`).description(`Create an intelligence report for a sandbox fleet`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).action(async(e,t)=>{await Jl({type:`fleet`,id:e},t)}),e.command(`create`).description(`Create a trace intelligence report`).requiredOption(`--subject-type <type>`,`sandbox | fleet`).requiredOption(`--subject-id <id>`,`Subject identifier`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).action(async e=>{await Jl({type:Xl(e.subjectType),id:e.subjectId},e)}),e.command(`get <job-id>`).description(`Get an intelligence report`).action(async(e,t)=>{let{client:n}=K(t),r=t.json?null:z(`Fetching intelligence report...`);r?.start();let i=await n.intelligence.getReport(e);if(r?.stop(),t.json){I(i);return}Yl(i)}),e.command(`list`).description(`List intelligence reports`).option(`--subject-type <type>`,`sandbox | fleet`).option(`--subject-id <id>`,`Subject identifier`).option(`--limit <count>`,`Maximum reports to return`).action(async e=>{let{client:t}=K(e),n=e.json?null:z(`Fetching intelligence reports...`);n?.start();let r=await t.intelligence.listReports({subjectType:e.subjectType===void 0?void 0:Xl(e.subjectType),subjectId:e.subjectId,limit:e.limit===void 0?void 0:$l(e.limit)});if(n?.stop(),e.json){I(r);return}F(r.map(e=>({jobId:e.jobId,subject:`${e.subject.type}:${e.subject.id}`,mode:e.mode,status:e.status,cost:`$${e.billing.costUsd.toFixed(2)}`,updatedAt:e.updatedAt})),[{key:`jobId`,header:`Job`,width:20},{key:`subject`,header:`Subject`,width:28},{key:`mode`,header:`Mode`,width:15},{key:`status`,header:`Status`,width:14},{key:`cost`,header:`Cost`,width:10},{key:`updatedAt`,header:`Updated`,width:18}])}),e}function Ul(e){B({Status:e.contentSeen?`content flowing`:e.tracesSeen?`metadata-only — a content gate is missing`:`no traces yet`,"Traces seen":e.tracesSeen?`yes`:`no`,"Content seen":e.contentSeen?`yes`:`no`,"Last seen":e.lastSeenAt??`never`,Window:`${e.windowDays}d`});let t=Object.entries(e.byAgent);t.length>0&&(console.log(),F(t.map(([e,t])=>({agent:e,traces:t.tracesSeen?`yes`:`no`,content:t.contentSeen?`yes`:`no`})),[{key:`agent`,header:`Agent`,width:18},{key:`traces`,header:`Traces`,width:10},{key:`content`,header:`Content`,width:10}]))}function Wl(e){let t=e??process.env.TANGLE_INTELLIGENCE_API_KEY??process.env.TANGLE_API_KEY;if(!t)throw Error(`--api-key, TANGLE_INTELLIGENCE_API_KEY, or TANGLE_API_KEY is required`);return t}function Gl(e){if(ua(e))return e;throw Error(`agent must be a known Tangle Intelligence agent surface`)}function Kl(e){try{return JSON.parse(e)}catch(e){throw Error(`--payload must be JSON: ${e instanceof Error?e.message:String(e)}`)}}async function ql(){if(process.stdin.isTTY)return;let e=``;for await(let t of process.stdin)if(e+=typeof t==`string`?t:t.toString(`utf8`),e.length>65536)throw Error(`hook payload exceeds 65536 bytes`);let t=e.trim();if(t)try{return JSON.parse(t)}catch{return{body:t.slice(0,4096)}}}async function Jl(e,t){let n=Zl(t.mode),r=eu(t.metadata),i=t.maxUsd===void 0?void 0:Ql(t.maxUsd);if(n===`agentic`&&i===void 0)throw Error(`Agentic intelligence reports require --max-usd`);let{client:a}=K(t),o=t.json?null:z(`Creating intelligence report...`);o?.start();let s=await a.intelligence.createReport({subject:e,mode:n,...i===void 0?{}:{budget:{billTo:`customer`,maxUsd:i}},...r===void 0?{}:{metadata:r}});if(o?.stop(),t.json){I(s);return}Yl(s)}function Yl(e){B({Job:e.jobId,Subject:`${e.subject.type}:${e.subject.id}`,Mode:e.mode,Status:e.status,"Billed To":e.billing.billedTo,Cost:`$${e.billing.costUsd.toFixed(2)}`,Budget:e.billing.budgetMaxUsd===void 0?void 0:`$${e.billing.budgetMaxUsd.toFixed(2)}`,Updated:e.updatedAt}),e.result!==null&&(console.log(),I(e.result))}function Xl(e){if(e===`sandbox`||e===`fleet`)return e;throw Error(`subject type must be sandbox or fleet`)}function Zl(e){if(e===`deterministic`||e===`agentic`)return e;throw Error(`mode must be deterministic or agentic`)}function Ql(e){let t=Number(e);if(!Number.isFinite(t)||t<0)throw Error(`--max-usd must be a non-negative number`);return t}function $l(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function eu(e){if(e===void 0)return;let t=JSON.parse(e);if(!t||typeof t!=`object`||Array.isArray(t))throw Error(`--metadata must be a JSON object`);return t}const tu=[`router`,`sandbox`,`blueprint-agent`,`evals`,`agent-builder`];async function nu(e,t){let n=await Lr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.platformUrl===void 0?{}:{baseUrl:e.platformUrl},...e.baseUrl===void 0?{}:{sandboxBaseUrl:e.baseUrl}});if(!t||!n.minted)return n;throw Error("This command needs a key you minted yourself. A browser login is exchanged for a short-lived key the platform will not accept for key management. Set TANGLE_API_KEY, run `tangle auth login --api-key sk-tan-…`, or mint the key in the web console. `tangle keys list` works from the login alone.")}async function ru(e,t,n={}){let r=new Headers(n.headers);n.body&&!r.has(`content-type`)&&r.set(`content-type`,`application/json`);let i=await Rr(e,t,{...n,headers:r});if(n.expected!==void 0&&i.status!==n.expected)throw Error(await iu(i,t));return i}async function iu(e,t){let n=await e.text().catch(()=>``),r;try{let e=JSON.parse(n),t=typeof e?.error==`string`?e.error:e?.error?.message;typeof t==`string`&&t.trim()&&(r=t)}catch{}if(r)return`${r} (HTTP ${e.status})`;let i=n?`: ${n.slice(0,400)}`:``;return`Platform request to ${t} returned ${e.status}${i}`}const au=[`ID`,`Prefix`,`Name`,`Product`,`Created`,`Last used`,`Expires`];function ou(e){return[e.id,e.keyPrefix??``,e.name,e.product??`all`,e.createdAt,e.lastUsedAt??`—`,e.expiresAt??`—`]}function su(){let e=new x(`keys`).description(`Manage sk-tan-* API keys on id.tangle.tools`);return e.command(`list`).description(`List your active API keys`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async e=>{let t=await nu(e,!1),n=t.baseUrl,r=await(await ru(t,`${n}/v1/keys`,{expected:200})).json();if(e.json){I(r);return}Bt(au,r.data.map(ou))}),e.command(`create`).description(`Create a new API key`).argument(`<name>`,`Human-readable name for the key`).option(`--product <product>`,`Restrict the key to one product (${tu.join(`|`)}). Omit for all products.`).option(`--budget-usd <amount>`,`Hard budget cap in USD`).option(`--rpm-limit <limit>`,`Requests-per-minute cap`).option(`--expires-in-days <days>`,`Expire the key after N days (integer)`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{if(t.product!==void 0&&!tu.includes(t.product))throw Error(`Invalid --product. Expected one of ${tu.join(`, `)}`);let n=await nu(t,!0),r=n.baseUrl,i=t.expiresInDays===void 0?void 0:new Date(Date.now()+Number.parseInt(t.expiresInDays,10)*24*60*60*1e3).toISOString(),a=z(`Creating API key...`);a.start();let o=await ru(n,`${r}/v1/keys`,{method:`POST`,expected:201,body:JSON.stringify({name:e,product:t.product,budgetUsd:t.budgetUsd?Number.parseFloat(t.budgetUsd):void 0,rpmLimit:t.rpmLimit?Number.parseInt(t.rpmLimit,10):void 0,expiresAt:i})});a.stop();let s=await o.json();if(t.json){I(s);return}L(`API key created: ${s.data.prefix}…`),R(`Copy this key now — it will never be shown again:\n${s.data.key}`)}),e.command(`revoke`).description(`Revoke an API key`).argument(`<keyId>`,"Key ID (from `tcloud keys list`)").option(`--yes`,`Skip the confirmation prompt`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{let n=await nu(t,!0),r=n.baseUrl;if(!t.yes&&!await $r(`Revoke key ${e}? Any service still using it will start to fail.`,`--yes`)){R(`Aborted.`);return}let i=await(await ru(n,`${r}/v1/keys/${encodeURIComponent(e)}`,{method:`DELETE`,expected:200})).json();if(t.json){I(i);return}L(`Revoked ${e}`)}),e}function cu(e){if(Kn().token)throw Error(`A line relay cannot manage numbers or attachments. Use your owner CLI outside the agent box.`);return G(W(e))}function lu(e){if(!e.yes)throw Error(`Review the selected line and use --yes to authorize this change. Attaching enables metered agent work.`)}function uu(e){if(e===`imessage`||e===`whatsapp`||e===`email`||e===`sms`||e===`voice`||e===`telegram`)return e;throw Error(`--transport must be imessage, whatsapp, email, sms, voice, or telegram`)}function du(e){return e().catch(U)}async function fu(e){let t=await Ue(e,`r`);try{if(!(await t.stat()).isFile())throw Error(`Attachment input must be a regular JSON file`);let e=Buffer.alloc(131073),n=0;for(;n<e.length;){let{bytesRead:r}=await t.read(e,n,e.length-n,null);if(r===0)break;n+=r}if(n===e.length)throw Error(`Attachment JSON exceeds 128 KiB`);let r;try{r=JSON.parse(e.subarray(0,n).toString(`utf8`))}catch{throw Error(`Attachment file is not valid JSON`)}if(!r||typeof r!=`object`||Array.isArray(r))throw Error(`Attachment JSON must be an object`);if(Object.hasOwn(r,`number`))throw Error(`Use the line ID argument, not a number field in the attachment file`);return r}finally{await t.close()}}function pu(e){e.command(`providers`).description(`List provider transports supported by this Hub deployment`).action(e=>du(async()=>{I(await cu(e).lines.providers())})),e.command(`list`).description(`List owned lines, optionally for a saved agent profile or sandbox`).option(`--profile-id <id>`,`Stored profile ID`).option(`--sandbox <id>`,`Existing sandbox ID`).action(e=>du(async()=>{I(await cu(e).lines.list({profileId:e.profileId,sandboxId:e.sandbox}))})),e.command(`get`).argument(`<line-id>`).description(`Inspect a line and its current attachment`).action((e,t)=>du(async()=>{I(await cu(t).lines.get(e))})),e.command(`numbers`).argument(`<connection-id>`).description(`Discover owned provider numbers; this does not purchase or reserve a number`).option(`--transport <transport>`,`imessage, whatsapp, or sms`,`imessage`).action((e,t)=>du(async()=>{let n=uu(t.transport);if(n===`email`)throw Error(`Email uses an owned mailbox, not phone inventory`);if(n===`voice`)throw Error(`Voice numbers are listed by ph0ny; provide the owned number ID to lines connect`);if(n===`telegram`)throw Error(`Telegram uses an owned bot, not phone inventory`);I(await cu(t).lines.numbers(e,n))})),e.command(`connect`).argument(`<connection-id>`).description(`Bind an owned number or identity through Hub; no provider rental is purchased`).option(`--transport <transport>`,`imessage, whatsapp, sms, email, voice, or telegram`,`imessage`).option(`--number-id <id>`,`Exact owned provider number ID; required for voice, SMS, WhatsApp and Linq iMessage`).option(`--address <email>`,`Owned mailbox on a verified email domain`).requiredOption(`--reference <reference>`,`Stable client reference; keep it unchanged on retry`).option(`--label <label>`,`Line display name`).option(`--yes`,`Authorize provider webhook configuration and line binding`).action((e,t)=>du(async()=>{lu(t);let n=uu(t.transport);if(n!==`email`&&t.address)throw Error(`--address is email-only`);if((n===`email`||n===`telegram`)&&t.numberId)throw Error(`${n} does not take --number-id`);let r={connectionId:e,label:t.label,clientReference:t.reference},i;if(n===`email`)i={...r,transport:n,address:t.address};else if(n===`telegram`)i={...r,transport:n};else if(n===`imessage`)i={...r,transport:n,phoneNumberId:t.numberId};else{if(!t.numberId)throw Error(`${n} requires --number-id`);i={...r,transport:n,phoneNumberId:t.numberId}}I(await cu(t).lines.fromConnection(i))})),e.command(`attach`).argument(`<line-id>`).description(`Attach a saved agent to any sandbox, or use an isolated on-demand member instance`).option(`--file <path>`,`Reviewed native attachment JSON (exclusive with quick-setup flags)`).option(`--profile-id <id>`,`Owner-scoped saved profile; each turn pins its source revision`).option(`--member <address>`,`The one allowed sender: E.164 phone or email`).option(`--sandbox <id>`,`Use an existing sandbox instead of an on-demand instance`).option(`--instance-prefix <prefix>`,`Stable instance namespace; defaults to profile:<profile-id>:`).option(`--tools <mode>`,`chat denies tools; act applies the profile's tools and permissions`).option(`--turns-per-day <count>`,`Per-member daily turn ceiling (default 30)`).option(`--yes`,`Authorize agent execution and spend against your key limits`).action((e,t)=>du(async()=>{lu(t);let n=cu(t),r;if(t.file){if(t.profileId||t.member||t.sandbox||t.instancePrefix||t.tools||t.turnsPerDay)throw Error(`Choose --file or quick-setup flags, not both`);r=await fu(t.file)}else{if(!t.profileId||!t.member)throw Error(`Provide --profile-id and --member, or --file`);if(t.sandbox&&t.instancePrefix)throw Error(`Choose --sandbox or --instance-prefix`);let e=t.tools??`chat`,n=Number(t.turnsPerDay??`30`);if(e!==`chat`&&e!==`act`)throw Error(`--tools must be chat or act`);if(!Number.isSafeInteger(n)||n<1||n>1e4)throw Error(`--turns-per-day must be 1–10000`);if(e===`act`&&t.sandbox)throw Error(`Acting tools require an isolated on-demand instance; omit --sandbox`);r={mode:`personal`,members:[{address:t.member,role:`owner`}],unknownSenders:`reject`,roles:{owner:{context:`own`,tools:e}},respond:{kind:`agent`,profileId:t.profileId,...e===`act`?{rolePolicy:{version:1,roles:{owner:{kind:`general`}},members:{}}}:{}},limits:{turnsPerMemberPerDay:n},...t.sandbox?{sandboxId:t.sandbox}:{instance:{keyPrefix:t.instancePrefix??`profile:${t.profileId}:`,create:{ownerContext:`isolated`,...e===`act`?{egressPolicy:{mode:`strict`,allowDomains:[new URL(ur()).hostname],includeImplicitDomains:!1}}:{}}}}}}if(typeof r.sandboxId==`string`==(r.instance!==void 0))throw Error(`Attachment requires exactly one of sandboxId and instance`);let{sandboxId:i,instance:a,...o}=r,s;if(i){let t=await n.get(i);if(!t)throw Error(`Sandbox not found`);s=await t.lines.attach({...o,number:e})}else{if(!a)throw Error(`Attachment requires an instance`);s=await n.lines.attach({...o,number:e,instance:a})}I(s)}));for(let t of[`detach`,`release`])e.command(t).argument(`<line-id>`).description(t===`detach`?`Stop dispatch; preserve history and provider rental`:`Retire a detached Hub line; does not cancel provider rental`).option(`--yes`,`Authorize this change`).action((e,n)=>du(async()=>{lu(n),I({[t]:await cu(n).lines[t](e)})}));e.command(`threads`).argument(`<line-id>`).description(`List this line's separate participant threads`).action((e,t)=>du(async()=>{I(await cu(t).lines.threads(e).list())})),e.command(`messages`).argument(`<line-id>`).argument(`<thread-id>`).description(`Read one authorized participant thread`).action((e,t,n)=>du(async()=>{I(await cu(n).lines.threads(e).messages(t))}))}async function mu(e){let{token:t,baseUrl:n}=Kn();if(t===void 0)return q(e);if(!t.startsWith(`lrc_`)||!n)throw Error(`The line box needs TANGLE_LINE_TOKEN and TANGLE_HUB_URL`);if(e.apiKey||e.baseUrl&&new URL(e.baseUrl).origin!==new URL(n).origin)throw Error(`A line token cannot be sent to another Hub or combined with an API key`);return new Ee({baseUrl:n,authHeaders:()=>({Authorization:`Bearer ${t}`})})}async function hu(e,t){if(t)return t;if(!Kn().token)throw Error(`Provide --line <line-id>`);return(await e.lines.context()).line.id}function gu(e){return e().catch(U)}function _u(){return new x(`context`).description(`Show live line identity, members, consent, reminders and quotas`).action(e=>gu(async()=>{I(await(await mu(e)).lines.context())}))}function vu(){let e=new x(`lines`).description(`Connect, manage, message and schedule on a Hub line`);return e.command(`members`).description(`List names, roles and consent on this line`).option(`--line <line-id>`,`Line ID; inferred in a line box`).action(e=>gu(async()=>{let t=await mu(e);I(await t.lines.members.list(await hu(t,e.line)))})),e.command(`send`).description(`Send to a consenting member through Hub`).argument(`<to-member>`,`Exact member ID for an owner; name, ID, or self in a line box`).argument(`<text>`,`Message text`).option(`--line <line-id>`,`Line ID; inferred in a line box`).option(`--on-behalf-of <member>`,`Verified sender for a member relay`).option(`--not-before <iso-time>`,`Delay delivery until this ISO time`).option(`--idempotency-key <key>`,`Stable key for a retry`).action((e,t,n)=>gu(async()=>{let r=await mu(n),i=await hu(r,n.line);if(!Kn().token){if(n.onBehalfOf)throw Error(`--on-behalf-of is only available inside a line box`);if(!n.idempotencyKey)throw Error(`Owner sends require --idempotency-key so a retry keeps the same message`);if(!(await r.lines.members.list(i)).some(t=>t.id===e))throw Error(`Owner sends require an exact member ID from tangle lines members`);I(await r.lines.send(i,{memberId:e,text:t,idempotencyKey:n.idempotencyKey,...n.notBefore?{notBefore:n.notBefore}:{}}));return}I(await r.lines.send(i,{toMember:e,text:t,...n.onBehalfOf?{onBehalfOf:n.onBehalfOf}:{},...n.notBefore?{notBefore:n.notBefore}:{},...n.idempotencyKey?{idempotencyKey:n.idempotencyKey}:{}}))})),e.command(`remind`).description(`Wake the agent at a future time to write your reminder`).argument(`<text>`,`What to remember`).requiredOption(`--at <iso-time>`,`Future ISO time`).option(`--line <line-id>`,`Line ID; inferred in a line box`).option(`--idempotency-key <key>`,`Stable key for a retry`).action((e,t)=>gu(async()=>{if(!t.at)throw Error(`--at is required`);let n=await mu(t),r=t.idempotencyKey??C(`sha256`).update(JSON.stringify([e,t.at])).digest(`hex`).slice(0,32);I(await n.lines.remind(await hu(n,t.line),{text:e,notBefore:t.at,idempotencyKey:r}))})),pu(e),e}function yu(){let e=new x(`mcp`).description(`Model Context Protocol bridge commands.`);return e.command(`serve <id-or-name>`).description(`Run a local MCP server (stdio) backed by the given sandbox (ID or name). Pipe its stdio from an MCP client config to expose sandbox tools.`).option(`-s, --session <id>`,`Session id for kernel scoping`,`mcp-local`).option(`--name <name>`,`MCP server name reported to clients`,`tangle-sandbox`).action(async(e,t)=>{let n=W({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=await J(G(n),n,e),i;try{i=(await import(`@modelcontextprotocol/sdk/server/stdio.js`)).StdioServerTransport}catch{throw Error("`@modelcontextprotocol/sdk` is not installed in this environment. Install it with: pnpm add -g @modelcontextprotocol/sdk (or as a dev dep in the project running this command).")}let{connect:a,close:o}=await nt(r,{sessionId:t.session,name:t.name});await a(new i),process.stdin.resume(),process.stdin.on(`end`,()=>{o().finally(()=>process.exit(0))});for(let e of[`SIGINT`,`SIGTERM`])process.on(e,()=>{o().finally(()=>process.exit(0))})}),e}async function bu(e,t){if(t.self&&e)throw Error(`Use --self or an explicit sandbox, not both`);if(!t.self&&!e)throw Error(`Specify a sandbox id/name or --self`);let n=Ln(),r=t.baseUrl||n.tangleBaseUrl||n.sandboxBaseUrl,i=n.hubUrl;if(t.self&&!r&&i&&new URL(i).origin!==`https://id.tangle.tools`)throw Error(`This deployment must set SANDBOX_BASE_URL or pass --base-url for self preview access`);let a=t.self?t.apiKey??nr():t.apiKey;if(t.self&&!a)throw Error(`Self preview access requires the injected sandbox runtime credential; it never reads saved owner credentials`);let o=W({apiKey:a,baseUrl:r}),s=G(o);return t.self?at(s):J(s,o,e)}async function xu(e,t,n){let r=z(e);t||r.start();try{return await n()}finally{r.stop()}}function Su(e){return e}function Cu(){let e=new x(`preview`).description(`Manage sandbox preview links`);return Su(e.command(`start`).description(`Start/reuse a managed development server and publish its ready preview`).argument(`[id-or-name]`,`Sandbox ID or name`).option(`--self`,`Use only the sandbox bound to the runtime credential`).option(`--cwd <directory>`,`Project directory in the selected workspace`).option(`--session <session-id>`,`Select the agent's session workspace`).option(`--name <name>`,`App/service label`)).action(async(e,t)=>{let n=await bu(e,t),r=await xu(`Starting managed preview...`,t.json,()=>rt(n,{cwd:t.cwd,sessionId:t.session,name:t.name}));t.json?I(r):(L(`Preview ready: ${r.url}`),console.log(`Preview ID: ${r.previewId}`))}),Su(e.command(`list`).alias(`ls`).description(`List active preview links for a sandbox`).argument(`[id-or-name]`,`Sandbox ID or name`).option(`--self`,`Use only the sandbox bound to the runtime credential`)).action(async(e,t)=>{let n=await bu(e,t),r=await xu(`Fetching preview links...`,t.json,()=>n.previewLinks.list());t.json?I(r):r.length===0?console.log(`No preview links found`):Bt([`App`,`Preview ID`,`Port`,`URL`,`Status`],r.map(e=>[wu(e.metadata),e.previewId.slice(0,12),String(e.port),e.url,e.status]))}),Su(e.command(`publish`).description(`Publish one existing HTTP service; never starts or replaces a process`).argument(`[id-or-name]`,`Sandbox ID or name`).option(`--self`,`Use only the sandbox bound to the runtime credential`).requiredOption(`--port <port>`,`Existing service port`).option(`--name <name>`,`App/service label`)).action(async(e,t)=>{if(!t.port||!/^\d+$/.test(t.port))throw Error(`An integer service port is required`);let n=await bu(e,t),r=await xu(`Publishing service...`,t.json,()=>it(n,{port:Number(t.port),name:t.name}));t.json?I(r):L(`Preview ready: ${r.url}`)}),Su(e.command(`create`).description(`Create a preview link for a port`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<port>`,`Port number to preview`)).action(async(e,t,n)=>{if(!/^\d+$/.test(t)||Number(t)<1||Number(t)>65535)throw Error(`Port must be an integer between 1 and 65535`);let r=await bu(e,n),i=await xu(`Creating preview for port ${t}...`,n.json,()=>r.previewLinks.create(Number(t)));n.json?I(i):(L(`Preview created: ${i.url}`),console.log(`Preview ID: ${i.previewId}`))}),Su(e.command(`remove`).alias(`rm`).description(`Remove a preview link`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<preview-id>`,`Preview link ID (from 'preview list')`)).action(async(e,t,n)=>{let r=await bu(e,n);await xu(`Removing preview...`,n.json,()=>r.previewLinks.remove(t)),n.json?I({success:!0,previewId:t}):L(`Preview removed: ${t}`)}),e}function wu(e){let t=e?.app;if(!t||typeof t!=`object`)return``;let n=`name`in t?t.name:void 0,r=`cwd`in t?t.cwd:void 0;return typeof n==`string`?n:typeof r==`string`?r:``}function Tu(){let e=new x(`process`).description(`Manage processes in a sandbox`);return e.command(`spawn`).description(`Spawn a process without blocking (returns PID)`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<command>`,`Command to execute`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`).option(`--blocking`,`Wait for completion (default: false)`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=ts(n.env??[],`--env`,`env`),o=z(`Spawning: ${t}`);n.json||o.start();let s=await J(i,r,e);if(s=await Y(s),n.blocking){let e=await s.exec(t,{cwd:n.cwd,env:Object.keys(a).length>0?a:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});o.stop(),n.json?I(e):(e.stdout&&globalThis.process.stdout.write(e.stdout),e.stderr&&globalThis.process.stderr.write(e.stderr),e.exitCode!==0&&globalThis.process.exit(e.exitCode))}else{let r=await s.process.spawn(t,{cwd:n.cwd,env:Object.keys(a).length>0?a:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});o.stop(),n.json?I({pid:r.pid,command:r.command}):(console.log(`Process started with PID: ${r.pid}`),console.log(`Use 'tangle process logs ${e} ${r.pid}' to view output`))}}),e.command(`list`).alias(`ls`).description(`List all processes in a sandbox`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--running`,`Show only running processes`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching processes...`);t.json||i.start();let a=await J(r,n,e);a=await Y(a);let o=await a.process.list();t.running&&(o=o.filter(e=>e.running)),i.stop(),t.json?I(o):o.length===0?console.log(`No processes found`):Bt([`PID`,`Command`,`Status`,`Exit Code`,`Started`],o.map(e=>[String(e.pid),e.command.length>40?`${e.command.slice(0,37)}...`:e.command,e.running?`running`:`exited`,String(e.exitCode),e.startedAt.toLocaleString()]))}),e.command(`get`).description(`Get detailed info about a process`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Fetching process info...`);n.json||a.start();let o=await J(i,r,e);o=await Y(o);let s=await o.process.get(Number.parseInt(t,10));if(a.stop(),!s){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}let c=await s.status();n.json?I(c):(console.log(`PID: ${c.pid}`),console.log(`Command: ${c.command}`),console.log(`CWD: ${c.cwd||`(default)`}`),console.log(`Status: ${c.running?`running`:`exited`}`),console.log(`Exit Code: ${c.exitCode}`),c.exitSignal&&console.log(`Signal: ${c.exitSignal}`),console.log(`Started: ${c.startedAt.toLocaleString()}`),c.exitedAt&&console.log(`Exited: ${c.exitedAt.toLocaleString()}`))}),e.command(`kill`).description(`Kill a process`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).option(`-s, --signal <signal>`,`Signal to send (SIGTERM, SIGKILL, etc.)`,`SIGTERM`).option(`--tree`,`Also kill descendants of the tracked process`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Sending ${n.signal} to PID ${t}...`);n.json||a.start();let o=await J(i,r,e);o=await Y(o);let s=await o.process.get(Number.parseInt(t,10));if(!s){a.stop(),console.error(`Process ${t} not found`),globalThis.process.exit(1);return}n.tree?await s.kill(n.signal,{tree:!0}):await s.kill(n.signal),a.stop(),n.json?I({pid:Number.parseInt(t,10),signal:n.signal,...n.tree===!0?{tree:!0}:{},killed:!0}):console.log(n.tree?`Sent ${n.signal} to process tree ${t}`:`Sent ${n.signal} to process ${t}`)}),e.command(`logs`).description(`Stream buffered and live process logs until the process exits`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).option(`--stdout-only`,`Only show stdout`).option(`--stderr-only`,`Only show stderr`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a);let o=await a.process.get(Number.parseInt(t,10));if(!o){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}for await(let e of o.logs())n.stdoutOnly&&e.type!==`stdout`||n.stderrOnly&&e.type!==`stderr`||(n.json?console.log(JSON.stringify(e)):e.type===`stdout`?globalThis.process.stdout.write(e.data):globalThis.process.stderr.write(e.data))}),e}const Eu=[`python`,`node`,`typescript`,`bash`];function Du(e){switch(he(e).toLowerCase()){case`.py`:return`python`;case`.js`:case`.mjs`:case`.cjs`:return`node`;case`.ts`:case`.tsx`:return`typescript`;case`.sh`:case`.bash`:return`bash`;default:return}}async function Ou(e){if(e===`-`){let e=[];for await(let t of process.stdin)e.push(typeof t==`string`?Buffer.from(t):t);return Buffer.concat(e).toString(`utf8`)}return await We(ve(e),`utf8`)}async function ku(e,t,n=Ou){let r=t?Eu.find(e=>e===t)??(()=>{throw Error(`unknown --lang ${t}: must be one of ${Eu.join(`, `)}`)})():void 0;if(!e||e===`-`){if(!r)throw Error(`reading from stdin requires --lang. Example: tangle run <id> -l python -`);return{language:r,source:await n(`-`)}}let i=Du(e);return{language:r??i??(()=>{throw Error(`cannot infer language from "${e}". Pass it explicitly: tangle run <id> -l <python|node|typescript|bash> ${e}`)})(),source:await n(e)}}function Au(e){return j(xe(),`tangle-run-images`,e)}function ju(){return new x(`run`).description(`Run code in a persistent kernel inside a sandbox. Variables persist across calls in the same --session.`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`[file]`,`Path to source file. Language is inferred from extension. Use - for stdin (requires --lang).`).option(`-l, --lang <lang>`,`Force language: ${Eu.join(` | `)}. Required for stdin.`).option(`-s, --session <id>`,`Session id for kernel scoping`).option(`-t, --timeout <ms>`,`Per-call timeout in ms (0 disables)`,`60000`).option(`--save-images <dir>`,`Write image results into this directory (default: $TMPDIR/tangle-run-images/<sandbox>/).`).option(`--no-save-images`,`Don't write image results to disk; print summary only`).action(async(e,t,n)=>{let{language:r,source:i}=await ku(t,n.lang),{context:a,client:o}=K(n),s=await J(o,a,e);s=await Y(s);let c=z(`Running ${r} (${i.length}b)…`);n.json||c.start();let l=await s.runCode(r,i,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10)});if(c.stop(),n.json){I(l),l.exitCode!==0&&process.exit(l.exitCode);return}l.stdout&&process.stdout.write(l.stdout),l.stderr&&process.stderr.write(l.stderr);let u=0;for(let t of l.results)if(t.type===`image`)if(n.saveImages!==!1){let r=typeof n.saveImages==`string`?n.saveImages:Au(e);ue(r,{recursive:!0});let i=`${r}/${Date.now()}-${u}.${t.format}`;fe(i,Buffer.from(t.data,`base64`)),process.stderr.write(b.green(`✓ image → ${i}\n`)),u++}else process.stderr.write(b.gray(`[image: ${t.format}, ${t.data.length}b base64]\n`));else if(t.type===`dataframe`){let e=t.columns.map(e=>`${e.name}:${e.dtype}`).join(` | `);process.stderr.write(b.gray(`[dataframe ${t.rows.length}×${t.columns.length}${t.truncated?` (truncated)`:``}]\n`)),process.stderr.write(`${e}\n`);for(let e of t.rows.slice(0,20))process.stderr.write(`${e.map(e=>String(e)).join(` | `)}\n`);t.rows.length>20&&process.stderr.write(b.gray(`… ${t.rows.length-20} more rows\n`))}else t.type===`json`?(process.stderr.write(b.gray(`[json] `)),process.stderr.write(`${JSON.stringify(t.value,null,2)}\n`)):t.type===`html`?process.stderr.write(b.gray(`[html ${t.value.length}b]\n`)):t.type===`error`?(process.stderr.write(b.red(`✗ ${t.name}: ${t.message}\n`)),t.traceback&&process.stderr.write(`${t.traceback}\n`)):t.type===`text`&&process.stderr.write(`${t.value}\n`);l.error&&(process.stderr.write(b.red(`\n✗ ${l.error.name}: ${l.error.message}\n`)),l.error.traceback&&process.stderr.write(`${l.error.traceback}\n`)),l.exitCode!==0&&process.exit(l.exitCode)})}function Mu(e){e.command(`network <id-or-name>`).description(`Show runtime network state (exposed ports) for a sandbox. Outbound policy is the sandbox's egress policy.`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Updating network configuration...`);i.start();let a=await J(r,n,e);i.stop();let o=await a.network.getConfig();t.json?I(o):(R(`Network Configuration:`),o.ports&&o.ports.length>0?R(` Exposed Ports: ${o.ports.join(`, `)}`):R(` No exposed ports`))}),e.command(`expose <id-or-name>`).description(`Expose a port and get a public URL`).option(`-p, --port <port>`,`Port to expose`,`8000`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=Number.parseInt(t.port,10);if(Number.isNaN(i)||i<1||i>65535)throw Error(`Port must be a number between 1 and 65535`);let a=z(`Exposing port ${i}...`);a.start();let o=await(await J(r,n,e)).network.exposePort(i);a.stop(),t.json?I({port:i,url:o}):(L(`Port ${i} exposed.`),R(` URL: ${o}`))}),e.command(`urls <id-or-name>`).description(`List exposed port URLs for a sandbox`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching exposed URLs...`);i.start();let a=await(await J(r,n,e)).network.listUrls();if(i.stop(),t.json)I(a);else{let e=Object.entries(a);if(e.length===0)R(`No ports exposed.`);else{R(`Exposed Ports:`);for(let[t,n]of e)R(` ${t}: ${n}`)}}})}function Nu(){let e=new x(`sandbox`).description(`Manage sandboxes`);return Ns(e),Ms(e),Ss(e),Mu(e),e}function Pu(){return new x(`search`).description(`Search for text patterns in sandbox files (ripgrep)`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pattern>`,`Search pattern (regex)`).option(`-g, --glob <pattern>`,`File glob filter (e.g. '**/*.ts')`).option(`-n, --max-results <count>`,`Max results to return`).option(`-i, --ignore-case`,`Case-insensitive search`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Searching...`);n.json||a.start();let o=await J(i,r,e),s=0,c=n.maxResults?Number.parseInt(n.maxResults,10):void 0,l={};n.glob&&(l.glob=n.glob),n.ignoreCase&&(l.ignoreCase=!0),c&&(l.maxResults=c);for await(let e of o.search(t,l))if(s===0&&a.stop(),s++,n.json?console.log(JSON.stringify(e)):console.log(`${e.path}:${e.line}:${e.column??0}: ${e.text}`),c&&s>=c)break;a.stop(),s===0&&!n.json&&console.log(`No matches found`)})}function Fu(){let e=new x(`secret`).description(`Manage secrets`);return e.command(`create`).description(`Create a new secret`).argument(`<name>`,`Secret name (e.g., HF_TOKEN, AWS_ACCESS_KEY)`).argument(`[value]`,`Secret value`).option(`--value-stdin`,`Read secret value from stdin`).action(async(e,t,n)=>{let r=await K(n).client.secrets.create(e,await Iu({value:t,valueStdin:n.valueStdin,prompt:`Enter value for secret '${e}': `}));n.json?I(r):(L(`Secret created: ${r.name}`),R(`Use --secret ${r.name} when creating a sandbox to select it for delivery.`))}),e.command(`list`).description(`List all secrets`).action(async e=>{let t=await K(e).client.secrets.list();e.json?I(t):t.length===0?(R(`No secrets found.`),R(`Use 'tangle secret create <name> [value]' to create one.`)):Bt([`Name`,`Created At`,`Updated At`],t.map(e=>[e.name,e.createdAt.toLocaleString(),e.updatedAt.toLocaleString()]))}),e.command(`delete`).description(`Delete a secret`).argument(`<name>`,`Secret name`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=K(t).client;if(!t.force&&!await $r(`Are you sure you want to delete secret '${e}'? This cannot be undone. (y/N) `,`--force`)){R(`Cancelled.`);return}await n.secrets.delete(e),t.json?I({success:!0,deleted:e}):L(`Secret deleted: ${e}`)}),e}async function Iu(e){if(e.value!==void 0&&e.valueStdin)throw Error(`Provide either a secret value argument or --value-stdin, not both`);let t=e.value??(e.valueStdin?await ti():await Qr(e.prompt));if(!t.length)throw Error(e.valueStdin?`Secret value from stdin cannot be empty`:`Secret value cannot be empty`);return t}function Lu(){let e=new x(`skill`).description(`Print paths to shipped skill documentation`);return e.command(`path`).description(`Print the absolute path to the SKILL.md shipped with this CLI`).action(()=>{let e=A.dirname($e(import.meta.url)),t=A.resolve(e,`..`,`SKILL.md`);console.log(t)}),e}function Ru(){let e=new x(`snapshot`).description(`Manage snapshots`);return e.command(`create <sandbox-id-or-name>`).description(`Create a snapshot of a sandbox`).option(`--tags <tags...>`,`Tags for the snapshot`).option(`--no-wait`,`Return once the snapshot is accepted and print the operation to poll`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Creating snapshot...`);i.start();let a=await J(r,n,e);if(t.wait===!1){let e=await a.snapshot({tags:t.tags,wait:!1});i.stop(),Cs(e.info,!!t.json);return}let o=await a.snapshot({tags:t.tags});i.stop(),t.json?I(o):(L(`Snapshot created: ${o.snapshotId}`),console.log(`Size: ${zu(o.sizeBytes??0)}`))}),e.command(`list <sandbox-id-or-name>`).description(`List snapshots for a sandbox`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching snapshots...`);i.start();let a=await(await J(r,n,e)).listSnapshots();i.stop(),t.json?I(a):F(a.map(e=>({...e,size:zu(e.sizeBytes??0)})),[{key:`snapshotId`,header:`ID`,width:24},{key:`createdAt`,header:`Created`,width:16},{key:`size`,header:`Size`,width:12},{key:`sandboxId`,header:`Sandbox`,width:20}])}),e.command(`restore <sandbox-id> <snapshot-id>`).description(`Create a new sandbox from a snapshot`).option(`--billing-owner <userId>`,`Platform user that pays for the restored sandbox. The API accepts this only from a first-party service key that is listed as a billing delegate, and refuses such a key that names no payer.`).action(async(e,t,n)=>{let{client:r}=K(n),i=z(`Restoring from snapshot...`);i.start();let a=await r.create({fromSnapshot:t,fromSandboxId:e,...n.billingOwner?{billingOwnerId:n.billingOwner}:{}});await a.waitFor(`running`,{timeoutMs:12e4}),i.stop(),n.json?I({sandboxId:a.id,restoredFrom:t,status:a.status}):(L(`New sandbox created: ${a.id}`),console.log(`Source snapshot: ${t}`))}),e.command(`revert <sandbox-id-or-name> <snapshot-id>`).description(`Revert an existing sandbox to a snapshot`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Reverting sandbox to snapshot...`);a.start();let o=await J(i,r,e),s=await o.revertToSnapshot(t);await o.refresh(),a.stop(),n.json?I({sandboxId:o.id,snapshotId:s.snapshotId,status:o.status}):(L(`Sandbox reverted: ${o.id}`),console.log(`Source snapshot: ${s.snapshotId}`))}),e.command(`delete <sandbox-id-or-name> <snapshot-id>`).description(`Delete a sandbox snapshot`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Deleting snapshot...`);a.start();let o=await(await J(i,r,e)).deleteSnapshot(t);a.stop(),n.json?I({success:!0,sandboxId:e,snapshotId:t,outcome:o.outcome}):o.outcome===`already_absent`?L(`Snapshot already gone: ${t}`):L(`Snapshot deleted: ${t}`)}),e}function zu(e){if(e===0)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`,`TB`],r=Math.floor(Math.log(e)/Math.log(t));return`${Number.parseFloat((e/t**r).toFixed(1))} ${n[r]}`}const Bu=`solve:device:secp256k1`,Vu=/^0x[0-9a-f]{64}$/i;function Hu(e){return e&&Vu.test(e)?e:void 0}function Uu(){let e=mn(Bu),t=Hu(e.value);if(!(!t||e.source===`none`))return{account:st(t),source:e.source}}function Wu(){let e=Uu();if(e)return e;let t=ot(),n=hn(Bu,t);return{account:st(t),source:n}}function Gu(e){let t=Hu(mn(Bu).value);if(!t||st(t).address!==e.account.address)throw Error(`The local Solve device key changed; it was not retired`);let n=`${Bu}:retired:${e.account.address.toLowerCase()}`;if(hn(n,t),mn(n).value!==t)throw Error(`The revoked device key could not be retired safely`);return _n(Bu),n}function Ku(e){let t=e.create?Wu():Uu();if(!t)throw Error("No Solve device signer found. Run `tangle solve account --create`");e.json?I({address:t.account.address,source:t.source}):B({Address:t.account.address,Source:t.source})}const qu=/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;function Ju(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function Yu(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`${t} must be an object`);return e}function Xu(e,t,n=2048){if(typeof e!=`string`||!e.trim()||e.length>n)throw Error(`${t} is missing or invalid`);if(Ju(e))throw Error(`${t} contains control characters`);return e.trim()}function Zu(e,t){let n=Xu(e,t,64).toLowerCase();if(!qu.test(n))throw Error(`${t} must be a 40 or 64 character Git revision`);return n}function Qu(e,t,n=!1){let r=typeof e==`number`&&Number.isSafeInteger(e)?String(e):Xu(e,t,80);if(!/^\d+$/.test(r)||!n&&r===`0`)throw Error(`${t} must be an unsigned integer`);return BigInt(r).toString()}function $u(e,t){let n=Xu(e,t,2048),r=new URL(n);if(r.protocol!==`https:`&&!(r.protocol===`http:`&&(r.hostname===`localhost`||r.hostname===`127.0.0.1`)))throw Error(`${t} must use HTTPS outside local development`);return n.replace(/\/$/,``)}function ed(e,t){let n=$u(e,t).replace(/\.git$/,``),r=new URL(n),i=r.pathname.split(`/`).filter(Boolean);if(r.hostname!==`github.com`||r.username||r.password||r.search||r.hash||i.length!==2)throw Error(`${t} must be an HTTPS GitHub repository URL`);return`https://github.com/${i.join(`/`)}`}function td(e,t){let n=Xu(e,t,42);if(!ht(n,{strict:!1}))throw Error(`${t} must be an EVM address`);return pt(n)}function nd(e,t){let n=Qu(e,t),r=Number(n);if(!Number.isSafeInteger(r)||r<=0)throw Error(`${t} is out of range`);return r}function rd(...e){for(let t of e)if(typeof t==`string`&&t.trim())return t.trim()}function id(e){let t=e.trim().replace(/\.git$/,``);return t.startsWith(`git@github.com:`)?`https://github.com/${t.slice(15)}`:t.startsWith(`ssh://git@github.com/`)?`https://github.com/${t.slice(21)}`:t}function ad(e){if(e===void 0)return;let t=Xu(e,`pull request URL`,2048);if(!/^https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/\d+(?:\/[^\s]*)?$/i.test(t))throw Error(`pull request URL must point to a GitHub pull request`);return t}function od(e,t){if(!/^https:\/\/[^\s]+$/i.test(e)&&!/^\/(?!\/).*$/.test(e)&&!/^[a-z][a-z0-9+.-]*:[^\s]+$/i.test(e))throw Error(`${t} must be an HTTPS URL or an absolute repository path`);if(e.split(/[?#]/,1)[0].split(`/`).includes(`..`))throw Error(`${t} cannot contain parent-directory segments`);return e}function sd(e){return Rn(`solve`,e.profile)}function cd(e){let t=sd(e),n=ir(void 0,t);if(!n)throw Error(`No Solve credential found for profile '${t}'. Run: tangle auth login --provider github --app solve`);return n}async function ld(e){let t=dr(e.apiUrl),n=await fetch(`${t}${e.path}`,{method:e.method??`GET`,headers:{Accept:`application/json`,...e.body===void 0?{}:{"Content-Type":`application/json`},Authorization:`Bearer ${cd(e)}`},...e.body===void 0?{}:{body:JSON.stringify(e.body)},signal:AbortSignal.timeout(3e4)}),r=await n.json().catch(()=>null);if(!n.ok||!r?.success||r.data===void 0){let e=r?.error?.message??`Solve API request failed with HTTP ${n.status}`;throw Error(r?.error?.code?`${r.error.code}: ${e}`:e)}return r.data}function ud(e){return ld({path:`/v1/wallet/challenges`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.purpose?{purpose:e.purpose}:{}}})}function dd(e){return ld({path:`/v1/devices`,apiUrl:e.apiUrl,profile:e.profile})}function fd(e){return ld({path:`/v1/devices/revoke`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.reason?{reason:e.reason}:{},...e.challengeId&&e.signature?{challengeId:e.challengeId,signature:e.signature}:{}}})}const pd={chainId:42431,rpcUrl:`https://rpc.moderato.tempo.xyz`,sponsorUrl:`https://drew-gtr-pro.taild10bfc.ts.net/solve-sponsor`,tangleAddress:`0xff137B9C879c47C28ce389e84501925438AB4cdA`,managerAddress:`0x5271732F893B622ac6793d6DBA5B2626CCa4EA14`,paymentAsset:`0x20C0000000000000000000000000000000000000`,blueprintId:15n,serviceId:9n,competitionId:1n,minStakeWei:0n};function md(e,t){return e.toLowerCase()===t.toLowerCase()}function hd(e){if(e.chainId!==pd.chainId)throw Error(`Solve submissions require Tempo Moderato (chain ${pd.chainId}); received ${e.chainId}`);if(e.rpcUrl!==pd.rpcUrl)throw Error(`Solve metadata RPC does not match the trusted deployment`);if(e.sponsorUrl!==pd.sponsorUrl)throw Error(`Solve metadata sponsor does not match the trusted deployment`);if(!md(e.tangleAddress,pd.tangleAddress))throw Error(`Solve metadata Tangle contract does not match the trusted deployment`);if(!md(e.managerAddress,pd.managerAddress))throw Error(`Solve metadata competition manager does not match the trusted deployment`);if(!md(e.paymentAsset,pd.paymentAsset))throw Error(`Solve metadata payment asset does not match the trusted deployment`);if(e.blueprintId!==pd.blueprintId)throw Error(`Solve submissions require blueprint ${pd.blueprintId}; received ${e.blueprintId}`);if(e.serviceId!==pd.serviceId)throw Error(`Solve submissions require service ${pd.serviceId}; received ${e.serviceId}`);if(e.competitionId!==pd.competitionId)throw Error(`Solve submissions require competition ${pd.competitionId}; received ${e.competitionId}`);if(e.minStakeWei!==pd.minStakeWei)throw Error(`Solve submissions require zero stake for the trusted deployment`)}function gd(e,t){let n=Yu(t.check??e.check,`competition.participation.check`),r=Xu(n.command,`competition.participation.check.command`,512);if(!Array.isArray(n.args)||n.args.some(e=>typeof e!=`string`))throw Error(`competition.participation.check.args must be an array of strings`);let i=n.args.map(e=>Xu(e,`competition checker argument`,2048)),a=rd(n.result_file,n.resultFile),o=n.timeout_ms??n.timeoutMs,s=o===void 0?void 0:nd(o,`competition checker timeout`);return{command:r,args:i,...a?{result_file:a}:{},...s?{timeout_ms:s}:{}}}function _d(e){if(e.provenance===void 0)return;let t=Yu(e.provenance,`competition.participation.provenance`);if(t.mode!==`github_pull_request`)throw Error(`competition.participation.provenance.mode is unsupported`);if(t.required!==void 0&&typeof t.required!=`boolean`)throw Error(`competition.participation.provenance.required must be a boolean`);return{mode:`github_pull_request`,required:t.required===!0}}function vd(e){let t=Yu(e.chain??e.network??{},`competition.chain`),n=e.rewards&&typeof e.rewards==`object`&&!Array.isArray(e.rewards)?Yu(e.rewards,`competition.rewards`):{},r=n.minStake&&typeof n.minStake==`object`&&!Array.isArray(n.minStake)?Yu(n.minStake,`competition.rewards.minStake`).raw:void 0,i=rd(t.minStakeWei,t.min_stake_wei,e.minStakeWei,e.min_stake_wei,r),a=t.chainId??t.chain_id??e.chainId??e.chain_id,o=rd(t.chainName,t.chain_name,e.chainName,e.chain_name)??`Tempo`,s=rd(t.nativeSymbol,t.native_symbol,e.nativeSymbol,e.native_symbol)??`TNT`,c=rd(t.rpcUrl,t.rpc_url,e.rpcUrl,e.rpc_url,process.env.TANGLE_SOLVE_RPC_URL),l=rd(t.sponsorUrl,t.sponsor_url,e.sponsorUrl,e.sponsor_url,process.env.TANGLE_SOLVE_SPONSOR_URL),u=rd(t.tangleAddress,t.tangle_address,t.coreAddress,t.core_address,e.tangleAddress,e.tangle_address,e.coreAddress,e.core_address),d=rd(t.managerAddress,t.manager_address,e.managerAddress,e.manager_address),f=rd(t.paymentAsset,t.payment_asset,t.servicePaymentAsset,t.service_payment_asset,e.paymentAsset,e.payment_asset,e.servicePaymentAsset,e.service_payment_asset),p=rd(t.blueprintId,t.blueprint_id,e.blueprintId,e.blueprint_id),m=rd(t.serviceId,t.service_id,e.serviceId,e.service_id),h=rd(t.competitionId,t.competition_id,e.competitionId,e.competition_id,e.id);if(!c||!l||!u||!d||!p||!m||!h||!i||a===void 0)throw Error(`Solve competition metadata must include complete Tempo chain configuration`);return{chainId:nd(a,`chain.chainId`),chainName:o,nativeSymbol:s,rpcUrl:$u(c,`chain.rpcUrl`),sponsorUrl:$u(l,`chain.sponsorUrl`),tangleAddress:td(u,`chain.tangleAddress`),managerAddress:td(d,`chain.managerAddress`),paymentAsset:td(f??pd.paymentAsset,`chain.paymentAsset`),blueprintId:Qu(p,`chain.blueprintId`),serviceId:Qu(m,`chain.serviceId`),competitionId:Qu(h,`chain.competitionId`,!0),minStakeWei:Qu(i,`chain.minStakeWei`,!0)}}function yd(e){let t=Yu(e,`competition`),n=Yu(t.participation??t.task,`competition.task`),r={...t,participation:{...n,...n.repositoryRevision===void 0&&n.revision!==void 0?{repositoryRevision:n.revision}:{}}},i=r.participation,a=ed(rd(r.repository,r.repo_url,i.repository)??``,`competition.repository`),o=Zu(rd(r.repositoryRevision,r.repository_revision,i.revision,i.repositoryRevision,i.repository_revision),`competition.repositoryRevision`),s=Xu(r.slug??r.id,`competition.slug`,128),c=Xu(r.name??r.title??s,`competition.name`,256),l=gd(r,i),u=_d(i);return{version:1,slug:s,title:c,repository:a,taskRevision:o,checker:l,chain:vd(r),...u?{provenance:u}:{}}}function bd(e){return{chainId:e.chain.chainId,chainName:e.chain.chainName,nativeSymbol:e.chain.nativeSymbol,rpcUrl:e.chain.rpcUrl,sponsorUrl:e.chain.sponsorUrl,tangleAddress:e.chain.tangleAddress,managerAddress:e.chain.managerAddress,paymentAsset:e.chain.paymentAsset,blueprintId:BigInt(e.chain.blueprintId),serviceId:BigInt(e.chain.serviceId),competitionId:BigInt(e.chain.competitionId),minStakeWei:BigInt(e.chain.minStakeWei)}}async function xd(e){let t=Yu(JSON.parse(await P.readFile(A.join(e,`.tangle-solve.json`),`utf8`)),`.tangle-solve.json`);if(t.version!==1)throw Error(`.tangle-solve.json has an unsupported version`);let n=Yu(t.checker,`.tangle-solve.json.checker`),r=Yu(t.chain,`.tangle-solve.json.chain`);return yd({slug:t.slug,name:t.title,repository:t.repository,repositoryRevision:t.taskRevision,participation:{check:n,provenance:t.provenance},chain:r,competitionId:r.competitionId})}const Sd=Ye(Se),Cd=`.tangle-solve-run.json`,wd=`.tangle-solve.json`,Td=`tangle.solve.manifestSha256`,Ed=new Set([wd,Cd]),Dd=`upstream`;async function Od(e,t){let n=await Sd(`git`,[`-C`,e,...t],{encoding:`utf8`,maxBuffer:1e6});return String(n.stdout).trim()}async function kd(e,t){let n=A.resolve(t??process.cwd()),r=await xd(n);if(e&&e!==r.slug&&e!==r.chain.competitionId)throw Error(`This directory contains '${r.slug}', not '${e}'`);return{root:n,manifest:r}}async function Ad(e){let t=A.join(e,wd),n;try{n=await P.lstat(t)}catch{throw Error(`${wd} is missing`)}if(n.isSymbolicLink()||!n.isFile())throw Error(`${wd} must be a regular file`);return C(`sha256`).update(await P.readFile(t)).digest(`hex`)}async function jd(e){let t=await Ad(e);return await Od(e,[`config`,`--local`,`--replace-all`,Td,t]),t}async function Md(e){let t;try{t=await Od(e,[`config`,`--local`,`--get`,Td])}catch{throw Error(`The local Git metadata has no ${Td} pin; run tangle solve clone again`)}if(!/^[0-9a-f]{64}$/i.test(t))throw Error(`The local ${Td} pin is invalid`);if(await Ad(e)!==t.toLowerCase())throw Error(`${wd} changed after clone; run tangle solve clone again`)}async function Nd(e,t){try{return await Od(e,[`ls-files`,`--error-unmatch`,`--`,t]),!0}catch{return!1}}async function Pd(e){await Md(e);for(let t of Ed)if(await Nd(e,t))throw Error(`${t} must remain untracked and local to this Solve workspace`);let t=await Sd(`git`,[`-C`,e,`status`,`--porcelain=v1`,`--untracked-files=all`,`--ignored=matching`],{encoding:`utf8`,maxBuffer:1e6});if(String(t.stdout).split(/\r?\n/).filter(Boolean).filter(e=>{let t=e.slice(0,2),n=e.slice(3);return!((t===`??`||t===`!!`)&&Ed.has(n))}).length>0)throw Error(`Commit the candidate before running Solve. Only the local manifest and run record may remain uncommitted.`);return Zu(await Od(e,[`rev-parse`,`HEAD`]),`submission revision`)}async function Fd(e,t,n,r={}){let i=await Id(e,t,r);if(i)return{taskRepository:t.repository,taskRevision:t.taskRevision,submissionRepository:i,submissionRevision:n}}async function Id(e,t,n={}){let r;try{r=id(await Od(e,[`config`,`--get`,`remote.origin.pushurl`]))}catch{try{r=id(await Od(e,[`config`,`--get`,`remote.origin.url`]))}catch{if(n.allowMissing)return;throw Error(`Add your GitHub fork as the 'origin' remote before submitting. The task repository is available as '${Dd}'.`)}}let i=ed(r,`git remote.origin.url`);if(i.toLowerCase()===t.repository.toLowerCase()){if(n.allowMissing)return;throw Error(`The 'origin' remote is the task repository. Add your GitHub fork as 'origin'; keep the task repository as '${Dd}' before submitting.`)}return i}function Ld(e,t){return!e||!t?!1:e.taskRepository.toLowerCase()===t.taskRepository.toLowerCase()&&e.taskRevision.toLowerCase()===t.taskRevision.toLowerCase()&&e.submissionRepository.toLowerCase()===t.submissionRepository.toLowerCase()&&e.submissionRevision.toLowerCase()===t.submissionRevision.toLowerCase()}function Rd(e,t){return`${e}/commit/${t}`}function zd(e,t,n,r,i={}){let a=e.evidenceRefs.map(e=>od(e.trim(),`checker evidence reference`));if(n){if(!t){if(i.allowMissingSource)return{evidence:e.evidence,evidenceRefs:a};throw Error(`Provenance policy requires a submission source`)}let o=ad(r);if(n.required&&(i.requirePullRequest??!0)&&!o)throw Error(`This competition requires a GitHub pull request`);a.push(Rd(t.taskRepository,t.taskRevision),Rd(t.submissionRepository,t.submissionRevision),...o?[o]:[])}return{evidence:e.evidence,evidenceRefs:[...new Set(a)]}}async function Bd(e,t){let n=`${e}.${process.pid}.tmp`;await P.writeFile(n,`${JSON.stringify(t,null,2)}\n`,{mode:384}),await P.rename(n,e)}async function Vd(e){let t=JSON.parse(await P.readFile(A.join(e,Cd),`utf8`));if(t.version!==1||typeof t.competition!=`string`)throw Error(`${Cd} has an unsupported format`);return t}async function Hd(e){let t=ad(e.pullRequest);if(!t)throw Error(`A pull request URL is required`);let n=new URL(t).pathname.split(`/`).filter(Boolean),r=await fetch(`https://api.github.com/repos/${n[0]}/${n[1]}/pulls/${n[3]}`,{headers:{Accept:`application/vnd.github+json`,"User-Agent":`tangle-solve-cli`},signal:AbortSignal.timeout(15e3)}),i=await r.json().catch(()=>null),a=e=>e.replace(/\/$/,``).toLowerCase();if(!r.ok||a(i?.base?.repo?.html_url??``)!==a(e.taskRepository)||i?.head?.sha?.toLowerCase()!==e.submissionRevision.toLowerCase()||a(i?.head?.repo?.html_url??``)!==a(e.submissionRepository))throw Error(`GitHub pull request must target the pinned task repository and contain the current committed submission`)}function Ud(e){return{...e.authorization?{authorization:e.authorization}:{},...e.stake?{stake:e.stake}:{},join:e.join,commit:e.commit,reveal:e.reveal,report:e.report,evaluation:e.evaluation}}const Wd=Ye(Se);function Gd(){return`Task source is '${Dd}'. Add your fork as 'origin', commit your candidate, push it, and open a pull request before submitting.`}async function Kd(e,t,n){try{let r=Yu(await ld({path:`/v1/competitions/${encodeURIComponent(e)}`,apiUrl:n.apiUrl,profile:n.profile}),`competition response`),i=yd(r.competition??r),a=A.resolve(t??i.slug),o=z(`Cloning ${i.slug}…`);n.json||o.start();try{await Wd(`git`,[`clone`,`--no-tags`,`--origin`,Dd,i.repository,a],{encoding:`utf8`,maxBuffer:1e6}),await Od(a,[`checkout`,`--detach`,i.taskRevision]);let e=await Od(a,[`rev-parse`,`HEAD`]);if(e.toLowerCase()!==i.taskRevision.toLowerCase())throw Error(`Pinned checkout resolved to ${e}, expected ${i.taskRevision}`);await Bd(A.join(a,`.tangle-solve.json`),i),await jd(a)}finally{o.stop()}n.json?I({competition:i,directory:a}):(L(`Cloned ${i.slug} at ${i.taskRevision.slice(0,12)}`),i.provenance&&R(Gd()),R(`Run the pinned checker with: cd ${a} && tangle solve run`))}catch(e){U(e)}}const qd=12e4,Jd=vt(`event JobSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint8 jobIndex, address caller, bytes inputs)`),Yd=vt(`event JobCompleted(uint64 indexed serviceId, uint64 indexed callId)`),Xd=vt(`event JobResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, address indexed operator, bytes result)`),Zd=vt(`event AggregatedResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint256 signerBitmap, bytes output)`),Qd=vt(`event EvaluationAccepted(uint64 indexed serviceId, uint64 indexed competitionId, address indexed researcher, bytes32 candidateId, bytes32 submissionRefHash, bytes32 evaluationDigest, bytes32 metricsHash, bytes32 evidenceRefsHash)`),$d=[..._t([`function submitJob(uint64 serviceId, uint8 jobIndex, bytes inputs) payable returns (uint64 callId)`,`function getJobEventRate(uint64 blueprintId, uint8 jobIndex) view returns (uint256 rate)`,`function getServicePaymentAsset(uint64 serviceId) view returns (address)`,`function isPermittedCaller(uint64 serviceId, address caller) view returns (bool)`]),Jd,Yd,Xd,Zd],ef=_t([`function authorizeSelf(uint64 serviceId)`,`function revokeSelf(uint64 serviceId)`,`function isDeviceRevoked(address device) view returns (bool)`,`function postStake(uint64 serviceId, uint64 competitionId) payable`,`function stakes(uint64 serviceId, uint64 competitionId, address researcher) view returns (uint256)`,`function pendingResults(uint64 serviceId, uint64 jobCallId) view returns (uint8 job, bytes32 outputHash, uint256 signerBitmap, bool exists, bool executed)`,`function executePendingResult(uint64 serviceId, uint64 jobCallId, bytes output)`,`function acceptedCandidates(uint64 serviceId, uint64 competitionId, address researcher, bytes32 candidateId) view returns (bool)`]),tf=_t([`function allowance(address owner, address spender) view returns (uint256)`,`function approve(address spender, uint256 amount) returns (bool)`]),nf=yt(`uint64 competitionId, uint256 stakeWei`),rf=yt(`uint64 competitionId, bytes32 commitment`),af=yt(`uint64 competitionId, bytes32 commitment, string artifactRef, bytes32 salt`),of=yt(`string artifactRef, bytes32 salt`),sf=yt(`uint64 competitionId, bytes32 candidateId, string submissionRef, string evidenceJson, string evidenceRefsJson`),cf=yt(`string status, string detail`),lf=/^0x[0-9a-f]{64}$/i;function uf(e,t){if(e!==t)throw Error(`Tempo RPC returned chain ${e}; expected ${t}`)}function df(e,t,n){return{...e,feePayer:!0,nonceKey:t,nonce:n}}function ff(e,t){if(e!==`success`)throw Error(`${t} transaction reverted`)}function pf(e,t,n,r){if(!lf.test(t))throw Error(`${n} transaction hash is invalid`);if(typeof e.transactionHash!=`string`||e.transactionHash.toLowerCase()!==t.toLowerCase())throw Error(`${n} receipt hash does not match the saved transaction`);if(ff(e.status??``,n),typeof e.from!=`string`||e.from.toLowerCase()!==r.from.toLowerCase())throw Error(`${n} receipt sender does not match the Solve device`);if(typeof e.to!=`string`||e.to.toLowerCase()!==r.to.toLowerCase())throw Error(`${n} receipt destination does not match the expected contract`)}function mf(e,t){return e>=t?[]:e>0n?[0n,t]:[t]}function hf(e,t,n=Date.now()){return n>=e+t}function gf(e,t){return e.filter(e=>e.args?.candidateId?.toLowerCase()===t.toLowerCase()).at(-1)?.transactionHash}function _f(e,t,n,r,i){for(let a of e.logs)if(a.address.toLowerCase()===t.tangleAddress.toLowerCase())try{let e=dt({abi:[Jd],eventName:`JobSubmitted`,data:a.data,topics:a.topics});if(e.args.serviceId===t.serviceId&&e.args.jobIndex===n&&e.args.caller.toLowerCase()===r.toLowerCase()&&(!i||e.args.inputs.toLowerCase()===i.toLowerCase()))return e.args.callId}catch{}throw Error(`Tangle did not emit job ${n} for ${r}`)}function vf(e,t,n,r){for(let i of e.logs)if(i.address.toLowerCase()===t.managerAddress.toLowerCase())try{let e=dt({abi:[Qd],eventName:`EvaluationAccepted`,data:i.data,topics:i.topics}).args;if(e.serviceId===t.serviceId&&e.competitionId===t.competitionId&&e.researcher.toLowerCase()===n.address.toLowerCase()&&e.candidateId.toLowerCase()===r.toLowerCase())return!0}catch{}return!1}function yf(e){if(e.chainId!==St.id)throw Error(`Solve submissions require Tempo Moderato (chain ${St.id}); received ${e.chainId}`);if(!e.sponsorUrl)throw Error(`Solve submissions require a Tempo sponsor relay URL; unsponsored writes are disabled`);return{...St,name:e.chainName,nativeCurrency:{name:e.nativeSymbol,symbol:e.nativeSymbol,decimals:18},rpcUrls:{default:{http:[e.rpcUrl]}}}}async function bf(e,t){hd(e);let n=yf(e),r=ct({chain:n,transport:mt(e.rpcUrl)});return uf(await r.getChainId(),e.chainId),await xf({publicClient:r},e),{publicClient:r,walletClient:lt({account:t,chain:n,transport:wt(mt(e.rpcUrl),mt(e.sponsorUrl))}),account:t}}async function xf(e,t){let n=await e.publicClient.readContract({address:t.tangleAddress,abi:$d,functionName:`getServicePaymentAsset`,args:[t.serviceId]});if(n.toLowerCase()!==t.paymentAsset.toLowerCase())throw Error(`Tempo service payment asset ${n} does not match the trusted Solve asset ${t.paymentAsset}`)}async function Sf(e,t,n){let[r,i]=await Promise.all([e.publicClient.readContract({address:t.tangleAddress,abi:$d,functionName:`getJobEventRate`,args:[t.blueprintId,n]}),e.publicClient.readContract({address:t.tangleAddress,abi:$d,functionName:`getServicePaymentAsset`,args:[t.serviceId]})]);if(i.toLowerCase()!==t.paymentAsset.toLowerCase())throw Error(`Tempo job payment asset ${i} does not match the trusted Solve asset ${t.paymentAsset}`);return{asset:i,amount:r,value:i===`0x0000000000000000000000000000000000000000`?r:0n}}async function Cf(e,t,n){return await e.publicClient.readContract({address:t,abi:tf,functionName:`allowance`,args:[e.account.address,n.tangleAddress]})}async function wf(e,t,n,r,i,a){let o=Date.now();for(;!hf(o,a);){if((await e.publicClient.getLogs({address:t.tangleAddress,event:Yd,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`})).length>0){let a=(await e.publicClient.getLogs({address:t.tangleAddress,event:Xd,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`}))[0]?.args.result;if(!a)throw Error(`Tangle job ${n} completed without a result`);let[o,s]=ut(cf,a);if(o!==i)throw Error(`Tangle job ${n} ${o}: ${s}`);return{status:o,detail:s}}await new Promise(e=>setTimeout(e,1e3))}throw Error(`Tangle job ${n} did not complete within 120 seconds`)}async function Tf(e,t,n,r,i){let a=Date.now();for(;!hf(a,i);){let i=(await e.publicClient.getLogs({address:t.tangleAddress,event:Zd,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`}))[0]?.args.output;if(i)return i;await new Promise(e=>setTimeout(e,1e3))}throw Error(`Tangle job ${n} did not produce an aggregate within 120 seconds`)}async function Ef(e,t,n){return!!await e.publicClient.readContract({address:t.managerAddress,abi:ef,functionName:`acceptedCandidates`,args:[t.serviceId,t.competitionId,e.account.address,n]})}const Df=BigInt(gt(bt(`tangle.solve.v1`)));async function Of(e,t){let n=await Ct.nonce.getNonce(e.publicClient,{account:e.account.address,nonceKey:Df});if(n>BigInt(2**53-1))throw Error(`The Solve transaction nonce exceeds the safe range`);return e.walletClient.writeContract(df(t,Df,Number(n)))}async function kf(e,t,n,r){if(!await e.publicClient.readContract({address:t.tangleAddress,abi:$d,functionName:`isPermittedCaller`,args:[t.serviceId,e.account.address]}))try{let i=r??await Of(e,{address:t.managerAddress,abi:ef,functionName:`authorizeSelf`,args:[t.serviceId]});if(r||await n?.(`authorization`,i),pf(await e.publicClient.waitForTransactionReceipt({hash:i}),i,`Authorization`,{from:e.account.address,to:t.managerAddress}),!await e.publicClient.readContract({address:t.tangleAddress,abi:$d,functionName:`isPermittedCaller`,args:[t.serviceId,e.account.address]}))throw Error(`authorization transaction did not add the device`);return i}catch(e){let t=e instanceof Error?e.message:`unknown chain error`;throw Error(`The competition manager did not authorize this device. The deployed manager must expose authorizeSelf(uint64): ${t}`)}}async function Af(e,t){let n=await Of(e,{address:t.managerAddress,abi:ef,functionName:`revokeSelf`,args:[t.serviceId]});return pf(await e.publicClient.waitForTransactionReceipt({hash:n}),n,`Revocation`,{from:e.account.address,to:t.managerAddress}),n}async function jf(e,t,n,r,i=`allowance`,a={}){if(t.amount===0n||t.asset===`0x0000000000000000000000000000000000000000`)return;let o=await Cf(e,t.asset,n);for(let s of mf(o,t.amount)){let o=s===0n?`${i}:reset`:`${i}:approval`,c=a[o];if(c){if(pf(await e.publicClient.waitForTransactionReceipt({hash:c}),c,s===0n?`ERC-20 allowance reset`:`ERC-20 allowance approval`,{from:e.account.address,to:t.asset}),await Cf(e,t.asset,n)!==s)throw Error(`${s===0n?`ERC-20 allowance reset`:`ERC-20 allowance approval`} did not set the expected allowance`);continue}let l=await Of(e,{address:t.asset,abi:tf,functionName:`approve`,args:[n.tangleAddress,s]});await r?.(o,l),pf(await e.publicClient.waitForTransactionReceipt({hash:l}),l,s===0n?`ERC-20 allowance reset`:`ERC-20 allowance approval`,{from:e.account.address,to:t.asset})}}async function Mf(e,t,n,r,i,a=`job:${n}`,o={}){let s=await Sf(e,t,n);await jf(e,s,t,i,`allowance:${a}`,o);let c=o[a],l=c??await Of(e,{address:t.tangleAddress,abi:$d,functionName:`submitJob`,args:[t.serviceId,n,r],value:s.value});c||await i?.(a,l);let u=await e.publicClient.waitForTransactionReceipt({hash:l});return pf(u,l,`Job ${n}`,{from:e.account.address,to:t.tangleAddress}),{hash:l,callId:_f(u,t,n,e.account.address,r),blockNumber:u.blockNumber}}async function Nf(e,t,n,r,i,a,o=`job:${n}`,s={}){let c=await Mf(e,t,n,r,a,o,s),l=await wf(e,t,c.callId,c.blockNumber,i,qd);return{...c,acknowledgement:l}}const Pf={...pd,chainName:`Tempo Moderato`,nativeSymbol:`TNT`},Ff={async read(e){let t=ct({chain:St,transport:mt(Pf.rpcUrl,{timeout:15e3})}),n=e=>e.catch(()=>null),r=await Promise.all(e.map(async e=>{let[r,i]=await Promise.all([n(t.readContract({address:Pf.tangleAddress,abi:$d,functionName:`isPermittedCaller`,args:[Pf.serviceId,e]})),n(t.readContract({address:Pf.managerAddress,abi:ef,functionName:`isDeviceRevoked`,args:[e]}))]);return[e.toLowerCase(),{permitted:r,revoked:i}]}));return new Map(r)},async revokeSelf(e){return Af(await bf(Pf,e),Pf)}},If={permitted:null,revoked:null};function Lf(e){return e.revoked?`revoked`:e.permitted===null?`unknown`:e.permitted?`permitted`:`not permitted`}async function Rf(e,t=Ff){try{let{devices:n}=await dd({apiUrl:e.apiUrl,profile:e.profile}),r=Uu()?.account.address.toLowerCase(),i=n.map(e=>({...e,local:e.address===r,status:e.revokedAt?`revoked`:`active`}));r&&!i.some(e=>e.local)&&i.push({address:r,local:!0,status:`unbound`,boundAt:null,lastUsedAt:null,revokedAt:null,revocationMethod:null,revocationReason:null});let a=await t.read(i.map(e=>pt(e.address))),o=i.map(e=>({...e,onChain:a.get(e.address)??If}));if(e.json){I({serviceId:Pf.serviceId.toString(),devices:o});return}Bt([`Address`,`Status`,`Local`,`Service ${Pf.serviceId}`,`Last used`,`Revoked`],o.map(e=>[e.address,e.status,e.local?`yes`:``,Lf(e.onChain),e.lastUsedAt??``,e.revokedAt?`${e.revokedAt} (${e.revocationMethod})`:``]))}catch(t){U(t,e.json)}}async function zf(e,t,n=Ff){try{if(!ht(e))throw Error(`${e} is not an EVM address`);let r=pt(e),i=Uu(),a=i?.account.address===r;if(!t.yes){if(!process.stdin.isTTY)throw Error(`Revoking a device is permanent. Re-run with --yes to confirm`);if(!await $r(`Permanently revoke Solve device ${r}${a?` (this machine's device)`:``}? [y/N] `,`--yes`)){R(`Revocation cancelled`);return}}let o;if(i&&a){let e=await ud({deviceAddress:r,purpose:`revoke`,apiUrl:t.apiUrl,profile:t.profile});o={challengeId:e.challengeId,signature:await i.account.signMessage({message:e.message})}}let s=await fd({deviceAddress:r,reason:t.reason,...o,apiUrl:t.apiUrl,profile:t.profile}),c=r.toLowerCase(),l=(await n.read([r])).get(c)??If,u;if(i&&a&&!l.revoked){try{u=await n.revokeSelf(i.account)}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`The Solve API revoked ${r}, but the on-chain revocation failed and the local key was kept: ${t}. Run the command again to retry`)}l=(await n.read([r])).get(c)??If}let d=i&&a&&l.revoked?Gu(i):void 0;if(t.json){I({...s,serviceId:Pf.serviceId.toString(),onChain:l,...u?{revocationTransaction:u}:{},localKeyRetired:!!d});return}L(s.alreadyRevoked?`${r} was already revoked in the Solve API`:`Revoked ${r}; the Solve API refuses its signatures`),u&&L(`Revoked on Tempo in ${u}; service ${Pf.serviceId} refuses its jobs`),d&&R("The local device key was moved aside because its address may still hold stake or rewards. Run `tangle solve account --create` for a new device"),!a&&l.permitted&&Ft(`The device can still submit jobs to service ${Pf.serviceId}. Only its key, or the Solve blueprint owner, can revoke it on chain`)}catch(e){U(e,t.json)}}function Bf(e,t){return gt(ft(of,[e.trim(),t]))}function Vf(e){let t=/^submission=(\S+)/.exec(e);if(!t?.[1])throw Error(`COMMIT_CANDIDATE did not return a submission reference`);return t[1]}async function Hf(e,t,n,r,i){let a=i.resumeTransactions?.evaluation;if(a){let n=await e.publicClient.waitForTransactionReceipt({hash:a});if(pf(n,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!vf(n,t,e.account,r))throw Error(`Saved evaluation transaction did not emit EvaluationAccepted for this candidate`);return a}let o=Date.now();for(;!hf(o,qd);){if(await Ef(e,t,r)){let i=gf(await e.publicClient.getLogs({address:t.managerAddress,event:Qd,args:{serviceId:t.serviceId,competitionId:t.competitionId,researcher:e.account.address},fromBlock:n.blockNumber,toBlock:`latest`}),r);if(i)return i;throw Error(`Candidate is already accepted, but its EvaluationAccepted transaction is unavailable`)}let[a,o,,s,c]=await e.publicClient.readContract({address:t.managerAddress,abi:ef,functionName:`pendingResults`,args:[t.serviceId,n.callId]});if(s&&a!==4)throw Error(`Manager pending result ${n.callId} has unexpected job ${a}`);if(s&&c)throw Error(`Manager executed the report without EvaluationAccepted`);if(s&&!c){if(o.toLowerCase()!==gt(n.output).toLowerCase())throw Error(`Manager pending report output does not match the aggregate`);let a=await Of(e,{address:t.managerAddress,abi:ef,functionName:`executePendingResult`,args:[t.serviceId,n.callId,n.output]});await i.onTransaction?.(`evaluation`,a);let s=await e.publicClient.waitForTransactionReceipt({hash:a});if(pf(s,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!vf(s,t,e.account,r))throw Error(`Evaluation transaction did not emit EvaluationAccepted for this candidate`);return a}await new Promise(e=>setTimeout(e,1e3))}throw Error(`Manager did not emit EvaluationAccepted within 120 seconds`)}async function Uf(e,t,n,r={}){if(hd(e),!/^0x[0-9a-f]{64}$/i.test(n.salt))throw Error(`Reveal salt must be bytes32`);if(!n.artifactRef.trim())throw Error(`Candidate reference is required`);if(!n.evidenceJson.trim()||n.evidenceRefs.length===0)throw Error(`Checker evidence is required`);let i=await bf(e,t),a=await kf(i,e,r.onTransaction,r.resumeTransactions?.authorization),o,s=await i.publicClient.readContract({address:e.managerAddress,abi:ef,functionName:`stakes`,args:[e.serviceId,e.competitionId,i.account.address]});s<e.minStakeWei&&(o=await Of(i,{address:e.managerAddress,abi:ef,functionName:`postStake`,args:[e.serviceId,e.competitionId],value:e.minStakeWei-s}),await r.onTransaction?.(`stake`,o),pf(await i.publicClient.waitForTransactionReceipt({hash:o}),o,`Stake`,{from:i.account.address,to:e.managerAddress}));let c=Bf(n.artifactRef,n.salt),l=ft(nf,[e.competitionId,e.minStakeWei]),u=ft(rf,[e.competitionId,c]),d=ft(af,[e.competitionId,c,n.artifactRef.trim(),n.salt]),f=await Nf(i,e,1,l,`joined`,r.onTransaction,`join`,r.resumeTransactions),p=await Nf(i,e,2,u,`committed`,r.onTransaction,`commit`,r.resumeTransactions),m=Vf(p.acknowledgement.detail),h=await Nf(i,e,3,d,`revealed`,r.onTransaction,`reveal`,r.resumeTransactions),g=await Mf(i,e,4,ft(sf,[e.competitionId,c,m,n.evidenceJson,JSON.stringify(n.evidenceRefs)]),r.onTransaction,`report`,r.resumeTransactions),_=await Tf(i,e,g.callId,g.blockNumber,qd),v=await Hf(i,e,{callId:g.callId,output:_,blockNumber:g.blockNumber},c,r);return{address:i.account.address,...a?{authorization:a}:{},...o?{stake:o}:{},join:f.hash,commit:p.hash,reveal:h.hash,report:g.hash,evaluation:v,candidateId:c,submissionRef:m}}const Wf=Ye(Se),Gf=`/usr/bin/bwrap`,Kf=[`/usr`,`/bin`,`/sbin`,`/lib`,`/lib64`];function qf(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function Jf(e,t){if(!e||e.length>2048||qf(e))throw Error(`${t} contains invalid control characters or is too long`)}function Yf(e,t){let n=t;for(;n<e.length&&/\s/.test(e[n]??``);)n+=1;return n}function Xf(e,t){if(e[t]!==`"`)throw Error(`Checker output must be valid JSON`);let n=t+1;for(;n<e.length;){let t=e[n];if(t===`\\`){n+=2;continue}if(t===`"`)return n+1;if((t?.charCodeAt(0)??0)<32)throw Error(`Checker output must be valid JSON`);n+=1}throw Error(`Checker output must be valid JSON`)}function Zf(e,t,n){let r=new Set,i=Yf(e,t+1);if(e[i]===`}`)return i+1;for(;i<e.length;){let t=Xf(e,i),a=JSON.parse(e.slice(i,t));if(r.has(a))throw Error(`Checker output must not contain duplicate object keys`);if(r.add(a),i=Yf(e,t),e[i]!==`:`)throw Error(`Checker output must be valid JSON`);let o=Yf(e,i+1),s=$f(e,o);if(n?.(a,o,s),i=Yf(e,s),e[i]===`}`)return i+1;if(e[i]!==`,`)throw Error(`Checker output must be valid JSON`);i=Yf(e,i+1)}throw Error(`Checker output must be valid JSON`)}function Qf(e,t){let n=Yf(e,t+1);if(e[n]===`]`)return n+1;for(;n<e.length;){if(n=Yf(e,$f(e,n)),e[n]===`]`)return n+1;if(e[n]!==`,`)throw Error(`Checker output must be valid JSON`);n=Yf(e,n+1)}throw Error(`Checker output must be valid JSON`)}function $f(e,t){if(e[t]===`"`)return Xf(e,t);if(e[t]===`{`)return Zf(e,t);if(e[t]===`[`)return Qf(e,t);let n=t;for(;n<e.length&&!/[\s,\]}]/.test(e[n]??``);)n+=1;return n}function ep(e){let t=e.trim();if(Yf(t,$f(t,0))!==t.length)throw Error(`Checker output must be valid JSON`)}function tp(e,t){let n=e.trim();if(n[0]!==`{`)return;let r;return Zf(n,0,(e,i,a)=>{e===t&&(r=n.slice(i,a).trim())}),r}function np(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Checker output must be one JSON object`)}if(ep(e),!t||typeof t!=`object`||Array.isArray(t))throw Error(`Checker output must be a JSON object`);let n=t,r=n.candidate_ref;if(typeof r!=`string`||!r.trim())throw Error(`Checker output must include candidate_ref`);let i=r.trim(),a=n.evidence_refs;if(!Array.isArray(a)||a.length===0||a.some(e=>typeof e!=`string`||!e.trim()))throw Error(`Checker output must include a non-empty evidence_refs array`);Jf(i,`candidate_ref`);for(let e of a)Jf(e.trim(),`evidence_refs`);if(!n.evidence_json||typeof n.evidence_json!=`object`||Array.isArray(n.evidence_json))throw Error(`Checker output must include an evidence_json object`);let o={...n.evidence_json},s=tp(e,`evidence_json`);if(!s)throw Error(`Checker evidence_json source text is missing`);if(o.candidate_ref!==i)throw Error(`Checker evidence_json candidate_ref must match candidate_ref`);return{candidateRef:i,evidenceRefs:a.map(e=>e.trim()),evidence:o,evidenceJson:s}}async function rp(e,t,n){let r=n.trim();if(r.startsWith(`{`)&&r.endsWith(`}`)||!t.result_file)return r;let i=await lp(e),a=A.resolve(i,t.result_file),o=A.relative(i,a);if(o.startsWith(`..`)||A.isAbsolute(o))throw Error(`Checker result_file must stay inside the competition repository`);let s;try{s=await P.lstat(a)}catch{throw Error(`Checker result_file must be an existing regular file inside the competition repository`)}if(s.isSymbolicLink())throw Error(`Checker result_file must not be a symbolic link`);if(!s.isFile())throw Error(`Checker result_file must be an existing regular file inside the competition repository`);let c;try{c=await P.realpath(a)}catch{throw Error(`Checker result_file must resolve to a regular file inside the competition repository`)}let l=A.relative(i,c);if(l.startsWith(`..`)||A.isAbsolute(l))throw Error(`Checker result_file must stay inside the competition repository`);return(await P.readFile(c,`utf8`)).trim()}function ip(e,t){let n=A.relative(e,t);return n===``||!n.startsWith(`..`)&&!A.isAbsolute(n)}function ap(e){return Kf.some(t=>ip(t,e))}async function op(e,t,n){let r=e.includes(`/`)?[A.resolve(t,e)]:(process.env.PATH??``).split(A.delimiter).filter(Boolean).map(t=>A.join(t,e));for(let i of r){let r;try{r=await P.realpath(i),await P.access(r,P.constants.X_OK)}catch{continue}if(!ip(t,r)&&!ap(r)&&r!==n)throw Error(`Checker executable '${e}' must resolve inside the competition repository or a trusted runtime directory`);return r}throw Error(`Checker executable '${e}' was not found`)}async function sp(e){let t=[];for(let n of e)try{(await P.stat(n)).isDirectory()&&t.push(n)}catch{}return t}async function cp(e){let t=await P.realpath(be.homedir());if(e===A.parse(e).root||e===t)throw Error(`Solve checker repository must be a dedicated directory, not the filesystem or home root`)}async function lp(e){let t=await P.realpath(e);return await cp(t),t}async function up(e){let t=A.join(e,`.git`),n;try{n=await P.lstat(t)}catch{return}if(n.isSymbolicLink())throw Error(`Solve checker repository .git must not be a symbolic link`);if(!n.isDirectory()&&!n.isFile())return;let r;try{let t={...process.env};for(let e of[`GIT_DIR`,`GIT_WORK_TREE`,`GIT_INDEX_FILE`,`GIT_OBJECT_DIRECTORY`,`GIT_ALTERNATE_OBJECT_DIRECTORIES`,`GIT_COMMON_DIR`,`GIT_CONFIG_COUNT`,`GIT_CONFIG_PARAMETERS`])delete t[e];let n=await Wf(`/usr/bin/git`,[`-C`,e,`rev-parse`,`--verify`,`HEAD^{commit}`],{encoding:`utf8`,maxBuffer:1e5,env:{...t,GIT_CONFIG_GLOBAL:`/dev/null`,GIT_CONFIG_SYSTEM:`/dev/null`,GIT_CONFIG_NOSYSTEM:`1`,GIT_TERMINAL_PROMPT:`0`}}),i=String(n.stdout).trim();/^[0-9a-f]{40}$/i.test(i)&&(r=i.toLowerCase())}catch{}return{kind:n.isDirectory()?`directory`:`file`,...r?{commit:r}:{}}}async function dp(e,t,n){let r=await lp(e);if(process.platform!==`linux`)throw Error(`Solve checkers require the Linux sandbox runtime (bubblewrap) with network isolation`);try{await P.access(Gf,P.constants.X_OK)}catch{throw Error(`Solve checkers require /usr/bin/bwrap; install bubblewrap or run the checker in a Tangle sandbox`)}let i=await op(t,r,await P.realpath(process.execPath)),a=await up(r),o=(await sp(Kf)).flatMap(e=>[`--ro-bind`,e,e]),s=ip(r,i)?`/work/${A.relative(r,i)}`:ap(i)?i:`/checker/node`;!ip(r,i)&&!ap(i)&&o.push(`--ro-bind`,i,`/checker/node`);let c=a?.kind===`directory`?[`--tmpfs`,`/work/.git`]:a?.kind===`file`?[`--ro-bind`,`/dev/null`,`/work/.git`]:[];return{executable:Gf,args:[`--die-with-parent`,`--new-session`,`--unshare-all`,`--clearenv`,...o,`--proc`,`/proc`,`--dev`,`/dev`,`--tmpfs`,`/tmp`,`--dir`,`/tmp/home`,`--bind`,r,`/work`,...c,`--chdir`,`/work`,`--setenv`,`HOME`,`/tmp/home`,...a?.commit?[`--setenv`,`TANGLE_SOLVE_COMMIT`,a.commit]:[],`--setenv`,`TMPDIR`,`/tmp`,`--setenv`,`PATH`,`/checker:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`,`--setenv`,`LANG`,`C.UTF-8`,`--setenv`,`PYTHONDONTWRITEBYTECODE`,`1`,`--setenv`,`XDG_CONFIG_HOME`,`/tmp/home/.config`,`--setenv`,`XDG_CACHE_HOME`,`/tmp/home/.cache`,`--setenv`,`XDG_DATA_HOME`,`/tmp/home/.local/share`,`--setenv`,`GIT_CONFIG_GLOBAL`,`/dev/null`,`--setenv`,`GIT_CONFIG_SYSTEM`,`/dev/null`,`--setenv`,`NPM_CONFIG_USERCONFIG`,`/dev/null`,s,...n]}}async function fp(e,t){if(!t.command||t.command.includes(`/../`)||qf(t.command))throw Error(`The competition checker command is invalid`);if(!Array.isArray(t.args))throw Error(`The competition checker arguments must be an array`);for(let e of t.args)Jf(e,`Checker argument`);let n=t.timeout_ms??15*6e4;if(!Number.isSafeInteger(n)||n<1e3||n>60*6e4)throw Error(`Checker timeout must be between one second and one hour`);let r=await lp(e),i;try{let e=await dp(r,t.command,t.args);i=await Wf(e.executable,e.args,{cwd:r,timeout:n,maxBuffer:4194304,encoding:`utf8`})}catch(e){let t=e,n=t.stderr?.trim()||t.stdout?.trim()||t.message||`checker failed`;throw Error(`Pinned checker failed: ${n}`)}let a=String(i.stdout),o=String(i.stderr);return{...np(await rp(r,t,a)),stdout:a,stderr:o}}async function pp(e,t){try{let{root:n,manifest:r}=await kd(e,t.directory),i=await Pd(n),a=r.provenance?await Fd(n,r,i,{allowMissing:!0}):void 0,o=Wu(),s=z(`Running ${r.title} checker…`);t.json||s.start();let c;try{c=await fp(n,r.checker)}finally{s.stop()}let l=zd(c,a,r.provenance,void 0,{allowMissingSource:!0,requirePullRequest:!1}),u=xt(te(32)),d=Bf(c.candidateRef,u),f={version:1,competition:r.slug,candidateRef:c.candidateRef,evidence:l.evidence,evidenceJson:c.evidenceJson,evidenceRefs:l.evidenceRefs,salt:u,candidateId:d,...a?{source:a}:{},deviceAddress:o.account.address,clientSubmissionId:w(),createdAt:new Date().toISOString()};await Bd(A.join(n,`.tangle-solve-run.json`),f),t.json?I({localRun:f}):(L(`Checker output recorded locally for operator evaluation`),B({Competition:r.slug,Candidate:c.candidateRef,"Device address":o.account.address,"Evidence refs":l.evidenceRefs.length}),R("Commit any changes, then run `tangle solve submit` from this directory."),r.provenance&&!a&&R(`Add your GitHub fork as 'origin' before submitting. The task repository is available as '${Dd}'.`))}catch(e){U(e)}}const mp=/^0x[0-9a-f]{64}$/i;async function hp(e){let t=await ud({deviceAddress:e.deviceAddress,apiUrl:e.apiUrl,profile:e.profile}),n=await e.signer.signMessage({message:t.message});return{walletChallengeId:t.challengeId,walletSignature:n}}async function gp(e,t){try{let{root:n,manifest:r}=await kd(e,t.directory);sd({profile:t.profile});let i=await Pd(n),a=await Vd(n);if(a.competition!==r.slug)throw Error(`.tangle-solve-run.json does not match this competition`);if(!mp.test(a.salt)||!mp.test(a.candidateId))throw Error("This run predates durable candidate identity. Run `tangle solve run` again");let o=r.provenance?await Fd(n,r,i):void 0;if(r.provenance&&a.source&&!Ld(a.source,o))throw Error("The saved run points to a different repository or revision. Keep your fork as 'origin' and run `tangle solve run` again before submitting");let s=Uu();if(!s)throw Error("No Solve device signer found. Run `tangle solve run` first");if(s.account.address.toLowerCase()!==a.deviceAddress.toLowerCase())throw Error("The local Solve device account changed after `tangle solve run`; run the checker again");let c=z(`Checking the committed candidate…`);t.json||c.start();let l;try{l=await fp(n,r.checker)}finally{c.stop()}if(l.candidateRef!==a.candidateRef||l.evidenceJson!==a.evidenceJson)throw Error("The committed checker output changed after `tangle solve run`; run the checker again");if(Bf(l.candidateRef,a.salt).toLowerCase()!==a.candidateId.toLowerCase())throw Error(`The saved candidate identity does not match the checker output; run the checker again`);let u=ad(t.prUrl);if(!r.provenance&&u)throw Error(`This competition does not accept GitHub pull request provenance`);if(u){if(!o)throw Error(`A provenance policy is required for a pull request`);await Hd({pullRequest:u,taskRepository:o.taskRepository,submissionRepository:o.submissionRepository,submissionRevision:i})}let d=zd(l,o,r.provenance,u,{requirePullRequest:!0}),f={...a,...o?{source:o}:{},chainState:{status:`submitting`,transactions:{...a.chainState?.transactions??{}}}},p=A.join(n,`.tangle-solve-run.json`);await Bd(p,f);let m=z(`Submitting candidate to Tempo…`);t.json||m.start();let h;try{h=await Uf(bd(r),s.account,{artifactRef:l.candidateRef,salt:a.salt,evidenceJson:l.evidenceJson,evidenceRefs:d.evidenceRefs},{resumeTransactions:f.chainState?.transactions,onTransaction:async(e,t)=>{f={...f,chainState:{status:`submitting`,transactions:{...f.chainState?.transactions??{},[e]:t}}},await Bd(p,f)}})}finally{m.stop()}f={...f,chainReceipt:h,chainState:{status:`accepted`,transactions:{...f.chainState?.transactions??{},...Ud(h)}}},await Bd(p,f);let g=await hp({deviceAddress:h.address,signer:s.account,apiUrl:t.apiUrl,profile:t.profile}),_=await ld({path:`/v1/submissions`,method:`POST`,apiUrl:t.apiUrl,profile:t.profile,body:{competition:r.slug,candidateRef:l.candidateRef,candidateId:h.candidateId,evidenceJson:l.evidenceJson,evidenceRefs:d.evidenceRefs,deviceAddress:h.address,reportTxHash:h.report,evaluationTxHash:h.evaluation,transactions:Ud(h),...r.provenance&&o?{source:{...o,...u?{pullRequest:u}:{}}}:{},clientSubmissionId:a.clientSubmissionId,...g,...t.model?{model:t.model}:{},...t.note?{note:t.note}:{}}});t.json?I({..._,transactions:Ud(h),candidateId:h.candidateId}):(L(`Submission accepted on Tempo`),B({Competition:r.slug,Candidate:h.candidateId,"Device address":h.address,"Report transaction":h.report,"Evaluation transaction":h.evaluation,"Submission ID":typeof _.id==`string`?_.id:_.submission?.id}))}catch(e){U(e)}}function _p(){let e=new x(`solve`).description(`Participate in Tangle Solve competitions`);e.command(`clone <competition>`).description(`Clone the pinned competition repository`).argument(`[directory]`,`Destination directory`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).action(Kd),e.command(`run [competition]`).description(`Run the competition checker and record its evidence`).option(`--directory <path>`,`Competition directory (defaults to the current directory)`).action(pp),e.command(`submit [competition]`).description(`Submit checker evidence through the device account and Tempo`).option(`--directory <path>`,`Competition directory (defaults to the current directory)`).option(`--pr-url <url>`,`GitHub pull request containing the submission`).option(`--model <name>`,`Model used to produce the submission`).option(`--note <text>`,`Short note shown with the accepted submission`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).action(gp),e.command(`account`).description(`Show the local Solve signing account`).option(`--create`,`Create the account if it does not exist`).action(Ku);let t=e.command(`device`).description(`List and revoke the Solve devices bound to your account`);return t.command(`list`).description(`List your devices and whether each may submit jobs on Tempo`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).action(e=>Rf(e)),t.command(`revoke <address>`).description(`Permanently revoke a device; the local device is revoked with its own key`).option(`--reason <text>`,`Why the device is revoked (shown to the account)`).option(`--yes`,`Confirm the permanent revocation without a prompt`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).action((e,t)=>zf(e,t)),e}function vp(e,t){return`tangle ssh-proxy ${e.replace(/\/+$/,``)}/v1/sandboxes/${t}/runtime/ssh`}function yp(e){return/^[A-Za-z0-9_/:=@%+.,-]+$/.test(e)?e:`'${e.replace(/'/g,`'"'"'`)}'`}function bp(e){return`'${e.replace(/'/g,`''`)}'`}function xp(e){return e===`win32`?`NUL`:`/dev/null`}function Sp(e,t){return t===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN=${bp(`<token>`)}; ssh ${e.map(bp).join(` `)}`:`TANGLE_SSH_PROXY_AUTH_TOKEN=${yp(`<token>`)} ssh ${e.map(yp).join(` `)}`}function Cp(e){return e.connection!==void 0&&!e.connection.ssh}function wp(){Pt(`SSH is not enabled for this sandbox.`),R(`Create a sandbox with --ssh to enable SSH access.`),process.exit(1)}function Tp(e,t=[],n=process.platform){let r=xp(n);return[`-o`,`ProxyCommand=${e.proxyCommand}`,`-o`,`StrictHostKeyChecking=no`,`-o`,`UserKnownHostsFile=${r}`,`-o`,`GlobalKnownHostsFile=${r}`,`-o`,`LogLevel=ERROR`,`-o`,`ServerAliveInterval=15`,`-o`,`ServerAliveCountMax=4`,`-o`,`TCPKeepAlive=yes`,`${e.username}@localhost`,`-p`,String(e.port),...t]}function Ep(){return new x(`ssh`).description(`Open SSH session to a sandbox`).argument(`<ref>`,`Sandbox ID or name`).argument(`[sshArgs...]`,`Extra args passed through to ssh`).option(`-i, --identity-file <path>`,`Private key file to pass to ssh`).option(`--print`,`Print SSH command instead of connecting`).allowUnknownOption(!0).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Getting SSH credentials...`);a.start();let o=await J(i,r,e);if(Cp(o)){a.stop(),wp();return}o=await Y(o);let s=await o.ssh();if(a.stop(),!s){wp();return}let c={...s,proxyCommand:vp(r.baseUrl,o.id)};if(!r.apiKey)throw Error(`SSH proxy requires API key auth. Set TANGLE_API_KEY or pass --api-key.`);let l=Tp(c,[...n.identityFile?[`-i`,n.identityFile,`-o`,`IdentitiesOnly=yes`]:[],...t]);if(n.print){console.log(Sp(l,process.platform));return}R(`Connecting via tunnel...`);let u=we(`ssh`,l,{stdio:`inherit`,env:{...process.env,TANGLE_SSH_PROXY_AUTH_TOKEN:r.apiKey}});u.on(`error`,e=>{e.code===`ENOENT`&&(Pt(`SSH client not found. Please install OpenSSH.`),process.exit(1)),U(e)}),u.on(`exit`,e=>{process.exit(e??0)})})}function Dp(){let e=new x(`ssh-keys`).description(`Manage SSH keys`);return e.command(`list`).description(`List SSH keys`).action(async e=>{let t=z(`Fetching SSH keys...`);try{t.start();let n=await G(W(e)).sshKeys.list();t.stop(),e.json?I({sshKeys:n}):n.length===0?R(`No SSH keys found.`):Bt([`Name`,`Type`,`Fingerprint`,`Created`],n.map(e=>[e.name,e.keyType,e.fingerprint,e.createdAt.toLocaleString()]))}catch(e){t.stop(),U(e)}}),e.command(`add`).description(`Add SSH key`).argument(`<name>`,`SSH key name`).requiredOption(`--key-file <path>`,`Public key file path`).action(async(e,t)=>{let n=z(`Adding SSH key...`);try{let r=k(t.keyFile,`utf8`).trim();n.start();let i=await G(W(t)).sshKeys.create(e,r);n.stop(),t.json?I({sshKey:i}):L(`Added SSH key ${i.name} (${i.fingerprint})`)}catch(e){n.stop(),U(e)}}),e.command(`delete`).description(`Delete SSH key`).argument(`<name>`,`SSH key name or ID`).action(async(e,t)=>{let n=z(`Deleting SSH key...`);try{n.start(),await G(W(t)).sshKeys.delete(e),n.stop(),L(`Deleted SSH key ${e}`)}catch(e){n.stop(),U(e)}}),e}function Op(e,t=1){process.stderr.write(`${e}\n`),process.exit(t)}function kp(){return new x(`ssh-proxy`).description(`SSH proxy helper that pipes stdin/stdout to WebSocket`).argument(`<runtime-url>`,`Runtime WebSocket URL`).action(async e=>{let t=process.env.TANGLE_SSH_PROXY_AUTH_TOKEN;t||Op(`TANGLE_SSH_PROXY_AUTH_TOKEN not set`);let n=new Tt(new URL(e.replace(/^http/,`ws`)),{headers:{Authorization:`Bearer ${t}`},perMessageDeflate:!1}),r;function i(){r&&=(clearInterval(r),void 0)}n.on(`open`,()=>{r=setInterval(()=>{n.readyState===Tt.OPEN&&n.ping()},15e3),r.unref?.(),process.stdin.on(`data`,e=>{n.readyState===Tt.OPEN&&n.send(e,{binary:!0,compress:!1})}),process.stdin.on(`end`,()=>n.close(1e3))}),n.on(`message`,e=>{let t=Buffer.isBuffer(e)?e:Array.isArray(e)?Buffer.concat(e):Buffer.from(e);process.stdout.write(t)}),n.on(`error`,e=>{i(),Op(`WebSocket error: ${e.message}`)}),n.on(`close`,e=>{i(),process.exit(e===1e3?0:1)}),process.stdin.on(`error`,()=>n.close())})}function Ap(){let e=new x(`team`).description(`Manage teams`);return $(e,`list`).description(`List teams for the current account`).action(async e=>{let t=W(e),n=G(t),r=e.json?null:z(`Fetching teams...`);r?.start();let i=await n.teams.list();if(r?.stop(),e.json){I({teams:i,activeTeamId:t.activeTeamId??null});return}F(i.map(e=>({active:e.id===t.activeTeamId,id:e.id,name:e.name,role:e.currentUserRole,members:e.memberCount})),[{key:`active`,header:`Active`,width:8},{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:24},{key:`role`,header:`Role`,width:10},{key:`members`,header:`Members`,width:10}])}),$(e,`create <name>`).description(`Create a team`).option(`--org-id <id>`,`External organization id`).option(`--no-switch`,`Do not set the new team as active`).action(async(e,t)=>{let n=W(t),r=G(n),i=t.json?null:z(`Creating team...`);i?.start();let a=await r.teams.create({name:e,orgId:t.orgId});if(t.switch&&Ds(a,n.profile),i?.stop(),t.json){I({team:a,active:!!t.switch});return}L(`Team created: ${ws(a)}`),t.switch&&L(`Active team set to ${a.name}`)}),$(e,`switch <team>`).description(`Set the active team for the current profile`).action(async(e,t)=>{let n=W(t),r=await Ts(G(n),e);if(Ds(r,n.profile),t.json){I({team:r,activeTeamId:r.id});return}L(`Active team set to ${ws(r)}`)}),e.command(`current`).description(`Show the active team for the current profile`).option(`--profile <profile>`,`Credential profile`).action(e=>{let t=pr(e.profile);if(e.json){I(t.activeTeamId?t:{activeTeamId:null});return}if(!t.activeTeamId){console.log(`No active team.`);return}B({ID:t.activeTeamId,Name:t.activeTeamName})}),e.command(`clear`).description(`Clear the active team for the current profile`).option(`--profile <profile>`,`Credential profile`).action(e=>{if(Os(e.profile),e.json){I({activeTeamId:null});return}L(`Active team cleared.`)}),$(e,`members [team]`).description(`List team members`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Es(r,e,n.profile),a=await r.teams.listMembers(i.id);if(t.json){I({team:i,members:a});return}F(a,[{key:`id`,header:`ID`,width:36},{key:`customerEmail`,header:`Email`,width:28},{key:`role`,header:`Role`,width:10},{key:`status`,header:`Status`,width:10},{key:`joinedAt`,header:`Joined`,width:16}])}),$(e,`update-member <member-id>`).description(`Update a team member role`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).requiredOption(`--role <role>`,`Role: admin, member, viewer`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Es(r,t.team,n.profile),a=jp(t.role),o=await r.teams.updateMember(i.id,e,{role:a});if(t.json){I({team:i,member:o});return}L(`Member updated: ${o.customerEmail}`),B({Team:i.name,Role:o.role,Status:o.status})}),$(e,`invite <email>`).description(`Invite a user to a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--role <role>`,`Role: admin, member, viewer`,`member`).option(`--ttl-hours <hours>`,`Invitation lifetime in hours`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Es(r,t.team,n.profile),a=jp(t.role),o=await r.teams.invite(i.id,{email:e,role:a,ttlHours:t.ttlHours?Number.parseInt(t.ttlHours,10):void 0});if(t.json){I({team:i,invitation:o});return}L(`Invitation created for ${o.email}`),B({Team:i.name,Role:o.role,Expires:o.expiresAt,"Invitation ID":o.id}),L(`Re-run with --json to retrieve the invitation token for sharing.`)}),$(e,`leave [team]`).description(`Leave a team as the current user`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Es(r,e,n.profile);if(!(!t.force&&!t.json&&!await $r(`Leave team '${i.name}'? (y/N) `,`--force`))){if(await r.teams.leave(i.id),n.activeTeamId===i.id&&Os(n.profile),t.json){I({success:!0,teamId:i.id});return}L(`Left team: ${i.name}`)}}),$(e,`transfer <new-owner-customer-id> [team]`).description(`Transfer team ownership to another active member`).option(`--force`,`Skip confirmation prompt`).action(async(e,t,n)=>{let r=W(n),i=G(r),a=await Es(i,t,r.profile);if(!(!n.force&&!n.json&&!await $r(`Transfer ownership of '${a.name}' to ${e}? This cannot be undone without the new owner's cooperation. (y/N) `,`--force`))){if(await i.teams.transferOwnership(a.id,e),n.json){I({success:!0,teamId:a.id,newOwnerCustomerId:e});return}L(`Ownership transferred for ${a.name}`)}}),e.addCommand(Mp()),e.addCommand(Np()),$(e,`invitations [team]`).description(`List pending and historical team invitations`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Es(r,e,n.profile),a=await r.teams.listInvitations(i.id);if(t.json){I({team:i,invitations:a});return}F(a,[{key:`id`,header:`ID`,width:38},{key:`email`,header:`Email`,width:28},{key:`role`,header:`Role`,width:10},{key:`status`,header:`Status`,width:12},{key:`expiresAt`,header:`Expires`,width:16}])}),$(e,`accept <token>`).description(`Accept a team invitation`).option(`--no-switch`,`Do not set the accepted team as active`).action(async(e,t)=>{let n=W(t),r=G(n),i=await r.teams.acceptInvitation(e),a=t.switch===!1?null:await r.teams.get(i.teamId);if(a&&Ds(a,n.profile),t.json){I({member:i,activeTeamId:a?.id??null});return}L(`Invitation accepted for team ${i.teamId}`),a&&L(`Active team set to ${a.name}`)}),$(e,`revoke-invitation <invitation-id>`).description(`Revoke a pending team invitation`).action(async(e,t)=>{if(await G(W(t)).teams.revokeInvitation(e),t.json){I({success:!0,invitationId:e});return}L(`Invitation revoked: ${e}`)}),$(e,`remove-member <member-id>`).description(`Remove a member from a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Es(r,t.team,n.profile);if(await r.teams.removeMember(i.id,e),t.json){I({success:!0,teamId:i.id,memberId:e});return}L(`Member removed: ${e}`)}),e}function jp(e){if(e===`admin`||e===`member`||e===`viewer`)return e;throw Error(`Role must be one of: admin, member, viewer`)}function Mp(){let e=new x(`secret`).description(`Manage team secrets`);return $(e,`list [team]`).description(`List team secret names`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Es(r,e,n.profile),a=await r.teams.listSecrets(i.id);if(t.json){I({team:i,secrets:a});return}F(a,[{key:`name`,header:`Name`,width:28},{key:`updatedAt`,header:`Updated`,width:24},{key:`updatedBy`,header:`Updated By`,width:28}])}),$(e,`set <name> [value]`).description(`Create or replace a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--value-stdin`,`Read secret value from stdin`).action(async(e,t,n)=>{let r=W(n),i=G(r),a=await Es(i,n.team,r.profile),o=await Iu({value:t,valueStdin:n.valueStdin,prompt:`Enter value for team secret '${e}': `}),s=await i.teams.upsertSecret(a.id,e,o);if(n.json){I({team:a,secret:s});return}L(`Team secret saved: ${s.name}`)}),$(e,`delete <name>`).description(`Delete a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Es(r,t.team,n.profile);if(!(!t.force&&!t.json&&!await $r(`Delete team secret '${e}' from '${i.name}'? (y/N) `,`--force`))){if(await r.teams.deleteSecret(i.id,e),t.json){I({success:!0,teamId:i.id,name:e});return}L(`Team secret deleted: ${e}`)}}),$(e,`reveal <name>`).description(`Reveal a team secret value`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Es(r,t.team,n.profile),a=await r.teams.revealSecret(i.id,e);if(t.json){I({teamId:i.id,...a});return}console.log(a.value)}),e}function Np(){let e=new x(`templates`).description(`Manage team golden-path templates`);return $(e,`list [team]`).description(`List a team's golden-path templates`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Es(r,e,n.profile),a=await r.teams.listTemplates(i.id);if(t.json){I({team:i,templates:a});return}if(a.length===0){console.log(`No templates yet for ${i.name}.`);return}F(a.map(e=>({id:e.id,name:e.name,environment:e.environment,snapshot:`${e.snapshotId.slice(0,12)}…`,updated:e.updatedAt})),[{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:28},{key:`environment`,header:`Env`,width:14},{key:`snapshot`,header:`Snapshot`,width:16},{key:`updated`,header:`Updated`,width:24}])}),$(e,`create <name> <snapshot-id>`).description(`Create a golden-path template from a snapshot`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`-d, --description <description>`,`Human-readable description shown in the dashboard`).option(`-e, --environment <environment>`,`Default environment to apply (defaults to 'universal')`).option(`--config <json>`,`Optional JSON config object merged into sandboxes created from this template`).action(async(e,t,n)=>{let r=W(n),i=G(r),a=await Es(i,n.team,r.profile),o;if(n.config)try{let e=JSON.parse(n.config);if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`--config must be a JSON object`);o=e}catch(e){throw Error(`--config is not valid JSON: ${e instanceof Error?e.message:String(e)}`)}let s=await i.teams.createTemplate(a.id,{name:e,snapshotId:t,description:n.description,environment:n.environment,config:o});if(n.json){I({team:a,template:s});return}L(`Team template created: ${s.name} (${s.id})`)}),$(e,`delete <template-id>`).description(`Delete a team golden-path template`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Es(r,t.team,n.profile);if(!(!t.force&&!t.json&&!await $r(`Delete template '${e}' from '${i.name}'? (y/N) `,`--force`))){if(await r.teams.deleteTemplate(i.id,e),t.json){I({success:!0,teamId:i.id,templateId:e});return}L(`Team template deleted: ${e}`)}}),e}function $(e,t){return e.command(t).option(`--profile <profile>`,`Credential profile`)}async function Pp(e,t,n){let r=new AbortController,i=()=>r.abort();try{let n=G(W({...e,timeout:void 0}));process.once(`SIGINT`,i),process.once(`SIGTERM`,i);let a=await t(n,{...e.timeout===void 0?{}:{timeoutMs:Number(e.timeout)*1e3},resumeJobId:e.resumeJob,signal:r.signal,onProgress:e=>{process.stderr.write(`Publication ${e.id}: ${e.status}\n`)}}).finally(()=>{process.off(`SIGINT`,i),process.off(`SIGTERM`,i)});e.json?I(a):L(`template`in a?`Published template: ${a.template.slug}`:`Published template version: ${a.version.id}`)}catch(t){if(t instanceof o&&t.status!==401&&t.job&&[`pending`,`scanning`,`ready`].includes(t.job.status)){let e=[`tangle`,`template`,...n,`--resume-job`,t.job.id].map(Be).join(` `);Object.assign(t,{fix:{command:e}})}U(t,e.json)}}function Fp(){let e=new x(`template`).description(`Manage published public templates`);return e.command(`list`).option(`-q, --query <query>`,`Search query`).option(`--tag <tag>`,`Filter by tag`).option(`--featured`,`Show featured templates only`).action(async e=>{let t=G(W(e)),n=e.featured?await t.publicTemplates.featured():await t.publicTemplates.list({query:e.query,tag:e.tag});if(e.json){I({templates:n});return}F(n,[{key:`slug`,header:`Slug`,width:28},{key:`name`,header:`Name`,width:28},{key:`forkCount`,header:`Forks`,width:8},{key:`sandboxCount`,header:`Sandboxes`,width:12},{key:`updatedAt`,header:`Updated`,width:24}])}),e.command(`get <id-or-slug>`).action(async(e,t)=>{let n=await G(W(t)).publicTemplates.get(e);if(t.json){I({template:n});return}I(n)}),e.command(`versions <id-or-slug>`).action(async(e,t)=>{let n=await G(W(t)).publicTemplates.versions(e);if(t.json){I({versions:n});return}F(n.map(e=>({...e})),[{key:`id`,header:`Version ID`,width:38},{key:`versionNumber`,header:`Version`,width:8},{key:`snapshotId`,header:`Snapshot`,width:20},{key:`createdAt`,header:`Created`,width:24}])}),e.command(`publish <name> <snapshot-id> <sandbox-id>`).option(`--timeout <seconds>`,`Maximum wait for publication`).option(`--resume-job <id>`,`Resume an accepted publication for this snapshot`).option(`--slug <slug>`,`Stable public slug`).option(`-d, --description <description>`,`Template description`).option(`--readme <markdown>`,`README markdown`).option(`--tags <tags...>`,`Template tags`).option(`--release-notes <text>`,`Release notes`).option(`--team-id <id>`,`Publish under a team`).option(`--forked-from <id>`,`Fork source template id`).action((e,t,n,r)=>Pp(r,async(i,a)=>({template:await i.publicTemplates.publish({name:e,slug:r.slug,description:r.description,snapshotId:t,sourceSandboxId:n,readmeMarkdown:r.readme,tags:r.tags,releaseNotes:r.releaseNotes,teamId:r.teamId,forkedFromTemplateId:r.forkedFrom},a)}),[`publish`,e,t,n])),e.command(`publish-version <id-or-slug> <snapshot-id> <sandbox-id>`).option(`--timeout <seconds>`,`Maximum wait for publication`).option(`--resume-job <id>`,`Resume an accepted publication for this snapshot`).option(`--readme <markdown>`,`README markdown`).option(`--tags <tags...>`,`Template tags`).option(`--release-notes <text>`,`Release notes`).action((e,t,n,r)=>Pp(r,async(i,a)=>({version:await i.publicTemplates.publishVersion(e,{snapshotId:t,sourceSandboxId:n,readmeMarkdown:r.readme,tags:r.tags,releaseNotes:r.releaseNotes},a)}),[`publish-version`,e,t,n])),e}function Ip(){let e=new x(`traces`).description(`Read hosted agent traces, spans, and eval-runs from Tangle Intelligence`);return e.command(`list`).description(`List trace summaries (one row per trace), newest first`).option(`--from <iso>`,`ISO-8601 lower bound on received time (inclusive)`).option(`--to <iso>`,`ISO-8601 upper bound on received time (inclusive)`).option(`--model <model>`,`Exact model match (any span carried this model)`).option(`--run <runId>`,`Exact run id match`).option(`--status <status>`,`ERROR | OK`).option(`-q, --query <text>`,`Substring over span name`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Page size (clamped server-side to [1, 200])`).action(async e=>{try{let t={from:e.from,to:e.to,model:e.model,runId:e.run,status:e.status===void 0?void 0:qp(e.status),q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:Qp(e.limit)},n=Rp(e),r=e.json?null:z(`Fetching traces...`);r?.start();let i=await n.listTraces(t);if(r?.stop(),e.json)return I(i);Vp(i.items),Gp(i.nextCursor)}catch(t){Bp(t,e)}}),e.command(`get <traceId>`).description(`Show one trace's spans. Streams NDJSON to stdout with --ndjson.`).option(`--ndjson`,`Stream the full span set as NDJSON to stdout`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Spans per page`).action(async(e,t)=>{try{let n=Rp(t);if(t.ndjson){await zp(n,e);return}let r=t.json?null:z(`Fetching trace spans...`);r?.start();let i=await n.getTraceSpans(e,{cursor:t.cursor,limit:t.limit===void 0?void 0:Qp(t.limit)});if(r?.stop(),t.json)return I(i);Hp(i.items),i.truncated&&B({Spans:`${i.items.length} of ${i.total} (truncated)`}),Gp(i.nextCursor)}catch(e){Bp(e,t)}}),e.addCommand(Lp()),e}function Lp(){let e=new x(`runs`).description(`Read eval-runs pivoted off the trace surface`);return e.command(`list`).description(`List eval-runs, newest first`).option(`--status <status>`,`Run status filter`).option(`--gate <decision>`,`Promotion-gate decision filter`).option(`--label <key:value>`,`Match over the run's labels`).option(`--from <iso>`,`ISO-8601 lower bound on received time`).option(`--to <iso>`,`ISO-8601 upper bound on received time`).option(`-q, --query <text>`,`Substring over run dir`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Page size`).action(async e=>{try{let t={status:e.status===void 0?void 0:Yp(e.status),gate:e.gate===void 0?void 0:Zp(e.gate),label:e.label,from:e.from,to:e.to,q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:Qp(e.limit)},n=Rp(e),r=e.json?null:z(`Fetching runs...`);r?.start();let i=await n.listRuns(t);if(r?.stop(),e.json)return I(i);Up(i.items),Gp(i.nextCursor)}catch(t){Bp(t,e)}}),e.command(`get <runId>`).description(`Show a single eval-run`).action(async(e,t)=>{try{let n=Rp(t),r=t.json?null:z(`Fetching run...`);r?.start();let i=await n.getRun(e);if(r?.stop(),t.json)return I(i);Wp(i)}catch(e){Bp(e,t)}}),e}function Rp(e){let t=rr(e.apiKey);if(!t)throw Error(`No API key found. Set TANGLE_API_KEY or run: tangle auth login`);return Et({apiKey:t,baseUrl:e.baseUrl??process.env.TANGLE_INTELLIGENCE_BASE_URL})}async function zp(e,t){let n=(await e.exportTraceSpansNdjson(t)).getReader();try{for(;;){let{value:e,done:t}=await n.read();if(t)break;e&&process.stdout.write(Buffer.from(e))}}finally{n.releaseLock()}}function Bp(e,t){return U(e,t.json===!0)}function Vp(e){F(e.map(e=>({traceId:e.traceId,root:e.rootName??`-`,model:e.model??`-`,spans:e.spanCount,errors:e.errorCount,durationMs:e.durationMs,cost:Kp(e.costUsd)})),[{key:`traceId`,header:`Trace`,width:36},{key:`root`,header:`Root`,width:24},{key:`model`,header:`Model`,width:22},{key:`spans`,header:`Spans`,width:8},{key:`errors`,header:`Errors`,width:8},{key:`durationMs`,header:`Duration(ms)`,width:14},{key:`cost`,header:`Cost`,width:10}])}function Hp(e){F(e.map(e=>({spanId:e.id,name:e.name,model:e.model??`-`,status:e.statusCode??`-`,cost:e.costUsd===null?`-`:`$${e.costUsd}`})),[{key:`spanId`,header:`Span`,width:40},{key:`name`,header:`Name`,width:28},{key:`model`,header:`Model`,width:22},{key:`status`,header:`Status`,width:10},{key:`cost`,header:`Cost`,width:12}])}function Up(e){F(e.map(e=>({runId:e.id,status:e.status,gate:e.gateDecision??`-`,cost:e.totalCostUsd===null?`-`:`$${e.totalCostUsd}`,receivedAt:e.receivedAt})),[{key:`runId`,header:`Run`,width:24},{key:`status`,header:`Status`,width:22},{key:`gate`,header:`Gate`,width:18},{key:`cost`,header:`Cost`,width:12},{key:`receivedAt`,header:`Received`,width:18}])}function Wp(e){B({Run:e.id,Status:e.status,Gate:e.gateDecision??void 0,"Run Dir":e.runDir??void 0,Cost:e.totalCostUsd===null?void 0:`$${e.totalCostUsd}`,Duration:e.totalDurationMs===null?void 0:`${e.totalDurationMs}ms`,"Holdout Lift":e.holdoutLift??void 0,Received:e.receivedAt})}function Gp(e){e&&B({"Next page":`--cursor ${e}`})}function Kp(e){return e===null?`-`:`$${e.toFixed(4)}`}function qp(e){if(e===`ERROR`||e===`OK`)return e;throw Error(`--status must be ERROR or OK`)}const Jp=[`started`,`baseline-complete`,`generation-complete`,`gate-decided`,`finished`,`errored`];function Yp(e){let t=Jp.find(t=>t===e);if(t)return t;throw Error(`--status must be one of ${Jp.join(`, `)}`)}const Xp=[`ship`,`hold`,`need_more_work`,`model_ceiling`,`arch_ceiling`];function Zp(e){let t=Xp.find(t=>t===e);if(t)return t;throw Error(`--gate must be one of ${Xp.join(`, `)}`)}function Qp(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function $p(){return new x(`usage`).description(`Show account usage and billing information`).action(async e=>{let{client:t}=K(e),n=e.json?null:z(`Fetching usage...`);n?.start();let[r,i]=await Promise.all([t.usage(),t.subscription().catch(()=>null)]);n?.stop(),e.json?I({...r,subscription:i}):(console.log(),console.log(`Account Usage`),console.log(`─`.repeat(40)),B({"Active Sandboxes":r.activeSandboxes,"Total Sandboxes":r.totalSandboxes,"Compute Minutes":em(r.computeMinutes),"GPU Seconds":r.gpuSeconds,"GPU Spend":tm(r.gpuCostUsd)}),i&&(console.log(),console.log(`Subscription`),console.log(`─`.repeat(40)),B({Plan:i.plan,Status:i.status,"Credits Available":tm(i.creditsAvailableUsd),"Credits Used":tm(i.creditsUsedUsd),"Monthly Balance":tm(i.monthlyBalanceUsd)})),console.log(),console.log(`Billing Period`),console.log(`─`.repeat(40)),B({Start:r.periodStart.toLocaleDateString(),End:r.periodEnd.toLocaleDateString()}),console.log())})}function em(e){if(e===void 0)return`-`;if(e<60)return`${e} min`;let t=Math.floor(e/60),n=e%60;return n===0?`${t} hr`:`${t} hr ${n} min`}function tm(e){return e<0?`-$${(-e).toFixed(2)}`:`$${e.toFixed(2)}`}function nm(){return new x(`use`).description(`Set or show the active sandbox (used when a command omits the id)`).argument(`[id]`,`Sandbox id to make active`).option(`--clear`,`Clear the active sandbox`).action((e,t)=>{if(t.clear){Yn(),R(`Cleared the active sandbox.`);return}if(e){Jn(e),R(`Active sandbox set to ${e}. Commands now default to it; override with --box or TANGLE_SANDBOX.`);return}let n=qn();R(n?`Active sandbox: ${n}`:"No active sandbox. Set one with `tangle use <id>`.")})}function rm(e){F(e,[{key:`id`,header:`ID`},{key:`nodeId`,header:`Node`},{key:`name`,header:`Name`},{key:`contentType`,header:`Content Type`},{key:`byteSize`,header:`Bytes`},{key:`createdAt`,header:`Created`}])}function im(e){e.command(`artifacts`).description(`List a run's artifact metadata (never the bytes)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Z(n)).workflows.listArtifacts(e,t);if(n.json)return I(r);rm(r.artifacts)}),e.command(`artifact-download`).description(`Download one run artifact's bytes to a file`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).argument(`<artifactId>`,`Artifact ID`).option(`--out <file>`,`Destination file (defaults to the artifact ID)`).action(async(e,t,n,r)=>{let i=await(await Z(r)).workflows.downloadArtifact(e,t,n),a=r.out??n;try{fe(a,i.bytes)}catch(e){throw Error(`Could not write artifact to "${a}": ${e instanceof Error?e.message:String(e)}`)}if(r.json)return I({file:a,contentType:i.contentType,bytes:i.bytes.length});R(`Wrote ${a} (${i.bytes.length} bytes, ${i.contentType}).`)})}function am(e){F(e.map(e=>({id:e.id,run:e.runId,title:e.title,options:e.options.join(`, `),requested:e.requestedAt,expires:e.expiresAt??``})),[{key:`id`,header:`ID`},{key:`run`,header:`Run`},{key:`title`,header:`Title`},{key:`options`,header:`Options`},{key:`requested`,header:`Requested`},{key:`expires`,header:`Expires`}])}function om(e){e.command(`decisions`).description(`List a workflow's pending human decisions`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=(await(await Z(t)).workflows.listPendingDecisions()).decisions.filter(t=>t.workflowId===e);if(t.json)return I({decisions:n});am(n)}),e.command(`decision-resolve`).description(`Answer the decision a run is parked on and resume it`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).requiredOption(`--choice <choice>`,`The option to resolve with (one of the decision's options)`).action(async(e,t,n)=>{let r=await Z(n),i=await r.workflows.getRunDecision(e,t),a=await r.workflows.resolveRunDecision(e,t,{decisionId:i.id,choice:n.choice});if(n.json)return I(a);if(a.resumed){R(`Resolved decision ${a.decisionId} with "${a.choice}" — run ${a.runId} resumed.`);return}R(`Resolved decision ${a.decisionId} with "${a.choice}", but run ${a.runId} had already finished — nothing to resume.`)})}function sm(e){try{return k(e,`utf8`)}catch(t){throw Error(`Could not read workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function cm(e){F(e.map(e=>({id:e.id,name:e.name,enabled:e.enabled?`yes`:`no`,issues:e.validationErrors.length,updated:e.updatedAt})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`enabled`,header:`Enabled`},{key:`issues`,header:`Issues`},{key:`updated`,header:`Updated`}])}function lm(e){let t=e.workflows.filter(e=>e.failed>0).length,n=e.workflows.filter(e=>e.failed===0&&e.waiting>0).length,r=e.workflows.filter(e=>e.failed===0&&e.waiting===0&&e.runsInWindow>0).length;R(`${t} failing · ${n} waiting · ${r} healthy · ${e.workflows.length} total over ${e.window}`),F(e.workflows.map(e=>({id:e.id,name:e.name,enabled:e.enabled?`yes`:`no`,runs:e.runsInWindow,failed:e.failed,waiting:e.waiting,success:e.successRate===null?`—`:`${Math.round(e.successRate*100)}%`,lastRun:e.lastRunStatus??`—`,lastRunAt:e.lastRunAt??`—`})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`enabled`,header:`Enabled`},{key:`runs`,header:`Runs`},{key:`failed`,header:`Failed`},{key:`waiting`,header:`Waiting`},{key:`success`,header:`Success`},{key:`lastRun`,header:`Last Run`},{key:`lastRunAt`,header:`Last Run At`}])}function um(e){if(B({ID:e.id,Name:e.name,Description:e.description??``,Enabled:e.enabled?`yes`:`no`,Actions:e.actions.length}),e.triggers&&e.triggers.length>0&&(R(`Triggers`),dm(e.triggers)),e.validationErrors.length>0){R(`Validation issues`);for(let t of e.validationErrors)console.log(` ${t.path}: ${t.message}`)}}function dm(e){F(e.map(e=>({id:e.id,kind:e.kind,enabled:e.enabled?`yes`:`no`,detail:e.kind===`schedule`?`${e.cron??``} (${e.timezone??``})`:`${e.provider??``}:${e.eventFilter?.event??``}${e.eventFilter?.action?`.${e.eventFilter.action}`:``}`})),[{key:`id`,header:`ID`},{key:`kind`,header:`Kind`},{key:`enabled`,header:`Enabled`},{key:`detail`,header:`Detail`}])}function fm(e){e.command(`list`).description(`List your workflows`).action(async e=>{let t=await(await Z(e)).workflows.list();if(e.json)return I(t);cm(t)}),e.command(`fleet`).description(`Fleet overview: every workflow's run tallies over a trailing window, failing-first`).option(`--window <window>`,`Trailing window: 24h, 7d, or 30d`,`7d`).action(async e=>{let t=await(await Z(e)).workflows.fleetInsights({window:e.window});if(e.json)return I(t);lm(t)}),e.command(`get`).description(`Show a workflow's definition and compiled triggers`).argument(`<id>`,`Workflow ID`).option(`--yaml`,`Print only the raw definition YAML (the export path — pipe to a file)`).action(async(e,t)=>{let n=await(await Z(t)).workflows.get(e);if(t.yaml){if(n.definitionYaml===null)throw Error(`Workflow ${n.id} has no stored definition YAML to export`);process.stdout.write(n.definitionYaml.endsWith(`
193
- `)?n.definitionYaml:`${n.definitionYaml}\n`);return}if(t.json)return I(n);um(n)}),e.command(`create`).description(`Create a workflow from a YAML file`).argument(`<file>`,`Path to the workflow YAML`).action(async(e,t)=>{let n=sm(e),r=await(await Z(t)).workflows.create(n);if(t.json)return I(r);R(`Created workflow ${r.id} (${r.name}).`),um(r)}),e.command(`apply`).description(`Create or update a workflow idempotently, matched by the definition's name`).argument(`<file>`,`Path to the workflow YAML`).action(async(e,t)=>{let n=sm(e),r=await Z(t),i=await r.workflows.validate(n,{structural:!0});if(!i.valid){if(process.exitCode=1,t.json)return I(i);R(`Invalid workflow:`);for(let e of i.errors)console.log(` ${e.path}: ${e.message}`);return}let a=(await r.workflows.list()).find(e=>e.name===i.name);if(a){let e=await r.workflows.update(a.id,n);if(t.json)return I({action:`updated`,workflow:e});R(`Updated workflow ${e.id} (${e.name}) — matched by name.`),um(e);return}let o=await r.workflows.create(n);if(t.json)return I({action:`created`,workflow:o});R(`Created workflow ${o.id} (${o.name}).`),um(o)}),e.command(`update`).description(`Replace a workflow's definition from a YAML file`).argument(`<id>`,`Workflow ID`).argument(`<file>`,`Path to the workflow YAML`).option(`--note <note>`,`Revision note recorded on the appended revision (why this change)`).action(async(e,t,n)=>{let r=sm(t),i=await(await Z(n)).workflows.update(e,r,{...n.note===void 0?{}:{note:n.note}});if(n.json)return I(i);R(`Updated workflow ${i.id} (${i.name}).`),um(i)}),e.command(`delete`).description(`Delete a workflow and its triggers`).argument(`<id>`,`Workflow ID`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{if(!t.force&&!await $r(`Delete workflow ${e}? `,`--force`)){R(`Delete cancelled.`);return}if(await(await Z(t)).workflows.delete(e),t.json)return I({deleted:!0,id:e});R(`Deleted workflow ${e}.`)}),e.command(`validate`).description(`Validate a workflow YAML file without saving it`).argument(`<file>`,`Path to the workflow YAML`).option(`--structural`,`CI mode: compile + capability checks only, no connection resolution — the verdict is the same regardless of connected providers`).action(async(e,t)=>{let n=sm(e),r=await(await Z(t)).workflows.validate(n,{...t.structural?{structural:!0}:{}});if(t.json)return I(r);if(r.valid)R(`Valid: ${r.name} (${r.actionCount} action(s), ${r.triggerCount} trigger(s)).`);else{R(`Invalid workflow:`);for(let e of r.errors)console.log(` ${e.path}: ${e.message}`);process.exitCode=1}}),e.command(`schema`).description(`Print the JSON Schema for the workflow YAML`).action(async e=>{I(await(await Z(e)).workflows.schema())})}async function pm(e,t,n){let r=await(await Z(n)).workflows.setEnabled(e,t);if(n.json)return I(r);R(`${t?`Enabled`:`Disabled`} workflow ${r.id}.`),um(r)}function mm(e,t){try{return JSON.parse(e)}catch{throw Error(`Invalid ${t}: not valid JSON`)}}function hm(e,t){try{fe(e,t,`utf8`)}catch(t){throw Error(`Could not write workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function gm(e){F(e.map(e=>({id:e.id,name:e.name,category:e.category,providers:e.providers.join(`, `),summary:e.summary})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`category`,header:`Category`},{key:`providers`,header:`Providers`},{key:`summary`,header:`Summary`}])}function _m(e,t){let n=e.kind===`github_app`,r=n?`${e.provider} (App installation)`:e.provider,i=e.connectUrl?` — ${n?`install`:`connect`}: ${e.connectUrl}`:``,a=e.prerequisite;return`${r}${i}${a&&t.some(e=>e.provider===a.provider&&e.kind===a.kind&&!e.connected)?` (after connecting ${a.provider})`:``}`}function vm(e){e.command(`enable`).description(`Enable a workflow so its triggers and manual runs fire`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{await pm(e,!0,t)}),e.command(`disable`).description(`Disable a workflow (pause its triggers and manual runs)`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{await pm(e,!1,t)}),e.command(`templates`).description(`List the curated starter workflow templates`).action(async e=>{let t=await(await Z(e)).workflows.listTemplates();if(e.json)return I(t);gm(t)}),e.command(`init`).description(`Create a workflow from a gallery template and print (or save) its YAML`).argument(`<template-id>`,"Template ID from `workflows templates`").option(`--param <key=value>`,`Template parameter value. Repeatable.`,xc,[]).option(`--file <out>`,`Write the instantiated workflow YAML to this file instead of stdout`).action(async(e,t)=>{let n=Sc(t.param,`param`)??{},r=await(await Z(t)).workflows.instantiateTemplate(e,n);if(t.json)return I(r);if(!r.created){R(`Template ${e} needs provider connections before it can run:`);for(let e of r.connectionRequirements)console.log(` ${e.connected?`✓`:`✗`} ${_m(e,r.connectionRequirements)}`);process.exitCode=1;return}let{workflow:i}=r;if(i.definitionYaml===null)throw Error(`Workflow ${i.id} was created but the server returned no definition YAML`);if(R(`Created workflow ${i.id} (${i.name}).`),t.file){hm(t.file,i.definitionYaml),R(`Wrote ${t.file}.`);return}process.stdout.write(i.definitionYaml.endsWith(`
194
- `)?i.definitionYaml:`${i.definitionYaml}\n`)})}function ym(e){F(e,[{key:`key`,header:`Key`},{key:`version`,header:`Version`},{key:`updatedAt`,header:`Updated`}])}function bm(e){B({Key:e.key,Version:e.version,Updated:e.updatedAt}),R(`Value`),I(e.value)}function xm(e){let t=e.command(`kv`).description(`Read and write a workflow's cross-run KV state`);t.command(`list`).description(`List every KV entry of a workflow`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=await(await Z(t)).workflows.listKv(e);if(t.json)return I(n);ym(n.entries)}),t.command(`get`).description(`Show one KV entry (value and version)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).action(async(e,t,n)=>{let r=await(await Z(n)).workflows.getKv(e,t);if(n.json)return I(r);bm(r)}),t.command(`set`).description(`Write a KV entry from a JSON value`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).argument(`<json>`,`Value as JSON (e.g. '{"cursor":123}' or '"abc"')`).option(`--cas <version>`,`Compare-and-swap: write only if the stored version still equals this`).action(async(e,t,n,r)=>{let i=mm(n,`<json>`),a=r.cas===void 0?void 0:ro(r.cas,`--cas`),o=await Z(r),s=a===void 0?await o.workflows.putKv(e,t,i):await o.workflows.casKv(e,t,a,i);if(r.json)return I(s);bm(s)}),t.command(`delete`).description(`Delete a KV entry (idempotent)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).action(async(e,t,n)=>{let r=await(await Z(n)).workflows.deleteKv(e,t);if(n.json)return I(r);R(r.deleted?`Deleted KV entry "${t}" of workflow ${e}.`:`No KV entry "${t}" on workflow ${e}.`)})}function Sm(e){F(e.map(e=>({rev:e.rev,created:e.createdAt,by:e.createdBy,source:e.source,note:e.note??``})),[{key:`rev`,header:`Rev`},{key:`created`,header:`Created`},{key:`by`,header:`Created By`},{key:`source`,header:`Source`},{key:`note`,header:`Note`}])}function Cm(e){e.command(`revisions`).description(`List a workflow's definition revision history (newest first)`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=await(await Z(t)).workflows.listRevisions(e);if(t.json)return I(n);Sm(n)}),e.command(`revision`).description(`Show one revision's metadata and definition YAML`).argument(`<id>`,`Workflow ID`).argument(`<rev>`,`Revision number`).action(async(e,t,n)=>{let r=ro(t,`<rev>`),i=await(await Z(n)).workflows.getRevision(e,r);if(n.json)return I(i);B({Revision:i.rev,Created:i.createdAt,"Created by":i.createdBy,Source:i.source,Note:i.note??``}),process.stdout.write(i.yaml.endsWith(`
195
- `)?i.yaml:`${i.yaml}\n`)}),e.command(`rollback`).description(`Restore a prior revision's definition as a NEW head revision (re-validated)`).argument(`<id>`,`Workflow ID`).argument(`<rev>`,`Revision number to restore`).action(async(e,t,n)=>{let r=ro(t,`<rev>`),i=await(await Z(n)).workflows.rollback(e,r);if(n.json)return I(i);R(`Rolled back workflow ${i.id} to rev ${r}.`),um(i)})}function wm(){let e=new x(`workflows`).description(`Create and manage Tangle workflows`);return fm(e),Dc(e),vm(e),Cm(e),xm(e),im(e),om(e),e}function Tm(e){for(let[t,n]of Object.entries(e.optsWithGlobals()))e.getOptionValue(t)===void 0&&n!==void 0&&e.setOptionValue(t,n)}const Em=e(import.meta.url)(`../package.json`);function Dm(){let e=new x;e.name(`tangle`).description(`CLI for Tangle Sandbox operations`).version(Em.version??`0.0.0`).option(`--json`,`Output JSON where supported, including errors`).option(`--api-key <key>`,`API key (or set TANGLE_API_KEY)`).option(`--base-url <url>`,`API base URL`),e.hook(`preAction`,(e,t)=>{Tm(t);let n=t.opts();Ot(n.json===!0||n.ndjson===!0)}),e.addCommand(Fi()),e.addCommand(Nu()),e.addCommand(nm()),e.addCommand(Fu()),e.addCommand(su()),e.addCommand(_u()),e.addCommand(vu()),e.addCommand(is()),e.addCommand(Ep()),e.addCommand(Dp()),e.addCommand(kp()),e.addCommand(hi()),e.addCommand(Ru()),e.addCommand(Zs()),e.addCommand($p()),e.addCommand(Ap()),e.addCommand(Fp()),e.addCommand(Wi()),e.addCommand(ta()),e.addCommand(Tu()),e.addCommand(Qs()),e.addCommand(tc()),e.addCommand(Vl()),e.addCommand(fl()),e.addCommand(wm()),e.addCommand(Uo()),e.addCommand(Pu()),e.addCommand(_p()),e.addCommand(Lu()),e.addCommand(na()),e.addCommand(Cu()),e.addCommand(Hl()),e.addCommand(Io()),e.addCommand(Lo()),e.addCommand(ju()),e.addCommand(yu()),e.addCommand(Ip()),e.addCommand(zc());function t(e){e.configureHelp({showGlobalOptions:!0}),e.configureOutput({writeErr:()=>{}}),e.exitOverride(t=>{t.exitCode===0&&process.exit(0),U(t,e.optsWithGlobals().json===!0)});for(let n of e.commands)t(n)}return t(e),e}const Om=Dm();Om.parseAsync(process.argv).catch(e=>{U(e,Om.opts().json===!0)});export{};
192
+ <script>${a(r)}<\/script></body></html>`,c=j(await He(j(xe(),`tangle-graph-`)),`${o}.html`);return await Ke(c,s,{mode:384}),c}function vl(e,t,n){e.command(`show <name-or-file>`).description(`Draw a graph file: labelled nodes, routes, loops and stops`).option(`--open`,`Write one offline page and open it in the browser`).action(async(e,r)=>{let i=await Ge(t(e,process.cwd())),a=ml(i,await We(i,`utf8`));if(r.json)return I(a);if(!r.open)return console.log(gl(a));let o=await _l(a,n);R(await Ei(tt(o).href)?`Opened ${o}`:`Open ${o}`)})}async function yl(e){if(!ir(e.apiKey)){if(e.json||e.dryRun||!process.stdin.isTTY)return;await Fi({baseUrl:e.sandboxBaseUrl,signal:e.signal})}return q(e)}async function bl(e,t,n){let r=Rl(t.parameter),i=n??await yl(t);if(!i)throw new V(`AUTH_REQUIRED`,`Hub authentication is required`,`No Tangle credential is configured`,`tangle auth login`);let a=await i.connections.start(e,{cli:!0,connectionParameters:r});return t.json?(I(Bl(a)),a):(zl(a,t.browser===!1?!1:await Ei(a.redirectUrl),t.wait),a)}async function xl(e,t,n){let r=async()=>{n.signal?.throwIfAborted();let{connections:r}=await e.connections.list(),i=r.filter(e=>e.status===`active`&&e.providerId.toLowerCase()===t.trim().toLowerCase());return i.length?wr(i,t):void 0},i=await r();if(i||n.json||n.dryRun||!process.stdin.isTTY)return i;let a=await bl(t,{...n,wait:!0},e);for(;!i&&Date.now()<Date.parse(a.expiresAt);)await Ae(1e3,void 0,{signal:n.signal}),i=await r();return i}function Sl(){let e=new x(`hub`).description(`Discover and run Tangle Hub tools`);e.command(`connect`).description(`Connect a provider account`).argument(`provider`,`Provider to connect`).option(`--no-browser`,`Print the authorization URL instead of opening it`).option(`--parameter <key=value>`,`Provider-specific OAuth value. Repeatable.`,(e,t)=>[...t,e],[]).action(async(e,t)=>{await bl(e,t)});let t=new x(`connections`).description(`List Hub provider connections`).action(async e=>{let t=await(await q(e)).connections.list();if(e.json){I(t);return}Ll(t.connections)});t.command(`revoke <connection-id>`).description(`Revoke a Hub provider connection`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=await q(t),r=await Cr(n,e);if(!t.force&&!await ei(`Revoke Hub connection ${r}? `,`--force`)){R(`Revoke cancelled.`);return}let i=await n.connections.revoke(r);if(t.json){I(i);return}R(`Revoked Hub connection ${i.connection.id}.`)}),e.addCommand(t);let n=new x(`permissions`).description(`Manage Hub action permissions`);n.command(`list`).description(`List Hub permissions for a connection`).requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);let t=await q(e),n=await Cr(t,e.connection),r=await t.permissions.list(n);if(e.json){I(r);return}Ml(r.policies)}),n.command(`set`).description(`Set Hub permission for one action`).requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).requiredOption(`--action <path>`,`Executor action path`).requiredOption(`--decision <allow|ask|deny>`,`Permission decision`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);if(!e.action)throw Error(`--action is required.`);let t=Nl(e.decision),n=await q(e),r=await Cr(n,e.connection),i=await n.permissions.set({connectionId:r,actionPath:e.action,decision:t});if(e.json){I(i);return}Ml([i.policy])}),n.command(`revert-writes`).description("Revoke a bulk `--allow-writes` grant for a connection (deletes only the auto-granted write rows; manual permissions are untouched)").requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);let t=await q(e),n=await Cr(t,e.connection),r=await t.permissions.revertWrites(n);if(e.json){I(r);return}R(`Reverted ${r.reverted} write permission${r.reverted===1?``:`s`} for connection ${r.connectionId}.`)}),e.addCommand(n),e.addCommand(wl());let r=new x(`tools`).description(`Discover Hub tools`);return r.command(`sources`).description(`List Hub tool sources`).action(async e=>{let t=await(await q(e)).tools.sources();if(e.json){I(t);return}Pl(t.sources)}),r.command(`describe`).description(`Describe a Hub tool`).argument(`path`,`Executor tool path`).action(async(e,t)=>{let n=await(await q(t)).tools.describe(e);if(t.json){I(n);return}Fl(n.tool)}),r.command(`search`).description(`Search Hub tools`).argument(`<query...>`,`Search query`).option(`--provider <provider>`,`Filter by provider/source ID`).action(async(e,t)=>{let n=await(await q(t)).tools.search(e.join(` `),{provider:t.provider});if(t.json){I(n);return}jl(n.tools)}),e.addCommand(r),e.addCommand(Cl(`call`)),e.addCommand(Cl(`exec`)),e.command(`resume`).description(`Resolve a Hub approval created by a paused execution`).argument(`approval-id`,`Hub approval ID from HUB_APPROVAL_REQUIRED`).option(`--accept`,`Approve the execution approval`).option(`--decline`,`Deny the execution approval`).option(`--cancel`,`Unsupported for approval-backed Hub resume`).action(async(e,t)=>{if(El(e),t.cancel)throw Error(`Hub approval resume does not support --cancel. Use --decline to deny the approval.`);if(t.accept&&t.decline)throw Error(`Choose only one of --accept or --decline.`);if(!t.accept&&!t.decline)throw Error(`Choose --accept to approve or --decline to deny the Hub approval.`);let n=await q(t);Ol(t.decline?await n.approvals.deny(e):await n.approvals.approve(e),t.json===!0)}),e.command(`status`).description(`Show Hub auth and connection status`).action(async e=>{let t=await(await q(e)).status();if(e.json){I(t);return}Vl(t)}),e}function Cl(e){return new x(e).description(`Execute a Hub tool`).argument(`<args...>`,`Tool path tokens followed by JSON input`).option(`--connection <ref>`,`Hub connection id, or provider[:account]`).option(`--auto-approve`,`Approve a HUB_APPROVAL_REQUIRED execution and retry once`).option(`--approve`,`Alias for --auto-approve`).option(`--no-hub-key`,`Do not auto-mint a platform Hub key; use the stored credential as-is`).action(async(e,t)=>{let{args:n,approve:r}=Tl(e,t),{path:i,input:a}=Al(n),o=await q(t),s=t.connection?await Cr(o,t.connection):void 0;I((await o.tools.invoke(i,a,{connectionId:s,approve:r})).result)})}function wl(){let e=new x(`approvals`).description(`List and resolve Hub execution approvals`);e.command(`list`).description(`List pending Hub execution approvals`).action(async e=>{let t=await(await q(e)).approvals.list();if(e.json){I(t);return}Dl(t.approvals)});for(let t of[`approve`,`deny`])e.command(t).description(`${t===`approve`?`Approve`:`Deny`} a pending Hub execution approval`).argument(`approval-id`,`Hub approval ID`).action(async(e,n)=>{El(e),Ol(await(await q(n)).approvals[t](e),n.json===!0)});return e}function Tl(e,t){let n=t.autoApprove;return{args:e.filter(e=>e!==`--approve`&&e!==`--auto-approve`),approve:t.approve===!0||n===!0||e.includes(`--approve`)||e.includes(`--auto-approve`)}}function El(e){if(!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`Hub approval ID must contain only letters, numbers, underscores, and dashes.`)}function Dl(e){F(e,[{key:`id`,header:`ID`},{key:`providerId`,header:`Provider`},{key:`actionPath`,header:`Action`},{key:`connectionId`,header:`Connection`},{key:`status`,header:`Status`},{key:`expiresAt`,header:`Expires`}])}function Ol(e,t){if(t){I(kl(e));return}R(`Hub approval ${e.approval.id} ${e.approval.status}.`),e.capabilityToken&&R("Capability token minted. Re-run the original command with `--approve` to execute automatically.")}function kl(e){return{approval:e.approval,...e.capabilityToken?{capabilityToken:{tokenId:e.capabilityToken.tokenId,expiresAt:e.capabilityToken.expiresAt}}:{}}}function Al(e){if(e.length<2)throw Error(`Usage: tangle hub call <path> <json-input>`);let t=e[e.length-1];try{return{path:e.slice(0,-1).join(`.`),input:JSON.parse(t)}}catch{throw Error(`Hub call input must be valid JSON.`)}}function jl(e){F(e.map(e=>({...e,provider:e.providerId??e.requiredConnectionProviderId,connection:Il(e)})),[{key:`path`,header:`Path`},{key:`provider`,header:`Provider`},{key:`title`,header:`Title`},{key:`description`,header:`Description`},{key:`connection`,header:`Connection`},{key:`policyState`,header:`Policy`}])}function Ml(e){F(e,[{key:`connectionId`,header:`Connection`},{key:`providerId`,header:`Provider`},{key:`actionPath`,header:`Action`},{key:`decision`,header:`Decision`},{key:`updatedAt`,header:`Updated`}])}function Nl(e){if(e===`allow`||e===`ask`||e===`deny`)return e;throw Error(`--decision must be one of: allow, ask, deny.`)}function Pl(e){F(e,[{key:`sourceId`,header:`Source`},{key:`displayName`,header:`Provider`},{key:`toolCount`,header:`Tools`},{key:`connectionStatus`,header:`Connection`},{key:`health`,header:`Health`},{key:`configured`,header:`Configured`}])}function Fl(e){B({Path:e.path,Provider:e.providerId??e.requiredConnectionProviderId,Title:e.title,Description:e.description,Connection:Il(e),Policy:e.policyState}),e.inputSchema!==void 0&&(R(`Input schema`),console.log(JSON.stringify(e.inputSchema,null,2))),e.outputSchema!==void 0&&(R(`Output schema`),console.log(JSON.stringify(e.outputSchema,null,2)))}function Il(e){if(e.connectionRequired===!1)return`not required`;if(e.connectionStatus)return e.connectionStatus}function Ll(e){F(e.map(e=>({...e,account:e.accountDisplay??e.displayName,scopes:e.scopes.join(`, `)})),[{key:`id`,header:`ID`},{key:`providerId`,header:`Provider`},{key:`account`,header:`Account`},{key:`scopes`,header:`Scopes`},{key:`status`,header:`Status`},{key:`health`,header:`Health`},{key:`lastUsedAt`,header:`Last Used`}])}function Rl(e){if(!e||e.length===0)return;let t={};for(let n of e){let e=n.indexOf(`=`);if(e<=0||e===n.length-1)throw Error(`Invalid --parameter "${n}": expected key=value (for example subdomain=acme)`);let r=n.slice(0,e);if(Object.hasOwn(t,r))throw Error(`Duplicate --parameter key "${r}".`);t[r]=n.slice(e+1)}return t}function zl(e,t,n=!1){t?R(`Opened browser to connect ${e.provider}.`):(R(`Open this URL to connect ${e.provider}:`),console.log(e.redirectUrl)),R(n?`Finish authorization in the browser; this run resumes when connected.`:"Finish authorization in the browser, then rerun `tangle hub status`.")}function Bl(e){return{provider:e.provider,redirectUrl:e.redirectUrl,expiresAt:e.expiresAt,scopes:e.scopes,cli:e.cli}}function Vl(e){let{principal:t,connections:n}=e;R(`Hub status`),B({Principal:t.kind,"User ID":t.userId,"API Key ID":t.apiKeyId,"Sandbox ID":t.sandboxId,"Connected Providers":n.connectedProviderCount,"Unhealthy Providers":n.unhealthyProviderCount}),n.unhealthyProviderCount>0&&R(`Some providers require reconnect.`)}const Hl=t(import.meta.url);if(!Hl)throw Error(`Tangle CLI package metadata was not found`);const Ul=me(Hl),Wl=e=>C(`sha256`).update(e).digest(`hex`);function Gl(e,t){let n=_e(e,t);return n!==`..`&&!n.startsWith(`..${ye}`)&&!ge(n)}function Kl(e,t){if(/[\\/]/.test(e)||/\.(yaml|yml|json)$/.test(e))return ve(t,e);let n=t;for(;!le(j(n,`.git`))&&me(n)!==n;)n=me(n);le(j(n,`.git`))||(n=t);let r=[`yaml`,`yml`,`json`].flatMap(e=>[`graph.${e}`,e]),i=[n,M()].flatMap(t=>r.map(n=>j(t,`.tangle/graphs/${e}.${n}`))),a=i.find(le);if(a)return a;throw new V(`GRAPH_NOT_FOUND`,`Graph '${e}' was not found`,`Looked in ${i.join(`, `)}`,`tangle graph --help`)}async function ql(e,t){return ic(e.signal,async n=>{let r=e.runId??w(),i;try{let a=j(M(),`.tangle`,`runs`,r);await Ve(a,{recursive:!0,mode:448});let o=await Ge(j(M(),`.tangle`)),s=await Ge(e.cwd??process.cwd()),c=[`runs`,`graph-registry`,`graphs`].some(e=>Gl(s,j(o,e))||Gl(j(o,e),s))?j(M(),`.tangle`,`workspaces`,r):s;await Ve(c,{recursive:!0,mode:448});let l;return await t({runId:r,runDir:a,cwd:c,bridge:t=>l??=(async()=>{n.throwIfAborted();let r=te(32).toString(`hex`),{loadConfig:o,startServer:s}=await import(`cli-bridge`),l=j(Ul,`dist`,`stdio.mjs`),u={...process.env,BRIDGE_HOST:`127.0.0.1`,BRIDGE_BEARER:r,BRIDGE_DATA_DIR:j(a,`bridge`),BRIDGE_BACKENDS:fc,BRIDGE_JAIL_MODE:`fs-jail`,BRIDGE_JAIL_FALLBACK:`deny`,BRIDGE_JAIL_NETWORK:`relay`,BRIDGE_SUBSCRIPTIONS_ONLY:`1`};e.relayAllow?u.BRIDGE_JAIL_RELAY_ALLOW=e.relayAllow:delete u.BRIDGE_JAIL_RELAY_ALLOW;let d=o(u);t&&d.jailReadablePaths.push(l),i=await s({cwd:c,config:{...d,port:0},handleSignals:!1,quiet:!0,hub:t?{client:t,hash:rc,serverForGrant:e=>{if(!i)throw Error(`Hub host is not ready`);return{transport:`stdio`,command:process.execPath,args:[{kind:`public`,value:l}],env:{TANGLE_HUB_MCP_ENDPOINT:{kind:`public`,value:`${i.url}/hub/mcp/grants/${e}`}}}}}:void 0});let{graphNativeCapture:f}=await import(`./graph-native-af-gs1TS.mjs`);return{harnessTranscript:f({bridgeUrl:i.url,bridgeBearer:r,cwd:c}),backend:`bridge`,bridgeUrl:i.url,bridgeBearer:r,cwd:c}})(),signal:n})}catch(t){throw t instanceof Error&&Object.assign(t,{runId:e.errorRunId??r}),t}finally{await i?.close()}},e.fix??`tangle graph --help`)}function Jl(e,t){return[`tangle graph run`,Be(e),...t.dryRun?[`--dry-run`]:[],...t.cloud?[`--cloud`]:[],...t.resume?[`--resume`,Be(t.resume)]:[],...t.seat?[`--seat`,Be(t.seat)]:[],...t.seatAccount?[`--seat-account`,Be(t.seatAccount)]:[],...t.seatCommand?[`--seat-command`,Be(t.seatCommand)]:[],...t.param.flatMap(e=>[`--param`,Be(e)])].join(` `)}async function Yl(e,t,n={}){let r=Jl(e,t);return await ic(n.signal,async i=>{i.throwIfAborted();let a=await Ge(Kl(e,n.cwd??process.cwd())),o=n.source??await We(a,`utf8`);if(!t.resume&&t.cloud||t.resume?.startsWith(`wfrun_`))return Rc(a,o,t,i);let s=await qc(),c=Wl(o),l=Object.entries(Mc(t.param,`param`)??{}),u=Object.fromEntries(l.filter(([e])=>!e.startsWith(`gate.`))),d=Object.fromEntries(l.filter(([e])=>e.startsWith(`gate.`)).map(([e,t])=>[e.slice(5),t])),f=t.resume?await lc(t.resume):void 0,p=s.graphRegistry(j(M(),`.tangle`,`graph-registry`)),m;if(f){f.file!==a&&X(`The recorded graph source path changed`);let e=await s.loadGraph(p,f.graphDigest);e||X(`The recorded executable graph is unavailable`),m=s.validateStoredGraph(e),dc(f,t,c,u,d)}let h={apiKey:t.apiKey,sandboxBaseUrl:t.baseUrl,signal:i,json:t.json,dryRun:t.dryRun&&!n.connectNeeds},g,_=()=>g??=yl(h),v=new Map,y=e=>{let t=e.trim().toLowerCase(),n=v.get(t)??(async()=>{let e=await _(),n=e&&await xl(e,t,h);return n?{connectionId:n,capabilities:[`*`]}:void 0})();return v.set(t,n),n},b=async e=>{if(i.throwIfAborted(),f&&m)return ac(m,f.gateChoices??{}),{graph:m,params:f.params};let r=await s.loadGraphFile(a,{source:o,seat:t.seat??Un().seat,resolveSeat:pc(e,i),resolveNeed:y,params:u,cwd:e,signal:i});if(i.throwIfAborted(),ac(r.graph,d),n.graphDigest&&r.graph.digest!==n.graphDigest)throw new V(`GRAPH_CHANGED`,`The validated graph changed before execution`,`Its compiled graph digest no longer matches validation`,`tangle graph run --help`);return r},ee=n.cwd??process.cwd(),x=await b(f?.cwd??ee),S=gc(x.graph);if(t.dryRun)return x;let C=_c(x.graph.nodes)?yc(t):void 0,te=f?.runId??n.runId??w(),T=f?.cwd??await s.graphWorkspace(x.graph,{cwd:ee,runId:te});return ql({...n,runId:te,cwd:T,signal:i,fix:r,relayAllow:S},async({runId:e,runDir:n,cwd:r,bridge:o})=>{let{superviseGraphPursuit:l,readSettleRecord:u}=await import(`@tangle-network/agent-runtime/durable`),m=await s.recordStoredGraphRun(p,x.graph),h=f??{version:1,runId:e,cwd:r,file:a,graphDigest:m.digest,sourceDigest:c,params:x.params,...Object.keys(d).length?{gateChoices:d}:{},startedAt:new Date().toISOString(),...t.seat===void 0?{}:{seat:t.seat}};f||await uc(n,h);let g=f?await u(n):void 0;if(g&&g.tree.root!==e&&X(`The settlement names another run`),g?.kind===`no-winner`&&X(`The local run is terminal: ${g.reason}`),g)return{runId:e,graphDigest:m.digest,sourceDigest:c,...Gc(g),replayed:!0};let v=s.graphFromStored(m),y=m.nodes.some(e=>e.profile.connections?.length),b=y?await _():void 0;if(y&&!b)throw new V(`AUTH_REQUIRED`,`Hub authentication is required`,`No Tangle credential is configured for this local graph`,`tangle auth login`);let ee=await o(b),S=C?Sc({bridgeUrl:ee.bridgeUrl,bridgeBearer:ee.bridgeBearer},C,i):void 0,te=h.startedAt;R(`Run ${e} · ${pe(a)} · ${r}`);let w=await Xl(n);R(`Viewer ${w.url}`);let T=new AbortController,ne=await l(v,{pursuitId:m.digest,runDir:n,runId:e,backend:ee,...v.entry===void 0?{driverBackend:ee}:{},...m.gates?.length?{decideGate:oc(h.gateChoices??{},{json:t.json,signal:AbortSignal.any([i,T.signal])})}:{},resume:!!f,signal:i,...S?{selectSeat:S,coordination:{authentication:!0}}:{},profileSecurity:{allowConnections:y,allowLocalMcp:!1,allowHooks:!1,allowedMcpHosts:[]}}).finally(async()=>{T.abort(),await w.close()}),E={runId:e,graphDigest:m.digest,sourceDigest:c,...Gc(ne.result.result)},D=ne.result.result,{tokens:re,tokensKnown:ie,iterations:ae,ms:oe}=D.spentTotal;if(await s.recordStoredGraphRun(p,m,{graphDigest:m.digest,evidence:[{kind:`authored-graph`,url:`urn:sha256:${m.digest}`},{kind:`authored-yaml`,url:`urn:sha256:${c}`}],taskDigest:s.taskShapeDigest({graph:pe(a),params:x.params}),startedAt:te,finishedAt:new Date().toISOString(),outcome:D.kind===`no-winner`?{kind:`no-winner`,reason:D.reason}:{kind:`delivered`,summary:E.text},cost:{iterations:ae,ms:oe,...ie===!1?{}:{tokens:re.input+re.output},...E.costUsd===null?{}:{usd:E.costUsd}},traversals:ne.result.ledger.length,exhaustedEdges:ne.result.exhaustedEdges,source:{kind:`tangle-cli-graph`,id:e}}),D.kind===`no-winner`)throw Object.assign(new V(`GRAPH_RUN_FAILED`,`Graph '${pe(a)}' finished without a result`,ne.result.stopped?.reason||ne.result.ledger.filter(e=>e.outcome===`unpropagated`&&e.reason).pop()?.reason||D.reason,`tangle graph inspect ${e}`),{runId:e,runtimeFailures:[...D.tree.nodes.filter(e=>e.failure).map(e=>({node:e.label,failure:e.failure})),...D.reason===`driver-failed`&&D.error.failure?[{node:`root`,failure:D.error.failure}]:[]]});return E})},r)}async function Xl(e){let{serveTopWeb:t}=await import(`@tangle-network/agent-runtime/tui`),{readGraphSessions:n}=await import(`./graph-native-af-gs1TS.mjs`);return t({roots:[e],assets:j(Ul,`dist`,`graph-viewer`),readSessions:n})}async function Zl(e,t){if(e.startsWith(`wfrun_`)){let n=await Z(t),r=await n.workflows.getRun(e);if(t.json)return I(r);for(let e of r.runtime?.checks??[])R(`${e.node} ${e.status} · exit ${e.exitCode??`none`} · pass ${e.pass??`none`}\n${e.reason??e.tail}`);return R(`Run ${e} · ${n.baseUrl}/app/workflows/${encodeURIComponent(r.workflowId)}/runs/${encodeURIComponent(e)}`)}let n=j(M(),`.tangle`,`runs`,e);if(!/^[a-f0-9-]{36}$/i.test(e)||!le(n))throw new V(`RUN_NOT_FOUND`,`Run '${e}' was not found`,`Use a run ID printed by tangle graph run`,`tangle graph inspect --help`);let{loadTopSnapshot:r}=await import(`@tangle-network/agent-runtime/tui`);if(t.json)return I(await r(process.cwd(),{runDir:n}));R(`Run ${e} · ${(await Xl(n)).url}`)}function Ql(){let e=new x(`graph`).description(`Build and run portable agent graphs`);return ll(e),kc(e),rl(e),vl(e,Kl,Ul),e.command(`inspect <run>`).description(`Inspect a live or retained graph run`).action(Zl),e.command(`run <name-or-file>`).description(`Run a saved graph over native subscriptions`).option(`--cloud`,`Run through Tangle's durable cloud workflow owner`).option(`--resume <run>`,`Resume this run's saved graph and durable execution`).option(`--seat <seat>`,`Use harness/model@effort for every node`).option(`--seat-account <account>`,`Account id for an all-eligible authored seat`).option(`--seat-command <program>`,`Executable that prints the account id; the harness is its first argument`).option(`--seat-credential <credential>`,`Credential name passed to the seat command after the harness`).option(`--param <key=value>`,`Graph parameter or gate.<id>=<choice>; repeatable`,(e,t)=>[...t,e],[]).option(`--dry-run`,`Validate and print the graph without starting agents`).action(async(e,t)=>{let n=await Yl(e,t);t.json||t.dryRun?I(n):`status`in n?(R(`${n.status} · ${n.runId}`),n.text&&console.log(n.text)):`viewerUrl`in n&&R(`Run ${n.runId} · ${n.viewerUrl}`)}),e}function $l(){let e=new x(`intelligence`).description(`Create and inspect trace intelligence reports`);return e.command(`connect [agent]`).alias(`connect-agent`).description(`Connect local agent CLIs to Tangle Intelligence`).option(`--endpoint <url>`,`OTLP endpoint base`,aa).option(`--workspace <path>`,`Workspace to write hook files into`,`.`).option(`--service-name <name>`,`OTel service.name label`).option(`--environment <name>`,`OTel deployment.environment label`,`local`).option(`--dry-run`,`Print planned writes without changing files`).option(`--hook-command <command>`,`Command native hooks should run`,`tangle intelligence hook`).option(`--no-smoke`,`Skip the install smoke trace`).action(async(e,t)=>{let n=e??`local`;ua(n);let r=tu(t.apiKey),i=await ha({selection:n,workspace:t.workspace,apiKey:r,endpoint:t.endpoint,serviceName:t.serviceName??fa(t.workspace),environment:t.environment,smoke:t.smoke,dryRun:!!t.dryRun,hookCommand:t.hookCommand}),a={configPath:i.configPath,agents:i.agents,nativeAgents:i.nativeAgents,manual:i.manual,written:i.written,smokeTraceId:i.smokeTraceId};if(t.json){I(a);return}B({Config:i.configPath,Agents:i.agents.join(`, `),"Native Hooks":i.nativeAgents.join(`, `)||void 0,"Manual Setup":i.manual.length?i.manual.map(e=>`${e.label}: ${e.reason}`).join(` `):void 0,Files:i.written.join(`, `),"Smoke Trace":i.smokeTraceId})}),e.command(`doctor`).description(`Check whether your agent traces carry CONTENT or are metadata-only`).option(`--endpoint <url>`,`OTLP endpoint base`,aa).action(async e=>{let t=ma(),n=await ba({endpoint:e.endpoint===`https://intelligence.tangle.tools/v1/otlp`?t?.endpoint??`https://intelligence.tangle.tools/v1/otlp`:e.endpoint,apiKey:tu(e.apiKey??t?.apiKey)});e.json?I(n):eu(n),n.contentSeen||(process.exitCode=1)}),e.command(`hook`).description(`Emit one local agent hook event to Tangle Intelligence`).requiredOption(`--agent <agent>`,`Agent surface`).requiredOption(`--event <event>`,`Hook event name`).option(`--payload <json>`,`Hook payload JSON`).option(`--endpoint <url>`,`OTLP endpoint base`).option(`--service-name <name>`,`OTel service.name label`).option(`--environment <name>`,`OTel deployment.environment label`).option(`--session-id <id>`,`Session id override`).option(`--dry-run`,`Build the OTLP request without sending it`).option(`--non-blocking`,`Do not fail the parent agent process`).action(async e=>{try{let t=nu(e.agent),n=ma(),r={agent:t,event:e.event,endpoint:e.endpoint??n?.endpoint??`https://intelligence.tangle.tools/v1/otlp`,apiKey:tu(e.apiKey??n?.apiKey),serviceName:e.serviceName??n?.serviceName??fa(process.cwd()),environment:e.environment??n?.environment??`local`,sessionId:e.sessionId,payload:e.payload===void 0?await iu():ru(e.payload)};if(e.dryRun){let n=_a(r);if(e.json){I(n);return}B({Trace:n.traceId,Agent:t,Event:e.event});return}let i=await va(r);if(e.json){I({traceId:i});return}B({Trace:i,Agent:t,Event:e.event})}catch(t){if(e.nonBlocking){let n=t instanceof Error?t.message:String(t);e.json?I({ok:!1,error:n}):console.error(`Tangle Intelligence hook skipped: ${n}`);return}U(t)}}),e.command(`sandbox <sandbox-id>`).description(`Create an intelligence report for one sandbox`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).action(async(e,t)=>{await au({type:`sandbox`,id:e},t)}),e.command(`fleet <fleet-id>`).description(`Create an intelligence report for a sandbox fleet`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).action(async(e,t)=>{await au({type:`fleet`,id:e},t)}),e.command(`create`).description(`Create a trace intelligence report`).requiredOption(`--subject-type <type>`,`sandbox | fleet`).requiredOption(`--subject-id <id>`,`Subject identifier`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).action(async e=>{await au({type:su(e.subjectType),id:e.subjectId},e)}),e.command(`get <job-id>`).description(`Get an intelligence report`).action(async(e,t)=>{let{client:n}=K(t),r=t.json?null:z(`Fetching intelligence report...`);r?.start();let i=await n.intelligence.getReport(e);if(r?.stop(),t.json){I(i);return}ou(i)}),e.command(`list`).description(`List intelligence reports`).option(`--subject-type <type>`,`sandbox | fleet`).option(`--subject-id <id>`,`Subject identifier`).option(`--limit <count>`,`Maximum reports to return`).action(async e=>{let{client:t}=K(e),n=e.json?null:z(`Fetching intelligence reports...`);n?.start();let r=await t.intelligence.listReports({subjectType:e.subjectType===void 0?void 0:su(e.subjectType),subjectId:e.subjectId,limit:e.limit===void 0?void 0:uu(e.limit)});if(n?.stop(),e.json){I(r);return}F(r.map(e=>({jobId:e.jobId,subject:`${e.subject.type}:${e.subject.id}`,mode:e.mode,status:e.status,cost:`$${e.billing.costUsd.toFixed(2)}`,updatedAt:e.updatedAt})),[{key:`jobId`,header:`Job`,width:20},{key:`subject`,header:`Subject`,width:28},{key:`mode`,header:`Mode`,width:15},{key:`status`,header:`Status`,width:14},{key:`cost`,header:`Cost`,width:10},{key:`updatedAt`,header:`Updated`,width:18}])}),e}function eu(e){B({Status:e.contentSeen?`content flowing`:e.tracesSeen?`metadata-only — a content gate is missing`:`no traces yet`,"Traces seen":e.tracesSeen?`yes`:`no`,"Content seen":e.contentSeen?`yes`:`no`,"Last seen":e.lastSeenAt??`never`,Window:`${e.windowDays}d`});let t=Object.entries(e.byAgent);t.length>0&&(console.log(),F(t.map(([e,t])=>({agent:e,traces:t.tracesSeen?`yes`:`no`,content:t.contentSeen?`yes`:`no`})),[{key:`agent`,header:`Agent`,width:18},{key:`traces`,header:`Traces`,width:10},{key:`content`,header:`Content`,width:10}]))}function tu(e){let t=e??process.env.TANGLE_INTELLIGENCE_API_KEY??process.env.TANGLE_API_KEY;if(!t)throw Error(`--api-key, TANGLE_INTELLIGENCE_API_KEY, or TANGLE_API_KEY is required`);return t}function nu(e){if(da(e))return e;throw Error(`agent must be a known Tangle Intelligence agent surface`)}function ru(e){try{return JSON.parse(e)}catch(e){throw Error(`--payload must be JSON: ${e instanceof Error?e.message:String(e)}`)}}async function iu(){if(process.stdin.isTTY)return;let e=``;for await(let t of process.stdin)if(e+=typeof t==`string`?t:t.toString(`utf8`),e.length>65536)throw Error(`hook payload exceeds 65536 bytes`);let t=e.trim();if(t)try{return JSON.parse(t)}catch{return{body:t.slice(0,4096)}}}async function au(e,t){let n=cu(t.mode),r=du(t.metadata),i=t.maxUsd===void 0?void 0:lu(t.maxUsd);if(n===`agentic`&&i===void 0)throw Error(`Agentic intelligence reports require --max-usd`);let{client:a}=K(t),o=t.json?null:z(`Creating intelligence report...`);o?.start();let s=await a.intelligence.createReport({subject:e,mode:n,...i===void 0?{}:{budget:{billTo:`customer`,maxUsd:i}},...r===void 0?{}:{metadata:r}});if(o?.stop(),t.json){I(s);return}ou(s)}function ou(e){B({Job:e.jobId,Subject:`${e.subject.type}:${e.subject.id}`,Mode:e.mode,Status:e.status,"Billed To":e.billing.billedTo,Cost:`$${e.billing.costUsd.toFixed(2)}`,Budget:e.billing.budgetMaxUsd===void 0?void 0:`$${e.billing.budgetMaxUsd.toFixed(2)}`,Updated:e.updatedAt}),e.result!==null&&(console.log(),I(e.result))}function su(e){if(e===`sandbox`||e===`fleet`)return e;throw Error(`subject type must be sandbox or fleet`)}function cu(e){if(e===`deterministic`||e===`agentic`)return e;throw Error(`mode must be deterministic or agentic`)}function lu(e){let t=Number(e);if(!Number.isFinite(t)||t<0)throw Error(`--max-usd must be a non-negative number`);return t}function uu(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function du(e){if(e===void 0)return;let t=JSON.parse(e);if(!t||typeof t!=`object`||Array.isArray(t))throw Error(`--metadata must be a JSON object`);return t}const fu=[`router`,`sandbox`,`blueprint-agent`,`evals`,`agent-builder`];async function pu(e,t){let n=await Rr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.platformUrl===void 0?{}:{baseUrl:e.platformUrl},...e.baseUrl===void 0?{}:{sandboxBaseUrl:e.baseUrl}});if(!t||!n.minted)return n;throw Error("This command needs a key you minted yourself. A browser login is exchanged for a short-lived key the platform will not accept for key management. Set TANGLE_API_KEY, run `tangle auth login --api-key sk-tan-…`, or mint the key in the web console. `tangle keys list` works from the login alone.")}async function mu(e,t,n={}){let r=new Headers(n.headers);n.body&&!r.has(`content-type`)&&r.set(`content-type`,`application/json`);let i=await zr(e,t,{...n,headers:r});if(n.expected!==void 0&&i.status!==n.expected)throw Error(await hu(i,t));return i}async function hu(e,t){let n=await e.text().catch(()=>``),r;try{let e=JSON.parse(n),t=typeof e?.error==`string`?e.error:e?.error?.message;typeof t==`string`&&t.trim()&&(r=t)}catch{}if(r)return`${r} (HTTP ${e.status})`;let i=n?`: ${n.slice(0,400)}`:``;return`Platform request to ${t} returned ${e.status}${i}`}const gu=[`ID`,`Prefix`,`Name`,`Product`,`Created`,`Last used`,`Expires`];function _u(e){return[e.id,e.keyPrefix??``,e.name,e.product??`all`,e.createdAt,e.lastUsedAt??`—`,e.expiresAt??`—`]}function vu(){let e=new x(`keys`).description(`Manage sk-tan-* API keys on id.tangle.tools`);return e.command(`list`).description(`List your active API keys`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async e=>{let t=await pu(e,!1),n=t.baseUrl,r=await(await mu(t,`${n}/v1/keys`,{expected:200})).json();if(e.json){I(r);return}Vt(gu,r.data.map(_u))}),e.command(`create`).description(`Create a new API key`).argument(`<name>`,`Human-readable name for the key`).option(`--product <product>`,`Restrict the key to one product (${fu.join(`|`)}). Omit for all products.`).option(`--budget-usd <amount>`,`Hard budget cap in USD`).option(`--rpm-limit <limit>`,`Requests-per-minute cap`).option(`--expires-in-days <days>`,`Expire the key after N days (integer)`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{if(t.product!==void 0&&!fu.includes(t.product))throw Error(`Invalid --product. Expected one of ${fu.join(`, `)}`);let n=await pu(t,!0),r=n.baseUrl,i=t.expiresInDays===void 0?void 0:new Date(Date.now()+Number.parseInt(t.expiresInDays,10)*24*60*60*1e3).toISOString(),a=z(`Creating API key...`);a.start();let o=await mu(n,`${r}/v1/keys`,{method:`POST`,expected:201,body:JSON.stringify({name:e,product:t.product,budgetUsd:t.budgetUsd?Number.parseFloat(t.budgetUsd):void 0,rpmLimit:t.rpmLimit?Number.parseInt(t.rpmLimit,10):void 0,expiresAt:i})});a.stop();let s=await o.json();if(t.json){I(s);return}L(`API key created: ${s.data.prefix}…`),R(`Copy this key now — it will never be shown again:\n${s.data.key}`)}),e.command(`revoke`).description(`Revoke an API key`).argument(`<keyId>`,"Key ID (from `tcloud keys list`)").option(`--yes`,`Skip the confirmation prompt`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{let n=await pu(t,!0),r=n.baseUrl;if(!t.yes&&!await ei(`Revoke key ${e}? Any service still using it will start to fail.`,`--yes`)){R(`Aborted.`);return}let i=await(await mu(n,`${r}/v1/keys/${encodeURIComponent(e)}`,{method:`DELETE`,expected:200})).json();if(t.json){I(i);return}L(`Revoked ${e}`)}),e}function yu(e){if(qn().token)throw Error(`A line relay cannot manage numbers or attachments. Use your owner CLI outside the agent box.`);return G(W(e))}function bu(e){if(!e.yes)throw Error(`Review the selected line and use --yes to authorize this change. Attaching enables metered agent work.`)}function xu(e){if(e===`imessage`||e===`whatsapp`||e===`email`||e===`sms`||e===`voice`||e===`telegram`)return e;throw Error(`--transport must be imessage, whatsapp, email, sms, voice, or telegram`)}function Su(e){return e().catch(U)}async function Cu(e){let t=await Ue(e,`r`);try{if(!(await t.stat()).isFile())throw Error(`Attachment input must be a regular JSON file`);let e=Buffer.alloc(131073),n=0;for(;n<e.length;){let{bytesRead:r}=await t.read(e,n,e.length-n,null);if(r===0)break;n+=r}if(n===e.length)throw Error(`Attachment JSON exceeds 128 KiB`);let r;try{r=JSON.parse(e.subarray(0,n).toString(`utf8`))}catch{throw Error(`Attachment file is not valid JSON`)}if(!r||typeof r!=`object`||Array.isArray(r))throw Error(`Attachment JSON must be an object`);if(Object.hasOwn(r,`number`))throw Error(`Use the line ID argument, not a number field in the attachment file`);return r}finally{await t.close()}}function wu(e){e.command(`providers`).description(`List provider transports supported by this Hub deployment`).action(e=>Su(async()=>{I(await yu(e).lines.providers())})),e.command(`list`).description(`List owned lines, optionally for a saved agent profile or sandbox`).option(`--profile-id <id>`,`Stored profile ID`).option(`--sandbox <id>`,`Existing sandbox ID`).action(e=>Su(async()=>{I(await yu(e).lines.list({profileId:e.profileId,sandboxId:e.sandbox}))})),e.command(`get`).argument(`<line-id>`).description(`Inspect a line and its current attachment`).action((e,t)=>Su(async()=>{I(await yu(t).lines.get(e))})),e.command(`numbers`).argument(`<connection-id>`).description(`Discover owned provider numbers; this does not purchase or reserve a number`).option(`--transport <transport>`,`imessage, whatsapp, or sms`,`imessage`).action((e,t)=>Su(async()=>{let n=xu(t.transport);if(n===`email`)throw Error(`Email uses an owned mailbox, not phone inventory`);if(n===`voice`)throw Error(`Voice numbers are listed by ph0ny; provide the owned number ID to lines connect`);if(n===`telegram`)throw Error(`Telegram uses an owned bot, not phone inventory`);I(await yu(t).lines.numbers(e,n))})),e.command(`connect`).argument(`<connection-id>`).description(`Bind an owned number or identity through Hub; no provider rental is purchased`).option(`--transport <transport>`,`imessage, whatsapp, sms, email, voice, or telegram`,`imessage`).option(`--number-id <id>`,`Exact owned provider number ID; required for voice, SMS, WhatsApp and Linq iMessage`).option(`--address <email>`,`Owned mailbox on a verified email domain`).requiredOption(`--reference <reference>`,`Stable client reference; keep it unchanged on retry`).option(`--label <label>`,`Line display name`).option(`--yes`,`Authorize provider webhook configuration and line binding`).action((e,t)=>Su(async()=>{bu(t);let n=xu(t.transport);if(n!==`email`&&t.address)throw Error(`--address is email-only`);if((n===`email`||n===`telegram`)&&t.numberId)throw Error(`${n} does not take --number-id`);let r={connectionId:e,label:t.label,clientReference:t.reference},i;if(n===`email`)i={...r,transport:n,address:t.address};else if(n===`telegram`)i={...r,transport:n};else if(n===`imessage`)i={...r,transport:n,phoneNumberId:t.numberId};else{if(!t.numberId)throw Error(`${n} requires --number-id`);i={...r,transport:n,phoneNumberId:t.numberId}}I(await yu(t).lines.fromConnection(i))})),e.command(`attach`).argument(`<line-id>`).description(`Attach a saved agent to any sandbox, or use an isolated on-demand member instance`).option(`--file <path>`,`Reviewed native attachment JSON (exclusive with quick-setup flags)`).option(`--profile-id <id>`,`Owner-scoped saved profile; each turn pins its source revision`).option(`--member <address>`,`The one allowed sender: E.164 phone or email`).option(`--sandbox <id>`,`Use an existing sandbox instead of an on-demand instance`).option(`--instance-prefix <prefix>`,`Stable instance namespace; defaults to profile:<profile-id>:`).option(`--tools <mode>`,`chat denies tools; act applies the profile's tools and permissions`).option(`--turns-per-day <count>`,`Per-member daily turn ceiling (default 30)`).option(`--yes`,`Authorize agent execution and spend against your key limits`).action((e,t)=>Su(async()=>{bu(t);let n=yu(t),r;if(t.file){if(t.profileId||t.member||t.sandbox||t.instancePrefix||t.tools||t.turnsPerDay)throw Error(`Choose --file or quick-setup flags, not both`);r=await Cu(t.file)}else{if(!t.profileId||!t.member)throw Error(`Provide --profile-id and --member, or --file`);if(t.sandbox&&t.instancePrefix)throw Error(`Choose --sandbox or --instance-prefix`);let e=t.tools??`chat`,n=Number(t.turnsPerDay??`30`);if(e!==`chat`&&e!==`act`)throw Error(`--tools must be chat or act`);if(!Number.isSafeInteger(n)||n<1||n>1e4)throw Error(`--turns-per-day must be 1–10000`);if(e===`act`&&t.sandbox)throw Error(`Acting tools require an isolated on-demand instance; omit --sandbox`);r={mode:`personal`,members:[{address:t.member,role:`owner`}],unknownSenders:`reject`,roles:{owner:{context:`own`,tools:e}},respond:{kind:`agent`,profileId:t.profileId,...e===`act`?{rolePolicy:{version:1,roles:{owner:{kind:`general`}},members:{}}}:{}},limits:{turnsPerMemberPerDay:n},...t.sandbox?{sandboxId:t.sandbox}:{instance:{keyPrefix:t.instancePrefix??`profile:${t.profileId}:`,create:{ownerContext:`isolated`,...e===`act`?{egressPolicy:{mode:`strict`,allowDomains:[new URL(dr()).hostname],includeImplicitDomains:!1}}:{}}}}}}if(typeof r.sandboxId==`string`==(r.instance!==void 0))throw Error(`Attachment requires exactly one of sandboxId and instance`);let{sandboxId:i,instance:a,...o}=r,s;if(i){let t=await n.get(i);if(!t)throw Error(`Sandbox not found`);s=await t.lines.attach({...o,number:e})}else{if(!a)throw Error(`Attachment requires an instance`);s=await n.lines.attach({...o,number:e,instance:a})}I(s)}));for(let t of[`detach`,`release`])e.command(t).argument(`<line-id>`).description(t===`detach`?`Stop dispatch; preserve history and provider rental`:`Retire a detached Hub line; does not cancel provider rental`).option(`--yes`,`Authorize this change`).action((e,n)=>Su(async()=>{bu(n),I({[t]:await yu(n).lines[t](e)})}));e.command(`threads`).argument(`<line-id>`).description(`List this line's separate participant threads`).action((e,t)=>Su(async()=>{I(await yu(t).lines.threads(e).list())})),e.command(`messages`).argument(`<line-id>`).argument(`<thread-id>`).description(`Read one authorized participant thread`).action((e,t,n)=>Su(async()=>{I(await yu(n).lines.threads(e).messages(t))}))}async function Tu(e){let{token:t,baseUrl:n}=qn();if(t===void 0)return q(e);if(!t.startsWith(`lrc_`)||!n)throw Error(`The line box needs TANGLE_LINE_TOKEN and TANGLE_HUB_URL`);if(e.apiKey||e.baseUrl&&new URL(e.baseUrl).origin!==new URL(n).origin)throw Error(`A line token cannot be sent to another Hub or combined with an API key`);return new Ee({baseUrl:n,authHeaders:()=>({Authorization:`Bearer ${t}`})})}async function Eu(e,t){if(t)return t;if(!qn().token)throw Error(`Provide --line <line-id>`);return(await e.lines.context()).line.id}function Du(e){return e().catch(U)}function Ou(){return new x(`context`).description(`Show live line identity, members, consent, reminders and quotas`).action(e=>Du(async()=>{I(await(await Tu(e)).lines.context())}))}function ku(){let e=new x(`lines`).description(`Connect, manage, message and schedule on a Hub line`);return e.command(`members`).description(`List names, roles and consent on this line`).option(`--line <line-id>`,`Line ID; inferred in a line box`).action(e=>Du(async()=>{let t=await Tu(e);I(await t.lines.members.list(await Eu(t,e.line)))})),e.command(`send`).description(`Send to a consenting member through Hub`).argument(`<to-member>`,`Exact member ID for an owner; name, ID, or self in a line box`).argument(`<text>`,`Message text`).option(`--line <line-id>`,`Line ID; inferred in a line box`).option(`--on-behalf-of <member>`,`Verified sender for a member relay`).option(`--not-before <iso-time>`,`Delay delivery until this ISO time`).option(`--idempotency-key <key>`,`Stable key for a retry`).action((e,t,n)=>Du(async()=>{let r=await Tu(n),i=await Eu(r,n.line);if(!qn().token){if(n.onBehalfOf)throw Error(`--on-behalf-of is only available inside a line box`);if(!n.idempotencyKey)throw Error(`Owner sends require --idempotency-key so a retry keeps the same message`);if(!(await r.lines.members.list(i)).some(t=>t.id===e))throw Error(`Owner sends require an exact member ID from tangle lines members`);I(await r.lines.send(i,{memberId:e,text:t,idempotencyKey:n.idempotencyKey,...n.notBefore?{notBefore:n.notBefore}:{}}));return}I(await r.lines.send(i,{toMember:e,text:t,...n.onBehalfOf?{onBehalfOf:n.onBehalfOf}:{},...n.notBefore?{notBefore:n.notBefore}:{},...n.idempotencyKey?{idempotencyKey:n.idempotencyKey}:{}}))})),e.command(`remind`).description(`Wake the agent at a future time to write your reminder`).argument(`<text>`,`What to remember`).requiredOption(`--at <iso-time>`,`Future ISO time`).option(`--line <line-id>`,`Line ID; inferred in a line box`).option(`--idempotency-key <key>`,`Stable key for a retry`).action((e,t)=>Du(async()=>{if(!t.at)throw Error(`--at is required`);let n=await Tu(t),r=t.idempotencyKey??C(`sha256`).update(JSON.stringify([e,t.at])).digest(`hex`).slice(0,32);I(await n.lines.remind(await Eu(n,t.line),{text:e,notBefore:t.at,idempotencyKey:r}))})),wu(e),e}function Au(){let e=new x(`mcp`).description(`Model Context Protocol bridge commands.`);return e.command(`serve <id-or-name>`).description(`Run a local MCP server (stdio) backed by the given sandbox (ID or name). Pipe its stdio from an MCP client config to expose sandbox tools.`).option(`-s, --session <id>`,`Session id for kernel scoping`,`mcp-local`).option(`--name <name>`,`MCP server name reported to clients`,`tangle-sandbox`).action(async(e,t)=>{let n=W({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=await J(G(n),n,e),i;try{i=(await import(`@modelcontextprotocol/sdk/server/stdio.js`)).StdioServerTransport}catch{throw Error("`@modelcontextprotocol/sdk` is not installed in this environment. Install it with: pnpm add -g @modelcontextprotocol/sdk (or as a dev dep in the project running this command).")}let{connect:a,close:o}=await rt(r,{sessionId:t.session,name:t.name});await a(new i),process.stdin.resume(),process.stdin.on(`end`,()=>{o().finally(()=>process.exit(0))});for(let e of[`SIGINT`,`SIGTERM`])process.on(e,()=>{o().finally(()=>process.exit(0))})}),e}async function ju(e,t){if(t.self&&e)throw Error(`Use --self or an explicit sandbox, not both`);if(!t.self&&!e)throw Error(`Specify a sandbox id/name or --self`);let n=Rn(),r=t.baseUrl||n.tangleBaseUrl||n.sandboxBaseUrl,i=n.hubUrl;if(t.self&&!r&&i&&new URL(i).origin!==`https://id.tangle.tools`)throw Error(`This deployment must set SANDBOX_BASE_URL or pass --base-url for self preview access`);let a=t.self?t.apiKey??rr():t.apiKey;if(t.self&&!a)throw Error(`Self preview access requires the injected sandbox runtime credential; it never reads saved owner credentials`);let o=W({apiKey:a,baseUrl:r}),s=G(o);return t.self?ot(s):J(s,o,e)}async function Mu(e,t,n){let r=z(e);t||r.start();try{return await n()}finally{r.stop()}}function Nu(e){return e}function Pu(){let e=new x(`preview`).description(`Manage sandbox preview links`);return Nu(e.command(`start`).description(`Start/reuse a managed development server and publish its ready preview`).argument(`[id-or-name]`,`Sandbox ID or name`).option(`--self`,`Use only the sandbox bound to the runtime credential`).option(`--cwd <directory>`,`Project directory in the selected workspace`).option(`--session <session-id>`,`Select the agent's session workspace`).option(`--name <name>`,`App/service label`)).action(async(e,t)=>{let n=await ju(e,t),r=await Mu(`Starting managed preview...`,t.json,()=>it(n,{cwd:t.cwd,sessionId:t.session,name:t.name}));t.json?I(r):(L(`Preview ready: ${r.url}`),console.log(`Preview ID: ${r.previewId}`))}),Nu(e.command(`list`).alias(`ls`).description(`List active preview links for a sandbox`).argument(`[id-or-name]`,`Sandbox ID or name`).option(`--self`,`Use only the sandbox bound to the runtime credential`)).action(async(e,t)=>{let n=await ju(e,t),r=await Mu(`Fetching preview links...`,t.json,()=>n.previewLinks.list());t.json?I(r):r.length===0?console.log(`No preview links found`):Vt([`App`,`Preview ID`,`Port`,`URL`,`Status`],r.map(e=>[Fu(e.metadata),e.previewId.slice(0,12),String(e.port),e.url,e.status]))}),Nu(e.command(`publish`).description(`Publish one existing HTTP service; never starts or replaces a process`).argument(`[id-or-name]`,`Sandbox ID or name`).option(`--self`,`Use only the sandbox bound to the runtime credential`).requiredOption(`--port <port>`,`Existing service port`).option(`--name <name>`,`App/service label`)).action(async(e,t)=>{if(!t.port||!/^\d+$/.test(t.port))throw Error(`An integer service port is required`);let n=await ju(e,t),r=await Mu(`Publishing service...`,t.json,()=>at(n,{port:Number(t.port),name:t.name}));t.json?I(r):L(`Preview ready: ${r.url}`)}),Nu(e.command(`create`).description(`Create a preview link for a port`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<port>`,`Port number to preview`)).action(async(e,t,n)=>{if(!/^\d+$/.test(t)||Number(t)<1||Number(t)>65535)throw Error(`Port must be an integer between 1 and 65535`);let r=await ju(e,n),i=await Mu(`Creating preview for port ${t}...`,n.json,()=>r.previewLinks.create(Number(t)));n.json?I(i):(L(`Preview created: ${i.url}`),console.log(`Preview ID: ${i.previewId}`))}),Nu(e.command(`remove`).alias(`rm`).description(`Remove a preview link`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<preview-id>`,`Preview link ID (from 'preview list')`)).action(async(e,t,n)=>{let r=await ju(e,n);await Mu(`Removing preview...`,n.json,()=>r.previewLinks.remove(t)),n.json?I({success:!0,previewId:t}):L(`Preview removed: ${t}`)}),e}function Fu(e){let t=e?.app;if(!t||typeof t!=`object`)return``;let n=`name`in t?t.name:void 0,r=`cwd`in t?t.cwd:void 0;return typeof n==`string`?n:typeof r==`string`?r:``}function Iu(){let e=new x(`process`).description(`Manage processes in a sandbox`);return e.command(`spawn`).description(`Spawn a process without blocking (returns PID)`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<command>`,`Command to execute`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`).option(`--blocking`,`Wait for completion (default: false)`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=ns(n.env??[],`--env`,`env`),o=z(`Spawning: ${t}`);n.json||o.start();let s=await J(i,r,e);if(s=await Y(s),n.blocking){let e=await s.exec(t,{cwd:n.cwd,env:Object.keys(a).length>0?a:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});o.stop(),n.json?I(e):(e.stdout&&globalThis.process.stdout.write(e.stdout),e.stderr&&globalThis.process.stderr.write(e.stderr),e.exitCode!==0&&globalThis.process.exit(e.exitCode))}else{let r=await s.process.spawn(t,{cwd:n.cwd,env:Object.keys(a).length>0?a:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});o.stop(),n.json?I({pid:r.pid,command:r.command}):(console.log(`Process started with PID: ${r.pid}`),console.log(`Use 'tangle process logs ${e} ${r.pid}' to view output`))}}),e.command(`list`).alias(`ls`).description(`List all processes in a sandbox`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--running`,`Show only running processes`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching processes...`);t.json||i.start();let a=await J(r,n,e);a=await Y(a);let o=await a.process.list();t.running&&(o=o.filter(e=>e.running)),i.stop(),t.json?I(o):o.length===0?console.log(`No processes found`):Vt([`PID`,`Command`,`Status`,`Exit Code`,`Started`],o.map(e=>[String(e.pid),e.command.length>40?`${e.command.slice(0,37)}...`:e.command,e.running?`running`:`exited`,String(e.exitCode),e.startedAt.toLocaleString()]))}),e.command(`get`).description(`Get detailed info about a process`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Fetching process info...`);n.json||a.start();let o=await J(i,r,e);o=await Y(o);let s=await o.process.get(Number.parseInt(t,10));if(a.stop(),!s){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}let c=await s.status();n.json?I(c):(console.log(`PID: ${c.pid}`),console.log(`Command: ${c.command}`),console.log(`CWD: ${c.cwd||`(default)`}`),console.log(`Status: ${c.running?`running`:`exited`}`),console.log(`Exit Code: ${c.exitCode}`),c.exitSignal&&console.log(`Signal: ${c.exitSignal}`),console.log(`Started: ${c.startedAt.toLocaleString()}`),c.exitedAt&&console.log(`Exited: ${c.exitedAt.toLocaleString()}`))}),e.command(`kill`).description(`Kill a process`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).option(`-s, --signal <signal>`,`Signal to send (SIGTERM, SIGKILL, etc.)`,`SIGTERM`).option(`--tree`,`Also kill descendants of the tracked process`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Sending ${n.signal} to PID ${t}...`);n.json||a.start();let o=await J(i,r,e);o=await Y(o);let s=await o.process.get(Number.parseInt(t,10));if(!s){a.stop(),console.error(`Process ${t} not found`),globalThis.process.exit(1);return}n.tree?await s.kill(n.signal,{tree:!0}):await s.kill(n.signal),a.stop(),n.json?I({pid:Number.parseInt(t,10),signal:n.signal,...n.tree===!0?{tree:!0}:{},killed:!0}):console.log(n.tree?`Sent ${n.signal} to process tree ${t}`:`Sent ${n.signal} to process ${t}`)}),e.command(`logs`).description(`Stream buffered and live process logs until the process exits`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).option(`--stdout-only`,`Only show stdout`).option(`--stderr-only`,`Only show stderr`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=await J(i,r,e);a=await Y(a);let o=await a.process.get(Number.parseInt(t,10));if(!o){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}for await(let e of o.logs())n.stdoutOnly&&e.type!==`stdout`||n.stderrOnly&&e.type!==`stderr`||(n.json?console.log(JSON.stringify(e)):e.type===`stdout`?globalThis.process.stdout.write(e.data):globalThis.process.stderr.write(e.data))}),e}const Lu=[`python`,`node`,`typescript`,`bash`];function Ru(e){switch(he(e).toLowerCase()){case`.py`:return`python`;case`.js`:case`.mjs`:case`.cjs`:return`node`;case`.ts`:case`.tsx`:return`typescript`;case`.sh`:case`.bash`:return`bash`;default:return}}async function zu(e){if(e===`-`){let e=[];for await(let t of process.stdin)e.push(typeof t==`string`?Buffer.from(t):t);return Buffer.concat(e).toString(`utf8`)}return await We(ve(e),`utf8`)}async function Bu(e,t,n=zu){let r=t?Lu.find(e=>e===t)??(()=>{throw Error(`unknown --lang ${t}: must be one of ${Lu.join(`, `)}`)})():void 0;if(!e||e===`-`){if(!r)throw Error(`reading from stdin requires --lang. Example: tangle run <id> -l python -`);return{language:r,source:await n(`-`)}}let i=Ru(e);return{language:r??i??(()=>{throw Error(`cannot infer language from "${e}". Pass it explicitly: tangle run <id> -l <python|node|typescript|bash> ${e}`)})(),source:await n(e)}}function Vu(e){return j(xe(),`tangle-run-images`,e)}function Hu(){return new x(`run`).description(`Run code in a persistent kernel inside a sandbox. Variables persist across calls in the same --session.`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`[file]`,`Path to source file. Language is inferred from extension. Use - for stdin (requires --lang).`).option(`-l, --lang <lang>`,`Force language: ${Lu.join(` | `)}. Required for stdin.`).option(`-s, --session <id>`,`Session id for kernel scoping`).option(`-t, --timeout <ms>`,`Per-call timeout in ms (0 disables)`,`60000`).option(`--save-images <dir>`,`Write image results into this directory (default: $TMPDIR/tangle-run-images/<sandbox>/).`).option(`--no-save-images`,`Don't write image results to disk; print summary only`).action(async(e,t,n)=>{let{language:r,source:i}=await Bu(t,n.lang),{context:a,client:o}=K(n),s=await J(o,a,e);s=await Y(s);let c=z(`Running ${r} (${i.length}b)…`);n.json||c.start();let l=await s.runCode(r,i,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10)});if(c.stop(),n.json){I(l),l.exitCode!==0&&process.exit(l.exitCode);return}l.stdout&&process.stdout.write(l.stdout),l.stderr&&process.stderr.write(l.stderr);let u=0;for(let t of l.results)if(t.type===`image`)if(n.saveImages!==!1){let r=typeof n.saveImages==`string`?n.saveImages:Vu(e);ue(r,{recursive:!0});let i=`${r}/${Date.now()}-${u}.${t.format}`;fe(i,Buffer.from(t.data,`base64`)),process.stderr.write(b.green(`✓ image → ${i}\n`)),u++}else process.stderr.write(b.gray(`[image: ${t.format}, ${t.data.length}b base64]\n`));else if(t.type===`dataframe`){let e=t.columns.map(e=>`${e.name}:${e.dtype}`).join(` | `);process.stderr.write(b.gray(`[dataframe ${t.rows.length}×${t.columns.length}${t.truncated?` (truncated)`:``}]\n`)),process.stderr.write(`${e}\n`);for(let e of t.rows.slice(0,20))process.stderr.write(`${e.map(e=>String(e)).join(` | `)}\n`);t.rows.length>20&&process.stderr.write(b.gray(`… ${t.rows.length-20} more rows\n`))}else t.type===`json`?(process.stderr.write(b.gray(`[json] `)),process.stderr.write(`${JSON.stringify(t.value,null,2)}\n`)):t.type===`html`?process.stderr.write(b.gray(`[html ${t.value.length}b]\n`)):t.type===`error`?(process.stderr.write(b.red(`✗ ${t.name}: ${t.message}\n`)),t.traceback&&process.stderr.write(`${t.traceback}\n`)):t.type===`text`&&process.stderr.write(`${t.value}\n`);l.error&&(process.stderr.write(b.red(`\n✗ ${l.error.name}: ${l.error.message}\n`)),l.error.traceback&&process.stderr.write(`${l.error.traceback}\n`)),l.exitCode!==0&&process.exit(l.exitCode)})}function Uu(e){e.command(`network <id-or-name>`).description(`Show runtime network state (exposed ports) for a sandbox. Outbound policy is the sandbox's egress policy.`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Updating network configuration...`);i.start();let a=await J(r,n,e);i.stop();let o=await a.network.getConfig();t.json?I(o):(R(`Network Configuration:`),o.ports&&o.ports.length>0?R(` Exposed Ports: ${o.ports.join(`, `)}`):R(` No exposed ports`))}),e.command(`expose <id-or-name>`).description(`Expose a port and get a public URL`).option(`-p, --port <port>`,`Port to expose`,`8000`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=Number.parseInt(t.port,10);if(Number.isNaN(i)||i<1||i>65535)throw Error(`Port must be a number between 1 and 65535`);let a=z(`Exposing port ${i}...`);a.start();let o=await(await J(r,n,e)).network.exposePort(i);a.stop(),t.json?I({port:i,url:o}):(L(`Port ${i} exposed.`),R(` URL: ${o}`))}),e.command(`urls <id-or-name>`).description(`List exposed port URLs for a sandbox`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching exposed URLs...`);i.start();let a=await(await J(r,n,e)).network.listUrls();if(i.stop(),t.json)I(a);else{let e=Object.entries(a);if(e.length===0)R(`No ports exposed.`);else{R(`Exposed Ports:`);for(let[t,n]of e)R(` ${t}: ${n}`)}}})}function Wu(){let e=new x(`sandbox`).description(`Manage sandboxes`);return Ps(e),Ns(e),Cs(e),Uu(e),e}function Gu(){return new x(`search`).description(`Search for text patterns in sandbox files (ripgrep)`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pattern>`,`Search pattern (regex)`).option(`-g, --glob <pattern>`,`File glob filter (e.g. '**/*.ts')`).option(`-n, --max-results <count>`,`Max results to return`).option(`-i, --ignore-case`,`Case-insensitive search`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Searching...`);n.json||a.start();let o=await J(i,r,e),s=0,c=n.maxResults?Number.parseInt(n.maxResults,10):void 0,l={};n.glob&&(l.glob=n.glob),n.ignoreCase&&(l.ignoreCase=!0),c&&(l.maxResults=c);for await(let e of o.search(t,l))if(s===0&&a.stop(),s++,n.json?console.log(JSON.stringify(e)):console.log(`${e.path}:${e.line}:${e.column??0}: ${e.text}`),c&&s>=c)break;a.stop(),s===0&&!n.json&&console.log(`No matches found`)})}function Ku(){let e=new x(`secret`).description(`Manage secrets`);return e.command(`create`).description(`Create a new secret`).argument(`<name>`,`Secret name (e.g., HF_TOKEN, AWS_ACCESS_KEY)`).argument(`[value]`,`Secret value`).option(`--value-stdin`,`Read secret value from stdin`).action(async(e,t,n)=>{let r=await K(n).client.secrets.create(e,await qu({value:t,valueStdin:n.valueStdin,prompt:`Enter value for secret '${e}': `}));n.json?I(r):(L(`Secret created: ${r.name}`),R(`Use --secret ${r.name} when creating a sandbox to select it for delivery.`))}),e.command(`list`).description(`List all secrets`).action(async e=>{let t=await K(e).client.secrets.list();e.json?I(t):t.length===0?(R(`No secrets found.`),R(`Use 'tangle secret create <name> [value]' to create one.`)):Vt([`Name`,`Created At`,`Updated At`],t.map(e=>[e.name,e.createdAt.toLocaleString(),e.updatedAt.toLocaleString()]))}),e.command(`delete`).description(`Delete a secret`).argument(`<name>`,`Secret name`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=K(t).client;if(!t.force&&!await ei(`Are you sure you want to delete secret '${e}'? This cannot be undone. (y/N) `,`--force`)){R(`Cancelled.`);return}await n.secrets.delete(e),t.json?I({success:!0,deleted:e}):L(`Secret deleted: ${e}`)}),e}async function qu(e){if(e.value!==void 0&&e.valueStdin)throw Error(`Provide either a secret value argument or --value-stdin, not both`);let t=e.value??(e.valueStdin?await ni():await $r(e.prompt));if(!t.length)throw Error(e.valueStdin?`Secret value from stdin cannot be empty`:`Secret value cannot be empty`);return t}function Ju(){let e=new x(`skill`).description(`Print paths to shipped skill documentation`);return e.command(`path`).description(`Print the absolute path to the SKILL.md shipped with this CLI`).action(()=>{let e=A.dirname(et(import.meta.url)),t=A.resolve(e,`..`,`SKILL.md`);console.log(t)}),e}function Yu(){let e=new x(`snapshot`).description(`Manage snapshots`);return e.command(`create <sandbox-id-or-name>`).description(`Create a snapshot of a sandbox`).option(`--tags <tags...>`,`Tags for the snapshot`).option(`--no-wait`,`Return once the snapshot is accepted and print the operation to poll`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Creating snapshot...`);i.start();let a=await J(r,n,e);if(t.wait===!1){let e=await a.snapshot({tags:t.tags,wait:!1});i.stop(),ws(e.info,!!t.json);return}let o=await a.snapshot({tags:t.tags});i.stop(),t.json?I(o):(L(`Snapshot created: ${o.snapshotId}`),console.log(`Size: ${Xu(o.sizeBytes??0)}`))}),e.command(`list <sandbox-id-or-name>`).description(`List snapshots for a sandbox`).action(async(e,t)=>{let{context:n,client:r}=K(t),i=z(`Fetching snapshots...`);i.start();let a=await(await J(r,n,e)).listSnapshots();i.stop(),t.json?I(a):F(a.map(e=>({...e,size:Xu(e.sizeBytes??0)})),[{key:`snapshotId`,header:`ID`,width:24},{key:`createdAt`,header:`Created`,width:16},{key:`size`,header:`Size`,width:12},{key:`sandboxId`,header:`Sandbox`,width:20}])}),e.command(`restore <sandbox-id> <snapshot-id>`).description(`Create a new sandbox from a snapshot`).option(`--billing-owner <userId>`,`Platform user that pays for the restored sandbox. The API accepts this only from a first-party service key that is listed as a billing delegate, and refuses such a key that names no payer.`).action(async(e,t,n)=>{let{client:r}=K(n),i=z(`Restoring from snapshot...`);i.start();let a=await r.create({fromSnapshot:t,fromSandboxId:e,...n.billingOwner?{billingOwnerId:n.billingOwner}:{}});await a.waitFor(`running`,{timeoutMs:12e4}),i.stop(),n.json?I({sandboxId:a.id,restoredFrom:t,status:a.status}):(L(`New sandbox created: ${a.id}`),console.log(`Source snapshot: ${t}`))}),e.command(`revert <sandbox-id-or-name> <snapshot-id>`).description(`Revert an existing sandbox to a snapshot`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Reverting sandbox to snapshot...`);a.start();let o=await J(i,r,e),s=await o.revertToSnapshot(t);await o.refresh(),a.stop(),n.json?I({sandboxId:o.id,snapshotId:s.snapshotId,status:o.status}):(L(`Sandbox reverted: ${o.id}`),console.log(`Source snapshot: ${s.snapshotId}`))}),e.command(`delete <sandbox-id-or-name> <snapshot-id>`).description(`Delete a sandbox snapshot`).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Deleting snapshot...`);a.start();let o=await(await J(i,r,e)).deleteSnapshot(t);a.stop(),n.json?I({success:!0,sandboxId:e,snapshotId:t,outcome:o.outcome}):o.outcome===`already_absent`?L(`Snapshot already gone: ${t}`):L(`Snapshot deleted: ${t}`)}),e}function Xu(e){if(e===0)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`,`TB`],r=Math.floor(Math.log(e)/Math.log(t));return`${Number.parseFloat((e/t**r).toFixed(1))} ${n[r]}`}const Zu=`solve:device:secp256k1`,Qu=/^0x[0-9a-f]{64}$/i;function $u(e){return e&&Qu.test(e)?e:void 0}function ed(){let e=hn(Zu),t=$u(e.value);if(!(!t||e.source===`none`))return{account:ct(t),source:e.source}}function td(){let e=ed();if(e)return e;let t=st(),n=gn(Zu,t);return{account:ct(t),source:n}}function nd(e){let t=$u(hn(Zu).value);if(!t||ct(t).address!==e.account.address)throw Error(`The local Solve device key changed; it was not retired`);let n=`${Zu}:retired:${e.account.address.toLowerCase()}`;if(gn(n,t),hn(n).value!==t)throw Error(`The revoked device key could not be retired safely`);return vn(Zu),n}function rd(e){let t=e.create?td():ed();if(!t)throw Error("No Solve device signer found. Run `tangle solve account --create`");e.json?I({address:t.account.address,source:t.source}):B({Address:t.account.address,Source:t.source})}const id=/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;function ad(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function od(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`${t} must be an object`);return e}function sd(e,t,n=2048){if(typeof e!=`string`||!e.trim()||e.length>n)throw Error(`${t} is missing or invalid`);if(ad(e))throw Error(`${t} contains control characters`);return e.trim()}function cd(e,t){let n=sd(e,t,64).toLowerCase();if(!id.test(n))throw Error(`${t} must be a 40 or 64 character Git revision`);return n}function ld(e,t,n=!1){let r=typeof e==`number`&&Number.isSafeInteger(e)?String(e):sd(e,t,80);if(!/^\d+$/.test(r)||!n&&r===`0`)throw Error(`${t} must be an unsigned integer`);return BigInt(r).toString()}function ud(e,t){let n=sd(e,t,2048),r=new URL(n);if(r.protocol!==`https:`&&!(r.protocol===`http:`&&(r.hostname===`localhost`||r.hostname===`127.0.0.1`)))throw Error(`${t} must use HTTPS outside local development`);return n.replace(/\/$/,``)}function dd(e,t){let n=ud(e,t).replace(/\.git$/,``),r=new URL(n),i=r.pathname.split(`/`).filter(Boolean);if(r.hostname!==`github.com`||r.username||r.password||r.search||r.hash||i.length!==2)throw Error(`${t} must be an HTTPS GitHub repository URL`);return`https://github.com/${i.join(`/`)}`}function fd(e,t){let n=sd(e,t,42);if(!gt(n,{strict:!1}))throw Error(`${t} must be an EVM address`);return mt(n)}function pd(e,t){let n=ld(e,t),r=Number(n);if(!Number.isSafeInteger(r)||r<=0)throw Error(`${t} is out of range`);return r}function md(...e){for(let t of e)if(typeof t==`string`&&t.trim())return t.trim()}function hd(e){let t=e.trim().replace(/\.git$/,``);return t.startsWith(`git@github.com:`)?`https://github.com/${t.slice(15)}`:t.startsWith(`ssh://git@github.com/`)?`https://github.com/${t.slice(21)}`:t}function gd(e){if(e===void 0)return;let t=sd(e,`pull request URL`,2048);if(!/^https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/\d+(?:\/[^\s]*)?$/i.test(t))throw Error(`pull request URL must point to a GitHub pull request`);return t}function _d(e,t){if(!/^https:\/\/[^\s]+$/i.test(e)&&!/^\/(?!\/).*$/.test(e)&&!/^[a-z][a-z0-9+.-]*:[^\s]+$/i.test(e))throw Error(`${t} must be an HTTPS URL or an absolute repository path`);if(e.split(/[?#]/,1)[0].split(`/`).includes(`..`))throw Error(`${t} cannot contain parent-directory segments`);return e}function vd(e){return zn(`solve`,e.profile)}function yd(e){let t=vd(e),n=ar(void 0,t);if(!n)throw Error(`No Solve credential found for profile '${t}'. Run: tangle auth login --provider github --app solve`);return n}async function bd(e){let t=fr(e.apiUrl),n=await fetch(`${t}${e.path}`,{method:e.method??`GET`,headers:{Accept:`application/json`,...e.body===void 0?{}:{"Content-Type":`application/json`},Authorization:`Bearer ${yd(e)}`},...e.body===void 0?{}:{body:JSON.stringify(e.body)},signal:AbortSignal.timeout(3e4)}),r=await n.json().catch(()=>null);if(!n.ok||!r?.success||r.data===void 0){let e=r?.error?.message??`Solve API request failed with HTTP ${n.status}`;throw Error(r?.error?.code?`${r.error.code}: ${e}`:e)}return r.data}function xd(e){return bd({path:`/v1/wallet/challenges`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.purpose?{purpose:e.purpose}:{}}})}function Sd(e){return bd({path:`/v1/devices`,apiUrl:e.apiUrl,profile:e.profile})}function Cd(e){return bd({path:`/v1/devices/revoke`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.reason?{reason:e.reason}:{},...e.challengeId&&e.signature?{challengeId:e.challengeId,signature:e.signature}:{}}})}const wd={chainId:42431,rpcUrl:`https://rpc.moderato.tempo.xyz`,sponsorUrl:`https://drew-gtr-pro.taild10bfc.ts.net/solve-sponsor`,tangleAddress:`0xff137B9C879c47C28ce389e84501925438AB4cdA`,managerAddress:`0x5271732F893B622ac6793d6DBA5B2626CCa4EA14`,paymentAsset:`0x20C0000000000000000000000000000000000000`,blueprintId:15n,serviceId:9n,competitionId:1n,minStakeWei:0n};function Td(e,t){return e.toLowerCase()===t.toLowerCase()}function Ed(e){if(e.chainId!==wd.chainId)throw Error(`Solve submissions require Tempo Moderato (chain ${wd.chainId}); received ${e.chainId}`);if(e.rpcUrl!==wd.rpcUrl)throw Error(`Solve metadata RPC does not match the trusted deployment`);if(e.sponsorUrl!==wd.sponsorUrl)throw Error(`Solve metadata sponsor does not match the trusted deployment`);if(!Td(e.tangleAddress,wd.tangleAddress))throw Error(`Solve metadata Tangle contract does not match the trusted deployment`);if(!Td(e.managerAddress,wd.managerAddress))throw Error(`Solve metadata competition manager does not match the trusted deployment`);if(!Td(e.paymentAsset,wd.paymentAsset))throw Error(`Solve metadata payment asset does not match the trusted deployment`);if(e.blueprintId!==wd.blueprintId)throw Error(`Solve submissions require blueprint ${wd.blueprintId}; received ${e.blueprintId}`);if(e.serviceId!==wd.serviceId)throw Error(`Solve submissions require service ${wd.serviceId}; received ${e.serviceId}`);if(e.competitionId!==wd.competitionId)throw Error(`Solve submissions require competition ${wd.competitionId}; received ${e.competitionId}`);if(e.minStakeWei!==wd.minStakeWei)throw Error(`Solve submissions require zero stake for the trusted deployment`)}function Dd(e,t){let n=od(t.check??e.check,`competition.participation.check`),r=sd(n.command,`competition.participation.check.command`,512);if(!Array.isArray(n.args)||n.args.some(e=>typeof e!=`string`))throw Error(`competition.participation.check.args must be an array of strings`);let i=n.args.map(e=>sd(e,`competition checker argument`,2048)),a=md(n.result_file,n.resultFile),o=n.timeout_ms??n.timeoutMs,s=o===void 0?void 0:pd(o,`competition checker timeout`);return{command:r,args:i,...a?{result_file:a}:{},...s?{timeout_ms:s}:{}}}function Od(e){if(e.provenance===void 0)return;let t=od(e.provenance,`competition.participation.provenance`);if(t.mode!==`github_pull_request`)throw Error(`competition.participation.provenance.mode is unsupported`);if(t.required!==void 0&&typeof t.required!=`boolean`)throw Error(`competition.participation.provenance.required must be a boolean`);return{mode:`github_pull_request`,required:t.required===!0}}function kd(e){let t=od(e.chain??e.network??{},`competition.chain`),n=e.rewards&&typeof e.rewards==`object`&&!Array.isArray(e.rewards)?od(e.rewards,`competition.rewards`):{},r=n.minStake&&typeof n.minStake==`object`&&!Array.isArray(n.minStake)?od(n.minStake,`competition.rewards.minStake`).raw:void 0,i=md(t.minStakeWei,t.min_stake_wei,e.minStakeWei,e.min_stake_wei,r),a=t.chainId??t.chain_id??e.chainId??e.chain_id,o=md(t.chainName,t.chain_name,e.chainName,e.chain_name)??`Tempo`,s=md(t.nativeSymbol,t.native_symbol,e.nativeSymbol,e.native_symbol)??`TNT`,c=md(t.rpcUrl,t.rpc_url,e.rpcUrl,e.rpc_url,process.env.TANGLE_SOLVE_RPC_URL),l=md(t.sponsorUrl,t.sponsor_url,e.sponsorUrl,e.sponsor_url,process.env.TANGLE_SOLVE_SPONSOR_URL),u=md(t.tangleAddress,t.tangle_address,t.coreAddress,t.core_address,e.tangleAddress,e.tangle_address,e.coreAddress,e.core_address),d=md(t.managerAddress,t.manager_address,e.managerAddress,e.manager_address),f=md(t.paymentAsset,t.payment_asset,t.servicePaymentAsset,t.service_payment_asset,e.paymentAsset,e.payment_asset,e.servicePaymentAsset,e.service_payment_asset),p=md(t.blueprintId,t.blueprint_id,e.blueprintId,e.blueprint_id),m=md(t.serviceId,t.service_id,e.serviceId,e.service_id),h=md(t.competitionId,t.competition_id,e.competitionId,e.competition_id,e.id);if(!c||!l||!u||!d||!p||!m||!h||!i||a===void 0)throw Error(`Solve competition metadata must include complete Tempo chain configuration`);return{chainId:pd(a,`chain.chainId`),chainName:o,nativeSymbol:s,rpcUrl:ud(c,`chain.rpcUrl`),sponsorUrl:ud(l,`chain.sponsorUrl`),tangleAddress:fd(u,`chain.tangleAddress`),managerAddress:fd(d,`chain.managerAddress`),paymentAsset:fd(f??wd.paymentAsset,`chain.paymentAsset`),blueprintId:ld(p,`chain.blueprintId`),serviceId:ld(m,`chain.serviceId`),competitionId:ld(h,`chain.competitionId`,!0),minStakeWei:ld(i,`chain.minStakeWei`,!0)}}function Ad(e){let t=od(e,`competition`),n=od(t.participation??t.task,`competition.task`),r={...t,participation:{...n,...n.repositoryRevision===void 0&&n.revision!==void 0?{repositoryRevision:n.revision}:{}}},i=r.participation,a=dd(md(r.repository,r.repo_url,i.repository)??``,`competition.repository`),o=cd(md(r.repositoryRevision,r.repository_revision,i.revision,i.repositoryRevision,i.repository_revision),`competition.repositoryRevision`),s=sd(r.slug??r.id,`competition.slug`,128),c=sd(r.name??r.title??s,`competition.name`,256),l=Dd(r,i),u=Od(i);return{version:1,slug:s,title:c,repository:a,taskRevision:o,checker:l,chain:kd(r),...u?{provenance:u}:{}}}function jd(e){return{chainId:e.chain.chainId,chainName:e.chain.chainName,nativeSymbol:e.chain.nativeSymbol,rpcUrl:e.chain.rpcUrl,sponsorUrl:e.chain.sponsorUrl,tangleAddress:e.chain.tangleAddress,managerAddress:e.chain.managerAddress,paymentAsset:e.chain.paymentAsset,blueprintId:BigInt(e.chain.blueprintId),serviceId:BigInt(e.chain.serviceId),competitionId:BigInt(e.chain.competitionId),minStakeWei:BigInt(e.chain.minStakeWei)}}async function Md(e){let t=od(JSON.parse(await P.readFile(A.join(e,`.tangle-solve.json`),`utf8`)),`.tangle-solve.json`);if(t.version!==1)throw Error(`.tangle-solve.json has an unsupported version`);let n=od(t.checker,`.tangle-solve.json.checker`),r=od(t.chain,`.tangle-solve.json.chain`);return Ad({slug:t.slug,name:t.title,repository:t.repository,repositoryRevision:t.taskRevision,participation:{check:n,provenance:t.provenance},chain:r,competitionId:r.competitionId})}const Nd=Ye(Se),Pd=`.tangle-solve-run.json`,Fd=`.tangle-solve.json`,Id=`tangle.solve.manifestSha256`,Ld=new Set([Fd,Pd]),Rd=`upstream`;async function zd(e,t){let n=await Nd(`git`,[`-C`,e,...t],{encoding:`utf8`,maxBuffer:1e6});return String(n.stdout).trim()}async function Bd(e,t){let n=A.resolve(t??process.cwd()),r=await Md(n);if(e&&e!==r.slug&&e!==r.chain.competitionId)throw Error(`This directory contains '${r.slug}', not '${e}'`);return{root:n,manifest:r}}async function Vd(e){let t=A.join(e,Fd),n;try{n=await P.lstat(t)}catch{throw Error(`${Fd} is missing`)}if(n.isSymbolicLink()||!n.isFile())throw Error(`${Fd} must be a regular file`);return C(`sha256`).update(await P.readFile(t)).digest(`hex`)}async function Hd(e){let t=await Vd(e);return await zd(e,[`config`,`--local`,`--replace-all`,Id,t]),t}async function Ud(e){let t;try{t=await zd(e,[`config`,`--local`,`--get`,Id])}catch{throw Error(`The local Git metadata has no ${Id} pin; run tangle solve clone again`)}if(!/^[0-9a-f]{64}$/i.test(t))throw Error(`The local ${Id} pin is invalid`);if(await Vd(e)!==t.toLowerCase())throw Error(`${Fd} changed after clone; run tangle solve clone again`)}async function Wd(e,t){try{return await zd(e,[`ls-files`,`--error-unmatch`,`--`,t]),!0}catch{return!1}}async function Gd(e){await Ud(e);for(let t of Ld)if(await Wd(e,t))throw Error(`${t} must remain untracked and local to this Solve workspace`);let t=await Nd(`git`,[`-C`,e,`status`,`--porcelain=v1`,`--untracked-files=all`,`--ignored=matching`],{encoding:`utf8`,maxBuffer:1e6});if(String(t.stdout).split(/\r?\n/).filter(Boolean).filter(e=>{let t=e.slice(0,2),n=e.slice(3);return!((t===`??`||t===`!!`)&&Ld.has(n))}).length>0)throw Error(`Commit the candidate before running Solve. Only the local manifest and run record may remain uncommitted.`);return cd(await zd(e,[`rev-parse`,`HEAD`]),`submission revision`)}async function Kd(e,t,n,r={}){let i=await qd(e,t,r);if(i)return{taskRepository:t.repository,taskRevision:t.taskRevision,submissionRepository:i,submissionRevision:n}}async function qd(e,t,n={}){let r;try{r=hd(await zd(e,[`config`,`--get`,`remote.origin.pushurl`]))}catch{try{r=hd(await zd(e,[`config`,`--get`,`remote.origin.url`]))}catch{if(n.allowMissing)return;throw Error(`Add your GitHub fork as the 'origin' remote before submitting. The task repository is available as '${Rd}'.`)}}let i=dd(r,`git remote.origin.url`);if(i.toLowerCase()===t.repository.toLowerCase()){if(n.allowMissing)return;throw Error(`The 'origin' remote is the task repository. Add your GitHub fork as 'origin'; keep the task repository as '${Rd}' before submitting.`)}return i}function Jd(e,t){return!e||!t?!1:e.taskRepository.toLowerCase()===t.taskRepository.toLowerCase()&&e.taskRevision.toLowerCase()===t.taskRevision.toLowerCase()&&e.submissionRepository.toLowerCase()===t.submissionRepository.toLowerCase()&&e.submissionRevision.toLowerCase()===t.submissionRevision.toLowerCase()}function Yd(e,t){return`${e}/commit/${t}`}function Xd(e,t,n,r,i={}){let a=e.evidenceRefs.map(e=>_d(e.trim(),`checker evidence reference`));if(n){if(!t){if(i.allowMissingSource)return{evidence:e.evidence,evidenceRefs:a};throw Error(`Provenance policy requires a submission source`)}let o=gd(r);if(n.required&&(i.requirePullRequest??!0)&&!o)throw Error(`This competition requires a GitHub pull request`);a.push(Yd(t.taskRepository,t.taskRevision),Yd(t.submissionRepository,t.submissionRevision),...o?[o]:[])}return{evidence:e.evidence,evidenceRefs:[...new Set(a)]}}async function Zd(e,t){let n=`${e}.${process.pid}.tmp`;await P.writeFile(n,`${JSON.stringify(t,null,2)}\n`,{mode:384}),await P.rename(n,e)}async function Qd(e){let t=JSON.parse(await P.readFile(A.join(e,Pd),`utf8`));if(t.version!==1||typeof t.competition!=`string`)throw Error(`${Pd} has an unsupported format`);return t}async function $d(e){let t=gd(e.pullRequest);if(!t)throw Error(`A pull request URL is required`);let n=new URL(t).pathname.split(`/`).filter(Boolean),r=await fetch(`https://api.github.com/repos/${n[0]}/${n[1]}/pulls/${n[3]}`,{headers:{Accept:`application/vnd.github+json`,"User-Agent":`tangle-solve-cli`},signal:AbortSignal.timeout(15e3)}),i=await r.json().catch(()=>null),a=e=>e.replace(/\/$/,``).toLowerCase();if(!r.ok||a(i?.base?.repo?.html_url??``)!==a(e.taskRepository)||i?.head?.sha?.toLowerCase()!==e.submissionRevision.toLowerCase()||a(i?.head?.repo?.html_url??``)!==a(e.submissionRepository))throw Error(`GitHub pull request must target the pinned task repository and contain the current committed submission`)}function ef(e){return{...e.authorization?{authorization:e.authorization}:{},...e.stake?{stake:e.stake}:{},join:e.join,commit:e.commit,reveal:e.reveal,report:e.report,evaluation:e.evaluation}}const tf=Ye(Se);function nf(){return`Task source is '${Rd}'. Add your fork as 'origin', commit your candidate, push it, and open a pull request before submitting.`}async function rf(e,t,n){try{let r=od(await bd({path:`/v1/competitions/${encodeURIComponent(e)}`,apiUrl:n.apiUrl,profile:n.profile}),`competition response`),i=Ad(r.competition??r),a=A.resolve(t??i.slug),o=z(`Cloning ${i.slug}…`);n.json||o.start();try{await tf(`git`,[`clone`,`--no-tags`,`--origin`,Rd,i.repository,a],{encoding:`utf8`,maxBuffer:1e6}),await zd(a,[`checkout`,`--detach`,i.taskRevision]);let e=await zd(a,[`rev-parse`,`HEAD`]);if(e.toLowerCase()!==i.taskRevision.toLowerCase())throw Error(`Pinned checkout resolved to ${e}, expected ${i.taskRevision}`);await Zd(A.join(a,`.tangle-solve.json`),i),await Hd(a)}finally{o.stop()}n.json?I({competition:i,directory:a}):(L(`Cloned ${i.slug} at ${i.taskRevision.slice(0,12)}`),i.provenance&&R(nf()),R(`Run the pinned checker with: cd ${a} && tangle solve run`))}catch(e){U(e)}}const af=12e4,of=yt(`event JobSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint8 jobIndex, address caller, bytes inputs)`),sf=yt(`event JobCompleted(uint64 indexed serviceId, uint64 indexed callId)`),cf=yt(`event JobResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, address indexed operator, bytes result)`),lf=yt(`event AggregatedResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint256 signerBitmap, bytes output)`),uf=yt(`event EvaluationAccepted(uint64 indexed serviceId, uint64 indexed competitionId, address indexed researcher, bytes32 candidateId, bytes32 submissionRefHash, bytes32 evaluationDigest, bytes32 metricsHash, bytes32 evidenceRefsHash)`),df=[...vt([`function submitJob(uint64 serviceId, uint8 jobIndex, bytes inputs) payable returns (uint64 callId)`,`function getJobEventRate(uint64 blueprintId, uint8 jobIndex) view returns (uint256 rate)`,`function getServicePaymentAsset(uint64 serviceId) view returns (address)`,`function isPermittedCaller(uint64 serviceId, address caller) view returns (bool)`]),of,sf,cf,lf],ff=vt([`function authorizeSelf(uint64 serviceId)`,`function revokeSelf(uint64 serviceId)`,`function isDeviceRevoked(address device) view returns (bool)`,`function postStake(uint64 serviceId, uint64 competitionId) payable`,`function stakes(uint64 serviceId, uint64 competitionId, address researcher) view returns (uint256)`,`function pendingResults(uint64 serviceId, uint64 jobCallId) view returns (uint8 job, bytes32 outputHash, uint256 signerBitmap, bool exists, bool executed)`,`function executePendingResult(uint64 serviceId, uint64 jobCallId, bytes output)`,`function acceptedCandidates(uint64 serviceId, uint64 competitionId, address researcher, bytes32 candidateId) view returns (bool)`]),pf=vt([`function allowance(address owner, address spender) view returns (uint256)`,`function approve(address spender, uint256 amount) returns (bool)`]),mf=bt(`uint64 competitionId, uint256 stakeWei`),hf=bt(`uint64 competitionId, bytes32 commitment`),gf=bt(`uint64 competitionId, bytes32 commitment, string artifactRef, bytes32 salt`),_f=bt(`string artifactRef, bytes32 salt`),vf=bt(`uint64 competitionId, bytes32 candidateId, string submissionRef, string evidenceJson, string evidenceRefsJson`),yf=bt(`string status, string detail`),bf=/^0x[0-9a-f]{64}$/i;function xf(e,t){if(e!==t)throw Error(`Tempo RPC returned chain ${e}; expected ${t}`)}function Sf(e,t,n){return{...e,feePayer:!0,nonceKey:t,nonce:n}}function Cf(e,t){if(e!==`success`)throw Error(`${t} transaction reverted`)}function wf(e,t,n,r){if(!bf.test(t))throw Error(`${n} transaction hash is invalid`);if(typeof e.transactionHash!=`string`||e.transactionHash.toLowerCase()!==t.toLowerCase())throw Error(`${n} receipt hash does not match the saved transaction`);if(Cf(e.status??``,n),typeof e.from!=`string`||e.from.toLowerCase()!==r.from.toLowerCase())throw Error(`${n} receipt sender does not match the Solve device`);if(typeof e.to!=`string`||e.to.toLowerCase()!==r.to.toLowerCase())throw Error(`${n} receipt destination does not match the expected contract`)}function Tf(e,t){return e>=t?[]:e>0n?[0n,t]:[t]}function Ef(e,t,n=Date.now()){return n>=e+t}function Df(e,t){return e.filter(e=>e.args?.candidateId?.toLowerCase()===t.toLowerCase()).at(-1)?.transactionHash}function Of(e,t,n,r,i){for(let a of e.logs)if(a.address.toLowerCase()===t.tangleAddress.toLowerCase())try{let e=ft({abi:[of],eventName:`JobSubmitted`,data:a.data,topics:a.topics});if(e.args.serviceId===t.serviceId&&e.args.jobIndex===n&&e.args.caller.toLowerCase()===r.toLowerCase()&&(!i||e.args.inputs.toLowerCase()===i.toLowerCase()))return e.args.callId}catch{}throw Error(`Tangle did not emit job ${n} for ${r}`)}function kf(e,t,n,r){for(let i of e.logs)if(i.address.toLowerCase()===t.managerAddress.toLowerCase())try{let e=ft({abi:[uf],eventName:`EvaluationAccepted`,data:i.data,topics:i.topics}).args;if(e.serviceId===t.serviceId&&e.competitionId===t.competitionId&&e.researcher.toLowerCase()===n.address.toLowerCase()&&e.candidateId.toLowerCase()===r.toLowerCase())return!0}catch{}return!1}function Af(e){if(e.chainId!==Ct.id)throw Error(`Solve submissions require Tempo Moderato (chain ${Ct.id}); received ${e.chainId}`);if(!e.sponsorUrl)throw Error(`Solve submissions require a Tempo sponsor relay URL; unsponsored writes are disabled`);return{...Ct,name:e.chainName,nativeCurrency:{name:e.nativeSymbol,symbol:e.nativeSymbol,decimals:18},rpcUrls:{default:{http:[e.rpcUrl]}}}}async function jf(e,t){Ed(e);let n=Af(e),r=lt({chain:n,transport:ht(e.rpcUrl)});return xf(await r.getChainId(),e.chainId),await Mf({publicClient:r},e),{publicClient:r,walletClient:ut({account:t,chain:n,transport:Tt(ht(e.rpcUrl),ht(e.sponsorUrl))}),account:t}}async function Mf(e,t){let n=await e.publicClient.readContract({address:t.tangleAddress,abi:df,functionName:`getServicePaymentAsset`,args:[t.serviceId]});if(n.toLowerCase()!==t.paymentAsset.toLowerCase())throw Error(`Tempo service payment asset ${n} does not match the trusted Solve asset ${t.paymentAsset}`)}async function Nf(e,t,n){let[r,i]=await Promise.all([e.publicClient.readContract({address:t.tangleAddress,abi:df,functionName:`getJobEventRate`,args:[t.blueprintId,n]}),e.publicClient.readContract({address:t.tangleAddress,abi:df,functionName:`getServicePaymentAsset`,args:[t.serviceId]})]);if(i.toLowerCase()!==t.paymentAsset.toLowerCase())throw Error(`Tempo job payment asset ${i} does not match the trusted Solve asset ${t.paymentAsset}`);return{asset:i,amount:r,value:i===`0x0000000000000000000000000000000000000000`?r:0n}}async function Pf(e,t,n){return await e.publicClient.readContract({address:t,abi:pf,functionName:`allowance`,args:[e.account.address,n.tangleAddress]})}async function Ff(e,t,n,r,i,a){let o=Date.now();for(;!Ef(o,a);){if((await e.publicClient.getLogs({address:t.tangleAddress,event:sf,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`})).length>0){let a=(await e.publicClient.getLogs({address:t.tangleAddress,event:cf,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`}))[0]?.args.result;if(!a)throw Error(`Tangle job ${n} completed without a result`);let[o,s]=dt(yf,a);if(o!==i)throw Error(`Tangle job ${n} ${o}: ${s}`);return{status:o,detail:s}}await new Promise(e=>setTimeout(e,1e3))}throw Error(`Tangle job ${n} did not complete within 120 seconds`)}async function If(e,t,n,r,i){let a=Date.now();for(;!Ef(a,i);){let i=(await e.publicClient.getLogs({address:t.tangleAddress,event:lf,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`}))[0]?.args.output;if(i)return i;await new Promise(e=>setTimeout(e,1e3))}throw Error(`Tangle job ${n} did not produce an aggregate within 120 seconds`)}async function Lf(e,t,n){return!!await e.publicClient.readContract({address:t.managerAddress,abi:ff,functionName:`acceptedCandidates`,args:[t.serviceId,t.competitionId,e.account.address,n]})}const Rf=BigInt(_t(xt(`tangle.solve.v1`)));async function zf(e,t){let n=await wt.nonce.getNonce(e.publicClient,{account:e.account.address,nonceKey:Rf});if(n>BigInt(2**53-1))throw Error(`The Solve transaction nonce exceeds the safe range`);return e.walletClient.writeContract(Sf(t,Rf,Number(n)))}async function Bf(e,t,n,r){if(!await e.publicClient.readContract({address:t.tangleAddress,abi:df,functionName:`isPermittedCaller`,args:[t.serviceId,e.account.address]}))try{let i=r??await zf(e,{address:t.managerAddress,abi:ff,functionName:`authorizeSelf`,args:[t.serviceId]});if(r||await n?.(`authorization`,i),wf(await e.publicClient.waitForTransactionReceipt({hash:i}),i,`Authorization`,{from:e.account.address,to:t.managerAddress}),!await e.publicClient.readContract({address:t.tangleAddress,abi:df,functionName:`isPermittedCaller`,args:[t.serviceId,e.account.address]}))throw Error(`authorization transaction did not add the device`);return i}catch(e){let t=e instanceof Error?e.message:`unknown chain error`;throw Error(`The competition manager did not authorize this device. The deployed manager must expose authorizeSelf(uint64): ${t}`)}}async function Vf(e,t){let n=await zf(e,{address:t.managerAddress,abi:ff,functionName:`revokeSelf`,args:[t.serviceId]});return wf(await e.publicClient.waitForTransactionReceipt({hash:n}),n,`Revocation`,{from:e.account.address,to:t.managerAddress}),n}async function Hf(e,t,n,r,i=`allowance`,a={}){if(t.amount===0n||t.asset===`0x0000000000000000000000000000000000000000`)return;let o=await Pf(e,t.asset,n);for(let s of Tf(o,t.amount)){let o=s===0n?`${i}:reset`:`${i}:approval`,c=a[o];if(c){if(wf(await e.publicClient.waitForTransactionReceipt({hash:c}),c,s===0n?`ERC-20 allowance reset`:`ERC-20 allowance approval`,{from:e.account.address,to:t.asset}),await Pf(e,t.asset,n)!==s)throw Error(`${s===0n?`ERC-20 allowance reset`:`ERC-20 allowance approval`} did not set the expected allowance`);continue}let l=await zf(e,{address:t.asset,abi:pf,functionName:`approve`,args:[n.tangleAddress,s]});await r?.(o,l),wf(await e.publicClient.waitForTransactionReceipt({hash:l}),l,s===0n?`ERC-20 allowance reset`:`ERC-20 allowance approval`,{from:e.account.address,to:t.asset})}}async function Uf(e,t,n,r,i,a=`job:${n}`,o={}){let s=await Nf(e,t,n);await Hf(e,s,t,i,`allowance:${a}`,o);let c=o[a],l=c??await zf(e,{address:t.tangleAddress,abi:df,functionName:`submitJob`,args:[t.serviceId,n,r],value:s.value});c||await i?.(a,l);let u=await e.publicClient.waitForTransactionReceipt({hash:l});return wf(u,l,`Job ${n}`,{from:e.account.address,to:t.tangleAddress}),{hash:l,callId:Of(u,t,n,e.account.address,r),blockNumber:u.blockNumber}}async function Wf(e,t,n,r,i,a,o=`job:${n}`,s={}){let c=await Uf(e,t,n,r,a,o,s),l=await Ff(e,t,c.callId,c.blockNumber,i,af);return{...c,acknowledgement:l}}const Gf={...wd,chainName:`Tempo Moderato`,nativeSymbol:`TNT`},Kf={async read(e){let t=lt({chain:Ct,transport:ht(Gf.rpcUrl,{timeout:15e3})}),n=e=>e.catch(()=>null),r=await Promise.all(e.map(async e=>{let[r,i]=await Promise.all([n(t.readContract({address:Gf.tangleAddress,abi:df,functionName:`isPermittedCaller`,args:[Gf.serviceId,e]})),n(t.readContract({address:Gf.managerAddress,abi:ff,functionName:`isDeviceRevoked`,args:[e]}))]);return[e.toLowerCase(),{permitted:r,revoked:i}]}));return new Map(r)},async revokeSelf(e){return Vf(await jf(Gf,e),Gf)}},qf={permitted:null,revoked:null};function Jf(e){return e.revoked?`revoked`:e.permitted===null?`unknown`:e.permitted?`permitted`:`not permitted`}async function Yf(e,t=Kf){try{let{devices:n}=await Sd({apiUrl:e.apiUrl,profile:e.profile}),r=ed()?.account.address.toLowerCase(),i=n.map(e=>({...e,local:e.address===r,status:e.revokedAt?`revoked`:`active`}));r&&!i.some(e=>e.local)&&i.push({address:r,local:!0,status:`unbound`,boundAt:null,lastUsedAt:null,revokedAt:null,revocationMethod:null,revocationReason:null});let a=await t.read(i.map(e=>mt(e.address))),o=i.map(e=>({...e,onChain:a.get(e.address)??qf}));if(e.json){I({serviceId:Gf.serviceId.toString(),devices:o});return}Vt([`Address`,`Status`,`Local`,`Service ${Gf.serviceId}`,`Last used`,`Revoked`],o.map(e=>[e.address,e.status,e.local?`yes`:``,Jf(e.onChain),e.lastUsedAt??``,e.revokedAt?`${e.revokedAt} (${e.revocationMethod})`:``]))}catch(t){U(t,e.json)}}async function Xf(e,t,n=Kf){try{if(!gt(e))throw Error(`${e} is not an EVM address`);let r=mt(e),i=ed(),a=i?.account.address===r;if(!t.yes){if(!process.stdin.isTTY)throw Error(`Revoking a device is permanent. Re-run with --yes to confirm`);if(!await ei(`Permanently revoke Solve device ${r}${a?` (this machine's device)`:``}? [y/N] `,`--yes`)){R(`Revocation cancelled`);return}}let o;if(i&&a){let e=await xd({deviceAddress:r,purpose:`revoke`,apiUrl:t.apiUrl,profile:t.profile});o={challengeId:e.challengeId,signature:await i.account.signMessage({message:e.message})}}let s=await Cd({deviceAddress:r,reason:t.reason,...o,apiUrl:t.apiUrl,profile:t.profile}),c=r.toLowerCase(),l=(await n.read([r])).get(c)??qf,u;if(i&&a&&!l.revoked){try{u=await n.revokeSelf(i.account)}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`The Solve API revoked ${r}, but the on-chain revocation failed and the local key was kept: ${t}. Run the command again to retry`)}l=(await n.read([r])).get(c)??qf}let d=i&&a&&l.revoked?nd(i):void 0;if(t.json){I({...s,serviceId:Gf.serviceId.toString(),onChain:l,...u?{revocationTransaction:u}:{},localKeyRetired:!!d});return}L(s.alreadyRevoked?`${r} was already revoked in the Solve API`:`Revoked ${r}; the Solve API refuses its signatures`),u&&L(`Revoked on Tempo in ${u}; service ${Gf.serviceId} refuses its jobs`),d&&R("The local device key was moved aside because its address may still hold stake or rewards. Run `tangle solve account --create` for a new device"),!a&&l.permitted&&It(`The device can still submit jobs to service ${Gf.serviceId}. Only its key, or the Solve blueprint owner, can revoke it on chain`)}catch(e){U(e,t.json)}}function Zf(e,t){return _t(pt(_f,[e.trim(),t]))}function Qf(e){let t=/^submission=(\S+)/.exec(e);if(!t?.[1])throw Error(`COMMIT_CANDIDATE did not return a submission reference`);return t[1]}async function $f(e,t,n,r,i){let a=i.resumeTransactions?.evaluation;if(a){let n=await e.publicClient.waitForTransactionReceipt({hash:a});if(wf(n,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!kf(n,t,e.account,r))throw Error(`Saved evaluation transaction did not emit EvaluationAccepted for this candidate`);return a}let o=Date.now();for(;!Ef(o,af);){if(await Lf(e,t,r)){let i=Df(await e.publicClient.getLogs({address:t.managerAddress,event:uf,args:{serviceId:t.serviceId,competitionId:t.competitionId,researcher:e.account.address},fromBlock:n.blockNumber,toBlock:`latest`}),r);if(i)return i;throw Error(`Candidate is already accepted, but its EvaluationAccepted transaction is unavailable`)}let[a,o,,s,c]=await e.publicClient.readContract({address:t.managerAddress,abi:ff,functionName:`pendingResults`,args:[t.serviceId,n.callId]});if(s&&a!==4)throw Error(`Manager pending result ${n.callId} has unexpected job ${a}`);if(s&&c)throw Error(`Manager executed the report without EvaluationAccepted`);if(s&&!c){if(o.toLowerCase()!==_t(n.output).toLowerCase())throw Error(`Manager pending report output does not match the aggregate`);let a=await zf(e,{address:t.managerAddress,abi:ff,functionName:`executePendingResult`,args:[t.serviceId,n.callId,n.output]});await i.onTransaction?.(`evaluation`,a);let s=await e.publicClient.waitForTransactionReceipt({hash:a});if(wf(s,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!kf(s,t,e.account,r))throw Error(`Evaluation transaction did not emit EvaluationAccepted for this candidate`);return a}await new Promise(e=>setTimeout(e,1e3))}throw Error(`Manager did not emit EvaluationAccepted within 120 seconds`)}async function ep(e,t,n,r={}){if(Ed(e),!/^0x[0-9a-f]{64}$/i.test(n.salt))throw Error(`Reveal salt must be bytes32`);if(!n.artifactRef.trim())throw Error(`Candidate reference is required`);if(!n.evidenceJson.trim()||n.evidenceRefs.length===0)throw Error(`Checker evidence is required`);let i=await jf(e,t),a=await Bf(i,e,r.onTransaction,r.resumeTransactions?.authorization),o,s=await i.publicClient.readContract({address:e.managerAddress,abi:ff,functionName:`stakes`,args:[e.serviceId,e.competitionId,i.account.address]});s<e.minStakeWei&&(o=await zf(i,{address:e.managerAddress,abi:ff,functionName:`postStake`,args:[e.serviceId,e.competitionId],value:e.minStakeWei-s}),await r.onTransaction?.(`stake`,o),wf(await i.publicClient.waitForTransactionReceipt({hash:o}),o,`Stake`,{from:i.account.address,to:e.managerAddress}));let c=Zf(n.artifactRef,n.salt),l=pt(mf,[e.competitionId,e.minStakeWei]),u=pt(hf,[e.competitionId,c]),d=pt(gf,[e.competitionId,c,n.artifactRef.trim(),n.salt]),f=await Wf(i,e,1,l,`joined`,r.onTransaction,`join`,r.resumeTransactions),p=await Wf(i,e,2,u,`committed`,r.onTransaction,`commit`,r.resumeTransactions),m=Qf(p.acknowledgement.detail),h=await Wf(i,e,3,d,`revealed`,r.onTransaction,`reveal`,r.resumeTransactions),g=await Uf(i,e,4,pt(vf,[e.competitionId,c,m,n.evidenceJson,JSON.stringify(n.evidenceRefs)]),r.onTransaction,`report`,r.resumeTransactions),_=await If(i,e,g.callId,g.blockNumber,af),v=await $f(i,e,{callId:g.callId,output:_,blockNumber:g.blockNumber},c,r);return{address:i.account.address,...a?{authorization:a}:{},...o?{stake:o}:{},join:f.hash,commit:p.hash,reveal:h.hash,report:g.hash,evaluation:v,candidateId:c,submissionRef:m}}const tp=Ye(Se),np=`/usr/bin/bwrap`,rp=[`/usr`,`/bin`,`/sbin`,`/lib`,`/lib64`];function ip(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function ap(e,t){if(!e||e.length>2048||ip(e))throw Error(`${t} contains invalid control characters or is too long`)}function op(e,t){let n=t;for(;n<e.length&&/\s/.test(e[n]??``);)n+=1;return n}function sp(e,t){if(e[t]!==`"`)throw Error(`Checker output must be valid JSON`);let n=t+1;for(;n<e.length;){let t=e[n];if(t===`\\`){n+=2;continue}if(t===`"`)return n+1;if((t?.charCodeAt(0)??0)<32)throw Error(`Checker output must be valid JSON`);n+=1}throw Error(`Checker output must be valid JSON`)}function cp(e,t,n){let r=new Set,i=op(e,t+1);if(e[i]===`}`)return i+1;for(;i<e.length;){let t=sp(e,i),a=JSON.parse(e.slice(i,t));if(r.has(a))throw Error(`Checker output must not contain duplicate object keys`);if(r.add(a),i=op(e,t),e[i]!==`:`)throw Error(`Checker output must be valid JSON`);let o=op(e,i+1),s=up(e,o);if(n?.(a,o,s),i=op(e,s),e[i]===`}`)return i+1;if(e[i]!==`,`)throw Error(`Checker output must be valid JSON`);i=op(e,i+1)}throw Error(`Checker output must be valid JSON`)}function lp(e,t){let n=op(e,t+1);if(e[n]===`]`)return n+1;for(;n<e.length;){if(n=op(e,up(e,n)),e[n]===`]`)return n+1;if(e[n]!==`,`)throw Error(`Checker output must be valid JSON`);n=op(e,n+1)}throw Error(`Checker output must be valid JSON`)}function up(e,t){if(e[t]===`"`)return sp(e,t);if(e[t]===`{`)return cp(e,t);if(e[t]===`[`)return lp(e,t);let n=t;for(;n<e.length&&!/[\s,\]}]/.test(e[n]??``);)n+=1;return n}function dp(e){let t=e.trim();if(op(t,up(t,0))!==t.length)throw Error(`Checker output must be valid JSON`)}function fp(e,t){let n=e.trim();if(n[0]!==`{`)return;let r;return cp(n,0,(e,i,a)=>{e===t&&(r=n.slice(i,a).trim())}),r}function pp(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Checker output must be one JSON object`)}if(dp(e),!t||typeof t!=`object`||Array.isArray(t))throw Error(`Checker output must be a JSON object`);let n=t,r=n.candidate_ref;if(typeof r!=`string`||!r.trim())throw Error(`Checker output must include candidate_ref`);let i=r.trim(),a=n.evidence_refs;if(!Array.isArray(a)||a.length===0||a.some(e=>typeof e!=`string`||!e.trim()))throw Error(`Checker output must include a non-empty evidence_refs array`);ap(i,`candidate_ref`);for(let e of a)ap(e.trim(),`evidence_refs`);if(!n.evidence_json||typeof n.evidence_json!=`object`||Array.isArray(n.evidence_json))throw Error(`Checker output must include an evidence_json object`);let o={...n.evidence_json},s=fp(e,`evidence_json`);if(!s)throw Error(`Checker evidence_json source text is missing`);if(o.candidate_ref!==i)throw Error(`Checker evidence_json candidate_ref must match candidate_ref`);return{candidateRef:i,evidenceRefs:a.map(e=>e.trim()),evidence:o,evidenceJson:s}}async function mp(e,t,n){let r=n.trim();if(r.startsWith(`{`)&&r.endsWith(`}`)||!t.result_file)return r;let i=await bp(e),a=A.resolve(i,t.result_file),o=A.relative(i,a);if(o.startsWith(`..`)||A.isAbsolute(o))throw Error(`Checker result_file must stay inside the competition repository`);let s;try{s=await P.lstat(a)}catch{throw Error(`Checker result_file must be an existing regular file inside the competition repository`)}if(s.isSymbolicLink())throw Error(`Checker result_file must not be a symbolic link`);if(!s.isFile())throw Error(`Checker result_file must be an existing regular file inside the competition repository`);let c;try{c=await P.realpath(a)}catch{throw Error(`Checker result_file must resolve to a regular file inside the competition repository`)}let l=A.relative(i,c);if(l.startsWith(`..`)||A.isAbsolute(l))throw Error(`Checker result_file must stay inside the competition repository`);return(await P.readFile(c,`utf8`)).trim()}function hp(e,t){let n=A.relative(e,t);return n===``||!n.startsWith(`..`)&&!A.isAbsolute(n)}function gp(e){return rp.some(t=>hp(t,e))}async function _p(e,t,n){let r=e.includes(`/`)?[A.resolve(t,e)]:(process.env.PATH??``).split(A.delimiter).filter(Boolean).map(t=>A.join(t,e));for(let i of r){let r;try{r=await P.realpath(i),await P.access(r,P.constants.X_OK)}catch{continue}if(!hp(t,r)&&!gp(r)&&r!==n)throw Error(`Checker executable '${e}' must resolve inside the competition repository or a trusted runtime directory`);return r}throw Error(`Checker executable '${e}' was not found`)}async function vp(e){let t=[];for(let n of e)try{(await P.stat(n)).isDirectory()&&t.push(n)}catch{}return t}async function yp(e){let t=await P.realpath(be.homedir());if(e===A.parse(e).root||e===t)throw Error(`Solve checker repository must be a dedicated directory, not the filesystem or home root`)}async function bp(e){let t=await P.realpath(e);return await yp(t),t}async function xp(e){let t=A.join(e,`.git`),n;try{n=await P.lstat(t)}catch{return}if(n.isSymbolicLink())throw Error(`Solve checker repository .git must not be a symbolic link`);if(!n.isDirectory()&&!n.isFile())return;let r;try{let t={...process.env};for(let e of[`GIT_DIR`,`GIT_WORK_TREE`,`GIT_INDEX_FILE`,`GIT_OBJECT_DIRECTORY`,`GIT_ALTERNATE_OBJECT_DIRECTORIES`,`GIT_COMMON_DIR`,`GIT_CONFIG_COUNT`,`GIT_CONFIG_PARAMETERS`])delete t[e];let n=await tp(`/usr/bin/git`,[`-C`,e,`rev-parse`,`--verify`,`HEAD^{commit}`],{encoding:`utf8`,maxBuffer:1e5,env:{...t,GIT_CONFIG_GLOBAL:`/dev/null`,GIT_CONFIG_SYSTEM:`/dev/null`,GIT_CONFIG_NOSYSTEM:`1`,GIT_TERMINAL_PROMPT:`0`}}),i=String(n.stdout).trim();/^[0-9a-f]{40}$/i.test(i)&&(r=i.toLowerCase())}catch{}return{kind:n.isDirectory()?`directory`:`file`,...r?{commit:r}:{}}}async function Sp(e,t,n){let r=await bp(e);if(process.platform!==`linux`)throw Error(`Solve checkers require the Linux sandbox runtime (bubblewrap) with network isolation`);try{await P.access(np,P.constants.X_OK)}catch{throw Error(`Solve checkers require /usr/bin/bwrap; install bubblewrap or run the checker in a Tangle sandbox`)}let i=await _p(t,r,await P.realpath(process.execPath)),a=await xp(r),o=(await vp(rp)).flatMap(e=>[`--ro-bind`,e,e]),s=hp(r,i)?`/work/${A.relative(r,i)}`:gp(i)?i:`/checker/node`;!hp(r,i)&&!gp(i)&&o.push(`--ro-bind`,i,`/checker/node`);let c=a?.kind===`directory`?[`--tmpfs`,`/work/.git`]:a?.kind===`file`?[`--ro-bind`,`/dev/null`,`/work/.git`]:[];return{executable:np,args:[`--die-with-parent`,`--new-session`,`--unshare-all`,`--clearenv`,...o,`--proc`,`/proc`,`--dev`,`/dev`,`--tmpfs`,`/tmp`,`--dir`,`/tmp/home`,`--bind`,r,`/work`,...c,`--chdir`,`/work`,`--setenv`,`HOME`,`/tmp/home`,...a?.commit?[`--setenv`,`TANGLE_SOLVE_COMMIT`,a.commit]:[],`--setenv`,`TMPDIR`,`/tmp`,`--setenv`,`PATH`,`/checker:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`,`--setenv`,`LANG`,`C.UTF-8`,`--setenv`,`PYTHONDONTWRITEBYTECODE`,`1`,`--setenv`,`XDG_CONFIG_HOME`,`/tmp/home/.config`,`--setenv`,`XDG_CACHE_HOME`,`/tmp/home/.cache`,`--setenv`,`XDG_DATA_HOME`,`/tmp/home/.local/share`,`--setenv`,`GIT_CONFIG_GLOBAL`,`/dev/null`,`--setenv`,`GIT_CONFIG_SYSTEM`,`/dev/null`,`--setenv`,`NPM_CONFIG_USERCONFIG`,`/dev/null`,s,...n]}}async function Cp(e,t){if(!t.command||t.command.includes(`/../`)||ip(t.command))throw Error(`The competition checker command is invalid`);if(!Array.isArray(t.args))throw Error(`The competition checker arguments must be an array`);for(let e of t.args)ap(e,`Checker argument`);let n=t.timeout_ms??15*6e4;if(!Number.isSafeInteger(n)||n<1e3||n>60*6e4)throw Error(`Checker timeout must be between one second and one hour`);let r=await bp(e),i;try{let e=await Sp(r,t.command,t.args);i=await tp(e.executable,e.args,{cwd:r,timeout:n,maxBuffer:4194304,encoding:`utf8`})}catch(e){let t=e,n=t.stderr?.trim()||t.stdout?.trim()||t.message||`checker failed`;throw Error(`Pinned checker failed: ${n}`)}let a=String(i.stdout),o=String(i.stderr);return{...pp(await mp(r,t,a)),stdout:a,stderr:o}}async function wp(e,t){try{let{root:n,manifest:r}=await Bd(e,t.directory),i=await Gd(n),a=r.provenance?await Kd(n,r,i,{allowMissing:!0}):void 0,o=td(),s=z(`Running ${r.title} checker…`);t.json||s.start();let c;try{c=await Cp(n,r.checker)}finally{s.stop()}let l=Xd(c,a,r.provenance,void 0,{allowMissingSource:!0,requirePullRequest:!1}),u=St(te(32)),d=Zf(c.candidateRef,u),f={version:1,competition:r.slug,candidateRef:c.candidateRef,evidence:l.evidence,evidenceJson:c.evidenceJson,evidenceRefs:l.evidenceRefs,salt:u,candidateId:d,...a?{source:a}:{},deviceAddress:o.account.address,clientSubmissionId:w(),createdAt:new Date().toISOString()};await Zd(A.join(n,`.tangle-solve-run.json`),f),t.json?I({localRun:f}):(L(`Checker output recorded locally for operator evaluation`),B({Competition:r.slug,Candidate:c.candidateRef,"Device address":o.account.address,"Evidence refs":l.evidenceRefs.length}),R("Commit any changes, then run `tangle solve submit` from this directory."),r.provenance&&!a&&R(`Add your GitHub fork as 'origin' before submitting. The task repository is available as '${Rd}'.`))}catch(e){U(e)}}const Tp=/^0x[0-9a-f]{64}$/i;async function Ep(e){let t=await xd({deviceAddress:e.deviceAddress,apiUrl:e.apiUrl,profile:e.profile}),n=await e.signer.signMessage({message:t.message});return{walletChallengeId:t.challengeId,walletSignature:n}}async function Dp(e,t){try{let{root:n,manifest:r}=await Bd(e,t.directory);vd({profile:t.profile});let i=await Gd(n),a=await Qd(n);if(a.competition!==r.slug)throw Error(`.tangle-solve-run.json does not match this competition`);if(!Tp.test(a.salt)||!Tp.test(a.candidateId))throw Error("This run predates durable candidate identity. Run `tangle solve run` again");let o=r.provenance?await Kd(n,r,i):void 0;if(r.provenance&&a.source&&!Jd(a.source,o))throw Error("The saved run points to a different repository or revision. Keep your fork as 'origin' and run `tangle solve run` again before submitting");let s=ed();if(!s)throw Error("No Solve device signer found. Run `tangle solve run` first");if(s.account.address.toLowerCase()!==a.deviceAddress.toLowerCase())throw Error("The local Solve device account changed after `tangle solve run`; run the checker again");let c=z(`Checking the committed candidate…`);t.json||c.start();let l;try{l=await Cp(n,r.checker)}finally{c.stop()}if(l.candidateRef!==a.candidateRef||l.evidenceJson!==a.evidenceJson)throw Error("The committed checker output changed after `tangle solve run`; run the checker again");if(Zf(l.candidateRef,a.salt).toLowerCase()!==a.candidateId.toLowerCase())throw Error(`The saved candidate identity does not match the checker output; run the checker again`);let u=gd(t.prUrl);if(!r.provenance&&u)throw Error(`This competition does not accept GitHub pull request provenance`);if(u){if(!o)throw Error(`A provenance policy is required for a pull request`);await $d({pullRequest:u,taskRepository:o.taskRepository,submissionRepository:o.submissionRepository,submissionRevision:i})}let d=Xd(l,o,r.provenance,u,{requirePullRequest:!0}),f={...a,...o?{source:o}:{},chainState:{status:`submitting`,transactions:{...a.chainState?.transactions??{}}}},p=A.join(n,`.tangle-solve-run.json`);await Zd(p,f);let m=z(`Submitting candidate to Tempo…`);t.json||m.start();let h;try{h=await ep(jd(r),s.account,{artifactRef:l.candidateRef,salt:a.salt,evidenceJson:l.evidenceJson,evidenceRefs:d.evidenceRefs},{resumeTransactions:f.chainState?.transactions,onTransaction:async(e,t)=>{f={...f,chainState:{status:`submitting`,transactions:{...f.chainState?.transactions??{},[e]:t}}},await Zd(p,f)}})}finally{m.stop()}f={...f,chainReceipt:h,chainState:{status:`accepted`,transactions:{...f.chainState?.transactions??{},...ef(h)}}},await Zd(p,f);let g=await Ep({deviceAddress:h.address,signer:s.account,apiUrl:t.apiUrl,profile:t.profile}),_=await bd({path:`/v1/submissions`,method:`POST`,apiUrl:t.apiUrl,profile:t.profile,body:{competition:r.slug,candidateRef:l.candidateRef,candidateId:h.candidateId,evidenceJson:l.evidenceJson,evidenceRefs:d.evidenceRefs,deviceAddress:h.address,reportTxHash:h.report,evaluationTxHash:h.evaluation,transactions:ef(h),...r.provenance&&o?{source:{...o,...u?{pullRequest:u}:{}}}:{},clientSubmissionId:a.clientSubmissionId,...g,...t.model?{model:t.model}:{},...t.note?{note:t.note}:{}}});t.json?I({..._,transactions:ef(h),candidateId:h.candidateId}):(L(`Submission accepted on Tempo`),B({Competition:r.slug,Candidate:h.candidateId,"Device address":h.address,"Report transaction":h.report,"Evaluation transaction":h.evaluation,"Submission ID":typeof _.id==`string`?_.id:_.submission?.id}))}catch(e){U(e)}}function Op(){let e=new x(`solve`).description(`Participate in Tangle Solve competitions`);e.command(`clone <competition>`).description(`Clone the pinned competition repository`).argument(`[directory]`,`Destination directory`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).action(rf),e.command(`run [competition]`).description(`Run the competition checker and record its evidence`).option(`--directory <path>`,`Competition directory (defaults to the current directory)`).action(wp),e.command(`submit [competition]`).description(`Submit checker evidence through the device account and Tempo`).option(`--directory <path>`,`Competition directory (defaults to the current directory)`).option(`--pr-url <url>`,`GitHub pull request containing the submission`).option(`--model <name>`,`Model used to produce the submission`).option(`--note <text>`,`Short note shown with the accepted submission`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).action(Dp),e.command(`account`).description(`Show the local Solve signing account`).option(`--create`,`Create the account if it does not exist`).action(rd);let t=e.command(`device`).description(`List and revoke the Solve devices bound to your account`);return t.command(`list`).description(`List your devices and whether each may submit jobs on Tempo`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).action(e=>Yf(e)),t.command(`revoke <address>`).description(`Permanently revoke a device; the local device is revoked with its own key`).option(`--reason <text>`,`Why the device is revoked (shown to the account)`).option(`--yes`,`Confirm the permanent revocation without a prompt`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).action((e,t)=>Xf(e,t)),e}function kp(e,t){return`tangle ssh-proxy ${e.replace(/\/+$/,``)}/v1/sandboxes/${t}/runtime/ssh`}function Ap(e){return/^[A-Za-z0-9_/:=@%+.,-]+$/.test(e)?e:`'${e.replace(/'/g,`'"'"'`)}'`}function jp(e){return`'${e.replace(/'/g,`''`)}'`}function Mp(e){return e===`win32`?`NUL`:`/dev/null`}function Np(e,t){return t===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN=${jp(`<token>`)}; ssh ${e.map(jp).join(` `)}`:`TANGLE_SSH_PROXY_AUTH_TOKEN=${Ap(`<token>`)} ssh ${e.map(Ap).join(` `)}`}function Pp(e){return e.connection!==void 0&&!e.connection.ssh}function Fp(){Ft(`SSH is not enabled for this sandbox.`),R(`Create a sandbox with --ssh to enable SSH access.`),process.exit(1)}function Ip(e,t=[],n=process.platform){let r=Mp(n);return[`-o`,`ProxyCommand=${e.proxyCommand}`,`-o`,`StrictHostKeyChecking=no`,`-o`,`UserKnownHostsFile=${r}`,`-o`,`GlobalKnownHostsFile=${r}`,`-o`,`LogLevel=ERROR`,`-o`,`ServerAliveInterval=15`,`-o`,`ServerAliveCountMax=4`,`-o`,`TCPKeepAlive=yes`,`${e.username}@localhost`,`-p`,String(e.port),...t]}function Lp(){return new x(`ssh`).description(`Open SSH session to a sandbox`).argument(`<ref>`,`Sandbox ID or name`).argument(`[sshArgs...]`,`Extra args passed through to ssh`).option(`-i, --identity-file <path>`,`Private key file to pass to ssh`).option(`--print`,`Print SSH command instead of connecting`).allowUnknownOption(!0).action(async(e,t,n)=>{let{context:r,client:i}=K(n),a=z(`Getting SSH credentials...`);a.start();let o=await J(i,r,e);if(Pp(o)){a.stop(),Fp();return}o=await Y(o);let s=await o.ssh();if(a.stop(),!s){Fp();return}let c={...s,proxyCommand:kp(r.baseUrl,o.id)};if(!r.apiKey)throw Error(`SSH proxy requires API key auth. Set TANGLE_API_KEY or pass --api-key.`);let l=Ip(c,[...n.identityFile?[`-i`,n.identityFile,`-o`,`IdentitiesOnly=yes`]:[],...t]);if(n.print){console.log(Np(l,process.platform));return}R(`Connecting via tunnel...`);let u=we(`ssh`,l,{stdio:`inherit`,env:{...process.env,TANGLE_SSH_PROXY_AUTH_TOKEN:r.apiKey}});u.on(`error`,e=>{e.code===`ENOENT`&&(Ft(`SSH client not found. Please install OpenSSH.`),process.exit(1)),U(e)}),u.on(`exit`,e=>{process.exit(e??0)})})}function Rp(){let e=new x(`ssh-keys`).description(`Manage SSH keys`);return e.command(`list`).description(`List SSH keys`).action(async e=>{let t=z(`Fetching SSH keys...`);try{t.start();let n=await G(W(e)).sshKeys.list();t.stop(),e.json?I({sshKeys:n}):n.length===0?R(`No SSH keys found.`):Vt([`Name`,`Type`,`Fingerprint`,`Created`],n.map(e=>[e.name,e.keyType,e.fingerprint,e.createdAt.toLocaleString()]))}catch(e){t.stop(),U(e)}}),e.command(`add`).description(`Add SSH key`).argument(`<name>`,`SSH key name`).requiredOption(`--key-file <path>`,`Public key file path`).action(async(e,t)=>{let n=z(`Adding SSH key...`);try{let r=k(t.keyFile,`utf8`).trim();n.start();let i=await G(W(t)).sshKeys.create(e,r);n.stop(),t.json?I({sshKey:i}):L(`Added SSH key ${i.name} (${i.fingerprint})`)}catch(e){n.stop(),U(e)}}),e.command(`delete`).description(`Delete SSH key`).argument(`<name>`,`SSH key name or ID`).action(async(e,t)=>{let n=z(`Deleting SSH key...`);try{n.start(),await G(W(t)).sshKeys.delete(e),n.stop(),L(`Deleted SSH key ${e}`)}catch(e){n.stop(),U(e)}}),e}function zp(e,t=1){process.stderr.write(`${e}\n`),process.exit(t)}function Bp(){return new x(`ssh-proxy`).description(`SSH proxy helper that pipes stdin/stdout to WebSocket`).argument(`<runtime-url>`,`Runtime WebSocket URL`).action(async e=>{let t=process.env.TANGLE_SSH_PROXY_AUTH_TOKEN;t||zp(`TANGLE_SSH_PROXY_AUTH_TOKEN not set`);let n=new Et(new URL(e.replace(/^http/,`ws`)),{headers:{Authorization:`Bearer ${t}`},perMessageDeflate:!1}),r;function i(){r&&=(clearInterval(r),void 0)}n.on(`open`,()=>{r=setInterval(()=>{n.readyState===Et.OPEN&&n.ping()},15e3),r.unref?.(),process.stdin.on(`data`,e=>{n.readyState===Et.OPEN&&n.send(e,{binary:!0,compress:!1})}),process.stdin.on(`end`,()=>n.close(1e3))}),n.on(`message`,e=>{let t=Buffer.isBuffer(e)?e:Array.isArray(e)?Buffer.concat(e):Buffer.from(e);process.stdout.write(t)}),n.on(`error`,e=>{i(),zp(`WebSocket error: ${e.message}`)}),n.on(`close`,e=>{i(),process.exit(e===1e3?0:1)}),process.stdin.on(`error`,()=>n.close())})}function Vp(){let e=new x(`team`).description(`Manage teams`);return $(e,`list`).description(`List teams for the current account`).action(async e=>{let t=W(e),n=G(t),r=e.json?null:z(`Fetching teams...`);r?.start();let i=await n.teams.list();if(r?.stop(),e.json){I({teams:i,activeTeamId:t.activeTeamId??null});return}F(i.map(e=>({active:e.id===t.activeTeamId,id:e.id,name:e.name,role:e.currentUserRole,members:e.memberCount})),[{key:`active`,header:`Active`,width:8},{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:24},{key:`role`,header:`Role`,width:10},{key:`members`,header:`Members`,width:10}])}),$(e,`create <name>`).description(`Create a team`).option(`--org-id <id>`,`External organization id`).option(`--no-switch`,`Do not set the new team as active`).action(async(e,t)=>{let n=W(t),r=G(n),i=t.json?null:z(`Creating team...`);i?.start();let a=await r.teams.create({name:e,orgId:t.orgId});if(t.switch&&Os(a,n.profile),i?.stop(),t.json){I({team:a,active:!!t.switch});return}L(`Team created: ${Ts(a)}`),t.switch&&L(`Active team set to ${a.name}`)}),$(e,`switch <team>`).description(`Set the active team for the current profile`).action(async(e,t)=>{let n=W(t),r=await Es(G(n),e);if(Os(r,n.profile),t.json){I({team:r,activeTeamId:r.id});return}L(`Active team set to ${Ts(r)}`)}),e.command(`current`).description(`Show the active team for the current profile`).option(`--profile <profile>`,`Credential profile`).action(e=>{let t=mr(e.profile);if(e.json){I(t.activeTeamId?t:{activeTeamId:null});return}if(!t.activeTeamId){console.log(`No active team.`);return}B({ID:t.activeTeamId,Name:t.activeTeamName})}),e.command(`clear`).description(`Clear the active team for the current profile`).option(`--profile <profile>`,`Credential profile`).action(e=>{if(ks(e.profile),e.json){I({activeTeamId:null});return}L(`Active team cleared.`)}),$(e,`members [team]`).description(`List team members`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Ds(r,e,n.profile),a=await r.teams.listMembers(i.id);if(t.json){I({team:i,members:a});return}F(a,[{key:`id`,header:`ID`,width:36},{key:`customerEmail`,header:`Email`,width:28},{key:`role`,header:`Role`,width:10},{key:`status`,header:`Status`,width:10},{key:`joinedAt`,header:`Joined`,width:16}])}),$(e,`update-member <member-id>`).description(`Update a team member role`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).requiredOption(`--role <role>`,`Role: admin, member, viewer`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Ds(r,t.team,n.profile),a=Hp(t.role),o=await r.teams.updateMember(i.id,e,{role:a});if(t.json){I({team:i,member:o});return}L(`Member updated: ${o.customerEmail}`),B({Team:i.name,Role:o.role,Status:o.status})}),$(e,`invite <email>`).description(`Invite a user to a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--role <role>`,`Role: admin, member, viewer`,`member`).option(`--ttl-hours <hours>`,`Invitation lifetime in hours`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Ds(r,t.team,n.profile),a=Hp(t.role),o=await r.teams.invite(i.id,{email:e,role:a,ttlHours:t.ttlHours?Number.parseInt(t.ttlHours,10):void 0});if(t.json){I({team:i,invitation:o});return}L(`Invitation created for ${o.email}`),B({Team:i.name,Role:o.role,Expires:o.expiresAt,"Invitation ID":o.id}),L(`Re-run with --json to retrieve the invitation token for sharing.`)}),$(e,`leave [team]`).description(`Leave a team as the current user`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Ds(r,e,n.profile);if(!(!t.force&&!t.json&&!await ei(`Leave team '${i.name}'? (y/N) `,`--force`))){if(await r.teams.leave(i.id),n.activeTeamId===i.id&&ks(n.profile),t.json){I({success:!0,teamId:i.id});return}L(`Left team: ${i.name}`)}}),$(e,`transfer <new-owner-customer-id> [team]`).description(`Transfer team ownership to another active member`).option(`--force`,`Skip confirmation prompt`).action(async(e,t,n)=>{let r=W(n),i=G(r),a=await Ds(i,t,r.profile);if(!(!n.force&&!n.json&&!await ei(`Transfer ownership of '${a.name}' to ${e}? This cannot be undone without the new owner's cooperation. (y/N) `,`--force`))){if(await i.teams.transferOwnership(a.id,e),n.json){I({success:!0,teamId:a.id,newOwnerCustomerId:e});return}L(`Ownership transferred for ${a.name}`)}}),e.addCommand(Up()),e.addCommand(Wp()),$(e,`invitations [team]`).description(`List pending and historical team invitations`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Ds(r,e,n.profile),a=await r.teams.listInvitations(i.id);if(t.json){I({team:i,invitations:a});return}F(a,[{key:`id`,header:`ID`,width:38},{key:`email`,header:`Email`,width:28},{key:`role`,header:`Role`,width:10},{key:`status`,header:`Status`,width:12},{key:`expiresAt`,header:`Expires`,width:16}])}),$(e,`accept <token>`).description(`Accept a team invitation`).option(`--no-switch`,`Do not set the accepted team as active`).action(async(e,t)=>{let n=W(t),r=G(n),i=await r.teams.acceptInvitation(e),a=t.switch===!1?null:await r.teams.get(i.teamId);if(a&&Os(a,n.profile),t.json){I({member:i,activeTeamId:a?.id??null});return}L(`Invitation accepted for team ${i.teamId}`),a&&L(`Active team set to ${a.name}`)}),$(e,`revoke-invitation <invitation-id>`).description(`Revoke a pending team invitation`).action(async(e,t)=>{if(await G(W(t)).teams.revokeInvitation(e),t.json){I({success:!0,invitationId:e});return}L(`Invitation revoked: ${e}`)}),$(e,`remove-member <member-id>`).description(`Remove a member from a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Ds(r,t.team,n.profile);if(await r.teams.removeMember(i.id,e),t.json){I({success:!0,teamId:i.id,memberId:e});return}L(`Member removed: ${e}`)}),e}function Hp(e){if(e===`admin`||e===`member`||e===`viewer`)return e;throw Error(`Role must be one of: admin, member, viewer`)}function Up(){let e=new x(`secret`).description(`Manage team secrets`);return $(e,`list [team]`).description(`List team secret names`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Ds(r,e,n.profile),a=await r.teams.listSecrets(i.id);if(t.json){I({team:i,secrets:a});return}F(a,[{key:`name`,header:`Name`,width:28},{key:`updatedAt`,header:`Updated`,width:24},{key:`updatedBy`,header:`Updated By`,width:28}])}),$(e,`set <name> [value]`).description(`Create or replace a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--value-stdin`,`Read secret value from stdin`).action(async(e,t,n)=>{let r=W(n),i=G(r),a=await Ds(i,n.team,r.profile),o=await qu({value:t,valueStdin:n.valueStdin,prompt:`Enter value for team secret '${e}': `}),s=await i.teams.upsertSecret(a.id,e,o);if(n.json){I({team:a,secret:s});return}L(`Team secret saved: ${s.name}`)}),$(e,`delete <name>`).description(`Delete a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Ds(r,t.team,n.profile);if(!(!t.force&&!t.json&&!await ei(`Delete team secret '${e}' from '${i.name}'? (y/N) `,`--force`))){if(await r.teams.deleteSecret(i.id,e),t.json){I({success:!0,teamId:i.id,name:e});return}L(`Team secret deleted: ${e}`)}}),$(e,`reveal <name>`).description(`Reveal a team secret value`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Ds(r,t.team,n.profile),a=await r.teams.revealSecret(i.id,e);if(t.json){I({teamId:i.id,...a});return}console.log(a.value)}),e}function Wp(){let e=new x(`templates`).description(`Manage team golden-path templates`);return $(e,`list [team]`).description(`List a team's golden-path templates`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Ds(r,e,n.profile),a=await r.teams.listTemplates(i.id);if(t.json){I({team:i,templates:a});return}if(a.length===0){console.log(`No templates yet for ${i.name}.`);return}F(a.map(e=>({id:e.id,name:e.name,environment:e.environment,snapshot:`${e.snapshotId.slice(0,12)}…`,updated:e.updatedAt})),[{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:28},{key:`environment`,header:`Env`,width:14},{key:`snapshot`,header:`Snapshot`,width:16},{key:`updated`,header:`Updated`,width:24}])}),$(e,`create <name> <snapshot-id>`).description(`Create a golden-path template from a snapshot`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`-d, --description <description>`,`Human-readable description shown in the dashboard`).option(`-e, --environment <environment>`,`Default environment to apply (defaults to 'universal')`).option(`--config <json>`,`Optional JSON config object merged into sandboxes created from this template`).action(async(e,t,n)=>{let r=W(n),i=G(r),a=await Ds(i,n.team,r.profile),o;if(n.config)try{let e=JSON.parse(n.config);if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`--config must be a JSON object`);o=e}catch(e){throw Error(`--config is not valid JSON: ${e instanceof Error?e.message:String(e)}`)}let s=await i.teams.createTemplate(a.id,{name:e,snapshotId:t,description:n.description,environment:n.environment,config:o});if(n.json){I({team:a,template:s});return}L(`Team template created: ${s.name} (${s.id})`)}),$(e,`delete <template-id>`).description(`Delete a team golden-path template`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=W(t),r=G(n),i=await Ds(r,t.team,n.profile);if(!(!t.force&&!t.json&&!await ei(`Delete template '${e}' from '${i.name}'? (y/N) `,`--force`))){if(await r.teams.deleteTemplate(i.id,e),t.json){I({success:!0,teamId:i.id,templateId:e});return}L(`Team template deleted: ${e}`)}}),e}function $(e,t){return e.command(t).option(`--profile <profile>`,`Credential profile`)}async function Gp(e,t,n){let r=new AbortController,i=()=>r.abort();try{let n=G(W({...e,timeout:void 0}));process.once(`SIGINT`,i),process.once(`SIGTERM`,i);let a=await t(n,{...e.timeout===void 0?{}:{timeoutMs:Number(e.timeout)*1e3},resumeJobId:e.resumeJob,signal:r.signal,onProgress:e=>{process.stderr.write(`Publication ${e.id}: ${e.status}\n`)}}).finally(()=>{process.off(`SIGINT`,i),process.off(`SIGTERM`,i)});e.json?I(a):L(`template`in a?`Published template: ${a.template.slug}`:`Published template version: ${a.version.id}`)}catch(t){if(t instanceof o&&t.status!==401&&t.job&&[`pending`,`scanning`,`ready`].includes(t.job.status)){let e=[`tangle`,`template`,...n,`--resume-job`,t.job.id].map(Be).join(` `);Object.assign(t,{fix:{command:e}})}U(t,e.json)}}function Kp(){let e=new x(`template`).description(`Manage published public templates`);return e.command(`list`).option(`-q, --query <query>`,`Search query`).option(`--tag <tag>`,`Filter by tag`).option(`--featured`,`Show featured templates only`).action(async e=>{let t=G(W(e)),n=e.featured?await t.publicTemplates.featured():await t.publicTemplates.list({query:e.query,tag:e.tag});if(e.json){I({templates:n});return}F(n,[{key:`slug`,header:`Slug`,width:28},{key:`name`,header:`Name`,width:28},{key:`forkCount`,header:`Forks`,width:8},{key:`sandboxCount`,header:`Sandboxes`,width:12},{key:`updatedAt`,header:`Updated`,width:24}])}),e.command(`get <id-or-slug>`).action(async(e,t)=>{let n=await G(W(t)).publicTemplates.get(e);if(t.json){I({template:n});return}I(n)}),e.command(`versions <id-or-slug>`).action(async(e,t)=>{let n=await G(W(t)).publicTemplates.versions(e);if(t.json){I({versions:n});return}F(n.map(e=>({...e})),[{key:`id`,header:`Version ID`,width:38},{key:`versionNumber`,header:`Version`,width:8},{key:`snapshotId`,header:`Snapshot`,width:20},{key:`createdAt`,header:`Created`,width:24}])}),e.command(`publish <name> <snapshot-id> <sandbox-id>`).option(`--timeout <seconds>`,`Maximum wait for publication`).option(`--resume-job <id>`,`Resume an accepted publication for this snapshot`).option(`--slug <slug>`,`Stable public slug`).option(`-d, --description <description>`,`Template description`).option(`--readme <markdown>`,`README markdown`).option(`--tags <tags...>`,`Template tags`).option(`--release-notes <text>`,`Release notes`).option(`--team-id <id>`,`Publish under a team`).option(`--forked-from <id>`,`Fork source template id`).action((e,t,n,r)=>Gp(r,async(i,a)=>({template:await i.publicTemplates.publish({name:e,slug:r.slug,description:r.description,snapshotId:t,sourceSandboxId:n,readmeMarkdown:r.readme,tags:r.tags,releaseNotes:r.releaseNotes,teamId:r.teamId,forkedFromTemplateId:r.forkedFrom},a)}),[`publish`,e,t,n])),e.command(`publish-version <id-or-slug> <snapshot-id> <sandbox-id>`).option(`--timeout <seconds>`,`Maximum wait for publication`).option(`--resume-job <id>`,`Resume an accepted publication for this snapshot`).option(`--readme <markdown>`,`README markdown`).option(`--tags <tags...>`,`Template tags`).option(`--release-notes <text>`,`Release notes`).action((e,t,n,r)=>Gp(r,async(i,a)=>({version:await i.publicTemplates.publishVersion(e,{snapshotId:t,sourceSandboxId:n,readmeMarkdown:r.readme,tags:r.tags,releaseNotes:r.releaseNotes},a)}),[`publish-version`,e,t,n])),e}function qp(){let e=new x(`traces`).description(`Read hosted agent traces, spans, and eval-runs from Tangle Intelligence`);return e.command(`list`).description(`List trace summaries (one row per trace), newest first`).option(`--from <iso>`,`ISO-8601 lower bound on received time (inclusive)`).option(`--to <iso>`,`ISO-8601 upper bound on received time (inclusive)`).option(`--model <model>`,`Exact model match (any span carried this model)`).option(`--run <runId>`,`Exact run id match`).option(`--status <status>`,`ERROR | OK`).option(`-q, --query <text>`,`Substring over span name`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Page size (clamped server-side to [1, 200])`).action(async e=>{try{let t={from:e.from,to:e.to,model:e.model,runId:e.run,status:e.status===void 0?void 0:im(e.status),q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:lm(e.limit)},n=Yp(e),r=e.json?null:z(`Fetching traces...`);r?.start();let i=await n.listTraces(t);if(r?.stop(),e.json)return I(i);Qp(i.items),nm(i.nextCursor)}catch(t){Zp(t,e)}}),e.command(`get <traceId>`).description(`Show one trace's spans. Streams NDJSON to stdout with --ndjson.`).option(`--ndjson`,`Stream the full span set as NDJSON to stdout`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Spans per page`).action(async(e,t)=>{try{let n=Yp(t);if(t.ndjson){await Xp(n,e);return}let r=t.json?null:z(`Fetching trace spans...`);r?.start();let i=await n.getTraceSpans(e,{cursor:t.cursor,limit:t.limit===void 0?void 0:lm(t.limit)});if(r?.stop(),t.json)return I(i);$p(i.items),i.truncated&&B({Spans:`${i.items.length} of ${i.total} (truncated)`}),nm(i.nextCursor)}catch(e){Zp(e,t)}}),e.addCommand(Jp()),e}function Jp(){let e=new x(`runs`).description(`Read eval-runs pivoted off the trace surface`);return e.command(`list`).description(`List eval-runs, newest first`).option(`--status <status>`,`Run status filter`).option(`--gate <decision>`,`Promotion-gate decision filter`).option(`--label <key:value>`,`Match over the run's labels`).option(`--from <iso>`,`ISO-8601 lower bound on received time`).option(`--to <iso>`,`ISO-8601 upper bound on received time`).option(`-q, --query <text>`,`Substring over run dir`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Page size`).action(async e=>{try{let t={status:e.status===void 0?void 0:om(e.status),gate:e.gate===void 0?void 0:cm(e.gate),label:e.label,from:e.from,to:e.to,q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:lm(e.limit)},n=Yp(e),r=e.json?null:z(`Fetching runs...`);r?.start();let i=await n.listRuns(t);if(r?.stop(),e.json)return I(i);em(i.items),nm(i.nextCursor)}catch(t){Zp(t,e)}}),e.command(`get <runId>`).description(`Show a single eval-run`).action(async(e,t)=>{try{let n=Yp(t),r=t.json?null:z(`Fetching run...`);r?.start();let i=await n.getRun(e);if(r?.stop(),t.json)return I(i);tm(i)}catch(e){Zp(e,t)}}),e}function Yp(e){let t=ir(e.apiKey);if(!t)throw Error(`No API key found. Set TANGLE_API_KEY or run: tangle auth login`);return Dt({apiKey:t,baseUrl:e.baseUrl??process.env.TANGLE_INTELLIGENCE_BASE_URL})}async function Xp(e,t){let n=(await e.exportTraceSpansNdjson(t)).getReader();try{for(;;){let{value:e,done:t}=await n.read();if(t)break;e&&process.stdout.write(Buffer.from(e))}}finally{n.releaseLock()}}function Zp(e,t){return U(e,t.json===!0)}function Qp(e){F(e.map(e=>({traceId:e.traceId,root:e.rootName??`-`,model:e.model??`-`,spans:e.spanCount,errors:e.errorCount,durationMs:e.durationMs,cost:rm(e.costUsd)})),[{key:`traceId`,header:`Trace`,width:36},{key:`root`,header:`Root`,width:24},{key:`model`,header:`Model`,width:22},{key:`spans`,header:`Spans`,width:8},{key:`errors`,header:`Errors`,width:8},{key:`durationMs`,header:`Duration(ms)`,width:14},{key:`cost`,header:`Cost`,width:10}])}function $p(e){F(e.map(e=>({spanId:e.id,name:e.name,model:e.model??`-`,status:e.statusCode??`-`,cost:e.costUsd===null?`-`:`$${e.costUsd}`})),[{key:`spanId`,header:`Span`,width:40},{key:`name`,header:`Name`,width:28},{key:`model`,header:`Model`,width:22},{key:`status`,header:`Status`,width:10},{key:`cost`,header:`Cost`,width:12}])}function em(e){F(e.map(e=>({runId:e.id,status:e.status,gate:e.gateDecision??`-`,cost:e.totalCostUsd===null?`-`:`$${e.totalCostUsd}`,receivedAt:e.receivedAt})),[{key:`runId`,header:`Run`,width:24},{key:`status`,header:`Status`,width:22},{key:`gate`,header:`Gate`,width:18},{key:`cost`,header:`Cost`,width:12},{key:`receivedAt`,header:`Received`,width:18}])}function tm(e){B({Run:e.id,Status:e.status,Gate:e.gateDecision??void 0,"Run Dir":e.runDir??void 0,Cost:e.totalCostUsd===null?void 0:`$${e.totalCostUsd}`,Duration:e.totalDurationMs===null?void 0:`${e.totalDurationMs}ms`,"Holdout Lift":e.holdoutLift??void 0,Received:e.receivedAt})}function nm(e){e&&B({"Next page":`--cursor ${e}`})}function rm(e){return e===null?`-`:`$${e.toFixed(4)}`}function im(e){if(e===`ERROR`||e===`OK`)return e;throw Error(`--status must be ERROR or OK`)}const am=[`started`,`baseline-complete`,`generation-complete`,`gate-decided`,`finished`,`errored`];function om(e){let t=am.find(t=>t===e);if(t)return t;throw Error(`--status must be one of ${am.join(`, `)}`)}const sm=[`ship`,`hold`,`need_more_work`,`model_ceiling`,`arch_ceiling`];function cm(e){let t=sm.find(t=>t===e);if(t)return t;throw Error(`--gate must be one of ${sm.join(`, `)}`)}function lm(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function um(){return new x(`usage`).description(`Show account usage and billing information`).action(async e=>{let{client:t}=K(e),n=e.json?null:z(`Fetching usage...`);n?.start();let[r,i]=await Promise.all([t.usage(),t.subscription().catch(()=>null)]);n?.stop(),e.json?I({...r,subscription:i}):(console.log(),console.log(`Account Usage`),console.log(`─`.repeat(40)),B({"Active Sandboxes":r.activeSandboxes,"Total Sandboxes":r.totalSandboxes,"Compute Minutes":dm(r.computeMinutes),"GPU Seconds":r.gpuSeconds,"GPU Spend":fm(r.gpuCostUsd)}),i&&(console.log(),console.log(`Subscription`),console.log(`─`.repeat(40)),B({Plan:i.plan,Status:i.status,"Credits Available":fm(i.creditsAvailableUsd),"Credits Used":fm(i.creditsUsedUsd),"Monthly Balance":fm(i.monthlyBalanceUsd)})),console.log(),console.log(`Billing Period`),console.log(`─`.repeat(40)),B({Start:r.periodStart.toLocaleDateString(),End:r.periodEnd.toLocaleDateString()}),console.log())})}function dm(e){if(e===void 0)return`-`;if(e<60)return`${e} min`;let t=Math.floor(e/60),n=e%60;return n===0?`${t} hr`:`${t} hr ${n} min`}function fm(e){return e<0?`-$${(-e).toFixed(2)}`:`$${e.toFixed(2)}`}function pm(){return new x(`use`).description(`Set or show the active sandbox (used when a command omits the id)`).argument(`[id]`,`Sandbox id to make active`).option(`--clear`,`Clear the active sandbox`).action((e,t)=>{if(t.clear){Xn(),R(`Cleared the active sandbox.`);return}if(e){Yn(e),R(`Active sandbox set to ${e}. Commands now default to it; override with --box or TANGLE_SANDBOX.`);return}let n=Jn();R(n?`Active sandbox: ${n}`:"No active sandbox. Set one with `tangle use <id>`.")})}function mm(e){F(e,[{key:`id`,header:`ID`},{key:`nodeId`,header:`Node`},{key:`name`,header:`Name`},{key:`contentType`,header:`Content Type`},{key:`byteSize`,header:`Bytes`},{key:`createdAt`,header:`Created`}])}function hm(e){e.command(`artifacts`).description(`List a run's artifact metadata (never the bytes)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Z(n)).workflows.listArtifacts(e,t);if(n.json)return I(r);mm(r.artifacts)}),e.command(`artifact-download`).description(`Download one run artifact's bytes to a file`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).argument(`<artifactId>`,`Artifact ID`).option(`--out <file>`,`Destination file (defaults to the artifact ID)`).action(async(e,t,n,r)=>{let i=await(await Z(r)).workflows.downloadArtifact(e,t,n),a=r.out??n;try{fe(a,i.bytes)}catch(e){throw Error(`Could not write artifact to "${a}": ${e instanceof Error?e.message:String(e)}`)}if(r.json)return I({file:a,contentType:i.contentType,bytes:i.bytes.length});R(`Wrote ${a} (${i.bytes.length} bytes, ${i.contentType}).`)})}function gm(e){F(e.map(e=>({id:e.id,run:e.runId,title:e.title,options:e.options.join(`, `),requested:e.requestedAt,expires:e.expiresAt??``})),[{key:`id`,header:`ID`},{key:`run`,header:`Run`},{key:`title`,header:`Title`},{key:`options`,header:`Options`},{key:`requested`,header:`Requested`},{key:`expires`,header:`Expires`}])}function _m(e){e.command(`decisions`).description(`List a workflow's pending human decisions`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=(await(await Z(t)).workflows.listPendingDecisions()).decisions.filter(t=>t.workflowId===e);if(t.json)return I({decisions:n});gm(n)}),e.command(`decision-resolve`).description(`Answer the decision a run is parked on and resume it`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).requiredOption(`--choice <choice>`,`The option to resolve with (one of the decision's options)`).action(async(e,t,n)=>{let r=await Z(n),i=await r.workflows.getRunDecision(e,t),a=await r.workflows.resolveRunDecision(e,t,{decisionId:i.id,choice:n.choice});if(n.json)return I(a);if(a.resumed){R(`Resolved decision ${a.decisionId} with "${a.choice}" — run ${a.runId} resumed.`);return}R(`Resolved decision ${a.decisionId} with "${a.choice}", but run ${a.runId} had already finished — nothing to resume.`)})}function vm(e){try{return k(e,`utf8`)}catch(t){throw Error(`Could not read workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function ym(e){F(e.map(e=>({id:e.id,name:e.name,enabled:e.enabled?`yes`:`no`,issues:e.validationErrors.length,updated:e.updatedAt})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`enabled`,header:`Enabled`},{key:`issues`,header:`Issues`},{key:`updated`,header:`Updated`}])}function bm(e){let t=e.workflows.filter(e=>e.failed>0).length,n=e.workflows.filter(e=>e.failed===0&&e.waiting>0).length,r=e.workflows.filter(e=>e.failed===0&&e.waiting===0&&e.runsInWindow>0).length;R(`${t} failing · ${n} waiting · ${r} healthy · ${e.workflows.length} total over ${e.window}`),F(e.workflows.map(e=>({id:e.id,name:e.name,enabled:e.enabled?`yes`:`no`,runs:e.runsInWindow,failed:e.failed,waiting:e.waiting,success:e.successRate===null?`—`:`${Math.round(e.successRate*100)}%`,lastRun:e.lastRunStatus??`—`,lastRunAt:e.lastRunAt??`—`})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`enabled`,header:`Enabled`},{key:`runs`,header:`Runs`},{key:`failed`,header:`Failed`},{key:`waiting`,header:`Waiting`},{key:`success`,header:`Success`},{key:`lastRun`,header:`Last Run`},{key:`lastRunAt`,header:`Last Run At`}])}function xm(e){if(B({ID:e.id,Name:e.name,Description:e.description??``,Enabled:e.enabled?`yes`:`no`,Actions:e.actions.length}),e.triggers&&e.triggers.length>0&&(R(`Triggers`),Sm(e.triggers)),e.validationErrors.length>0){R(`Validation issues`);for(let t of e.validationErrors)console.log(` ${t.path}: ${t.message}`)}}function Sm(e){F(e.map(e=>({id:e.id,kind:e.kind,enabled:e.enabled?`yes`:`no`,detail:e.kind===`schedule`?`${e.cron??``} (${e.timezone??``})`:`${e.provider??``}:${e.eventFilter?.event??``}${e.eventFilter?.action?`.${e.eventFilter.action}`:``}`})),[{key:`id`,header:`ID`},{key:`kind`,header:`Kind`},{key:`enabled`,header:`Enabled`},{key:`detail`,header:`Detail`}])}function Cm(e){e.command(`list`).description(`List your workflows`).action(async e=>{let t=await(await Z(e)).workflows.list();if(e.json)return I(t);ym(t)}),e.command(`fleet`).description(`Fleet overview: every workflow's run tallies over a trailing window, failing-first`).option(`--window <window>`,`Trailing window: 24h, 7d, or 30d`,`7d`).action(async e=>{let t=await(await Z(e)).workflows.fleetInsights({window:e.window});if(e.json)return I(t);bm(t)}),e.command(`get`).description(`Show a workflow's definition and compiled triggers`).argument(`<id>`,`Workflow ID`).option(`--yaml`,`Print only the raw definition YAML (the export path — pipe to a file)`).action(async(e,t)=>{let n=await(await Z(t)).workflows.get(e);if(t.yaml){if(n.definitionYaml===null)throw Error(`Workflow ${n.id} has no stored definition YAML to export`);process.stdout.write(n.definitionYaml.endsWith(`
193
+ `)?n.definitionYaml:`${n.definitionYaml}\n`);return}if(t.json)return I(n);xm(n)}),e.command(`create`).description(`Create a workflow from a YAML file`).argument(`<file>`,`Path to the workflow YAML`).action(async(e,t)=>{let n=vm(e),r=await(await Z(t)).workflows.create(n);if(t.json)return I(r);R(`Created workflow ${r.id} (${r.name}).`),xm(r)}),e.command(`apply`).description(`Create or update a workflow idempotently, matched by the definition's name`).argument(`<file>`,`Path to the workflow YAML`).action(async(e,t)=>{let n=vm(e),r=await Z(t),i=await r.workflows.validate(n,{structural:!0});if(!i.valid){if(process.exitCode=1,t.json)return I(i);R(`Invalid workflow:`);for(let e of i.errors)console.log(` ${e.path}: ${e.message}`);return}let a=(await r.workflows.list()).find(e=>e.name===i.name);if(a){let e=await r.workflows.update(a.id,n);if(t.json)return I({action:`updated`,workflow:e});R(`Updated workflow ${e.id} (${e.name}) — matched by name.`),xm(e);return}let o=await r.workflows.create(n);if(t.json)return I({action:`created`,workflow:o});R(`Created workflow ${o.id} (${o.name}).`),xm(o)}),e.command(`update`).description(`Replace a workflow's definition from a YAML file`).argument(`<id>`,`Workflow ID`).argument(`<file>`,`Path to the workflow YAML`).option(`--note <note>`,`Revision note recorded on the appended revision (why this change)`).action(async(e,t,n)=>{let r=vm(t),i=await(await Z(n)).workflows.update(e,r,{...n.note===void 0?{}:{note:n.note}});if(n.json)return I(i);R(`Updated workflow ${i.id} (${i.name}).`),xm(i)}),e.command(`delete`).description(`Delete a workflow and its triggers`).argument(`<id>`,`Workflow ID`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{if(!t.force&&!await ei(`Delete workflow ${e}? `,`--force`)){R(`Delete cancelled.`);return}if(await(await Z(t)).workflows.delete(e),t.json)return I({deleted:!0,id:e});R(`Deleted workflow ${e}.`)}),e.command(`validate`).description(`Validate a workflow YAML file without saving it`).argument(`<file>`,`Path to the workflow YAML`).option(`--structural`,`CI mode: compile + capability checks only, no connection resolution — the verdict is the same regardless of connected providers`).action(async(e,t)=>{let n=vm(e),r=await(await Z(t)).workflows.validate(n,{...t.structural?{structural:!0}:{}});if(t.json)return I(r);if(r.valid)R(`Valid: ${r.name} (${r.actionCount} action(s), ${r.triggerCount} trigger(s)).`);else{R(`Invalid workflow:`);for(let e of r.errors)console.log(` ${e.path}: ${e.message}`);process.exitCode=1}}),e.command(`schema`).description(`Print the JSON Schema for the workflow YAML`).action(async e=>{I(await(await Z(e)).workflows.schema())})}async function wm(e,t,n){let r=await(await Z(n)).workflows.setEnabled(e,t);if(n.json)return I(r);R(`${t?`Enabled`:`Disabled`} workflow ${r.id}.`),xm(r)}function Tm(e,t){try{return JSON.parse(e)}catch{throw Error(`Invalid ${t}: not valid JSON`)}}function Em(e,t){try{fe(e,t,`utf8`)}catch(t){throw Error(`Could not write workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function Dm(e){F(e.map(e=>({id:e.id,name:e.name,category:e.category,providers:e.providers.join(`, `),summary:e.summary})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`category`,header:`Category`},{key:`providers`,header:`Providers`},{key:`summary`,header:`Summary`}])}function Om(e,t){let n=e.kind===`github_app`,r=n?`${e.provider} (App installation)`:e.provider,i=e.connectUrl?` — ${n?`install`:`connect`}: ${e.connectUrl}`:``,a=e.prerequisite;return`${r}${i}${a&&t.some(e=>e.provider===a.provider&&e.kind===a.kind&&!e.connected)?` (after connecting ${a.provider})`:``}`}function km(e){e.command(`enable`).description(`Enable a workflow so its triggers and manual runs fire`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{await wm(e,!0,t)}),e.command(`disable`).description(`Disable a workflow (pause its triggers and manual runs)`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{await wm(e,!1,t)}),e.command(`templates`).description(`List the curated starter workflow templates`).action(async e=>{let t=await(await Z(e)).workflows.listTemplates();if(e.json)return I(t);Dm(t)}),e.command(`init`).description(`Create a workflow from a gallery template and print (or save) its YAML`).argument(`<template-id>`,"Template ID from `workflows templates`").option(`--param <key=value>`,`Template parameter value. Repeatable.`,jc,[]).option(`--file <out>`,`Write the instantiated workflow YAML to this file instead of stdout`).action(async(e,t)=>{let n=Mc(t.param,`param`)??{},r=await(await Z(t)).workflows.instantiateTemplate(e,n);if(t.json)return I(r);if(!r.created){R(`Template ${e} needs provider connections before it can run:`);for(let e of r.connectionRequirements)console.log(` ${e.connected?`✓`:`✗`} ${Om(e,r.connectionRequirements)}`);process.exitCode=1;return}let{workflow:i}=r;if(i.definitionYaml===null)throw Error(`Workflow ${i.id} was created but the server returned no definition YAML`);if(R(`Created workflow ${i.id} (${i.name}).`),t.file){Em(t.file,i.definitionYaml),R(`Wrote ${t.file}.`);return}process.stdout.write(i.definitionYaml.endsWith(`
194
+ `)?i.definitionYaml:`${i.definitionYaml}\n`)})}function Am(e){F(e,[{key:`key`,header:`Key`},{key:`version`,header:`Version`},{key:`updatedAt`,header:`Updated`}])}function jm(e){B({Key:e.key,Version:e.version,Updated:e.updatedAt}),R(`Value`),I(e.value)}function Mm(e){let t=e.command(`kv`).description(`Read and write a workflow's cross-run KV state`);t.command(`list`).description(`List every KV entry of a workflow`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=await(await Z(t)).workflows.listKv(e);if(t.json)return I(n);Am(n.entries)}),t.command(`get`).description(`Show one KV entry (value and version)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).action(async(e,t,n)=>{let r=await(await Z(n)).workflows.getKv(e,t);if(n.json)return I(r);jm(r)}),t.command(`set`).description(`Write a KV entry from a JSON value`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).argument(`<json>`,`Value as JSON (e.g. '{"cursor":123}' or '"abc"')`).option(`--cas <version>`,`Compare-and-swap: write only if the stored version still equals this`).action(async(e,t,n,r)=>{let i=Tm(n,`<json>`),a=r.cas===void 0?void 0:io(r.cas,`--cas`),o=await Z(r),s=a===void 0?await o.workflows.putKv(e,t,i):await o.workflows.casKv(e,t,a,i);if(r.json)return I(s);jm(s)}),t.command(`delete`).description(`Delete a KV entry (idempotent)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).action(async(e,t,n)=>{let r=await(await Z(n)).workflows.deleteKv(e,t);if(n.json)return I(r);R(r.deleted?`Deleted KV entry "${t}" of workflow ${e}.`:`No KV entry "${t}" on workflow ${e}.`)})}function Nm(e){F(e.map(e=>({rev:e.rev,created:e.createdAt,by:e.createdBy,source:e.source,note:e.note??``})),[{key:`rev`,header:`Rev`},{key:`created`,header:`Created`},{key:`by`,header:`Created By`},{key:`source`,header:`Source`},{key:`note`,header:`Note`}])}function Pm(e){e.command(`revisions`).description(`List a workflow's definition revision history (newest first)`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=await(await Z(t)).workflows.listRevisions(e);if(t.json)return I(n);Nm(n)}),e.command(`revision`).description(`Show one revision's metadata and definition YAML`).argument(`<id>`,`Workflow ID`).argument(`<rev>`,`Revision number`).action(async(e,t,n)=>{let r=io(t,`<rev>`),i=await(await Z(n)).workflows.getRevision(e,r);if(n.json)return I(i);B({Revision:i.rev,Created:i.createdAt,"Created by":i.createdBy,Source:i.source,Note:i.note??``}),process.stdout.write(i.yaml.endsWith(`
195
+ `)?i.yaml:`${i.yaml}\n`)}),e.command(`rollback`).description(`Restore a prior revision's definition as a NEW head revision (re-validated)`).argument(`<id>`,`Workflow ID`).argument(`<rev>`,`Revision number to restore`).action(async(e,t,n)=>{let r=io(t,`<rev>`),i=await(await Z(n)).workflows.rollback(e,r);if(n.json)return I(i);R(`Rolled back workflow ${i.id} to rev ${r}.`),xm(i)})}function Fm(){let e=new x(`workflows`).description(`Create and manage Tangle workflows`);return Cm(e),Lc(e),km(e),Pm(e),Mm(e),hm(e),_m(e),e}function Im(e){for(let[t,n]of Object.entries(e.optsWithGlobals()))e.getOptionValue(t)===void 0&&n!==void 0&&e.setOptionValue(t,n)}const Lm=e(import.meta.url)(`../package.json`);function Rm(){let e=new x;e.name(`tangle`).description(`CLI for Tangle Sandbox operations`).version(Lm.version??`0.0.0`).option(`--json`,`Output JSON where supported, including errors`).option(`--api-key <key>`,`API key (or set TANGLE_API_KEY)`).option(`--base-url <url>`,`API base URL`),e.hook(`preAction`,(e,t)=>{Im(t);let n=t.opts();kt(n.json===!0||n.ndjson===!0)}),e.addCommand(Ii()),e.addCommand(Wu()),e.addCommand(pm()),e.addCommand(Ku()),e.addCommand(vu()),e.addCommand(Ou()),e.addCommand(ku()),e.addCommand(as()),e.addCommand(Lp()),e.addCommand(Rp()),e.addCommand(Bp()),e.addCommand(gi()),e.addCommand(Yu()),e.addCommand(Qs()),e.addCommand(um()),e.addCommand(Vp()),e.addCommand(Kp()),e.addCommand(Gi()),e.addCommand(na()),e.addCommand(Iu()),e.addCommand($s()),e.addCommand(nc()),e.addCommand(Ql()),e.addCommand(Sl()),e.addCommand(Fm()),e.addCommand(Wo()),e.addCommand(Gu()),e.addCommand(Op()),e.addCommand(Ju()),e.addCommand(ra()),e.addCommand(Pu()),e.addCommand($l()),e.addCommand(Lo()),e.addCommand(Ro()),e.addCommand(Hu()),e.addCommand(Au()),e.addCommand(qp()),e.addCommand(Yc());function t(e){e.configureHelp({showGlobalOptions:!0}),e.configureOutput({writeErr:()=>{}}),e.exitOverride(t=>{t.exitCode===0&&process.exit(0),U(t,e.optsWithGlobals().json===!0)});for(let n of e.commands)t(n)}return t(e),e}const zm=Rm();zm.parseAsync(process.argv).catch(e=>{U(e,zm.opts().json===!0)});export{};