@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.
package/dist/bin.cjs CHANGED
@@ -1725,7 +1725,7 @@ var init_surface = __esm({
1725
1725
  audit: {},
1726
1726
  credential: { set: {} }
1727
1727
  },
1728
- spend: { show: {}, reset: {} }
1728
+ spend: { show: {}, set: {}, reset: {} }
1729
1729
  },
1730
1730
  app: {
1731
1731
  archive: {},
@@ -1820,11 +1820,16 @@ var init_surface = __esm({
1820
1820
  });
1821
1821
 
1822
1822
  // src/admin-spend.ts
1823
- async function call(ctx, method, scope) {
1824
- const url = `${ctx.platformUrl.replace(/\/$/, "")}/registry/platform/spend?scope=${encodeURIComponent(scope)}`;
1823
+ async function call(ctx, method, scope, payload) {
1824
+ const base = `${ctx.platformUrl.replace(/\/$/, "")}/registry/platform/spend`;
1825
+ const url = scope === "default" ? `${base}/default` : `${base}?scope=${encodeURIComponent(scope)}`;
1825
1826
  const response2 = await ctx.doFetch(url, {
1826
1827
  method,
1827
- headers: { authorization: `Bearer ${ctx.token}` }
1828
+ headers: {
1829
+ authorization: `Bearer ${ctx.token}`,
1830
+ ...payload === void 0 ? {} : { "content-type": "application/json" }
1831
+ },
1832
+ ...payload === void 0 ? {} : { body: JSON.stringify(payload) }
1828
1833
  });
1829
1834
  const body = await response2.json().catch(() => ({}));
1830
1835
  if (!response2.ok) {
@@ -1867,14 +1872,36 @@ async function spendReset(ctx, scope) {
1867
1872
  async function adminSpend(parsed, ctx) {
1868
1873
  const action2 = parsed.positionals[2];
1869
1874
  const scope = parsed.positionals[3] ?? stringOpt(parsed.options.scope);
1870
- if (action2 !== "show" && action2 !== "reset") rejectWord(["admin", "spend"], action2);
1875
+ if (action2 !== "show" && action2 !== "reset" && action2 !== "set") rejectWord(["admin", "spend"], action2);
1871
1876
  if (!scope) {
1872
1877
  throw new Error(
1873
- `"admin spend ${action2}" needs a scope, e.g. odla-ai admin spend ${action2} app:my-app:<incarnation>`
1878
+ `"admin spend ${action2}" needs a scope, e.g. odla-ai admin spend ${action2} app:my-app:<incarnation> (or "default" for the fleet-wide fallback)`
1874
1879
  );
1875
1880
  }
1881
+ if (action2 === "set") return adminSpendSet(ctx, parsed, scope);
1876
1882
  return action2 === "show" ? spendShow(ctx, scope) : spendReset(ctx, scope);
1877
1883
  }
1884
+ async function adminSpendSet(ctx, parsed, scope) {
1885
+ const daily = stringOpt(parsed.options.daily);
1886
+ const none = parsed.options.none === true;
1887
+ if (none === (daily !== void 0)) {
1888
+ throw new Error("admin spend set needs exactly one of --daily <usd> or --none");
1889
+ }
1890
+ const dailyCapUsd = none ? null : Number(daily);
1891
+ if (dailyCapUsd !== null && (!Number.isFinite(dailyCapUsd) || dailyCapUsd < 0)) {
1892
+ throw new Error("--daily takes a non-negative dollar amount, for example --daily 25");
1893
+ }
1894
+ const result = await call(ctx, "PUT", scope, { dailyCapUsd });
1895
+ if (ctx.json) {
1896
+ ctx.out.log(JSON.stringify(result, null, 2));
1897
+ return;
1898
+ }
1899
+ ctx.out.log(`${result.scope ?? scope}: ${result.message}`);
1900
+ if (typeof result.spentUsd === "number") ctx.out.log(` spent today ${money(result.spentUsd)}`);
1901
+ if (result.alreadyOverCap) {
1902
+ ctx.out.log(" today's spend already exceeds this cap \u2014 the next call will latch it.");
1903
+ }
1904
+ }
1878
1905
  var money;
1879
1906
  var init_admin_spend = __esm({
1880
1907
  "src/admin-spend.ts"() {
@@ -2723,7 +2750,7 @@ async function adminCommand(parsed, deps = {}) {
2723
2750
  rejectWord(["admin", "ai", "credential"], parsed.positionals[3]);
2724
2751
  }
2725
2752
  if (area === "spend") {
2726
- assertArgs(parsed, JSON_OPTIONS, 4);
2753
+ assertArgs(parsed, [...JSON_OPTIONS, "daily", "none", "scope"], 4);
2727
2754
  const context2 = await resolveOperatorContext(parsed, { allowMissingConfig: true });
2728
2755
  const out = deps.stdout ?? console;
2729
2756
  const doFetch = deps.fetch ?? fetch;
@@ -12139,6 +12166,7 @@ Usage:
12139
12166
  odla-ai admin ai usage [--context <name>] [--app-id <id>] [--env <env>] [--run-id <id>] [--limit <1-500>] [--json]
12140
12167
  odla-ai admin ai audit [--context <name>] [--limit <1-200>] [--json]
12141
12168
  odla-ai admin spend show <app:<id>:<incarnation>> [--context <name>] [--json]
12169
+ odla-ai admin spend set <app:<id>:<incarnation>> (--daily <usd>|--none) [--context <name>] [--json]
12142
12170
  odla-ai admin spend reset <app:<id>:<incarnation>> [--context <name>] [--json]
12143
12171
  odla-ai security github connect [--repo owner/name] [--env dev] [continue in Studio; human session required]
12144
12172
  odla-ai security github disconnect --source <id> [--env dev] [continue in Studio; human session required]