@odla-ai/cli 0.27.12 → 0.27.13

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/dist/index.cjs CHANGED
@@ -386,23 +386,30 @@ function handshakeWaitMs(waitSeconds, interactive = import_node_process3.default
386
386
 
387
387
  // src/token.ts
388
388
  async function getDeveloperToken(cfg, options, doFetch, out, grantRequest = {}) {
389
- if (options.token) return options.token;
390
389
  const audience = platformAudience(cfg.platformUrl);
391
- if (import_node_process4.default.env.ODLA_DEV_TOKEN) {
392
- const declared = import_node_process4.default.env.ODLA_DEV_TOKEN_AUDIENCE;
393
- if (declared) {
394
- if (platformAudience(declared) !== audience) throw new Error("ODLA_DEV_TOKEN_AUDIENCE does not match the configured platform");
395
- } else if (audience !== "https://odla.ai") {
396
- throw new Error("ODLA_DEV_TOKEN_AUDIENCE is required for a non-default platform");
397
- }
398
- return import_node_process4.default.env.ODLA_DEV_TOKEN;
399
- }
400
390
  const optionalProjectCapabilities = grantRequest.optionalProjectCapabilities ?? [];
401
391
  const grantIntent = { projectIds: [cfg.app.id], optionalProjectCapabilities };
402
392
  const cached = readJsonFile(cfg.local.tokenFile);
403
- if (cached?.token && cached.platform === audience && (cached.expiresAt ?? 0) > Date.now() + 6e4 && cachedGrantCovers(cached, grantIntent)) {
404
- out.error(`auth: using cached developer token (${displayPath(cfg.local.tokenFile, cfg.rootDir)})`);
405
- return cached.token;
393
+ if (!grantRequest.forceReview) {
394
+ if (options.token) return options.token;
395
+ if (import_node_process4.default.env.ODLA_DEV_TOKEN) {
396
+ const declared = import_node_process4.default.env.ODLA_DEV_TOKEN_AUDIENCE;
397
+ if (declared) {
398
+ if (platformAudience(declared) !== audience) throw new Error("ODLA_DEV_TOKEN_AUDIENCE does not match the configured platform");
399
+ } else if (audience !== "https://odla.ai") {
400
+ throw new Error("ODLA_DEV_TOKEN_AUDIENCE is required for a non-default platform");
401
+ }
402
+ return import_node_process4.default.env.ODLA_DEV_TOKEN;
403
+ }
404
+ if (cached?.token && cached.platform === audience && (cached.expiresAt ?? 0) > Date.now() + 6e4 && cachedGrantCovers(cached, grantIntent)) {
405
+ out.error(`auth: using cached developer token (${displayPath(cfg.local.tokenFile, cfg.rootDir)})`);
406
+ return cached.token;
407
+ }
408
+ } else {
409
+ if (options.token) {
410
+ throw new Error("--request-grant cannot be combined with --token; remove --token so the approved replacement credential can be collected and cached");
411
+ }
412
+ out.error(`auth: requesting fresh owner review for app.manage on exact project "${cfg.app.id}"`);
406
413
  }
407
414
  const ctx = {
408
415
  cfg,
@@ -2899,11 +2906,11 @@ async function assertTenantAdminAccess(doFetch, cfg, env, token) {
2899
2906
  }
2900
2907
  if (code === "provision_approval_required") {
2901
2908
  throw new Error(
2902
- `${env}: the agent credential does not carry the owner-reviewed app.manage grant required to provision "${cfg.app.id}" (tenant ${tenantId}). The human owner id on the token is accountability, not agent authority. Discard the cached or supplied token and run this command with the current CLI to approve one fresh exact-project provisioning handshake`
2909
+ `${env}: the agent credential does not carry the owner-reviewed app.manage grant required to provision "${cfg.app.id}" (tenant ${tenantId}). The human owner id on the token is accountability, not agent authority. Run "odla-ai provision --request-grant --email <odla-account>" to open one fresh exact-project owner review; do not change app ownership unless the human account itself is not an owner`
2903
2910
  );
2904
2911
  }
2905
2912
  throw new Error(
2906
- `${env}: this credential lacks live app.manage authority for "${cfg.app.id}" (tenant ${tenantId}) \u2014 nothing was minted or written; re-run provision with a fresh owner-approved provision handshake. If the human account is not an owner, an existing owner must add it in signed-in Studio; an agent token cannot repair ownership`
2913
+ `${env}: this credential lacks live app.manage authority for "${cfg.app.id}" (tenant ${tenantId}) \u2014 nothing was minted or written; run "odla-ai provision --request-grant --email <odla-account>" to open a fresh owner review. If the human account is not an owner, an existing owner must add it in signed-in Studio; an agent token cannot repair ownership`
2907
2914
  );
2908
2915
  }
2909
2916
  throw new Error(`${env}: tenant access preflight (${tenantId}) failed: ${res.status} ${await safeText4(res)}`);
@@ -8652,7 +8659,7 @@ Usage:
8652
8659
  odla-ai security report <job-id> [--json]
8653
8660
  odla-ai security run [target] --ack-redacted-source [--env dev] [--profile odla] [--fail-on high]
8654
8661
  odla-ai security run [target] --self --ack-redacted-source
8655
- odla-ai provision [--config odla.config.mjs] [--email <odla-account>] [--wait <seconds>] [--dry-run] [--push-secrets] [--rotate-o11y-token] [--write-dev-vars[=path]] [--yes]
8662
+ odla-ai provision [--config odla.config.mjs] [--email <odla-account>] [--request-grant] [--wait <seconds>] [--dry-run] [--push-secrets] [--rotate-o11y-token] [--write-dev-vars[=path]] [--yes]
8656
8663
  odla-ai smoke [--config odla.config.mjs] [--env dev] [--email <odla-account>] [--no-open]
8657
8664
  odla-ai skill install [--dir <project>] [--agent <name>] [--global] [--force]
8658
8665
  odla-ai secrets push --env <env> [--config odla.config.mjs] [--dry-run] [--yes]
@@ -8787,6 +8794,10 @@ Safety:
8787
8794
  The email is a non-secret identity hint: never provide a password or session
8788
8795
  token. The matching account must already exist, be signed in, explicitly
8789
8796
  review the exact code, and finish any current request before claiming another.
8797
+ If provision reports that the current agent principal has no live app.manage
8798
+ grant, run it once with --request-grant. That flag ignores ODLA_DEV_TOKEN and
8799
+ the local cache, prints and opens a fresh exact-project owner-review URL, then
8800
+ continues provisioning with the approved replacement credential.
8790
8801
  Run Code from a GitHub checkout already connected to an app in Studio; an
8791
8802
  odla.config.mjs may select the app explicitly but is not required. Code host
8792
8803
  approval and credential hashes live in odla-ai/db. The host
@@ -10752,14 +10763,25 @@ async function provision(options) {
10752
10763
  }
10753
10764
  const doFetch = options.fetch ?? fetch;
10754
10765
  const token = await getDeveloperToken(cfg, options, doFetch, out, {
10755
- optionalProjectCapabilities: ["app.manage"]
10766
+ optionalProjectCapabilities: ["app.manage"],
10767
+ forceReview: options.requestGrant
10756
10768
  });
10757
10769
  const apps = (0, import_apps12.createAppsClient)({ endpoint: cfg.platformUrl, token, fetcher: { fetch: doFetch } });
10758
10770
  const existing = await apps.resolveApp(cfg.app.id);
10759
10771
  if (existing) {
10760
10772
  out.log(`app: ${cfg.app.id} already exists`);
10761
10773
  } else {
10762
- await apps.createApp({ name: cfg.app.name, appId: cfg.app.id });
10774
+ try {
10775
+ await apps.createApp({ name: cfg.app.name, appId: cfg.app.id });
10776
+ } catch (error) {
10777
+ if (error instanceof import_apps12.AppsError && error.status === 403) {
10778
+ throw new Error(
10779
+ `app "${cfg.app.id}" does not exist, and this authenticated agent credential has no owner-reviewed app.manage bootstrap grant for that exact id. Run "odla-ai provision --request-grant --email <odla-account>" to open the review URL and continue; developer ownership alone is not agent authority`,
10780
+ { cause: error }
10781
+ );
10782
+ }
10783
+ throw error;
10784
+ }
10763
10785
  out.log(`app: created ${cfg.app.id}`);
10764
10786
  }
10765
10787
  for (const env of cfg.envs) {
@@ -12878,6 +12900,7 @@ async function provisionCommand(parsed, dependencies) {
12878
12900
  "write-credentials",
12879
12901
  "write-dev-vars",
12880
12902
  "token",
12903
+ "request-grant",
12881
12904
  "email",
12882
12905
  "open",
12883
12906
  "wait",
@@ -12893,6 +12916,7 @@ async function provisionCommand(parsed, dependencies) {
12893
12916
  writeCredentials: parsed.options["write-credentials"] !== false,
12894
12917
  writeDevVars: typeof writeDevVars2 === "string" ? writeDevVars2 : writeDevVars2 === true,
12895
12918
  token: stringOpt(parsed.options.token),
12919
+ requestGrant: parsed.options["request-grant"] === true,
12896
12920
  email: stringOpt(parsed.options.email),
12897
12921
  open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
12898
12922
  wait: numberOpt(parsed.options.wait, "--wait"),