@tonbo/cli 0.1.0 → 0.1.1

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
@@ -17,12 +17,12 @@ No Harness-specific configuration was found in this project.
17
17
  ❯ PI (`pi`) Run this project with the pi command.
18
18
  ? How should this Agent connect to Tonbo?
19
19
  ❯ Create a new project Create it only after you confirm the complete configuration.
20
- Use an existing project
20
+ Use an existing agent
21
21
  Set up later
22
- ? Project name [my-agent]:
22
+ ? Agent name [my-agent]:
23
23
 
24
24
  Tonbo Agent configuration:
25
- Project: Create my-agent in my-account (permanent address assigned after creation)
25
+ Agent: Create my-agent in my-account (permanent address assigned after creation)
26
26
  Harness: PI
27
27
  Execution: PI CLI (`pi`)
28
28
  Model: claude-sonnet-4-5
@@ -31,7 +31,7 @@ Tonbo Agent configuration:
31
31
  Edit configuration Change the project, Harness, execution mode, model, or SDK entrypoint.
32
32
  Cancel
33
33
  Created project my-agent and .tonbo.
34
- Project: my-agent (my-agent-my-account.tonbo.sh)
34
+ Agent: my-agent (my-agent-my-account.tonbo.sh)
35
35
  Organization: my-account
36
36
  Application: https://my-agent-my-account.tonbo.sh
37
37
  Harness: PI
@@ -39,12 +39,12 @@ Mode: PI CLI
39
39
  Next: tonbo deploy
40
40
  ```
41
41
 
42
- Use the arrow keys and Enter to select a supported Harness and either create or select the one Project owned by this source tree. Project creation and file writes wait until the final review; cancelling leaves both local and cloud state unchanged. `AGENTS.md` is Harness-neutral and never identifies PI by itself. When `.pi/settings.json` exists, the shared source inspector identifies the PI Harness and reports its project-local packages. A regular PI project defaults to the native PI CLI; choose `Edit configuration` only when changing the Project, execution mode, model, or another setting. Unsupported and planned Harnesses are not shown.
42
+ Use the arrow keys and Enter to select a supported Harness and either create or select the one Agent owned by this source tree. Agent creation and file writes wait until the final review; cancelling leaves both local and cloud state unchanged. `AGENTS.md` is Harness-neutral and never identifies PI by itself. When `.pi/settings.json` exists, the shared source inspector identifies the PI Harness and reports its workspace-local packages. A regular PI project defaults to the native PI CLI; choose `Edit configuration` only when changing the Agent, execution mode, model, or another setting. Unsupported and planned Harnesses are not shown.
43
43
 
44
44
  The generated `.tonbo` is TOML:
45
45
 
46
46
  ```toml
47
- # Tonbo Project Agent configuration.
47
+ # Tonbo Agent 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"
@@ -59,14 +59,14 @@ kind = "native"
59
59
  model = "claude-sonnet-4-5"
60
60
  ```
61
61
 
62
- The immutable full Project hostname is the only durable Project authority in the source tree; it is not a credential. This keeps Projects with the same name in different Organizations unambiguous. `deploy`, `run`, `ssh` and `secret` refuse an unbound declaration. `tonbo project 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.
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
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 `project use`:
65
65
 
66
66
  ```console
67
67
  tonbo init --harness pi --driver native
68
68
  tonbo init --harness pi --driver command --agent-entry dist/agent.mjs
69
- tonbo project use my-project-my-account.tonbo.sh
69
+ tonbo agent use my-project-my-account.tonbo.sh
70
70
  ```
71
71
 
72
72
  After interactive initialization, deploy the current contents:
@@ -76,7 +76,7 @@ tonbo deploy
76
76
  tonbo run "Reply with exactly READY."
77
77
  ```
78
78
 
79
- Choose `Use an existing project` during `init` when the Project already exists. `tonbo project create <name>` and `tonbo project use <name-hostname-or-id>` remain explicit automation and recovery commands.
79
+ Choose `Use an existing agent` during `init` when the Agent already exists. `tonbo agent create <name>` and `tonbo agent use <name-hostname-or-id>` remain explicit automation and recovery commands.
80
80
 
81
81
  `run` creates a durable Session and prints its ID in `--json` output. Pass that identity back to continue the same PI conversation:
82
82
 
@@ -84,7 +84,7 @@ Choose `Use an existing project` during `init` when the Project already exists.
84
84
  tonbo run --session 4d8e9501-... "Continue the previous task."
85
85
  ```
86
86
 
87
- Every `tonbo deploy` creates one immutable Deployment: the uploaded source, the `.tonbo` settings and the git provenance of the source root (commit, branch, subject, author and whether the tree was dirty) when the directory is inside a git work tree. Git is optional; without it the Deployment records `tonbo deploy` as its source. Deployments are named by their commit subject, or by their short id (the first eight hex characters) when there is no commit, and every command that takes a Deployment accepts any unambiguous id prefix. The Project's Production pointer names the one Deployment that serves its hostname; `deploy` moves Production to the new Deployment and prints the Deployment, its Production state and the exact standard OpenSSH command for the bound Project and its username:
87
+ Every `tonbo deploy` creates one immutable Deployment: the uploaded source, the `.tonbo` settings and the git provenance of the source root (commit, branch, subject, author and whether the tree was dirty) when the directory is inside a git work tree. Git is optional; without it the Deployment records `tonbo deploy` as its source. Deployments are named by their commit subject, or by their short id (the first eight hex characters) when there is no commit, and every command that takes a Deployment accepts any unambiguous id prefix. The Agent's Production pointer names the one Deployment that serves its hostname; `deploy` moves Production to the new Deployment and prints the Deployment, its Production state and the exact standard OpenSSH command for the bound Agent and its username:
88
88
 
