@tonbo/cli 0.3.2 → 0.3.4
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 +4 -1
- package/dist/bin/tonbo.js +99 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -207,7 +207,8 @@ Machines belong to an Account independently of Agents. Allocate in `us-east-1`,
|
|
|
207
207
|
|
|
208
208
|
```console
|
|
209
209
|
tonbo --json region list
|
|
210
|
-
tonbo --json machine allocate --account <account-uuid> --region us-east-1
|
|
210
|
+
tonbo --json machine allocate --account <account-uuid> --region us-east-1 --request-id <request-uuid>
|
|
211
|
+
tonbo --json machine allocation <request-uuid> --account <account-uuid>
|
|
211
212
|
tonbo --json machine list --account <account-uuid>
|
|
212
213
|
tonbo --json machine bind <machine-uuid> --agent <agent-uuid>
|
|
213
214
|
tonbo --json machine show <machine-uuid>
|
|
@@ -219,3 +220,5 @@ tonbo --json machine release <machine-uuid>
|
|
|
219
220
|
Only one active Agent binding per Machine and one Machine per Agent are currently supported. Unbinding drains execution and completes physical deletion, final usage settlement and storage credential revocation before the Machine becomes available. Wait for `available: true` in `machine show` before rebinding. Cross-Agent reassignment resets rootfs; the destination mounts its own Agent Workspace and Sessions. Hidden pause/resume within the same Agent retains rootfs and process state. Release also drains an existing binding automatically; it does not delete Agent files or Sessions.
|
|
220
221
|
|
|
221
222
|
`tonbo agent list` lists accessible Agents without requiring a local `.tonbo` file. JSON command output uses `agent` for one Agent and `agents` for the list; there is no duplicate `agent` output alias.
|
|
223
|
+
|
|
224
|
+
Persist the allocation request UUID before sending when automating. Reuse it with the same account and region after a lost response; lookup returns the original Machine even after release. Omitting `--request-id` generates one, included in the success output or retry error.
|
package/dist/bin/tonbo.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/app.ts
|
|
4
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
4
5
|
import { Command } from "commander";
|
|
5
6
|
import { readFileSync } from "node:fs";
|
|
6
7
|
|
|
@@ -523,6 +524,9 @@ var TonboApi = class {
|
|
|
523
524
|
this.accountOrigin = accountOrigin;
|
|
524
525
|
this.managementOrigin = managementOrigin;
|
|
525
526
|
}
|
|
527
|
+
cancelActivities(agentId, token, body) {
|
|
528
|
+
return this.management("POST", `/v1/agents/${agentId}/production/cancellations`, token, body);
|
|
529
|
+
}
|
|
526
530
|
async listRegions(oauthToken) {
|
|
527
531
|
return parseRegionDiscovery(
|
|
528
532
|
await requestJson(this.fetcher, `${this.accountOrigin}/api/cli/regions`, {
|
|
@@ -558,7 +562,7 @@ var TonboApi = class {
|
|
|
558
562
|
}
|
|
559
563
|
).then((body) => body.organizations);
|
|
560
564
|
}
|
|
561
|
-
createAgent(oauthToken, name, organizationId) {
|
|
565
|
+
createAgent(oauthToken, name, organizationId, requestId = randomUUID()) {
|
|
562
566
|
return requestJson(
|
|
563
567
|
this.fetcher,
|
|
564
568
|
`${this.accountOrigin}/api/cli/agents`,
|
|
@@ -568,9 +572,28 @@ var TonboApi = class {
|
|
|
568
572
|
authorization: `Bearer ${oauthToken}`,
|
|
569
573
|
"content-type": "application/json"
|
|
570
574
|
},
|
|
571
|
-
body: JSON.stringify(
|
|
575
|
+
body: JSON.stringify({
|
|
576
|
+
name,
|
|
577
|
+
requestId,
|
|
578
|
+
...organizationId ? { orgId: organizationId } : {}
|
|
579
|
+
})
|
|
572
580
|
}
|
|
573
|
-
).then((body) => body.agent)
|
|
581
|
+
).then((body) => body.agent).catch((cause) => {
|
|
582
|
+
if (cause instanceof Error && "status" in cause && typeof cause.status === "number" && cause.status >= 400 && cause.status < 500)
|
|
583
|
+
throw cause;
|
|
584
|
+
throw new Error(
|
|
585
|
+
`Agent creation was not confirmed. Query \`tonbo agent creation ${requestId}${organizationId ? ` --account ${organizationId}` : ""}\` or retry creation with --request-id ${requestId} and the same name and account.`,
|
|
586
|
+
{ cause }
|
|
587
|
+
);
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
readAgentCreationRequest(oauthToken, requestId, accountId) {
|
|
591
|
+
const account = accountId ? `?account=${encodeURIComponent(accountId)}` : "";
|
|
592
|
+
return requestJson(
|
|
593
|
+
this.fetcher,
|
|
594
|
+
`${this.accountOrigin}/api/cli/agents/creations/${encodeURIComponent(requestId)}${account}`,
|
|
595
|
+
{ headers: { authorization: `Bearer ${oauthToken}` } }
|
|
596
|
+
);
|
|
574
597
|
}
|
|
575
598
|
registerSshKey(oauthToken, key) {
|
|
576
599
|
return requestJson(
|
|
@@ -1256,8 +1279,9 @@ async function openBrowser(url) {
|
|
|
1256
1279
|
|
|
1257
1280
|
// ../../packages/agent-source-bundler/dist/src/generated/contracts.js
|
|
1258
1281
|
var inferenceDefault = { "model": "claude-sonnet-5" };
|
|
1259
|
-
var sourceBundleContract = { "version": 1, "format": "tar-v1", "key_prefix": "agent-source-bundles", "content_type": "application/vnd.tonbo.source+tar", "max_bytes": 67108864 };
|
|
1282
|
+
var sourceBundleContract = { "version": 1, "format": "tar-v1", "key_prefix": "agent-source-bundles", "content_type": "application/vnd.tonbo.source+tar", "max_bytes": 67108864, "runtime_cache_directories": [".pi/npm", ".pi/git"] };
|
|
1260
1283
|
var piSessionContract = { "version": 1, "adapter": "pi-jsonl-v3", "format_version": 3, "durable_completion_timeout_seconds": 30, "turn_claim_seconds": 30, "turn_claim_renew_seconds": 10, "session_directory": "/sessions", "path_template": "/sessions/{session_id}.jsonl", "preflight_command": ["/usr/local/bin/artifacts", "runtime", "session-preflight"] };
|
|
1284
|
+
var piSlackTemplate = { "repository": "tonbo-io/pi-slack-agent", "source_directory": "examples/pi-slack-agent", "service": { "command": ["node", "slack/server.mjs"], "secrets": ["SLACK_SIGNING_SECRET", "SLACK_BOT_TOKEN", "SLACK_BOT_USER_ID", "SLACK_TEAM_ID", "TONBO_AGENT_API_KEY", "TONBO_AGENT_API_ORIGIN", "TONBO_IAM_ORIGIN"] } };
|
|
1261
1285
|
|
|
1262
1286
|
// ../../packages/agent-source-bundler/dist/src/inference-default.js
|
|
1263
1287
|
var DEFAULT_INFERENCE_MODEL = inferenceDefault.model;
|
|
@@ -1292,6 +1316,7 @@ function githubRepositoryUrl(remote) {
|
|
|
1292
1316
|
|
|
1293
1317
|
// src/commands.ts
|
|
1294
1318
|
import path4 from "node:path";
|
|
1319
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
1295
1320
|
|
|
1296
1321
|
// src/build.ts
|
|
1297
1322
|
import { spawn } from "node:child_process";
|
|
@@ -1320,11 +1345,13 @@ async function runBuildCommand(root, command) {
|
|
|
1320
1345
|
|
|
1321
1346
|
// ../../packages/agent-source-bundler/dist/src/native-pi.js
|
|
1322
1347
|
import { stringify } from "smol-toml";
|
|
1323
|
-
|
|
1348
|
+
var PI_SLACK_TEMPLATE_SERVICE = piSlackTemplate.service;
|
|
1349
|
+
function nativePiDeclaration(model, service) {
|
|
1324
1350
|
return {
|
|
1325
1351
|
version: 2,
|
|
1326
1352
|
harness: { runtime: "pi", driver: { kind: "native" } },
|
|
1327
|
-
inference: { model }
|
|
1353
|
+
inference: { model },
|
|
1354
|
+
...service ? { service } : {}
|
|
1328
1355
|
};
|
|
1329
1356
|
}
|
|
1330
1357
|
|
|
@@ -1446,8 +1473,7 @@ var DEFAULT_IGNORES = [
|
|
|
1446
1473
|
"!.env.example",
|
|
1447
1474
|
".tonbo-cache/",
|
|
1448
1475
|
".tonbo-system/",
|
|
1449
|
-
|
|
1450
|
-
".pi/git/"
|
|
1476
|
+
...sourceBundleContract.runtime_cache_directories.map((directory) => `${directory}/`)
|
|
1451
1477
|
];
|
|
1452
1478
|
var EXACT_NPM_VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
1453
1479
|
var GIT_COMMIT = /^[0-9a-f]{40}$/i;
|
|
@@ -2129,7 +2155,7 @@ async function agentUseCommand(deps, selector, force = false) {
|
|
|
2129
2155
|
await bindDeclarationAgent(root, agent.publicHostname);
|
|
2130
2156
|
deps.output({ message: `Bound .tonbo to agent ${agent.publicHostname}.`, agent });
|
|
2131
2157
|
}
|
|
2132
|
-
async function agentCreateCommand(deps, name) {
|
|
2158
|
+
async function agentCreateCommand(deps, name, options = {}) {
|
|
2133
2159
|
const root = await findDeclarationRoot(deps.cwd());
|
|
2134
2160
|
const declaration = await loadDeclaration(root);
|
|
2135
2161
|
if (declaration.agent) {
|
|
@@ -2139,7 +2165,8 @@ async function agentCreateCommand(deps, name) {
|
|
|
2139
2165
|
}
|
|
2140
2166
|
const oauthToken = await deps.auth.accessToken();
|
|
2141
2167
|
validateAgentName(name);
|
|
2142
|
-
const
|
|
2168
|
+
const requestId = options.requestId ?? randomUUID3();
|
|
2169
|
+
const agent = await deps.api.createAgent(oauthToken, name, options.account, requestId);
|
|
2143
2170
|
try {
|
|
2144
2171
|
await bindDeclarationAgent(root, agent.publicHostname);
|
|
2145
2172
|
} catch (error) {
|
|
@@ -2148,7 +2175,11 @@ async function agentCreateCommand(deps, name) {
|
|
|
2148
2175
|
{ cause: error }
|
|
2149
2176
|
);
|
|
2150
2177
|
}
|
|
2151
|
-
deps.output({
|
|
2178
|
+
deps.output({
|
|
2179
|
+
message: `Created agent ${agent.name} and bound it in .tonbo.`,
|
|
2180
|
+
agent,
|
|
2181
|
+
requestId
|
|
2182
|
+
});
|
|
2152
2183
|
}
|
|
2153
2184
|
async function deployCommand(deps, options = { promote: true }) {
|
|
2154
2185
|
const { declaration, oauthToken, agent, root } = await resolveAgent(deps);
|
|
@@ -2440,9 +2471,23 @@ async function secretRemoveCommand(deps, name) {
|
|
|
2440
2471
|
await deps.api.deleteAgentSecret(agent.id, name, token);
|
|
2441
2472
|
deps.output({ message: `Removed agent secret ${name}.`, agent, name });
|
|
2442
2473
|
}
|
|
2474
|
+
async function cancelActivitiesCommand(deps, options) {
|
|
2475
|
+
const { oauthToken, agent } = await resolveAgent(deps);
|
|
2476
|
+
const token = await deps.api.exchangeManagementToken(oauthToken, agent.id);
|
|
2477
|
+
const result = await deps.api.cancelActivities(agent.id, token, {
|
|
2478
|
+
sandbox_id: options.sandbox,
|
|
2479
|
+
runtime_session_id: options.runtimeSession,
|
|
2480
|
+
work_keys: options.workKey,
|
|
2481
|
+
reason: options.reason
|
|
2482
|
+
});
|
|
2483
|
+
deps.output({
|
|
2484
|
+
message: "Activity cancellation requested. Physical retirement and application checkpoint cancellation must still be verified.",
|
|
2485
|
+
cancellation: result
|
|
2486
|
+
});
|
|
2487
|
+
}
|
|
2443
2488
|
|
|
2444
2489
|
// src/credentials.ts
|
|
2445
|
-
import { randomUUID as
|
|
2490
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
2446
2491
|
import { chmod, lstat as lstat4, mkdir, open as open2, readFile as readFile5, rename as rename2, rm as rm2 } from "node:fs/promises";
|
|
2447
2492
|
import os from "node:os";
|
|
2448
2493
|
import path5 from "node:path";
|
|
@@ -2473,7 +2518,7 @@ var FileCredentialStore = class {
|
|
|
2473
2518
|
await assertExistingDestinationIsSafe(this.filename);
|
|
2474
2519
|
const temporary = path5.join(
|
|
2475
2520
|
directory,
|
|
2476
|
-
`.${path5.basename(this.filename)}.${process.pid}.${
|
|
2521
|
+
`.${path5.basename(this.filename)}.${process.pid}.${randomUUID4()}.tmp`
|
|
2477
2522
|
);
|
|
2478
2523
|
let handle = null;
|
|
2479
2524
|
try {
|
|
@@ -2719,13 +2764,33 @@ function createProgram(dependencies = createDependencies) {
|
|
|
2719
2764
|
)
|
|
2720
2765
|
);
|
|
2721
2766
|
});
|
|
2722
|
-
machine.command("allocate").requiredOption("--account <account>", "owning account UUID").requiredOption("--region <region>", "compute region (see tonbo region list)").
|
|
2767
|
+
machine.command("allocate").requiredOption("--account <account>", "owning account UUID").requiredOption("--region <region>", "compute region (see tonbo region list)").option(
|
|
2768
|
+
"--request-id <uuid>",
|
|
2769
|
+
"stable allocation request UUID; reuse it after an uncertain response"
|
|
2770
|
+
).action(async (options) => {
|
|
2723
2771
|
const deps = dependencies(jsonOutput(program));
|
|
2724
|
-
|
|
2725
|
-
|
|
2772
|
+
const requestId = options.requestId ?? randomUUID5();
|
|
2773
|
+
try {
|
|
2774
|
+
const result = await deps.api.machineRequest(await deps.auth.accessToken(), "", "POST", {
|
|
2726
2775
|
accountId: options.account,
|
|
2727
|
-
region: options.region
|
|
2728
|
-
|
|
2776
|
+
region: options.region,
|
|
2777
|
+
requestId
|
|
2778
|
+
});
|
|
2779
|
+
deps.output({ ...result, requestId });
|
|
2780
|
+
} catch (cause) {
|
|
2781
|
+
throw new Error(
|
|
2782
|
+
`Machine allocation was not confirmed. Retry with --request-id ${requestId} and the same account and region.`,
|
|
2783
|
+
{ cause }
|
|
2784
|
+
);
|
|
2785
|
+
}
|
|
2786
|
+
});
|
|
2787
|
+
machine.command("allocation <requestId>").description("query the original Machine for an allocation request").requiredOption("--account <account>", "owning account UUID").action(async (requestId, options) => {
|
|
2788
|
+
const deps = dependencies(jsonOutput(program));
|
|
2789
|
+
deps.output(
|
|
2790
|
+
await deps.api.machineRequest(
|
|
2791
|
+
await deps.auth.accessToken(),
|
|
2792
|
+
`/allocations/${encodeURIComponent(requestId)}?account=${encodeURIComponent(options.account)}`
|
|
2793
|
+
)
|
|
2729
2794
|
);
|
|
2730
2795
|
});
|
|
2731
2796
|
for (const operation of ["show", "metrics", "release"]) {
|
|
@@ -2765,7 +2830,19 @@ function createProgram(dependencies = createDependencies) {
|
|
|
2765
2830
|
);
|
|
2766
2831
|
});
|
|
2767
2832
|
const agent = program.command("agent").description("manage the Agent bound to this source directory");
|
|
2768
|
-
agent.command("create <name>").description("create an agent and bind this directory to it").
|
|
2833
|
+
agent.command("create <name>").description("create an agent and bind this directory to it").option("--account <account>", "owning account UUID; defaults to your personal account").option("--request-id <uuid>", "reuse the same creation UUID after an uncertain response").action(
|
|
2834
|
+
async (name, options) => agentCreateCommand(dependencies(jsonOutput(program)), name, options)
|
|
2835
|
+
);
|
|
2836
|
+
agent.command("creation <requestId>").description("query the original Agent for a creation request").option("--account <account>", "owning account UUID; defaults to your personal account").action(async (requestId, options) => {
|
|
2837
|
+
const deps = dependencies(jsonOutput(program));
|
|
2838
|
+
deps.output(
|
|
2839
|
+
await deps.api.readAgentCreationRequest(
|
|
2840
|
+
await deps.auth.accessToken(),
|
|
2841
|
+
requestId,
|
|
2842
|
+
options.account
|
|
2843
|
+
)
|
|
2844
|
+
);
|
|
2845
|
+
});
|
|
2769
2846
|
agent.command("list").description("list the agents available to your account").action(async () => agentListCommand(dependencies(jsonOutput(program))));
|
|
2770
2847
|
const sshKey = program.command("ssh-key").description("manage public keys used by native agent SSH");
|
|
2771
2848
|
sshKey.command("add <public-key>").description("register an OpenSSH public key with the current Tonbo account").action(async (path6) => sshKeyAddCommand(dependencies(jsonOutput(program)), path6));
|
|
@@ -2787,6 +2864,9 @@ function createProgram(dependencies = createDependencies) {
|
|
|
2787
2864
|
deployments.command("promote <deployment>").description("move Production to a Deployment by id prefix").action(
|
|
2788
2865
|
async (prefix) => deploymentsPromoteCommand(dependencies(jsonOutput(program)), prefix)
|
|
2789
2866
|
);
|
|
2867
|
+
deployments.command("cancel-activities").description("cancel selected named work on an exact retired runtime").requiredOption("--sandbox <id>", "retired Sandbox UUID").requiredOption("--runtime-session <id>", "exact activation UUID").requiredOption("--work-key <keys...>", "named work keys to cancel").requiredOption("--reason <reason>", "reason retained in the cancellation audit").action(
|
|
2868
|
+
async (options) => cancelActivitiesCommand(dependencies(jsonOutput(program)), options)
|
|
2869
|
+
);
|
|
2790
2870
|
deployments.command("rollback [deployment]").description("move Production back to the previous Production Deployment, or to a named one").action(
|
|
2791
2871
|
async (prefix) => deploymentsRollbackCommand(dependencies(jsonOutput(program)), prefix)
|
|
2792
2872
|
);
|