dev-prism 0.3.0 → 0.6.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 (100) hide show
  1. package/README.md +262 -70
  2. package/bin/dev-prism.js +45 -42
  3. package/dist/chunk-24OM3LGM.js +35 -0
  4. package/dist/chunk-3FYEGH2G.js +217 -0
  5. package/dist/chunk-3NW2OWIU.js +78 -0
  6. package/dist/chunk-3Q454U3I.js +71 -0
  7. package/dist/chunk-3TRRZEFR.js +38 -0
  8. package/dist/chunk-4UNCSJRM.js +70 -0
  9. package/dist/chunk-63II3EL4.js +98 -0
  10. package/dist/chunk-76LSQIZI.js +31 -0
  11. package/dist/chunk-7OSTLJLO.js +219 -0
  12. package/dist/chunk-7YEZWM6Y.js +97 -0
  13. package/dist/chunk-AEVARZQ4.js +203 -0
  14. package/dist/chunk-AIVPJ467.js +70 -0
  15. package/dist/chunk-AOM6BONB.js +98 -0
  16. package/dist/chunk-BXYXWNGH.js +30 -0
  17. package/dist/chunk-CUQVGZBX.js +44 -0
  18. package/dist/chunk-DQER5GNG.js +72 -0
  19. package/dist/chunk-DTE5YQMI.js +41 -0
  20. package/dist/chunk-EXRHG5KQ.js +60 -0
  21. package/dist/chunk-FKTFCSU7.js +78 -0
  22. package/dist/chunk-GKXXK2ZH.js +203 -0
  23. package/dist/chunk-H3L73URT.js +65 -0
  24. package/dist/chunk-H4HPDIY3.js +95 -0
  25. package/dist/chunk-HZBJF67X.js +60 -0
  26. package/dist/chunk-I3U6JK77.js +66 -0
  27. package/dist/chunk-JMKE3ZKI.js +61 -0
  28. package/dist/chunk-JZ2VPQXP.js +132 -0
  29. package/dist/chunk-KDYKLH6P.js +40 -0
  30. package/dist/chunk-KZJE62TK.js +203 -0
  31. package/dist/chunk-LAOWFCQL.js +21 -0
  32. package/dist/chunk-LNIOSGC4.js +78 -0
  33. package/dist/chunk-MRBTH5PL.js +66 -0
  34. package/dist/chunk-NNVP5F6I.js +77 -0
  35. package/dist/chunk-OL25TBYX.js +67 -0
  36. package/dist/chunk-OOJ6YOGS.js +53 -0
  37. package/dist/chunk-OPEZFBBI.js +219 -0
  38. package/dist/chunk-Q5DPX4WL.js +219 -0
  39. package/dist/chunk-RC2AUYZ7.js +49 -0
  40. package/dist/chunk-RQ245R7T.js +67 -0
  41. package/dist/chunk-SD3TON6N.js +32 -0
  42. package/dist/chunk-SEKH4ZV6.js +60 -0
  43. package/dist/chunk-SUMJLXT7.js +30 -0
  44. package/dist/chunk-UKYQN4A3.js +38 -0
  45. package/dist/chunk-URGGS3XM.js +95 -0
  46. package/dist/chunk-VUNPVDSO.js +74 -0
  47. package/dist/chunk-VXP2SPRI.js +51 -0
  48. package/dist/chunk-W54CPPSK.js +217 -0
  49. package/dist/chunk-X2PXZRYU.js +41 -0
  50. package/dist/chunk-X6FHBEAS.js +200 -0
  51. package/dist/chunk-YSO3IDZZ.js +40 -0
  52. package/dist/chunk-YY5DA35Z.js +40 -0
  53. package/dist/chunk-Z2ISJMLW.js +92 -0
  54. package/dist/chunk-ZKHNUDSL.js +119 -0
  55. package/dist/commands/create.d.ts +2 -1
  56. package/dist/commands/create.js +6 -5
  57. package/dist/commands/destroy.d.ts +1 -1
  58. package/dist/commands/destroy.js +4 -3
  59. package/dist/commands/info.d.ts +3 -0
  60. package/dist/commands/info.js +3 -2
  61. package/dist/commands/list.d.ts +1 -1
  62. package/dist/commands/list.js +3 -5
  63. package/dist/commands/logs.d.ts +8 -0
  64. package/dist/commands/logs.js +3 -2
  65. package/dist/commands/prune.d.ts +6 -0
  66. package/dist/commands/prune.js +4 -3
  67. package/dist/commands/start.d.ts +7 -0
  68. package/dist/commands/start.js +3 -2
  69. package/dist/commands/stop-all.d.ts +3 -0
  70. package/dist/commands/stop-all.js +3 -4
  71. package/dist/commands/stop.d.ts +3 -0
  72. package/dist/commands/stop.js +3 -2
  73. package/dist/index.d.ts +14 -2
  74. package/dist/index.js +36 -18
  75. package/dist/lib/compose.d.ts +12 -0
  76. package/dist/lib/compose.js +12 -0
  77. package/dist/lib/config.d.ts +4 -0
  78. package/dist/lib/config.test.d.ts +1 -0
  79. package/dist/lib/config.test.js +32 -0
  80. package/dist/lib/docker-inspect.d.ts +24 -0
  81. package/dist/lib/docker-inspect.js +16 -0
  82. package/dist/lib/env.d.ts +5 -4
  83. package/dist/lib/env.js +1 -1
  84. package/dist/lib/env.test.d.ts +1 -0
  85. package/dist/lib/env.test.js +68 -0
  86. package/dist/lib/ports.d.ts +3 -3
  87. package/dist/lib/ports.js +3 -3
  88. package/dist/lib/ports.test.d.ts +1 -0
  89. package/dist/lib/ports.test.js +61 -0
  90. package/dist/lib/session.d.ts +16 -0
  91. package/dist/lib/session.js +13 -0
  92. package/dist/lib/store.d.ts +46 -0
  93. package/dist/lib/store.js +1 -1
  94. package/dist/lib/store.test.d.ts +1 -0
  95. package/dist/lib/store.test.js +205 -0
  96. package/dist/lib/worktree.d.ts +3 -13
  97. package/dist/lib/worktree.js +1 -1
  98. package/dist/lib/worktree.test.d.ts +1 -0
  99. package/dist/lib/worktree.test.js +41 -0
  100. package/package.json +2 -5
