dev-prism 0.4.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 +180 -131
- package/bin/dev-prism.js +77 -97
- 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-Y3GR6XK7.js → chunk-NJAITOCG.js} +3 -13
- 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 -4
- package/dist/commands/create.js +5 -7
- package/dist/commands/destroy.d.ts +1 -1
- package/dist/commands/destroy.js +4 -5
- package/dist/commands/env.d.ts +7 -0
- package/dist/commands/env.js +9 -0
- package/dist/commands/info.js +4 -2
- package/dist/commands/list.d.ts +1 -3
- package/dist/commands/list.js +2 -5
- package/dist/commands/prune.d.ts +1 -1
- package/dist/commands/prune.js +2 -5
- package/dist/commands/with-env.d.ts +3 -0
- package/dist/commands/with-env.js +9 -0
- package/dist/index.d.ts +9 -12
- package/dist/index.js +58 -56
- package/dist/lib/config.d.ts +4 -7
- 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 +2 -3
- package/dist/lib/worktree.js +1 -3
- package/package.json +8 -8
- package/dist/chunk-35SHBLIZ.js +0 -69
- package/dist/chunk-3ATDGV4Y.js +0 -22
- 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-AOM6BONB.js +0 -98
- package/dist/chunk-AW2FJGXA.js +0 -38
- package/dist/chunk-C4WLIOBR.js +0 -67
- package/dist/chunk-D6QWWXZD.js +0 -49
- 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-H4HPDIY3.js +0 -95
- package/dist/chunk-HCCZKLC4.js +0 -64
- package/dist/chunk-HZUN6NRB.js +0 -70
- package/dist/chunk-J36LRUXM.js +0 -60
- package/dist/chunk-JHR4WADC.js +0 -200
- package/dist/chunk-JIU574KX.js +0 -41
- package/dist/chunk-KZJE62TK.js +0 -203
- 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-NNVP5F6I.js +0 -77
- package/dist/chunk-OL25TBYX.js +0 -67
- 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-QSG5CXPX.js +0 -171
- package/dist/chunk-QUMZI5KK.js +0 -98
- package/dist/chunk-RC2AUYZ7.js +0 -49
- 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-VR3QWHHB.js +0 -57
- package/dist/chunk-X5A6H4Q7.js +0 -70
- package/dist/chunk-X6FHBEAS.js +0 -200
- package/dist/chunk-XUWQUDLT.js +0 -67
- package/dist/commands/logs.d.ts +0 -8
- package/dist/commands/logs.js +0 -8
- package/dist/commands/start.d.ts +0 -7
- package/dist/commands/start.js +0 -9
- package/dist/commands/stop-all.d.ts +0 -3
- package/dist/commands/stop-all.js +0 -9
- package/dist/commands/stop.d.ts +0 -3
- package/dist/commands/stop.js +0 -7
- package/dist/lib/docker.d.ts +0 -12
- package/dist/lib/docker.js +0 -14
- package/dist/lib/ports.d.ts +0 -6
- package/dist/lib/ports.js +0 -8
- package/dist/lib/store.d.ts +0 -46
- package/dist/lib/store.js +0 -6
package/README.md
CHANGED
|
@@ -4,27 +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 `.env.session` with calculated ports
|
|
14
|
-
3. Runs `docker compose` commands
|
|
11
|
+
**Allocate ports. Inject env. Get out of the way.**
|
|
15
12
|
|
|
16
|
-
|
|
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.
|
|
17
19
|
|
|
18
20
|
## Features
|
|
19
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
|
|
20
24
|
- **Git worktrees** for isolated working directories (or in-place mode)
|
|
21
|
-
- **
|
|
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
|
|
25
|
-
- **Two modes**: Docker (apps in containers) or Native (apps run locally)
|
|
25
|
+
- **App-specific env** — different env vars for different apps in a monorepo
|
|
26
26
|
- **Claude Code integration** built-in (`dev-prism claude`)
|
|
27
|
-
- **Portable**: Works with any project
|
|
27
|
+
- **Portable**: Works with any project, any runtime, any Docker setup
|
|
28
28
|
|
|
29
29
|
## Installation
|
|
30
30
|
|
|
@@ -34,66 +34,101 @@ npm install -g dev-prism
|
|
|
34
34
|
pnpm add -D dev-prism
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Create a session (allocates ports + creates worktree)
|
|
41
|
+
dev-prism create --branch feature/auth
|
|
42
|
+
|
|
43
|
+
# Or create in current directory
|
|
44
|
+
dev-prism create --in-place
|
|
45
|
+
|
|
46
|
+
# Start Docker services with allocated ports
|
|
47
|
+
dev-prism with-env -- docker compose up -d
|
|
48
|
+
|
|
49
|
+
# Run app with session env injected
|
|
50
|
+
dev-prism with-env my-app -- pnpm dev
|
|
51
|
+
|
|
52
|
+
# Show allocated ports and env vars
|
|
53
|
+
dev-prism info
|
|
54
|
+
|
|
55
|
+
# Print env vars (for eval or piping)
|
|
56
|
+
dev-prism env
|
|
57
|
+
|
|
58
|
+
# Write .env file for IDE
|
|
59
|
+
dev-prism env --write .env
|
|
60
|
+
|
|
61
|
+
# Destroy session
|
|
62
|
+
dev-prism destroy
|
|
63
|
+
```
|
|
64
|
+
|
|
37
65
|
## Usage
|
|
38
66
|
|
|
39
67
|
### Create a session
|
|
40
68
|
|
|
41
69
|
```bash
|
|
42
|
-
#
|
|
70
|
+
# Create with worktree (generates timestamp-based branch)
|
|
43
71
|
dev-prism create
|
|
44
72
|
|
|
45
|
-
# Explicit session ID
|
|
46
|
-
dev-prism create 001
|
|
47
|
-
|
|
48
73
|
# Custom branch name
|
|
49
74
|
dev-prism create --branch feature/my-feature
|
|
50
75
|
|
|
51
|
-
#
|
|
52
|
-
dev-prism create --mode native
|
|
53
|
-
|
|
54
|
-
# Exclude specific apps from Docker
|
|
55
|
-
dev-prism create --without web,widget
|
|
56
|
-
|
|
57
|
-
# In-place mode - use current directory instead of creating worktree
|
|
76
|
+
# In-place mode — use current directory instead of creating worktree
|
|
58
77
|
dev-prism create --in-place
|
|
59
|
-
|
|
60
|
-
# Stream logs after creation instead of detaching
|
|
61
|
-
dev-prism create --no-detach
|
|
62
78
|
```
|
|
63
79
|
|
|
64
|
-
###
|
|
80
|
+
### Inject env and run commands
|
|
65
81
|
|
|
66
82
|
```bash
|
|
67
|
-
|
|
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
|
|
68
91
|
```
|
|
69
92
|
|
|
70
|
-
|
|
93
|
+
`with-env` is a no-op outside sessions — safe to use unconditionally in scripts and Makefiles.
|
|
94
|
+
|
|
95
|
+
### View env vars
|
|
71
96
|
|
|
72
97
|
```bash
|
|
73
|
-
|
|
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
|
|
103
|
+
|
|
104
|
+
# Include app-specific vars
|
|
105
|
+
dev-prism env --app convas-app
|
|
74
106
|
```
|
|
75
107
|
|
|
76
|
-
###
|
|
108
|
+
### List sessions
|
|
77
109
|
|
|
78
110
|
```bash
|
|
79
|
-
dev-prism
|
|
80
|
-
dev-prism start 001 # Start again
|
|
81
|
-
dev-prism stop-all # Stop all sessions
|
|
111
|
+
dev-prism list
|
|
82
112
|
```
|
|
83
113
|
|
|
84
|
-
###
|
|
114
|
+
### Session info
|
|
85
115
|
|
|
86
116
|
```bash
|
|
87
|
-
dev-prism
|
|
117
|
+
dev-prism info
|
|
88
118
|
```
|
|
89
119
|
|
|
90
120
|
### Cleanup
|
|
91
121
|
|
|
92
122
|
```bash
|
|
93
|
-
|
|
94
|
-
dev-prism destroy
|
|
95
|
-
|
|
96
|
-
|
|
123
|
+
# Destroy session in current directory
|
|
124
|
+
dev-prism destroy
|
|
125
|
+
|
|
126
|
+
# Destroy all sessions
|
|
127
|
+
dev-prism destroy --all
|
|
128
|
+
|
|
129
|
+
# Remove orphaned sessions from database
|
|
130
|
+
dev-prism prune
|
|
131
|
+
dev-prism prune -y # Skip confirmation
|
|
97
132
|
```
|
|
98
133
|
|
|
99
134
|
### Claude Code integration
|
|
@@ -103,134 +138,148 @@ dev-prism claude # Install Claude Code skill + CLAUDE.md
|
|
|
103
138
|
dev-prism claude --force # Overwrite existing files
|
|
104
139
|
```
|
|
105
140
|
|
|
106
|
-
## Port Allocation
|
|
107
|
-
|
|
108
|
-
Formula: `port = portBase + (sessionId * 100) + offset`
|
|
109
|
-
|
|
110
|
-
With base port 47000:
|
|
111
|
-
|
|
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 |
|
|
119
|
-
|
|
120
141
|
## Configuration
|
|
121
142
|
|
|
122
|
-
###
|
|
143
|
+
### prism.config.mjs
|
|
123
144
|
|
|
124
145
|
```javascript
|
|
125
146
|
export default {
|
|
126
|
-
|
|
127
|
-
portBase: 47000,
|
|
128
|
-
sessionsDir: '../my-project-sessions',
|
|
129
|
-
|
|
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
|
-
},
|
|
138
|
-
|
|
139
|
-
// Docker Compose profiles for app containers (used in docker mode)
|
|
140
|
-
// These match service names with `profiles: ["app-name"]` in docker-compose
|
|
141
|
-
apps: ['app', 'web'],
|
|
142
|
-
|
|
143
|
-
// .env files to copy to session worktree (DATABASE_URL auto-updated)
|
|
144
|
-
envFiles: [
|
|
145
|
-
'apps/my-app/.env',
|
|
146
|
-
'packages/db/.env',
|
|
147
|
-
],
|
|
147
|
+
ports: ['postgres', 'mailpit_http', 'mailpit_smtp', 'app', 'web'],
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
|
|
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
|
+
},
|
|
151
155
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
DATABASE_URL: 'postgresql://postgres:postgres@localhost:${
|
|
156
|
+
apps: {
|
|
157
|
+
'convas-app': {
|
|
158
|
+
PORT: '${app}',
|
|
159
|
+
DATABASE_URL: 'postgresql://postgres:postgres@localhost:${postgres}/postgres',
|
|
156
160
|
},
|
|
161
|
+
'convas-web': { PORT: '${web}' },
|
|
157
162
|
},
|
|
163
|
+
|
|
164
|
+
setup: ['pnpm install'],
|
|
158
165
|
};
|
|
159
166
|
```
|
|
160
167
|
|
|
161
|
-
### docker-compose.
|
|
168
|
+
### docker-compose.yml (user-managed)
|
|
162
169
|
|
|
163
170
|
```yaml
|
|
164
171
|
services:
|
|
165
172
|
postgres:
|
|
166
173
|
image: postgres:16
|
|
167
|
-
container_name: postgres-${SESSION_ID}
|
|
168
174
|
ports:
|
|
169
|
-
- "${POSTGRES_PORT}:5432"
|
|
175
|
+
- "${POSTGRES_PORT:-5432}:5432"
|
|
170
176
|
environment:
|
|
171
177
|
POSTGRES_USER: postgres
|
|
172
178
|
POSTGRES_PASSWORD: postgres
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
my-app:
|
|
180
|
-
profiles: ["apps"] # Only runs in docker mode
|
|
181
|
-
build:
|
|
182
|
-
context: .
|
|
183
|
-
dockerfile: apps/my-app/Dockerfile.dev
|
|
184
|
-
container_name: my-app-${SESSION_ID}
|
|
179
|
+
volumes:
|
|
180
|
+
- postgres-data:/var/lib/postgresql/data
|
|
181
|
+
|
|
182
|
+
mailpit:
|
|
183
|
+
image: axllent/mailpit
|
|
185
184
|
ports:
|
|
186
|
-
- "${
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
condition: service_healthy
|
|
185
|
+
- "${MAILPIT_HTTP_PORT:-8025}:8025"
|
|
186
|
+
- "${MAILPIT_SMTP_PORT:-1025}:1025"
|
|
187
|
+
|
|
188
|
+
volumes:
|
|
189
|
+
postgres-data:
|
|
192
190
|
```
|
|
193
191
|
|
|
194
|
-
|
|
192
|
+
The `:-` defaults mean it works without dev-prism too (solo dev, standard ports).
|
|
195
193
|
|
|
196
|
-
|
|
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`
|
|
202
|
-
- Runs setup commands
|
|
194
|
+
## How It Works
|
|
203
195
|
|
|
204
|
-
|
|
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
|
|
205
199
|
|
|
206
|
-
|
|
207
|
-
4. **Native mode**: Only infrastructure runs; apps use `pnpm dev` with `.env.session`
|
|
200
|
+
### Typical workflow
|
|
208
201
|
|
|
209
|
-
|
|
202
|
+
```bash
|
|
203
|
+
dev-prism create --branch feature/auth
|
|
204
|
+
cd ../sessions/feature/auth
|
|
210
205
|
|
|
211
|
-
|
|
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
|
|
212
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"
|
|
213
212
|
```
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
213
|
+
|
|
214
|
+
## Architecture
|
|
215
|
+
|
|
216
|
+
### SQLite as Source of Truth
|
|
217
|
+
|
|
218
|
+
Location: `<project-root>/.dev-prism/sessions.db`
|
|
219
|
+
|
|
220
|
+
```sql
|
|
221
|
+
CREATE TABLE sessions (
|
|
222
|
+
id TEXT PRIMARY KEY, -- working directory path
|
|
223
|
+
branch TEXT,
|
|
224
|
+
created_at TEXT NOT NULL
|
|
225
|
+
);
|
|
226
|
+
|
|
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
|
+
);
|
|
218
233
|
```
|
|
219
234
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
235
|
+
### Port Allocation Strategy
|
|
236
|
+
|
|
237
|
+
Two-phase: `get-port` finds free TCP ports, SQLite UNIQUE prevents cross-session conflicts.
|
|
238
|
+
|
|
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
|
+
|
|
227
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
|
+
```
|
|
251
|
+
|
|
252
|
+
This makes `with-env` safe to use unconditionally in scripts, Makefiles, and CI.
|
|
228
253
|
|
|
229
254
|
## Portability
|
|
230
255
|
|
|
231
256
|
To use in another project:
|
|
232
257
|
|
|
233
258
|
1. Install: `pnpm add -D dev-prism`
|
|
234
|
-
2. Create `
|
|
235
|
-
3.
|
|
236
|
-
4. Run `dev-prism create`
|
|
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`
|
|
262
|
+
|
|
263
|
+
dev-prism doesn't generate any Docker files — you own your Docker setup entirely.
|
|
264
|
+
|
|
265
|
+
## Migration from v0.6.x
|
|
266
|
+
|
|
267
|
+
v0.7.0 is a breaking change that removes Docker orchestration:
|
|
268
|
+
|
|
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`
|
|
275
|
+
|
|
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
|
|
282
|
+
|
|
283
|
+
## License
|
|
284
|
+
|
|
285
|
+
MIT
|
package/bin/dev-prism.js
CHANGED
|
@@ -6,114 +6,96 @@ import { destroySession } from '../dist/commands/destroy.js';
|
|
|
6
6
|
import { listSessions } from '../dist/commands/list.js';
|
|
7
7
|
import { installClaude } from '../dist/commands/claude.js';
|
|
8
8
|
import { showInfo } from '../dist/commands/info.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { stopAllSessions } from '../dist/commands/stop-all.js';
|
|
9
|
+
import { withEnv } from '../dist/commands/with-env.js';
|
|
10
|
+
import { showEnv } from '../dist/commands/env.js';
|
|
12
11
|
import { pruneSessions } from '../dist/commands/prune.js';
|
|
13
|
-
import { streamLogs } from '../dist/commands/logs.js';
|
|
14
12
|
|
|
15
13
|
const program = new Command();
|
|
16
14
|
|
|
17
15
|
program
|
|
18
16
|
.name('dev-prism')
|
|
19
|
-
.description('
|
|
20
|
-
.version('0.
|
|
17
|
+
.description('Port allocator, env injector, and worktree manager for parallel development')
|
|
18
|
+
.version('0.7.0')
|
|
19
|
+
.enablePositionalOptions();
|
|
21
20
|
|
|
22
21
|
program
|
|
23
|
-
.command('create
|
|
24
|
-
.description('Create a new
|
|
25
|
-
.option('-
|
|
26
|
-
.option('-b, --branch <branch>', 'Git branch name (default: session/YYYY-MM-DD/XXX)')
|
|
27
|
-
.option('-W, --without <apps>', 'Exclude apps (comma-separated: app,web,widget)', (val) => val.split(','))
|
|
28
|
-
.option('--no-detach', 'Stream container logs after starting (default: detach)')
|
|
22
|
+
.command('create')
|
|
23
|
+
.description('Create a new session (allocate ports + optional worktree)')
|
|
24
|
+
.option('-b, --branch <branch>', 'Git branch name (default: session/TIMESTAMP)')
|
|
29
25
|
.option('--in-place', 'Run in current directory instead of creating a worktree')
|
|
30
|
-
.action(async (
|
|
26
|
+
.action(async (options) => {
|
|
31
27
|
const projectRoot = process.cwd();
|
|
32
|
-
await createSession(projectRoot,
|
|
33
|
-
mode: options.mode,
|
|
28
|
+
await createSession(projectRoot, {
|
|
34
29
|
branch: options.branch,
|
|
35
|
-
detach: options.detach,
|
|
36
|
-
without: options.without,
|
|
37
30
|
inPlace: options.inPlace,
|
|
38
31
|
});
|
|
39
32
|
});
|
|
40
33
|
|
|
41
34
|
program
|
|
42
|
-
.command('destroy
|
|
43
|
-
.description('Destroy
|
|
35
|
+
.command('destroy')
|
|
36
|
+
.description('Destroy session for current directory (deallocate ports + remove worktree)')
|
|
44
37
|
.option('-a, --all', 'Destroy all sessions')
|
|
45
|
-
.action(async (
|
|
46
|
-
|
|
47
|
-
await destroySession(projectRoot, sessionId, { all: options.all });
|
|
38
|
+
.action(async (options) => {
|
|
39
|
+
await destroySession(process.cwd(), { all: options.all });
|
|
48
40
|
});
|
|
49
41
|
|
|
50
42
|
program
|
|
51
43
|
.command('list')
|
|
52
|
-
.description('List all
|
|
53
|
-
.
|
|
54
|
-
|
|
55
|
-
const projectRoot = process.cwd();
|
|
56
|
-
await listSessions(projectRoot, { all: options.all });
|
|
44
|
+
.description('List all sessions')
|
|
45
|
+
.action(async () => {
|
|
46
|
+
await listSessions();
|
|
57
47
|
});
|
|
58
48
|
|
|
59
49
|
program
|
|
60
50
|
.command('info')
|
|
61
|
-
.description('Show session
|
|
51
|
+
.description('Show session ports and env vars for current directory')
|
|
62
52
|
.action(async () => {
|
|
63
53
|
await showInfo(process.cwd());
|
|
64
54
|
});
|
|
65
55
|
|
|
66
|
-
program
|
|
67
|
-
.command('
|
|
68
|
-
.description('
|
|
69
|
-
.
|
|
70
|
-
.
|
|
71
|
-
.action(async (
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
.option('-n, --tail <lines>', 'Number of lines to show from the end', '50')
|
|
93
|
-
.action(async (sessionId, options) => {
|
|
94
|
-
const projectRoot = process.cwd();
|
|
95
|
-
await streamLogs(projectRoot, sessionId, {
|
|
96
|
-
mode: options.mode,
|
|
97
|
-
without: options.without,
|
|
98
|
-
tail: options.tail,
|
|
99
|
-
});
|
|
56
|
+
const withEnvCmd = program
|
|
57
|
+
.command('with-env [app]')
|
|
58
|
+
.description('Inject session env vars and exec a command')
|
|
59
|
+
.passThroughOptions()
|
|
60
|
+
.allowUnknownOption()
|
|
61
|
+
.action(async (app, options, cmd) => {
|
|
62
|
+
// cmd.args includes [app] as its first element when set — strip it.
|
|
63
|
+
const rawArgs = app ? cmd.args.slice(1) : cmd.args;
|
|
64
|
+
|
|
65
|
+
let appName;
|
|
66
|
+
let command;
|
|
67
|
+
|
|
68
|
+
const dashIdx = rawArgs.indexOf('--');
|
|
69
|
+
if (dashIdx !== -1) {
|
|
70
|
+
// dev-prism with-env my-app -- echo hello
|
|
71
|
+
appName = app;
|
|
72
|
+
command = rawArgs.slice(dashIdx + 1);
|
|
73
|
+
} else if (app) {
|
|
74
|
+
// No --, treat app as start of command (not an app name)
|
|
75
|
+
// dev-prism with-env echo hello world
|
|
76
|
+
command = [app, ...rawArgs];
|
|
77
|
+
} else {
|
|
78
|
+
command = rawArgs;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
await withEnv(command, appName);
|
|
100
82
|
});
|
|
101
83
|
|
|
102
84
|
program
|
|
103
|
-
.command('
|
|
104
|
-
.description('
|
|
105
|
-
.
|
|
106
|
-
|
|
107
|
-
|
|
85
|
+
.command('env')
|
|
86
|
+
.description('Print or write session env vars')
|
|
87
|
+
.option('-w, --write <path>', 'Write env to file instead of stdout')
|
|
88
|
+
.option('-a, --app <name>', 'Include app-specific env vars')
|
|
89
|
+
.action(async (options) => {
|
|
90
|
+
await showEnv({ write: options.write, app: options.app });
|
|
108
91
|
});
|
|
109
92
|
|
|
110
93
|
program
|
|
111
94
|
.command('prune')
|
|
112
|
-
.description('Remove
|
|
95
|
+
.description('Remove orphaned sessions from the database')
|
|
113
96
|
.option('-y, --yes', 'Skip confirmation prompt')
|
|
114
97
|
.action(async (options) => {
|
|
115
|
-
|
|
116
|
-
await pruneSessions(projectRoot, { yes: options.yes });
|
|
98
|
+
await pruneSessions({ yes: options.yes });
|
|
117
99
|
});
|
|
118
100
|
|
|
119
101
|
program
|
|
@@ -131,53 +113,51 @@ program
|
|
|
131
113
|
const chalk = (await import('chalk')).default;
|
|
132
114
|
|
|
133
115
|
console.log(`
|
|
134
|
-
${chalk.bold('dev-prism')} -
|
|
116
|
+
${chalk.bold('dev-prism')} - Port allocator, env injector, and worktree manager
|
|
135
117
|
|
|
136
118
|
${chalk.bold('USAGE')}
|
|
137
119
|
dev-prism <command> [options]
|
|
138
120
|
|
|
139
121
|
${chalk.bold('COMMANDS')}
|
|
140
|
-
${chalk.cyan('create')}
|
|
141
|
-
${chalk.cyan('destroy')}
|
|
142
|
-
${chalk.cyan('list')}
|
|
143
|
-
${chalk.cyan('info')}
|
|
144
|
-
${chalk.cyan('
|
|
145
|
-
${chalk.cyan('
|
|
146
|
-
${chalk.cyan('
|
|
147
|
-
${chalk.cyan('
|
|
148
|
-
${chalk.cyan('prune')} Remove all stopped sessions
|
|
122
|
+
${chalk.cyan('create')} Create a new session (ports + worktree)
|
|
123
|
+
${chalk.cyan('destroy')} Destroy session for current directory
|
|
124
|
+
${chalk.cyan('list')} List all sessions
|
|
125
|
+
${chalk.cyan('info')} Show session info for current directory
|
|
126
|
+
${chalk.cyan('with-env')} [app] -- <command> Inject env vars + exec command
|
|
127
|
+
${chalk.cyan('env')} Print/write session env vars
|
|
128
|
+
${chalk.cyan('prune')} Remove orphaned sessions
|
|
129
|
+
${chalk.cyan('claude')} Install Claude Code integration
|
|
149
130
|
|
|
150
131
|
${chalk.bold('EXAMPLES')}
|
|
151
|
-
${chalk.gray('# Create a new session
|
|
132
|
+
${chalk.gray('# Create a new session with worktree')}
|
|
152
133
|
$ dev-prism create
|
|
153
134
|
|
|
154
|
-
${chalk.gray('# Create session with specific branch')}
|
|
135
|
+
${chalk.gray('# Create session with specific branch name')}
|
|
155
136
|
$ dev-prism create --branch feature/my-feature
|
|
156
137
|
|
|
157
|
-
${chalk.gray('# Create session in native mode (apps run on host)')}
|
|
158
|
-
$ dev-prism create --mode native
|
|
159
|
-
|
|
160
|
-
${chalk.gray('# Create session without web app')}
|
|
161
|
-
$ dev-prism create --without web
|
|
162
|
-
|
|
163
138
|
${chalk.gray('# Create session in current directory (no worktree)')}
|
|
164
139
|
$ dev-prism create --in-place
|
|
165
140
|
|
|
166
|
-
${chalk.gray('#
|
|
167
|
-
$ dev-prism
|
|
141
|
+
${chalk.gray('# Start Docker services with injected ports')}
|
|
142
|
+
$ dev-prism with-env -- docker compose up -d
|
|
168
143
|
|
|
169
|
-
${chalk.gray('#
|
|
170
|
-
$ dev-prism
|
|
144
|
+
${chalk.gray('# Run app with app-specific env vars')}
|
|
145
|
+
$ dev-prism with-env my-app -- pnpm dev
|
|
171
146
|
|
|
172
|
-
${chalk.gray('#
|
|
173
|
-
$ dev-prism
|
|
147
|
+
${chalk.gray('# Show session env vars')}
|
|
148
|
+
$ dev-prism env
|
|
149
|
+
|
|
150
|
+
${chalk.gray('# Write env file for IDE')}
|
|
151
|
+
$ dev-prism env --write .env
|
|
152
|
+
|
|
153
|
+
${chalk.gray('# Destroy session in current directory')}
|
|
154
|
+
$ dev-prism destroy
|
|
174
155
|
|
|
175
156
|
${chalk.gray('# Destroy all sessions')}
|
|
176
157
|
$ dev-prism destroy --all
|
|
177
158
|
|
|
178
|
-
${chalk.
|
|
179
|
-
$
|
|
180
|
-
${chalk.cyan('native')} Only infrastructure in Docker, apps on host
|
|
159
|
+
${chalk.gray('# Clean up orphaned sessions')}
|
|
160
|
+
$ dev-prism prune
|
|
181
161
|
|
|
182
162
|
${chalk.bold('MORE INFO')}
|
|
183
163
|
Run ${chalk.cyan('dev-prism <command> --help')} for command-specific options
|