@ponderbot/cli 0.1.0-alpha.24 → 0.1.0-alpha.26

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
@@ -90,6 +90,45 @@ uses `@ponderbot/sdk` for authoring and local loading. The CLI bundles the SDK
90
90
  Worker Entry into the artifact. A project can set `worker.build.dockerfile` when
91
91
  it needs a custom system image or install process.
92
92
 
93
+ ## Environment selection
94
+
95
+ Every command resolves one Project environment from `ponderbot/config.ts`. The
96
+ CLI selects the environment in this order:
97
+
98
+ 1. `--env <name>` on the command.
99
+ 2. A non-empty `PONDERBOT_ENV` in the process environment.
100
+ 3. The `development` environment.
101
+
102
+ A named environment (`--env` or `PONDERBOT_ENV`) is the source of truth:
103
+
104
+ - The URL comes from the environment `url`. `PONDERBOT_URL` does not change
105
+ it.
106
+ - The token comes from the environment `tokenEnv` variable. `PONDERBOT_TOKEN`
107
+ is only a fallback when that variable is not set.
108
+ - The Space comes from `--space` or the environment `spaceId`. A named
109
+ environment never reads `PONDERBOT_SPACE_ID`. Space-scoped commands exit 2
110
+ when neither `--space` nor `spaceId` is set. `spaces list` and
111
+ `spaces create` do not need a Space.
112
+
113
+ The default `development` environment keeps the `ponder start` contract:
114
+ `PONDERBOT_URL`, `PONDERBOT_SPACE_ID`, and `PONDERBOT_TOKEN` override the
115
+ environment values when they are set. `--space` still wins over both.
116
+
117
+ Example with a `.env` file that `ponder start` printed:
118
+
119
+ ```sh
120
+ export PONDERBOT_URL=http://127.0.0.1:4000
121
+ export PONDERBOT_TOKEN_PRODUCTION=prod-token
122
+ ponder spaces list --env production
123
+ ```
124
+
125
+ The command lists the Spaces of the `production` URL with `prod-token`. The
126
+ local `PONDERBOT_URL` does not change the target.
127
+
128
+ Mutating commands, such as `manifest deploy`, `spaces create`, and
129
+ `action run`, print the resolved target. Human output starts with `environment`
130
+ and `base URL` lines. JSON output adds the `environment` and `base_url` keys.
131
+
93
132
  Useful space commands:
94
133
 
