@mdulghier/devtree 0.1.5

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/dist/vite.js ADDED
@@ -0,0 +1,72 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ function create_core_devtree_plugin() {
10
+ return {
11
+ name: "devtree",
12
+ apply: "serve",
13
+ config(user_config) {
14
+ const next_config = {};
15
+ const tailscale_host = process.env.DEVTREE_TAILSCALE_HOST?.trim();
16
+ if (!user_config.server?.host) {
17
+ next_config.server = {
18
+ ...user_config.server,
19
+ host: "127.0.0.1",
20
+ };
21
+ }
22
+ if (tailscale_host && user_config.server?.allowedHosts !== true) {
23
+ const allowed_hosts = user_config.server?.allowedHosts ?? [];
24
+ if (!allowed_hosts.includes(tailscale_host)) {
25
+ next_config.server = {
26
+ ...next_config.server,
27
+ ...user_config.server,
28
+ allowedHosts: [...allowed_hosts, tailscale_host],
29
+ };
30
+ }
31
+ }
32
+ if (user_config.clearScreen === undefined) {
33
+ next_config.clearScreen = false;
34
+ }
35
+ return next_config;
36
+ },
37
+ configResolved(resolved_config) {
38
+ if (process.env.VITEST === "true" || process.env.NODE_ENV === "test") {
39
+ return;
40
+ }
41
+ if (resolved_config.command !== "serve") {
42
+ return;
43
+ }
44
+ if (process.env.DEVTREE_ACTIVE === "1") {
45
+ console.log(`[devtree] URL ${process.env.DEVTREE_PUBLIC_URL ?? "unknown"}`);
46
+ console.log(`[devtree] Instance ${process.env.DEVTREE_INSTANCE_ID ?? "unknown"}`);
47
+ return;
48
+ }
49
+ console.warn("[devtree] Run `vp run devtree dev` for isolated multi-instance development.");
50
+ },
51
+ };
52
+ }
53
+ export async function devtree_vite_plugins(config) {
54
+ const plugins = [create_core_devtree_plugin()];
55
+ if (config.env.provider !== "varlock") {
56
+ return plugins;
57
+ }
58
+ const package_name = "@varlock/vite-integration";
59
+ try {
60
+ const imported_module = (await import(__rewriteRelativeImportExtension(package_name)));
61
+ if (!imported_module.varlockVitePlugin) {
62
+ throw new Error(`Expected varlockVitePlugin export from ${package_name}.`);
63
+ }
64
+ plugins.unshift(imported_module.varlockVitePlugin({ ssrInjectMode: "init-only" }));
65
+ return plugins;
66
+ }
67
+ catch (error) {
68
+ const message = error instanceof Error ? error.message : String(error);
69
+ throw new Error(`Varlock mode is enabled, but ${package_name} could not be loaded. ${message}`);
70
+ }
71
+ }
72
+ //# sourceMappingURL=vite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.js","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@mdulghier/devtree",
3
+ "version": "0.1.5",
4
+ "description": "Worktree-aware multi-instance dev orchestration for Vite+ apps.",
5
+ "keywords": [
6
+ "devtree",
7
+ "portless",
8
+ "varlock",
9
+ "vite",
10
+ "vite-plus",
11
+ "worktree",
12
+ "tanstack-intent"
13
+ ],
14
+ "homepage": "https://github.com/mdulghier/devtree#readme",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/mdulghier/devtree.git"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/mdulghier/devtree/issues"
21
+ },
22
+ "license": "UNLICENSED",
23
+ "bin": {
24
+ "devtree": "./bin/devtree.mjs"
25
+ },
26
+ "files": [
27
+ "bin",
28
+ "dist",
29
+ "README.md",
30
+ "skills",
31
+ "!skills/_artifacts"
32
+ ],
33
+ "type": "module",
34
+ "sideEffects": false,
35
+ "types": "./dist/index.d.ts",
36
+ "exports": {
37
+ ".": {
38
+ "types": "./dist/index.d.ts",
39
+ "import": "./dist/index.js"
40
+ },
41
+ "./vite": {
42
+ "types": "./dist/vite.d.ts",
43
+ "import": "./dist/vite.js"
44
+ },
45
+ "./package.json": "./package.json"
46
+ },
47
+ "scripts": {
48
+ "build": "tsc -p tsconfig.build.json",
49
+ "prepare": "npm run build",
50
+ "prepack": "npm run build",
51
+ "ci": "npm run check && npm test && npm run build",
52
+ "check": "tsc --noEmit -p tsconfig.json",
53
+ "test": "vp test run src/*.test.ts"
54
+ },
55
+ "dependencies": {
56
+ "dotenv": "^17.3.1",
57
+ "tsx": "^4.21.0"
58
+ },
59
+ "devDependencies": {
60
+ "@types/node": "^24.5.2",
61
+ "@tanstack/intent": "^0.0.23",
62
+ "typescript": "^5.7.2",
63
+ "vite-plus": "latest"
64
+ },
65
+ "peerDependencies": {
66
+ "@varlock/vite-integration": "*",
67
+ "varlock": "*",
68
+ "vite-plus": "*"
69
+ },
70
+ "peerDependenciesMeta": {
71
+ "@varlock/vite-integration": {
72
+ "optional": true
73
+ },
74
+ "varlock": {
75
+ "optional": true
76
+ }
77
+ },
78
+ "engines": {
79
+ "node": ">=24"
80
+ },
81
+ "packageManager": "pnpm@10.32.1"
82
+ }
@@ -0,0 +1,179 @@
1
+ ---
2
+ name: devtree-run-and-operate-devtree
3
+ description: >
4
+ Run and troubleshoot daily devtree workflows: `doctor`, `setup`, `dev`,
5
+ `info`, `env write`, `env show`, `deps start|stop|logs`, and `gc`. Load
6
+ this when an agent needs to verify that the app is running, reachable at
7
+ the worktree URL, and cleaned up correctly after worktrees are deleted.
8
+ type: core
9
+ library: devtree
10
+ library_version: "0.1.0"
11
+ sources:
12
+ - "mdulghier/devtree:README.md"
13
+ - "mdulghier/devtree:src/cli.ts"
14
+ - "mdulghier/devtree:src/command-builder.ts"
15
+ - "mdulghier/devtree:src/gc.ts"
16
+ - "mdulghier/devtree:src/registry.ts"
17
+ - "mdulghier/devtree:src/process.ts"
18
+ - "mdulghier/devtree:src/instance.ts"
19
+ ---
20
+
21
+ # Devtree - Run And Operate
22
+
23
+ ## Setup
24
+
25
+ Use the CLI in this order when bringing up a worktree instance.
26
+
27
+ ```bash
28
+ pnpm devtree doctor --fix
29
+ pnpm devtree setup
30
+ pnpm devtree dev
31
+ ```
32
+
33
+ Then inspect the assigned URL and names.
34
+
35
+ ```bash
36
+ pnpm devtree info
37
+ ```
38
+
39
+ For cleanup and dependency inspection:
40
+
41
+ ```bash
42
+ pnpm devtree deps logs
43
+ pnpm devtree gc --dry-run
44
+ ```
45
+
46
+ ## Core Patterns
47
+
48
+ ### Verify health with doctor first
49
+
50
+ ```bash
51
+ pnpm devtree doctor --fix
52
+ ```
53
+
54
+ Use `doctor` as the first check; it validates local prerequisites and bootstraps `portless` when needed.
55
+
56
+ ### Bring up dependencies before the dev server
57
+
58
+ ```bash
59
+ pnpm devtree setup
60
+ pnpm devtree dev
61
+ ```
62
+
63
+ `setup` writes env overrides, starts configured dependencies, and runs setup hooks before `dev` starts the app.
64
+
65
+ ### Inspect the current instance URL and names
66
+
67
+ ```bash
68
+ pnpm devtree info
69
+ ```
70
+
71
+ `info` prints the public URL, app name, instance ID, scoped name, worktree path, env provider, env file, and Compose project names.
72
+
73
+ ### Clean up orphaned Docker resources safely
74
+
75
+ ```bash
76
+ pnpm devtree gc --dry-run
77
+ pnpm devtree gc
78
+ ```
79
+
80
+ Dry-run first, then remove orphaned dependency resources created by deleted worktrees.
81
+
82
+ ## Common Mistakes
83
+
84
+ ### CRITICAL Start Vite directly instead of devtree
85
+
86
+ Wrong:
87
+
88
+ ```json
89
+ {
90
+ "scripts": {
91
+ "dev": "vp dev"
92
+ }
93
+ }
94
+ ```
95
+
96
+ ```bash
97
+ pnpm dev
98
+ ```
99
+
100
+ Correct:
101
+
102
+ ```json
103
+ {
104
+ "scripts": {
105
+ "devtree": "devtree"
106
+ }
107
+ }
108
+ ```
109
+
110
+ ```bash
111
+ pnpm devtree dev
112
+ ```
113
+
114
+ Starting raw Vite skips devtree's portless wrapping and runtime env injection, so multi-worktree isolation disappears.
115
+
116
+ Source: `README.md`, `src/command-builder.ts:17`
117
+
118
+ ### HIGH Disable portless and expect APP_URL to exist
119
+
120
+ Wrong:
121
+
122
+ ```bash
123
+ PORTLESS=0 pnpm devtree dev
124
+ ```
125
+
126
+ Correct:
127
+
128
+ ```bash
129
+ BETTER_AUTH_URL=http://localhost:3000 PORTLESS=0 pnpm devtree dev
130
+ ```
131
+
132
+ When portless is disabled, devtree does not inject the public URL, so callback-based auth flows need an explicit fallback URL.
133
+
134
+ Source: `src/cli.ts:499`
135
+
136
+ ### HIGH Skip setup when dependencies or hooks matter
137
+
138
+ Wrong:
139
+
140
+ ```bash
141
+ pnpm devtree dev
142
+ ```
143
+
144
+ Correct:
145
+
146
+ ```bash
147
+ pnpm devtree setup
148
+ pnpm devtree dev
149
+ ```
150
+
151
+ `dev` starts the app, but `setup` is what starts dependencies and runs `setup`, `migrate`, and `post_setup` hooks.
152
+
153
+ Source: `README.md`, `src/cli.ts:448`
154
+
155
+ ### MEDIUM Assume gc removes unknown docker projects
156
+
157
+ Wrong:
158
+
159
+ ```bash
160
+ pnpm devtree gc
161
+ ```
162
+
163
+ Correct:
164
+
165
+ ```bash
166
+ pnpm devtree gc --dry-run
167
+ ```
168
+
169
+ Unknown projects without worktree metadata are reported and skipped, so `gc` is not a universal Docker janitor.
170
+
171
+ Source: `src/gc.ts:356`
172
+
173
+ ### HIGH Tension: portless compatibility versus public URL correctness
174
+
175
+ Disabling portless can simplify local bootstrapping in odd environments, but it removes the stable public URL contract that devtree normally provides. Agents that take the shortcut need to replace that URL explicitly.
176
+
177
+ See also: `devtree-set-up-devtree` - setup choices around portless and env injection decide whether runtime URLs work.
178
+
179
+ See also: `devtree-set-up-devtree` - configuration drives most runtime failures.
@@ -0,0 +1,355 @@
1
+ ---
2
+ name: devtree-set-up-devtree
3
+ description: >
4
+ Set up devtree in a Vite+ repository: install `devtree`, create
5
+ `devtree.config.ts`, define `env.entries`, choose `dotenv` or `varlock`,
6
+ register `devtree_vite_plugins`, and configure optional `dependencies`
7
+ and `hooks`. Load this when an agent needs to bootstrap worktree-aware
8
+ local development without URL, env, or Docker naming collisions.
9
+ type: core
10
+ library: devtree
11
+ library_version: "0.1.0"
12
+ sources:
13
+ - "mdulghier/devtree:README.md"
14
+ - "mdulghier/devtree:src/config.ts"
15
+ - "mdulghier/devtree:src/cli.ts"
16
+ - "mdulghier/devtree:src/vite.ts"
17
+ - "mdulghier/devtree:src/env-file.ts"
18
+ - "mdulghier/devtree:src/instance.ts"
19
+ ---
20
+
21
+ # Devtree - Set Up
22
+
23
+ ## Setup
24
+
25
+ Install `devtree` and register both the config file and the Vite plugin.
26
+
27
+ ```bash
28
+ pnpm add -D devtree vite-plus
29
+ ```
30
+
31
+ ```ts
32
+ import { define_devtree_config } from 'devtree'
33
+
34
+ export default define_devtree_config({
35
+ app_name: 'my-app',
36
+ env: {
37
+ provider: 'dotenv',
38
+ entries: ({ instance }) => [
39
+ {
40
+ kind: 'value',
41
+ key: 'APP_URL',
42
+ value: instance.public_url,
43
+ },
44
+ {
45
+ kind: 'value',
46
+ key: 'DATABASE_PORT',
47
+ value: String(instance.allocate_port('postgres', 5400)),
48
+ },
49
+ ],
50
+ },
51
+ })
52
+ ```
53
+
54
+ ```ts
55
+ import { defineConfig } from 'vite-plus'
56
+ import { devtree_vite_plugins } from 'devtree/vite'
57
+
58
+ import devtree_config from './devtree.config.ts'
59
+
60
+ export default defineConfig({
61
+ plugins: [...(await devtree_vite_plugins(devtree_config))],
62
+ })
63
+ ```
64
+
65
+ ```json
66
+ {
67
+ "scripts": {
68
+ "devtree": "devtree"
69
+ }
70
+ }
71
+ ```
72
+
73
+ ```bash
74
+ pnpm devtree doctor --fix
75
+ pnpm devtree setup
76
+ ```
77
+
78
+ ## Core Patterns
79
+
80
+ ### Keep env values instance-derived
81
+
82
+ ```ts
83
+ import { define_devtree_config } from 'devtree'
84
+
85
+ export default define_devtree_config({
86
+ app_name: 'my-app',
87
+ env: {
88
+ provider: 'dotenv',
89
+ entries: ({ instance }) => [
90
+ { kind: 'value', key: 'APP_URL', value: instance.public_url },
91
+ {
92
+ kind: 'value',
93
+ key: 'REDIS_PORT',
94
+ value: String(instance.allocate_port('redis', 6300)),
95
+ },
96
+ ],
97
+ },
98
+ })
99
+ ```
100
+
101
+ Use `instance.public_url`, `instance.get_scoped_name()` and `instance.allocate_port()` instead of fixed local values.
102
+
103
+ ### Start Docker dependencies through config
104
+
105
+ ```ts
106
+ import { define_devtree_config } from 'devtree'
107
+
108
+ export default define_devtree_config({
109
+ app_name: 'my-app',
110
+ env: {
111
+ provider: 'dotenv',
112
+ entries: ({ instance }) => [
113
+ { kind: 'value', key: 'APP_URL', value: instance.public_url },
114
+ ],
115
+ },
116
+ dependencies: [
117
+ {
118
+ kind: 'compose',
119
+ name: 'postgres',
120
+ file_path: 'docker-compose.yml',
121
+ project_name: ({ instance }) => instance.get_scoped_name('db'),
122
+ services: ['db'],
123
+ },
124
+ ],
125
+ })
126
+ ```
127
+
128
+ Compose dependencies are the default way to give each worktree isolated container, network, and volume names.
129
+
130
+ ### Use hooks for repo-specific setup
131
+
132
+ ```ts
133
+ import { define_devtree_config } from 'devtree'
134
+
135
+ export default define_devtree_config({
136
+ app_name: 'my-app',
137
+ env: {
138
+ provider: 'dotenv',
139
+ entries: ({ instance }) => [
140
+ { kind: 'value', key: 'APP_URL', value: instance.public_url },
141
+ ],
142
+ },
143
+ hooks: {
144
+ migrate: [
145
+ {
146
+ command: ['pnpm', 'db:migrate'],
147
+ },
148
+ ],
149
+ pre_dev: [
150
+ {
151
+ command: ['pnpm', 'codegen'],
152
+ },
153
+ ],
154
+ },
155
+ })
156
+ ```
157
+
158
+ `setup` runs `setup`, `migrate`, and `post_setup`; `dev` runs `pre_dev` before starting the server.
159
+
160
+ ### Turn on varlock only with its prerequisites
161
+
162
+ ```bash
163
+ pnpm add -D varlock @varlock/vite-integration
164
+ touch .env.schema
165
+ ```
166
+
167
+ ```ts
168
+ import { define_devtree_config } from 'devtree'
169
+
170
+ export default define_devtree_config({
171
+ app_name: 'my-app',
172
+ env: {
173
+ provider: 'varlock',
174
+ schema_path: '.env.schema',
175
+ entries: ({ instance }) => [
176
+ { kind: 'value', key: 'APP_URL', value: instance.public_url },
177
+ ],
178
+ },
179
+ })
180
+ ```
181
+
182
+ Keep the simple `dotenv` path as the default; use `varlock` when the repo already wants schema-based env handling.
183
+
184
+ ## Common Mistakes
185
+
186
+ ### CRITICAL Hard-code shared URLs and ports
187
+
188
+ Wrong:
189
+
190
+ ```ts
191
+ import { define_devtree_config } from 'devtree'
192
+
193
+ export default define_devtree_config({
194
+ app_name: 'my-app',
195
+ env: {
196
+ provider: 'dotenv',
197
+ entries: () => [
198
+ { kind: 'value', key: 'APP_URL', value: 'http://localhost:3000' },
199
+ { kind: 'value', key: 'DATABASE_PORT', value: '5432' },
200
+ ],
201
+ },
202
+ })
203
+ ```
204
+
205
+ Correct:
206
+
207
+ ```ts
208
+ import { define_devtree_config } from 'devtree'
209
+
210
+ export default define_devtree_config({
211
+ app_name: 'my-app',
212
+ env: {
213
+ provider: 'dotenv',
214
+ entries: ({ instance }) => [
215
+ { kind: 'value', key: 'APP_URL', value: instance.public_url },
216
+ {
217
+ kind: 'value',
218
+ key: 'DATABASE_PORT',
219
+ value: String(instance.allocate_port('postgres', 5400)),
220
+ },
221
+ ],
222
+ },
223
+ })
224
+ ```
225
+
226
+ Static values remove the per-worktree isolation that devtree is supposed to enforce.
227
+
228
+ Source: `README.md`
229
+
230
+ ### HIGH Store manual values inside managed block
231
+
232
+ Wrong:
233
+
234
+ ```dotenv
235
+ # >>> devtree managed env >>>
236
+ APP_URL=http://feature-x.my-app.localhost:1355
237
+ STRIPE_SECRET_KEY=sk_live_manual_override
238
+ # <<< devtree managed env <<<
239
+ ```
240
+
241
+ Correct:
242
+
243
+ ```dotenv
244
+ # >>> devtree managed env >>>
245
+ APP_URL=http://feature-x.my-app.localhost:1355
246
+ # <<< devtree managed env <<<
247
+
248
+ STRIPE_SECRET_KEY=sk_live_manual_override
249
+ ```
250
+
251
+ Devtree rewrites the managed block on each run and only preserves custom content outside that block.
252
+
253
+ Source: `src/env-file.ts:78`
254
+
255
+ ### HIGH Force shared dependency project names
256
+
257
+ Wrong:
258
+
259
+ ```ts
260
+ import { define_devtree_config } from 'devtree'
261
+
262
+ export default define_devtree_config({
263
+ app_name: 'my-app',
264
+ env: {
265
+ provider: 'dotenv',
266
+ entries: ({ instance }) => [
267
+ { kind: 'value', key: 'APP_URL', value: instance.public_url },
268
+ ],
269
+ },
270
+ dependencies: [
271
+ {
272
+ kind: 'compose',
273
+ name: 'db',
274
+ project_name: 'my-app',
275
+ },
276
+ ],
277
+ })
278
+ ```
279
+
280
+ Correct:
281
+
282
+ ```ts
283
+ import { define_devtree_config } from 'devtree'
284
+
285
+ export default define_devtree_config({
286
+ app_name: 'my-app',
287
+ env: {
288
+ provider: 'dotenv',
289
+ entries: ({ instance }) => [
290
+ { kind: 'value', key: 'APP_URL', value: instance.public_url },
291
+ ],
292
+ },
293
+ dependencies: [
294
+ {
295
+ kind: 'compose',
296
+ name: 'db',
297
+ project_name: ({ instance }) => instance.get_scoped_name('db'),
298
+ },
299
+ ],
300
+ })
301
+ ```
302
+
303
+ Static Compose project names silently make multiple worktrees fight over the same Docker resources.
304
+
305
+ Source: `src/cli.ts:156`
306
+
307
+ ### HIGH Enable varlock without integration prerequisites
308
+
309
+ Wrong:
310
+
311
+ ```ts
312
+ import { define_devtree_config } from 'devtree'
313
+
314
+ export default define_devtree_config({
315
+ app_name: 'my-app',
316
+ env: {
317
+ provider: 'varlock',
318
+ entries: ({ instance }) => [
319
+ { kind: 'value', key: 'APP_URL', value: instance.public_url },
320
+ ],
321
+ },
322
+ })
323
+ ```
324
+
325
+ Correct:
326
+
327
+ ```bash
328
+ pnpm add -D varlock @varlock/vite-integration
329
+ touch .env.schema
330
+ ```
331
+
332
+ ```ts
333
+ import { define_devtree_config } from 'devtree'
334
+
335
+ export default define_devtree_config({
336
+ app_name: 'my-app',
337
+ env: {
338
+ provider: 'varlock',
339
+ schema_path: '.env.schema',
340
+ entries: ({ instance }) => [
341
+ { kind: 'value', key: 'APP_URL', value: instance.public_url },
342
+ ],
343
+ },
344
+ })
345
+ ```
346
+
347
+ `varlock` mode depends on the CLI, the schema file, and `@varlock/vite-integration`; missing any of them breaks setup or plugin loading.
348
+
349
+ Source: `src/cli.ts:338`, `src/vite.ts:45`
350
+
351
+ ### HIGH Tension: simple setup versus explicit override freedom
352
+
353
+ Devtree works best when it owns URL, env, and dependency naming. Agents trying to be “helpful” by hard-coding familiar local values usually delete the whole point of the library.
354
+
355
+ See also: `devtree-run-and-operate-devtree` - runtime checks expose the fallout from setup shortcuts.