worktree-env 0.2.0__tar.gz

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 (35) hide show
  1. worktree_env-0.2.0/.github/workflows/publish.yml +30 -0
  2. worktree_env-0.2.0/.github/workflows/tests.yml +22 -0
  3. worktree_env-0.2.0/.gitignore +25 -0
  4. worktree_env-0.2.0/CHANGELOG.md +50 -0
  5. worktree_env-0.2.0/CONTRIBUTING.md +27 -0
  6. worktree_env-0.2.0/LICENSE +21 -0
  7. worktree_env-0.2.0/PKG-INFO +330 -0
  8. worktree_env-0.2.0/README.md +303 -0
  9. worktree_env-0.2.0/README.zh-CN.md +250 -0
  10. worktree_env-0.2.0/SECURITY.md +17 -0
  11. worktree_env-0.2.0/examples/fullstack.yaml +33 -0
  12. worktree_env-0.2.0/migration/git-worktree-env/README.md +43 -0
  13. worktree_env-0.2.0/migration/git-worktree-env/pyproject.toml +37 -0
  14. worktree_env-0.2.0/migration/git-worktree-env/src/git_worktree_env_compat/__init__.py +8 -0
  15. worktree_env-0.2.0/pyproject.toml +53 -0
  16. worktree_env-0.2.0/src/git_worktree_env/__init__.py +3 -0
  17. worktree_env-0.2.0/src/git_worktree_env/__main__.py +7 -0
  18. worktree_env-0.2.0/src/git_worktree_env/cli.py +233 -0
  19. worktree_env-0.2.0/src/git_worktree_env/config.py +127 -0
  20. worktree_env-0.2.0/src/git_worktree_env/hooks.py +217 -0
  21. worktree_env-0.2.0/src/git_worktree_env/paths.py +64 -0
  22. worktree_env-0.2.0/src/git_worktree_env/profiles.py +215 -0
  23. worktree_env-0.2.0/src/git_worktree_env/projector.py +166 -0
  24. worktree_env-0.2.0/src/git_worktree_env/reconciler.py +273 -0
  25. worktree_env-0.2.0/src/git_worktree_env/registry.py +166 -0
  26. worktree_env-0.2.0/src/git_worktree_env/utils.py +82 -0
  27. worktree_env-0.2.0/tests/conftest.py +46 -0
  28. worktree_env-0.2.0/tests/test_cli.py +48 -0
  29. worktree_env-0.2.0/tests/test_config.py +43 -0
  30. worktree_env-0.2.0/tests/test_hooks.py +31 -0
  31. worktree_env-0.2.0/tests/test_profiles.py +34 -0
  32. worktree_env-0.2.0/tests/test_projector.py +62 -0
  33. worktree_env-0.2.0/tests/test_reconciler.py +87 -0
  34. worktree_env-0.2.0/tests/test_registry.py +54 -0
  35. worktree_env-0.2.0/uv.lock +277 -0