package/README.md CHANGED
@@ -8,20 +8,22 @@ A minimal CLI tool for managing isolated parallel development sessions. Enables
8
8
 
9
9
  ## Philosophy
10
10
 
11
- **Minimal orchestration, maximal Docker Compose.** This tool does the bare minimum:
11
+ **Stateless orchestration, Docker as source of truth.** This tool does the bare minimum:
12
12
  1. Creates git worktrees for isolated working directories
13
- 2. Generates `.env.session` with calculated ports
13
+ 2. Generates `docker-compose.session.yml` with random port bindings
14
14
  3. Runs `docker compose` commands
15
+ 4. Discovers ports from running containers and writes `.env.session`
15
16
 
16
- All Docker configuration lives in `docker-compose.session.yml` in your project - a standard file you control.
17
+ No database, no state tracking—everything is derived from Docker's reality.
17
18
 
18
19
  ## Features
19
20
 
21
+ - **Stateless** - No database, Docker is the single source of truth
20
22
  - **Git worktrees** for isolated working directories (or in-place mode)
21
23
  - **Docker Compose** handles all container orchestration
22
- - **Unique ports** per session (calculated from session ID, displayed as clickable URLs)
23
- - **Auto-assign** session IDs or choose your own
24
- - **SQLite tracking** all sessions stored in a local database
24
+ - **Random port allocation** via Docker (zero conflicts)
25
+ - **Automatic port discovery** from running containers
26
+ - **Auto-healing** - commands always sync to Docker reality
25
27
  - **Two modes**: Docker (apps in containers) or Native (apps run locally)
26
28
  - **Claude Code integration** built-in (`dev-prism claude`)
27
29
  - **Portable**: Works with any project
@@ -34,17 +36,36 @@ npm install -g dev-prism
34
36
  pnpm add -D dev-prism
