@typhons/cli 0.2.7

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/cli.js +26 -0
  2. package/package.json +26 -0
package/dist/cli.js ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ import f from"fs";import c from"path";import{fileURLToPath as se}from"url";import{execSync as A,execFileSync as ie}from"child_process";import O from"fs";import E from"path";function G(o){let t=[E.join(o,".devcontainer","devcontainer.json"),E.join(o,".devcontainer.json")];for(let e of t)if(O.existsSync(e))return e;return null}function Q(o){let t=O.readFileSync(o,"utf8");return t=t.replace(/"(?:[^"\\]|\\.)*"|\/\/.*$|\/\*[\s\S]*?\*\//gm,e=>e.startsWith('"')?e:""),t=t.replace(/,\s*([}\]])/g,"$1"),JSON.parse(t)}function j(o){let t=G(o);if(!t)return{jsonPath:null,jsonPathRel:null,workspaceFolder:`/workspaces/${E.basename(o)}`,remoteUser:"root",postCreateCommand:null,postStartCommand:null,service:"app",forwardPorts:[],dockerComposeFile:null};let e=Q(t),s=e.postCreateCommand?typeof e.postCreateCommand=="string"?e.postCreateCommand:Array.isArray(e.postCreateCommand)?e.postCreateCommand.join(" "):Object.values(e.postCreateCommand).join(" && "):null,p=e.postStartCommand?typeof e.postStartCommand=="string"?e.postStartCommand:Array.isArray(e.postStartCommand)?e.postStartCommand.join(" "):Object.values(e.postStartCommand).join(" && "):null;return{jsonPath:t,jsonPathRel:E.relative(o,t),workspaceFolder:e.workspaceFolder||`/workspaces/${E.basename(o)}`,remoteUser:e.remoteUser||"root",postCreateCommand:s,postStartCommand:p,service:e.service||"app",forwardPorts:Array.isArray(e.forwardPorts)?e.forwardPorts.map(Number).filter(g=>g>0):[],dockerComposeFile:e.dockerComposeFile||null}}import _ from"fs";import V from"os";import B from"path";import{execSync as X}from"child_process";import{fileURLToPath as Z}from"url";function U(){throw new Error("Direct template builds are not available in the published CLI. Remove --direct-build flag to use server-proxied builds instead.")}var Se=B.dirname(Z(import.meta.url));function K(o){console.error(`[${new Date().toISOString().slice(11,19)}] ${o}`)}function N(o){return`'${String(o).replace(/'/g,`'"'"'`)}'`}function R(o,t=[]){let e=B.join(V.tmpdir(),`e2b-repo-${Date.now()}.tar.gz`);K("Creating repo tarball...");let s=["node_modules",".codex-worktrees",...t].map(p=>`--exclude=${N(p)}`).join(" ");return X(`tar czf ${N(e)} ${s} .`,{cwd:o,maxBuffer:500*1024*1024,env:{...process.env,COPYFILE_DISABLE:"1"}}),e}async function M(o){let t=R(o.repoDir,o.ignorePatterns);try{return await U({tarballPath:t,mode:"raw",tag:o.tag,remoteUser:o.remoteUser,workspace:o.workspace,script:o.script,startupScript:o.startupScript,sshPublicKey:o.sshPublicKey,cpuCount:o.cpuCount,memoryMB:o.memoryMB,repoBasename:B.basename(o.repoDir),noRepo:o.noRepo,image:o.image},K)}finally{try{_.unlinkSync(t)}catch{}}}async function Y(o){let t=R(o.repoDir,o.ignorePatterns);try{return await U({tarballPath:t,mode:"devcontainer",tag:o.tag,remoteUser:o.remoteUser,workspace:o.workspace,postCreateCommand:o.postCreateCommand,postStartCommand:o.postStartCommand,composeService:o.composeService,sshPublicKey:o.sshPublicKey,cpuCount:o.cpuCount,memoryMB:o.memoryMB,repoBasename:B.basename(o.repoDir)},K)}finally{try{_.unlinkSync(t)}catch{}}}async function L(o){let t=R(o.repoDir,o.ignorePatterns),e=B.resolve(o.repoDir,o.dockerfile),s=_.readFileSync(e,"utf8");try{return await U({tarballPath:t,mode:"dockerfile",tag:o.tag,remoteUser:o.remoteUser,workspace:o.workspace,script:o.script,startupScript:o.startupScript,dockerfileContent:s,sshPublicKey:o.sshPublicKey,cpuCount:o.cpuCount,memoryMB:o.memoryMB,repoBasename:B.basename(o.repoDir)},K)}finally{try{_.unlinkSync(t)}catch{}}}import F from"fs";import ee from"os";import oe from"path";import{execSync as re}from"child_process";function T(o){console.error(`[${new Date().toISOString().slice(11,19)}] ${o}`)}function H(o){return`'${String(o).replace(/'/g,`'"'"'`)}'`}function te(o,t=[]){let e=oe.join(ee.tmpdir(),`repo-upload-${Date.now()}.tar.gz`),s=["node_modules",".codex-worktrees",...t].map(p=>`--exclude=${H(p)}`).join(" ");return re(`tar czf ${H(e)} ${s} .`,{cwd:o,maxBuffer:500*1024*1024,env:{...process.env,COPYFILE_DISABLE:"1"}}),e}async function I({repoDir:o,serverUrl:t,apiKey:e,config:s}){T("Creating repo tarball for upload...");let p=te(o,s.ignorePatterns),g=F.statSync(p).size;T(`Tarball size: ${(g/1024/1024).toFixed(1)} MB`);try{let{FormData:b,Blob:w}=globalThis,$=new b,P=F.readFileSync(p);$.append("tarball",new w([P]),"repo.tar.gz"),$.append("config",JSON.stringify(s)),T(`Uploading to ${t}/api/builds ...`);let y=await fetch(`${t}/api/builds`,{method:"POST",headers:{Authorization:`Bearer ${e}`},body:$});if(!y.ok&&!y.headers.get("content-type")?.includes("text/event-stream")){let d=await y.text(),r;try{r=JSON.parse(d).error}catch{r=d}let i=new Error(`Server build failed (HTTP ${y.status}): ${r}`);throw i.statusCode=y.status,i}let m=y.body.getReader(),h=new TextDecoder,l="",n=null;for(;;){let{done:d,value:r}=await m.read();if(d)break;l+=h.decode(r,{stream:!0});let i=l.split(`
3
+ `);l=i.pop()||"";for(let u of i)if(u.startsWith("data: ")){let S=u.slice(6);try{let a=JSON.parse(S);if(a.type==="log")T(a.message);else if(a.type==="done")n={snapshotId:a.snapshotId,templateId:a.templateId,buildId:a.buildId};else if(a.type==="error")throw new Error(`Server build error: ${a.error}`)}catch(a){if(a.message?.startsWith("Server build error:"))throw a}}}if(!n)throw new Error("Server build ended without returning a result");return n}finally{try{F.unlinkSync(p)}catch{}}}var z=c.dirname(se(import.meta.url));if(!process.argv.includes("--no-update")&&process.env.TYPHONS_NO_UPDATE!=="1")try{let o=c.join(z,"..","package.json"),t=JSON.parse(f.readFileSync(o,"utf8")),e=t.version,s=A(`npm view ${t.name} version 2>/dev/null`,{timeout:1e4}).toString().trim();if(s&&s!==e){console.log(`Updating ${t.name}: ${e} \u2192 ${s}...`),A(`npm install -g ${t.name}@latest`,{timeout:12e4,stdio:"inherit"});let p=[...process.argv.slice(1),"--no-update"];try{ie(process.argv[0],p,{stdio:"inherit"})}catch(g){process.exit(g.status||1)}process.exit(0)}}catch{}var ne=process.argv.filter(o=>o!=="--no-update");function W(o){if(!f.existsSync(o))return{};let t={};for(let e of f.readFileSync(o,"utf8").split(/\r?\n/)){if(!e||/^\s*#/.test(e))continue;let s=e.match(/^\s*([^=]+?)\s*=\s*(.*)\s*$/);if(!s)continue;let p=s[2];(p.startsWith('"')&&p.endsWith('"')||p.startsWith("'")&&p.endsWith("'"))&&(p=p.slice(1,-1)),t[s[1]]=p}return t}async function J(o){if(!process.stdin.isTTY)return null;let t=`${o}/cli/auth`;console.log(""),console.log("Authenticate with the server to continue."),console.log(""),console.log(" Open this URL in your browser and authorize:"),console.log(` ${t}`),console.log("");try{process.platform==="darwin"?A(`open "${t}"`,{stdio:"ignore"}):A(`xdg-open "${t}" 2>/dev/null || true`,{stdio:"ignore"})}catch{}let s=(await import("readline")).createInterface({input:process.stdin,output:process.stdout}),p=await new Promise(w=>s.question("Paste your API key here: ",w));s.close();let g=p.trim();if(!g)return null;let b=c.join(process.env.HOME||"",".config","typhons");return f.mkdirSync(b,{recursive:!0}),f.writeFileSync(c.join(b,"api-key"),g,{mode:384}),console.log(`API key saved to ${c.join(b,"api-key")}`),g}function q(){console.log(`Usage: typhons build [options] <repo-dir>
4
+
5
+ Build a typhon image for a repo. The repo will be copied over
6
+
7
+ Options:
8
+ --image NAME Build from a Docker image (e.g. node:20, python:3.12-slim)
9
+ --script CMD Script to run in dev server (in the repo root) to do setup (e.g. npm install, etc)
10
+ --startup-script CMD Script to run at dev server startup (e.g. start postgres and app server)
11
+ --user USER Remote user (default: from devcontainer.json or 'user')
12
+ --devcontainer Build from a .devcontainer config located in the repo root (use instead of image and script args above, if you prefer using .devcontainer config)
13
+ --cpu COUNT CPU count for template build (default: 1)
14
+ --memory GB Memory in GB for template build (default: 4)
15
+ -t, --tag TAG Template tag/name (default: timestamp)
16
+ -p, --ports PORTS Comma-separated ports (optional - all ports will be reachable via http/ws)
17
+ --ignore PATTERNS Comma-separated glob patterns to exclude from repo tarball
18
+ (in addition to default excludes: node_modules, .codex-worktrees)
19
+ Can be specified multiple times. Uses gitignore-style patterns.
20
+ --ignore-file PATH Path to a file with ignore patterns (one per line, like .gitignore/.dockerignore)
21
+ Lines starting with # are treated as comments. Can be specified multiple times.
22
+ --ssh-key PATH Path to SSH public key file for dev server access (default: SSH_PUBLIC_KEY env)
23
+ --workspace PATH Workspace (repo) path inside dev server (default: /home/user/<repo-basename>)
24
+ --no-repo Don't copy the repo into the dev server
25
+ -h, --help Show this help
26
+ `),process.exit(0)}async function ae(){let o=ne.slice(2);(o.length===0||o[0]==="--help"||o[0]==="-h")&&q();let t=o[0];t!=="build"&&(console.error(`Unknown command: ${t}`),console.error("Available commands: build"),process.exit(1));let e={tag:new Date().toISOString().replace(/[-:T]/g,"").slice(0,8)+"-"+new Date().toISOString().replace(/[-:T]/g,"").slice(8,14),ports:"",apiKey:process.env.BUILD_API_KEY||"",serverUrl:process.env.BUILD_SERVER_URL||"https://www.typhons.dev",directBuild:!1,devcontainer:!1,script:"",dockerfile:"",image:"",startupScript:"",sshKey:"",workspace:"",remoteUser:"",repoDir:"",cpuCount:0,memoryMB:0,noRepo:!1,ignorePatterns:[],ignoreFiles:[]},s=o.slice(1);for(let r=0;r<s.length;r++)switch(s[r]){case"-t":case"--tag":e.tag=s[++r];break;case"-p":case"--ports":e.ports=s[++r];break;case"--api-key":e.apiKey=s[++r];break;case"--server-url":e.serverUrl=s[++r];break;case"--direct-build":e.directBuild=!0;break;case"--devcontainer":e.devcontainer=!0;break;case"--script":e.script=s[++r];break;case"--dockerfile":console.error("Error: --dockerfile is not yet supported. Use --image instead."),process.exit(1);case"--image":e.image=s[++r];break;case"--startup-script":e.startupScript=s[++r];break;case"--ssh-key":e.sshKey=s[++r];break;case"--workspace":e.workspace=s[++r];break;case"--user":case"--remote-user":e.remoteUser=s[++r];break;case"--cpu":e.cpuCount=parseInt(s[++r],10);break;case"--memory":e.memoryMB=Math.round(parseFloat(s[++r])*1024);break;case"--no-repo":e.noRepo=!0;break;case"--ignore":e.ignorePatterns.push(...s[++r].split(","));break;case"--ignore-file":e.ignoreFiles.push(s[++r]);break;case"-h":case"--help":q();break;default:s[r].startsWith("-")&&(console.error(`Unknown option: ${s[r]}`),process.exit(1)),e.repoDir=s[r]}e.repoDir||(console.error("Error: repo directory is required"),process.exit(1)),e.repoDir=c.resolve(e.repoDir);for(let r of e.ignoreFiles){let i=c.resolve(r);f.existsSync(i)||(console.error(`Error: ignore file not found: ${i}`),process.exit(1));let u=f.readFileSync(i,"utf8").split(/\r?\n/);for(let S of u){let a=S.trim();!a||a.startsWith("#")||e.ignorePatterns.push(a)}}if(!e.script&&!e.dockerfile&&!e.image&&!e.devcontainer){let r=j(e.repoDir);if(r.jsonPath)if(process.stdin.isTTY){let u=(await import("readline")).createInterface({input:process.stdin,output:process.stdout});console.log(`.devcontainer detected: ${r.jsonPath}`),console.log(" 1) Use devcontainer (recommended) (pass --devcontainer to skip this prompt)"),console.log(" 2) Raw build (just copy repo, no package install)");let S=await new Promise(C=>u.question("Select build mode [1]: ",C));u.close(),S.trim()==="2"?console.log(""):e.devcontainer=!0}else e.devcontainer=!0;else console.log("No .devcontainer found, making a default build with just the repo and a base image. Pass --script, --startup-script, and/or --image to install dependencies")}let p=c.join(z,".."),g=W(c.join(p,".env")),b=W(c.join(e.repoDir,".env")),w=process.env.HOME||"",$=(f.existsSync(c.join(w,".config","typhons","api-key"))?f.readFileSync(c.join(w,".config","typhons","api-key"),"utf8").trim():"")||(f.existsSync(c.join(w,".config","remote-claude","api-key"))?f.readFileSync(c.join(w,".config","remote-claude","api-key"),"utf8").trim():"");e.apiKey||(e.apiKey=$||g.BUILD_API_KEY||b.BUILD_API_KEY||"");let P=process.env.E2B_API_KEY||process.env.E2B_API_TOKEN||g.E2B_API_KEY||g.E2B_API_TOKEN||"";P&&(process.env.E2B_API_KEY=P);let y=!P&&!e.directBuild&&e.apiKey;if(!P&&!y)if(e.directBuild&&(console.error("Error: E2B_API_KEY or E2B_API_TOKEN is required for --direct-build"),process.exit(1)),!e.apiKey&&process.stdin.isTTY){console.log("No API key found.");let r=await J(e.serverUrl);r||(console.error("No key provided."),process.exit(1)),e.apiKey=r}else e.apiKey||(console.error("Error: E2B_API_KEY or BUILD_API_KEY is required for template builds."),console.error(" Set E2B_API_KEY for direct builds, or BUILD_API_KEY to build via the server."),console.error(" Run without --direct-build to authenticate interactively."),process.exit(1));y=!P&&!e.directBuild&&e.apiKey,e.directBuild&&!P&&(console.error("Error: E2B_API_KEY or E2B_API_TOKEN is required for --direct-build"),process.exit(1));let m="";if(e.sshKey){let r=c.resolve(e.sshKey);f.existsSync(r)||(console.error(`Error: SSH key file not found: ${r}`),process.exit(1)),m=f.readFileSync(r,"utf8").trim()}else m=process.env.SSH_PUBLIC_KEY||g.SSH_PUBLIC_KEY||b.SSH_PUBLIC_KEY||"";if(m){let r=m.split(" "),i=r.length>=3?r[2]:(r[1]||"").slice(0,20)+"...";console.log(`SSH key: ${r[0]} ${i}`)}if(!m){process.stdin.isTTY||(console.error("Error: SSH public key is required. Set SSH_PUBLIC_KEY env var or pass --ssh-key <path>."),process.exit(1));let r=process.env.HOME||"",i=c.join(r,".ssh"),u=[];if(f.existsSync(i))for(let v of f.readdirSync(i).sort())v.endsWith(".pub")&&u.push(v);let a=(await import("readline")).createInterface({input:process.stdin,output:process.stdout}),C=v=>new Promise(D=>a.question(v,D));console.log("SSH public key is required for dev server access."),u.length>0&&console.log("Found keys in ~/.ssh:"),u.forEach((v,D)=>console.log(` ${D+1}) ${v}`)),console.log(" p) Paste a public key"),console.log(" q) Exit");let k=(await C(u.length>0?"Select a key [1]: ":"Select an option: ")).trim();if(k==="q"||k==="Q")a.close(),process.exit(0);else if(k==="p"||k==="P"||u.length===0&&k!=="q")m=(await C("Paste your SSH public key: ")).trim(),(!m||!m.startsWith("ssh-"))&&(console.error("Error: Invalid SSH public key (should start with ssh-ed25519, ssh-rsa, etc.)"),a.close(),process.exit(1));else{let v=k===""?1:parseInt(k,10);if(v>0&&v<=u.length){let D=c.join(i,u[v-1]);m=f.readFileSync(D,"utf8").trim(),console.log(`Using ${u[v-1]}`)}else console.error("Invalid selection."),a.close(),process.exit(1)}a.close()}let h,l,n,d;if(e.dockerfile){let r="",i="";try{let S=f.readFileSync(c.resolve(e.repoDir,e.dockerfile),"utf8");if(!e.remoteUser){let a=S.match(/^\s*USER\s+(\S+)/gmi);a&&(r=a[a.length-1].match(/USER\s+(\S+)/i)[1])}if(!e.startupScript){let a=S.match(/^\s*CMD\s+(.+)$/mi),C=S.match(/^\s*ENTRYPOINT\s+(.+)$/mi),x=a?.[1]||C?.[1]||"";if(x)try{let k=JSON.parse(x);Array.isArray(k)&&(i=k.join(" "))}catch{i=x.trim()}}}catch{}n=e.remoteUser||r||"user",i&&!e.startupScript&&(e.startupScript=i);let u=n==="root"?"/root":`/home/${n}`;if(d=e.workspace||`${u}/${c.basename(e.repoDir)}`,l=e.ports||"",console.log(`==> Building E2B template (Dockerfile mode): ${e.tag}`),console.log(` Dockerfile: ${e.dockerfile}`),console.log(` Workspace: ${d}`),console.log(` Remote user: ${n}`),e.startupScript&&console.log(` Startup script: ${e.startupScript} ${i?"(from Dockerfile CMD)":""}`),l&&console.log(` Ports: ${l}`),console.log(""),y){console.log("==> Building template via server...");let S=f.readFileSync(c.resolve(e.repoDir,e.dockerfile),"utf8");h=await I({repoDir:e.repoDir,serverUrl:e.serverUrl,apiKey:e.apiKey,config:{mode:"dockerfile",tag:e.tag,remoteUser:n,workspace:d,dockerfileContent:S,script:e.script||void 0,startupScript:e.startupScript,ports:l,sshPublicKey:m,cpuCount:e.cpuCount||void 0,memoryMB:e.memoryMB||void 0,repoBasename:c.basename(e.repoDir),ignorePatterns:e.ignorePatterns}})}else console.log("==> Building template from Dockerfile..."),h=await L({repoDir:e.repoDir,workspace:d,tag:e.tag,remoteUser:n,dockerfile:e.dockerfile,script:e.script||void 0,startupScript:e.startupScript,ports:l,sshPublicKey:m,cpuCount:e.cpuCount||void 0,memoryMB:e.memoryMB||void 0,ignorePatterns:e.ignorePatterns})}else if(e.script||e.image){n=e.remoteUser||"user";let r=n==="root"?"/root":`/home/${n}`;d=e.workspace||`${r}/${c.basename(e.repoDir)}`,l=e.ports||"",console.log(`==> Building E2B template (${e.image?"image":"raw"} mode): ${e.tag}`),e.image&&console.log(` Image: ${e.image}`),console.log(` Workspace: ${d}`),console.log(` Remote user: ${n}`),e.script&&console.log(` Script: ${e.script}`),e.startupScript&&console.log(` Startup script: ${e.startupScript}`),l&&console.log(` Ports: ${l}`),console.log(""),y?(console.log("==> Building template via server..."),h=await I({repoDir:e.repoDir,serverUrl:e.serverUrl,apiKey:e.apiKey,config:{mode:"raw",tag:e.tag,remoteUser:n,workspace:d,image:e.image||void 0,script:e.script,startupScript:e.startupScript,ports:l,sshPublicKey:m,cpuCount:e.cpuCount||void 0,memoryMB:e.memoryMB||void 0,repoBasename:c.basename(e.repoDir),ignorePatterns:e.ignorePatterns}})):(console.log("==> Building template..."),h=await M({repoDir:e.repoDir,workspace:d,tag:e.tag,remoteUser:n,image:e.image||void 0,script:e.script,startupScript:e.startupScript,ports:l,sshPublicKey:m,cpuCount:e.cpuCount||void 0,memoryMB:e.memoryMB||void 0,noRepo:e.noRepo,ignorePatterns:e.ignorePatterns}))}else if(e.devcontainer){let r=j(e.repoDir);r.jsonPath?console.log(`==> Found devcontainer config: ${r.jsonPath}`):(console.error("Error: --devcontainer specified but no .devcontainer config found in "+e.repoDir),process.exit(1)),n=e.remoteUser||r.remoteUser,d=e.workspace||r.workspaceFolder,l=e.ports||r.forwardPorts.join(","),console.log(`==> Building E2B template: ${e.tag}`),console.log(` Workspace: ${d}`),console.log(` Remote user: ${n}`),console.log(` Service: ${r.service}`),l&&console.log(` Ports: ${l}`),r.postCreateCommand&&console.log(` postCreateCommand: ${r.postCreateCommand}`),r.postStartCommand&&console.log(` postStartCommand: ${r.postStartCommand}`),console.log(""),y?(console.log("==> Building template via server..."),h=await I({repoDir:e.repoDir,serverUrl:e.serverUrl,apiKey:e.apiKey,config:{mode:"devcontainer",tag:e.tag,remoteUser:n,workspace:d,postCreateCommand:r.postCreateCommand,postStartCommand:r.postStartCommand,composeService:r.service,sshPublicKey:m,cpuCount:e.cpuCount||void 0,memoryMB:e.memoryMB||void 0,repoBasename:c.basename(e.repoDir),ignorePatterns:e.ignorePatterns}})):(console.log("==> Building template..."),h=await Y({repoDir:e.repoDir,workspace:d,tag:e.tag,remoteUser:n,postCreateCommand:r.postCreateCommand,postStartCommand:r.postStartCommand,composeService:r.service,sshPublicKey:m,cpuCount:e.cpuCount||void 0,memoryMB:e.memoryMB||void 0,ignorePatterns:e.ignorePatterns}))}else{n=e.remoteUser||"user";let r=n==="root"?"/root":`/home/${n}`;d=e.workspace||`${r}/${c.basename(e.repoDir)}`,l=e.ports||"",console.log(`==> Building E2B template: ${e.tag}`),console.log(` Workspace: ${d}`),console.log(` Remote user: ${n}`),l&&console.log(` Ports: ${l}`),console.log(""),y?(console.log("==> Building template via server..."),h=await I({repoDir:e.repoDir,serverUrl:e.serverUrl,apiKey:e.apiKey,config:{mode:"raw",tag:e.tag,remoteUser:n,workspace:d,sshPublicKey:m,cpuCount:e.cpuCount||void 0,memoryMB:e.memoryMB||void 0,repoBasename:c.basename(e.repoDir),ignorePatterns:e.ignorePatterns}})):(console.log("==> Building template..."),h=await M({repoDir:e.repoDir,workspace:d,tag:e.tag,remoteUser:n,ports:l,sshPublicKey:m,cpuCount:e.cpuCount||void 0,memoryMB:e.memoryMB||void 0,ignorePatterns:e.ignorePatterns}))}if(console.log(""),console.log(`==> Snapshot ID: ${h.snapshotId}`),e.apiKey){console.log("==> Registering image with server...");let r=l?l.split(",").map(Number).filter(i=>i>0):[];try{let i=await fetch(`${e.serverUrl}/api/images`,{method:"POST",headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({tag:e.tag,image:h.snapshotId,type:e.dockerfile?"e2b-dockerfile":e.script?"e2b-raw":"e2b-devcontainer",build_method:"template",ports:r,cmd:[],remote_user:n,workspace_folder:d,built_at:new Date().toISOString()})});i.ok?console.log("==> Registered successfully"):console.log(`WARNING: Failed to register image with server (HTTP ${i.status})`)}catch(i){console.log(`WARNING: Failed to register image with server: ${i.message}`)}}console.log(""),console.log("==> Done!"),console.log(` Template tag: ${e.tag}`),console.log(` Snapshot ID: ${h.snapshotId}`),console.log(` Remote user: ${n}`),console.log(` Workspace: ${d}`),l&&console.log(` Ports: ${l}`)}ae().catch(async o=>{o.statusCode===401&&process.stdin.isTTY&&(console.error("Authentication failed. Your API key may be invalid or expired."),await J(process.env.BUILD_SERVER_URL||"https://www.typhons.dev")&&console.log("API key updated. Please re-run your build command."),process.exit(1)),console.error("Error:",o.message),process.exit(1)});
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@typhons/cli",
3
+ "version": "0.2.7",
4
+ "description": "CLI for building remote dev environments",
5
+ "type": "module",
6
+ "bin": {
7
+ "typhons": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist/"
11
+ ],
12
+ "scripts": {
13
+ "build": "node scripts/build.mjs",
14
+ "prepublishOnly": "node scripts/build.mjs"
15
+ },
16
+ "dependencies": {
17
+ "e2b": "^2.18.0"
18
+ },
19
+ "devDependencies": {
20
+ "esbuild": "^0.27.4",
21
+ "tsx": "^4.0.0"
22
+ },
23
+ "engines": {
24
+ "node": ">=18"
25
+ }
26
+ }