From 8f28280c4c92c739093d29ec36112bfe7e81086c Mon Sep 17 00:00:00 2001 From: ben-fornefeld Date: Fri, 1 Aug 2025 16:58:31 +0200 Subject: [PATCH 1/6] Add sandbox inspection URL and enhance spawn command output --- packages/cli/src/commands/sandbox/spawn.ts | 41 ++++++++++++++++------ packages/cli/src/user.ts | 4 +++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/packages/cli/src/commands/sandbox/spawn.ts b/packages/cli/src/commands/sandbox/spawn.ts index 584034985a..0451149a16 100644 --- a/packages/cli/src/commands/sandbox/spawn.ts +++ b/packages/cli/src/commands/sandbox/spawn.ts @@ -8,13 +8,14 @@ import { asBold, asFormattedSandboxTemplate } from 'src/utils/format' import { getRoot } from '../../utils/filesystem' import { getConfigPath, loadConfig } from '../../config' import fs from 'fs' -import { configOption, pathOption } from '../../options' +import { configOption, pathOption, teamOption } from '../../options' +import { getUserConfig, SANDBOX_INSPECT_URL } from '../../user' export const spawnCommand = new commander.Command('spawn') .description('spawn sandbox and connect terminal to it') .argument( '[template]', - `spawn and connect to sandbox specified by ${asBold('[template]')}`, + `spawn and connect to sandbox specified by ${asBold('[template]')}` ) .addOption(pathOption) .addOption(configOption) @@ -26,7 +27,7 @@ export const spawnCommand = new commander.Command('spawn') name?: string path?: string config?: string - }, + } ) => { try { const apiKey = ensureAPIKey() @@ -49,15 +50,15 @@ export const spawnCommand = new commander.Command('spawn') ? [config.template_name] : undefined, }, - relativeConfigPath, - )}`, + relativeConfigPath + )}` ) templateID = config.template_id } if (!templateID) { console.error( - 'You need to specify sandbox template ID or path to sandbox template config', + 'You need to specify sandbox template ID or path to sandbox template config' ) process.exit(1) } @@ -68,7 +69,7 @@ export const spawnCommand = new commander.Command('spawn') console.error(err) process.exit(1) } - }, + } ) export async function connectSandbox({ @@ -80,6 +81,24 @@ export async function connectSandbox({ }) { const sandbox = await e2b.Sandbox.create(template.templateID, { apiKey }) + const userConfig = getUserConfig() + + if (userConfig) { + const teamId = userConfig.teamId + + if (teamId) { + const url = SANDBOX_INSPECT_URL(teamId, sandbox.sandboxId) + const clickable = `\u001b]8;;${url}\u0007${url}\u001b]8;;\u0007` + + console.log('') + console.log( + 'Use the following link to inspect this Sandbox live inside the E2B Dashboard️:' + ) + console.log(` \x1b[38;5;208m${clickable}\x1b[0m`) + console.log('') + } + } + // keep-alive loop const intervalId = setInterval(async () => { await sandbox.setTimeout(30_000) @@ -87,8 +106,8 @@ export async function connectSandbox({ console.log( `Terminal connecting to template ${asFormattedSandboxTemplate( - template, - )} with sandbox ID ${asBold(`${sandbox.sandboxId}`)}`, + template + )} with sandbox ID ${asBold(`${sandbox.sandboxId}`)}` ) try { await spawnConnectedTerminal(sandbox) @@ -97,8 +116,8 @@ export async function connectSandbox({ await sandbox.kill() console.log( `Closing terminal connection to template ${asFormattedSandboxTemplate( - template, - )} with sandbox ID ${asBold(`${sandbox.sandboxId}`)}`, + template + )} with sandbox ID ${asBold(`${sandbox.sandboxId}`)}` ) } } diff --git a/packages/cli/src/user.ts b/packages/cli/src/user.ts index fc3217fe02..5339c98372 100644 --- a/packages/cli/src/user.ts +++ b/packages/cli/src/user.ts @@ -28,6 +28,10 @@ export const USER_CONFIG_PATH = path.join(os.homedir(), '.e2b', 'config.json') / export const DOCS_BASE = process.env.E2B_DOCS_BASE || `https://${process.env.E2B_DOMAIN || 'e2b.dev'}/docs` +export const SANDBOX_INSPECT_URL = (teamId: string, sandboxId: string) => + `https://${ + process.env.E2B_DOMAIN || 'e2b.dev' + }/dashboard/${teamId}/sandboxes/${sandboxId}/inspect` export function getUserConfig(): UserConfig | null { if (!fs.existsSync(USER_CONFIG_PATH)) return null From 08d22210c1f7a067125f1504102a0c2848850f99 Mon Sep 17 00:00:00 2001 From: ben-fornefeld Date: Fri, 1 Aug 2025 17:06:35 +0200 Subject: [PATCH 2/6] Refactor sandbox connection logging and improve output formatting --- packages/cli/src/commands/sandbox/spawn.ts | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/cli/src/commands/sandbox/spawn.ts b/packages/cli/src/commands/sandbox/spawn.ts index 0451149a16..0602472337 100644 --- a/packages/cli/src/commands/sandbox/spawn.ts +++ b/packages/cli/src/commands/sandbox/spawn.ts @@ -63,7 +63,10 @@ export const spawnCommand = new commander.Command('spawn') process.exit(1) } - await connectSandbox({ apiKey, template: { templateID } }) + await connectSandbox({ + apiKey, + template: { templateID }, + }) process.exit(0) } catch (err: any) { console.error(err) @@ -82,21 +85,18 @@ export async function connectSandbox({ const sandbox = await e2b.Sandbox.create(template.templateID, { apiKey }) const userConfig = getUserConfig() + const teamId = userConfig?.teamId - if (userConfig) { - const teamId = userConfig.teamId + if (teamId) { + const url = SANDBOX_INSPECT_URL(teamId, sandbox.sandboxId) + const clickable = `\u001b]8;;${url}\u0007${url}\u001b]8;;\u0007` - if (teamId) { - const url = SANDBOX_INSPECT_URL(teamId, sandbox.sandboxId) - const clickable = `\u001b]8;;${url}\u0007${url}\u001b]8;;\u0007` - - console.log('') - console.log( - 'Use the following link to inspect this Sandbox live inside the E2B Dashboard️:' - ) - console.log(` \x1b[38;5;208m${clickable}\x1b[0m`) - console.log('') - } + console.log('') + console.log( + 'Use the following link to inspect this Sandbox live inside the E2B Dashboard️:' + ) + console.log(`↪\x1b[38;5;208m${clickable}\x1b[0m`) + console.log('') } // keep-alive loop From d359a90ed551c9c5e2ad231cf98ba93c2da6f3fd Mon Sep 17 00:00:00 2001 From: ben-fornefeld Date: Fri, 1 Aug 2025 17:07:45 +0200 Subject: [PATCH 3/6] Improve sandbox connection logging format for better readability --- packages/cli/src/commands/sandbox/spawn.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/sandbox/spawn.ts b/packages/cli/src/commands/sandbox/spawn.ts index 0602472337..e54353e11c 100644 --- a/packages/cli/src/commands/sandbox/spawn.ts +++ b/packages/cli/src/commands/sandbox/spawn.ts @@ -95,7 +95,7 @@ export async function connectSandbox({ console.log( 'Use the following link to inspect this Sandbox live inside the E2B Dashboard️:' ) - console.log(`↪\x1b[38;5;208m${clickable}\x1b[0m`) + console.log(`\x1b[38;5;208m↪ ${clickable}\x1b[0m`) console.log('') } From 470e28eadd4f98f8ef24aea7d14783381945f349 Mon Sep 17 00:00:00 2001 From: ben-fornefeld Date: Fri, 1 Aug 2025 17:09:56 +0200 Subject: [PATCH 4/6] chore: create changeset --- .changeset/orange-hotels-worry.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/orange-hotels-worry.md diff --git a/.changeset/orange-hotels-worry.md b/.changeset/orange-hotels-worry.md new file mode 100644 index 0000000000..7be734515d --- /dev/null +++ b/.changeset/orange-hotels-worry.md @@ -0,0 +1,5 @@ +--- +'@e2b/cli': patch +--- + +Returns a url to inspect a spawned sandbox inside the dashboard. From 5f9a93a13d658e75be7aadf6614fc9988fd9fc5b Mon Sep 17 00:00:00 2001 From: ben-fornefeld Date: Fri, 1 Aug 2025 17:14:29 +0200 Subject: [PATCH 5/6] chore: remove unused import --- packages/cli/src/commands/sandbox/spawn.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/sandbox/spawn.ts b/packages/cli/src/commands/sandbox/spawn.ts index e54353e11c..1b92db6de4 100644 --- a/packages/cli/src/commands/sandbox/spawn.ts +++ b/packages/cli/src/commands/sandbox/spawn.ts @@ -8,7 +8,7 @@ import { asBold, asFormattedSandboxTemplate } from 'src/utils/format' import { getRoot } from '../../utils/filesystem' import { getConfigPath, loadConfig } from '../../config' import fs from 'fs' -import { configOption, pathOption, teamOption } from '../../options' +import { configOption, pathOption } from '../../options' import { getUserConfig, SANDBOX_INSPECT_URL } from '../../user' export const spawnCommand = new commander.Command('spawn') From 32a2abbdc49f0002bd9dfd10b493aa0911f87ed1 Mon Sep 17 00:00:00 2001 From: ben-fornefeld Date: Mon, 15 Sep 2025 14:50:31 +0200 Subject: [PATCH 6/6] refactor: sandbox inspection url printing - Introduced a new utility function `printDashboardSandboxInspectUrl` to streamline the process of generating and printing the sandbox inspection URL. - Updated the `createCommand` function to utilize the new utility instead of the previous direct URL construction method. - Added a new constant `DASHBOARD_BASE` for better URL management. --- packages/cli/src/commands/sandbox/create.ts | 12 ++--------- packages/cli/src/user.ts | 9 +++++--- packages/cli/src/utils/urls.ts | 23 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 packages/cli/src/utils/urls.ts diff --git a/packages/cli/src/commands/sandbox/create.ts b/packages/cli/src/commands/sandbox/create.ts index 2602d2109d..51c00b47c7 100644 --- a/packages/cli/src/commands/sandbox/create.ts +++ b/packages/cli/src/commands/sandbox/create.ts @@ -9,7 +9,7 @@ import { getRoot } from '../../utils/filesystem' import { getConfigPath, loadConfig } from '../../config' import fs from 'fs' import { configOption, pathOption } from '../../options' -import { SANDBOX_INSPECT_URL } from 'src/user' +import { printDashboardSandboxInspectUrl } from 'src/utils/urls' export function createCommand( name: string, @@ -92,15 +92,7 @@ export async function connectSandbox({ }) { const sandbox = await e2b.Sandbox.create(template.templateID, { apiKey }) - const url = SANDBOX_INSPECT_URL(sandbox.sandboxId) - const clickable = `\u001b]8;;${url}\u0007${url}\u001b]8;;\u0007` - - console.log('') - console.log( - 'Use the following link to inspect this Sandbox live inside the E2B Dashboard️:' - ) - console.log(`\x1b[38;5;208m↪ ${clickable}\x1b[0m`) - console.log('') + printDashboardSandboxInspectUrl(sandbox.sandboxId) // keep-alive loop const intervalId = setInterval(async () => { diff --git a/packages/cli/src/user.ts b/packages/cli/src/user.ts index 74ab816951..be1e86d8c0 100644 --- a/packages/cli/src/user.ts +++ b/packages/cli/src/user.ts @@ -15,14 +15,17 @@ export interface UserConfig { } export const USER_CONFIG_PATH = path.join(os.homedir(), '.e2b', 'config.json') // TODO: Keep in Keychain + export const DOCS_BASE = process.env.E2B_DOCS_BASE || `https://${process.env.E2B_DOMAIN || 'e2b.dev'}/docs` +export const DASHBOARD_BASE = + process.env.E2B_DASHBOARD_BASE || + `https://${process.env.E2B_DOMAIN || 'e2b.dev'}/dashboard` + export const SANDBOX_INSPECT_URL = (sandboxId: string) => - `https://${ - process.env.E2B_DOMAIN || 'e2b.dev' - }/dashboard/inspect/${sandboxId}` + `${DASHBOARD_BASE}/inspect/sandbox/${sandboxId}` export function getUserConfig(): UserConfig | null { if (!fs.existsSync(USER_CONFIG_PATH)) return null diff --git a/packages/cli/src/utils/urls.ts b/packages/cli/src/utils/urls.ts new file mode 100644 index 0000000000..083099fdbc --- /dev/null +++ b/packages/cli/src/utils/urls.ts @@ -0,0 +1,23 @@ +import { SANDBOX_INSPECT_URL } from 'src/user' +import { asPrimary } from './format' + +/** + * Prints a clickable URL to the E2B Dashboard for inspecting a sandbox + * + * This function creates a terminal-clickable link that allows users to + * inspect their sandbox in the E2B Dashboard. The link is formatted with + * ANSI escape sequences to make it clickable in compatible terminals. + * + * @param {string} sandboxId - The ID of the sandbox to inspect + */ +export const printDashboardSandboxInspectUrl = (sandboxId: string) => { + const url = SANDBOX_INSPECT_URL(sandboxId) + const clickable = `\u001b]8;;${url}\u0007${url}\u001b]8;;\u0007` + + console.log('') + console.log( + 'Use the following link to inspect this Sandbox live inside the E2B Dashboard️:' + ) + console.log(asPrimary(`↪ ${clickable}`)) + console.log('') +}