35
37
  ```
36
38
 
39
+ ## Quick Start
40
+
41
+ ```bash
42
+ # Create a session with worktree
43
+ dev-prism create
44
+
45
+ # Or create in current directory
46
+ dev-prism create --in-place
47
+
48
+ # List active sessions
49
+ dev-prism list
50
+
51
+ # Check current directory status
52
+ dev-prism info
53
+
54
+ # Stop session in current directory
55
+ dev-prism stop
56
+
57
+ # Destroy session in current directory
58
+ dev-prism destroy
59
+ ```
60
+
37
61
  ## Usage
38
62
 
39
63
  ### Create a session
40
64
 
41
65
  ```bash
42
- # Auto-assign session ID
66
+ # Create with worktree (generates timestamp-based branch)
43
67
  dev-prism create
44
68
 
45
- # Explicit session ID
46
- dev-prism create 001
47
-
48
69
  # Custom branch name
49
70
  dev-prism create --branch feature/my-feature
50
71
 
@@ -67,33 +88,59 @@ dev-prism create --no-detach
67
88
  dev-prism list
68
89
  ```
69
90
 
70
- ### Session info (for current directory)
91
+ Shows only running sessions with their ports and container counts.
92
+
93
+ ### Session info
71
94
 
72
95
  ```bash
96
+ # Show info for current directory
73
97
  dev-prism info
98
+
99
+ # Or specify directory
100
+ dev-prism info /path/to/session
74
101
  ```
75
102
 
76
103
  ### Start/Stop services
77
104
 
78
105
  ```bash
79
- dev-prism stop 001 # Stop without destroying
80
- dev-prism start 001 # Start again
81
- dev-prism stop-all # Stop all sessions
106
+ # Stop session in current directory
107
+ dev-prism stop
108
+
109
+ # Or specify directory
110
+ dev-prism stop /path/to/session
111
+
112
+ # Stop all running sessions
113
+ dev-prism stop-all
114
+
115
+ # Start stopped session
116
+ dev-prism start
82
117
  ```
83
118
 
84
119
  ### View logs
85
120
 
86
121
  ```bash
87
- dev-prism logs 001
122
+ # Stream logs from current directory
123
+ dev-prism logs
124
+
125
+ # Or specify directory
126
+ dev-prism logs /path/to/session
88
127
  ```
89
128
 
90
129
  ### Cleanup
91
130
 
92
131
  ```bash
93
- dev-prism destroy 001 # Destroy specific session
94
- dev-prism destroy --all # Destroy all sessions
95
- dev-prism prune # Remove all stopped sessions
96
- dev-prism prune -y # Skip confirmation
132
+ # Destroy session in current directory
133
+ dev-prism destroy
134
+
135
+ # Or specify directory
136
+ dev-prism destroy /path/to/session
137
+
138
+ # Destroy all sessions
139
+ dev-prism destroy --all
140
+
141
+ # Remove all stopped session directories
142
+ dev-prism prune
143
+ dev-prism prune -y # Skip confirmation
97
144
  ```
98
145
 
99
146
  ### Claude Code integration
@@ -103,19 +150,57 @@ dev-prism claude # Install Claude Code skill + CLAUDE.md
103
150
  dev-prism claude --force # Overwrite existing files
104
151
  ```
105
152
 
106
- ## Port Allocation
153
+ ## Architecture
154
+
155
+ ### Stateless Design
156
+
157
+ dev-prism v0.6+ has **zero persistent state**. Every command queries Docker to understand current reality:
158
+
159
+ ```bash
160
+ # Session discovery
161
+ docker ps --filter "label=dev-prism.managed=true"
162
+
163
+ # Session identity = working directory path
164
+ # Stored in container label: dev-prism.working_dir=/path/to/session
165
+ ```
166
+
167
+ ### Port Management
168
+
169
+ Ports are **randomly assigned by Docker** and **discovered after startup**:
170
+
171
+ 1. Generate `docker-compose.session.yml` with `"0:5432"` (random host port)
172
+ 2. Start containers: `docker compose up -d`
173
+ 3. Inspect containers: `docker inspect` to get actual ports
174
+ 4. Write `.env.session` with discovered ports
175
+
176
+ Example discovered ports:
177
+ ```bash
178
+ POSTGRES_PORT=54321 # Random
179
+ APP_PORT=32768 # Random
180
+ WEB_PORT=32769 # Random
181
+ ```
182
+
183
+ **Why random ports?**
184
+ - Zero configuration
185
+ - Docker handles conflicts automatically
186
+ - Large ephemeral port range (32768-60999)
187
+ - Simpler than centralized allocation
188
+
189
+ ### Auto-Healing
190
+
191
+ Commands always reflect Docker's current state:
192
+
193
+ ```bash
194
+ # If .env.session is deleted, it regenerates from Docker
195
+ dev-prism info # Queries Docker, recreates .env.session
107
196
 
108
- Formula: `port = portBase + (sessionId * 100) + offset`
197
+ # If containers are manually removed, session disappears from list
198
+ dev-prism list # Only shows what Docker reports
109
199
 
110
- With base port 47000:
200
+ # If containers exist but .env.session is missing, file is recreated
201
+ ```
111
202
 
