Skip to content

Commit b0ab7f7

Browse files
authored
fix(cli): add implicit limit to sandbox list (#1164)
<!-- CURSOR_SUMMARY --> > [!NOTE] > **Low Risk** > Low risk: CLI-only behavior change that adds a default cap and minor output messaging; main risk is surprising users who previously relied on unlimited listing unless they pass `--limit 0`. > > **Overview** > Adds an **implicit default limit** to `sandbox list` (now defaults to `1000`, with `--limit 0` meaning no limit) to avoid unbounded sandbox listing. > > Updates `listSandboxes` to return `{ sandboxes, hasMore }` and prints a note in pretty output when results are truncated, while keeping API pagination capped at `100` per page. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 3a29103. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 16c86d1 commit b0ab7f7

File tree

2 files changed

+32
-21
lines changed

2 files changed

+32
-21
lines changed

.changeset/plenty-onions-do.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@e2b/cli': patch
3+
---
4+
5+
Add implicit limit for sandbox list query to CLI

packages/cli/src/commands/sandbox/list.ts

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import { components, Sandbox, SandboxInfo } from 'e2b'
55
import { ensureAPIKey } from 'src/api'
66
import { parseMetadata } from './utils'
77

8+
const DEFAULT_LIMIT = 1000
9+
const PAGE_LIMIT = 100
10+
811
function getStateTitle(state?: components['schemas']['SandboxState'][]) {
912
if (state?.length === 1) {
1013
if (state?.includes('running')) return 'Running sandboxes'
@@ -24,22 +27,29 @@ export const listCommand = new commander.Command('list')
2427
.option('-m, --metadata <metadata>', 'filter by metadata, eg. key1=value1')
2528
.option(
2629
'-l, --limit <limit>',
27-
'limit the number of sandboxes returned',
30+
`limit the number of sandboxes returned (default: ${DEFAULT_LIMIT}, 0 for no limit)`,
2831
(value) => parseInt(value)
2932
)
3033
.option('-f, --format <format>', 'output format, eg. json, pretty')
3134
.action(async (options) => {
3235
try {
3336
const state = options.state || ['running']
3437
const format = options.format || 'pretty'
35-
const sandboxes = await listSandboxes({
36-
limit: options.limit,
38+
const limit =
39+
options.limit === 0 ? undefined : (options.limit ?? DEFAULT_LIMIT)
40+
const { sandboxes, hasMore } = await listSandboxes({
41+
limit,
3742
state,
3843
metadataRaw: options.metadata,
3944
})
4045

4146
if (format === 'pretty') {
4247
renderTable(sandboxes, state)
48+
if (hasMore) {
49+
console.log(
50+
`Showing first ${limit} sandboxes. Use --limit to change.`
51+
)
52+
}
4353
} else if (format === 'json') {
4454
console.log(JSON.stringify(sandboxes, null, 2))
4555
} else {
@@ -130,23 +140,22 @@ type ListSandboxesOptions = {
130140
metadataRaw?: string
131141
}
132142

143+
type ListSandboxesResult = {
144+
sandboxes: SandboxInfo[]
145+
hasMore: boolean
146+
}
147+
133148
export async function listSandboxes({
134149
limit,
135150
state,
136151
metadataRaw,
137-
}: ListSandboxesOptions = {}): Promise<SandboxInfo[]> {
152+
}: ListSandboxesOptions = {}): Promise<ListSandboxesResult> {
138153
const apiKey = ensureAPIKey()
139154
const metadata = parseMetadata(metadataRaw)
140155

141156
let pageLimit = limit
142-
if (!limit || limit > 100) {
143-
pageLimit = 100
144-
}
145-
146-
let remainingLimit = limit
147-
//backwards compatibility
148-
if (limit === 0) {
149-
remainingLimit = undefined
157+
if (!limit || limit > PAGE_LIMIT) {
158+
pageLimit = PAGE_LIMIT
150159
}
151160

152161
const sandboxes: SandboxInfo[] = []
@@ -156,17 +165,14 @@ export async function listSandboxes({
156165
query: { state, metadata },
157166
})
158167

159-
while (
160-
iterator.hasNext &&
161-
(remainingLimit === undefined || remainingLimit > 0)
162-
) {
168+
while (iterator.hasNext && (!limit || sandboxes.length < limit)) {
163169
const batch = await iterator.nextItems()
164170
sandboxes.push(...batch)
165-
166-
if (limit && remainingLimit) {
167-
remainingLimit -= batch.length
168-
}
169171
}
170172

171-
return sandboxes
173+
return {
174+
sandboxes: limit ? sandboxes.slice(0, limit) : sandboxes,
175+
// We can't change the page size during iteration, so we may have to check if we have more sandboxes than the limit
176+
hasMore: iterator.hasNext || (limit ? sandboxes.length > limit : false),
177+
}
172178
}

0 commit comments

Comments
 (0)