@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/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 (
|
|
404
|
-
|
|
405
|
-
|
|
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.
|
|
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;
|
|
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
|
-
|
|
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"),
|