create-vextro 0.1.1 → 0.1.3

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 CHANGED
@@ -1,136 +1,146 @@
1
1
  # create-vextro
2
2
 
3
- [![CI](https://github.com/lasalasa/vextro/actions/workflows/ci.yml/badge.svg)](https://github.com/lasalasa/vextro/actions/workflows/ci.yml)
3
+ [![CI](https://github.com/CodeCanvasCollective/vextro/actions/workflows/ci.yml/badge.svg)](https://github.com/CodeCanvasCollective/vextro/actions/workflows/ci.yml)
4
4
  [![npm version](https://img.shields.io/npm/v/create-vextro?color=blue&style=flat-square)](https://www.npmjs.com/package/create-vextro)
5
5
  [![npm downloads](https://img.shields.io/npm/dt/create-vextro?style=flat-square)](https://www.npmjs.com/package/create-vextro)
6
- [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg?style=flat-square)](https://github.com/lasalasa/vextro/blob/main/LICENSE)
7
- [![GitHub stars](https://img.shields.io/github/stars/lasalasa/vextro?style=flat-square)](https://github.com/lasalasa/vextro/stargazers)
8
- [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square)](https://github.com/lasalasa/vextro/pulls)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg?style=flat-square)](https://github.com/CodeCanvasCollective/vextro/blob/main/LICENSE)
7
+ [![GitHub stars](https://img.shields.io/github/stars/CodeCanvasCollective/vextro?style=flat-square)](https://github.com/CodeCanvasCollective/vextro/stargazers)
8
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square)](https://github.com/CodeCanvasCollective/vextro/pulls)
9
9
 
10
- > Scaffold modern browser extensions for Chrome, Edge, and Firefox — powered by Vite + React + Tailwind.
10
+ > CLI for scaffolding modern browser extensions with Vite, React, and Tailwind CSS.
11
11
 
12
- **Vextro** is a CLI tool for building fast, modern browser extensions using:
12
+ **Vextro** creates a browser extension project on top of Vite's React + TypeScript template. It adds popup and options UIs, background and content scripts, storage helpers, icons, and browser-specific extension configuration for Chrome/Edge or Firefox.
13
13
 
14
- - ⚡ [Vite](https://vitejs.dev/)
15
- - ⚛️ [React + TypeScript](https://reactjs.org/)
16
- - 🎨 [Tailwind CSS](https://tailwindcss.com/)
17
- - 🧩 [Manifest V3](https://developer.chrome.com/docs/extensions/mv3/intro/)
18
- - 🔌 [CRXJS](https://crxjs.dev/) (Chrome/Edge) or [vite-plugin-web-extension](https://github.com/nicedoc/vite-plugin-web-extension) (Firefox)
14
+ ## Features
19
15
 
20
- ---
16
+ - Fast Vite-based development workflow for popup and options pages.
17
+ - React, TypeScript, and Tailwind CSS preconfigured out of the box.
18
+ - Browser-specific extension setup:
19
+ Chrome and Edge use CRXJS with a typed `src/manifest.ts`.
20
+ Firefox uses `vite-plugin-web-extension` with `src/manifest.json`.
21
+ - Starter boilerplate for popup, options, background, content, and storage utilities.
21
22
 
22
- ## 🌐 Browser Support
23
+ ## Prerequisites
23
24
 
24
- | Browser | Status | Flag | Notes |
25
- | ----------- | ------------------ | ----------- | ----------------------------------------------------------------- |
26
- | **Chrome** | Fully supported | `--chrome` | Uses CRXJS Vite Plugin |
27
- | **Edge** | Fully supported | `--chrome` | Chromium-based same as Chrome, load from `edge://extensions` |
28
- | **Firefox** | ✅ Fully supported | `--firefox` | Uses vite-plugin-web-extension + `chrome.*` namespace |
29
- | **Safari** | 📄 Documented | — | Convert Chrome output with `xcrun safari-web-extension-converter` |
25
+ - Node.js 20 or newer
26
+ - npm
27
+ - Chrome, Edge, or Firefox for local extension testing
28
+ - macOS with Xcode only if you plan to convert a Chrome build for Safari
30
29
 
31
- ---
30
+ ## Browser Support
32
31
 
33
- ## 🚀 Quick Start
32
+ | Browser | Status | Flag | Notes |
33
+ | ----------- | ----------------- | ----------- | ----------------------------------------------------------------- |
34
+ | **Chrome** | Template included | `--chrome` | Uses CRXJS and typed `src/manifest.ts` |
35
+ | **Edge** | Template included | `--chrome` | Same Chromium template as Chrome |
36
+ | **Firefox** | Template included | `--firefox` | Uses `vite-plugin-web-extension` and `src/manifest.json` |
37
+ | **Safari** | Manual conversion | n/a | Convert Chrome output with `xcrun safari-web-extension-converter` |
34
38
 
35
- ```bash
36
- # Interactive (prompts for browser)
37
- npx create-vextro create my-extension
39
+ ## Quick Start
40
+
41
+ You can scaffold a new project with `npm create`. No global install is required.
38
42
 
39
- # Chrome / Edge (skip prompt)
40
- npx create-vextro create my-extension --chrome
43
+ ```bash
44
+ # Provide a project name and choose the browser interactively
45
+ npm create vextro@latest my-extension
41
46
 
42
- # Firefox (skip prompt)
43
- npx create-vextro create my-extension --firefox
47
+ # Or skip the browser prompt
48
+ npm create vextro@latest my-extension -- --chrome
49
+ npm create vextro@latest my-extension -- --firefox
44
50
  ```
45
51
 
46
- Then:
52
+ `npm create` automatically inserts `--` before package-specific flags. You can also run the package directly with `npx`, for example `npx create-vextro@latest create my-extension --chrome`.
53
+
54
+ Vextro scaffolds the project and installs dependencies for you. Then start the dev workflow:
47
55
 
48
56
  ```bash
49
57
  cd my-extension
50
58
  npm run dev
51
59
  ```
52
60
 
53
- ### Loading your extension
54
-
55
- **Chrome / Edge:**
61
+ ### Load the Extension During Development
56
62
 
57
- 1. Open `chrome://extensions` (or `edge://extensions`)
58
- 2. Enable **Developer mode**
59
- 3. Click **"Load unpacked"** → select the `dist/` folder
63
+ **Chrome / Edge**
60
64
 
61
- **Firefox:**
65
+ 1. Open `chrome://extensions` or `edge://extensions`.
66
+ 2. Enable **Developer mode**.
67
+ 3. Click **Load unpacked** and select the generated `dist/` folder.
62
68
 
63
- 1. Open `about:debugging#/runtime/this-firefox`
64
- 2. Click **"Load Temporary Add-on"**
65
- 3. Select any file in the `dist/` folder
69
+ **Firefox**
66
70
 
67
- **Safari (macOS only):**
71
+ 1. Open `about:debugging#/runtime/this-firefox`.
72
+ 2. Click **Load Temporary Add-on**.
73
+ 3. Select any file inside the generated `dist/` folder.
68
74
 
69
- 1. Build a Chrome extension first using `--chrome`
70
- 2. Run `xcrun safari-web-extension-converter dist/` to create an Xcode project
71
- 3. Build and run from Xcode
75
+ **Safari (macOS only)**
72
76
 
73
- ---
77
+ 1. Scaffold a Chrome project with `--chrome`.
78
+ 2. Run `xcrun safari-web-extension-converter dist/`.
79
+ 3. Build and run the generated Xcode project.
74
80
 
75
- ## 📋 Commands
81
+ ## CLI Commands
76
82
 
77
83
  ```bash
78
- create-vextro create <name> # Interactive (prompts for browser)
79
- create-vextro create <name> --chrome # Chrome / Edge
80
- create-vextro create <name> --firefox # Firefox
81
- create-vextro create <name> --force # Overwrite existing directory
82
- create-vextro --version # Show version
83
- create-vextro --help # Show help
84
- create-vextro --verbose # Enable verbose output
84
+ # Interactive setup
85
+ npx create-vextro@latest create <project-name>
86
+
87
+ # Target a specific browser
88
+ npx create-vextro@latest create <project-name> --chrome
89
+ npx create-vextro@latest create <project-name> --firefox
90
+
91
+ # Overwrite an existing directory
92
+ npx create-vextro@latest create <project-name> --chrome --force
93
+
94
+ # Global flags
95
+ npx create-vextro@latest --help
96
+ npx create-vextro@latest --version
97
+ npx create-vextro@latest --verbose create <project-name> --chrome
85
98
  ```
86
99
 
87
- ---
100
+ `--verbose` is a global flag, so place it before the explicit `create` command.
88
101
 
89
- ## What You Get
102
+ ## What You Get
90
103
 
91
104
  Every generated project includes:
92
105
 
93
- | Feature | Description |
94
- | ------------------ | ------------------------------------------------------ |
95
- | **Popup** | React popup with `chrome.storage` demo |
96
- | **Options page** | Settings page with save/load via storage sync |
97
- | **Background** | Service worker with `onInstalled` and message listener |
98
- | **Content script** | Injected script with background messaging example |
99
- | **Storage utils** | Typed wrapper around browser storage API |
100
- | **Hot Reload** | Vite HMR for popup and options pages |
101
- | **TypeScript** | Full type safety |
102
- | **Tailwind CSS** | Utility-first styling pre-configured |
106
+ | Feature | Description |
107
+ | ------------------ | --------------------------------------------------------------------------------------- |
108
+ | **Popup** | React popup with a `chrome.storage` demo |
109
+ | **Options page** | Settings page with save and load via storage sync |
110
+ | **Background** | Chrome template uses a service worker; Firefox template uses a module background script |
111
+ | **Content script** | Injected script with background messaging example |
112
+ | **Storage utils** | Typed wrapper around `chrome.storage.sync` |
113
+ | **Manifest setup** | Chrome gets `src/manifest.ts`; Firefox gets `src/manifest.json` |
114
+ | **TypeScript** | Type-safe React and extension code |
115
+ | **Tailwind CSS** | Utility-first styling preconfigured |
103
116
 
104
- ---
117
+ ## What's Included
105
118
 
106
- ## 📁 Generated Project Structure
119
+ Each generated project follows this structure. The manifest file differs by browser target.
107
120
 
108
- ```
121
+ ```text
109
122
  my-extension/
110
- ├── public/
111
- ├── icon.png
112
- └── icons/ # Extension icons (16, 48, 128)
113
- ├── src/
114
- ├── background/ # Background service worker / script
115
- ├── content/ # Content scripts
116
- ├── options/ # Options page (React + Tailwind)
117
- ├── popup/ # Popup UI (React + Tailwind)
118
- ├── utils/ # Storage utilities
119
- ├── manifest.ts/.json # Manifest config (format depends on browser)
120
- └── styles.css # Tailwind CSS entrypoint
121
- ├── vite.config.ts # Vite + browser plugin config
122
- ├── tsconfig.json
123
- └── package.json
123
+ |-- public/
124
+ | |-- icon.png
125
+ | `-- icons/
126
+ |-- src/
127
+ | |-- background/
128
+ | |-- content/
129
+ | |-- options/
130
+ | |-- popup/
131
+ | |-- utils/
132
+ | |-- styles.css
133
+ | `-- manifest.ts or manifest.json
134
+ |-- vite.config.ts
135
+ |-- tsconfig.app.json
136
+ |-- tsconfig.json
137
+ `-- package.json
124
138
  ```
125
139
 
126
- ---
127
-
128
- ## 🤝 Contributing
129
-
130
- See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for development setup and contribution guidelines.
140
+ ## Contributing
131
141
 
132
- ---
142
+ We welcome contributions. See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for development setup and contribution guidelines.
133
143
 
134
- ## 📄 License
144
+ ## License
135
145
 
136
- MIT © [Lasantha Lakmal](https://github.com/lasalasa)
146
+ MIT © [CodeCanvas Collective](https://github.com/CodeCanvasCollective)
package/dist/index.js CHANGED
@@ -172,7 +172,7 @@ var ExtensionGenerator = class {
172
172
  const s = spinner("Creating base Vite + React + TS project...");
173
173
  s.start();
174
174
  try {
175
- execSync(`npm create vite@latest ${this.config.name} -- --template react-ts`, {
175
+ execSync(`npm exec --yes -- create-vite@latest ${this.config.name} --template react-ts`, {
176
176
  cwd: path2.dirname(this.config.targetDir),
177
177
  stdio: "pipe",
178
178
  maxBuffer: 10 * 1024 * 1024
@@ -424,7 +424,7 @@ async function handleCreate(projectName, options) {
424
424
  // package.json
425
425
  var package_default = {
426
426
  name: "create-vextro",
427
- version: "0.1.1",
427
+ version: "0.1.3",
428
428
  description: "Scaffold modern browser extensions (Chrome, Edge, Firefox) with Vite + React + Tailwind",
429
429
  type: "module",
430
430
  bin: {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/commands/create.ts","../src/prompts/index.ts","../src/constants.ts","../src/utils/logger.ts","../src/utils/file.ts","../src/utils/validator.ts","../src/generators/extension.ts","../package.json","../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createCommand } from './commands/create.js';\nimport { setVerbose } from './utils/logger.js';\nimport pkg from '../package.json' with { type: 'json' };\n\nconst CLI_VERSION = pkg.version || '0.1.0';\n\nexport function createCli(): Command {\n const program = new Command();\n\n program\n .name('create-vextro')\n .description('Scaffold modern browser extensions with Vite + React + Tailwind')\n .version(CLI_VERSION)\n .option('--verbose', 'Enable verbose output')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts();\n if (opts.verbose) {\n setVerbose(true);\n }\n });\n\n program.addCommand(createCommand(), { isDefault: true });\n\n return program;\n}\n","import { Command } from 'commander';\nimport path from 'node:path';\nimport fs from 'fs-extra';\nimport { promptProjectName, promptBrowser } from '../prompts/index.js';\nimport { ExtensionGenerator } from '../generators/extension.js';\nimport {\n validateProjectName,\n validateDirectory,\n error,\n success,\n newLine,\n banner,\n} from '../utils/index.js';\nimport { BROWSERS } from '../constants.js';\nimport type { CreateOptions, ProjectConfig, BrowserTarget } from '../types/index.js';\n\nexport function createCommand(): Command {\n const cmd = new Command('create')\n .description('Create a new browser extension project')\n .argument('[project-name]', 'Name of the extension project')\n .option('--chrome', 'Target Chrome / Edge (default)')\n .option('--firefox', 'Target Firefox')\n .option('--force', 'Overwrite existing directory')\n .action(async (projectName: string | undefined, options: CreateOptions) => {\n try {\n await handleCreate(projectName, options);\n } catch (err) {\n error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\nfunction resolveBrowserFromFlags(options: CreateOptions): BrowserTarget | null {\n if (options.chrome) return 'chrome';\n if (options.firefox) return 'firefox';\n return null;\n}\n\nasync function handleCreate(\n projectName: string | undefined,\n options: CreateOptions,\n): Promise<void> {\n // If no project name given as arg, prompt for it\n if (!projectName) {\n projectName = await promptProjectName();\n }\n\n // Validate the project name\n const nameValidation = validateProjectName(projectName);\n if (nameValidation !== true) {\n throw new Error(nameValidation);\n }\n\n // Resolve browser target\n let browser = resolveBrowserFromFlags(options);\n if (!browser) {\n browser = await promptBrowser();\n }\n\n const targetDir = path.resolve(process.cwd(), projectName);\n\n // Check if directory already exists\n if (!options.force) {\n const dirValidation = await validateDirectory(targetDir);\n if (dirValidation !== true) {\n throw new Error(dirValidation);\n }\n } else if (await fs.pathExists(targetDir)) {\n await fs.remove(targetDir);\n }\n\n const config: ProjectConfig = {\n name: projectName,\n targetDir,\n browser,\n };\n\n const browserMeta = BROWSERS[browser];\n\n newLine();\n banner(`🚀 Creating Vextro Extension for ${browserMeta.displayName} — \"${config.name}\"...`);\n newLine();\n\n // Handle SIGINT — clean up partial directory\n const cleanup = async () => {\n newLine();\n error('Interrupted! Cleaning up...');\n try {\n if (await fs.pathExists(targetDir)) {\n await fs.remove(targetDir);\n }\n } catch {\n // best-effort cleanup\n }\n process.exit(1);\n };\n process.on('SIGINT', cleanup);\n\n const generator = new ExtensionGenerator(config);\n await generator.generate();\n\n // Remove SIGINT handler after success\n process.removeListener('SIGINT', cleanup);\n\n newLine();\n success(\n `Vextro project \"${config.name}\" created successfully for ${browserMeta.displayName}! 🎉`,\n );\n newLine();\n console.log('Next steps:');\n console.log(` cd ${config.name}`);\n console.log(' npm run dev');\n newLine();\n\n if (browser === 'chrome') {\n console.log('Load extension:');\n console.log(' 1. Open chrome://extensions (or edge://extensions)');\n console.log(' 2. Enable \"Developer mode\"');\n console.log(' 3. Click \"Load unpacked\" → select the dist/ folder');\n } else if (browser === 'firefox') {\n console.log('Load extension:');\n console.log(' 1. Open about:debugging#/runtime/this-firefox');\n console.log(' 2. Click \"Load Temporary Add-on\"');\n console.log(' 3. Select any file in the dist/ folder');\n }\n\n newLine();\n console.log('Happy coding! 🚀');\n newLine();\n}\n","import inquirer from 'inquirer';\nimport { DEFAULT_PROJECT_NAME, BROWSERS } from '../constants.js';\nimport { validateProjectName } from '../utils/index.js';\nimport type { BrowserTarget } from '../types/index.js';\n\nexport async function promptProjectName(): Promise<string> {\n const { projectName } = await inquirer.prompt([\n {\n name: 'projectName',\n message: 'Enter your extension project name:',\n default: DEFAULT_PROJECT_NAME,\n validate: (input: string) => {\n const result = validateProjectName(input);\n return result === true ? true : result;\n },\n },\n ]);\n return projectName;\n}\n\nexport async function promptBrowser(): Promise<BrowserTarget> {\n const { browser } = await inquirer.prompt([\n {\n type: 'list',\n name: 'browser',\n message: 'Select target browser:',\n choices: Object.entries(BROWSERS).map(([value, meta]) => ({\n name: `${meta.displayName} — ${meta.description}`,\n value,\n })),\n default: 'chrome',\n },\n ]);\n return browser;\n}\n","import type { BrowserTarget } from './types/index.js';\n\nexport const PACKAGE_NAME = 'create-vextro';\nexport const BRAND_NAME = 'Vextro';\n\nexport const VALID_PROJECT_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/;\n\nexport const DEFAULT_PROJECT_NAME = 'my-extension';\nexport const DEFAULT_BROWSER: BrowserTarget = 'chrome';\n\nexport const FILES_TO_REMOVE = [\n 'src/App.tsx',\n 'src/main.tsx',\n 'src/index.css',\n 'src/App.css',\n 'src/assets',\n 'index.html',\n];\n\nexport const BROWSERS: Record<BrowserTarget, { displayName: string; description: string }> = {\n chrome: {\n displayName: 'Chrome / Edge',\n description: 'Google Chrome & Microsoft Edge (Chromium-based, uses CRXJS)',\n },\n firefox: {\n displayName: 'Firefox',\n description: 'Mozilla Firefox (uses vite-plugin-web-extension)',\n },\n};\n\nexport const CHROME_DEV_DEPS = [\n '@types/chrome',\n '@types/node',\n '@crxjs/vite-plugin',\n 'tailwindcss',\n '@tailwindcss/vite',\n];\n\nexport const FIREFOX_DEV_DEPS = [\n '@types/chrome',\n '@types/node',\n 'vite-plugin-web-extension',\n 'tailwindcss',\n '@tailwindcss/vite',\n];\n","import chalk from 'chalk';\nimport ora, { type Ora } from 'ora';\n\nlet verbose = false;\n\nexport function setVerbose(value: boolean): void {\n verbose = value;\n}\n\nexport function info(message: string): void {\n console.log(chalk.blue('ℹ'), message);\n}\n\nexport function success(message: string): void {\n console.log(chalk.green('✔'), message);\n}\n\nexport function warn(message: string): void {\n console.log(chalk.yellow('⚠'), message);\n}\n\nexport function error(message: string): void {\n console.log(chalk.red('✖'), message);\n}\n\nexport function debug(message: string): void {\n if (verbose) {\n console.log(chalk.gray('⬥'), chalk.gray(message));\n }\n}\n\nexport function spinner(text: string): Ora {\n return ora({ text, color: 'cyan' });\n}\n\nexport function newLine(): void {\n console.log();\n}\n\nexport function banner(text: string): void {\n console.log(chalk.bold.cyan(text));\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport { fileURLToPath } from 'node:url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport function getTemplatesDir(): string {\n // When bundled with tsup, __dirname is dist/ → go up 1 level to project root\n // When running unbundled (vitest), __dirname is src/utils/ → go up 2 levels to project root\n const isBundled =\n __dirname.replace(/\\\\/g, '/').endsWith('/dist') ||\n __dirname.replace(/\\\\/g, '/').includes('/dist/');\n const projectRoot = isBundled\n ? path.resolve(__dirname, '..')\n : path.resolve(__dirname, '..', '..');\n return path.resolve(projectRoot, 'src', 'templates');\n}\n\nexport async function createDir(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\nexport async function directoryExists(dirPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirPath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(filePath);\n return stat.isFile();\n } catch {\n return false;\n }\n}\n","import { VALID_PROJECT_NAME } from '../constants.js';\nimport { directoryExists } from './file.js';\n\nexport function validateProjectName(name: string): string | true {\n if (!name || name.trim().length === 0) {\n return 'Project name is required.';\n }\n\n if (!VALID_PROJECT_NAME.test(name)) {\n return 'Project name must be a valid npm package name (lowercase, no spaces, can use hyphens and dots).';\n }\n\n if (name.length > 214) {\n return 'Project name must be less than 214 characters.';\n }\n\n return true;\n}\n\nexport async function validateDirectory(dirPath: string): Promise<string | true> {\n if (await directoryExists(dirPath)) {\n return `Directory \"${dirPath}\" already exists. Use --force to overwrite.`;\n }\n return true;\n}\n\nexport function checkNodeVersion(minMajor: number = 20): string | true {\n const version = process.version;\n const major = parseInt(version.slice(1).split('.')[0], 10);\n\n if (major < minMajor) {\n return `Node.js ${minMajor}+ is required. You are using ${version}.`;\n }\n\n return true;\n}\n","import path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport fs from 'fs-extra';\nimport { getTemplatesDir, spinner, success, debug } from '../utils/index.js';\nimport { FILES_TO_REMOVE, CHROME_DEV_DEPS, FIREFOX_DEV_DEPS } from '../constants.js';\nimport type { ProjectConfig } from '../types/index.js';\n\nexport class ExtensionGenerator {\n private config: ProjectConfig;\n private templatesDir: string;\n\n constructor(config: ProjectConfig) {\n this.config = config;\n this.templatesDir = getTemplatesDir();\n }\n\n async generate(): Promise<void> {\n await this.scaffoldVite();\n await this.installBaseDeps();\n await this.cleanViteDefaults();\n await this.copySharedFiles();\n await this.copyBrowserFiles();\n await this.overrideConfigs();\n await this.patchTsConfig();\n await this.injectProjectName();\n await this.installExtensionDeps();\n }\n\n private async scaffoldVite(): Promise<void> {\n const s = spinner('Creating base Vite + React + TS project...');\n s.start();\n try {\n execSync(`npm create vite@latest ${this.config.name} -- --template react-ts`, {\n cwd: path.dirname(this.config.targetDir),\n stdio: 'pipe',\n maxBuffer: 10 * 1024 * 1024,\n });\n s.stop();\n success('Created base Vite + React + TS project');\n } catch (err) {\n s.stop();\n throw new Error(\n `Failed to scaffold Vite project: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n private async installBaseDeps(): Promise<void> {\n const s = spinner('Installing base dependencies...');\n s.start();\n try {\n execSync('npm install', {\n cwd: this.config.targetDir,\n stdio: 'pipe',\n maxBuffer: 10 * 1024 * 1024,\n });\n s.stop();\n success('Installed base dependencies');\n } catch (err) {\n s.stop();\n throw new Error(\n `Failed to install dependencies: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n private async cleanViteDefaults(): Promise<void> {\n const s = spinner('Removing default Vite template files...');\n s.start();\n\n for (const file of FILES_TO_REMOVE) {\n const fullPath = path.join(this.config.targetDir, file);\n if (await fs.pathExists(fullPath)) {\n await fs.remove(fullPath);\n debug(`Removed: ${file}`);\n }\n }\n\n const publicPath = path.join(this.config.targetDir, 'public');\n if (await fs.pathExists(publicPath)) {\n await fs.emptyDir(publicPath);\n }\n\n s.stop();\n success('Cleaned default Vite template files');\n }\n\n private async copySharedFiles(): Promise<void> {\n const s = spinner('Copying shared extension files...');\n s.start();\n\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n // Copy shared src files (popup, options, utils, styles)\n const sharedSrcDir = path.join(sharedDir, 'src');\n if (await fs.pathExists(sharedSrcDir)) {\n await fs.copy(sharedSrcDir, path.join(this.config.targetDir, 'src'));\n }\n\n // Copy shared public files (icons)\n const sharedPublicDir = path.join(sharedDir, 'public');\n if (await fs.pathExists(sharedPublicDir)) {\n await fs.copy(sharedPublicDir, path.join(this.config.targetDir, 'public'));\n }\n\n s.stop();\n success('Copied shared extension files');\n }\n\n private async copyBrowserFiles(): Promise<void> {\n const s = spinner(`Copying ${this.config.browser} browser files...`);\n s.start();\n\n const browserDir = path.join(this.templatesDir, this.config.browser);\n\n // Copy browser-specific src files (manifest, background, content)\n const browserSrcDir = path.join(browserDir, 'src');\n if (await fs.pathExists(browserSrcDir)) {\n await fs.copy(browserSrcDir, path.join(this.config.targetDir, 'src'), {\n overwrite: true,\n });\n }\n\n s.stop();\n success(`Copied ${this.config.browser} browser files`);\n }\n\n private async overrideConfigs(): Promise<void> {\n const s = spinner('Overriding config files...');\n s.start();\n\n const browserDir = path.join(this.templatesDir, this.config.browser);\n const viteConfigFrom = path.join(browserDir, 'vite.config.ts');\n const viteConfigTo = path.join(this.config.targetDir, 'vite.config.ts');\n\n if (await fs.pathExists(viteConfigFrom)) {\n await fs.copy(viteConfigFrom, viteConfigTo, { overwrite: true });\n debug('Overrode: vite.config.ts');\n }\n\n s.stop();\n success('Overrode config files');\n }\n\n private async patchTsConfig(): Promise<void> {\n const s = spinner('Patching tsconfig for extension types...');\n s.start();\n\n const tsconfigAppPath = path.join(this.config.targetDir, 'tsconfig.app.json');\n\n if (await fs.pathExists(tsconfigAppPath)) {\n let content = await fs.readFile(tsconfigAppPath, 'utf-8');\n\n // Both Chrome and Firefox use @types/chrome (Firefox MV3 supports chrome.* namespace)\n const typeToAdd = 'chrome';\n\n // Inject the type into the \"types\" array using string replacement\n // This preserves comments and formatting in the JSONC file\n content = content.replace(\n /(\"types\"\\s*:\\s*\\[)([\\s\\S]*?)(\\])/,\n (match, prefix, existing, suffix) => {\n const trimmed = existing.trim();\n if (trimmed.includes(`\"${typeToAdd}\"`)) return match; // already present\n if (trimmed.length === 0) {\n return `${prefix}\"${typeToAdd}\"${suffix}`;\n }\n return `${prefix}${existing.trimEnd()}, \"${typeToAdd}\"${suffix}`;\n },\n );\n\n await fs.writeFile(tsconfigAppPath, content, 'utf-8');\n debug(`Patched tsconfig.app.json with type: ${typeToAdd}`);\n }\n\n s.stop();\n success('Patched tsconfig for extension types');\n }\n\n private async injectProjectName(): Promise<void> {\n const s = spinner('Injecting project name...');\n s.start();\n\n if (this.config.browser === 'chrome') {\n // Chrome uses manifest.ts\n const manifestPath = path.join(this.config.targetDir, 'src', 'manifest.ts');\n if (await fs.pathExists(manifestPath)) {\n let manifest = await fs.readFile(manifestPath, 'utf-8');\n manifest = manifest.replace(/__EXT_NAME__/g, this.config.name);\n await fs.writeFile(manifestPath, manifest, 'utf-8');\n }\n } else if (this.config.browser === 'firefox') {\n // Firefox uses manifest.json\n const manifestPath = path.join(this.config.targetDir, 'src', 'manifest.json');\n if (await fs.pathExists(manifestPath)) {\n let manifest = await fs.readFile(manifestPath, 'utf-8');\n manifest = manifest.replace(/__EXT_NAME__/g, this.config.name);\n await fs.writeFile(manifestPath, manifest, 'utf-8');\n }\n }\n\n // Update package.json name\n const pkgPath = path.join(this.config.targetDir, 'package.json');\n if (await fs.pathExists(pkgPath)) {\n let pkg = await fs.readFile(pkgPath, 'utf-8');\n pkg = pkg.replace(/\"__EXT_NAME__\"/g, `\"${this.config.name}\"`);\n await fs.writeFile(pkgPath, pkg, 'utf-8');\n }\n\n s.stop();\n success('Injected project name');\n }\n\n private async installExtensionDeps(): Promise<void> {\n const deps = this.config.browser === 'firefox' ? FIREFOX_DEV_DEPS : CHROME_DEV_DEPS;\n\n const s = spinner(`Installing ${this.config.browser} extension dev dependencies...`);\n s.start();\n try {\n execSync(`npm install --save-dev ${deps.join(' ')}`, {\n cwd: this.config.targetDir,\n stdio: 'pipe',\n maxBuffer: 10 * 1024 * 1024,\n });\n s.stop();\n success(`Installed ${this.config.browser} extension dev dependencies`);\n } catch (err) {\n s.stop();\n throw new Error(\n `Failed to install extension dependencies: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n","{\n \"name\": \"create-vextro\",\n \"version\": \"0.1.1\",\n \"description\": \"Scaffold modern browser extensions (Chrome, Edge, Firefox) with Vite + React + Tailwind\",\n \"type\": \"module\",\n \"bin\": {\n \"create-vextro\": \"./dist/index.js\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"lint\": \"eslint src/\",\n \"format\": \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n \"prepublishOnly\": \"npm run build && npm test\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"dependencies\": {\n \"chalk\": \"^5.3.0\",\n \"commander\": \"^12.1.0\",\n \"fs-extra\": \"^11.2.0\",\n \"inquirer\": \"^9.2.8\",\n \"ora\": \"^8.0.0\"\n },\n \"devDependencies\": {\n \"@changesets/cli\": \"^2.27.0\",\n \"@types/fs-extra\": \"^11.0.4\",\n \"@types/inquirer\": \"^9.0.7\",\n \"@types/node\": \"^20.0.0\",\n \"eslint\": \"^9.0.0\",\n \"prettier\": \"^3.3.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.5.0\",\n \"typescript-eslint\": \"^8.0.0\",\n \"vitest\": \"^2.0.0\"\n },\n \"files\": [\n \"dist\",\n \"src/templates\"\n ],\n \"keywords\": [\n \"vite\",\n \"chrome-extension\",\n \"firefox-extension\",\n \"browser-extension\",\n \"vite-plugin\",\n \"react\",\n \"tailwind\",\n \"crxjs\",\n \"manifest-v3\",\n \"scaffold\",\n \"cli\",\n \"generator\",\n \"starter-kit\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/CodeCanvasCollective/vextro.git\"\n },\n \"author\": \"Lasantha <lasanthaslakmal@gmail.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/CodeCanvasCollective/vextro/issues\"\n },\n \"homepage\": \"https://github.com/CodeCanvasCollective/vextro#readme\"\n}\n","import { createCli } from './cli.js';\n\nconst program = createCli();\nprogram.parse();\n"],"mappings":"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","names":["Command","path","fs","__filename","__dirname","path","fs","path","fs","path","fs","program","Command"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/commands/create.ts","../src/prompts/index.ts","../src/constants.ts","../src/utils/logger.ts","../src/utils/file.ts","../src/utils/validator.ts","../src/generators/extension.ts","../package.json","../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createCommand } from './commands/create.js';\nimport { setVerbose } from './utils/logger.js';\nimport pkg from '../package.json' with { type: 'json' };\n\nconst CLI_VERSION = pkg.version || '0.1.0';\n\nexport function createCli(): Command {\n const program = new Command();\n\n program\n .name('create-vextro')\n .description('Scaffold modern browser extensions with Vite + React + Tailwind')\n .version(CLI_VERSION)\n .option('--verbose', 'Enable verbose output')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts();\n if (opts.verbose) {\n setVerbose(true);\n }\n });\n\n program.addCommand(createCommand(), { isDefault: true });\n\n return program;\n}\n","import { Command } from 'commander';\nimport path from 'node:path';\nimport fs from 'fs-extra';\nimport { promptProjectName, promptBrowser } from '../prompts/index.js';\nimport { ExtensionGenerator } from '../generators/extension.js';\nimport {\n validateProjectName,\n validateDirectory,\n error,\n success,\n newLine,\n banner,\n} from '../utils/index.js';\nimport { BROWSERS } from '../constants.js';\nimport type { CreateOptions, ProjectConfig, BrowserTarget } from '../types/index.js';\n\nexport function createCommand(): Command {\n const cmd = new Command('create')\n .description('Create a new browser extension project')\n .argument('[project-name]', 'Name of the extension project')\n .option('--chrome', 'Target Chrome / Edge (default)')\n .option('--firefox', 'Target Firefox')\n .option('--force', 'Overwrite existing directory')\n .action(async (projectName: string | undefined, options: CreateOptions) => {\n try {\n await handleCreate(projectName, options);\n } catch (err) {\n error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\nfunction resolveBrowserFromFlags(options: CreateOptions): BrowserTarget | null {\n if (options.chrome) return 'chrome';\n if (options.firefox) return 'firefox';\n return null;\n}\n\nasync function handleCreate(\n projectName: string | undefined,\n options: CreateOptions,\n): Promise<void> {\n // If no project name given as arg, prompt for it\n if (!projectName) {\n projectName = await promptProjectName();\n }\n\n // Validate the project name\n const nameValidation = validateProjectName(projectName);\n if (nameValidation !== true) {\n throw new Error(nameValidation);\n }\n\n // Resolve browser target\n let browser = resolveBrowserFromFlags(options);\n if (!browser) {\n browser = await promptBrowser();\n }\n\n const targetDir = path.resolve(process.cwd(), projectName);\n\n // Check if directory already exists\n if (!options.force) {\n const dirValidation = await validateDirectory(targetDir);\n if (dirValidation !== true) {\n throw new Error(dirValidation);\n }\n } else if (await fs.pathExists(targetDir)) {\n await fs.remove(targetDir);\n }\n\n const config: ProjectConfig = {\n name: projectName,\n targetDir,\n browser,\n };\n\n const browserMeta = BROWSERS[browser];\n\n newLine();\n banner(`🚀 Creating Vextro Extension for ${browserMeta.displayName} — \"${config.name}\"...`);\n newLine();\n\n // Handle SIGINT — clean up partial directory\n const cleanup = async () => {\n newLine();\n error('Interrupted! Cleaning up...');\n try {\n if (await fs.pathExists(targetDir)) {\n await fs.remove(targetDir);\n }\n } catch {\n // best-effort cleanup\n }\n process.exit(1);\n };\n process.on('SIGINT', cleanup);\n\n const generator = new ExtensionGenerator(config);\n await generator.generate();\n\n // Remove SIGINT handler after success\n process.removeListener('SIGINT', cleanup);\n\n newLine();\n success(\n `Vextro project \"${config.name}\" created successfully for ${browserMeta.displayName}! 🎉`,\n );\n newLine();\n console.log('Next steps:');\n console.log(` cd ${config.name}`);\n console.log(' npm run dev');\n newLine();\n\n if (browser === 'chrome') {\n console.log('Load extension:');\n console.log(' 1. Open chrome://extensions (or edge://extensions)');\n console.log(' 2. Enable \"Developer mode\"');\n console.log(' 3. Click \"Load unpacked\" → select the dist/ folder');\n } else if (browser === 'firefox') {\n console.log('Load extension:');\n console.log(' 1. Open about:debugging#/runtime/this-firefox');\n console.log(' 2. Click \"Load Temporary Add-on\"');\n console.log(' 3. Select any file in the dist/ folder');\n }\n\n newLine();\n console.log('Happy coding! 🚀');\n newLine();\n}\n","import inquirer from 'inquirer';\nimport { DEFAULT_PROJECT_NAME, BROWSERS } from '../constants.js';\nimport { validateProjectName } from '../utils/index.js';\nimport type { BrowserTarget } from '../types/index.js';\n\nexport async function promptProjectName(): Promise<string> {\n const { projectName } = await inquirer.prompt([\n {\n name: 'projectName',\n message: 'Enter your extension project name:',\n default: DEFAULT_PROJECT_NAME,\n validate: (input: string) => {\n const result = validateProjectName(input);\n return result === true ? true : result;\n },\n },\n ]);\n return projectName;\n}\n\nexport async function promptBrowser(): Promise<BrowserTarget> {\n const { browser } = await inquirer.prompt([\n {\n type: 'list',\n name: 'browser',\n message: 'Select target browser:',\n choices: Object.entries(BROWSERS).map(([value, meta]) => ({\n name: `${meta.displayName} — ${meta.description}`,\n value,\n })),\n default: 'chrome',\n },\n ]);\n return browser;\n}\n","import type { BrowserTarget } from './types/index.js';\n\nexport const PACKAGE_NAME = 'create-vextro';\nexport const BRAND_NAME = 'Vextro';\n\nexport const VALID_PROJECT_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/;\n\nexport const DEFAULT_PROJECT_NAME = 'my-extension';\nexport const DEFAULT_BROWSER: BrowserTarget = 'chrome';\n\nexport const FILES_TO_REMOVE = [\n 'src/App.tsx',\n 'src/main.tsx',\n 'src/index.css',\n 'src/App.css',\n 'src/assets',\n 'index.html',\n];\n\nexport const BROWSERS: Record<BrowserTarget, { displayName: string; description: string }> = {\n chrome: {\n displayName: 'Chrome / Edge',\n description: 'Google Chrome & Microsoft Edge (Chromium-based, uses CRXJS)',\n },\n firefox: {\n displayName: 'Firefox',\n description: 'Mozilla Firefox (uses vite-plugin-web-extension)',\n },\n};\n\nexport const CHROME_DEV_DEPS = [\n '@types/chrome',\n '@types/node',\n '@crxjs/vite-plugin',\n 'tailwindcss',\n '@tailwindcss/vite',\n];\n\nexport const FIREFOX_DEV_DEPS = [\n '@types/chrome',\n '@types/node',\n 'vite-plugin-web-extension',\n 'tailwindcss',\n '@tailwindcss/vite',\n];\n","import chalk from 'chalk';\nimport ora, { type Ora } from 'ora';\n\nlet verbose = false;\n\nexport function setVerbose(value: boolean): void {\n verbose = value;\n}\n\nexport function info(message: string): void {\n console.log(chalk.blue('ℹ'), message);\n}\n\nexport function success(message: string): void {\n console.log(chalk.green('✔'), message);\n}\n\nexport function warn(message: string): void {\n console.log(chalk.yellow('⚠'), message);\n}\n\nexport function error(message: string): void {\n console.log(chalk.red('✖'), message);\n}\n\nexport function debug(message: string): void {\n if (verbose) {\n console.log(chalk.gray('⬥'), chalk.gray(message));\n }\n}\n\nexport function spinner(text: string): Ora {\n return ora({ text, color: 'cyan' });\n}\n\nexport function newLine(): void {\n console.log();\n}\n\nexport function banner(text: string): void {\n console.log(chalk.bold.cyan(text));\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport { fileURLToPath } from 'node:url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport function getTemplatesDir(): string {\n // When bundled with tsup, __dirname is dist/ → go up 1 level to project root\n // When running unbundled (vitest), __dirname is src/utils/ → go up 2 levels to project root\n const isBundled =\n __dirname.replace(/\\\\/g, '/').endsWith('/dist') ||\n __dirname.replace(/\\\\/g, '/').includes('/dist/');\n const projectRoot = isBundled\n ? path.resolve(__dirname, '..')\n : path.resolve(__dirname, '..', '..');\n return path.resolve(projectRoot, 'src', 'templates');\n}\n\nexport async function createDir(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\nexport async function directoryExists(dirPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirPath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(filePath);\n return stat.isFile();\n } catch {\n return false;\n }\n}\n","import { VALID_PROJECT_NAME } from '../constants.js';\nimport { directoryExists } from './file.js';\n\nexport function validateProjectName(name: string): string | true {\n if (!name || name.trim().length === 0) {\n return 'Project name is required.';\n }\n\n if (!VALID_PROJECT_NAME.test(name)) {\n return 'Project name must be a valid npm package name (lowercase, no spaces, can use hyphens and dots).';\n }\n\n if (name.length > 214) {\n return 'Project name must be less than 214 characters.';\n }\n\n return true;\n}\n\nexport async function validateDirectory(dirPath: string): Promise<string | true> {\n if (await directoryExists(dirPath)) {\n return `Directory \"${dirPath}\" already exists. Use --force to overwrite.`;\n }\n return true;\n}\n\nexport function checkNodeVersion(minMajor: number = 20): string | true {\n const version = process.version;\n const major = parseInt(version.slice(1).split('.')[0], 10);\n\n if (major < minMajor) {\n return `Node.js ${minMajor}+ is required. You are using ${version}.`;\n }\n\n return true;\n}\n","import path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport fs from 'fs-extra';\nimport { getTemplatesDir, spinner, success, debug } from '../utils/index.js';\nimport { FILES_TO_REMOVE, CHROME_DEV_DEPS, FIREFOX_DEV_DEPS } from '../constants.js';\nimport type { ProjectConfig } from '../types/index.js';\n\nexport class ExtensionGenerator {\n private config: ProjectConfig;\n private templatesDir: string;\n\n constructor(config: ProjectConfig) {\n this.config = config;\n this.templatesDir = getTemplatesDir();\n }\n\n async generate(): Promise<void> {\n await this.scaffoldVite();\n await this.installBaseDeps();\n await this.cleanViteDefaults();\n await this.copySharedFiles();\n await this.copyBrowserFiles();\n await this.overrideConfigs();\n await this.patchTsConfig();\n await this.injectProjectName();\n await this.installExtensionDeps();\n }\n\n private async scaffoldVite(): Promise<void> {\n const s = spinner('Creating base Vite + React + TS project...');\n s.start();\n try {\n execSync(`npm exec --yes -- create-vite@latest ${this.config.name} --template react-ts`, {\n cwd: path.dirname(this.config.targetDir),\n stdio: 'pipe',\n maxBuffer: 10 * 1024 * 1024,\n });\n s.stop();\n success('Created base Vite + React + TS project');\n } catch (err) {\n s.stop();\n throw new Error(\n `Failed to scaffold Vite project: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n private async installBaseDeps(): Promise<void> {\n const s = spinner('Installing base dependencies...');\n s.start();\n try {\n execSync('npm install', {\n cwd: this.config.targetDir,\n stdio: 'pipe',\n maxBuffer: 10 * 1024 * 1024,\n });\n s.stop();\n success('Installed base dependencies');\n } catch (err) {\n s.stop();\n throw new Error(\n `Failed to install dependencies: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n private async cleanViteDefaults(): Promise<void> {\n const s = spinner('Removing default Vite template files...');\n s.start();\n\n for (const file of FILES_TO_REMOVE) {\n const fullPath = path.join(this.config.targetDir, file);\n if (await fs.pathExists(fullPath)) {\n await fs.remove(fullPath);\n debug(`Removed: ${file}`);\n }\n }\n\n const publicPath = path.join(this.config.targetDir, 'public');\n if (await fs.pathExists(publicPath)) {\n await fs.emptyDir(publicPath);\n }\n\n s.stop();\n success('Cleaned default Vite template files');\n }\n\n private async copySharedFiles(): Promise<void> {\n const s = spinner('Copying shared extension files...');\n s.start();\n\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n // Copy shared src files (popup, options, utils, styles)\n const sharedSrcDir = path.join(sharedDir, 'src');\n if (await fs.pathExists(sharedSrcDir)) {\n await fs.copy(sharedSrcDir, path.join(this.config.targetDir, 'src'));\n }\n\n // Copy shared public files (icons)\n const sharedPublicDir = path.join(sharedDir, 'public');\n if (await fs.pathExists(sharedPublicDir)) {\n await fs.copy(sharedPublicDir, path.join(this.config.targetDir, 'public'));\n }\n\n s.stop();\n success('Copied shared extension files');\n }\n\n private async copyBrowserFiles(): Promise<void> {\n const s = spinner(`Copying ${this.config.browser} browser files...`);\n s.start();\n\n const browserDir = path.join(this.templatesDir, this.config.browser);\n\n // Copy browser-specific src files (manifest, background, content)\n const browserSrcDir = path.join(browserDir, 'src');\n if (await fs.pathExists(browserSrcDir)) {\n await fs.copy(browserSrcDir, path.join(this.config.targetDir, 'src'), {\n overwrite: true,\n });\n }\n\n s.stop();\n success(`Copied ${this.config.browser} browser files`);\n }\n\n private async overrideConfigs(): Promise<void> {\n const s = spinner('Overriding config files...');\n s.start();\n\n const browserDir = path.join(this.templatesDir, this.config.browser);\n const viteConfigFrom = path.join(browserDir, 'vite.config.ts');\n const viteConfigTo = path.join(this.config.targetDir, 'vite.config.ts');\n\n if (await fs.pathExists(viteConfigFrom)) {\n await fs.copy(viteConfigFrom, viteConfigTo, { overwrite: true });\n debug('Overrode: vite.config.ts');\n }\n\n s.stop();\n success('Overrode config files');\n }\n\n private async patchTsConfig(): Promise<void> {\n const s = spinner('Patching tsconfig for extension types...');\n s.start();\n\n const tsconfigAppPath = path.join(this.config.targetDir, 'tsconfig.app.json');\n\n if (await fs.pathExists(tsconfigAppPath)) {\n let content = await fs.readFile(tsconfigAppPath, 'utf-8');\n\n // Both Chrome and Firefox use @types/chrome (Firefox MV3 supports chrome.* namespace)\n const typeToAdd = 'chrome';\n\n // Inject the type into the \"types\" array using string replacement\n // This preserves comments and formatting in the JSONC file\n content = content.replace(\n /(\"types\"\\s*:\\s*\\[)([\\s\\S]*?)(\\])/,\n (match, prefix, existing, suffix) => {\n const trimmed = existing.trim();\n if (trimmed.includes(`\"${typeToAdd}\"`)) return match; // already present\n if (trimmed.length === 0) {\n return `${prefix}\"${typeToAdd}\"${suffix}`;\n }\n return `${prefix}${existing.trimEnd()}, \"${typeToAdd}\"${suffix}`;\n },\n );\n\n await fs.writeFile(tsconfigAppPath, content, 'utf-8');\n debug(`Patched tsconfig.app.json with type: ${typeToAdd}`);\n }\n\n s.stop();\n success('Patched tsconfig for extension types');\n }\n\n private async injectProjectName(): Promise<void> {\n const s = spinner('Injecting project name...');\n s.start();\n\n if (this.config.browser === 'chrome') {\n // Chrome uses manifest.ts\n const manifestPath = path.join(this.config.targetDir, 'src', 'manifest.ts');\n if (await fs.pathExists(manifestPath)) {\n let manifest = await fs.readFile(manifestPath, 'utf-8');\n manifest = manifest.replace(/__EXT_NAME__/g, this.config.name);\n await fs.writeFile(manifestPath, manifest, 'utf-8');\n }\n } else if (this.config.browser === 'firefox') {\n // Firefox uses manifest.json\n const manifestPath = path.join(this.config.targetDir, 'src', 'manifest.json');\n if (await fs.pathExists(manifestPath)) {\n let manifest = await fs.readFile(manifestPath, 'utf-8');\n manifest = manifest.replace(/__EXT_NAME__/g, this.config.name);\n await fs.writeFile(manifestPath, manifest, 'utf-8');\n }\n }\n\n // Update package.json name\n const pkgPath = path.join(this.config.targetDir, 'package.json');\n if (await fs.pathExists(pkgPath)) {\n let pkg = await fs.readFile(pkgPath, 'utf-8');\n pkg = pkg.replace(/\"__EXT_NAME__\"/g, `\"${this.config.name}\"`);\n await fs.writeFile(pkgPath, pkg, 'utf-8');\n }\n\n s.stop();\n success('Injected project name');\n }\n\n private async installExtensionDeps(): Promise<void> {\n const deps = this.config.browser === 'firefox' ? FIREFOX_DEV_DEPS : CHROME_DEV_DEPS;\n\n const s = spinner(`Installing ${this.config.browser} extension dev dependencies...`);\n s.start();\n try {\n execSync(`npm install --save-dev ${deps.join(' ')}`, {\n cwd: this.config.targetDir,\n stdio: 'pipe',\n maxBuffer: 10 * 1024 * 1024,\n });\n s.stop();\n success(`Installed ${this.config.browser} extension dev dependencies`);\n } catch (err) {\n s.stop();\n throw new Error(\n `Failed to install extension dependencies: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n","{\n \"name\": \"create-vextro\",\n \"version\": \"0.1.3\",\n \"description\": \"Scaffold modern browser extensions (Chrome, Edge, Firefox) with Vite + React + Tailwind\",\n \"type\": \"module\",\n \"bin\": {\n \"create-vextro\": \"./dist/index.js\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"lint\": \"eslint src/\",\n \"format\": \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n \"prepublishOnly\": \"npm run build && npm test\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"dependencies\": {\n \"chalk\": \"^5.3.0\",\n \"commander\": \"^12.1.0\",\n \"fs-extra\": \"^11.2.0\",\n \"inquirer\": \"^9.2.8\",\n \"ora\": \"^8.0.0\"\n },\n \"devDependencies\": {\n \"@changesets/cli\": \"^2.27.0\",\n \"@types/fs-extra\": \"^11.0.4\",\n \"@types/inquirer\": \"^9.0.7\",\n \"@types/node\": \"^20.0.0\",\n \"eslint\": \"^9.0.0\",\n \"prettier\": \"^3.3.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.5.0\",\n \"typescript-eslint\": \"^8.0.0\",\n \"vitest\": \"^2.0.0\"\n },\n \"files\": [\n \"dist\",\n \"src/templates\"\n ],\n \"keywords\": [\n \"vite\",\n \"chrome-extension\",\n \"firefox-extension\",\n \"browser-extension\",\n \"vite-plugin\",\n \"react\",\n \"tailwind\",\n \"crxjs\",\n \"manifest-v3\",\n \"scaffold\",\n \"cli\",\n \"generator\",\n \"starter-kit\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/CodeCanvasCollective/vextro.git\"\n },\n \"author\": \"Lasantha <lasanthaslakmal@gmail.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/CodeCanvasCollective/vextro/issues\"\n },\n \"homepage\": \"https://github.com/CodeCanvasCollective/vextro#readme\"\n}\n","import { createCli } from './cli.js';\n\nconst program = createCli();\nprogram.parse();\n"],"mappings":"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","names":["Command","path","fs","__filename","__dirname","path","fs","path","fs","path","fs","program","Command"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-vextro",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Scaffold modern browser extensions (Chrome, Edge, Firefox) with Vite + React + Tailwind",
5
5
  "type": "module",
6
6
  "bin": {
@@ -53,7 +53,7 @@ export default function App() {
53
53
  <p className="text-sm text-blue-700">
54
54
  This extension was scaffolded with{' '}
55
55
  <a
56
- href="https://github.com/lasalasa/vextro"
56
+ href="https://github.com/CodeCanvasCollective/vextro"
57
57
  target="_blank"
58
58
  rel="noopener noreferrer"
59
59
  className="underline"