@abyrd9/harbor-cli 1.0.0 → 1.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.
Files changed (3) hide show
  1. package/README.md +248 -37
  2. package/dist/index.js +87 -2
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -1,47 +1,58 @@
1
1
  # Harbor CLI
2
2
 
3
- A CLI tool for those small side projects that only run a few services. Harbor allows you to:
3
+ A CLI tool for managing local development services with ease. Harbor helps you orchestrate multiple development services in tmux sessions, perfect for microservices and polyglot projects.
4
4
 
5
- 1. šŸ› ļø Define your services in a configuration file
6
- 2. šŸš€ Launch your services in a tmux session
5
+ ## ✨ Features
6
+
7
+ - šŸ› ļø **Automatic Service Discovery**: Detects project types and suggests appropriate commands
8
+ - šŸ“ **Flexible Configuration**: Store config in `harbor.json` or `package.json`
9
+ - šŸš€ **One-Command Launch**: Start all services with a single command
10
+ - šŸ”„ **Dependency Management**: Automatically checks for required system dependencies
11
+ - šŸŽÆ **Multi-Language Support**: Works with Node.js, Go, Rust, Python, PHP, Java, and more
12
+ - šŸ–„ļø **Tmux Integration**: Professional terminal multiplexing for service management
7
13
 
8
14
  ## Installation
9
15
 
10
16
  ```bash
11
- npm i -g @abyrd9/harbor-cli
17
+ npm install -g @abyrd9/harbor-cli
12
18
  ```
13
19
 
14
20
  ## Prerequisites
15
21
 
