@tangle-network/sandbox-cli 0.21.40 → 0.21.42

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 +4 -4
  2. package/package.json +5 -5
package/dist/index.mjs CHANGED
@@ -145,7 +145,7 @@ await connect(new StdioServerTransport());`;case`claude-desktop`:return`// Add t
145
145
  Recommended actions:`);for(let e of i.insights.recommendedActions)console.log(` - ${e}`)}}),e.command(`cost <fleet-id>`).description(`Show the fleet's cost estimate`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Estimating cost...`);r.start();let i=await n.fleets.cost(e);r.stop(),t.json?j(i):F({Plan:i.plan,Currency:i.currency,"Hourly (USD)":i.hourlyUsd,"Max lifetime (s)":i.maxLifetimeSeconds,"Estimated max lifetime (USD)":i.estimatedMaxLifetimeUsd,Machines:i.requestedResources.machines,"Total CPU":i.requestedResources.totalCpu,"Total memory (MB)":i.requestedResources.totalMemoryMb})})}function qo(e){return[...e.entries()].map(([e,t])=>({machineId:e,sandboxId:t.id,status:t.status}))}function Jo(e){e.command(`list <fleet-id>`).description(`List the machines of one fleet (fleet id is required)`).option(`--status <status>`,`Filter machines by status`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Fetching fleet...`);r.start();let i=await n.fleets.list({fleetId:e,status:t.status});r.stop();let a=qo(i.machines);t.json?j({fleetId:i.fleetId,machines:a}):A(a,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}])}),e.command(`get <fleet-id>`).description(`Show one fleet's manifest (server record)`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Fetching manifest...`);r.start();let i=await n.fleets.manifest(e);r.stop(),t.json?j(i):(F({"Fleet ID":i.fleetId??i.id,Machines:i.machines.length,"Workspace mode":i.workspace?.mode,"Workspace status":i.workspace?.status,"Max lifetime (s)":i.policy?.maxLifetimeSeconds,"Max spend (USD)":i.policy?.maxSpendUsd,Created:i.createdAt,Updated:i.updatedAt}),A(i.machines,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`role`,header:`Role`,width:14},{key:`status`,header:`Status`,width:14}]))}),e.command(`delete <fleet-id>`).description(`Delete a fleet's machine sandboxes and its record`).option(`--continue-on-error`,`Keep deleting remaining machines if one delete fails`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Deleting fleet...`);r.start(),await n.fleets.delete(e,{continueOnError:t.continueOnError}),r.stop(),t.json?j({success:!0,fleetId:e}):M(`Fleet deleted: ${e}`)}),e.command(`reap`).description(`TTL cleanup of all expired fleets (fleet-wide)`).option(`--dry-run`,`Report what would be reaped without deleting`).action(async e=>{let{client:t}=U(e),n=P(`Reaping expired fleets...`);n.start();let r=await t.fleets.reapExpired({dryRun:e.dryRun});n.stop(),e.json?j(r):(F({"Dry run":r.dryRun,Expired:r.expired,Deleted:r.deleted}),A(r.fleets,[{key:`fleetId`,header:`Fleet`,width:24},{key:`expiredAt`,header:`Expired`,width:18},{key:`deleted`,header:`Deleted`,width:10}]))}),e.command(`reconcile`).description(`Drop fleet records whose underlying sandboxes vanished`).option(`--dry-run`,`Report orphans without removing them`).action(async e=>{let{client:t}=U(e),n=P(`Reconciling fleets...`);n.start();let r=await t.fleets.reconcile({dryRun:e.dryRun});n.stop(),e.json?j(r):(F({"Dry run":r.dryRun,Checked:r.checked,Orphaned:r.orphaned,Removed:r.removed}),A(r.machines,[{key:`fleetId`,header:`Fleet`,width:24},{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`removed`,header:`Removed`,width:10}]))})}function Yo(e){let t=e.memory?$o(e.memory,`--accelerator-memory`):void 0;return{kind:ts(e.kind),count:e.count?$o(e.count,`--accelerator-count`):1,...t===void 0?{}:{memoryMB:t}}}function Xo(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:es(e.provider,`--gpu-provider`)}:{},...e.image?{image:e.image}:{},...e.env?{env:Qo(e.env,`--gpu-env`,`GPU env`)}:{},maxSpendUsd:ns(e.maxSpendUsd,`--gpu-max-spend-usd`),maxLifetimeSeconds:$o(e.maxLifetime,`--gpu-max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:$o(e.idleTimeout,`--gpu-idle-timeout`)}:{}}}}function Zo(e){return{...e.provider?{provider:es(e.provider,`GPU provider`)}:{},accelerator:Yo({kind:e.acceleratorKind,count:e.acceleratorCount,memory:e.acceleratorMemory}),...e.image?{image:e.image}:{},...e.env?{env:Qo(e.env,`--env`,`env`)}:{},maxSpendUsd:ns(e.maxSpendUsd,`--max-spend-usd`),maxLifetimeSeconds:$o(e.maxLifetime,`--max-lifetime`),...e.idleTimeout?{idleTimeoutSeconds:$o(e.idleTimeout,`--idle-timeout`)}:{}}}function Qo(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 $o(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 es(e,t){if(i.includes(e))return e;throw Error(`${t} must be one of ${i.join(`, `)}`)}function ts(e){let t=e.trim().toLowerCase();if(/^[a-z0-9][a-z0-9._-]*$/.test(t))return t;throw Error(`--accelerator-kind must contain only letters, numbers, dots, underscores, or hyphens`)}function ns(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 rs(e){if(e.spec){let t=JSON.parse(T(e.spec,`utf8`));return{base:{fleetId:e.fleetId,defaults:t.defaults,policy:t.policy,workspace:t.workspace,metadata:t.metadata},machines:t.machines??[]}}let t=os(e),n=ss(e,!!t?.accelerator),r={...e.environment?{environment:e.environment}:{},...t?{resources:t}:{},...e.driver?{driver:{type:e.driver}}:{},...n?{gpuLease:n}:{},...e.backend?{backend:{type:e.backend}}:{}},i=cs(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 is(e){let{base:t,machines:n}=rs(e);return{...t,machines:n}}function as(e){let{base:t,machines:n}=rs(e);return{...t,workers:n}}function os(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=Yo({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 ss(e,t){return Xo({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 cs(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 ls(e){e.command(`create`).description(`Create a sandbox fleet`).option(`--fleet-id <id>`,`Stable fleet id (generated when omitted)`).option(`--count <n>`,`Number of worker machines`,`1`).option(`--environment <environment>`,`Named environment, container image, or built image ID for each machine`).option(`--cpu <cores>`,`CPU cores per machine`).option(`--memory <mb>`,`Memory in MB per machine`).option(`--disk <gb>`,`Disk in GB per machine`).option(`--accelerator-kind <kind>`,`Accelerator kind per machine, for example nvidia-l4 or nvidia-h100`).option(`--accelerator-count <count>`,`Accelerator devices per machine`).option(`--accelerator-memory <mb>`,`Minimum accelerator memory in MB per machine`).option(`--gpu-provider <provider>`,`GPU cloud provider per machine; omitted picks the cheapest configured provider`).option(`--gpu-worker-image <image>`,`GPU worker image override`).option(`--gpu-env <vars...>`,`Environment variables for each GPU worker (KEY=VALUE)`).option(`--gpu-max-spend-usd <usd>`,`Maximum spend per machine GPU lease`).option(`--gpu-max-lifetime <seconds>`,`Maximum GPU lease lifetime per machine in seconds`).option(`--gpu-idle-timeout <seconds>`,`Destroy each GPU lease after this many idle seconds`).option(`--driver <type>`,`Infrastructure driver type`).option(`--backend <id>`,`Agent backend type`).option(`--workspace <mode>`,`Workspace mode: isolated | shared`,`isolated`).option(`--max-spend-usd <n>`,`Fleet spend cap in USD (policy)`).option(`--max-lifetime <s>`,`Max machine lifetime in seconds (policy)`).option(`--spec <file.json>`,`Path to a JSON file describing the fleet (overrides synthesized machines)`).option(`--coordinator`,`Create a coordinator + workers fleet (routes to createWithCoordinator)`).action(async e=>{let{client:t}=U(e),n=P(`Creating fleet...`);n.start();let r=e.coordinator?await t.fleets.createWithCoordinator(as(e)):await t.fleets.create(is(e));n.stop();let i=qo(r.machines);e.json?j({fleetId:r.fleetId,machines:i}):(M(`Fleet created: ${r.fleetId}`),A(i,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`status`,header:`Status`,width:14}]))})}function us(e){e.command(`exec <fleet-id> <command>`).description(`Run a shell command across the fleet's machines`).option(`--machine <id...>`,`Restrict to a subset of machine ids (default: all)`).option(`--cwd <dir>`,`Working directory for the command`).option(`--timeout <ms>`,`Per-machine timeout in milliseconds`).option(`--max-concurrent <n>`,`Max concurrent dispatches`).action(async(e,t,n)=>{let{client:r}=U(n),i=P(`Dispatching command...`);i.start();let a=await(await r.fleets.list({fleetId:e})).dispatchExecDetailed(t,{machines:n.machine,cwd:n.cwd,timeoutMs:n.timeout?Number(n.timeout):void 0,maxConcurrent:n.maxConcurrent?Number(n.maxConcurrent):void 0});if(i.stop(),n.json)j(a);else{A(a.results.map(e=>({machineId:e.machineId,ok:e.ok,exitCode:e.result?.exitCode,durationMs:e.durationMs})),[{key:`machineId`,header:`Machine`,width:20},{key:`ok`,header:`OK`,width:6},{key:`exitCode`,header:`Exit`,width:8},{key:`durationMs`,header:`Duration(ms)`,width:14}]);for(let e of a.results){let t=e.result?.stdout,n=e.result?.stderr;t&&(console.log(`\n[${e.machineId}] stdout:`),console.log(t)),n&&(console.log(`\n[${e.machineId}] stderr:`),console.log(n)),e.error&&console.log(`\n[${e.machineId}] error: ${e.error.message}`)}}a.results.some(e=>e.ok===!1)&&(process.exitCode=1)}),e.command(`run [prompt]`).description(`Create a fleet of agents, run one turn on every agent, print each result, then delete the fleet`).requiredOption(`--agents <n|file>`,`Number of agents, or a JSON file with an array of agent specs (agentId, harness, model, profile or { profileId, revision }, task)`).option(`--placement <mode>`,`auto (pack by sandbox memory), dedicated (one sandbox per agent), or a number of agents per sandbox`,`auto`).option(`--model <id>`,`Model every agent runs, e.g. gpt-4.1-mini`).option(`--memory <mb>`,`Memory in MB per sandbox; auto placement packs by it`).option(`--environment <environment>`,`Environment for each sandbox`).option(`--max-spend-usd <usd>`,`Budget for the fleet in USD, enforced by the Platform on the fleet's own key`).option(`--timeout <ms>`,`Per-agent turn timeout in milliseconds`).option(`--fleet-id <id>`,`Stable fleet id (generated when omitted)`).option(`--parent-fleet <id>`,`Fleet that spawns this one; its cap must cover this cap`).option(`--parent-agent <id>`,`Agent of --parent-fleet that spawns this one`).option(`--keep`,`Keep the fleet after the run instead of deleting it`).action(async(e,t)=>{let n=/^\d+$/.test(t.agents)?Number(t.agents):JSON.parse(T(t.agents,`utf8`));if(!Array.isArray(n)&&e===void 0)throw Error(`A prompt is required unless --agents names a file whose agents carry tasks`);let{client:r}=U(t);if(!!t.parentFleet!=!!t.parentAgent)throw Error(`--parent-fleet and --parent-agent go together`);let i=t.placement===`auto`||t.placement===`dedicated`?t.placement:{agentsPerSandbox:Number(t.placement)},a=t.maxSpendUsd?Number(t.maxSpendUsd):void 0,o=P(`Creating fleet...`);o.start();let s=Date.now(),c=await r.fleets.create({fleetId:t.fleetId,agents:n,placement:i,defaults:{...t.environment?{environment:t.environment}:{},...t.memory?{resources:{memoryMB:Number(t.memory)}}:{},...t.model?{backend:{type:`opencode`,model:{model:t.model}}}:{}},...a===void 0?{}:{budgetUsd:a},...t.parentFleet?{parent:{fleetId:t.parentFleet,agentId:t.parentAgent}}:{}}),l=Date.now()-s;o.stop(),t.json||M(`Fleet ${c.fleetId}: ${c.agents.length} agents on ${c.machines.size} sandboxes in ${l} ms`);let u=[],d;try{for await(let n of c.run(e,{timeoutMs:t.timeout?Number(t.timeout):void 0})){if(n.type===`agent.finished`&&!t.json){let e=n.result;console.log(`[${e.agentId}] ${e.harness??`default`}/${e.model??`default`} ${e.status} ${e.durationMs}ms ${e.costUsd===void 0?`no cost reported`:`$${e.costUsd.toFixed(5)}`} ${e.result?.response??e.error??``}`)}n.type===`fleet.finished`&&(u=n.results,d=n.spend)}}finally{t.keep||await c.delete({continueOnError:!0})}t.json?j({fleetId:c.fleetId,createMs:l,sandboxes:c.machines.size,results:u,spend:d,deleted:!t.keep}):F({fleetId:c.fleetId,completed:u.filter(e=>e.status===`completed`).length,agents:u.length,spend:JSON.stringify(d),deleted:!t.keep}),u.some(e=>e.status!==`completed`)&&(process.exitCode=1)}),e.command(`cancel <fleet-id>`).description(`Interrupt every agent of a fleet and cancel its child fleets; sandboxes keep running`).action(async(e,t)=>{let{client:n}=U(t),r=await(await n.fleets.list({fleetId:e})).cancel();t.json?j({fleetId:e,...r}):M(`Fleet ${e}: interrupted ${r.interrupted} agents, cancelled ${r.children} child fleets`)})}const ds=[`list`,`create`,`delete`,`exec`,`prompt`,`read`,`write`];function fs(e){if(!(!e||e.length===0)){for(let t of e)if(!ds.includes(t))throw Error(`Invalid token action '${t}'. Allowed: ${ds.join(`, `)}`);return e}}function ps(e){return e.length<=12?`****`:`${e.slice(0,6)}...${e.slice(-4)} (masked — use --json for full value)`}function ms(e){e.command(`token <fleet-id>`).description(`Mint a scoped fleet bearer token (treated as a secret)`).option(`--action <a...>`,`Allowed actions: list create delete exec prompt read write (prompt grants nothing since fleet prompt dispatch was removed)`).option(`--ttl-minutes <n>`,`Token lifetime in minutes`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Minting fleet token...`);r.start();let i=await n.fleets.createToken(e,{actions:fs(t.action),ttlMinutes:t.ttlMinutes?Number(t.ttlMinutes):void 0});r.stop(),t.json?j(i):(F({"Fleet ID":i.fleetId,Token:ps(i.token),"Expires at":new Date(i.expiresAt).toISOString(),Actions:i.actions.join(`, `)}),console.log(`
146
146
  Re-run with --json to print the full token value.`))})}function hs(){let e=new b(`workspace`).description(`Manage a fleet's shared workspace`);return e.command(`snapshot <fleet-id>`).description(`Snapshot the fleet's shared workspace`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Creating workspace snapshot...`);r.start();let i=await n.fleets.createWorkspaceSnapshot(e);r.stop(),t.json?j(i):M(`Workspace snapshot created: ${i.snapshotId??i.id}`)}),e.command(`restore <fleet-id> <snapshot-id>`).description(`Restore the fleet's shared workspace from a snapshot`).action(async(e,t,n)=>{let{client:r}=U(n),i=P(`Restoring workspace...`);i.start();let a=await r.fleets.restoreWorkspaceSnapshot(e,t);i.stop(),n.json?j(a):M(`Workspace restored from ${a.snapshotId??t}`)}),e.command(`reconcile <fleet-id>`).description(`Re-mount the shared workspace on all fleet machines`).action(async(e,t)=>{let{client:n}=U(t),r=P(`Reconciling workspace...`);r.start();let i=await n.fleets.reconcileWorkspace(e);r.stop(),t.json?j(i):(F({"Fleet ID":i.fleetId,Checked:i.checked,"Orphaned mounts":i.orphanedMounts}),A(i.machines,[{key:`machineId`,header:`Machine`,width:20},{key:`sandboxId`,header:`Sandbox`,width:24},{key:`mounted`,header:`Mounted`,width:10}]))}),e}function gs(){let e=new b(`fleet`).description(`Manage sandbox fleets`);return ls(e),Jo(e),e.addCommand(hs()),us(e),Ko(e),ms(e),e}function _s(){let e=new b(`fs`).description(`File system operations on sandboxes`);return e.command(`upload`).description(`Upload a file to a sandbox`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<local-path>`,`Local file path`).argument(`<remote-path>`,`Remote destination path`).action(async(e,t,n,r)=>{let{context:i,client:a}=U(r),o=await G(a,i,e);if(o=await K(o),!w.existsSync(t))throw Error(`Local file not found: ${t}`);let s=w.statSync(t),c=Date.now();r.json||console.error(`Uploading ${t} to ${n}...`),await o.fs.upload(t,n,{onProgress:e=>{if(r.json)return;let t=e.percentage.toFixed(1);process.stderr.write(`\rProgress: ${t}% (${e.bytesUploaded}/${e.totalBytes} bytes)`)}});let l=Date.now()-c;r.json||console.error(``),r.json?j({success:!0,localPath:t,remotePath:n,size:s.size,durationMs:l}):console.log(`✓ Uploaded ${s.size} bytes in ${l}ms`)}),e.command(`download`).description(`Download a file from a sandbox`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<remote-path>`,`Remote file path`).argument(`<local-path>`,`Local destination path`).action(async(e,t,n,r)=>{let{context:i,client:a}=U(r),o=await G(a,i,e);o=await K(o);let s=Date.now();r.json||console.error(`Downloading ${t} to ${n}...`),await o.fs.download(t,n,{onProgress:e=>{if(r.json)return;let t=e.percentage.toFixed(1);process.stderr.write(`\rProgress: ${t}% (${e.bytesDownloaded}/${e.totalBytes} bytes)`)}});let c=Date.now()-s,l=w.statSync(n);r.json||console.error(``),r.json?j({success:!0,remotePath:t,localPath:n,size:l.size,durationMs:c}):console.log(`✓ Downloaded ${l.size} bytes in ${c}ms`)}),e.command(`ls`).description(`List directory contents`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`[path]`,`Directory path`,`.`).option(`-l, --long`,`Show detailed information`).option(`-a, --all`,`Include hidden files`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a);let o=await a.fs.list(t,{all:n.all,long:n.long});if(n.json)j(o);else if(n.long)Rt([`Mode`,`Owner`,`Group`,`Size`,`Modified`,`Name`],o.map(e=>{let t=e.isDir?`d`:e.isSymlink?`l`:`-`,n=vs(e.permissions),r=e.isDir?`<DIR>`:ys(e.size),i=e.modTime.toLocaleDateString();return[t+n,e.owner,e.group,r,i,e.name]}));else{let e=o.map(e=>e.isDir?`${e.name}/`:e.name);console.log(e.join(` `))}}),e.command(`stat`).description(`Get file or directory information`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to file or directory`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a);let o=await a.fs.stat(t);n.json?j(o):(console.log(` File: ${o.name}`),console.log(` Path: ${o.path}`),console.log(` Size: ${ys(o.size)} (${o.size} bytes)`),console.log(` Type: ${o.isDir?`directory`:o.isSymlink?`symlink`:`file`}`),console.log(` Mode: ${vs(o.permissions)} (${o.permissions.toString(8)})`),console.log(` Owner: ${o.owner}`),console.log(` Group: ${o.group}`),console.log(` Modified: ${o.modTime.toISOString()}`),console.log(` Accessed: ${o.accessTime.toISOString()}`))}),e.command(`cat`).description(`Print file contents`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to file`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a);let o=await a.read(t);n.json?j({path:t,content:o}):console.log(o)}),e.command(`rm`).description(`Delete a file or directory`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to delete`).option(`-r, --recursive`,`Delete directories recursively`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a),await a.fs.delete(t,{recursive:n.recursive}),n.json?j({success:!0,path:t,deleted:!0}):console.log(`✓ Deleted: ${t}`)}),e.command(`mkdir`).description(`Create a directory`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Directory path to create`).option(`-p, --parents`,`Create parent directories as needed`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a),await a.fs.mkdir(t,{recursive:n.parents}),n.json?j({success:!0,path:t,created:!0}):console.log(`✓ Created: ${t}`)}),e.command(`exists`).description(`Check if a path exists`).argument(`<sandbox-id-or-name>`,`Sandbox ID or name`).argument(`<path>`,`Path to check`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a);let o=await a.fs.exists(t);n.json?j({path:t,exists:o}):(console.log(o?`exists`:`not found`),process.exit(+!o))}),e}function vs(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 ys(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 bs(){let e=new b(`git`).description(`Git operations in a sandbox workspace`);return e.command(`status`).description(`Show git repository status`).argument(`<id-or-name>`,`Sandbox ID or name`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching status...`);t.json||i.start();let a=await G(r,n,e);a=await K(a);let o=await a.git.status();if(i.stop(),t.json)j(o);else if(!o.isRepo)console.log(`No git repository in the sandbox workspace.`);else{if(console.log(`Branch: ${o.branch??`unknown`}`),console.log(`HEAD: ${o.head.slice(0,7)||`(no commits)`}`),console.log(`Dirty: ${o.isDirty?`yes`:`no`}`),o.ahead&&console.log(`Ahead: ${o.ahead}`),o.behind&&console.log(`Behind: ${o.behind}`),o.staged.length>0){console.log(`\nStaged (${o.staged.length}):`);for(let e of o.staged)console.log(` + ${e}`)}if(o.modified.length>0){console.log(`\nModified (${o.modified.length}):`);for(let e of o.modified)console.log(` M ${e}`)}if(o.untracked.length>0){console.log(`\nUntracked (${o.untracked.length}):`);for(let e of o.untracked)console.log(` ? ${e}`)}}}),e.command(`log`).description(`Show commit log`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`-n, --limit <count>`,`Max commits to show`,`10`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching log...`);t.json||i.start();let a=await G(r,n,e);a=await K(a);let o=await a.git.log(Number.parseInt(t.limit,10));if(i.stop(),t.json)j(o);else if(o.length===0)console.log(`No commits found`);else for(let e of o)console.log(`${e.shortSha} ${e.message.split(`
147
147
  `)[0]} (${e.author}, ${e.date.toLocaleDateString()})`)}),e.command(`diff`).description(`Show diff`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--ref <ref>`,`Ref to diff against`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching diff...`);t.json||i.start();let a=await G(r,n,e);a=await K(a);let o=await a.git.diff(t.ref);i.stop(),t.json?j(o):o.raw?console.log(o.raw):console.log(`${o.additions} additions, ${o.deletions} deletions across ${o.files.length} files`)}),e.command(`add`).description(`Stage files`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<paths...>`,`Paths to stage`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a),await a.git.add(t),M(`Staged: ${t.join(`, `)}`)}),e.command(`commit`).description(`Create a commit`).argument(`<id-or-name>`,`Sandbox ID or name`).requiredOption(`-m, --message <msg>`,`Commit message`).option(`--amend`,`Amend the previous commit`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=await G(r,n,e);i=await K(i);let a=await i.git.commit(t.message,{amend:t.amend});t.json?j(a):M(`Committed: ${a.shortSha} ${a.message}`)}),e.command(`push`).description(`Push to remote`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--force`,`Force push`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Pushing...`);i.start();let a=await G(r,n,e);a=await K(a),await a.git.push({force:t.force}),i.stop(),M(`Pushed to remote`)}),e.command(`pull`).description(`Pull from remote`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--rebase`,`Rebase instead of merge`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Pulling...`);i.start();let a=await G(r,n,e);a=await K(a),await a.git.pull({rebase:t.rebase}),i.stop(),M(`Pulled from remote`)}),e.command(`branches`).description(`List branches`).argument(`<id-or-name>`,`Sandbox ID or name`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching branches...`);t.json||i.start();let a=await G(r,n,e);a=await K(a);let o=await a.git.branches();i.stop(),t.json?j(o):o.length===0?console.log(`No branches found`):Rt([`Name`,`Current`,`Remote`],o.map(e=>[e.name,e.current?`* `:` `,e.upstream??`-`]))}),e.command(`checkout`).description(`Checkout a branch or ref`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<ref>`,`Branch name or ref`).option(`-b, --create`,`Create a new branch`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a),await a.git.checkout(t,{create:n.create}),M(`Checked out: ${t}${n.create?` (new)`:``}`)}),e}function xs(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 x(`sha256`).update(n).digest(`hex`).slice(0,t)}Object.freeze([`HS256`]),Object.freeze([`RS256`]);async function Ss(e,t,n=`tangle --help`){let r=new AbortController,i=e??r.signal,a=()=>{r.abort(),process.stderr.write(`Stopping…
148
- `)};e||(process.once(`SIGINT`,a),process.once(`SIGTERM`,a));try{return i.throwIfAborted(),await t(i)}catch(e){if(!i.aborted||e instanceof I&&e.code===`RUN_STOPPED`)throw e;let t=new I(`RUN_STOPPED`,`Command interrupted`,`A stop request ended this execution`,n);throw e instanceof Error&&`runId`in e&&typeof e.runId==`string`&&Object.assign(t,{runId:e.runId}),t}finally{e||(process.off(`SIGINT`,a),process.off(`SIGTERM`,a))}}const Cs=`claude,codex,kimi,opencode,gemini,pi`;function ws(e,t){let n;return async(r,{node:i,lastCandidate:a})=>{t.throwIfAborted();let o;try{o=r===void 0?void 0:ce(r)}catch(e){throw e instanceof Error&&Object.assign(e,{node:i,seat:r,fixCommand:`tangle graph run --help`}),e}n??=Je({cwd:e,signal:t,config:Ye({...process.env,BRIDGE_BACKENDS:Cs,BRIDGE_SUBSCRIPTIONS_ONLY:`1`})});let s=await n;t.throwIfAborted();let c=e=>e.authentication?.status===`authenticated`&&e.authentication.authMode===`subscription`,l=o?.harness??s.find(e=>e.provider&&c(e))?.backend,u=s.filter(e=>e.backend===l),d=u.filter(c),f=o?u.find(e=>e.id===`${o.harness}/${o.model}`)??d.find(e=>e.provider===o.provider):d.find(e=>e.default)??d.find(e=>e.recommended)??d[0];if(!f||!c(f)){if(a===!1)return;let e=f?.authentication??u[0]?.authentication??(o?void 0:s.find(e=>e.authentication?.fix)?.authentication);throw Object.assign(new I(o?`SEAT_NOT_LOGGED_IN`:`SEAT_NONE_DETECTED`,`Node '${i}' has no available subscription${o?` for ${o.harness}`:``}`,e?`Selected provider: ${e.status} (${e.authMode})`:`No authenticated subscription route was detected`,e?.fix??`tangle graph run --help`),{node:i,seat:r})}let p=o?.harness??ce(f.id).harness,m=o?.provider??f.provider,h=o?.model??f.id.slice(p.length+1);if(!m||!h)throw new I(`MODEL_PROVIDER_MISMATCH`,`Node '${i}' has an unresolved model provider`,`Bridge has no configured provider for ${r??p}`,`tangle graph run --help`);return{harness:p,provider:m,model:h,selector:{kind:`all-eligible`},...o?.reasoningEffort===void 0?{}:{reasoningEffort:o.reasoningEffort}}}}async function Ts(e,t,n){let r=`tangle secret create ${Ke(t)} --from-login claude`,i=(e,t=r)=>new I(`NATIVE_CREDENTIAL_GRANT_FAILED`,`Claude subscription enrollment failed`,e,t),a;try{a=new URL(e.getBaseUrl())}catch{throw i(`The Sandbox API URL is invalid`,`tangle auth login`)}if(a.protocol!==`https:`||a.username||a.password||a.search||a.hash)throw i(`Native credentials require a credential-free HTTPS Sandbox API URL`,`tangle auth login`);if(!Qe.safeParse({account:`cli`,secretEnv:t,format:`token`}).success)throw i(`The secret name is not valid for a native credential reference`,`tangle secret create --help`);return process.stderr.write(`Authorize Claude in its native browser. Store the token as ${t} at ${a.href}. The token stays out of terminal output.\n`),Ss(n,async n=>{let r=await Es(n,i);n.throwIfAborted();let a=await e.secrets.create(t,r).catch(e=>{if(n.aborted)return;let t=e instanceof u?e.status:void 0;throw i(t?`Sandbox secret storage returned HTTP ${t}; enrollment is unconfirmed`:`Sandbox secret storage did not confirm enrollment`,t===401||t===403?`tangle auth login`:`tangle secret list --json`)});if(await Ne(),n.aborted)throw new I(`RUN_STOPPED`,`Native enrollment interrupted`,`Secret upload may already have completed`,`tangle secret list --json`);if(!a||a.name!==t)throw i(`The Sandbox API did not confirm the requested secret name`);return a},r)}async function Es(e,t){let n=new AbortController,r=qe({command:`claude`,args:[`setup-token`],cwd:process.cwd(),signal:AbortSignal.any([e,n.signal]),timeoutMs:12e4,spawnOptions:{stdio:[process.stdin,`pipe`,`pipe`],detached:!1},env:{ANTHROPIC_API_KEY:void 0,ANTHROPIC_AUTH_TOKEN:void 0,CLAUDE_CODE_OAUTH_TOKEN:void 0,ANTHROPIC_BASE_URL:void 0}}),i=``,a=!1,o=new Set,s=e=>{if(!a){if(Buffer.byteLength(i)+e.length>65536){a=!0,i=``,n.abort();return}i+=e.toString(`utf8`);for(let e of i.split(`\x1B]8;;`).slice(1)){let t=Math.min(...[e.indexOf(`\x07`),e.indexOf(`\x1B\\`)].filter(e=>e>=0));if(!Number.isFinite(t))continue;let n=e.slice(0,t);if(!URL.canParse(n))continue;let r=new URL(n);![`https://platform.claude.com/oauth/authorize`,`https://claude.com/cai/oauth/authorize`].includes(`${r.origin}${r.pathname}`)||r.username||r.password||r.hash||/sk-ant-|(?:access_token|refresh_token|id_token|code|key)=/.test(r.href)||![`client_id`,`state`,`redirect_uri`,`code_challenge`].every(e=>r.searchParams.has(e))||o.has(r.href)||(o.add(r.href),process.stderr.write(`Open to authorize Claude:\n${r.href}\n`))}Ze(i).includes(`Paste code here`)&&!o.has(`code`)&&(o.add(`code`),process.stderr.write(`Paste the code shown in your browser into this terminal and press Enter: `))}};r.process.stdout?.on(`data`,s),r.process.stderr?.on(`data`,s);let c=await r.exitPromise;if(e.throwIfAborted(),!c.success||a)throw t(a?`Native consent output exceeded its private capture bound`:c.timedOut?`Native browser consent timed out`:c.spawnError?`The native claude command could not start`:`Native consent exited ${c.code??c.signal??`without a result`}`);let l=[...new Set([...Ze(i).matchAll(/Your OAuth token \(valid for[^\n]*\):\s+([\s\S]*?)\s+Store this token securely/g)].map(e=>e[1].replace(/\s/g,``)))];if(i=``,l.length!==1||!/^sk-ant-oat\d+-[A-Za-z0-9_-]+$/.test(l[0]))throw t(`Native consent returned no unambiguous subscription token`);return l[0]}async function Ds(e,t,n){let r=new Map;for(let e of new Set(t)){if(e!==`claude-code`&&e!==`codex`)throw new I(`NATIVE_CREDENTIAL_UNSUPPORTED`,`Cloud subscription grant for ${e} is unavailable`,`This Sandbox native credential channel supports Claude Code and Codex`,`tangle graph run --help`);r.set(e,{account:`cli`,secretEnv:e===`claude-code`?`CLAUDE_TOKEN`:`CODEX_AUTH`,format:e===`claude-code`?`token`:`bundle`})}let i=await e.secrets.list();for(let[t,a]of r)if(n.throwIfAborted(),!i.some(e=>e.name===a.secretEnv)){if(t!==`claude-code`)throw new I(`NATIVE_CREDENTIAL_NOT_ENROLLED`,`Codex cloud credential is not enrolled`,`A local Codex login does not grant the Sandbox API a stored credential reference`,`tangle secret create CODEX_AUTH --value-stdin`);await Ts(e,a.secretEnv,n)}return r}function J(e){throw new I(`GRAPH_INVALID`,`Graph creation failed`,e,`tangle graph new --help`)}function Os(e){return typeof e==`string`&&/^[a-z0-9][a-z0-9-]{0,62}$/i.test(e)}const ks={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 As=class{owned;lastFailure;pending=Promise.resolve();revision=0;sealed=!1;constructor(e,t,n){this.directory=e,this.options=t,this.cwd=n}async digest(e=this.owned){e||J(`No graph file was saved`);let t=await Ue(e.file,ue.O_RDONLY|ue.O_NOFOLLOW);try{let[n,r]=await Promise.all([t.stat(),e.handle.stat()]);return(!n.isFile()||n.dev!==r.dev||n.ino!==r.ino)&&J(`The owned graph file was replaced`),Cc(await t.readFile())}finally{await t.close()}}enqueue(e){let t=++this.revision,n=this.pending.then(()=>e(t));return this.pending=n.then(()=>void 0,()=>void 0),n}check=()=>this.enqueue(async e=>{let t=this.owned;if(!t?.result)return!1;let{digest:n,result:r}=t,i=await this.digest(t),a=this.revision===e&&this.owned===t&&t.digest===n&&t.result===r&&i===n;return a&&(this.sealed=!0),a});receipt(){this.owned?.result||J(`No successful graph run was recorded`);let{file:e,digest:t,result:n}=this.owned;return{file:e,digest:t,result:n}}invoke(e,t){return this.sealed&&J(`The graph is accepted; submit its recorded successful run`),this.enqueue(()=>this.write(e,t)).catch(e=>(this.lastFailure=e,{ok:!1,diagnostic:Yt(e)}))}async write(e,t){t.throwIfAborted(),this.lastFailure=void 0;let n=e;(!n||!Os(n.name)||typeof n.source!=`string`||typeof n.run!=`boolean`||Object.keys(n).some(e=>![`name`,`source`,`run`].includes(e)))&&J(`Expected only name, source and boolean run`),this.options.name!==void 0&&n.name!==this.options.name&&J(`The graph name must match --name`),this.owned&&(this.owned.result=void 0);let r=D(this.directory,`${n.name}.yaml`);if(this.owned&&this.owned.file!==r&&J(`This invocation owns one named graph file`),!this.owned)try{this.owned={file:r,handle:await Ue(r,ue.O_RDWR|ue.O_CREAT|ue.O_EXCL|ue.O_NOFOLLOW,384),digest:Cc(``)}}catch(e){throw e.code===`EEXIST`&&J(`Graph already exists: ${r}; choose another --name`),e}let i=this.owned;await this.digest()!==i.digest&&J(`The owned graph was changed`);let a=Buffer.from(n.source);for(let e=0;e<a.length;){let{bytesWritten:t}=await i.handle.write(a,e,a.length-e,e);if(!t)throw Error(`Graph file write made no progress`);e+=t}await i.handle.truncate(a.length),await i.handle.sync(),i.digest=Cc(a);let o={...this.options,param:[]},s={cwd:this.cwd,signal:t,source:n.source},c=await Ac(r,{...o,dryRun:!0},{...s,connectNeeds:!0});if(`graph`in c||J(`No canonical graph was returned`),c.graph.deliverable.checkRef===`command`&&J(`Host command checks need a jailed verifier node`),await this.digest()!==i.digest&&J(`Graph changed during validation`),!n.run)return{file:r,graphDigest:c.graph.digest,validated:!0};let l=await Ac(r,o,{...s,graphDigest:c.graph.digest});return(!(`status`in l)||l.status!==`winner`||l.graphDigest!==c.graph.digest||await this.digest()!==i.digest)&&J(`The graph must succeed with unchanged YAML`),i.result=l,this.receipt()}async close(){await this.pending,await this.owned?.handle.close()}};async function js(e,t,n){let{runId:r,runDir:i,cwd:a,bridge:o,signal:s}=e,c=await o(),l=D(await Ge(D(Ce(),`.tangle`)),`graphs`);(wc(a,l)||wc(l,a))&&J(`The graph store must be outside the agent workspace; choose another working directory`);try{await He(l,{mode:448})}catch(e){if(e.code!==`EEXIST`)throw e}await Ge(l)!==l&&J(`The graph store redirects outside its canonical location`);let u=n.seat??B().seat,d=await ws(a,s)(u,{node:`graph-designer`,cwd:a,signal:s,lastCandidate:!0});d||J(`No authenticated native subscription is available`);let{graphDesignerProfile:f}=await import(`@tangle-network/agent-runtime/profiles`),{supervisePursuit:p}=await import(`@tangle-network/agent-runtime/durable`),m=f({profile:{name:`graph-designer`,harness:d.harness,model:{provider:d.provider,default:d.model,...d.reasoningEffort===void 0?{}:{reasoningEffort:d.reasoningEffort}},prompt:{instructions:[`You are the sole graph designer. Author a canonical YAML graph for the requested intent, then qualify and run it using write_graph. Its nodes are complete AgentProfiles with a real independent verifier and declarative route/data outside check. Command checks execute on the host and are refused here; put executable verification in the verifier node's normal native tools. Read the supplied skills and preserve the user's task and authority.`,`Call write_graph with name, complete YAML source and run:false to validate; repair its concrete diagnostics, then call it with the identical source and run:true. The graph schema and executor are owned by the installed loader. Supply defaults for parameters needed by the first run. Only a real successful host run of the unchanged saved file passes. Submit that evidence using submit_result; explain concrete blockers using report_blocked.`]},tools:{agent_runtime_coordination_write_graph:!0,agent_runtime_coordination_submit_result:!0,agent_runtime_coordination_read_continuation:!0,agent_runtime_coordination_report_blocked:!0}}}),h=oe(m),g=new As(l,{...n,seat:u},a),_={maxIterations:6,maxTokens:3e4,deadlineMs:3e5};try{let e=await p(m,{intent:t,name:n.name},{pursuitId:r,runId:r,runDir:i,signal:s,backend:{...c,timeoutMs:_.deadlineMs},budget:_,maxDepth:0,coordination:{authentication:!0,requestTimeoutMs:_.deadlineMs},deliverable:{describe:`The saved graph succeeds with unchanged YAML`,check:g.check,checkState:g.check},continuation:ks,resolveSupervisorTools:e=>e.runId!==r||e.nodeId!==r||e.depth!==0||e.identity.profileDigest!==h?[]:[{name:`write_graph`,description:`Save, validate and run this graph.`,inputSchema:{type:`object`,properties:{name:{type:`string`},source:{type:`string`},run:{type:`boolean`}},required:[`name`,`source`,`run`],additionalProperties:!1},handler:(t,n)=>((n.nodeId!==e.nodeId||n.ownerId!==e.ownerId||n.runId!==e.runId)&&J(`Wrong graph tool owner`),g.invoke(t,n.signal))}]});if(e.result.kind===`no-winner`||!await g.check()){if(g.lastFailure)throw g.lastFailure;let t=e.result.kind===`no-winner`?e.result.error?.message??e.result.reason:`The graph file changed after its successful run`;throw Object.assign(new I(`GRAPH_DESIGN_FAILED`,`Graph design did not finish`,t,`tangle graph new --help`),{runId:r,node:`graph-designer`})}return g.receipt()}finally{await g.close()}}function Ms(e){e.command(`new <intent>`).description(`Design, validate and run one portable graph`).option(`--seat <seat>`,`Use harness/model@effort for the designer and graph`).option(`--name <name>`,`Save this graph name`).action(async(e,t)=>{process.env.BRIDGE_JAIL_RW_PATHS?.trim()&&J(`Remove BRIDGE_JAIL_RW_PATHS before graph new; extra native write roots cannot contain its host store`),t.name!==void 0&&!Os(t.name)&&J(`Use letters, numbers and hyphens in --name`);let n=await Ec({},n=>js(n,e,t));t.json?j(n):N(`Created ${n.file} · run ${n.result.runId}`)})}async function Ns(e){if(!tr(e.apiKey)){if(e.json||e.dryRun||!process.stdin.isTTY)return;await Fi({baseUrl:e.sandboxBaseUrl,signal:e.signal})}return W(e)}async function Ps(e,t,n){let r=Qs(t.parameter),i=n??await Ns(t);if(!i)throw new I(`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?(j(ec(a)),a):($s(a,t.browser===!1?!1:await Ei(a.redirectUrl),t.wait),a)}async function Fs(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 Ps(t,{...n,wait:!0},e);for(;!i&&Date.now()<Date.parse(a.expiresAt);)await Pe(1e3,void 0,{signal:n.signal}),i=await r();return i}function Is(){let e=new b(`hub`).description(`Discover and run Tangle Hub tools`);e.command(`connect`).description(`Connect a provider account`).argument(`provider`,`Provider to connect`).option(`--no-browser`,`Print the authorization URL instead of opening it`).option(`--parameter <key=value>`,`Provider-specific OAuth value. Repeatable.`,(e,t)=>[...t,e],[]).action(async(e,t)=>{await Ps(e,t)});let t=new b(`connections`).description(`List Hub provider connections`).action(async e=>{let t=await(await W(e)).connections.list();if(e.json){j(t);return}Zs(t.connections)});t.command(`revoke <connection-id>`).description(`Revoke a Hub provider connection`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=await W(t),r=await Cr(n,e);if(!t.force&&!await ei(`Revoke Hub connection ${r}? `,`--force`)){N(`Revoke cancelled.`);return}let i=await n.connections.revoke(r);if(t.json){j(i);return}N(`Revoked Hub connection ${i.connection.id}.`)}),e.addCommand(t);let n=new b(`permissions`).description(`Manage Hub action permissions`);n.command(`list`).description(`List Hub permissions for a connection`).requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);let t=await W(e),n=await Cr(t,e.connection),r=await t.permissions.list(n);if(e.json){j(r);return}Ks(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=qs(e.decision),n=await W(e),r=await Cr(n,e.connection),i=await n.permissions.set({connectionId:r,actionPath:e.action,decision:t});if(e.json){j(i);return}Ks([i.policy])}),n.command(`revert-writes`).description("Revoke a bulk `--allow-writes` grant for a connection (deletes only the auto-granted write rows; manual permissions are untouched)").requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);let t=await W(e),n=await Cr(t,e.connection),r=await t.permissions.revertWrites(n);if(e.json){j(r);return}N(`Reverted ${r.reverted} write permission${r.reverted===1?``:`s`} for connection ${r.connectionId}.`)}),e.addCommand(n),e.addCommand(Rs());let r=new b(`tools`).description(`Discover Hub tools`);return r.command(`sources`).description(`List Hub tool sources`).action(async e=>{let t=await(await W(e)).tools.sources();if(e.json){j(t);return}Js(t.sources)}),r.command(`describe`).description(`Describe a Hub tool`).argument(`path`,`Executor tool path`).action(async(e,t)=>{let n=await(await W(t)).tools.describe(e);if(t.json){j(n);return}Ys(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 W(t)).tools.search(e.join(` `),{provider:t.provider});if(t.json){j(n);return}Gs(n.tools)}),e.addCommand(r),e.addCommand(Ls(`call`)),e.addCommand(Ls(`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(Bs(e),t.cancel)throw Error(`Hub approval resume does not support --cancel. Use --decline to deny the approval.`);if(t.accept&&t.decline)throw Error(`Choose only one of --accept or --decline.`);if(!t.accept&&!t.decline)throw Error(`Choose --accept to approve or --decline to deny the Hub approval.`);let n=await W(t);Hs(t.decline?await n.approvals.deny(e):await n.approvals.approve(e),t.json===!0)}),e.command(`status`).description(`Show Hub auth and connection status`).action(async e=>{let t=await(await W(e)).status();if(e.json){j(t);return}tc(t)}),e}function Ls(e){return new b(e).description(`Execute a Hub tool`).argument(`<args...>`,`Tool path tokens followed by JSON input`).option(`--connection <ref>`,`Hub connection id, or provider[:account]`).option(`--auto-approve`,`Approve a HUB_APPROVAL_REQUIRED execution and retry once`).option(`--approve`,`Alias for --auto-approve`).option(`--no-hub-key`,`Do not auto-mint a platform Hub key; use the stored credential as-is`).action(async(e,t)=>{let{args:n,approve:r}=zs(e,t),{path:i,input:a}=Ws(n),o=await W(t),s=t.connection?await Cr(o,t.connection):void 0;j((await o.tools.invoke(i,a,{connectionId:s,approve:r})).result)})}function Rs(){let e=new b(`approvals`).description(`List and resolve Hub execution approvals`);e.command(`list`).description(`List pending Hub execution approvals`).action(async e=>{let t=await(await W(e)).approvals.list();if(e.json){j(t);return}Vs(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)=>{Bs(e),Hs(await(await W(n)).approvals[t](e),n.json===!0)});return e}function zs(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 Bs(e){if(!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`Hub approval ID must contain only letters, numbers, underscores, and dashes.`)}function Vs(e){A(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 Hs(e,t){if(t){j(Us(e));return}N(`Hub approval ${e.approval.id} ${e.approval.status}.`),e.capabilityToken&&N("Capability token minted. Re-run the original command with `--approve` to execute automatically.")}function Us(e){return{approval:e.approval,...e.capabilityToken?{capabilityToken:{tokenId:e.capabilityToken.tokenId,expiresAt:e.capabilityToken.expiresAt}}:{}}}function Ws(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 Gs(e){A(e.map(e=>({...e,provider:e.providerId??e.requiredConnectionProviderId,connection:Xs(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 Ks(e){A(e,[{key:`connectionId`,header:`Connection`},{key:`providerId`,header:`Provider`},{key:`actionPath`,header:`Action`},{key:`decision`,header:`Decision`},{key:`updatedAt`,header:`Updated`}])}function qs(e){if(e===`allow`||e===`ask`||e===`deny`)return e;throw Error(`--decision must be one of: allow, ask, deny.`)}function Js(e){A(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 Ys(e){F({Path:e.path,Provider:e.providerId??e.requiredConnectionProviderId,Title:e.title,Description:e.description,Connection:Xs(e),Policy:e.policyState}),e.inputSchema!==void 0&&(N(`Input schema`),console.log(JSON.stringify(e.inputSchema,null,2))),e.outputSchema!==void 0&&(N(`Output schema`),console.log(JSON.stringify(e.outputSchema,null,2)))}function Xs(e){if(e.connectionRequired===!1)return`not required`;if(e.connectionStatus)return e.connectionStatus}function Zs(e){A(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 Qs(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 $s(e,t,n=!1){t?N(`Opened browser to connect ${e.provider}.`):(N(`Open this URL to connect ${e.provider}:`),console.log(e.redirectUrl)),N(n?`Finish authorization in the browser; this run resumes when connected.`:"Finish authorization in the browser, then rerun `tangle hub status`.")}function ec(e){return{provider:e.provider,redirectUrl:e.redirectUrl,expiresAt:e.expiresAt,scopes:e.scopes,cli:e.cli}}function tc(e){let{principal:t,connections:n}=e;N(`Hub status`),F({Principal:t.kind,"User ID":t.userId,"API Key ID":t.apiKeyId,"Sandbox ID":t.sandboxId,"Connected Providers":n.connectedProviderCount,"Unhealthy Providers":n.unhealthyProviderCount}),n.unhealthyProviderCount>0&&N(`Some providers require reconnect.`)}const nc=[`claude-code`,`opencode`,`codex`,`kimi-code`,`prime`],rc=process.env.TANGLE_ROUTER_URL??`https://router.tangle.tools/v1`;function ic(e){let t=se(e);if(t)return t;throw Error(`--model '${e}' has no provider. Pass a canonical id, for example 'google/${e}'.`)}function ac(e){let t=e.harness??`claude-code`;if(!nc.includes(t))throw Error(`Unknown --harness '${t}'. Supported: ${nc.join(`, `)}.`);let n=oc(e.maxTokens,2e5,`--max-tokens`),r=oc(e.maxIterations,50,`--max-iterations`),i=e.maxWorkers===void 0?void 0:oc(e.maxWorkers,0,`--max-workers`);return{harness:t,...e.model?{model:e.model}:{},maxTokens:n,maxIterations:r,...i===void 0?{}:{maxWorkers:i}}}function oc(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 sc(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 cc(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 lc=null;function uc(){return lc??=import(`@tangle-network/agent-runtime/kernel`).catch(e=>{throw lc=null,e?.code===`ERR_MODULE_NOT_FOUND`?new I(`RUNTIME_UNAVAILABLE`,`Agent Runtime could not be loaded`,e.message,`npm install -g @tangle-network/sandbox-cli@latest`):e}),lc}async function dc(e,t,n){let r=V({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=H(r),{budget:a,perWorker:o}=sc(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||N(`worker ${a.id} spawned`),a}},l=await uc(),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-2.5-flash-lite`,provider:t.model?ic(t.model):`google`},tools:{agent_runtime_coordination_spawn_worker:!0,agent_runtime_coordination_observe_agent:!0}},p={routerBaseUrl:rc,routerKey:r.apiKey},m=cc(await l.supervise(f,{goal:e},{budget:a,makeWorkerAgent:d,router:p,...o?{perWorker:o}:{},...t.model?{allowedModels:[t.model]}:{},runId:`supervise-${C()}`})),h=m.status===`winner`?`settled`:`failed`;for(let e of s)e.status=h,n.json||N(`worker ${e.id} settled (${e.status})`);return{task:e,result:m.text,workers:s,tokenUsage:m.tokenUsage,costUsd:m.costUsd,status:m.status}}function fc(){let e=new b(`supervise`);return e.description(`Run a budget-conserving supervisor that spawns isolated sandbox workers to deliver a task.`).argument(`<task>`,`What the supervisor should accomplish`).option(`--harness <name>`,`Worker harness (${nc.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=ac({harness:t.harness,model:t.model,maxTokens:t.maxTokens,maxIterations:t.maxIterations,maxWorkers:t.maxWorkers});t.json||(N(`Supervising: ${e}`),N(`harness=${n.harness} budget=${n.maxTokens}tok/${n.maxIterations}it`),console.log());let r=await dc(e,n,{apiKey:t.apiKey,baseUrl:t.baseUrl,json:t.json});if(t.json){j(r),r.status!==`winner`&&(process.exitCode=1);return}if(console.log(),r.result&&(console.log(r.result),console.log()),F({"Input Tokens":r.tokenUsage.input??`Unavailable`,"Output Tokens":r.tokenUsage.output??`Unavailable`,Cost:r.costUsd===null?`Unavailable`:`$${r.costUsd.toFixed(4)}`}),r.status!==`winner`)throw Error(`Supervisor finished without a winner: ${r.status}`)}),e}function Y(e){return Hr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.baseUrl===void 0?{}:{baseUrl:e.baseUrl}})}const pc=1e3;function mc(e,t){return[...t,e]}function hc(e,t=`input`,n){if(n===void 0&&!e?.length)return;let r={};if(n!==void 0)try{if(r=JSON.parse(T(n,`utf8`)),!r||typeof r!=`object`||Array.isArray(r)||Object.entries(r).some(([e,t])=>!e.length||typeof t!=`string`))throw Error(`Invalid input map`)}catch{throw new I(`WORKFLOW_INPUT_FILE_INVALID`,`Could not load --input-file '${n}'`,`Expected a readable JSON object with nonempty keys and string values`,`tangle workflows run --help`)}let i=Object.entries(r);for(let n of e??[]){let e=n.indexOf(`=`);if(e<=0)throw Error(`Invalid --${t} "${n}": expected key=value (e.g. pull_request.number=123)`);i.push([n.slice(0,e),n.slice(e+1)])}return Object.fromEntries(i)}function gc(e){A(e.map(e=>({id:e.id,status:e.status,attempts:e.attempts,created:e.createdAt,completed:e.completedAt??``})),[{key:`id`,header:`Run ID`},{key:`status`,header:`Status`},{key:`attempts`,header:`Attempts`},{key:`created`,header:`Created`},{key:`completed`,header:`Completed`}])}function _c(e){if(F({"Run ID":e.id,Workflow:e.workflowId,Status:e.status,Error:e.error??``,Attempts:e.attempts,Created:e.createdAt,Started:e.startedAt??``,Completed:e.completedAt??``}),e.actionResults.length>0){N(`Actions`);let t=e.actionResults.some(e=>e.nodeId!==void 0||e.visit!==void 0);A(e.actionResults.map(e=>({index:e.index,...t?{node:e.nodeId??``,visit:e.visit??``}:{},kind:e.kind,status:e.status,error:e.error??``,cost:e.costUsd??``})),[{key:`index`,header:`#`},...t?[{key:`node`,header:`Node`},{key:`visit`,header:`Visit`}]:[],{key:`kind`,header:`Kind`},{key:`status`,header:`Status`},{key:`error`,header:`Error`},{key:`cost`,header:`Cost (USD)`}])}e.graph&&(N(`Graph`),F({Nodes:e.graph.nodes.length,Edges:e.graph.edges.length,"Max node visits":e.graph.maxNodeVisits}),A(e.graph.edges.map(e=>({from:e.from,to:e.to,guard:e.when===void 0?``:JSON.stringify(e.when)})),[{key:`from`,header:`From`},{key:`to`,header:`To`},{key:`guard`,header:`Guard`}])),e.edgeVerdicts&&e.edgeVerdicts.length>0&&(N(`Edge verdicts`),A(e.edgeVerdicts.flatMap(e=>Object.entries(e.verdicts).map(([t,n])=>({node:e.nodeId,edge:t,verdict:n?`taken`:`not taken`}))),[{key:`node`,header:`Node`},{key:`edge`,header:`Edge`},{key:`verdict`,header:`Verdict`}]))}function vc(e){if(e.status===`cancelled`){N(`Cancelled run ${e.runId}.`);return}if(e.signalled){N(`Cancelling run ${e.runId} — signalled the worker; it will stop shortly.`);return}N(`Requested cancellation of run ${e.runId}, but couldn't confirm it — the run may have just finished, or it's running on another instance and will stop on its own.`)}function yc(e){switch(e.type){case`snapshot`:N(`snapshot: ${e.run.status} (${e.run.actionResults.length} action(s))`);break;case`action.started`:console.log(`→ action[${e.index}] ${e.kind} started`);break;case`action.finished`:{let t=e.status===`succeeded`?`✓`:e.status===`skipped`?`⊘`:`✗`;console.log(`${t} action[${e.index}] ${e.kind} ${e.status}${e.error?`: ${e.error}`:``}`);break}case`iteration.started`:console.log(` · action[${e.actionIndex}] iteration ${e.iterationIndex} started`);break;case`iteration.ended`:console.log(` · action[${e.actionIndex}] iteration ${e.iterationIndex} ${e.status}`);break;case`token`:typeof e.delta==`string`&&process.stdout.write(e.delta);break;case`ping`:break;case`run.done`:console.log(`\nrun.done: ${e.status}${e.error?`: ${e.error}`:``}`);break;case`run.waiting`:console.log(`\nrun.waiting: parked on a human decision (${e.decisionId}) — resolve it to resume`);break}}function bc(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.`,mc,[]).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=hc(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 Y(t),{runId:o}=await a.workflows.run(e,n);if(!t.wait){if(t.json)return j({runId:o});N(`Started run ${o} for workflow ${e}.`),N(`Inspect it with: tangle workflows run-detail ${e} ${o}`);return}let s=t.json?null:P(`Waiting for run ${o} to finish...`).start(),c;try{c=await a.workflows.waitForRun(e,o,{...r===void 0?{}:{timeoutMs:r},...i===void 0?{}:{pollIntervalMs:i}})}finally{s?.stop()}if(c.status===`failed`&&(process.exitCode=1),t.json)return j(c);_c(c)}),e.command(`runs`).description(`List a workflow's run history (newest first)`).argument(`<id>`,`Workflow ID`).option(`--limit <n>`,`Runs per page (1-100)`).option(`--cursor <cursor>`,`Pagination cursor from a previous page`).option(`--all`,`Fetch every page, not just the first`).action(async(e,t)=>{let n=await Y(t),r=t.limit===void 0?void 0: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>=pc){s=c.nextCursor,t.json||N(`Stopped after ${pc} pages (${i.length} runs); more may exist — resume with --cursor ${c.nextCursor}`);break}a=c.nextCursor}if(t.json)return j({runs:i,nextCursor:s});gc(i);return}let i=await n.workflows.listRuns(e,{...r===void 0?{}:{limit:r},...t.cursor===void 0?{}:{cursor:t.cursor}});if(t.json)return j(i);gc(i.runs),i.nextCursor&&N(`More runs available — next page: --cursor ${i.nextCursor}`)}),e.command(`run-detail`).description(`Show a single run's detail (per-action output and errors)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.getRun(e,t);if(n.json)return j(r);_c(r)}),e.command(`cancel`).description(`Cancel a queued or in-progress run`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.cancel(e,t);if(n.json)return j(r);vc(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 Y(n),o=await a.workflows.retryRun(e,t);if(!n.wait){if(n.json)return j(o);N(`Started run ${o.runId} (retry of ${t}).`),N(`Inspect it with: tangle workflows run-detail ${e} ${o.runId}`);return}let s=n.json?null:P(`Waiting for run ${o.runId} to finish...`).start(),c;try{c=await a.workflows.waitForRun(e,o.runId,{...r===void 0?{}:{timeoutMs:r},...i===void 0?{}:{pollIntervalMs:i}})}finally{s?.stop()}if(c.status===`failed`&&(process.exitCode=1),n.json)return j(c);_c(c)}),e.command(`events`).description(`Tail a run's live progress events until it finishes`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await Y(n);for await(let i of r.workflows.watchRun(e,t))n.json?console.log(JSON.stringify(i)):yc(i),i.type===`run.done`&&i.status===`failed`&&(process.exitCode=1)})}const xc=t(import.meta.url);if(!xc)throw Error(`Tangle CLI package metadata was not found`);const Sc=ge(xc),Cc=e=>x(`sha256`).update(e).digest(`hex`);function wc(e,t){let n=ye(e,t);return n!==`..`&&!n.startsWith(`..${xe}`)&&!ve(n)}function Tc(e,t){if(/[\\/]/.test(e)||/\.(yaml|yml|json)$/.test(e))return be(t,e);let n=t;for(;!de(D(n,`.git`))&&ge(n)!==n;)n=ge(n);de(D(n,`.git`))||(n=t);let r=[D(n,`.tangle`,`graphs`,`${e}.yaml`),D(Ce(),`.tangle`,`graphs`,`${e}.yaml`)],i=r.find(de);if(i)return i;throw new I(`GRAPH_NOT_FOUND`,`Graph '${e}' was not found`,`Looked in ${r.join(` and `)}`,`tangle graph --help`)}async function Ec(e,t){return Ss(e.signal,async n=>{let r=C(),i;try{let a=D(Ce(),`.tangle`,`runs`,r);await He(a,{recursive:!0,mode:448});let o=await Ge(D(Ce(),`.tangle`)),s=await Ge(e.cwd??process.cwd()),c=[`runs`,`graph-registry`,`graphs`].some(e=>wc(s,D(o,e))||wc(D(o,e),s))?D(Ce(),`.tangle`,`workspaces`,r):s;await He(c,{recursive:!0,mode:448});let l;return await t({runId:r,runDir:a,cwd:c,bridge:e=>l??=(async()=>{n.throwIfAborted();let t=S(32).toString(`hex`),{loadConfig:r,startServer:o}=await import(`cli-bridge`),s=D(Sc,`dist`,`stdio.mjs`),l=r({...process.env,BRIDGE_HOST:`127.0.0.1`,BRIDGE_PORT:`3344`,BRIDGE_BEARER:t,BRIDGE_DATA_DIR:D(a,`bridge`),BRIDGE_BACKENDS:Cs,BRIDGE_JAIL_MODE:`fs-jail`,BRIDGE_JAIL_FALLBACK:`deny`,BRIDGE_SUBSCRIPTIONS_ONLY:`1`});return e&&l.jailReadablePaths.push(s),i=await o({cwd:c,config:{...l,port:0},handleSignals:!1,quiet:!0,hub:e?{client:e,hash:xs,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}),{backend:`bridge`,bridgeUrl:i.url,bridgeBearer:t,cwd:c}})(),signal:n})}catch(e){throw e instanceof Error&&Object.assign(e,{runId:r}),e}finally{await i?.close()}},`tangle graph --help`)}function Dc(e){throw new I(`GRAPH_CLOUD_UNAVAILABLE`,`Cloud subscription execution was refused`,e,`tangle graph run --help`)}function Oc(e){(e.observed||!e.entry||e.deliverable.checkRef===`command`)&&Dc(`Cloud needs an executable flow and portable outside check; root coordination and host checks are unsupported`);let{digest:t,...n}=e;return{...n,nodes:e.nodes.map(({id:e,profile:t})=>{t.seats&&Dc(`Node '${e}' has an account-selection chain; direct single-account execution cannot drop it`);let n=t.model?.metadata?.credentialSource;return n!==void 0&&n!==`subscription`&&Dc(`Node '${e}' declares a non-subscription credential source`),{id:e,profile:ae.parse({...t,model:{...t.model,metadata:{...t.model?.metadata,credentialSource:`subscription`}}})}})}}async function kc(e,t,n){let r=[...new Set(e.nodes.map(({profile:e})=>e.harness))];(r.length!==1||!r[0])&&Dc(`Direct cloud execution currently needs one concrete harness across nodes`);let i=U(t).client,a=(await Ds(i,[r[0]],n)).get(r[0]);a||Dc(`No enrolled native reference for ${r[0]}`);let{createTangleProvider:o}=await import(`@tangle-network/agent-provider-tangle`);return{backend:`provider`,provider:o({client:i,modelCredentials:{cliAuth:a},requireNativeSessionCapture:!0}),destroyOnSettle:!0,requireTerminalEvent:!0}}async function Ac(e,t,n={}){try{return await Ss(n.signal,async r=>{let i=await uc();r.throwIfAborted();let a=Tc(e,n.cwd??process.cwd()),o=n.source??await We(a,`utf8`),s=Cc(o),c={apiKey:t.apiKey,sandboxBaseUrl:t.baseUrl,signal:r,json:t.json,dryRun:t.dryRun&&!n.connectNeeds},l,u=()=>l??=Ns(c),d=new Map,f=e=>{let t=e.trim().toLowerCase(),n=d.get(t)??(async()=>{let e=await u(),n=e&&await Fs(e,t,c);return n?{connectionId:n,capabilities:[`*`]}:void 0})();return d.set(t,n),n},p=async e=>{r.throwIfAborted();let c=await i.loadGraphFile(a,{source:o,seat:t.seat??B().seat,resolveSeat:ws(e,r),resolveNeed:f,params:hc(t.param,`param`),cwd:e,signal:r});if(r.throwIfAborted(),n.graphDigest&&c.graph.digest!==n.graphDigest)throw new I(`GRAPH_CHANGED`,`The validated graph changed before execution`,`Its compiled graph digest no longer matches validation`,`tangle graph run --help`);if(!t.cloud)return c;let l=Oc(c.graph);return{...c,sourceGraph:c.graph,sourceDigest:s,graph:{...l,digest:i.graphDigest(l)}}};return t.dryRun?p(n.cwd??process.cwd()):Ec({...n,signal:r},async({runId:e,runDir:n,cwd:o,bridge:c})=>{let l=await p(o),{superviseGraphPursuit:d}=await import(`@tangle-network/agent-runtime/durable`),f=i.graphRegistry(D(Ce(),`.tangle`,`graph-registry`)),m=`sourceGraph`in l?l.sourceGraph:l.graph;t.cloud&&await i.recordStoredGraphRun(f,m);let h=await i.recordStoredGraphRun(f,l.graph),g=i.graphFromStored(h),_=h.nodes.some(e=>e.profile.connections?.length),ee=_&&!t.cloud?await u():void 0;if(_&&!t.cloud&&!ee)throw new I(`AUTH_REQUIRED`,`Hub authentication is required`,`No Tangle credential is configured for this local graph`,`tangle auth login`);let te=t.cloud?await kc(h,t,r):await c(ee),v=new Date().toISOString(),ne=new Map;N(`Run ${e} · ${he(a)} · ${o}`);let{serveTopWeb:y}=await import(`@tangle-network/agent-runtime/tui`),re=await y({roots:[n],assets:D(Sc,`dist`,`graph-viewer`)});N(`Viewer ${re.url}`);let b=await d(g,{pursuitId:h.digest,runDir:n,runId:e,backend:te,signal:r,profileSecurity:{allowConnections:_,allowLocalMcp:!1,allowHooks:!1,allowedMcpHosts:[]},hooks:{onEvent:e=>{let t=e.payload;e.target===`agent.spawn`&&t?.childId&&typeof t.label==`string`&&ne.set(t.childId,t.label);let n=ne.get(t?.childId??e.parentId??``);process.stderr.write(`${n?`${JSON.stringify(n)} `:``}${e.target} ${JSON.stringify(t?.status??e.phase)}\n`)}}}).finally(re.close),x={runId:e,graphDigest:h.digest,sourceDigest:s,...t.cloud?{authoredGraphDigest:m.digest}:{},...cc(b.result.result)},S=b.result.result;if(await i.recordStoredGraphRun(f,h,{graphDigest:h.digest,evidence:[{kind:`authored-graph`,url:`urn:sha256:${m.digest}`},{kind:`authored-yaml`,url:`urn:sha256:${s}`}],taskDigest:i.taskShapeDigest({graph:he(a),params:l.params}),startedAt:v,finishedAt:new Date().toISOString(),outcome:S.kind===`no-winner`?{kind:`no-winner`,reason:S.reason}:{kind:`delivered`,summary:x.text},cost:{iterations:S.spentTotal.iterations,ms:S.spentTotal.ms,...Object.fromEntries(Object.entries({inputTokens:x.tokenUsage.input,outputTokens:x.tokenUsage.output,usd:x.costUsd}).filter(([,e])=>e!==null))},traversals:b.result.ledger.length,exhaustedEdges:b.result.exhaustedEdges,source:{kind:`tangle-cli-graph`,id:e}}),S.kind===`no-winner`)throw Object.assign(new I(`GRAPH_RUN_FAILED`,`Graph '${he(a)}' finished without a result`,b.result.ledger.filter(e=>e.outcome===`unpropagated`&&e.reason).pop()?.reason||S.reason,`tangle graph run --help`),{runId:e,runtimeFailures:S.tree.nodes.filter(e=>e.failure).map(e=>({node:e.label,failure:e.failure}))});return x})},`tangle graph --help`)}catch(n){throw n instanceof I&&n.code===`RUN_STOPPED`&&Object.assign(n,{fix:[`tangle graph run`,Ke(e),...t.dryRun?[`--dry-run`]:[],...t.cloud?[`--cloud`]:[],...t.seat?[`--seat`,Ke(t.seat)]:[],...t.param.flatMap(e=>[`--param`,Ke(e)])].join(` `)}),n}}function jc(){let e=new b(`graph`).description(`Build and run portable agent graphs`);return Ms(e),e.command(`run <name-or-file>`).description(`Run a saved graph over native subscriptions`).option(`--cloud`,`Run each node in a Tangle sandbox using your subscription`).option(`--seat <seat>`,`Use harness/model@effort for every node`).option(`--param <key=value>`,`Graph parameter; repeatable`,(e,t)=>[...t,e],[]).option(`--dry-run`,`Validate and print the graph without starting agents`).action(async(e,t)=>{let n=await Ac(e,t);t.json||t.dryRun?j(n):`status`in n&&(N(`${n.status} · ${n.runId}`),n.text&&console.log(n.text))}),e}function Mc(){let e=new b(`intelligence`).description(`Create and inspect trace intelligence reports`);return e.command(`connect [agent]`).alias(`connect-agent`).description(`Connect local agent CLIs to Tangle Intelligence`).option(`--endpoint <url>`,`OTLP endpoint base`,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=Pc(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){j(a);return}F({Config:i.configPath,Agents:i.agents.join(`, `),"Native Hooks":i.nativeAgents.join(`, `)||void 0,"Manual Setup":i.manual.length?i.manual.map(e=>`${e.label}: ${e.reason}`).join(` `):void 0,Files:i.written.join(`, `),"Smoke Trace":i.smokeTraceId})}),e.command(`doctor`).description(`Check whether your agent traces carry CONTENT or are metadata-only`).option(`--endpoint <url>`,`OTLP endpoint base`,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:Pc(e.apiKey??t?.apiKey)});e.json?j(n):Nc(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=Fc(e.agent),n=ma(),r={agent:t,event:e.event,endpoint:e.endpoint??n?.endpoint??`https://intelligence.tangle.tools/v1/otlp`,apiKey:Pc(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 Lc():Ic(e.payload)};if(e.dryRun){let n=_a(r);if(e.json){j(n);return}F({Trace:n.traceId,Agent:t,Event:e.event});return}let i=await va(r);if(e.json){j({traceId:i});return}F({Trace:i,Agent:t,Event:e.event})}catch(t){if(e.nonBlocking){let n=t instanceof Error?t.message:String(t);e.json?j({ok:!1,error:n}):console.error(`Tangle Intelligence hook skipped: ${n}`);return}R(t)}}),e.command(`sandbox <sandbox-id>`).description(`Create an intelligence report for one sandbox`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).action(async(e,t)=>{await Rc({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 Rc({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 Rc({type:Bc(e.subjectType),id:e.subjectId},e)}),e.command(`get <job-id>`).description(`Get an intelligence report`).action(async(e,t)=>{let{client:n}=U(t),r=t.json?null:P(`Fetching intelligence report...`);r?.start();let i=await n.intelligence.getReport(e);if(r?.stop(),t.json){j(i);return}zc(i)}),e.command(`list`).description(`List intelligence reports`).option(`--subject-type <type>`,`sandbox | fleet`).option(`--subject-id <id>`,`Subject identifier`).option(`--limit <count>`,`Maximum reports to return`).action(async e=>{let{client:t}=U(e),n=e.json?null:P(`Fetching intelligence reports...`);n?.start();let r=await t.intelligence.listReports({subjectType:e.subjectType===void 0?void 0:Bc(e.subjectType),subjectId:e.subjectId,limit:e.limit===void 0?void 0:Uc(e.limit)});if(n?.stop(),e.json){j(r);return}A(r.map(e=>({jobId:e.jobId,subject:`${e.subject.type}:${e.subject.id}`,mode:e.mode,status:e.status,cost:`$${e.billing.costUsd.toFixed(2)}`,updatedAt:e.updatedAt})),[{key:`jobId`,header:`Job`,width:20},{key:`subject`,header:`Subject`,width:28},{key:`mode`,header:`Mode`,width:15},{key:`status`,header:`Status`,width:14},{key:`cost`,header:`Cost`,width:10},{key:`updatedAt`,header:`Updated`,width:18}])}),e}function Nc(e){F({Status:e.contentSeen?`content flowing`:e.tracesSeen?`metadata-only — a content gate is missing`:`no traces yet`,"Traces seen":e.tracesSeen?`yes`:`no`,"Content seen":e.contentSeen?`yes`:`no`,"Last seen":e.lastSeenAt??`never`,Window:`${e.windowDays}d`});let t=Object.entries(e.byAgent);t.length>0&&(console.log(),A(t.map(([e,t])=>({agent:e,traces:t.tracesSeen?`yes`:`no`,content:t.contentSeen?`yes`:`no`})),[{key:`agent`,header:`Agent`,width:18},{key:`traces`,header:`Traces`,width:10},{key:`content`,header:`Content`,width:10}]))}function Pc(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 Fc(e){if(da(e))return e;throw Error(`agent must be a known Tangle Intelligence agent surface`)}function Ic(e){try{return JSON.parse(e)}catch(e){throw Error(`--payload must be JSON: ${e instanceof Error?e.message:String(e)}`)}}async function Lc(){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 Rc(e,t){let n=Vc(t.mode),r=Wc(t.metadata),i=t.maxUsd===void 0?void 0:Hc(t.maxUsd);if(n===`agentic`&&i===void 0)throw Error(`Agentic intelligence reports require --max-usd`);let{client:a}=U(t),o=t.json?null:P(`Creating intelligence report...`);o?.start();let s=await a.intelligence.createReport({subject:e,mode:n,...i===void 0?{}:{budget:{billTo:`customer`,maxUsd:i}},...r===void 0?{}:{metadata:r}});if(o?.stop(),t.json){j(s);return}zc(s)}function zc(e){F({Job:e.jobId,Subject:`${e.subject.type}:${e.subject.id}`,Mode:e.mode,Status:e.status,"Billed To":e.billing.billedTo,Cost:`$${e.billing.costUsd.toFixed(2)}`,Budget:e.billing.budgetMaxUsd===void 0?void 0:`$${e.billing.budgetMaxUsd.toFixed(2)}`,Updated:e.updatedAt}),e.result!==null&&(console.log(),j(e.result))}function Bc(e){if(e===`sandbox`||e===`fleet`)return e;throw Error(`subject type must be sandbox or fleet`)}function Vc(e){if(e===`deterministic`||e===`agentic`)return e;throw Error(`mode must be deterministic or agentic`)}function Hc(e){let t=Number(e);if(!Number.isFinite(t)||t<0)throw Error(`--max-usd must be a non-negative number`);return t}function Uc(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function Wc(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 Gc=[`router`,`sandbox`,`blueprint-agent`,`evals`,`agent-builder`];async function Kc(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 qc(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 Jc(i,t));return i}async function Jc(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 Yc=[`ID`,`Prefix`,`Name`,`Product`,`Created`,`Last used`,`Expires`];function Xc(e){return[e.id,e.keyPrefix??``,e.name,e.product??`all`,e.createdAt,e.lastUsedAt??`—`,e.expiresAt??`—`]}function Zc(){let e=new b(`keys`).description(`Manage sk-tan-* API keys on id.tangle.tools`);return e.command(`list`).description(`List your active API keys`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async e=>{let t=await Kc(e,!1),n=t.baseUrl,r=await(await qc(t,`${n}/v1/keys`,{expected:200})).json();if(e.json){j(r);return}Rt(Yc,r.data.map(Xc))}),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 (${Gc.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&&!Gc.includes(t.product))throw Error(`Invalid --product. Expected one of ${Gc.join(`, `)}`);let n=await Kc(t,!0),r=n.baseUrl,i=t.expiresInDays===void 0?void 0:new Date(Date.now()+Number.parseInt(t.expiresInDays,10)*24*60*60*1e3).toISOString(),a=P(`Creating API key...`);a.start();let o=await qc(n,`${r}/v1/keys`,{method:`POST`,expected:201,body:JSON.stringify({name:e,product:t.product,budgetUsd:t.budgetUsd?Number.parseFloat(t.budgetUsd):void 0,rpmLimit:t.rpmLimit?Number.parseInt(t.rpmLimit,10):void 0,expiresAt:i})});a.stop();let s=await o.json();if(t.json){j(s);return}M(`API key created: ${s.data.prefix}…`),N(`Copy this key now — it will never be shown again:\n${s.data.key}`)}),e.command(`revoke`).description(`Revoke an API key`).argument(`<keyId>`,"Key ID (from `tcloud keys list`)").option(`--yes`,`Skip the confirmation prompt`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{let n=await Kc(t,!0),r=n.baseUrl;if(!t.yes&&!await ei(`Revoke key ${e}? Any service still using it will start to fail.`,`--yes`)){N(`Aborted.`);return}let i=await(await qc(n,`${r}/v1/keys/${encodeURIComponent(e)}`,{method:`DELETE`,expected:200})).json();if(t.json){j(i);return}M(`Revoked ${e}`)}),e}function Qc(e){if(Wn().token)throw Error(`A line relay cannot manage numbers or attachments. Use your owner CLI outside the agent box.`);return H(V(e))}function $c(e){if(!e.yes)throw Error(`Review the selected line and use --yes to authorize this change. Attaching enables metered agent work.`)}function el(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 tl(e){return e().catch(R)}async function nl(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 rl(e){e.command(`providers`).description(`List provider transports supported by this Hub deployment`).action(e=>tl(async()=>{j(await Qc(e).lines.providers())})),e.command(`list`).description(`List owned lines, optionally for a saved agent profile or sandbox`).option(`--profile-id <id>`,`Stored profile ID`).option(`--sandbox <id>`,`Existing sandbox ID`).action(e=>tl(async()=>{j(await Qc(e).lines.list({profileId:e.profileId,sandboxId:e.sandbox}))})),e.command(`get`).argument(`<line-id>`).description(`Inspect a line and its current attachment`).action((e,t)=>tl(async()=>{j(await Qc(t).lines.get(e))})),e.command(`numbers`).argument(`<connection-id>`).description(`Discover owned provider numbers; this does not purchase or reserve a number`).option(`--transport <transport>`,`imessage, whatsapp, or sms`,`imessage`).action((e,t)=>tl(async()=>{let n=el(t.transport);if(n===`email`)throw Error(`Email uses an owned mailbox, not phone inventory`);if(n===`voice`)throw Error(`Voice numbers are listed by ph0ny; provide the owned number ID to lines connect`);if(n===`telegram`)throw Error(`Telegram uses an owned bot, not phone inventory`);j(await Qc(t).lines.numbers(e,n))})),e.command(`connect`).argument(`<connection-id>`).description(`Bind an owned number or identity through Hub; no provider rental is purchased`).option(`--transport <transport>`,`imessage, whatsapp, sms, email, voice, or telegram`,`imessage`).option(`--number-id <id>`,`Exact owned provider number ID; required for voice, SMS, WhatsApp and Linq iMessage`).option(`--address <email>`,`Owned mailbox on a verified email domain`).requiredOption(`--reference <reference>`,`Stable client reference; keep it unchanged on retry`).option(`--label <label>`,`Line display name`).option(`--yes`,`Authorize provider webhook configuration and line binding`).action((e,t)=>tl(async()=>{$c(t);let n=el(t.transport);if(n!==`email`&&t.address)throw Error(`--address is email-only`);if((n===`email`||n===`telegram`)&&t.numberId)throw Error(`${n} does not take --number-id`);let r={connectionId:e,label:t.label,clientReference:t.reference},i;if(n===`email`)i={...r,transport:n,address:t.address};else if(n===`telegram`)i={...r,transport:n};else if(n===`imessage`)i={...r,transport:n,phoneNumberId:t.numberId};else{if(!t.numberId)throw Error(`${n} requires --number-id`);i={...r,transport:n,phoneNumberId:t.numberId}}j(await Qc(t).lines.fromConnection(i))})),e.command(`attach`).argument(`<line-id>`).description(`Attach a saved agent to any sandbox, or use an isolated on-demand member instance`).option(`--file <path>`,`Reviewed native attachment JSON (exclusive with quick-setup flags)`).option(`--profile-id <id>`,`Owner-scoped saved profile; each turn pins its source revision`).option(`--member <address>`,`The one allowed sender: E.164 phone or email`).option(`--sandbox <id>`,`Use an existing sandbox instead of an on-demand instance`).option(`--instance-prefix <prefix>`,`Stable instance namespace; defaults to profile:<profile-id>:`).option(`--tools <mode>`,`chat denies tools; act applies the profile's tools and permissions`).option(`--turns-per-day <count>`,`Per-member daily turn ceiling (default 30)`).option(`--yes`,`Authorize agent execution and spend against your key limits`).action((e,t)=>tl(async()=>{$c(t);let n=Qc(t),r;if(t.file){if(t.profileId||t.member||t.sandbox||t.instancePrefix||t.tools||t.turnsPerDay)throw Error(`Choose --file or quick-setup flags, not both`);r=await nl(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(lr()).hostname],includeImplicitDomains:!1}}:{}}}}}}if(typeof r.sandboxId==`string`==(r.instance!==void 0))throw Error(`Attachment requires exactly one of sandboxId and instance`);let{sandboxId:i,instance:a,...o}=r,s;if(i){let t=await n.get(i);if(!t)throw Error(`Sandbox not found`);s=await t.lines.attach({...o,number:e})}else{if(!a)throw Error(`Attachment requires an instance`);s=await n.lines.attach({...o,number:e,instance:a})}j(s)}));for(let t of[`detach`,`release`])e.command(t).argument(`<line-id>`).description(t===`detach`?`Stop dispatch; preserve history and provider rental`:`Retire a detached Hub line; does not cancel provider rental`).option(`--yes`,`Authorize this change`).action((e,n)=>tl(async()=>{$c(n),j({[t]:await Qc(n).lines[t](e)})}));e.command(`threads`).argument(`<line-id>`).description(`List this line's separate participant threads`).action((e,t)=>tl(async()=>{j(await Qc(t).lines.threads(e).list())})),e.command(`messages`).argument(`<line-id>`).argument(`<thread-id>`).description(`Read one authorized participant thread`).action((e,t,n)=>tl(async()=>{j(await Qc(n).lines.threads(e).messages(t))}))}async function il(e){let{token:t,baseUrl:n}=Wn();if(t===void 0)return W(e);if(!t.startsWith(`lrc_`)||!n)throw Error(`The line box needs TANGLE_LINE_TOKEN and TANGLE_HUB_URL`);if(e.apiKey||e.baseUrl&&new URL(e.baseUrl).origin!==new URL(n).origin)throw Error(`A line token cannot be sent to another Hub or combined with an API key`);return new ke({baseUrl:n,authHeaders:()=>({Authorization:`Bearer ${t}`})})}async function al(e,t){if(t)return t;if(!Wn().token)throw Error(`Provide --line <line-id>`);return(await e.lines.context()).line.id}function ol(e){return e().catch(R)}function sl(){return new b(`context`).description(`Show live line identity, members, consent, reminders and quotas`).action(e=>ol(async()=>{j(await(await il(e)).lines.context())}))}function cl(){let e=new b(`lines`).description(`Connect, manage, message and schedule on a Hub line`);return e.command(`members`).description(`List names, roles and consent on this line`).option(`--line <line-id>`,`Line ID; inferred in a line box`).action(e=>ol(async()=>{let t=await il(e);j(await t.lines.members.list(await al(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)=>ol(async()=>{let r=await il(n),i=await al(r,n.line);if(!Wn().token){if(n.onBehalfOf)throw Error(`--on-behalf-of is only available inside a line box`);if(!n.idempotencyKey)throw Error(`Owner sends require --idempotency-key so a retry keeps the same message`);if(!(await r.lines.members.list(i)).some(t=>t.id===e))throw Error(`Owner sends require an exact member ID from tangle lines members`);j(await r.lines.send(i,{memberId:e,text:t,idempotencyKey:n.idempotencyKey,...n.notBefore?{notBefore:n.notBefore}:{}}));return}j(await r.lines.send(i,{toMember:e,text:t,...n.onBehalfOf?{onBehalfOf:n.onBehalfOf}:{},...n.notBefore?{notBefore:n.notBefore}:{},...n.idempotencyKey?{idempotencyKey:n.idempotencyKey}:{}}))})),e.command(`remind`).description(`Wake the agent at a future time to write your reminder`).argument(`<text>`,`What to remember`).requiredOption(`--at <iso-time>`,`Future ISO time`).option(`--line <line-id>`,`Line ID; inferred in a line box`).option(`--idempotency-key <key>`,`Stable key for a retry`).action((e,t)=>ol(async()=>{if(!t.at)throw Error(`--at is required`);let n=await il(t),r=t.idempotencyKey??x(`sha256`).update(JSON.stringify([e,t.at])).digest(`hex`).slice(0,32);j(await n.lines.remind(await al(n,t.line),{text:e,notBefore:t.at,idempotencyKey:r}))})),rl(e),e}function ll(){let e=new b(`mcp`).description(`Model Context Protocol bridge commands.`);return e.command(`serve <id-or-name>`).description(`Run a local MCP server (stdio) backed by the given sandbox (ID or name). Pipe its stdio from an MCP client config to expose sandbox tools.`).option(`-s, --session <id>`,`Session id for kernel scoping`,`mcp-local`).option(`--name <name>`,`MCP server name reported to clients`,`tangle-sandbox`).action(async(e,t)=>{let n=V({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=await G(H(n),n,e),i;try{i=(await import(`@modelcontextprotocol/sdk/server/stdio.js`)).StdioServerTransport}catch{throw Error("`@modelcontextprotocol/sdk` is not installed in this environment. Install it with: pnpm add -g @modelcontextprotocol/sdk (or as a dev dep in the project running this command).")}let{connect:a,close:o}=await $e(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 ul(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=Pn(),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??er():t.apiKey;if(t.self&&!a)throw Error(`Self preview access requires the injected sandbox runtime credential; it never reads saved owner credentials`);let o=V({apiKey:a,baseUrl:r}),s=H(o);return t.self?nt(s):G(s,o,e)}async function dl(e,t,n){let r=P(e);t||r.start();try{return await n()}finally{r.stop()}}function fl(e){return e}function pl(){let e=new b(`preview`).description(`Manage sandbox preview links`);return fl(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 ul(e,t),r=await dl(`Starting managed preview...`,t.json,()=>et(n,{cwd:t.cwd,sessionId:t.session,name:t.name}));t.json?j(r):(M(`Preview ready: ${r.url}`),console.log(`Preview ID: ${r.previewId}`))}),fl(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 ul(e,t),r=await dl(`Fetching preview links...`,t.json,()=>n.previewLinks.list());t.json?j(r):r.length===0?console.log(`No preview links found`):Rt([`App`,`Preview ID`,`Port`,`URL`,`Status`],r.map(e=>[ml(e.metadata),e.previewId.slice(0,12),String(e.port),e.url,e.status]))}),fl(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 ul(e,t),r=await dl(`Publishing service...`,t.json,()=>tt(n,{port:Number(t.port),name:t.name}));t.json?j(r):M(`Preview ready: ${r.url}`)}),fl(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 ul(e,n),i=await dl(`Creating preview for port ${t}...`,n.json,()=>r.previewLinks.create(Number(t)));n.json?j(i):(M(`Preview created: ${i.url}`),console.log(`Preview ID: ${i.previewId}`))}),fl(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 ul(e,n);await dl(`Removing preview...`,n.json,()=>r.previewLinks.remove(t)),n.json?j({success:!0,previewId:t}):M(`Preview removed: ${t}`)}),e}function ml(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 hl(){let e=new b(`process`).description(`Manage processes in a sandbox`);return e.command(`spawn`).description(`Spawn a process without blocking (returns PID)`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<command>`,`Command to execute`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`).option(`--blocking`,`Wait for completion (default: false)`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a={};if(n.env)for(let e of n.env){let[t,...n]=e.split(`=`);t&&n.length>0&&(a[t]=n.join(`=`))}let o=P(`Spawning: ${t}`);n.json||o.start();let s=await G(i,r,e);if(s=await K(s),n.blocking){let e=await s.exec(t,{cwd:n.cwd,env:Object.keys(a).length>0?a:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});o.stop(),n.json?j(e):(e.stdout&&globalThis.process.stdout.write(e.stdout),e.stderr&&globalThis.process.stderr.write(e.stderr),e.exitCode!==0&&globalThis.process.exit(e.exitCode))}else{let r=await s.process.spawn(t,{cwd:n.cwd,env:Object.keys(a).length>0?a:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});o.stop(),n.json?j({pid:r.pid,command:r.command}):(console.log(`Process started with PID: ${r.pid}`),console.log(`Use 'tangle process logs ${e} ${r.pid}' to view output`))}}),e.command(`list`).alias(`ls`).description(`List all processes in a sandbox`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--running`,`Show only running processes`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching processes...`);t.json||i.start();let a=await G(r,n,e);a=await K(a);let o=await a.process.list();t.running&&(o=o.filter(e=>e.running)),i.stop(),t.json?j(o):o.length===0?console.log(`No processes found`):Rt([`PID`,`Command`,`Status`,`Exit Code`,`Started`],o.map(e=>[String(e.pid),e.command.length>40?`${e.command.slice(0,37)}...`:e.command,e.running?`running`:`exited`,String(e.exitCode),e.startedAt.toLocaleString()]))}),e.command(`get`).description(`Get detailed info about a process`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Fetching process info...`);n.json||a.start();let o=await G(i,r,e);o=await K(o);let s=await o.process.get(Number.parseInt(t,10));if(a.stop(),!s){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}let c=await s.status();n.json?j(c):(console.log(`PID: ${c.pid}`),console.log(`Command: ${c.command}`),console.log(`CWD: ${c.cwd||`(default)`}`),console.log(`Status: ${c.running?`running`:`exited`}`),console.log(`Exit Code: ${c.exitCode}`),c.exitSignal&&console.log(`Signal: ${c.exitSignal}`),console.log(`Started: ${c.startedAt.toLocaleString()}`),c.exitedAt&&console.log(`Exited: ${c.exitedAt.toLocaleString()}`))}),e.command(`kill`).description(`Kill a process`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).option(`-s, --signal <signal>`,`Signal to send (SIGTERM, SIGKILL, etc.)`,`SIGTERM`).option(`--tree`,`Also kill descendants of the tracked process`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Sending ${n.signal} to PID ${t}...`);n.json||a.start();let o=await G(i,r,e);o=await K(o);let s=await o.process.get(Number.parseInt(t,10));if(!s){a.stop(),console.error(`Process ${t} not found`),globalThis.process.exit(1);return}n.tree?await s.kill(n.signal,{tree:!0}):await s.kill(n.signal),a.stop(),n.json?j({pid:Number.parseInt(t,10),signal:n.signal,...n.tree===!0?{tree:!0}:{},killed:!0}):console.log(n.tree?`Sent ${n.signal} to process tree ${t}`:`Sent ${n.signal} to process ${t}`)}),e.command(`logs`).description(`Stream buffered and live process logs until the process exits`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).option(`--stdout-only`,`Only show stdout`).option(`--stderr-only`,`Only show stderr`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a);let o=await a.process.get(Number.parseInt(t,10));if(!o){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}for await(let e of o.logs())n.stdoutOnly&&e.type!==`stdout`||n.stderrOnly&&e.type!==`stderr`||(n.json?console.log(JSON.stringify(e)):e.type===`stdout`?globalThis.process.stdout.write(e.data):globalThis.process.stderr.write(e.data))}),e}const gl=[`python`,`node`,`typescript`,`bash`];function _l(e){switch(_e(e).toLowerCase()){case`.py`:return`python`;case`.js`:case`.mjs`:case`.cjs`:return`node`;case`.ts`:case`.tsx`:return`typescript`;case`.sh`:case`.bash`:return`bash`;default:return}}async function vl(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(be(e),`utf8`)}async function yl(e,t,n=vl){let r=t?gl.find(e=>e===t)??(()=>{throw Error(`unknown --lang ${t}: must be one of ${gl.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=_l(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 bl(e){return D(we(),`tangle-run-images`,e)}function xl(){return new b(`run`).description(`Run code in a persistent kernel inside a sandbox. Variables persist across calls in the same --session.`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`[file]`,`Path to source file. Language is inferred from extension. Use - for stdin (requires --lang).`).option(`-l, --lang <lang>`,`Force language: ${gl.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 yl(t,n.lang),{context:a,client:o}=U(n),s=await G(o,a,e);s=await K(s);let c=P(`Running ${r} (${i.length}b)…`);n.json||c.start();let l=await s.runCode(r,i,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10)});if(c.stop(),n.json){j(l),l.exitCode!==0&&process.exit(l.exitCode);return}l.stdout&&process.stdout.write(l.stdout),l.stderr&&process.stderr.write(l.stderr);let u=0;for(let t of l.results)if(t.type===`image`)if(n.saveImages!==!1){let r=typeof n.saveImages==`string`?n.saveImages:bl(e);fe(r,{recursive:!0});let i=`${r}/${Date.now()}-${u}.${t.format}`;me(i,Buffer.from(t.data,`base64`)),process.stderr.write(y.green(`✓ image → ${i}\n`)),u++}else process.stderr.write(y.gray(`[image: ${t.format}, ${t.data.length}b base64]\n`));else if(t.type===`dataframe`){let e=t.columns.map(e=>`${e.name}:${e.dtype}`).join(` | `);process.stderr.write(y.gray(`[dataframe ${t.rows.length}×${t.columns.length}${t.truncated?` (truncated)`:``}]\n`)),process.stderr.write(`${e}\n`);for(let e of t.rows.slice(0,20))process.stderr.write(`${e.map(e=>String(e)).join(` | `)}\n`);t.rows.length>20&&process.stderr.write(y.gray(`… ${t.rows.length-20} more rows\n`))}else t.type===`json`?(process.stderr.write(y.gray(`[json] `)),process.stderr.write(`${JSON.stringify(t.value,null,2)}\n`)):t.type===`html`?process.stderr.write(y.gray(`[html ${t.value.length}b]\n`)):t.type===`error`?(process.stderr.write(y.red(`✗ ${t.name}: ${t.message}\n`)),t.traceback&&process.stderr.write(`${t.traceback}\n`)):t.type===`text`&&process.stderr.write(`${t.value}\n`);l.error&&(process.stderr.write(y.red(`\n✗ ${l.error.name}: ${l.error.message}\n`)),l.error.traceback&&process.stderr.write(`${l.error.traceback}\n`)),l.exitCode!==0&&process.exit(l.exitCode)})}async function Sl(e,t){let n=await Rr({apiKey:t.apiKey,baseUrl:t.baseUrl??lr()}),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 Cl(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 wl(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 Tl(e){if(e!==void 0)return e.map(e=>{let t=e.indexOf(`@`);if(t===-1)return e;let n=e.slice(0,t),r=e.slice(t+1),i=r.indexOf(`:`),a=i===-1?r:r.slice(0,i),o=i===-1?void 0:r.slice(i+1);if(!n||!a||o===``)throw Error(`--secret ${e}: expected NAME, NAME@host or NAME@host:Header`);return o===void 0?{name:n,host:a}:{name:n,host:a,header:o}})}function El(e,t){let n={};return e.cpu!==void 0&&(n.cpuCores=$o(e.cpu,`--cpu`)),e.memory!==void 0&&(n.memoryMB=$o(e.memory,`--memory`)),e.disk!==void 0&&(n.diskGB=$o(e.disk,`--disk`)),t&&(n.accelerator=t),Object.keys(n).length>0?n:void 0}function Dl(e){let t=e.split(`/`);return t.length>=2?{provider:t[0],model:t.slice(1).join(`/`)}:{model:e}}function Ol(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]=kl(r.join(`=`))}return t}function kl(e){try{return JSON.parse(e)}catch{return e}}function Al(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`?$o(e.gitDepth,`--git-depth`):void 0,sparse:Array.isArray(e.gitSparse)?e.gitSparse:void 0,auth:t?{token:t}:void 0}}}function jl(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:Ml(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 Ml(e){if(e===`s3`||e===`gcs`||e===`r2`)return e;throw Error(`--storage-type must be one of s3, gcs, or r2`)}function Nl(e){N(` Status: ${e.status}`),N(` Provider: ${e.provider}`),N(` GPU: ${e.accelerator.kind} x ${e.accelerator.count}`),e.customerPricePerHourUsd!==void 0&&N(` Customer price: $${e.customerPricePerHourUsd}/hr`),e.estimatedCustomerCostUsd!==void 0&&N(` Max estimate: $${e.estimatedCustomerCostUsd}`),e.billing&&(N(` Billed seconds: ${e.billing.seconds}`),N(` Customer cost: $${e.billing.customerCostUsd}`))}function Pl(e){e.result.stdout&&process.stdout.write(e.result.stdout),e.result.stderr&&process.stderr.write(e.result.stderr),N(`Exit code: ${e.result.exitCode}`)}function Fl(e){let t=e.command(`gpu`).description(`Manage on-demand GPU leases for a sandbox`);t.command(`providers <id-or-name>`).description(`List GPU clouds, whether each credential works, and current prices`).option(`--accelerator-kind <kind>`,`Price this GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`).option(`--accelerator-memory <mb>`,`Minimum GPU memory in MB`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Checking GPU providers...`);i.start();let a=await(await G(r,n,e)).gpu.providers(t.acceleratorKind?{accelerator:Yo({kind:t.acceleratorKind,count:t.acceleratorCount,memory:t.acceleratorMemory})}:{});if(i.stop(),t.json){j(a);return}A(a.statuses.map(e=>({provider:e.provider,state:e.state,gpu:e.estimate?.providerInstanceType??``,usdHr:e.estimate?e.estimate.customerPricePerHourUsd.toFixed(4):``,pricing:e.estimate?.pricingSource??``,needs:e.envVars.join(` `)})),[{key:`provider`,header:`Provider`},{key:`state`,header:`State`},{key:`gpu`,header:`GPU`},{key:`usdHr`,header:`$/hr`},{key:`pricing`,header:`Price`},{key:`needs`,header:`Needs`}]);for(let e of a.statuses){let t=e.state===`credential-invalid`?e.credential?.detail:e.estimateError;t&&N(`${e.provider}: ${t}`)}a.usable.length===0&&N(`No GPU provider is usable on this deployment: set the variables in Needs for one provider on the server.`)}),t.command(`attach <id-or-name>`).description(`Attach a temporary GPU worker to a sandbox`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <mb>`,`Minimum GPU memory in MB`).option(`--provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--image <image>`,`GPU worker image override`).option(`--env <vars...>`,`Environment variables for the GPU worker (KEY=VALUE)`).requiredOption(`--max-spend-usd <usd>`,`Maximum customer spend for this lease`).requiredOption(`--max-lifetime <seconds>`,`Maximum lease lifetime in seconds`).option(`--idle-timeout <seconds>`,`Destroy after this many idle seconds`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Attaching GPU lease...`);i.start();let a=await(await G(r,n,e)).gpu.attach(Zo(t));i.stop(),t.json?j(a):(M(`GPU lease attached: ${a.id}`),Nl(a))}),t.command(`run <id-or-name> <command...>`).description(`Attach a temporary GPU, run a command, then destroy it`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <mb>`,`Minimum GPU memory in MB`).option(`--provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--image <image>`,`GPU worker image override`).option(`--env <vars...>`,`Environment variables for the GPU worker and command (KEY=VALUE)`).requiredOption(`--max-spend-usd <usd>`,`Maximum customer spend for this lease`).requiredOption(`--max-lifetime <seconds>`,`Maximum lease lifetime in seconds`).option(`--idle-timeout <seconds>`,`Destroy after this many idle seconds`).option(`--timeout <ms>`,`Command timeout in milliseconds`).option(`--cwd <path>`,`Working directory`).action(async(e,t,n)=>{let r,i,a,o;try{let{context:a,client:o}=U(n),s=await G(o,a,e),c=P(`Attaching GPU lease...`);c.start(),r=await s.gpu.attach(Zo(n)),c.stop();let l=P(`Running GPU command...`);l.start(),i=await s.gpu.exec(r.id,{command:t.join(` `),timeoutMs:n.timeout?$o(String(n.timeout),`--timeout`):void 0,cwd:n.cwd,env:n.env?Qo(n.env,`--env`,`env`):void 0}),l.stop(),n.json||Pl(i)}catch(e){a=e}finally{if(r)try{let{context:t,client:i}=U(n);r=await(await G(i,t,e)).gpu.detach(r.id)}catch(e){o=e}}if(a){R(a),o&&R(o);return}if(o){R(o);return}n.json?j({lease:r,result:i}):r&&M(`GPU lease detached: ${r.id}`);let s=i?.result.exitCode;s&&s!==0&&(process.exitCode=s)}),t.command(`list <id-or-name>`).description(`List GPU leases attached to a sandbox`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching GPU leases...`);i.start();let a=await(await G(r,n,e)).gpu.list();i.stop(),t.json?j(a):a.length===0?N(`No GPU leases attached.`):A(a.map(e=>({id:e.id,status:e.status,provider:e.provider,accelerator:`${e.accelerator.kind}x${e.accelerator.count}`,customerUsdHr:e.customerPricePerHourUsd??``})),[{key:`id`,header:`ID`,width:28},{key:`status`,header:`Status`,width:12},{key:`provider`,header:`Provider`,width:12},{key:`accelerator`,header:`GPU`,width:24},{key:`customerUsdHr`,header:`$/hr`,width:10}])}),t.command(`exec <id-or-name> <lease-id> <command...>`).description(`Run a command on an attached GPU lease`).option(`--timeout <ms>`,`Command timeout in milliseconds`).option(`--cwd <path>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).action(async(e,t,n,r)=>{let{context:i,client:a}=U(r),o=P(`Running GPU command...`);o.start();let s=await(await G(a,i,e)).gpu.exec(t,{command:n.join(` `),timeoutMs:r.timeout?$o(String(r.timeout),`--timeout`):void 0,cwd:r.cwd,env:r.env?Qo(r.env,`--env`,`env`):void 0});o.stop(),r.json?j(s):Pl(s)}),t.command(`detach <id-or-name> <lease-id>`).description(`Detach and destroy a GPU lease`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Detaching GPU lease...`);a.start();let o=await(await G(i,r,e)).gpu.detach(t);a.stop(),n.json?j(o):(M(`GPU lease detached: ${o.id}`),Nl(o))})}function Il(e,t){if(t){j(e);return}if(!e.id){e.kind===`snapshot`&&e.result?.snapshot?M(`Snapshot created: ${e.result.snapshot.snapshotId}`):M(`Sandbox ${e.sandboxId} stopped.`);return}M(`${e.kind===`snapshot`?`Snapshot`:`Stop`} of sandbox ${e.sandboxId} accepted.`),N(`Operation: ${e.id}`),N(`Status: ${e.statusUrl}`)}function Ll(e){return`${e.name} (${e.id})`}async function Rl(e,t){if(t.startsWith(`team_`))return e.teams.get(t);let n=(await e.teams.list()).filter(e=>e.name.toLowerCase()===t.toLowerCase());if(n.length===0)throw Error(`Team not found: ${t}`);if(n.length>1)throw Error(`Team name is ambiguous: ${t}. Use a team id instead.`);return n[0]}async function X(e,t,n){if(t)return Rl(e,t);let r=fr(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 zl(e,t){pr({id:e.id,name:e.name},t)}function Bl(e){mr(e)}async function Vl(e){if(e.explicitTeam&&e.personal)throw Error(`--team and --personal cannot be used together`);if(!e.personal)return e.explicitTeam?(await Rl(e.client,e.explicitTeam)).id:e.activeTeamId}async function Hl(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 Rl(e.client,e.explicitTeam)).id}`;if(e.activeTeamId)return`team:${e.activeTeamId}`}function Ul(e){return!e||e.authToken===void 0?e:{...e,authToken:`[REDACTED]`}}function Wl(e){e.command(`attestation <id-or-name>`).description(`Fetch TEE attestation evidence for a sandbox`).option(`--nonce <hex|auto>`,`Nonce to bind into a fresh attestation report; use auto to generate one`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=t.nonce===`auto`?ee():t.nonce,a=P(`Fetching TEE attestation...`);a.start();let o=await(await G(r,n,e)).getTeeAttestation(i?{attestationNonce:i}:void 0);a.stop(),t.json?j(o):(M(`Attestation fetched for ${e}`),console.log(`TEE type: ${o.attestation.tee_type}`),console.log(`Evidence bytes: ${o.attestation.evidence.length}`),console.log(`Measurement bytes: ${o.attestation.measurement.length}`),console.log(`Timestamp: ${o.attestation.timestamp}`),o.attestationNonce&&console.log(`Nonce: ${o.attestationNonce}`))}),e.command(`list`).description(`List all sandboxes`).option(`-s, --status <status>`,`Filter by status (running, stopped, all)`).option(`-l, --limit <n>`,`Limit results`,`50`).option(`--team <team>`,`List sandboxes for a team by id or name`).option(`--personal`,`List personal sandboxes`).option(`--all-scopes`,`List personal and team sandboxes`).action(async e=>{let{context:t,client:n}=U(e),r=P(`Fetching sandboxes...`);r.start();let i=await Hl({client:n,explicitTeam:e.team,personal:e.personal,allScopes:e.allScopes,activeTeamId:t.activeTeamId}),a=await n.list({status:e.status===`all`?void 0:e.status,limit:Number.parseInt(e.limit,10),scope:i});r.stop(),e.json?j(a):A(a.map(e=>({id:e.id,status:e.status,createdAt:e.createdAt,name:e.name??``})),[{key:`id`,header:`ID`,width:24},{key:`status`,header:`Status`,width:14},{key:`createdAt`,header:`Created`,width:16},{key:`name`,header:`Name`,width:20}])}),e.command(`get <id-or-name>`).description(`Get sandbox details`).option(`--profile`,`Show the active agent profile provenance (name, hash, skills)`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching sandbox...`);i.start();let a=await G(r,n,e);if(i.stop(),t.profile){let e=a.getProfileProvenance?.();e?(N(`Agent profile provenance:`),N(` Base profile: ${e.base.name??`(inline)`} (${e.base.sha256.slice(0,12)}...)`),N(` Effective: ${e.effective.name??`(inline)`} (${e.effective.sha256.slice(0,12)}...)`),N(` Materialized: ${e.materializedAt}`),e.base.sha256!==e.effective.sha256&&N(` ⚠ Profile changed since creation (base ≠ effective)`)):N(`No profile materialized (bare sandbox). Create with --profile <name> to install one.`);return}t.json?j(a):Lt({id:a.id,name:a.name,status:a.status,resources:a.resources,createdAt:a.createdAt?.toISOString(),expiresAt:a.expiresAt?.toISOString(),connection:a.connection})}),e.command(`shapes`).description(`List the named sandbox sizes, the default, and this account's ceiling`).action(async e=>{let{client:t}=U(e),n=await t.shapes();if(e.json){j(n);return}let r=e=>e.cpuCores<=n.ceiling.cpuCores&&e.memoryMB<=n.ceiling.memoryMB&&e.diskGB<=n.ceiling.diskGB;A(n.presets.map(e=>({name:e.name===n.default?`${e.name} (default)`:e.name,cpu:e.cpuCores,memory:`${e.memoryMB} MB`,disk:`${e.diskGB} GB`,available:r(e)?`yes`:e.name===n.default?`clamped to ceiling`:`above ceiling`})),[{key:`name`,header:`Shape`,width:18},{key:`cpu`,header:`vCPU`,width:6},{key:`memory`,header:`Memory`,width:10},{key:`disk`,header:`Disk`,width:8},{key:`available`,header:`Available`,width:14}]),N(`Ceiling for this account: ${It(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`)){N(`Cancelled.`);return}let{context:n,client:r}=U(t),i=P(`Deleting sandbox...`);i.start();let a=await qr(r,n,e,{retryCleanup:t.retryCleanup,name:t.name});i.stop(),M(a===`already_absent`?`Sandbox ${e} was already gone.`:`Sandbox ${e} deleted.`)}),e.command(`stop <id-or-name>`).description(`Stop a running sandbox`).option(`--name`,`Treat the reference as a sandbox name`).option(`--no-wait`,`Return once the stop is accepted and print the operation to poll`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Stopping sandbox...`);i.start();let a=await G(r,n,e,{nameOnly:t.name});if(t.wait===!1){let e=await a.stop({wait:!1});i.stop(),Il(e.info,!!t.json);return}await a.stop(),i.stop(),M(`Sandbox ${e} stopped.`)}),e.command(`resume <id-or-name>`).description(`Resume a stopped sandbox`).option(`--wait`,`Wait for sandbox to be running`,!0).option(`-t, --timeout <ms>`,`Resume timeout in milliseconds; a cold resume re-provisions the sandbox, so this defaults higher than other commands (default 120000)`,`120000`).action(async(e,t)=>{let n=Number.parseInt(t.timeout,10);if(!Number.isFinite(n)||n<=0)throw Error(`--timeout must be a positive number of milliseconds`);let r=V({apiKey:t.apiKey,baseUrl:t.baseUrl,timeout:n}),i=H(r),a=P(`Resuming sandbox...`);a.start();let o=await G(i,r,e);await o.resume({timeoutMs:n}),t.wait&&(a.text=`Waiting for sandbox to start...`,await o.waitFor(`running`,{timeoutMs:n})),a.stop(),M(`Sandbox ${o.id} resumed.`)})}function Gl(e){e.command(`create`).description(`Create a new sandbox`).option(`-n, --name <name>`,`Sandbox name`).option(`-e, --environment <environment>`,`Named environment, container image, or built image ID`).option(`--bare`,`Create a bare sandbox without the agent runtime`).option(`--ssh`,`Enable SSH access`).option(`--ssh-key <key>`,`SSH public key for authentication`).option(`--ssh-keys <names...>`,`Stored SSH key names or IDs for authentication`).option(`--ssh-key-file <paths...>`,`SSH public key file paths for authentication`).option(`--web-terminal`,`Enable web terminal`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`--secret <names...>`,`Secrets to inject as environment variables. NAME@host keeps the value out of the sandbox and sends it to that host only (NAME@host:Header for a header other than Authorization)`).option(`--metadata <entries...>`,`Metadata entries (KEY=VALUE or KEY=JSON)`).option(`--cpu <cores>`,"CPU cores (omit for the platform default; see `sandbox shapes`)").option(`--memory <mb>`,`Memory in MB (omit for the platform default)`).option(`--disk <gb>`,`Disk size in GB (omit for the platform default)`).option(`--accelerator-kind <kind>`,`Accelerator kind, for example nvidia-h100 or amd-mi300x`).option(`--accelerator-count <count>`,`Accelerator device count`,`1`).option(`--accelerator-memory <mb>`,`Minimum accelerator memory in MB`).option(`--gpu-provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--gpu-worker-image <image>`,`GPU worker image override`).option(`--gpu-env <vars...>`,`Environment variables for the GPU worker (KEY=VALUE)`).option(`--gpu-max-spend-usd <usd>`,`Maximum customer spend for the create-time GPU lease`).option(`--gpu-max-lifetime <seconds>`,`Maximum create-time GPU lease lifetime in seconds`).option(`--gpu-idle-timeout <seconds>`,`Destroy the create-time GPU lease after this many idle seconds`).option(`--lifetime <seconds>`,`Max wall-clock lifetime before the sandbox is suspended — stopped, not deleted; resume it within the cold window (default 3600 = 1h). Raise it for long sessions, e.g. --lifetime 7200`,`3600`).option(`--idle-timeout <seconds>`,"Idle time before the sandbox is stopped — not deleted (default 900 = 15m). Resume it later with `tangle sandbox resume <id-or-name>`, or it auto-resumes on next use. Raise it for demos, e.g. --idle-timeout 3600",`900`).option(`--from-snapshot <id>`,`Create the sandbox from a snapshot`).option(`--public-template <id-or-slug>`,`Create the sandbox from a published public template`).option(`--public-template-version <id>`,`Pin creation to a specific published public-template version`).option(`--billing-owner <userId>`,`Platform user that pays for the sandbox. The API accepts this only from a first-party service key that is listed as a billing delegate, and refuses such a key that names no payer.`).option(`--team <team>`,`Create in a team by id or name`).option(`--personal`,`Create a personal sandbox even when a team is active`).option(`--git-url <url>`,`Git repository URL to clone during provisioning`).option(`--git-ref <ref>`,`Git branch, tag, or commit to checkout`).option(`--git-depth <depth>`,`Git clone depth`).option(`--git-sparse <paths...>`,`Sparse checkout paths`).option(`--git-token-env <name>`,`Name of an environment variable containing the Git HTTPS auth token`).option(`--git-token-stdin`,`Read the Git HTTPS auth token from stdin`).option(`--storage-type <type>`,`BYOS3 storage type (s3, gcs, r2)`).option(`--storage-bucket <name>`,`BYOS3 bucket name`).option(`--storage-endpoint <url>`,`BYOS3 endpoint URL`).option(`--storage-region <region>`,`BYOS3 region`).option(`--storage-prefix <prefix>`,`BYOS3 path prefix`).option(`--storage-access-key-id <id>`,`BYOS3 access key ID`).option(`--storage-secret-access-key-env <name>`,`Name of an environment variable containing the BYOS3 secret access key`).option(`--storage-secret-access-key-stdin`,`Read the BYOS3 secret access key from stdin`).option(`--driver <type>`,`Infrastructure driver (docker, firecracker, host-agent, tangle)`).option(`--driver-criu`,`Enable CRIU checkpointing (firecracker only)`).option(`--driver-region <region>`,`Preferred region for host-agent driver`).option(`--backend <type>`,`Backend agent type (${n.join(`, `)})`).option(`--backend-model <model>`,`Model override (format: provider/model)`).option(`--backend-api-key-env <name>`,`Name of an environment variable containing the BYOK backend API key`).option(`--backend-api-key-stdin`,`Read the BYOK backend API key from stdin`).option(`--cli-auth <secret>`,"Run --backend claude-code or codex on your own subscription: the stored secret holding a `claude setup-token` token or a Codex auth.json (see `tangle secret create`)").option(`--profile <path>`,`Path to an AgentProfile JSON file to install as the sandbox's backend profile (carries skills, tools, MCP, model). Use with --backend; the profile's inline skills materialize into the harness's native skill directory on first turn`).option(`--profile-stdin`,`Read the AgentProfile JSON from stdin instead of a file (use with --profile)`).option(`--tee <type>`,`Require a TEE backend (any, tdx, nitro, sev-snp, phala-dstack)`).option(`--sealed`,`Request TEE sealed-secret support`).option(`--attestation-nonce <hex|auto>`,`Deploy-time attestation nonce; use auto to generate one`).option(`--attestation-refresh`,`Generate a fresh deploy-time attestation nonce when --tee is set`).option(`--require-attestation`,`Fail unless TEE attestation evidence is returned`).option(`--wait`,`Wait for sandbox to be running`,!0).option(`--timeout <ms>`,`HTTP timeout in milliseconds`,`30000`).action(async e=>{let t=await Cl({envVarName:e.gitTokenEnv,fromStdin:e.gitTokenStdin,flagPrefix:`--git-token`}),n=await Cl({envVarName:e.storageSecretAccessKeyEnv,fromStdin:e.storageSecretAccessKeyStdin,flagPrefix:`--storage-secret-access-key`}),r=await Cl({envVarName:e.backendApiKeyEnv,fromStdin:e.backendApiKeyStdin,flagPrefix:`--backend-api-key`}),i=wl({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{R(Error(`--profile-stdin: the input is not valid JSON`));return}}else if(e.profile){let t=String(e.profile);if(t.startsWith(`.`)||t.startsWith(`/`)||t.endsWith(`.json`))try{a=JSON.parse(T(t,`utf8`))}catch(e){R(Error(`--profile ${t}: ${e.message}`));return}else try{a=await Sl(t,e)}catch(e){R(Error(`--profile ${t}: ${e.message}`));return}}let o=V({apiKey:e.apiKey,baseUrl:e.baseUrl,timeout:e.timeout?Number.parseInt(e.timeout,10):void 0}),s=H(o),c=P(`Creating sandbox...`);c.start();let l=await Vl({client:s,explicitTeam:e.team,personal:e.personal,activeTeamId:o.activeTeamId}),u={};if(e.env)for(let t of e.env){let[e,...n]=t.split(`=`);e&&n.length>0&&(u[e]=n.join(`=`))}let d=e.metadata?Ol(e.metadata):void 0,f=Al(e,t),p=jl(e,n),m=e.acceleratorKind?Yo({kind:String(e.acceleratorKind),count:String(e.acceleratorCount),memory:typeof e.acceleratorMemory==`string`?e.acceleratorMemory:void 0}):void 0,h=Xo({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`),g=e.driver?{type:e.driver,enableCriu:e.driverCriu||void 0,preferredRegion:e.driverRegion}:void 0,ee=e.backend||e.backendModel||a?{...e.backend?{type:te(e.backend)}:{},...a?{profile:a}:{},model:e.backendModel||r||i?{...e.backendModel?Dl(e.backendModel):{},apiKey:r,...i?{cliAuth:i}:{}}:void 0}:void 0,v=Tl(e.secret),ne=i?[...new Set([...v??[],i.secretEnv])]:v,y=El(e,m),re=[...e.sshKey?[e.sshKey]:[],...(e.sshKeyFile??[]).map(e=>T(e,`utf8`).trim())],b={name:e.name,environment:e.environment,bare:e.bare||void 0,sshEnabled:e.ssh||!!e.sshKey||re.length>0||!!e.sshKeys?.length,sshPublicKeys:re.length>0?re:void 0,sshKeyIds:e.sshKeys,webTerminalEnabled:e.webTerminal,env:Object.keys(u).length>0?u:void 0,git:f,...y?{resources:y}:{},gpuLease:h,maxLifetimeSeconds:Number.parseInt(e.lifetime,10),idleTimeoutSeconds:Number.parseInt(e.idleTimeout,10),storage:p,fromSnapshot:e.fromSnapshot,publicTemplateId:e.publicTemplate,publicTemplateVersionId:e.publicTemplateVersion,teamId:l,...e.billingOwner?{billingOwnerId:e.billingOwner}:{},secrets:ne,metadata:d,driver:g,backend:ee},x=e.tee?{tee:e.tee,sealed:e.sealed||void 0,attestationRefresh:e.attestationRefresh||e.attestationNonce===`auto`||void 0}:void 0,S=x?await _(s,{...b,confidential:x,attestationNonce:e.attestationNonce??(e.attestationRefresh?`auto`:void 0),requireAttestation:e.requireAttestation??!0}):void 0,C=S?.sandbox??await s.create(b);e.wait&&(c.text=`Waiting for sandbox to start...`,await C.waitFor(`running`,{timeoutMs:12e4}),await C.refresh()),c.stop(),e.json?j({id:C.id,name:C.name,status:C.status,resources:C.resources,createdAt:C.createdAt,expiresAt:C.expiresAt,connection:Ul(C.connection),teamId:l,gpuLease:C.gpuLease,confidential:x,attestation:S?.attestation,attestationNonce:S?.attestationNonce}):(M(`Sandbox created: ${C.id}`),Lt({id:C.id,name:C.name,status:C.status,resources:C.resources,createdAt:C.createdAt?.toISOString(),expiresAt:C.expiresAt?.toISOString(),connection:C.connection}),l&&console.log(`Team: ${l}`),C.gpuLease&&(console.log(`GPU lease: ${C.gpuLease.id}`),Nl(C.gpuLease)),x&&(console.log(`TEE: ${x.tee}`),console.log(`Attestation: ${S?.attestation?`present`:`not returned`}`),S?.attestationNonce&&console.log(`Attestation nonce: ${S.attestationNonce}`)))})}function Kl(e){e.command(`network <id-or-name>`).description(`Show runtime network state (exposed ports) for a sandbox. Outbound policy is not settable here — see the outbound flags.`).option(`--block-outbound`,`Unenforceable; the server rejects it. Block outbound traffic with an egress policy of mode "blocked"`).option(`--allow-list <cidrs>`,`Unenforceable; the server rejects it. Egress policy allowlists domains, not CIDRs`).option(`--clear`,`Unenforceable; the server rejects it. There is no per-sandbox outbound restriction here to clear`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Updating network configuration...`);i.start();let a=await G(r,n,e);if(t.clear)await a.network.update({blockOutbound:!1,allowList:[]});else if(t.blockOutbound)await a.network.update({blockOutbound:!0});else if(t.allowList){let e=t.allowList.split(`,`).map(e=>e.trim());await a.network.update({allowList:e})}else{i.stop();let e=await a.network.getConfig();t.json?j(e):(N(`Network Configuration:`),e.ports&&e.ports.length>0?N(` Exposed Ports: ${e.ports.join(`, `)}`):N(` No exposed ports`));return}i.stop();let o=await a.network.getConfig();t.json?j(o):(M(`Network configuration updated.`),o.ports&&o.ports.length>0&&N(` Exposed Ports: ${o.ports.join(`, `)}`))}),e.command(`expose <id-or-name>`).description(`Expose a port and get a public URL`).option(`-p, --port <port>`,`Port to expose`,`8000`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=Number.parseInt(t.port,10);if(Number.isNaN(i)||i<1||i>65535)throw Error(`Port must be a number between 1 and 65535`);let a=P(`Exposing port ${i}...`);a.start();let o=await(await G(r,n,e)).network.exposePort(i);a.stop(),t.json?j({port:i,url:o}):(M(`Port ${i} exposed.`),N(` URL: ${o}`))}),e.command(`urls <id-or-name>`).description(`List exposed port URLs for a sandbox`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching exposed URLs...`);i.start();let a=await(await G(r,n,e)).network.listUrls();if(i.stop(),t.json)j(a);else{let e=Object.entries(a);if(e.length===0)N(`No ports exposed.`);else{N(`Exposed Ports:`);for(let[t,n]of e)N(` ${t}: ${n}`)}}})}function ql(){let e=new b(`sandbox`).description(`Manage sandboxes`);return Gl(e),Wl(e),Fl(e),Kl(e),e}function Jl(){return new b(`search`).description(`Search for text patterns in sandbox files (ripgrep)`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pattern>`,`Search pattern (regex)`).option(`-g, --glob <pattern>`,`File glob filter (e.g. '**/*.ts')`).option(`-n, --max-results <count>`,`Max results to return`).option(`-i, --ignore-case`,`Case-insensitive search`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Searching...`);n.json||a.start();let o=await G(i,r,e),s=0,c=n.maxResults?Number.parseInt(n.maxResults,10):void 0,l={};n.glob&&(l.glob=n.glob),n.ignoreCase&&(l.ignoreCase=!0),c&&(l.maxResults=c);for await(let e of o.search(t,l))if(s===0&&a.stop(),s++,n.json?console.log(JSON.stringify(e)):console.log(`${e.path}:${e.line}:${e.column??0}: ${e.text}`),c&&s>=c)break;a.stop(),s===0&&!n.json&&console.log(`No matches found`)})}function Yl(){let e=new b(`secret`).description(`Manage secrets`);return e.command(`create`).description(`Create a new secret`).argument(`<name>`,`Secret name (e.g., HF_TOKEN, AWS_ACCESS_KEY)`).argument(`[value]`,`Secret value`).option(`--value-stdin`,`Read secret value from stdin`).option(`--from-login <harness>`,`Authorize Claude in its native browser and store its token privately`).action(async(e,t,n)=>{if(n.fromLogin!==void 0&&(n.fromLogin!==`claude`||t!==void 0||n.valueStdin))throw new I(`NATIVE_CREDENTIAL_ARGUMENTS`,`Native enrollment arguments are invalid`,`Use --from-login claude without a value argument or --value-stdin`,`tangle secret create --help`);let r=U(n).client,i=n.fromLogin===void 0?await r.secrets.create(e,await Xl({value:t,valueStdin:n.valueStdin,prompt:`Enter value for secret '${e}': `})):await Ts(r,e);n.json?j(i):(M(`Secret created: ${i.name}`),N(`Use --secrets ${i.name} when creating a sandbox to inject it as an environment variable.`))}),e.command(`list`).description(`List all secrets`).action(async e=>{let t=await U(e).client.secrets.list();e.json?j(t):t.length===0?(N(`No secrets found.`),N(`Use 'tangle secret create <name> [value]' to create one.`)):Rt([`Name`,`Created At`,`Updated At`],t.map(e=>[e.name,e.createdAt.toLocaleString(),e.updatedAt.toLocaleString()]))}),e.command(`delete`).description(`Delete a secret`).argument(`<name>`,`Secret name`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=U(t).client;if(!t.force&&!await ei(`Are you sure you want to delete secret '${e}'? This cannot be undone. (y/N) `,`--force`)){N(`Cancelled.`);return}await n.secrets.delete(e),t.json?j({success:!0,deleted:e}):M(`Secret deleted: ${e}`)}),e}async function Xl(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 Zl(){let e=new b(`skill`).description(`Print paths to shipped skill documentation`);return e.command(`path`).description(`Print the absolute path to the SKILL.md shipped with this CLI`).action(()=>{let e=E.dirname(rt(import.meta.url)),t=E.resolve(e,`..`,`SKILL.md`);console.log(t)}),e}function Ql(){let e=new b(`snapshot`).description(`Manage snapshots`);return e.command(`create <sandbox-id-or-name>`).description(`Create a snapshot of a sandbox`).option(`--tags <tags...>`,`Tags for the snapshot`).option(`--no-wait`,`Return once the snapshot is accepted and print the operation to poll`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Creating snapshot...`);i.start();let a=await G(r,n,e);if(t.wait===!1){let e=await a.snapshot({tags:t.tags,wait:!1});i.stop(),Il(e.info,!!t.json);return}let o=await a.snapshot({tags:t.tags});i.stop(),t.json?j(o):(M(`Snapshot created: ${o.snapshotId}`),console.log(`Size: ${$l(o.sizeBytes??0)}`))}),e.command(`list <sandbox-id-or-name>`).description(`List snapshots for a sandbox`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching snapshots...`);i.start();let a=await(await G(r,n,e)).listSnapshots();i.stop(),t.json?j(a):A(a.map(e=>({...e,size:$l(e.sizeBytes??0)})),[{key:`snapshotId`,header:`ID`,width:24},{key:`createdAt`,header:`Created`,width:16},{key:`size`,header:`Size`,width:12},{key:`sandboxId`,header:`Sandbox`,width:20}])}),e.command(`restore <sandbox-id> <snapshot-id>`).description(`Create a new sandbox from a snapshot`).option(`--billing-owner <userId>`,`Platform user that pays for the restored sandbox. The API accepts this only from a first-party service key that is listed as a billing delegate, and refuses such a key that names no payer.`).action(async(e,t,n)=>{let{client:r}=U(n),i=P(`Restoring from snapshot...`);i.start();let a=await r.create({fromSnapshot:t,fromSandboxId:e,...n.billingOwner?{billingOwnerId:n.billingOwner}:{}});await a.waitFor(`running`,{timeoutMs:12e4}),i.stop(),n.json?j({sandboxId:a.id,restoredFrom:t,status:a.status}):(M(`New sandbox created: ${a.id}`),console.log(`Source snapshot: ${t}`))}),e.command(`revert <sandbox-id-or-name> <snapshot-id>`).description(`Revert an existing sandbox to a snapshot`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Reverting sandbox to snapshot...`);a.start();let o=await G(i,r,e),s=await o.revertToSnapshot(t);await o.refresh(),a.stop(),n.json?j({sandboxId:o.id,snapshotId:s.snapshotId,status:o.status}):(M(`Sandbox reverted: ${o.id}`),console.log(`Source snapshot: ${s.snapshotId}`))}),e.command(`delete <sandbox-id-or-name> <snapshot-id>`).description(`Delete a sandbox snapshot`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Deleting snapshot...`);a.start();let o=await(await G(i,r,e)).deleteSnapshot(t);a.stop(),n.json?j({success:!0,sandboxId:e,snapshotId:t,outcome:o.outcome}):o.outcome===`already_absent`?M(`Snapshot already gone: ${t}`):M(`Snapshot deleted: ${t}`)}),e}function $l(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 eu=`solve:device:secp256k1`,tu=/^0x[0-9a-f]{64}$/i;function nu(e){return e&&tu.test(e)?e:void 0}function ru(){let e=fn(eu),t=nu(e.value);if(!(!t||e.source===`none`))return{account:at(t),source:e.source}}function iu(){let e=ru();if(e)return e;let t=it(),n=pn(eu,t);return{account:at(t),source:n}}function au(e){let t=nu(fn(eu).value);if(!t||at(t).address!==e.account.address)throw Error(`The local Solve device key changed; it was not retired`);let n=`${eu}:retired:${e.account.address.toLowerCase()}`;if(pn(n,t),fn(n).value!==t)throw Error(`The revoked device key could not be retired safely`);return hn(eu),n}function ou(e){let t=e.create?iu():ru();if(!t)throw Error("No Solve device signer found. Run `tangle solve account --create`");e.json?j({address:t.account.address,source:t.source}):F({Address:t.account.address,Source:t.source})}const su=/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;function cu(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function lu(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`${t} must be an object`);return e}function uu(e,t,n=2048){if(typeof e!=`string`||!e.trim()||e.length>n)throw Error(`${t} is missing or invalid`);if(cu(e))throw Error(`${t} contains control characters`);return e.trim()}function du(e,t){let n=uu(e,t,64).toLowerCase();if(!su.test(n))throw Error(`${t} must be a 40 or 64 character Git revision`);return n}function fu(e,t,n=!1){let r=typeof e==`number`&&Number.isSafeInteger(e)?String(e):uu(e,t,80);if(!/^\d+$/.test(r)||!n&&r===`0`)throw Error(`${t} must be an unsigned integer`);return BigInt(r).toString()}function pu(e,t){let n=uu(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 mu(e,t){let n=pu(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 hu(e,t){let n=uu(e,t,42);if(!pt(n,{strict:!1}))throw Error(`${t} must be an EVM address`);return dt(n)}function gu(e,t){let n=fu(e,t),r=Number(n);if(!Number.isSafeInteger(r)||r<=0)throw Error(`${t} is out of range`);return r}function Z(...e){for(let t of e)if(typeof t==`string`&&t.trim())return t.trim()}function _u(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 vu(e){if(e===void 0)return;let t=uu(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 yu(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 bu(e){return Fn(`solve`,e.profile)}function xu(e){let t=bu(e),n=nr(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 Su(e){let t=ur(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 ${xu(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 Cu(e){return Su({path:`/v1/wallet/challenges`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.purpose?{purpose:e.purpose}:{}}})}function wu(e){return Su({path:`/v1/devices`,apiUrl:e.apiUrl,profile:e.profile})}function Tu(e){return Su({path:`/v1/devices/revoke`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.reason?{reason:e.reason}:{},...e.challengeId&&e.signature?{challengeId:e.challengeId,signature:e.signature}:{}}})}const Q={chainId:42431,rpcUrl:`https://rpc.moderato.tempo.xyz`,sponsorUrl:`https://drew-gtr-pro.taild10bfc.ts.net/solve-sponsor`,tangleAddress:`0xff137B9C879c47C28ce389e84501925438AB4cdA`,managerAddress:`0x5271732F893B622ac6793d6DBA5B2626CCa4EA14`,paymentAsset:`0x20C0000000000000000000000000000000000000`,blueprintId:15n,serviceId:9n,competitionId:1n,minStakeWei:0n};function Eu(e,t){return e.toLowerCase()===t.toLowerCase()}function Du(e){if(e.chainId!==Q.chainId)throw Error(`Solve submissions require Tempo Moderato (chain ${Q.chainId}); received ${e.chainId}`);if(e.rpcUrl!==Q.rpcUrl)throw Error(`Solve metadata RPC does not match the trusted deployment`);if(e.sponsorUrl!==Q.sponsorUrl)throw Error(`Solve metadata sponsor does not match the trusted deployment`);if(!Eu(e.tangleAddress,Q.tangleAddress))throw Error(`Solve metadata Tangle contract does not match the trusted deployment`);if(!Eu(e.managerAddress,Q.managerAddress))throw Error(`Solve metadata competition manager does not match the trusted deployment`);if(!Eu(e.paymentAsset,Q.paymentAsset))throw Error(`Solve metadata payment asset does not match the trusted deployment`);if(e.blueprintId!==Q.blueprintId)throw Error(`Solve submissions require blueprint ${Q.blueprintId}; received ${e.blueprintId}`);if(e.serviceId!==Q.serviceId)throw Error(`Solve submissions require service ${Q.serviceId}; received ${e.serviceId}`);if(e.competitionId!==Q.competitionId)throw Error(`Solve submissions require competition ${Q.competitionId}; received ${e.competitionId}`);if(e.minStakeWei!==Q.minStakeWei)throw Error(`Solve submissions require zero stake for the trusted deployment`)}function Ou(e,t){let n=lu(t.check??e.check,`competition.participation.check`),r=uu(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=>uu(e,`competition checker argument`,2048)),a=Z(n.result_file,n.resultFile),o=n.timeout_ms??n.timeoutMs,s=o===void 0?void 0:gu(o,`competition checker timeout`);return{command:r,args:i,...a?{result_file:a}:{},...s?{timeout_ms:s}:{}}}function ku(e){if(e.provenance===void 0)return;let t=lu(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 Au(e){let t=lu(e.chain??e.network??{},`competition.chain`),n=e.rewards&&typeof e.rewards==`object`&&!Array.isArray(e.rewards)?lu(e.rewards,`competition.rewards`):{},r=n.minStake&&typeof n.minStake==`object`&&!Array.isArray(n.minStake)?lu(n.minStake,`competition.rewards.minStake`).raw:void 0,i=Z(t.minStakeWei,t.min_stake_wei,e.minStakeWei,e.min_stake_wei,r),a=t.chainId??t.chain_id??e.chainId??e.chain_id,o=Z(t.chainName,t.chain_name,e.chainName,e.chain_name)??`Tempo`,s=Z(t.nativeSymbol,t.native_symbol,e.nativeSymbol,e.native_symbol)??`TNT`,c=Z(t.rpcUrl,t.rpc_url,e.rpcUrl,e.rpc_url,process.env.TANGLE_SOLVE_RPC_URL),l=Z(t.sponsorUrl,t.sponsor_url,e.sponsorUrl,e.sponsor_url,process.env.TANGLE_SOLVE_SPONSOR_URL),u=Z(t.tangleAddress,t.tangle_address,t.coreAddress,t.core_address,e.tangleAddress,e.tangle_address,e.coreAddress,e.core_address),d=Z(t.managerAddress,t.manager_address,e.managerAddress,e.manager_address),f=Z(t.paymentAsset,t.payment_asset,t.servicePaymentAsset,t.service_payment_asset,e.paymentAsset,e.payment_asset,e.servicePaymentAsset,e.service_payment_asset),p=Z(t.blueprintId,t.blueprint_id,e.blueprintId,e.blueprint_id),m=Z(t.serviceId,t.service_id,e.serviceId,e.service_id),h=Z(t.competitionId,t.competition_id,e.competitionId,e.competition_id,e.id);if(!c||!l||!u||!d||!p||!m||!h||!i||a===void 0)throw Error(`Solve competition metadata must include complete Tempo chain configuration`);return{chainId:gu(a,`chain.chainId`),chainName:o,nativeSymbol:s,rpcUrl:pu(c,`chain.rpcUrl`),sponsorUrl:pu(l,`chain.sponsorUrl`),tangleAddress:hu(u,`chain.tangleAddress`),managerAddress:hu(d,`chain.managerAddress`),paymentAsset:hu(f??Q.paymentAsset,`chain.paymentAsset`),blueprintId:fu(p,`chain.blueprintId`),serviceId:fu(m,`chain.serviceId`),competitionId:fu(h,`chain.competitionId`,!0),minStakeWei:fu(i,`chain.minStakeWei`,!0)}}function ju(e){let t=lu(e,`competition`),n=lu(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=mu(Z(r.repository,r.repo_url,i.repository)??``,`competition.repository`),o=du(Z(r.repositoryRevision,r.repository_revision,i.revision,i.repositoryRevision,i.repository_revision),`competition.repositoryRevision`),s=uu(r.slug??r.id,`competition.slug`,128),c=uu(r.name??r.title??s,`competition.name`,256),l=Ou(r,i),u=ku(i);return{version:1,slug:s,title:c,repository:a,taskRevision:o,checker:l,chain:Au(r),...u?{provenance:u}:{}}}function Mu(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 Nu(e){let t=lu(JSON.parse(await k.readFile(E.join(e,`.tangle-solve.json`),`utf8`)),`.tangle-solve.json`);if(t.version!==1)throw Error(`.tangle-solve.json has an unsupported version`);let n=lu(t.checker,`.tangle-solve.json.checker`),r=lu(t.chain,`.tangle-solve.json.chain`);return ju({slug:t.slug,name:t.title,repository:t.repository,repositoryRevision:t.taskRevision,participation:{check:n,provenance:t.provenance},chain:r,competitionId:r.competitionId})}const Pu=Xe(Te),Fu=`.tangle-solve-run.json`,Iu=`.tangle-solve.json`,Lu=`tangle.solve.manifestSha256`,Ru=new Set([Iu,Fu]),zu=`upstream`;async function Bu(e,t){let n=await Pu(`git`,[`-C`,e,...t],{encoding:`utf8`,maxBuffer:1e6});return String(n.stdout).trim()}async function Vu(e,t){let n=E.resolve(t??process.cwd()),r=await Nu(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 Hu(e){let t=E.join(e,Iu),n;try{n=await k.lstat(t)}catch{throw Error(`${Iu} is missing`)}if(n.isSymbolicLink()||!n.isFile())throw Error(`${Iu} must be a regular file`);return x(`sha256`).update(await k.readFile(t)).digest(`hex`)}async function Uu(e){let t=await Hu(e);return await Bu(e,[`config`,`--local`,`--replace-all`,Lu,t]),t}async function Wu(e){let t;try{t=await Bu(e,[`config`,`--local`,`--get`,Lu])}catch{throw Error(`The local Git metadata has no ${Lu} pin; run tangle solve clone again`)}if(!/^[0-9a-f]{64}$/i.test(t))throw Error(`The local ${Lu} pin is invalid`);if(await Hu(e)!==t.toLowerCase())throw Error(`${Iu} changed after clone; run tangle solve clone again`)}async function Gu(e,t){try{return await Bu(e,[`ls-files`,`--error-unmatch`,`--`,t]),!0}catch{return!1}}async function Ku(e){await Wu(e);for(let t of Ru)if(await Gu(e,t))throw Error(`${t} must remain untracked and local to this Solve workspace`);let t=await Pu(`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===`!!`)&&Ru.has(n))}).length>0)throw Error(`Commit the candidate before running Solve. Only the local manifest and run record may remain uncommitted.`);return du(await Bu(e,[`rev-parse`,`HEAD`]),`submission revision`)}async function qu(e,t,n,r={}){let i=await Ju(e,t,r);if(i)return{taskRepository:t.repository,taskRevision:t.taskRevision,submissionRepository:i,submissionRevision:n}}async function Ju(e,t,n={}){let r;try{r=_u(await Bu(e,[`config`,`--get`,`remote.origin.pushurl`]))}catch{try{r=_u(await Bu(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 '${zu}'.`)}}let i=mu(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 '${zu}' before submitting.`)}return i}function Yu(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 Xu(e,t){return`${e}/commit/${t}`}function Zu(e,t,n,r,i={}){let a=e.evidenceRefs.map(e=>yu(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=vu(r);if(n.required&&(i.requirePullRequest??!0)&&!o)throw Error(`This competition requires a GitHub pull request`);a.push(Xu(t.taskRepository,t.taskRevision),Xu(t.submissionRepository,t.submissionRevision),...o?[o]:[])}return{evidence:e.evidence,evidenceRefs:[...new Set(a)]}}async function Qu(e,t){let n=`${e}.${process.pid}.tmp`;await k.writeFile(n,`${JSON.stringify(t,null,2)}\n`,{mode:384}),await k.rename(n,e)}async function $u(e){let t=JSON.parse(await k.readFile(E.join(e,Fu),`utf8`));if(t.version!==1||typeof t.competition!=`string`)throw Error(`${Fu} has an unsupported format`);return t}async function ed(e){let t=vu(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 td(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 nd=Xe(Te);function rd(){return`Task source is '${zu}'. Add your fork as 'origin', commit your candidate, push it, and open a pull request before submitting.`}async function id(e,t,n){try{let r=lu(await Su({path:`/v1/competitions/${encodeURIComponent(e)}`,apiUrl:n.apiUrl,profile:n.profile}),`competition response`),i=ju(r.competition??r),a=E.resolve(t??i.slug),o=P(`Cloning ${i.slug}…`);n.json||o.start();try{await nd(`git`,[`clone`,`--no-tags`,`--origin`,zu,i.repository,a],{encoding:`utf8`,maxBuffer:1e6}),await Bu(a,[`checkout`,`--detach`,i.taskRevision]);let e=await Bu(a,[`rev-parse`,`HEAD`]);if(e.toLowerCase()!==i.taskRevision.toLowerCase())throw Error(`Pinned checkout resolved to ${e}, expected ${i.taskRevision}`);await Qu(E.join(a,`.tangle-solve.json`),i),await Uu(a)}finally{o.stop()}n.json?j({competition:i,directory:a}):(M(`Cloned ${i.slug} at ${i.taskRevision.slice(0,12)}`),i.provenance&&N(rd()),N(`Run the pinned checker with: cd ${a} && tangle solve run`))}catch(e){R(e)}}const ad=12e4,od=gt(`event JobSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint8 jobIndex, address caller, bytes inputs)`),sd=gt(`event JobCompleted(uint64 indexed serviceId, uint64 indexed callId)`),cd=gt(`event JobResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, address indexed operator, bytes result)`),ld=gt(`event AggregatedResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint256 signerBitmap, bytes output)`),ud=gt(`event EvaluationAccepted(uint64 indexed serviceId, uint64 indexed competitionId, address indexed researcher, bytes32 candidateId, bytes32 submissionRefHash, bytes32 evaluationDigest, bytes32 metricsHash, bytes32 evidenceRefsHash)`),dd=[...ht([`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)`]),od,sd,cd,ld],fd=ht([`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)`]),pd=ht([`function allowance(address owner, address spender) view returns (uint256)`,`function approve(address spender, uint256 amount) returns (bool)`]),md=_t(`uint64 competitionId, uint256 stakeWei`),hd=_t(`uint64 competitionId, bytes32 commitment`),gd=_t(`uint64 competitionId, bytes32 commitment, string artifactRef, bytes32 salt`),_d=_t(`string artifactRef, bytes32 salt`),vd=_t(`uint64 competitionId, bytes32 candidateId, string submissionRef, string evidenceJson, string evidenceRefsJson`),yd=_t(`string status, string detail`),bd=/^0x[0-9a-f]{64}$/i;function xd(e,t){if(e!==t)throw Error(`Tempo RPC returned chain ${e}; expected ${t}`)}function Sd(e,t,n){return{...e,feePayer:!0,nonceKey:t,nonce:n}}function Cd(e,t){if(e!==`success`)throw Error(`${t} transaction reverted`)}function wd(e,t,n,r){if(!bd.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(Cd(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 Td(e,t){return e>=t?[]:e>0n?[0n,t]:[t]}function Ed(e,t,n=Date.now()){return n>=e+t}function Dd(e,t){return e.filter(e=>e.args?.candidateId?.toLowerCase()===t.toLowerCase()).at(-1)?.transactionHash}function Od(e,t,n,r,i){for(let a of e.logs)if(a.address.toLowerCase()===t.tangleAddress.toLowerCase())try{let e=lt({abi:[od],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 kd(e,t,n,r){for(let i of e.logs)if(i.address.toLowerCase()===t.managerAddress.toLowerCase())try{let e=lt({abi:[ud],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 Ad(e){if(e.chainId!==bt.id)throw Error(`Solve submissions require Tempo Moderato (chain ${bt.id}); received ${e.chainId}`);if(!e.sponsorUrl)throw Error(`Solve submissions require a Tempo sponsor relay URL; unsponsored writes are disabled`);return{...bt,name:e.chainName,nativeCurrency:{name:e.nativeSymbol,symbol:e.nativeSymbol,decimals:18},rpcUrls:{default:{http:[e.rpcUrl]}}}}async function jd(e,t){Du(e);let n=Ad(e),r=ot({chain:n,transport:ft(e.rpcUrl)});return xd(await r.getChainId(),e.chainId),await Md({publicClient:r},e),{publicClient:r,walletClient:st({account:t,chain:n,transport:St(ft(e.rpcUrl),ft(e.sponsorUrl))}),account:t}}async function Md(e,t){let n=await e.publicClient.readContract({address:t.tangleAddress,abi:dd,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 Nd(e,t,n){let[r,i]=await Promise.all([e.publicClient.readContract({address:t.tangleAddress,abi:dd,functionName:`getJobEventRate`,args:[t.blueprintId,n]}),e.publicClient.readContract({address:t.tangleAddress,abi:dd,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 Pd(e,t,n){return await e.publicClient.readContract({address:t,abi:pd,functionName:`allowance`,args:[e.account.address,n.tangleAddress]})}async function Fd(e,t,n,r,i,a){let o=Date.now();for(;!Ed(o,a);){if((await e.publicClient.getLogs({address:t.tangleAddress,event:sd,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`})).length>0){let a=(await e.publicClient.getLogs({address:t.tangleAddress,event:cd,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]=ct(yd,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 Id(e,t,n,r,i){let a=Date.now();for(;!Ed(a,i);){let i=(await e.publicClient.getLogs({address:t.tangleAddress,event:ld,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 Ld(e,t,n){return!!await e.publicClient.readContract({address:t.managerAddress,abi:fd,functionName:`acceptedCandidates`,args:[t.serviceId,t.competitionId,e.account.address,n]})}const Rd=BigInt(mt(vt(`tangle.solve.v1`)));async function zd(e,t){let n=await xt.nonce.getNonce(e.publicClient,{account:e.account.address,nonceKey:Rd});if(n>BigInt(2**53-1))throw Error(`The Solve transaction nonce exceeds the safe range`);return e.walletClient.writeContract(Sd(t,Rd,Number(n)))}async function Bd(e,t,n,r){if(!await e.publicClient.readContract({address:t.tangleAddress,abi:dd,functionName:`isPermittedCaller`,args:[t.serviceId,e.account.address]}))try{let i=r??await zd(e,{address:t.managerAddress,abi:fd,functionName:`authorizeSelf`,args:[t.serviceId]});if(r||await n?.(`authorization`,i),wd(await e.publicClient.waitForTransactionReceipt({hash:i}),i,`Authorization`,{from:e.account.address,to:t.managerAddress}),!await e.publicClient.readContract({address:t.tangleAddress,abi:dd,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 Vd(e,t){let n=await zd(e,{address:t.managerAddress,abi:fd,functionName:`revokeSelf`,args:[t.serviceId]});return wd(await e.publicClient.waitForTransactionReceipt({hash:n}),n,`Revocation`,{from:e.account.address,to:t.managerAddress}),n}async function Hd(e,t,n,r,i=`allowance`,a={}){if(t.amount===0n||t.asset===`0x0000000000000000000000000000000000000000`)return;let o=await Pd(e,t.asset,n);for(let s of Td(o,t.amount)){let o=s===0n?`${i}:reset`:`${i}:approval`,c=a[o];if(c){if(wd(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 Pd(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 zd(e,{address:t.asset,abi:pd,functionName:`approve`,args:[n.tangleAddress,s]});await r?.(o,l),wd(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 Ud(e,t,n,r,i,a=`job:${n}`,o={}){let s=await Nd(e,t,n);await Hd(e,s,t,i,`allowance:${a}`,o);let c=o[a],l=c??await zd(e,{address:t.tangleAddress,abi:dd,functionName:`submitJob`,args:[t.serviceId,n,r],value:s.value});c||await i?.(a,l);let u=await e.publicClient.waitForTransactionReceipt({hash:l});return wd(u,l,`Job ${n}`,{from:e.account.address,to:t.tangleAddress}),{hash:l,callId:Od(u,t,n,e.account.address,r),blockNumber:u.blockNumber}}async function Wd(e,t,n,r,i,a,o=`job:${n}`,s={}){let c=await Ud(e,t,n,r,a,o,s),l=await Fd(e,t,c.callId,c.blockNumber,i,ad);return{...c,acknowledgement:l}}const Gd={...Q,chainName:`Tempo Moderato`,nativeSymbol:`TNT`},Kd={async read(e){let t=ot({chain:bt,transport:ft(Gd.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:Gd.tangleAddress,abi:dd,functionName:`isPermittedCaller`,args:[Gd.serviceId,e]})),n(t.readContract({address:Gd.managerAddress,abi:fd,functionName:`isDeviceRevoked`,args:[e]}))]);return[e.toLowerCase(),{permitted:r,revoked:i}]}));return new Map(r)},async revokeSelf(e){return Vd(await jd(Gd,e),Gd)}},qd={permitted:null,revoked:null};function Jd(e){return e.revoked?`revoked`:e.permitted===null?`unknown`:e.permitted?`permitted`:`not permitted`}async function Yd(e,t=Kd){try{let{devices:n}=await wu({apiUrl:e.apiUrl,profile:e.profile}),r=ru()?.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=>dt(e.address))),o=i.map(e=>({...e,onChain:a.get(e.address)??qd}));if(e.json){j({serviceId:Gd.serviceId.toString(),devices:o});return}Rt([`Address`,`Status`,`Local`,`Service ${Gd.serviceId}`,`Last used`,`Revoked`],o.map(e=>[e.address,e.status,e.local?`yes`:``,Jd(e.onChain),e.lastUsedAt??``,e.revokedAt?`${e.revokedAt} (${e.revocationMethod})`:``]))}catch(t){R(t,e.json)}}async function Xd(e,t,n=Kd){try{if(!pt(e))throw Error(`${e} is not an EVM address`);let r=dt(e),i=ru(),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`)){N(`Revocation cancelled`);return}}let o;if(i&&a){let e=await Cu({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 Tu({deviceAddress:r,reason:t.reason,...o,apiUrl:t.apiUrl,profile:t.profile}),c=r.toLowerCase(),l=(await n.read([r])).get(c)??qd,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)??qd}let d=i&&a&&l.revoked?au(i):void 0;if(t.json){j({...s,serviceId:Gd.serviceId.toString(),onChain:l,...u?{revocationTransaction:u}:{},localKeyRetired:!!d});return}M(s.alreadyRevoked?`${r} was already revoked in the Solve API`:`Revoked ${r}; the Solve API refuses its signatures`),u&&M(`Revoked on Tempo in ${u}; service ${Gd.serviceId} refuses its jobs`),d&&N("The local device key was moved aside because its address may still hold stake or rewards. Run `tangle solve account --create` for a new device"),!a&&l.permitted&&Nt(`The device can still submit jobs to service ${Gd.serviceId}. Only its key, or the Solve blueprint owner, can revoke it on chain`)}catch(e){R(e,t.json)}}function Zd(e,t){return mt(ut(_d,[e.trim(),t]))}function Qd(e){let t=/^submission=(\S+)/.exec(e);if(!t?.[1])throw Error(`COMMIT_CANDIDATE did not return a submission reference`);return t[1]}async function $d(e,t,n,r,i){let a=i.resumeTransactions?.evaluation;if(a){let n=await e.publicClient.waitForTransactionReceipt({hash:a});if(wd(n,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!kd(n,t,e.account,r))throw Error(`Saved evaluation transaction did not emit EvaluationAccepted for this candidate`);return a}let o=Date.now();for(;!Ed(o,ad);){if(await Ld(e,t,r)){let i=Dd(await e.publicClient.getLogs({address:t.managerAddress,event:ud,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:fd,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()!==mt(n.output).toLowerCase())throw Error(`Manager pending report output does not match the aggregate`);let a=await zd(e,{address:t.managerAddress,abi:fd,functionName:`executePendingResult`,args:[t.serviceId,n.callId,n.output]});await i.onTransaction?.(`evaluation`,a);let s=await e.publicClient.waitForTransactionReceipt({hash:a});if(wd(s,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!kd(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 ef(e,t,n,r={}){if(Du(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 jd(e,t),a=await Bd(i,e,r.onTransaction,r.resumeTransactions?.authorization),o,s=await i.publicClient.readContract({address:e.managerAddress,abi:fd,functionName:`stakes`,args:[e.serviceId,e.competitionId,i.account.address]});s<e.minStakeWei&&(o=await zd(i,{address:e.managerAddress,abi:fd,functionName:`postStake`,args:[e.serviceId,e.competitionId],value:e.minStakeWei-s}),await r.onTransaction?.(`stake`,o),wd(await i.publicClient.waitForTransactionReceipt({hash:o}),o,`Stake`,{from:i.account.address,to:e.managerAddress}));let c=Zd(n.artifactRef,n.salt),l=ut(md,[e.competitionId,e.minStakeWei]),u=ut(hd,[e.competitionId,c]),d=ut(gd,[e.competitionId,c,n.artifactRef.trim(),n.salt]),f=await Wd(i,e,1,l,`joined`,r.onTransaction,`join`,r.resumeTransactions),p=await Wd(i,e,2,u,`committed`,r.onTransaction,`commit`,r.resumeTransactions),m=Qd(p.acknowledgement.detail),h=await Wd(i,e,3,d,`revealed`,r.onTransaction,`reveal`,r.resumeTransactions),g=await Ud(i,e,4,ut(vd,[e.competitionId,c,m,n.evidenceJson,JSON.stringify(n.evidenceRefs)]),r.onTransaction,`report`,r.resumeTransactions),_=await Id(i,e,g.callId,g.blockNumber,ad),ee=await $d(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:ee,candidateId:c,submissionRef:m}}const tf=Xe(Te),nf=`/usr/bin/bwrap`,rf=[`/usr`,`/bin`,`/sbin`,`/lib`,`/lib64`];function af(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function of(e,t){if(!e||e.length>2048||af(e))throw Error(`${t} contains invalid control characters or is too long`)}function sf(e,t){let n=t;for(;n<e.length&&/\s/.test(e[n]??``);)n+=1;return n}function cf(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 lf(e,t,n){let r=new Set,i=sf(e,t+1);if(e[i]===`}`)return i+1;for(;i<e.length;){let t=cf(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=sf(e,t),e[i]!==`:`)throw Error(`Checker output must be valid JSON`);let o=sf(e,i+1),s=df(e,o);if(n?.(a,o,s),i=sf(e,s),e[i]===`}`)return i+1;if(e[i]!==`,`)throw Error(`Checker output must be valid JSON`);i=sf(e,i+1)}throw Error(`Checker output must be valid JSON`)}function uf(e,t){let n=sf(e,t+1);if(e[n]===`]`)return n+1;for(;n<e.length;){if(n=sf(e,df(e,n)),e[n]===`]`)return n+1;if(e[n]!==`,`)throw Error(`Checker output must be valid JSON`);n=sf(e,n+1)}throw Error(`Checker output must be valid JSON`)}function df(e,t){if(e[t]===`"`)return cf(e,t);if(e[t]===`{`)return lf(e,t);if(e[t]===`[`)return uf(e,t);let n=t;for(;n<e.length&&!/[\s,\]}]/.test(e[n]??``);)n+=1;return n}function ff(e){let t=e.trim();if(sf(t,df(t,0))!==t.length)throw Error(`Checker output must be valid JSON`)}function pf(e,t){let n=e.trim();if(n[0]!==`{`)return;let r;return lf(n,0,(e,i,a)=>{e===t&&(r=n.slice(i,a).trim())}),r}function mf(e,t){let n=e.trim(),r=[];return lf(n,0,(e,i,a)=>{if(e===`evidence_refs`)return;let o=e===`candidate_ref`?JSON.stringify(t):n.slice(i,a).trim();r.push(`${JSON.stringify(e)}:${o}`)}),`{${r.join(`,`)}}`}function hf(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Checker output must be one JSON object`)}if(ff(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`);of(i,`candidate_ref`);for(let e of a)of(e.trim(),`evidence_refs`);let o,s;if(n.evidence_json!==void 0){if(!n.evidence_json||typeof n.evidence_json!=`object`||Array.isArray(n.evidence_json))throw Error(`Checker evidence_json must be an object`);o={...n.evidence_json};let t=pf(e,`evidence_json`);if(!t)throw Error(`Checker evidence_json source text is missing`);if(s=t,o.candidate_ref!==i)throw Error(`Checker evidence_json candidate_ref must match candidate_ref`)}else{let{evidence_refs:t,...r}=n;o=r,o.candidate_ref=i,s=mf(e,i)}return{candidateRef:i,evidenceRefs:a.map(e=>e.trim()),evidence:o,evidenceJson:s}}async function gf(e,t,n){let r=n.trim();if(r.startsWith(`{`)&&r.endsWith(`}`)||!t.result_file)return r;let i=await Sf(e),a=E.resolve(i,t.result_file),o=E.relative(i,a);if(o.startsWith(`..`)||E.isAbsolute(o))throw Error(`Checker result_file must stay inside the competition repository`);let s;try{s=await k.lstat(a)}catch{throw Error(`Checker result_file must be an existing regular file inside the competition repository`)}if(s.isSymbolicLink())throw Error(`Checker result_file must not be a symbolic link`);if(!s.isFile())throw Error(`Checker result_file must be an existing regular file inside the competition repository`);let c;try{c=await k.realpath(a)}catch{throw Error(`Checker result_file must resolve to a regular file inside the competition repository`)}let l=E.relative(i,c);if(l.startsWith(`..`)||E.isAbsolute(l))throw Error(`Checker result_file must stay inside the competition repository`);return(await k.readFile(c,`utf8`)).trim()}function _f(e,t){let n=E.relative(e,t);return n===``||!n.startsWith(`..`)&&!E.isAbsolute(n)}function vf(e){return rf.some(t=>_f(t,e))}async function yf(e,t,n){let r=e.includes(`/`)?[E.resolve(t,e)]:(process.env.PATH??``).split(E.delimiter).filter(Boolean).map(t=>E.join(t,e));for(let i of r){let r;try{r=await k.realpath(i),await k.access(r,k.constants.X_OK)}catch{continue}if(!_f(t,r)&&!vf(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 bf(e){let t=[];for(let n of e)try{(await k.stat(n)).isDirectory()&&t.push(n)}catch{}return t}async function xf(e){let t=await k.realpath(Se.homedir());if(e===E.parse(e).root||e===t)throw Error(`Solve checker repository must be a dedicated directory, not the filesystem or home root`)}async function Sf(e){let t=await k.realpath(e);return await xf(t),t}async function Cf(e){let t=E.join(e,`.git`),n;try{n=await k.lstat(t)}catch{return}if(n.isSymbolicLink())throw Error(`Solve checker repository .git must not be a symbolic link`);if(!n.isDirectory()&&!n.isFile())return;let r;try{let t={...process.env};for(let e of[`GIT_DIR`,`GIT_WORK_TREE`,`GIT_INDEX_FILE`,`GIT_OBJECT_DIRECTORY`,`GIT_ALTERNATE_OBJECT_DIRECTORIES`,`GIT_COMMON_DIR`,`GIT_CONFIG_COUNT`,`GIT_CONFIG_PARAMETERS`])delete t[e];let n=await tf(`/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 wf(e,t,n){let r=await Sf(e);if(process.platform!==`linux`)throw Error(`Solve checkers require the Linux sandbox runtime (bubblewrap) with network isolation`);try{await k.access(nf,k.constants.X_OK)}catch{throw Error(`Solve checkers require /usr/bin/bwrap; install bubblewrap or run the checker in a Tangle sandbox`)}let i=await yf(t,r,await k.realpath(process.execPath)),a=await Cf(r),o=(await bf(rf)).flatMap(e=>[`--ro-bind`,e,e]),s=_f(r,i)?`/work/${E.relative(r,i)}`:vf(i)?i:`/checker/node`;!_f(r,i)&&!vf(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:nf,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 Tf(e,t){if(!t.command||t.command.includes(`/../`)||af(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)of(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 Sf(e),i;try{let e=await wf(r,t.command,t.args);i=await tf(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{...hf(await gf(r,t,a)),stdout:a,stderr:o}}async function Ef(e,t){try{let{root:n,manifest:r}=await Vu(e,t.directory),i=await Ku(n),a=r.provenance?await qu(n,r,i,{allowMissing:!0}):void 0,o=iu(),s=P(`Running ${r.title} checker…`);t.json||s.start();let c;try{c=await Tf(n,r.checker)}finally{s.stop()}let l=Zu(c,a,r.provenance,void 0,{allowMissingSource:!0,requirePullRequest:!1}),u=yt(S(32)),d=Zd(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:C(),createdAt:new Date().toISOString()};await Qu(E.join(n,`.tangle-solve-run.json`),f),t.json?j({localRun:f}):(M(`Checker output recorded locally for operator evaluation`),F({Competition:r.slug,Candidate:c.candidateRef,"Device address":o.account.address,"Evidence refs":l.evidenceRefs.length}),N("Commit any changes, then run `tangle solve submit` from this directory."),r.provenance&&!a&&N(`Add your GitHub fork as 'origin' before submitting. The task repository is available as '${zu}'.`))}catch(e){R(e)}}const Df=/^0x[0-9a-f]{64}$/i;async function Of(e){let t=await Cu({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 kf(e,t){try{let{root:n,manifest:r}=await Vu(e,t.directory);bu({profile:t.profile});let i=await Ku(n),a=await $u(n);if(a.competition!==r.slug)throw Error(`.tangle-solve-run.json does not match this competition`);if(!Df.test(a.salt)||!Df.test(a.candidateId))throw Error("This run predates durable candidate identity. Run `tangle solve run` again");let o=r.provenance?await qu(n,r,i):void 0;if(r.provenance&&a.source&&!Yu(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=ru();if(!s)throw Error("No Solve device signer found. Run `tangle solve run` first");if(s.account.address.toLowerCase()!==a.deviceAddress.toLowerCase())throw Error("The local Solve device account changed after `tangle solve run`; run the checker again");let c=P(`Checking the committed candidate…`);t.json||c.start();let l;try{l=await Tf(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(Zd(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=vu(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 ed({pullRequest:u,taskRepository:o.taskRepository,submissionRepository:o.submissionRepository,submissionRevision:i})}let d=Zu(l,o,r.provenance,u,{requirePullRequest:!0}),f={...a,...o?{source:o}:{},chainState:{status:`submitting`,transactions:{...a.chainState?.transactions??{}}}},p=E.join(n,`.tangle-solve-run.json`);await Qu(p,f);let m=P(`Submitting candidate to Tempo…`);t.json||m.start();let h;try{h=await ef(Mu(r),s.account,{artifactRef:l.candidateRef,salt:a.salt,evidenceJson:l.evidenceJson,evidenceRefs:d.evidenceRefs},{resumeTransactions:f.chainState?.transactions,onTransaction:async(e,t)=>{f={...f,chainState:{status:`submitting`,transactions:{...f.chainState?.transactions??{},[e]:t}}},await Qu(p,f)}})}finally{m.stop()}f={...f,chainReceipt:h,chainState:{status:`accepted`,transactions:{...f.chainState?.transactions??{},...td(h)}}},await Qu(p,f);let g=await Of({deviceAddress:h.address,signer:s.account,apiUrl:t.apiUrl,profile:t.profile}),_=await Su({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:td(h),...r.provenance&&o?{source:{...o,...u?{pullRequest:u}:{}}}:{},clientSubmissionId:a.clientSubmissionId,...g,...t.model?{model:t.model}:{},...t.note?{note:t.note}:{}}});t.json?j({..._,transactions:td(h),candidateId:h.candidateId}):(M(`Submission accepted on Tempo`),F({Competition:r.slug,Candidate:h.candidateId,"Device address":h.address,"Report transaction":h.report,"Evaluation transaction":h.evaluation,"Submission ID":typeof _.id==`string`?_.id:_.submission?.id}))}catch(e){R(e)}}function Af(){let e=new b(`solve`).description(`Participate in Tangle Solve competitions`);e.command(`clone <competition>`).description(`Clone the pinned competition repository`).argument(`[directory]`,`Destination directory`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).action(id),e.command(`run [competition]`).description(`Run the competition checker and record its evidence`).option(`--directory <path>`,`Competition directory (defaults to the current directory)`).action(Ef),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(kf),e.command(`account`).description(`Show the local Solve signing account`).option(`--create`,`Create the account if it does not exist`).action(ou);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=>Yd(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)=>Xd(e,t)),e}function jf(e,t){return`tangle ssh-proxy ${e.replace(/\/+$/,``)}/v1/sidecar-proxy/${t}/ssh`}function Mf(e){return/^[A-Za-z0-9_/:=@%+.,-]+$/.test(e)?e:`'${e.replace(/'/g,`'"'"'`)}'`}function Nf(e){return`'${e.replace(/'/g,`''`)}'`}function Pf(e){return e===`win32`?`NUL`:`/dev/null`}function Ff(e,t){return t===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN=${Nf(`<token>`)}; ssh ${e.map(Nf).join(` `)}`:`TANGLE_SSH_PROXY_AUTH_TOKEN=${Mf(`<token>`)} ssh ${e.map(Mf).join(` `)}`}function If(e){return e.connection!==void 0&&!e.connection.ssh}function Lf(){Mt(`SSH is not enabled for this sandbox.`),N(`Create a sandbox with --ssh to enable SSH access.`),process.exit(1)}function Rf(e,t=[],n=process.platform){let r=Pf(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 zf(){return new b(`ssh`).description(`Open SSH session to a sandbox`).argument(`<ref>`,`Sandbox ID or name`).argument(`[sshArgs...]`,`Extra args passed through to ssh`).option(`-i, --identity-file <path>`,`Private key file to pass to ssh`).option(`--print`,`Print SSH command instead of connecting`).allowUnknownOption(!0).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Getting SSH credentials...`);a.start();let o=await G(i,r,e);if(If(o)){a.stop(),Lf();return}o=await K(o);let s=await o.ssh();if(a.stop(),!s){Lf();return}let c={...s,proxyCommand:jf(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=Rf(c,[...n.identityFile?[`-i`,n.identityFile,`-o`,`IdentitiesOnly=yes`]:[],...t]);if(n.print){console.log(Ff(l,process.platform));return}N(`Connecting via tunnel...`);let u=De(`ssh`,l,{stdio:`inherit`,env:{...process.env,TANGLE_SSH_PROXY_AUTH_TOKEN:r.apiKey}});u.on(`error`,e=>{e.code===`ENOENT`&&(Mt(`SSH client not found. Please install OpenSSH.`),process.exit(1)),R(e)}),u.on(`exit`,e=>{process.exit(e??0)})})}function Bf(){let e=new b(`ssh-keys`).description(`Manage SSH keys`);return e.command(`list`).description(`List SSH keys`).action(async e=>{let t=P(`Fetching SSH keys...`);try{t.start();let n=await H(V(e)).sshKeys.list();t.stop(),e.json?j({sshKeys:n}):n.length===0?N(`No SSH keys found.`):Rt([`Name`,`Type`,`Fingerprint`,`Created`],n.map(e=>[e.name,e.keyType,e.fingerprint,e.createdAt.toLocaleString()]))}catch(e){t.stop(),R(e)}}),e.command(`add`).description(`Add SSH key`).argument(`<name>`,`SSH key name`).requiredOption(`--key-file <path>`,`Public key file path`).action(async(e,t)=>{let n=P(`Adding SSH key...`);try{let r=T(t.keyFile,`utf8`).trim();n.start();let i=await H(V(t)).sshKeys.create(e,r);n.stop(),t.json?j({sshKey:i}):M(`Added SSH key ${i.name} (${i.fingerprint})`)}catch(e){n.stop(),R(e)}}),e.command(`delete`).description(`Delete SSH key`).argument(`<name>`,`SSH key name or ID`).action(async(e,t)=>{let n=P(`Deleting SSH key...`);try{n.start(),await H(V(t)).sshKeys.delete(e),n.stop(),M(`Deleted SSH key ${e}`)}catch(e){n.stop(),R(e)}}),e}function Vf(e,t=1){process.stderr.write(`${e}\n`),process.exit(t)}function Hf(){return new b(`ssh-proxy`).description(`SSH proxy helper that pipes stdin/stdout to WebSocket`).argument(`<runtime-url>`,`Runtime WebSocket URL`).action(async e=>{let t=process.env.TANGLE_SSH_PROXY_AUTH_TOKEN;t||Vf(`TANGLE_SSH_PROXY_AUTH_TOKEN not set`);let n=new Ct(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===Ct.OPEN&&n.ping()},15e3),r.unref?.(),process.stdin.on(`data`,e=>{n.readyState===Ct.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(),Vf(`WebSocket error: ${e.message}`)}),n.on(`close`,e=>{i(),process.exit(e===1e3?0:1)}),process.stdin.on(`error`,()=>n.close())})}function Uf(){let e=new b(`team`).description(`Manage teams`);return $(e,`list`).description(`List teams for the current account`).action(async e=>{let t=V(e),n=H(t),r=e.json?null:P(`Fetching teams...`);r?.start();let i=await n.teams.list();if(r?.stop(),e.json){j({teams:i,activeTeamId:t.activeTeamId??null});return}A(i.map(e=>({active:e.id===t.activeTeamId,id:e.id,name:e.name,role:e.currentUserRole,members:e.memberCount})),[{key:`active`,header:`Active`,width:8},{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:24},{key:`role`,header:`Role`,width:10},{key:`members`,header:`Members`,width:10}])}),$(e,`create <name>`).description(`Create a team`).option(`--org-id <id>`,`External organization id`).option(`--no-switch`,`Do not set the new team as active`).action(async(e,t)=>{let n=V(t),r=H(n),i=t.json?null:P(`Creating team...`);i?.start();let a=await r.teams.create({name:e,orgId:t.orgId});if(t.switch&&zl(a,n.profile),i?.stop(),t.json){j({team:a,active:!!t.switch});return}M(`Team created: ${Ll(a)}`),t.switch&&M(`Active team set to ${a.name}`)}),$(e,`switch <team>`).description(`Set the active team for the current profile`).action(async(e,t)=>{let n=V(t),r=await Rl(H(n),e);if(zl(r,n.profile),t.json){j({team:r,activeTeamId:r.id});return}M(`Active team set to ${Ll(r)}`)}),e.command(`current`).description(`Show the active team for the current profile`).option(`--profile <profile>`,`Credential profile`).action(e=>{let t=fr(e.profile);if(e.json){j(t.activeTeamId?t:{activeTeamId:null});return}if(!t.activeTeamId){console.log(`No active team.`);return}F({ID:t.activeTeamId,Name:t.activeTeamName})}),e.command(`clear`).description(`Clear the active team for the current profile`).option(`--profile <profile>`,`Credential profile`).action(e=>{if(Bl(e.profile),e.json){j({activeTeamId:null});return}M(`Active team cleared.`)}),$(e,`members [team]`).description(`List team members`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile),a=await r.teams.listMembers(i.id);if(t.json){j({team:i,members:a});return}A(a,[{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=V(t),r=H(n),i=await X(r,t.team,n.profile),a=Wf(t.role),o=await r.teams.updateMember(i.id,e,{role:a});if(t.json){j({team:i,member:o});return}M(`Member updated: ${o.customerEmail}`),F({Team:i.name,Role:o.role,Status:o.status})}),$(e,`invite <email>`).description(`Invite a user to a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--role <role>`,`Role: admin, member, viewer`,`member`).option(`--ttl-hours <hours>`,`Invitation lifetime in hours`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile),a=Wf(t.role),o=await r.teams.invite(i.id,{email:e,role:a,ttlHours:t.ttlHours?Number.parseInt(t.ttlHours,10):void 0});if(t.json){j({team:i,invitation:o});return}M(`Invitation created for ${o.email}`),F({Team:i.name,Role:o.role,Expires:o.expiresAt,"Invitation ID":o.id}),M(`Re-run with --json to retrieve the invitation token for sharing.`)}),$(e,`leave [team]`).description(`Leave a team as the current user`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile);if(!(!t.force&&!t.json&&!await ei(`Leave team '${i.name}'? (y/N) `,`--force`))){if(await r.teams.leave(i.id),n.activeTeamId===i.id&&Bl(n.profile),t.json){j({success:!0,teamId:i.id});return}M(`Left team: ${i.name}`)}}),$(e,`transfer <new-owner-customer-id> [team]`).description(`Transfer team ownership to another active member`).option(`--force`,`Skip confirmation prompt`).action(async(e,t,n)=>{let r=V(n),i=H(r),a=await X(i,t,r.profile);if(!(!n.force&&!n.json&&!await 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){j({success:!0,teamId:a.id,newOwnerCustomerId:e});return}M(`Ownership transferred for ${a.name}`)}}),e.addCommand(Gf()),e.addCommand(Kf()),$(e,`invitations [team]`).description(`List pending and historical team invitations`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile),a=await r.teams.listInvitations(i.id);if(t.json){j({team:i,invitations:a});return}A(a,[{key:`id`,header:`ID`,width:38},{key:`email`,header:`Email`,width:28},{key:`role`,header:`Role`,width:10},{key:`status`,header:`Status`,width:12},{key:`expiresAt`,header:`Expires`,width:16}])}),$(e,`accept <token>`).description(`Accept a team invitation`).option(`--no-switch`,`Do not set the accepted team as active`).action(async(e,t)=>{let n=V(t),r=H(n),i=await r.teams.acceptInvitation(e),a=t.switch===!1?null:await r.teams.get(i.teamId);if(a&&zl(a,n.profile),t.json){j({member:i,activeTeamId:a?.id??null});return}M(`Invitation accepted for team ${i.teamId}`),a&&M(`Active team set to ${a.name}`)}),$(e,`revoke-invitation <invitation-id>`).description(`Revoke a pending team invitation`).action(async(e,t)=>{if(await H(V(t)).teams.revokeInvitation(e),t.json){j({success:!0,invitationId:e});return}M(`Invitation revoked: ${e}`)}),$(e,`remove-member <member-id>`).description(`Remove a member from a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile);if(await r.teams.removeMember(i.id,e),t.json){j({success:!0,teamId:i.id,memberId:e});return}M(`Member removed: ${e}`)}),e}function Wf(e){if(e===`admin`||e===`member`||e===`viewer`)return e;throw Error(`Role must be one of: admin, member, viewer`)}function Gf(){let e=new b(`secret`).description(`Manage team secrets`);return $(e,`list [team]`).description(`List team secret names`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile),a=await r.teams.listSecrets(i.id);if(t.json){j({team:i,secrets:a});return}A(a,[{key:`name`,header:`Name`,width:28},{key:`updatedAt`,header:`Updated`,width:24},{key:`updatedBy`,header:`Updated By`,width:28}])}),$(e,`set <name> [value]`).description(`Create or replace a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--value-stdin`,`Read secret value from stdin`).action(async(e,t,n)=>{let r=V(n),i=H(r),a=await X(i,n.team,r.profile),o=await Xl({value:t,valueStdin:n.valueStdin,prompt:`Enter value for team secret '${e}': `}),s=await i.teams.upsertSecret(a.id,e,o);if(n.json){j({team:a,secret:s});return}M(`Team secret saved: ${s.name}`)}),$(e,`delete <name>`).description(`Delete a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile);if(!(!t.force&&!t.json&&!await ei(`Delete team secret '${e}' from '${i.name}'? (y/N) `,`--force`))){if(await r.teams.deleteSecret(i.id,e),t.json){j({success:!0,teamId:i.id,name:e});return}M(`Team secret deleted: ${e}`)}}),$(e,`reveal <name>`).description(`Reveal a team secret value`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile),a=await r.teams.revealSecret(i.id,e);if(t.json){j({teamId:i.id,...a});return}console.log(a.value)}),e}function Kf(){let e=new b(`templates`).description(`Manage team golden-path templates`);return $(e,`list [team]`).description(`List a team's golden-path templates`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile),a=await r.teams.listTemplates(i.id);if(t.json){j({team:i,templates:a});return}if(a.length===0){console.log(`No templates yet for ${i.name}.`);return}A(a.map(e=>({id:e.id,name:e.name,environment:e.environment,snapshot:`${e.snapshotId.slice(0,12)}…`,updated:e.updatedAt})),[{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:28},{key:`environment`,header:`Env`,width:14},{key:`snapshot`,header:`Snapshot`,width:16},{key:`updated`,header:`Updated`,width:24}])}),$(e,`create <name> <snapshot-id>`).description(`Create a golden-path template from a snapshot`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`-d, --description <description>`,`Human-readable description shown in the dashboard`).option(`-e, --environment <environment>`,`Default environment to apply (defaults to 'universal')`).option(`--config <json>`,`Optional JSON config object merged into sandboxes created from this template`).action(async(e,t,n)=>{let r=V(n),i=H(r),a=await X(i,n.team,r.profile),o;if(n.config)try{let e=JSON.parse(n.config);if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`--config must be a JSON object`);o=e}catch(e){throw Error(`--config is not valid JSON: ${e instanceof Error?e.message:String(e)}`)}let s=await i.teams.createTemplate(a.id,{name:e,snapshotId:t,description:n.description,environment:n.environment,config:o});if(n.json){j({team:a,template:s});return}M(`Team template created: ${s.name} (${s.id})`)}),$(e,`delete <template-id>`).description(`Delete a team golden-path template`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile);if(!(!t.force&&!t.json&&!await ei(`Delete template '${e}' from '${i.name}'? (y/N) `,`--force`))){if(await r.teams.deleteTemplate(i.id,e),t.json){j({success:!0,teamId:i.id,templateId:e});return}M(`Team template deleted: ${e}`)}}),e}function $(e,t){return e.command(t).option(`--profile <profile>`,`Credential profile`)}async function qf(e,t,n){let r=new AbortController,i=()=>r.abort();try{let n=H(V({...e,timeout:void 0}));process.once(`SIGINT`,i),process.once(`SIGTERM`,i);let a=await t(n,{...e.timeout===void 0?{}:{timeoutMs:Number(e.timeout)*1e3},resumeJobId:e.resumeJob,signal:r.signal,onProgress:e=>{process.stderr.write(`Publication ${e.id}: ${e.status}\n`)}}).finally(()=>{process.off(`SIGINT`,i),process.off(`SIGTERM`,i)});e.json?j(a):M(`template`in a?`Published template: ${a.template.slug}`:`Published template version: ${a.version.id}`)}catch(t){if(t instanceof s&&t.status!==401&&t.job&&[`pending`,`scanning`,`ready`].includes(t.job.status)){let e=[`tangle`,`template`,...n,`--resume-job`,t.job.id].map(Ke).join(` `);Object.assign(t,{fix:{command:e}})}R(t,e.json)}}function Jf(){let e=new b(`template`).description(`Manage published public templates`);return e.command(`list`).option(`-q, --query <query>`,`Search query`).option(`--tag <tag>`,`Filter by tag`).option(`--featured`,`Show featured templates only`).action(async e=>{let t=H(V(e)),n=e.featured?await t.publicTemplates.featured():await t.publicTemplates.list({query:e.query,tag:e.tag});if(e.json){j({templates:n});return}A(n,[{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 H(V(t)).publicTemplates.get(e);if(t.json){j({template:n});return}j(n)}),e.command(`versions <id-or-slug>`).action(async(e,t)=>{let n=await H(V(t)).publicTemplates.versions(e);if(t.json){j({versions:n});return}A(n.map(e=>({...e})),[{key:`id`,header:`Version ID`,width:38},{key:`versionNumber`,header:`Version`,width:8},{key:`snapshotId`,header:`Snapshot`,width:20},{key:`createdAt`,header:`Created`,width:24}])}),e.command(`publish <name> <snapshot-id> <sandbox-id>`).option(`--timeout <seconds>`,`Maximum wait for publication`).option(`--resume-job <id>`,`Resume an accepted publication for this snapshot`).option(`--slug <slug>`,`Stable public slug`).option(`-d, --description <description>`,`Template description`).option(`--readme <markdown>`,`README markdown`).option(`--tags <tags...>`,`Template tags`).option(`--release-notes <text>`,`Release notes`).option(`--team-id <id>`,`Publish under a team`).option(`--forked-from <id>`,`Fork source template id`).action((e,t,n,r)=>qf(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)=>qf(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 Yf(){let e=new b(`traces`).description(`Read hosted agent traces, spans, and eval-runs from Tangle Intelligence`);return e.command(`list`).description(`List trace summaries (one row per trace), newest first`).option(`--from <iso>`,`ISO-8601 lower bound on received time (inclusive)`).option(`--to <iso>`,`ISO-8601 upper bound on received time (inclusive)`).option(`--model <model>`,`Exact model match (any span carried this model)`).option(`--run <runId>`,`Exact run id match`).option(`--status <status>`,`ERROR | OK`).option(`-q, --query <text>`,`Substring over span name`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Page size (clamped server-side to [1, 200])`).action(async e=>{try{let t={from:e.from,to:e.to,model:e.model,runId:e.run,status:e.status===void 0?void 0:op(e.status),q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:dp(e.limit)},n=Zf(e),r=e.json?null:P(`Fetching traces...`);r?.start();let i=await n.listTraces(t);if(r?.stop(),e.json)return j(i);ep(i.items),ip(i.nextCursor)}catch(t){$f(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=Zf(t);if(t.ndjson){await Qf(n,e);return}let r=t.json?null:P(`Fetching trace spans...`);r?.start();let i=await n.getTraceSpans(e,{cursor:t.cursor,limit:t.limit===void 0?void 0:dp(t.limit)});if(r?.stop(),t.json)return j(i);tp(i.items),i.truncated&&F({Spans:`${i.items.length} of ${i.total} (truncated)`}),ip(i.nextCursor)}catch(e){$f(e,t)}}),e.addCommand(Xf()),e}function Xf(){let e=new b(`runs`).description(`Read eval-runs pivoted off the trace surface`);return e.command(`list`).description(`List eval-runs, newest first`).option(`--status <status>`,`Run status filter`).option(`--gate <decision>`,`Promotion-gate decision filter`).option(`--label <key:value>`,`Match over the run's labels`).option(`--from <iso>`,`ISO-8601 lower bound on received time`).option(`--to <iso>`,`ISO-8601 upper bound on received time`).option(`-q, --query <text>`,`Substring over run dir`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Page size`).action(async e=>{try{let t={status:e.status===void 0?void 0:cp(e.status),gate:e.gate===void 0?void 0:up(e.gate),label:e.label,from:e.from,to:e.to,q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:dp(e.limit)},n=Zf(e),r=e.json?null:P(`Fetching runs...`);r?.start();let i=await n.listRuns(t);if(r?.stop(),e.json)return j(i);np(i.items),ip(i.nextCursor)}catch(t){$f(t,e)}}),e.command(`get <runId>`).description(`Show a single eval-run`).action(async(e,t)=>{try{let n=Zf(t),r=t.json?null:P(`Fetching run...`);r?.start();let i=await n.getRun(e);if(r?.stop(),t.json)return j(i);rp(i)}catch(e){$f(e,t)}}),e}function Zf(e){let t=tr(e.apiKey);if(!t)throw Error(`No API key found. Set TANGLE_API_KEY or run: tangle auth login`);return wt({apiKey:t,baseUrl:e.baseUrl??process.env.TANGLE_INTELLIGENCE_BASE_URL})}async function Qf(e,t){let n=(await e.exportTraceSpansNdjson(t)).getReader();try{for(;;){let{value:e,done:t}=await n.read();if(t)break;e&&process.stdout.write(Buffer.from(e))}}finally{n.releaseLock()}}function $f(e,t){return R(e,t.json===!0)}function ep(e){A(e.map(e=>({traceId:e.traceId,root:e.rootName??`-`,model:e.model??`-`,spans:e.spanCount,errors:e.errorCount,durationMs:e.durationMs,cost:ap(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 tp(e){A(e.map(e=>({spanId:e.id,name:e.name,model:e.model??`-`,status:e.statusCode??`-`,cost:e.costUsd===null?`-`:`$${e.costUsd}`})),[{key:`spanId`,header:`Span`,width:40},{key:`name`,header:`Name`,width:28},{key:`model`,header:`Model`,width:22},{key:`status`,header:`Status`,width:10},{key:`cost`,header:`Cost`,width:12}])}function np(e){A(e.map(e=>({runId:e.id,status:e.status,gate:e.gateDecision??`-`,cost:e.totalCostUsd===null?`-`:`$${e.totalCostUsd}`,receivedAt:e.receivedAt})),[{key:`runId`,header:`Run`,width:24},{key:`status`,header:`Status`,width:22},{key:`gate`,header:`Gate`,width:18},{key:`cost`,header:`Cost`,width:12},{key:`receivedAt`,header:`Received`,width:18}])}function rp(e){F({Run:e.id,Status:e.status,Gate:e.gateDecision??void 0,"Run Dir":e.runDir??void 0,Cost:e.totalCostUsd===null?void 0:`$${e.totalCostUsd}`,Duration:e.totalDurationMs===null?void 0:`${e.totalDurationMs}ms`,"Holdout Lift":e.holdoutLift??void 0,Received:e.receivedAt})}function ip(e){e&&F({"Next page":`--cursor ${e}`})}function ap(e){return e===null?`-`:`$${e.toFixed(4)}`}function op(e){if(e===`ERROR`||e===`OK`)return e;throw Error(`--status must be ERROR or OK`)}const sp=[`started`,`baseline-complete`,`generation-complete`,`gate-decided`,`finished`,`errored`];function cp(e){let t=sp.find(t=>t===e);if(t)return t;throw Error(`--status must be one of ${sp.join(`, `)}`)}const lp=[`ship`,`hold`,`need_more_work`,`model_ceiling`,`arch_ceiling`];function up(e){let t=lp.find(t=>t===e);if(t)return t;throw Error(`--gate must be one of ${lp.join(`, `)}`)}function dp(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function fp(){return new b(`usage`).description(`Show account usage and billing information`).action(async e=>{let{client:t}=U(e),n=e.json?null:P(`Fetching usage...`);n?.start();let[r,i]=await Promise.all([t.usage(),t.subscription().catch(()=>null)]);n?.stop(),e.json?j({...r,subscription:i}):(console.log(),console.log(`Account Usage`),console.log(`─`.repeat(40)),F({"Active Sandboxes":r.activeSandboxes,"Total Sandboxes":r.totalSandboxes,"Compute Minutes":pp(r.computeMinutes),"GPU Seconds":r.gpuSeconds,"GPU Spend":mp(r.gpuCostUsd)}),i&&(console.log(),console.log(`Subscription`),console.log(`─`.repeat(40)),F({Plan:i.plan,Status:i.status,"Credits Available":mp(i.creditsAvailableUsd),"Credits Used":mp(i.creditsUsedUsd),"Monthly Balance":mp(i.monthlyBalanceUsd)})),console.log(),console.log(`Billing Period`),console.log(`─`.repeat(40)),F({Start:r.periodStart.toLocaleDateString(),End:r.periodEnd.toLocaleDateString()}),console.log())})}function pp(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 mp(e){return e<0?`-$${(-e).toFixed(2)}`:`$${e.toFixed(2)}`}function hp(){return new b(`use`).description(`Set or show the active sandbox (used when a command omits the id)`).argument(`[id]`,`Sandbox id to make active`).option(`--clear`,`Clear the active sandbox`).action((e,t)=>{if(t.clear){qn(),N(`Cleared the active sandbox.`);return}if(e){Kn(e),N(`Active sandbox set to ${e}. Commands now default to it; override with --box or TANGLE_SANDBOX.`);return}let n=Gn();N(n?`Active sandbox: ${n}`:"No active sandbox. Set one with `tangle use <id>`.")})}function gp(e){A(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 _p(e){e.command(`artifacts`).description(`List a run's artifact metadata (never the bytes)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.listArtifacts(e,t);if(n.json)return j(r);gp(r.artifacts)}),e.command(`artifact-download`).description(`Download one run artifact's bytes to a file`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).argument(`<artifactId>`,`Artifact ID`).option(`--out <file>`,`Destination file (defaults to the artifact ID)`).action(async(e,t,n,r)=>{let i=await(await Y(r)).workflows.downloadArtifact(e,t,n),a=r.out??n;try{me(a,i.bytes)}catch(e){throw Error(`Could not write artifact to "${a}": ${e instanceof Error?e.message:String(e)}`)}if(r.json)return j({file:a,contentType:i.contentType,bytes:i.bytes.length});N(`Wrote ${a} (${i.bytes.length} bytes, ${i.contentType}).`)})}function vp(e){A(e.map(e=>({id:e.id,run:e.runId,title:e.title,options:e.options.join(`, `),requested:e.requestedAt,expires:e.expiresAt??``})),[{key:`id`,header:`ID`},{key:`run`,header:`Run`},{key:`title`,header:`Title`},{key:`options`,header:`Options`},{key:`requested`,header:`Requested`},{key:`expires`,header:`Expires`}])}function yp(e){e.command(`decisions`).description(`List a workflow's pending human decisions`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=(await(await Y(t)).workflows.listPendingDecisions()).decisions.filter(t=>t.workflowId===e);if(t.json)return j({decisions:n});vp(n)}),e.command(`decision-resolve`).description(`Answer the decision a run is parked on and resume it`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).requiredOption(`--choice <choice>`,`The option to resolve with (one of the decision's options)`).action(async(e,t,n)=>{let r=await Y(n),i=await r.workflows.getRunDecision(e,t),a=await r.workflows.resolveRunDecision(e,t,{decisionId:i.id,choice:n.choice});if(n.json)return j(a);if(a.resumed){N(`Resolved decision ${a.decisionId} with "${a.choice}" — run ${a.runId} resumed.`);return}N(`Resolved decision ${a.decisionId} with "${a.choice}", but run ${a.runId} had already finished — nothing to resume.`)})}function bp(e){try{return T(e,`utf8`)}catch(t){throw Error(`Could not read workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function xp(e){A(e.map(e=>({id:e.id,name:e.name,enabled:e.enabled?`yes`:`no`,issues:e.validationErrors.length,updated:e.updatedAt})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`enabled`,header:`Enabled`},{key:`issues`,header:`Issues`},{key:`updated`,header:`Updated`}])}function Sp(e){let t=e.workflows.filter(e=>e.failed>0).length,n=e.workflows.filter(e=>e.failed===0&&e.waiting>0).length,r=e.workflows.filter(e=>e.failed===0&&e.waiting===0&&e.runsInWindow>0).length;N(`${t} failing · ${n} waiting · ${r} healthy · ${e.workflows.length} total over ${e.window}`),A(e.workflows.map(e=>({id:e.id,name:e.name,enabled:e.enabled?`yes`:`no`,runs:e.runsInWindow,failed:e.failed,waiting:e.waiting,success:e.successRate===null?`—`:`${Math.round(e.successRate*100)}%`,lastRun:e.lastRunStatus??`—`,lastRunAt:e.lastRunAt??`—`})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`enabled`,header:`Enabled`},{key:`runs`,header:`Runs`},{key:`failed`,header:`Failed`},{key:`waiting`,header:`Waiting`},{key:`success`,header:`Success`},{key:`lastRun`,header:`Last Run`},{key:`lastRunAt`,header:`Last Run At`}])}function Cp(e){if(F({ID:e.id,Name:e.name,Description:e.description??``,Enabled:e.enabled?`yes`:`no`,Actions:e.actions.length}),e.triggers&&e.triggers.length>0&&(N(`Triggers`),wp(e.triggers)),e.validationErrors.length>0){N(`Validation issues`);for(let t of e.validationErrors)console.log(` ${t.path}: ${t.message}`)}}function wp(e){A(e.map(e=>({id:e.id,kind:e.kind,enabled:e.enabled?`yes`:`no`,detail:e.kind===`schedule`?`${e.cron??``} (${e.timezone??``})`:`${e.provider??``}:${e.eventFilter?.event??``}${e.eventFilter?.action?`.${e.eventFilter.action}`:``}`})),[{key:`id`,header:`ID`},{key:`kind`,header:`Kind`},{key:`enabled`,header:`Enabled`},{key:`detail`,header:`Detail`}])}function Tp(e){e.command(`list`).description(`List your workflows`).action(async e=>{let t=await(await Y(e)).workflows.list();if(e.json)return j(t);xp(t)}),e.command(`fleet`).description(`Fleet overview: every workflow's run tallies over a trailing window, failing-first`).option(`--window <window>`,`Trailing window: 24h, 7d, or 30d`,`7d`).action(async e=>{let t=await(await Y(e)).workflows.fleetInsights({window:e.window});if(e.json)return j(t);Sp(t)}),e.command(`get`).description(`Show a workflow's definition and compiled triggers`).argument(`<id>`,`Workflow ID`).option(`--yaml`,`Print only the raw definition YAML (the export path — pipe to a file)`).action(async(e,t)=>{let n=await(await Y(t)).workflows.get(e);if(t.yaml){if(n.definitionYaml===null)throw Error(`Workflow ${n.id} has no stored definition YAML to export`);process.stdout.write(n.definitionYaml.endsWith(`
149
- `)?n.definitionYaml:`${n.definitionYaml}\n`);return}if(t.json)return j(n);Cp(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=bp(e),r=await(await Y(t)).workflows.create(n);if(t.json)return j(r);N(`Created workflow ${r.id} (${r.name}).`),Cp(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=bp(e),r=await Y(t),i=await r.workflows.validate(n,{structural:!0});if(!i.valid){if(process.exitCode=1,t.json)return j(i);N(`Invalid workflow:`);for(let e of i.errors)console.log(` ${e.path}: ${e.message}`);return}let a=(await r.workflows.list()).find(e=>e.name===i.name);if(a){let e=await r.workflows.update(a.id,n);if(t.json)return j({action:`updated`,workflow:e});N(`Updated workflow ${e.id} (${e.name}) — matched by name.`),Cp(e);return}let o=await r.workflows.create(n);if(t.json)return j({action:`created`,workflow:o});N(`Created workflow ${o.id} (${o.name}).`),Cp(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=bp(t),i=await(await Y(n)).workflows.update(e,r,{...n.note===void 0?{}:{note:n.note}});if(n.json)return j(i);N(`Updated workflow ${i.id} (${i.name}).`),Cp(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`)){N(`Delete cancelled.`);return}if(await(await Y(t)).workflows.delete(e),t.json)return j({deleted:!0,id:e});N(`Deleted workflow ${e}.`)}),e.command(`validate`).description(`Validate a workflow YAML file without saving it`).argument(`<file>`,`Path to the workflow YAML`).option(`--structural`,`CI mode: compile + capability checks only, no connection resolution — the verdict is the same regardless of connected providers`).action(async(e,t)=>{let n=bp(e),r=await(await Y(t)).workflows.validate(n,{...t.structural?{structural:!0}:{}});if(t.json)return j(r);if(r.valid)N(`Valid: ${r.name} (${r.actionCount} action(s), ${r.triggerCount} trigger(s)).`);else{N(`Invalid workflow:`);for(let e of r.errors)console.log(` ${e.path}: ${e.message}`);process.exitCode=1}}),e.command(`schema`).description(`Print the JSON Schema for the workflow YAML`).action(async e=>{j(await(await Y(e)).workflows.schema())})}async function Ep(e,t,n){let r=await(await Y(n)).workflows.setEnabled(e,t);if(n.json)return j(r);N(`${t?`Enabled`:`Disabled`} workflow ${r.id}.`),Cp(r)}function Dp(e,t){try{return JSON.parse(e)}catch{throw Error(`Invalid ${t}: not valid JSON`)}}function Op(e,t){try{me(e,t,`utf8`)}catch(t){throw Error(`Could not write workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function kp(e){A(e.map(e=>({id:e.id,name:e.name,category:e.category,providers:e.providers.join(`, `),summary:e.summary})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`category`,header:`Category`},{key:`providers`,header:`Providers`},{key:`summary`,header:`Summary`}])}function Ap(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 jp(e){e.command(`enable`).description(`Enable a workflow so its triggers and manual runs fire`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{await Ep(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 Ep(e,!1,t)}),e.command(`templates`).description(`List the curated starter workflow templates`).action(async e=>{let t=await(await Y(e)).workflows.listTemplates();if(e.json)return j(t);kp(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.`,mc,[]).option(`--file <out>`,`Write the instantiated workflow YAML to this file instead of stdout`).action(async(e,t)=>{let n=hc(t.param,`param`)??{},r=await(await Y(t)).workflows.instantiateTemplate(e,n);if(t.json)return j(r);if(!r.created){N(`Template ${e} needs provider connections before it can run:`);for(let e of r.connectionRequirements)console.log(` ${e.connected?`✓`:`✗`} ${Ap(e,r.connectionRequirements)}`);process.exitCode=1;return}let{workflow:i}=r;if(i.definitionYaml===null)throw Error(`Workflow ${i.id} was created but the server returned no definition YAML`);if(N(`Created workflow ${i.id} (${i.name}).`),t.file){Op(t.file,i.definitionYaml),N(`Wrote ${t.file}.`);return}process.stdout.write(i.definitionYaml.endsWith(`
150
- `)?i.definitionYaml:`${i.definitionYaml}\n`)})}function Mp(e){A(e,[{key:`key`,header:`Key`},{key:`version`,header:`Version`},{key:`updatedAt`,header:`Updated`}])}function Np(e){F({Key:e.key,Version:e.version,Updated:e.updatedAt}),N(`Value`),j(e.value)}function Pp(e){let t=e.command(`kv`).description(`Read and write a workflow's cross-run KV state`);t.command(`list`).description(`List every KV entry of a workflow`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=await(await Y(t)).workflows.listKv(e);if(t.json)return j(n);Mp(n.entries)}),t.command(`get`).description(`Show one KV entry (value and version)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.getKv(e,t);if(n.json)return j(r);Np(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=Dp(n,`<json>`),a=r.cas===void 0?void 0:ro(r.cas,`--cas`),o=await Y(r),s=a===void 0?await o.workflows.putKv(e,t,i):await o.workflows.casKv(e,t,a,i);if(r.json)return j(s);Np(s)}),t.command(`delete`).description(`Delete a KV entry (idempotent)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.deleteKv(e,t);if(n.json)return j(r);N(r.deleted?`Deleted KV entry "${t}" of workflow ${e}.`:`No KV entry "${t}" on workflow ${e}.`)})}function Fp(e){A(e.map(e=>({rev:e.rev,created:e.createdAt,by:e.createdBy,source:e.source,note:e.note??``})),[{key:`rev`,header:`Rev`},{key:`created`,header:`Created`},{key:`by`,header:`Created By`},{key:`source`,header:`Source`},{key:`note`,header:`Note`}])}function Ip(e){e.command(`revisions`).description(`List a workflow's definition revision history (newest first)`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=await(await Y(t)).workflows.listRevisions(e);if(t.json)return j(n);Fp(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 Y(n)).workflows.getRevision(e,r);if(n.json)return j(i);F({Revision:i.rev,Created:i.createdAt,"Created by":i.createdBy,Source:i.source,Note:i.note??``}),process.stdout.write(i.yaml.endsWith(`
151
- `)?i.yaml:`${i.yaml}\n`)}),e.command(`rollback`).description(`Restore a prior revision's definition as a NEW head revision (re-validated)`).argument(`<id>`,`Workflow ID`).argument(`<rev>`,`Revision number to restore`).action(async(e,t,n)=>{let r=ro(t,`<rev>`),i=await(await Y(n)).workflows.rollback(e,r);if(n.json)return j(i);N(`Rolled back workflow ${i.id} to rev ${r}.`),Cp(i)})}function Lp(){let e=new b(`workflows`).description(`Create and manage Tangle workflows`);return Tp(e),bc(e),jp(e),Ip(e),Pp(e),_p(e),yp(e),e}function Rp(e){for(let[t,n]of Object.entries(e.optsWithGlobals()))e.getOptionValue(t)===void 0&&n!==void 0&&e.setOptionValue(t,n)}const zp=e(import.meta.url)(`../package.json`);function Bp(){let e=new b;e.name(`tangle`).description(`CLI for Tangle Sandbox operations`).version(zp.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)=>{Rp(t);let n=t.opts();Et(n.json===!0||n.ndjson===!0)}),e.addCommand(Ii()),e.addCommand(ql()),e.addCommand(hp()),e.addCommand(Yl()),e.addCommand(Zc()),e.addCommand(sl()),e.addCommand(cl()),e.addCommand(Go()),e.addCommand(zf()),e.addCommand(Bf()),e.addCommand(Hf()),e.addCommand(gi()),e.addCommand(Ql()),e.addCommand(gs()),e.addCommand(fp()),e.addCommand(Uf()),e.addCommand(Jf()),e.addCommand(Gi()),e.addCommand(na()),e.addCommand(hl()),e.addCommand(_s()),e.addCommand(bs()),e.addCommand(jc()),e.addCommand(Is()),e.addCommand(Lp()),e.addCommand(Wo()),e.addCommand(Jl()),e.addCommand(Af()),e.addCommand(Zl()),e.addCommand(ra()),e.addCommand(pl()),e.addCommand(Mc()),e.addCommand(Lo()),e.addCommand(Ro()),e.addCommand(xl()),e.addCommand(ll()),e.addCommand(Yf()),e.addCommand(fc());function t(e){e.configureHelp({showGlobalOptions:!0}),e.configureOutput({writeErr:()=>{}}),e.exitOverride(t=>{t.exitCode===0&&process.exit(0),R(t,e.optsWithGlobals().json===!0)});for(let n of e.commands)t(n)}return t(e),e}const Vp=Bp();Vp.parseAsync(process.argv).catch(e=>{R(e,Vp.opts().json===!0)});export{};
148
+ `)};e||(process.once(`SIGINT`,a),process.once(`SIGTERM`,a));try{return i.throwIfAborted(),await t(i)}catch(e){if(!i.aborted||e instanceof I&&e.code===`RUN_STOPPED`)throw e;let t=new I(`RUN_STOPPED`,`Command interrupted`,`A stop request ended this execution`,n);throw e instanceof Error&&`runId`in e&&typeof e.runId==`string`&&Object.assign(t,{runId:e.runId}),t}finally{e||(process.off(`SIGINT`,a),process.off(`SIGTERM`,a))}}const Cs=`claude,codex,kimi,opencode,gemini,pi`;function ws(e,t){let n;return async(r,{node:i,lastCandidate:a})=>{t.throwIfAborted();let o;try{o=r===void 0?void 0:ce(r)}catch(e){throw e instanceof Error&&Object.assign(e,{node:i,seat:r,fixCommand:`tangle graph run --help`}),e}n??=Je({cwd:e,signal:t,config:Ye({...process.env,BRIDGE_BACKENDS:Cs,BRIDGE_SUBSCRIPTIONS_ONLY:`1`})});let s=await n;t.throwIfAborted();let c=e=>e.authentication?.status===`authenticated`&&e.authentication.authMode===`subscription`,l=o?.harness??s.find(e=>e.provider&&c(e))?.backend,u=s.filter(e=>e.backend===l),d=u.filter(c),f=o?u.find(e=>e.id===`${o.harness}/${o.model}`)??d.find(e=>e.provider===o.provider):d.find(e=>e.default)??d.find(e=>e.recommended)??d[0];if(!f||!c(f)){if(a===!1)return;let e=f?.authentication??u[0]?.authentication??(o?void 0:s.find(e=>e.authentication?.fix)?.authentication);throw Object.assign(new I(o?`SEAT_NOT_LOGGED_IN`:`SEAT_NONE_DETECTED`,`Node '${i}' has no available subscription${o?` for ${o.harness}`:``}`,e?`Selected provider: ${e.status} (${e.authMode})`:`No authenticated subscription route was detected`,e?.fix??`tangle graph run --help`),{node:i,seat:r})}let p=o?.harness??ce(f.id).harness,m=o?.provider??f.provider,h=o?.model??f.id.slice(p.length+1);if(!m||!h)throw new I(`MODEL_PROVIDER_MISMATCH`,`Node '${i}' has an unresolved model provider`,`Bridge has no configured provider for ${r??p}`,`tangle graph run --help`);return{harness:p,provider:m,model:h,selector:{kind:`all-eligible`},...o?.reasoningEffort===void 0?{}:{reasoningEffort:o.reasoningEffort}}}}async function Ts(e,t,n){let r=`tangle secret create ${Ke(t)} --from-login claude`,i=(e,t=r)=>new I(`NATIVE_CREDENTIAL_GRANT_FAILED`,`Claude subscription enrollment failed`,e,t),a;try{a=new URL(e.getBaseUrl())}catch{throw i(`The Sandbox API URL is invalid`,`tangle auth login`)}if(a.protocol!==`https:`||a.username||a.password||a.search||a.hash)throw i(`Native credentials require a credential-free HTTPS Sandbox API URL`,`tangle auth login`);if(!Qe.safeParse({account:`cli`,secretEnv:t,format:`token`}).success)throw i(`The secret name is not valid for a native credential reference`,`tangle secret create --help`);return process.stderr.write(`Authorize Claude in its native browser. Store the token as ${t} at ${a.href}. The token stays out of terminal output.\n`),Ss(n,async n=>{let r=await Es(n,i);n.throwIfAborted();let a=await e.secrets.create(t,r).catch(e=>{if(n.aborted)return;let t=e instanceof u?e.status:void 0;throw i(t?`Sandbox secret storage returned HTTP ${t}; enrollment is unconfirmed`:`Sandbox secret storage did not confirm enrollment`,t===401||t===403?`tangle auth login`:`tangle secret list --json`)});if(await Ne(),n.aborted)throw new I(`RUN_STOPPED`,`Native enrollment interrupted`,`Secret upload may already have completed`,`tangle secret list --json`);if(!a||a.name!==t)throw i(`The Sandbox API did not confirm the requested secret name`);return a},r)}async function Es(e,t){let n=new AbortController,r=qe({command:`claude`,args:[`setup-token`],cwd:process.cwd(),signal:AbortSignal.any([e,n.signal]),timeoutMs:12e4,spawnOptions:{stdio:[process.stdin,`pipe`,`pipe`],detached:!1},env:{ANTHROPIC_API_KEY:void 0,ANTHROPIC_AUTH_TOKEN:void 0,CLAUDE_CODE_OAUTH_TOKEN:void 0,ANTHROPIC_BASE_URL:void 0}}),i=``,a=!1,o=new Set,s=e=>{if(!a){if(Buffer.byteLength(i)+e.length>65536){a=!0,i=``,n.abort();return}i+=e.toString(`utf8`);for(let e of i.split(`\x1B]8;;`).slice(1)){let t=Math.min(...[e.indexOf(`\x07`),e.indexOf(`\x1B\\`)].filter(e=>e>=0));if(!Number.isFinite(t))continue;let n=e.slice(0,t);if(!URL.canParse(n))continue;let r=new URL(n);![`https://platform.claude.com/oauth/authorize`,`https://claude.com/cai/oauth/authorize`].includes(`${r.origin}${r.pathname}`)||r.username||r.password||r.hash||/sk-ant-|(?:access_token|refresh_token|id_token|code|key)=/.test(r.href)||![`client_id`,`state`,`redirect_uri`,`code_challenge`].every(e=>r.searchParams.has(e))||o.has(r.href)||(o.add(r.href),process.stderr.write(`Open to authorize Claude:\n${r.href}\n`))}Ze(i).includes(`Paste code here`)&&!o.has(`code`)&&(o.add(`code`),process.stderr.write(`Paste the code shown in your browser into this terminal and press Enter: `))}};r.process.stdout?.on(`data`,s),r.process.stderr?.on(`data`,s);let c=await r.exitPromise;if(e.throwIfAborted(),!c.success||a)throw t(a?`Native consent output exceeded its private capture bound`:c.timedOut?`Native browser consent timed out`:c.spawnError?`The native claude command could not start`:`Native consent exited ${c.code??c.signal??`without a result`}`);let l=[...new Set([...Ze(i).matchAll(/Your OAuth token \(valid for[^\n]*\):\s+([\s\S]*?)\s+Store this token securely/g)].map(e=>e[1].replace(/\s/g,``)))];if(i=``,l.length!==1||!/^sk-ant-oat\d+-[A-Za-z0-9_-]+$/.test(l[0]))throw t(`Native consent returned no unambiguous subscription token`);return l[0]}async function Ds(e,t,n){let r=new Map;for(let e of new Set(t)){if(e!==`claude-code`&&e!==`codex`)throw new I(`NATIVE_CREDENTIAL_UNSUPPORTED`,`Cloud subscription grant for ${e} is unavailable`,`This Sandbox native credential channel supports Claude Code and Codex`,`tangle graph run --help`);r.set(e,{account:`cli`,secretEnv:e===`claude-code`?`CLAUDE_TOKEN`:`CODEX_AUTH`,format:e===`claude-code`?`token`:`bundle`})}let i=await e.secrets.list();for(let[t,a]of r)if(n.throwIfAborted(),!i.some(e=>e.name===a.secretEnv)){if(t!==`claude-code`)throw new I(`NATIVE_CREDENTIAL_NOT_ENROLLED`,`Codex cloud credential is not enrolled`,`A local Codex login does not grant the Sandbox API a stored credential reference`,`tangle secret create CODEX_AUTH --value-stdin`);await Ts(e,a.secretEnv,n)}return r}function J(e){throw new I(`GRAPH_INVALID`,`Graph creation failed`,e,`tangle graph new --help`)}function Os(e){return typeof e==`string`&&/^[a-z0-9][a-z0-9-]{0,62}$/i.test(e)}const ks={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 As=class{owned;lastFailure;pending=Promise.resolve();revision=0;sealed=!1;constructor(e,t,n){this.directory=e,this.options=t,this.cwd=n}async digest(e=this.owned){e||J(`No graph file was saved`);let t=await Ue(e.file,ue.O_RDONLY|ue.O_NOFOLLOW);try{let[n,r]=await Promise.all([t.stat(),e.handle.stat()]);return(!n.isFile()||n.dev!==r.dev||n.ino!==r.ino)&&J(`The owned graph file was replaced`),Cc(await t.readFile())}finally{await t.close()}}enqueue(e){let t=++this.revision,n=this.pending.then(()=>e(t));return this.pending=n.then(()=>void 0,()=>void 0),n}check=()=>this.enqueue(async e=>{let t=this.owned;if(!t?.result)return!1;let{digest:n,result:r}=t,i=await this.digest(t),a=this.revision===e&&this.owned===t&&t.digest===n&&t.result===r&&i===n;return a&&(this.sealed=!0),a});receipt(){this.owned?.result||J(`No successful graph run was recorded`);let{file:e,digest:t,result:n}=this.owned;return{file:e,digest:t,result:n}}invoke(e,t){return this.sealed&&J(`The graph is accepted; submit its recorded successful run`),this.enqueue(()=>this.write(e,t)).catch(e=>(this.lastFailure=e,{ok:!1,diagnostic:Yt(e)}))}async write(e,t){t.throwIfAborted(),this.lastFailure=void 0;let n=e;(!n||!Os(n.name)||typeof n.source!=`string`||typeof n.run!=`boolean`||Object.keys(n).some(e=>![`name`,`source`,`run`].includes(e)))&&J(`Expected only name, source and boolean run`),this.options.name!==void 0&&n.name!==this.options.name&&J(`The graph name must match --name`),this.owned&&(this.owned.result=void 0);let r=D(this.directory,`${n.name}.yaml`);if(this.owned&&this.owned.file!==r&&J(`This invocation owns one named graph file`),!this.owned)try{this.owned={file:r,handle:await Ue(r,ue.O_RDWR|ue.O_CREAT|ue.O_EXCL|ue.O_NOFOLLOW,384),digest:Cc(``)}}catch(e){throw e.code===`EEXIST`&&J(`Graph already exists: ${r}; choose another --name`),e}let i=this.owned;await this.digest()!==i.digest&&J(`The owned graph was changed`);let a=Buffer.from(n.source);for(let e=0;e<a.length;){let{bytesWritten:t}=await i.handle.write(a,e,a.length-e,e);if(!t)throw Error(`Graph file write made no progress`);e+=t}await i.handle.truncate(a.length),await i.handle.sync(),i.digest=Cc(a);let o={...this.options,param:[]},s={cwd:this.cwd,signal:t,source:n.source},c=await Ac(r,{...o,dryRun:!0},{...s,connectNeeds:!0});if(`graph`in c||J(`No canonical graph was returned`),c.graph.deliverable.checkRef===`command`&&J(`Host command checks need a jailed verifier node`),await this.digest()!==i.digest&&J(`Graph changed during validation`),!n.run)return{file:r,graphDigest:c.graph.digest,validated:!0};let l=await Ac(r,o,{...s,graphDigest:c.graph.digest});return(!(`status`in l)||l.status!==`winner`||l.graphDigest!==c.graph.digest||await this.digest()!==i.digest)&&J(`The graph must succeed with unchanged YAML`),i.result=l,this.receipt()}async close(){await this.pending,await this.owned?.handle.close()}};async function js(e,t,n){let{runId:r,runDir:i,cwd:a,bridge:o,signal:s}=e,c=await o(),l=D(await Ge(D(Ce(),`.tangle`)),`graphs`);(wc(a,l)||wc(l,a))&&J(`The graph store must be outside the agent workspace; choose another working directory`);try{await He(l,{mode:448})}catch(e){if(e.code!==`EEXIST`)throw e}await Ge(l)!==l&&J(`The graph store redirects outside its canonical location`);let u=n.seat??B().seat,d=await ws(a,s)(u,{node:`graph-designer`,cwd:a,signal:s,lastCandidate:!0});d||J(`No authenticated native subscription is available`);let{graphDesignerProfile:f}=await import(`@tangle-network/agent-runtime/profiles`),{supervisePursuit:p}=await import(`@tangle-network/agent-runtime/durable`),m=f({profile:{name:`graph-designer`,harness:d.harness,model:{provider:d.provider,default:d.model,...d.reasoningEffort===void 0?{}:{reasoningEffort:d.reasoningEffort}},prompt:{instructions:[`You are the sole graph designer. Author a canonical YAML graph for the requested intent, then qualify and run it using write_graph. Its nodes are complete AgentProfiles with a real independent verifier and declarative route/data outside check. Command checks execute on the host and are refused here; put executable verification in the verifier node's normal native tools. Read the supplied skills and preserve the user's task and authority.`,`Call write_graph with name, complete YAML source and run:false to validate; repair its concrete diagnostics, then call it with the identical source and run:true. The graph schema and executor are owned by the installed loader. Supply defaults for parameters needed by the first run. Only a real successful host run of the unchanged saved file passes. Submit that evidence using submit_result; explain concrete blockers using report_blocked.`]},tools:{agent_runtime_coordination_write_graph:!0,agent_runtime_coordination_submit_result:!0,agent_runtime_coordination_read_continuation:!0,agent_runtime_coordination_report_blocked:!0}}}),h=oe(m),g=new As(l,{...n,seat:u},a),_={maxIterations:6,maxTokens:3e4,deadlineMs:3e5};try{let e=await p(m,{intent:t,name:n.name},{pursuitId:r,runId:r,runDir:i,signal:s,backend:{...c,timeoutMs:_.deadlineMs},budget:_,maxDepth:0,coordination:{authentication:!0,requestTimeoutMs:_.deadlineMs},deliverable:{describe:`The saved graph succeeds with unchanged YAML`,check:g.check,checkState:g.check},continuation:ks,resolveSupervisorTools:e=>e.runId!==r||e.nodeId!==r||e.depth!==0||e.identity.profileDigest!==h?[]:[{name:`write_graph`,description:`Save, validate and run this graph.`,inputSchema:{type:`object`,properties:{name:{type:`string`},source:{type:`string`},run:{type:`boolean`}},required:[`name`,`source`,`run`],additionalProperties:!1},handler:(t,n)=>((n.nodeId!==e.nodeId||n.ownerId!==e.ownerId||n.runId!==e.runId)&&J(`Wrong graph tool owner`),g.invoke(t,n.signal))}]});if(e.result.kind===`no-winner`||!await g.check()){if(g.lastFailure)throw g.lastFailure;let t=e.result.kind===`no-winner`?e.result.error?.message??e.result.reason:`The graph file changed after its successful run`;throw Object.assign(new I(`GRAPH_DESIGN_FAILED`,`Graph design did not finish`,t,`tangle graph new --help`),{runId:r,node:`graph-designer`})}return g.receipt()}finally{await g.close()}}function Ms(e){e.command(`new <intent>`).description(`Design, validate and run one portable graph`).option(`--seat <seat>`,`Use harness/model@effort for the designer and graph`).option(`--name <name>`,`Save this graph name`).action(async(e,t)=>{process.env.BRIDGE_JAIL_RW_PATHS?.trim()&&J(`Remove BRIDGE_JAIL_RW_PATHS before graph new; extra native write roots cannot contain its host store`),t.name!==void 0&&!Os(t.name)&&J(`Use letters, numbers and hyphens in --name`);let n=await Ec({},n=>js(n,e,t));t.json?j(n):N(`Created ${n.file} · run ${n.result.runId}`)})}async function Ns(e){if(!tr(e.apiKey)){if(e.json||e.dryRun||!process.stdin.isTTY)return;await Fi({baseUrl:e.sandboxBaseUrl,signal:e.signal})}return W(e)}async function Ps(e,t,n){let r=Qs(t.parameter),i=n??await Ns(t);if(!i)throw new I(`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?(j(ec(a)),a):($s(a,t.browser===!1?!1:await Ei(a.redirectUrl),t.wait),a)}async function Fs(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 Ps(t,{...n,wait:!0},e);for(;!i&&Date.now()<Date.parse(a.expiresAt);)await Pe(1e3,void 0,{signal:n.signal}),i=await r();return i}function Is(){let e=new b(`hub`).description(`Discover and run Tangle Hub tools`);e.command(`connect`).description(`Connect a provider account`).argument(`provider`,`Provider to connect`).option(`--no-browser`,`Print the authorization URL instead of opening it`).option(`--parameter <key=value>`,`Provider-specific OAuth value. Repeatable.`,(e,t)=>[...t,e],[]).action(async(e,t)=>{await Ps(e,t)});let t=new b(`connections`).description(`List Hub provider connections`).action(async e=>{let t=await(await W(e)).connections.list();if(e.json){j(t);return}Zs(t.connections)});t.command(`revoke <connection-id>`).description(`Revoke a Hub provider connection`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=await W(t),r=await Cr(n,e);if(!t.force&&!await ei(`Revoke Hub connection ${r}? `,`--force`)){N(`Revoke cancelled.`);return}let i=await n.connections.revoke(r);if(t.json){j(i);return}N(`Revoked Hub connection ${i.connection.id}.`)}),e.addCommand(t);let n=new b(`permissions`).description(`Manage Hub action permissions`);n.command(`list`).description(`List Hub permissions for a connection`).requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);let t=await W(e),n=await Cr(t,e.connection),r=await t.permissions.list(n);if(e.json){j(r);return}Ks(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=qs(e.decision),n=await W(e),r=await Cr(n,e.connection),i=await n.permissions.set({connectionId:r,actionPath:e.action,decision:t});if(e.json){j(i);return}Ks([i.policy])}),n.command(`revert-writes`).description("Revoke a bulk `--allow-writes` grant for a connection (deletes only the auto-granted write rows; manual permissions are untouched)").requiredOption(`--connection <ref>`,`Hub connection id, or provider[:account]`).action(async e=>{if(!e.connection)throw Error(`--connection is required.`);let t=await W(e),n=await Cr(t,e.connection),r=await t.permissions.revertWrites(n);if(e.json){j(r);return}N(`Reverted ${r.reverted} write permission${r.reverted===1?``:`s`} for connection ${r.connectionId}.`)}),e.addCommand(n),e.addCommand(Rs());let r=new b(`tools`).description(`Discover Hub tools`);return r.command(`sources`).description(`List Hub tool sources`).action(async e=>{let t=await(await W(e)).tools.sources();if(e.json){j(t);return}Js(t.sources)}),r.command(`describe`).description(`Describe a Hub tool`).argument(`path`,`Executor tool path`).action(async(e,t)=>{let n=await(await W(t)).tools.describe(e);if(t.json){j(n);return}Ys(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 W(t)).tools.search(e.join(` `),{provider:t.provider});if(t.json){j(n);return}Gs(n.tools)}),e.addCommand(r),e.addCommand(Ls(`call`)),e.addCommand(Ls(`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(Bs(e),t.cancel)throw Error(`Hub approval resume does not support --cancel. Use --decline to deny the approval.`);if(t.accept&&t.decline)throw Error(`Choose only one of --accept or --decline.`);if(!t.accept&&!t.decline)throw Error(`Choose --accept to approve or --decline to deny the Hub approval.`);let n=await W(t);Hs(t.decline?await n.approvals.deny(e):await n.approvals.approve(e),t.json===!0)}),e.command(`status`).description(`Show Hub auth and connection status`).action(async e=>{let t=await(await W(e)).status();if(e.json){j(t);return}tc(t)}),e}function Ls(e){return new b(e).description(`Execute a Hub tool`).argument(`<args...>`,`Tool path tokens followed by JSON input`).option(`--connection <ref>`,`Hub connection id, or provider[:account]`).option(`--auto-approve`,`Approve a HUB_APPROVAL_REQUIRED execution and retry once`).option(`--approve`,`Alias for --auto-approve`).option(`--no-hub-key`,`Do not auto-mint a platform Hub key; use the stored credential as-is`).action(async(e,t)=>{let{args:n,approve:r}=zs(e,t),{path:i,input:a}=Ws(n),o=await W(t),s=t.connection?await Cr(o,t.connection):void 0;j((await o.tools.invoke(i,a,{connectionId:s,approve:r})).result)})}function Rs(){let e=new b(`approvals`).description(`List and resolve Hub execution approvals`);e.command(`list`).description(`List pending Hub execution approvals`).action(async e=>{let t=await(await W(e)).approvals.list();if(e.json){j(t);return}Vs(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)=>{Bs(e),Hs(await(await W(n)).approvals[t](e),n.json===!0)});return e}function zs(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 Bs(e){if(!/^[A-Za-z0-9_-]+$/.test(e))throw Error(`Hub approval ID must contain only letters, numbers, underscores, and dashes.`)}function Vs(e){A(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 Hs(e,t){if(t){j(Us(e));return}N(`Hub approval ${e.approval.id} ${e.approval.status}.`),e.capabilityToken&&N("Capability token minted. Re-run the original command with `--approve` to execute automatically.")}function Us(e){return{approval:e.approval,...e.capabilityToken?{capabilityToken:{tokenId:e.capabilityToken.tokenId,expiresAt:e.capabilityToken.expiresAt}}:{}}}function Ws(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 Gs(e){A(e.map(e=>({...e,provider:e.providerId??e.requiredConnectionProviderId,connection:Xs(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 Ks(e){A(e,[{key:`connectionId`,header:`Connection`},{key:`providerId`,header:`Provider`},{key:`actionPath`,header:`Action`},{key:`decision`,header:`Decision`},{key:`updatedAt`,header:`Updated`}])}function qs(e){if(e===`allow`||e===`ask`||e===`deny`)return e;throw Error(`--decision must be one of: allow, ask, deny.`)}function Js(e){A(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 Ys(e){F({Path:e.path,Provider:e.providerId??e.requiredConnectionProviderId,Title:e.title,Description:e.description,Connection:Xs(e),Policy:e.policyState}),e.inputSchema!==void 0&&(N(`Input schema`),console.log(JSON.stringify(e.inputSchema,null,2))),e.outputSchema!==void 0&&(N(`Output schema`),console.log(JSON.stringify(e.outputSchema,null,2)))}function Xs(e){if(e.connectionRequired===!1)return`not required`;if(e.connectionStatus)return e.connectionStatus}function Zs(e){A(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 Qs(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 $s(e,t,n=!1){t?N(`Opened browser to connect ${e.provider}.`):(N(`Open this URL to connect ${e.provider}:`),console.log(e.redirectUrl)),N(n?`Finish authorization in the browser; this run resumes when connected.`:"Finish authorization in the browser, then rerun `tangle hub status`.")}function ec(e){return{provider:e.provider,redirectUrl:e.redirectUrl,expiresAt:e.expiresAt,scopes:e.scopes,cli:e.cli}}function tc(e){let{principal:t,connections:n}=e;N(`Hub status`),F({Principal:t.kind,"User ID":t.userId,"API Key ID":t.apiKeyId,"Sandbox ID":t.sandboxId,"Connected Providers":n.connectedProviderCount,"Unhealthy Providers":n.unhealthyProviderCount}),n.unhealthyProviderCount>0&&N(`Some providers require reconnect.`)}const nc=[`claude-code`,`opencode`,`codex`,`kimi-code`,`prime`],rc=process.env.TANGLE_ROUTER_URL??`https://router.tangle.tools/v1`;function ic(e){let t=se(e);if(t)return t;throw Error(`--model '${e}' has no provider. Pass a canonical id, for example 'google/${e}'.`)}function ac(e){let t=e.harness??`claude-code`;if(!nc.includes(t))throw Error(`Unknown --harness '${t}'. Supported: ${nc.join(`, `)}.`);let n=oc(e.maxTokens,2e5,`--max-tokens`),r=oc(e.maxIterations,50,`--max-iterations`),i=e.maxWorkers===void 0?void 0:oc(e.maxWorkers,0,`--max-workers`);return{harness:t,...e.model?{model:e.model}:{},maxTokens:n,maxIterations:r,...i===void 0?{}:{maxWorkers:i}}}function oc(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 sc(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 cc(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 lc=null;function uc(){return lc??=import(`@tangle-network/agent-runtime/kernel`).catch(e=>{throw lc=null,e?.code===`ERR_MODULE_NOT_FOUND`?new I(`RUNTIME_UNAVAILABLE`,`Agent Runtime could not be loaded`,e.message,`npm install -g @tangle-network/sandbox-cli@latest`):e}),lc}async function dc(e,t,n){let r=V({apiKey:n.apiKey,baseUrl:n.baseUrl}),i=H(r),{budget:a,perWorker:o}=sc(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||N(`worker ${a.id} spawned`),a}},l=await uc(),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-2.5-flash-lite`,provider:t.model?ic(t.model):`google`},tools:{agent_runtime_coordination_spawn_worker:!0,agent_runtime_coordination_observe_agent:!0}},p={routerBaseUrl:rc,routerKey:r.apiKey},m=cc(await l.supervise(f,{goal:e},{budget:a,makeWorkerAgent:d,router:p,...o?{perWorker:o}:{},...t.model?{allowedModels:[t.model]}:{},runId:`supervise-${C()}`})),h=m.status===`winner`?`settled`:`failed`;for(let e of s)e.status=h,n.json||N(`worker ${e.id} settled (${e.status})`);return{task:e,result:m.text,workers:s,tokenUsage:m.tokenUsage,costUsd:m.costUsd,status:m.status}}function fc(){let e=new b(`supervise`);return e.description(`Run a budget-conserving supervisor that spawns isolated sandbox workers to deliver a task.`).argument(`<task>`,`What the supervisor should accomplish`).option(`--harness <name>`,`Worker harness (${nc.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=ac({harness:t.harness,model:t.model,maxTokens:t.maxTokens,maxIterations:t.maxIterations,maxWorkers:t.maxWorkers});t.json||(N(`Supervising: ${e}`),N(`harness=${n.harness} budget=${n.maxTokens}tok/${n.maxIterations}it`),console.log());let r=await dc(e,n,{apiKey:t.apiKey,baseUrl:t.baseUrl,json:t.json});if(t.json){j(r),r.status!==`winner`&&(process.exitCode=1);return}if(console.log(),r.result&&(console.log(r.result),console.log()),F({"Input Tokens":r.tokenUsage.input??`Unavailable`,"Output Tokens":r.tokenUsage.output??`Unavailable`,Cost:r.costUsd===null?`Unavailable`:`$${r.costUsd.toFixed(4)}`}),r.status!==`winner`)throw Error(`Supervisor finished without a winner: ${r.status}`)}),e}function Y(e){return Hr({...e.apiKey===void 0?{}:{apiKey:e.apiKey},...e.baseUrl===void 0?{}:{baseUrl:e.baseUrl}})}const pc=1e3;function mc(e,t){return[...t,e]}function hc(e,t=`input`,n){if(n===void 0&&!e?.length)return;let r={};if(n!==void 0)try{if(r=JSON.parse(T(n,`utf8`)),!r||typeof r!=`object`||Array.isArray(r)||Object.entries(r).some(([e,t])=>!e.length||typeof t!=`string`))throw Error(`Invalid input map`)}catch{throw new I(`WORKFLOW_INPUT_FILE_INVALID`,`Could not load --input-file '${n}'`,`Expected a readable JSON object with nonempty keys and string values`,`tangle workflows run --help`)}let i=Object.entries(r);for(let n of e??[]){let e=n.indexOf(`=`);if(e<=0)throw Error(`Invalid --${t} "${n}": expected key=value (e.g. pull_request.number=123)`);i.push([n.slice(0,e),n.slice(e+1)])}return Object.fromEntries(i)}function gc(e){A(e.map(e=>({id:e.id,status:e.status,attempts:e.attempts,created:e.createdAt,completed:e.completedAt??``})),[{key:`id`,header:`Run ID`},{key:`status`,header:`Status`},{key:`attempts`,header:`Attempts`},{key:`created`,header:`Created`},{key:`completed`,header:`Completed`}])}function _c(e){if(F({"Run ID":e.id,Workflow:e.workflowId,Status:e.status,Error:e.error??``,Attempts:e.attempts,Created:e.createdAt,Started:e.startedAt??``,Completed:e.completedAt??``}),e.actionResults.length>0){N(`Actions`);let t=e.actionResults.some(e=>e.nodeId!==void 0||e.visit!==void 0);A(e.actionResults.map(e=>({index:e.index,...t?{node:e.nodeId??``,visit:e.visit??``}:{},kind:e.kind,status:e.status,error:e.error??``,cost:e.costUsd??``})),[{key:`index`,header:`#`},...t?[{key:`node`,header:`Node`},{key:`visit`,header:`Visit`}]:[],{key:`kind`,header:`Kind`},{key:`status`,header:`Status`},{key:`error`,header:`Error`},{key:`cost`,header:`Cost (USD)`}])}e.graph&&(N(`Graph`),F({Nodes:e.graph.nodes.length,Edges:e.graph.edges.length,"Max node visits":e.graph.maxNodeVisits}),A(e.graph.edges.map(e=>({from:e.from,to:e.to,guard:e.when===void 0?``:JSON.stringify(e.when)})),[{key:`from`,header:`From`},{key:`to`,header:`To`},{key:`guard`,header:`Guard`}])),e.edgeVerdicts&&e.edgeVerdicts.length>0&&(N(`Edge verdicts`),A(e.edgeVerdicts.flatMap(e=>Object.entries(e.verdicts).map(([t,n])=>({node:e.nodeId,edge:t,verdict:n?`taken`:`not taken`}))),[{key:`node`,header:`Node`},{key:`edge`,header:`Edge`},{key:`verdict`,header:`Verdict`}]))}function vc(e){if(e.status===`cancelled`){N(`Cancelled run ${e.runId}.`);return}if(e.signalled){N(`Cancelling run ${e.runId} — signalled the worker; it will stop shortly.`);return}N(`Requested cancellation of run ${e.runId}, but couldn't confirm it — the run may have just finished, or it's running on another instance and will stop on its own.`)}function yc(e){switch(e.type){case`snapshot`:N(`snapshot: ${e.run.status} (${e.run.actionResults.length} action(s))`);break;case`action.started`:console.log(`→ action[${e.index}] ${e.kind} started`);break;case`action.finished`:{let t=e.status===`succeeded`?`✓`:e.status===`skipped`?`⊘`:`✗`;console.log(`${t} action[${e.index}] ${e.kind} ${e.status}${e.error?`: ${e.error}`:``}`);break}case`iteration.started`:console.log(` · action[${e.actionIndex}] iteration ${e.iterationIndex} started`);break;case`iteration.ended`:console.log(` · action[${e.actionIndex}] iteration ${e.iterationIndex} ${e.status}`);break;case`token`:typeof e.delta==`string`&&process.stdout.write(e.delta);break;case`ping`:break;case`run.done`:console.log(`\nrun.done: ${e.status}${e.error?`: ${e.error}`:``}`);break;case`run.waiting`:console.log(`\nrun.waiting: parked on a human decision (${e.decisionId}) — resolve it to resume`);break}}function bc(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.`,mc,[]).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=hc(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 Y(t),{runId:o}=await a.workflows.run(e,n);if(!t.wait){if(t.json)return j({runId:o});N(`Started run ${o} for workflow ${e}.`),N(`Inspect it with: tangle workflows run-detail ${e} ${o}`);return}let s=t.json?null:P(`Waiting for run ${o} to finish...`).start(),c;try{c=await a.workflows.waitForRun(e,o,{...r===void 0?{}:{timeoutMs:r},...i===void 0?{}:{pollIntervalMs:i}})}finally{s?.stop()}if(c.status===`failed`&&(process.exitCode=1),t.json)return j(c);_c(c)}),e.command(`runs`).description(`List a workflow's run history (newest first)`).argument(`<id>`,`Workflow ID`).option(`--limit <n>`,`Runs per page (1-100)`).option(`--cursor <cursor>`,`Pagination cursor from a previous page`).option(`--all`,`Fetch every page, not just the first`).action(async(e,t)=>{let n=await Y(t),r=t.limit===void 0?void 0: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>=pc){s=c.nextCursor,t.json||N(`Stopped after ${pc} pages (${i.length} runs); more may exist — resume with --cursor ${c.nextCursor}`);break}a=c.nextCursor}if(t.json)return j({runs:i,nextCursor:s});gc(i);return}let i=await n.workflows.listRuns(e,{...r===void 0?{}:{limit:r},...t.cursor===void 0?{}:{cursor:t.cursor}});if(t.json)return j(i);gc(i.runs),i.nextCursor&&N(`More runs available — next page: --cursor ${i.nextCursor}`)}),e.command(`run-detail`).description(`Show a single run's detail (per-action output and errors)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.getRun(e,t);if(n.json)return j(r);_c(r)}),e.command(`cancel`).description(`Cancel a queued or in-progress run`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.cancel(e,t);if(n.json)return j(r);vc(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 Y(n),o=await a.workflows.retryRun(e,t);if(!n.wait){if(n.json)return j(o);N(`Started run ${o.runId} (retry of ${t}).`),N(`Inspect it with: tangle workflows run-detail ${e} ${o.runId}`);return}let s=n.json?null:P(`Waiting for run ${o.runId} to finish...`).start(),c;try{c=await a.workflows.waitForRun(e,o.runId,{...r===void 0?{}:{timeoutMs:r},...i===void 0?{}:{pollIntervalMs:i}})}finally{s?.stop()}if(c.status===`failed`&&(process.exitCode=1),n.json)return j(c);_c(c)}),e.command(`events`).description(`Tail a run's live progress events until it finishes`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await Y(n);for await(let i of r.workflows.watchRun(e,t))n.json?console.log(JSON.stringify(i)):yc(i),i.type===`run.done`&&i.status===`failed`&&(process.exitCode=1)})}const xc=t(import.meta.url);if(!xc)throw Error(`Tangle CLI package metadata was not found`);const Sc=ge(xc),Cc=e=>x(`sha256`).update(e).digest(`hex`);function wc(e,t){let n=ye(e,t);return n!==`..`&&!n.startsWith(`..${xe}`)&&!ve(n)}function Tc(e,t){if(/[\\/]/.test(e)||/\.(yaml|yml|json)$/.test(e))return be(t,e);let n=t;for(;!de(D(n,`.git`))&&ge(n)!==n;)n=ge(n);de(D(n,`.git`))||(n=t);let r=[D(n,`.tangle`,`graphs`,`${e}.yaml`),D(Ce(),`.tangle`,`graphs`,`${e}.yaml`)],i=r.find(de);if(i)return i;throw new I(`GRAPH_NOT_FOUND`,`Graph '${e}' was not found`,`Looked in ${r.join(` and `)}`,`tangle graph --help`)}async function Ec(e,t){return Ss(e.signal,async n=>{let r=C(),i;try{let a=D(Ce(),`.tangle`,`runs`,r);await He(a,{recursive:!0,mode:448});let o=await Ge(D(Ce(),`.tangle`)),s=await Ge(e.cwd??process.cwd()),c=[`runs`,`graph-registry`,`graphs`].some(e=>wc(s,D(o,e))||wc(D(o,e),s))?D(Ce(),`.tangle`,`workspaces`,r):s;await He(c,{recursive:!0,mode:448});let l;return await t({runId:r,runDir:a,cwd:c,bridge:e=>l??=(async()=>{n.throwIfAborted();let t=S(32).toString(`hex`),{loadConfig:r,startServer:o}=await import(`cli-bridge`),s=D(Sc,`dist`,`stdio.mjs`),l=r({...process.env,BRIDGE_HOST:`127.0.0.1`,BRIDGE_PORT:`3344`,BRIDGE_BEARER:t,BRIDGE_DATA_DIR:D(a,`bridge`),BRIDGE_BACKENDS:Cs,BRIDGE_JAIL_MODE:`fs-jail`,BRIDGE_JAIL_FALLBACK:`deny`,BRIDGE_SUBSCRIPTIONS_ONLY:`1`});return e&&l.jailReadablePaths.push(s),i=await o({cwd:c,config:{...l,port:0},handleSignals:!1,quiet:!0,hub:e?{client:e,hash:xs,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}),{backend:`bridge`,bridgeUrl:i.url,bridgeBearer:t,cwd:c}})(),signal:n})}catch(e){throw e instanceof Error&&Object.assign(e,{runId:r}),e}finally{await i?.close()}},e.fix??`tangle graph --help`)}function Dc(e){throw new I(`GRAPH_CLOUD_UNAVAILABLE`,`Cloud subscription execution was refused`,e,`tangle graph run --help`)}function Oc(e){(e.observed||!e.entry||e.deliverable.checkRef===`command`)&&Dc(`Cloud needs an executable flow and portable outside check; root coordination and host checks are unsupported`);let{digest:t,...n}=e;return{...n,nodes:e.nodes.map(({id:e,profile:t})=>{t.seats&&Dc(`Node '${e}' has an account-selection chain; direct single-account execution cannot drop it`);let n=t.model?.metadata?.credentialSource;return n!==void 0&&n!==`subscription`&&Dc(`Node '${e}' declares a non-subscription credential source`),{id:e,profile:{...t,model:{...t.model,metadata:{...t.model?.metadata,credentialSource:`subscription`}}}}})}}async function kc(e,t,n){let r=e.nodes[0]?.profile.harness;(!r||e.nodes.some(e=>e.profile.harness!==r))&&Dc(`Direct cloud execution currently needs one concrete harness across nodes`);let i=U(t).client,a=(await Ds(i,[r],n)).get(r);a||Dc(`No enrolled native reference for ${r}`);let{createTangleProvider:o}=await import(`@tangle-network/agent-provider-tangle`);return{backend:`provider`,provider:o({client:i,modelCredentials:{cliAuth:a},requireNativeSessionCapture:!0}),destroyOnSettle:!0,requireTerminalEvent:!0}}async function Ac(e,t,n={}){let r=[`tangle graph run`,Ke(e),...t.dryRun?[`--dry-run`]:[],...t.cloud?[`--cloud`]:[],...t.seat?[`--seat`,Ke(t.seat)]:[],...t.param.flatMap(e=>[`--param`,Ke(e)])].join(` `);return await Ss(n.signal,async i=>{let a=await uc();i.throwIfAborted();let o=Tc(e,n.cwd??process.cwd()),s=n.source??await We(o,`utf8`),c=Cc(s),l={apiKey:t.apiKey,sandboxBaseUrl:t.baseUrl,signal:i,json:t.json,dryRun:t.dryRun&&!n.connectNeeds},u,d=()=>u??=Ns(l),f=new Map,p=e=>{let t=e.trim().toLowerCase(),n=f.get(t)??(async()=>{let e=await d(),n=e&&await Fs(e,t,l);return n?{connectionId:n,capabilities:[`*`]}:void 0})();return f.set(t,n),n},m=async e=>{i.throwIfAborted();let r=await a.loadGraphFile(o,{source:s,seat:t.seat??B().seat,resolveSeat:ws(e,i),resolveNeed:p,params:hc(t.param,`param`),cwd:e,signal:i});if(i.throwIfAborted(),n.graphDigest&&r.graph.digest!==n.graphDigest)throw new I(`GRAPH_CHANGED`,`The validated graph changed before execution`,`Its compiled graph digest no longer matches validation`,`tangle graph run --help`);if(!t.cloud)return r;let l=Oc(r.graph);return{...r,sourceGraph:r.graph,sourceDigest:c,graph:{...l,digest:a.graphDigest(l)}}};return t.dryRun?m(n.cwd??process.cwd()):Ec({...n,signal:i,fix:r},async({runId:e,runDir:n,cwd:r,bridge:s})=>{let l=await m(r),{superviseGraphPursuit:u}=await import(`@tangle-network/agent-runtime/durable`),f=a.graphRegistry(D(Ce(),`.tangle`,`graph-registry`)),p=`sourceGraph`in l?l.sourceGraph:l.graph;t.cloud&&await a.recordStoredGraphRun(f,p);let h=await a.recordStoredGraphRun(f,l.graph),g=a.graphFromStored(h),_=h.nodes.some(e=>e.profile.connections?.length),ee=_&&!t.cloud?await d():void 0;if(_&&!t.cloud&&!ee)throw new I(`AUTH_REQUIRED`,`Hub authentication is required`,`No Tangle credential is configured for this local graph`,`tangle auth login`);let te=t.cloud?await kc(h,t,i):await s(ee),v=new Date().toISOString(),ne=new Map;N(`Run ${e} · ${he(o)} · ${r}`);let y=await jc(n);N(`Viewer ${y.url}`);let re=await u(g,{pursuitId:h.digest,runDir:n,runId:e,backend:te,signal:i,profileSecurity:{allowConnections:_,allowLocalMcp:!1,allowHooks:!1,allowedMcpHosts:[]},hooks:{onEvent:e=>{let t=e.payload;e.target===`agent.spawn`&&t?.childId&&typeof t.label==`string`&&ne.set(t.childId,t.label);let n=ne.get(t?.childId??e.parentId??``);process.stderr.write(`${n?`${JSON.stringify(n)} `:``}${e.target} ${JSON.stringify(t?.status??e.phase)}\n`)}}}).finally(y.close),b={runId:e,graphDigest:h.digest,sourceDigest:c,...t.cloud?{authoredGraphDigest:p.digest}:{},...cc(re.result.result)},x=re.result.result,{tokens:S,tokensKnown:C,iterations:ie,ms:ae}=x.spentTotal;if(await a.recordStoredGraphRun(f,h,{graphDigest:h.digest,evidence:[{kind:`authored-graph`,url:`urn:sha256:${p.digest}`},{kind:`authored-yaml`,url:`urn:sha256:${c}`}],taskDigest:a.taskShapeDigest({graph:he(o),params:l.params}),startedAt:v,finishedAt:new Date().toISOString(),outcome:x.kind===`no-winner`?{kind:`no-winner`,reason:x.reason}:{kind:`delivered`,summary:b.text},cost:{iterations:ie,ms:ae,...C===!1?{}:{tokens:S.input+S.output},...b.costUsd===null?{}:{usd:b.costUsd}},traversals:re.result.ledger.length,exhaustedEdges:re.result.exhaustedEdges,source:{kind:`tangle-cli-graph`,id:e}}),x.kind===`no-winner`)throw Object.assign(new I(`GRAPH_RUN_FAILED`,`Graph '${he(o)}' finished without a result`,re.result.ledger.filter(e=>e.outcome===`unpropagated`&&e.reason).pop()?.reason||x.reason,`tangle graph inspect ${e}`),{runId:e,runtimeFailures:x.tree.nodes.filter(e=>e.failure).map(e=>({node:e.label,failure:e.failure}))});return b})},r)}async function jc(e){let{serveTopWeb:t}=await import(`@tangle-network/agent-runtime/tui`);return t({roots:[e],assets:D(Sc,`dist`,`graph-viewer`)})}async function Mc(e,t){let n=D(Ce(),`.tangle`,`runs`,e);if(!/^[a-f0-9-]{36}$/i.test(e)||!de(n))throw new I(`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 j(await r(process.cwd(),{runDir:n}));N(`Run ${e} · ${(await jc(n)).url}`)}function Nc(){let e=new b(`graph`).description(`Build and run portable agent graphs`);return Ms(e),e.command(`inspect <run>`).description(`Inspect a live or retained graph run`).action(Mc),e.command(`run <name-or-file>`).description(`Run a saved graph over native subscriptions`).option(`--cloud`,`Run each node in a Tangle sandbox using your subscription`).option(`--seat <seat>`,`Use harness/model@effort for every node`).option(`--param <key=value>`,`Graph parameter; repeatable`,(e,t)=>[...t,e],[]).option(`--dry-run`,`Validate and print the graph without starting agents`).action(async(e,t)=>{let n=await Ac(e,t);t.json||t.dryRun?j(n):`status`in n&&(N(`${n.status} · ${n.runId}`),n.text&&console.log(n.text))}),e}function Pc(){let e=new b(`intelligence`).description(`Create and inspect trace intelligence reports`);return e.command(`connect [agent]`).alias(`connect-agent`).description(`Connect local agent CLIs to Tangle Intelligence`).option(`--endpoint <url>`,`OTLP endpoint base`,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=Ic(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){j(a);return}F({Config:i.configPath,Agents:i.agents.join(`, `),"Native Hooks":i.nativeAgents.join(`, `)||void 0,"Manual Setup":i.manual.length?i.manual.map(e=>`${e.label}: ${e.reason}`).join(` `):void 0,Files:i.written.join(`, `),"Smoke Trace":i.smokeTraceId})}),e.command(`doctor`).description(`Check whether your agent traces carry CONTENT or are metadata-only`).option(`--endpoint <url>`,`OTLP endpoint base`,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:Ic(e.apiKey??t?.apiKey)});e.json?j(n):Fc(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=Lc(e.agent),n=ma(),r={agent:t,event:e.event,endpoint:e.endpoint??n?.endpoint??`https://intelligence.tangle.tools/v1/otlp`,apiKey:Ic(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 zc():Rc(e.payload)};if(e.dryRun){let n=_a(r);if(e.json){j(n);return}F({Trace:n.traceId,Agent:t,Event:e.event});return}let i=await va(r);if(e.json){j({traceId:i});return}F({Trace:i,Agent:t,Event:e.event})}catch(t){if(e.nonBlocking){let n=t instanceof Error?t.message:String(t);e.json?j({ok:!1,error:n}):console.error(`Tangle Intelligence hook skipped: ${n}`);return}R(t)}}),e.command(`sandbox <sandbox-id>`).description(`Create an intelligence report for one sandbox`).option(`--mode <mode>`,`deterministic | agentic`,`deterministic`).option(`--max-usd <amount>`,`Maximum customer charge for agentic analysis`).option(`--metadata <json>`,`Metadata JSON object`).action(async(e,t)=>{await Bc({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 Bc({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 Bc({type:Hc(e.subjectType),id:e.subjectId},e)}),e.command(`get <job-id>`).description(`Get an intelligence report`).action(async(e,t)=>{let{client:n}=U(t),r=t.json?null:P(`Fetching intelligence report...`);r?.start();let i=await n.intelligence.getReport(e);if(r?.stop(),t.json){j(i);return}Vc(i)}),e.command(`list`).description(`List intelligence reports`).option(`--subject-type <type>`,`sandbox | fleet`).option(`--subject-id <id>`,`Subject identifier`).option(`--limit <count>`,`Maximum reports to return`).action(async e=>{let{client:t}=U(e),n=e.json?null:P(`Fetching intelligence reports...`);n?.start();let r=await t.intelligence.listReports({subjectType:e.subjectType===void 0?void 0:Hc(e.subjectType),subjectId:e.subjectId,limit:e.limit===void 0?void 0:Gc(e.limit)});if(n?.stop(),e.json){j(r);return}A(r.map(e=>({jobId:e.jobId,subject:`${e.subject.type}:${e.subject.id}`,mode:e.mode,status:e.status,cost:`$${e.billing.costUsd.toFixed(2)}`,updatedAt:e.updatedAt})),[{key:`jobId`,header:`Job`,width:20},{key:`subject`,header:`Subject`,width:28},{key:`mode`,header:`Mode`,width:15},{key:`status`,header:`Status`,width:14},{key:`cost`,header:`Cost`,width:10},{key:`updatedAt`,header:`Updated`,width:18}])}),e}function Fc(e){F({Status:e.contentSeen?`content flowing`:e.tracesSeen?`metadata-only — a content gate is missing`:`no traces yet`,"Traces seen":e.tracesSeen?`yes`:`no`,"Content seen":e.contentSeen?`yes`:`no`,"Last seen":e.lastSeenAt??`never`,Window:`${e.windowDays}d`});let t=Object.entries(e.byAgent);t.length>0&&(console.log(),A(t.map(([e,t])=>({agent:e,traces:t.tracesSeen?`yes`:`no`,content:t.contentSeen?`yes`:`no`})),[{key:`agent`,header:`Agent`,width:18},{key:`traces`,header:`Traces`,width:10},{key:`content`,header:`Content`,width:10}]))}function Ic(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 Lc(e){if(da(e))return e;throw Error(`agent must be a known Tangle Intelligence agent surface`)}function Rc(e){try{return JSON.parse(e)}catch(e){throw Error(`--payload must be JSON: ${e instanceof Error?e.message:String(e)}`)}}async function zc(){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 Bc(e,t){let n=Uc(t.mode),r=Kc(t.metadata),i=t.maxUsd===void 0?void 0:Wc(t.maxUsd);if(n===`agentic`&&i===void 0)throw Error(`Agentic intelligence reports require --max-usd`);let{client:a}=U(t),o=t.json?null:P(`Creating intelligence report...`);o?.start();let s=await a.intelligence.createReport({subject:e,mode:n,...i===void 0?{}:{budget:{billTo:`customer`,maxUsd:i}},...r===void 0?{}:{metadata:r}});if(o?.stop(),t.json){j(s);return}Vc(s)}function Vc(e){F({Job:e.jobId,Subject:`${e.subject.type}:${e.subject.id}`,Mode:e.mode,Status:e.status,"Billed To":e.billing.billedTo,Cost:`$${e.billing.costUsd.toFixed(2)}`,Budget:e.billing.budgetMaxUsd===void 0?void 0:`$${e.billing.budgetMaxUsd.toFixed(2)}`,Updated:e.updatedAt}),e.result!==null&&(console.log(),j(e.result))}function Hc(e){if(e===`sandbox`||e===`fleet`)return e;throw Error(`subject type must be sandbox or fleet`)}function Uc(e){if(e===`deterministic`||e===`agentic`)return e;throw Error(`mode must be deterministic or agentic`)}function Wc(e){let t=Number(e);if(!Number.isFinite(t)||t<0)throw Error(`--max-usd must be a non-negative number`);return t}function Gc(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function Kc(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 qc=[`router`,`sandbox`,`blueprint-agent`,`evals`,`agent-builder`];async function Jc(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 Yc(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 Xc(i,t));return i}async function Xc(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 Zc=[`ID`,`Prefix`,`Name`,`Product`,`Created`,`Last used`,`Expires`];function Qc(e){return[e.id,e.keyPrefix??``,e.name,e.product??`all`,e.createdAt,e.lastUsedAt??`—`,e.expiresAt??`—`]}function $c(){let e=new b(`keys`).description(`Manage sk-tan-* API keys on id.tangle.tools`);return e.command(`list`).description(`List your active API keys`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async e=>{let t=await Jc(e,!1),n=t.baseUrl,r=await(await Yc(t,`${n}/v1/keys`,{expected:200})).json();if(e.json){j(r);return}Rt(Zc,r.data.map(Qc))}),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 (${qc.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&&!qc.includes(t.product))throw Error(`Invalid --product. Expected one of ${qc.join(`, `)}`);let n=await Jc(t,!0),r=n.baseUrl,i=t.expiresInDays===void 0?void 0:new Date(Date.now()+Number.parseInt(t.expiresInDays,10)*24*60*60*1e3).toISOString(),a=P(`Creating API key...`);a.start();let o=await Yc(n,`${r}/v1/keys`,{method:`POST`,expected:201,body:JSON.stringify({name:e,product:t.product,budgetUsd:t.budgetUsd?Number.parseFloat(t.budgetUsd):void 0,rpmLimit:t.rpmLimit?Number.parseInt(t.rpmLimit,10):void 0,expiresAt:i})});a.stop();let s=await o.json();if(t.json){j(s);return}M(`API key created: ${s.data.prefix}…`),N(`Copy this key now — it will never be shown again:\n${s.data.key}`)}),e.command(`revoke`).description(`Revoke an API key`).argument(`<keyId>`,"Key ID (from `tcloud keys list`)").option(`--yes`,`Skip the confirmation prompt`).option(`--platform-url <url>`,`Override the platform URL (id.tangle.tools)`).action(async(e,t)=>{let n=await Jc(t,!0),r=n.baseUrl;if(!t.yes&&!await ei(`Revoke key ${e}? Any service still using it will start to fail.`,`--yes`)){N(`Aborted.`);return}let i=await(await Yc(n,`${r}/v1/keys/${encodeURIComponent(e)}`,{method:`DELETE`,expected:200})).json();if(t.json){j(i);return}M(`Revoked ${e}`)}),e}function el(e){if(Wn().token)throw Error(`A line relay cannot manage numbers or attachments. Use your owner CLI outside the agent box.`);return H(V(e))}function tl(e){if(!e.yes)throw Error(`Review the selected line and use --yes to authorize this change. Attaching enables metered agent work.`)}function nl(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 rl(e){return e().catch(R)}async function il(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 al(e){e.command(`providers`).description(`List provider transports supported by this Hub deployment`).action(e=>rl(async()=>{j(await el(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=>rl(async()=>{j(await el(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)=>rl(async()=>{j(await el(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)=>rl(async()=>{let n=nl(t.transport);if(n===`email`)throw Error(`Email uses an owned mailbox, not phone inventory`);if(n===`voice`)throw Error(`Voice numbers are listed by ph0ny; provide the owned number ID to lines connect`);if(n===`telegram`)throw Error(`Telegram uses an owned bot, not phone inventory`);j(await el(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)=>rl(async()=>{tl(t);let n=nl(t.transport);if(n!==`email`&&t.address)throw Error(`--address is email-only`);if((n===`email`||n===`telegram`)&&t.numberId)throw Error(`${n} does not take --number-id`);let r={connectionId:e,label:t.label,clientReference:t.reference},i;if(n===`email`)i={...r,transport:n,address:t.address};else if(n===`telegram`)i={...r,transport:n};else if(n===`imessage`)i={...r,transport:n,phoneNumberId:t.numberId};else{if(!t.numberId)throw Error(`${n} requires --number-id`);i={...r,transport:n,phoneNumberId:t.numberId}}j(await el(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)=>rl(async()=>{tl(t);let n=el(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 il(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(lr()).hostname],includeImplicitDomains:!1}}:{}}}}}}if(typeof r.sandboxId==`string`==(r.instance!==void 0))throw Error(`Attachment requires exactly one of sandboxId and instance`);let{sandboxId:i,instance:a,...o}=r,s;if(i){let t=await n.get(i);if(!t)throw Error(`Sandbox not found`);s=await t.lines.attach({...o,number:e})}else{if(!a)throw Error(`Attachment requires an instance`);s=await n.lines.attach({...o,number:e,instance:a})}j(s)}));for(let t of[`detach`,`release`])e.command(t).argument(`<line-id>`).description(t===`detach`?`Stop dispatch; preserve history and provider rental`:`Retire a detached Hub line; does not cancel provider rental`).option(`--yes`,`Authorize this change`).action((e,n)=>rl(async()=>{tl(n),j({[t]:await el(n).lines[t](e)})}));e.command(`threads`).argument(`<line-id>`).description(`List this line's separate participant threads`).action((e,t)=>rl(async()=>{j(await el(t).lines.threads(e).list())})),e.command(`messages`).argument(`<line-id>`).argument(`<thread-id>`).description(`Read one authorized participant thread`).action((e,t,n)=>rl(async()=>{j(await el(n).lines.threads(e).messages(t))}))}async function ol(e){let{token:t,baseUrl:n}=Wn();if(t===void 0)return W(e);if(!t.startsWith(`lrc_`)||!n)throw Error(`The line box needs TANGLE_LINE_TOKEN and TANGLE_HUB_URL`);if(e.apiKey||e.baseUrl&&new URL(e.baseUrl).origin!==new URL(n).origin)throw Error(`A line token cannot be sent to another Hub or combined with an API key`);return new ke({baseUrl:n,authHeaders:()=>({Authorization:`Bearer ${t}`})})}async function sl(e,t){if(t)return t;if(!Wn().token)throw Error(`Provide --line <line-id>`);return(await e.lines.context()).line.id}function cl(e){return e().catch(R)}function ll(){return new b(`context`).description(`Show live line identity, members, consent, reminders and quotas`).action(e=>cl(async()=>{j(await(await ol(e)).lines.context())}))}function ul(){let e=new b(`lines`).description(`Connect, manage, message and schedule on a Hub line`);return e.command(`members`).description(`List names, roles and consent on this line`).option(`--line <line-id>`,`Line ID; inferred in a line box`).action(e=>cl(async()=>{let t=await ol(e);j(await t.lines.members.list(await sl(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)=>cl(async()=>{let r=await ol(n),i=await sl(r,n.line);if(!Wn().token){if(n.onBehalfOf)throw Error(`--on-behalf-of is only available inside a line box`);if(!n.idempotencyKey)throw Error(`Owner sends require --idempotency-key so a retry keeps the same message`);if(!(await r.lines.members.list(i)).some(t=>t.id===e))throw Error(`Owner sends require an exact member ID from tangle lines members`);j(await r.lines.send(i,{memberId:e,text:t,idempotencyKey:n.idempotencyKey,...n.notBefore?{notBefore:n.notBefore}:{}}));return}j(await r.lines.send(i,{toMember:e,text:t,...n.onBehalfOf?{onBehalfOf:n.onBehalfOf}:{},...n.notBefore?{notBefore:n.notBefore}:{},...n.idempotencyKey?{idempotencyKey:n.idempotencyKey}:{}}))})),e.command(`remind`).description(`Wake the agent at a future time to write your reminder`).argument(`<text>`,`What to remember`).requiredOption(`--at <iso-time>`,`Future ISO time`).option(`--line <line-id>`,`Line ID; inferred in a line box`).option(`--idempotency-key <key>`,`Stable key for a retry`).action((e,t)=>cl(async()=>{if(!t.at)throw Error(`--at is required`);let n=await ol(t),r=t.idempotencyKey??x(`sha256`).update(JSON.stringify([e,t.at])).digest(`hex`).slice(0,32);j(await n.lines.remind(await sl(n,t.line),{text:e,notBefore:t.at,idempotencyKey:r}))})),al(e),e}function dl(){let e=new b(`mcp`).description(`Model Context Protocol bridge commands.`);return e.command(`serve <id-or-name>`).description(`Run a local MCP server (stdio) backed by the given sandbox (ID or name). Pipe its stdio from an MCP client config to expose sandbox tools.`).option(`-s, --session <id>`,`Session id for kernel scoping`,`mcp-local`).option(`--name <name>`,`MCP server name reported to clients`,`tangle-sandbox`).action(async(e,t)=>{let n=V({apiKey:t.apiKey,baseUrl:t.baseUrl}),r=await G(H(n),n,e),i;try{i=(await import(`@modelcontextprotocol/sdk/server/stdio.js`)).StdioServerTransport}catch{throw Error("`@modelcontextprotocol/sdk` is not installed in this environment. Install it with: pnpm add -g @modelcontextprotocol/sdk (or as a dev dep in the project running this command).")}let{connect:a,close:o}=await $e(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 fl(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=Pn(),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??er():t.apiKey;if(t.self&&!a)throw Error(`Self preview access requires the injected sandbox runtime credential; it never reads saved owner credentials`);let o=V({apiKey:a,baseUrl:r}),s=H(o);return t.self?nt(s):G(s,o,e)}async function pl(e,t,n){let r=P(e);t||r.start();try{return await n()}finally{r.stop()}}function ml(e){return e}function hl(){let e=new b(`preview`).description(`Manage sandbox preview links`);return ml(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 fl(e,t),r=await pl(`Starting managed preview...`,t.json,()=>et(n,{cwd:t.cwd,sessionId:t.session,name:t.name}));t.json?j(r):(M(`Preview ready: ${r.url}`),console.log(`Preview ID: ${r.previewId}`))}),ml(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 fl(e,t),r=await pl(`Fetching preview links...`,t.json,()=>n.previewLinks.list());t.json?j(r):r.length===0?console.log(`No preview links found`):Rt([`App`,`Preview ID`,`Port`,`URL`,`Status`],r.map(e=>[gl(e.metadata),e.previewId.slice(0,12),String(e.port),e.url,e.status]))}),ml(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 fl(e,t),r=await pl(`Publishing service...`,t.json,()=>tt(n,{port:Number(t.port),name:t.name}));t.json?j(r):M(`Preview ready: ${r.url}`)}),ml(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 fl(e,n),i=await pl(`Creating preview for port ${t}...`,n.json,()=>r.previewLinks.create(Number(t)));n.json?j(i):(M(`Preview created: ${i.url}`),console.log(`Preview ID: ${i.previewId}`))}),ml(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 fl(e,n);await pl(`Removing preview...`,n.json,()=>r.previewLinks.remove(t)),n.json?j({success:!0,previewId:t}):M(`Preview removed: ${t}`)}),e}function gl(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 _l(){let e=new b(`process`).description(`Manage processes in a sandbox`);return e.command(`spawn`).description(`Spawn a process without blocking (returns PID)`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<command>`,`Command to execute`).option(`--cwd <dir>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`-t, --timeout <ms>`,`Timeout in milliseconds`).option(`--blocking`,`Wait for completion (default: false)`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a={};if(n.env)for(let e of n.env){let[t,...n]=e.split(`=`);t&&n.length>0&&(a[t]=n.join(`=`))}let o=P(`Spawning: ${t}`);n.json||o.start();let s=await G(i,r,e);if(s=await K(s),n.blocking){let e=await s.exec(t,{cwd:n.cwd,env:Object.keys(a).length>0?a:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});o.stop(),n.json?j(e):(e.stdout&&globalThis.process.stdout.write(e.stdout),e.stderr&&globalThis.process.stderr.write(e.stderr),e.exitCode!==0&&globalThis.process.exit(e.exitCode))}else{let r=await s.process.spawn(t,{cwd:n.cwd,env:Object.keys(a).length>0?a:void 0,timeoutMs:n.timeout?Number.parseInt(n.timeout,10):void 0});o.stop(),n.json?j({pid:r.pid,command:r.command}):(console.log(`Process started with PID: ${r.pid}`),console.log(`Use 'tangle process logs ${e} ${r.pid}' to view output`))}}),e.command(`list`).alias(`ls`).description(`List all processes in a sandbox`).argument(`<id-or-name>`,`Sandbox ID or name`).option(`--running`,`Show only running processes`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching processes...`);t.json||i.start();let a=await G(r,n,e);a=await K(a);let o=await a.process.list();t.running&&(o=o.filter(e=>e.running)),i.stop(),t.json?j(o):o.length===0?console.log(`No processes found`):Rt([`PID`,`Command`,`Status`,`Exit Code`,`Started`],o.map(e=>[String(e.pid),e.command.length>40?`${e.command.slice(0,37)}...`:e.command,e.running?`running`:`exited`,String(e.exitCode),e.startedAt.toLocaleString()]))}),e.command(`get`).description(`Get detailed info about a process`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Fetching process info...`);n.json||a.start();let o=await G(i,r,e);o=await K(o);let s=await o.process.get(Number.parseInt(t,10));if(a.stop(),!s){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}let c=await s.status();n.json?j(c):(console.log(`PID: ${c.pid}`),console.log(`Command: ${c.command}`),console.log(`CWD: ${c.cwd||`(default)`}`),console.log(`Status: ${c.running?`running`:`exited`}`),console.log(`Exit Code: ${c.exitCode}`),c.exitSignal&&console.log(`Signal: ${c.exitSignal}`),console.log(`Started: ${c.startedAt.toLocaleString()}`),c.exitedAt&&console.log(`Exited: ${c.exitedAt.toLocaleString()}`))}),e.command(`kill`).description(`Kill a process`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).option(`-s, --signal <signal>`,`Signal to send (SIGTERM, SIGKILL, etc.)`,`SIGTERM`).option(`--tree`,`Also kill descendants of the tracked process`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Sending ${n.signal} to PID ${t}...`);n.json||a.start();let o=await G(i,r,e);o=await K(o);let s=await o.process.get(Number.parseInt(t,10));if(!s){a.stop(),console.error(`Process ${t} not found`),globalThis.process.exit(1);return}n.tree?await s.kill(n.signal,{tree:!0}):await s.kill(n.signal),a.stop(),n.json?j({pid:Number.parseInt(t,10),signal:n.signal,...n.tree===!0?{tree:!0}:{},killed:!0}):console.log(n.tree?`Sent ${n.signal} to process tree ${t}`:`Sent ${n.signal} to process ${t}`)}),e.command(`logs`).description(`Stream buffered and live process logs until the process exits`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pid>`,`Process ID`).option(`--stdout-only`,`Only show stdout`).option(`--stderr-only`,`Only show stderr`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=await G(i,r,e);a=await K(a);let o=await a.process.get(Number.parseInt(t,10));if(!o){console.error(`Process ${t} not found`),globalThis.process.exit(1);return}for await(let e of o.logs())n.stdoutOnly&&e.type!==`stdout`||n.stderrOnly&&e.type!==`stderr`||(n.json?console.log(JSON.stringify(e)):e.type===`stdout`?globalThis.process.stdout.write(e.data):globalThis.process.stderr.write(e.data))}),e}const vl=[`python`,`node`,`typescript`,`bash`];function yl(e){switch(_e(e).toLowerCase()){case`.py`:return`python`;case`.js`:case`.mjs`:case`.cjs`:return`node`;case`.ts`:case`.tsx`:return`typescript`;case`.sh`:case`.bash`:return`bash`;default:return}}async function bl(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(be(e),`utf8`)}async function xl(e,t,n=bl){let r=t?vl.find(e=>e===t)??(()=>{throw Error(`unknown --lang ${t}: must be one of ${vl.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=yl(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 Sl(e){return D(we(),`tangle-run-images`,e)}function Cl(){return new b(`run`).description(`Run code in a persistent kernel inside a sandbox. Variables persist across calls in the same --session.`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`[file]`,`Path to source file. Language is inferred from extension. Use - for stdin (requires --lang).`).option(`-l, --lang <lang>`,`Force language: ${vl.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 xl(t,n.lang),{context:a,client:o}=U(n),s=await G(o,a,e);s=await K(s);let c=P(`Running ${r} (${i.length}b)…`);n.json||c.start();let l=await s.runCode(r,i,{sessionId:n.session,timeoutMs:Number.parseInt(n.timeout,10)});if(c.stop(),n.json){j(l),l.exitCode!==0&&process.exit(l.exitCode);return}l.stdout&&process.stdout.write(l.stdout),l.stderr&&process.stderr.write(l.stderr);let u=0;for(let t of l.results)if(t.type===`image`)if(n.saveImages!==!1){let r=typeof n.saveImages==`string`?n.saveImages:Sl(e);fe(r,{recursive:!0});let i=`${r}/${Date.now()}-${u}.${t.format}`;me(i,Buffer.from(t.data,`base64`)),process.stderr.write(y.green(`✓ image → ${i}\n`)),u++}else process.stderr.write(y.gray(`[image: ${t.format}, ${t.data.length}b base64]\n`));else if(t.type===`dataframe`){let e=t.columns.map(e=>`${e.name}:${e.dtype}`).join(` | `);process.stderr.write(y.gray(`[dataframe ${t.rows.length}×${t.columns.length}${t.truncated?` (truncated)`:``}]\n`)),process.stderr.write(`${e}\n`);for(let e of t.rows.slice(0,20))process.stderr.write(`${e.map(e=>String(e)).join(` | `)}\n`);t.rows.length>20&&process.stderr.write(y.gray(`… ${t.rows.length-20} more rows\n`))}else t.type===`json`?(process.stderr.write(y.gray(`[json] `)),process.stderr.write(`${JSON.stringify(t.value,null,2)}\n`)):t.type===`html`?process.stderr.write(y.gray(`[html ${t.value.length}b]\n`)):t.type===`error`?(process.stderr.write(y.red(`✗ ${t.name}: ${t.message}\n`)),t.traceback&&process.stderr.write(`${t.traceback}\n`)):t.type===`text`&&process.stderr.write(`${t.value}\n`);l.error&&(process.stderr.write(y.red(`\n✗ ${l.error.name}: ${l.error.message}\n`)),l.error.traceback&&process.stderr.write(`${l.error.traceback}\n`)),l.exitCode!==0&&process.exit(l.exitCode)})}async function wl(e,t){let n=await Rr({apiKey:t.apiKey,baseUrl:t.baseUrl??lr()}),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 Tl(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 El(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 Dl(e){if(e!==void 0)return e.map(e=>{let t=e.indexOf(`@`);if(t===-1)return e;let n=e.slice(0,t),r=e.slice(t+1),i=r.indexOf(`:`),a=i===-1?r:r.slice(0,i),o=i===-1?void 0:r.slice(i+1);if(!n||!a||o===``)throw Error(`--secret ${e}: expected NAME, NAME@host or NAME@host:Header`);return o===void 0?{name:n,host:a}:{name:n,host:a,header:o}})}function Ol(e,t){let n={};return e.cpu!==void 0&&(n.cpuCores=$o(e.cpu,`--cpu`)),e.memory!==void 0&&(n.memoryMB=$o(e.memory,`--memory`)),e.disk!==void 0&&(n.diskGB=$o(e.disk,`--disk`)),t&&(n.accelerator=t),Object.keys(n).length>0?n:void 0}function kl(e){let t=e.split(`/`);return t.length>=2?{provider:t[0],model:t.slice(1).join(`/`)}:{model:e}}function Al(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]=jl(r.join(`=`))}return t}function jl(e){try{return JSON.parse(e)}catch{return e}}function Ml(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`?$o(e.gitDepth,`--git-depth`):void 0,sparse:Array.isArray(e.gitSparse)?e.gitSparse:void 0,auth:t?{token:t}:void 0}}}function Nl(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:Pl(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 Pl(e){if(e===`s3`||e===`gcs`||e===`r2`)return e;throw Error(`--storage-type must be one of s3, gcs, or r2`)}function Fl(e){N(` Status: ${e.status}`),N(` Provider: ${e.provider}`),N(` GPU: ${e.accelerator.kind} x ${e.accelerator.count}`),e.customerPricePerHourUsd!==void 0&&N(` Customer price: $${e.customerPricePerHourUsd}/hr`),e.estimatedCustomerCostUsd!==void 0&&N(` Max estimate: $${e.estimatedCustomerCostUsd}`),e.billing&&(N(` Billed seconds: ${e.billing.seconds}`),N(` Customer cost: $${e.billing.customerCostUsd}`))}function Il(e){e.result.stdout&&process.stdout.write(e.result.stdout),e.result.stderr&&process.stderr.write(e.result.stderr),N(`Exit code: ${e.result.exitCode}`)}function Ll(e){let t=e.command(`gpu`).description(`Manage on-demand GPU leases for a sandbox`);t.command(`providers <id-or-name>`).description(`List GPU clouds, whether each credential works, and current prices`).option(`--accelerator-kind <kind>`,`Price this GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`).option(`--accelerator-memory <mb>`,`Minimum GPU memory in MB`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Checking GPU providers...`);i.start();let a=await(await G(r,n,e)).gpu.providers(t.acceleratorKind?{accelerator:Yo({kind:t.acceleratorKind,count:t.acceleratorCount,memory:t.acceleratorMemory})}:{});if(i.stop(),t.json){j(a);return}A(a.statuses.map(e=>({provider:e.provider,state:e.state,gpu:e.estimate?.providerInstanceType??``,usdHr:e.estimate?e.estimate.customerPricePerHourUsd.toFixed(4):``,pricing:e.estimate?.pricingSource??``,needs:e.envVars.join(` `)})),[{key:`provider`,header:`Provider`},{key:`state`,header:`State`},{key:`gpu`,header:`GPU`},{key:`usdHr`,header:`$/hr`},{key:`pricing`,header:`Price`},{key:`needs`,header:`Needs`}]);for(let e of a.statuses){let t=e.state===`credential-invalid`?e.credential?.detail:e.estimateError;t&&N(`${e.provider}: ${t}`)}a.usable.length===0&&N(`No GPU provider is usable on this deployment: set the variables in Needs for one provider on the server.`)}),t.command(`attach <id-or-name>`).description(`Attach a temporary GPU worker to a sandbox`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <mb>`,`Minimum GPU memory in MB`).option(`--provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--image <image>`,`GPU worker image override`).option(`--env <vars...>`,`Environment variables for the GPU worker (KEY=VALUE)`).requiredOption(`--max-spend-usd <usd>`,`Maximum customer spend for this lease`).requiredOption(`--max-lifetime <seconds>`,`Maximum lease lifetime in seconds`).option(`--idle-timeout <seconds>`,`Destroy after this many idle seconds`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Attaching GPU lease...`);i.start();let a=await(await G(r,n,e)).gpu.attach(Zo(t));i.stop(),t.json?j(a):(M(`GPU lease attached: ${a.id}`),Fl(a))}),t.command(`run <id-or-name> <command...>`).description(`Attach a temporary GPU, run a command, then destroy it`).requiredOption(`--accelerator-kind <kind>`,`GPU kind, for example nvidia-h100`).option(`--accelerator-count <count>`,`GPU device count`,`1`).option(`--accelerator-memory <mb>`,`Minimum GPU memory in MB`).option(`--provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--image <image>`,`GPU worker image override`).option(`--env <vars...>`,`Environment variables for the GPU worker and command (KEY=VALUE)`).requiredOption(`--max-spend-usd <usd>`,`Maximum customer spend for this lease`).requiredOption(`--max-lifetime <seconds>`,`Maximum lease lifetime in seconds`).option(`--idle-timeout <seconds>`,`Destroy after this many idle seconds`).option(`--timeout <ms>`,`Command timeout in milliseconds`).option(`--cwd <path>`,`Working directory`).action(async(e,t,n)=>{let r,i,a,o;try{let{context:a,client:o}=U(n),s=await G(o,a,e),c=P(`Attaching GPU lease...`);c.start(),r=await s.gpu.attach(Zo(n)),c.stop();let l=P(`Running GPU command...`);l.start(),i=await s.gpu.exec(r.id,{command:t.join(` `),timeoutMs:n.timeout?$o(String(n.timeout),`--timeout`):void 0,cwd:n.cwd,env:n.env?Qo(n.env,`--env`,`env`):void 0}),l.stop(),n.json||Il(i)}catch(e){a=e}finally{if(r)try{let{context:t,client:i}=U(n);r=await(await G(i,t,e)).gpu.detach(r.id)}catch(e){o=e}}if(a){R(a),o&&R(o);return}if(o){R(o);return}n.json?j({lease:r,result:i}):r&&M(`GPU lease detached: ${r.id}`);let s=i?.result.exitCode;s&&s!==0&&(process.exitCode=s)}),t.command(`list <id-or-name>`).description(`List GPU leases attached to a sandbox`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching GPU leases...`);i.start();let a=await(await G(r,n,e)).gpu.list();i.stop(),t.json?j(a):a.length===0?N(`No GPU leases attached.`):A(a.map(e=>({id:e.id,status:e.status,provider:e.provider,accelerator:`${e.accelerator.kind}x${e.accelerator.count}`,customerUsdHr:e.customerPricePerHourUsd??``})),[{key:`id`,header:`ID`,width:28},{key:`status`,header:`Status`,width:12},{key:`provider`,header:`Provider`,width:12},{key:`accelerator`,header:`GPU`,width:24},{key:`customerUsdHr`,header:`$/hr`,width:10}])}),t.command(`exec <id-or-name> <lease-id> <command...>`).description(`Run a command on an attached GPU lease`).option(`--timeout <ms>`,`Command timeout in milliseconds`).option(`--cwd <path>`,`Working directory`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).action(async(e,t,n,r)=>{let{context:i,client:a}=U(r),o=P(`Running GPU command...`);o.start();let s=await(await G(a,i,e)).gpu.exec(t,{command:n.join(` `),timeoutMs:r.timeout?$o(String(r.timeout),`--timeout`):void 0,cwd:r.cwd,env:r.env?Qo(r.env,`--env`,`env`):void 0});o.stop(),r.json?j(s):Il(s)}),t.command(`detach <id-or-name> <lease-id>`).description(`Detach and destroy a GPU lease`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Detaching GPU lease...`);a.start();let o=await(await G(i,r,e)).gpu.detach(t);a.stop(),n.json?j(o):(M(`GPU lease detached: ${o.id}`),Fl(o))})}function Rl(e,t){if(t){j(e);return}if(!e.id){e.kind===`snapshot`&&e.result?.snapshot?M(`Snapshot created: ${e.result.snapshot.snapshotId}`):M(`Sandbox ${e.sandboxId} stopped.`);return}M(`${e.kind===`snapshot`?`Snapshot`:`Stop`} of sandbox ${e.sandboxId} accepted.`),N(`Operation: ${e.id}`),N(`Status: ${e.statusUrl}`)}function zl(e){return`${e.name} (${e.id})`}async function Bl(e,t){if(t.startsWith(`team_`))return e.teams.get(t);let n=(await e.teams.list()).filter(e=>e.name.toLowerCase()===t.toLowerCase());if(n.length===0)throw Error(`Team not found: ${t}`);if(n.length>1)throw Error(`Team name is ambiguous: ${t}. Use a team id instead.`);return n[0]}async function X(e,t,n){if(t)return Bl(e,t);let r=fr(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 Vl(e,t){pr({id:e.id,name:e.name},t)}function Hl(e){mr(e)}async function Ul(e){if(e.explicitTeam&&e.personal)throw Error(`--team and --personal cannot be used together`);if(!e.personal)return e.explicitTeam?(await Bl(e.client,e.explicitTeam)).id:e.activeTeamId}async function Wl(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 Bl(e.client,e.explicitTeam)).id}`;if(e.activeTeamId)return`team:${e.activeTeamId}`}function Gl(e){return!e||e.authToken===void 0?e:{...e,authToken:`[REDACTED]`}}function Kl(e){e.command(`attestation <id-or-name>`).description(`Fetch TEE attestation evidence for a sandbox`).option(`--nonce <hex|auto>`,`Nonce to bind into a fresh attestation report; use auto to generate one`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=t.nonce===`auto`?ee():t.nonce,a=P(`Fetching TEE attestation...`);a.start();let o=await(await G(r,n,e)).getTeeAttestation(i?{attestationNonce:i}:void 0);a.stop(),t.json?j(o):(M(`Attestation fetched for ${e}`),console.log(`TEE type: ${o.attestation.tee_type}`),console.log(`Evidence bytes: ${o.attestation.evidence.length}`),console.log(`Measurement bytes: ${o.attestation.measurement.length}`),console.log(`Timestamp: ${o.attestation.timestamp}`),o.attestationNonce&&console.log(`Nonce: ${o.attestationNonce}`))}),e.command(`list`).description(`List all sandboxes`).option(`-s, --status <status>`,`Filter by status (running, stopped, all)`).option(`-l, --limit <n>`,`Limit results`,`50`).option(`--team <team>`,`List sandboxes for a team by id or name`).option(`--personal`,`List personal sandboxes`).option(`--all-scopes`,`List personal and team sandboxes`).action(async e=>{let{context:t,client:n}=U(e),r=P(`Fetching sandboxes...`);r.start();let i=await Wl({client:n,explicitTeam:e.team,personal:e.personal,allScopes:e.allScopes,activeTeamId:t.activeTeamId}),a=await n.list({status:e.status===`all`?void 0:e.status,limit:Number.parseInt(e.limit,10),scope:i});r.stop(),e.json?j(a):A(a.map(e=>({id:e.id,status:e.status,createdAt:e.createdAt,name:e.name??``})),[{key:`id`,header:`ID`,width:24},{key:`status`,header:`Status`,width:14},{key:`createdAt`,header:`Created`,width:16},{key:`name`,header:`Name`,width:20}])}),e.command(`get <id-or-name>`).description(`Get sandbox details`).option(`--profile`,`Show the active agent profile provenance (name, hash, skills)`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching sandbox...`);i.start();let a=await G(r,n,e);if(i.stop(),t.profile){let e=a.getProfileProvenance?.();e?(N(`Agent profile provenance:`),N(` Base profile: ${e.base.name??`(inline)`} (${e.base.sha256.slice(0,12)}...)`),N(` Effective: ${e.effective.name??`(inline)`} (${e.effective.sha256.slice(0,12)}...)`),N(` Materialized: ${e.materializedAt}`),e.base.sha256!==e.effective.sha256&&N(` ⚠ Profile changed since creation (base ≠ effective)`)):N(`No profile materialized (bare sandbox). Create with --profile <name> to install one.`);return}t.json?j(a):Lt({id:a.id,name:a.name,status:a.status,resources:a.resources,createdAt:a.createdAt?.toISOString(),expiresAt:a.expiresAt?.toISOString(),connection:a.connection})}),e.command(`shapes`).description(`List the named sandbox sizes, the default, and this account's ceiling`).action(async e=>{let{client:t}=U(e),n=await t.shapes();if(e.json){j(n);return}let r=e=>e.cpuCores<=n.ceiling.cpuCores&&e.memoryMB<=n.ceiling.memoryMB&&e.diskGB<=n.ceiling.diskGB;A(n.presets.map(e=>({name:e.name===n.default?`${e.name} (default)`:e.name,cpu:e.cpuCores,memory:`${e.memoryMB} MB`,disk:`${e.diskGB} GB`,available:r(e)?`yes`:e.name===n.default?`clamped to ceiling`:`above ceiling`})),[{key:`name`,header:`Shape`,width:18},{key:`cpu`,header:`vCPU`,width:6},{key:`memory`,header:`Memory`,width:10},{key:`disk`,header:`Disk`,width:8},{key:`available`,header:`Available`,width:14}]),N(`Ceiling for this account: ${It(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`)){N(`Cancelled.`);return}let{context:n,client:r}=U(t),i=P(`Deleting sandbox...`);i.start();let a=await qr(r,n,e,{retryCleanup:t.retryCleanup,name:t.name});i.stop(),M(a===`already_absent`?`Sandbox ${e} was already gone.`:`Sandbox ${e} deleted.`)}),e.command(`stop <id-or-name>`).description(`Stop a running sandbox`).option(`--name`,`Treat the reference as a sandbox name`).option(`--no-wait`,`Return once the stop is accepted and print the operation to poll`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Stopping sandbox...`);i.start();let a=await G(r,n,e,{nameOnly:t.name});if(t.wait===!1){let e=await a.stop({wait:!1});i.stop(),Rl(e.info,!!t.json);return}await a.stop(),i.stop(),M(`Sandbox ${e} stopped.`)}),e.command(`resume <id-or-name>`).description(`Resume a stopped sandbox`).option(`--wait`,`Wait for sandbox to be running`,!0).option(`-t, --timeout <ms>`,`Resume timeout in milliseconds; a cold resume re-provisions the sandbox, so this defaults higher than other commands (default 120000)`,`120000`).action(async(e,t)=>{let n=Number.parseInt(t.timeout,10);if(!Number.isFinite(n)||n<=0)throw Error(`--timeout must be a positive number of milliseconds`);let r=V({apiKey:t.apiKey,baseUrl:t.baseUrl,timeout:n}),i=H(r),a=P(`Resuming sandbox...`);a.start();let o=await G(i,r,e);await o.resume({timeoutMs:n}),t.wait&&(a.text=`Waiting for sandbox to start...`,await o.waitFor(`running`,{timeoutMs:n})),a.stop(),M(`Sandbox ${o.id} resumed.`)})}function ql(e){e.command(`create`).description(`Create a new sandbox`).option(`-n, --name <name>`,`Sandbox name`).option(`-e, --environment <environment>`,`Named environment, container image, or built image ID`).option(`--bare`,`Create a bare sandbox without the agent runtime`).option(`--ssh`,`Enable SSH access`).option(`--ssh-key <key>`,`SSH public key for authentication`).option(`--ssh-keys <names...>`,`Stored SSH key names or IDs for authentication`).option(`--ssh-key-file <paths...>`,`SSH public key file paths for authentication`).option(`--web-terminal`,`Enable web terminal`).option(`--env <vars...>`,`Environment variables (KEY=VALUE)`).option(`--secret <names...>`,`Secrets to inject as environment variables. NAME@host keeps the value out of the sandbox and sends it to that host only (NAME@host:Header for a header other than Authorization)`).option(`--metadata <entries...>`,`Metadata entries (KEY=VALUE or KEY=JSON)`).option(`--cpu <cores>`,"CPU cores (omit for the platform default; see `sandbox shapes`)").option(`--memory <mb>`,`Memory in MB (omit for the platform default)`).option(`--disk <gb>`,`Disk size in GB (omit for the platform default)`).option(`--accelerator-kind <kind>`,`Accelerator kind, for example nvidia-h100 or amd-mi300x`).option(`--accelerator-count <count>`,`Accelerator device count`,`1`).option(`--accelerator-memory <mb>`,`Minimum accelerator memory in MB`).option(`--gpu-provider <provider>`,`GPU cloud provider; omitted picks the cheapest configured provider`).option(`--gpu-worker-image <image>`,`GPU worker image override`).option(`--gpu-env <vars...>`,`Environment variables for the GPU worker (KEY=VALUE)`).option(`--gpu-max-spend-usd <usd>`,`Maximum customer spend for the create-time GPU lease`).option(`--gpu-max-lifetime <seconds>`,`Maximum create-time GPU lease lifetime in seconds`).option(`--gpu-idle-timeout <seconds>`,`Destroy the create-time GPU lease after this many idle seconds`).option(`--lifetime <seconds>`,`Max wall-clock lifetime before the sandbox is suspended — stopped, not deleted; resume it within the cold window (default 3600 = 1h). Raise it for long sessions, e.g. --lifetime 7200`,`3600`).option(`--idle-timeout <seconds>`,"Idle time before the sandbox is stopped — not deleted (default 900 = 15m). Resume it later with `tangle sandbox resume <id-or-name>`, or it auto-resumes on next use. Raise it for demos, e.g. --idle-timeout 3600",`900`).option(`--from-snapshot <id>`,`Create the sandbox from a snapshot`).option(`--public-template <id-or-slug>`,`Create the sandbox from a published public template`).option(`--public-template-version <id>`,`Pin creation to a specific published public-template version`).option(`--billing-owner <userId>`,`Platform user that pays for the sandbox. The API accepts this only from a first-party service key that is listed as a billing delegate, and refuses such a key that names no payer.`).option(`--team <team>`,`Create in a team by id or name`).option(`--personal`,`Create a personal sandbox even when a team is active`).option(`--git-url <url>`,`Git repository URL to clone during provisioning`).option(`--git-ref <ref>`,`Git branch, tag, or commit to checkout`).option(`--git-depth <depth>`,`Git clone depth`).option(`--git-sparse <paths...>`,`Sparse checkout paths`).option(`--git-token-env <name>`,`Name of an environment variable containing the Git HTTPS auth token`).option(`--git-token-stdin`,`Read the Git HTTPS auth token from stdin`).option(`--storage-type <type>`,`BYOS3 storage type (s3, gcs, r2)`).option(`--storage-bucket <name>`,`BYOS3 bucket name`).option(`--storage-endpoint <url>`,`BYOS3 endpoint URL`).option(`--storage-region <region>`,`BYOS3 region`).option(`--storage-prefix <prefix>`,`BYOS3 path prefix`).option(`--storage-access-key-id <id>`,`BYOS3 access key ID`).option(`--storage-secret-access-key-env <name>`,`Name of an environment variable containing the BYOS3 secret access key`).option(`--storage-secret-access-key-stdin`,`Read the BYOS3 secret access key from stdin`).option(`--driver <type>`,`Infrastructure driver (docker, firecracker, host-agent, tangle)`).option(`--driver-criu`,`Enable CRIU checkpointing (firecracker only)`).option(`--driver-region <region>`,`Preferred region for host-agent driver`).option(`--backend <type>`,`Backend agent type (${n.join(`, `)})`).option(`--backend-model <model>`,`Model override (format: provider/model)`).option(`--backend-api-key-env <name>`,`Name of an environment variable containing the BYOK backend API key`).option(`--backend-api-key-stdin`,`Read the BYOK backend API key from stdin`).option(`--cli-auth <secret>`,"Run --backend claude-code or codex on your own subscription: the stored secret holding a `claude setup-token` token or a Codex auth.json (see `tangle secret create`)").option(`--profile <path>`,`Path to an AgentProfile JSON file to install as the sandbox's backend profile (carries skills, tools, MCP, model). Use with --backend; the profile's inline skills materialize into the harness's native skill directory on first turn`).option(`--profile-stdin`,`Read the AgentProfile JSON from stdin instead of a file (use with --profile)`).option(`--tee <type>`,`Require a TEE backend (any, tdx, nitro, sev-snp, phala-dstack)`).option(`--sealed`,`Request TEE sealed-secret support`).option(`--attestation-nonce <hex|auto>`,`Deploy-time attestation nonce; use auto to generate one`).option(`--attestation-refresh`,`Generate a fresh deploy-time attestation nonce when --tee is set`).option(`--require-attestation`,`Fail unless TEE attestation evidence is returned`).option(`--wait`,`Wait for sandbox to be running`,!0).option(`--timeout <ms>`,`HTTP timeout in milliseconds`,`30000`).action(async e=>{let t=await Tl({envVarName:e.gitTokenEnv,fromStdin:e.gitTokenStdin,flagPrefix:`--git-token`}),n=await Tl({envVarName:e.storageSecretAccessKeyEnv,fromStdin:e.storageSecretAccessKeyStdin,flagPrefix:`--storage-secret-access-key`}),r=await Tl({envVarName:e.backendApiKeyEnv,fromStdin:e.backendApiKeyStdin,flagPrefix:`--backend-api-key`}),i=El({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{R(Error(`--profile-stdin: the input is not valid JSON`));return}}else if(e.profile){let t=String(e.profile);if(t.startsWith(`.`)||t.startsWith(`/`)||t.endsWith(`.json`))try{a=JSON.parse(T(t,`utf8`))}catch(e){R(Error(`--profile ${t}: ${e.message}`));return}else try{a=await wl(t,e)}catch(e){R(Error(`--profile ${t}: ${e.message}`));return}}let o=V({apiKey:e.apiKey,baseUrl:e.baseUrl,timeout:e.timeout?Number.parseInt(e.timeout,10):void 0}),s=H(o),c=P(`Creating sandbox...`);c.start();let l=await Ul({client:s,explicitTeam:e.team,personal:e.personal,activeTeamId:o.activeTeamId}),u={};if(e.env)for(let t of e.env){let[e,...n]=t.split(`=`);e&&n.length>0&&(u[e]=n.join(`=`))}let d=e.metadata?Al(e.metadata):void 0,f=Ml(e,t),p=Nl(e,n),m=e.acceleratorKind?Yo({kind:String(e.acceleratorKind),count:String(e.acceleratorCount),memory:typeof e.acceleratorMemory==`string`?e.acceleratorMemory:void 0}):void 0,h=Xo({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`),g=e.driver?{type:e.driver,enableCriu:e.driverCriu||void 0,preferredRegion:e.driverRegion}:void 0,ee=e.backend||e.backendModel||a?{...e.backend?{type:te(e.backend)}:{},...a?{profile:a}:{},model:e.backendModel||r||i?{...e.backendModel?kl(e.backendModel):{},apiKey:r,...i?{cliAuth:i}:{}}:void 0}:void 0,v=Dl(e.secret),ne=i?[...new Set([...v??[],i.secretEnv])]:v,y=Ol(e,m),re=[...e.sshKey?[e.sshKey]:[],...(e.sshKeyFile??[]).map(e=>T(e,`utf8`).trim())],b={name:e.name,environment:e.environment,bare:e.bare||void 0,sshEnabled:e.ssh||!!e.sshKey||re.length>0||!!e.sshKeys?.length,sshPublicKeys:re.length>0?re:void 0,sshKeyIds:e.sshKeys,webTerminalEnabled:e.webTerminal,env:Object.keys(u).length>0?u:void 0,git:f,...y?{resources:y}:{},gpuLease:h,maxLifetimeSeconds:Number.parseInt(e.lifetime,10),idleTimeoutSeconds:Number.parseInt(e.idleTimeout,10),storage:p,fromSnapshot:e.fromSnapshot,publicTemplateId:e.publicTemplate,publicTemplateVersionId:e.publicTemplateVersion,teamId:l,...e.billingOwner?{billingOwnerId:e.billingOwner}:{},secrets:ne,metadata:d,driver:g,backend:ee},x=e.tee?{tee:e.tee,sealed:e.sealed||void 0,attestationRefresh:e.attestationRefresh||e.attestationNonce===`auto`||void 0}:void 0,S=x?await _(s,{...b,confidential:x,attestationNonce:e.attestationNonce??(e.attestationRefresh?`auto`:void 0),requireAttestation:e.requireAttestation??!0}):void 0,C=S?.sandbox??await s.create(b);e.wait&&(c.text=`Waiting for sandbox to start...`,await C.waitFor(`running`,{timeoutMs:12e4}),await C.refresh()),c.stop(),e.json?j({id:C.id,name:C.name,status:C.status,resources:C.resources,createdAt:C.createdAt,expiresAt:C.expiresAt,connection:Gl(C.connection),teamId:l,gpuLease:C.gpuLease,confidential:x,attestation:S?.attestation,attestationNonce:S?.attestationNonce}):(M(`Sandbox created: ${C.id}`),Lt({id:C.id,name:C.name,status:C.status,resources:C.resources,createdAt:C.createdAt?.toISOString(),expiresAt:C.expiresAt?.toISOString(),connection:C.connection}),l&&console.log(`Team: ${l}`),C.gpuLease&&(console.log(`GPU lease: ${C.gpuLease.id}`),Fl(C.gpuLease)),x&&(console.log(`TEE: ${x.tee}`),console.log(`Attestation: ${S?.attestation?`present`:`not returned`}`),S?.attestationNonce&&console.log(`Attestation nonce: ${S.attestationNonce}`)))})}function Jl(e){e.command(`network <id-or-name>`).description(`Show runtime network state (exposed ports) for a sandbox. Outbound policy is not settable here — see the outbound flags.`).option(`--block-outbound`,`Unenforceable; the server rejects it. Block outbound traffic with an egress policy of mode "blocked"`).option(`--allow-list <cidrs>`,`Unenforceable; the server rejects it. Egress policy allowlists domains, not CIDRs`).option(`--clear`,`Unenforceable; the server rejects it. There is no per-sandbox outbound restriction here to clear`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Updating network configuration...`);i.start();let a=await G(r,n,e);if(t.clear)await a.network.update({blockOutbound:!1,allowList:[]});else if(t.blockOutbound)await a.network.update({blockOutbound:!0});else if(t.allowList){let e=t.allowList.split(`,`).map(e=>e.trim());await a.network.update({allowList:e})}else{i.stop();let e=await a.network.getConfig();t.json?j(e):(N(`Network Configuration:`),e.ports&&e.ports.length>0?N(` Exposed Ports: ${e.ports.join(`, `)}`):N(` No exposed ports`));return}i.stop();let o=await a.network.getConfig();t.json?j(o):(M(`Network configuration updated.`),o.ports&&o.ports.length>0&&N(` Exposed Ports: ${o.ports.join(`, `)}`))}),e.command(`expose <id-or-name>`).description(`Expose a port and get a public URL`).option(`-p, --port <port>`,`Port to expose`,`8000`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=Number.parseInt(t.port,10);if(Number.isNaN(i)||i<1||i>65535)throw Error(`Port must be a number between 1 and 65535`);let a=P(`Exposing port ${i}...`);a.start();let o=await(await G(r,n,e)).network.exposePort(i);a.stop(),t.json?j({port:i,url:o}):(M(`Port ${i} exposed.`),N(` URL: ${o}`))}),e.command(`urls <id-or-name>`).description(`List exposed port URLs for a sandbox`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching exposed URLs...`);i.start();let a=await(await G(r,n,e)).network.listUrls();if(i.stop(),t.json)j(a);else{let e=Object.entries(a);if(e.length===0)N(`No ports exposed.`);else{N(`Exposed Ports:`);for(let[t,n]of e)N(` ${t}: ${n}`)}}})}function Yl(){let e=new b(`sandbox`).description(`Manage sandboxes`);return ql(e),Kl(e),Ll(e),Jl(e),e}function Xl(){return new b(`search`).description(`Search for text patterns in sandbox files (ripgrep)`).argument(`<id-or-name>`,`Sandbox ID or name`).argument(`<pattern>`,`Search pattern (regex)`).option(`-g, --glob <pattern>`,`File glob filter (e.g. '**/*.ts')`).option(`-n, --max-results <count>`,`Max results to return`).option(`-i, --ignore-case`,`Case-insensitive search`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Searching...`);n.json||a.start();let o=await G(i,r,e),s=0,c=n.maxResults?Number.parseInt(n.maxResults,10):void 0,l={};n.glob&&(l.glob=n.glob),n.ignoreCase&&(l.ignoreCase=!0),c&&(l.maxResults=c);for await(let e of o.search(t,l))if(s===0&&a.stop(),s++,n.json?console.log(JSON.stringify(e)):console.log(`${e.path}:${e.line}:${e.column??0}: ${e.text}`),c&&s>=c)break;a.stop(),s===0&&!n.json&&console.log(`No matches found`)})}function Zl(){let e=new b(`secret`).description(`Manage secrets`);return e.command(`create`).description(`Create a new secret`).argument(`<name>`,`Secret name (e.g., HF_TOKEN, AWS_ACCESS_KEY)`).argument(`[value]`,`Secret value`).option(`--value-stdin`,`Read secret value from stdin`).option(`--from-login <harness>`,`Authorize Claude in its native browser and store its token privately`).action(async(e,t,n)=>{if(n.fromLogin!==void 0&&(n.fromLogin!==`claude`||t!==void 0||n.valueStdin))throw new I(`NATIVE_CREDENTIAL_ARGUMENTS`,`Native enrollment arguments are invalid`,`Use --from-login claude without a value argument or --value-stdin`,`tangle secret create --help`);let r=U(n).client,i=n.fromLogin===void 0?await r.secrets.create(e,await Ql({value:t,valueStdin:n.valueStdin,prompt:`Enter value for secret '${e}': `})):await Ts(r,e);n.json?j(i):(M(`Secret created: ${i.name}`),N(`Use --secrets ${i.name} when creating a sandbox to inject it as an environment variable.`))}),e.command(`list`).description(`List all secrets`).action(async e=>{let t=await U(e).client.secrets.list();e.json?j(t):t.length===0?(N(`No secrets found.`),N(`Use 'tangle secret create <name> [value]' to create one.`)):Rt([`Name`,`Created At`,`Updated At`],t.map(e=>[e.name,e.createdAt.toLocaleString(),e.updatedAt.toLocaleString()]))}),e.command(`delete`).description(`Delete a secret`).argument(`<name>`,`Secret name`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=U(t).client;if(!t.force&&!await ei(`Are you sure you want to delete secret '${e}'? This cannot be undone. (y/N) `,`--force`)){N(`Cancelled.`);return}await n.secrets.delete(e),t.json?j({success:!0,deleted:e}):M(`Secret deleted: ${e}`)}),e}async function Ql(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 $l(){let e=new b(`skill`).description(`Print paths to shipped skill documentation`);return e.command(`path`).description(`Print the absolute path to the SKILL.md shipped with this CLI`).action(()=>{let e=E.dirname(rt(import.meta.url)),t=E.resolve(e,`..`,`SKILL.md`);console.log(t)}),e}function eu(){let e=new b(`snapshot`).description(`Manage snapshots`);return e.command(`create <sandbox-id-or-name>`).description(`Create a snapshot of a sandbox`).option(`--tags <tags...>`,`Tags for the snapshot`).option(`--no-wait`,`Return once the snapshot is accepted and print the operation to poll`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Creating snapshot...`);i.start();let a=await G(r,n,e);if(t.wait===!1){let e=await a.snapshot({tags:t.tags,wait:!1});i.stop(),Rl(e.info,!!t.json);return}let o=await a.snapshot({tags:t.tags});i.stop(),t.json?j(o):(M(`Snapshot created: ${o.snapshotId}`),console.log(`Size: ${tu(o.sizeBytes??0)}`))}),e.command(`list <sandbox-id-or-name>`).description(`List snapshots for a sandbox`).action(async(e,t)=>{let{context:n,client:r}=U(t),i=P(`Fetching snapshots...`);i.start();let a=await(await G(r,n,e)).listSnapshots();i.stop(),t.json?j(a):A(a.map(e=>({...e,size:tu(e.sizeBytes??0)})),[{key:`snapshotId`,header:`ID`,width:24},{key:`createdAt`,header:`Created`,width:16},{key:`size`,header:`Size`,width:12},{key:`sandboxId`,header:`Sandbox`,width:20}])}),e.command(`restore <sandbox-id> <snapshot-id>`).description(`Create a new sandbox from a snapshot`).option(`--billing-owner <userId>`,`Platform user that pays for the restored sandbox. The API accepts this only from a first-party service key that is listed as a billing delegate, and refuses such a key that names no payer.`).action(async(e,t,n)=>{let{client:r}=U(n),i=P(`Restoring from snapshot...`);i.start();let a=await r.create({fromSnapshot:t,fromSandboxId:e,...n.billingOwner?{billingOwnerId:n.billingOwner}:{}});await a.waitFor(`running`,{timeoutMs:12e4}),i.stop(),n.json?j({sandboxId:a.id,restoredFrom:t,status:a.status}):(M(`New sandbox created: ${a.id}`),console.log(`Source snapshot: ${t}`))}),e.command(`revert <sandbox-id-or-name> <snapshot-id>`).description(`Revert an existing sandbox to a snapshot`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Reverting sandbox to snapshot...`);a.start();let o=await G(i,r,e),s=await o.revertToSnapshot(t);await o.refresh(),a.stop(),n.json?j({sandboxId:o.id,snapshotId:s.snapshotId,status:o.status}):(M(`Sandbox reverted: ${o.id}`),console.log(`Source snapshot: ${s.snapshotId}`))}),e.command(`delete <sandbox-id-or-name> <snapshot-id>`).description(`Delete a sandbox snapshot`).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Deleting snapshot...`);a.start();let o=await(await G(i,r,e)).deleteSnapshot(t);a.stop(),n.json?j({success:!0,sandboxId:e,snapshotId:t,outcome:o.outcome}):o.outcome===`already_absent`?M(`Snapshot already gone: ${t}`):M(`Snapshot deleted: ${t}`)}),e}function tu(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 nu=`solve:device:secp256k1`,ru=/^0x[0-9a-f]{64}$/i;function iu(e){return e&&ru.test(e)?e:void 0}function au(){let e=fn(nu),t=iu(e.value);if(!(!t||e.source===`none`))return{account:at(t),source:e.source}}function ou(){let e=au();if(e)return e;let t=it(),n=pn(nu,t);return{account:at(t),source:n}}function su(e){let t=iu(fn(nu).value);if(!t||at(t).address!==e.account.address)throw Error(`The local Solve device key changed; it was not retired`);let n=`${nu}:retired:${e.account.address.toLowerCase()}`;if(pn(n,t),fn(n).value!==t)throw Error(`The revoked device key could not be retired safely`);return hn(nu),n}function cu(e){let t=e.create?ou():au();if(!t)throw Error("No Solve device signer found. Run `tangle solve account --create`");e.json?j({address:t.account.address,source:t.source}):F({Address:t.account.address,Source:t.source})}const lu=/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;function uu(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function du(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`${t} must be an object`);return e}function fu(e,t,n=2048){if(typeof e!=`string`||!e.trim()||e.length>n)throw Error(`${t} is missing or invalid`);if(uu(e))throw Error(`${t} contains control characters`);return e.trim()}function pu(e,t){let n=fu(e,t,64).toLowerCase();if(!lu.test(n))throw Error(`${t} must be a 40 or 64 character Git revision`);return n}function mu(e,t,n=!1){let r=typeof e==`number`&&Number.isSafeInteger(e)?String(e):fu(e,t,80);if(!/^\d+$/.test(r)||!n&&r===`0`)throw Error(`${t} must be an unsigned integer`);return BigInt(r).toString()}function hu(e,t){let n=fu(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 gu(e,t){let n=hu(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 _u(e,t){let n=fu(e,t,42);if(!pt(n,{strict:!1}))throw Error(`${t} must be an EVM address`);return dt(n)}function vu(e,t){let n=mu(e,t),r=Number(n);if(!Number.isSafeInteger(r)||r<=0)throw Error(`${t} is out of range`);return r}function Z(...e){for(let t of e)if(typeof t==`string`&&t.trim())return t.trim()}function yu(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 bu(e){if(e===void 0)return;let t=fu(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 xu(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 Su(e){return Fn(`solve`,e.profile)}function Cu(e){let t=Su(e),n=nr(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 wu(e){let t=ur(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 ${Cu(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 Tu(e){return wu({path:`/v1/wallet/challenges`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.purpose?{purpose:e.purpose}:{}}})}function Eu(e){return wu({path:`/v1/devices`,apiUrl:e.apiUrl,profile:e.profile})}function Du(e){return wu({path:`/v1/devices/revoke`,method:`POST`,apiUrl:e.apiUrl,profile:e.profile,body:{deviceAddress:e.deviceAddress,...e.reason?{reason:e.reason}:{},...e.challengeId&&e.signature?{challengeId:e.challengeId,signature:e.signature}:{}}})}const Q={chainId:42431,rpcUrl:`https://rpc.moderato.tempo.xyz`,sponsorUrl:`https://drew-gtr-pro.taild10bfc.ts.net/solve-sponsor`,tangleAddress:`0xff137B9C879c47C28ce389e84501925438AB4cdA`,managerAddress:`0x5271732F893B622ac6793d6DBA5B2626CCa4EA14`,paymentAsset:`0x20C0000000000000000000000000000000000000`,blueprintId:15n,serviceId:9n,competitionId:1n,minStakeWei:0n};function Ou(e,t){return e.toLowerCase()===t.toLowerCase()}function ku(e){if(e.chainId!==Q.chainId)throw Error(`Solve submissions require Tempo Moderato (chain ${Q.chainId}); received ${e.chainId}`);if(e.rpcUrl!==Q.rpcUrl)throw Error(`Solve metadata RPC does not match the trusted deployment`);if(e.sponsorUrl!==Q.sponsorUrl)throw Error(`Solve metadata sponsor does not match the trusted deployment`);if(!Ou(e.tangleAddress,Q.tangleAddress))throw Error(`Solve metadata Tangle contract does not match the trusted deployment`);if(!Ou(e.managerAddress,Q.managerAddress))throw Error(`Solve metadata competition manager does not match the trusted deployment`);if(!Ou(e.paymentAsset,Q.paymentAsset))throw Error(`Solve metadata payment asset does not match the trusted deployment`);if(e.blueprintId!==Q.blueprintId)throw Error(`Solve submissions require blueprint ${Q.blueprintId}; received ${e.blueprintId}`);if(e.serviceId!==Q.serviceId)throw Error(`Solve submissions require service ${Q.serviceId}; received ${e.serviceId}`);if(e.competitionId!==Q.competitionId)throw Error(`Solve submissions require competition ${Q.competitionId}; received ${e.competitionId}`);if(e.minStakeWei!==Q.minStakeWei)throw Error(`Solve submissions require zero stake for the trusted deployment`)}function Au(e,t){let n=du(t.check??e.check,`competition.participation.check`),r=fu(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=>fu(e,`competition checker argument`,2048)),a=Z(n.result_file,n.resultFile),o=n.timeout_ms??n.timeoutMs,s=o===void 0?void 0:vu(o,`competition checker timeout`);return{command:r,args:i,...a?{result_file:a}:{},...s?{timeout_ms:s}:{}}}function ju(e){if(e.provenance===void 0)return;let t=du(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 Mu(e){let t=du(e.chain??e.network??{},`competition.chain`),n=e.rewards&&typeof e.rewards==`object`&&!Array.isArray(e.rewards)?du(e.rewards,`competition.rewards`):{},r=n.minStake&&typeof n.minStake==`object`&&!Array.isArray(n.minStake)?du(n.minStake,`competition.rewards.minStake`).raw:void 0,i=Z(t.minStakeWei,t.min_stake_wei,e.minStakeWei,e.min_stake_wei,r),a=t.chainId??t.chain_id??e.chainId??e.chain_id,o=Z(t.chainName,t.chain_name,e.chainName,e.chain_name)??`Tempo`,s=Z(t.nativeSymbol,t.native_symbol,e.nativeSymbol,e.native_symbol)??`TNT`,c=Z(t.rpcUrl,t.rpc_url,e.rpcUrl,e.rpc_url,process.env.TANGLE_SOLVE_RPC_URL),l=Z(t.sponsorUrl,t.sponsor_url,e.sponsorUrl,e.sponsor_url,process.env.TANGLE_SOLVE_SPONSOR_URL),u=Z(t.tangleAddress,t.tangle_address,t.coreAddress,t.core_address,e.tangleAddress,e.tangle_address,e.coreAddress,e.core_address),d=Z(t.managerAddress,t.manager_address,e.managerAddress,e.manager_address),f=Z(t.paymentAsset,t.payment_asset,t.servicePaymentAsset,t.service_payment_asset,e.paymentAsset,e.payment_asset,e.servicePaymentAsset,e.service_payment_asset),p=Z(t.blueprintId,t.blueprint_id,e.blueprintId,e.blueprint_id),m=Z(t.serviceId,t.service_id,e.serviceId,e.service_id),h=Z(t.competitionId,t.competition_id,e.competitionId,e.competition_id,e.id);if(!c||!l||!u||!d||!p||!m||!h||!i||a===void 0)throw Error(`Solve competition metadata must include complete Tempo chain configuration`);return{chainId:vu(a,`chain.chainId`),chainName:o,nativeSymbol:s,rpcUrl:hu(c,`chain.rpcUrl`),sponsorUrl:hu(l,`chain.sponsorUrl`),tangleAddress:_u(u,`chain.tangleAddress`),managerAddress:_u(d,`chain.managerAddress`),paymentAsset:_u(f??Q.paymentAsset,`chain.paymentAsset`),blueprintId:mu(p,`chain.blueprintId`),serviceId:mu(m,`chain.serviceId`),competitionId:mu(h,`chain.competitionId`,!0),minStakeWei:mu(i,`chain.minStakeWei`,!0)}}function Nu(e){let t=du(e,`competition`),n=du(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=gu(Z(r.repository,r.repo_url,i.repository)??``,`competition.repository`),o=pu(Z(r.repositoryRevision,r.repository_revision,i.revision,i.repositoryRevision,i.repository_revision),`competition.repositoryRevision`),s=fu(r.slug??r.id,`competition.slug`,128),c=fu(r.name??r.title??s,`competition.name`,256),l=Au(r,i),u=ju(i);return{version:1,slug:s,title:c,repository:a,taskRevision:o,checker:l,chain:Mu(r),...u?{provenance:u}:{}}}function Pu(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 Fu(e){let t=du(JSON.parse(await k.readFile(E.join(e,`.tangle-solve.json`),`utf8`)),`.tangle-solve.json`);if(t.version!==1)throw Error(`.tangle-solve.json has an unsupported version`);let n=du(t.checker,`.tangle-solve.json.checker`),r=du(t.chain,`.tangle-solve.json.chain`);return Nu({slug:t.slug,name:t.title,repository:t.repository,repositoryRevision:t.taskRevision,participation:{check:n,provenance:t.provenance},chain:r,competitionId:r.competitionId})}const Iu=Xe(Te),Lu=`.tangle-solve-run.json`,Ru=`.tangle-solve.json`,zu=`tangle.solve.manifestSha256`,Bu=new Set([Ru,Lu]),Vu=`upstream`;async function Hu(e,t){let n=await Iu(`git`,[`-C`,e,...t],{encoding:`utf8`,maxBuffer:1e6});return String(n.stdout).trim()}async function Uu(e,t){let n=E.resolve(t??process.cwd()),r=await Fu(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 Wu(e){let t=E.join(e,Ru),n;try{n=await k.lstat(t)}catch{throw Error(`${Ru} is missing`)}if(n.isSymbolicLink()||!n.isFile())throw Error(`${Ru} must be a regular file`);return x(`sha256`).update(await k.readFile(t)).digest(`hex`)}async function Gu(e){let t=await Wu(e);return await Hu(e,[`config`,`--local`,`--replace-all`,zu,t]),t}async function Ku(e){let t;try{t=await Hu(e,[`config`,`--local`,`--get`,zu])}catch{throw Error(`The local Git metadata has no ${zu} pin; run tangle solve clone again`)}if(!/^[0-9a-f]{64}$/i.test(t))throw Error(`The local ${zu} pin is invalid`);if(await Wu(e)!==t.toLowerCase())throw Error(`${Ru} changed after clone; run tangle solve clone again`)}async function qu(e,t){try{return await Hu(e,[`ls-files`,`--error-unmatch`,`--`,t]),!0}catch{return!1}}async function Ju(e){await Ku(e);for(let t of Bu)if(await qu(e,t))throw Error(`${t} must remain untracked and local to this Solve workspace`);let t=await Iu(`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===`!!`)&&Bu.has(n))}).length>0)throw Error(`Commit the candidate before running Solve. Only the local manifest and run record may remain uncommitted.`);return pu(await Hu(e,[`rev-parse`,`HEAD`]),`submission revision`)}async function Yu(e,t,n,r={}){let i=await Xu(e,t,r);if(i)return{taskRepository:t.repository,taskRevision:t.taskRevision,submissionRepository:i,submissionRevision:n}}async function Xu(e,t,n={}){let r;try{r=yu(await Hu(e,[`config`,`--get`,`remote.origin.pushurl`]))}catch{try{r=yu(await Hu(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 '${Vu}'.`)}}let i=gu(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 '${Vu}' before submitting.`)}return i}function Zu(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 Qu(e,t){return`${e}/commit/${t}`}function $u(e,t,n,r,i={}){let a=e.evidenceRefs.map(e=>xu(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=bu(r);if(n.required&&(i.requirePullRequest??!0)&&!o)throw Error(`This competition requires a GitHub pull request`);a.push(Qu(t.taskRepository,t.taskRevision),Qu(t.submissionRepository,t.submissionRevision),...o?[o]:[])}return{evidence:e.evidence,evidenceRefs:[...new Set(a)]}}async function ed(e,t){let n=`${e}.${process.pid}.tmp`;await k.writeFile(n,`${JSON.stringify(t,null,2)}\n`,{mode:384}),await k.rename(n,e)}async function td(e){let t=JSON.parse(await k.readFile(E.join(e,Lu),`utf8`));if(t.version!==1||typeof t.competition!=`string`)throw Error(`${Lu} has an unsupported format`);return t}async function nd(e){let t=bu(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 rd(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 id=Xe(Te);function ad(){return`Task source is '${Vu}'. Add your fork as 'origin', commit your candidate, push it, and open a pull request before submitting.`}async function od(e,t,n){try{let r=du(await wu({path:`/v1/competitions/${encodeURIComponent(e)}`,apiUrl:n.apiUrl,profile:n.profile}),`competition response`),i=Nu(r.competition??r),a=E.resolve(t??i.slug),o=P(`Cloning ${i.slug}…`);n.json||o.start();try{await id(`git`,[`clone`,`--no-tags`,`--origin`,Vu,i.repository,a],{encoding:`utf8`,maxBuffer:1e6}),await Hu(a,[`checkout`,`--detach`,i.taskRevision]);let e=await Hu(a,[`rev-parse`,`HEAD`]);if(e.toLowerCase()!==i.taskRevision.toLowerCase())throw Error(`Pinned checkout resolved to ${e}, expected ${i.taskRevision}`);await ed(E.join(a,`.tangle-solve.json`),i),await Gu(a)}finally{o.stop()}n.json?j({competition:i,directory:a}):(M(`Cloned ${i.slug} at ${i.taskRevision.slice(0,12)}`),i.provenance&&N(ad()),N(`Run the pinned checker with: cd ${a} && tangle solve run`))}catch(e){R(e)}}const sd=12e4,cd=gt(`event JobSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint8 jobIndex, address caller, bytes inputs)`),ld=gt(`event JobCompleted(uint64 indexed serviceId, uint64 indexed callId)`),ud=gt(`event JobResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, address indexed operator, bytes result)`),dd=gt(`event AggregatedResultSubmitted(uint64 indexed serviceId, uint64 indexed callId, uint256 signerBitmap, bytes output)`),fd=gt(`event EvaluationAccepted(uint64 indexed serviceId, uint64 indexed competitionId, address indexed researcher, bytes32 candidateId, bytes32 submissionRefHash, bytes32 evaluationDigest, bytes32 metricsHash, bytes32 evidenceRefsHash)`),pd=[...ht([`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)`]),cd,ld,ud,dd],md=ht([`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)`]),hd=ht([`function allowance(address owner, address spender) view returns (uint256)`,`function approve(address spender, uint256 amount) returns (bool)`]),gd=_t(`uint64 competitionId, uint256 stakeWei`),_d=_t(`uint64 competitionId, bytes32 commitment`),vd=_t(`uint64 competitionId, bytes32 commitment, string artifactRef, bytes32 salt`),yd=_t(`string artifactRef, bytes32 salt`),bd=_t(`uint64 competitionId, bytes32 candidateId, string submissionRef, string evidenceJson, string evidenceRefsJson`),xd=_t(`string status, string detail`),Sd=/^0x[0-9a-f]{64}$/i;function Cd(e,t){if(e!==t)throw Error(`Tempo RPC returned chain ${e}; expected ${t}`)}function wd(e,t,n){return{...e,feePayer:!0,nonceKey:t,nonce:n}}function Td(e,t){if(e!==`success`)throw Error(`${t} transaction reverted`)}function Ed(e,t,n,r){if(!Sd.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(Td(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 Dd(e,t){return e>=t?[]:e>0n?[0n,t]:[t]}function Od(e,t,n=Date.now()){return n>=e+t}function kd(e,t){return e.filter(e=>e.args?.candidateId?.toLowerCase()===t.toLowerCase()).at(-1)?.transactionHash}function Ad(e,t,n,r,i){for(let a of e.logs)if(a.address.toLowerCase()===t.tangleAddress.toLowerCase())try{let e=lt({abi:[cd],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 jd(e,t,n,r){for(let i of e.logs)if(i.address.toLowerCase()===t.managerAddress.toLowerCase())try{let e=lt({abi:[fd],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 Md(e){if(e.chainId!==bt.id)throw Error(`Solve submissions require Tempo Moderato (chain ${bt.id}); received ${e.chainId}`);if(!e.sponsorUrl)throw Error(`Solve submissions require a Tempo sponsor relay URL; unsponsored writes are disabled`);return{...bt,name:e.chainName,nativeCurrency:{name:e.nativeSymbol,symbol:e.nativeSymbol,decimals:18},rpcUrls:{default:{http:[e.rpcUrl]}}}}async function Nd(e,t){ku(e);let n=Md(e),r=ot({chain:n,transport:ft(e.rpcUrl)});return Cd(await r.getChainId(),e.chainId),await Pd({publicClient:r},e),{publicClient:r,walletClient:st({account:t,chain:n,transport:St(ft(e.rpcUrl),ft(e.sponsorUrl))}),account:t}}async function Pd(e,t){let n=await e.publicClient.readContract({address:t.tangleAddress,abi:pd,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 Fd(e,t,n){let[r,i]=await Promise.all([e.publicClient.readContract({address:t.tangleAddress,abi:pd,functionName:`getJobEventRate`,args:[t.blueprintId,n]}),e.publicClient.readContract({address:t.tangleAddress,abi:pd,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 Id(e,t,n){return await e.publicClient.readContract({address:t,abi:hd,functionName:`allowance`,args:[e.account.address,n.tangleAddress]})}async function Ld(e,t,n,r,i,a){let o=Date.now();for(;!Od(o,a);){if((await e.publicClient.getLogs({address:t.tangleAddress,event:ld,args:{serviceId:t.serviceId,callId:n},fromBlock:r,toBlock:`latest`})).length>0){let a=(await e.publicClient.getLogs({address:t.tangleAddress,event:ud,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]=ct(xd,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 Rd(e,t,n,r,i){let a=Date.now();for(;!Od(a,i);){let i=(await e.publicClient.getLogs({address:t.tangleAddress,event:dd,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 zd(e,t,n){return!!await e.publicClient.readContract({address:t.managerAddress,abi:md,functionName:`acceptedCandidates`,args:[t.serviceId,t.competitionId,e.account.address,n]})}const Bd=BigInt(mt(vt(`tangle.solve.v1`)));async function Vd(e,t){let n=await xt.nonce.getNonce(e.publicClient,{account:e.account.address,nonceKey:Bd});if(n>BigInt(2**53-1))throw Error(`The Solve transaction nonce exceeds the safe range`);return e.walletClient.writeContract(wd(t,Bd,Number(n)))}async function Hd(e,t,n,r){if(!await e.publicClient.readContract({address:t.tangleAddress,abi:pd,functionName:`isPermittedCaller`,args:[t.serviceId,e.account.address]}))try{let i=r??await Vd(e,{address:t.managerAddress,abi:md,functionName:`authorizeSelf`,args:[t.serviceId]});if(r||await n?.(`authorization`,i),Ed(await e.publicClient.waitForTransactionReceipt({hash:i}),i,`Authorization`,{from:e.account.address,to:t.managerAddress}),!await e.publicClient.readContract({address:t.tangleAddress,abi:pd,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 Ud(e,t){let n=await Vd(e,{address:t.managerAddress,abi:md,functionName:`revokeSelf`,args:[t.serviceId]});return Ed(await e.publicClient.waitForTransactionReceipt({hash:n}),n,`Revocation`,{from:e.account.address,to:t.managerAddress}),n}async function Wd(e,t,n,r,i=`allowance`,a={}){if(t.amount===0n||t.asset===`0x0000000000000000000000000000000000000000`)return;let o=await Id(e,t.asset,n);for(let s of Dd(o,t.amount)){let o=s===0n?`${i}:reset`:`${i}:approval`,c=a[o];if(c){if(Ed(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 Id(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 Vd(e,{address:t.asset,abi:hd,functionName:`approve`,args:[n.tangleAddress,s]});await r?.(o,l),Ed(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 Gd(e,t,n,r,i,a=`job:${n}`,o={}){let s=await Fd(e,t,n);await Wd(e,s,t,i,`allowance:${a}`,o);let c=o[a],l=c??await Vd(e,{address:t.tangleAddress,abi:pd,functionName:`submitJob`,args:[t.serviceId,n,r],value:s.value});c||await i?.(a,l);let u=await e.publicClient.waitForTransactionReceipt({hash:l});return Ed(u,l,`Job ${n}`,{from:e.account.address,to:t.tangleAddress}),{hash:l,callId:Ad(u,t,n,e.account.address,r),blockNumber:u.blockNumber}}async function Kd(e,t,n,r,i,a,o=`job:${n}`,s={}){let c=await Gd(e,t,n,r,a,o,s),l=await Ld(e,t,c.callId,c.blockNumber,i,sd);return{...c,acknowledgement:l}}const qd={...Q,chainName:`Tempo Moderato`,nativeSymbol:`TNT`},Jd={async read(e){let t=ot({chain:bt,transport:ft(qd.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:qd.tangleAddress,abi:pd,functionName:`isPermittedCaller`,args:[qd.serviceId,e]})),n(t.readContract({address:qd.managerAddress,abi:md,functionName:`isDeviceRevoked`,args:[e]}))]);return[e.toLowerCase(),{permitted:r,revoked:i}]}));return new Map(r)},async revokeSelf(e){return Ud(await Nd(qd,e),qd)}},Yd={permitted:null,revoked:null};function Xd(e){return e.revoked?`revoked`:e.permitted===null?`unknown`:e.permitted?`permitted`:`not permitted`}async function Zd(e,t=Jd){try{let{devices:n}=await Eu({apiUrl:e.apiUrl,profile:e.profile}),r=au()?.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=>dt(e.address))),o=i.map(e=>({...e,onChain:a.get(e.address)??Yd}));if(e.json){j({serviceId:qd.serviceId.toString(),devices:o});return}Rt([`Address`,`Status`,`Local`,`Service ${qd.serviceId}`,`Last used`,`Revoked`],o.map(e=>[e.address,e.status,e.local?`yes`:``,Xd(e.onChain),e.lastUsedAt??``,e.revokedAt?`${e.revokedAt} (${e.revocationMethod})`:``]))}catch(t){R(t,e.json)}}async function Qd(e,t,n=Jd){try{if(!pt(e))throw Error(`${e} is not an EVM address`);let r=dt(e),i=au(),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`)){N(`Revocation cancelled`);return}}let o;if(i&&a){let e=await Tu({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 Du({deviceAddress:r,reason:t.reason,...o,apiUrl:t.apiUrl,profile:t.profile}),c=r.toLowerCase(),l=(await n.read([r])).get(c)??Yd,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)??Yd}let d=i&&a&&l.revoked?su(i):void 0;if(t.json){j({...s,serviceId:qd.serviceId.toString(),onChain:l,...u?{revocationTransaction:u}:{},localKeyRetired:!!d});return}M(s.alreadyRevoked?`${r} was already revoked in the Solve API`:`Revoked ${r}; the Solve API refuses its signatures`),u&&M(`Revoked on Tempo in ${u}; service ${qd.serviceId} refuses its jobs`),d&&N("The local device key was moved aside because its address may still hold stake or rewards. Run `tangle solve account --create` for a new device"),!a&&l.permitted&&Nt(`The device can still submit jobs to service ${qd.serviceId}. Only its key, or the Solve blueprint owner, can revoke it on chain`)}catch(e){R(e,t.json)}}function $d(e,t){return mt(ut(yd,[e.trim(),t]))}function ef(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 tf(e,t,n,r,i){let a=i.resumeTransactions?.evaluation;if(a){let n=await e.publicClient.waitForTransactionReceipt({hash:a});if(Ed(n,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!jd(n,t,e.account,r))throw Error(`Saved evaluation transaction did not emit EvaluationAccepted for this candidate`);return a}let o=Date.now();for(;!Od(o,sd);){if(await zd(e,t,r)){let i=kd(await e.publicClient.getLogs({address:t.managerAddress,event:fd,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:md,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()!==mt(n.output).toLowerCase())throw Error(`Manager pending report output does not match the aggregate`);let a=await Vd(e,{address:t.managerAddress,abi:md,functionName:`executePendingResult`,args:[t.serviceId,n.callId,n.output]});await i.onTransaction?.(`evaluation`,a);let s=await e.publicClient.waitForTransactionReceipt({hash:a});if(Ed(s,a,`Evaluation`,{from:e.account.address,to:t.managerAddress}),!jd(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 nf(e,t,n,r={}){if(ku(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 Nd(e,t),a=await Hd(i,e,r.onTransaction,r.resumeTransactions?.authorization),o,s=await i.publicClient.readContract({address:e.managerAddress,abi:md,functionName:`stakes`,args:[e.serviceId,e.competitionId,i.account.address]});s<e.minStakeWei&&(o=await Vd(i,{address:e.managerAddress,abi:md,functionName:`postStake`,args:[e.serviceId,e.competitionId],value:e.minStakeWei-s}),await r.onTransaction?.(`stake`,o),Ed(await i.publicClient.waitForTransactionReceipt({hash:o}),o,`Stake`,{from:i.account.address,to:e.managerAddress}));let c=$d(n.artifactRef,n.salt),l=ut(gd,[e.competitionId,e.minStakeWei]),u=ut(_d,[e.competitionId,c]),d=ut(vd,[e.competitionId,c,n.artifactRef.trim(),n.salt]),f=await Kd(i,e,1,l,`joined`,r.onTransaction,`join`,r.resumeTransactions),p=await Kd(i,e,2,u,`committed`,r.onTransaction,`commit`,r.resumeTransactions),m=ef(p.acknowledgement.detail),h=await Kd(i,e,3,d,`revealed`,r.onTransaction,`reveal`,r.resumeTransactions),g=await Gd(i,e,4,ut(bd,[e.competitionId,c,m,n.evidenceJson,JSON.stringify(n.evidenceRefs)]),r.onTransaction,`report`,r.resumeTransactions),_=await Rd(i,e,g.callId,g.blockNumber,sd),ee=await tf(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:ee,candidateId:c,submissionRef:m}}const rf=Xe(Te),af=`/usr/bin/bwrap`,of=[`/usr`,`/bin`,`/sbin`,`/lib`,`/lib64`];function sf(e){return[...e].some(e=>{let t=e.charCodeAt(0);return t<32||t===127})}function cf(e,t){if(!e||e.length>2048||sf(e))throw Error(`${t} contains invalid control characters or is too long`)}function lf(e,t){let n=t;for(;n<e.length&&/\s/.test(e[n]??``);)n+=1;return n}function uf(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 df(e,t,n){let r=new Set,i=lf(e,t+1);if(e[i]===`}`)return i+1;for(;i<e.length;){let t=uf(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=lf(e,t),e[i]!==`:`)throw Error(`Checker output must be valid JSON`);let o=lf(e,i+1),s=pf(e,o);if(n?.(a,o,s),i=lf(e,s),e[i]===`}`)return i+1;if(e[i]!==`,`)throw Error(`Checker output must be valid JSON`);i=lf(e,i+1)}throw Error(`Checker output must be valid JSON`)}function ff(e,t){let n=lf(e,t+1);if(e[n]===`]`)return n+1;for(;n<e.length;){if(n=lf(e,pf(e,n)),e[n]===`]`)return n+1;if(e[n]!==`,`)throw Error(`Checker output must be valid JSON`);n=lf(e,n+1)}throw Error(`Checker output must be valid JSON`)}function pf(e,t){if(e[t]===`"`)return uf(e,t);if(e[t]===`{`)return df(e,t);if(e[t]===`[`)return ff(e,t);let n=t;for(;n<e.length&&!/[\s,\]}]/.test(e[n]??``);)n+=1;return n}function mf(e){let t=e.trim();if(lf(t,pf(t,0))!==t.length)throw Error(`Checker output must be valid JSON`)}function hf(e,t){let n=e.trim();if(n[0]!==`{`)return;let r;return df(n,0,(e,i,a)=>{e===t&&(r=n.slice(i,a).trim())}),r}function gf(e,t){let n=e.trim(),r=[];return df(n,0,(e,i,a)=>{if(e===`evidence_refs`)return;let o=e===`candidate_ref`?JSON.stringify(t):n.slice(i,a).trim();r.push(`${JSON.stringify(e)}:${o}`)}),`{${r.join(`,`)}}`}function _f(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Checker output must be one JSON object`)}if(mf(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`);cf(i,`candidate_ref`);for(let e of a)cf(e.trim(),`evidence_refs`);let o,s;if(n.evidence_json!==void 0){if(!n.evidence_json||typeof n.evidence_json!=`object`||Array.isArray(n.evidence_json))throw Error(`Checker evidence_json must be an object`);o={...n.evidence_json};let t=hf(e,`evidence_json`);if(!t)throw Error(`Checker evidence_json source text is missing`);if(s=t,o.candidate_ref!==i)throw Error(`Checker evidence_json candidate_ref must match candidate_ref`)}else{let{evidence_refs:t,...r}=n;o=r,o.candidate_ref=i,s=gf(e,i)}return{candidateRef:i,evidenceRefs:a.map(e=>e.trim()),evidence:o,evidenceJson:s}}async function vf(e,t,n){let r=n.trim();if(r.startsWith(`{`)&&r.endsWith(`}`)||!t.result_file)return r;let i=await wf(e),a=E.resolve(i,t.result_file),o=E.relative(i,a);if(o.startsWith(`..`)||E.isAbsolute(o))throw Error(`Checker result_file must stay inside the competition repository`);let s;try{s=await k.lstat(a)}catch{throw Error(`Checker result_file must be an existing regular file inside the competition repository`)}if(s.isSymbolicLink())throw Error(`Checker result_file must not be a symbolic link`);if(!s.isFile())throw Error(`Checker result_file must be an existing regular file inside the competition repository`);let c;try{c=await k.realpath(a)}catch{throw Error(`Checker result_file must resolve to a regular file inside the competition repository`)}let l=E.relative(i,c);if(l.startsWith(`..`)||E.isAbsolute(l))throw Error(`Checker result_file must stay inside the competition repository`);return(await k.readFile(c,`utf8`)).trim()}function yf(e,t){let n=E.relative(e,t);return n===``||!n.startsWith(`..`)&&!E.isAbsolute(n)}function bf(e){return of.some(t=>yf(t,e))}async function xf(e,t,n){let r=e.includes(`/`)?[E.resolve(t,e)]:(process.env.PATH??``).split(E.delimiter).filter(Boolean).map(t=>E.join(t,e));for(let i of r){let r;try{r=await k.realpath(i),await k.access(r,k.constants.X_OK)}catch{continue}if(!yf(t,r)&&!bf(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 Sf(e){let t=[];for(let n of e)try{(await k.stat(n)).isDirectory()&&t.push(n)}catch{}return t}async function Cf(e){let t=await k.realpath(Se.homedir());if(e===E.parse(e).root||e===t)throw Error(`Solve checker repository must be a dedicated directory, not the filesystem or home root`)}async function wf(e){let t=await k.realpath(e);return await Cf(t),t}async function Tf(e){let t=E.join(e,`.git`),n;try{n=await k.lstat(t)}catch{return}if(n.isSymbolicLink())throw Error(`Solve checker repository .git must not be a symbolic link`);if(!n.isDirectory()&&!n.isFile())return;let r;try{let t={...process.env};for(let e of[`GIT_DIR`,`GIT_WORK_TREE`,`GIT_INDEX_FILE`,`GIT_OBJECT_DIRECTORY`,`GIT_ALTERNATE_OBJECT_DIRECTORIES`,`GIT_COMMON_DIR`,`GIT_CONFIG_COUNT`,`GIT_CONFIG_PARAMETERS`])delete t[e];let n=await rf(`/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 Ef(e,t,n){let r=await wf(e);if(process.platform!==`linux`)throw Error(`Solve checkers require the Linux sandbox runtime (bubblewrap) with network isolation`);try{await k.access(af,k.constants.X_OK)}catch{throw Error(`Solve checkers require /usr/bin/bwrap; install bubblewrap or run the checker in a Tangle sandbox`)}let i=await xf(t,r,await k.realpath(process.execPath)),a=await Tf(r),o=(await Sf(of)).flatMap(e=>[`--ro-bind`,e,e]),s=yf(r,i)?`/work/${E.relative(r,i)}`:bf(i)?i:`/checker/node`;!yf(r,i)&&!bf(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:af,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 Df(e,t){if(!t.command||t.command.includes(`/../`)||sf(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)cf(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 wf(e),i;try{let e=await Ef(r,t.command,t.args);i=await rf(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{..._f(await vf(r,t,a)),stdout:a,stderr:o}}async function Of(e,t){try{let{root:n,manifest:r}=await Uu(e,t.directory),i=await Ju(n),a=r.provenance?await Yu(n,r,i,{allowMissing:!0}):void 0,o=ou(),s=P(`Running ${r.title} checker…`);t.json||s.start();let c;try{c=await Df(n,r.checker)}finally{s.stop()}let l=$u(c,a,r.provenance,void 0,{allowMissingSource:!0,requirePullRequest:!1}),u=yt(S(32)),d=$d(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:C(),createdAt:new Date().toISOString()};await ed(E.join(n,`.tangle-solve-run.json`),f),t.json?j({localRun:f}):(M(`Checker output recorded locally for operator evaluation`),F({Competition:r.slug,Candidate:c.candidateRef,"Device address":o.account.address,"Evidence refs":l.evidenceRefs.length}),N("Commit any changes, then run `tangle solve submit` from this directory."),r.provenance&&!a&&N(`Add your GitHub fork as 'origin' before submitting. The task repository is available as '${Vu}'.`))}catch(e){R(e)}}const kf=/^0x[0-9a-f]{64}$/i;async function Af(e){let t=await Tu({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 jf(e,t){try{let{root:n,manifest:r}=await Uu(e,t.directory);Su({profile:t.profile});let i=await Ju(n),a=await td(n);if(a.competition!==r.slug)throw Error(`.tangle-solve-run.json does not match this competition`);if(!kf.test(a.salt)||!kf.test(a.candidateId))throw Error("This run predates durable candidate identity. Run `tangle solve run` again");let o=r.provenance?await Yu(n,r,i):void 0;if(r.provenance&&a.source&&!Zu(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=au();if(!s)throw Error("No Solve device signer found. Run `tangle solve run` first");if(s.account.address.toLowerCase()!==a.deviceAddress.toLowerCase())throw Error("The local Solve device account changed after `tangle solve run`; run the checker again");let c=P(`Checking the committed candidate…`);t.json||c.start();let l;try{l=await Df(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($d(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=bu(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 nd({pullRequest:u,taskRepository:o.taskRepository,submissionRepository:o.submissionRepository,submissionRevision:i})}let d=$u(l,o,r.provenance,u,{requirePullRequest:!0}),f={...a,...o?{source:o}:{},chainState:{status:`submitting`,transactions:{...a.chainState?.transactions??{}}}},p=E.join(n,`.tangle-solve-run.json`);await ed(p,f);let m=P(`Submitting candidate to Tempo…`);t.json||m.start();let h;try{h=await nf(Pu(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 ed(p,f)}})}finally{m.stop()}f={...f,chainReceipt:h,chainState:{status:`accepted`,transactions:{...f.chainState?.transactions??{},...rd(h)}}},await ed(p,f);let g=await Af({deviceAddress:h.address,signer:s.account,apiUrl:t.apiUrl,profile:t.profile}),_=await wu({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:rd(h),...r.provenance&&o?{source:{...o,...u?{pullRequest:u}:{}}}:{},clientSubmissionId:a.clientSubmissionId,...g,...t.model?{model:t.model}:{},...t.note?{note:t.note}:{}}});t.json?j({..._,transactions:rd(h),candidateId:h.candidateId}):(M(`Submission accepted on Tempo`),F({Competition:r.slug,Candidate:h.candidateId,"Device address":h.address,"Report transaction":h.report,"Evaluation transaction":h.evaluation,"Submission ID":typeof _.id==`string`?_.id:_.submission?.id}))}catch(e){R(e)}}function Mf(){let e=new b(`solve`).description(`Participate in Tangle Solve competitions`);e.command(`clone <competition>`).description(`Clone the pinned competition repository`).argument(`[directory]`,`Destination directory`).option(`--api-url <url>`,`Solve API base URL`).option(`--profile <name>`,`Tangle profile`,`solve`).action(od),e.command(`run [competition]`).description(`Run the competition checker and record its evidence`).option(`--directory <path>`,`Competition directory (defaults to the current directory)`).action(Of),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(jf),e.command(`account`).description(`Show the local Solve signing account`).option(`--create`,`Create the account if it does not exist`).action(cu);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=>Zd(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)=>Qd(e,t)),e}function Nf(e,t){return`tangle ssh-proxy ${e.replace(/\/+$/,``)}/v1/sidecar-proxy/${t}/ssh`}function Pf(e){return/^[A-Za-z0-9_/:=@%+.,-]+$/.test(e)?e:`'${e.replace(/'/g,`'"'"'`)}'`}function Ff(e){return`'${e.replace(/'/g,`''`)}'`}function If(e){return e===`win32`?`NUL`:`/dev/null`}function Lf(e,t){return t===`win32`?`$env:TANGLE_SSH_PROXY_AUTH_TOKEN=${Ff(`<token>`)}; ssh ${e.map(Ff).join(` `)}`:`TANGLE_SSH_PROXY_AUTH_TOKEN=${Pf(`<token>`)} ssh ${e.map(Pf).join(` `)}`}function Rf(e){return e.connection!==void 0&&!e.connection.ssh}function zf(){Mt(`SSH is not enabled for this sandbox.`),N(`Create a sandbox with --ssh to enable SSH access.`),process.exit(1)}function Bf(e,t=[],n=process.platform){let r=If(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 Vf(){return new b(`ssh`).description(`Open SSH session to a sandbox`).argument(`<ref>`,`Sandbox ID or name`).argument(`[sshArgs...]`,`Extra args passed through to ssh`).option(`-i, --identity-file <path>`,`Private key file to pass to ssh`).option(`--print`,`Print SSH command instead of connecting`).allowUnknownOption(!0).action(async(e,t,n)=>{let{context:r,client:i}=U(n),a=P(`Getting SSH credentials...`);a.start();let o=await G(i,r,e);if(Rf(o)){a.stop(),zf();return}o=await K(o);let s=await o.ssh();if(a.stop(),!s){zf();return}let c={...s,proxyCommand:Nf(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=Bf(c,[...n.identityFile?[`-i`,n.identityFile,`-o`,`IdentitiesOnly=yes`]:[],...t]);if(n.print){console.log(Lf(l,process.platform));return}N(`Connecting via tunnel...`);let u=De(`ssh`,l,{stdio:`inherit`,env:{...process.env,TANGLE_SSH_PROXY_AUTH_TOKEN:r.apiKey}});u.on(`error`,e=>{e.code===`ENOENT`&&(Mt(`SSH client not found. Please install OpenSSH.`),process.exit(1)),R(e)}),u.on(`exit`,e=>{process.exit(e??0)})})}function Hf(){let e=new b(`ssh-keys`).description(`Manage SSH keys`);return e.command(`list`).description(`List SSH keys`).action(async e=>{let t=P(`Fetching SSH keys...`);try{t.start();let n=await H(V(e)).sshKeys.list();t.stop(),e.json?j({sshKeys:n}):n.length===0?N(`No SSH keys found.`):Rt([`Name`,`Type`,`Fingerprint`,`Created`],n.map(e=>[e.name,e.keyType,e.fingerprint,e.createdAt.toLocaleString()]))}catch(e){t.stop(),R(e)}}),e.command(`add`).description(`Add SSH key`).argument(`<name>`,`SSH key name`).requiredOption(`--key-file <path>`,`Public key file path`).action(async(e,t)=>{let n=P(`Adding SSH key...`);try{let r=T(t.keyFile,`utf8`).trim();n.start();let i=await H(V(t)).sshKeys.create(e,r);n.stop(),t.json?j({sshKey:i}):M(`Added SSH key ${i.name} (${i.fingerprint})`)}catch(e){n.stop(),R(e)}}),e.command(`delete`).description(`Delete SSH key`).argument(`<name>`,`SSH key name or ID`).action(async(e,t)=>{let n=P(`Deleting SSH key...`);try{n.start(),await H(V(t)).sshKeys.delete(e),n.stop(),M(`Deleted SSH key ${e}`)}catch(e){n.stop(),R(e)}}),e}function Uf(e,t=1){process.stderr.write(`${e}\n`),process.exit(t)}function Wf(){return new b(`ssh-proxy`).description(`SSH proxy helper that pipes stdin/stdout to WebSocket`).argument(`<runtime-url>`,`Runtime WebSocket URL`).action(async e=>{let t=process.env.TANGLE_SSH_PROXY_AUTH_TOKEN;t||Uf(`TANGLE_SSH_PROXY_AUTH_TOKEN not set`);let n=new Ct(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===Ct.OPEN&&n.ping()},15e3),r.unref?.(),process.stdin.on(`data`,e=>{n.readyState===Ct.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(),Uf(`WebSocket error: ${e.message}`)}),n.on(`close`,e=>{i(),process.exit(e===1e3?0:1)}),process.stdin.on(`error`,()=>n.close())})}function Gf(){let e=new b(`team`).description(`Manage teams`);return $(e,`list`).description(`List teams for the current account`).action(async e=>{let t=V(e),n=H(t),r=e.json?null:P(`Fetching teams...`);r?.start();let i=await n.teams.list();if(r?.stop(),e.json){j({teams:i,activeTeamId:t.activeTeamId??null});return}A(i.map(e=>({active:e.id===t.activeTeamId,id:e.id,name:e.name,role:e.currentUserRole,members:e.memberCount})),[{key:`active`,header:`Active`,width:8},{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:24},{key:`role`,header:`Role`,width:10},{key:`members`,header:`Members`,width:10}])}),$(e,`create <name>`).description(`Create a team`).option(`--org-id <id>`,`External organization id`).option(`--no-switch`,`Do not set the new team as active`).action(async(e,t)=>{let n=V(t),r=H(n),i=t.json?null:P(`Creating team...`);i?.start();let a=await r.teams.create({name:e,orgId:t.orgId});if(t.switch&&Vl(a,n.profile),i?.stop(),t.json){j({team:a,active:!!t.switch});return}M(`Team created: ${zl(a)}`),t.switch&&M(`Active team set to ${a.name}`)}),$(e,`switch <team>`).description(`Set the active team for the current profile`).action(async(e,t)=>{let n=V(t),r=await Bl(H(n),e);if(Vl(r,n.profile),t.json){j({team:r,activeTeamId:r.id});return}M(`Active team set to ${zl(r)}`)}),e.command(`current`).description(`Show the active team for the current profile`).option(`--profile <profile>`,`Credential profile`).action(e=>{let t=fr(e.profile);if(e.json){j(t.activeTeamId?t:{activeTeamId:null});return}if(!t.activeTeamId){console.log(`No active team.`);return}F({ID:t.activeTeamId,Name:t.activeTeamName})}),e.command(`clear`).description(`Clear the active team for the current profile`).option(`--profile <profile>`,`Credential profile`).action(e=>{if(Hl(e.profile),e.json){j({activeTeamId:null});return}M(`Active team cleared.`)}),$(e,`members [team]`).description(`List team members`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile),a=await r.teams.listMembers(i.id);if(t.json){j({team:i,members:a});return}A(a,[{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=V(t),r=H(n),i=await X(r,t.team,n.profile),a=Kf(t.role),o=await r.teams.updateMember(i.id,e,{role:a});if(t.json){j({team:i,member:o});return}M(`Member updated: ${o.customerEmail}`),F({Team:i.name,Role:o.role,Status:o.status})}),$(e,`invite <email>`).description(`Invite a user to a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--role <role>`,`Role: admin, member, viewer`,`member`).option(`--ttl-hours <hours>`,`Invitation lifetime in hours`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile),a=Kf(t.role),o=await r.teams.invite(i.id,{email:e,role:a,ttlHours:t.ttlHours?Number.parseInt(t.ttlHours,10):void 0});if(t.json){j({team:i,invitation:o});return}M(`Invitation created for ${o.email}`),F({Team:i.name,Role:o.role,Expires:o.expiresAt,"Invitation ID":o.id}),M(`Re-run with --json to retrieve the invitation token for sharing.`)}),$(e,`leave [team]`).description(`Leave a team as the current user`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile);if(!(!t.force&&!t.json&&!await ei(`Leave team '${i.name}'? (y/N) `,`--force`))){if(await r.teams.leave(i.id),n.activeTeamId===i.id&&Hl(n.profile),t.json){j({success:!0,teamId:i.id});return}M(`Left team: ${i.name}`)}}),$(e,`transfer <new-owner-customer-id> [team]`).description(`Transfer team ownership to another active member`).option(`--force`,`Skip confirmation prompt`).action(async(e,t,n)=>{let r=V(n),i=H(r),a=await X(i,t,r.profile);if(!(!n.force&&!n.json&&!await 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){j({success:!0,teamId:a.id,newOwnerCustomerId:e});return}M(`Ownership transferred for ${a.name}`)}}),e.addCommand(qf()),e.addCommand(Jf()),$(e,`invitations [team]`).description(`List pending and historical team invitations`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile),a=await r.teams.listInvitations(i.id);if(t.json){j({team:i,invitations:a});return}A(a,[{key:`id`,header:`ID`,width:38},{key:`email`,header:`Email`,width:28},{key:`role`,header:`Role`,width:10},{key:`status`,header:`Status`,width:12},{key:`expiresAt`,header:`Expires`,width:16}])}),$(e,`accept <token>`).description(`Accept a team invitation`).option(`--no-switch`,`Do not set the accepted team as active`).action(async(e,t)=>{let n=V(t),r=H(n),i=await r.teams.acceptInvitation(e),a=t.switch===!1?null:await r.teams.get(i.teamId);if(a&&Vl(a,n.profile),t.json){j({member:i,activeTeamId:a?.id??null});return}M(`Invitation accepted for team ${i.teamId}`),a&&M(`Active team set to ${a.name}`)}),$(e,`revoke-invitation <invitation-id>`).description(`Revoke a pending team invitation`).action(async(e,t)=>{if(await H(V(t)).teams.revokeInvitation(e),t.json){j({success:!0,invitationId:e});return}M(`Invitation revoked: ${e}`)}),$(e,`remove-member <member-id>`).description(`Remove a member from a team`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile);if(await r.teams.removeMember(i.id,e),t.json){j({success:!0,teamId:i.id,memberId:e});return}M(`Member removed: ${e}`)}),e}function Kf(e){if(e===`admin`||e===`member`||e===`viewer`)return e;throw Error(`Role must be one of: admin, member, viewer`)}function qf(){let e=new b(`secret`).description(`Manage team secrets`);return $(e,`list [team]`).description(`List team secret names`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile),a=await r.teams.listSecrets(i.id);if(t.json){j({team:i,secrets:a});return}A(a,[{key:`name`,header:`Name`,width:28},{key:`updatedAt`,header:`Updated`,width:24},{key:`updatedBy`,header:`Updated By`,width:28}])}),$(e,`set <name> [value]`).description(`Create or replace a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--value-stdin`,`Read secret value from stdin`).action(async(e,t,n)=>{let r=V(n),i=H(r),a=await X(i,n.team,r.profile),o=await Ql({value:t,valueStdin:n.valueStdin,prompt:`Enter value for team secret '${e}': `}),s=await i.teams.upsertSecret(a.id,e,o);if(n.json){j({team:a,secret:s});return}M(`Team secret saved: ${s.name}`)}),$(e,`delete <name>`).description(`Delete a team secret`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile);if(!(!t.force&&!t.json&&!await ei(`Delete team secret '${e}' from '${i.name}'? (y/N) `,`--force`))){if(await r.teams.deleteSecret(i.id,e),t.json){j({success:!0,teamId:i.id,name:e});return}M(`Team secret deleted: ${e}`)}}),$(e,`reveal <name>`).description(`Reveal a team secret value`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile),a=await r.teams.revealSecret(i.id,e);if(t.json){j({teamId:i.id,...a});return}console.log(a.value)}),e}function Jf(){let e=new b(`templates`).description(`Manage team golden-path templates`);return $(e,`list [team]`).description(`List a team's golden-path templates`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,e,n.profile),a=await r.teams.listTemplates(i.id);if(t.json){j({team:i,templates:a});return}if(a.length===0){console.log(`No templates yet for ${i.name}.`);return}A(a.map(e=>({id:e.id,name:e.name,environment:e.environment,snapshot:`${e.snapshotId.slice(0,12)}…`,updated:e.updatedAt})),[{key:`id`,header:`ID`,width:38},{key:`name`,header:`Name`,width:28},{key:`environment`,header:`Env`,width:14},{key:`snapshot`,header:`Snapshot`,width:16},{key:`updated`,header:`Updated`,width:24}])}),$(e,`create <name> <snapshot-id>`).description(`Create a golden-path template from a snapshot`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`-d, --description <description>`,`Human-readable description shown in the dashboard`).option(`-e, --environment <environment>`,`Default environment to apply (defaults to 'universal')`).option(`--config <json>`,`Optional JSON config object merged into sandboxes created from this template`).action(async(e,t,n)=>{let r=V(n),i=H(r),a=await X(i,n.team,r.profile),o;if(n.config)try{let e=JSON.parse(n.config);if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`--config must be a JSON object`);o=e}catch(e){throw Error(`--config is not valid JSON: ${e instanceof Error?e.message:String(e)}`)}let s=await i.teams.createTemplate(a.id,{name:e,snapshotId:t,description:n.description,environment:n.environment,config:o});if(n.json){j({team:a,template:s});return}M(`Team template created: ${s.name} (${s.id})`)}),$(e,`delete <template-id>`).description(`Delete a team golden-path template`).option(`-t, --team <team>`,`Team id or name (defaults to active team)`).option(`--force`,`Skip confirmation prompt`).action(async(e,t)=>{let n=V(t),r=H(n),i=await X(r,t.team,n.profile);if(!(!t.force&&!t.json&&!await ei(`Delete template '${e}' from '${i.name}'? (y/N) `,`--force`))){if(await r.teams.deleteTemplate(i.id,e),t.json){j({success:!0,teamId:i.id,templateId:e});return}M(`Team template deleted: ${e}`)}}),e}function $(e,t){return e.command(t).option(`--profile <profile>`,`Credential profile`)}async function Yf(e,t,n){let r=new AbortController,i=()=>r.abort();try{let n=H(V({...e,timeout:void 0}));process.once(`SIGINT`,i),process.once(`SIGTERM`,i);let a=await t(n,{...e.timeout===void 0?{}:{timeoutMs:Number(e.timeout)*1e3},resumeJobId:e.resumeJob,signal:r.signal,onProgress:e=>{process.stderr.write(`Publication ${e.id}: ${e.status}\n`)}}).finally(()=>{process.off(`SIGINT`,i),process.off(`SIGTERM`,i)});e.json?j(a):M(`template`in a?`Published template: ${a.template.slug}`:`Published template version: ${a.version.id}`)}catch(t){if(t instanceof s&&t.status!==401&&t.job&&[`pending`,`scanning`,`ready`].includes(t.job.status)){let e=[`tangle`,`template`,...n,`--resume-job`,t.job.id].map(Ke).join(` `);Object.assign(t,{fix:{command:e}})}R(t,e.json)}}function Xf(){let e=new b(`template`).description(`Manage published public templates`);return e.command(`list`).option(`-q, --query <query>`,`Search query`).option(`--tag <tag>`,`Filter by tag`).option(`--featured`,`Show featured templates only`).action(async e=>{let t=H(V(e)),n=e.featured?await t.publicTemplates.featured():await t.publicTemplates.list({query:e.query,tag:e.tag});if(e.json){j({templates:n});return}A(n,[{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 H(V(t)).publicTemplates.get(e);if(t.json){j({template:n});return}j(n)}),e.command(`versions <id-or-slug>`).action(async(e,t)=>{let n=await H(V(t)).publicTemplates.versions(e);if(t.json){j({versions:n});return}A(n.map(e=>({...e})),[{key:`id`,header:`Version ID`,width:38},{key:`versionNumber`,header:`Version`,width:8},{key:`snapshotId`,header:`Snapshot`,width:20},{key:`createdAt`,header:`Created`,width:24}])}),e.command(`publish <name> <snapshot-id> <sandbox-id>`).option(`--timeout <seconds>`,`Maximum wait for publication`).option(`--resume-job <id>`,`Resume an accepted publication for this snapshot`).option(`--slug <slug>`,`Stable public slug`).option(`-d, --description <description>`,`Template description`).option(`--readme <markdown>`,`README markdown`).option(`--tags <tags...>`,`Template tags`).option(`--release-notes <text>`,`Release notes`).option(`--team-id <id>`,`Publish under a team`).option(`--forked-from <id>`,`Fork source template id`).action((e,t,n,r)=>Yf(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)=>Yf(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 Zf(){let e=new b(`traces`).description(`Read hosted agent traces, spans, and eval-runs from Tangle Intelligence`);return e.command(`list`).description(`List trace summaries (one row per trace), newest first`).option(`--from <iso>`,`ISO-8601 lower bound on received time (inclusive)`).option(`--to <iso>`,`ISO-8601 upper bound on received time (inclusive)`).option(`--model <model>`,`Exact model match (any span carried this model)`).option(`--run <runId>`,`Exact run id match`).option(`--status <status>`,`ERROR | OK`).option(`-q, --query <text>`,`Substring over span name`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Page size (clamped server-side to [1, 200])`).action(async e=>{try{let t={from:e.from,to:e.to,model:e.model,runId:e.run,status:e.status===void 0?void 0:cp(e.status),q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:pp(e.limit)},n=$f(e),r=e.json?null:P(`Fetching traces...`);r?.start();let i=await n.listTraces(t);if(r?.stop(),e.json)return j(i);np(i.items),op(i.nextCursor)}catch(t){tp(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=$f(t);if(t.ndjson){await ep(n,e);return}let r=t.json?null:P(`Fetching trace spans...`);r?.start();let i=await n.getTraceSpans(e,{cursor:t.cursor,limit:t.limit===void 0?void 0:pp(t.limit)});if(r?.stop(),t.json)return j(i);rp(i.items),i.truncated&&F({Spans:`${i.items.length} of ${i.total} (truncated)`}),op(i.nextCursor)}catch(e){tp(e,t)}}),e.addCommand(Qf()),e}function Qf(){let e=new b(`runs`).description(`Read eval-runs pivoted off the trace surface`);return e.command(`list`).description(`List eval-runs, newest first`).option(`--status <status>`,`Run status filter`).option(`--gate <decision>`,`Promotion-gate decision filter`).option(`--label <key:value>`,`Match over the run's labels`).option(`--from <iso>`,`ISO-8601 lower bound on received time`).option(`--to <iso>`,`ISO-8601 upper bound on received time`).option(`-q, --query <text>`,`Substring over run dir`).option(`--cursor <cursor>`,`Opaque pagination cursor from a prior page`).option(`--limit <count>`,`Page size`).action(async e=>{try{let t={status:e.status===void 0?void 0:up(e.status),gate:e.gate===void 0?void 0:fp(e.gate),label:e.label,from:e.from,to:e.to,q:e.query,cursor:e.cursor,limit:e.limit===void 0?void 0:pp(e.limit)},n=$f(e),r=e.json?null:P(`Fetching runs...`);r?.start();let i=await n.listRuns(t);if(r?.stop(),e.json)return j(i);ip(i.items),op(i.nextCursor)}catch(t){tp(t,e)}}),e.command(`get <runId>`).description(`Show a single eval-run`).action(async(e,t)=>{try{let n=$f(t),r=t.json?null:P(`Fetching run...`);r?.start();let i=await n.getRun(e);if(r?.stop(),t.json)return j(i);ap(i)}catch(e){tp(e,t)}}),e}function $f(e){let t=tr(e.apiKey);if(!t)throw Error(`No API key found. Set TANGLE_API_KEY or run: tangle auth login`);return wt({apiKey:t,baseUrl:e.baseUrl??process.env.TANGLE_INTELLIGENCE_BASE_URL})}async function ep(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 tp(e,t){return R(e,t.json===!0)}function np(e){A(e.map(e=>({traceId:e.traceId,root:e.rootName??`-`,model:e.model??`-`,spans:e.spanCount,errors:e.errorCount,durationMs:e.durationMs,cost:sp(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 rp(e){A(e.map(e=>({spanId:e.id,name:e.name,model:e.model??`-`,status:e.statusCode??`-`,cost:e.costUsd===null?`-`:`$${e.costUsd}`})),[{key:`spanId`,header:`Span`,width:40},{key:`name`,header:`Name`,width:28},{key:`model`,header:`Model`,width:22},{key:`status`,header:`Status`,width:10},{key:`cost`,header:`Cost`,width:12}])}function ip(e){A(e.map(e=>({runId:e.id,status:e.status,gate:e.gateDecision??`-`,cost:e.totalCostUsd===null?`-`:`$${e.totalCostUsd}`,receivedAt:e.receivedAt})),[{key:`runId`,header:`Run`,width:24},{key:`status`,header:`Status`,width:22},{key:`gate`,header:`Gate`,width:18},{key:`cost`,header:`Cost`,width:12},{key:`receivedAt`,header:`Received`,width:18}])}function ap(e){F({Run:e.id,Status:e.status,Gate:e.gateDecision??void 0,"Run Dir":e.runDir??void 0,Cost:e.totalCostUsd===null?void 0:`$${e.totalCostUsd}`,Duration:e.totalDurationMs===null?void 0:`${e.totalDurationMs}ms`,"Holdout Lift":e.holdoutLift??void 0,Received:e.receivedAt})}function op(e){e&&F({"Next page":`--cursor ${e}`})}function sp(e){return e===null?`-`:`$${e.toFixed(4)}`}function cp(e){if(e===`ERROR`||e===`OK`)return e;throw Error(`--status must be ERROR or OK`)}const lp=[`started`,`baseline-complete`,`generation-complete`,`gate-decided`,`finished`,`errored`];function up(e){let t=lp.find(t=>t===e);if(t)return t;throw Error(`--status must be one of ${lp.join(`, `)}`)}const dp=[`ship`,`hold`,`need_more_work`,`model_ceiling`,`arch_ceiling`];function fp(e){let t=dp.find(t=>t===e);if(t)return t;throw Error(`--gate must be one of ${dp.join(`, `)}`)}function pp(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`--limit must be a positive integer`);return t}function mp(){return new b(`usage`).description(`Show account usage and billing information`).action(async e=>{let{client:t}=U(e),n=e.json?null:P(`Fetching usage...`);n?.start();let[r,i]=await Promise.all([t.usage(),t.subscription().catch(()=>null)]);n?.stop(),e.json?j({...r,subscription:i}):(console.log(),console.log(`Account Usage`),console.log(`─`.repeat(40)),F({"Active Sandboxes":r.activeSandboxes,"Total Sandboxes":r.totalSandboxes,"Compute Minutes":hp(r.computeMinutes),"GPU Seconds":r.gpuSeconds,"GPU Spend":gp(r.gpuCostUsd)}),i&&(console.log(),console.log(`Subscription`),console.log(`─`.repeat(40)),F({Plan:i.plan,Status:i.status,"Credits Available":gp(i.creditsAvailableUsd),"Credits Used":gp(i.creditsUsedUsd),"Monthly Balance":gp(i.monthlyBalanceUsd)})),console.log(),console.log(`Billing Period`),console.log(`─`.repeat(40)),F({Start:r.periodStart.toLocaleDateString(),End:r.periodEnd.toLocaleDateString()}),console.log())})}function hp(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 gp(e){return e<0?`-$${(-e).toFixed(2)}`:`$${e.toFixed(2)}`}function _p(){return new b(`use`).description(`Set or show the active sandbox (used when a command omits the id)`).argument(`[id]`,`Sandbox id to make active`).option(`--clear`,`Clear the active sandbox`).action((e,t)=>{if(t.clear){qn(),N(`Cleared the active sandbox.`);return}if(e){Kn(e),N(`Active sandbox set to ${e}. Commands now default to it; override with --box or TANGLE_SANDBOX.`);return}let n=Gn();N(n?`Active sandbox: ${n}`:"No active sandbox. Set one with `tangle use <id>`.")})}function vp(e){A(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 yp(e){e.command(`artifacts`).description(`List a run's artifact metadata (never the bytes)`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.listArtifacts(e,t);if(n.json)return j(r);vp(r.artifacts)}),e.command(`artifact-download`).description(`Download one run artifact's bytes to a file`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).argument(`<artifactId>`,`Artifact ID`).option(`--out <file>`,`Destination file (defaults to the artifact ID)`).action(async(e,t,n,r)=>{let i=await(await Y(r)).workflows.downloadArtifact(e,t,n),a=r.out??n;try{me(a,i.bytes)}catch(e){throw Error(`Could not write artifact to "${a}": ${e instanceof Error?e.message:String(e)}`)}if(r.json)return j({file:a,contentType:i.contentType,bytes:i.bytes.length});N(`Wrote ${a} (${i.bytes.length} bytes, ${i.contentType}).`)})}function bp(e){A(e.map(e=>({id:e.id,run:e.runId,title:e.title,options:e.options.join(`, `),requested:e.requestedAt,expires:e.expiresAt??``})),[{key:`id`,header:`ID`},{key:`run`,header:`Run`},{key:`title`,header:`Title`},{key:`options`,header:`Options`},{key:`requested`,header:`Requested`},{key:`expires`,header:`Expires`}])}function xp(e){e.command(`decisions`).description(`List a workflow's pending human decisions`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=(await(await Y(t)).workflows.listPendingDecisions()).decisions.filter(t=>t.workflowId===e);if(t.json)return j({decisions:n});bp(n)}),e.command(`decision-resolve`).description(`Answer the decision a run is parked on and resume it`).argument(`<id>`,`Workflow ID`).argument(`<runId>`,`Run ID`).requiredOption(`--choice <choice>`,`The option to resolve with (one of the decision's options)`).action(async(e,t,n)=>{let r=await Y(n),i=await r.workflows.getRunDecision(e,t),a=await r.workflows.resolveRunDecision(e,t,{decisionId:i.id,choice:n.choice});if(n.json)return j(a);if(a.resumed){N(`Resolved decision ${a.decisionId} with "${a.choice}" — run ${a.runId} resumed.`);return}N(`Resolved decision ${a.decisionId} with "${a.choice}", but run ${a.runId} had already finished — nothing to resume.`)})}function Sp(e){try{return T(e,`utf8`)}catch(t){throw Error(`Could not read workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function Cp(e){A(e.map(e=>({id:e.id,name:e.name,enabled:e.enabled?`yes`:`no`,issues:e.validationErrors.length,updated:e.updatedAt})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`enabled`,header:`Enabled`},{key:`issues`,header:`Issues`},{key:`updated`,header:`Updated`}])}function wp(e){let t=e.workflows.filter(e=>e.failed>0).length,n=e.workflows.filter(e=>e.failed===0&&e.waiting>0).length,r=e.workflows.filter(e=>e.failed===0&&e.waiting===0&&e.runsInWindow>0).length;N(`${t} failing · ${n} waiting · ${r} healthy · ${e.workflows.length} total over ${e.window}`),A(e.workflows.map(e=>({id:e.id,name:e.name,enabled:e.enabled?`yes`:`no`,runs:e.runsInWindow,failed:e.failed,waiting:e.waiting,success:e.successRate===null?`—`:`${Math.round(e.successRate*100)}%`,lastRun:e.lastRunStatus??`—`,lastRunAt:e.lastRunAt??`—`})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`enabled`,header:`Enabled`},{key:`runs`,header:`Runs`},{key:`failed`,header:`Failed`},{key:`waiting`,header:`Waiting`},{key:`success`,header:`Success`},{key:`lastRun`,header:`Last Run`},{key:`lastRunAt`,header:`Last Run At`}])}function Tp(e){if(F({ID:e.id,Name:e.name,Description:e.description??``,Enabled:e.enabled?`yes`:`no`,Actions:e.actions.length}),e.triggers&&e.triggers.length>0&&(N(`Triggers`),Ep(e.triggers)),e.validationErrors.length>0){N(`Validation issues`);for(let t of e.validationErrors)console.log(` ${t.path}: ${t.message}`)}}function Ep(e){A(e.map(e=>({id:e.id,kind:e.kind,enabled:e.enabled?`yes`:`no`,detail:e.kind===`schedule`?`${e.cron??``} (${e.timezone??``})`:`${e.provider??``}:${e.eventFilter?.event??``}${e.eventFilter?.action?`.${e.eventFilter.action}`:``}`})),[{key:`id`,header:`ID`},{key:`kind`,header:`Kind`},{key:`enabled`,header:`Enabled`},{key:`detail`,header:`Detail`}])}function Dp(e){e.command(`list`).description(`List your workflows`).action(async e=>{let t=await(await Y(e)).workflows.list();if(e.json)return j(t);Cp(t)}),e.command(`fleet`).description(`Fleet overview: every workflow's run tallies over a trailing window, failing-first`).option(`--window <window>`,`Trailing window: 24h, 7d, or 30d`,`7d`).action(async e=>{let t=await(await Y(e)).workflows.fleetInsights({window:e.window});if(e.json)return j(t);wp(t)}),e.command(`get`).description(`Show a workflow's definition and compiled triggers`).argument(`<id>`,`Workflow ID`).option(`--yaml`,`Print only the raw definition YAML (the export path — pipe to a file)`).action(async(e,t)=>{let n=await(await Y(t)).workflows.get(e);if(t.yaml){if(n.definitionYaml===null)throw Error(`Workflow ${n.id} has no stored definition YAML to export`);process.stdout.write(n.definitionYaml.endsWith(`
149
+ `)?n.definitionYaml:`${n.definitionYaml}\n`);return}if(t.json)return j(n);Tp(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=Sp(e),r=await(await Y(t)).workflows.create(n);if(t.json)return j(r);N(`Created workflow ${r.id} (${r.name}).`),Tp(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=Sp(e),r=await Y(t),i=await r.workflows.validate(n,{structural:!0});if(!i.valid){if(process.exitCode=1,t.json)return j(i);N(`Invalid workflow:`);for(let e of i.errors)console.log(` ${e.path}: ${e.message}`);return}let a=(await r.workflows.list()).find(e=>e.name===i.name);if(a){let e=await r.workflows.update(a.id,n);if(t.json)return j({action:`updated`,workflow:e});N(`Updated workflow ${e.id} (${e.name}) — matched by name.`),Tp(e);return}let o=await r.workflows.create(n);if(t.json)return j({action:`created`,workflow:o});N(`Created workflow ${o.id} (${o.name}).`),Tp(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=Sp(t),i=await(await Y(n)).workflows.update(e,r,{...n.note===void 0?{}:{note:n.note}});if(n.json)return j(i);N(`Updated workflow ${i.id} (${i.name}).`),Tp(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`)){N(`Delete cancelled.`);return}if(await(await Y(t)).workflows.delete(e),t.json)return j({deleted:!0,id:e});N(`Deleted workflow ${e}.`)}),e.command(`validate`).description(`Validate a workflow YAML file without saving it`).argument(`<file>`,`Path to the workflow YAML`).option(`--structural`,`CI mode: compile + capability checks only, no connection resolution — the verdict is the same regardless of connected providers`).action(async(e,t)=>{let n=Sp(e),r=await(await Y(t)).workflows.validate(n,{...t.structural?{structural:!0}:{}});if(t.json)return j(r);if(r.valid)N(`Valid: ${r.name} (${r.actionCount} action(s), ${r.triggerCount} trigger(s)).`);else{N(`Invalid workflow:`);for(let e of r.errors)console.log(` ${e.path}: ${e.message}`);process.exitCode=1}}),e.command(`schema`).description(`Print the JSON Schema for the workflow YAML`).action(async e=>{j(await(await Y(e)).workflows.schema())})}async function Op(e,t,n){let r=await(await Y(n)).workflows.setEnabled(e,t);if(n.json)return j(r);N(`${t?`Enabled`:`Disabled`} workflow ${r.id}.`),Tp(r)}function kp(e,t){try{return JSON.parse(e)}catch{throw Error(`Invalid ${t}: not valid JSON`)}}function Ap(e,t){try{me(e,t,`utf8`)}catch(t){throw Error(`Could not write workflow file "${e}": ${t instanceof Error?t.message:String(t)}`)}}function jp(e){A(e.map(e=>({id:e.id,name:e.name,category:e.category,providers:e.providers.join(`, `),summary:e.summary})),[{key:`id`,header:`ID`},{key:`name`,header:`Name`},{key:`category`,header:`Category`},{key:`providers`,header:`Providers`},{key:`summary`,header:`Summary`}])}function Mp(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 Np(e){e.command(`enable`).description(`Enable a workflow so its triggers and manual runs fire`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{await Op(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 Op(e,!1,t)}),e.command(`templates`).description(`List the curated starter workflow templates`).action(async e=>{let t=await(await Y(e)).workflows.listTemplates();if(e.json)return j(t);jp(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.`,mc,[]).option(`--file <out>`,`Write the instantiated workflow YAML to this file instead of stdout`).action(async(e,t)=>{let n=hc(t.param,`param`)??{},r=await(await Y(t)).workflows.instantiateTemplate(e,n);if(t.json)return j(r);if(!r.created){N(`Template ${e} needs provider connections before it can run:`);for(let e of r.connectionRequirements)console.log(` ${e.connected?`✓`:`✗`} ${Mp(e,r.connectionRequirements)}`);process.exitCode=1;return}let{workflow:i}=r;if(i.definitionYaml===null)throw Error(`Workflow ${i.id} was created but the server returned no definition YAML`);if(N(`Created workflow ${i.id} (${i.name}).`),t.file){Ap(t.file,i.definitionYaml),N(`Wrote ${t.file}.`);return}process.stdout.write(i.definitionYaml.endsWith(`
150
+ `)?i.definitionYaml:`${i.definitionYaml}\n`)})}function Pp(e){A(e,[{key:`key`,header:`Key`},{key:`version`,header:`Version`},{key:`updatedAt`,header:`Updated`}])}function Fp(e){F({Key:e.key,Version:e.version,Updated:e.updatedAt}),N(`Value`),j(e.value)}function Ip(e){let t=e.command(`kv`).description(`Read and write a workflow's cross-run KV state`);t.command(`list`).description(`List every KV entry of a workflow`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=await(await Y(t)).workflows.listKv(e);if(t.json)return j(n);Pp(n.entries)}),t.command(`get`).description(`Show one KV entry (value and version)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.getKv(e,t);if(n.json)return j(r);Fp(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=kp(n,`<json>`),a=r.cas===void 0?void 0:ro(r.cas,`--cas`),o=await Y(r),s=a===void 0?await o.workflows.putKv(e,t,i):await o.workflows.casKv(e,t,a,i);if(r.json)return j(s);Fp(s)}),t.command(`delete`).description(`Delete a KV entry (idempotent)`).argument(`<id>`,`Workflow ID`).argument(`<key>`,`KV key`).action(async(e,t,n)=>{let r=await(await Y(n)).workflows.deleteKv(e,t);if(n.json)return j(r);N(r.deleted?`Deleted KV entry "${t}" of workflow ${e}.`:`No KV entry "${t}" on workflow ${e}.`)})}function Lp(e){A(e.map(e=>({rev:e.rev,created:e.createdAt,by:e.createdBy,source:e.source,note:e.note??``})),[{key:`rev`,header:`Rev`},{key:`created`,header:`Created`},{key:`by`,header:`Created By`},{key:`source`,header:`Source`},{key:`note`,header:`Note`}])}function Rp(e){e.command(`revisions`).description(`List a workflow's definition revision history (newest first)`).argument(`<id>`,`Workflow ID`).action(async(e,t)=>{let n=await(await Y(t)).workflows.listRevisions(e);if(t.json)return j(n);Lp(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 Y(n)).workflows.getRevision(e,r);if(n.json)return j(i);F({Revision:i.rev,Created:i.createdAt,"Created by":i.createdBy,Source:i.source,Note:i.note??``}),process.stdout.write(i.yaml.endsWith(`
151
+ `)?i.yaml:`${i.yaml}\n`)}),e.command(`rollback`).description(`Restore a prior revision's definition as a NEW head revision (re-validated)`).argument(`<id>`,`Workflow ID`).argument(`<rev>`,`Revision number to restore`).action(async(e,t,n)=>{let r=ro(t,`<rev>`),i=await(await Y(n)).workflows.rollback(e,r);if(n.json)return j(i);N(`Rolled back workflow ${i.id} to rev ${r}.`),Tp(i)})}function zp(){let e=new b(`workflows`).description(`Create and manage Tangle workflows`);return Dp(e),bc(e),Np(e),Rp(e),Ip(e),yp(e),xp(e),e}function Bp(e){for(let[t,n]of Object.entries(e.optsWithGlobals()))e.getOptionValue(t)===void 0&&n!==void 0&&e.setOptionValue(t,n)}const Vp=e(import.meta.url)(`../package.json`);function Hp(){let e=new b;e.name(`tangle`).description(`CLI for Tangle Sandbox operations`).version(Vp.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)=>{Bp(t);let n=t.opts();Et(n.json===!0||n.ndjson===!0)}),e.addCommand(Ii()),e.addCommand(Yl()),e.addCommand(_p()),e.addCommand(Zl()),e.addCommand($c()),e.addCommand(ll()),e.addCommand(ul()),e.addCommand(Go()),e.addCommand(Vf()),e.addCommand(Hf()),e.addCommand(Wf()),e.addCommand(gi()),e.addCommand(eu()),e.addCommand(gs()),e.addCommand(mp()),e.addCommand(Gf()),e.addCommand(Xf()),e.addCommand(Gi()),e.addCommand(na()),e.addCommand(_l()),e.addCommand(_s()),e.addCommand(bs()),e.addCommand(Nc()),e.addCommand(Is()),e.addCommand(zp()),e.addCommand(Wo()),e.addCommand(Xl()),e.addCommand(Mf()),e.addCommand($l()),e.addCommand(ra()),e.addCommand(hl()),e.addCommand(Pc()),e.addCommand(Lo()),e.addCommand(Ro()),e.addCommand(Cl()),e.addCommand(dl()),e.addCommand(Zf()),e.addCommand(fc());function t(e){e.configureHelp({showGlobalOptions:!0}),e.configureOutput({writeErr:()=>{}}),e.exitOverride(t=>{t.exitCode===0&&process.exit(0),R(t,e.optsWithGlobals().json===!0)});for(let n of e.commands)t(n)}return t(e),e}const Up=Hp();Up.parseAsync(process.argv).catch(e=>{R(e,Up.opts().json===!0)});export{};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-cli",
3
- "version": "0.21.40",
3
+ "version": "0.21.42",
4
4
  "description": "CLI for Tangle Sandbox operations",
5
5
  "type": "module",
6
6
  "engines": {
@@ -23,9 +23,9 @@
23
23
  "@tangle-network/agent-eval": "1.0.0",
24
24
  "@tangle-network/agent-interface": "^5.10.2",
25
25
  "@tangle-network/agent-provider-tangle": "4.5.0",
26
- "@tangle-network/agent-runtime": "2.3.4",
26
+ "@tangle-network/agent-runtime": "2.3.9",
27
27
  "@tangle-network/hub-sdk": "1.0.5",
28
- "@tangle-network/sandbox": "^1.0.52",
28
+ "@tangle-network/sandbox": "^1.0.53",
29
29
  "@tangle-network/sdk-cli-runner": "^0.3.0",
30
30
  "chalk": "^5.6.2",
31
31
  "cli-bridge": "https://github.com/drewstone/cli-bridge/archive/27a9d985a054cab5287e4f1b9d35687e4295f5ca.tar.gz",
@@ -66,8 +66,8 @@
66
66
  "author": "Tangle Network",
67
67
  "license": "MIT",
68
68
  "tangleRelease": {
69
- "sourceSha": "59d5d283c48e1bb21efaa77ccc088d2ea5530fde",
70
- "mergedAt": "2026-10-28T05:39:47-06:00"
69
+ "sourceSha": "63d47e506531a1ed0a1102912ca799cd3df4ae98",
70
+ "mergedAt": "2026-10-28T10:01:26-06:00"
71
71
  },
72
72
  "scripts": {
73
73
  "build": "tsdown",