112
- | Service | Session 001 | Session 002 | Session 003 |
113
- |----------------|-------------|-------------|-------------|
114
- | APP_PORT | 47100 | 47200 | 47300 |
115
- | WEB_PORT | 47101 | 47201 | 47301 |
116
- | POSTGRES_PORT | 47110 | 47210 | 47310 |
117
- | MAILPIT_SMTP | 47111 | 47211 | 47311 |
118
- | MAILPIT_WEB | 47112 | 47212 | 47312 |
203
+ No warnings, no errors, no stale state—just current reality.
119
204
 
120
205
  ## Configuration
121
206
 
@@ -123,18 +208,11 @@ With base port 47000:
123
208
 
124
209
  ```javascript
125
210
  export default {
126
- // Required
127
- portBase: 47000,
128
- sessionsDir: '../my-project-sessions',
211
+ // Project name for Docker namespace (defaults to directory name)
212
+ projectName: 'myproject',
129
213
 
130
- // Port offsets - become env vars for docker-compose
131
- // Formula: portBase + (sessionId * 100) + offset
132
- ports: {
133
- APP_PORT: 0, // 47100, 47200, 47300...
134
- WEB_PORT: 1, // 47101, 47201, 47301...
135
- POSTGRES_PORT: 10, // 47110, 47210, 47310...
136
- REDIS_PORT: 11, // 47111, 47211, 47311...
137
- },
214
+ // Where to create worktrees (relative to project root)
215
+ sessionsDir: '../my-project-sessions',
138
216
 
139
217
  // Docker Compose profiles for app containers (used in docker mode)
140
218
  // These match service names with `profiles: ["app-name"]` in docker-compose
@@ -158,15 +236,14 @@ export default {
158
236
  };
159
237
  ```
160
238
 
161
- ### docker-compose.session.yml (standard Docker Compose)
239
+ ### docker-compose.yml (your base services)
240
+
241
+ Define your services as usual:
162
242
 
163
243
  ```yaml
164
244
  services:
165
245
  postgres:
166
246
  image: postgres:16
167
- container_name: postgres-${SESSION_ID}
168
- ports:
169
- - "${POSTGRES_PORT}:5432"
170
247
  environment:
171
248
  POSTGRES_USER: postgres
172
249
  POSTGRES_PASSWORD: postgres
@@ -176,14 +253,11 @@ services:
176
253
  timeout: 5s
177
254
  retries: 5
178
255
 
179
- my-app:
180
- profiles: ["apps"] # Only runs in docker mode
256
+ app:
257
+ profiles: ["app"] # Only runs in docker mode
181
258
  build:
182
259
  context: .
183
260
  dockerfile: apps/my-app/Dockerfile.dev
184
- container_name: my-app-${SESSION_ID}
185
- ports:
186
- - "${APP_PORT}:3000"
187
261
  environment:
188
262
  DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres
189
263
  depends_on:
@@ -191,39 +265,101 @@ services:
191
265
  condition: service_healthy
192
266
  ```
193
267
 
