@odla-ai/cli 0.27.12 → 0.27.14

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,13 @@ 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.
8801
+ Before a non-dry-run provision, the executable checks npm's current CLI
8802
+ release. A confirmed stale client stops with a safe npx rerun command; a
8803
+ workspace-linked client also identifies the worktree that must be updated.
8790
8804
  Run Code from a GitHub checkout already connected to an app in Studio; an
8791
8805
  odla.config.mjs may select the app explicitly but is not required. Code host
8792
8806
  approval and credential hashes live in odla-ai/db. The host
@@ -10752,14 +10766,25 @@ async function provision(options) {
10752
10766
  }
10753
10767
  const doFetch = options.fetch ?? fetch;
10754
10768
  const token = await getDeveloperToken(cfg, options, doFetch, out, {
10755
- optionalProjectCapabilities: ["app.manage"]
10769
+ optionalProjectCapabilities: ["app.manage"],
10770
+ forceReview: options.requestGrant
10756
10771
  });
10757
10772
  const apps = (0, import_apps12.createAppsClient)({ endpoint: cfg.platformUrl, token, fetcher: { fetch: doFetch } });
10758
10773
  const existing = await apps.resolveApp(cfg.app.id);
10759
10774
  if (existing) {
10760
10775
  out.log(`app: ${cfg.app.id} already exists`);
10761
10776
  } else {
10762
- await apps.createApp({ name: cfg.app.name, appId: cfg.app.id });
10777
+ try {
10778
+ await apps.createApp({ name: cfg.app.name, appId: cfg.app.id });
10779
+ } catch (error) {
10780
+ if (error instanceof import_apps12.AppsError && error.status === 403) {
10781
+ throw new Error(
10782
+ `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`,
10783
+ { cause: error }
10784
+ );
10785
+ }
10786
+ throw error;
10787
+ }
10763
10788
  out.log(`app: created ${cfg.app.id}`);
10764
10789
  }
10765
10790
  for (const env of cfg.envs) {
@@ -12878,6 +12903,7 @@ async function provisionCommand(parsed, dependencies) {
12878
12903
  "write-credentials",
12879
12904
  "write-dev-vars",
12880
12905
  "token",
12906
+ "request-grant",
12881
12907
  "email",
12882
12908
  "open",
12883
12909
  "wait",
@@ -12893,6 +12919,7 @@ async function provisionCommand(parsed, dependencies) {
12893
12919
  writeCredentials: parsed.options["write-credentials"] !== false,
12894
12920
  writeDevVars: typeof writeDevVars2 === "string" ? writeDevVars2 : writeDevVars2 === true,
12895
12921
  token: stringOpt(parsed.options.token),
12922
+ requestGrant: parsed.options["request-grant"] === true,
12896
12923
  email: stringOpt(parsed.options.email),
12897
12924
  open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
12898
12925
  wait: numberOpt(parsed.options.wait, "--wait"),