Rename to sandbox

This commit is contained in:
f-trycua
2025-11-18 13:11:29 +01:00
parent baea04339b
commit 77e765b6af
5 changed files with 37 additions and 38 deletions

View File

@@ -22,18 +22,17 @@ bun run ./index.ts -- --help
- `cua auth pull` writes/updates `.env` with `CUA_API_KEY`
- `cua auth logout` clears stored API key
- **VMs**
- `cua vm list`
- `cua vm create --os OS --configuration SIZE --region REGION` creates a new VM
- **Sandboxes**
- `cua sandbox list` (aliases: `ls`, `ps`)
- `cua sandbox create --os OS --configuration SIZE --region REGION` creates a new sandbox
- OS: `linux`, `windows`, `macos`
- SIZE: `small`, `medium`, `large`
- REGION: `north-america`, `europe`, `asia-pacific`, `south-america`
- `cua vm delete NAME` deletes a VM
- `cua vm start NAME`
- `cua vm stop NAME`
- `cua vm restart NAME`
- `cua vm vnc NAME` opens NoVNC URL in your browser
- `cua vm chat NAME` opens Dashboard Playground for the VM
- `cua sandbox delete NAME` deletes a sandbox
- `cua sandbox start NAME`
- `cua sandbox stop NAME`
- `cua sandbox restart NAME`
- `cua sandbox open NAME` opens NoVNC URL in your browser
## Auth Flow (Dynamic Callback Port)
@@ -49,7 +48,7 @@ bun run ./index.ts -- --help
- `index.ts` entry point (shebang + start CLI)
- `src/cli.ts` yargs bootstrapping
- `src/commands/auth.ts` auth/login/pull/logout commands
- `src/commands/vm.ts` vm list/start/stop/restart commands
- `src/commands/sandbox.ts` sandbox list/start/stop/restart commands
- `src/auth.ts` browser flow + local callback server (dynamic port)
- `src/http.ts` HTTP helper
- `src/storage.ts` SQLite-backed key-value storage
@@ -72,5 +71,5 @@ export CUA_API_BASE=https://api.staging.cua.ai
export CUA_WEBSITE_URL=https://staging.cua.ai
cua auth login
cua vm chat my-vm # opens https://staging.cua.ai/dashboard/playground?...
cua sandbox open my-sandbox # opens NoVNC for the sandbox
```

View File

@@ -2,7 +2,7 @@
"name": "@trycua/cli",
"version": "0.1.2",
"packageManager": "bun@1.1.38",
"description": "Command-line interface for CUA cloud VMs and authentication",
"description": "Command-line interface for CUA cloud sandboxes and authentication",
"type": "module",
"license": "MIT",
"homepage": "https://github.com/trycua/cua/tree/main/libs/typescript/cua-cli",

View File

@@ -1,11 +1,11 @@
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { registerAuthCommands } from './commands/auth';
import { registerVmCommands } from './commands/vm';
import { registerSandboxCommands } from './commands/sandbox';
export async function runCli() {
let argv = yargs(hideBin(process.argv)).scriptName('cua');
argv = registerAuthCommands(argv);
argv = registerVmCommands(argv);
argv = registerSandboxCommands(argv);
await argv.demandCommand(1).strict().help().parseAsync();
}

View File

@@ -3,10 +3,10 @@ import { ensureApiKeyInteractive } from '../auth';
import { WEBSITE_URL } from '../config';
import { http } from '../http';
import { clearApiKey } from '../storage';
import type { VmItem } from '../util';
import { openInBrowser, printVmList } from '../util';
import type { SandboxItem } from '../util';
import { openInBrowser, printSandboxList } from '../util';
export function registerVmCommands(y: Argv) {
export function registerSandboxCommands(y: Argv) {
return y
.command(
['list', 'ls', 'ps'],
@@ -29,8 +29,8 @@ export function registerVmCommands(y: Argv) {
console.error(`Request failed: ${res.status}`);
process.exit(1);
}
const data = (await res.json()) as VmItem[];
printVmList(data, Boolean(argv['show-passwords']));
const data = (await res.json()) as SandboxItem[];
printSandboxList(data, Boolean(argv['show-passwords']));
}
)
.command(
@@ -266,17 +266,17 @@ export function registerVmCommands(y: Argv) {
console.error(`Request failed: ${listRes.status}`);
process.exit(1);
}
const vms = (await listRes.json()) as VmItem[];
const vm = vms.find((v) => v.name === name);
if (!vm) {
const sandboxes = (await listRes.json()) as SandboxItem[];
const sandbox = sandboxes.find((s) => s.name === name);
if (!sandbox) {
console.error('Sandbox not found');
process.exit(1);
}
const host =
vm.host && vm.host.length
? vm.host
: `${vm.name}.containers.cloud.trycua.com`;
const url = `https://${host}/vnc.html?autoconnect=true&password=${encodeURIComponent(vm.password)}`;
sandbox.host && sandbox.host.length
? sandbox.host
: `${sandbox.name}.containers.cloud.trycua.com`;
const url = `https://${host}/vnc.html?autoconnect=true&password=${encodeURIComponent(sandbox.password)}`;
console.log(`Opening NoVNC: ${url}`);
await openInBrowser(url);
}
@@ -298,18 +298,18 @@ export function registerVmCommands(y: Argv) {
// console.error(`Request failed: ${listRes.status}`);
// process.exit(1);
// }
// const vms = (await listRes.json()) as VmItem[];
// const vm = vms.find((v) => v.name === name);
// if (!vm) {
// const sandboxes = (await listRes.json()) as SandboxItem[];
// const sandbox = sandboxes.find((s) => s.name === name);
// if (!sandbox) {
// console.error('Sandbox not found');
// process.exit(1);
// }
// const host =
// vm.host && vm.host.length
// ? vm.host
// : `${vm.name}.containers.cloud.trycua.com`;
// sandbox.host && sandbox.host.length
// ? sandbox.host
// : `${sandbox.name}.containers.cloud.trycua.com`;
// const base = WEBSITE_URL.replace(/\/$/, '');
// const url = `${base}/dashboard/playground?host=${encodeURIComponent(host)}&id=${encodeURIComponent(vm.name)}&name=${encodeURIComponent(vm.name)}&vnc_password=${encodeURIComponent(vm.password)}&fullscreen=true`;
// const url = `${base}/dashboard/playground?host=${encodeURIComponent(host)}&id=${encodeURIComponent(sandbox.name)}&name=${encodeURIComponent(sandbox.name)}&vnc_password=${encodeURIComponent(sandbox.password)}&fullscreen=true`;
// console.log(`Opening Playground: ${url}`);
// await openInBrowser(url);
// }

View File

@@ -12,20 +12,20 @@ export async function writeEnvFile(cwd: string, key: string) {
return path;
}
export type VmStatus =
export type SandboxStatus =
| 'pending'
| 'running'
| 'stopped'
| 'terminated'
| 'failed';
export type VmItem = {
export type SandboxItem = {
name: string;
password: string;
status: VmStatus;
status: SandboxStatus;
host?: string;
};
export function printVmList(items: VmItem[], showPasswords: boolean = false) {
export function printSandboxList(items: SandboxItem[], showPasswords: boolean = false) {
const headers = showPasswords
? ['NAME', 'STATUS', 'PASSWORD', 'HOST']
: ['NAME', 'STATUS', 'HOST'];
@@ -49,7 +49,7 @@ export function printVmList(items: VmItem[], showPasswords: boolean = false) {
for (const r of rows)
console.log(r.map((c, i) => (c ?? '').padEnd(widths[i] ?? 0)).join(' '));
if (items.length === 0) console.log('No VMs found');
if (items.length === 0) console.log('No sandboxes found');
}
export async function openInBrowser(url: string) {