devrun 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/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # devrun 🚀
2
+
3
+ A blazingly fast interactive npm script runner with fuzzy search.
4
+
5
+ ## Why devrun?
6
+
7
+ Tired of typing `npm run` repeatedly? Can't remember your script names? **devrun** makes running npm scripts a breeze with:
8
+
9
+ ✨ **Interactive fuzzy search** - Type to filter scripts instantly
10
+ ⚡ **Lightning fast** - No config, zero overhead
11
+ 📋 **Command preview** - See what you're about to run
12
+ 🎯 **Smart filtering** - Fuzzy matching finds what you mean
13
+ 🔥 **Two commands**: `devrun` or `dr` (shorter!)
14
+
15
+ ## 🎬 Demo
16
+
17
+ ### The Old Way 😴
18
+ ```bash
19
+ $ npm run
20
+ # Scroll through scripts...
21
+ # Try to remember the name...
22
+ # Type the full command...
23
+ $ npm run dev:server:watch
24
+ ```
25
+
26
+ ### The devrun Way 😎
27
+ ```bash
28
+ $ dr
29
+
30
+ ? Select a script to run: ›
31
+ ❯ dev tsc --watch
32
+ build tsc
33
+ test echo "Running tests..."
34
+ lint eslint src/
35
+
36
+ # Type 'te' to filter:
37
+ ? Select a script to run: › te
38
+ ❯ test echo "Running tests..."
39
+
40
+ # Press Enter:
41
+ ✔ Selected: test
42
+ > echo "Running tests..."
43
+ Running tests... ✅
44
+ ```
45
+
46
+ **That's it!** No memorization, no typing long commands, just fuzzy search and go.
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ npm install -g devrun
52
+ ```
53
+
54
+ Or use with npx (no installation needed):
55
+
56
+ ```bash
57
+ npx devrun
58
+ ```
59
+
60
+ ## Usage
61
+
62
+ In any project with a `package.json`, just run:
63
+
64
+ ```bash
65
+ devrun
66
+ # or the shorter version
67
+ dr
68
+ ```
69
+
70
+ You'll get an interactive list of all available scripts. Start typing to filter, use arrow keys to select, and hit Enter to run!
71
+
72
+ ### Example
73
+
74
+ ```bash
75
+ $ dr
76
+ ? Select a script to run: ›
77
+ ❯ build tsc && vite build
78
+ dev vite --port 3000
79
+ test vitest run
80
+ test:watch vitest
81
+ lint eslint src/
82
+ format prettier --write src/
83
+ ```
84
+
85
+ Type "te" and it instantly filters to test scripts. Press Enter to run it!
86
+
87
+ ## Features
88
+
89
+ - 🔍 **Fuzzy search** - Type any part of the script name
90
+ - 🎨 **Syntax highlighting** - Easy-to-read output
91
+ - 📂 **Smart discovery** - Automatically finds package.json in current or parent directories
92
+ - ⌨️ **Keyboard navigation** - Intuitive and fast
93
+ - 🚫 **No configuration** - Just works out of the box
94
+
95
+ ## Why not just use npm run?
96
+
97
+ ```bash
98
+ # Traditional way 😴
99
+ npm run dev
100
+ # Wait, what was it called? Let me check...
101
+ npm run
102
+ # Scroll through the list...
103
+ npm run start:dev
104
+
105
+ # With devrun 😎
106
+ dr
107
+ # Type 'dev', press Enter. Done!
108
+ ```
109
+
110
+ ## Comparison
111
+
112
+ | Feature | devrun | npm run | |
113
+ |---------|--------|---------|---|
114
+ | Interactive selection | ✅ | ❌ | |
115
+ | Fuzzy search | ✅ | ❌ | |
116
+ | Command preview | ✅ | ❌ | |
117
+ | Zero config | ✅ | ✅ | |
118
+ | Speed | ⚡ Fast | 🐌 Slow | |
119
+
120
+ ## Contributing
121
+
122
+ Found a bug or have a feature request? Open an issue on [GitHub](https://github.com/yourusername/devrun)!
123
+
124
+ ## License
125
+
126
+ MIT
127
+
128
+ ---
129
+
130
+ Made with ❤️ for developers who hate typing `npm run`
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,100 @@
1
+ #!/usr/bin/env node
2
+ import prompts from 'prompts';
3
+ import fuzzysort from 'fuzzysort';
4
+ import chalk from 'chalk';
5
+ import { execa } from 'execa';
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ import { findPackageJson, getScripts } from './index.js';
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+ function getVersion() {
13
+ try {
14
+ const pkgPath = path.join(__dirname, '..', 'package.json');
15
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
16
+ return pkg.version || '0.0.0';
17
+ }
18
+ catch {
19
+ return '0.0.0';
20
+ }
21
+ }
22
+ function showHelp() {
23
+ console.log(chalk.bold.cyan('\ndevrun') + chalk.dim(' - Interactive npm script runner\n'));
24
+ console.log('Usage:');
25
+ console.log(' ' + chalk.cyan('devrun') + ' or ' + chalk.cyan('dr') + ' Run in interactive mode');
26
+ console.log(' ' + chalk.cyan('devrun --help') + ' Show this help message');
27
+ console.log(' ' + chalk.cyan('devrun --version') + ' Show version number\n');
28
+ console.log('Examples:');
29
+ console.log(' ' + chalk.dim('$ devrun'));
30
+ console.log(' ' + chalk.dim('$ dr\n'));
31
+ }
32
+ async function main() {
33
+ const args = process.argv.slice(2);
34
+ if (args.includes('--help') || args.includes('-h')) {
35
+ showHelp();
36
+ process.exit(0);
37
+ }
38
+ if (args.includes('--version') || args.includes('-v')) {
39
+ console.log(getVersion());
40
+ process.exit(0);
41
+ }
42
+ const packageJsonPath = findPackageJson();
43
+ if (!packageJsonPath) {
44
+ console.error(chalk.red('✗ No package.json found in current directory or parents'));
45
+ process.exit(1);
46
+ }
47
+ const scripts = getScripts(packageJsonPath);
48
+ if (scripts.length === 0) {
49
+ console.error(chalk.yellow('⚠ No scripts found in package.json'));
50
+ process.exit(1);
51
+ }
52
+ const maxNameLength = Math.max(...scripts.map(s => s.name.length));
53
+ const choices = scripts.map(script => ({
54
+ title: chalk.cyan(script.name.padEnd(maxNameLength + 2)) + chalk.dim(script.command),
55
+ value: script.name,
56
+ script
57
+ }));
58
+ const response = await prompts({
59
+ type: 'autocomplete',
60
+ name: 'scriptName',
61
+ message: 'Select a script to run:',
62
+ choices,
63
+ suggest: async (input, choices) => {
64
+ if (!input)
65
+ return choices;
66
+ const results = fuzzysort.go(input, choices, {
67
+ key: 'value',
68
+ limit: 10,
69
+ threshold: -10000
70
+ });
71
+ return results.map(result => result.obj);
72
+ }
73
+ });
74
+ if (!response.scriptName) {
75
+ console.log(chalk.dim('Cancelled'));
76
+ process.exit(0);
77
+ }
78
+ const selectedScript = scripts.find(s => s.name === response.scriptName);
79
+ if (!selectedScript) {
80
+ console.error(chalk.red('✗ Script not found'));
81
+ process.exit(1);
82
+ }
83
+ console.log(chalk.dim(`\n> ${selectedScript.command}\n`));
84
+ try {
85
+ await execa('npm', ['run', selectedScript.name], {
86
+ stdio: 'inherit',
87
+ cwd: process.cwd()
88
+ });
89
+ }
90
+ catch (error) {
91
+ if (error.exitCode) {
92
+ process.exit(error.exitCode);
93
+ }
94
+ throw error;
95
+ }
96
+ }
97
+ main().catch(error => {
98
+ console.error(chalk.red('Error:'), error.message);
99
+ process.exit(1);
100
+ });
@@ -0,0 +1,4 @@
1
+ import type { Script } from './types.js';
2
+ export declare function findPackageJson(startDir?: string): string | null;
3
+ export declare function getScripts(packageJsonPath: string): Script[];
4
+ export declare function formatScriptForDisplay(script: Script, maxNameLength: number): string;
package/dist/index.js ADDED
@@ -0,0 +1,36 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ export function findPackageJson(startDir = process.cwd()) {
4
+ let currentDir = startDir;
5
+ while (true) {
6
+ const packageJsonPath = path.join(currentDir, 'package.json');
7
+ if (fs.existsSync(packageJsonPath)) {
8
+ return packageJsonPath;
9
+ }
10
+ const parentDir = path.dirname(currentDir);
11
+ if (parentDir === currentDir) {
12
+ return null;
13
+ }
14
+ currentDir = parentDir;
15
+ }
16
+ }
17
+ export function getScripts(packageJsonPath) {
18
+ try {
19
+ const content = fs.readFileSync(packageJsonPath, 'utf-8');
20
+ const packageJson = JSON.parse(content);
21
+ if (!packageJson.scripts) {
22
+ return [];
23
+ }
24
+ return Object.entries(packageJson.scripts).map(([name, command]) => ({
25
+ name,
26
+ command
27
+ }));
28
+ }
29
+ catch (error) {
30
+ return [];
31
+ }
32
+ }
33
+ export function formatScriptForDisplay(script, maxNameLength) {
34
+ const paddedName = script.name.padEnd(maxNameLength + 2);
35
+ return `${paddedName} ${script.command}`;
36
+ }
@@ -0,0 +1,7 @@
1
+ export interface Script {
2
+ name: string;
3
+ command: string;
4
+ }
5
+ export interface PackageJson {
6
+ scripts?: Record<string, string>;
7
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "devrun",
3
+ "version": "0.1.0",
4
+ "description": "A blazingly fast interactive npm script runner with fuzzy search",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "devrun": "dist/cli.js",
8
+ "dr": "dist/cli.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "test": "echo \"Running tests...\" && echo \"All tests passed!\"",
14
+ "lint": "echo \"Linting code...\"",
15
+ "format": "echo \"Formatting code...\"",
16
+ "clean": "rm -rf dist",
17
+ "prepublishOnly": "npm run clean && npm run build"
18
+ },
19
+ "keywords": [
20
+ "npm",
21
+ "scripts",
22
+ "runner",
23
+ "cli",
24
+ "fuzzy",
25
+ "interactive",
26
+ "developer-tools",
27
+ "productivity",
28
+ "npm-run",
29
+ "task-runner"
30
+ ],
31
+ "author": "",
32
+ "license": "MIT",
33
+ "engines": {
34
+ "node": ">=16"
35
+ },
36
+ "type": "module",
37
+ "dependencies": {
38
+ "chalk": "^5.6.2",
39
+ "execa": "^9.6.1",
40
+ "fuzzysort": "^3.1.0",
41
+ "prompts": "^2.4.2"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^25.2.3",
45
+ "@types/prompts": "^2.4.9",
46
+ "typescript": "^5.9.3"
47
+ }
48
+ }