@sanlabs/sanbox-cli 0.0.12 → 0.0.13

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/README.md CHANGED
@@ -15,7 +15,10 @@ installed_cli_version="$(sanbox --version)"
15
15
  test "$installed_cli_version" = "$latest_cli_version"
16
16
  ```
17
17
 
18
- Always use the latest published CLI. CLI 0.0.12 adopts the Stop, Resume, and Delete lifecycle,
18
+ Always use the latest published CLI. CLI 0.0.13 allows service templates to start without an
19
+ initial task, including OpenCode Computers that are ready for later SDK steering, and supports
20
+ Custom OpenAI Proxy providers when creating templates, including Browser Use templates.
21
+ CLI 0.0.12 adopted the Stop, Resume, and Delete lifecycle,
19
22
  separates run state from execution outcome, retains scrubbed deleted-run tombstones, and adds
20
23
  administrator-confirmed template deletion.
21
24
  CLI 0.0.11 added OpenCode Computer templates and short-lived native SDK connections for HTTP, SSE
@@ -128,7 +131,8 @@ and `--force` so scripts cannot remove a template accidentally.
128
131
  ## Create A Browser Use Template
129
132
 
130
133
  Browser Use runs local headless Chromium inside the Firecracker sandbox. It requires OpenAI,
131
- Anthropic, Google Gemini, or Hetzner Inference and at least one explicit browser target:
134
+ Anthropic, Google Gemini, Hetzner Inference, or a Custom OpenAI Proxy and at least one
135
+ explicit browser target:
132
136
 
133
137
  ```bash
134
138
  sanbox templates create \
@@ -151,6 +155,8 @@ allowed downloads. Browser Use templates are one-shot agent executions.
151
155
 
152
156
  ## Run Idempotently
153
157
 
158
+ Task templates require a positional task or `--task`. Service templates may omit it:
159
+
154
160
  ```bash
155
161
  sanbox run "Review this repo and write output/report.md" \
156
162
  --input src/ \
@@ -163,8 +169,18 @@ sanbox run "Review this repo and write output/report.md" \
163
169
  --input src/ \
164
170
  --wait \
165
171
  --json
172
+
173
+ sanbox run \
174
+ --template "<service-template-id>" \
175
+ --external-run-id "<stable-service-id>" \
176
+ --json
166
177
  ```
167
178
 
179
+ A taskless OpenCode Computer starts `opencode serve` without making an initial model call. A
180
+ taskless Hermes service starts its gateways and waits for WebUI or configured channel messages.
181
+ Supplying instructions starts the initial OpenCode task or seeds Hermes's persistent operating
182
+ context, preserving the existing behavior.
183
+
168
184
  Repeat `--input` for files, directories, or globs. The CLI excludes common secrets and applies `.sanboxignore`. `--include` is a deprecated compatibility alias.
169
185
 
170
186
  For a Hermes template that allows `email`, optionally request an address from one of the AgentMail
@@ -289,8 +305,9 @@ authenticated WebSocket. The temporary key is deleted when the connection closes
289
305
  user token is not passed to the OpenSSH child process.
290
306
 
291
307
  OpenCode and Browser Use runs are one-shot agent executions. OpenCode Computer keeps its private
292
- server running after the initial task so it can accept later steering. A persisted task workspace can
293
- still be fresh-booted manually for inspection after the run stops.
308
+ server running so it can accept later steering; when an initial task is supplied, Sanbox submits it
309
+ after the server becomes ready. A persisted task workspace can still be fresh-booted manually for
310
+ inspection after the run stops.
294
311
 
295
312
  ## Connect The OpenCode SDK
296
313
 
package/dist/cli.js CHANGED
@@ -44,6 +44,7 @@ Commands:
44
44
  sanbox templates delete <template-id> --force [--json]
45
45
  sanbox run "task" --template <template-id> [--email-address <address>] [--telegram-bot-token <token>] [--telegram-allowed-user <id>] [--input <path>] [--wait | --watch] [--json | --jsonl]
46
46
  sanbox run --task "..." --template <template-id> [--email-address <address>] [--telegram-bot-token <token>] [--telegram-allowed-user <id>] [--input <path>] [--wait | --watch] [--json | --jsonl]
47
+ sanbox run --template <service-template-id> [--email-address <address>] [--telegram-bot-token <token>] [--telegram-allowed-user <id>] [--json]
47
48
  sanbox batch --tasks tasks.json --template <template-id> [--input <path>] [--max-parallel 5] [--wait] [--json]
