@sanlabs/sanbox-cli 0.0.15 → 0.0.16
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 +10 -2
- package/dist/cli.js +38 -129
- package/dist/skill.js +82 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# Sanbox CLI
|
|
2
2
|
|
|
3
|
+
Fetch the LLM guide with `sanbox skill` through `/v1/skill`, which validates `SANBOX_API_KEY` from the agent environment. `/agent.md` remains public for older clients and direct links; the new CLI does not fall back to that route. `sanbox skill --write` saves the current guide to `.sanbox/agent.md`. `sanbox init agent` remains a deprecated alias; `sanbox init` writes only a bootstrap pointer. Set `SANBOX_API_URL` to your console's API origin for staging or self-hosted installations. Remote origins require HTTPS; development HTTP is limited to literal loopback.
|
|
4
|
+
|
|
3
5
|
Run isolated Sanbox agent tasks from a terminal, CI job, or autonomous coding agent.
|
|
4
6
|
|
|
5
7
|
Sanbox packages a task and selected inputs, starts an isolated runner, streams events, and keeps the sandbox and outputs indefinitely.
|
|
6
8
|
|
|
7
|
-
The full machine operating protocol is available at https://console.sanbox.cloud/agent.md and in [`
|
|
9
|
+
The full machine operating protocol is available at https://console.sanbox.cloud/agent.md and in [`app/docs/agent.md`](../app/docs/agent.md).
|
|
8
10
|
|
|
9
11
|
## Install
|
|
10
12
|
|
|
@@ -15,7 +17,13 @@ installed_cli_version="$(sanbox --version)"
|
|
|
15
17
|
test "$installed_cli_version" = "$latest_cli_version"
|
|
16
18
|
```
|
|
17
19
|
|
|
18
|
-
Always use the latest published CLI. CLI 0.0.
|
|
20
|
+
Always use the latest published CLI. CLI 0.0.16 adds `sanbox skill` to retrieve the current LLM
|
|
21
|
+
guide from `/v1/skill` using an organization API key in `SANBOX_API_KEY`. It prints Markdown by
|
|
22
|
+
default, supports `--json`, and saves `.sanbox/agent.md` atomically with `--write`.
|
|
23
|
+
`sanbox init agent` is now a deprecated alias that requires the same key; plain `sanbox init`
|
|
24
|
+
writes a bootstrap pointer instead of an embedded guide. The new CLI requires API support for
|
|
25
|
+
`/v1/skill` and does not fall back to the public `/agent.md` compatibility URL.
|
|
26
|
+
CLI 0.0.15 adds Secret Proxy management, template grants,
|
|
19
27
|
and run-scope inspection. Use `--path` or `--all-paths` to configure request scope and repeatable
|
|
20
28
|
`--secret-proxy` options to select proxies during template creation. Grants check HTTPS access;
|
|
21
29
|
`--add-network-access` explicitly adds missing host rules on port 443. Proxy details include
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { proxyCommand, formatProxyResult, secretProxiesHelp } from "./secretProxies.js";
|
|
3
3
|
import { formatNetworkAccess, grantTemplateProxies, resolveSecretProxies } from "./templateSecretProxies.js";
|
|
4
|
+
import { agentGuideUrl, fetchSkill, writeSkill, skillBootstrap } from "./skill.js";
|
|
4
5
|
import fs from "node:fs/promises";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import { formatActivityJsonl, formatActivityLine, parseActivityView, shouldRenderEvent } from "./activity.js";
|
|
@@ -67,7 +68,8 @@ Commands:
|
|
|
67
68
|
sanbox opencode connections revoke <run-id> <connection-id> [--json]
|
|
68
69
|
sanbox ssh <run-id>
|
|
69
70
|
sanbox init [--force]
|
|
70
|
-
sanbox
|
|
71
|
+
sanbox skill [--write] [--json]
|
|
72
|
+
sanbox init agent [--write] (deprecated alias for skill)
|
|
71
73
|
`;
|
|
72
74
|
const sshHelp = `Sanbox SSH
|
|
73
75
|
|
|
@@ -194,111 +196,6 @@ Optional controls: --browser-max-steps, --browser-step-timeout-seconds,
|
|
|
194
196
|
--browser-download-policy allow|deny, and --browser-additional-instructions.
|
|
195
197
|
Deleting a template requires --force. Existing runs and their retained sandboxes are preserved.
|
|
196
198
|
`;
|
|
197
|
-
const agentInstructions = `# Operate Sanbox Autonomously
|
|
198
|
-
|
|
199
|
-
Use the \`sanbox\` CLI for focused, isolated, long-running, risky, or parallel work. The canonical
|
|
200
|
-
protocol is https://console.sanbox.cloud/agent.md.
|
|
201
|
-
|
|
202
|
-
Always use the latest published CLI. Install and verify it at the start of every operating session:
|
|
203
|
-
\`\`\`bash
|
|
204
|
-
npm install -g @sanlabs/sanbox-cli@latest
|
|
205
|
-
latest_cli_version="$(npm view @sanlabs/sanbox-cli version)"
|
|
206
|
-
installed_cli_version="$(sanbox --version)"
|
|
207
|
-
test "$installed_cli_version" = "$latest_cli_version"
|
|
208
|
-
\`\`\`
|
|
209
|
-
|
|
210
|
-
Human bootstrap:
|
|
211
|
-
- A human/admin supplies an organization-scoped SANBOX_API_KEY and configures provider credentials plus a runnable template.
|
|
212
|
-
- Never print, persist, prompt with, or upload API keys or provider credentials.
|
|
213
|
-
- If the key or a runnable template is unavailable, stop with the exact human action required.
|
|
214
|
-
|
|
215
|
-
Deterministic startup:
|
|
216
|
-
\`\`\`bash
|
|
217
|
-
sanbox --version
|
|
218
|
-
sanbox auth check --json
|
|
219
|
-
sanbox context --json
|
|
220
|
-
sanbox templates list --json
|
|
221
|
-
export SANBOX_TEMPLATE=<returned-template-id-or-slug>
|
|
222
|
-
sanbox templates validate "$SANBOX_TEMPLATE" --json
|
|
223
|
-
sanbox doctor --json
|
|
224
|
-
\`\`\`
|
|
225
|
-
|
|
226
|
-
Never guess opaque IDs. The CLI derives the organization from the API key and requires the key to
|
|
227
|
-
resolve to exactly one organization. For task execution, select only a template with runnable: true,
|
|
228
|
-
template_type: "runner", and runner_config.harness: "opencode" or "browser-use". Select Browser Use
|
|
229
|
-
only for a one-shot web task whose target domains are already approved on the template. Never select
|
|
230
|
-
a Hermes service template for a waited task because it is always-on. Select automatically only when exactly one task
|
|
231
|
-
template qualifies; otherwise ask the user. Provider credentials and template administration are
|
|
232
|
-
console-only.
|
|
233
|
-
|
|
234
|
-
For an explicitly requested OpenCode Computer, use a service template with harness opencode and
|
|
235
|
-
execution_mode computer. The task is optional; omit --wait. Use sanbox run --model <model-id> to
|
|
236
|
-
select an exact ID from the template's allowed_model_ids, keeping its provider unchanged. Omit
|
|
237
|
-
--model to use the template default. The startup model is saved on the run and reused on Resume
|
|
238
|
-
without re-specifying --model. SDK per-prompt switching changes neither the template default nor
|
|
239
|
-
the run's saved startup model. This flag is not supported for task or Hermes templates.
|
|
240
|
-
|
|
241
|
-
Use --json for request/response commands and --jsonl for streams. Parse the versioned envelope:
|
|
242
|
-
schema_version, ok, command, context, data or error, and next_actions. Execute command actions as
|
|
243
|
-
argv arrays, never shell strings. Exit 0 means command success, 1 local/API failure, 2 readiness or
|
|
244
|
-
waited remote failure, and 130 detached while remote work continues.
|
|
245
|
-
|
|
246
|
-
Preview and submit each logical task with a stable idempotency key:
|
|
247
|
-
\`\`\`bash
|
|
248
|
-
sanbox run "Investigate one focused task and write output/report.md" --input app/ --dry-run --json
|
|
249
|
-
sanbox run "Investigate one focused task and write output/report.md" \\
|
|
250
|
-
--template "$SANBOX_TEMPLATE" --external-run-id "<stable-project-task-id>" \\
|
|
251
|
-
--input app/ --wait --json
|
|
252
|
-
\`\`\`
|
|
253
|
-
|
|
254
|
-
Reuse the same --external-run-id after ambiguous failures. Retry network errors, HTTP 429, HTTP 5xx,
|
|
255
|
-
and workspace_busy with bounded backoff. Do not retry other 4xx errors unless next_actions directs
|
|
256
|
-
recovery. A run is inactive when state is stopped; inspect latest_execution.outcome for the most
|
|
257
|
-
recent bounded execution outcome.
|
|
258
|
-
|
|
259
|
-
Recover and retrieve results:
|
|
260
|
-
\`\`\`bash
|
|
261
|
-
sanbox runs list --limit 50 --json
|
|
262
|
-
sanbox runs get <run-id> --json
|
|
263
|
-
sanbox runs events <run-id> --after-event-id <cursor> --json
|
|
264
|
-
sanbox runs watch <run-id> --after-event-id <cursor> --jsonl
|
|
265
|
-
sanbox runs artifacts <run-id> --json
|
|
266
|
-
sanbox runs download <run-id> --output .sanbox/output/<run-id> --json
|
|
267
|
-
\`\`\`
|
|
268
|
-
|
|
269
|
-
Tasks must put durable files under /workspace/output. Downloads preserve relative paths and report
|
|
270
|
-
byte counts plus SHA-256 digests; existing files require explicit --overwrite.
|
|
271
|
-
|
|
272
|
-
While a sandbox is running, create one read-only capability URL for its entire root filesystem:
|
|
273
|
-
\`\`\`bash
|
|
274
|
-
sanbox runs share <run-id> --expires 1h --json
|
|
275
|
-
sanbox runs shares <run-id> --json
|
|
276
|
-
sanbox runs unshare <run-id> <access-point-id> --json
|
|
277
|
-
\`\`\`
|
|
278
|
-
The URL starts at /, supports directory JSON with ?format=json, and stops working when the sandbox
|
|
279
|
-
stops, the link expires, or it is revoked. Treat the URL as a bearer secret.
|
|
280
|
-
|
|
281
|
-
Manage the retained sandbox independently of its agent harness:
|
|
282
|
-
\`\`\`bash
|
|
283
|
-
sanbox runs get <run-id> --json
|
|
284
|
-
sanbox runs resume <run-id> --wait --json
|
|
285
|
-
sanbox runs share <run-id> --expires 1h --json
|
|
286
|
-
sanbox runs stop <run-id> --wait --json
|
|
287
|
-
sanbox runs delete <run-id> --yes --json
|
|
288
|
-
\`\`\`
|
|
289
|
-
|
|
290
|
-
Stop terminates compute and durably syncs the workspace without retaining RAM or VM state. Resume
|
|
291
|
-
fresh-boots the pinned runtime artifact with that workspace; it does not restore process state or
|
|
292
|
-
silently replay a finished task. Delete permanently removes the workspace after archiving usage.
|
|
293
|
-
|
|
294
|
-
For independent fan-out, use \`sanbox batch\` with a stable external_run_id per task and keep the
|
|
295
|
-
client alive until submission completes.
|
|
296
|
-
|
|
297
|
-
Do not claim completion until state is stopped, latest_execution.outcome is completed, and required
|
|
298
|
-
artifacts are downloaded and verified. Report run/external/template IDs, run state, execution outcome, workspace save time,
|
|
299
|
-
artifact paths/digests, and blockers. The CLI excludes common secrets by default; add
|
|
300
|
-
.sanboxignore for project rules.
|
|
301
|
-
`;
|
|
302
199
|
const cwd = () => process.cwd();
|
|
303
200
|
const makeClient = (flags) => new SanboxClient(readConfig(flags));
|
|
304
201
|
const jsonContext = (client) => ({
|
|
@@ -552,6 +449,7 @@ const flagSets = {
|
|
|
552
449
|
logout: ["api-url", "json", "help"],
|
|
553
450
|
init: [...commonFlags, "force", "template"],
|
|
554
451
|
"init.agent": [...commonFlags, "write"],
|
|
452
|
+
skill: ["api-url", "json", "help", "write"],
|
|
555
453
|
version: ["json", "help"]
|
|
556
454
|
};
|
|
557
455
|
const commandKey = (command) => {
|
|
@@ -645,6 +543,7 @@ const validatePositionals = (command, flags) => {
|
|
|
645
543
|
"secret-proxies.update": 3, "secret-proxies.rotate": 3, "secret-proxies.delete": 3,
|
|
646
544
|
"templates.secret-proxies": 5, "runs.secret-proxies": 3,
|
|
647
545
|
"auth.check": 2,
|
|
546
|
+
skill: 1,
|
|
648
547
|
context: 1,
|
|
649
548
|
doctor: 1,
|
|
650
549
|
"model-providers.list": 2,
|
|
@@ -1826,33 +1725,31 @@ const commandLogout = async (flags) => {
|
|
|
1826
1725
|
process.stdout.write(session ? "Signed out.\n" : "No saved Sanbox user session.\n");
|
|
1827
1726
|
}
|
|
1828
1727
|
};
|
|
1728
|
+
const commandSkill = async (flags, command = "skill") => {
|
|
1729
|
+
const guide = await fetchSkill(resolveApiUrl(flags));
|
|
1730
|
+
if (hasFlag(flags, "write")) {
|
|
1731
|
+
await writeSkill(cwd(), guide);
|
|
1732
|
+
if (hasFlag(flags, "json"))
|
|
1733
|
+
printSuccess(command, { path: ".sanbox/agent.md", status: "written" }, localJsonContext(flags));
|
|
1734
|
+
else
|
|
1735
|
+
process.stdout.write(".sanbox/agent.md written\n");
|
|
1736
|
+
}
|
|
1737
|
+
else if (hasFlag(flags, "json")) {
|
|
1738
|
+
printSuccess(command, { instructions: guide }, localJsonContext(flags));
|
|
1739
|
+
}
|
|
1740
|
+
else
|
|
1741
|
+
process.stdout.write(guide);
|
|
1742
|
+
};
|
|
1829
1743
|
const commandInit = async (command, flags) => {
|
|
1830
1744
|
const dir = path.join(cwd(), ".sanbox");
|
|
1831
|
-
if (command[1] === "agent")
|
|
1832
|
-
|
|
1833
|
-
await fs.mkdir(dir, { recursive: true });
|
|
1834
|
-
await fs.writeFile(path.join(dir, "agent.md"), agentInstructions, "utf8");
|
|
1835
|
-
if (hasFlag(flags, "json")) {
|
|
1836
|
-
printSuccess("init.agent", { path: ".sanbox/agent.md", status: "written" }, localJsonContext(flags));
|
|
1837
|
-
}
|
|
1838
|
-
else {
|
|
1839
|
-
process.stdout.write(".sanbox/agent.md written\n");
|
|
1840
|
-
}
|
|
1841
|
-
return;
|
|
1842
|
-
}
|
|
1843
|
-
if (hasFlag(flags, "json")) {
|
|
1844
|
-
printSuccess("init.agent", { instructions: agentInstructions }, localJsonContext(flags));
|
|
1845
|
-
}
|
|
1846
|
-
else {
|
|
1847
|
-
process.stdout.write(agentInstructions);
|
|
1848
|
-
}
|
|
1849
|
-
return;
|
|
1850
|
-
}
|
|
1745
|
+
if (command[1] === "agent")
|
|
1746
|
+
return commandSkill(flags, "init.agent");
|
|
1851
1747
|
if (command[1])
|
|
1852
1748
|
throw new Error("init supports no subcommand or `agent`.");
|
|
1853
1749
|
const force = hasFlag(flags, "force");
|
|
1854
1750
|
const localConfig = readLocalConfig();
|
|
1855
1751
|
const apiUrl = String(flags["api-url"] || process.env.SANBOX_API_URL || localConfig.api_url || defaultApiUrl).replace(/\/+$/, "");
|
|
1752
|
+
const bootstrap = skillBootstrap(apiUrl);
|
|
1856
1753
|
const template = readTemplateSelection(flags, { required: false });
|
|
1857
1754
|
const config = {
|
|
1858
1755
|
api_url: apiUrl,
|
|
@@ -1869,7 +1766,7 @@ const commandInit = async (command, flags) => {
|
|
|
1869
1766
|
await fs.mkdir(dir, { recursive: true });
|
|
1870
1767
|
const results = [
|
|
1871
1768
|
[".sanbox/config.json", await writeIfNeeded(path.join(dir, "config.json"), `${JSON.stringify(config, null, 2)}\n`, force)],
|
|
1872
|
-
[".sanbox/agent.md", await writeIfNeeded(path.join(dir, "agent.md"),
|
|
1769
|
+
[".sanbox/agent.md", await writeIfNeeded(path.join(dir, "agent.md"), bootstrap, force)],
|
|
1873
1770
|
[".sanboxignore", await writeIfNeeded(path.join(cwd(), ".sanboxignore"), sanboxIgnore, force)]
|
|
1874
1771
|
];
|
|
1875
1772
|
if (hasFlag(flags, "json")) {
|
|
@@ -1998,17 +1895,29 @@ const main = async (command, flags) => {
|
|
|
1998
1895
|
process.exitCode = exitCode;
|
|
1999
1896
|
return;
|
|
2000
1897
|
}
|
|
1898
|
+
if (command[0] === "skill")
|
|
1899
|
+
return commandSkill(flags);
|
|
2001
1900
|
if (command[0] === "init")
|
|
2002
1901
|
return commandInit(command, flags);
|
|
2003
1902
|
throw new CliError("unknown_command", `Unknown command: ${command.join(" ")}`);
|
|
2004
1903
|
};
|
|
2005
1904
|
const parsed = parseArgs(process.argv.slice(2));
|
|
2006
1905
|
main(parsed.command, parsed.flags).catch((error) => {
|
|
1906
|
+
let context = localJsonContext(parsed.flags);
|
|
1907
|
+
if (parsed.command[0] === "skill" || parsed.command[0] === "init") {
|
|
1908
|
+
// Rejected origins may contain a password/query secret; never echo them.
|
|
1909
|
+
try {
|
|
1910
|
+
context = { api_url: agentGuideUrl(resolveApiUrl(parsed.flags)).origin };
|
|
1911
|
+
}
|
|
1912
|
+
catch {
|
|
1913
|
+
context = {};
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
2007
1916
|
if (hasFlag(parsed.flags, "jsonl")) {
|
|
2008
|
-
printJsonlError(commandId(parsed.command), error,
|
|
1917
|
+
printJsonlError(commandId(parsed.command), error, context);
|
|
2009
1918
|
}
|
|
2010
1919
|
else if (hasFlag(parsed.flags, "json")) {
|
|
2011
|
-
printError(commandId(parsed.command), error,
|
|
1920
|
+
printError(commandId(parsed.command), error, context);
|
|
2012
1921
|
}
|
|
2013
1922
|
else {
|
|
2014
1923
|
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
package/dist/skill.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { CliError } from "./errors.js";
|
|
5
|
+
export function agentGuideUrl(apiUrl) {
|
|
6
|
+
try {
|
|
7
|
+
const url = new URL(apiUrl);
|
|
8
|
+
const loopback = url.hostname === "127.0.0.1" || url.hostname === "[::1]";
|
|
9
|
+
if ((url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) ||
|
|
10
|
+
url.username || url.password || url.search || url.hash || !/^\/*$/.test(url.pathname))
|
|
11
|
+
throw new Error();
|
|
12
|
+
return new URL("/v1/skill", url);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
throw new CliError("invalid_api_url", "Use an HTTPS API origin, or HTTP on literal loopback for local development.");
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export async function fetchSkill(apiUrl) {
|
|
19
|
+
const url = agentGuideUrl(apiUrl);
|
|
20
|
+
const apiKey = process.env.SANBOX_API_KEY;
|
|
21
|
+
if (!apiKey?.startsWith("sbx_live_")) {
|
|
22
|
+
throw new CliError("api_key_required", "Set SANBOX_API_KEY to an organization API key in your agent environment, then run sanbox skill.");
|
|
23
|
+
}
|
|
24
|
+
let response;
|
|
25
|
+
try {
|
|
26
|
+
response = await fetch(url, {
|
|
27
|
+
headers: { Authorization: `Bearer ${apiKey}`, Accept: "text/markdown" },
|
|
28
|
+
redirect: "error",
|
|
29
|
+
signal: AbortSignal.timeout(15_000)
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
throw new CliError("skill_fetch_failed", "Could not fetch the guide. Check SANBOX_API_URL and connectivity. Redirects are not followed.");
|
|
34
|
+
}
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
await response.body?.cancel();
|
|
37
|
+
// Do not echo an untrusted response body or credential-bearing URL.
|
|
38
|
+
throw new CliError("skill_fetch_failed", response.status === 401 || response.status === 403
|
|
39
|
+
? "The guide requires an active organization API key. Check SANBOX_API_KEY."
|
|
40
|
+
: `The guide could not be fetched (HTTP ${response.status}).`, { status: response.status });
|
|
41
|
+
}
|
|
42
|
+
if (response.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() !== "text/markdown") {
|
|
43
|
+
await response.body?.cancel();
|
|
44
|
+
throw new CliError("invalid_skill_response", "The API did not return a Markdown guide.");
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const reader = response.body.getReader();
|
|
48
|
+
const chunks = [];
|
|
49
|
+
let size = 0;
|
|
50
|
+
while (true) {
|
|
51
|
+
const { value, done } = await reader.read();
|
|
52
|
+
if (done)
|
|
53
|
+
break;
|
|
54
|
+
size += value.length;
|
|
55
|
+
if (size > 1_048_576) {
|
|
56
|
+
await reader.cancel();
|
|
57
|
+
throw new Error();
|
|
58
|
+
}
|
|
59
|
+
chunks.push(value);
|
|
60
|
+
}
|
|
61
|
+
const guide = Buffer.concat(chunks).toString("utf8");
|
|
62
|
+
if (!guide.trim())
|
|
63
|
+
throw new Error();
|
|
64
|
+
return guide;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
throw new CliError("invalid_skill_response", "The guide was empty, incomplete, or exceeded 1 MiB. Try again.");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export async function writeSkill(cwd, guide) {
|
|
71
|
+
const directory = path.join(cwd, ".sanbox");
|
|
72
|
+
await fs.mkdir(directory, { recursive: true });
|
|
73
|
+
const temporary = path.join(directory, `.agent-${randomUUID()}.tmp`);
|
|
74
|
+
try {
|
|
75
|
+
await fs.writeFile(temporary, guide, { encoding: "utf8", mode: 0o600, flag: "wx" });
|
|
76
|
+
await fs.rename(temporary, path.join(directory, "agent.md"));
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
await fs.rm(temporary, { force: true });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export const skillBootstrap = (apiUrl) => `# Sanbox skill\n\nSet SANBOX_API_KEY in your agent environment or secret settings. Never put the key in chat or tracked files.\n\nUse SANBOX_API_URL=${agentGuideUrl(apiUrl).origin} and run \`sanbox skill\` to read the guide through the authenticated API, or \`sanbox skill --write\` to replace this file.\n`;
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "0.0.
|
|
1
|
+
export const version = "0.0.16";
|