@odla-ai/cli 0.46.4 → 0.46.6

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runCli
4
- } from "./chunk-PCEGBCLZ.js";
4
+ } from "./chunk-AVUBGTWE.js";
5
5
  import {
6
6
  exitCodeFor
7
7
  } from "./chunk-5MEO3BVF.js";
@@ -9,4 +9,4 @@ export {
9
9
  exitCodeFor,
10
10
  runCli
11
11
  };
12
- //# sourceMappingURL=cli-UTMLBANX.js.map
12
+ //# sourceMappingURL=cli-IAA6SOCV.js.map
package/dist/index.cjs CHANGED
@@ -1327,7 +1327,7 @@ var COMMAND_SURFACE = {
1327
1327
  audit: {},
1328
1328
  credential: { set: {} }
1329
1329
  },
1330
- spend: { show: {}, reset: {} }
1330
+ spend: { show: {}, set: {}, reset: {} }
1331
1331
  },
1332
1332
  app: {
1333
1333
  archive: {},
@@ -1475,11 +1475,16 @@ function surfacePaths(node = COMMAND_SURFACE, prefix = []) {
1475
1475
  }
1476
1476
 
1477
1477
  // src/admin-spend.ts
1478
- async function call(ctx, method, scope) {
1479
- const url = `${ctx.platformUrl.replace(/\/$/, "")}/registry/platform/spend?scope=${encodeURIComponent(scope)}`;
1478
+ async function call(ctx, method, scope, payload) {
1479
+ const base = `${ctx.platformUrl.replace(/\/$/, "")}/registry/platform/spend`;
1480
+ const url = scope === "default" ? `${base}/default` : `${base}?scope=${encodeURIComponent(scope)}`;
1480
1481
  const response2 = await ctx.doFetch(url, {
1481
1482
  method,
1482
- headers: { authorization: `Bearer ${ctx.token}` }
1483
+ headers: {
1484
+ authorization: `Bearer ${ctx.token}`,
1485
+ ...payload === void 0 ? {} : { "content-type": "application/json" }
1486
+ },
1487
+ ...payload === void 0 ? {} : { body: JSON.stringify(payload) }
1483
1488
  });
1484
1489
  const body = await response2.json().catch(() => ({}));
1485
1490
  if (!response2.ok) {
@@ -1523,14 +1528,36 @@ async function spendReset(ctx, scope) {
1523
1528
  async function adminSpend(parsed, ctx) {
1524
1529
  const action2 = parsed.positionals[2];
1525
1530
  const scope = parsed.positionals[3] ?? stringOpt(parsed.options.scope);
1526
- if (action2 !== "show" && action2 !== "reset") rejectWord(["admin", "spend"], action2);
1531
+ if (action2 !== "show" && action2 !== "reset" && action2 !== "set") rejectWord(["admin", "spend"], action2);
1527
1532
  if (!scope) {
1528
1533
  throw new Error(
1529
- `"admin spend ${action2}" needs a scope, e.g. odla-ai admin spend ${action2} app:my-app:<incarnation>`
1534
+ `"admin spend ${action2}" needs a scope, e.g. odla-ai admin spend ${action2} app:my-app:<incarnation> (or "default" for the fleet-wide fallback)`
1530
1535
  );
1531
1536
  }
1537
+ if (action2 === "set") return adminSpendSet(ctx, parsed, scope);
1532
1538
  return action2 === "show" ? spendShow(ctx, scope) : spendReset(ctx, scope);
1533
1539
  }
1540
+ async function adminSpendSet(ctx, parsed, scope) {
1541
+ const daily = stringOpt(parsed.options.daily);
1542
+ const none = parsed.options.none === true;
1543
+ if (none === (daily !== void 0)) {
1544
+ throw new Error("admin spend set needs exactly one of --daily <usd> or --none");
1545
+ }
1546
+ const dailyCapUsd = none ? null : Number(daily);
1547
+ if (dailyCapUsd !== null && (!Number.isFinite(dailyCapUsd) || dailyCapUsd < 0)) {
1548
+ throw new Error("--daily takes a non-negative dollar amount, for example --daily 25");
1549
+ }
1550
+ const result = await call(ctx, "PUT", scope, { dailyCapUsd });
1551
+ if (ctx.json) {
1552
+ ctx.out.log(JSON.stringify(result, null, 2));
1553
+ return;
1554
+ }
1555
+ ctx.out.log(`${result.scope ?? scope}: ${result.message}`);
1556
+ if (typeof result.spentUsd === "number") ctx.out.log(` spent today ${money(result.spentUsd)}`);
1557
+ if (result.alreadyOverCap) {
1558
+ ctx.out.log(" today's spend already exceeds this cap \u2014 the next call will latch it.");
1559
+ }
1560
+ }
1534
1561
 
1535
1562
  // src/operator-context.ts
1536
1563
  var import_node_fs8 = require("fs");
@@ -2328,7 +2355,7 @@ async function adminCommand(parsed, deps = {}) {
2328
2355
  rejectWord(["admin", "ai", "credential"], parsed.positionals[3]);
2329
2356
  }
2330
2357
  if (area === "spend") {
2331
- assertArgs(parsed, JSON_OPTIONS, 4);
2358
+ assertArgs(parsed, [...JSON_OPTIONS, "daily", "none", "scope"], 4);
2332
2359
  const context2 = await resolveOperatorContext(parsed, { allowMissingConfig: true });
2333
2360
  const out = deps.stdout ?? console;
2334
2361
  const doFetch = deps.fetch ?? fetch;
@@ -11208,6 +11235,7 @@ Usage:
11208
11235
  odla-ai admin ai usage [--context <name>] [--app-id <id>] [--env <env>] [--run-id <id>] [--limit <1-500>] [--json]
11209
11236
  odla-ai admin ai audit [--context <name>] [--limit <1-200>] [--json]
11210
11237
  odla-ai admin spend show <app:<id>:<incarnation>> [--context <name>] [--json]
11238
+ odla-ai admin spend set <app:<id>:<incarnation>> (--daily <usd>|--none) [--context <name>] [--json]
11211
11239
  odla-ai admin spend reset <app:<id>:<incarnation>> [--context <name>] [--json]
11212
11240
  odla-ai security github connect [--repo owner/name] [--env dev] [continue in Studio; human session required]
11213
11241
  odla-ai security github disconnect --source <id> [--env dev] [continue in Studio; human session required]