48
49
  sanbox runs list [--limit 50] [--json]
49
50
  sanbox runs get <run-id> [--json]
@@ -93,8 +94,10 @@ const runHelp = `Sanbox run
93
94
  Usage:
94
95
  sanbox run "Review these files" --template <template-id> --input report.pdf --input data/ --wait
95
96
  sanbox run --task "Review these files" --template <template-id> --input report.pdf --wait --json
97
+ sanbox run --template <service-template-id> --json
96
98
 
97
99
  Options:
100
+ --task <instruction> Required for task templates; optional for service templates.
98
101
  --input <path> File, directory, or glob to upload. Repeatable.
99
102
  --template <id> Template id or slug. Required unless SANBOX_TEMPLATE or project config sets it.
100
103
  --external-run-id <id> Idempotency key for retries.
@@ -726,8 +729,6 @@ const commandRun = async (command, flags) => {
726
729
  throw new CliError("conflicting_arguments", "Use either --task or a positional task, not both.");
727
730
  }
728
731
  const task = runTask(command, flags);
729
- if (!task)
730
- throw new Error("--task or a positional task is required.");
731
732
  if (hasFlag(flags, "wait") && wantsWatch(flags)) {
732
733
  throw new Error("--wait cannot be combined with --watch or --jsonl.");
733
734
  }
@@ -771,7 +772,7 @@ const commandRun = async (command, flags) => {
771
772
  try {
772
773
  payload = await createRun(client, {
773
774
  cwd: cwd(),
774
- instruction: task,
775
+ instruction: task || undefined,
775
776
  inputs: flagList(flags, "input"),
776
777
  externalRunId: flagString(flags, "external-run-id") || undefined,
777
778
  supabaseUserId: supabaseUserId || undefined,
@@ -1198,6 +1199,9 @@ const commandTemplates = async (command, flags) => {
1198
1199
  if (harness === "opencode" && mode === "computer" && llmBudgetUsd !== undefined) {
1199
1200
  throw new CliError("opencode_computer_budget_unsupported", "OpenCode Computer templates do not support --llm-budget-usd yet.");
1200
1201
  }
1202
+ if (modelProvider === "custom" && llmBudgetUsd !== undefined) {
1203
+ throw new CliError("custom_provider_budget_unsupported", "Custom OpenAI Proxy providers do not support --llm-budget-usd yet.");
1204
+ }
1201
1205
  const channels = [...new Set(flagList(flags, "channel").map((value) => value.trim()).filter(Boolean))];
1202
1206
  if (channels.some((channel) => channel !== "email" && channel !== "telegram")) {
1203
1207
  throw new CliError("invalid_hermes_channels", "--channel must be email or telegram.");
@@ -1218,8 +1222,9 @@ const commandTemplates = async (command, flags) => {
1218
1222
  modelProvider !== "openai" &&
1219
1223
  modelProvider !== "anthropic" &&
1220
1224
  modelProvider !== "google" &&
1221
- modelProvider !== "hetzner") {
1222
- throw new CliError("browser_use_provider_unsupported", "Browser Use templates require --model-provider openai, anthropic, google, or hetzner.");
1225
+ modelProvider !== "hetzner" &&
1226
+ modelProvider !== "custom") {
1227
+ throw new CliError("browser_use_provider_unsupported", "Browser Use templates require --model-provider openai, anthropic, google, hetzner, or custom.");
1223
1228
  }
1224
1229
  const browserDomains = harness === "browser-use"
1225
1230
  ? parseBrowserDomains(flagList(flags, "browser-domain"))
package/dist/runs.js CHANGED
@@ -52,7 +52,7 @@ export const createRun = async (client, options) => {
52
52
  return client.createRun({
53
53
  external_run_id: options.externalRunId,
54
54
  workload_id: options.templateId,
55
- instruction: options.instruction,
55
+ ...(options.instruction ? { instruction: options.instruction } : {}),
56
56
  ...(options.supabaseUserId ? { supabase_user_id: options.supabaseUserId } : {}),
57
57
  ...(options.emailAddress ? { email_address: options.emailAddress } : {}),
58
58
  ...(options.telegramBotToken ? {
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = "0.0.12";
1
+ export const version = "0.0.13";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanlabs/sanbox-cli",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",