89
89
  ```console
90
90
  $ tonbo deploy
@@ -115,15 +115,15 @@ tonbo deployments rollback # move Production back to the previous Pr
115
115
  tonbo deployments rollback 9b8c1d22 # or to a named one
116
116
  ```
117
117
 
118
- `tonbo deployments` (alias `tonbo deployments list`) marks the current Production Deployment with `●` and earlier ones with `○`; `STATUS` is the Deployment's relationship to Production: `current`, `promoting`, `failed`, `stopped`, `previous` or `none`. Promotion and rollback compare-and-swap the Production generation, so two people moving Production at once cannot silently overwrite each other; a conflict is reported and the command can be retried after checking `tonbo deployments`. `tonbo project show` prints the Production Deployment and its state alongside the Project addresses.
118
+ `tonbo deployments` (alias `tonbo deployments list`) marks the current Production Deployment with `●` and earlier ones with `○`; `STATUS` is the Deployment's relationship to Production: `current`, `promoting`, `failed`, `stopped`, `previous` or `none`. Promotion and rollback compare-and-swap the Production generation, so two people moving Production at once cannot silently overwrite each other; a conflict is reported and the command can be retried after checking `tonbo deployments`. `tonbo agent show` prints the Production Deployment and its state alongside the Agent addresses.
119
119
 
120
- Use `tonbo project show` to rediscover the username, application address and SSH command later. `tonbo login` registers public keys found at the conventional `~/.ssh/id_ed25519.pub`, `id_ecdsa.pub` and `id_rsa.pub` paths. Register a key at another path with `tonbo ssh-key add <path.pub>` and revoke a lost or retired key with `tonbo ssh-key remove SHA256:...`. The CLI is not part of the SSH connection; ordinary OpenSSH, `scp` and `rsync` connect directly:
120
+ Use `tonbo agent show` to rediscover the username, application address and SSH command later. `tonbo login` registers public keys found at the conventional `~/.ssh/id_ed25519.pub`, `id_ecdsa.pub` and `id_rsa.pub` paths. Register a key at another path with `tonbo ssh-key add <path.pub>` and revoke a lost or retired key with `tonbo ssh-key remove SHA256:...`. The CLI is not part of the SSH connection; ordinary OpenSSH, `scp` and `rsync` connect directly:
121
121
 
122
122
  ```console
123
123
  ssh my-project.my-account@tonbo.sh
124
124
  ```
125
125
 
126
- The SSH user name is the Project qualified by its username; the signed public key identifies the Tonbo user and is checked against membership and IAM at connection time. The CLI resolves the Project name in `.tonbo` and prints the server-authoritative destination, so users never need to remember or assemble a username. The shell and HTTP turns may coexist on the singleton runtime, allowing the shell to observe the Agent while it works. Session writer fencing protects durable conversation history; ordinary workspace files retain Linux process concurrency semantics.
126
+ The SSH user name is the Agent qualified by its username; the signed public key identifies the Tonbo user and is checked against membership and IAM at connection time. The CLI resolves the Agent name in `.tonbo` and prints the server-authoritative destination, so users never need to remember or assemble a username. The shell and HTTP turns may coexist on the singleton runtime, allowing the shell to observe the Agent while it works. Session writer fencing protects durable conversation history; ordinary workspace files retain Linux process concurrency semantics.
127
127
 
128
128
  Deploy does not create a hidden Session just to prewarm PI. The first real `tonbo run` starts the Session-bound PI RPC process; successful Turns keep that process hot, including across native Session switches. The process is disposable cache rather than durable state: pause, replacement and uncertain failures remove it, and the next Turn restores authority from the durable Session JSONL.
129
129
 
@@ -133,7 +133,7 @@ Deploy snapshots regular files under `.tonbo`, excluding `.git`, `node_modules`,
133
133
 
134
134
  ## Supported PI project shapes
135
135
 
136
- ### 1. Project-local Agent
136
+ ### 1. Agent-local Agent
137
137
 
138
138
  Keep the normal PI project layout. Tonbo runs the same `AGENTS.md`, `.pi/APPEND_SYSTEM.md`, `.pi/settings.json`, `.pi/extensions`, `.pi/skills` and `.pi/prompts` that local `pi` loads:
139
139
 
@@ -182,7 +182,7 @@ model = "claude-sonnet-4-5"
182
182
 
183
183
  `tonbo deploy` runs the build command before creating the source snapshot. The entrypoint must keep stdout exclusively for PI RPC and send logs to stderr. It receives `PI_CODING_AGENT_MODULE`, `PI_CODING_AGENT_DIR`, `PI_CODING_AGENT_SESSION_DIR`, `TONBO_PI_SESSION_FILE`, `TONBO_PI_SESSION_ID`, `TONBO_PI_PROVIDER`, `TONBO_PI_MODEL` and `TONBO_PI_RPC_PROTOCOL`. Load the platform PI SDK from `PI_CODING_AGENT_MODULE`, open `TONBO_PI_SESSION_FILE`, create an `AgentSessionRuntime`, and pass it to `runRpcMode()`. This lets the app customize tools and runtime services without forking PI while preserving Tonbo's durable Session and Turn protocol.
