@tonbo/cli 0.1.2 → 0.3.0

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.
Files changed (3) hide show
  1. package/README.md +21 -21
  2. package/dist/bin/tonbo.js +389 -261
  3. package/package.json +7 -7
package/dist/bin/tonbo.js CHANGED
@@ -49,14 +49,14 @@ var TonboApi = class {
49
49
  ...body === void 0 ? {} : { body: JSON.stringify(body) }
50
50
  });
51
51
  }
52
- listProjects(oauthToken) {
52
+ listAgents(oauthToken) {
53
53
  return requestJson(
54
54
  this.fetcher,
55
55
  `${this.accountOrigin}/api/cli/agents`,
56
56
  {
57
57
  headers: { authorization: `Bearer ${oauthToken}` }
58
58
  }
59
- ).then((body) => body.projects);
59
+ ).then((body) => body.agents);
60
60
  }
61
61
  listOrganizations(oauthToken) {
62
62
  return requestJson(
@@ -67,7 +67,7 @@ var TonboApi = class {
67
67
  }
68
68
  ).then((body) => body.organizations);
69
69
  }
70
- createProject(oauthToken, name, organizationId) {
70
+ createAgent(oauthToken, name, organizationId) {
71
71
  return requestJson(
72
72
  this.fetcher,
73
73
  `${this.accountOrigin}/api/cli/agents`,
@@ -79,7 +79,7 @@ var TonboApi = class {
79
79
  },
80
80
  body: JSON.stringify(organizationId ? { name, orgId: organizationId } : { name })
81
81
  }
82
- ).then((body) => body.project);
82
+ ).then((body) => body.agent);
83
83
  }
84
84
  registerSshKey(oauthToken, key) {
85
85
  return requestJson(
@@ -113,10 +113,10 @@ var TonboApi = class {
113
113
  }
114
114
  ).then((body) => body.key);
115
115
  }
