atmn 0.0.13 → 0.0.16
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/chunk-ZBY46DYM.js +50 -0
- package/dist/cli.cjs +172 -89
- package/dist/cli.js +170 -87
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// source/compose/builders/builderFunctions.ts
|
|
2
|
+
var product = (p) => p;
|
|
3
|
+
var feature = (f) => f;
|
|
4
|
+
var featureItem = ({
|
|
5
|
+
feature_id,
|
|
6
|
+
included_usage,
|
|
7
|
+
interval,
|
|
8
|
+
reset_usage_when_enabled,
|
|
9
|
+
entity_feature_id
|
|
10
|
+
}) => {
|
|
11
|
+
return {
|
|
12
|
+
included_usage,
|
|
13
|
+
feature_id,
|
|
14
|
+
interval,
|
|
15
|
+
reset_usage_when_enabled,
|
|
16
|
+
entity_feature_id
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
var pricedFeatureItem = ({
|
|
20
|
+
feature_id,
|
|
21
|
+
price,
|
|
22
|
+
interval,
|
|
23
|
+
included_usage = void 0,
|
|
24
|
+
billing_units = 1,
|
|
25
|
+
usage_model = "pay_per_use",
|
|
26
|
+
reset_usage_when_enabled,
|
|
27
|
+
entity_feature_id
|
|
28
|
+
}) => {
|
|
29
|
+
return {
|
|
30
|
+
price,
|
|
31
|
+
interval,
|
|
32
|
+
billing_units,
|
|
33
|
+
feature_id,
|
|
34
|
+
usage_model,
|
|
35
|
+
included_usage,
|
|
36
|
+
reset_usage_when_enabled,
|
|
37
|
+
entity_feature_id
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
var priceItem = ({
|
|
41
|
+
price,
|
|
42
|
+
interval
|
|
43
|
+
}) => {
|
|
44
|
+
return {
|
|
45
|
+
price,
|
|
46
|
+
interval
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export { feature, featureItem, priceItem, pricedFeatureItem, product };
|
package/dist/cli.cjs
CHANGED
|
@@ -2,29 +2,29 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var commander = require('commander');
|
|
5
|
-
var
|
|
5
|
+
var chalk7 = require('chalk');
|
|
6
6
|
var axios = require('axios');
|
|
7
7
|
var fs = require('fs');
|
|
8
8
|
var prompts = require('@inquirer/prompts');
|
|
9
9
|
var dotenv = require('dotenv');
|
|
10
|
+
var yoctoSpinner = require('yocto-spinner');
|
|
10
11
|
var path = require('path');
|
|
11
12
|
var createJiti = require('jiti');
|
|
12
13
|
var url = require('url');
|
|
13
14
|
var child_process = require('child_process');
|
|
14
15
|
var zod = require('zod');
|
|
15
16
|
var open = require('open');
|
|
16
|
-
var yoctoSpinner = require('yocto-spinner');
|
|
17
17
|
|
|
18
18
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
19
19
|
|
|
20
|
-
var
|
|
20
|
+
var chalk7__default = /*#__PURE__*/_interopDefault(chalk7);
|
|
21
21
|
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
22
22
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
23
23
|
var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
|
|
24
|
+
var yoctoSpinner__default = /*#__PURE__*/_interopDefault(yoctoSpinner);
|
|
24
25
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
25
26
|
var createJiti__default = /*#__PURE__*/_interopDefault(createJiti);
|
|
26
27
|
var open__default = /*#__PURE__*/_interopDefault(open);
|
|
27
|
-
var yoctoSpinner__default = /*#__PURE__*/_interopDefault(yoctoSpinner);
|
|
28
28
|
|
|
29
29
|
// ../node_modules/.pnpm/tsup@8.5.0_@swc+core@1.13.2_jiti@2.4.2_postcss@8.5.6_tsx@4.20.3_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/assets/cjs_shims.js
|
|
30
30
|
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
|
|
@@ -115,18 +115,18 @@ AUTUMN_SECRET_KEY=${sandboxKey}
|
|
|
115
115
|
if (fs__default.default.existsSync(envPath)) {
|
|
116
116
|
upsertEnvVar(envPath, "AUTUMN_PROD_SECRET_KEY", prodKey);
|
|
117
117
|
upsertEnvVar(envPath, "AUTUMN_SECRET_KEY", sandboxKey);
|
|
118
|
-
console.log(
|
|
118
|
+
console.log(chalk7__default.default.green(".env file found. Updated keys."));
|
|
119
119
|
} else if (fs__default.default.existsSync(envLocalPath)) {
|
|
120
120
|
fs__default.default.writeFileSync(envPath, envVars);
|
|
121
121
|
console.log(
|
|
122
|
-
|
|
122
|
+
chalk7__default.default.green(
|
|
123
123
|
".env.local found but .env not found. Created new .env file and wrote keys."
|
|
124
124
|
)
|
|
125
125
|
);
|
|
126
126
|
} else {
|
|
127
127
|
fs__default.default.writeFileSync(envPath, envVars);
|
|
128
128
|
console.log(
|
|
129
|
-
|
|
129
|
+
chalk7__default.default.green(
|
|
130
130
|
"No .env or .env.local file found. Created new .env file and wrote keys."
|
|
131
131
|
)
|
|
132
132
|
);
|
|
@@ -151,6 +151,13 @@ function readFromEnv() {
|
|
|
151
151
|
}
|
|
152
152
|
return void 0;
|
|
153
153
|
}
|
|
154
|
+
function initSpinner(message) {
|
|
155
|
+
const spinner2 = yoctoSpinner__default.default({
|
|
156
|
+
text: message
|
|
157
|
+
});
|
|
158
|
+
spinner2.start();
|
|
159
|
+
return spinner2;
|
|
160
|
+
}
|
|
154
161
|
|
|
155
162
|
// source/core/api.ts
|
|
156
163
|
var INTERNAL_BASE = BACKEND_URL;
|
|
@@ -182,8 +189,8 @@ async function request({
|
|
|
182
189
|
throw error;
|
|
183
190
|
}
|
|
184
191
|
console.error(
|
|
185
|
-
|
|
186
|
-
|
|
192
|
+
chalk7__default.default.red("\nError occured when making API request:"),
|
|
193
|
+
chalk7__default.default.red(error.response.data.message || error.response.data.error)
|
|
187
194
|
);
|
|
188
195
|
process.exit(1);
|
|
189
196
|
}
|
|
@@ -317,7 +324,7 @@ var getResetUsageStr = ({
|
|
|
317
324
|
return "";
|
|
318
325
|
};
|
|
319
326
|
var getIntervalStr = ({ item }) => {
|
|
320
|
-
if (item.interval == null) return
|
|
327
|
+
if (item.interval == null) return ``;
|
|
321
328
|
return `${getItemFieldPrefix()}interval: '${item.interval}',`;
|
|
322
329
|
};
|
|
323
330
|
var getEntityFeatureIdStr = ({ item }) => {
|
|
@@ -453,7 +460,7 @@ async function installAtmn() {
|
|
|
453
460
|
});
|
|
454
461
|
if (!shouldInstall) {
|
|
455
462
|
console.log(
|
|
456
|
-
|
|
463
|
+
chalk7__default.default.yellow(
|
|
457
464
|
"Skipping installation. You can install atmn manually with your preferred package manager."
|
|
458
465
|
)
|
|
459
466
|
);
|
|
@@ -469,13 +476,13 @@ async function installAtmn() {
|
|
|
469
476
|
default: "npm"
|
|
470
477
|
});
|
|
471
478
|
try {
|
|
472
|
-
console.log(
|
|
479
|
+
console.log(chalk7__default.default.blue(`Installing atmn with ${packageManager}...`));
|
|
473
480
|
const installCommand = packageManager === "npm" ? "npm install atmn" : packageManager === "pnpm" ? "pnpm add atmn" : "bun add atmn";
|
|
474
481
|
child_process.execSync(installCommand, { stdio: "inherit" });
|
|
475
|
-
console.log(
|
|
482
|
+
console.log(chalk7__default.default.green("atmn installed successfully!"));
|
|
476
483
|
return true;
|
|
477
484
|
} catch (error) {
|
|
478
|
-
console.error(
|
|
485
|
+
console.error(chalk7__default.default.red("Failed to install atmn:"), error);
|
|
479
486
|
return false;
|
|
480
487
|
}
|
|
481
488
|
}
|
|
@@ -529,9 +536,16 @@ async function loadAutumnConfigFile() {
|
|
|
529
536
|
}
|
|
530
537
|
}
|
|
531
538
|
}
|
|
539
|
+
const secretKey = readFromEnv();
|
|
540
|
+
if (secretKey?.includes("live")) {
|
|
541
|
+
console.log(chalk7__default.default.magentaBright("Running in production environment..."));
|
|
542
|
+
} else {
|
|
543
|
+
console.log(chalk7__default.default.yellow("Running in sandbox environment..."));
|
|
544
|
+
}
|
|
532
545
|
return {
|
|
533
546
|
products,
|
|
534
|
-
features
|
|
547
|
+
features,
|
|
548
|
+
env: secretKey?.includes("live") ? "prod" : "sandbox"
|
|
535
549
|
};
|
|
536
550
|
}
|
|
537
551
|
function writeConfig(config) {
|
|
@@ -541,7 +555,7 @@ function writeConfig(config) {
|
|
|
541
555
|
|
|
542
556
|
// source/commands/pull.ts
|
|
543
557
|
async function Pull({ config }) {
|
|
544
|
-
console.log(
|
|
558
|
+
console.log(chalk7__default.default.green("Pulling products and features from Autumn..."));
|
|
545
559
|
const products = await getAllProducts();
|
|
546
560
|
const features = await getFeatures();
|
|
547
561
|
const productSnippets = products.map(
|
|
@@ -558,7 +572,7 @@ ${importBuilder()}
|
|
|
558
572
|
// Products${productSnippets.join("\n")}
|
|
559
573
|
`;
|
|
560
574
|
writeConfig(autumnConfig);
|
|
561
|
-
console.log(
|
|
575
|
+
console.log(chalk7__default.default.green("Success! Config has been updated."));
|
|
562
576
|
}
|
|
563
577
|
|
|
564
578
|
// source/core/auth.ts
|
|
@@ -574,14 +588,14 @@ async function getOTP(otp) {
|
|
|
574
588
|
var passwordTheme = {
|
|
575
589
|
style: {
|
|
576
590
|
answer: (text) => {
|
|
577
|
-
return
|
|
591
|
+
return chalk7__default.default.magenta("*".repeat(text.length));
|
|
578
592
|
}
|
|
579
593
|
}
|
|
580
594
|
};
|
|
581
595
|
var inputTheme = {
|
|
582
596
|
style: {
|
|
583
597
|
answer: (text) => {
|
|
584
|
-
return
|
|
598
|
+
return chalk7__default.default.magenta(text);
|
|
585
599
|
}
|
|
586
600
|
}
|
|
587
601
|
};
|
|
@@ -619,7 +633,7 @@ async function AuthCommand() {
|
|
|
619
633
|
);
|
|
620
634
|
} else {
|
|
621
635
|
console.log(
|
|
622
|
-
|
|
636
|
+
chalk7__default.default.yellow(
|
|
623
637
|
"Okay, no worries. Go to the Autumn dashboard when you're ready!"
|
|
624
638
|
)
|
|
625
639
|
);
|
|
@@ -627,7 +641,7 @@ async function AuthCommand() {
|
|
|
627
641
|
}
|
|
628
642
|
storeToEnv(keyInfo.prodKey, keyInfo.sandboxKey);
|
|
629
643
|
console.log(
|
|
630
|
-
|
|
644
|
+
chalk7__default.default.green(
|
|
631
645
|
"Success! Keys have been stored locally. You may now use the CLI."
|
|
632
646
|
)
|
|
633
647
|
);
|
|
@@ -637,31 +651,33 @@ async function AuthCommand() {
|
|
|
637
651
|
async function Init({ config }) {
|
|
638
652
|
let apiKey = readFromEnv();
|
|
639
653
|
if (apiKey) {
|
|
640
|
-
console.log(
|
|
654
|
+
console.log(chalk7__default.default.green("API key found. Pulling latest config..."));
|
|
641
655
|
await Pull({ config });
|
|
642
656
|
console.log(
|
|
643
|
-
|
|
657
|
+
chalk7__default.default.green("Project initialized and config pulled successfully!")
|
|
644
658
|
);
|
|
645
659
|
return;
|
|
646
660
|
}
|
|
647
|
-
console.log(
|
|
661
|
+
console.log(chalk7__default.default.yellow("No API key found. Running authentication..."));
|
|
648
662
|
await AuthCommand();
|
|
649
663
|
apiKey = readFromEnv();
|
|
650
664
|
if (apiKey) {
|
|
651
665
|
await Pull({ config });
|
|
652
666
|
console.log(
|
|
653
|
-
|
|
667
|
+
chalk7__default.default.green(
|
|
654
668
|
"Project initialized! You are now authenticated and config has been pulled."
|
|
655
669
|
)
|
|
656
670
|
);
|
|
657
671
|
} else {
|
|
658
672
|
console.log(
|
|
659
|
-
|
|
673
|
+
chalk7__default.default.red(
|
|
660
674
|
"Authentication did not yield an API key. Please check your setup."
|
|
661
675
|
)
|
|
662
676
|
);
|
|
663
677
|
}
|
|
664
678
|
}
|
|
679
|
+
|
|
680
|
+
// source/core/push.ts
|
|
665
681
|
async function checkForDeletables(currentFeatures, currentProducts) {
|
|
666
682
|
const features = await getFeatures();
|
|
667
683
|
const featureIds = features.map((feature) => feature.id);
|
|
@@ -677,12 +693,17 @@ async function checkForDeletables(currentFeatures, currentProducts) {
|
|
|
677
693
|
const productsToDelete = productIds.filter(
|
|
678
694
|
(productId) => !currentProductIds.includes(productId)
|
|
679
695
|
);
|
|
680
|
-
return {
|
|
696
|
+
return {
|
|
697
|
+
curFeatures: features,
|
|
698
|
+
curProducts: products,
|
|
699
|
+
featuresToDelete,
|
|
700
|
+
productsToDelete
|
|
701
|
+
};
|
|
681
702
|
}
|
|
682
703
|
var isDuplicate = (error) => {
|
|
683
704
|
return error.response && error.response.data && (error.response.data.code === "duplicate_feature_id" || error.response.data.code === "product_already_exists");
|
|
684
705
|
};
|
|
685
|
-
async function upsertFeature(feature) {
|
|
706
|
+
async function upsertFeature(feature, s) {
|
|
686
707
|
try {
|
|
687
708
|
const response = await externalRequest({
|
|
688
709
|
method: "POST",
|
|
@@ -705,56 +726,67 @@ async function upsertFeature(feature) {
|
|
|
705
726
|
Failed to push feature ${feature.id}: ${error.response?.data?.message || "Unknown error"}`
|
|
706
727
|
);
|
|
707
728
|
process.exit(1);
|
|
729
|
+
} finally {
|
|
730
|
+
s.text = `Pushed feature [${feature.id}]`;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
async function checkProductForConfirmation({
|
|
734
|
+
curProducts,
|
|
735
|
+
product
|
|
736
|
+
}) {
|
|
737
|
+
let curProduct = curProducts.find((p) => p.id === product.id);
|
|
738
|
+
if (!curProduct) {
|
|
739
|
+
return {
|
|
740
|
+
id: product.id,
|
|
741
|
+
will_version: false
|
|
742
|
+
};
|
|
708
743
|
}
|
|
744
|
+
const res1 = await externalRequest({
|
|
745
|
+
method: "GET",
|
|
746
|
+
path: `/products/${product.id}/has_customers`,
|
|
747
|
+
data: product
|
|
748
|
+
});
|
|
749
|
+
return {
|
|
750
|
+
id: product.id,
|
|
751
|
+
will_version: res1.will_version
|
|
752
|
+
};
|
|
709
753
|
}
|
|
710
754
|
async function upsertProduct({
|
|
755
|
+
curProducts,
|
|
711
756
|
product,
|
|
712
|
-
spinner: spinner2
|
|
757
|
+
spinner: spinner2,
|
|
758
|
+
shouldUpdate = true
|
|
713
759
|
}) {
|
|
714
|
-
|
|
715
|
-
|
|
760
|
+
if (!shouldUpdate) {
|
|
761
|
+
spinner2.text = `Skipping update to product ${product.id}`;
|
|
762
|
+
return {
|
|
763
|
+
id: product.id,
|
|
764
|
+
action: "skipped"
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
let curProduct = curProducts.find((p) => p.id === product.id);
|
|
768
|
+
if (!curProduct) {
|
|
769
|
+
await externalRequest({
|
|
716
770
|
method: "POST",
|
|
717
771
|
path: `/products`,
|
|
718
|
-
data: product
|
|
719
|
-
throwOnError: true
|
|
772
|
+
data: product
|
|
720
773
|
});
|
|
721
|
-
spinner2.
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
});
|
|
738
|
-
}
|
|
739
|
-
if (shouldUpdate) {
|
|
740
|
-
spinner2.start();
|
|
741
|
-
const response = await externalRequest({
|
|
742
|
-
method: "POST",
|
|
743
|
-
path: `/products/${product.id}`,
|
|
744
|
-
data: product
|
|
745
|
-
});
|
|
746
|
-
spinner2.success(`Pushed product [${product.id}]`);
|
|
747
|
-
return response;
|
|
748
|
-
} else {
|
|
749
|
-
spinner2.info(`Skipping update to product ${product.id}`);
|
|
750
|
-
return;
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
console.error(
|
|
754
|
-
`
|
|
755
|
-
Failed to push product ${product.id}: ${error.response?.data?.message || "Unknown error"}`
|
|
756
|
-
);
|
|
757
|
-
process.exit(1);
|
|
774
|
+
spinner2.text = `Created product [${product.id}]`;
|
|
775
|
+
return {
|
|
776
|
+
id: product.id,
|
|
777
|
+
action: "create"
|
|
778
|
+
};
|
|
779
|
+
} else {
|
|
780
|
+
await externalRequest({
|
|
781
|
+
method: "POST",
|
|
782
|
+
path: `/products/${product.id}`,
|
|
783
|
+
data: product
|
|
784
|
+
});
|
|
785
|
+
spinner2.text = `Updated product [${product.id}]`;
|
|
786
|
+
return {
|
|
787
|
+
id: product.id,
|
|
788
|
+
action: "updated"
|
|
789
|
+
};
|
|
758
790
|
}
|
|
759
791
|
}
|
|
760
792
|
|
|
@@ -771,53 +803,104 @@ async function Push({
|
|
|
771
803
|
yes,
|
|
772
804
|
prod
|
|
773
805
|
}) {
|
|
774
|
-
let { features, products } = config;
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
806
|
+
let { features, products, env } = config;
|
|
807
|
+
if (env === "prod") {
|
|
808
|
+
const shouldProceed = await prompts.confirm({
|
|
809
|
+
message: "You are about to push products to your prod environment. Are you sure you want to proceed?",
|
|
810
|
+
default: false
|
|
811
|
+
});
|
|
812
|
+
if (!shouldProceed) {
|
|
813
|
+
console.log(chalk7__default.default.yellow("Aborting..."));
|
|
814
|
+
process.exit(1);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
let { curFeatures, curProducts, featuresToDelete, productsToDelete } = await checkForDeletables(features, products);
|
|
779
818
|
for (let productId of productsToDelete) {
|
|
780
819
|
let shouldDelete = yes || await prompts.confirm({
|
|
781
820
|
message: `Delete product [${productId}]?`
|
|
782
821
|
});
|
|
783
822
|
if (shouldDelete) {
|
|
784
|
-
const
|
|
823
|
+
const s3 = spinner(`Deleting product [${productId}]`);
|
|
785
824
|
await deleteProduct(productId);
|
|
786
|
-
|
|
825
|
+
s3.success(`Product [${productId}] deleted successfully!`);
|
|
787
826
|
}
|
|
788
827
|
}
|
|
828
|
+
const batchFeatures = [];
|
|
829
|
+
const s = initSpinner(`Pushing features`);
|
|
789
830
|
for (let feature of features) {
|
|
790
|
-
|
|
791
|
-
await upsertFeature(feature);
|
|
792
|
-
s.success(`Pushed feature [${feature.id}]`);
|
|
831
|
+
batchFeatures.push(upsertFeature(feature, s));
|
|
793
832
|
}
|
|
833
|
+
await Promise.all(batchFeatures);
|
|
834
|
+
s.success(`Features pushed successfully!`);
|
|
835
|
+
console.log(chalk7__default.default.dim("\nFeatures pushed:"));
|
|
836
|
+
features.forEach((feature) => {
|
|
837
|
+
console.log(chalk7__default.default.cyan(` \u2022 ${feature.id}`));
|
|
838
|
+
});
|
|
839
|
+
console.log();
|
|
840
|
+
const productDecisions = /* @__PURE__ */ new Map();
|
|
841
|
+
const batchCheckProducts = [];
|
|
794
842
|
for (let product of products) {
|
|
795
|
-
|
|
796
|
-
|
|
843
|
+
batchCheckProducts.push(
|
|
844
|
+
checkProductForConfirmation({
|
|
845
|
+
curProducts,
|
|
846
|
+
product
|
|
847
|
+
})
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
const checkProductResults = await Promise.all(batchCheckProducts);
|
|
851
|
+
for (let result of checkProductResults) {
|
|
852
|
+
if (result.will_version) {
|
|
853
|
+
const shouldUpdate = await prompts.confirm({
|
|
854
|
+
message: `Product ${result.id} has customers on it and updating it will create a new version.
|
|
855
|
+
Are you sure you'd like to continue? `
|
|
856
|
+
});
|
|
857
|
+
productDecisions.set(result.id, shouldUpdate);
|
|
858
|
+
} else {
|
|
859
|
+
productDecisions.set(result.id, true);
|
|
860
|
+
}
|
|
797
861
|
}
|
|
862
|
+
const s2 = initSpinner(`Pushing products`);
|
|
863
|
+
const batchProducts = [];
|
|
864
|
+
for (let product of products) {
|
|
865
|
+
const shouldUpdate = productDecisions.get(product.id);
|
|
866
|
+
batchProducts.push(
|
|
867
|
+
upsertProduct({ curProducts, product, spinner: s2, shouldUpdate })
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
const prodResults = await Promise.all(batchProducts);
|
|
871
|
+
s2.success(`Products pushed successfully!`);
|
|
872
|
+
console.log(chalk7__default.default.dim("\nProducts pushed:"));
|
|
873
|
+
prodResults.forEach((result) => {
|
|
874
|
+
let action = result.action;
|
|
875
|
+
console.log(
|
|
876
|
+
chalk7__default.default.cyan(
|
|
877
|
+
` \u2022 ${result.id} ${action == "skipped" ? `(${action})` : ""}`
|
|
878
|
+
)
|
|
879
|
+
);
|
|
880
|
+
});
|
|
881
|
+
console.log();
|
|
798
882
|
for (let featureId of featuresToDelete) {
|
|
799
883
|
let shouldDelete = yes || await prompts.confirm({
|
|
800
884
|
message: `Delete feature [${featureId}]?`
|
|
801
885
|
});
|
|
802
886
|
if (shouldDelete) {
|
|
803
|
-
const
|
|
887
|
+
const s3 = spinner(`Deleting feature [${featureId}]`);
|
|
804
888
|
await deleteFeature(featureId);
|
|
805
|
-
|
|
889
|
+
s3.success(`Feature [${featureId}] deleted successfully!`);
|
|
806
890
|
}
|
|
807
891
|
}
|
|
808
|
-
const env = prod ? "prod" : "sandbox";
|
|
809
892
|
console.log(
|
|
810
|
-
|
|
893
|
+
chalk7__default.default.magentaBright(`Success! Changes have been pushed to ${env}.`)
|
|
811
894
|
);
|
|
812
895
|
if (prod) {
|
|
813
896
|
console.log(
|
|
814
|
-
|
|
897
|
+
chalk7__default.default.magentaBright(
|
|
815
898
|
`You can view the products at ${FRONTEND_URL}/products`
|
|
816
899
|
)
|
|
817
900
|
);
|
|
818
901
|
} else {
|
|
819
902
|
console.log(
|
|
820
|
-
|
|
903
|
+
chalk7__default.default.magentaBright(
|
|
821
904
|
`You can view the products at ${FRONTEND_URL}/sandbox/products`
|
|
822
905
|
)
|
|
823
906
|
);
|
|
@@ -844,6 +927,6 @@ commander.program.command("dashboard").description("Open the Autumn dashboard in
|
|
|
844
927
|
open__default.default(`${FRONTEND_URL}`);
|
|
845
928
|
});
|
|
846
929
|
commander.program.command("version").description("Show the version of Autumn").action(() => {
|
|
847
|
-
console.log(
|
|
930
|
+
console.log(chalk7__default.default.green(`Autumn v${VERSION}`));
|
|
848
931
|
});
|
|
849
932
|
commander.program.parse();
|
package/dist/cli.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { program } from 'commander';
|
|
3
|
-
import
|
|
3
|
+
import chalk7 from 'chalk';
|
|
4
4
|
import axios from 'axios';
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import { confirm, input, password, select } from '@inquirer/prompts';
|
|
7
7
|
import dotenv from 'dotenv';
|
|
8
|
+
import yoctoSpinner from 'yocto-spinner';
|
|
8
9
|
import path, { resolve } from 'path';
|
|
9
10
|
import createJiti from 'jiti';
|
|
10
11
|
import { pathToFileURL } from 'url';
|
|
11
12
|
import { execSync } from 'child_process';
|
|
12
13
|
import { z } from 'zod';
|
|
13
14
|
import open from 'open';
|
|
14
|
-
import yoctoSpinner from 'yocto-spinner';
|
|
15
15
|
|
|
16
16
|
// source/constants.ts
|
|
17
17
|
var FRONTEND_URL = "http://app.useautumn.com";
|
|
@@ -98,18 +98,18 @@ AUTUMN_SECRET_KEY=${sandboxKey}
|
|
|
98
98
|
if (fs.existsSync(envPath)) {
|
|
99
99
|
upsertEnvVar(envPath, "AUTUMN_PROD_SECRET_KEY", prodKey);
|
|
100
100
|
upsertEnvVar(envPath, "AUTUMN_SECRET_KEY", sandboxKey);
|
|
101
|
-
console.log(
|
|
101
|
+
console.log(chalk7.green(".env file found. Updated keys."));
|
|
102
102
|
} else if (fs.existsSync(envLocalPath)) {
|
|
103
103
|
fs.writeFileSync(envPath, envVars);
|
|
104
104
|
console.log(
|
|
105
|
-
|
|
105
|
+
chalk7.green(
|
|
106
106
|
".env.local found but .env not found. Created new .env file and wrote keys."
|
|
107
107
|
)
|
|
108
108
|
);
|
|
109
109
|
} else {
|
|
110
110
|
fs.writeFileSync(envPath, envVars);
|
|
111
111
|
console.log(
|
|
112
|
-
|
|
112
|
+
chalk7.green(
|
|
113
113
|
"No .env or .env.local file found. Created new .env file and wrote keys."
|
|
114
114
|
)
|
|
115
115
|
);
|
|
@@ -134,6 +134,13 @@ function readFromEnv() {
|
|
|
134
134
|
}
|
|
135
135
|
return void 0;
|
|
136
136
|
}
|
|
137
|
+
function initSpinner(message) {
|
|
138
|
+
const spinner2 = yoctoSpinner({
|
|
139
|
+
text: message
|
|
140
|
+
});
|
|
141
|
+
spinner2.start();
|
|
142
|
+
return spinner2;
|
|
143
|
+
}
|
|
137
144
|
|
|
138
145
|
// source/core/api.ts
|
|
139
146
|
var INTERNAL_BASE = BACKEND_URL;
|
|
@@ -165,8 +172,8 @@ async function request({
|
|
|
165
172
|
throw error;
|
|
166
173
|
}
|
|
167
174
|
console.error(
|
|
168
|
-
|
|
169
|
-
|
|
175
|
+
chalk7.red("\nError occured when making API request:"),
|
|
176
|
+
chalk7.red(error.response.data.message || error.response.data.error)
|
|
170
177
|
);
|
|
171
178
|
process.exit(1);
|
|
172
179
|
}
|
|
@@ -300,7 +307,7 @@ var getResetUsageStr = ({
|
|
|
300
307
|
return "";
|
|
301
308
|
};
|
|
302
309
|
var getIntervalStr = ({ item }) => {
|
|
303
|
-
if (item.interval == null) return
|
|
310
|
+
if (item.interval == null) return ``;
|
|
304
311
|
return `${getItemFieldPrefix()}interval: '${item.interval}',`;
|
|
305
312
|
};
|
|
306
313
|
var getEntityFeatureIdStr = ({ item }) => {
|
|
@@ -436,7 +443,7 @@ async function installAtmn() {
|
|
|
436
443
|
});
|
|
437
444
|
if (!shouldInstall) {
|
|
438
445
|
console.log(
|
|
439
|
-
|
|
446
|
+
chalk7.yellow(
|
|
440
447
|
"Skipping installation. You can install atmn manually with your preferred package manager."
|
|
441
448
|
)
|
|
442
449
|
);
|
|
@@ -452,13 +459,13 @@ async function installAtmn() {
|
|
|
452
459
|
default: "npm"
|
|
453
460
|
});
|
|
454
461
|
try {
|
|
455
|
-
console.log(
|
|
462
|
+
console.log(chalk7.blue(`Installing atmn with ${packageManager}...`));
|
|
456
463
|
const installCommand = packageManager === "npm" ? "npm install atmn" : packageManager === "pnpm" ? "pnpm add atmn" : "bun add atmn";
|
|
457
464
|
execSync(installCommand, { stdio: "inherit" });
|
|
458
|
-
console.log(
|
|
465
|
+
console.log(chalk7.green("atmn installed successfully!"));
|
|
459
466
|
return true;
|
|
460
467
|
} catch (error) {
|
|
461
|
-
console.error(
|
|
468
|
+
console.error(chalk7.red("Failed to install atmn:"), error);
|
|
462
469
|
return false;
|
|
463
470
|
}
|
|
464
471
|
}
|
|
@@ -512,9 +519,16 @@ async function loadAutumnConfigFile() {
|
|
|
512
519
|
}
|
|
513
520
|
}
|
|
514
521
|
}
|
|
522
|
+
const secretKey = readFromEnv();
|
|
523
|
+
if (secretKey?.includes("live")) {
|
|
524
|
+
console.log(chalk7.magentaBright("Running in production environment..."));
|
|
525
|
+
} else {
|
|
526
|
+
console.log(chalk7.yellow("Running in sandbox environment..."));
|
|
527
|
+
}
|
|
515
528
|
return {
|
|
516
529
|
products,
|
|
517
|
-
features
|
|
530
|
+
features,
|
|
531
|
+
env: secretKey?.includes("live") ? "prod" : "sandbox"
|
|
518
532
|
};
|
|
519
533
|
}
|
|
520
534
|
function writeConfig(config) {
|
|
@@ -524,7 +538,7 @@ function writeConfig(config) {
|
|
|
524
538
|
|
|
525
539
|
// source/commands/pull.ts
|
|
526
540
|
async function Pull({ config }) {
|
|
527
|
-
console.log(
|
|
541
|
+
console.log(chalk7.green("Pulling products and features from Autumn..."));
|
|
528
542
|
const products = await getAllProducts();
|
|
529
543
|
const features = await getFeatures();
|
|
530
544
|
const productSnippets = products.map(
|
|
@@ -541,7 +555,7 @@ ${importBuilder()}
|
|
|
541
555
|
// Products${productSnippets.join("\n")}
|
|
542
556
|
`;
|
|
543
557
|
writeConfig(autumnConfig);
|
|
544
|
-
console.log(
|
|
558
|
+
console.log(chalk7.green("Success! Config has been updated."));
|
|
545
559
|
}
|
|
546
560
|
|
|
547
561
|
// source/core/auth.ts
|
|
@@ -557,14 +571,14 @@ async function getOTP(otp) {
|
|
|
557
571
|
var passwordTheme = {
|
|
558
572
|
style: {
|
|
559
573
|
answer: (text) => {
|
|
560
|
-
return
|
|
574
|
+
return chalk7.magenta("*".repeat(text.length));
|
|
561
575
|
}
|
|
562
576
|
}
|
|
563
577
|
};
|
|
564
578
|
var inputTheme = {
|
|
565
579
|
style: {
|
|
566
580
|
answer: (text) => {
|
|
567
|
-
return
|
|
581
|
+
return chalk7.magenta(text);
|
|
568
582
|
}
|
|
569
583
|
}
|
|
570
584
|
};
|
|
@@ -602,7 +616,7 @@ async function AuthCommand() {
|
|
|
602
616
|
);
|
|
603
617
|
} else {
|
|
604
618
|
console.log(
|
|
605
|
-
|
|
619
|
+
chalk7.yellow(
|
|
606
620
|
"Okay, no worries. Go to the Autumn dashboard when you're ready!"
|
|
607
621
|
)
|
|
608
622
|
);
|
|
@@ -610,7 +624,7 @@ async function AuthCommand() {
|
|
|
610
624
|
}
|
|
611
625
|
storeToEnv(keyInfo.prodKey, keyInfo.sandboxKey);
|
|
612
626
|
console.log(
|
|
613
|
-
|
|
627
|
+
chalk7.green(
|
|
614
628
|
"Success! Keys have been stored locally. You may now use the CLI."
|
|
615
629
|
)
|
|
616
630
|
);
|
|
@@ -620,31 +634,33 @@ async function AuthCommand() {
|
|
|
620
634
|
async function Init({ config }) {
|
|
621
635
|
let apiKey = readFromEnv();
|
|
622
636
|
if (apiKey) {
|
|
623
|
-
console.log(
|
|
637
|
+
console.log(chalk7.green("API key found. Pulling latest config..."));
|
|
624
638
|
await Pull({ config });
|
|
625
639
|
console.log(
|
|
626
|
-
|
|
640
|
+
chalk7.green("Project initialized and config pulled successfully!")
|
|
627
641
|
);
|
|
628
642
|
return;
|
|
629
643
|
}
|
|
630
|
-
console.log(
|
|
644
|
+
console.log(chalk7.yellow("No API key found. Running authentication..."));
|
|
631
645
|
await AuthCommand();
|
|
632
646
|
apiKey = readFromEnv();
|
|
633
647
|
if (apiKey) {
|
|
634
648
|
await Pull({ config });
|
|
635
649
|
console.log(
|
|
636
|
-
|
|
650
|
+
chalk7.green(
|
|
637
651
|
"Project initialized! You are now authenticated and config has been pulled."
|
|
638
652
|
)
|
|
639
653
|
);
|
|
640
654
|
} else {
|
|
641
655
|
console.log(
|
|
642
|
-
|
|
656
|
+
chalk7.red(
|
|
643
657
|
"Authentication did not yield an API key. Please check your setup."
|
|
644
658
|
)
|
|
645
659
|
);
|
|
646
660
|
}
|
|
647
661
|
}
|
|
662
|
+
|
|
663
|
+
// source/core/push.ts
|
|
648
664
|
async function checkForDeletables(currentFeatures, currentProducts) {
|
|
649
665
|
const features = await getFeatures();
|
|
650
666
|
const featureIds = features.map((feature) => feature.id);
|
|
@@ -660,12 +676,17 @@ async function checkForDeletables(currentFeatures, currentProducts) {
|
|
|
660
676
|
const productsToDelete = productIds.filter(
|
|
661
677
|
(productId) => !currentProductIds.includes(productId)
|
|
662
678
|
);
|
|
663
|
-
return {
|
|
679
|
+
return {
|
|
680
|
+
curFeatures: features,
|
|
681
|
+
curProducts: products,
|
|
682
|
+
featuresToDelete,
|
|
683
|
+
productsToDelete
|
|
684
|
+
};
|
|
664
685
|
}
|
|
665
686
|
var isDuplicate = (error) => {
|
|
666
687
|
return error.response && error.response.data && (error.response.data.code === "duplicate_feature_id" || error.response.data.code === "product_already_exists");
|
|
667
688
|
};
|
|
668
|
-
async function upsertFeature(feature) {
|
|
689
|
+
async function upsertFeature(feature, s) {
|
|
669
690
|
try {
|
|
670
691
|
const response = await externalRequest({
|
|
671
692
|
method: "POST",
|
|
@@ -688,56 +709,67 @@ async function upsertFeature(feature) {
|
|
|
688
709
|
Failed to push feature ${feature.id}: ${error.response?.data?.message || "Unknown error"}`
|
|
689
710
|
);
|
|
690
711
|
process.exit(1);
|
|
712
|
+
} finally {
|
|
713
|
+
s.text = `Pushed feature [${feature.id}]`;
|
|
691
714
|
}
|
|
692
715
|
}
|
|
716
|
+
async function checkProductForConfirmation({
|
|
717
|
+
curProducts,
|
|
718
|
+
product
|
|
719
|
+
}) {
|
|
720
|
+
let curProduct = curProducts.find((p) => p.id === product.id);
|
|
721
|
+
if (!curProduct) {
|
|
722
|
+
return {
|
|
723
|
+
id: product.id,
|
|
724
|
+
will_version: false
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
const res1 = await externalRequest({
|
|
728
|
+
method: "GET",
|
|
729
|
+
path: `/products/${product.id}/has_customers`,
|
|
730
|
+
data: product
|
|
731
|
+
});
|
|
732
|
+
return {
|
|
733
|
+
id: product.id,
|
|
734
|
+
will_version: res1.will_version
|
|
735
|
+
};
|
|
736
|
+
}
|
|
693
737
|
async function upsertProduct({
|
|
738
|
+
curProducts,
|
|
694
739
|
product,
|
|
695
|
-
spinner: spinner2
|
|
740
|
+
spinner: spinner2,
|
|
741
|
+
shouldUpdate = true
|
|
696
742
|
}) {
|
|
697
|
-
|
|
698
|
-
|
|
743
|
+
if (!shouldUpdate) {
|
|
744
|
+
spinner2.text = `Skipping update to product ${product.id}`;
|
|
745
|
+
return {
|
|
746
|
+
id: product.id,
|
|
747
|
+
action: "skipped"
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
let curProduct = curProducts.find((p) => p.id === product.id);
|
|
751
|
+
if (!curProduct) {
|
|
752
|
+
await externalRequest({
|
|
699
753
|
method: "POST",
|
|
700
754
|
path: `/products`,
|
|
701
|
-
data: product
|
|
702
|
-
throwOnError: true
|
|
755
|
+
data: product
|
|
703
756
|
});
|
|
704
|
-
spinner2.
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
});
|
|
721
|
-
}
|
|
722
|
-
if (shouldUpdate) {
|
|
723
|
-
spinner2.start();
|
|
724
|
-
const response = await externalRequest({
|
|
725
|
-
method: "POST",
|
|
726
|
-
path: `/products/${product.id}`,
|
|
727
|
-
data: product
|
|
728
|
-
});
|
|
729
|
-
spinner2.success(`Pushed product [${product.id}]`);
|
|
730
|
-
return response;
|
|
731
|
-
} else {
|
|
732
|
-
spinner2.info(`Skipping update to product ${product.id}`);
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
console.error(
|
|
737
|
-
`
|
|
738
|
-
Failed to push product ${product.id}: ${error.response?.data?.message || "Unknown error"}`
|
|
739
|
-
);
|
|
740
|
-
process.exit(1);
|
|
757
|
+
spinner2.text = `Created product [${product.id}]`;
|
|
758
|
+
return {
|
|
759
|
+
id: product.id,
|
|
760
|
+
action: "create"
|
|
761
|
+
};
|
|
762
|
+
} else {
|
|
763
|
+
await externalRequest({
|
|
764
|
+
method: "POST",
|
|
765
|
+
path: `/products/${product.id}`,
|
|
766
|
+
data: product
|
|
767
|
+
});
|
|
768
|
+
spinner2.text = `Updated product [${product.id}]`;
|
|
769
|
+
return {
|
|
770
|
+
id: product.id,
|
|
771
|
+
action: "updated"
|
|
772
|
+
};
|
|
741
773
|
}
|
|
742
774
|
}
|
|
743
775
|
|
|
@@ -754,53 +786,104 @@ async function Push({
|
|
|
754
786
|
yes,
|
|
755
787
|
prod
|
|
756
788
|
}) {
|
|
757
|
-
let { features, products } = config;
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
789
|
+
let { features, products, env } = config;
|
|
790
|
+
if (env === "prod") {
|
|
791
|
+
const shouldProceed = await confirm({
|
|
792
|
+
message: "You are about to push products to your prod environment. Are you sure you want to proceed?",
|
|
793
|
+
default: false
|
|
794
|
+
});
|
|
795
|
+
if (!shouldProceed) {
|
|
796
|
+
console.log(chalk7.yellow("Aborting..."));
|
|
797
|
+
process.exit(1);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
let { curFeatures, curProducts, featuresToDelete, productsToDelete } = await checkForDeletables(features, products);
|
|
762
801
|
for (let productId of productsToDelete) {
|
|
763
802
|
let shouldDelete = yes || await confirm({
|
|
764
803
|
message: `Delete product [${productId}]?`
|
|
765
804
|
});
|
|
766
805
|
if (shouldDelete) {
|
|
767
|
-
const
|
|
806
|
+
const s3 = spinner(`Deleting product [${productId}]`);
|
|
768
807
|
await deleteProduct(productId);
|
|
769
|
-
|
|
808
|
+
s3.success(`Product [${productId}] deleted successfully!`);
|
|
770
809
|
}
|
|
771
810
|
}
|
|
811
|
+
const batchFeatures = [];
|
|
812
|
+
const s = initSpinner(`Pushing features`);
|
|
772
813
|
for (let feature of features) {
|
|
773
|
-
|
|
774
|
-
await upsertFeature(feature);
|
|
775
|
-
s.success(`Pushed feature [${feature.id}]`);
|
|
814
|
+
batchFeatures.push(upsertFeature(feature, s));
|
|
776
815
|
}
|
|
816
|
+
await Promise.all(batchFeatures);
|
|
817
|
+
s.success(`Features pushed successfully!`);
|
|
818
|
+
console.log(chalk7.dim("\nFeatures pushed:"));
|
|
819
|
+
features.forEach((feature) => {
|
|
820
|
+
console.log(chalk7.cyan(` \u2022 ${feature.id}`));
|
|
821
|
+
});
|
|
822
|
+
console.log();
|
|
823
|
+
const productDecisions = /* @__PURE__ */ new Map();
|
|
824
|
+
const batchCheckProducts = [];
|
|
825
|
+
for (let product of products) {
|
|
826
|
+
batchCheckProducts.push(
|
|
827
|
+
checkProductForConfirmation({
|
|
828
|
+
curProducts,
|
|
829
|
+
product
|
|
830
|
+
})
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
const checkProductResults = await Promise.all(batchCheckProducts);
|
|
834
|
+
for (let result of checkProductResults) {
|
|
835
|
+
if (result.will_version) {
|
|
836
|
+
const shouldUpdate = await confirm({
|
|
837
|
+
message: `Product ${result.id} has customers on it and updating it will create a new version.
|
|
838
|
+
Are you sure you'd like to continue? `
|
|
839
|
+
});
|
|
840
|
+
productDecisions.set(result.id, shouldUpdate);
|
|
841
|
+
} else {
|
|
842
|
+
productDecisions.set(result.id, true);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
const s2 = initSpinner(`Pushing products`);
|
|
846
|
+
const batchProducts = [];
|
|
777
847
|
for (let product of products) {
|
|
778
|
-
const
|
|
779
|
-
|
|
848
|
+
const shouldUpdate = productDecisions.get(product.id);
|
|
849
|
+
batchProducts.push(
|
|
850
|
+
upsertProduct({ curProducts, product, spinner: s2, shouldUpdate })
|
|
851
|
+
);
|
|
780
852
|
}
|
|
853
|
+
const prodResults = await Promise.all(batchProducts);
|
|
854
|
+
s2.success(`Products pushed successfully!`);
|
|
855
|
+
console.log(chalk7.dim("\nProducts pushed:"));
|
|
856
|
+
prodResults.forEach((result) => {
|
|
857
|
+
let action = result.action;
|
|
858
|
+
console.log(
|
|
859
|
+
chalk7.cyan(
|
|
860
|
+
` \u2022 ${result.id} ${action == "skipped" ? `(${action})` : ""}`
|
|
861
|
+
)
|
|
862
|
+
);
|
|
863
|
+
});
|
|
864
|
+
console.log();
|
|
781
865
|
for (let featureId of featuresToDelete) {
|
|
782
866
|
let shouldDelete = yes || await confirm({
|
|
783
867
|
message: `Delete feature [${featureId}]?`
|
|
784
868
|
});
|
|
785
869
|
if (shouldDelete) {
|
|
786
|
-
const
|
|
870
|
+
const s3 = spinner(`Deleting feature [${featureId}]`);
|
|
787
871
|
await deleteFeature(featureId);
|
|
788
|
-
|
|
872
|
+
s3.success(`Feature [${featureId}] deleted successfully!`);
|
|
789
873
|
}
|
|
790
874
|
}
|
|
791
|
-
const env = prod ? "prod" : "sandbox";
|
|
792
875
|
console.log(
|
|
793
|
-
|
|
876
|
+
chalk7.magentaBright(`Success! Changes have been pushed to ${env}.`)
|
|
794
877
|
);
|
|
795
878
|
if (prod) {
|
|
796
879
|
console.log(
|
|
797
|
-
|
|
880
|
+
chalk7.magentaBright(
|
|
798
881
|
`You can view the products at ${FRONTEND_URL}/products`
|
|
799
882
|
)
|
|
800
883
|
);
|
|
801
884
|
} else {
|
|
802
885
|
console.log(
|
|
803
|
-
|
|
886
|
+
chalk7.magentaBright(
|
|
804
887
|
`You can view the products at ${FRONTEND_URL}/sandbox/products`
|
|
805
888
|
)
|
|
806
889
|
);
|
|
@@ -827,6 +910,6 @@ program.command("dashboard").description("Open the Autumn dashboard in your brow
|
|
|
827
910
|
open(`${FRONTEND_URL}`);
|
|
828
911
|
});
|
|
829
912
|
program.command("version").description("Show the version of Autumn").action(() => {
|
|
830
|
-
console.log(
|
|
913
|
+
console.log(chalk7.green(`Autumn v${VERSION}`));
|
|
831
914
|
});
|
|
832
915
|
program.parse();
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED