@tangle-network/sandbox-cli 0.22.78 → 0.22.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -168,8 +168,8 @@ git init -q --bare -b main "$2.partial" && git --git-dir "$g" push -q "$2.partia
168
168
  mv "$2.partial" "$2"`,i,a);let l=h(t.id),u=j(ee,`remotes`,`${l.upstream}.git`),{issueTitle:d,issueBodyClean:f}=l,p=`https://github.com/${l.upstream}/issues/${l.issue}`,m=JSON.stringify({title:d,body:f,url:p,state:`OPEN`}),[g,_]=[];try{await Yc(`rm -rf "$2" && git clone -q --bare "$1" "$2" && printf %s "$4" > "$2/tangle-issue-$3.json"`,a,u,`${l.issue}`,m);try{let t={param:v(l,i),json:!0,...n&&{seat:n}},a=await Ql(e.file,t,{signal:r});g=`runId`in a?a.runId:void 0;let o=JSON.parse(`text`in a?a.text:`{}`);_=Object.values(o).find(e=>e?.json?.branch)?.json?.branch}catch(e){let n=e;if(n.code!==`GRAPH_RUN_FAILED`)throw e;if(e.runtimeFailures?.some(({failure:e})=>el(e)))throw new et(t.id,{cause:e});g=n.runId}let o=j(M(),`.tangle`,`runs`,`${g}`),d=(await s(o)).map(e=>e.toolName).find(e=>/web.?(search|fetch)/i.test(e));d&&C.abort(Error(`${g} called ${d}: not offline`)),C.signal.throwIfAborted();let f=_?await Yc(`b=$(git --git-dir "$1" rev-parse main); git --git-dir "$2" diff --binary "$b" "$3"`,a,u,_):``,p=await c(o),h=p&&Uc(p).tokenUsage;return{patch:f,tokens:h?.input!=null&&h.output!=null?{inputTokens:h.input??0,outputTokens:h.output??0}:$c(e.cap),...g&&{runId:g}}}finally{let e=g&&(await sc(g)).cwd;await Ke(u,{recursive:!0,force:!0}),e?.startsWith(`${Zc}/`)&&await Ke(e,{recursive:!0})}},w=await o.benchmarkScenarios(S,[d]),T=new Set(w.slice(0,n.probe).map(e=>e.id)),E=n.reps??1,D=[...Array(E).keys()],O=[...T].flatMap(e=>D.flatMap(t=>b.map((n,r)=>`${r}|${e}:${t}`))),ne=new Map,re=new Map(O.map(e=>[e,new Promise(t=>ne.set(e,t))])),ie=new Map([...T].map(e=>[e,E*b.length])),ae=b.map(async(e,r)=>{let a=`${e.digest}:${n.seat.join(`,`)}`,s=j(Xc,`base`,ql(`${t}:${d}:${a}`));if(d===`holdout`){await Ve(s,{recursive:!0});let e={at:new Date,reason:n.unseal,arms:l};await qe(j(s,`holdout-access.jsonl`),`${JSON.stringify(e)}\n`,{flag:`a`})}return i({scenarios:w,reps:E,runDir:s,resumable:!0,dispatchRef:a,cellFilter:e=>T.has(e.scenario.id),judges:[o.benchmarkJudge(S)],maxConcurrency:3,signal:C.signal,dispatchTimeoutMs:4*36e5,onCellSettled:async(e,{id:t,item:n})=>{e.cached&&ne.get(`${r}|${e.cellId}`)?.(),ie.set(t,(ie.get(t)??1)-1),ie.get(t)||await o.releaseCaseEnvironment(n,{host:x})},dispatch:async(t,i)=>{let a=O.indexOf(`${r}|${i.cellId}`),o=n.seat[a%n.seat.length],s=o??`graph-default`;try{await Promise.all(O.slice(0,a).map(e=>re.get(e)));let n=await i.cost.runPaidCall({actor:e.file,model:s,signal:i.signal,maximumCharge:{model:s,inputTokens:0,outputTokens:e.cap},execute:n=>te(e,t.item,{seat:o,signal:n}),receipt:({tokens:e})=>({model:s,...e}),receiptFromError:()=>({model:s,...$c(e.cap)})});if(!n.succeeded)throw n.error;return n.value}finally{ne.get(`${r}|${i.cellId}`)?.()}}})}),k=await Promise.all(ae);if(C.signal.aborted)throw C.signal.reason;let oe=e=>e.reduce((e,t)=>e+t,0)/e.length,se=k.map((e,t)=>{let n=e.cells.filter(e=>!e.error),r=e=>Object.values(e.judgeScores)[0]?.composite??0,i=n.filter(e=>e.rep===0),o=i.filter(e=>r(e)>=1).length,s=e.cells.filter(e=>e.error),{inputTokens:c,outputTokens:u,usageComplete:d}=e.aggregates.cost;return{graph:l[t],resolved:o,n:i.length,runDir:e.runDir,wilson95:a(o,i.length),unmeasured:s.map(e=>`${e.cellId}: ${e.error}`),tokens:c+u,usageComplete:d,rewards:Object.fromEntries(n.map(e=>[e.cellId,r(e)]))}}),ce=({rewards:e},t)=>D.flatMap(n=>e[`${t}:${n}`]??[]),[le,...ue]=se,de=ue.map((e,t)=>{let n=[...T].filter(t=>ce(le,t).length&&ce(e,t).length),i=[...new Set(n.map(e=>h(e).upstream))],a=i.map(e=>n.filter(t=>h(t).upstream===e)),o=e=>a.map(t=>oe(t.map(t=>oe(ce(e,t))))),[s,c]=[o(le),o(e)],u=r(s,c,{continuous:!0}),{n:d,minimumPairs:f,low:p,threshold:m}=u,g=u.promote?void 0:!u.sufficient&&`insufficient pairs: n ${d} < minimumPairs ${f}`||p<=m&&`interval low ${p} ≤ threshold ${m}`||u.exactTestVetoes&&`McNemar exact test vetoes`||`indeterminate interval`;return{arm:l[t+1],cases:n.length,repos:i.length,rates:[oe(s),oe(c)],delta:u.delta,method:u.method,interval95:[u.low,u.high],sufficient:u.sufficient,decision:u.promote?`promote`:`hold`,why:g}});I({split:n.split,arms:se,paired:de})}async function rl(e,t,n){try{let r=await Ql(e,{param:t,json:!0,...n});return`runId`in r?r.runId:void 0}catch(e){if(e.code!==`GRAPH_RUN_FAILED`)throw e;return e.runId}}const il=async(e,t)=>JSON.parse(await Yc(`cat "$(ls -t "$1"/*/"$2".json | head -1)"`,j(Qc,`${e}`,`graph-evidence`),t));async function al(e,t){let n=await sc(e),r=await We(n.file,`utf8`),i=await Yc(`cd "$1"; jq -c '{kind,reason,nodes:[.tree.nodes[]|select(.status!="done")|{label,status,failure}]}' result.json