268
+ ### Generated docker-compose.session.yml
269
+
270
+ dev-prism generates this automatically with random ports and labels:
271
+
272
+ ```yaml
273
+ # Auto-generated by dev-prism - DO NOT EDIT
274
+ version: "3.8"
275
+
276
+ x-dev-prism-labels: &dev-prism-labels
277
+ dev-prism.managed: "true"
278
+ dev-prism.working_dir: "/Users/you/worktrees/session-2026-02-06T12-30-45"
279
+ dev-prism.session_id: "/Users/you/worktrees/session-2026-02-06T12-30-45"
280
+ dev-prism.created_at: "2026-02-06T12:30:45.123Z"
281
+
282
+ services:
283
+ postgres:
284
+ extends:
285
+ file: docker-compose.yml
286
+ service: postgres
287
+ ports:
288
+ - "0:5432" # Random host port
289
+ labels:
290
+ <<: *dev-prism-labels
291
+ dev-prism.service: "postgres"
292
+ dev-prism.internal_port: "5432"
293
+
294
+ app:
295
+ extends:
296
+ file: docker-compose.yml
297
+ service: app
298
+ ports:
299
+ - "0:3000" # Random host port
300
+ labels:
301
+ <<: *dev-prism-labels
302
+ dev-prism.service: "app"
303
+ dev-prism.internal_port: "3000"
304
+ ```
305
+
194
306
  ## How It Works
195
307
 
196
308
  1. **Create session**: `dev-prism create`
197
- - Auto-assigns next available session ID (or use explicit ID)
198
- - Creates git worktree at `../project-sessions/session-001` (or uses current dir with `--in-place`)
199
- - Generates `.env.session` with calculated ports
200
- - Records session in local SQLite database
201
- - Runs `docker compose --env-file .env.session up -d`
309
+ - Checks for existing session in directory via Docker labels
310
+ - Creates git worktree (or uses current dir with `--in-place`)
311
+ - Generates `docker-compose.session.yml` with random port bindings (`"0:5432"`)
312
+ - Writes `.env.session` stub with compose project name
313
+ - Runs `docker compose up -d`
314
+ - Inspects running containers to discover actual ports
315
+ - Updates `.env.session` with discovered ports
202
316
  - Runs setup commands
203
317
 
204
- 2. **Docker Compose** reads `.env.session` and substitutes `${VAR}` placeholders
318
+ 2. **Port discovery**
319
+ - Query containers: `docker inspect <container-id>`
320
+ - Extract `NetworkSettings.Ports` mappings
321
+ - Write discovered ports to `.env.session`
322
+
323
+ 3. **Session identity**
324
+ - Session ID = full working directory path
325
+ - Stored in container labels: `dev-prism.working_dir=/path/to/session`
326
+ - One session per directory maximum
205
327
 
206
- 3. **Docker mode** (`--profile apps`): All services including apps run in containers
207
- 4. **Native mode**: Only infrastructure runs; apps use `pnpm dev` with `.env.session`
328
+ 4. **List sessions**: `dev-prism list`
329
+ - Query Docker: `docker ps --filter label=dev-prism.managed=true`
330
+ - Group by `working_dir` label
331
+ - Show only running sessions
208
332
 
209
- All session state is tracked in a SQLite database (`~/.dev-prism/sessions.db`), making both worktree and in-place sessions first-class citizens across all commands.
333
+ 5. **Stop session**: `dev-prism stop`
334
+ - Find containers via labels
335
+ - Run `docker compose stop`
336
+ - Delete `.env.session` file
210
337
 
211
338
  ## Generated Files
212
339
 
213
340
  ```
214
- session-001/
215
- ├── .env.session # Port variables for docker-compose
216
- ├── docker-compose.session.yml # (from git, not generated)
217
- └── apps/my-app/.env.session # App-specific env for host CLI
341
+ session-2026-02-06T12-30-45/
342
+ ├── .env.session # Discovered ports (gitignored)
343
+ ├── docker-compose.session.yml # Generated compose file (gitignored)
344
+ └── apps/my-app/.env.session # App-specific env (gitignored)
218
345
  ```
219
346
 
220
- Example `.env.session`:
347
+ Example `.env.session` (after port discovery):
221
348
  ```bash
222
- SESSION_ID=001
223
- POSTGRES_PORT=47110
224
- MAILPIT_SMTP_PORT=47111
225
- MAILPIT_WEB_PORT=47112
226
- APP_PORT=47100
349
+ # Auto-generated by dev-prism
350
+ COMPOSE_PROJECT_NAME=myproject-a1b2c3d4
351
+ SESSION_DIR=/Users/you/worktrees/session-2026-02-06T12-30-45
352
+
353
+ # Discovered ports from running containers
354
+ POSTGRES_PORT=54321
355
+ APP_PORT=32768
356
+ WEB_PORT=32769
357
+ ```
358
+
359
+ Add to `.gitignore`:
360
+ ```
361
+ .env.session
362
+ docker-compose.session.yml
227
363
  ```