@@ -0,0 +1,30 @@
1
+ name: publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ pypi:
10
+ name: Publish to PyPI
11
+ runs-on: ubuntu-latest
12
+ environment:
13
+ name: pypi
14
+ url: https://pypi.org/project/worktree-env/
15
+ permissions:
16
+ contents: read
17
+ id-token: write
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: astral-sh/setup-uv@v6
21
+ - name: Build worktree-env
22
+ run: uv build
23
+ - name: Build git-worktree-env transition package
24
+ if: github.ref == 'refs/tags/v0.2.0'
25
+ run: uv build migration/git-worktree-env --out-dir migration/git-worktree-env/dist
26
+ - name: Publish worktree-env
27
+ run: uv publish dist/* --trusted-publishing always
28
+ - name: Publish git-worktree-env transition package
29
+ if: github.ref == 'refs/tags/v0.2.0'
30
+ run: uv publish migration/git-worktree-env/dist/* --trusted-publishing always
@@ -0,0 +1,22 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ os: [ubuntu-latest, macos-latest]
13
+ python-version: ["3.9", "3.13"]
14
+ runs-on: ${{ matrix.os }}
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: astral-sh/setup-uv@v6
18
+ with:
19
+ python-version: ${{ matrix.python-version }}
20
+ enable-cache: true
21
+ - run: uv sync --all-groups
22
+ - run: uv run pytest
@@ -0,0 +1,25 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .venv/
6
+ dist/
7
+ build/
8
+ *.egg-info/
9
+
10
+ # Editors and operating systems
11
+ .DS_Store
12
+ .idea/
13
+ .vscode/
14
+
15
+ # Private runtime data (never publish)
16
+ /*.yaml
17
+ /*.yml
18
+ /*.json
19
+ /state/
20
+ /hooks/
21
+
22
+ # Local coverage and logs
23
+ .coverage
24
+ htmlcov/
25
+ *.log
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.2.0] - 2026-08-21
8
+
9
+ - Renamed the PyPI package and GitHub repository from `git-worktree-env` to
10
+ `worktree-env`.
11
+ - Kept the `wte` command, `git_worktree_env` Python module, and existing
12
+ `~/.config/wte/` configuration compatible.
13
+ - Added a final `git-worktree-env` transition package and runtime migration guidance.
14
+
15
+ ## [0.1.4] - 2026-08-20
16
+
17
+ - Rewrote the English and Chinese READMEs with clearer positioning, product comparisons, and configuration guidance.
18
+
19
+ ## [0.1.3] - 2026-08-20
20
+
21
+ - Renamed `wte setup` to `wte init` for one-time core initialization.
22
+ - Made host monitoring explicit through `wte monitor enable|disable`.
23
+ - Removed the option to replace an existing global `core.hooksPath`.
24
+ - Kept `wte doctor` as the single status surface for hooks and monitoring.
25
+
26
+ ## [0.1.2] - 2026-08-20
27
+
28
+ - Added event-driven host reconciliation for worktrees created without Git hooks.
29
+ - Added macOS LaunchAgent and Linux systemd user path-unit integration.
30
+ - Made registry commits transactional with secret and generated-file projection.
31
+ - Added reconciler status to `wte doctor` and removal to `wte uninstall`.
32
+
33
+ ## [0.1.1] - 2026-08-20
34
+
35
+ - Reduced the public CLI to `setup`, `sync`, `list`, `doctor`, and `uninstall`.
36
+ - Added a commented project-profile template generated by `wte setup`.
37
+ - Made synchronization operate only on the current worktree.
38
+ - Hid the fail-open Git hook entry point from public help and documentation.
39
+ - Changed the new-install default port range to `20000-29999` to avoid common
40
+ OS ephemeral ranges and the Kubernetes NodePort range.
41
+
42
+ ## [0.1.0] - 2026-08-20
43
+
44
+ - Initial public release.
45
+ - Sticky, contiguous per-worktree port allocation.
46
+ - Main-worktree-based project matching.
47
+ - Secret symlinks and generated per-worktree files.
48
+ - Optional asynchronous post-checkout initialization.
49
+ - Installable global Git hook dispatcher with local-hook chaining.
50
+ - Atomic registry writes, explicit release, garbage collection, and diagnostics.
@@ -0,0 +1,27 @@
1
+ # Contributing
2
+
3
+ Thank you for improving worktree-env.
4
+
5
+ ## Development setup
6
+
7
+ ```bash
8
+ git clone https://github.com/archcst/worktree-env.git
9
+ cd worktree-env
10
+ uv sync
11
+ uv run pytest
12
+ ```
13
+
14
+ ## Pull requests
15
+
16
+ - Keep behavior changes covered by tests.
17
+ - Keep code, comments, commit messages, and the primary README in English.
18
+ - Update `README.zh-CN.md` when user-facing behavior changes.
19
+ - Never commit real profiles, secret paths, or `ports.json` data.
20
+ - Preserve Python 3.9 and POSIX compatibility unless a release explicitly changes it.
21
+
22
+ Before opening a pull request, run:
23
+
24
+ ```bash
25
+ uv run pytest
26
+ wte validate
27
+ ```
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shitong Chen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,330 @@
1
+ Metadata-Version: 2.5
2
+ Name: worktree-env
3
+ Version: 0.2.0
4
+ Summary: Per-worktree ports, secrets, and local environment setup for Git
5
+ Project-URL: Homepage, https://github.com/archcst/worktree-env
6
+ Project-URL: Repository, https://github.com/archcst/worktree-env
7
+ Project-URL: Issues, https://github.com/archcst/worktree-env/issues
8
+ Author: Shitong Chen
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: development,environment,git,ports,worktree
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Software Development :: Version Control :: Git
24
+ Requires-Python: >=3.9
25
+ Requires-Dist: pyyaml>=6.0
26
+ Description-Content-Type: text/markdown
27
+
28
+ # worktree-env (`wte`)
29
+
30
+ [中文文档](README.zh-CN.md)
31
+
32
+ Automatically prepare an isolated, runnable local development environment for every
33
+ Git worktree. Lightweight, minimal, no magic.
34
+
35
+ ## The problem
36
+
37
+ Git worktrees are widely used for parallel development and task isolation. However,
38
+ a new worktree usually contains only code, not a development environment that is
39
+ ready to run:
40
+
41
+ - The frontend, backend, database, and debugger still use the same fixed ports,
42
+ preventing multiple worktrees from running at the same time.
43
+ - `.env` files, private keys, and other local secrets must be copied repeatedly and
44
+ can easily be committed by mistake.
45
+ - URLs and port settings shared by services within a project must be kept in sync
46
+ manually.
47
+
48
+ Common solutions often require adding extra scripts to the project, changing how it
49
+ is started, modifying `AGENTS.md` or `CLAUDE.md`, or creating skills.
50
+ These approaches are intrusive to some degree: they must either be adopted across
51
+ the team or affect how other team members work.
52
+
53
+ `wte` uses a Git `post-checkout` hook to assign stable, conflict-free ports to a
54
+ project's worktrees, link environment variables, and generate local configuration.
55
+ The hook is not committed to the repository. It is available globally on the local
56
+ machine and does not modify any project code.
57
+
58
+ ## Comparison with existing tools
59
+
60
+ - [Portless](https://github.com/vercel-labs/portless): Requires applications to be
61
+ started through `portless`, introducing a reverse proxy, a local CA, and a
62
+ background service.
63
+ - [devports](https://github.com/bendechrai/devports): Wraps worktree creation and
64
+ removal in `devports` commands; worktrees created directly by an agent or IDE are
65
+ not handled automatically.
66
+ - [Worktrunk](https://worktrunk.dev/): Replaces the native Git workflow with `wt`,
67
+ does not participate in environment setup, and does not automatically handle
68
+ worktrees created directly by an agent or IDE.
69
+ - [workz](https://github.com/rohansx/workz): Uses `.workz.toml`,
70
+ `workz sync`/`workz start`, or separately configured hooks for Cursor, Claude Code,
71
+ and Worktrunk.
72
+ - [Hyve](https://github.com/eladkishon/hyve): Adopts a
73
+ `hyve create`/`hyve run` workflow and depends on Docker, database containers, and
74
+ service orchestration.
75
+
76
+ `wte` does not take over how worktrees are created or how a project is started.
77
+ Instead, it automatically projects a complete local development environment after a
78
+ worktree is created. It requires no changes to project code, start commands, or agent
79
+ prompts; no scripts need to be added to the project, and no traffic proxy or resident
80
+ process is required. Worktrees created by Git, an IDE, or a coding agent can all be
81
+ handled automatically.
82
+
83
+ All rules are declared explicitly in profiles stored outside the repository. For each
84
+ worktree, `wte` assigns stable ports, mounts secrets, generates local configuration,
85
+ and can initialize dependencies in the background, making the worktree ready
86
+ immediately after creation.
87
+
88
+ ## Features
89
+
90
+ - Allocates contiguous port blocks from a machine-wide shared pool and keeps them
91
+ stable for the lifetime of the worktree path.
92
+ - Mounts secrets stored outside the repository into the worktree as symlinks,
93
+ preserving a single source of truth and avoiding copy and paste.
94
+ - Organizes configuration by repository rather than by service. Supports monorepos
95
+ and multiple port requests.
96
+ - Optionally monitors host directories to discover newly added linked worktrees,
97
+ including those created within coding agent sandboxes.
98
+ - Preserves the project's own Git hooks. After the `post-checkout` hook for `wte`
99
+ finishes, it invokes the project's own executable Git hook.
100
+ - Zero intrusion: no wrapper, no skill, and no changes to coding agent prompts or
101
+ project start commands.
102
+
103
+ ## Requirements
104
+
105
+ - macOS or Linux
106
+ - Python 3.9+
107
+ - Git
108
+ - Bash
109
+
110
+ ## Installation
111
+
112
+ ```bash
113
+ uv tool install worktree-env
114
+ ```
115
+
116
+ ## Upgrading
117
+
118
+ ```bash
119
+ uv tool upgrade worktree-env
120
+ ```
121
+
122
+ ## Migrating from `git-worktree-env`
123
+
124
+ The PyPI package and GitHub repository were renamed in version 0.2.0. Existing
125
+ configuration under `~/.config/wte/` is fully compatible:
126
+
127
+ ```bash
128
+ uv tool uninstall git-worktree-env
129
+ uv tool install worktree-env
130
+ wte init
131
+ # If you previously enabled the optional Monitor:
132
+ wte monitor enable
133
+ ```
134
+
135
+ Running `wte init` refreshes the Git hook's absolute executable path. The `wte`
136
+ command and all existing profiles and state remain unchanged.
137
+
138
+ ## Getting started
139
+
140
+ ```bash
141
+ wte init
142
+ ```
143
+
144
+ This command:
145
+
146
+ - Initializes the personal configuration directory at `~/.config/wte/`.
147
+ - Runs `git config --global core.hooksPath ~/.config/wte/hooks` to install the global
148
+ Git hook dispatcher.
149
+
150
+ > If the global `core.hooksPath` already points somewhere else, `wte` displays the
151
+ > current value and refuses to change it. Confirm its purpose and migrate or remove
152
+ > it as appropriate before retrying `wte init`.
153
+
154
+ ## `~/.config/wte/`
155
+
156
+ Personal profiles, hooks, and runtime state are stored together in:
157
+
158
+ ```text
159
+ ~/.config/wte/
160
+ ├── config.yaml # Machine-wide port pool
161
+ ├── project_a.yaml # Project A profile
162
+ ├── project_b.yaml # Project B profile
163
+ ├── hooks/ # Global Git hook dispatcher
164
+ └── state/ # Managed by wte; do not edit manually.
165
+ ├── ports.json # Port registry
166
+ ├── ports.lock # Concurrency lock
167
+ ├── hooks-state.json # Hook installation state
168
+ └── reconciler.log # Monitor log (present only when the optional Monitor is enabled; see the Monitor section)
169
+ ```
170
+
171
+ Every root-level `*.yaml` file except `config.yaml` is loaded as a project profile.
172
+
173
+ Set `WTE_CONFIG_HOME` to change this directory. When it is not set,
174
+ `XDG_CONFIG_HOME` is respected.
175
+
176
+ ## Configuration examples
177
+
178
+ ### Port range
179
+
180
+ The machine-wide port range is configured in `~/.config/wte/config.yaml`:
181
+
182
+ ```yaml
183
+ port_range:
184
+ start: 20000
185
+ end: 29999
186
+ ```
187
+
188
+ The default range is `20000-29999`. You can change it manually; new worktrees will
189
+ be allocated from the new range, while existing allocations remain unchanged.
190
+
191
+ ### Project profile
192
+
193
+ Copy the configuration template:
194
+
195
+ ```bash
196
+ cp ~/.config/wte/project.example.yaml.template \
197
+ ~/.config/wte/example-project.yaml
198
+ ```
199
+
200
+ The following profile describes a project with separate frontend and backend services:
201
+
202
+ ```yaml
203
+ name: example-project
204
+
205
+ match:
206
+ # Points to the project's main worktree directory.
207
+ main_worktree: $HOME/code/example-app
208
+
209
+ ports:
210
+ # Names of the ports to request. Add as many as the project needs;
211
+ # each id must be unique within the profile.
212
+ - id: frontend_port
213
+ - id: backend_port
214
+
215
+ secrets:
216
+ # Environment files shared through symlinks.
217
+ # source points to the original environment file, while target is a path
218
+ # relative to the worktree root.
219
+ - source: $HOME/path/to/your/frontend.env
220
+ target: frontend-dir/.env
221
+ - source: $HOME/path/to/your/backend.env
222
+ target: backend-dir/.env
223
+
224
+ writes:
225
+ # Frontend configuration:
226
+ - path: frontend-dir/.env.development
227
+ body: |
228
+ VITE_PORT=${frontend_port}
229
+ SERVER_URL=http://127.0.0.1:${backend_port}
230
+
231
+ # Backend configuration:
232
+ - path: backend-dir/.env.development
233
+ body: |
234
+ PORT=${backend_port}
235
+ ```
236
+
237
+ > This example applies when both the frontend and backend can load `.env.{env name}`
238
+ > files. Adjust it to match how your project loads environment variables.
239
+ >
240
+ > After a worktree directory is deleted, its ports are reclaimed the next time `wte`
241
+ > is triggered.
242
+
243
+ ## Monitor
244
+
245
+ Some coding agents create worktrees inside a sandbox, which can prevent the `wte` hook from running.
246
+ To support these tools, enable the Monitor:
247
+
248
+ ```bash
249
+ wte monitor enable
250
+ ```
251
+
252
+ It watches the `.git/worktrees/` metadata directory associated with each configured
253
+ main worktree:
254
+
255
+ - macOS uses a LaunchAgent with `WatchPaths`.
256
+ - Linux uses a systemd user path unit.
257
+
258
+ When the directory changes, the operating system starts a short-lived Reconciler.
259
+ _It is not a resident daemon and does not poll on a timer_, so its resource usage is
260
+ minimal.
261
+
262
+ The Reconciler:
263
+
264
+ 1. Runs `git worktree list --porcelain` to retrieve the actual list of worktrees.
265
+ 2. Compares it with `ports.json`, then assigns ports, mounts secrets, and generates
266
+ files for unregistered worktrees.
267
+
268
+ After adding a profile or changing a `main_worktree` path, run this command again:
269
+
270
+ ```bash
271
+ wte monitor enable
272
+ ```
273
+
274
+ To disable the Monitor, run:
275
+
276
+ ```bash
277
+ wte monitor disable
278
+ ```
279
+
280
+ Afterward, filesystem changes will no longer be monitored.
281
+
282
+ ## Asynchronous initialization
283
+
284
+ `wte` can automatically run commands after a worktree is created, allowing the
285
+ environment to be initialized in the background:
286
+
287
+ ```yaml
288
+ init:
289
+ - command: npm install
290
+ cwd: frontend-dir # Use "." to run from the worktree root.
291
+ skip_if: node_modules # Skip this command if the file or directory exists.
292
+
293
+ - command: uv sync
294
+ cwd: backend-dir # Use "." to run from the worktree root.
295
+ skip_if: .venv # Skip this command if the file or directory exists.
296
+ ```
297
+
298
+ A typical timeline looks like this:
299
+
300
+ ```text
301
+ Create a worktree
302
+ → wte projects the environment and starts npm install in the background
303
+ → The user describes the task; the AI reads, analyzes, and modifies the code
304
+ → By the time the user or AI starts the project, dependencies are usually ready
305
+ ```
306
+
307
+ Asynchronous initialization is started only by the normal `post-checkout` hook.
308
+ Neither `wte sync` nor the Monitor Reconciler runs these commands, preventing manual
309
+ synchronization or background reconciliation from repeatedly starting expensive
310
+ tasks.
311
+
312
+ ## Commands supported by `wte`
313
+
314
+ ```text
315
+ wte init Create personal configuration and templates, and install core Git hooks
316
+ wte sync Synchronize ports, secrets, and generated files for the current worktree
317
+ wte list List port allocations for worktrees that still exist
318
+ wte doctor Diagnose configuration, profiles, registry, secrets, hooks, and Monitor
319
+ wte monitor enable Install or refresh optional host monitoring
320
+ wte monitor disable Remove host monitoring only, preserving Git hooks
321
+ wte uninstall Remove hooks and the Monitor, preserving configuration and runtime state
322
+ ```
323
+
324
+ Run `wte sync` from inside the target worktree. It reuses existing ports, recreates
325
+ secret symlinks, and regenerates configuration files.
326
+ You may need it when a worktree is created through an unconventional method.
327
+
328
+ ## License
329
+
330
+ [MIT](LICENSE)