95
134
  ```sh
package/dist/main.js CHANGED
@@ -31,6 +31,7 @@ const resolveProject = async () => {
31
31
  };
32
32
  const resolveConfig = async (envName, spaceId) => requireExecutionSpace(await resolveEnvironmentConfig(envName), spaceId);
33
33
  const resolveProjectReleaseConfig = async (envName) => resolveEnvironmentConfig(envName, { resolveApplicationOrigin: true });
34
+ const resolveRuntimeConfig = async (envName) => resolveEnvironmentConfig(envName);
34
35
  const resolveDevConfig = async (envName) => requireExecutionSpace(await resolveEnvironmentConfig(envName ?? "development", {
35
36
  requireDevAllowed: true,
36
37
  resolveApplicationOrigin: true,
@@ -72,7 +73,7 @@ const resolveEnvironmentConfig = async (envName, options = {}) => {
72
73
  };
73
74
  const requireExecutionSpace = (config, spaceId) => {
74
75
  const resolvedSpaceId = spaceId !== void 0 && spaceId.length > 0 ? spaceId : config.spaceId;
75
- if (resolvedSpaceId === void 0 || resolvedSpaceId.length === 0) return exitConfig(`set the execution Space with --space, PONDERBOT_SPACE_ID, or spaceId for environment "${config.environment}" in ponderbot/config.ts`);
76
+ if (resolvedSpaceId === void 0 || resolvedSpaceId.length === 0) return exitConfig(`set the execution Space with --space or spaceId for environment "${config.environment}" in ponderbot/config.ts`);
76
77
  return {
77
78
  ...config,
78
79
  spaceId: resolvedSpaceId
@@ -90,17 +91,23 @@ const clientFor = (config) => createClient({
90
91
  token: config.token,
91
92
  spaceId: config.spaceId
92
93
  });
94
+ const withResolvedTarget = (config, result) => ({
95
+ ...result,
96
+ environment: config.environment,
97
+ base_url: config.url
98
+ });
93
99
  //#endregion
94
100
  //#region src/deployment-environment.ts
95
101
  const INERT_SOURCE_SETTINGS = {
96
102
  allow_schedules: false,
103
+ allow_persistent_development_schedules: false,
97
104
  allow_webhooks: false,
98
105
  allow_manual_triggers: false
99
106
  };
100
107
  const reconcileDeploymentEnvironment = async (client, config) => {
101
108
  if (config.environmentRole === "release-source") {
102
109
  const { settings } = await client.spaces.settings.update(INERT_SOURCE_SETTINGS);
103
- if (settings.allow_schedules !== false || settings.allow_webhooks !== false || settings.allow_manual_triggers !== false) throw new Error("release-source Space settings did not become execution-inert");
110
+ if (settings.allow_schedules !== false || settings.allow_persistent_development_schedules !== false || settings.allow_webhooks !== false || settings.allow_manual_triggers !== false) throw new Error("release-source Space settings did not become execution-inert");
104
111
  }
105
112
  };
106
113
  //#endregion
@@ -349,6 +356,14 @@ const formatError = (error) => {
349
356
  return String(error);
350
357
  };
351
358
  const lines = (data) => {
359
+ if (isRecord$1(data) && typeof data.environment === "string" && typeof data.base_url === "string") {
360
+ const { environment, base_url: baseUrl, ...result } = data;
361
+ return [
362
+ `environment ${environment}`,
363
+ `base URL ${baseUrl}`,
364
+ ...lines(result)
365
+ ];
366
+ }
352
367
  if (isRecord$1(data) && isRecord$1(data.release) && isRecord$1(data.resources)) return releaseCatalogLines(data.release, data.resources);
353
368
  if (isStartedDevStack(data)) return [
354
369
  "Ponderbot dev stack ready.",
@@ -1780,7 +1795,7 @@ const providerAuth = async (options) => {
1780
1795
  }
1781
1796
  if (options.allSpaces === true) await client.providerBindings.authorize(binding.id, { allSpaces: true });
1782
1797
  else await client.providerBindings.authorize(binding.id, { spaceIds: sharedSpaceIds });
1783
- return providerAuthResult(provider, method, spaceId, {
1798
+ return providerAuthResult(provider, method, spaceId, config.environment, config.url, {
1784
1799
  bindingId: binding.id,
1785
1800
  allSpaces: options.allSpaces === true,
1786
1801
  spaceIds: options.allSpaces === true ? void 0 : sharedSpaceIds
@@ -1792,16 +1807,16 @@ const providerAuth = async (options) => {
1792
1807
  provider,
1793
1808
  apiKey
1794
1809
  });
1795
- return providerAuthResult(provider, method, spaceId);
1810
+ return providerAuthResult(provider, method, spaceId, config.environment, config.url);
1796
1811
  }
1797
1812
  if (!canPrompt()) throw new Error("OAuth login needs an interactive terminal. Run locally with a browser, or rerun with --no-browser to paste the callback URL.");
1798
1813
  await authorizeOAuthLogin(() => client.modelProviders.startOAuthLogin(spaceId, provider), (authorizationResponse, state) => client.modelProviders.completeOAuthLogin(spaceId, provider, {
1799
1814
  authorizationResponse,
1800
1815
  state
1801
1816
  }), options.browser !== false);
1802
- return providerAuthResult(provider, method, spaceId);
1817
+ return providerAuthResult(provider, method, spaceId, config.environment, config.url);
1803
1818
  };
1804
- const providerAuthResult = (provider, method, spaceId, shared) => ({
1819
+ const providerAuthResult = (provider, method, spaceId, environment, baseUrl, shared) => ({
1805
1820
  type: "provider_auth",
1806
1821
  status: "saved",
1807
1822
  provider,
@@ -1810,7 +1825,9 @@ const providerAuthResult = (provider, method, spaceId, shared) => ({
1810
1825
  binding_id: shared?.bindingId,
1811
1826
  all_spaces: shared?.allSpaces,
1812
1827
  space_ids: shared?.spaceIds,
1813
- smoke_test: "ponder spaces show"
1828
+ smoke_test: "ponder spaces show",
1829
+ environment,
1830
+ base_url: baseUrl
1814
1831
  });
1815
1832
  const resolveProvider = async (value, entries) => {
1816
1833
  const providers = entries.map((entry) => entry.id);
@@ -2361,10 +2378,10 @@ manifest.command("deploy").option("--env <name>", "environment").option("--image
2361
2378
  });
2362
2379
  printManifestDiagnostics(plan.instructionBudgets, plan.warnings);
2363
2380
  const release = await client.projects.releases.deploy(config.projectDefinition.name, config.environment, plan.manifest, config.sourceName, void 0, config.applicationOrigin);
2364
- print(versionBump === void 0 ? release : {
2381
+ print(withResolvedTarget(config, versionBump === void 0 ? release : {
2365
2382
  ...release,
2366
2383
  version_bump: versionBump
2367
- }, program.opts());
2384
+ }), program.opts());
2368
2385
  } catch (error) {
2369
2386
  fail(error, error instanceof WorkerImageError ? 2 : 1);
2370
2387
  }
@@ -2378,19 +2395,19 @@ manifest.command("dev").option("--env <name>", "environment").description("watch
2378
2395
  });
2379
2396
  const spaces = program.command("spaces").description("manage runtime spaces");
2380
2397
  spaces.command("list").option("--env <name>", "environment").description("list spaces").action(async (options) => {
2381
- const config = await resolveConfig(options.env);
2398
+ const config = await resolveRuntimeConfig(options.env);
2382
2399
  await runSpacesCommand("spaces:read", "*", async () => {
2383
2400
  print({ spaces: await listSpaces(clientFor(config)) }, program.opts());
2384
2401
  });
2385
2402
  });
2386
2403
  spaces.command("create <spaceId>").option("--name <name>", "space name").option("--env <name>", "environment").description("create a space").action(async (spaceId, options) => {
2387
- const config = await resolveConfig(options.env);
2404
+ const config = await resolveRuntimeConfig(options.env);
2388
2405
  await runSpacesCommand("spaces:write", "*", async () => {
2389
2406
  try {
2390
- print(await clientFor(config).spaces.create({
2407
+ print(withResolvedTarget(config, await clientFor(config).spaces.create({
2391
2408
  id: spaceId,
2392
2409
  name: options.name ?? spaceId
2393
- }), program.opts());
2410
+ })), program.opts());
2394
2411
  } catch (error) {
2395
2412
  throw spaceCreateError(error, spaceId);
2396
2413
  }
@@ -2422,7 +2439,7 @@ spaces.command("budget [spaceId]").option("--set <file>", "replace budget from a
2422
2439
  print(await client.spaces.budget.get(resolvedSpaceId), program.opts());
2423
2440
  return;
2424
2441
  }
2425
- print(await client.spaces.budget.set(await readJsonFile(options.set), resolvedSpaceId), program.opts());
2442
+ print(withResolvedTarget(config, await client.spaces.budget.set(await readJsonFile(options.set), resolvedSpaceId)), program.opts());
2426
2443
  });
2427
2444
  });
2428
2445
  program.command("provider").description("configure model provider credentials").command("auth").description("authenticate a model provider for a space").option("--env <name>", "environment").option("--space <spaceId>", "target space (defaults to the configured space)").option("--provider <name>", "anthropic | mistral | openai (skips the picker)").option("--method <method>", "api-key | oauth").option("--shared", "store one Runtime credential binding instead of a Space credential").option("--all-spaces", "authorize the shared binding for every Space").option("--spaces <spaceIds...>", "authorize the shared binding for selected Spaces").option("--no-browser", "print the Codex authorize URL and paste the callback URL").action(async (options) => {
@@ -2432,7 +2449,7 @@ const model = program.command("model").description("manage Space model policy");
2432
2449
  model.command("add <modelRef>").requiredOption("--provider <name>", "anthropic | fake | mistral | openai").requiredOption("--model <name>", "provider model name").option("--capability <name...>", "declared model capabilities").option("--fallback <modelRef...>", "ordered fallback model refs").option("--space <spaceId>", "target space (defaults to the configured space)").option("--env <name>", "environment").description("add or update a model in the Space catalog").action(async (modelRef, options) => {
2433
2450
  const config = await resolveConfig(options.env, options.space);
2434
2451
  await runSpacesCommand("spaces:write", config.spaceId, async () => {
2435
- print(await clientFor(config).models.upsert(modelRef, modelDefinitionInput(options)), program.opts());
2452
+ print(withResolvedTarget(config, await clientFor(config).models.upsert(modelRef, modelDefinitionInput(options))), program.opts());
2436
2453
  });
2437
2454
  });
2438
2455
  model.command("list").option("--space <spaceId>", "target space (defaults to the configured space)").option("--env <name>", "environment").description("list models in the Space catalog").action(async (options) => {
@@ -2444,7 +2461,7 @@ model.command("list").option("--space <spaceId>", "target space (defaults to the
2444
2461
  model.command("assign <agentRef> <modelRef>").option("--space <spaceId>", "target space (defaults to the configured space)").option("--env <name>", "environment").description("assign a Space catalog model to an exact Agent ref").action(async (agentRef, modelRef, options) => {
2445
2462
  const config = await resolveConfig(options.env, options.space);
2446
2463
  await runSpacesCommand("spaces:write", config.spaceId, async () => {
2447
- print(await clientFor(config).models.assign(agentRef, modelRef), program.opts());
2464
+ print(withResolvedTarget(config, await clientFor(config).models.assign(agentRef, modelRef)), program.opts());
2448
2465
  });
2449
2466
  });
2450
2467
  model.command("assignments").option("--space <spaceId>", "target space (defaults to the configured space)").option("--env <name>", "environment").description("list exact Agent model assignments for a Space").action(async (options) => {
@@ -2463,7 +2480,8 @@ releases.command("catalog [releaseId]").option("--space <spaceId>", "target spac
2463
2480
  print(await client.releases.catalog(resolvedReleaseId), program.opts());
2464
2481
  });
2465
2482
  program.command("rollback <releaseId>").option("--env <name>", "environment").description("roll back to a release").action(async (releaseId, options) => {
2466
- print(await clientFor(await resolveConfig(options.env)).releases.rollback(releaseId), program.opts());
2483
+ const config = await resolveConfig(options.env);
2484
+ print(withResolvedTarget(config, await clientFor(config).releases.rollback(releaseId)), program.opts());
2467
2485
  });
2468
2486
  program.command("runs").option("--type <type>", "run type").option("--status <status>", "run status").option("--env <name>", "environment").description("list runs").action(async (options) => {
2469
2487
  print(await clientFor(await resolveConfig(options.env)).runs.list(Object.fromEntries([["type", options.type], ["status", options.status]].filter((entry) => typeof entry[1] === "string"))), program.opts());
@@ -2475,19 +2493,22 @@ program.command("run <type> <id>").option("--export", "export run bundle").optio
2475
2493
  });
2476
2494
  program.command("cancel <type> <id>").option("--env <name>", "environment").description("cancel a run").action(async (type, id, options) => {
2477
2495
  const runType = parseRunType(type);
2478
- print(await clientFor(await resolveConfig(options.env)).runs.cancel(runType, id), program.opts());
2496
+ const config = await resolveConfig(options.env);
2497
+ print(withResolvedTarget(config, await clientFor(config).runs.cancel(runType, id)), program.opts());
2479
2498
  });
2480
2499
  program.command("action").command("run <ref>").option("--input <json>", "input payload", "{}").option("--space <spaceId>", "target space (defaults to the configured space)").option("--env <name>", "environment").option("--release-id <id>", "pinned release id").option("--manifest-name <name>", "current release selector").description("start an Action Run").action(async (ref, options) => {
2481
- print(await clientFor(await resolveConfig(options.env, options.space)).actions.run(ref, JSON.parse(options.input), {
2500
+ const config = await resolveConfig(options.env, options.space);
2501
+ print(withResolvedTarget(config, await clientFor(config).actions.run(ref, JSON.parse(options.input), {
2482
2502
  releaseId: options.releaseId,
2483
2503
  manifestName: options.manifestName
2484
- }), program.opts());
2504
+ })), program.opts());
2485
2505
  });
2486
2506
  program.command("workflow").command("trigger <ref>").option("--input <json>", "input payload", "{}").option("--space <spaceId>", "target space (defaults to the configured space)").option("--env <name>", "environment").option("--release-id <id>", "pinned release id").option("--manifest-name <name>", "current release selector").description("start a Workflow Run").action(async (ref, options) => {
2487
- print(await clientFor(await resolveConfig(options.env, options.space)).workflows.trigger(ref, JSON.parse(options.input), {
2507
+ const config = await resolveConfig(options.env, options.space);
2508
+ print(withResolvedTarget(config, await clientFor(config).workflows.trigger(ref, JSON.parse(options.input), {
2488
2509
  releaseId: options.releaseId,
2489
2510
  manifestName: options.manifestName
2490
- }), program.opts());
2511
+ })), program.opts());
2491
2512
  });
2492
2513
  program.command("decisions").option("--env <name>", "environment").option("--actionable", "only generations this actor could answer").description("list pending decisions").action(async (options) => {
2493
2514
  print(await clientFor(await resolveConfig(options.env)).decisions.list({
@@ -2496,10 +2517,12 @@ program.command("decisions").option("--env <name>", "environment").option("--act
2496
2517
  }), program.opts());
2497
2518
  });
2498
2519
  program.command("approve <id>").option("--env <name>", "environment").option("--reason <reason>", "bounded reason recorded on the response").description("approve a decision").action(async (id, options) => {
2499
- print(await clientFor(await resolveConfig(options.env)).decisions.approve(id, { ...options.reason === void 0 ? {} : { reason: options.reason } }), program.opts());
2520
+ const config = await resolveConfig(options.env);
2521
+ print(withResolvedTarget(config, await clientFor(config).decisions.approve(id, { ...options.reason === void 0 ? {} : { reason: options.reason } })), program.opts());
2500
2522
  });
2501
2523
  program.command("reject <id>").option("--env <name>", "environment").option("--reason <reason>", "bounded reason recorded on the response").description("reject a decision").action(async (id, options) => {
2502
- print(await clientFor(await resolveConfig(options.env)).decisions.reject(id, { ...options.reason === void 0 ? {} : { reason: options.reason } }), program.opts());
2524
+ const config = await resolveConfig(options.env);
2525
+ print(withResolvedTarget(config, await clientFor(config).decisions.reject(id, { ...options.reason === void 0 ? {} : { reason: options.reason } })), program.opts());
2503
2526
  });
2504
2527
  program.command("events").option("--follow", "follow runtime events").option("--env <name>", "environment").description("show recent events or follow the event stream").action(async (options) => {
2505
2528
  const client = clientFor(await resolveConfig(options.env));