| name | ext-pack-dev |
| description | Development guidelines and workflows for ext-pack, a Node.js CLI tool for bundling and installing Chromium browser extensions. Use when working on ext-pack codebase for (1) Making code changes (bug fixes, features, refactors), (2) Understanding the architecture and patterns, (3) Testing changes, (4) Committing and pushing code. Enforces consistent workflows across all developers and AI agents. |
ext-pack Development
Overview
This skill provides the architectural patterns, development workflows, and coding standards for ext-pack, ensuring all developers and AI agents follow consistent practices when working on the codebase.
Architecture
Project Structure
ext-pack/
├── bin/ext-pack.js # Entry point - CLI arg parsing
├── src/
│ ├── commands/ # Thin command handlers
│ ├── ui/ # Interactive prompts (inquirer)
│ ├── core/ # Business logic (no UI dependencies)
│ │ ├── pack-codec.js # Pack create/validate/read/write
│ │ ├── extension-scanner.js
│ │ ├── pack-installer.js
│ │ ├── browser-launcher.js
│ │ └── github-api.js
│ └── utils/ # Cross-cutting utilities
│ ├── browser-detector.js
│ └── config-manager.js
└── CLAUDE.md # Project documentation
Layer Separation (CRITICAL)
Flow: Command → UI wizard → Core logic
export async function createCommand() {
const packPath = await runCreateWizard();
if (packPath) console.log(`Created: ${packPath}`);
}
export async function runCreateWizard() {
const extensions = scanDirectory(scanPath);
const pack = createPack(name, desc, author, extensions);
await writePackFile(outputFile, pack);
}
export function scanDirectory(dir) {
const { confirm } = await inquirer.prompt([...]);
}
Rule: Core modules (src/core/) must NEVER import or depend on UI modules (src/ui/).
Module Patterns (CRITICAL)
All modules use ESM with both named exports AND default object export:
export function scanDirectory(path) { ... }
export function validateExtension(manifest) { ... }
export default {
scanDirectory,
validateExtension
};
export function scanDirectory(path) { ... }
Development Workflows
🚨 CRITICAL: Publishing to npm
AFTER EVERY PUSH, REMIND USER TO PUBLISH:
npm publish --otp=YOUR_CODE
When to publish:
- ✅ After bug fixes (patch: x.x.X)
- ✅ After new features (minor: x.X.0)
- ✅ After breaking changes (major: X.0.0)
NEVER SKIP THIS! Pushed code won't reach users until published to npm.
Workflow 1: Making Code Changes
🚨 CRITICAL: SYSTEMATIC TESTING IS MANDATORY
ALWAYS follow this sequence for ANY code change (NO EXCEPTIONS):
- Make the change using dedicated tools (Read, Edit, Write, Glob, Grep)
- Install changes globally - Run
npm link to install updated code
- Run FULL testing checklist - Execute every test in
.claude/skills/testing-checklist/SKILL.md
- Test 1: Create flow (end-to-end)
- Test 2: Install flow (end-to-end)
- Test 3: List flow (end-to-end)
- Test 4: Publish flow (end-to-end)
- Test 5: Error handling & edge cases
- Verify all tests pass - If ANY test fails, FIX IT and re-test from Test 1
- Mark testing complete - Run
touch .testing-verified (required for commit)
- Commit with clear message following the project's commit style
- Push to remote
- REMIND USER TO PUBLISH TO NPM ← CRITICAL!
Pre-commit hook will BLOCK commits if .testing-verified doesn't exist or is stale (>10 min)
git add <files>
git commit -m "Fix Ollama connection using IPv4 address"
git push
npm link
Commit Message Style (learned from git log):
- Imperative mood: "Fix", "Add", "Update", "Improve", "Change"
- Concise subject line (under 70 chars)
- Optional body for context
Workflow 2: Creating New Features
Before starting:
- Read relevant existing files to understand patterns
- Identify which layer the feature belongs to (command/ui/core/utils)
- Follow the established patterns in that layer
Implementation steps:
- Core logic first - Implement in
src/core/ with no UI dependencies
- UI wizard second - Create interactive prompts in
src/ui/
- Command handler last - Thin wrapper in
src/commands/
- Test the feature - Run
npm run dev to verify
- Follow ESM patterns - Named exports + default object export
- Update CLAUDE.md if architectural patterns change
Example: Adding GitHub Extension Support
export async function downloadRelease(repo, version) { ... }
export default { downloadRelease };
import { downloadRelease } from '../core/github-api.js';
const path = await downloadRelease(repo, version);
import { runInstallWizard } from '../ui/install-wizard.js';
export async function installCommand(args) {
await runInstallWizard(args);
}
Workflow 3: Bug Fixes and Debugging
Investigation:
- Read the relevant files - Use Read tool to understand context
- Search for patterns - Use Grep to find related code
- Check git history -
git log --oneline to see recent changes
- Test to reproduce - Run
npm run dev to trigger the bug
Fix process:
- Identify root cause - Don't just treat symptoms
- Make minimal changes - Fix only what's broken
- Test the fix - Verify it works with
npm link
- No backwards-compatibility hacks - Delete unused code completely
export function oldFunction() { ... }
export const deprecated_var = null;
Workflow 4: Testing Changes
🚨 CRITICAL RULE: SYSTEMATIC TESTING CHECKLIST IS MANDATORY
NO CODE IS COMMITTED WITHOUT COMPLETING THE FULL TESTING CHECKLIST
Testing Protocol:
- Install globally:
npm link
- Follow systematic checklist: See
.claude/skills/testing-checklist/SKILL.md
- Run ALL tests (create, install, list, publish, error handling)
- Verify EVERY checkbox in the testing checklist
- Mark complete:
touch .testing-verified (enables commit)
Quick testing methods (for rapid iteration before full checklist):
- Local development:
npm run dev (runs node bin/ext-pack.js)
- Global installation:
npm link (installs as ext-pack command)
- Syntax check:
node -c <file> for quick validation
Git hooks enforce testing:
pre-commit - Requires .testing-verified file to exist and be recent (<10 min)
pre-push - Final confirmation that all flows were tested
NEVER:
- Skip any test in the checklist
- Commit without testing verification file
- Make exceptions to the testing protocol
- Assume code works without end-to-end verification
Coding Standards
Use Dedicated Tools Over Bash
bash("cat src/ui/create-wizard.js | grep ollama")
bash("find . -name '*.js'")
bash("echo 'content' > file.js")
Read({ file_path: "src/ui/create-wizard.js" })
Grep({ pattern: "ollama", glob: "*.js" })
Write({ file_path: "file.js", content: "content" })
Glob({ pattern: "**/*.js" })
When to use Bash:
- Git operations:
git status, git commit, git push
- npm commands:
npm link, npm run dev
- System commands:
ollama list, curl
When NOT to use Bash:
- File operations (read, write, edit, search, find)
No Test Framework
Important: ext-pack has NO test framework configured (no Jest, Mocha, etc.)
Testing is manual via npm run dev or npm link. Don't try to run test commands that don't exist.
API Connections
When connecting to local services (like Ollama), use IPv4 addresses instead of localhost to avoid Node.js fetch IPv6 issues:
fetch('http://127.0.0.1:11434/api/tags')
fetch('http://localhost:11434/api/tags')
Common Patterns
Extension Types
Three types of extensions are supported:
- local - Filesystem paths to extension directories
- github - GitHub releases (downloaded and extracted)
- store - Chrome Web Store (manual install only)
Config Management
User config lives at ~/.ext-pack/:
config.json - User settings
installed.json - Installation registry
downloads/ - Downloaded extensions cache
packs/ - Default location for created packs
Interactive Prompts
Use inquirer for all interactive input:
import inquirer from 'inquirer';
const { answer } = await inquirer.prompt([{
type: 'input',
name: 'answer',
message: 'Question:',
default: 'default value'
}]);
Quick Reference
| Task | Tool | Example |
|---|
| Read file | Read | Read({ file_path: "src/ui/create-wizard.js" }) |
| Edit file | Edit | Edit({ file_path: "...", old_string: "...", new_string: "..." }) |
| Create file | Write | Write({ file_path: "...", content: "..." }) |
| Search code | Grep | Grep({ pattern: "ollama", output_mode: "content" }) |
| Find files | Glob | Glob({ pattern: "src/**/*.js" }) |
| Test changes | Bash | npm run dev or npm link |
| Commit | Bash | git add . && git commit -m "message" && git push |