dev-prism 0.6.0 → 0.7.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 +143 -286
- package/bin/dev-prism.js +65 -87
- package/dist/{chunk-7YGOMAJG.js → chunk-3CIXBEXK.js} +22 -28
- package/dist/chunk-AHC6CD7F.js +92 -0
- package/dist/chunk-FQTS57VO.js +64 -0
- package/dist/chunk-GWQPK7MZ.js +50 -0
- package/dist/chunk-HDGBJGIH.js +55 -0
- package/dist/chunk-ILICQAU7.js +60 -0
- package/dist/chunk-IWZN6P6M.js +155 -0
- package/dist/chunk-KP56QH72.js +133 -0
- package/dist/{chunk-3Q454U3I.js → chunk-NJAITOCG.js} +0 -10
- package/dist/{chunk-25WQHUYW.js → chunk-TSNFAXVQ.js} +5 -12
- package/dist/chunk-VAPRJUC7.js +67 -0
- package/dist/chunk-VL56YPMK.js +45 -0
- package/dist/commands/claude.js +1 -1
- package/dist/commands/create.d.ts +1 -5
- package/dist/commands/create.js +5 -8
- package/dist/commands/destroy.d.ts +1 -1
- package/dist/commands/destroy.js +4 -6
- package/dist/commands/env.d.ts +7 -0
- package/dist/commands/env.js +9 -0
- package/dist/commands/info.js +4 -3
- package/dist/commands/list.js +2 -3
- package/dist/commands/prune.js +2 -6
- package/dist/commands/with-env.d.ts +3 -0
- package/dist/commands/with-env.js +9 -0
- package/dist/index.d.ts +9 -14
- package/dist/index.js +57 -73
- package/dist/lib/config.d.ts +4 -11
- package/dist/lib/config.js +1 -3
- package/dist/lib/db.d.ts +26 -0
- package/dist/lib/db.js +28 -0
- package/dist/lib/env.d.ts +7 -5
- package/dist/lib/env.js +9 -9
- package/dist/lib/worktree.d.ts +1 -2
- package/dist/lib/worktree.js +1 -3
- package/package.json +9 -6
- package/dist/chunk-24OM3LGM.js +0 -35
- package/dist/chunk-35SHBLIZ.js +0 -69
- package/dist/chunk-3ATDGV4Y.js +0 -22
- package/dist/chunk-3FYEGH2G.js +0 -217
- package/dist/chunk-3MSC3CGG.js +0 -78
- package/dist/chunk-3NW2OWIU.js +0 -78
- package/dist/chunk-3TRRZEFR.js +0 -38
- package/dist/chunk-4UNCSJRM.js +0 -70
- package/dist/chunk-5KDDYO6Y.js +0 -168
- package/dist/chunk-63II3EL4.js +0 -98
- package/dist/chunk-6YMQTISJ.js +0 -84
- package/dist/chunk-76LSQIZI.js +0 -31
- package/dist/chunk-7OSTLJLO.js +0 -219
- package/dist/chunk-7YEZWM6Y.js +0 -97
- package/dist/chunk-AEVARZQ4.js +0 -203
- package/dist/chunk-AIVPJ467.js +0 -70
- package/dist/chunk-AOM6BONB.js +0 -98
- package/dist/chunk-AW2FJGXA.js +0 -38
- package/dist/chunk-BXYXWNGH.js +0 -30
- package/dist/chunk-C4WLIOBR.js +0 -67
- package/dist/chunk-CUQVGZBX.js +0 -44
- package/dist/chunk-D6QWWXZD.js +0 -49
- package/dist/chunk-DQER5GNG.js +0 -72
- package/dist/chunk-DTE5YQMI.js +0 -41
- package/dist/chunk-EXRHG5KQ.js +0 -60
- package/dist/chunk-FKTFCSU7.js +0 -78
- package/dist/chunk-GBN67HYD.js +0 -57
- package/dist/chunk-GKXXK2ZH.js +0 -203
- package/dist/chunk-GWDGC2OE.js +0 -116
- package/dist/chunk-H3L73URT.js +0 -65
- package/dist/chunk-H4HPDIY3.js +0 -95
- package/dist/chunk-HCCZKLC4.js +0 -64
- package/dist/chunk-HZBJF67X.js +0 -60
- package/dist/chunk-HZUN6NRB.js +0 -70
- package/dist/chunk-I3U6JK77.js +0 -66
- package/dist/chunk-J36LRUXM.js +0 -60
- package/dist/chunk-JHR4WADC.js +0 -200
- package/dist/chunk-JIU574KX.js +0 -41
- package/dist/chunk-JMKE3ZKI.js +0 -61
- package/dist/chunk-JZ2VPQXP.js +0 -132
- package/dist/chunk-KDYKLH6P.js +0 -40
- package/dist/chunk-KZJE62TK.js +0 -203
- package/dist/chunk-LAOWFCQL.js +0 -21
- package/dist/chunk-LDK6QMR6.js +0 -67
- package/dist/chunk-LEHA65A7.js +0 -59
- package/dist/chunk-LNIOSGC4.js +0 -78
- package/dist/chunk-LOVO4P3Y.js +0 -41
- package/dist/chunk-MRBTH5PL.js +0 -66
- package/dist/chunk-NNVP5F6I.js +0 -77
- package/dist/chunk-OL25TBYX.js +0 -67
- package/dist/chunk-OOJ6YOGS.js +0 -53
- package/dist/chunk-OPEZFBBI.js +0 -219
- package/dist/chunk-P3ETW2KK.js +0 -166
- package/dist/chunk-PJKUD2N2.js +0 -22
- package/dist/chunk-PKC2ZED2.js +0 -168
- package/dist/chunk-PS76Q3HD.js +0 -168
- package/dist/chunk-Q5DPX4WL.js +0 -219
- package/dist/chunk-QSG5CXPX.js +0 -171
- package/dist/chunk-QUMZI5KK.js +0 -98
- package/dist/chunk-RC2AUYZ7.js +0 -49
- package/dist/chunk-RQ245R7T.js +0 -67
- package/dist/chunk-SD3TON6N.js +0 -32
- package/dist/chunk-SEKH4ZV6.js +0 -60
- package/dist/chunk-SMFAL2VP.js +0 -69
- package/dist/chunk-SSQ7XBY2.js +0 -30
- package/dist/chunk-SUMJLXT7.js +0 -30
- package/dist/chunk-UHI2QJFI.js +0 -200
- package/dist/chunk-UKYQN4A3.js +0 -38
- package/dist/chunk-URGGS3XM.js +0 -95
- package/dist/chunk-VR3QWHHB.js +0 -57
- package/dist/chunk-VUNPVDSO.js +0 -74
- package/dist/chunk-VXP2SPRI.js +0 -51
- package/dist/chunk-W54CPPSK.js +0 -217
- package/dist/chunk-X2PXZRYU.js +0 -41
- package/dist/chunk-X5A6H4Q7.js +0 -70
- package/dist/chunk-X6FHBEAS.js +0 -200
- package/dist/chunk-XUWQUDLT.js +0 -67
- package/dist/chunk-Y3GR6XK7.js +0 -71
- package/dist/chunk-YSO3IDZZ.js +0 -40
- package/dist/chunk-YY5DA35Z.js +0 -40
- package/dist/chunk-Z2ISJMLW.js +0 -92
- package/dist/chunk-ZKHNUDSL.js +0 -119
- package/dist/commands/logs.d.ts +0 -8
- package/dist/commands/logs.js +0 -9
- package/dist/commands/start.d.ts +0 -7
- package/dist/commands/start.js +0 -10
- package/dist/commands/stop-all.d.ts +0 -3
- package/dist/commands/stop-all.js +0 -8
- package/dist/commands/stop.d.ts +0 -3
- package/dist/commands/stop.js +0 -8
- package/dist/lib/compose.d.ts +0 -12
- package/dist/lib/compose.js +0 -12
- package/dist/lib/config.test.d.ts +0 -1
- package/dist/lib/config.test.js +0 -32
- package/dist/lib/docker-inspect.d.ts +0 -24
- package/dist/lib/docker-inspect.js +0 -16
- package/dist/lib/docker.d.ts +0 -12
- package/dist/lib/docker.js +0 -14
- package/dist/lib/env.test.d.ts +0 -1
- package/dist/lib/env.test.js +0 -68
- package/dist/lib/ports.d.ts +0 -6
- package/dist/lib/ports.js +0 -8
- package/dist/lib/ports.test.d.ts +0 -1
- package/dist/lib/ports.test.js +0 -61
- package/dist/lib/session.d.ts +0 -16
- package/dist/lib/session.js +0 -13
- package/dist/lib/store.d.ts +0 -46
- package/dist/lib/store.js +0 -6
- package/dist/lib/store.test.d.ts +0 -1
- package/dist/lib/store.test.js +0 -205
- package/dist/lib/worktree.test.d.ts +0 -1
- package/dist/lib/worktree.test.js +0 -41
package/README.md
CHANGED
|
@@ -4,29 +4,27 @@
|
|
|
4
4
|
<img src="banner.png" alt="dev-prism - One codebase, many parallel sessions" width="600">
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
A
|
|
7
|
+
A port allocator, env injector, and worktree manager for parallel development sessions. Enables multiple Claude Code (or human developer) sessions to work on the same repo simultaneously with complete isolation.
|
|
8
8
|
|
|
9
9
|
## Philosophy
|
|
10
10
|
|
|
11
|
-
**
|
|
12
|
-
1. Creates git worktrees for isolated working directories
|
|
13
|
-
2. Generates `docker-compose.session.yml` with random port bindings
|
|
14
|
-
3. Runs `docker compose` commands
|
|
15
|
-
4. Discovers ports from running containers and writes `.env.session`
|
|
11
|
+
**Allocate ports. Inject env. Get out of the way.**
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
dev-prism does three things:
|
|
14
|
+
1. Allocates unique ports via SQLite (UNIQUE constraints prevent conflicts)
|
|
15
|
+
2. Injects those ports into any command via `with-env`
|
|
16
|
+
3. Optionally manages git worktrees for isolated working directories
|
|
17
|
+
|
|
18
|
+
Docker is the user's responsibility. dev-prism just hands ports to whatever you run.
|
|
18
19
|
|
|
19
20
|
## Features
|
|
20
21
|
|
|
21
|
-
- **
|
|
22
|
+
- **SQLite-backed port allocation** with UNIQUE constraints (zero conflicts)
|
|
23
|
+
- **`with-env` pass-through** — injects env vars into any command, no-op outside sessions
|
|
22
24
|
- **Git worktrees** for isolated working directories (or in-place mode)
|
|
23
|
-
- **
|
|
24
|
-
- **Random port allocation** via Docker (zero conflicts)
|
|
25
|
-
- **Automatic port discovery** from running containers
|
|
26
|
-
- **Auto-healing** - commands always sync to Docker reality
|
|
27
|
-
- **Two modes**: Docker (apps in containers) or Native (apps run locally)
|
|
25
|
+
- **App-specific env** — different env vars for different apps in a monorepo
|
|
28
26
|
- **Claude Code integration** built-in (`dev-prism claude`)
|
|
29
|
-
- **Portable**: Works with any project
|
|
27
|
+
- **Portable**: Works with any project, any runtime, any Docker setup
|
|
30
28
|
|
|
31
29
|
## Installation
|
|
32
30
|
|
|
@@ -39,22 +37,28 @@ pnpm add -D dev-prism
|
|
|
39
37
|
## Quick Start
|
|
40
38
|
|
|
41
39
|
```bash
|
|
42
|
-
# Create a session
|
|
43
|
-
dev-prism create
|
|
40
|
+
# Create a session (allocates ports + creates worktree)
|
|
41
|
+
dev-prism create --branch feature/auth
|
|
44
42
|
|
|
45
43
|
# Or create in current directory
|
|
46
44
|
dev-prism create --in-place
|
|
47
45
|
|
|
48
|
-
#
|
|
49
|
-
dev-prism
|
|
46
|
+
# Start Docker services with allocated ports
|
|
47
|
+
dev-prism with-env -- docker compose up -d
|
|
50
48
|
|
|
51
|
-
#
|
|
49
|
+
# Run app with session env injected
|
|
50
|
+
dev-prism with-env my-app -- pnpm dev
|
|
51
|
+
|
|
52
|
+
# Show allocated ports and env vars
|
|
52
53
|
dev-prism info
|
|
53
54
|
|
|
54
|
-
#
|
|
55
|
-
dev-prism
|
|
55
|
+
# Print env vars (for eval or piping)
|
|
56
|
+
dev-prism env
|
|
56
57
|
|
|
57
|
-
#
|
|
58
|
+
# Write .env file for IDE
|
|
59
|
+
dev-prism env --write .env
|
|
60
|
+
|
|
61
|
+
# Destroy session
|
|
58
62
|
dev-prism destroy
|
|
59
63
|
```
|
|
60
64
|
|
|
@@ -69,61 +73,48 @@ dev-prism create
|
|
|
69
73
|
# Custom branch name
|
|
70
74
|
dev-prism create --branch feature/my-feature
|
|
71
75
|
|
|
72
|
-
#
|
|
73
|
-
dev-prism create --mode native
|
|
74
|
-
|
|
75
|
-
# Exclude specific apps from Docker
|
|
76
|
-
dev-prism create --without web,widget
|
|
77
|
-
|
|
78
|
-
# In-place mode - use current directory instead of creating worktree
|
|
76
|
+
# In-place mode — use current directory instead of creating worktree
|
|
79
77
|
dev-prism create --in-place
|
|
80
|
-
|
|
81
|
-
# Stream logs after creation instead of detaching
|
|
82
|
-
dev-prism create --no-detach
|
|
83
78
|
```
|
|
84
79
|
|
|
85
|
-
###
|
|
80
|
+
### Inject env and run commands
|
|
86
81
|
|
|
87
82
|
```bash
|
|
88
|
-
|
|
83
|
+
# Inject session env into any command
|
|
84
|
+
dev-prism with-env -- docker compose up -d
|
|
85
|
+
dev-prism with-env -- pnpm dev
|
|
86
|
+
dev-prism with-env -- cargo run
|
|
87
|
+
|
|
88
|
+
# Inject app-specific env (merges global + app config)
|
|
89
|
+
dev-prism with-env convas-app -- pnpm --filter convas-app dev
|
|
90
|
+
dev-prism with-env convas-web -- pnpm --filter convas-web dev
|
|
89
91
|
```
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
`with-env` is a no-op outside sessions — safe to use unconditionally in scripts and Makefiles.
|
|
92
94
|
|
|
93
|
-
###
|
|
95
|
+
### View env vars
|
|
94
96
|
|
|
95
97
|
```bash
|
|
96
|
-
#
|
|
97
|
-
dev-prism
|
|
98
|
+
# Print all env vars to stdout
|
|
99
|
+
dev-prism env
|
|
100
|
+
|
|
101
|
+
# Write to file (for IDE/GUI tools)
|
|
102
|
+
dev-prism env --write .env
|
|
98
103
|
|
|
99
|
-
#
|
|
100
|
-
dev-prism
|
|
104
|
+
# Include app-specific vars
|
|
105
|
+
dev-prism env --app convas-app
|
|
101
106
|
```
|
|
102
107
|
|
|
103
|
-
###
|
|
108
|
+
### List sessions
|
|
104
109
|
|
|
105
110
|
```bash
|
|
106
|
-
|
|
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
|
|
111
|
+
dev-prism list
|
|
117
112
|
```
|
|
118
113
|
|
|
119
|
-
###
|
|
114
|
+
### Session info
|
|
120
115
|
|
|
121
116
|
```bash
|
|
122
|
-
|
|
123
|
-
dev-prism logs
|
|
124
|
-
|
|
125
|
-
# Or specify directory
|
|
126
|
-
dev-prism logs /path/to/session
|
|
117
|
+
dev-prism info
|
|
127
118
|
```
|
|
128
119
|
|
|
129
120
|
### Cleanup
|
|
@@ -132,13 +123,10 @@ dev-prism logs /path/to/session
|
|
|
132
123
|
# Destroy session in current directory
|
|
133
124
|
dev-prism destroy
|
|
134
125
|
|
|
135
|
-
# Or specify directory
|
|
136
|
-
dev-prism destroy /path/to/session
|
|
137
|
-
|
|
138
126
|
# Destroy all sessions
|
|
139
127
|
dev-prism destroy --all
|
|
140
128
|
|
|
141
|
-
# Remove
|
|
129
|
+
# Remove orphaned sessions from database
|
|
142
130
|
dev-prism prune
|
|
143
131
|
dev-prism prune -y # Skip confirmation
|
|
144
132
|
```
|
|
@@ -150,278 +138,147 @@ dev-prism claude # Install Claude Code skill + CLAUDE.md
|
|
|
150
138
|
dev-prism claude --force # Overwrite existing files
|
|
151
139
|
```
|
|
152
140
|
|
|
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
|
|
196
|
-
|
|
197
|
-
# If containers are manually removed, session disappears from list
|
|
198
|
-
dev-prism list # Only shows what Docker reports
|
|
199
|
-
|
|
200
|
-
# If containers exist but .env.session is missing, file is recreated
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
No warnings, no errors, no stale state—just current reality.
|
|
204
|
-
|
|
205
141
|
## Configuration
|
|
206
142
|
|
|
207
|
-
###
|
|
143
|
+
### prism.config.mjs
|
|
208
144
|
|
|
209
145
|
```javascript
|
|
210
146
|
export default {
|
|
211
|
-
|
|
212
|
-
projectName: 'myproject',
|
|
213
|
-
|
|
214
|
-
// Where to create worktrees (relative to project root)
|
|
215
|
-
sessionsDir: '../my-project-sessions',
|
|
216
|
-
|
|
217
|
-
// Docker Compose profiles for app containers (used in docker mode)
|
|
218
|
-
// These match service names with `profiles: ["app-name"]` in docker-compose
|
|
219
|
-
apps: ['app', 'web'],
|
|
220
|
-
|
|
221
|
-
// .env files to copy to session worktree (DATABASE_URL auto-updated)
|
|
222
|
-
envFiles: [
|
|
223
|
-
'apps/my-app/.env',
|
|
224
|
-
'packages/db/.env',
|
|
225
|
-
],
|
|
147
|
+
ports: ['postgres', 'mailpit_http', 'mailpit_smtp', 'app', 'web'],
|
|
226
148
|
|
|
227
|
-
|
|
228
|
-
|
|
149
|
+
env: {
|
|
150
|
+
POSTGRES_PORT: '${postgres}',
|
|
151
|
+
MAILPIT_HTTP_PORT: '${mailpit_http}',
|
|
152
|
+
MAILPIT_SMTP_PORT: '${mailpit_smtp}',
|
|
153
|
+
DATABASE_URL: 'postgresql://postgres:postgres@localhost:${postgres}/postgres',
|
|
154
|
+
},
|
|
229
155
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
DATABASE_URL: 'postgresql://postgres:postgres@localhost:${
|
|
156
|
+
apps: {
|
|
157
|
+
'convas-app': {
|
|
158
|
+
PORT: '${app}',
|
|
159
|
+
DATABASE_URL: 'postgresql://postgres:postgres@localhost:${postgres}/postgres',
|
|
234
160
|
},
|
|
161
|
+
'convas-web': { PORT: '${web}' },
|
|
235
162
|
},
|
|
163
|
+
|
|
164
|
+
setup: ['pnpm install'],
|
|
236
165
|
};
|
|
237
166
|
```
|
|
238
167
|
|
|
239
|
-
### docker-compose.yml (
|
|
240
|
-
|
|
241
|
-
Define your services as usual:
|
|
168
|
+
### docker-compose.yml (user-managed)
|
|
242
169
|
|
|
243
170
|
```yaml
|
|
244
171
|
services:
|
|
245
172
|
postgres:
|
|
246
173
|
image: postgres:16
|
|
174
|
+
ports:
|
|
175
|
+
- "${POSTGRES_PORT:-5432}:5432"
|
|
247
176
|
environment:
|
|
248
177
|
POSTGRES_USER: postgres
|
|
249
178
|
POSTGRES_PASSWORD: postgres
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
interval: 5s
|
|
253
|
-
timeout: 5s
|
|
254
|
-
retries: 5
|
|
255
|
-
|
|
256
|
-
app:
|
|
257
|
-
profiles: ["app"] # Only runs in docker mode
|
|
258
|
-
build:
|
|
259
|
-
context: .
|
|
260
|
-
dockerfile: apps/my-app/Dockerfile.dev
|
|
261
|
-
environment:
|
|
262
|
-
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres
|
|
263
|
-
depends_on:
|
|
264
|
-
postgres:
|
|
265
|
-
condition: service_healthy
|
|
266
|
-
```
|
|
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"
|
|
179
|
+
volumes:
|
|
180
|
+
- postgres-data:/var/lib/postgresql/data
|
|
281
181
|
|
|
282
|
-
|
|
283
|
-
|
|
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
|
|
182
|
+
mailpit:
|
|
183
|
+
image: axllent/mailpit
|
|
298
184
|
ports:
|
|
299
|
-
- "
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
185
|
+
- "${MAILPIT_HTTP_PORT:-8025}:8025"
|
|
186
|
+
- "${MAILPIT_SMTP_PORT:-1025}:1025"
|
|
187
|
+
|
|
188
|
+
volumes:
|
|
189
|
+
postgres-data:
|
|
304
190
|
```
|
|
305
191
|
|
|
192
|
+
The `:-` defaults mean it works without dev-prism too (solo dev, standard ports).
|
|
193
|
+
|
|
306
194
|
## How It Works
|
|
307
195
|
|
|
308
|
-
1.
|
|
309
|
-
|
|
310
|
-
|
|
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
|
|
316
|
-
- Runs setup commands
|
|
317
|
-
|
|
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
|
|
327
|
-
|
|
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
|
|
332
|
-
|
|
333
|
-
5. **Stop session**: `dev-prism stop`
|
|
334
|
-
- Find containers via labels
|
|
335
|
-
- Run `docker compose stop`
|
|
336
|
-
- Delete `.env.session` file
|
|
337
|
-
|
|
338
|
-
## Generated Files
|
|
196
|
+
1. **`dev-prism create`** allocates ports via `get-port` + SQLite UNIQUE constraints
|
|
197
|
+
2. **`dev-prism with-env -- <cmd>`** reads ports from SQLite, renders env templates, injects into command
|
|
198
|
+
3. **Docker Compose** uses `${VAR:-default}` substitution — standard, no dev-prism dependency
|
|
339
199
|
|
|
340
|
-
|
|
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)
|
|
345
|
-
```
|
|
200
|
+
### Typical workflow
|
|
346
201
|
|
|
347
|
-
Example `.env.session` (after port discovery):
|
|
348
202
|
```bash
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
```
|
|
203
|
+
dev-prism create --branch feature/auth
|
|
204
|
+
cd ../sessions/feature/auth
|
|
358
205
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
206
|
+
dev-prism with-env -- docker compose up -d # infra on allocated ports
|
|
207
|
+
dev-prism with-env convas-app -- pnpm dev # app with PORT + DATABASE_URL
|
|
208
|
+
|
|
209
|
+
# Or in package.json scripts:
|
|
210
|
+
# "dev": "dev-prism with-env -- turbo dev"
|
|
211
|
+
# "docker:up": "dev-prism with-env -- docker compose up -d"
|
|
363
212
|
```
|
|
364
213
|
|
|
365
|
-
##
|
|
214
|
+
## Architecture
|
|
366
215
|
|
|
367
|
-
|
|
216
|
+
### SQLite as Source of Truth
|
|
368
217
|
|
|
369
|
-
|
|
370
|
-
2. Create `session.config.mjs` (optional, has defaults)
|
|
371
|
-
3. Define services in `docker-compose.yml`
|
|
372
|
-
4. Run `dev-prism create`
|
|
218
|
+
Location: `<project-root>/.dev-prism/sessions.db`
|
|
373
219
|
|
|
374
|
-
|
|
220
|
+
```sql
|
|
221
|
+
CREATE TABLE sessions (
|
|
222
|
+
id TEXT PRIMARY KEY, -- working directory path
|
|
223
|
+
branch TEXT,
|
|
224
|
+
created_at TEXT NOT NULL
|
|
225
|
+
);
|
|
375
226
|
|
|
376
|
-
|
|
227
|
+
CREATE TABLE port_allocations (
|
|
228
|
+
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
229
|
+
service TEXT NOT NULL,
|
|
230
|
+
port INTEGER NOT NULL UNIQUE, -- prevents cross-session conflicts
|
|
231
|
+
PRIMARY KEY (session_id, service)
|
|
232
|
+
);
|
|
233
|
+
```
|
|
377
234
|
|
|
378
|
-
|
|
235
|
+
### Port Allocation Strategy
|
|
379
236
|
|
|
380
|
-
|
|
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)
|
|
237
|
+
Two-phase: `get-port` finds free TCP ports, SQLite UNIQUE prevents cross-session conflicts.
|
|
385
238
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
239
|
+
1. Query all existing allocated + reserved ports
|
|
240
|
+
2. Use `get-port` to find free ports (excluding existing)
|
|
241
|
+
3. INSERT all in a single transaction
|
|
242
|
+
4. Retry once on UNIQUE violation (race condition)
|
|
243
|
+
|
|
244
|
+
### `with-env` Pass-Through
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
No project root found → exec command as-is
|
|
248
|
+
No session in DB → exec command as-is
|
|
249
|
+
Session found → render env templates → merge with process.env → exec
|
|
250
|
+
```
|
|
390
251
|
|
|
391
|
-
|
|
252
|
+
This makes `with-env` safe to use unconditionally in scripts, Makefiles, and CI.
|
|
392
253
|
|
|
393
|
-
##
|
|
254
|
+
## Portability
|
|
394
255
|
|
|
395
|
-
|
|
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
|
|
256
|
+
To use in another project:
|
|
400
257
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
-
|
|
404
|
-
|
|
405
|
-
- Simpler codebase (fewer abstractions)
|
|
406
|
-
- Auto-heals on every command
|
|
407
|
-
- Zero configuration for port conflicts
|
|
258
|
+
1. Install: `pnpm add -D dev-prism`
|
|
259
|
+
2. Create `prism.config.mjs` with your ports and env templates
|
|
260
|
+
3. Write your own `docker-compose.yml` using `${VAR:-default}` for ports
|
|
261
|
+
4. Run `dev-prism create --in-place`
|
|
408
262
|
|
|
409
|
-
|
|
263
|
+
dev-prism doesn't generate any Docker files — you own your Docker setup entirely.
|
|
410
264
|
|
|
411
|
-
|
|
412
|
-
- Session only exists when containers are running
|
|
413
|
-
- Run `dev-prism create` to start a new session
|
|
265
|
+
## Migration from v0.6.x
|
|
414
266
|
|
|
415
|
-
|
|
416
|
-
- Containers are already running here
|
|
417
|
-
- Use `dev-prism stop` first, then `dev-prism create` again
|
|
267
|
+
v0.7.0 is a breaking change that removes Docker orchestration:
|
|
418
268
|
|
|
419
|
-
**
|
|
420
|
-
-
|
|
269
|
+
**What changed:**
|
|
270
|
+
- Port allocation: Docker random → `get-port` + SQLite
|
|
271
|
+
- State storage: Docker labels → SQLite database
|
|
272
|
+
- Docker management: Removed (user's responsibility)
|
|
273
|
+
- New commands: `with-env`, `env`
|
|
274
|
+
- Removed commands: `start`, `stop`, `stop-all`, `logs`
|
|
421
275
|
|
|
422
|
-
**
|
|
423
|
-
|
|
424
|
-
|
|
276
|
+
**Migration steps:**
|
|
277
|
+
1. Stop all v0.6 sessions: `dev-prism stop-all` (on v0.6.x)
|
|
278
|
+
2. Upgrade: `pnpm add -g dev-prism@0.7`
|
|
279
|
+
3. Update config to `prism.config.mjs` with new format (ports array, env templates)
|
|
280
|
+
4. Write your own `docker-compose.yml` with `${VAR:-default}` port substitution
|
|
281
|
+
5. Recreate sessions
|
|
425
282
|
|
|
426
283
|
## License
|
|
427
284
|
|