@gachlab/devup 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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +332 -0
  3. package/dist/chunk-LG7UD5ZR.js +54 -0
  4. package/dist/chunk-LG7UD5ZR.js.map +1 -0
  5. package/dist/config/cli.d.ts +17 -0
  6. package/dist/config/cli.d.ts.map +1 -0
  7. package/dist/config/loader.d.ts +4 -0
  8. package/dist/config/loader.d.ts.map +1 -0
  9. package/dist/config/types.d.ts +37 -0
  10. package/dist/config/types.d.ts.map +1 -0
  11. package/dist/config/validator.d.ts +8 -0
  12. package/dist/config/validator.d.ts.map +1 -0
  13. package/dist/darwin-3KJ3IEXN.js +17 -0
  14. package/dist/darwin-3KJ3IEXN.js.map +1 -0
  15. package/dist/index.d.ts +5 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +1336 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/lazy/classifier.d.ts +14 -0
  20. package/dist/lazy/classifier.d.ts.map +1 -0
  21. package/dist/lazy/proxy.d.ts +17 -0
  22. package/dist/lazy/proxy.d.ts.map +1 -0
  23. package/dist/linux-OQ3Q4Z2Z.js +8 -0
  24. package/dist/linux-OQ3Q4Z2Z.js.map +1 -0
  25. package/dist/platform/darwin.d.ts +6 -0
  26. package/dist/platform/darwin.d.ts.map +1 -0
  27. package/dist/platform/detect.d.ts +3 -0
  28. package/dist/platform/detect.d.ts.map +1 -0
  29. package/dist/platform/linux.d.ts +8 -0
  30. package/dist/platform/linux.d.ts.map +1 -0
  31. package/dist/platform/types.d.ts +11 -0
  32. package/dist/platform/types.d.ts.map +1 -0
  33. package/dist/platform/win32.d.ts +8 -0
  34. package/dist/platform/win32.d.ts.map +1 -0
  35. package/dist/process/health.d.ts +8 -0
  36. package/dist/process/health.d.ts.map +1 -0
  37. package/dist/process/installer.d.ts +12 -0
  38. package/dist/process/installer.d.ts.map +1 -0
  39. package/dist/process/manager.d.ts +26 -0
  40. package/dist/process/manager.d.ts.map +1 -0
  41. package/dist/process/types.d.ts +21 -0
  42. package/dist/process/types.d.ts.map +1 -0
  43. package/dist/proxy-config/detect.d.ts +3 -0
  44. package/dist/proxy-config/detect.d.ts.map +1 -0
  45. package/dist/proxy-config/traefik.d.ts +8 -0
  46. package/dist/proxy-config/traefik.d.ts.map +1 -0
  47. package/dist/proxy-config/types.d.ts +21 -0
  48. package/dist/proxy-config/types.d.ts.map +1 -0
  49. package/dist/tui/App.d.ts +17 -0
  50. package/dist/tui/App.d.ts.map +1 -0
  51. package/dist/tui/LogsPanel.d.ts +14 -0
  52. package/dist/tui/LogsPanel.d.ts.map +1 -0
  53. package/dist/tui/SearchInput.d.ts +7 -0
  54. package/dist/tui/SearchInput.d.ts.map +1 -0
  55. package/dist/tui/ServiceList.d.ts +11 -0
  56. package/dist/tui/ServiceList.d.ts.map +1 -0
  57. package/dist/tui/StatsPanel.d.ts +13 -0
  58. package/dist/tui/StatsPanel.d.ts.map +1 -0
  59. package/dist/tui/StatusBar.d.ts +2 -0
  60. package/dist/tui/StatusBar.d.ts.map +1 -0
  61. package/dist/tui/hooks/useKeyBindings.d.ts +31 -0
  62. package/dist/tui/hooks/useKeyBindings.d.ts.map +1 -0
  63. package/dist/tui/hooks/useProcessManager.d.ts +26 -0
  64. package/dist/tui/hooks/useProcessManager.d.ts.map +1 -0
  65. package/dist/tui/hooks/useProxySync.d.ts +4 -0
  66. package/dist/tui/hooks/useProxySync.d.ts.map +1 -0
  67. package/dist/utils.d.ts +22 -0
  68. package/dist/utils.d.ts.map +1 -0
  69. package/dist/win32-3X2OLSI6.js +49 -0
  70. package/dist/win32-3X2OLSI6.js.map +1 -0
  71. package/package.json +67 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gachlab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,332 @@