16
- Before using Harbor, make sure you have the following installed:
22
+ Harbor automatically checks for these required dependencies:
23
+
24
+ - **[tmux](https://github.com/tmux/tmux/wiki/Installing)** - Terminal multiplexer for managing services
25
+ - **[jq](https://stedolan.github.io/jq/download/)** - JSON processor for service management
17
26
 
18
- - [tmux](https://github.com/tmux/tmux/wiki/Installing) (for terminal multiplexing)
19
- - [jq](https://stedolan.github.io/jq/download/) (for JSON processing within tmux)
27
+ If missing, Harbor will provide installation instructions.
20
28
 
21
29
  ## Quick Start
22
30
 
23
- 1. Initialize your development environment:
24
- ```bash
25
- harbor dock
26
- ```
31
+ 1. **Initialize your project**:
32
+ ```bash
33
+ harbor dock
34
+ ```
35
+ This scans your directory structure and creates a harbor configuration.
27
36
 
28
- 2. Add new services to your configuration:
29
- ```bash
30
- harbor moor
31
- ```
37
+ 2. **Add more services** (optional):
38
+ ```bash
39
+ harbor moor
40
+ ```
41
+ Scans for new services and adds them to your configuration.
32
42
 
33
- 3. Launch your services:
34
- ```bash
35
- harbor launch
36
- ```
43
+ 3. **Launch all services**:
44
+ ```bash
45
+ harbor launch
46
+ ```
47
+ Starts all configured services in organized tmux windows.
37
48
 
38
49
  ## Configuration
39
50
 
40
- Harbor uses a configuration file to manage your services:
51
+ Harbor supports two configuration formats:
41
52
 
42
- ### harbor.json
53
+ ### Option 1: harbor.json
43
54
 
44
- Contains your service configurations that are used to launch the services:
55
+ Create a dedicated configuration file:
45
56
 
46
57
  ```json
47
58
  {
@@ -57,34 +68,234 @@ Contains your service configurations that are used to launch the services:
57
68
  "command": "go run ."
58
69
  },
59
70
  {
60
- "name": "dashboard",
61
- "path": "./vite-frontend",
62
- "command": "npx drizzle-kit studio"
71
+ "name": "database",
72
+ "path": "./db",
73
+ "command": "docker-compose up"
74
+ }
75
+ ],
76
+ "before": [
77
+ {
78
+ "path": "./",
79
+ "command": "echo 'Starting development environment...' && docker-compose up -d"
80
+ },
81
+ {
82
+ "path": "./scripts",
83
+ "command": "./setup-dev.sh"
84
+ }
85
+ ],
86
+ "after": [
87
+ {
88
+ "path": "./",
89
+ "command": "echo 'Development environment ready!'"
63
90
  }
64
91
  ]
65
92
  }
66
93
  ```
67
94
 
95
+ ### Option 2: package.json
96
+
97
+ Store configuration directly in your `package.json`:
98
+
99
+ ```json
100
+ {
101
+ "name": "my-project",
102
+ "version": "1.0.0",
103
+ "harbor": {
104
+ "services": [
105
+ {
106
+ "name": "frontend",
107
+ "path": "./frontend",
108
+ "command": "npm run dev"
109
+ },
110
+ {
111
+ "name": "api",
112
+ "path": "./api",
113
+ "command": "go run main.go"
114
+ }
115
+ ],
116
+ "before": [
117
+ {
118
+ "path": "./",
119
+ "command": "docker-compose up -d database"
120
+ }
121
+ ],
122
+ "after": [
123
+ {
124
+ "path": "./",
125
+ "command": "echo 'All services are running!'"
126
+ }
127
+ ]
128
+ }
129
+ }
130
+ ```
131
+
68
132
  ## Commands
69
133
 
70
- - `harbor dock`: Generate a new harbor.json file
71
- - `harbor moor`: Add new services to your harbor.json file
72
- - `harbor launch`: Start all services defined in your harbor.json file in a tmux session
134
+ | Command | Description |
135
+ |---------|-------------|
136
+ | `harbor dock` | Initialize harbor configuration by scanning project directories |
137
+ | `harbor moor` | Scan for and add new services to existing configuration |
138
+ | `harbor launch` | Start all services in tmux sessions |
139
+ | `harbor --help` | Show help and available commands |
140
+ | `harbor --version` | Show version information |
141
+
142
+ ### Command Options
143
+
144
+ - `-p, --path <path>`: Specify project root path (defaults to `./`)
145
+
146
+ ## Supported Project Types
147
+
148
+ Harbor automatically detects and configures services for:
149
+
150
+ - **Node.js**: `package.json` → `npm run dev`
151
+ - **Go**: `go.mod` → `go run .`
152
+ - **Rust**: `Cargo.toml` → `cargo run`
153
+ - **Python**: `requirements.txt` → `python app.py`
154
+ - **PHP**: `composer.json` → `php artisan serve`
155
+ - **Java**: `pom.xml`/`build.gradle` → `mvn spring-boot:run` or `./gradlew bootRun`
156
+
157
+ ## How It Works
158
+
159
+ 1. **Service Discovery**: Harbor scans your directory for folders containing project files
160
+ 2. **Command Detection**: Based on project type, suggests appropriate development commands
161
+ 3. **Configuration Generation**: Creates/updates harbor config with discovered services
162
+ 4. **Tmux Session**: Launches each service in its own tmux window with proper working directories
163
+ 5. **Process Management**: All services run independently with proper I/O handling
73
164
 
74
- ## Terminal Multiplexer
165
+ ## Terminal Multiplexer (Tmux)
75
166
 
76
- Harbor uses tmux for managing your services. Some useful shortcuts:
167
+ Harbor uses tmux for professional service management. Essential shortcuts:
77
168
 
78
- - `Ctrl+a d`: Detach from session
79
- - `Ctrl+a c`: Create new window
80
- - `Ctrl+a n`: Next window
81
- - `Ctrl+a p`: Previous window
82
- - `Ctrl+q`: Quit session
169
+ ### Session Management
170
+ - `Ctrl+a d` - Detach from session (services continue running)
171
+ - `Ctrl+a :attach` - Reattach to session
172
+ - `Ctrl+a &` - Kill current window
173
+ - `Ctrl+a ?` - Show all keybindings
174
+
175
+ ### Window Navigation
176
+ - `Ctrl+a c` - Create new window
177
+ - `Ctrl+a n` - Next window
178
+ - `Ctrl+a p` - Previous window
179
+ - `Ctrl+a 0-9` - Jump to window number
180
+ - `Ctrl+a w` - List all windows
181
+
182
+ ### Pane Management
183
+ - `Ctrl+a %` - Split window vertically
184
+ - `Ctrl+a "` - Split window horizontally
185
+ - `Ctrl+a →/←/↑/↓` - Navigate between panes
186
+ - `Ctrl+a x` - Close current pane
187
+
188
+ ## Advanced Usage
189
+
190
+ ### Custom Commands
191
+ Override auto-detected commands by editing your configuration:
192
+
193
+ ```json
194
+ {
195
+ "services": [
196
+ {
197
+ "name": "custom-service",
198
+ "path": "./my-service",
199
+ "command": "custom-command --with-flags"
200
+ }
201
+ ]
202
+ }
203
+ ```
204
+
205
+ ### Before/After Scripts
206
+ Run custom scripts before and after your services start:
207
+
208
+ ```json
209
+ {
210
+ "before": [
211
+ {
212
+ "path": "./infrastructure",
213
+ "command": "docker-compose up -d"
214
+ },
215
+ {
216
+ "path": "./",
217
+ "command": "npm run setup:dev"
218
+ }
219
+ ],
220
+ "after": [
221
+ {
222
+ "path": "./",
223
+ "command": "npm run seed:database"
224
+ },
225
+ {
226
+ "path": "./scripts",
227
+ "command": "./notify-dev-ready.sh"
228
+ }
229
+ ]
230
+ }
231
+ ```
232
+
233
+ **Execution Flow:**
234
+ 1. **Before scripts** run sequentially before services start
235
+ 2. Services launch in tmux windows
236
+ 3. **After scripts** run sequentially after services are ready
237
+
238
+ **Use Cases:**
239
+ - Set up databases or infrastructure
240
+ - Run database migrations or seeds
241
+ - Send notifications when environment is ready
242
+ - Clean up temporary files
243
+ - Run integration tests
244
+
245
+ ### Selective Launch
246
+ Currently launches all services. Future versions may support selective service launching.
247
+
248
+ ### Environment Variables
249
+ Services inherit your shell environment. Use `.env` files or export variables before running `harbor launch`.
250
+
251
+ ## Troubleshooting
252
+
253
+ ### Common Issues
254
+
255
+ 1. **"Missing required dependencies"**
256
+ - Install tmux and jq as indicated in the error message
257
+
258
+ 2. **"No harbor configuration found"**
259
+ - Run `harbor dock` to initialize configuration
260
+ - Ensure you're in the correct project directory
261
+
262
+ 3. **Services not starting**
263
+ - Check that commands are correct in your harbor configuration
264
+ - Verify project dependencies are installed in each service directory
265
+ - Check tmux windows for error messages
266
+
267
+ 4. **Tmux not responding**
268
+ - Try `tmux kill-session -t harbor` to clean up
269
+ - Restart with `harbor launch`
270
+
271
+ ## Examples
272
+
273
+ ### Monorepo Setup
274
+ ```
275
+ my-project/
276
+ ā”œā”€ā”€ frontend/ (package.json)
277
+ ā”œā”€ā”€ backend/ (go.mod)
278
+ ā”œā”€ā”€ database/ (docker-compose.yml)
279
+ └── harbor.json
280
+ ```
281
+
282
+ ### Polyglot Microservices
283
+ ```
284
+ services/
285
+ ā”œā”€ā”€ auth-service/ (Node.js)
286
+ ā”œā”€ā”€ user-service/ (Go)
287
+ ā”œā”€ā”€ payment-service/ (Python)
288
+ └── notification-service/ (Rust)
289
+ ```
83
290
 
84
291
  ## Contributing
85
292
 
86
- Contributions are welcome! Please feel free to submit a Pull Request.
293
+ Contributions are welcome! Please feel free to:
294
+
295
+ - Report bugs and request features via GitHub Issues
296
+ - Submit pull requests for improvements
297
+ - Help improve documentation
87
298
 
88
299
  ## License
89
300
 
90
- MIT
301
+ MIT - See LICENSE file for details
package/dist/index.js CHANGED
@@ -148,6 +148,36 @@ function validateConfig(config) {
148
148
  return 'Service path is required';
149
149
  }
150
150
  }
151
+ // Validate before scripts
152
+ if (config.before && !Array.isArray(config.before)) {
153
+ return 'Before scripts must be an array';
154
+ }
155
+ if (config.before) {
156
+ for (let i = 0; i < config.before.length; i++) {
157
+ const script = config.before[i];
158
+ if (!script.path) {
159
+ return `Before script ${i} must have a path`;
160
+ }
161
+ if (!script.command) {
162
+ return `Before script ${i} must have a command`;
163
+ }
164
+ }
165
+ }
166
+ // Validate after scripts
167
+ if (config.after && !Array.isArray(config.after)) {
168
+ return 'After scripts must be an array';
169
+ }
170
+ if (config.after) {
171
+ for (let i = 0; i < config.after.length; i++) {
172
+ const script = config.after[i];
173
+ if (!script.path) {
174
+ return `After script ${i} must have a path`;
175
+ }
176
+ if (!script.command) {
177
+ return `After script ${i} must have a command`;
178
+ }
179
+ }
180
+ }
151
181
  return null;
152
182
  }
153
183
  async function generateDevFile(dirPath) {
@@ -178,6 +208,8 @@ async function generateDevFile(dirPath) {
178
208
  writeToPackageJson = true;
179
209
  config = {
180
210
  services: [],
211
+ before: [],
212
+ after: [],
181
213
  };
182
214
  console.log('Creating new harbor config in package.json...');
183
215
  }
@@ -185,6 +217,8 @@ async function generateDevFile(dirPath) {
185
217
  // No package.json, create harbor.json
186
218
  config = {
187
219
  services: [],
220
+ before: [],
221
+ after: [],
188
222
  };
189
223
  console.log('Creating new harbor.json...');
190
224
  }
@@ -296,6 +330,41 @@ async function readHarborConfig() {
296
330
  }
297
331
  throw new Error('No harbor configuration found in harbor.json or package.json');
298
332
  }
333
+ async function execute(scripts, scriptType) {
334
+ if (!scripts || scripts.length === 0) {
335
+ return;
336
+ }
337
+ console.log(`\nšŸš€ Executing ${scriptType} scripts...`);
338
+ for (let i = 0; i < scripts.length; i++) {
339
+ const script = scripts[i];
340
+ console.log(`\nšŸ“‹ Running ${scriptType} script ${i + 1}/${scripts.length}: ${script.command}`);
341
+ console.log(` šŸ“ In directory: ${script.path}`);
342
+ try {
343
+ await new Promise((resolve, reject) => {
344
+ const process = spawn('sh', ['-c', `cd "${script.path}" && ${script.command}`], {
345
+ stdio: 'inherit',
346
+ });
347
+ process.on('close', (code) => {
348
+ if (code === 0) {
349
+ console.log(`āœ… ${scriptType} script ${i + 1} completed successfully`);
350
+ resolve(null);
351
+ }
352
+ else {
353
+ reject(new Error(`${scriptType} script ${i + 1} exited with code ${code}`));
354
+ }
355
+ });
356
+ process.on('error', (err) => {
357
+ reject(new Error(`${scriptType} script ${i + 1} failed: ${err.message}`));
358
+ });
359
+ });
360
+ }
361
+ catch (err) {
362
+ console.error(`āŒ Error executing ${scriptType} script ${i + 1}:`, err instanceof Error ? err.message : 'Unknown error');
363
+ throw err;
364
+ }
365
+ }
366
+ console.log(`\nāœ… All ${scriptType} scripts completed successfully`);
367
+ }
299
368
  async function runServices() {
300
369
  const hasHarborConfig = checkHasHarborConfig();
301
370
  if (!hasHarborConfig) {
@@ -318,6 +387,14 @@ async function runServices() {
318
387
  console.error('Error reading config:', err);
319
388
  process.exit(1);
320
389
  }
390
+ // Execute before scripts
391
+ try {
392
+ await execute(config.before || [], 'before');
393
+ }
394
+ catch (err) {
395
+ console.error('āŒ Before scripts failed, aborting launch');
396
+ process.exit(1);
397
+ }
321
398
  // Ensure scripts exist and are executable
322
399
  await ensureScriptsExist();
323
400
  // Execute the script directly using spawn to handle I/O streams
@@ -330,12 +407,20 @@ async function runServices() {
330
407
  console.error(`Error running dev.sh: ${err}`);
331
408
  process.exit(1);
332
409
  });
333
- command.on('close', (code) => {
410
+ command.on('close', async (code) => {
334
411
  if (code !== 0) {
335
412
  console.error(`dev.sh exited with code ${code}`);
336
413
  process.exit(1);
337
414
  }
338
- resolve();
415
+ // Execute after scripts
416
+ try {
417
+ await execute(config.after || [], 'after');
418
+ resolve();
419
+ }
420
+ catch (err) {
421
+ console.error('āŒ After scripts failed');
422
+ process.exit(1);
423
+ }
339
424
  });
340
425
  });
341
426
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abyrd9/harbor-cli",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "A CLI tool for managing simple local development services with tmux sessions",
5
5
  "type": "module",
6
6
  "bin": {
@@ -38,12 +38,12 @@
38
38
  "node": ">=18.0.0"
39
39
  },
40
40
  "dependencies": {
41
- "@commander-js/extra-typings": "^13.1.0"
41
+ "@commander-js/extra-typings": "^14.0.0"
42
42
  },
43
43
  "devDependencies": {
44
- "@types/node": "^22.13.1",
44
+ "@types/node": "^24.0.3",
45
45
  "bun-types": "latest",
46
- "typescript": "^5.7.3"
46
+ "typescript": "^5.8.3"
47
47
  },
48
48
  "main": "index.js",
49
49
  "harbor": {