@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/README.md +7 -1
- package/dist/bin.cjs +42 -18
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-ECRBOR66.js → chunk-3YSCRXPF.js} +44 -20
- package/dist/chunk-3YSCRXPF.js.map +1 -0
- package/dist/index.cjs +42 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/odla/references/build.md +8 -0
- package/dist/chunk-ECRBOR66.js.map +0 -1
package/README.md
CHANGED
|
@@ -359,6 +359,8 @@ npx odla-ai code connect --env prod --once # bounded enrollment + heartbeat proo
|
|
|
359
359
|
# install SDKs, write the Worker, and create wrangler.jsonc before secret push
|
|
360
360
|
npx odla-ai provision --dry-run
|
|
361
361
|
npx odla-ai provision --email owner@example.com --write-dev-vars --push-secrets
|
|
362
|
+
# recovery when the selected agent credential has no live app.manage grant
|
|
363
|
+
npx odla-ai provision --request-grant --email owner@example.com --write-dev-vars --push-secrets
|
|
362
364
|
npx odla-ai smoke --env dev
|
|
363
365
|
npx odla-ai agent jobs --env dev --state dead_letter --json
|
|
364
366
|
npx odla-ai agent retry <job-id> --env dev --json
|
|
@@ -472,7 +474,11 @@ shown-once credential.
|
|
|
472
474
|
needed by the run; it does not permit ownership, rename/category, archive,
|
|
473
475
|
restore, or purge. A cached or pending baseline handshake without
|
|
474
476
|
`app.manage` is not reused for provision: the CLI starts a fresh request for
|
|
475
|
-
owner review.
|
|
477
|
+
owner review. An explicit `--token` or `ODLA_DEV_TOKEN` has no trustworthy
|
|
478
|
+
local grant metadata, so a server refusal cannot be repaired by retrying it.
|
|
479
|
+
Run `provision --request-grant --email <account>` to ignore the ambient and
|
|
480
|
+
cached credentials, open a new exact-project review, collect the approved
|
|
481
|
+
replacement, and continue the same provisioning run. If
|
|
476
482
|
the exact project id does not exist yet, approval reserves that id for this
|
|
477
483
|
credential instead of failing: the credential may create only that app once,
|
|
478
484
|
and Registry binds its reviewed grant to the new app incarnation.
|
package/dist/bin.cjs
CHANGED
|
@@ -318,23 +318,30 @@ function handshakeWaitMs(waitSeconds, interactive = import_node_process3.default
|
|
|
318
318
|
|
|
319
319
|
// src/token.ts
|
|
320
320
|
async function getDeveloperToken(cfg, options, doFetch, out, grantRequest = {}) {
|
|
321
|
-
if (options.token) return options.token;
|
|
322
321
|
const audience = platformAudience(cfg.platformUrl);
|
|
323
|
-
if (import_node_process4.default.env.ODLA_DEV_TOKEN) {
|
|
324
|
-
const declared = import_node_process4.default.env.ODLA_DEV_TOKEN_AUDIENCE;
|
|
325
|
-
if (declared) {
|
|
326
|
-
if (platformAudience(declared) !== audience) throw new Error("ODLA_DEV_TOKEN_AUDIENCE does not match the configured platform");
|
|
327
|
-
} else if (audience !== "https://odla.ai") {
|
|
328
|
-
throw new Error("ODLA_DEV_TOKEN_AUDIENCE is required for a non-default platform");
|
|
329
|
-
}
|
|
330
|
-
return import_node_process4.default.env.ODLA_DEV_TOKEN;
|
|
331
|
-
}
|
|
332
322
|
const optionalProjectCapabilities = grantRequest.optionalProjectCapabilities ?? [];
|
|
333
323
|
const grantIntent = { projectIds: [cfg.app.id], optionalProjectCapabilities };
|
|
334
324
|
const cached = readJsonFile(cfg.local.tokenFile);
|
|
335
|
-
if (
|
|
336
|
-
|
|
337
|
-
|
|
325
|
+
if (!grantRequest.forceReview) {
|
|
326
|
+
if (options.token) return options.token;
|
|
327
|
+
if (import_node_process4.default.env.ODLA_DEV_TOKEN) {
|
|
328
|
+
const declared = import_node_process4.default.env.ODLA_DEV_TOKEN_AUDIENCE;
|
|
329
|
+
if (declared) {
|
|
330
|
+
if (platformAudience(declared) !== audience) throw new Error("ODLA_DEV_TOKEN_AUDIENCE does not match the configured platform");
|
|
331
|
+
} else if (audience !== "https://odla.ai") {
|
|
332
|
+
throw new Error("ODLA_DEV_TOKEN_AUDIENCE is required for a non-default platform");
|
|
333
|
+
}
|
|
334
|
+
return import_node_process4.default.env.ODLA_DEV_TOKEN;
|
|
335
|
+
}
|
|
336
|
+
if (cached?.token && cached.platform === audience && (cached.expiresAt ?? 0) > Date.now() + 6e4 && cachedGrantCovers(cached, grantIntent)) {
|
|
337
|
+
out.error(`auth: using cached developer token (${displayPath(cfg.local.tokenFile, cfg.rootDir)})`);
|
|
338
|
+
return cached.token;
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
if (options.token) {
|
|
342
|
+
throw new Error("--request-grant cannot be combined with --token; remove --token so the approved replacement credential can be collected and cached");
|
|
343
|
+
}
|
|
344
|
+
out.error(`auth: requesting fresh owner review for app.manage on exact project "${cfg.app.id}"`);
|
|
338
345
|
}
|
|
339
346
|
const ctx = {
|
|
340
347
|
cfg,
|
|
@@ -2831,11 +2838,11 @@ async function assertTenantAdminAccess(doFetch, cfg, env, token) {
|
|
|
2831
2838
|
}
|
|
2832
2839
|
if (code === "provision_approval_required") {
|
|
2833
2840
|
throw new Error(
|
|
2834
|
-
`${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.
|
|
2841
|
+
`${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`
|
|
2835
2842
|
);
|
|
2836
2843
|
}
|
|
2837
2844
|
throw new Error(
|
|
2838
|
-
`${env}: this credential lacks live app.manage authority for "${cfg.app.id}" (tenant ${tenantId}) \u2014 nothing was minted or written;
|
|
2845
|
+
`${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`
|
|
2839
2846
|
);
|
|
2840
2847
|
}
|
|
2841
2848
|
throw new Error(`${env}: tenant access preflight (${tenantId}) failed: ${res.status} ${await safeText4(res)}`);
|
|
@@ -8517,7 +8524,7 @@ Usage:
|
|
|
8517
8524
|
odla-ai security report <job-id> [--json]
|
|
8518
8525
|
odla-ai security run [target] --ack-redacted-source [--env dev] [--profile odla] [--fail-on high]
|
|
8519
8526
|
odla-ai security run [target] --self --ack-redacted-source
|
|
8520
|
-
odla-ai provision [--config odla.config.mjs] [--email <odla-account>] [--wait <seconds>] [--dry-run] [--push-secrets] [--rotate-o11y-token] [--write-dev-vars[=path]] [--yes]
|
|
8527
|
+
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]
|
|
8521
8528
|
odla-ai smoke [--config odla.config.mjs] [--env dev] [--email <odla-account>] [--no-open]
|
|
8522
8529
|
odla-ai skill install [--dir <project>] [--agent <name>] [--global] [--force]
|
|
8523
8530
|
odla-ai secrets push --env <env> [--config odla.config.mjs] [--dry-run] [--yes]
|
|
@@ -8652,6 +8659,10 @@ Safety:
|
|
|
8652
8659
|
The email is a non-secret identity hint: never provide a password or session
|
|
8653
8660
|
token. The matching account must already exist, be signed in, explicitly
|
|
8654
8661
|
review the exact code, and finish any current request before claiming another.
|
|
8662
|
+
If provision reports that the current agent principal has no live app.manage
|
|
8663
|
+
grant, run it once with --request-grant. That flag ignores ODLA_DEV_TOKEN and
|
|
8664
|
+
the local cache, prints and opens a fresh exact-project owner-review URL, then
|
|
8665
|
+
continues provisioning with the approved replacement credential.
|
|
8655
8666
|
Run Code from a GitHub checkout already connected to an app in Studio; an
|
|
8656
8667
|
odla.config.mjs may select the app explicitly but is not required. Code host
|
|
8657
8668
|
approval and credential hashes live in odla-ai/db. The host
|
|
@@ -10617,14 +10628,25 @@ async function provision(options) {
|
|
|
10617
10628
|
}
|
|
10618
10629
|
const doFetch = options.fetch ?? fetch;
|
|
10619
10630
|
const token = await getDeveloperToken(cfg, options, doFetch, out, {
|
|
10620
|
-
optionalProjectCapabilities: ["app.manage"]
|
|
10631
|
+
optionalProjectCapabilities: ["app.manage"],
|
|
10632
|
+
forceReview: options.requestGrant
|
|
10621
10633
|
});
|
|
10622
10634
|
const apps = (0, import_apps12.createAppsClient)({ endpoint: cfg.platformUrl, token, fetcher: { fetch: doFetch } });
|
|
10623
10635
|
const existing = await apps.resolveApp(cfg.app.id);
|
|
10624
10636
|
if (existing) {
|
|
10625
10637
|
out.log(`app: ${cfg.app.id} already exists`);
|
|
10626
10638
|
} else {
|
|
10627
|
-
|
|
10639
|
+
try {
|
|
10640
|
+
await apps.createApp({ name: cfg.app.name, appId: cfg.app.id });
|
|
10641
|
+
} catch (error) {
|
|
10642
|
+
if (error instanceof import_apps12.AppsError && error.status === 403) {
|
|
10643
|
+
throw new Error(
|
|
10644
|
+
`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`,
|
|
10645
|
+
{ cause: error }
|
|
10646
|
+
);
|
|
10647
|
+
}
|
|
10648
|
+
throw error;
|
|
10649
|
+
}
|
|
10628
10650
|
out.log(`app: created ${cfg.app.id}`);
|
|
10629
10651
|
}
|
|
10630
10652
|
for (const env of cfg.envs) {
|
|
@@ -12723,6 +12745,7 @@ async function provisionCommand(parsed, dependencies) {
|
|
|
12723
12745
|
"write-credentials",
|
|
12724
12746
|
"write-dev-vars",
|
|
12725
12747
|
"token",
|
|
12748
|
+
"request-grant",
|
|
12726
12749
|
"email",
|
|
12727
12750
|
"open",
|
|
12728
12751
|
"wait",
|
|
@@ -12738,6 +12761,7 @@ async function provisionCommand(parsed, dependencies) {
|
|
|
12738
12761
|
writeCredentials: parsed.options["write-credentials"] !== false,
|
|
12739
12762
|
writeDevVars: typeof writeDevVars2 === "string" ? writeDevVars2 : writeDevVars2 === true,
|
|
12740
12763
|
token: stringOpt(parsed.options.token),
|
|
12764
|
+
requestGrant: parsed.options["request-grant"] === true,
|
|
12741
12765
|
email: stringOpt(parsed.options.email),
|
|
12742
12766
|
open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
|
|
12743
12767
|
wait: numberOpt(parsed.options.wait, "--wait"),
|