astro-config-cli 1.0.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/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # astro-config-cli
2
+
3
+ CLI tool for generating and managing Astro framework configuration files
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g astro-config-cli
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Initialize configuration
14
+
15
+ ```bash
16
+ astro-config init
17
+ astro-config init --template advanced
18
+ astro-config init --output custom-config.json
19
+ ```
20
+
21
+ ### Validate configuration
22
+
23
+ ```bash
24
+ astro-config validate
25
+ astro-config validate path/to/config.json
26
+ ```
27
+
28
+ ### View configuration
29
+
30
+ ```bash
31
+ astro-config show
32
+ astro-config show --env production
33
+ astro-config show --json
34
+ ```
35
+
36
+ ### Modify configuration
37
+
38
+ ```bash
39
+ astro-config set settings.debug true
40
+ astro-config set settings.logLevel \"warn\"
41
+ ```
42
+
43
+ ### Compare configurations
44
+
45
+ ```bash
46
+ astro-config diff config-dev.json config-prod.json
47
+ ```
48
+
49
+ ### List templates
50
+
51
+ ```bash
52
+ astro-config templates
53
+ ```
54
+
55
+ ## Templates
56
+
57
+ | Template | Description |
58
+ |----------|-------------|
59
+ | `minimal` | Bare minimum configuration |
60
+ | `standard` | Recommended defaults for most projects |
61
+ | `advanced` | Full-featured with security, caching, and multi-environment support |
62
+
63
+ ## Why astro-config-cli?
64
+
65
+ - **Zero dependencies at runtime** — just `commander` and `chalk`
66
+ - **Template-based** — start with minimal, standard, or advanced presets
67
+ - **Validation built-in** — catch config errors before deployment
68
+ - **Environment-aware** — manage dev/staging/production configs in one file
69
+ - **Diff support** — compare configs across environments
70
+
71
+ ## License
72
+
73
+ MIT
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,372 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+ import chalk from "chalk";
6
+ import fs from "fs";
7
+ var CONFIG_FILE = "astro-cli.json";
8
+ function loadConfig() {
9
+ if (fs.existsSync(CONFIG_FILE)) {
10
+ try {
11
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
12
+ } catch {
13
+ console.error(chalk.red("Error: Could not parse " + CONFIG_FILE));
14
+ process.exit(1);
15
+ }
16
+ }
17
+ return {};
18
+ }
19
+ function saveConfig(cfg) {
20
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
21
+ console.log(chalk.green("\u2714") + " Config saved to " + chalk.cyan(CONFIG_FILE));
22
+ }
23
+ function integrationImport(name) {
24
+ const map = {
25
+ react: "import react from '@astrojs/react';",
26
+ vue: "import vue from '@astrojs/vue';",
27
+ svelte: "import svelte from '@astrojs/svelte';",
28
+ tailwind: "import tailwind from '@astrojs/tailwind';",
29
+ mdx: "import mdx from '@astrojs/mdx';",
30
+ sitemap: "import sitemap from '@astrojs/sitemap';",
31
+ partytown: "import partytown from '@astrojs/partytown';"
32
+ };
33
+ return map[name];
34
+ }
35
+ function integrationCall(name) {
36
+ const map = {
37
+ react: "react()",
38
+ vue: "vue()",
39
+ svelte: "svelte()",
40
+ tailwind: "tailwind()",
41
+ mdx: "mdx()",
42
+ sitemap: "sitemap()",
43
+ partytown: 'partytown({ config: { forward: ["dataLayer.push"] } })'
44
+ };
45
+ return map[name];
46
+ }
47
+ function adapterImport(name) {
48
+ const map = {
49
+ node: "import node from '@astrojs/node';",
50
+ vercel: "import vercel from '@astrojs/vercel/serverless';",
51
+ netlify: "import netlify from '@astrojs/netlify';",
52
+ cloudflare: "import cloudflare from '@astrojs/cloudflare';",
53
+ deno: "import deno from '@astrojs/deno';"
54
+ };
55
+ return map[name];
56
+ }
57
+ function adapterCall(name, opts) {
58
+ if (Object.keys(opts).length === 0) return `${name}()`;
59
+ const args = JSON.stringify(opts, null, 2).replace(/^{/, "").replace(/}$/, "").trim();
60
+ return `${name}({ ${args.replace(/\n/g, " ")} })`;
61
+ }
62
+ function generateAstroConfig(cfg) {
63
+ const imports = ["import { defineConfig } from 'astro/config';"];
64
+ const parts = [];
65
+ if (cfg.output && cfg.output !== "static") {
66
+ parts.push(` output: '${cfg.output}',`);
67
+ }
68
+ if (cfg.site) parts.push(` site: '${cfg.site}',`);
69
+ if (cfg.base) parts.push(` base: '${cfg.base}',`);
70
+ if (cfg.srcDir) parts.push(` srcDir: '${cfg.srcDir}',`);
71
+ if (cfg.outDir) parts.push(` outDir: '${cfg.outDir}',`);
72
+ if (cfg.publicDir) parts.push(` publicDir: '${cfg.publicDir}',`);
73
+ if (cfg.adapter) {
74
+ imports.push(adapterImport(cfg.adapter));
75
+ parts.push(` adapter: ${adapterCall(cfg.adapter, cfg.adapterOptions ?? {})},`);
76
+ }
77
+ const integrations = cfg.integrations ?? [];
78
+ if (integrations.length > 0) {
79
+ integrations.forEach((i) => imports.push(integrationImport(i)));
80
+ const calls = integrations.map((i) => " " + integrationCall(i)).join(",\n");
81
+ parts.push(` integrations: [
82
+ ${calls},
83
+ ],`);
84
+ }
85
+ if (cfg.image && Object.keys(cfg.image).length > 0) {
86
+ const img = cfg.image;
87
+ const imgLines = [];
88
+ if (img.service) {
89
+ imgLines.push(` service: { entrypoint: 'astro/assets/services/${img.service}' },`);
90
+ }
91
+ if (img.domains?.length) {
92
+ imgLines.push(` domains: ${JSON.stringify(img.domains)},`);
93
+ }
94
+ if (img.remotePatterns?.length) {
95
+ const pats = img.remotePatterns.map((p) => ` { hostname: '${p}' }`).join(",\n");
96
+ imgLines.push(` remotePatterns: [
97
+ ${pats},
98
+ ],`);
99
+ }
100
+ if (img.format) imgLines.push(` format: '${img.format}',`);
101
+ if (img.quality !== void 0) imgLines.push(` quality: ${img.quality},`);
102
+ parts.push(` image: {
103
+ ${imgLines.join("\n")}
104
+ },`);
105
+ }
106
+ if (cfg.i18n) {
107
+ const i = cfg.i18n;
108
+ const i18n = [
109
+ ` defaultLocale: '${i.defaultLocale}',`,
110
+ ` locales: ${JSON.stringify(i.locales)},`
111
+ ];
112
+ if (i.routing) {
113
+ i18n.push(` routing: { prefixDefaultLocale: ${i.routing === "prefix-always"} },`);
114
+ }
115
+ if (i.fallback && Object.keys(i.fallback).length) {
116
+ i18n.push(` fallback: ${JSON.stringify(i.fallback)},`);
117
+ }
118
+ parts.push(` i18n: {
119
+ ${i18n.join("\n")}
120
+ },`);
121
+ }
122
+ if (cfg.markdown && Object.keys(cfg.markdown).length > 0) {
123
+ const m = cfg.markdown;
124
+ const md = [];
125
+ if (m.syntaxHighlight !== void 0) {
126
+ md.push(` syntaxHighlight: ${m.syntaxHighlight === false ? "false" : `'${m.syntaxHighlight}'`},`);
127
+ }
128
+ if (m.shikiConfig) md.push(` shikiConfig: ${JSON.stringify(m.shikiConfig)},`);
129
+ if (m.gfm !== void 0) md.push(` gfm: ${m.gfm},`);
130
+ if (m.smartypants !== void 0) md.push(` smartypants: ${m.smartypants},`);
131
+ if (m.remarkPlugins?.length) md.push(` remarkPlugins: ${JSON.stringify(m.remarkPlugins)},`);
132
+ if (m.rehypePlugins?.length) md.push(` rehypePlugins: ${JSON.stringify(m.rehypePlugins)},`);
133
+ parts.push(` markdown: {
134
+ ${md.join("\n")}
135
+ },`);
136
+ }
137
+ if (cfg.prefetch !== void 0) {
138
+ if (typeof cfg.prefetch === "boolean") {
139
+ parts.push(` prefetch: ${cfg.prefetch},`);
140
+ } else {
141
+ const pf = [];
142
+ if (cfg.prefetch.prefetchAll !== void 0) pf.push(` prefetchAll: ${cfg.prefetch.prefetchAll},`);
143
+ if (cfg.prefetch.defaultStrategy) pf.push(` defaultStrategy: '${cfg.prefetch.defaultStrategy}',`);
144
+ parts.push(` prefetch: {
145
+ ${pf.join("\n")}
146
+ },`);
147
+ }
148
+ }
149
+ if (cfg.devToolbar) {
150
+ parts.push(` devToolbar: { enabled: ${cfg.devToolbar.enabled ?? true} },`);
151
+ }
152
+ if (cfg.vitePlugins?.length) {
153
+ cfg.vitePlugins.forEach((p) => imports.push(`import ${p.name} from '${p.package}';`));
154
+ const pluginCalls = cfg.vitePlugins.map((p) => {
155
+ const opts = p.options && Object.keys(p.options).length ? JSON.stringify(p.options) : "";
156
+ return ` ${p.name}(${opts})`;
157
+ }).join(",\n");
158
+ parts.push(` vite: {
159
+ plugins: [
160
+ ${pluginCalls},
161
+ ],
162
+ },`);
163
+ }
164
+ if (cfg.server) {
165
+ const srv = [];
166
+ if (cfg.server.port) srv.push(` port: ${cfg.server.port},`);
167
+ if (cfg.server.host) srv.push(` host: '${cfg.server.host}',`);
168
+ if (srv.length) parts.push(` server: {
169
+ ${srv.join("\n")}
170
+ },`);
171
+ }
172
+ const body = parts.length > 0 ? "\n" + parts.join("\n") + "\n" : "";
173
+ return `${imports.join("\n")}
174
+
175
+ export default defineConfig({${body}});
176
+ `;
177
+ }
178
+ function validateConfig(cfg) {
179
+ const errors = [];
180
+ if ((cfg.output === "server" || cfg.output === "hybrid") && !cfg.adapter) {
181
+ errors.push(`output: "${cfg.output}" requires an adapter \u2014 run: astro-config set-adapter <name>`);
182
+ }
183
+ if (cfg.i18n) {
184
+ if (!cfg.i18n.defaultLocale) errors.push("i18n.defaultLocale is required");
185
+ if (!cfg.i18n.locales?.length) errors.push("i18n.locales must have at least one entry");
186
+ if (cfg.i18n.locales && cfg.i18n.defaultLocale && !cfg.i18n.locales.includes(cfg.i18n.defaultLocale)) {
187
+ errors.push("i18n.defaultLocale must appear in i18n.locales");
188
+ }
189
+ }
190
+ if (cfg.image?.quality !== void 0 && (cfg.image.quality < 1 || cfg.image.quality > 100)) {
191
+ errors.push("image.quality must be between 1 and 100");
192
+ }
193
+ return errors;
194
+ }
195
+ var program = new Command();
196
+ program.name("astro-config").description(chalk.cyan("Astro Config CLI") + " \u2014 Generate and manage astro.config.mjs").version("1.0.0");
197
+ program.command("init").description("Initialize a new Astro config (creates astro-cli.json)").option("--output <mode>", "Output mode: static | server | hybrid", "static").option("--site <url>", "Canonical site URL, e.g. https://example.com").option("--base <path>", "Base path, e.g. /app").option("--src <dir>", "Source directory", "./src").option("--out <dir>", "Build output directory", "./dist").option("--port <port>", "Dev server port", "4321").option("--host <host>", "Dev server host (true = expose to LAN)").action((opts) => {
198
+ const cfg = {
199
+ output: opts.output,
200
+ srcDir: opts.src,
201
+ outDir: opts.out,
202
+ server: { port: parseInt(opts.port, 10) }
203
+ };
204
+ if (opts.host) cfg.server.host = opts.host;
205
+ if (opts.site) cfg.site = opts.site;
206
+ if (opts.base) cfg.base = opts.base;
207
+ saveConfig(cfg);
208
+ console.log(chalk.green("\u2714") + " Initialized \u2014 output mode: " + chalk.yellow(opts.output));
209
+ console.log(chalk.dim(" Run `astro-config export` to generate astro.config.mjs"));
210
+ });
211
+ program.command("set-output <mode>").description("Set output mode: static | server | hybrid").action((mode) => {
212
+ const valid = ["static", "server", "hybrid"];
213
+ if (!valid.includes(mode)) {
214
+ console.error(chalk.red("Error: mode must be one of: " + valid.join(", ")));
215
+ process.exit(1);
216
+ }
217
+ const cfg = loadConfig();
218
+ cfg.output = mode;
219
+ if (mode !== "static" && !cfg.adapter) {
220
+ console.log(chalk.yellow("\u26A0") + ' output="' + mode + '" needs an adapter \u2014 run: astro-config set-adapter <name>');
221
+ }
222
+ saveConfig(cfg);
223
+ console.log(chalk.green("\u2714") + " Output set to: " + chalk.yellow(mode));
224
+ });
225
+ var validIntegrations = ["react", "vue", "svelte", "tailwind", "mdx", "sitemap", "partytown"];
226
+ program.command("add-integration <name>").description("Add an integration: " + validIntegrations.join(" | ")).action((name) => {
227
+ if (!validIntegrations.includes(name)) {
228
+ console.error(chalk.red('Error: unknown integration "' + name + '"'));
229
+ console.log(" Available: " + validIntegrations.join(", "));
230
+ process.exit(1);
231
+ }
232
+ const cfg = loadConfig();
233
+ cfg.integrations = cfg.integrations ?? [];
234
+ if (cfg.integrations.includes(name)) {
235
+ console.log(chalk.yellow("\u26A0") + " " + name + " is already in integrations");
236
+ return;
237
+ }
238
+ cfg.integrations.push(name);
239
+ saveConfig(cfg);
240
+ console.log(chalk.green("\u2714") + " Added: " + chalk.cyan(name));
241
+ console.log(chalk.dim(" npm install @astrojs/" + name));
242
+ });
243
+ var validAdapters = ["node", "vercel", "netlify", "cloudflare", "deno"];
244
+ program.command("set-adapter <name>").description("Set SSR adapter: " + validAdapters.join(" | ")).option("--mode <mode>", "node adapter mode: standalone | middleware", "standalone").option("--region <region>", "Deploy region (vercel / netlify / cloudflare)").option("--runtime <runtime>", "Cloudflare runtime: advanced | directory").action((name, opts) => {
245
+ if (!validAdapters.includes(name)) {
246
+ console.error(chalk.red('Error: unknown adapter "' + name + '"'));
247
+ console.log(" Available: " + validAdapters.join(", "));
248
+ process.exit(1);
249
+ }
250
+ const cfg = loadConfig();
251
+ cfg.adapter = name;
252
+ cfg.adapterOptions = {};
253
+ if (name === "node") cfg.adapterOptions["mode"] = opts.mode;
254
+ if (name === "cloudflare" && opts.runtime) cfg.adapterOptions["runtime"] = opts.runtime;
255
+ if ((name === "vercel" || name === "netlify") && opts.region) {
256
+ cfg.adapterOptions["region"] = opts.region;
257
+ }
258
+ if (!cfg.output || cfg.output === "static") {
259
+ cfg.output = "server";
260
+ console.log(chalk.yellow("\u26A0") + ' Auto-set output \u2192 "server"');
261
+ }
262
+ saveConfig(cfg);
263
+ console.log(chalk.green("\u2714") + " Adapter: " + chalk.cyan(name));
264
+ console.log(chalk.dim(" npm install @astrojs/" + name));
265
+ });
266
+ program.command("set-image").description("Configure image optimization").option("--service <svc>", "sharp | squoosh | noop", "sharp").option("--domains <list>", "Comma-separated allowed remote domains").option("--patterns <list>", "Comma-separated remote hostname patterns").option("--format <fmt>", "Default output format: webp | avif | png | jpg").option("--quality <n>", "Default quality 1\u2013100", "80").action((opts) => {
267
+ const cfg = loadConfig();
268
+ cfg.image = {
269
+ service: opts.service,
270
+ quality: parseInt(opts.quality, 10)
271
+ };
272
+ if (opts.domains) cfg.image.domains = opts.domains.split(",").map((d) => d.trim());
273
+ if (opts.patterns) cfg.image.remotePatterns = opts.patterns.split(",").map((p) => p.trim());
274
+ if (opts.format) cfg.image.format = opts.format;
275
+ saveConfig(cfg);
276
+ console.log(chalk.green("\u2714") + " Image: service=" + chalk.cyan(opts.service) + ", quality=" + opts.quality);
277
+ });
278
+ program.command("set-i18n").description("Configure internationalization routing").requiredOption("--default <locale>", "Default locale, e.g. en").requiredOption("--locales <list>", "Comma-separated locales, e.g. en,fr,de").option("--routing <mode>", "prefix-always | prefix-other-locales", "prefix-other-locales").option("--fallback <json>", `Fallback map JSON, e.g. '{"fr":"en"}'`).action((opts) => {
279
+ const locales = opts.locales.split(",").map((l) => l.trim());
280
+ if (!locales.includes(opts.default)) {
281
+ console.error(chalk.red("Error: --default locale must be listed in --locales"));
282
+ process.exit(1);
283
+ }
284
+ const cfg = loadConfig();
285
+ cfg.i18n = {
286
+ defaultLocale: opts.default,
287
+ locales,
288
+ routing: opts.routing
289
+ };
290
+ if (opts.fallback) {
291
+ try {
292
+ cfg.i18n.fallback = JSON.parse(opts.fallback);
293
+ } catch {
294
+ console.error(chalk.red("Error: --fallback must be valid JSON"));
295
+ process.exit(1);
296
+ }
297
+ }
298
+ saveConfig(cfg);
299
+ console.log(chalk.green("\u2714") + " i18n: " + chalk.cyan(opts.default) + " \u2192 [" + locales.join(", ") + "]");
300
+ });
301
+ program.command("set-markdown").description("Configure Markdown / MDX processing").option("--highlight <engine>", "shiki | prism | false", "shiki").option("--theme <theme>", "Shiki theme name", "github-dark").option("--wrap", "Enable shiki code-block word wrap").option("--no-gfm", "Disable GitHub Flavored Markdown").option("--no-smartypants", "Disable Smartypants typographic transforms").option("--remark <plugins>", "Comma-separated remark plugin package names").option("--rehype <plugins>", "Comma-separated rehype plugin package names").action((opts) => {
302
+ const cfg = loadConfig();
303
+ const hl = opts.highlight === "false" ? false : opts.highlight;
304
+ cfg.markdown = {
305
+ syntaxHighlight: hl,
306
+ gfm: opts.gfm !== false,
307
+ smartypants: opts.smartypants !== false
308
+ };
309
+ if (hl === "shiki") {
310
+ cfg.markdown.shikiConfig = { theme: opts.theme, wrap: !!opts.wrap };
311
+ }
312
+ if (opts.remark) cfg.markdown.remarkPlugins = opts.remark.split(",").map((r) => r.trim());
313
+ if (opts.rehype) cfg.markdown.rehypePlugins = opts.rehype.split(",").map((r) => r.trim());
314
+ saveConfig(cfg);
315
+ console.log(chalk.green("\u2714") + " Markdown: highlight=" + (hl === false ? "false" : chalk.cyan(String(hl))));
316
+ });
317
+ program.command("set-prefetch").description("Configure link prefetch behavior").option("--all", "Prefetch all links on the page").option("--strategy <s>", "hover | tap | viewport | load", "hover").action((opts) => {
318
+ const cfg = loadConfig();
319
+ cfg.prefetch = opts.all ? { prefetchAll: true, defaultStrategy: opts.strategy } : { defaultStrategy: opts.strategy };
320
+ saveConfig(cfg);
321
+ console.log(chalk.green("\u2714") + " Prefetch: " + (opts.all ? "all links, " : "") + "strategy=" + opts.strategy);
322
+ });
323
+ program.command("set-toolbar").description("Enable or disable the Astro dev toolbar").option("--disable", "Disable the toolbar (enabled by default)").action((opts) => {
324
+ const cfg = loadConfig();
325
+ cfg.devToolbar = { enabled: !opts.disable };
326
+ saveConfig(cfg);
327
+ console.log(chalk.green("\u2714") + " Dev toolbar: " + (cfg.devToolbar.enabled ? chalk.green("enabled") : chalk.red("disabled")));
328
+ });
329
+ program.command("validate").description("Validate the current config for errors and show a summary").action(() => {
330
+ const cfg = loadConfig();
331
+ const errors = validateConfig(cfg);
332
+ if (errors.length === 0) {
333
+ console.log(chalk.green("\u2714") + " Config is valid\n");
334
+ console.log(" Output: " + chalk.yellow(cfg.output ?? "static"));
335
+ if (cfg.adapter) console.log(" Adapter: " + chalk.cyan(cfg.adapter));
336
+ if (cfg.integrations?.length) console.log(" Integrations: " + cfg.integrations.join(", "));
337
+ if (cfg.i18n) console.log(" i18n: " + cfg.i18n.defaultLocale + " / [" + cfg.i18n.locales.join(", ") + "]");
338
+ if (cfg.image?.service) console.log(" Image: " + cfg.image.service);
339
+ if (cfg.markdown?.syntaxHighlight) console.log(" Markdown: " + cfg.markdown.syntaxHighlight);
340
+ } else {
341
+ console.log(chalk.red("\u2716") + " " + errors.length + " validation error(s):\n");
342
+ errors.forEach((e) => console.log(" " + chalk.red("\u2022") + " " + e));
343
+ process.exit(1);
344
+ }
345
+ });
346
+ program.command("export").description("Generate astro.config.mjs from the current CLI config").option("--out <file>", "Output file path", "astro.config.mjs").option("--dry-run", "Print to stdout without writing").action((opts) => {
347
+ const cfg = loadConfig();
348
+ const errors = validateConfig(cfg);
349
+ if (errors.length > 0) {
350
+ console.log(chalk.red("\u2716") + " Export blocked \u2014 fix errors first:\n");
351
+ errors.forEach((e) => console.log(" " + chalk.red("\u2022") + " " + e));
352
+ process.exit(1);
353
+ }
354
+ const content = generateAstroConfig(cfg);
355
+ if (opts.dryRun) {
356
+ console.log(chalk.dim("\u2500\u2500\u2500 " + opts.out + " \u2500\u2500\u2500"));
357
+ console.log(content);
358
+ } else {
359
+ fs.writeFileSync(opts.out, content, "utf-8");
360
+ console.log(chalk.green("\u2714") + " Written \u2192 " + chalk.cyan(opts.out));
361
+ console.log(chalk.dim("\n" + content));
362
+ }
363
+ });
364
+ program.command("show").description("Show the raw astro-cli.json state").action(() => {
365
+ const cfg = loadConfig();
366
+ console.log(chalk.bold("\nCurrent config (" + CONFIG_FILE + "):"));
367
+ console.log(chalk.dim(JSON.stringify(cfg, null, 2)));
368
+ });
369
+ if (process.argv.length < 3) {
370
+ program.help();
371
+ }
372
+ program.parse(process.argv);
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "astro-config-cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool for generating and managing Astro framework configuration files",
5
+ "type": "module",
6
+ "bin": {
7
+ "astro-config": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "node node_modules/tsup/dist/cli-default.js",
14
+ "dev": "node node_modules/tsup/dist/cli-default.js --watch",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "astro",
19
+ "cli",
20
+ "config",
21
+ "generator",
22
+ "framework"
23
+ ],
24
+ "author": "",
25
+ "license": "MIT",
26
+ "dependencies": {
27
+ "chalk": "^5.3.0",
28
+ "commander": "^12.1.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^20.14.0",
32
+ "tsup": "^8.1.0",
33
+ "typescript": "^5.4.5"
34
+ },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/okirmio-create/cli-forge.git",
38
+ "directory": "astro-config-cli"
39
+ },
40
+ "homepage": "https://github.com/okirmio-create/cli-forge/tree/main/astro-config-cli",
41
+ "bugs": {
42
+ "url": "https://github.com/okirmio-create/cli-forge/issues"
43
+ }
44
+ }