@odla-ai/cli 0.27.15 → 0.27.17
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 +5 -1
- package/dist/bin.cjs +102 -20
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-MR5QXX3B.js → chunk-3WVVHH3Y.js} +86 -12
- package/dist/chunk-3WVVHH3Y.js.map +1 -0
- package/dist/{cli-2RZFZRRT.js → cli-DCSVQAZ6.js} +2 -2
- package/dist/index.cjs +92 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +3 -1
- package/dist/runtime/pi-agent.js +15 -314577
- package/package.json +2 -2
- package/dist/chunk-MR5QXX3B.js.map +0 -1
- /package/dist/{cli-2RZFZRRT.js.map → cli-DCSVQAZ6.js.map} +0 -0
package/dist/bin.js
CHANGED
|
@@ -174,7 +174,7 @@ function absoluteEntryPath(entryPath) {
|
|
|
174
174
|
|
|
175
175
|
// src/bin.ts
|
|
176
176
|
var argv = process.argv.slice(2);
|
|
177
|
-
requireCurrentCliForProvision(argv).then(() => requireCoherentProvisionRuntime(argv)).then(async () => (await import("./cli-
|
|
177
|
+
requireCurrentCliForProvision(argv).then(() => requireCoherentProvisionRuntime(argv)).then(async () => (await import("./cli-DCSVQAZ6.js")).runCli()).catch((err) => {
|
|
178
178
|
console.error(redactSecrets(`odla-ai: ${err instanceof Error ? err.message : String(err)}`));
|
|
179
179
|
process.exitCode = exitCodeFor(err);
|
|
180
180
|
});
|
|
@@ -2577,6 +2577,63 @@ function printGroup(out, heading, items) {
|
|
|
2577
2577
|
out.log("");
|
|
2578
2578
|
}
|
|
2579
2579
|
|
|
2580
|
+
// src/ai-models.ts
|
|
2581
|
+
import { DEFAULT_CATALOG } from "@odla-ai/ai";
|
|
2582
|
+
async function aiModels(options = {}) {
|
|
2583
|
+
const cfg = await loadProjectConfig(options.configPath ?? "odla.config.mjs");
|
|
2584
|
+
const env = options.env ?? cfg.envs[0] ?? "dev";
|
|
2585
|
+
if (!cfg.envs.includes(env)) throw new Error(`ai models env "${env}" is not declared in config envs`);
|
|
2586
|
+
const url = new URL(`/registry/apps/${encodeURIComponent(cfg.app.id)}/public-config`, cfg.platformUrl);
|
|
2587
|
+
url.searchParams.set("env", env);
|
|
2588
|
+
const response2 = await (options.fetch ?? fetch)(url);
|
|
2589
|
+
if (!response2.ok) throw new Error(`read app AI models failed (${response2.status}): ${await safeText4(response2)}`);
|
|
2590
|
+
const body = await response2.json();
|
|
2591
|
+
if (!body.ai) throw new Error(`ai is not configured for ${cfg.app.id}/${env}`);
|
|
2592
|
+
const mode = body.ai.mode === "hosted" ? "hosted" : "byok";
|
|
2593
|
+
const defaultModel = typeof body.ai.model === "string" ? body.ai.model : void 0;
|
|
2594
|
+
let models;
|
|
2595
|
+
if (mode === "hosted") {
|
|
2596
|
+
if (body.ai.enabled !== true) throw new Error(`hosted ai is disabled for ${cfg.app.id}/${env}`);
|
|
2597
|
+
if (!Array.isArray(body.ai.models) || !body.ai.models.every(isModelSpec)) {
|
|
2598
|
+
throw new Error("platform returned an invalid hosted AI model catalog");
|
|
2599
|
+
}
|
|
2600
|
+
models = body.ai.models;
|
|
2601
|
+
} else {
|
|
2602
|
+
const provider = typeof body.ai.provider === "string" ? body.ai.provider : cfg.ai?.provider;
|
|
2603
|
+
if (!provider) throw new Error(`BYOK ai has no provider for ${cfg.app.id}/${env}`);
|
|
2604
|
+
models = Object.values(DEFAULT_CATALOG).filter((model) => model.provider === provider);
|
|
2605
|
+
}
|
|
2606
|
+
if (options.provider) models = models.filter((model) => model.provider === options.provider);
|
|
2607
|
+
models.sort((a, b) => a.provider.localeCompare(b.provider) || a.id.localeCompare(b.id));
|
|
2608
|
+
const out = options.stdout ?? console;
|
|
2609
|
+
if (options.json) {
|
|
2610
|
+
out.log(JSON.stringify({ appId: cfg.app.id, env, mode, defaultModel: defaultModel ?? null, models }, null, 2));
|
|
2611
|
+
return;
|
|
2612
|
+
}
|
|
2613
|
+
out.log("provider model default capabilities");
|
|
2614
|
+
for (const model of models) {
|
|
2615
|
+
out.log([model.provider, model.id, model.id === defaultModel ? "yes" : "", capabilityList(model)].join(" "));
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
function capabilityList(model) {
|
|
2619
|
+
return [
|
|
2620
|
+
model.capabilities.imageIn ? "image" : "",
|
|
2621
|
+
model.capabilities.audioIn ? "audio" : "",
|
|
2622
|
+
model.capabilities.documentIn ? "document" : "",
|
|
2623
|
+
model.capabilities.toolUse ? "tools" : "",
|
|
2624
|
+
model.capabilities.thinking || model.capabilities.effort ? "reasoning" : "",
|
|
2625
|
+
model.capabilities.webSearch || model.superpowers?.webSearch ? "web-search" : ""
|
|
2626
|
+
].filter(Boolean).join(",");
|
|
2627
|
+
}
|
|
2628
|
+
function isModelSpec(value2) {
|
|
2629
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return false;
|
|
2630
|
+
const model = value2;
|
|
2631
|
+
return typeof model.id === "string" && typeof model.nativeId === "string" && (model.provider === "anthropic" || model.provider === "openai" || model.provider === "google") && Boolean(model.capabilities) && typeof model.capabilities === "object";
|
|
2632
|
+
}
|
|
2633
|
+
async function safeText4(response2) {
|
|
2634
|
+
return (await response2.text().catch(() => "request failed")).slice(0, 300);
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2580
2637
|
// src/config-operation-command.ts
|
|
2581
2638
|
import {
|
|
2582
2639
|
AppsError,
|
|
@@ -2768,7 +2825,7 @@ async function assertTenantAdminAccess(doFetch, cfg, env, token) {
|
|
|
2768
2825
|
});
|
|
2769
2826
|
if (res.ok || res.status === 404) return;
|
|
2770
2827
|
if (res.status === 403) {
|
|
2771
|
-
const detail = await
|
|
2828
|
+
const detail = await safeText5(res);
|
|
2772
2829
|
const code = errorCode(detail);
|
|
2773
2830
|
if (code === "human_session_required") {
|
|
2774
2831
|
throw new Error(
|
|
@@ -2784,7 +2841,7 @@ async function assertTenantAdminAccess(doFetch, cfg, env, token) {
|
|
|
2784
2841
|
`${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`
|
|
2785
2842
|
);
|
|
2786
2843
|
}
|
|
2787
|
-
throw new Error(`${env}: tenant access preflight (${tenantId}) failed: ${res.status} ${await
|
|
2844
|
+
throw new Error(`${env}: tenant access preflight (${tenantId}) failed: ${res.status} ${await safeText5(res)}`);
|
|
2788
2845
|
}
|
|
2789
2846
|
function errorCode(text2) {
|
|
2790
2847
|
try {
|
|
@@ -2800,7 +2857,7 @@ async function postJson(doFetch, url, bearer, body) {
|
|
|
2800
2857
|
headers: { authorization: `Bearer ${bearer}`, "content-type": "application/json" },
|
|
2801
2858
|
body: JSON.stringify(body)
|
|
2802
2859
|
});
|
|
2803
|
-
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await
|
|
2860
|
+
if (!res.ok) throw new Error(`${new URL(url).pathname} failed: ${res.status} ${await safeText5(res)}`);
|
|
2804
2861
|
}
|
|
2805
2862
|
function normalizeClerkConfig(value2) {
|
|
2806
2863
|
if (!value2) return null;
|
|
@@ -2813,7 +2870,7 @@ function normalizeClerkConfig(value2) {
|
|
|
2813
2870
|
const publishableKey = envValue(cfg.publishableKey);
|
|
2814
2871
|
return publishableKey ? { publishableKey, ...cfg.audience ? { audience: cfg.audience } : {}, ...cfg.mode ? { mode: cfg.mode } : {} } : null;
|
|
2815
2872
|
}
|
|
2816
|
-
async function
|
|
2873
|
+
async function safeText5(res) {
|
|
2817
2874
|
try {
|
|
2818
2875
|
return redactSecrets((await res.text()).slice(0, 500));
|
|
2819
2876
|
} catch {
|
|
@@ -4583,7 +4640,7 @@ async function getJson(doFetch, url, bearer) {
|
|
|
4583
4640
|
const res = await doFetch(url, {
|
|
4584
4641
|
headers: bearer ? { authorization: `Bearer ${bearer}` } : void 0
|
|
4585
4642
|
});
|
|
4586
|
-
if (!res.ok) throw new Error(`${new URL(url).pathname} returned ${res.status}: ${await
|
|
4643
|
+
if (!res.ok) throw new Error(`${new URL(url).pathname} returned ${res.status}: ${await safeText6(res)}`);
|
|
4587
4644
|
return res.json();
|
|
4588
4645
|
}
|
|
4589
4646
|
async function postJson2(doFetch, url, bearer, body) {
|
|
@@ -4592,7 +4649,7 @@ async function postJson2(doFetch, url, bearer, body) {
|
|
|
4592
4649
|
headers: { authorization: `Bearer ${bearer}`, "content-type": "application/json" },
|
|
4593
4650
|
body: JSON.stringify(body)
|
|
4594
4651
|
});
|
|
4595
|
-
if (!res.ok) throw new Error(`${new URL(url).pathname} returned ${res.status}: ${await
|
|
4652
|
+
if (!res.ok) throw new Error(`${new URL(url).pathname} returned ${res.status}: ${await safeText6(res)}`);
|
|
4596
4653
|
return res.json();
|
|
4597
4654
|
}
|
|
4598
4655
|
function publicConfigUrl(platformUrl, appId, env) {
|
|
@@ -4600,7 +4657,7 @@ function publicConfigUrl(platformUrl, appId, env) {
|
|
|
4600
4657
|
url.searchParams.set("env", env);
|
|
4601
4658
|
return url.toString();
|
|
4602
4659
|
}
|
|
4603
|
-
async function
|
|
4660
|
+
async function safeText6(res) {
|
|
4604
4661
|
try {
|
|
4605
4662
|
return redactSecrets((await res.text()).slice(0, 500));
|
|
4606
4663
|
} catch {
|
|
@@ -4656,6 +4713,20 @@ async function secretsCommand(parsed, deps) {
|
|
|
4656
4713
|
});
|
|
4657
4714
|
}
|
|
4658
4715
|
async function projectCommand(command, parsed, deps) {
|
|
4716
|
+
if (command === "ai") {
|
|
4717
|
+
const sub = parsed.positionals[1];
|
|
4718
|
+
if (sub !== "models") throw new Error(`unknown ai subcommand "${sub ?? ""}". Try "odla-ai ai models --env dev".`);
|
|
4719
|
+
assertArgs(parsed, ["config", "env", "provider", "json"], 2);
|
|
4720
|
+
await aiModels({
|
|
4721
|
+
configPath: stringOpt(parsed.options.config) ?? "odla.config.mjs",
|
|
4722
|
+
env: stringOpt(parsed.options.env),
|
|
4723
|
+
provider: stringOpt(parsed.options.provider),
|
|
4724
|
+
json: parsed.options.json === true,
|
|
4725
|
+
fetch: deps.fetch,
|
|
4726
|
+
stdout: deps.stdout
|
|
4727
|
+
});
|
|
4728
|
+
return true;
|
|
4729
|
+
}
|
|
4659
4730
|
if (command === "config") {
|
|
4660
4731
|
const sub = parsed.positionals[1];
|
|
4661
4732
|
if (sub !== "diff" && sub !== "plan" && sub !== "apply") {
|
|
@@ -8432,6 +8503,7 @@ Usage:
|
|
|
8432
8503
|
odla-ai setup [--dir <project>] [--agent <name>] [--global] [--force]
|
|
8433
8504
|
odla-ai init --app-id <id> --name <name> [--services db,ai,o11y,calendar] [--env dev --env prod] [--ai-provider <byok-provider>]
|
|
8434
8505
|
odla-ai doctor [--config odla.config.mjs]
|
|
8506
|
+
odla-ai ai models [--config odla.config.mjs] [--env dev] [--provider <id>] [--json]
|
|
8435
8507
|
odla-ai config <diff|plan> [--config odla.config.mjs] [--email <odla-account>] [--json]
|
|
8436
8508
|
odla-ai config apply --plan <plan.json> [--idempotency-key <key>] [--email <odla-account>] [--json]
|
|
8437
8509
|
odla-ai operations get <operation-id> [--json]
|
|
@@ -10535,14 +10607,14 @@ async function mintDbKey(opts, tenantId) {
|
|
|
10535
10607
|
appId: tenantId
|
|
10536
10608
|
})
|
|
10537
10609
|
});
|
|
10538
|
-
if (!created.ok) throw new Error(`db app create (${tenantId}) failed: ${created.status} ${await
|
|
10610
|
+
if (!created.ok) throw new Error(`db app create (${tenantId}) failed: ${created.status} ${await safeText7(created)}`);
|
|
10539
10611
|
res = await opts.fetch(`${opts.cfg.dbEndpoint}/admin/apps/${encodeURIComponent(tenantId)}/keys`, {
|
|
10540
10612
|
method: "POST",
|
|
10541
10613
|
headers,
|
|
10542
10614
|
body: "{}"
|
|
10543
10615
|
});
|
|
10544
10616
|
}
|
|
10545
|
-
if (!res.ok) throw new Error(`db key mint (${tenantId}) failed: ${res.status} ${await
|
|
10617
|
+
if (!res.ok) throw new Error(`db key mint (${tenantId}) failed: ${res.status} ${await safeText7(res)}`);
|
|
10546
10618
|
const body = await res.json();
|
|
10547
10619
|
if (!body.key) throw new Error(`db key mint (${tenantId}) returned no key`);
|
|
10548
10620
|
return body.key;
|
|
@@ -10558,12 +10630,12 @@ async function issueO11yToken(opts) {
|
|
|
10558
10630
|
`o11y token already exists for env "${opts.env}", but its shown-once value is not in the local credentials file; run "odla-ai provision --rotate-o11y-token --push-secrets" to replace it explicitly`
|
|
10559
10631
|
);
|
|
10560
10632
|
}
|
|
10561
|
-
if (!res.ok) throw new Error(`o11y token ${opts.rotateO11y ? "rotation" : "issue"} (${opts.env}) failed: ${res.status} ${await
|
|
10633
|
+
if (!res.ok) throw new Error(`o11y token ${opts.rotateO11y ? "rotation" : "issue"} (${opts.env}) failed: ${res.status} ${await safeText7(res)}`);
|
|
10562
10634
|
const body = await res.json();
|
|
10563
10635
|
if (!body.token) throw new Error(`o11y token ${opts.rotateO11y ? "rotation" : "issue"} (${opts.env}) returned no token`);
|
|
10564
10636
|
return body.token;
|
|
10565
10637
|
}
|
|
10566
|
-
async function
|
|
10638
|
+
async function safeText7(res) {
|
|
10567
10639
|
try {
|
|
10568
10640
|
return redactSecrets((await res.text()).slice(0, 500));
|
|
10569
10641
|
} catch {
|
|
@@ -10818,6 +10890,7 @@ var PM_ENTITIES = {
|
|
|
10818
10890
|
};
|
|
10819
10891
|
var COMMAND_SURFACE = {
|
|
10820
10892
|
agent: { jobs: {}, retry: {} },
|
|
10893
|
+
ai: { models: {} },
|
|
10821
10894
|
admin: {
|
|
10822
10895
|
ai: {
|
|
10823
10896
|
show: {},
|
|
@@ -12793,6 +12866,7 @@ export {
|
|
|
12793
12866
|
calendarDisconnect,
|
|
12794
12867
|
CAPABILITIES,
|
|
12795
12868
|
printCapabilities,
|
|
12869
|
+
aiModels,
|
|
12796
12870
|
ConfigOperationCommandError,
|
|
12797
12871
|
desiredRegistryState,
|
|
12798
12872
|
configApply,
|
|
@@ -12837,4 +12911,4 @@ export {
|
|
|
12837
12911
|
isTerminalHostedSecurityStatus,
|
|
12838
12912
|
runCli
|
|
12839
12913
|
};
|
|
12840
|
-
//# sourceMappingURL=chunk-
|
|
12914
|
+
//# sourceMappingURL=chunk-3WVVHH3Y.js.map
|