184
184
 
185
- For a non-interactive invocation, provide a current Tonbo CLI OAuth access token; the committed `.tonbo` supplies the only Project context:
185
+ For a non-interactive invocation, provide a current Tonbo CLI OAuth access token; the committed `.tonbo` supplies the only Agent context:
186
186
 
187
187
  ```console
188
188
  TONBO_ACCESS_TOKEN=... tonbo --json deploy
@@ -196,7 +196,7 @@ Node.js 22 or newer is required. Human OAuth tokens are stored at `${XDG_CONFIG_
196
196
  - [Design documentation map](../../docs/design/README.md)
197
197
  - [Agent source inspection and onboarding](../../docs/design/agent-source-onboarding.md)
198
198
  - [Shared source inspector](../../packages/agent-source-inspector/README.md)
199
- - [Project resource model](../../docs/design/project-resource-model.md)
200
- - [Project Deployments, Production and Rollouts](../../docs/design/project-deployments.md)
199
+ - [Agent resource model](../../docs/design/project-resource-model.md)
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)
package/dist/bin/tonbo.js CHANGED
@@ -52,7 +52,7 @@ var TonboApi = class {
52
52
  listProjects(oauthToken) {
53
53
  return requestJson(
54
54
  this.fetcher,
55
- `${this.accountOrigin}/api/cli/projects`,
55
+ `${this.accountOrigin}/api/cli/agents`,
56
56
  {
57
57
  headers: { authorization: `Bearer ${oauthToken}` }
58
58
  }
@@ -70,7 +70,7 @@ var TonboApi = class {
70
70
  createProject(oauthToken, name, organizationId) {
71
71
  return requestJson(
72
72
  this.fetcher,
73
- `${this.accountOrigin}/api/cli/projects`,
73
+ `${this.accountOrigin}/api/cli/agents`,
74
74
  {
75
75
  method: "POST",
76
76
  headers: {
@@ -116,7 +116,7 @@ var TonboApi = class {
116
116
  exchangeManagementToken(oauthToken, projectId) {
117
117
  return requestJson(
118
118
  this.fetcher,
119
- `${this.accountOrigin}/api/cli/projects/${projectId}/token`,
119
+ `${this.accountOrigin}/api/cli/agents/${projectId}/token`,
120
120
  {
121
121
  method: "POST",
122
122
  headers: { authorization: `Bearer ${oauthToken}` }
@@ -136,7 +136,7 @@ var TonboApi = class {
136
136
  sha256: bundle.sha256,
137
137
  size_bytes: bundle.size_bytes
138
138
  };
139
- const bundlesPath = `/v1/projects/${projectId}/source-bundles`;
139
+ const bundlesPath = `/v1/agents/${projectId}/source-bundles`;
140
140
  const prepared = await this.management("PUT", `${bundlesPath}/${bundle.sha256}`, token, {
141
141
  format: descriptor.format,
142
142
  size_bytes: descriptor.size_bytes
@@ -188,25 +188,25 @@ var TonboApi = class {
188
188
  createDeployment(projectId, body, token) {
189
189
  return this.management(
190
190
  "POST",
191
- `/v1/projects/${projectId}/deployments`,
191
+ `/v1/agents/${projectId}/deployments`,
192
192
  token,
193
193
  body
194
194
  ).then((response) => response.data);
195
195
  }
196
196
  listDeployments(projectId, token) {
197
- return this.managementList(`/v1/projects/${projectId}/deployments`, token);
197
+ return this.managementList(`/v1/agents/${projectId}/deployments`, token);
198
198
  }
199
199
  getDeployment(projectId, deploymentId, token) {
200
200
  return this.management(
201
201
  "GET",
202
- `/v1/projects/${projectId}/deployments/${deploymentId}`,
202
+ `/v1/agents/${projectId}/deployments/${deploymentId}`,
203
203
  token
204
204
  ).then((response) => response.data);
205
205
  }
206
206
  getProduction(projectId, token) {
207
207
  return this.management(
208
208
  "GET",
209
- `/v1/projects/${projectId}/production`,
209
+ `/v1/agents/${projectId}/production`,
210
210
  token
211
211
  ).then(
212
212
  (response) => response.data,
@@ -219,14 +219,14 @@ var TonboApi = class {
219
219
  putProduction(projectId, body, token) {
220
220
  return this.management(
221
221
  "PUT",
222
- `/v1/projects/${projectId}/production`,
222
+ `/v1/agents/${projectId}/production`,
223
223
  token,
224
224
  body
225
225
  ).then((response) => response.data);
226
226
  }
227
227
  listRollouts(projectId, token) {
228
228
  return this.managementList(
229
- `/v1/projects/${projectId}/production/rollouts`,
229
+ `/v1/agents/${projectId}/production/rollouts`,
230
230
  token
231
231
  );
232
232
  }
@@ -237,10 +237,10 @@ var TonboApi = class {
237
237
  token,
238
238
  turnId = randomUUID()
239
239
  }) {
240
- const projectPath = `/v1/projects/${projectId}`;
240
+ const projectPath = `/v1/agents/${projectId}`;
241
241
  const production = await this.getProduction(projectId, token);
242
242
  if (!production)
243
- throw new Error("Project has no Production Deployment; run `tonbo deploy` first.");
243
+ throw new Error("Agent has no Production Deployment; run `tonbo deploy` first.");
244
244
  if (production.observed_state !== "running")
245
245
  throw new Error(
246
246
  `Production is ${production.observed_state}${production.last_error ? ` (${production.last_error})` : ""}; wait for it to be running.`
@@ -269,21 +269,21 @@ var TonboApi = class {
269
269
  }) {
270
270
  return this.management(
271
271
  "GET",
272
- `/v1/projects/${projectId}/sessions/${sessionId}/turns/${turnId}/events?after=${after}`,
272
+ `/v1/agents/${projectId}/sessions/${sessionId}/turns/${turnId}/events?after=${after}`,
273
273
  token
274
274
  );
275
275
  }
276
276
  listProjectSecrets(projectId, token) {
277
277
  return this.management(
278
278
  "GET",
279
- `/v1/projects/${projectId}/secrets`,
279
+ `/v1/agents/${projectId}/secrets`,
280
280
  token
281
281
  ).then((body) => body.data);
282
282
  }
283
283
  setProjectSecret(projectId, name, value, token) {
284
284
  return this.management(
285
285
  "PUT",
286
- `/v1/projects/${projectId}/secrets/${encodeURIComponent(name)}`,
286
+ `/v1/agents/${projectId}/secrets/${encodeURIComponent(name)}`,
287
287
  token,
288
288
  { value }
289
289
  );
@@ -291,7 +291,7 @@ var TonboApi = class {
291
291
  deleteProjectSecret(projectId, name, token) {
292
292
  return this.management(
293
293
  "DELETE",
294
- `/v1/projects/${projectId}/secrets/${encodeURIComponent(name)}`,
294
+ `/v1/agents/${projectId}/secrets/${encodeURIComponent(name)}`,
295
295
  token
296
296
  );
297
297
  }
@@ -1315,7 +1315,7 @@ async function validatePackageSource(root, source) {
1315
1315
  throw error;
1316
1316
  }
1317
1317
  if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
1318
- throw new Error(`Local PI package ${source} must resolve to a real project directory.`);
1318
+ throw new Error(`Local PI package ${source} must resolve to a real agent directory.`);
1319
1319
  }
1320
1320
  return;
1321
1321
  }
@@ -1506,7 +1506,7 @@ function validateProjectName(name) {
1506
1506
  const valid = name.length >= PROJECT_NAME_RULE.minLength && name.length <= PROJECT_NAME_RULE.maxLength && PROJECT_NAME_PATTERN.test(name) && !RESERVED_PROJECT_NAMES.has(name);
1507
1507
  if (!valid) {
1508
1508
  throw new Error(
1509
- `Project name must be ${PROJECT_NAME_RULE.minLength}-${PROJECT_NAME_RULE.maxLength} lowercase letters, digits, or single hyphens, start with a letter, and not be reserved.`
1509
+ `Agent name must be ${PROJECT_NAME_RULE.minLength}-${PROJECT_NAME_RULE.maxLength} lowercase letters, digits, or single hyphens, start with a letter, and not be reserved.`
1510
1510
  );
1511
1511
  }
1512
1512
  }
@@ -1526,7 +1526,7 @@ async function resolveProject(deps) {
1526
1526
  const root = await findDeclarationRoot(deps.cwd());
1527
1527
  const declaration = await loadDeclaration(root);
1528
1528
  if (!declaration.agent) {
1529
- throw new Error("No Project is configured in .tonbo. Run `tonbo project use <project>` first.");
1529
+ throw new Error("No Agent is configured in .tonbo. Run `tonbo agent use <agent>` first.");
1530
1530
  }
1531
1531
  const oauthToken = await deps.auth.accessToken();
1532
1532
  return {
@@ -1541,10 +1541,10 @@ function selectProject(projects, selector) {
1541
1541
  const matches = projects.filter(
1542
1542
  (project) => project.id === selector || project.name === normalized || project.publicHostname === normalized
1543
1543
  );
1544
- if (matches.length === 0) throw new Error(`Project ${selector} was not found in your account.`);
1544
+ if (matches.length === 0) throw new Error(`Agent ${selector} was not found in your account.`);
1545
1545
  if (matches.length > 1)
1546
- throw new Error(`Project name ${selector} is ambiguous; use its full hostname or ID.`);
1547
- if (matches[0].status !== "active") throw new Error(`Project ${selector} is not active.`);
1546
+ throw new Error(`Agent name ${selector} is ambiguous; use its full hostname or ID.`);
1547
+ if (matches[0].status !== "active") throw new Error(`Agent ${selector} is not active.`);
1548
1548
  return matches[0];
1549
1549
  }
1550
1550
  async function initCommand(deps, options) {
@@ -1618,7 +1618,7 @@ async function initCommand(deps, options) {
1618
1618
  value: "save"
1619
1619
  },
1620
1620
  {
1621
- description: "Change the project, Harness, execution mode, model, or SDK entrypoint.",
1621
+ description: "Change the agent, Harness, execution mode, model, or SDK entrypoint.",
1622
1622
  name: "Edit configuration",
1623
1623
  value: "edit"
1624
1624
  },
@@ -1702,7 +1702,7 @@ async function initCommand(deps, options) {
1702
1702
  } catch (error) {
1703
1703
  if (createdProject) {
1704
1704
  throw new Error(
1705
- `Created project ${createdProject.name}, but could not write ${DECLARATION_FILENAME}. Fix the file and run \`tonbo project use ${createdProject.publicHostname}\`.`,
1705
+ `Created agent ${createdProject.name}, but could not write ${DECLARATION_FILENAME}. Fix the file and run \`tonbo agent use ${createdProject.publicHostname}\`.`,
1706
1706
  { cause: error }
1707
1707
  );
1708
1708
  }
@@ -1711,14 +1711,14 @@ async function initCommand(deps, options) {
1711
1711
  const driverSummary = driver === "command" ? `PI SDK app
1712
1712
  Build: ${buildCommand?.join(" ")}
1713
1713
  Entrypoint: node ${entry}` : inspection.pi.packageCount > 0 ? `PI CLI with ${inspection.pi.packageCount} package${inspection.pi.packageCount === 1 ? "" : "s"}` : "PI CLI";
1714
- const projectSummary = createdProject ? `Project: ${createdProject.name} (${createdProject.publicHostname})
1714
+ const projectSummary = createdProject ? `Agent: ${createdProject.name} (${createdProject.publicHostname})
1715
1715
  Organization: ${createdProject.organizationName}
1716
1716
  Application: https://${createdProject.publicHostname}
1717
- SSH after deploy: ssh ${createdProject.sshDestination}` : projectPlan.kind === "existing" ? `Project: ${projectPlan.name ? `${projectPlan.name} (${projectPlan.publicHostname})` : projectPlan.publicHostname}${projectPlan.organizationName ? `
1717
+ SSH after deploy: ssh ${createdProject.sshDestination}` : projectPlan.kind === "existing" ? `Agent: ${projectPlan.name ? `${projectPlan.name} (${projectPlan.publicHostname})` : projectPlan.publicHostname}${projectPlan.organizationName ? `
1718
1718
  Organization: ${projectPlan.organizationName}` : ""}${projectPlan.sshDestination ? `
1719
- SSH after deploy: ssh ${projectPlan.sshDestination}` : ""}` : "Next: tonbo project create <name>";
1719
+ SSH after deploy: ssh ${projectPlan.sshDestination}` : ""}` : "Next: tonbo agent create <name>";
1720
1720
  deps.output({
1721
- message: `${createdProject ? `Created project ${createdProject.name} and` : exists ? "Updated" : "Created"} ${DECLARATION_FILENAME}.
1721
+ message: `${createdProject ? `Created agent ${createdProject.name} and` : exists ? "Updated" : "Created"} ${DECLARATION_FILENAME}.
1722
1722
  ${projectSummary}
1723
1723
  Harness: PI
1724
1724
  Mode: ${driverSummary}${projectPlan.kind === "later" ? "" : "\nNext: tonbo deploy"}`,
@@ -1728,7 +1728,7 @@ Mode: ${driverSummary}${projectPlan.kind === "later" ? "" : "\nNext: tonbo deplo
1728
1728
  }
1729
1729
  function initSaveLabel(exists, project) {
1730
1730
  if (project.kind === "create") {
1731
- return exists ? `Create project and replace ${DECLARATION_FILENAME}` : `Create project and ${DECLARATION_FILENAME}`;
1731
+ return exists ? `Create agent and replace ${DECLARATION_FILENAME}` : `Create agent and ${DECLARATION_FILENAME}`;
1732
1732
  }
1733
1733
  return exists ? `Replace ${DECLARATION_FILENAME}` : `Create ${DECLARATION_FILENAME}`;
1734
1734
  }
@@ -1737,16 +1737,16 @@ async function selectInitProject(deps, root) {
1737
1737
  const action = await deps.select("How should this Agent connect to Tonbo?", [
1738
1738
  {
1739
1739
  description: "Create it only after you confirm the complete configuration.",
1740
- name: "Create a new project",
1740
+ name: "Create a new agent",
1741
1741
  value: "create"
1742
1742
  },
1743
1743
  {
1744
- description: "Bind this source tree to one project you can access.",
1745
- name: "Use an existing project",
1744
+ description: "Bind this source tree to one agent you can access.",
1745
+ name: "Use an existing agent",
1746
1746
  value: "existing"
1747
1747
  },
1748
1748
  {
1749
- description: "Write an unbound declaration and configure its project later.",
1749
+ description: "Write an unbound declaration and configure its agent later.",
1750
1750
  name: "Set up later",
1751
1751
  value: "later"
1752
1752
  }
@@ -1756,7 +1756,7 @@ async function selectInitProject(deps, root) {
1756
1756
  const organization = await selectInitOrganization(deps);
1757
1757
  const defaultName = projectNameSuggestion(path4.basename(root)) || "tonbo-agent";
1758
1758
  for (; ; ) {
1759
- const answer = (await deps.prompt(`Project name [${defaultName}]: `)).trim().toLowerCase();
1759
+ const answer = (await deps.prompt(`Agent name [${defaultName}]: `)).trim().toLowerCase();
1760
1760
  const name = answer || defaultName;
1761
1761
  try {
1762
1762
  validateProjectName(name);
@@ -1768,7 +1768,7 @@ async function selectInitProject(deps, root) {
1768
1768
  };
1769
1769
  } catch (error) {
1770
1770
  deps.output({
1771
- message: error instanceof Error ? error.message : "Project name is invalid."
1771
+ message: error instanceof Error ? error.message : "Agent name is invalid."
1772
1772
  });
1773
1773
  }
1774
1774
  }
@@ -1778,11 +1778,11 @@ async function selectInitProject(deps, root) {
1778
1778
  (project2) => project2.status === "active"
1779
1779
  );
1780
1780
  if (projects.length === 0) {
1781
- deps.output({ message: "No active projects are available. Create a new project instead." });
1781
+ deps.output({ message: "No active agents are available. Create a new agent instead." });
1782
1782
  continue;
1783
1783
  }
1784
1784
  const id = await deps.select(
1785
- "Which project should this Agent use?",
1785
+ "Which agent should this Agent use?",
1786
1786
  projects.map((project2) => ({
1787
1787
  name: project2.name,
1788
1788
  description: `Organization: ${project2.organizationName} \xB7 ${project2.publicHostname} \xB7 ${project2.id}`,
@@ -1816,7 +1816,7 @@ async function selectInitOrganization(deps) {
1816
1816
  throw new Error("No organization lets you create a project. Ask an admin or owner.");
1817
1817
  if (organizations.length === 1) return organizations[0];
1818
1818
  const id = await deps.select(
1819
- "Which organization should own the new project?",
1819
+ "Which organization should own the new agent?",
1820
1820
  organizations.map((organization) => ({
1821
1821
  description: organization.role,
1822
1822
  name: organization.name,
@@ -1829,7 +1829,7 @@ async function selectHarness(deps) {
1829
1829
  return await deps.select(
1830
1830
  "Which supported Harness should Tonbo use?",
1831
1831
  supportedHarnesses.map((supported) => ({
1832
- description: `Run this project with the ${supported.command} command.`,
1832
+ description: `Run this agent with the ${supported.command} command.`,
1833
1833
  name: `${supported.name} (\`${supported.command}\`)`,
1834
1834
  value: supported.id
1835
1835
  }))
@@ -1843,7 +1843,7 @@ function renderInitSummary(project, harness, driver, model, entry, buildCommand)
1843
1843
  const lines = [
1844
1844
  "",
1845
1845
  "Tonbo Agent configuration:",
1846
- ` Project: ${initProjectSummary(project)}`,
1846
+ ` Agent: ${initProjectSummary(project)}`,
1847
1847
  ` Harness: ${harnessName(harness)}`,
1848
1848
  ` Execution: ${driver === "native" ? "PI CLI (`pi`)" : "PI SDK app"}`,
1849
1849
  ` Model: ${model}`
@@ -1935,7 +1935,7 @@ 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({ message: `.tonbo already uses project ${project.publicHostname}.`, project });
1938
+ deps.output({ message: `.tonbo already uses agent ${project.publicHostname}.`, project });
1939
1939
  return;
1940
1940
  }
1941
1941
  if (declaration.agent && !force) {
@@ -1943,7 +1943,7 @@ async function projectUseCommand(deps, selector, force = false) {
1943
1943
  const currentLabel = current?.publicHostname ?? declaration.agent;
1944
1944
  if (!deps.interactive()) {
1945
1945
  throw new Error(
1946
- `.tonbo already uses project ${currentLabel}. Pass --force to rebind it to ${project.publicHostname}.`
1946
+ `.tonbo already uses agent ${currentLabel}. Pass --force to rebind it to ${project.publicHostname}.`
1947
1947
  );
1948
1948
  }
1949
1949
  const action = await deps.select(
@@ -1954,19 +1954,19 @@ async function projectUseCommand(deps, selector, force = false) {
1954
1954
  ]
1955
1955
  );
1956
1956
  if (action !== "rebind") {
1957
- deps.output({ message: `Cancelled. .tonbo still uses project ${currentLabel}.` });
1957
+ deps.output({ message: `Cancelled. .tonbo still uses agent ${currentLabel}.` });
1958
1958
  return;
1959
1959
  }
1960
1960
  }
1961
1961
  await bindDeclarationProject(root, project.publicHostname);
1962
- deps.output({ message: `Bound .tonbo to project ${project.publicHostname}.`, project });
1962
+ deps.output({ message: `Bound .tonbo to agent ${project.publicHostname}.`, project });
1963
1963
  }
1964
1964
  async function projectCreateCommand(deps, name) {
1965
1965
  const root = await findDeclarationRoot(deps.cwd());
1966
1966
  const declaration = await loadDeclaration(root);
1967
1967
  if (declaration.agent) {
1968
1968
  throw new Error(
1969
- `.tonbo is already bound to project ${declaration.agent}. Run \`tonbo project use <project>\` to review a rebind.`
1969
+ `.tonbo is already bound to agent ${declaration.agent}. Run \`tonbo agent use <agent>\` to review a rebind.`
1970
1970
  );
1971
1971
  }
1972
1972
  const oauthToken = await deps.auth.accessToken();
@@ -1976,11 +1976,11 @@ async function projectCreateCommand(deps, name) {
1976
1976
  await bindDeclarationProject(root, project.publicHostname);
1977
1977
  } catch (error) {
1978
1978
  throw new Error(
1979
- `Created project ${project.name}, but could not bind ${DECLARATION_FILENAME}. Fix the file and run \`tonbo project use ${project.publicHostname}\`.`,
1979
+ `Created agent ${project.name}, but could not bind ${DECLARATION_FILENAME}. Fix the file and run \`tonbo agent use ${project.publicHostname}\`.`,
1980
1980
  { cause: error }
1981
1981
  );
1982
1982
  }
1983
- deps.output({ message: `Created project ${project.name} and bound it in .tonbo.`, project });
1983
+ deps.output({ message: `Created agent ${project.name} and bound it in .tonbo.`, project });
1984
1984
  }
1985
1985
  async function deployCommand(deps, options = { promote: true }) {
1986
1986
  const { declaration, oauthToken, project, root } = await resolveProject(deps);
@@ -1999,7 +1999,7 @@ async function deployCommand(deps, options = { promote: true }) {
1999
1999
  const { deployment } = result;
2000
2000
  const shortId = shortDeploymentId(deployment.id);
2001
2001
  const lines = [
2002
- options.promote ? `Deployed project ${project.name}.` : `Created Deployment ${deploymentName(deployment)} (${shortId}) for project ${project.name} without promoting it.`,
2002
+ options.promote ? `Deployed agent ${project.name}.` : `Created Deployment ${deploymentName(deployment)} (${shortId}) for agent ${project.name} without promoting it.`,
2003
2003
  `Organization: ${project.organizationName}`,
2004
2004
  `Deployment: ${deploymentName(deployment)} (${shortId})`,
2005
2005
  `Source: ${deploymentSourceLabel(deployment)}`,
@@ -2045,7 +2045,7 @@ async function projectShowCommand(deps) {
2045
2045
  const production = await deps.api.getProduction(project.id, token);
2046
2046
  const deployment = production ? await deps.api.getDeployment(project.id, production.deployment_id, token) : null;
2047
2047
  const lines = [
2048
- `project: ${project.name}`,
2048
+ `agent: ${project.name}`,
2049
2049
  `Organization: ${project.organizationName}`,
2050
2050
  `application: https://${project.publicHostname}`,
2051
2051
  `ssh: ssh ${project.sshDestination}`
@@ -2124,7 +2124,7 @@ async function deploymentsListCommand(deps) {
2124
2124
  formatTimestamp(deployment.created_at),
2125
2125
  deployment.created_by_user_id ? shortDeploymentId(deployment.created_by_user_id) : ""
2126
2126
  ])
2127
- ) : `No Deployments exist for project ${project.name}. Run \`tonbo deploy\` to create one.`;
2127
+ ) : `No Deployments exist for agent ${project.name}. Run \`tonbo deploy\` to create one.`;
2128
2128
  deps.output({ message, project, production, deployments });
2129
2129
  }
2130
2130
  async function deploymentsShowCommand(deps, prefix) {
@@ -2197,7 +2197,7 @@ async function deploymentsRollbackCommand(deps, prefix) {
2197
2197
  )?.previous_deployment_id;
2198
2198
  if (!previousId) {
2199
2199
  throw new Error(
2200
- `Project ${project.name} has no previous Production Deployment to roll back to. Name one with \`tonbo deployments rollback <id>\`.`
2200
+ `Agent ${project.name} has no previous Production Deployment to roll back to. Name one with \`tonbo deployments rollback <id>\`.`
2201
2201
  );
2202
2202
  }
2203
2203
  target = await deps.api.getDeployment(project.id, previousId, token);
@@ -2229,7 +2229,7 @@ async function moveProduction(deps, projectId, target, token) {
2229
2229
  function describeProductionMove(project, move, verb) {
2230
2230
  const { deployment, previous } = move;
2231
2231
  const name = `${deploymentName(deployment)} (${shortDeploymentId(deployment.id)})`;
2232
- const headline = previous?.deployment_id === deployment.id ? `Deployment ${name} is already Production for project ${project.name}; requested it to be running.` : `${verb} ${name} to Production for project ${project.name}${previous ? ` (from ${shortDeploymentId(previous.deployment_id)})` : ""}.`;
2232
+ const headline = previous?.deployment_id === deployment.id ? `Deployment ${name} is already Production for agent ${project.name}; requested it to be running.` : `${verb} ${name} to Production for agent ${project.name}${previous ? ` (from ${shortDeploymentId(previous.deployment_id)})` : ""}.`;
2233
2233
  return `${headline}
2234
2234
  Production: ${productionStateLabel(deployment)}
2235
2235
  Application: https://${project.publicHostname}`;
@@ -2245,7 +2245,7 @@ async function secretListCommand(deps) {
2245
2245
  const { project, token } = await projectManagement(deps);
2246
2246
  const secrets = await deps.api.listProjectSecrets(project.id, token);
2247
2247
  deps.output({
2248
- message: secrets.length ? secrets.map((secret) => secret.name).join("\n") : "No project secrets are configured.",
2248
+ message: secrets.length ? secrets.map((secret) => secret.name).join("\n") : "No agent secrets are configured.",
2249
2249
  project,
2250
2250
  secrets
2251
2251
  });
@@ -2255,7 +2255,7 @@ async function secretSetCommand(deps, name, options) {
2255
2255
  const { project, token } = await projectManagement(deps);
2256
2256
  const secret = await deps.api.setProjectSecret(project.id, name, value, token);
2257
2257
  deps.output({
2258
- message: `Set project secret ${secret.name}. Redeploy to replace the active runtime with this value.`,
2258
+ message: `Set agent secret ${secret.name}. Redeploy to replace the active runtime with this value.`,
2259
2259
  project,
2260
2260
  secret
2261
2261
  });
@@ -2263,7 +2263,7 @@ async function secretSetCommand(deps, name, options) {
2263
2263
  async function secretRemoveCommand(deps, name) {
2264
2264
  const { project, token } = await projectManagement(deps);
2265
2265
  await deps.api.deleteProjectSecret(project.id, name, token);
2266
- deps.output({ message: `Removed project secret ${name}.`, project, name });
2266
+ deps.output({ message: `Removed agent secret ${name}.`, project, name });
2267
2267
  }
2268
2268
 
2269
2269
  // src/credentials.ts
@@ -2523,7 +2523,7 @@ function jsonOutput(program) {
2523
2523
  return program.opts().json === true;
2524
2524
  }
2525
2525
  function createProgram(dependencies = createDependencies) {
2526
- const program = new Command().name("tonbo").description("Deploy a persistent Project Agent to Tonbo.").version(packageVersion.version).option("--json", "print machine-readable JSON");
2526
+ const program = new Command().name("tonbo").description("Deploy a persistent Agent Agent to Tonbo.").version(packageVersion.version).option("--json", "print machine-readable JSON");
2527
2527
  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
2528
  async (options) => initCommand(dependencies(jsonOutput(program)), options)
2529
2529
  );
@@ -2583,21 +2583,21 @@ function createProgram(dependencies = createDependencies) {
2583
2583
  })
2584
2584
  );
2585
2585
  });
2586
- const project = program.command("project").description("manage the project bound to this Agent directory");
2587
- project.command("create <name>").description("create and bind a project to this Agent directory").action(async (name) => projectCreateCommand(dependencies(jsonOutput(program)), name));
2588
- const sshKey = program.command("ssh-key").description("manage public keys used by native project SSH");
2586
+ const project = program.command("agent").description("manage the agent bound to this Agent directory");
2587
+ project.command("create <name>").description("create and bind a agent to this Agent directory").action(async (name) => projectCreateCommand(dependencies(jsonOutput(program)), name));
2588
+ const sshKey = program.command("ssh-key").description("manage public keys used by native agent SSH");
2589
2589
  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
2590
  sshKey.command("remove <fingerprint>").description("revoke an SSH public key from the current Tonbo account").action(
2591
2591
  async (fingerprint) => sshKeyRemoveCommand(dependencies(jsonOutput(program)), fingerprint)
2592
2592
  );
2593
- project.command("use <project>").description("write a project ID into this Agent's .tonbo declaration").option("--force", "replace an existing project binding without confirmation").action(
2593
+ project.command("use <agent>").description("write a agent ID into this Agent's .tonbo declaration").option("--force", "replace an existing agent binding without confirmation").action(
2594
2594
  async (selector, options) => projectUseCommand(dependencies(jsonOutput(program)), selector, options.force === true)
2595
2595
  );
2596
- project.command("show").description("show the project bound to this Agent directory and its connection addresses").action(async () => projectShowCommand(dependencies(jsonOutput(program))));
2596
+ project.command("show").description("show the agent bound to this Agent directory and its connection addresses").action(async () => projectShowCommand(dependencies(jsonOutput(program))));
2597
2597
  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
2598
  async (options) => deployCommand(dependencies(jsonOutput(program)), { promote: options.promote })
2599
2599
  );
2600
- const deployments = program.command("deployments").description("list and move between the immutable Deployments of the bound project");
2600
+ const deployments = program.command("deployments").description("list and move between the immutable Deployments of the bound agent");
2601
2601
  deployments.command("list", { isDefault: true }).description("list Deployments, newest first").action(async () => deploymentsListCommand(dependencies(jsonOutput(program))));
2602
2602
  deployments.command("show <deployment>").description("show one Deployment and its Rollouts by id prefix").action(
2603
2603
  async (prefix) => deploymentsShowCommand(dependencies(jsonOutput(program)), prefix)
@@ -2608,10 +2608,10 @@ function createProgram(dependencies = createDependencies) {
2608
2608
  deployments.command("rollback [deployment]").description("move Production back to the previous Production Deployment, or to a named one").action(
2609
2609
  async (prefix) => deploymentsRollbackCommand(dependencies(jsonOutput(program)), prefix)
2610
2610
  );
2611
- program.command("run <prompt>").description("run one prompt in a durable project session").option("--session <session>", "resume an existing Agent Session UUID").action(
2611
+ program.command("run <prompt>").description("run one prompt in a durable agent session").option("--session <session>", "resume an existing Agent Session UUID").action(
2612
2612
  async (prompt, options) => runCommand(dependencies(jsonOutput(program)), prompt, options)
2613
2613
  );
2614
- const secret = program.command("secret").description("manage encrypted environment secrets for the project service");
2614
+ const secret = program.command("secret").description("manage encrypted environment secrets for the agent service");
2615
2615
  secret.command("list").action(async () => secretListCommand(dependencies(jsonOutput(program))));
2616
2616
  secret.command("set <name>").description("set a secret from an environment variable (the same name by default)").option("--from-env <name>", "read the value from another environment variable").action(
2617
2617
  async (name, options) => secretSetCommand(dependencies(jsonOutput(program)), name, options)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tonbo/cli",
3
- "version": "0.1.0",
4
- "description": "Deploy one persistent Agent per Project from the command line.",
3
+ "version": "0.1.1",
4
+ "description": "Deploy persistent Agents and manage their Machines from the command line.",
5
5
  "homepage": "https://tonbo.dev",
6
6
  "bugs": {
7
7
  "url": "https://github.com/tonbo-io/cloud/issues"