169
169
  jq -c 'select(.valid==false)|{node:.nodeName,exit:.exitCode,tail:.output[-3000:]}' command-checks.jsonl 2>/dev/null || :
170
170
  for f in $(ls -tr graph-evidence/*/*.json 2>/dev/null); do printf '%s ' "$(basename "$f")"; tail -c 2000 "$f"; echo; done | tail -c 24000`,j(Qc,e)),a=[`from`,`branch`,`failure`,`approved_head`],o=Object.entries(n.params).filter(([e])=>!a.includes(e)).map(([e,t])=>`${e}=${typeof t==`string`?t:JSON.stringify(t)}`),s=JSON.stringify({records:i,graph:r}),c=[...o,`from=diagnose`,`failure=${s}`],l=await rl(n.file,c,t),u=await il(l,`diagnose`),d={run:e,diagnoseRun:l,verdict:u};if(u.owner!==`graph`||!u.patch)return I(d);let f=j(Xc,`repairs`,e);await Ve(f,{recursive:!0});let p=j(f,`graph.yaml`);await qe(p,r),await qe(j(f,`patch.diff`),u.patch),await Yc(`patch -s -p1 -d "$1" -i "$1/patch.diff"`,f);let m=async e=>{let t=await Ql(e,{param:o,dryRun:!0});if(!(`graph`in t))throw Error(`${e} did not load locally`);let{nodes:n,deliverable:r,edges:i}=t.graph,a=e=>i.filter(t=>[`from`in t&&t.from,t.to].flat().includes(e)),s=n.filter(e=>e.check).map(e=>[e.id,e.check,a(e.id)]);return JSON.stringify([r,s])};if(await m(n.file)!==await m(p))return I({...d,refused:`patch touches a check; not resumed`});let{branch:h,test:g}=(await il(e,`intake`)).json??{},{from:_=`intake`,failure:v,approved_head:y}=u.resume??{},b=[`from=${_}`];_!==`intake`&&b.push(`branch=${h}`),`test`in n.params||b.push(`test=${g}`),v&&b.push(`failure=${v}`),y&&b.push(`approved_head=${y}`);let ee=await rl(p,[...o,...b],t);I({...d,patched:p,resumed:ee})}function ol(e){e.command(`repair <run>`).description(`Diagnose a failed local graph run; patch and resume it when the graph owns the fix`).option(`--seat-command <program>`,`Executable that prints the account id`).action(al);let t=(e,t)=>[...t,e];e.command(`improve <graph> [dataset]`).description(`Measure graph arms on js-issues by offline replay`).option(`--arm <graph>`,`Another arm, interleaved; repeatable`,t,[]).option(`--split <split>`,`train, or test (needs --unseal)`,`train`).option(`--unseal <reason>`,`Read the sealed test split, logging why`).option(`--probe <n>`,`Stop after the first n cases`,Number).option(`--reps <n>`,`Reps of every case per arm (default 1)`,Number).option(`--seat <seat>`,`Replay seat; repeatable, one per replay`,t,[]).option(`--docker-host <ssh>`,`Build, verify and grade on this ssh host`).action((e,t,n)=>nl(e,t??j(Xc,`js-issues`),n))}const sl=1e5;function Q(e){throw new V(`GRAPH_INVALID`,`Graph creation failed`,e,`tangle graph new --help`)}function cl(e){return typeof e==`string`&&/^[a-z0-9][a-z0-9-]{0,62}$/i.test(e)}const ll={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 ul=class{owned;lastFailure;pending=Promise.resolve();revision=0;sealed=!1;constructor(e,t,n){this.directory=e,this.options=t,this.cwd=n}async digest(e=this.owned){e||Q(`No graph file was saved`);let t=await Ue(e.file,se.O_RDONLY|se.O_NOFOLLOW);try{let[n,r]=await Promise.all([t.stat(),e.handle.stat()]);return(!n.isFile()||n.dev!==r.dev||n.ino!==r.ino)&&Q(`The owned graph file was replaced`),ql(await t.readFile())}finally{await t.close()}}enqueue(e){let t=++this.revision,n=this.pending.then(()=>e(t));return this.pending=n.then(()=>void 0,()=>void 0),n}check=()=>this.enqueue(async e=>{let t=this.owned;if(!t?.result)return!1;let{digest:n,result:r}=t,i=await this.digest(t),a=this.revision===e&&this.owned===t&&t.digest===n&&t.result===r&&i===n;return a&&(this.sealed=!0),a});receipt(){this.owned?.result||Q(`No successful graph run was recorded`);let{file:e,digest:t,result:n}=this.owned;return{file:e,digest:t,result:n}}invoke(e,t){return this.sealed&&Q(`The graph is accepted; submit its recorded successful run`),this.enqueue(()=>this.write(e,t)).catch(e=>(this.lastFailure=e,{ok:!1,diagnostic:$t(e)}))}async write(e,t){t.throwIfAborted(),this.lastFailure=void 0;let n=e;(!n||!cl(n.name)||typeof n.source!=`string`||typeof n.run!=`boolean`||Object.keys(n).some(e=>![`name`,`source`,`run`].includes(e)))&&Q(`Expected only name, source and boolean run`),this.options.name!==void 0&&n.name!==this.options.name&&Q(`The graph name must match --name`),this.owned&&(this.owned.result=void 0);let r=j(this.directory,`${n.name}.yaml`);if(this.owned&&this.owned.file!==r&&Q(`This invocation owns one named graph file`),!this.owned)try{this.owned={file:r,handle:await Ue(r,se.O_RDWR|se.O_CREAT|se.O_EXCL|se.O_NOFOLLOW,384),digest:ql(``)}}catch(e){throw e.code===`EEXIST`&&Q(`Graph already exists: ${r}; choose another --name`),e}let i=this.owned;await this.digest()!==i.digest&&Q(`The owned graph was changed`);let a=Buffer.from(n.source);for(let e=0;e<a.length;){let{bytesWritten:t}=await i.handle.write(a,e,a.length-e,e);if(!t)throw Error(`Graph file write made no progress`);e+=t}await i.handle.truncate(a.length),await i.handle.sync(),i.digest=ql(a);let o={...this.options,param:[]},s={cwd:this.cwd,signal:t,source:n.source},c=await Ql(r,{...o,dryRun:!0},{...s,connectNeeds:!0});`graph`in c||Q(`No canonical graph was returned`),c.graph.deliverable.checkRef===`command`&&Q(`Host command checks need a jailed verifier node`);let{nodes:l,edges:u,budget:d}=c.graph,f=u.reduce((e,t)=>e+(`maxTraversals`in t?(t.maxTraversals??1)-1:0),l.length),p=(f+1)*sl;if(d?.maxTokens!==void 0&&d.maxTokens<p&&Q(`budget.maxTokens ${d.maxTokens} is below ${p}: ${f} agent spawns plus one reservation at ${sl} tokens per native turn`),await this.digest()!==i.digest&&Q(`Graph changed during validation`),!n.run)return{file:r,graphDigest:c.graph.digest,validated:!0};let m=await Ql(r,o,{...s,graphDigest:c.graph.digest});return(!(`status`in m)||m.status!==`winner`||m.graphDigest!==c.graph.digest||await this.digest()!==i.digest)&&Q(`The graph must succeed with unchanged YAML`),i.result=m,this.receipt()}async close(){await this.pending,await this.owned?.handle.close()}};async function dl(e,t,n){let{runId:r,runDir:i,cwd:a,bridge:o,signal:s}=e,c=await o(),l=j(await Ge(j(M(),`.tangle`)),`graphs`);(Jl(a,l)||Jl(l,a))&&Q(`The graph store must be outside the agent workspace; choose another working directory`);try{await Ve(l,{mode:448})}catch(e){if(e.code!==`EEXIST`)throw e}await Ge(l)!==l&&Q(`The graph store redirects outside its canonical location`);let u=n.seat??Vn().seat,d=await dc(a,s)(u,{node:`graph-designer`,cwd:a,signal:s,lastCandidate:!0});d||Q(`No authenticated native subscription is available`);let{graphDesignerProfile:f}=await import(`@tangle-network/agent-runtime/profiles`),{supervisePursuit:p}=await import(`@tangle-network/agent-runtime/durable`),m=f({profile:{name:`graph-designer`,harness:d.harness,model:{provider:d.provider,default:d.model,...d.reasoningEffort===void 0?{}:{reasoningEffort:d.reasoningEffort}},prompt:{instructions:[`You are the sole graph designer. Author a canonical YAML graph for the requested intent, then qualify and run it using write_graph. Its nodes are complete AgentProfiles with a real independent verifier and declarative route/data outside check. Command checks execute on the host and are refused here; put executable verification in the verifier node's normal native tools. Read the supplied skills and preserve the user's task and authority.`,`Call write_graph with name, complete YAML source and run:false to validate; repair its concrete diagnostics, then call it with the identical source and run:true. The graph schema and executor are owned by the installed loader. Supply defaults for parameters needed by the first run. Only a real successful host run of the unchanged saved file passes. Submit that evidence using submit_result; explain concrete blockers using report_blocked.`]},tools:{agent_runtime_coordination_write_graph:!0,agent_runtime_coordination_submit_result:!0,agent_runtime_coordination_read_continuation:!0,agent_runtime_coordination_report_blocked:!0}}}),h=ne(m),g=new ul(l,{...n,seat:u},a),_={maxIterations:6,maxTokens:2e6,deadlineMs:9e5};try{let e=await p(m,{intent:t,name:n.name},{pursuitId:r,runId:r,runDir:i,signal:s,backend:{...c,timeoutMs:_.deadlineMs},budget:_,maxDepth:0,coordination:{authentication:!0,requestTimeoutMs:_.deadlineMs},deliverable:{describe:`The saved graph succeeds with unchanged YAML`,check:g.check,checkState:g.check},continuation:ll,resolveSupervisorTools:e=>e.runId!==r||e.nodeId!==r||e.depth!==0||e.identity.profileDigest!==h?[]:[{name:`write_graph`,description:`Save, validate and run this graph.`,inputSchema:{type:`object`,properties:{name:{type:`string`},source:{type:`string`},run:{type:`boolean`}},required:[`name`,`source`,`run`],additionalProperties:!1},handler:(t,n)=>((n.nodeId!==e.nodeId||n.ownerId!==e.ownerId||n.runId!==e.runId)&&Q(`Wrong graph tool owner`),g.invoke(t,n.signal))}]});if(e.result.kind===`no-winner`||!await g.check()){if(g.lastFailure)throw g.lastFailure;let t=e.result.kind===`no-winner`?e.result.error?.message??e.result.reason:`The graph file changed after its successful run`;throw Object.assign(new V(`GRAPH_DESIGN_FAILED`,`Graph design did not finish`,t,`tangle graph new --help`),{runId:r,node:`graph-designer`})}return g.receipt()}finally{await g.close()}}function fl(e){e.command(`new <intent>`).description(`Design, validate and run one portable graph`).option(`--seat <seat>`,`Use harness/model@effort for the designer and graph`).option(`--name <name>`,`Save this graph name`).action(async(e,t)=>{process.env.BRIDGE_JAIL_RW_PATHS?.trim()&&Q(`Remove BRIDGE_JAIL_RW_PATHS before graph new; extra native write roots cannot contain its host store`),t.name!==void 0&&!cl(t.name)&&Q(`Use letters, numbers and hyphens in --name`);let n=await Xl({},n=>dl(n,e,t));t.json?I(n):R(`Created ${n.file} · run ${n.result.runId}`)})}const pl=e=>e===void 0?[]:(Array.isArray(e)?e:[e]).map(String),ml=(e=``)=>{let t=e.replace(/\s+/g,` `).trim(),n=t.match(/^.+?[.!?](?=\s|$)/)?.[0]??t;return n.length>90?`${n.slice(0,89)}…`:n},hl=e=>e&&(e.all??[e]).map(e=>{let t=`equals`in e?`= ${JSON.stringify(e.equals)}`:`in`in e?`∈ ${JSON.stringify(e.in)}`:e.exists===!1?`absent`:`exists`;return`${e.node??``}${e.pointer||`/`} ${t}`}).join(` and `);function gl(e,t){try{let n=rt(t,{uniqueKeys:!0,strict:!0}),r=[...n.errors,...n.warnings][0];if(r)throw r;let i=he(e)===`.json`?JSON.parse(t):n.toJS();if(Array.isArray(i?.nodes)&&Array.isArray(i.edges))return i;throw Error(`A graph needs nodes and edges lists`)}catch(t){throw new V(`GRAPH_INVALID`,`Graph file ${e} cannot be read`,t.message,`tangle graph show --help`)}}function _l(e,t){let n=gl(e,t),r=e=>{let t=String(e).match(/^\$\{params\.([\w-]+)\}$/)?.[1];return t?`${n.params?.[t]?.default??`?`} (params.${t})`:e},i=n.nodes.map(e=>{if(e.check){let t=String(e.check.command??``),n=t.match(RegExp(`#\\s*${e.id}:\\s*(.+)`))?.[1],r=t.split(`
171
- `).find(e=>e.trim()&&!/^\s*#/.test(e));return{id:e.id,kind:`check`,detail:ml(n??`$ ${r}`)}}let t=[e.profile?.harness,e.profile?.model?.default],n=pl(e.seat).join(` › `)||t.filter(Boolean).join(` · `),r=ml(e.profile?.prompt?.systemPrompt),i=[n||`default seat`,r].filter(Boolean).join(`
172
- `);return{id:e.id,kind:`agent`,detail:i}});for(let e of n.gates??[]){let t=pl(e.choices).join(` | `);i.push({id:e.id,kind:`gate`,detail:`${t}\n${e.question}`})}let a=pl(n.entry?.map(e=>e.node??e)),o=[];if(a.length){i.unshift({id:`start`,kind:`start`,detail:``});let e=a.length>1?`fork`:``;o.push({from:[`start`],to:a,label:e,loop:!1})}for(let e of n.edges){let t=e.to?.finish===void 0?`stop`:`finish`,a=e.to?.[t]===void 0?void 0:`${t}:${e.to[t]}`,s=a===void 0?pl(e.to??e.join):[a];a&&!i.some(e=>e.id===a)&&i.push({id:a,kind:t,detail:``});let c=pl(e.kind===`analyzes`?e.over:e.from),l=n.edges.some(t=>!e.when&&t.when&&pl(t.from).join()===c.join()),u=e.maxTraversals!==void 0,d=[hl(e.when)??(l?`otherwise`:e.kind?.replace(`routes`,``)),c.length>1&&`join`,s.length>1&&`fork`,u&&`↺ loop ≤${r(e.maxTraversals)}`];o.push({from:c,to:s,label:d.filter(Boolean).join(` · `),loop:u})}let s=n.check??{},c=[[`params`,Object.entries(n.params??{}).map(([e,t])=>`${e}${`default`in t?`=${JSON.stringify(t.default)}`:` (required)`}`).join(`, `)],[`workspace`,n.workspace],[`done when`,s.command?.command??s.command??hl(s.all||s.pointer?s:void 0)],[``,s.describe]];return{name:n.graph??e.replace(/^.*\/|(\.graph)?\.(ya?ml|json)$/g,``),describe:n.describe?.trim(),facts:c.filter(e=>e[1]),nodes:i,edges:o}}const vl={start:[`▶`,b.green],agent:[`●`,b.cyan.bold],check:[`▣`,b.yellow.bold],gate:[`◇`,b.magenta.bold],finish:[`✓`,b.green.bold],stop:[`■`,b.red.bold]};function yl(e){let t=t=>e.nodes.find(e=>e.id===t)?.kind??`agent`,n=e=>{let[n,r]=vl[t(e)];return r(`${n} ${e.replace(/^(finish|stop):/,``)}`)},r=Math.max(...e.nodes.map(e=>e.id.length))+4,i=[`${b.bold(`◆ ${e.name}`)}`,...e.describe?[` ${e.describe}`]:[],``];for(let[t,n]of e.facts)i.push(` ${b.dim(t.padEnd(10))} ${n}`);i.push(``,b.bold(`NODES`));for(let t of e.nodes.filter(e=>[`agent`,`check`,`gate`].includes(e.kind))){let[e,...a]=t.detail.split(`
171
+ `).find(e=>e.trim()&&!/^\s*#/.test(e)),i=ml(n??`$ ${r}`);return{id:e.id,kind:`check`,detail:i,body:t.trim()}}let t=[e.profile?.harness,e.profile?.model?.default],n=pl(e.seat).join(` › `)||t.filter(Boolean).join(` · `),r=e.profile?.prompt?.systemPrompt?.trim(),i=ml(r),a=[n||`default seat`,i].filter(Boolean).join(`
172
+ `);return{id:e.id,kind:`agent`,detail:a,body:r}});for(let e of n.gates??[]){let t=pl(e.choices).join(` | `);i.push({id:e.id,kind:`gate`,detail:`${t}\n${e.question}`})}let a=pl(n.entry?.map(e=>e.node??e)),o=[];if(a.length){i.unshift({id:`start`,kind:`start`,detail:``});let e=a.length>1?`fork`:``;o.push({from:[`start`],to:a,label:e,loop:!1})}for(let e of n.edges){let t=e.to?.finish===void 0?`stop`:`finish`,a=e.to?.[t]===void 0?void 0:`${t}:${e.to[t]}`,s=a===void 0?pl(e.to??e.join):[a];a&&!i.some(e=>e.id===a)&&i.push({id:a,kind:t,detail:``});let c=pl(e.kind===`analyzes`?e.over:e.from),l=n.edges.some(t=>!e.when&&t.when&&pl(t.from).join()===c.join()),u=e.maxTraversals!==void 0,d=[hl(e.when)??(l?`otherwise`:e.kind?.replace(`routes`,``)),c.length>1&&`join`,s.length>1&&`fork`,u&&`↺ loop ≤${r(e.maxTraversals)}`];o.push({from:c,to:s,label:d.filter(Boolean).join(` · `),loop:u})}let s=n.check??{},c=[[`params`,Object.entries(n.params??{}).map(([e,t])=>`${e}${`default`in t?`=${JSON.stringify(t.default)}`:` (required)`}`).join(`, `)],[`workspace`,n.workspace],[`done when`,s.command?.command??s.command??hl(s.all||s.pointer?s:void 0)],[``,s.describe]];return{name:n.graph??e.replace(/^.*\/|(\.graph)?\.(ya?ml|json)$/g,``),describe:n.describe?.trim(),facts:c.filter(e=>e[1]),nodes:i,edges:o}}const vl={start:[`▶`,b.green],agent:[`●`,b.cyan.bold],check:[`▣`,b.yellow.bold],gate:[`◇`,b.magenta.bold],finish:[`✓`,b.green.bold],stop:[`■`,b.red.bold]};function yl(e){let t=t=>e.nodes.find(e=>e.id===t)?.kind??`agent`,n=e=>{let[n,r]=vl[t(e)];return r(`${n} ${e.replace(/^(finish|stop):/,``)}`)},r=Math.max(...e.nodes.map(e=>e.id.length))+4,i=[`${b.bold(`◆ ${e.name}`)}`,...e.describe?[` ${e.describe}`]:[],``];for(let[t,n]of e.facts)i.push(` ${b.dim(t.padEnd(10))} ${n}`);i.push(``,b.bold(`NODES`));for(let t of e.nodes.filter(e=>[`agent`,`check`,`gate`].includes(e.kind))){let[e,...a]=t.detail.split(`
173
173
  `);i.push(` ${n(t.id)}${` `.repeat(Math.max(1,r-t.id.length))}${e}`);for(let e of a)i.push(`${` `.repeat(r+4)}${b.dim(e)}`)}i.push(``,b.bold(`FLOW`));for(let t of e.edges){let e=` ${t.from.map(n).join(b.dim(` + `))} ${b.dim(`─▶`)} ${t.to.map(n).join(b.dim(` ∥ `))}`,r=t.loop?b.magenta(t.label):b.blue(t.label);i.push(...t.label.length+Ze(e).length>100?[e,` ${r}`]:[`${e} ${r}`])}return i.join(`
174
174
  `)}async function bl(e,t){let n=j(t,`dist`,`graph-show`),[r,i]=await Promise.all([`viewer.iife.js`,`styles.css`].map(e=>We(j(n,e),`utf8`))),a=(e=``)=>e.replace(/<\/(script)/gi,`<\\/$1`).replace(/<!--/g,`<\\!--`),o=e.name.replace(/[^\w.-]+/g,`-`),s=`<!doctype html><html lang="en"><head><meta charset="utf-8"><title>${o} · tangle graph</title>
175
175
  <meta name="description" content="${(e.describe??o).replace(/[&<>"]/g,``)}">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-cli",
3
- "version": "0.22.78",
3
+ "version": "0.22.80",
4
4
  "description": "CLI for Tangle Sandbox operations",
5
5
  "type": "module",
6
6
  "engines": {
@@ -26,7 +26,7 @@
26
26
  "@tangle-network/agent-runtime": "^9.0.3",
27
27
  "@tangle-network/harness-sessions": "^1.0.2",
28
28
  "@tangle-network/hub-sdk": "1.0.26",
29
- "@tangle-network/sandbox": "^1.0.356",
29
+ "@tangle-network/sandbox": "^1.0.358",
30
30
  "@tangle-network/sdk-cli-runner": "^0.3.12",
31
31
  "chalk": "^5.6.2",
32
32
  "cli-bridge": "https://github.com/drewstone/cli-bridge/archive/6c215f6912dc65ab6145d4102fee744d7fd09b79.tar.gz",
@@ -59,8 +59,8 @@
59
59
  "tsx": "^4.23.15",
60
60
  "typescript": "^6.0.3",
61
61
  "vitest": "^4.1.12",
62
- "@repo/shared": "0.0.0",
63
- "@tangle-network/runtime-contracts": "0.20.0"
62
+ "@tangle-network/runtime-contracts": "0.20.0",
63
+ "@repo/shared": "0.0.0"
64
64
  },
65
65
  "publishConfig": {
66
66
  "access": "public",
@@ -84,8 +84,8 @@
84
84
  "author": "Tangle Network",
85
85
  "license": "MIT",
86
86
  "tangleRelease": {
87
- "sourceSha": "53971bb1d13c5401cab1d48e1ce86a4801062855",
88
- "mergedAt": "2026-11-09T17:39:37-08:00"
87
+ "sourceSha": "a8b4845ca412f331d1089273862d166ae8f60c95",
88
+ "mergedAt": "2026-11-10T11:02:57-08:00"
89
89
  },
90
90
  "scripts": {
91
91
  "build": "tsdown",