@typhons/sandbox-tools 0.5.0 → 0.5.1
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/clone.js +1 -1
- package/package.json +1 -1
package/clone.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import m from"fs";import S from"crypto";import{setTimeout as
|
|
2
|
+
import m from"fs";import S from"crypto";import{setTimeout as f}from"timers/promises";var l="",n="",i=process.env.TYPHONS_SERVER||"https://www.typhons.dev",t="",r=process.argv.slice(2).map(e=>e.replace(/[\x00-\x1f\x7f]/g,""));for(let e=0;e<r.length;e++)switch(r[e]){case"--name":case"-n":l=r[++e];break;case"--box":case"-b":n=r[++e];break;case"--server":case"-s":i=r[++e];break;case"--api-key":case"-k":t=r[++e];break;case"-h":case"--help":console.log("Usage: clone NAME [--api-key KEY]"),console.log(""),console.log("Clone the current dev server."),console.log("If NAME is omitted, auto-generates a name."),process.exit(0);default:r[e].startsWith("-")||(l=r[e])}if(!t)for(let e of[`${process.env.HOME}/.config/typhons/api-key`,`${process.env.HOME}/.config/remote-claude/api-key`])try{t=m.readFileSync(e,"utf8").trim();break}catch{}!t&&process.env.TYPHONS_API_KEY&&(t=process.env.TYPHONS_API_KEY);t||(console.error("Error: No API key found."),console.error(" Set TYPHONS_API_KEY, pass --api-key, or save to ~/.config/typhons/api-key"),process.exit(1));if(!n){let e="";try{e=m.readFileSync("/run/e2b/.E2B_SANDBOX_ID","utf8").trim()}catch{}if(e)try{let a=(await(await fetch(`${i}/api/machines`,{headers:{Authorization:`Bearer ${t}`},signal:AbortSignal.timeout(1e4)})).json()).find(d=>d.machine?.sandboxId===e||d.sandboxId===e);a&&(n=a.app?.name||a.devboxName||"")}catch{}n||(console.error("Error: Could not detect current dev server."),console.error(` sandbox_id=${e}, server=${i}`),process.exit(1))}var x=process.env.USER||"root",g=i.match(/https?:\/\/[^.]*\.(.+?)(?::\d+)?$/),b=g?g[1]:"d.typhons.dev",_=b.replace(/^d\./,"");function $(){try{return m.readFileSync("/run/e2b/.E2B_SANDBOX_ID","utf8").trim()}catch{}return""}async function h(e,s,p){try{let a={method:e,headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},signal:AbortSignal.timeout(5e3)};return p&&(a.body=JSON.stringify(p)),await(await fetch(`${i}${s}`,a)).json()}catch{return{}}}function u(e){console.log(`Clone ready: ${e}`),console.log(` ssh ${x}.${e}@ssh.${_}`),console.log(` https://${e}.${b}:PORT`)}console.log(`Cloning ${n}...`);var v=S.randomBytes(24).toString("base64url").slice(0,32);function E(){let e={idempotencyKey:v},s=$();return s&&(e.sandboxId=s),l&&(e.name=l),e}var o=await h("POST",`/api/machines/${n}/clone`,E()),c=o.jobId||"";c||(o.error&&(console.error(`Error: ${o.error}`),process.exit(1)),o.name&&(u(o.name),process.exit(0)));var y="";for(let e=0;e<120;e++){if(!c&&(o=await h("POST",`/api/machines/${n}/clone`,E()),c=o.jobId||"",o.status==="ready"&&(u(o.name),process.exit(0)),o.status==="you_are_the_clone"&&(console.log(`You are the clone (${o.name}).`),process.exit(0)),!c)){await f(1e3);continue}o=await h("GET",`/api/clone-jobs/${c}`);let s=o.status||"";if(s===""){await f(500);continue}if(s!==y){switch(s){case"snapshotting":console.log("Snapshotting... (the current dev server will briefly freeze)");break;case"creating":console.log("Snapshot done, cloning to new machine...");break;case"registering":console.log("Waiting for clone to be ready...");break;case"auth":break;case"ready":u(o.name),process.exit(0);case"failed":console.error(`Error: ${o.error||"Clone failed"}`),process.exit(1)}y=s}await f(1e3)}console.error("Error: Clone did not complete within 2 minutes");process.exit(1);
|