@tarout/cli 0.4.0 → 0.6.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/index.js +278 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -61,7 +61,7 @@ import { Command } from "commander";
|
|
|
61
61
|
// package.json
|
|
62
62
|
var package_default = {
|
|
63
63
|
name: "@tarout/cli",
|
|
64
|
-
version: "0.
|
|
64
|
+
version: "0.6.0",
|
|
65
65
|
description: "Tarout CLI \u2014 the Saudi cloud platform for coding agents",
|
|
66
66
|
type: "module",
|
|
67
67
|
bin: {
|
|
@@ -3758,8 +3758,8 @@ async function performBillingChange(client, input2) {
|
|
|
3758
3758
|
addons: input2.addons
|
|
3759
3759
|
});
|
|
3760
3760
|
} else if (kind === "addon") {
|
|
3761
|
-
const
|
|
3762
|
-
result = await client.subscription.purchaseAddons.mutate({
|
|
3761
|
+
const items = input2.addons ?? (input2.addonKey ? [{ addonKey: input2.addonKey, quantity: input2.quantity ?? 1 }] : []);
|
|
3762
|
+
result = await client.subscription.purchaseAddons.mutate({ items });
|
|
3763
3763
|
} else {
|
|
3764
3764
|
result = await client.subscription.setPlanQuantity.mutate({
|
|
3765
3765
|
quantity: input2.quantity
|
|
@@ -3949,6 +3949,46 @@ async function pollCheckoutUntilTerminal(client, orderId, opts) {
|
|
|
3949
3949
|
};
|
|
3950
3950
|
}
|
|
3951
3951
|
|
|
3952
|
+
// src/lib/plan-cart.ts
|
|
3953
|
+
function planFamily(planKey) {
|
|
3954
|
+
if (!planKey) return null;
|
|
3955
|
+
if (planKey === "free") return "FREE";
|
|
3956
|
+
if (planKey === "shared" || planKey.startsWith("shared_") || planKey.startsWith("bundle_")) {
|
|
3957
|
+
return "SHARED";
|
|
3958
|
+
}
|
|
3959
|
+
if (planKey === "dedicated" || planKey.startsWith("dedicated_")) {
|
|
3960
|
+
return "DEDICATED";
|
|
3961
|
+
}
|
|
3962
|
+
return null;
|
|
3963
|
+
}
|
|
3964
|
+
function isPaidFamily(planKey) {
|
|
3965
|
+
const family = planFamily(planKey);
|
|
3966
|
+
return family === "SHARED" || family === "DEDICATED";
|
|
3967
|
+
}
|
|
3968
|
+
function resourceAddonKeysForPlan(planKey) {
|
|
3969
|
+
switch (planFamily(planKey)) {
|
|
3970
|
+
case "SHARED":
|
|
3971
|
+
return { dbAddonKey: "db.starter", storageAddonKey: "storage.gb" };
|
|
3972
|
+
case "DEDICATED":
|
|
3973
|
+
return { dbAddonKey: "db.pro", storageAddonKey: "storage.gb" };
|
|
3974
|
+
default:
|
|
3975
|
+
return { dbAddonKey: null, storageAddonKey: null };
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
3978
|
+
function buildPlanAddonCart(planKey, resources) {
|
|
3979
|
+
const { dbAddonKey, storageAddonKey } = resourceAddonKeysForPlan(planKey);
|
|
3980
|
+
const databases = Math.max(0, Math.floor(resources.databases ?? 0));
|
|
3981
|
+
const storageGb = Math.max(0, Math.floor(resources.storageGb ?? 0));
|
|
3982
|
+
const cart = [];
|
|
3983
|
+
if (dbAddonKey && databases > 0) {
|
|
3984
|
+
cart.push({ addonKey: dbAddonKey, quantity: databases });
|
|
3985
|
+
}
|
|
3986
|
+
if (storageAddonKey && storageGb > 0) {
|
|
3987
|
+
cart.push({ addonKey: storageAddonKey, quantity: storageGb });
|
|
3988
|
+
}
|
|
3989
|
+
return cart;
|
|
3990
|
+
}
|
|
3991
|
+
|
|
3952
3992
|
// src/commands/billing.ts
|
|
3953
3993
|
function reportBillingResult(result, label) {
|
|
3954
3994
|
const code = emitBillingResult(result, { label });
|
|
@@ -4078,7 +4118,8 @@ function registerBillingCommands(program2) {
|
|
|
4078
4118
|
const client = getApiClient();
|
|
4079
4119
|
let targetPlan = planKey || options.plan;
|
|
4080
4120
|
const billingPeriod = options.billingPeriod;
|
|
4081
|
-
|
|
4121
|
+
let planQuantity = options.quantity;
|
|
4122
|
+
let addons = Array.isArray(options.addon) && options.addon.length > 0 ? options.addon : void 0;
|
|
4082
4123
|
if (!targetPlan) {
|
|
4083
4124
|
const _spinner = startSpinner("Fetching plans...");
|
|
4084
4125
|
const catalog = await client.subscription.getCatalog.query();
|
|
@@ -4109,12 +4150,31 @@ function registerBillingCommands(program2) {
|
|
|
4109
4150
|
if (!targetPlan) {
|
|
4110
4151
|
throw new Error("No plan selected");
|
|
4111
4152
|
}
|
|
4153
|
+
if (!isJsonMode() && !isNonInteractiveMode() && !shouldSkipConfirmation() && !addons && isPaidFamily(targetPlan)) {
|
|
4154
|
+
if (planQuantity === void 0 && planFamily(targetPlan) === "SHARED") {
|
|
4155
|
+
const apps = parsePositiveInt(
|
|
4156
|
+
await input("How many apps (app slots)?", "1"),
|
|
4157
|
+
1
|
|
4158
|
+
);
|
|
4159
|
+
planQuantity = Math.max(1, apps);
|
|
4160
|
+
}
|
|
4161
|
+
const databases = parsePositiveInt(
|
|
4162
|
+
await input("How many databases to include?", "1"),
|
|
4163
|
+
0
|
|
4164
|
+
);
|
|
4165
|
+
const storageGb = parsePositiveInt(
|
|
4166
|
+
await input("Object storage to include (GB, 0 for none)?", "5"),
|
|
4167
|
+
0
|
|
4168
|
+
);
|
|
4169
|
+
const cart = buildPlanAddonCart(targetPlan, { databases, storageGb });
|
|
4170
|
+
if (cart.length > 0) addons = cart;
|
|
4171
|
+
}
|
|
4112
4172
|
const _previewSpinner = startSpinner("Calculating change...");
|
|
4113
4173
|
let preview;
|
|
4114
4174
|
try {
|
|
4115
4175
|
preview = await client.subscription.previewPlanChange.query({
|
|
4116
4176
|
planKey: targetPlan,
|
|
4117
|
-
planQuantity
|
|
4177
|
+
planQuantity,
|
|
4118
4178
|
billingPeriod,
|
|
4119
4179
|
addons
|
|
4120
4180
|
});
|
|
@@ -4126,7 +4186,7 @@ function registerBillingCommands(program2) {
|
|
|
4126
4186
|
if (!shouldSkipConfirmation()) {
|
|
4127
4187
|
log("");
|
|
4128
4188
|
log(`Plan: ${colors.cyan(targetPlan)}`);
|
|
4129
|
-
if (
|
|
4189
|
+
if (planQuantity) log(`Quantity: ${planQuantity}`);
|
|
4130
4190
|
if (billingPeriod) log(`Billing period: ${billingPeriod}`);
|
|
4131
4191
|
if (addons && addons.length > 0) {
|
|
4132
4192
|
log(
|
|
@@ -4153,7 +4213,7 @@ function registerBillingCommands(program2) {
|
|
|
4153
4213
|
flag: "--yes",
|
|
4154
4214
|
context: {
|
|
4155
4215
|
plan: targetPlan,
|
|
4156
|
-
quantity:
|
|
4216
|
+
quantity: planQuantity,
|
|
4157
4217
|
billingPeriod,
|
|
4158
4218
|
addons,
|
|
4159
4219
|
amountDueHalalas
|
|
@@ -4169,7 +4229,7 @@ function registerBillingCommands(program2) {
|
|
|
4169
4229
|
const result = await performBillingChange(client, {
|
|
4170
4230
|
kind: "plan",
|
|
4171
4231
|
planKey: targetPlan,
|
|
4172
|
-
quantity:
|
|
4232
|
+
quantity: planQuantity,
|
|
4173
4233
|
billingPeriod,
|
|
4174
4234
|
addons,
|
|
4175
4235
|
wait: options.wait,
|
|
@@ -4461,7 +4521,7 @@ function registerBillingCommands(program2) {
|
|
|
4461
4521
|
const client = getApiClient();
|
|
4462
4522
|
const _spinner = startSpinner("Calculating preview...");
|
|
4463
4523
|
const preview = await client.subscription.previewAddonsPurchase.query({
|
|
4464
|
-
|
|
4524
|
+
items: [{ addonKey, quantity: options.quantity || 1 }]
|
|
4465
4525
|
});
|
|
4466
4526
|
succeedSpinner();
|
|
4467
4527
|
if (isJsonMode()) {
|
|
@@ -4771,6 +4831,10 @@ function collectAddon(value, previous) {
|
|
|
4771
4831
|
}
|
|
4772
4832
|
return [...previous, { addonKey, quantity }];
|
|
4773
4833
|
}
|
|
4834
|
+
function parsePositiveInt(raw, fallback) {
|
|
4835
|
+
const n = Number.parseInt(String(raw).trim(), 10);
|
|
4836
|
+
return Number.isFinite(n) && n >= 0 ? n : fallback;
|
|
4837
|
+
}
|
|
4774
4838
|
function parseBillingPeriod(raw) {
|
|
4775
4839
|
const v = raw.toLowerCase();
|
|
4776
4840
|
if (v === "monthly" || v === "yearly") return v;
|
|
@@ -6465,6 +6529,20 @@ function resolveEntitlementRemedy(failedKey, catalog, opts) {
|
|
|
6465
6529
|
hint: `A dedicated host slot is required \u2014 upgrade to ${plan2?.name ?? target2}.`
|
|
6466
6530
|
};
|
|
6467
6531
|
}
|
|
6532
|
+
if (failedKey === "db.free.slots" || failedKey === "storage.free.slots") {
|
|
6533
|
+
const target2 = nextPlanForRequested(opts?.requestedPlan);
|
|
6534
|
+
const plan2 = plans.find((p) => planKeyOf(p) === target2);
|
|
6535
|
+
const resource = failedKey === "db.free.slots" ? "database" : "storage bucket";
|
|
6536
|
+
return {
|
|
6537
|
+
kind: "plan",
|
|
6538
|
+
failedKey,
|
|
6539
|
+
targetKey: target2,
|
|
6540
|
+
targetName: plan2?.name,
|
|
6541
|
+
priceHalalas: plan2?.priceHalalas,
|
|
6542
|
+
command: `tarout billing upgrade ${target2} --wait`,
|
|
6543
|
+
hint: `The free plan includes a single ${resource} for the whole org \u2014 delete the existing free ${resource}, or upgrade to ${plan2?.name ?? target2} to add more.`
|
|
6544
|
+
};
|
|
6545
|
+
}
|
|
6468
6546
|
if (failedKey?.startsWith("db.") || failedKey?.startsWith("storage.") || failedKey?.startsWith("domain") || failedKey?.startsWith("email")) {
|
|
6469
6547
|
const matched = addons.find(
|
|
6470
6548
|
(a) => a.grants?.some((g) => g.entitlementKey === failedKey)
|
|
@@ -7305,6 +7383,97 @@ async function runInlineUpgrade(client, planKey) {
|
|
|
7305
7383
|
}
|
|
7306
7384
|
return false;
|
|
7307
7385
|
}
|
|
7386
|
+
async function getCurrentPlanQuantitySafely(client) {
|
|
7387
|
+
try {
|
|
7388
|
+
const sub = await client.subscription.getCurrent.query();
|
|
7389
|
+
const q = Number(sub?.planQuantity);
|
|
7390
|
+
return Number.isFinite(q) && q > 0 ? q : 1;
|
|
7391
|
+
} catch {
|
|
7392
|
+
return 1;
|
|
7393
|
+
}
|
|
7394
|
+
}
|
|
7395
|
+
async function runInlineTargetedRemedy(client, remedy) {
|
|
7396
|
+
let input2;
|
|
7397
|
+
let label;
|
|
7398
|
+
if (remedy.kind === "addon") {
|
|
7399
|
+
input2 = { kind: "addon", addonKey: remedy.targetKey, quantity: 1 };
|
|
7400
|
+
label = remedy.targetName ?? remedy.targetKey;
|
|
7401
|
+
} else {
|
|
7402
|
+
const next = await getCurrentPlanQuantitySafely(client) + 1;
|
|
7403
|
+
input2 = { kind: "plan_quantity", planKey: remedy.targetKey, quantity: next };
|
|
7404
|
+
label = `${remedy.targetName ?? remedy.targetKey} \xD7${next}`;
|
|
7405
|
+
}
|
|
7406
|
+
const _spinner = startSpinner(`Adding ${label}...`);
|
|
7407
|
+
const result = await performBillingChange(client, {
|
|
7408
|
+
...input2,
|
|
7409
|
+
wait: true,
|
|
7410
|
+
timeoutMs: 6e5,
|
|
7411
|
+
openBrowser: isJsonMode() ? void 0 : async (url) => {
|
|
7412
|
+
await open4(url);
|
|
7413
|
+
},
|
|
7414
|
+
onCheckoutOpened: ({ orderId, paymentUrl }) => {
|
|
7415
|
+
log("");
|
|
7416
|
+
log("Open this URL to complete payment:");
|
|
7417
|
+
log(` ${colors.cyan(paymentUrl)}`);
|
|
7418
|
+
log(`Order ID: ${colors.dim(orderId)}`);
|
|
7419
|
+
}
|
|
7420
|
+
});
|
|
7421
|
+
if (result.status === "applied" || result.status === "paid") {
|
|
7422
|
+
succeedSpinner(`${label} added.`);
|
|
7423
|
+
return true;
|
|
7424
|
+
}
|
|
7425
|
+
failSpinner(
|
|
7426
|
+
result.status === "deferred" ? "Change did not require an immediate payment." : result.status === "pending_timeout" ? "Payment still pending after 10 minutes." : `Payment ${result.status}.`
|
|
7427
|
+
);
|
|
7428
|
+
if (result.failureReason) log(colors.error(result.failureReason));
|
|
7429
|
+
if (result.orderId) {
|
|
7430
|
+
log(
|
|
7431
|
+
colors.dim(
|
|
7432
|
+
`Resume later with: tarout billing wait ${result.orderId.slice(0, 8)} --timeout 600`
|
|
7433
|
+
)
|
|
7434
|
+
);
|
|
7435
|
+
}
|
|
7436
|
+
return false;
|
|
7437
|
+
}
|
|
7438
|
+
async function promptEntitlementRemedy(client, err, requestedPlan) {
|
|
7439
|
+
const failedKey = extractEntitlementKeyFromError(err);
|
|
7440
|
+
const catalog = await fetchCatalogSafely(client);
|
|
7441
|
+
const remedy = resolveEntitlementRemedy(failedKey, catalog, { requestedPlan });
|
|
7442
|
+
if (remedy.kind === "plan") {
|
|
7443
|
+
return promptUpgradeFromEntitlementError(client, err, requestedPlan);
|
|
7444
|
+
}
|
|
7445
|
+
const price = remedy.priceHalalas !== void 0 ? ` (${formatPlanPrice(remedy.priceHalalas)})` : "";
|
|
7446
|
+
const targetedLabel = remedy.kind === "plan_quantity" ? `Add one more app slot${price}` : `Add just the ${remedy.targetName ?? remedy.targetKey}${price}`;
|
|
7447
|
+
log("");
|
|
7448
|
+
log(colors.warn("That resource isn't included in your current plan."));
|
|
7449
|
+
log("");
|
|
7450
|
+
const UPGRADE = "__upgrade__";
|
|
7451
|
+
const TARGETED = "__targeted__";
|
|
7452
|
+
const CANCEL = "__cancel__";
|
|
7453
|
+
const choice = await select(
|
|
7454
|
+
"How would you like to add it?",
|
|
7455
|
+
[
|
|
7456
|
+
{ name: "Upgrade the plan", value: UPGRADE },
|
|
7457
|
+
{ name: targetedLabel, value: TARGETED },
|
|
7458
|
+
{ name: "Cancel", value: CANCEL }
|
|
7459
|
+
],
|
|
7460
|
+
{
|
|
7461
|
+
field: "entitlement_remedy",
|
|
7462
|
+
flag: "--plan <key> (upgrade) | tarout billing addon:buy <key> (addon)",
|
|
7463
|
+
context: {
|
|
7464
|
+
failedEntitlementKey: failedKey,
|
|
7465
|
+
remedyKind: remedy.kind,
|
|
7466
|
+
targetKey: remedy.targetKey,
|
|
7467
|
+
command: remedy.command
|
|
7468
|
+
}
|
|
7469
|
+
}
|
|
7470
|
+
);
|
|
7471
|
+
if (choice === CANCEL) return false;
|
|
7472
|
+
if (choice === UPGRADE) {
|
|
7473
|
+
return promptUpgradeFromEntitlementError(client, err, requestedPlan);
|
|
7474
|
+
}
|
|
7475
|
+
return runInlineTargetedRemedy(client, remedy);
|
|
7476
|
+
}
|
|
7308
7477
|
async function getAppPlanChoices(client, preloadedOptions) {
|
|
7309
7478
|
try {
|
|
7310
7479
|
const options = preloadedOptions ?? await client.application.getCreateOptions.query();
|
|
@@ -7411,6 +7580,63 @@ async function emitNeedsUpgrade(client, err, requestedPlan, retryCommand) {
|
|
|
7411
7580
|
hint: `${remedy.hint} Then retry: ${retryCommand}.`
|
|
7412
7581
|
});
|
|
7413
7582
|
}
|
|
7583
|
+
async function listFreeDatabasesSafely(client) {
|
|
7584
|
+
try {
|
|
7585
|
+
const [pgRows, myRows] = await Promise.all([
|
|
7586
|
+
client.postgres.allByOrganization.query().catch(() => []),
|
|
7587
|
+
client.mysql.allByOrganization.query().catch(() => [])
|
|
7588
|
+
]);
|
|
7589
|
+
const out = [];
|
|
7590
|
+
for (const r of pgRows ?? []) {
|
|
7591
|
+
if ((r?.plan ?? "FREE") === "FREE" && r?.postgresId) {
|
|
7592
|
+
out.push({ kind: "postgres", id: r.postgresId, name: r.name });
|
|
7593
|
+
}
|
|
7594
|
+
}
|
|
7595
|
+
for (const r of myRows ?? []) {
|
|
7596
|
+
if ((r?.plan ?? "FREE") === "FREE" && r?.mysqlId) {
|
|
7597
|
+
out.push({ kind: "mysql", id: r.mysqlId, name: r.name });
|
|
7598
|
+
}
|
|
7599
|
+
}
|
|
7600
|
+
return out;
|
|
7601
|
+
} catch {
|
|
7602
|
+
return [];
|
|
7603
|
+
}
|
|
7604
|
+
}
|
|
7605
|
+
async function explainFreeResourceSlotExhaustion(client, failedKey) {
|
|
7606
|
+
const isDb = failedKey === "db.free.slots";
|
|
7607
|
+
const resource = isDb ? "database" : "storage bucket";
|
|
7608
|
+
log("");
|
|
7609
|
+
log(
|
|
7610
|
+
colors.warn(
|
|
7611
|
+
`The free plan includes one ${resource} for the whole organization (across all environments).`
|
|
7612
|
+
)
|
|
7613
|
+
);
|
|
7614
|
+
if (isDb) {
|
|
7615
|
+
const existing = await listFreeDatabasesSafely(client);
|
|
7616
|
+
if (existing.length > 0) {
|
|
7617
|
+
log("You already have:");
|
|
7618
|
+
for (const d of existing) {
|
|
7619
|
+
log(
|
|
7620
|
+
` \u2022 ${d.name} ${colors.dim(`(${d.kind} \xB7 ${d.id.slice(0, 8)})`)}`
|
|
7621
|
+
);
|
|
7622
|
+
}
|
|
7623
|
+
} else {
|
|
7624
|
+
log(
|
|
7625
|
+
colors.dim(
|
|
7626
|
+
"Your existing free database may be in another environment \u2014 run `tarout db list`."
|
|
7627
|
+
)
|
|
7628
|
+
);
|
|
7629
|
+
}
|
|
7630
|
+
}
|
|
7631
|
+
log("");
|
|
7632
|
+
log("To continue, pick one:");
|
|
7633
|
+
if (isDb) {
|
|
7634
|
+
log(` \u2022 Reuse it: ${colors.cyan("tarout deploy --reuse-database auto")}`);
|
|
7635
|
+
log(` \u2022 Delete it: ${colors.cyan("tarout db delete <id>")}`);
|
|
7636
|
+
}
|
|
7637
|
+
log(` \u2022 Upgrade: ${colors.cyan("tarout billing upgrade shared --wait")}`);
|
|
7638
|
+
log("");
|
|
7639
|
+
}
|
|
7414
7640
|
async function promptUpgradeFromEntitlementError(client, err, requestedPlan) {
|
|
7415
7641
|
const catalog = await fetchCatalogSafely(client);
|
|
7416
7642
|
const allPlans = catalog?.plans ?? [];
|
|
@@ -8529,7 +8755,11 @@ function registerDeployCommands(program2) {
|
|
|
8529
8755
|
}
|
|
8530
8756
|
log("");
|
|
8531
8757
|
log(colors.warn(message));
|
|
8532
|
-
const
|
|
8758
|
+
const failedKey = extractEntitlementKeyFromError(err);
|
|
8759
|
+
if (failedKey === "db.free.slots" || failedKey === "storage.free.slots") {
|
|
8760
|
+
await explainFreeResourceSlotExhaustion(getApiClient(), failedKey);
|
|
8761
|
+
}
|
|
8762
|
+
const upgraded = await promptEntitlementRemedy(
|
|
8533
8763
|
getApiClient(),
|
|
8534
8764
|
err,
|
|
8535
8765
|
options.plan
|
|
@@ -8543,7 +8773,7 @@ function registerDeployCommands(program2) {
|
|
|
8543
8773
|
);
|
|
8544
8774
|
exit(ExitCode.PERMISSION_DENIED);
|
|
8545
8775
|
}
|
|
8546
|
-
box("
|
|
8776
|
+
box("Billing updated", [
|
|
8547
8777
|
colors.success("Subscription updated."),
|
|
8548
8778
|
`Run ${colors.cyan("tarout deploy")} again to deploy on the new plan.`
|
|
8549
8779
|
]);
|
|
@@ -19146,7 +19376,7 @@ function registerUpCommand(program2) {
|
|
|
19146
19376
|
}
|
|
19147
19377
|
log("");
|
|
19148
19378
|
log(colors.warn(message));
|
|
19149
|
-
const upgraded = await
|
|
19379
|
+
const upgraded = await promptEntitlementRemedy(
|
|
19150
19380
|
client,
|
|
19151
19381
|
err,
|
|
19152
19382
|
options.plan
|
|
@@ -19155,7 +19385,7 @@ function registerUpCommand(program2) {
|
|
|
19155
19385
|
await emitNeedsUpgrade(client, err, options.plan, "tarout up");
|
|
19156
19386
|
exit(ExitCode.PERMISSION_DENIED);
|
|
19157
19387
|
}
|
|
19158
|
-
box("
|
|
19388
|
+
box("Billing updated", [
|
|
19159
19389
|
colors.success("Subscription updated."),
|
|
19160
19390
|
`Run ${colors.cyan("tarout up")} again to deploy on the new plan.`
|
|
19161
19391
|
]);
|
|
@@ -19252,6 +19482,39 @@ function registerUpCommand(program2) {
|
|
|
19252
19482
|
app.applicationId
|
|
19253
19483
|
);
|
|
19254
19484
|
} catch (err) {
|
|
19485
|
+
if (isEntitlementError(err)) {
|
|
19486
|
+
const message = err instanceof Error ? err.message : "Plan upgrade required";
|
|
19487
|
+
if (isJsonMode() || shouldSkipConfirmation()) {
|
|
19488
|
+
await emitNeedsUpgrade(
|
|
19489
|
+
getApiClient(),
|
|
19490
|
+
err,
|
|
19491
|
+
options.plan,
|
|
19492
|
+
"tarout up"
|
|
19493
|
+
);
|
|
19494
|
+
exit(ExitCode.PERMISSION_DENIED);
|
|
19495
|
+
}
|
|
19496
|
+
log("");
|
|
19497
|
+
log(colors.warn(message));
|
|
19498
|
+
const upgraded = await promptEntitlementRemedy(
|
|
19499
|
+
getApiClient(),
|
|
19500
|
+
err,
|
|
19501
|
+
options.plan
|
|
19502
|
+
);
|
|
19503
|
+
if (!upgraded) {
|
|
19504
|
+
await emitNeedsUpgrade(
|
|
19505
|
+
getApiClient(),
|
|
19506
|
+
err,
|
|
19507
|
+
options.plan,
|
|
19508
|
+
"tarout up"
|
|
19509
|
+
);
|
|
19510
|
+
exit(ExitCode.PERMISSION_DENIED);
|
|
19511
|
+
}
|
|
19512
|
+
box("Billing updated", [
|
|
19513
|
+
colors.success("Subscription updated."),
|
|
19514
|
+
`Run ${colors.cyan("tarout up")} again to deploy on the new plan.`
|
|
19515
|
+
]);
|
|
19516
|
+
return;
|
|
19517
|
+
}
|
|
19255
19518
|
if (err instanceof Error && err.message.startsWith("Invalid --source")) {
|
|
19256
19519
|
outputError("INVALID_ARGUMENTS", err.message);
|
|
19257
19520
|
if (!isJsonMode()) log(colors.error(err.message));
|
|
@@ -19480,10 +19743,11 @@ program.name("tarout").description("Tarout PaaS Command Line Interface").version
|
|
|
19480
19743
|
"Fail fast on missing input (emit needs_input + exit 6 instead of prompting on TTY)"
|
|
19481
19744
|
).option("-q, --quiet", "Minimal output").option("-v, --verbose", "Extra debug information").option("--no-color", "Disable colored output").hook("preAction", (thisCommand) => {
|
|
19482
19745
|
const opts = thisCommand.opts();
|
|
19746
|
+
const stdinIsTTY = Boolean(process.stdin.isTTY);
|
|
19483
19747
|
setGlobalOptions({
|
|
19484
19748
|
json: opts.json || false,
|
|
19485
19749
|
yes: opts.yes || false,
|
|
19486
|
-
nonInteractive: opts.nonInteractive ||
|
|
19750
|
+
nonInteractive: opts.nonInteractive || !stdinIsTTY,
|
|
19487
19751
|
quiet: opts.quiet || false,
|
|
19488
19752
|
verbose: opts.verbose || false,
|
|
19489
19753
|
noColor: opts.color === false
|