1
+ # devup
2
+
3
+ [![CI](https://github.com/gachlab/devup/actions/workflows/ci.yml/badge.svg)](https://github.com/gachlab/devup/actions/workflows/ci.yml)
4
+
5
+ A terminal UI dev stack runner for Node.js monorepos. Define your services in a config file, and devup handles the rest: phased startup, health checks, lazy on-demand proxies, process stats, and reverse proxy config generation — all in a single TUI dashboard.
6
+
7
+ Built with TypeScript 6, Ink (React for terminals), and zero test dependencies (uses `node:test` natively).
8
+
9
+ ## Features
10
+
11
+ - **Phased startup** — boot services in dependency order with automatic port readiness detection
12
+ - **Lazy mode** — only start services when they receive traffic. Idle services shut down after a configurable timeout
13
+ - **TUI dashboard** — live logs and process stats (CPU, memory, health, errors, restarts) in a split-panel terminal UI
14
+ - **Cross-platform** — Linux, macOS, and Windows. Platform-specific process management, stats collection, and browser opening
15
+ - **Reverse proxy config** — generate Traefik (or other) dynamic config from running services. Health-aware: only routes to healthy services
16
+ - **Project-agnostic** — works with any Node.js monorepo. Your project defines a `devup.config.ts`, devup does the rest
17
+ - **npm install management** — automatic dependency installation with hash-based stamps to skip redundant installs
18
+ - **Auto-restart with backoff** — crashed services restart automatically with exponential backoff (2s → 4s → 8s), max 3 attempts
19
+ - **Port conflict detection** — checks if a port is already in use before starting a service
20
+
21
+ ## Quick start
22
+
23
+ ### 1. Install
24
+
25
+ ```bash
26
+ npm install -D @gachlab/devup
27
+ ```
28
+
29
+ ### 2. Create config
30
+
31
+ Create `devup.config.ts` in your project root:
32
+
33
+ ```typescript
34
+ import { defineConfig } from '@gachlab/devup';
35
+
36
+ export default defineConfig({
37
+ name: 'MyProject',
38
+ icon: '🚀',
39
+ envFile: '.env',
40
+
41
+ services: [
42
+ {
43
+ name: 'api',
44
+ cwd: 'packages/api',
45
+ cmd: 'node',
46
+ args: ['--watch-path', 'src', 'src/index.js'],
47
+ type: 'api',
48
+ port: 3000,
49
+ phase: 0,
50
+ maxMem: 256,
51
+ },
52
+ {
53
+ name: 'web',
54
+ cwd: 'packages/web',
55
+ cmd: 'npx',
56
+ args: ['vite', '--port', '4200'],
57
+ type: 'web',
58
+ port: 4200,
59
+ phase: 1,
60
+ maxMem: 512,
61
+ },
62
+ ],
63
+ });
64
+ ```
65
+
66
+ ### 3. Run
67
+
68
+ ```bash
69
+ npx devup
70
+ ```
71
+
72
+ ## Config reference
73
+
74
+ ### `DevStackConfig`
75
+
76
+ | Field | Type | Required | Description |
77
+ |---|---|---|---|
78
+ | `name` | `string` | ✅ | Project name shown in the TUI header |
79
+ | `icon` | `string` | | Emoji shown before the project name. Default: `📦` |
80
+ | `envFile` | `string` | | Path to `.env` file relative to project root. Default: `.env` |
81
+ | `env` | `Record<string, string>` | | Extra environment variables. Won't overwrite existing ones |
82
+ | `services` | `ServiceConfig[]` | ✅ | List of services to manage |
83
+ | `lazy` | `LazyConfig` | | Lazy mode configuration |
84
+ | `proxy` | `ProxyConfig` | | Reverse proxy config generation |
85
+
86
+ ### `ServiceConfig`
87
+
88
+ | Field | Type | Required | Description |
89
+ |---|---|---|---|
90
+ | `name` | `string` | ✅ | Unique service name |
91
+ | `cwd` | `string` | ✅ | Working directory relative to project root |
92
+ | `cmd` | `string` | ✅ | Command to run (`node`, `npx`, etc.) |
93
+ | `args` | `string[]` | ✅ | Command arguments |
94
+ | `type` | `'api' \| 'web'` | ✅ | Service type. APIs get health-checked; webs are assumed ready after start |
95
+ | `port` | `number` | ✅ | Port the service listens on. Must be unique |
96
+ | `phase` | `number` | ✅ | Startup phase (0 = first). Services in the same phase start together; devup waits for all APIs in a phase to be ready before starting the next phase |
97
+ | `maxMem` | `number` | | Max memory in MB. Injects `--max-old-space-size` for `node` commands, or `NODE_OPTIONS` for `npx` |
98
+ | `preBuild` | `string` | | Command to run before starting (e.g., `npm run build`) |
99
+ | `watchBuild` | `string` | | Watch command to run alongside the service (e.g., `npx tsup --watch`) |
100
+ | `nodeArgs` | `string[]` | | Extra Node.js arguments |
101
+ | `extraEnv` | `Record<string, string>` | | Extra environment variables for this service |
102
+
103
+ ### `LazyConfig`
104
+
105
+ | Field | Type | Required | Description |
106
+ |---|---|---|---|
107
+ | `alwaysOn` | `string[]` | ✅ | Service names that always start immediately |
108
+ | `timeout` | `number` | | Minutes of inactivity before stopping a lazy service. Default: `10` |
109
+
110
+ When lazy mode is active (default), services not in `alwaysOn` start a TCP proxy on their port. The real service only boots when something connects to that port. After `timeout` minutes of no connections, the service shuts down and returns to idle.
111
+
112
+ ### `ProxyConfig`
113
+
114
+ | Field | Type | Required | Description |
115
+ |---|---|---|---|
116
+ | `provider` | `string` | ✅ | Proxy provider name. Currently: `'traefik'` |
117
+ | `routes` | `Record<string, string>` | ✅ | Map of service name → subdomain. Empty string = root domain |
118
+ | `confPath` | `string` | | Path to write the config file. Default: `~/.traefik/traefik_conf.yaml` |
119
+ | `host` | `string` | | Target host for proxy URLs. Default: auto-detected per platform |
120
+ | `tls` | `boolean` | | Enable TLS config. Default: `true` |
121
+ | `entrypoint` | `string` | | Proxy entrypoint name. Default: `'websecure'` |
122
+
123
+ The proxy config is only generated when `--proxy` is passed on the CLI. Only services with `health === 'up'` are included in the generated config.
124
+
125
+ ## CLI flags
126
+
127
+ ```
128
+ devup [options]
129
+ ```
130
+
131
+ ### Service selection
132
+
133
+ | Flag | Description |
134
+ |---|---|
135
+ | `--only apis` | Only start API services |
136
+ | `--only webs` | Only start web services |
137
+ | `--services api,web,auth` | Start only the named services |
138
+ | `--skip tasks-api,pickup-api` | Start everything except these |
139
+ | `--config path/to/config.ts` | Use a custom config file |
140
+
141
+ ### Lazy mode
142
+
143
+ | Flag | Description |
144
+ |---|---|
145
+ | `--lazy` | Enable lazy mode (default) |
146
+ | `--no-lazy` | Disable lazy mode — start everything immediately |
147
+ | `--timeout 15` | Idle timeout in minutes (default: 10) |
148
+
149
+ ### Reverse proxy
150
+
151
+ | Flag | Description |
152
+ |---|---|
153
+ | `--proxy` | Enable proxy config generation |
154
+ | `--proxy-host 127.0.0.1` | Override target host |
155
+ | `--proxy-conf /path/to/file` | Override config file path |
156
+ | `--proxy-tls` | Enable TLS (default) |
157
+ | `--no-proxy-tls` | Disable TLS |
158
+ | `--proxy-entrypoint web` | Override entrypoint name |
159
+
160
+ ## TUI keybindings
161
+
162
+ | Key | Action |
163
+ |---|---|
164
+ | `q` / `Ctrl+C` | Quit and stop all services |
165
+ | `Tab` | Switch focus between Logs and Stats panels |
166
+ | `f` | Filter logs by service |
167
+ | `a` | Show all logs (clear filter) |
168
+ | `/` | Search in logs |
169
+ | `p` | Pause/resume log output |
170
+ | `t` | Toggle timestamps |
171
+ | `c` | Clear logs |
172
+ | `s` | Cycle sort mode (name → memory → errors) |
173
+ | `r` | Restart a service |
174
+ | `o` | Open a web service in browser |
175
+ | `T` | Toggle reverse proxy config sync |
176
+
177
+ ## Config file formats
178
+
179
+ devup looks for config files in this order:
180
+
181
+ 1. `devup.config.ts` — TypeScript with full type checking and intellisense
182
+ 2. `devup.config.js` — JavaScript (ESM or CJS)
183
+ 3. `devup.config.json` — JSON (no functions or imports)
184
+
185
+ Or pass `--config path/to/file` to use a custom path.
186
+
187
+ ## Phases
188
+
189
+ Services boot in phase order. Within a phase, all services start simultaneously. devup waits for all API services in a phase to respond on their port before moving to the next phase.
190
+
191
+ ```
192
+ Phase 0: Core infrastructure (config server, auth)
193
+ Phase 1: Base APIs (app, users, files, events)
194
+ Phase 2: Dependent APIs (communications, notifications)
195
+ Phase 3: Final APIs
196
+ Phase 4: Frontends (Angular, Svelte, React, Vite)
197
+ ```
198
+
199
+ Phase numbers are arbitrary — use whatever makes sense for your dependency graph.
200
+
201
+ ## Lazy mode
202
+
203
+ In lazy mode, devup creates a TCP proxy on each lazy service's original port. The real service runs on `port + 10000` when started.
204
+
205
+ ```
206
+ Client → :3000 (proxy) → :13000 (real service)
207
+ ```
208
+
209
+ When a connection arrives and the service is idle, devup:
210
+ 1. Runs `npm install` if needed
211
+ 2. Starts the service on the offset port
212
+ 3. Waits for the port to be ready
213
+ 4. Pipes the buffered connection through
214
+
215
+ After `timeout` minutes with no connections, the service stops and returns to idle.
216
+
217
+ Services listed in `lazy.alwaysOn` skip the proxy and start normally.
218
+
219
+ ## Platform support
220
+
221
+ | Feature | Linux | macOS | Windows |
222
+ |---|---|---|---|
223
+ | Process stats (CPU, memory) | `ps` | `ps` | `wmic` |
224
+ | Kill process tree | `kill -pid` | `kill -pid` | `taskkill /T /F` |
225
+ | Open browser | `xdg-open` | `open` | `cmd /c start` |
226
+ | Default proxy host | `172.17.0.1` | `host.docker.internal` | `host.docker.internal` |
227
+
228
+ ## Reverse proxy providers
229
+
230
+ devup generates dynamic config for reverse proxies. Currently supported:
231
+
232
+ ### Traefik
233
+
234
+ Generates a YAML file for Traefik's [file provider](https://doc.traefik.io/traefik/providers/file/). Mount the config file as a volume in your Traefik container.
235
+
236
+ ```yaml
237
+ # docker-compose.yml
238
+ services:
239
+ traefik:
240
+ volumes:
241
+ - ~/.traefik:/etc/traefik/dynamic
242
+ ```
243
+
244
+ ```bash
245
+ devup --proxy --proxy-host 172.17.0.1
246
+ ```
247
+
248
+ Adding a new provider (Nginx, Caddy, etc.) requires implementing the `ProxyConfigProvider` interface:
249
+
250
+ ```typescript
251
+ interface ProxyConfigProvider {
252
+ readonly name: string;
253
+ generate(services: Map<string, ServiceState>, opts: ProxyOpts): string;
254
+ write(content: string, opts: ProxyOpts): void;
255
+ clear(opts: ProxyOpts): void;
256
+ }
257
+ ```
258
+
259
+ ## Example: full config
260
+
261
+ ```typescript
262
+ import { defineConfig } from '@gachlab/devup';
263
+
264
+ export default defineConfig({
265
+ name: 'MyApp',
266
+ icon: '⚡',
267
+ envFile: '.env',
268
+ env: {
269
+ DOMAIN: 'localhost',
270
+ },
271
+
272
+ services: [
273
+ // Phase 0 — Core
274
+ { name: 'config-api', cwd: 'config/api', cmd: 'node', args: ['src/index.js'], type: 'api', port: 2999, phase: 0, maxMem: 192 },
275
+
276
+ // Phase 1 — APIs
277
+ { name: 'auth-api', cwd: 'auth/api', cmd: 'node', args: ['src/index.js'], type: 'api', port: 3002, phase: 1, maxMem: 192 },
278
+ { name: 'app-api', cwd: 'app/api', cmd: 'node', args: ['src/index.js'], type: 'api', port: 3000, phase: 1, maxMem: 256 },
279
+ { name: 'files-api', cwd: 'files/api', cmd: 'node', args: ['src/index.js'], type: 'api', port: 3013, phase: 1, maxMem: 192 },
280
+
281
+ // Phase 1 — TypeScript API with build step
282
+ { name: 'orders-api', cwd: 'orders/api', cmd: 'node', args: ['dist/index.js'], type: 'api', port: 3031, phase: 1, maxMem: 256,
283
+ preBuild: 'npm run build', watchBuild: 'npx tsup --watch' },
284
+
285
+ // Phase 2 — Dependent APIs
286
+ { name: 'notifications-api', cwd: 'notifications/api', cmd: 'node', args: ['src/index.js'], type: 'api', port: 3010, phase: 2, maxMem: 256 },
287
+
288
+ // Phase 4 — Frontends
289
+ { name: 'app-web', cwd: 'app/web', cmd: 'npx', args: ['ng', 'serve', '--port', '4201'], type: 'web', port: 4201, phase: 4, maxMem: 512 },
290
+ { name: 'admin-web', cwd: 'admin/web', cmd: 'npx', args: ['vite', '--port', '4204'], type: 'web', port: 4204, phase: 4, maxMem: 384 },
291
+ { name: 'staff-web', cwd: 'staff/web', cmd: 'npx', args: ['vite', '--port', '4040'], type: 'web', port: 4040, phase: 4, maxMem: 384 },
292
+ ],
293
+
294
+ lazy: {
295
+ alwaysOn: ['config-api', 'app-web'],
296
+ timeout: 10,
297
+ },
298
+
299
+ proxy: {
300
+ provider: 'traefik',
301
+ routes: {
302
+ 'app-web': '',
303
+ 'admin-web': 'admin',
304
+ 'staff-web': 'staff',
305
+ 'app-api': 'app-api',
306
+ 'auth-api': 'auth-api',
307
+ 'files-api': 'files-api',
308
+ },
309
+ },
310
+ });
311
+ ```
312
+
313
+ ## Requirements
314
+
315
+ - Node.js >= 22
316
+ - npm (for dependency installation)
317
+ - A terminal with TTY support (for the interactive TUI)
318
+
319
+ ## Development
320
+
321
+ ```bash
322
+ git clone https://github.com/gachlab/devup.git
323
+ cd devup
324
+ npm install
325
+ npm run build
326
+ npm test # 112 tests, node:test native
327
+ npm run test:coverage # coverage report
328
+ ```
329
+
330
+ ## License
331
+
332
+ MIT © gachlab
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/platform/linux.ts
4
+ import { exec, spawn } from "child_process";
5
+ function parsePsTime(time) {
6
+ const parts = time.split(":").map(Number);
7
+ if (parts.length === 3) return parts[0] * 3600 + parts[1] * 60 + parts[2];
8
+ if (parts.length === 2) return parts[0] * 60 + parts[1];
9
+ return 0;
10
+ }
11
+ var LinuxPlatform = class {
12
+ defaultTraefikHost = "172.17.0.1";
13
+ getProcessStats(pids) {
14
+ if (!pids.length) return Promise.resolve(/* @__PURE__ */ new Map());
15
+ return new Promise((resolve) => {
16
+ exec(
17
+ `ps -o pid=,rss=,time= -p ${pids.join(",")} 2>/dev/null || true`,
18
+ { encoding: "utf8", timeout: 5e3 },
19
+ (err, stdout) => {
20
+ const map = /* @__PURE__ */ new Map();
21
+ if (err || !stdout) return resolve(map);
22
+ for (const line of stdout.trim().split("\n")) {
23
+ const parts = line.trim().split(/\s+/);
24
+ if (parts.length < 3) continue;
25
+ const pid = parseInt(parts[0], 10);
26
+ map.set(pid, {
27
+ rss: parseInt(parts[1], 10) || 0,
28
+ cpuSeconds: parsePsTime(parts[2])
29
+ });
30
+ }
31
+ resolve(map);
32
+ }
33
+ );
34
+ });
35
+ }
36
+ killTree(pid, signal = "SIGTERM") {
37
+ try {
38
+ process.kill(-pid, signal);
39
+ } catch {
40
+ try {
41
+ process.kill(pid, signal);
42
+ } catch {
43
+ }
44
+ }
45
+ }
46
+ openBrowser(url) {
47
+ spawn("xdg-open", [url], { detached: true, stdio: "ignore" }).unref();
48
+ }
49
+ };
50
+
51
+ export {
52
+ LinuxPlatform
53
+ };
54
+ //# sourceMappingURL=chunk-LG7UD5ZR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/platform/linux.ts"],"sourcesContent":["import { exec, spawn } from 'node:child_process';\nimport type { Platform, ProcessStats } from './types.js';\n\nfunction parsePsTime(time: string): number {\n const parts = time.split(':').map(Number);\n if (parts.length === 3) return parts[0]! * 3600 + parts[1]! * 60 + parts[2]!;\n if (parts.length === 2) return parts[0]! * 60 + parts[1]!;\n return 0;\n}\n\nexport class LinuxPlatform implements Platform {\n readonly defaultTraefikHost: string = '172.17.0.1';\n\n getProcessStats(pids: number[]): Promise<Map<number, ProcessStats>> {\n if (!pids.length) return Promise.resolve(new Map());\n\n return new Promise(resolve => {\n exec(\n `ps -o pid=,rss=,time= -p ${pids.join(',')} 2>/dev/null || true`,\n { encoding: 'utf8', timeout: 5000 },\n (err, stdout) => {\n const map = new Map<number, ProcessStats>();\n if (err || !stdout) return resolve(map);\n\n for (const line of stdout.trim().split('\\n')) {\n const parts = line.trim().split(/\\s+/);\n if (parts.length < 3) continue;\n const pid = parseInt(parts[0]!, 10);\n map.set(pid, {\n rss: parseInt(parts[1]!, 10) || 0,\n cpuSeconds: parsePsTime(parts[2]!),\n });\n }\n resolve(map);\n },\n );\n });\n }\n\n killTree(pid: number, signal: NodeJS.Signals = 'SIGTERM'): void {\n try { process.kill(-pid, signal); } catch {\n try { process.kill(pid, signal); } catch { /* already dead */ }\n }\n }\n\n openBrowser(url: string): void {\n spawn('xdg-open', [url], { detached: true, stdio: 'ignore' }).unref();\n }\n}\n"],"mappings":";;;AAAA,SAAS,MAAM,aAAa;AAG5B,SAAS,YAAY,MAAsB;AACzC,QAAM,QAAQ,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM;AACxC,MAAI,MAAM,WAAW,EAAG,QAAO,MAAM,CAAC,IAAK,OAAO,MAAM,CAAC,IAAK,KAAK,MAAM,CAAC;AAC1E,MAAI,MAAM,WAAW,EAAG,QAAO,MAAM,CAAC,IAAK,KAAK,MAAM,CAAC;AACvD,SAAO;AACT;AAEO,IAAM,gBAAN,MAAwC;AAAA,EACpC,qBAA6B;AAAA,EAEtC,gBAAgB,MAAoD;AAClE,QAAI,CAAC,KAAK,OAAQ,QAAO,QAAQ,QAAQ,oBAAI,IAAI,CAAC;AAElD,WAAO,IAAI,QAAQ,aAAW;AAC5B;AAAA,QACE,4BAA4B,KAAK,KAAK,GAAG,CAAC;AAAA,QAC1C,EAAE,UAAU,QAAQ,SAAS,IAAK;AAAA,QAClC,CAAC,KAAK,WAAW;AACf,gBAAM,MAAM,oBAAI,IAA0B;AAC1C,cAAI,OAAO,CAAC,OAAQ,QAAO,QAAQ,GAAG;AAEtC,qBAAW,QAAQ,OAAO,KAAK,EAAE,MAAM,IAAI,GAAG;AAC5C,kBAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,KAAK;AACrC,gBAAI,MAAM,SAAS,EAAG;AACtB,kBAAM,MAAM,SAAS,MAAM,CAAC,GAAI,EAAE;AAClC,gBAAI,IAAI,KAAK;AAAA,cACX,KAAK,SAAS,MAAM,CAAC,GAAI,EAAE,KAAK;AAAA,cAChC,YAAY,YAAY,MAAM,CAAC,CAAE;AAAA,YACnC,CAAC;AAAA,UACH;AACA,kBAAQ,GAAG;AAAA,QACb;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,SAAS,KAAa,SAAyB,WAAiB;AAC9D,QAAI;AAAE,cAAQ,KAAK,CAAC,KAAK,MAAM;AAAA,IAAG,QAAQ;AACxC,UAAI;AAAE,gBAAQ,KAAK,KAAK,MAAM;AAAA,MAAG,QAAQ;AAAA,MAAqB;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,YAAY,KAAmB;AAC7B,UAAM,YAAY,CAAC,GAAG,GAAG,EAAE,UAAU,MAAM,OAAO,SAAS,CAAC,EAAE,MAAM;AAAA,EACtE;AACF;","names":[]}
@@ -0,0 +1,17 @@
1
+ import type { ServiceConfig } from './types.js';
2
+ export interface CliArgs {
3
+ configPath?: string;
4
+ only?: string;
5
+ skip: string[];
6
+ services?: string[];
7
+ lazy: boolean;
8
+ lazyTimeout: number;
9
+ proxy: boolean;
10
+ proxyHost?: string;
11
+ proxyConf?: string;
12
+ proxyTls: boolean;
13
+ proxyEntrypoint: string;
14
+ }
15
+ export declare function parseCliArgs(argv: string[]): CliArgs;
16
+ export declare function filterServices(services: ServiceConfig[], args: CliArgs): ServiceConfig[];
17
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/config/cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,OAAO;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CACzB;AAID,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAgCpD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,aAAa,EAAE,CAoBxF"}
@@ -0,0 +1,4 @@
1
+ import type { DevStackConfig } from './types.js';
2
+ export declare function findConfigFile(cwd: string, explicit?: string): string;
3
+ export declare function loadConfig(configPath: string): Promise<DevStackConfig>;
4
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAQjD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAcrE;AAED,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAgB5E"}
@@ -0,0 +1,37 @@
1
+ export interface ServiceConfig {
2
+ name: string;
3
+ cwd: string;
4
+ cmd: string;
5
+ args: string[];
6
+ type: 'api' | 'web';
7
+ port: number;
8
+ phase: number;
9
+ maxMem?: number;
10
+ preBuild?: string;
11
+ watchBuild?: string;
12
+ nodeArgs?: string[];
13
+ extraEnv?: Record<string, string>;
14
+ }
15
+ export interface LazyConfig {
16
+ alwaysOn: string[];
17
+ timeout?: number;
18
+ }
19
+ export interface ProxyConfig {
20
+ provider: string;
21
+ routes: Record<string, string>;
22
+ confPath?: string;
23
+ host?: string;
24
+ tls?: boolean;
25
+ entrypoint?: string;
26
+ }
27
+ export interface DevStackConfig {
28
+ name: string;
29
+ icon?: string;
30
+ envFile?: string;
31
+ env?: Record<string, string>;
32
+ services: ServiceConfig[];
33
+ lazy?: LazyConfig;
34
+ proxy?: ProxyConfig;
35
+ }
36
+ export declare function defineConfig(config: DevStackConfig): DevStackConfig;
37
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAEnE"}
@@ -0,0 +1,8 @@
1
+ import type { DevStackConfig } from './types.js';
2
+ export interface ValidationError {
3
+ field: string;
4
+ message: string;
5
+ }
6
+ export declare function validateConfig(config: DevStackConfig, cwd: string): ValidationError[];
7
+ export declare function formatValidationErrors(errors: ValidationError[]): string;
8
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/config/validator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,eAAe,EAAE,CAuErF;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,CAExE"}
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ LinuxPlatform
4
+ } from "./chunk-LG7UD5ZR.js";
5
+
6
+ // src/platform/darwin.ts
7
+ import { spawn } from "child_process";
8
+ var DarwinPlatform = class extends LinuxPlatform {
9
+ defaultTraefikHost = "host.docker.internal";
10
+ openBrowser(url) {
11
+ spawn("open", [url], { detached: true, stdio: "ignore" }).unref();
12
+ }
13
+ };
14
+ export {
15
+ DarwinPlatform
16
+ };
17
+ //# sourceMappingURL=darwin-3KJ3IEXN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/platform/darwin.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport { LinuxPlatform } from './linux.js';\n\nexport class DarwinPlatform extends LinuxPlatform {\n override readonly defaultTraefikHost = 'host.docker.internal';\n\n override openBrowser(url: string): void {\n spawn('open', [url], { detached: true, stdio: 'ignore' }).unref();\n }\n}\n"],"mappings":";;;;;;AAAA,SAAS,aAAa;AAGf,IAAM,iBAAN,cAA6B,cAAc;AAAA,EAC9B,qBAAqB;AAAA,EAE9B,YAAY,KAAmB;AACtC,UAAM,QAAQ,CAAC,GAAG,GAAG,EAAE,UAAU,MAAM,OAAO,SAAS,CAAC,EAAE,MAAM;AAAA,EAClE;AACF;","names":[]}
@@ -0,0 +1,5 @@
1
+ export { defineConfig } from './config/types.js';
2
+ export type { DevStackConfig, ServiceConfig, LazyConfig, ProxyConfig } from './config/types.js';
3
+ export type { Platform, ProcessStats } from './platform/types.js';
4
+ export type { ProxyConfigProvider, ProxyOpts } from './proxy-config/types.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChG,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAClE,YAAY,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC"}