@gravity-rail/cli 0.11.0 → 0.13.0

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/lib.js CHANGED
@@ -7823,6 +7823,11 @@ function priceSummary(product) {
7823
7823
  }
7824
7824
  return parts.join(", ") || "\u2014";
7825
7825
  }
7826
+ function checkoutPeriod(args) {
7827
+ const value = typeof args.period === "string" ? args.period : "month";
7828
+ if (value === "month" || value === "quarter" || value === "year") return value;
7829
+ throw new Error("Billing period must be 'month', 'quarter', or 'year'");
7830
+ }
7826
7831
  var PRODUCT_COLUMNS2 = [
7827
7832
  { header: "ID", getValue: (p) => String(p.id ?? "") },
7828
7833
  { header: "NAME", getValue: (p) => p.name ?? "" },
@@ -7847,6 +7852,14 @@ var SUBSCRIPTION_COLUMNS = [
7847
7852
  getValue: (s) => String(s.customerOrganizationUuid ?? s.organizationUuid ?? "")
7848
7853
  }
7849
7854
  ];
7855
+ var CONTRACT_BEARING_STATUSES = /* @__PURE__ */ new Set([
7856
+ "incomplete",
7857
+ "trialing",
7858
+ "active",
7859
+ "past_due",
7860
+ "unpaid",
7861
+ "paused"
7862
+ ]);
7850
7863
  function isTable(ctx) {
7851
7864
  return (ctx.outputFormat ?? "table") === "table";
7852
7865
  }
@@ -7884,7 +7897,7 @@ var billingDomain = {
7884
7897
  } else {
7885
7898
  hint(ctx, [
7886
7899
  "Next \u2014 buy an organization plan to get started:",
7887
- " gr billing checkout --product <id> [--period month|year]"
7900
+ " gr billing checkout --product <id> [--org <id>|--new-org]"
7888
7901
  ]);
7889
7902
  }
7890
7903
  }
