@tonbo/cli 0.1.1 → 0.1.2
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 +20 -2
- package/dist/bin/tonbo.js +31 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ Use the arrow keys and Enter to select a supported Harness and either create or
|
|
|
44
44
|
The generated `.tonbo` is TOML:
|
|
45
45
|
|
|
46
46
|
```toml
|
|
47
|
-
# Tonbo Agent
|
|
47
|
+
# Tonbo Agent configuration.
|
|
48
48
|
# Edit this file directly or run `tonbo init` to reconfigure.
|
|
49
49
|
version = 2
|
|
50
50
|
agent = "my-agent-my-account.tonbo.sh"
|
|
@@ -61,7 +61,7 @@ model = "claude-sonnet-4-5"
|
|
|
61
61
|
|
|
62
62
|
The immutable full Agent hostname is the only durable Agent authority in the source tree; it is not a credential. This keeps Agents with the same name in different Organizations unambiguous. `deploy`, `run`, `ssh` and `secret` refuse an unbound declaration. `tonbo agent use <name-hostname-or-id>` accepts any convenient selector, resolves it through the signed-in account and writes the selected `project-organization.tonbo.sh` hostname into `.tonbo`; rebinding an existing declaration requires interactive confirmation or `--force`. UUIDs remain internal API identities and are never committed by the CLI.
|
|
63
63
|
|
|
64
|
-
The default inference model is written without prompting. Override it explicitly with `--model`. Headless initialization makes Harness and driver choices explicit and may bind the resulting declaration with `
|
|
64
|
+
The default inference model is written without prompting. Override it explicitly with `--model`. Headless initialization makes Harness and driver choices explicit and may bind the resulting declaration with `agent use`:
|
|
65
65
|
|
|
66
66
|
```console
|
|
67
67
|
tonbo init --harness pi --driver native
|
|
@@ -200,3 +200,21 @@ Node.js 22 or newer is required. Human OAuth tokens are stored at `${XDG_CONFIG_
|
|
|
200
200
|
- [Agent Deployments, Production and Rollouts](../../docs/design/project-deployments.md)
|
|
201
201
|
- [ADR-0008: Tonbo CLI onboarding and credential boundaries](../../apps/user-center/docs/decisions/adr-0008-tonbo-cli-onboarding.md)
|
|
202
202
|
- [Management API v1](../../contracts/management/openapi-v1.yaml)
|
|
203
|
+
|
|
204
|
+
## Machines
|
|
205
|
+
|
|
206
|
+
Machines belong to an Account independently of Agents. Allocate in `us-east-1`, bind an available Machine from Agent detail or the CLI, inspect measured metrics, and release it when no longer needed. Allocation starts no compute. The platform handles idle pause/resume automatically; there are no customer power controls or arbitrary Machine command/upload APIs.
|
|
207
|
+
|
|
208
|
+
```console
|
|
209
|
+
tonbo --json machine allocate --account <account-uuid> --region us-east-1
|
|
210
|
+
tonbo --json machine list --account <account-uuid>
|
|
211
|
+
tonbo --json machine bind <machine-uuid> --agent <agent-uuid>
|
|
212
|
+
tonbo --json machine show <machine-uuid>
|
|
213
|
+
tonbo --json machine metrics <machine-uuid>
|
|
214
|
+
tonbo --json machine unbind <machine-uuid>
|
|
215
|
+
tonbo --json machine release <machine-uuid>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
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.
|
|
219
|
+
|
|
220
|
+
`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 `project` output alias.
|
package/dist/bin/tonbo.js
CHANGED
|
@@ -1734,7 +1734,7 @@ function initSaveLabel(exists, project) {
|
|
|
1734
1734
|
}
|
|
1735
1735
|
async function selectInitProject(deps, root) {
|
|
1736
1736
|
for (; ; ) {
|
|
1737
|
-
const action = await deps.select("How should this
|
|
1737
|
+
const action = await deps.select("How should this directory connect to Tonbo?", [
|
|
1738
1738
|
{
|
|
1739
1739
|
description: "Create it only after you confirm the complete configuration.",
|
|
1740
1740
|
name: "Create a new agent",
|
|
@@ -1782,7 +1782,7 @@ async function selectInitProject(deps, root) {
|
|
|
1782
1782
|
continue;
|
|
1783
1783
|
}
|
|
1784
1784
|
const id = await deps.select(
|
|
1785
|
-
"Which agent should this
|
|
1785
|
+
"Which agent should this directory use?",
|
|
1786
1786
|
projects.map((project2) => ({
|
|
1787
1787
|
name: project2.name,
|
|
1788
1788
|
description: `Organization: ${project2.organizationName} \xB7 ${project2.publicHostname} \xB7 ${project2.id}`,
|
|
@@ -1935,7 +1935,10 @@ async function projectUseCommand(deps, selector, force = false) {
|
|
|
1935
1935
|
const projects = await deps.api.listProjects(oauthToken);
|
|
1936
1936
|
const project = selectProject(projects, selector);
|
|
1937
1937
|
if (declaration.agent === project.publicHostname) {
|
|
1938
|
-
deps.output({
|
|
1938
|
+
deps.output({
|
|
1939
|
+
message: `.tonbo already uses agent ${project.publicHostname}.`,
|
|
1940
|
+
agent: project
|
|
1941
|
+
});
|
|
1939
1942
|
return;
|
|
1940
1943
|
}
|
|
1941
1944
|
if (declaration.agent && !force) {
|
|
@@ -1959,7 +1962,7 @@ async function projectUseCommand(deps, selector, force = false) {
|
|
|
1959
1962
|
}
|
|
1960
1963
|
}
|
|
1961
1964
|
await bindDeclarationProject(root, project.publicHostname);
|
|
1962
|
-
deps.output({ message: `Bound .tonbo to agent ${project.publicHostname}.`, project });
|
|
1965
|
+
deps.output({ message: `Bound .tonbo to agent ${project.publicHostname}.`, agent: project });
|
|
1963
1966
|
}
|
|
1964
1967
|
async function projectCreateCommand(deps, name) {
|
|
1965
1968
|
const root = await findDeclarationRoot(deps.cwd());
|
|
@@ -1980,7 +1983,7 @@ async function projectCreateCommand(deps, name) {
|
|
|
1980
1983
|
{ cause: error }
|
|
1981
1984
|
);
|
|
1982
1985
|
}
|
|
1983
|
-
deps.output({ message: `Created agent ${project.name} and bound it in .tonbo.`, project });
|
|
1986
|
+
deps.output({ message: `Created agent ${project.name} and bound it in .tonbo.`, agent: project });
|
|
1984
1987
|
}
|
|
1985
1988
|
async function deployCommand(deps, options = { promote: true }) {
|
|
1986
1989
|
const { declaration, oauthToken, project, root } = await resolveProject(deps);
|
|
@@ -2023,7 +2026,7 @@ async function deployCommand(deps, options = { promote: true }) {
|
|
|
2023
2026
|
` ssh ${project.sshDestination}`
|
|
2024
2027
|
);
|
|
2025
2028
|
}
|
|
2026
|
-
deps.output({ message: lines.join("\n"), project, ...result });
|
|
2029
|
+
deps.output({ message: lines.join("\n"), agent: project, ...result });
|
|
2027
2030
|
}
|
|
2028
2031
|
async function runCommand(deps, prompt, options) {
|
|
2029
2032
|
const { oauthToken, project } = await resolveProject(deps);
|
|
@@ -2036,10 +2039,17 @@ async function runCommand(deps, prompt, options) {
|
|
|
2036
2039
|
});
|
|
2037
2040
|
deps.output({
|
|
2038
2041
|
message: result.turn.assistant_text,
|
|
2039
|
-
project,
|
|
2042
|
+
agent: project,
|
|
2040
2043
|
...result
|
|
2041
2044
|
});
|
|
2042
2045
|
}
|
|
2046
|
+
async function agentListCommand(deps) {
|
|
2047
|
+
const agents = await deps.api.listProjects(await deps.auth.accessToken());
|
|
2048
|
+
deps.output({
|
|
2049
|
+
message: agents.length ? agents.map((agent) => `${agent.name} \xB7 ${agent.publicHostname}`).join("\n") : "No agents are available.",
|
|
2050
|
+
agents
|
|
2051
|
+
});
|
|
2052
|
+
}
|
|
2043
2053
|
async function projectShowCommand(deps) {
|
|
2044
2054
|
const { project, token } = await projectManagement(deps);
|
|
2045
2055
|
const production = await deps.api.getProduction(project.id, token);
|
|
@@ -2055,7 +2065,7 @@ async function projectShowCommand(deps) {
|
|
|
2055
2065
|
`production: ${deploymentName(deployment)} (${shortDeploymentId(deployment.id)}) ${productionStateLabel(deployment)}`
|
|
2056
2066
|
);
|
|
2057
2067
|
}
|
|
2058
|
-
deps.output({ message: lines.join("\n"), project, production, deployment });
|
|
2068
|
+
deps.output({ message: lines.join("\n"), agent: project, production, deployment });
|
|
2059
2069
|
}
|
|
2060
2070
|
function shortDeploymentId(id) {
|
|
2061
2071
|
return id.replace(/-/g, "").slice(0, 8);
|
|
@@ -2125,7 +2135,7 @@ async function deploymentsListCommand(deps) {
|
|
|
2125
2135
|
deployment.created_by_user_id ? shortDeploymentId(deployment.created_by_user_id) : ""
|
|
2126
2136
|
])
|
|
2127
2137
|
) : `No Deployments exist for agent ${project.name}. Run \`tonbo deploy\` to create one.`;
|
|
2128
|
-
deps.output({ message, project, production, deployments });
|
|
2138
|
+
deps.output({ message, agent: project, production, deployments });
|
|
2129
2139
|
}
|
|
2130
2140
|
async function deploymentsShowCommand(deps, prefix) {
|
|
2131
2141
|
const { project, token } = await projectManagement(deps);
|
|
@@ -2135,7 +2145,7 @@ async function deploymentsShowCommand(deps, prefix) {
|
|
|
2135
2145
|
);
|
|
2136
2146
|
deps.output({
|
|
2137
2147
|
message: renderDeploymentDetail(deployment, rollouts),
|
|
2138
|
-
project,
|
|
2148
|
+
agent: project,
|
|
2139
2149
|
deployment,
|
|
2140
2150
|
rollouts
|
|
2141
2151
|
});
|
|
@@ -2181,7 +2191,7 @@ async function deploymentsPromoteCommand(deps, prefix) {
|
|
|
2181
2191
|
const result = await moveProduction(deps, project.id, target, token);
|
|
2182
2192
|
deps.output({
|
|
2183
2193
|
message: describeProductionMove(project, result, "Promoted"),
|
|
2184
|
-
project,
|
|
2194
|
+
agent: project,
|
|
2185
2195
|
...result
|
|
2186
2196
|
});
|
|
2187
2197
|
}
|
|
@@ -2205,7 +2215,7 @@ async function deploymentsRollbackCommand(deps, prefix) {
|
|
|
2205
2215
|
const result = await moveProduction(deps, project.id, target, token);
|
|
2206
2216
|
deps.output({
|
|
2207
2217
|
message: describeProductionMove(project, result, "Rolled back"),
|
|
2208
|
-
project,
|
|
2218
|
+
agent: project,
|
|
2209
2219
|
...result
|
|
2210
2220
|
});
|
|
2211
2221
|
}
|
|
@@ -2246,7 +2256,7 @@ async function secretListCommand(deps) {
|
|
|
2246
2256
|
const secrets = await deps.api.listProjectSecrets(project.id, token);
|
|
2247
2257
|
deps.output({
|
|
2248
2258
|
message: secrets.length ? secrets.map((secret) => secret.name).join("\n") : "No agent secrets are configured.",
|
|
2249
|
-
project,
|
|
2259
|
+
agent: project,
|
|
2250
2260
|
secrets
|
|
2251
2261
|
});
|
|
2252
2262
|
}
|
|
@@ -2256,14 +2266,14 @@ async function secretSetCommand(deps, name, options) {
|
|
|
2256
2266
|
const secret = await deps.api.setProjectSecret(project.id, name, value, token);
|
|
2257
2267
|
deps.output({
|
|
2258
2268
|
message: `Set agent secret ${secret.name}. Redeploy to replace the active runtime with this value.`,
|
|
2259
|
-
project,
|
|
2269
|
+
agent: project,
|
|
2260
2270
|
secret
|
|
2261
2271
|
});
|
|
2262
2272
|
}
|
|
2263
2273
|
async function secretRemoveCommand(deps, name) {
|
|
2264
2274
|
const { project, token } = await projectManagement(deps);
|
|
2265
2275
|
await deps.api.deleteProjectSecret(project.id, name, token);
|
|
2266
|
-
deps.output({ message: `Removed agent secret ${name}.`, project, name });
|
|
2276
|
+
deps.output({ message: `Removed agent secret ${name}.`, agent: project, name });
|
|
2267
2277
|
}
|
|
2268
2278
|
|
|
2269
2279
|
// src/credentials.ts
|
|
@@ -2523,7 +2533,7 @@ function jsonOutput(program) {
|
|
|
2523
2533
|
return program.opts().json === true;
|
|
2524
2534
|
}
|
|
2525
2535
|
function createProgram(dependencies = createDependencies) {
|
|
2526
|
-
const program = new Command().name("tonbo").description("Deploy a persistent Agent
|
|
2536
|
+
const program = new Command().name("tonbo").description("Deploy a persistent Agent to Tonbo.").version(packageVersion.version).option("--json", "print machine-readable JSON");
|
|
2527
2537
|
program.command("init").description("interactively create a Tonbo Agent declaration in this directory").option("--harness <harness>", "Agent Harness (currently pi)").option("--model <model>", "inference model").option("--driver <driver>", "PI driver: native or command").option("--agent-entry <file>", "Node entry file for the command driver").option("--build-command <argv...>", "build command argv for the command driver").option("--force", `replace an existing ${DECLARATION_FILENAME}`).action(
|
|
2528
2538
|
async (options) => initCommand(dependencies(jsonOutput(program)), options)
|
|
2529
2539
|
);
|
|
@@ -2583,17 +2593,18 @@ function createProgram(dependencies = createDependencies) {
|
|
|
2583
2593
|
})
|
|
2584
2594
|
);
|
|
2585
2595
|
});
|
|
2586
|
-
const project = program.command("agent").description("manage the
|
|
2587
|
-
project.command("create <name>").description("create and bind
|
|
2596
|
+
const project = program.command("agent").description("manage the Agent bound to this source directory");
|
|
2597
|
+
project.command("create <name>").description("create an agent and bind this directory to it").action(async (name) => projectCreateCommand(dependencies(jsonOutput(program)), name));
|
|
2598
|
+
project.command("list").description("list the agents available to your account").action(async () => agentListCommand(dependencies(jsonOutput(program))));
|
|
2588
2599
|
const sshKey = program.command("ssh-key").description("manage public keys used by native agent SSH");
|
|
2589
2600
|
sshKey.command("add <public-key>").description("register an OpenSSH public key with the current Tonbo account").action(async (path6) => sshKeyAddCommand(dependencies(jsonOutput(program)), path6));
|
|
2590
2601
|
sshKey.command("remove <fingerprint>").description("revoke an SSH public key from the current Tonbo account").action(
|
|
2591
2602
|
async (fingerprint) => sshKeyRemoveCommand(dependencies(jsonOutput(program)), fingerprint)
|
|
2592
2603
|
);
|
|
2593
|
-
project.command("use <agent>").description("write
|
|
2604
|
+
project.command("use <agent>").description("write the agent hostname into this directory's .tonbo declaration").option("--force", "replace an existing agent binding without confirmation").action(
|
|
2594
2605
|
async (selector, options) => projectUseCommand(dependencies(jsonOutput(program)), selector, options.force === true)
|
|
2595
2606
|
);
|
|
2596
|
-
project.command("show").description("show the agent bound to this
|
|
2607
|
+
project.command("show").description("show the agent bound to this directory and its connection addresses").action(async () => projectShowCommand(dependencies(jsonOutput(program))));
|
|
2597
2608
|
program.command("deploy").description("upload this directory as a new Deployment and promote it to Production").option("--no-promote", "create the Deployment without moving Production").action(
|
|
2598
2609
|
async (options) => deployCommand(dependencies(jsonOutput(program)), { promote: options.promote })
|
|
2599
2610
|
);
|