228
364
 
229
365
  ## Portability
@@ -231,6 +367,62 @@ APP_PORT=47100
231
367
  To use in another project:
232
368
 
233
369
  1. Install: `pnpm add -D dev-prism`
234
- 2. Create `session.config.mjs` with port offsets
235
- 3. Create `docker-compose.session.yml` with `${VAR}` placeholders
370
+ 2. Create `session.config.mjs` (optional, has defaults)
371
+ 3. Define services in `docker-compose.yml`
236
372
  4. Run `dev-prism create`
373
+
374
+ dev-prism generates `docker-compose.session.yml` automatically—you never need to write it.
375
+
376
+ ## Migration from v0.5.x
377
+
378
+ v0.6.0 is a breaking change with a new stateless architecture:
379
+
380
+ **What changed:**
381
+ - Session IDs: `001, 002, 003` → full directory paths
382
+ - Port allocation: calculated → random (Docker assigns)
383
+ - State storage: SQLite database → stateless (Docker labels)
384
+ - Commands: `dev-prism stop 001` → `dev-prism stop` (uses cwd)
385
+
386
+ **Migration steps:**
387
+ 1. Stop all v0.5 sessions: `dev-prism stop-all` (on v0.5.x)
388
+ 2. Upgrade to v0.6: `pnpm add -g dev-prism@0.6`
389
+ 3. Recreate sessions as needed
390
+
391
+ Old session directories can be deleted manually if no longer needed.
392
+
393
+ ## Why Stateless?
394
+
395
+ **Problems with v0.5.x database approach:**
396
+ - State could diverge from Docker reality (manual container removal)
397
+ - Required reconciliation logic
398
+ - Database was single point of failure
399
+ - Stored data that Docker already knows
400
+
401
+ **v0.6+ stateless benefits:**
402
+ - Docker is always the source of truth
403
+ - No state sync issues
404
+ - Survives `docker system prune`
405
+ - Simpler codebase (fewer abstractions)
406
+ - Auto-heals on every command
407
+ - Zero configuration for port conflicts
408
+
409
+ ## Troubleshooting
410
+
411
+ **"No session found in this directory"**
412
+ - Session only exists when containers are running
413
+ - Run `dev-prism create` to start a new session
414
+
415
+ **"Session already running in this directory"**
416
+ - Containers are already running here
417
+ - Use `dev-prism stop` first, then `dev-prism create` again
418
+
419
+ **Ports not in .env.session**
420
+ - Run `dev-prism info` to regenerate from Docker
421
+
422
+ **Want predictable ports?**
423
+ - Override in your `docker-compose.yml`: `ports: ["5432:5432"]`
424
+ - Trade-off: potential conflicts across sessions
425
+
426
+ ## License
427
+
428
+ MIT
package/bin/dev-prism.js CHANGED
@@ -17,19 +17,19 @@ const program = new Command();
17
17
  program
18
18
  .name('dev-prism')
19
19
  .description('CLI tool for managing isolated parallel development sessions')
20
- .version('0.3.0');
20
+ .version('0.6.0');
21
21
 
22
22
  program
23
- .command('create [sessionId]')
23
+ .command('create')
24
24
  .description('Create a new isolated development session')
25
25
  .option('-m, --mode <mode>', 'App mode: docker (default) or native', 'docker')
26
- .option('-b, --branch <branch>', 'Git branch name (default: session/YYYY-MM-DD/XXX)')
26
+ .option('-b, --branch <branch>', 'Git branch name (default: session/TIMESTAMP)')
27
27
  .option('-W, --without <apps>', 'Exclude apps (comma-separated: app,web,widget)', (val) => val.split(','))
28
28
  .option('--no-detach', 'Stream container logs after starting (default: detach)')
29
29
  .option('--in-place', 'Run in current directory instead of creating a worktree')
