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 +130 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +100 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +36 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.js +1 -0
- package/package.json +48 -0
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
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
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|
package/dist/types.d.ts
ADDED
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
|
+
}
|