@@ -7896,15 +7909,40 @@ var billingDomain = {
7896
7909
  requiresWorkspace: false,
7897
7910
  args: [
7898
7911
  { name: "product", description: "Product ID of the org plan to buy", required: true },
7899
- { name: "period", description: "Billing period: 'month' or 'year'", default: "month" }
7912
+ {
7913
+ name: "period",
7914
+ description: "Billing period: 'month', 'quarter', or 'year'",
7915
+ default: "month"
7916
+ },
7917
+ {
7918
+ name: "org",
7919
+ description: "Existing organization ID to own the subscription"
7920
+ },
7921
+ {
7922
+ name: "new-org",
7923
+ description: "Create a new organization for this subscription",
7924
+ isFlag: true
7925
+ }
7926
+ ],
7927
+ examples: [
7928
+ "gr billing checkout --product 12 --period month --org 7",
7929
+ "gr billing checkout --product 12 --period month --new-org"
7900
7930
  ],
7901
- examples: ["gr billing checkout --product 12 --period month"],
7902
7931
  handler: async ({ ctx, args }) => {
7903
7932
  const productId = Number(requireString(args, "product"));
7904
- const period = args.period || "month";
7933
+ const period = checkoutPeriod(args);
7934
+ const organizationId = typeof args.org === "string" ? Number(args.org) : void 0;
7935
+ const createNewOrg = args["new-org"] === true;
7936
+ if (organizationId !== void 0 && (!Number.isInteger(organizationId) || organizationId <= 0)) {
7937
+ throw new Error("Organization ID must be a positive integer");
7938
+ }
7939
+ if (organizationId !== void 0 && createNewOrg) {
7940
+ throw new Error("Choose either --org or --new-org, not both");
7941
+ }
7905
7942
  const result2 = await requireAuth(ctx).apiClient.createCheckoutSession(
7906
7943
  productId,
7907
- period
7944
+ period,
7945
+ organizationId !== void 0 || createNewOrg ? { checkoutContext: { organizationId, createNewOrg } } : void 0
7908
7946
  );
7909
7947
  if (isTable(ctx)) {
7910
7948
  process.stdout.write(
@@ -7931,10 +7969,10 @@ Then check it landed:
7931
7969
  handler: async ({ ctx }) => {
7932
7970
  const subs = await requireAuth(ctx).apiClient.getSubscriptions();
7933
7971
  outputData(subs, ctx, SUBSCRIPTION_COLUMNS);
7934
- const active = subs.find(
7935
- (s) => ["active", "trialing"].includes(String(s.status ?? s.subscriptionStatus ?? ""))
7972
+ const contract = subs.find(
7973
+ (s) => CONTRACT_BEARING_STATUSES.has(String(s.status ?? s.subscriptionStatus ?? ""))
7936
7974
  );
7937
- if (!active) {
7975
+ if (!contract) {
7938
7976
  hint(ctx, [
7939
7977
  "No active subscription yet. To get started:",
7940
7978
  " gr billing products --type org # pick a plan",
@@ -7942,8 +7980,16 @@ Then check it landed:
7942
7980
  ]);
7943
7981
  return;
7944
7982
  }
7983
+ const contractStatus = String(contract.status ?? contract.subscriptionStatus ?? "");
7984
+ if (!["active", "trialing"].includes(contractStatus)) {
7985
+ hint(ctx, [
7986
+ `Your subscription is ${contractStatus}; it still represents a live billing contract.`,
7987
+ "Resolve its payment or cancellation status in Gravity Rail billing before starting another checkout."
7988
+ ]);
7989
+ return;
7990
+ }
7945
7991
  const orgUuid = String(
7946
- active.organizationUuid ?? active.customerOrganizationUuid ?? "<org-uuid>"
7992
+ contract.organizationUuid ?? contract.customerOrganizationUuid ?? "<org-uuid>"
7947
7993
  );
7948
7994
  hint(ctx, [
7949
7995
  "You have an active subscription. Add a workspace:",
@@ -15835,6 +15881,7 @@ var MAX_HITL_ROUNDS = 25;
15835
15881
  async function runConciergeAguiLoop(client, initialMessages, onEvent, opts) {
15836
15882
  let streamText = "";
15837
15883
  let hasToolCalls = false;
15884
+ let errorMessage;
15838
15885
  let resume;
15839
15886
  for (let round = 0; round < MAX_HITL_ROUNDS; round++) {
15840
15887
  let hitlPayload = null;
@@ -15851,8 +15898,11 @@ async function runConciergeAguiLoop(client, initialMessages, onEvent, opts) {
15851
15898
  const type = event.type?.toLowerCase() ?? "";
15852
15899
  if (type === "tool_call_start") hasToolCalls = true;
15853
15900
  const errorMsg = getErrorMessage(event);
15854
- if (errorMsg) process.stderr.write(`\x1B[31mError: ${errorMsg}\x1B[0m
15901
+ if (errorMsg) {
15902
+ errorMessage = errorMsg;
15903
+ process.stderr.write(`\x1B[31mError: ${errorMsg}\x1B[0m
15855
15904
  `);
15905
+ }
15856
15906
  const hitl = extractHumanInputRequest(event);
15857
15907
  if (hitl) hitlPayload = hitl;
15858
15908
  },
@@ -15881,13 +15931,15 @@ async function runConciergeAguiLoop(client, initialMessages, onEvent, opts) {
15881
15931
  return {
15882
15932
  streamText,
15883
15933
  hasToolCalls,
15884
- unsupportedHitl: normalizeUnsupportedHitl(hitlPayload)
15934
+ unsupportedHitl: normalizeUnsupportedHitl(hitlPayload),
15935
+ errorMessage
15885
15936
  };
15886
15937
  }
15887
15938
  resume = next;
15888
15939
  streamText = "";
15940
+ errorMessage = void 0;
15889
15941
  }
15890
- return { streamText, hasToolCalls };
15942
+ return { streamText, hasToolCalls, errorMessage };
15891
15943
  }
15892
15944
  function normalizeUnsupportedHitl(raw) {
15893
15945
  const payload = raw && typeof raw === "object" ? raw : {};
@@ -17463,6 +17515,7 @@ var AudioPlayer = class extends EventEmitter2 {
17463
17515
 
17464
17516
  // src/lib/chat-session.ts
17465
17517
  var HITL_INTERRUPT_EXIT_CODE = 3;
17518
+ var NO_FINAL_RESPONSE_EXIT_CODE = 4;
17466
17519
  async function runChatSession(session, args) {
17467
17520
  const debug = !!args.debug;
17468
17521
  const isVoice = !!args.voice;
@@ -17519,7 +17572,7 @@ async function singleTurnChatSession(session, message, debug, autoApprove = fals
17519
17572
  `);
17520
17573
  }
17521
17574
  };
17522
- const { streamText, hasToolCalls, unsupportedHitl } = await runConciergeAguiLoop(
17575
+ const { streamText, hasToolCalls, unsupportedHitl, errorMessage } = await runConciergeAguiLoop(
17523
17576
  aguiClient,
17524
17577
  [{ role: "user", content: message }],
17525
17578
  onEvent,
@@ -17573,12 +17626,30 @@ async function singleTurnChatSession(session, message, debug, autoApprove = fals
17573
17626
  } catch {
17574
17627
  }
17575
17628
  }
17576
- process.stdout.write(`\x1B[32mAssistant:\x1B[0m ${finalText || "(no text response)"}
17577
- `);
17578
- } else {
17579
- process.stdout.write(`\x1B[32mAssistant:\x1B[0m (no response)
17629
+ if (finalText) {
17630
+ process.stdout.write(`\x1B[32mAssistant:\x1B[0m ${finalText}
17580
17631
  `);
17632
+ return;
17633
+ }
17634
+ throw noFinalResponseError(
17635
+ errorMessage,
17636
+ /* hadToolCalls */
17637
+ true
17638
+ );
17581
17639
  }
17640
+ if (errorMessage) {
17641
+ throw noFinalResponseError(
17642
+ errorMessage,
17643
+ /* hadToolCalls */
17644
+ false
17645
+ );
17646
+ }
17647
+ process.stdout.write(`\x1B[32mAssistant:\x1B[0m (no response)
17648
+ `);
17649
+ }
17650
+ function noFinalResponseError(errorMessage, hadToolCalls) {
17651
+ const detail = errorMessage ? `inference error: ${errorMessage}` : hadToolCalls ? "the turn ran tool calls but returned no summary (side effects may have been applied)" : "no response from the assistant";
17652
+ return new CLIError(`No assistant reply \u2014 ${detail}`, NO_FINAL_RESPONSE_EXIT_CODE);
17582
17653
  }
17583
17654
  async function interactiveChatSession(session, debug, autoApprove, allowWrite) {
17584
17655
  const aguiClient = new AGUIClient({