116
- exchangeManagementToken(oauthToken, projectId) {
116
+ exchangeManagementToken(oauthToken, agentId) {
117
117
  return requestJson(
118
118
  this.fetcher,
119
- `${this.accountOrigin}/api/cli/agents/${projectId}/token`,
119
+ `${this.accountOrigin}/api/cli/agents/${agentId}/token`,
120
120
  {
121
121
  method: "POST",
122
122
  headers: { authorization: `Bearer ${oauthToken}` }
@@ -126,7 +126,7 @@ var TonboApi = class {
126
126
  async deploy({
127
127
  bundle,
128
128
  origin,
129
- projectId,
129
+ agentId,
130
130
  promote,
131
131
  spec,
132
132
  token
@@ -136,19 +136,19 @@ var TonboApi = class {
136
136
  sha256: bundle.sha256,
137
137
  size_bytes: bundle.size_bytes
138
138
  };
139
- const bundlesPath = `/v1/agents/${projectId}/source-bundles`;
139
+ const bundlesPath = `/v1/agents/${agentId}/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
143
143
  });
144
144
  if (prepared.status === "upload") {
145
145
  if (!prepared.upload_url) throw new Error("Tonbo did not return a source upload URL.");
146
+ if (!prepared.upload_headers || prepared.upload_headers["if-none-match"] !== "*")
147
+ throw new Error("Missing immutable source upload headers.");
146
148
  const uploaded = await this.fetcher(prepared.upload_url, {
149
+ redirect: "error",
147
150
  method: "PUT",
148
- headers: {
149
- "content-type": prepared.content_type ?? "application/vnd.tonbo.source+tar",
150
- "x-upsert": "false"
151
- },
151
+ headers: prepared.upload_headers,
152
152
  body: new Blob([new Uint8Array(bundle.bytes)])
153
153
  });
154
154
  let uploadError = null;
@@ -166,14 +166,14 @@ var TonboApi = class {
166
166
  throw error;
167
167
  }
168
168
  }
169
- let deployment = await this.createDeployment(projectId, { spec, origin }, token);
170
- const previous = await this.getProduction(projectId, token);
171
- const previousDeployment = previous ? await this.getDeployment(projectId, previous.deployment_id, token) : null;
169
+ let deployment = await this.createDeployment(agentId, { spec, origin }, token);
170
+ const previous = await this.getProduction(agentId, token);
171
+ const previousDeployment = previous ? await this.getDeployment(agentId, previous.deployment_id, token) : null;
172
172
  const unchanged = previousDeployment?.spec_sha256 === deployment.spec_sha256;
173
173
  let production = previous;
174
174
  if (promote) {
175
175
  production = await this.putProduction(
176
- projectId,
176
+ agentId,
177
177
  {
178
178
  deployment_id: deployment.id,
179
179
  desired_state: "running",
@@ -181,32 +181,32 @@ var TonboApi = class {
181
181
  },
182
182
  token
183
183
  );
184
- deployment = await this.getDeployment(projectId, deployment.id, token);
184
+ deployment = await this.getDeployment(agentId, deployment.id, token);
185
185
  }
186
186
  return { deployment, production, unchanged };
187
187
  }
188
- createDeployment(projectId, body, token) {
188
+ createDeployment(agentId, body, token) {
189
189
  return this.management(
190
190
  "POST",
191
- `/v1/agents/${projectId}/deployments`,
191
+ `/v1/agents/${agentId}/deployments`,
192
192
  token,
193
193
  body
194
194
  ).then((response) => response.data);
195
195
  }
196
- listDeployments(projectId, token) {
197
- return this.managementList(`/v1/agents/${projectId}/deployments`, token);
196
+ listDeployments(agentId, token) {
197
+ return this.managementList(`/v1/agents/${agentId}/deployments`, token);
198
198
  }
199
- getDeployment(projectId, deploymentId, token) {
199
+ getDeployment(agentId, deploymentId, token) {
200
200
  return this.management(
201
201
  "GET",
202
- `/v1/agents/${projectId}/deployments/${deploymentId}`,
202
+ `/v1/agents/${agentId}/deployments/${deploymentId}`,
203
203
  token
204
204
  ).then((response) => response.data);
205
205
  }
206
- getProduction(projectId, token) {
206
+ getProduction(agentId, token) {
207
207
  return this.management(
208
208
  "GET",
209
- `/v1/agents/${projectId}/production`,
209
+ `/v1/agents/${agentId}/production`,
210
210
  token
211
211
  ).then(
212
212
  (response) => response.data,
@@ -216,44 +216,38 @@ var TonboApi = class {
216
216
  }
217
217
  );
218
218
  }
219
- putProduction(projectId, body, token) {
219
+ putProduction(agentId, body, token) {
220
220
  return this.management(
221
221
  "PUT",
222
- `/v1/agents/${projectId}/production`,
222
+ `/v1/agents/${agentId}/production`,
223
223
  token,
224
224
  body
225
225
  ).then((response) => response.data);
226
226
  }
227
- listRollouts(projectId, token) {
228
- return this.managementList(
229
- `/v1/agents/${projectId}/production/rollouts`,
230
- token
231
- );
227
+ listRollouts(agentId, token) {
228
+ return this.managementList(`/v1/agents/${agentId}/production/rollouts`, token);
232
229
  }
233
230
  async run({
234
- projectId,
231
+ agentId,
235
232
  prompt,
236
233
  sessionId,
237
234
  token,
238
235
  turnId = randomUUID()
239
236
  }) {
240
- const projectPath = `/v1/agents/${projectId}`;
241
- const production = await this.getProduction(projectId, token);
237
+ const agentPath = `/v1/agents/${agentId}`;
238
+ const production = await this.getProduction(agentId, token);
242
239
  if (!production)
243
240
  throw new Error("Agent has no Production Deployment; run `tonbo deploy` first.");
244
241
  if (production.observed_state !== "running")
245
242
  throw new Error(
246
243
  `Production is ${production.observed_state}${production.last_error ? ` (${production.last_error})` : ""}; wait for it to be running.`
247
244
  );
248
- const session = sessionId ? { id: sessionId } : (await this.management(
249
- "POST",
250
- `${projectPath}/sessions`,
251
- token,
252
- { deployment_id: production.deployment_id }
253
- )).data;
245
+ const session = sessionId ? { id: sessionId } : (await this.management("POST", `${agentPath}/sessions`, token, {
246
+ deployment_id: production.deployment_id
247
+ })).data;
254
248
  const turn = (await this.management(
255
249
  "POST",
256
- `${projectPath}/sessions/${session.id}/turns`,
250
+ `${agentPath}/sessions/${session.id}/turns`,
257
251
  token,
258
252
  { prompt },
259
253
  turnId
@@ -262,36 +256,36 @@ var TonboApi = class {
262
256
  }
263
257
  turnEvents({
264
258
  after = 0,
265
- projectId,
259
+ agentId,
266
260
  sessionId,
267
261
  token,
268
262
  turnId
269
263
  }) {
270
264
  return this.management(
271
265
  "GET",
272
- `/v1/agents/${projectId}/sessions/${sessionId}/turns/${turnId}/events?after=${after}`,
266
+ `/v1/agents/${agentId}/sessions/${sessionId}/turns/${turnId}/events?after=${after}`,
273
267
  token
274
268
  );
275
269
  }
276
- listProjectSecrets(projectId, token) {
270
+ listAgentSecrets(agentId, token) {
277
271
  return this.management(
278
272
  "GET",
279
- `/v1/agents/${projectId}/secrets`,
273
+ `/v1/agents/${agentId}/secrets`,
280
274
  token
281
275
  ).then((body) => body.data);
282
276
  }
283
- setProjectSecret(projectId, name, value, token) {
277
+ setAgentSecret(agentId, name, value, token) {
284
278
  return this.management(
285
279
  "PUT",
286
- `/v1/agents/${projectId}/secrets/${encodeURIComponent(name)}`,
280
+ `/v1/agents/${agentId}/secrets/${encodeURIComponent(name)}`,
287
281
  token,
288
282
  { value }
289
283
  );
290
284
  }
291
- deleteProjectSecret(projectId, name, token) {
285
+ deleteAgentSecret(agentId, name, token) {
292
286
  return this.management(
293
287
  "DELETE",
294
- `/v1/agents/${projectId}/secrets/${encodeURIComponent(name)}`,
288
+ `/v1/agents/${agentId}/secrets/${encodeURIComponent(name)}`,
295
289
  token
296
290
  );
297
291
  }
@@ -779,6 +773,40 @@ async function openBrowser(url) {
779
773
  return void await exec("xdg-open", [url]);
780
774
  }
781
775
 
776
+ // src/commands.ts
777
+ import { DEFAULT_INFERENCE_MODEL as DEFAULT_INFERENCE_MODEL2 } from "@tonbo/agent-source-bundler/inference-default";
778
+
779
+ // ../../packages/agent-source-bundler/src/generated/contracts.ts
780
+ var sourceBundleContract = { "version": 1, "format": "tar-v1", "key_prefix": "agent-source-bundles", "content_type": "application/vnd.tonbo.source+tar", "max_bytes": 67108864 };
781
+ var piSessionContract = { "version": 1, "adapter": "pi-jsonl-v3", "format_version": 3, "durable_completion_timeout_seconds": 30, "session_directory": "/sessions", "path_template": "/sessions/{session_id}.jsonl", "preflight_command": ["/usr/local/bin/artifacts", "runtime", "session-preflight"] };
782
+
783
+ // ../../packages/agent-source-bundler/src/deployment-origin.ts
784
+ function deploymentOriginLabel(actor) {
785
+ return actor === "onboarding" ? "Setup guide" : "tonbo deploy";
786
+ }
787
+ function githubRepositoryUrl(remote) {
788
+ if (typeof remote !== "string" || !remote || /\s/.test(remote) || [...remote].some((character) => character.charCodeAt(0) < 32))
789
+ return null;
790
+ let path6;
791
+ const ssh = /^git@github\.com:([^?#]+)$/.exec(remote);
792
+ if (ssh) path6 = ssh[1];
793
+ else {
794
+ try {
795
+ const url = new URL(remote);
796
+ if (url.hostname !== "github.com" || url.port || !["https:", "ssh:"].includes(url.protocol))
797
+ return null;
798
+ path6 = url.pathname.slice(1);
799
+ } catch {
800
+ return null;
801
+ }
802
+ }
803
+ path6 = path6.replace(/\/$/, "").replace(/\.git$/, "");
804
+ const parts = path6.split("/");
805
+ if (parts.length !== 2 || !/^[a-z\d](?:[a-z\d-]{0,38})$/i.test(parts[0]) || !/^[a-z\d._-]{1,100}$/i.test(parts[1]) || [".", ".."].includes(parts[1]))
806
+ return null;
807
+ return `https://github.com/${parts[0]}/${parts[1]}`;
808
+ }
809
+
782
810
  // src/commands.ts
783
811
  import path4 from "node:path";
784
812
 
@@ -879,10 +907,10 @@ var piAgentSchema = {
879
907
  }
880
908
  }
881
909
  };
882
- var projectServiceSchema = {
910
+ var agentServiceSchema = {
883
911
  "$schema": "https://json-schema.org/draft/2020-12/schema",
884
- "$id": "https://contracts.tonbo.dev/agents/project-service-v1.schema.json",
885
- "title": "Tonbo Project application service v1",
912
+ "$id": "https://contracts.tonbo.dev/agents/agent-service-v1.schema.json",
913
+ "title": "Tonbo Agent application service v1",
886
914
  "type": "object",
887
915
  "additionalProperties": false,
888
916
  "required": [
@@ -982,10 +1010,10 @@ var declarationSchema = {
982
1010
  }
983
1011
  },
984
1012
  "service": {
985
- "$ref": "https://contracts.tonbo.dev/agents/project-service-v1.schema.json"
1013
+ "$ref": "https://contracts.tonbo.dev/agents/agent-service-v1.schema.json"
986
1014
  },
987
1015
  "agent": {
988
- "$ref": "https://contracts.tonbo.dev/agents/project-name-v1.json#/$defs/publicHostname"
1016
+ "$ref": "https://contracts.tonbo.dev/agents/agent-name-v1.json#/$defs/publicHostname"
989
1017
  },
990
1018
  "harness": {
991
1019
  "$ref": "https://contracts.tonbo.dev/agents/pi-agent-v1.schema.json"
@@ -995,7 +1023,7 @@ var declarationSchema = {
995
1023
  var deploymentSchema = {
996
1024
  "$schema": "https://json-schema.org/draft/2020-12/schema",
997
1025
  "$id": "https://contracts.tonbo.dev/agents/managed-deployment-v1.schema.json",
998
- "title": "Managed Project Deployment v1",
1026
+ "title": "Managed Agent Deployment v1",
999
1027
  "type": "object",
1000
1028
  "additionalProperties": false,
1001
1029
  "required": [
@@ -1049,36 +1077,16 @@ var deploymentSchema = {
1049
1077
  }
1050
1078
  },
1051
1079
  "service": {
1052
- "$ref": "https://contracts.tonbo.dev/agents/project-service-v1.schema.json"
1080
+ "$ref": "https://contracts.tonbo.dev/agents/agent-service-v1.schema.json"
1053
1081
  }
1054
1082
  }
1055
1083
  };
1056
- var sourceBundleContract = {
1057
- "version": 1,
1058
- "format": "tar-v1",
1059
- "bucket": "agent-source-bundles",
1060
- "content_type": "application/vnd.tonbo.source+tar",
1061
- "max_bytes": 67108864
1062
- };
1063
- var piSessionContract = {
1064
- "version": 1,
1065
- "adapter": "pi-jsonl-v3",
1066
- "format_version": 3,
1067
- "durable_completion_timeout_seconds": 30,
1068
- "session_directory": "/sessions",
1069
- "path_template": "/sessions/{session_id}.jsonl",
1070
- "preflight_command": [
1071
- "/usr/local/bin/artifacts",
1072
- "runtime",
1073
- "session-preflight"
1074
- ]
1075
- };
1076
- var projectNameContract = {
1084
+ var agentNameContract = {
1077
1085
  "$schema": "https://json-schema.org/draft/2020-12/schema",
1078
- "$id": "https://contracts.tonbo.dev/agents/project-name-v1.json",
1086
+ "$id": "https://contracts.tonbo.dev/agents/agent-name-v1.json",
1079
1087
  "x-tonbo-version": 1,
1080
1088
  "x-tonbo-public-hostname-apex": "tonbo.sh",
1081
- "x-tonbo-public-hostname-template": "<project>-<organization>.tonbo.sh",
1089
+ "x-tonbo-public-hostname-template": "<agent>-<organization>-<word>-<word>.tonbo.sh",
1082
1090
  "$defs": {
1083
1091
  "name": {
1084
1092
  "type": "string",
@@ -1117,6 +1125,116 @@ var projectNameContract = {
1117
1125
  "www.tonbo.sh"
1118
1126
  ]
1119
1127
  }
1128
+ },
1129
+ "hostnameWord": {
1130
+ "type": "string",
1131
+ "enum": [
1132
+ "arch",
1133
+ "bark",
1134
+ "beam",
1135
+ "bell",
1136
+ "bird",
1137
+ "blue",
1138
+ "boat",
1139
+ "bold",
1140
+ "book",
1141
+ "calm",
1142
+ "cave",
1143
+ "clay",
1144
+ "coal",
1145
+ "cool",
1146
+ "cove",
1147
+ "dawn",
1148
+ "deer",
1149
+ "dove",
1150
+ "dune",
1151
+ "dusk",
1152
+ "echo",
1153
+ "fern",
1154
+ "fire",
1155
+ "flax",
1156
+ "flow",
1157
+ "foam",
1158
+ "fawn",
1159
+ "frog",
1160
+ "gate",
1161
+ "glow",
1162
+ "gold",
1163
+ "gray",
1164
+ "gulf",
1165
+ "hail",
1166
+ "halo",
1167
+ "hare",
1168
+ "hawk",
1169
+ "hill",
1170
+ "iris",
1171
+ "jade",
1172
+ "kite",
1173
+ "lake",
1174
+ "lamb",
1175
+ "leaf",
1176
+ "lime",
1177
+ "lion",
1178
+ "lobe",
1179
+ "loft",
1180
+ "loom",
1181
+ "luma",
1182
+ "lynx",
1183
+ "mint",
1184
+ "mist",
1185
+ "moon",
1186
+ "moss",
1187
+ "navy",
1188
+ "nest",
1189
+ "nova",
1190
+ "oak",
1191
+ "ocean",
1192
+ "onyx",
1193
+ "opal",
1194
+ "otter",
1195
+ "palm",
1196
+ "peak",
1197
+ "pine",
1198
+ "pond",
1199
+ "pool",
1200
+ "rain",
1201
+ "reed",
1202
+ "reef",
1203
+ "rice",
1204
+ "ring",
1205
+ "rise",
1206
+ "road",
1207
+ "rock",
1208
+ "rose",
1209
+ "ruby",
1210
+ "sage",
1211
+ "sand",
1212
+ "seal",
1213
+ "seed",
1214
+ "silk",
1215
+ "sky",
1216
+ "snow",
1217
+ "soft",
1218
+ "star",
1219
+ "stem",
1220
+ "stone",
1221
+ "surf",
1222
+ "swan",
1223
+ "teal",
1224
+ "tide",
1225
+ "tree",
1226
+ "vale",
1227
+ "vine",
1228
+ "wave",
1229
+ "west",
1230
+ "wind",
1231
+ "wing",
1232
+ "wolf",
1233
+ "wood",
1234
+ "wren",
1235
+ "yarn",
1236
+ "zest"
1237
+ ]
1120
1238
  }
1121
1239
  }
1122
1240
  };
@@ -1129,8 +1247,8 @@ ajv.addKeyword({ keyword: "x-tonbo-public-hostname-apex" });
1129
1247
  ajv.addKeyword({ keyword: "x-tonbo-public-hostname-template" });
1130
1248
  ajv.addSchema(kubernetesProfilesSchema);
1131
1249
  ajv.addSchema(piAgentSchema);
1132
- ajv.addSchema(projectNameContract);
1133
- ajv.addSchema(projectServiceSchema);
1250
+ ajv.addSchema(agentNameContract);
1251
+ ajv.addSchema(agentServiceSchema);
1134
1252
  var validateDeclaration = ajv.compile(declarationSchema);
1135
1253
  var validateDeploymentSpec = ajv.compile(deploymentSchema);
1136
1254
  function validationMessage(label, errors) {
@@ -1150,30 +1268,42 @@ function assertManagedDeploymentSpec(value) {
1150
1268
  }
1151
1269
  }
1152
1270
 
1271
+ // src/declaration.ts
1272
+ import { DEFAULT_INFERENCE_MODEL } from "@tonbo/agent-source-bundler/inference-default";
1273
+
1274
+ // ../../packages/agent-source-bundler/src/native-pi.ts
1275
+ import { stringify } from "smol-toml";
1276
+ function nativePiDeclaration(model) {
1277
+ return {
1278
+ version: 2,
1279
+ harness: { runtime: "pi", driver: { kind: "native" } },
1280
+ inference: { model }
1281
+ };
1282
+ }
1283
+
1153
1284
  // src/declaration.ts
1154
1285
  import { randomUUID as randomUUID2 } from "node:crypto";
1155
1286
  import { lstat as lstat2, open, readFile as readFile2, rename, rm } from "node:fs/promises";
1156
1287
  import path2 from "node:path";
1157
- import { parse, stringify } from "smol-toml";
1288
+ import { parse, stringify as stringify2 } from "smol-toml";
1158
1289
  var DECLARATION_FILENAME = ".tonbo";
1159
- var DEFAULT_INFERENCE_MODEL = "claude-sonnet-4-5";
1160
- function createDeclaration(model = DEFAULT_INFERENCE_MODEL, driver = { kind: "native" }, buildCommand, projectHostname) {
1290
+ function createDeclaration(model = DEFAULT_INFERENCE_MODEL, driver = { kind: "native" }, buildCommand, agentHostname) {
1291
+ const base = nativePiDeclaration(model.trim());
1161
1292
  return parseDeclaration({
1162
- version: 2,
1163
- ...projectHostname ? { agent: projectHostname } : {},
1164
- harness: { runtime: "pi", driver },
1165
- inference: { model: model.trim() },
1293
+ ...base,
1294
+ ...agentHostname ? { agent: agentHostname } : {},
1295
+ harness: { ...base.harness, driver },
1166
1296
  ...buildCommand ? { build: { command: buildCommand } } : {}
1167
1297
  });
1168
1298
  }
1169
1299
  function renderDeclaration(declaration) {
1170
1300
  return `# Tonbo Agent configuration.
1171
1301
  # Edit this file directly or run \`tonbo init\` to reconfigure.
1172
- ${stringify(declaration)}`;
1302
+ ${stringify2(declaration)}`;
1173
1303
  }
1174
- async function bindDeclarationProject(root, projectHostname) {
1304
+ async function bindDeclarationAgent(root, agentHostname) {
1175
1305
  const declaration = await loadDeclaration(root);
1176
- const bound = parseDeclaration({ ...declaration, agent: projectHostname });
1306
+ const bound = parseDeclaration({ ...declaration, agent: agentHostname });
1177
1307
  await saveDeclaration(root, bound, true);
1178
1308
  return bound;
1179
1309
  }
@@ -1252,7 +1382,7 @@ function buildDeploymentSpec(declaration, source) {
1252
1382
  return spec;
1253
1383
  }
1254
1384
 
1255
- // src/source.ts
1385
+ // ../../packages/agent-source-bundler/src/index.ts
1256
1386
  import { createHash as createHash2 } from "node:crypto";
1257
1387
  import { lstat as lstat3, readFile as readFile3, readdir } from "node:fs/promises";
1258
1388
  import path3 from "node:path";
@@ -1303,7 +1433,7 @@ async function validatePackageSource(root, source) {
1303
1433
  const resolved = path3.resolve(settingsDirectory, source);
1304
1434
  const relative = path3.relative(root, resolved);
1305
1435
  if (relative === ".." || relative.startsWith(`..${path3.sep}`) || path3.isAbsolute(relative)) {
1306
- throw new Error(`Local PI package ${source} resolves outside the deployed project.`);
1436
+ throw new Error(`Local PI package ${source} resolves outside the deployed agent.`);
1307
1437
  }
1308
1438
  let metadata;
1309
1439
  try {
@@ -1320,7 +1450,7 @@ async function validatePackageSource(root, source) {
1320
1450
  return;
1321
1451
  }
1322
1452
  throw new Error(
1323
- `PI package ${source} must use an exact npm version, a full Git commit, or a project-local path.`
1453
+ `PI package ${source} must use an exact npm version, a full Git commit, or a agent-local path.`
1324
1454
  );
1325
1455
  }
1326
1456
  async function validatePiPackages(root) {
@@ -1498,31 +1628,31 @@ async function readDefaultSshPublicKeys(sshDirectory = join(homedir(), ".ssh"))
1498
1628
  return keys;
1499
1629
  }
1500
1630
 
1501
- // src/project-name.ts
1502
- var PROJECT_NAME_RULE = projectNameContract.$defs.name;
1503
- var PROJECT_NAME_PATTERN = new RegExp(PROJECT_NAME_RULE.pattern);
1504
- var RESERVED_PROJECT_NAMES = new Set(PROJECT_NAME_RULE.not.enum);
1505
- function validateProjectName(name) {
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);
1631
+ // src/agent-name.ts
1632
+ var AGENT_NAME_RULE = agentNameContract.$defs.name;
1633
+ var AGENT_NAME_PATTERN = new RegExp(AGENT_NAME_RULE.pattern);
1634
+ var RESERVED_AGENT_NAMES = new Set(AGENT_NAME_RULE.not.enum);
1635
+ function validateAgentName(name) {
1636
+ const valid = name.length >= AGENT_NAME_RULE.minLength && name.length <= AGENT_NAME_RULE.maxLength && AGENT_NAME_PATTERN.test(name) && !RESERVED_AGENT_NAMES.has(name);
1507
1637
  if (!valid) {
1508
1638
  throw new Error(
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.`
1639
+ `Agent name must be ${AGENT_NAME_RULE.minLength}-${AGENT_NAME_RULE.maxLength} lowercase letters, digits, or single hyphens, start with a letter, and not be reserved.`
1510
1640
  );
1511
1641
  }
1512
1642
  }
1513
- function projectNameSuggestion(value) {
1643
+ function agentNameSuggestion(value) {
1514
1644
  let name = value.normalize("NFKD").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-+/g, "-");
1515
1645
  if (!/^[a-z]/.test(name)) name = `agent-${name}`;
1516
- name = name.slice(0, PROJECT_NAME_RULE.maxLength).replace(/-+$/g, "");
1517
- if (name.length < PROJECT_NAME_RULE.minLength) {
1518
- name = `${name || "agent"}-agent`.slice(0, PROJECT_NAME_RULE.maxLength);
1646
+ name = name.slice(0, AGENT_NAME_RULE.maxLength).replace(/-+$/g, "");
1647
+ if (name.length < AGENT_NAME_RULE.minLength) {
1648
+ name = `${name || "agent"}-agent`.slice(0, AGENT_NAME_RULE.maxLength);
1519
1649
  }
1520
- if (RESERVED_PROJECT_NAMES.has(name)) name = `${name}-agent`;
1650
+ if (RESERVED_AGENT_NAMES.has(name)) name = `${name}-agent`;
1521
1651
  return name;
1522
1652
  }
1523
1653
 
1524
1654
  // src/commands.ts
1525
- async function resolveProject(deps) {
1655
+ async function resolveAgent(deps) {
1526
1656
  const root = await findDeclarationRoot(deps.cwd());
1527
1657
  const declaration = await loadDeclaration(root);
1528
1658
  if (!declaration.agent) {
@@ -1532,14 +1662,14 @@ async function resolveProject(deps) {
1532
1662
  return {
1533
1663
  declaration,
1534
1664
  oauthToken,
1535
- project: selectProject(await deps.api.listProjects(oauthToken), declaration.agent),
1665
+ agent: selectAgent(await deps.api.listAgents(oauthToken), declaration.agent),
1536
1666
  root
1537
1667
  };
1538
1668
  }
1539
- function selectProject(projects, selector) {
1669
+ function selectAgent(agents, selector) {
1540
1670
  const normalized = selector.toLowerCase();
1541
- const matches = projects.filter(
1542
- (project) => project.id === selector || project.name === normalized || project.publicHostname === normalized
1671
+ const matches = agents.filter(
1672
+ (agent) => agent.id === selector || agent.name === normalized || agent.publicHostname === normalized
1543
1673
  );
1544
1674
  if (matches.length === 0) throw new Error(`Agent ${selector} was not found in your account.`);
1545
1675
  if (matches.length > 1)
@@ -1573,7 +1703,7 @@ async function initCommand(deps, options) {
1573
1703
  throw new Error("No Harness-specific configuration found. Pass --harness pi.");
1574
1704
  } else {
1575
1705
  deps.output({
1576
- message: "No Harness-specific configuration was found in this project."
1706
+ message: "No Harness-specific configuration was found in this agent."
1577
1707
  });
1578
1708
  harness = await selectHarness(deps);
1579
1709
  }
@@ -1597,21 +1727,21 @@ async function initCommand(deps, options) {
1597
1727
  entry = (await deps.prompt("PI SDK entry file [dist/agent.mjs]: ")).trim();
1598
1728
  }
1599
1729
  entry ||= "dist/agent.mjs";
1600
- let model = options.model?.trim() || existingDeclaration?.inference.model || DEFAULT_INFERENCE_MODEL;
1730
+ let model = options.model?.trim() || existingDeclaration?.inference.model || DEFAULT_INFERENCE_MODEL2;
1601
1731
  let buildCommand = driver === "command" ? options.buildCommand ?? existingDeclaration?.build?.command ?? ["npm", "run", "build"] : void 0;
1602
- let projectPlan = existingDeclaration?.agent ? {
1732
+ let agentPlan = existingDeclaration?.agent ? {
1603
1733
  kind: "existing",
1604
1734
  publicHostname: existingDeclaration.agent
1605
1735
  } : { kind: "later" };
1606
1736
  if (interactive && !existingDeclaration?.agent) {
1607
- projectPlan = await selectInitProject(deps, root);
1737
+ agentPlan = await selectInitAgent(deps, root);
1608
1738
  }
1609
1739
  if (interactive) {
1610
1740
  while (true) {
1611
1741
  deps.output({
1612
- message: renderInitSummary(projectPlan, harness, driver, model, entry, buildCommand)
1742
+ message: renderInitSummary(agentPlan, harness, driver, model, entry, buildCommand)
1613
1743
  });
1614
- const saveLabel = initSaveLabel(exists, projectPlan);
1744
+ const saveLabel = initSaveLabel(exists, agentPlan);
1615
1745
  const action = await deps.select(`${saveLabel} with this configuration?`, [
1616
1746
  {
1617
1747
  name: saveLabel,
@@ -1633,9 +1763,9 @@ async function initCommand(deps, options) {
1633
1763
  if (action === "save") break;
1634
1764
  const setting = await deps.select("What would you like to change?", [
1635
1765
  {
1636
- description: initProjectSummary(projectPlan),
1637
- name: "Project",
1638
- value: "project"
1766
+ description: initAgentSummary(agentPlan),
1767
+ name: "Agent",
1768
+ value: "agent"
1639
1769
  },
1640
1770
  { description: harnessName(harness), name: "Harness", value: "harness" },
1641
1771
  {
@@ -1647,7 +1777,7 @@ async function initCommand(deps, options) {
1647
1777
  ...driver === "command" ? [{ description: entry, name: "PI SDK entry file", value: "entry" }] : [],
1648
1778
  { name: "Back to review", value: "back" }
1649
1779
  ]);
1650
- if (setting === "project") projectPlan = await selectInitProject(deps, root);
1780
+ if (setting === "agent") agentPlan = await selectInitAgent(deps, root);
1651
1781
  if (setting === "harness") harness = await selectHarness(deps);
1652
1782
  if (setting === "driver") {
1653
1783
  driver = await deps.select(
@@ -1672,22 +1802,18 @@ async function initCommand(deps, options) {
1672
1802
  }
1673
1803
  }
1674
1804
  }
1675
- let projectHostname = projectPlan.kind === "existing" ? projectPlan.publicHostname : void 0;
1676
- let createdProject;
1677
- if (projectPlan.kind === "create") {
1805
+ let agentHostname = agentPlan.kind === "existing" ? agentPlan.publicHostname : void 0;
1806
+ let createdAgent;
1807
+ if (agentPlan.kind === "create") {
1678
1808
  const oauthToken = await deps.auth.accessToken();
1679
- createdProject = await deps.api.createProject(
1680
- oauthToken,
1681
- projectPlan.name,
1682
- projectPlan.organizationId
1683
- );
1684
- projectHostname = createdProject.publicHostname;
1809
+ createdAgent = await deps.api.createAgent(oauthToken, agentPlan.name, agentPlan.organizationId);
1810
+ agentHostname = createdAgent.publicHostname;
1685
1811
  }
1686
1812
  const configuredDeclaration = createDeclaration(
1687
1813
  model,
1688
1814
  driver === "native" ? { kind: "native" } : { kind: "command", protocol: "pi-rpc-v1", command: ["node", entry] },
1689
1815
  buildCommand,
1690
- projectHostname
1816
+ agentHostname
1691
1817
  );
1692
1818
  const declaration = parseDeclaration({
1693
1819
  ...configuredDeclaration,
@@ -1700,9 +1826,9 @@ async function initCommand(deps, options) {
1700
1826
  try {
1701
1827
  await saveDeclaration(root, declaration, overwrite);
1702
1828
  } catch (error) {
1703
- if (createdProject) {
1829
+ if (createdAgent) {
1704
1830
  throw new Error(
1705
- `Created agent ${createdProject.name}, but could not write ${DECLARATION_FILENAME}. Fix the file and run \`tonbo agent use ${createdProject.publicHostname}\`.`,
1831
+ `Created agent ${createdAgent.name}, but could not write ${DECLARATION_FILENAME}. Fix the file and run \`tonbo agent use ${createdAgent.publicHostname}\`.`,
1706
1832
  { cause: error }
1707
1833
  );
1708
1834
  }
@@ -1711,28 +1837,28 @@ async function initCommand(deps, options) {
1711
1837
  const driverSummary = driver === "command" ? `PI SDK app
1712
1838
  Build: ${buildCommand?.join(" ")}
1713
1839
  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 ? `Agent: ${createdProject.name} (${createdProject.publicHostname})
1715
- Organization: ${createdProject.organizationName}
1716
- Application: https://${createdProject.publicHostname}
1717
- SSH after deploy: ssh ${createdProject.sshDestination}` : projectPlan.kind === "existing" ? `Agent: ${projectPlan.name ? `${projectPlan.name} (${projectPlan.publicHostname})` : projectPlan.publicHostname}${projectPlan.organizationName ? `
1718
- Organization: ${projectPlan.organizationName}` : ""}${projectPlan.sshDestination ? `
1719
- SSH after deploy: ssh ${projectPlan.sshDestination}` : ""}` : "Next: tonbo agent create <name>";
1840
+ const agentSummary = createdAgent ? `Agent: ${createdAgent.name} (${createdAgent.publicHostname})
1841
+ Organization: ${createdAgent.organizationName}
1842
+ Application: https://${createdAgent.publicHostname}
1843
+ SSH after deploy: ssh ${createdAgent.sshDestination}` : agentPlan.kind === "existing" ? `Agent: ${agentPlan.name ? `${agentPlan.name} (${agentPlan.publicHostname})` : agentPlan.publicHostname}${agentPlan.organizationName ? `
1844
+ Organization: ${agentPlan.organizationName}` : ""}${agentPlan.sshDestination ? `
1845
+ SSH after deploy: ssh ${agentPlan.sshDestination}` : ""}` : "Next: tonbo agent create <name>";
1720
1846
  deps.output({
1721
- message: `${createdProject ? `Created agent ${createdProject.name} and` : exists ? "Updated" : "Created"} ${DECLARATION_FILENAME}.
1722
- ${projectSummary}
1847
+ message: `${createdAgent ? `Created agent ${createdAgent.name} and` : exists ? "Updated" : "Created"} ${DECLARATION_FILENAME}.
1848
+ ${agentSummary}
1723
1849
  Harness: PI
1724
- Mode: ${driverSummary}${projectPlan.kind === "later" ? "" : "\nNext: tonbo deploy"}`,
1850
+ Mode: ${driverSummary}${agentPlan.kind === "later" ? "" : "\nNext: tonbo deploy"}`,
1725
1851
  declaration,
1726
1852
  path: path4.join(root, DECLARATION_FILENAME)
1727
1853
  });
1728
1854
  }
1729
- function initSaveLabel(exists, project) {
1730
- if (project.kind === "create") {
1855
+ function initSaveLabel(exists, agent) {
1856
+ if (agent.kind === "create") {
1731
1857
  return exists ? `Create agent and replace ${DECLARATION_FILENAME}` : `Create agent and ${DECLARATION_FILENAME}`;
1732
1858
  }
1733
1859
  return exists ? `Replace ${DECLARATION_FILENAME}` : `Create ${DECLARATION_FILENAME}`;
1734
1860
  }
1735
- async function selectInitProject(deps, root) {
1861
+ async function selectInitAgent(deps, root) {
1736
1862
  for (; ; ) {
1737
1863
  const action = await deps.select("How should this directory connect to Tonbo?", [
1738
1864
  {
@@ -1754,12 +1880,12 @@ async function selectInitProject(deps, root) {
1754
1880
  if (action === "later") return { kind: "later" };
1755
1881
  if (action === "create") {
1756
1882
  const organization = await selectInitOrganization(deps);
1757
- const defaultName = projectNameSuggestion(path4.basename(root)) || "tonbo-agent";
1883
+ const defaultName = agentNameSuggestion(path4.basename(root)) || "tonbo-agent";
1758
1884
  for (; ; ) {
1759
1885
  const answer = (await deps.prompt(`Agent name [${defaultName}]: `)).trim().toLowerCase();
1760
1886
  const name = answer || defaultName;
1761
1887
  try {
1762
- validateProjectName(name);
1888
+ validateAgentName(name);
1763
1889
  return {
1764
1890
  kind: "create",
1765
1891
  name,
@@ -1774,36 +1900,36 @@ async function selectInitProject(deps, root) {
1774
1900
  }
1775
1901
  }
1776
1902
  const oauthToken = await deps.auth.accessToken();
1777
- const projects = (await deps.api.listProjects(oauthToken)).filter(
1778
- (project2) => project2.status === "active"
1903
+ const agents = (await deps.api.listAgents(oauthToken)).filter(
1904
+ (agent2) => agent2.status === "active"
1779
1905
  );
1780
- if (projects.length === 0) {
1906
+ if (agents.length === 0) {
1781
1907
  deps.output({ message: "No active agents are available. Create a new agent instead." });
1782
1908
  continue;
1783
1909
  }
1784
1910
  const id = await deps.select(
1785
1911
  "Which agent should this directory use?",
1786
- projects.map((project2) => ({
1787
- name: project2.name,
1788
- description: `Organization: ${project2.organizationName} \xB7 ${project2.publicHostname} \xB7 ${project2.id}`,
1789
- value: project2.id
1912
+ agents.map((agent2) => ({
1913
+ name: agent2.name,
1914
+ description: `Organization: ${agent2.organizationName} \xB7 ${agent2.publicHostname} \xB7 ${agent2.id}`,
1915
+ value: agent2.id
1790
1916
  }))
1791
1917
  );
1792
- const project = selectProject(projects, id);
1918
+ const agent = selectAgent(agents, id);
1793
1919
  return {
1794
1920
  kind: "existing",
1795
- name: project.name,
1796
- organizationName: project.organizationName,
1797
- publicHostname: project.publicHostname,
1798
- sshDestination: project.sshDestination
1921
+ name: agent.name,
1922
+ organizationName: agent.organizationName,
1923
+ publicHostname: agent.publicHostname,
1924
+ sshDestination: agent.sshDestination
1799
1925
  };
1800
1926
  }
1801
1927
  }
1802
- function initProjectSummary(project) {
1803
- if (project.kind === "create")
1804
- return `Create ${project.name}${project.organizationName ? ` in ${project.organizationName}` : ""} (permanent address assigned after creation)`;
1805
- if (project.kind === "existing") {
1806
- return project.name ? `${project.name}${project.organizationName ? ` in ${project.organizationName}` : ""} (${project.publicHostname})` : `Keep ${project.publicHostname}`;
1928
+ function initAgentSummary(agent) {
1929
+ if (agent.kind === "create")
1930
+ return `Create ${agent.name}${agent.organizationName ? ` in ${agent.organizationName}` : ""} (permanent address assigned after creation)`;
1931
+ if (agent.kind === "existing") {
1932
+ return agent.name ? `${agent.name}${agent.organizationName ? ` in ${agent.organizationName}` : ""} (${agent.publicHostname})` : `Keep ${agent.publicHostname}`;
1807
1933
  }
1808
1934
  return "Set up later";
1809
1935
  }
@@ -1813,7 +1939,7 @@ async function selectInitOrganization(deps) {
1813
1939
  (organization) => organization.role !== "member"
1814
1940
  );
1815
1941
  if (organizations.length === 0)
1816
- throw new Error("No organization lets you create a project. Ask an admin or owner.");
1942
+ throw new Error("No organization lets you create a agent. Ask an admin or owner.");
1817
1943
  if (organizations.length === 1) return organizations[0];
1818
1944
  const id = await deps.select(
1819
1945
  "Which organization should own the new agent?",
@@ -1839,11 +1965,11 @@ function harnessName(harness) {
1839
1965
  const supported = supportedHarnesses.find((candidate) => candidate.id === harness);
1840
1966
  return supported?.name ?? harness;
1841
1967
  }
1842
- function renderInitSummary(project, harness, driver, model, entry, buildCommand) {
1968
+ function renderInitSummary(agent, harness, driver, model, entry, buildCommand) {
1843
1969
  const lines = [
1844
1970
  "",
1845
1971
  "Tonbo Agent configuration:",
1846
- ` Agent: ${initProjectSummary(project)}`,
1972
+ ` Agent: ${initAgentSummary(agent)}`,
1847
1973
  ` Harness: ${harnessName(harness)}`,
1848
1974
  ` Execution: ${driver === "native" ? "PI CLI (`pi`)" : "PI SDK app"}`,
1849
1975
  ` Model: ${model}`
@@ -1862,7 +1988,7 @@ function piTargetChoices(settingsFound) {
1862
1988
  value: "command"
1863
1989
  },
1864
1990
  native: {
1865
- description: settingsFound ? "Run pi directly and load the detected project-local PI configuration." : "Run pi directly with AGENTS.md and optional project-local .pi resources.",
1991
+ description: settingsFound ? "Run pi directly and load the detected agent-local PI configuration." : "Run pi directly with AGENTS.md and optional agent-local .pi resources.",
1866
1992
  name: "PI CLI (`pi`)",
1867
1993
  value: "native"
1868
1994
  }
@@ -1928,31 +2054,31 @@ async function sshKeyRemoveCommand(deps, fingerprint) {
1928
2054
  const key = await deps.api.revokeSshKey(oauthToken, fingerprint);
1929
2055
  deps.output({ message: `Revoked SSH key ${key.fingerprint}.`, key });
1930
2056
  }
1931
- async function projectUseCommand(deps, selector, force = false) {
2057
+ async function agentUseCommand(deps, selector, force = false) {
1932
2058
  const root = await findDeclarationRoot(deps.cwd());
1933
2059
  const declaration = await loadDeclaration(root);
1934
2060
  const oauthToken = await deps.auth.accessToken();
1935
- const projects = await deps.api.listProjects(oauthToken);
1936
- const project = selectProject(projects, selector);
1937
- if (declaration.agent === project.publicHostname) {
2061
+ const agents = await deps.api.listAgents(oauthToken);
2062
+ const agent = selectAgent(agents, selector);
2063
+ if (declaration.agent === agent.publicHostname) {
1938
2064
  deps.output({
1939
- message: `.tonbo already uses agent ${project.publicHostname}.`,
1940
- agent: project
2065
+ message: `.tonbo already uses agent ${agent.publicHostname}.`,
2066
+ agent
1941
2067
  });
1942
2068
  return;
1943
2069
  }
1944
2070
  if (declaration.agent && !force) {
1945
- const current = projects.find((candidate) => candidate.publicHostname === declaration.agent);
2071
+ const current = agents.find((candidate) => candidate.publicHostname === declaration.agent);
1946
2072
  const currentLabel = current?.publicHostname ?? declaration.agent;
1947
2073
  if (!deps.interactive()) {
1948
2074
  throw new Error(
1949
- `.tonbo already uses agent ${currentLabel}. Pass --force to rebind it to ${project.publicHostname}.`
2075
+ `.tonbo already uses agent ${currentLabel}. Pass --force to rebind it to ${agent.publicHostname}.`
1950
2076
  );
1951
2077
  }
1952
2078
  const action = await deps.select(
1953
- `Rebind .tonbo from ${currentLabel} to ${project.publicHostname}?`,
2079
+ `Rebind .tonbo from ${currentLabel} to ${agent.publicHostname}?`,
1954
2080
  [
1955
- { name: `Rebind to ${project.publicHostname}`, value: "rebind" },
2081
+ { name: `Rebind to ${agent.publicHostname}`, value: "rebind" },
1956
2082
  { name: "Cancel", value: "cancel" }
1957
2083
  ]
1958
2084
  );
@@ -1961,10 +2087,10 @@ async function projectUseCommand(deps, selector, force = false) {
1961
2087
  return;
1962
2088
  }
1963
2089
  }
1964
- await bindDeclarationProject(root, project.publicHostname);
1965
- deps.output({ message: `Bound .tonbo to agent ${project.publicHostname}.`, agent: project });
2090
+ await bindDeclarationAgent(root, agent.publicHostname);
2091
+ deps.output({ message: `Bound .tonbo to agent ${agent.publicHostname}.`, agent });
1966
2092
  }
1967
- async function projectCreateCommand(deps, name) {
2093
+ async function agentCreateCommand(deps, name) {
1968
2094
  const root = await findDeclarationRoot(deps.cwd());
1969
2095
  const declaration = await loadDeclaration(root);
1970
2096
  if (declaration.agent) {
@@ -1973,28 +2099,28 @@ async function projectCreateCommand(deps, name) {
1973
2099
  );
1974
2100
  }
1975
2101
  const oauthToken = await deps.auth.accessToken();
1976
- validateProjectName(name);
1977
- const project = await deps.api.createProject(oauthToken, name);
2102
+ validateAgentName(name);
2103
+ const agent = await deps.api.createAgent(oauthToken, name);
1978
2104
  try {
1979
- await bindDeclarationProject(root, project.publicHostname);
2105
+ await bindDeclarationAgent(root, agent.publicHostname);
1980
2106
  } catch (error) {
1981
2107
  throw new Error(
1982
- `Created agent ${project.name}, but could not bind ${DECLARATION_FILENAME}. Fix the file and run \`tonbo agent use ${project.publicHostname}\`.`,
2108
+ `Created agent ${agent.name}, but could not bind ${DECLARATION_FILENAME}. Fix the file and run \`tonbo agent use ${agent.publicHostname}\`.`,
1983
2109
  { cause: error }
1984
2110
  );
1985
2111
  }
1986
- deps.output({ message: `Created agent ${project.name} and bound it in .tonbo.`, agent: project });
2112
+ deps.output({ message: `Created agent ${agent.name} and bound it in .tonbo.`, agent });
1987
2113
  }
1988
2114
  async function deployCommand(deps, options = { promote: true }) {
1989
- const { declaration, oauthToken, project, root } = await resolveProject(deps);
2115
+ const { declaration, oauthToken, agent, root } = await resolveAgent(deps);
1990
2116
  if (declaration.build) await runBuildCommand(root, declaration.build.command);
1991
2117
  const source = await buildSourceBundle(root);
1992
2118
  const origin = { actor: "cli", git: await deps.gitProvenance(root) };
1993
- const managementToken = await deps.api.exchangeManagementToken(oauthToken, project.id);
2119
+ const managementToken = await deps.api.exchangeManagementToken(oauthToken, agent.id);
1994
2120
  const result = await deps.api.deploy({
1995
2121
  bundle: source,
1996
2122
  origin,
1997
- projectId: project.id,
2123
+ agentId: agent.id,
1998
2124
  promote: options.promote,
1999
2125
  spec: buildDeploymentSpec(declaration, source),
2000
2126
  token: managementToken
@@ -2002,12 +2128,12 @@ async function deployCommand(deps, options = { promote: true }) {
2002
2128
  const { deployment } = result;
2003
2129
  const shortId = shortDeploymentId(deployment.id);
2004
2130
  const lines = [
2005
- options.promote ? `Deployed agent ${project.name}.` : `Created Deployment ${deploymentName(deployment)} (${shortId}) for agent ${project.name} without promoting it.`,
2006
- `Organization: ${project.organizationName}`,
2131
+ options.promote ? `Deployed agent ${agent.name}.` : `Created Deployment ${deploymentName(deployment)} (${shortId}) for agent ${agent.name} without promoting it.`,
2132
+ `Organization: ${agent.organizationName}`,
2007
2133
  `Deployment: ${deploymentName(deployment)} (${shortId})`,
2008
2134
  `Source: ${deploymentSourceLabel(deployment)}`,
2009
2135
  `Production: ${options.promote ? productionStateLabel(deployment) : `not promoted; run \`tonbo deployments promote ${shortId}\` to move Production here`}`,
2010
- `Application: https://${project.publicHostname}`
2136
+ `Application: https://${agent.publicHostname}`
2011
2137
  ];
2012
2138
  if (result.unchanged) {
2013
2139
  lines.push(
@@ -2023,49 +2149,49 @@ async function deployCommand(deps, options = { promote: true }) {
2023
2149
  ' tonbo run "<prompt>"',
2024
2150
  "",
2025
2151
  "Connect with SSH:",
2026
- ` ssh ${project.sshDestination}`
2152
+ ` ssh ${agent.sshDestination}`
2027
2153
  );
2028
2154
  }
2029
- deps.output({ message: lines.join("\n"), agent: project, ...result });
2155
+ deps.output({ message: lines.join("\n"), agent, ...result });
2030
2156
  }
2031
2157
  async function runCommand(deps, prompt, options) {
2032
- const { oauthToken, project } = await resolveProject(deps);
2033
- const managementToken = await deps.api.exchangeManagementToken(oauthToken, project.id);
2158
+ const { oauthToken, agent } = await resolveAgent(deps);
2159
+ const managementToken = await deps.api.exchangeManagementToken(oauthToken, agent.id);
2034
2160
  const result = await deps.api.run({
2035
- projectId: project.id,
2161
+ agentId: agent.id,
2036
2162
  prompt,
2037
2163
  sessionId: options.session,
2038
2164
  token: managementToken
2039
2165
  });
2040
2166
  deps.output({
2041
2167
  message: result.turn.assistant_text,
2042
- agent: project,
2168
+ agent,
2043
2169
  ...result
2044
2170
  });
2045
2171
  }
2046
2172
  async function agentListCommand(deps) {
2047
- const agents = await deps.api.listProjects(await deps.auth.accessToken());
2173
+ const agents = await deps.api.listAgents(await deps.auth.accessToken());
2048
2174
  deps.output({
2049
2175
  message: agents.length ? agents.map((agent) => `${agent.name} \xB7 ${agent.publicHostname}`).join("\n") : "No agents are available.",
2050
2176
  agents
2051
2177
  });
2052
2178
  }
2053
- async function projectShowCommand(deps) {
2054
- const { project, token } = await projectManagement(deps);
2055
- const production = await deps.api.getProduction(project.id, token);
2056
- const deployment = production ? await deps.api.getDeployment(project.id, production.deployment_id, token) : null;
2179
+ async function agentShowCommand(deps) {
2180
+ const { agent, token } = await agentManagement(deps);
2181
+ const production = await deps.api.getProduction(agent.id, token);
2182
+ const deployment = production ? await deps.api.getDeployment(agent.id, production.deployment_id, token) : null;
2057
2183
  const lines = [
2058
- `agent: ${project.name}`,
2059
- `Organization: ${project.organizationName}`,
2060
- `application: https://${project.publicHostname}`,
2061
- `ssh: ssh ${project.sshDestination}`
2184
+ `agent: ${agent.name}`,
2185
+ `Organization: ${agent.organizationName}`,
2186
+ `application: https://${agent.publicHostname}`,
2187
+ `ssh: ssh ${agent.sshDestination}`
2062
2188
  ];
2063
2189
  if (deployment) {
2064
2190
  lines.push(
2065
2191
  `production: ${deploymentName(deployment)} (${shortDeploymentId(deployment.id)}) ${productionStateLabel(deployment)}`
2066
2192
  );
2067
2193
  }
2068
- deps.output({ message: lines.join("\n"), agent: project, production, deployment });
2194
+ deps.output({ message: lines.join("\n"), agent, production, deployment });
2069
2195
  }
2070
2196
  function shortDeploymentId(id) {
2071
2197
  return id.replace(/-/g, "").slice(0, 8);
@@ -2076,7 +2202,7 @@ function deploymentName(deployment) {
2076
2202
  }
2077
2203
  function deploymentSourceLabel(deployment) {
2078
2204
  const git = deployment.origin.git;
2079
- if (!git) return "tonbo deploy";
2205
+ if (!git) return deploymentOriginLabel(deployment.origin.actor);
2080
2206
  const sha = git.commit_sha.slice(0, 7);
2081
2207
  return git.ref ? `${sha} \xB7 ${git.ref}` : sha;
2082
2208
  }
@@ -2092,7 +2218,7 @@ function selectDeployment(deployments, prefix) {
2092
2218
  const matches = deployments.filter(
2093
2219
  (deployment) => deployment.id.replace(/-/g, "").startsWith(normalized)
2094
2220
  );
2095
- if (matches.length === 0) throw new Error(`Deployment ${prefix} was not found in this project.`);
2221
+ if (matches.length === 0) throw new Error(`Deployment ${prefix} was not found in this agent.`);
2096
2222
  if (matches.length > 1) {
2097
2223
  throw new Error(
2098
2224
  `Deployment id ${prefix} is ambiguous; it matches ${matches.map((deployment) => shortDeploymentId(deployment.id)).join(", ")}. Use more characters.`
@@ -2118,10 +2244,10 @@ function productionMarker(state) {
2118
2244
  return "";
2119
2245
  }
2120
2246
  async function deploymentsListCommand(deps) {
2121
- const { project, token } = await projectManagement(deps);
2247
+ const { agent, token } = await agentManagement(deps);
2122
2248
  const [deployments, production] = await Promise.all([
2123
- deps.api.listDeployments(project.id, token),
2124
- deps.api.getProduction(project.id, token)
2249
+ deps.api.listDeployments(agent.id, token),
2250
+ deps.api.getProduction(agent.id, token)
2125
2251
  ]);
2126
2252
  const message = deployments.length ? renderTable(
2127
2253
  ["ID", "NAME", "STATUS", "PRODUCTION", "SOURCE", "CREATED", "BY"],
@@ -2134,18 +2260,18 @@ async function deploymentsListCommand(deps) {
2134
2260
  formatTimestamp(deployment.created_at),
2135
2261
  deployment.created_by_user_id ? shortDeploymentId(deployment.created_by_user_id) : ""
2136
2262
  ])
2137
- ) : `No Deployments exist for agent ${project.name}. Run \`tonbo deploy\` to create one.`;
2138
- deps.output({ message, agent: project, production, deployments });
2263
+ ) : `No Deployments exist for agent ${agent.name}. Run \`tonbo deploy\` to create one.`;
2264
+ deps.output({ message, agent, production, deployments });
2139
2265
  }
2140
2266
  async function deploymentsShowCommand(deps, prefix) {
2141
- const { project, token } = await projectManagement(deps);
2142
- const deployment = selectDeployment(await deps.api.listDeployments(project.id, token), prefix);
2143
- const rollouts = (await deps.api.listRollouts(project.id, token)).filter(
2267
+ const { agent, token } = await agentManagement(deps);
2268
+ const deployment = selectDeployment(await deps.api.listDeployments(agent.id, token), prefix);
2269
+ const rollouts = (await deps.api.listRollouts(agent.id, token)).filter(
2144
2270
  (rollout) => rollout.deployment_id === deployment.id || rollout.previous_deployment_id === deployment.id
2145
2271
  );
2146
2272
  deps.output({
2147
2273
  message: renderDeploymentDetail(deployment, rollouts),
2148
- agent: project,
2274
+ agent,
2149
2275
  deployment,
2150
2276
  rollouts
2151
2277
  });
@@ -2186,43 +2312,43 @@ function renderDeploymentDetail(deployment, rollouts) {
2186
2312
  return lines.join("\n");
2187
2313
  }
2188
2314
  async function deploymentsPromoteCommand(deps, prefix) {
2189
- const { project, token } = await projectManagement(deps);
2190
- const target = selectDeployment(await deps.api.listDeployments(project.id, token), prefix);
2191
- const result = await moveProduction(deps, project.id, target, token);
2315
+ const { agent, token } = await agentManagement(deps);
2316
+ const target = selectDeployment(await deps.api.listDeployments(agent.id, token), prefix);
2317
+ const result = await moveProduction(deps, agent.id, target, token);
2192
2318
  deps.output({
2193
- message: describeProductionMove(project, result, "Promoted"),
2194
- agent: project,
2319
+ message: describeProductionMove(agent, result, "Promoted"),
2320
+ agent,
2195
2321
  ...result
2196
2322
  });
2197
2323
  }
2198
2324
  async function deploymentsRollbackCommand(deps, prefix) {
2199
- const { project, token } = await projectManagement(deps);
2325
+ const { agent, token } = await agentManagement(deps);
2200
2326
  let target;
2201
2327
  if (prefix !== void 0) {
2202
- target = selectDeployment(await deps.api.listDeployments(project.id, token), prefix);
2328
+ target = selectDeployment(await deps.api.listDeployments(agent.id, token), prefix);
2203
2329
  } else {
2204
- const rollouts = await deps.api.listRollouts(project.id, token);
2330
+ const rollouts = await deps.api.listRollouts(agent.id, token);
2205
2331
  const previousId = rollouts.find(
2206
2332
  (rollout) => rollout.previous_deployment_id !== null
2207
2333
  )?.previous_deployment_id;
2208
2334
  if (!previousId) {
2209
2335
  throw new Error(
2210
- `Agent ${project.name} has no previous Production Deployment to roll back to. Name one with \`tonbo deployments rollback <id>\`.`
2336
+ `Agent ${agent.name} has no previous Production Deployment to roll back to. Name one with \`tonbo deployments rollback <id>\`.`
2211
2337
  );
2212
2338
  }
2213
- target = await deps.api.getDeployment(project.id, previousId, token);
2339
+ target = await deps.api.getDeployment(agent.id, previousId, token);
2214
2340
  }
2215
- const result = await moveProduction(deps, project.id, target, token);
2341
+ const result = await moveProduction(deps, agent.id, target, token);
2216
2342
  deps.output({
2217
- message: describeProductionMove(project, result, "Rolled back"),
2218
- agent: project,
2343
+ message: describeProductionMove(agent, result, "Rolled back"),
2344
+ agent,
2219
2345
  ...result
2220
2346
  });
2221
2347
  }
2222
- async function moveProduction(deps, projectId, target, token) {
2223
- const previous = await deps.api.getProduction(projectId, token);
2348
+ async function moveProduction(deps, agentId, target, token) {
2349
+ const previous = await deps.api.getProduction(agentId, token);
2224
2350
  const production = await deps.api.putProduction(
2225
- projectId,
2351
+ agentId,
2226
2352
  {
2227
2353
  deployment_id: target.id,
2228
2354
  desired_state: "running",
@@ -2231,49 +2357,49 @@ async function moveProduction(deps, projectId, target, token) {
2231
2357
  token
2232
2358
  );
2233
2359
  return {
2234
- deployment: await deps.api.getDeployment(projectId, target.id, token),
2360
+ deployment: await deps.api.getDeployment(agentId, target.id, token),
2235
2361
  previous,
2236
2362
  production
2237
2363
  };
2238
2364
  }
2239
- function describeProductionMove(project, move, verb) {
2365
+ function describeProductionMove(agent, move, verb) {
2240
2366
  const { deployment, previous } = move;
2241
2367
  const name = `${deploymentName(deployment)} (${shortDeploymentId(deployment.id)})`;
2242
- 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)})` : ""}.`;
2368
+ const headline = previous?.deployment_id === deployment.id ? `Deployment ${name} is already Production for agent ${agent.name}; requested it to be running.` : `${verb} ${name} to Production for agent ${agent.name}${previous ? ` (from ${shortDeploymentId(previous.deployment_id)})` : ""}.`;
2243
2369
  return `${headline}
2244
2370
  Production: ${productionStateLabel(deployment)}
2245
- Application: https://${project.publicHostname}`;
2371
+ Application: https://${agent.publicHostname}`;
2246
2372
  }
2247
- async function projectManagement(deps) {
2248
- const { oauthToken, project } = await resolveProject(deps);
2373
+ async function agentManagement(deps) {
2374
+ const { oauthToken, agent } = await resolveAgent(deps);
2249
2375
  return {
2250
- project,
2251
- token: await deps.api.exchangeManagementToken(oauthToken, project.id)
2376
+ agent,
2377
+ token: await deps.api.exchangeManagementToken(oauthToken, agent.id)
2252
2378
  };
2253
2379
  }
2254
2380
  async function secretListCommand(deps) {
2255
- const { project, token } = await projectManagement(deps);
2256
- const secrets = await deps.api.listProjectSecrets(project.id, token);
2381
+ const { agent, token } = await agentManagement(deps);
2382
+ const secrets = await deps.api.listAgentSecrets(agent.id, token);
2257
2383
  deps.output({
2258
2384
  message: secrets.length ? secrets.map((secret) => secret.name).join("\n") : "No agent secrets are configured.",
2259
- agent: project,
2385
+ agent,
2260
2386
  secrets
2261
2387
  });
2262
2388
  }
2263
2389
  async function secretSetCommand(deps, name, options) {
2264
2390
  const value = await deps.secretValue(name, options.fromEnv);
2265
- const { project, token } = await projectManagement(deps);
2266
- const secret = await deps.api.setProjectSecret(project.id, name, value, token);
2391
+ const { agent, token } = await agentManagement(deps);
2392
+ const secret = await deps.api.setAgentSecret(agent.id, name, value, token);
2267
2393
  deps.output({
2268
2394
  message: `Set agent secret ${secret.name}. Redeploy to replace the active runtime with this value.`,
2269
- agent: project,
2395
+ agent,
2270
2396
  secret
2271
2397
  });
2272
2398
  }
2273
2399
  async function secretRemoveCommand(deps, name) {
2274
- const { project, token } = await projectManagement(deps);
2275
- await deps.api.deleteProjectSecret(project.id, name, token);
2276
- deps.output({ message: `Removed agent secret ${name}.`, agent: project, name });
2400
+ const { agent, token } = await agentManagement(deps);
2401
+ await deps.api.deleteAgentSecret(agent.id, name, token);
2402
+ deps.output({ message: `Removed agent secret ${name}.`, agent, name });
2277
2403
  }
2278
2404
 
2279
2405
  // src/credentials.ts
@@ -2379,15 +2505,17 @@ var AUTHOR_MAX_LENGTH = 255;
2379
2505
  async function collectGitProvenance(root, run = defaultGitRunner) {
2380
2506
  const commitSha = await read(run, ["rev-parse", "HEAD"], root);
2381
2507
  if (!commitSha || !COMMIT_SHA.test(commitSha)) return null;
2382
- const [ref, subject, author, status] = await Promise.all([
2508
+ const [ref, subject, author, status, remote] = await Promise.all([
2383
2509
  read(run, ["rev-parse", "--abbrev-ref", "HEAD"], root),
2384
2510
  read(run, ["log", "-1", "--format=%s"], root),
2385
2511
  read(run, ["log", "-1", "--format=%an"], root),
2386
2512
  // Only the deployed tree matters: changes elsewhere in the repository do
2387
2513
  // not alter the uploaded bundle.
2388
- read(run, ["status", "--porcelain", "--", "."], root)
2514
+ read(run, ["status", "--porcelain", "--", "."], root),
2515
+ read(run, ["remote", "get-url", "origin"], root)
2389
2516
  ]);
2390
2517
  return {
2518
+ ...githubRepositoryUrl(remote) ? { repository_url: githubRepositoryUrl(remote) } : {},
2391
2519
  commit_sha: commitSha,
2392
2520
  ref: ref === "HEAD" ? null : clamp(ref, REF_MAX_LENGTH),
2393
2521
  subject: clamp(subject, SUBJECT_MAX_LENGTH),
@@ -2593,18 +2721,18 @@ function createProgram(dependencies = createDependencies) {
2593
2721
  })
2594
2722
  );
2595
2723
  });
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))));
2724
+ const agent = program.command("agent").description("manage the Agent bound to this source directory");
2725
+ agent.command("create <name>").description("create an agent and bind this directory to it").action(async (name) => agentCreateCommand(dependencies(jsonOutput(program)), name));
2726
+ agent.command("list").description("list the agents available to your account").action(async () => agentListCommand(dependencies(jsonOutput(program))));
2599
2727
  const sshKey = program.command("ssh-key").description("manage public keys used by native agent SSH");
2600
2728
  sshKey.command("add <public-key>").description("register an OpenSSH public key with the current Tonbo account").action(async (path6) => sshKeyAddCommand(dependencies(jsonOutput(program)), path6));
2601
2729
  sshKey.command("remove <fingerprint>").description("revoke an SSH public key from the current Tonbo account").action(
2602
2730
  async (fingerprint) => sshKeyRemoveCommand(dependencies(jsonOutput(program)), fingerprint)
2603
2731
  );
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(
2605
- async (selector, options) => projectUseCommand(dependencies(jsonOutput(program)), selector, options.force === true)
2732
+ agent.command("use <agent>").description("write the agent hostname into this directory's .tonbo declaration").option("--force", "replace an existing agent binding without confirmation").action(
2733
+ async (selector, options) => agentUseCommand(dependencies(jsonOutput(program)), selector, options.force === true)
2606
2734
  );
2607
- project.command("show").description("show the agent bound to this directory and its connection addresses").action(async () => projectShowCommand(dependencies(jsonOutput(program))));
2735
+ agent.command("show").description("show the agent bound to this directory and its connection addresses").action(async () => agentShowCommand(dependencies(jsonOutput(program))));
2608
2736
  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(
2609
2737
  async (options) => deployCommand(dependencies(jsonOutput(program)), { promote: options.promote })
2610
2738
  );