30
- .action(async (sessionId, options) => {
30
+ .action(async (options) => {
31
31
  const projectRoot = process.cwd();
32
- await createSession(projectRoot, sessionId, {
32
+ await createSession(projectRoot, undefined, {
33
33
  mode: options.mode,
34
34
  branch: options.branch,
35
35
  detach: options.detach,
@@ -39,20 +39,19 @@ program
39
39
  });
40
40
 
41
41
  program
42
- .command('destroy [sessionId]')
43
- .description('Destroy a development session')
42
+ .command('destroy [directory]')
43
+ .description('Destroy a development session (defaults to current directory)')
44
44
  .option('-a, --all', 'Destroy all sessions')
45
- .action(async (sessionId, options) => {
46
- const projectRoot = process.cwd();
47
- await destroySession(projectRoot, sessionId, { all: options.all });
45
+ .action(async (directory, options) => {
46
+ const workingDir = directory || process.cwd();
47
+ await destroySession(workingDir, { all: options.all });
48
48
  });
49
49
 
50
50
  program
51
51
  .command('list')
52
52
  .description('List all active development sessions')
53
53
  .action(async () => {
54
- const projectRoot = process.cwd();
55
- await listSessions(projectRoot);
54
+ await listSessions();
56
55
  });
57
56
 
58
57
  program
@@ -63,35 +62,35 @@ program
63
62
  });
64
63
 
65
64
  program
66
- .command('start <sessionId>')
67
- .description('Start Docker services for a session')
65
+ .command('start [directory]')
66
+ .description('Start Docker services for a session (defaults to current directory)')
68
67
  .option('-m, --mode <mode>', 'App mode: docker or native', 'docker')
69
68
  .option('-W, --without <apps>', 'Exclude apps (comma-separated: app,web,widget)', (val) => val.split(','))
70
- .action(async (sessionId, options) => {
71
- const projectRoot = process.cwd();
72
- await startSession(projectRoot, sessionId, {
69
+ .action(async (directory, options) => {
70
+ const workingDir = directory || process.cwd();
71
+ await startSession(workingDir, {
73
72
  mode: options.mode,
74
73
  without: options.without,
75
74
  });
76
75
  });
77
76
 
78
77
  program
79
- .command('stop <sessionId>')
80
- .description('Stop Docker services for a session (without destroying)')
81
- .action(async (sessionId) => {
82
- const projectRoot = process.cwd();
83
- await stopSession(projectRoot, sessionId);
78
+ .command('stop [directory]')
79
+ .description('Stop Docker services for a session (defaults to current directory)')
80
+ .action(async (directory) => {
81
+ const workingDir = directory || process.cwd();
82
+ await stopSession(workingDir);
84
83
  });
85
84
 
86
85
  program
87
- .command('logs <sessionId>')
88
- .description('Stream logs from a session\'s Docker services')
86
+ .command('logs [directory]')
87
+ .description('Stream logs from a session\'s Docker services (defaults to current directory)')
89
88
  .option('-m, --mode <mode>', 'App mode: docker or native', 'docker')
90
89
  .option('-W, --without <apps>', 'Exclude apps (comma-separated: app,web,widget)', (val) => val.split(','))
91
90
  .option('-n, --tail <lines>', 'Number of lines to show from the end', '50')
92
- .action(async (sessionId, options) => {
93
- const projectRoot = process.cwd();
94
- await streamLogs(projectRoot, sessionId, {
91
+ .action(async (directory, options) => {
92
+ const workingDir = directory || process.cwd();
93
+ await streamLogs(workingDir, {
95
94
  mode: options.mode,
96
95
  without: options.without,
97
96
  tail: options.tail,
@@ -102,8 +101,7 @@ program
102
101
  .command('stop-all')
103
102
  .description('Stop all running sessions (preserves data)')
104
103
  .action(async () => {
105
- const projectRoot = process.cwd();
106
- await stopAllSessions(projectRoot);
104
+ await stopAllSessions();
107
105
  });
108
106
 
109
107
  program
@@ -111,8 +109,7 @@ program
111
109
  .description('Remove all stopped sessions (destroys data)')
112
110
  .option('-y, --yes', 'Skip confirmation prompt')
113
111
  .action(async (options) => {
114
- const projectRoot = process.cwd();
115
- await pruneSessions(projectRoot, { yes: options.yes });
112
+ await pruneSessions({ yes: options.yes });
116
113
  });
117
114
 
118
115
  program
@@ -136,21 +133,21 @@ ${chalk.bold('USAGE')}
136
133
  dev-prism <command> [options]
137
134
 
138
135
  ${chalk.bold('COMMANDS')}
139
- ${chalk.cyan('create')} [id] Create a new session (auto-assigns ID if not provided)
140
- ${chalk.cyan('destroy')} <id> Destroy a specific session
141
- ${chalk.cyan('list')} List all sessions and their status
136
+ ${chalk.cyan('create')} Create a new session
137
+ ${chalk.cyan('destroy')} [dir] Destroy a session (defaults to current directory)
138
+ ${chalk.cyan('list')} List all active sessions
142
139
  ${chalk.cyan('info')} Show session info for current directory
143
- ${chalk.cyan('start')} <id> Start Docker services for a stopped session
144
- ${chalk.cyan('stop')} <id> Stop Docker services (preserves data)
140
+ ${chalk.cyan('start')} [dir] Start Docker services (defaults to current directory)
141
+ ${chalk.cyan('stop')} [dir] Stop Docker services (defaults to current directory)
145
142
  ${chalk.cyan('stop-all')} Stop all running sessions
146
- ${chalk.cyan('logs')} <id> Stream logs from a session
147
- ${chalk.cyan('prune')} Remove all stopped sessions
143
+ ${chalk.cyan('logs')} [dir] Stream logs (defaults to current directory)
144
+ ${chalk.cyan('prune')} Remove all stopped session directories
148
145
 
149
146
  ${chalk.bold('EXAMPLES')}
150
- ${chalk.gray('# Create a new session (auto-assigns next available ID)')}
147
+ ${chalk.gray('# Create a new session with worktree')}
151
148
  $ dev-prism create
152
149
 
153
- ${chalk.gray('# Create session with specific branch')}
150
+ ${chalk.gray('# Create session with specific branch name')}
154
151
  $ dev-prism create --branch feature/my-feature
155
152
 
156
153
  ${chalk.gray('# Create session in native mode (apps run on host)')}
@@ -165,12 +162,18 @@ ${chalk.bold('EXAMPLES')}
165
162
  ${chalk.gray('# Check session status in current directory')}
166
163
  $ dev-prism info
167
164
 
168
- ${chalk.gray('# Stop all running sessions before switching context')}
165
+ ${chalk.gray('# Stop session in current directory')}
166
+ $ dev-prism stop
167
+
168
+ ${chalk.gray('# Stop all running sessions')}
169
169
  $ dev-prism stop-all
170
170
 
171
- ${chalk.gray('# Clean up old stopped sessions')}
171
+ ${chalk.gray('# Clean up old stopped session directories')}
172
172
  $ dev-prism prune
173
173
 
174
+ ${chalk.gray('# Destroy session in current directory')}
175
+ $ dev-prism destroy
176
+
174
177
  ${chalk.gray('# Destroy all sessions')}
175
178
  $ dev-prism destroy --all
176
179
 
@@ -0,0 +1,35 @@
1
+ import {
2
+ listActiveSessions
3
+ } from "./chunk-DQER5GNG.js";
4
+
5
+ // src/commands/list.ts
6
+ import chalk from "chalk";
7
+ async function listSessions() {
8
+ const sessions = await listActiveSessions();
9
+ if (sessions.length === 0) {
10
+ console.log(chalk.gray("No active sessions found."));
11
+ console.log(chalk.gray("\nTo create a session:"));
12
+ console.log(chalk.cyan(" dev-prism create"));
13
+ return;
14
+ }
15
+ console.log(chalk.blue("Active Sessions:"));
16
+ console.log(chalk.gray("================\n"));
17
+ for (const session of sessions) {
18
+ const statusIcon = session.running ? chalk.green("\u25CF") : chalk.red("\u25CB");
19
+ const statusText = session.running ? chalk.green("running") : chalk.gray("stopped");
20
+ const containerCount = session.containers.length;
21
+ console.log(`${statusIcon} Session ${statusText} (${containerCount} container${containerCount !== 1 ? "s" : ""})`);
22
+ console.log(chalk.gray(` Directory: ${session.workingDir}`));
23
+ if (session.ports.length > 0) {
24
+ console.log(chalk.gray(" Ports:"));
25
+ for (const port of session.ports) {
26
+ console.log(chalk.cyan(` ${port.service}: http://localhost:${port.externalPort}`));
27
+ }
28
+ }
29
+ console.log("");
30
+ }
31
+ }
32
+
33
+ export {
34
+ listSessions
35
+ };