env-drift-check 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 EnvWise Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # env-drift-check
2
+
3
+ [![npm version](https://img.shields.io/npm/v/env-drift-check.svg)](https://www.npmjs.com/package/env-drift-check)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ > **Stop copy-pasting `.env` files.** Onboard developers in seconds with interactive prompts and smart validation.
7
+
8
+ **env-drift-check** is a powerful CLI tool that ensures your environment variables are always in sync with your code. Unlike other tools that just fail when keys are missing, we help you **fix them interactively**.
9
+
10
+ ## Why use this?
11
+
12
+ | Feature | Other Tools | **env-drift-check** |
13
+ | :--- | :--- | :--- |
14
+ | **Missing Keys** | Crash & Exit | 🛠 **Interactive Setup Wizard** |
15
+ | **Validation** | Basic Existence Check | **Rich Types** (Email, URL, Regex) |
16
+ | **Onboarding** | Manual (Read docs → Copy → Paste) | **Automated** (Run command → Fill prompts) |
17
+
18
+ ## Features
19
+
20
+ - **Interactive Mode**: Automatically prompts users to fill in missing variables.
21
+ - **Smart Validation**: enforce types like `email`, `url`, `number`, `boolean`, and `regex`.
22
+ - **Drift Detection**: Compares your `.env` against `.env.example`.
23
+ - **Zero Config**: Works out of the box, or add `envwise.config.json` for superpowers.
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ npm install -g env-drift-check
29
+ # OR
30
+ npx env-drift-check
31
+ ```
32
+
33
+ ## 🛠 Usage
34
+
35
+ ### 1. Basic Check
36
+ Check if your `.env` is missing any keys defined in `.env.example`:
37
+
38
+ ```bash
39
+ npx env-drift-check
40
+ ```
41
+
42
+ ### 2. Interactive Setup (Recommended)
43
+ Automatically prompt the user to fill in missing keys:
44
+
45
+ ```bash
46
+ npx env-drift-check --interactive
47
+ # OR
48
+ npx env-drift-check -i
49
+ ```
50
+
51
+ ### 3. CI/CD Mode (Strict)
52
+ Fail the build if drift is detected (great for pipelines):
53
+
54
+ ```bash
55
+ npx env-drift-check --strict
56
+ ```
57
+
58
+ ## Configuration
59
+
60
+ Create a `envwise.config.json` to define validation rules.
61
+
62
+ ```json
63
+ {
64
+ "baseEnv": ".env.example",
65
+ "rules": {
66
+ "PORT": {
67
+ "type": "number",
68
+ "min": 3000,
69
+ "max": 9000
70
+ },
71
+ "DATABASE_URL": {
72
+ "type": "url",
73
+ "description": "Connection string for MongoDB"
74
+ },
75
+ "ADMIN_EMAIL": {
76
+ "type": "email",
77
+ "required": true
78
+ },
79
+ "FEATURE_FLAG": {
80
+ "type": "boolean",
81
+ "mustBeFalseIn": "production"
82
+ },
83
+ "API_KEY": {
84
+ "type": "regex",
85
+ "regex": "^[A-Z0-9]{32}$",
86
+ "description": "32-character alphanumeric key"
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ ### Validation Types
93
+
94
+ | Type | Options | Description |
95
+ | :--- | :--- | :--- |
96
+ | `string` | `min`, `max` | String length validation |
97
+ | `number` | `min`, `max` | Numeric range validation |
98
+ | `boolean` | `mustBeFalseIn` | True/False check |
99
+ | `enum` | `values` (array) | Must be one of the allowlist |
100
+ | `email` | - | Valid email format |
101
+ | `url` | - | Valid URL format |
102
+ | `regex` | `regex` (string) | Custom pattern matching |
103
+
104
+ ## Contributing
105
+
106
+ 1. Fork the repository
107
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
108
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
109
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
110
+ 5. Open a Pull Request
111
+
112
+ ## License
113
+
114
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const envParser_1 = require("./engine/envParser");
10
+ const driftChecker_1 = require("./engine/driftChecker");
11
+ const consoleReporter_1 = require("./reporter/consoleReporter");
12
+ const interactive_1 = require("./engine/interactive");
13
+ const loadConfig_1 = require("./config/loadConfig");
14
+ const args = process.argv.slice(2);
15
+ const strict = args.includes("--strict");
16
+ const interactive = args.includes("--interactive") || args.includes("-i");
17
+ const checkAll = args.includes("--all");
18
+ const positionalArgs = args.filter(a => !a.startsWith("-"));
19
+ const config = (0, loadConfig_1.loadConfig)();
20
+ const basePath = path_1.default.resolve(config.baseEnv || ".env.example");
21
+ if (!fs_1.default.existsSync(basePath)) {
22
+ console.error(`Reference file missing: ${basePath}`);
23
+ process.exit(1);
24
+ }
25
+ const baseEnv = (0, envParser_1.parseEnv)(basePath);
26
+ async function runForFile(targetFile) {
27
+ const targetPath = path_1.default.resolve(targetFile);
28
+ if (!fs_1.default.existsSync(targetPath)) {
29
+ console.error(`File missing: ${targetFile}`);
30
+ return false;
31
+ }
32
+ console.log(`\n Checking ${path_1.default.basename(targetPath)} against ${path_1.default.basename(basePath)}...`);
33
+ const targetEnv = (0, envParser_1.parseEnv)(targetPath);
34
+ let result = (0, driftChecker_1.checkDrift)(baseEnv, targetEnv, config);
35
+ if (result.missing.length > 0 && interactive) {
36
+ const newValues = await (0, interactive_1.interactiveSetup)(result.missing, baseEnv, config);
37
+ // Merge new values into targetEnv
38
+ const updatedEnv = { ...targetEnv, ...newValues };
39
+ // Write back to file
40
+ const newContent = Object.entries(updatedEnv)
41
+ .map(([k, v]) => `${k}=${v}`)
42
+ .join("\n");
43
+ fs_1.default.writeFileSync(targetPath, newContent);
44
+ console.log(`\n ✅ Updated ${path_1.default.basename(targetPath)} with new values.`);
45
+ // Re-check drift
46
+ result = (0, driftChecker_1.checkDrift)(baseEnv, updatedEnv, config);
47
+ }
48
+ (0, consoleReporter_1.report)(result);
49
+ const hasIssues = result.missing.length || result.mismatches.length || result.errors.length;
50
+ return !hasIssues;
51
+ }
52
+ async function main() {
53
+ let allFiles = [];
54
+ if (checkAll) {
55
+ allFiles = fs_1.default.readdirSync(process.cwd())
56
+ .filter(f => f.startsWith(".env") && f !== path_1.default.basename(basePath));
57
+ }
58
+ else {
59
+ allFiles = [positionalArgs[0] || ".env"];
60
+ }
61
+ let overallSuccess = true;
62
+ for (const file of allFiles) {
63
+ const success = await runForFile(file);
64
+ if (!success)
65
+ overallSuccess = false;
66
+ }
67
+ if (strict && !overallSuccess) {
68
+ console.error("\n Strict mode failed for one or more files");
69
+ process.exit(1);
70
+ }
71
+ }
72
+ main().catch(err => {
73
+ console.error(err);
74
+ process.exit(1);
75
+ });
@@ -0,0 +1,2 @@
1
+ import { Config } from "../types";
2
+ export declare function loadConfig(): Config;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadConfig = loadConfig;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const DEFAULT_CONFIG = {
10
+ baseEnv: ".env.example",
11
+ rules: {}
12
+ };
13
+ function loadConfig() {
14
+ const configPath = path_1.default.resolve("envwise.config.json");
15
+ if (!fs_1.default.existsSync(configPath)) {
16
+ return DEFAULT_CONFIG;
17
+ }
18
+ const raw = fs_1.default.readFileSync(configPath, "utf-8");
19
+ const userConfig = JSON.parse(raw);
20
+ return {
21
+ ...DEFAULT_CONFIG,
22
+ ...userConfig
23
+ };
24
+ }
@@ -0,0 +1,2 @@
1
+ import { DriftResult, Config } from "../types";
2
+ export declare function checkDrift(base: Record<string, string>, target: Record<string, string>, config: Config): DriftResult;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkDrift = checkDrift;
4
+ const validator_1 = require("./validator");
5
+ function checkDrift(base, target, config) {
6
+ const result = {
7
+ missing: [],
8
+ extra: [],
9
+ errors: [],
10
+ warnings: [],
11
+ mismatches: []
12
+ };
13
+ // Missing & extra keys
14
+ for (const key of Object.keys(base)) {
15
+ if (!(key in target))
16
+ result.missing.push(key);
17
+ }
18
+ for (const key of Object.keys(target)) {
19
+ if (!(key in base))
20
+ result.extra.push(key);
21
+ }
22
+ // Value mismatch detection
23
+ for (const key of Object.keys(base)) {
24
+ if (key in target && base[key] !== target[key]) {
25
+ result.mismatches.push({
26
+ key,
27
+ expected: base[key],
28
+ actual: target[key]
29
+ });
30
+ }
31
+ }
32
+ // Rule-based validation
33
+ const rules = config.rules || {};
34
+ for (const [key, rule] of Object.entries(rules)) {
35
+ if (target[key]) {
36
+ const err = (0, validator_1.validateValue)(key, target[key], rule, target["NODE_ENV"]);
37
+ if (err)
38
+ result.errors.push({ key, message: err });
39
+ }
40
+ }
41
+ return result;
42
+ }
@@ -0,0 +1 @@
1
+ export declare function parseEnv(path: string): Record<string, string>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseEnv = parseEnv;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const dotenv_1 = __importDefault(require("dotenv"));
9
+ function parseEnv(path) {
10
+ if (!fs_1.default.existsSync(path)) {
11
+ throw new Error(`Env file not found: ${path}`);
12
+ }
13
+ const content = fs_1.default.readFileSync(path);
14
+ return dotenv_1.default.parse(content);
15
+ }
@@ -0,0 +1,2 @@
1
+ import { DriftResult } from "../types";
2
+ export declare function applyFixes(base: Record<string, string>, target: Record<string, string>, result: DriftResult): Record<string, string>;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applyFixes = applyFixes;
4
+ function applyFixes(base, target, result) {
5
+ const fixedEnv = { ...target };
6
+ // Add missing keys
7
+ for (const key of result.missing) {
8
+ if (base[key]) {
9
+ fixedEnv[key] = base[key];
10
+ }
11
+ }
12
+ // Fix mismatched values (base → target)
13
+ for (const mismatch of result.mismatches) {
14
+ if (mismatch.expected) {
15
+ fixedEnv[mismatch.key] = mismatch.expected;
16
+ }
17
+ }
18
+ return fixedEnv;
19
+ }
@@ -0,0 +1,2 @@
1
+ import { Config } from "../types";
2
+ export declare function interactiveSetup(missingKeys: string[], baseEnv: Record<string, string>, config: Config): Promise<Record<string, string>>;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.interactiveSetup = interactiveSetup;
7
+ const prompts_1 = __importDefault(require("prompts"));
8
+ const validator_1 = require("./validator");
9
+ async function interactiveSetup(missingKeys, baseEnv, config) {
10
+ const newValues = {};
11
+ console.log("\n🛠 Interactive Setup: Let's fill in the missing variables.\n");
12
+ for (const key of missingKeys) {
13
+ const rule = config.rules?.[key] || { type: "string" };
14
+ const initial = baseEnv[key] || "";
15
+ // Determine prompt type
16
+ let promptType = "text";
17
+ if (rule.type === "boolean")
18
+ promptType = "confirm";
19
+ if (rule.type === "number")
20
+ promptType = "number";
21
+ if (key.includes("PASSWORD") || key.includes("SECRET"))
22
+ promptType = "password";
23
+ const response = await (0, prompts_1.default)({
24
+ type: promptType,
25
+ name: "value",
26
+ message: `${key}${rule.description ? ` (${rule.description})` : ""}:`,
27
+ initial: promptType === "confirm" ? initial === "true" : initial,
28
+ validate: (val) => {
29
+ const strVal = String(val);
30
+ const error = (0, validator_1.validateValue)(key, strVal, rule, "local"); // Assuming 'local' context for now
31
+ return error || true;
32
+ }
33
+ });
34
+ // Handle user cancellation (Ctrl+C)
35
+ if (response.value === undefined) {
36
+ console.log("\nSetup cancelled.");
37
+ process.exit(1);
38
+ }
39
+ newValues[key] = String(response.value);
40
+ }
41
+ return newValues;
42
+ }
@@ -0,0 +1,2 @@
1
+ import { Rule } from "../types";
2
+ export declare function validateValue(key: string, value: string, rule: Rule, env: string): string | null;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateValue = validateValue;
4
+ function validateValue(key, value, rule, env) {
5
+ if (!value && rule.required !== false) {
6
+ return `${key} is required`;
7
+ }
8
+ // Number validation
9
+ if (rule.type === "number") {
10
+ const num = Number(value);
11
+ if (isNaN(num))
12
+ return `${key} must be a number`;
13
+ if (rule.min !== undefined && num < rule.min)
14
+ return `${key} must be at least ${rule.min}`;
15
+ if (rule.max !== undefined && num > rule.max)
16
+ return `${key} must be at most ${rule.max}`;
17
+ }
18
+ // String length validation
19
+ if (rule.type === "string") {
20
+ if (rule.min !== undefined && value.length < rule.min)
21
+ return `${key} must be at least ${rule.min} chars`;
22
+ if (rule.max !== undefined && value.length > rule.max)
23
+ return `${key} must be at most ${rule.max} chars`;
24
+ }
25
+ // Enum validation
26
+ if (rule.type === "enum" && rule.values && !rule.values.includes(value)) {
27
+ return `${key} must be one of: ${rule.values.join(", ")}`;
28
+ }
29
+ // Boolean validation
30
+ if (rule.type === "boolean") {
31
+ if (value !== "true" && value !== "false")
32
+ return `${key} must be true or false`;
33
+ if (rule.mustBeFalseIn === env && value === "true") {
34
+ return `${key} must be false in ${env}`;
35
+ }
36
+ }
37
+ // Email validation
38
+ if (rule.type === "email") {
39
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
40
+ if (!emailRegex.test(value))
41
+ return `${key} must be a valid email`;
42
+ }
43
+ // URL validation
44
+ if (rule.type === "url") {
45
+ try {
46
+ new URL(value);
47
+ }
48
+ catch {
49
+ return `${key} must be a valid URL`;
50
+ }
51
+ }
52
+ // Regex validation
53
+ if (rule.type === "regex" && rule.regex) {
54
+ const regex = new RegExp(rule.regex);
55
+ if (!regex.test(value))
56
+ return `${key} does not match required pattern`;
57
+ }
58
+ return null;
59
+ }
@@ -0,0 +1,6 @@
1
+ export * from "./engine/driftChecker";
2
+ export * from "./engine/envParser";
3
+ export * from "./engine/validator";
4
+ export * from "./engine/interactive";
5
+ export * from "./config/loadConfig";
6
+ export * from "./types";
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./engine/driftChecker"), exports);
18
+ __exportStar(require("./engine/envParser"), exports);
19
+ __exportStar(require("./engine/validator"), exports);
20
+ __exportStar(require("./engine/interactive"), exports);
21
+ __exportStar(require("./config/loadConfig"), exports);
22
+ __exportStar(require("./types"), exports);
@@ -0,0 +1,2 @@
1
+ import { DriftResult } from "../types";
2
+ export declare function report(result: DriftResult): void;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.report = report;
4
+ function report(result) {
5
+ if (result.missing.length) {
6
+ console.log("\n Missing Variables:");
7
+ result.missing.forEach(v => console.log(" -", v));
8
+ }
9
+ if (result.extra.length) {
10
+ console.log("\n Extra Variables:");
11
+ result.extra.forEach(v => console.log(" -", v));
12
+ }
13
+ if (result.errors.length) {
14
+ console.log("\n Errors:");
15
+ result.errors.forEach(e => console.log(" -", `${e.key}: ${e.message}`));
16
+ }
17
+ if (result.mismatches.length) {
18
+ console.log("\n Value Mismatches:");
19
+ result.mismatches.forEach(m => {
20
+ console.log(` - ${m.key}: expected="${m.expected}" actual="${m.actual}"`);
21
+ console.log(` -Run --fix to sync ${m.key}`);
22
+ });
23
+ }
24
+ if (!result.missing.length &&
25
+ !result.extra.length &&
26
+ !result.errors.length &&
27
+ !result.mismatches.length) {
28
+ console.log("No environment drift detected");
29
+ }
30
+ }
@@ -0,0 +1,29 @@
1
+ export interface Rule {
2
+ type: "string" | "number" | "boolean" | "enum" | "email" | "url" | "regex";
3
+ values?: string[];
4
+ regex?: string;
5
+ min?: number;
6
+ max?: number;
7
+ description?: string;
8
+ mustBeFalseIn?: string;
9
+ required?: boolean;
10
+ }
11
+ export interface Config {
12
+ baseEnv?: string;
13
+ rules?: Record<string, Rule>;
14
+ }
15
+ export interface ValueMismatch {
16
+ key: string;
17
+ expected: string;
18
+ actual: string;
19
+ }
20
+ export interface DriftResult {
21
+ missing: string[];
22
+ extra: string[];
23
+ errors: {
24
+ key: string;
25
+ message: string;
26
+ }[];
27
+ warnings: string[];
28
+ mismatches: ValueMismatch[];
29
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "env-drift-check",
3
+ "version": "0.1.0",
4
+ "description": "Interactive environment variable checker and setup wizard. Sync .env files with validation (Email, URL, Regex) and prompts.",
5
+ "keywords": [
6
+ "env",
7
+ "dotenv",
8
+ "check-env",
9
+ "dotenv-safe",
10
+ "environment-variables",
11
+ "config",
12
+ "validation",
13
+ "interactive",
14
+ "setup",
15
+ "onboarding",
16
+ "drift",
17
+ "checker"
18
+ ],
19
+ "author": "Shashidhar Naik",
20
+ "license": "MIT",
21
+ "bugs": {
22
+ "url": "https://github.com/shashi089/env-drift-check/issues"
23
+ },
24
+ "homepage": "https://github.com/shashi089/env-drift-check#readme",
25
+ "engines": {
26
+ "node": ">=16.0.0"
27
+ },
28
+ "main": "dist/cli.js",
29
+ "bin": {
30
+ "env-drift-check": "dist/cli.js"
31
+ },
32
+ "types": "dist/cli.d.ts",
33
+ "files": [
34
+ "dist",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "scripts": {
39
+ "build": "tsc",
40
+ "prepare": "npm run build",
41
+ "prepublishOnly": "npm run build"
42
+ },
43
+ "dependencies": {
44
+ "commander": "^11.0.0",
45
+ "dotenv": "^16.4.0",
46
+ "prompts": "^2.4.2"
47
+ },
48
+ "devDependencies": {
49
+ "@types/prompts": "^2.4.9",
50
+ "ts-node": "^10.9.2",
51
+ "typescript": "^5.3.3"
52
+ }
53
+ }