workforest 0.1.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 (44) hide show
  1. workforest-0.1.0/.github/workflows/ci.yml +47 -0
  2. workforest-0.1.0/.github/workflows/publish_pypi.yml +22 -0
  3. workforest-0.1.0/.github/workflows/release.yml +34 -0
  4. workforest-0.1.0/.gitignore +21 -0
  5. workforest-0.1.0/LICENSE +21 -0
  6. workforest-0.1.0/Makefile +33 -0
  7. workforest-0.1.0/PKG-INFO +188 -0
  8. workforest-0.1.0/README.md +169 -0
  9. workforest-0.1.0/completions/_workforest +23 -0
  10. workforest-0.1.0/packaging/AUR/.SRCINFO +19 -0
  11. workforest-0.1.0/packaging/AUR/PKGBUILD +37 -0
  12. workforest-0.1.0/pyproject.toml +77 -0
  13. workforest-0.1.0/src/workforest/__init__.py +3 -0
  14. workforest-0.1.0/src/workforest/__main__.py +4 -0
  15. workforest-0.1.0/src/workforest/cli.py +254 -0
  16. workforest-0.1.0/src/workforest/commands.py +284 -0
  17. workforest-0.1.0/src/workforest/completions.py +76 -0
  18. workforest-0.1.0/src/workforest/config.py +188 -0
  19. workforest-0.1.0/src/workforest/errors.py +34 -0
  20. workforest-0.1.0/src/workforest/examples/config.yaml +117 -0
  21. workforest-0.1.0/src/workforest/gitutil.py +194 -0
  22. workforest-0.1.0/src/workforest/hooks.py +146 -0
  23. workforest-0.1.0/src/workforest/integrations/__init__.py +2 -0
  24. workforest-0.1.0/src/workforest/integrations/claude.py +129 -0
  25. workforest-0.1.0/src/workforest/launch.py +107 -0
  26. workforest-0.1.0/src/workforest/output.py +75 -0
  27. workforest-0.1.0/src/workforest/shell/completion.bash +27 -0
  28. workforest-0.1.0/src/workforest/shell/completion.zsh +38 -0
  29. workforest-0.1.0/src/workforest/shell/workforest.sh +16 -0
  30. workforest-0.1.0/src/workforest/shellinit.py +27 -0
  31. workforest-0.1.0/src/workforest/tui.py +206 -0
  32. workforest-0.1.0/tests/__init__.py +0 -0
  33. workforest-0.1.0/tests/conftest.py +196 -0
  34. workforest-0.1.0/tests/test_claude.py +167 -0
  35. workforest-0.1.0/tests/test_cli.py +138 -0
  36. workforest-0.1.0/tests/test_commands.py +337 -0
  37. workforest-0.1.0/tests/test_config.py +256 -0
  38. workforest-0.1.0/tests/test_gitutil.py +153 -0
  39. workforest-0.1.0/tests/test_harness.py +34 -0
  40. workforest-0.1.0/tests/test_hooks.py +185 -0
  41. workforest-0.1.0/tests/test_launch.py +113 -0
  42. workforest-0.1.0/tests/test_shell.py +184 -0
  43. workforest-0.1.0/tests/test_tui.py +118 -0
  44. workforest-0.1.0/uv.lock +431 -0
@@ -0,0 +1,47 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ check:
10
+ runs-on: ubuntu-latest
11
+ container: archlinux:latest
12
+ steps:
13
+ - name: Install system dependencies
14
+ run: pacman -Syu --noconfirm git python uv make zsh
15
+
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Sync dev environment
19
+ run: uv sync
20
+
21
+ - name: Lint, type-check, test
22
+ run: make check
23
+
24
+ package-smoke:
25
+ # Builds the wheel the AUR package would build and installs it into a
26
+ # clean venv — catches missing package data and broken entry points.
27
+ # The full `makepkg -si` + namcap check runs in the release workflow,
28
+ # where a source tarball exists.
29
+ runs-on: ubuntu-latest
30
+ container: archlinux:latest
31
+ steps:
32
+ - name: Install system dependencies
33
+ run: pacman -Syu --noconfirm git python python-build python-installer python-wheel python-hatchling
34
+
35
+ - uses: actions/checkout@v4
36
+
37
+ - name: Build wheel (no isolation, like the PKGBUILD)
38
+ run: python -m build --wheel --no-isolation
39
+
40
+ - name: Install into a clean venv and smoke test
41
+ run: |
42
+ python -m venv /tmp/venv
43
+ /tmp/venv/bin/pip install dist/*.whl
44
+ /tmp/venv/bin/workforest --version
45
+ /tmp/venv/bin/wf --version
46
+ /tmp/venv/bin/workforest shell-init bash | bash -n
47
+ /tmp/venv/bin/workforest shell-init zsh | head -1 | grep -q Workforest
@@ -0,0 +1,22 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ environment: pypi
11
+ permissions:
12
+ id-token: write # OIDC for PyPI trusted publishing
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - uses: astral-sh/setup-uv@v5
17
+
18
+ - name: Build sdist and wheel
19
+ run: uv build
20
+
21
+ - name: Publish to PyPI
22
+ run: uv publish
@@ -0,0 +1,34 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ jobs:
8
+ release:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+
13
+ - name: Read package version
14
+ id: version
15
+ run: |
16
+ version=$(sed -n 's/^__version__ = "\(.*\)"$/\1/p' src/workforest/__init__.py)
17
+ if [ -z "$version" ]; then
18
+ echo "Could not parse __version__ from src/workforest/__init__.py" >&2
19
+ exit 1
20
+ fi
21
+ echo "version=$version" >> "$GITHUB_OUTPUT"
22
+
23
+ - name: Create tag and release if missing
24
+ env:
25
+ # Must be a PAT, not github.token: releases created with the default
26
+ # token do not trigger the release-published publisher workflows.
27
+ GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
28
+ run: |
29
+ tag="v${{ steps.version.outputs.version }}"
30
+ if git ls-remote --exit-code --tags origin "refs/tags/$tag" > /dev/null; then
31
+ echo "Tag $tag already exists — nothing to release."
32
+ else
33
+ gh release create "$tag" --target "$GITHUB_SHA" --generate-notes
34
+ fi
@@ -0,0 +1,21 @@
1
+ # Python
2
+ __pycache__/
3
+ *.pyc
4
+ .venv/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+
9
+ # Tooling caches
10
+ .pytest_cache/
11
+ .mypy_cache/
12
+ .ruff_cache/
13
+ .coverage
14
+ htmlcov/
15
+
16
+ # Packaging artifacts
17
+ *.pkg.tar.zst
18
+ pkg/
19
+
20
+ # Tooling config
21
+ .workforest.yaml
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Arkady Buryakov
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,33 @@
1
+ # Dev targets wrap `uv run`; `uv sync` is the only setup step.
2
+
3
+ .PHONY: check test lint type cov sync install uninstall
4
+
5
+ sync:
6
+ uv sync
7
+
8
+ test:
9
+ uv run pytest
10
+
11
+ lint:
12
+ uv run ruff check .
13
+ uv run ruff format --check .
14
+
15
+ type:
16
+ uv run mypy
17
+
18
+ check: lint type test
19
+
20
+ cov:
21
+ uv run pytest --cov-report=html
22
+ @echo "open htmlcov/index.html"
23
+
24
+ # Install the current checkout as a uv tool (~/.local/bin/workforest).
25
+ # --reinstall so re-running picks up changes even without a version bump.
26
+ install:
27
+ uv tool install --reinstall .
28
+ @echo
29
+ @echo 'workforest installed. Make sure your shell rc has:'
30
+ @echo ' eval "$$(workforest shell-init)"'
31
+
32
+ uninstall:
33
+ uv tool uninstall workforest
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.4
2
+ Name: workforest
3
+ Version: 0.1.0
4
+ Summary: Git worktree forest management: create, open, and clean up per-branch worktrees with project-defined setup hooks
5
+ Project-URL: Homepage, https://github.com/arkadyb/workforest
6
+ Author-email: Arkady Buryakov <arkady@buryakov.pro>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Keywords: cli,developer-tools,git,worktree
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: POSIX :: Linux
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Topic :: Software Development :: Version Control :: Git
16
+ Requires-Python: >=3.14
17
+ Requires-Dist: pyyaml>=6.0
18
+ Description-Content-Type: text/markdown
19
+
20
+ # Workforest
21
+
22
+ Git worktree forest management: one main checkout plus any number of
23
+ disposable, per-branch worktrees in a predictable location — created, set up,
24
+ opened, and cleaned up with one command.
25
+
26
+ ```
27
+ ~/dev/
28
+ ├── api/ # main checkout
29
+ └── worktrees/
30
+ └── api/
31
+ ├── feature-x/ # wf create feature-x
32
+ └── fix-y/
33
+ ```
34
+
35
+ - **Create** a worktree for any branch (local, remote, or brand new) and have
36
+ it set up automatically: symlinks for untracked assets (`node_modules`,
37
+ `.env`, …) and project-defined setup scripts.
38
+ - **Open** it in your editor — in the current shell, or in a new terminal
39
+ window via a configurable command template.
40
+ - **Run** named project scripts with well-known `WF_*` environment variables.
41
+ - **Delete** worktrees safely, or **checkout**: collapse one back into the
42
+ main checkout.
43
+ - Drive everything from an interactive fzf **TUI** (`wf` with no arguments).
44
+
45
+ ## Install
46
+
47
+ ```sh
48
+ # Arch Linux
49
+ yay -S workforest # AUR
50
+
51
+ # anywhere else
52
+ uv tool install workforest # or: pipx install workforest
53
+ ```
54
+
55
+ This installs two commands: `workforest` and its alias `wf`. Then add one
56
+ line to your `~/.bashrc` / `~/.zshrc`:
57
+
58
+ ```sh
59
+ eval "$(workforest shell-init)"
60
+ ```
61
+
62
+ This upgrades `wf` to a shell function (needed so `wf open` can change your
63
+ shell's directory — a plain binary cannot) and registers completions. Without
64
+ it everything still works, but "open in current shell" prints the `cd`
65
+ command instead of performing it.
66
+
67
+ Requirements: Linux, git ≥ 2.36, Python ≥ 3.14. Optional: `fzf` for the TUI.
68
+
69
+ ## Quick start
70
+
71
+ ```sh
72
+ wf create feature/login # create worktree + run hooks + open in $EDITOR
73
+ wf list # what's in the forest
74
+ wf open login -o 'lazygit' # open with any command instead
75
+ wf run test # run a named script from config
76
+ wf run make check -j2 # extra args are appended to the script command
77
+ wf checkout login # fold the branch back into the main checkout
78
+ wf delete fix-y # remove a worktree (asks about dirty changes)
79
+ wf # interactive TUI (fzf)
80
+ ```
81
+
82
+ Any unknown first word is an opener shortcut: `wf edit api` ≡
83
+ `wf open api -o edit`.
84
+
85
+ ## Configuration
86
+
87
+ Layered, YAML or JSON; later layers override earlier ones:
88
+
89
+ | Layer | Location | Typical content |
90
+ |---|---|---|
91
+ | system | `/etc/workforest/config.yaml` | org-wide defaults |
92
+ | user | `~/.config/workforest/config.yaml` | your terminal/editor setup |
93
+ | project (shared) | `.workforest.yaml` in the repo root | repo policy, committed |
94
+ | project (local) | `.vscode/` or `.idea/` `.workforest.yaml` | personal overrides, untracked |
95
+
96
+ Scalars and lists replace; the `scripts`/`openers` mappings merge per key
97
+ (`null` removes an entry). `workforest config` shows the merged result and
98
+ where each layer came from; `workforest init` scaffolds a project file
99
+ (`--local` for a personal one).
100
+
101
+ All keys, with defaults:
102
+
103
+ ```yaml
104
+ worktrees_dir: "$WF_MAIN/../worktrees/$WF_NAME" # where the forest lives
105
+ opener: "" # default opener; "" → $VISUAL → $EDITOR
106
+ openers: {} # name -> command template, e.g. edit: "$EDITOR {path}"
107
+ window_command: "" # "" → current shell; or e.g.
108
+ # "kitty --title {title} --directory {path} {command}"
109
+ symlinks: [] # untracked assets linked from main into new worktrees
110
+ setup_scripts: [] # shell snippets run in a fresh worktree
111
+ scripts: {} # name -> snippet for `wf run NAME`
112
+ ```
113
+
114
+ Openers are command templates: `{path}` is replaced with the target path; a
115
+ template without `{path}` just runs with the worktree as working directory.
116
+ Environment variables expand in both openers and `window_command`.
117
+
118
+ Fully commented reference configs:
119
+ [`config.yaml`](src/workforest/examples/config.yaml) (user/system) and
120
+ [`.workforest.yaml`](src/workforest/examples/.workforest.yaml) (project) —
121
+ installed to `/usr/share/doc/workforest/examples/` by the Arch package.
122
+
123
+ ### Script environment
124
+
125
+ `setup_scripts`, `scripts`, and hooks run via `$SHELL -c` with:
126
+
127
+ | Variable | Value |
128
+ |---|---|
129
+ | `WF_MAIN` | main worktree path |
130
+ | `WF_NAME` | repo name (main checkout directory name) |
131
+ | `WF_WORKTREE` | current/new worktree path |
132
+ | `WF_WORKTREES_DIR` | resolved worktrees directory |
133
+ | `WF_BRANCH` | branch of the current/new worktree |
134
+
135
+ `worktrees_dir` is a template using the same naming pattern: `$WF_MAIN` and
136
+ `$WF_NAME` (plus regular environment variables like `$HOME`) expand there —
137
+ the per-worktree variables don't, since no worktree exists yet when the base
138
+ directory is resolved.
139
+
140
+ ### Example project config
141
+
142
+ ```yaml
143
+ # .workforest.yaml — committed to the repo
144
+ symlinks: [node_modules, .env]
145
+ setup_scripts:
146
+ - npm install --prefer-offline
147
+ scripts:
148
+ test: npm test
149
+ migrate: npm run db:migrate
150
+ ```
151
+
152
+ ## Commands
153
+
154
+ ```
155
+ workforest create [BRANCH] [-o OPENER] [-p PATH] [--no-hooks] [--no-open]
156
+ workforest open [NAME] [-o OPENER] [-p PATH]
157
+ workforest list [--porcelain]
158
+ workforest delete NAME... [--force] [--delete-branch | --keep-branch]
159
+ workforest checkout NAME [--force]
160
+ workforest run SCRIPT [ARGS...]
161
+ workforest tui [MODE]
162
+ workforest init [--local]
163
+ workforest config [--json]
164
+ workforest shell-init [bash|zsh]
165
+ ```
166
+
167
+ Exit codes: `0` ok · `1` error · `2` usage · `3` cancelled · `4` config error.
168
+ Human messages go to stderr; stdout carries only machine output (`cd`
169
+ directives for the `wf` wrapper, `--porcelain` listings, dumps).
170
+
171
+ ## Development
172
+
173
+ ```sh
174
+ uv sync # venv + dev dependencies (uv.lock)
175
+ make check # ruff + mypy --strict + pytest (coverage gate ≥ 90%)
176
+ make install # install this checkout as a uv tool (~/.local/bin/workforest)
177
+ make uninstall # remove it again
178
+ ```
179
+
180
+ Packaging recipes live under
181
+ `packaging/` (one directory per package manager; currently `packaging/AUR/`).
182
+ Release: bump `__version__`, tag, update `sha256sums` in
183
+ `packaging/AUR/PKGBUILD`, regenerate `.SRCINFO`
184
+ (`makepkg --printsrcinfo > .SRCINFO` inside `packaging/AUR/`), push to AUR.
185
+
186
+ ## License
187
+
188
+ [MIT](./LICENSE)
@@ -0,0 +1,169 @@
1
+ # Workforest
2
+
3
+ Git worktree forest management: one main checkout plus any number of
4
+ disposable, per-branch worktrees in a predictable location — created, set up,
5
+ opened, and cleaned up with one command.
6
+
7
+ ```
8
+ ~/dev/
9
+ ├── api/ # main checkout
10
+ └── worktrees/
11
+ └── api/
12
+ ├── feature-x/ # wf create feature-x
13
+ └── fix-y/
14
+ ```
15
+
16
+ - **Create** a worktree for any branch (local, remote, or brand new) and have
17
+ it set up automatically: symlinks for untracked assets (`node_modules`,
18
+ `.env`, …) and project-defined setup scripts.
19
+ - **Open** it in your editor — in the current shell, or in a new terminal
20
+ window via a configurable command template.
21
+ - **Run** named project scripts with well-known `WF_*` environment variables.
22
+ - **Delete** worktrees safely, or **checkout**: collapse one back into the
23
+ main checkout.
24
+ - Drive everything from an interactive fzf **TUI** (`wf` with no arguments).
25
+
26
+ ## Install
27
+
28
+ ```sh
29
+ # Arch Linux
30
+ yay -S workforest # AUR
31
+
32
+ # anywhere else
33
+ uv tool install workforest # or: pipx install workforest
34
+ ```
35
+
36
+ This installs two commands: `workforest` and its alias `wf`. Then add one
37
+ line to your `~/.bashrc` / `~/.zshrc`:
38
+
39
+ ```sh
40
+ eval "$(workforest shell-init)"
41
+ ```
42
+
43
+ This upgrades `wf` to a shell function (needed so `wf open` can change your
44
+ shell's directory — a plain binary cannot) and registers completions. Without
45
+ it everything still works, but "open in current shell" prints the `cd`
46
+ command instead of performing it.
47
+
48
+ Requirements: Linux, git ≥ 2.36, Python ≥ 3.14. Optional: `fzf` for the TUI.
49
+
50
+ ## Quick start
51
+
52
+ ```sh
53
+ wf create feature/login # create worktree + run hooks + open in $EDITOR
54
+ wf list # what's in the forest
55
+ wf open login -o 'lazygit' # open with any command instead
56
+ wf run test # run a named script from config
57
+ wf run make check -j2 # extra args are appended to the script command
58
+ wf checkout login # fold the branch back into the main checkout
59
+ wf delete fix-y # remove a worktree (asks about dirty changes)
60
+ wf # interactive TUI (fzf)
61
+ ```
62
+
63
+ Any unknown first word is an opener shortcut: `wf edit api` ≡
64
+ `wf open api -o edit`.
65
+
66
+ ## Configuration
67
+
68
+ Layered, YAML or JSON; later layers override earlier ones:
69
+
70
+ | Layer | Location | Typical content |
71
+ |---|---|---|
72
+ | system | `/etc/workforest/config.yaml` | org-wide defaults |
73
+ | user | `~/.config/workforest/config.yaml` | your terminal/editor setup |
74
+ | project (shared) | `.workforest.yaml` in the repo root | repo policy, committed |
75
+ | project (local) | `.vscode/` or `.idea/` `.workforest.yaml` | personal overrides, untracked |
76
+
77
+ Scalars and lists replace; the `scripts`/`openers` mappings merge per key
78
+ (`null` removes an entry). `workforest config` shows the merged result and
79
+ where each layer came from; `workforest init` scaffolds a project file
80
+ (`--local` for a personal one).
81
+
82
+ All keys, with defaults:
83
+
84
+ ```yaml
85
+ worktrees_dir: "$WF_MAIN/../worktrees/$WF_NAME" # where the forest lives
86
+ opener: "" # default opener; "" → $VISUAL → $EDITOR
87
+ openers: {} # name -> command template, e.g. edit: "$EDITOR {path}"
88
+ window_command: "" # "" → current shell; or e.g.
89
+ # "kitty --title {title} --directory {path} {command}"
90
+ symlinks: [] # untracked assets linked from main into new worktrees
91
+ setup_scripts: [] # shell snippets run in a fresh worktree
92
+ scripts: {} # name -> snippet for `wf run NAME`
93
+ ```
94
+
95
+ Openers are command templates: `{path}` is replaced with the target path; a
96
+ template without `{path}` just runs with the worktree as working directory.
97
+ Environment variables expand in both openers and `window_command`.
98
+
99
+ Fully commented reference configs:
100
+ [`config.yaml`](src/workforest/examples/config.yaml) (user/system) and
101
+ [`.workforest.yaml`](src/workforest/examples/.workforest.yaml) (project) —
102
+ installed to `/usr/share/doc/workforest/examples/` by the Arch package.
103
+
104
+ ### Script environment
105
+
106
+ `setup_scripts`, `scripts`, and hooks run via `$SHELL -c` with:
107
+
108
+ | Variable | Value |
109
+ |---|---|
110
+ | `WF_MAIN` | main worktree path |
111
+ | `WF_NAME` | repo name (main checkout directory name) |
112
+ | `WF_WORKTREE` | current/new worktree path |
113
+ | `WF_WORKTREES_DIR` | resolved worktrees directory |
114
+ | `WF_BRANCH` | branch of the current/new worktree |
115
+
116
+ `worktrees_dir` is a template using the same naming pattern: `$WF_MAIN` and
117
+ `$WF_NAME` (plus regular environment variables like `$HOME`) expand there —
118
+ the per-worktree variables don't, since no worktree exists yet when the base
119
+ directory is resolved.
120
+
121
+ ### Example project config
122
+
123
+ ```yaml
124
+ # .workforest.yaml — committed to the repo
125
+ symlinks: [node_modules, .env]
126
+ setup_scripts:
127
+ - npm install --prefer-offline
128
+ scripts:
129
+ test: npm test
130
+ migrate: npm run db:migrate
131
+ ```
132
+
133
+ ## Commands
134
+
135
+ ```
136
+ workforest create [BRANCH] [-o OPENER] [-p PATH] [--no-hooks] [--no-open]
137
+ workforest open [NAME] [-o OPENER] [-p PATH]
138
+ workforest list [--porcelain]
139
+ workforest delete NAME... [--force] [--delete-branch | --keep-branch]
140
+ workforest checkout NAME [--force]
141
+ workforest run SCRIPT [ARGS...]
142
+ workforest tui [MODE]
143
+ workforest init [--local]
144
+ workforest config [--json]
145
+ workforest shell-init [bash|zsh]
146
+ ```
147
+
148
+ Exit codes: `0` ok · `1` error · `2` usage · `3` cancelled · `4` config error.
149
+ Human messages go to stderr; stdout carries only machine output (`cd`
150
+ directives for the `wf` wrapper, `--porcelain` listings, dumps).
151
+
152
+ ## Development
153
+
154
+ ```sh
155
+ uv sync # venv + dev dependencies (uv.lock)
156
+ make check # ruff + mypy --strict + pytest (coverage gate ≥ 90%)
157
+ make install # install this checkout as a uv tool (~/.local/bin/workforest)
158
+ make uninstall # remove it again
159
+ ```
160
+
161
+ Packaging recipes live under
162
+ `packaging/` (one directory per package manager; currently `packaging/AUR/`).
163
+ Release: bump `__version__`, tag, update `sha256sums` in
164
+ `packaging/AUR/PKGBUILD`, regenerate `.SRCINFO`
165
+ (`makepkg --printsrcinfo > .SRCINFO` inside `packaging/AUR/`), push to AUR.
166
+
167
+ ## License
168
+
169
+ [MIT](./LICENSE)
@@ -0,0 +1,23 @@
1
+ #compdef workforest wf
2
+ # zsh completion for workforest / wf — installed to zsh site-functions.
3
+ # Dynamic candidates are delegated to `workforest --complete TOPIC`.
4
+
5
+ local topic cmd
6
+ local -a items
7
+ cmd="${words[2]:-}"
8
+ if (( CURRENT == 2 )); then
9
+ topic=commands
10
+ else
11
+ case "$cmd" in
12
+ create) topic=branches ;;
13
+ open|delete|checkout) topic=worktrees ;;
14
+ run) topic=scripts ;;
15
+ claude) topic=claude-sessions ;;
16
+ tui|list|init|config|shell-init) topic=none ;;
17
+ *) topic=worktrees ;;
18
+ esac
19
+ fi
20
+ if [[ "$topic" != none ]]; then
21
+ items=(${(f)"$(workforest --complete "$topic" 2>/dev/null)"})
22
+ (( ${#items} )) && compadd -a items
23
+ fi
@@ -0,0 +1,19 @@
1
+ pkgbase = workforest
2
+ pkgdesc = Git worktree forest management: per-branch worktrees with project-defined setup hooks
3
+ pkgver = 0.1.0
4
+ pkgrel = 1
5
+ url = https://github.com/arkadyb/workforest
6
+ arch = any
7
+ license = MIT
8
+ makedepends = python-build
9
+ makedepends = python-installer
10
+ makedepends = python-wheel
11
+ makedepends = python-hatchling
12
+ depends = python
13
+ depends = python-yaml
14
+ depends = git
15
+ optdepends = fzf: interactive TUI (workforest tui)
16
+ source = workforest-0.1.0.tar.gz::https://github.com/arkadyb/workforest/archive/v0.1.0.tar.gz
17
+ sha256sums = SKIP
18
+
19
+ pkgname = workforest
@@ -0,0 +1,37 @@
1
+ # Maintainer: Arkady Buryakov <arkady@buryakov.pro>
2
+ pkgname=workforest
3
+ pkgver=0.1.0
4
+ pkgrel=1
5
+ pkgdesc="Git worktree forest management: per-branch worktrees with project-defined setup hooks"
6
+ arch=(any)
7
+ url="https://github.com/arkadyb/workforest"
8
+ license=(MIT)
9
+ depends=(python python-yaml git)
10
+ makedepends=(python-build python-installer python-wheel python-hatchling)
11
+ optdepends=('fzf: interactive TUI (workforest tui)')
12
+ source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz")
13
+ sha256sums=('SKIP') # set the real checksum when cutting a release
14
+
15
+ build() {
16
+ cd "$pkgname-$pkgver"
17
+ python -m build --wheel --no-isolation
18
+ }
19
+
20
+ package() {
21
+ cd "$pkgname-$pkgver"
22
+ python -m installer --destdir="$pkgdir" dist/*.whl
23
+
24
+ install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
25
+
26
+ # Shell completions (the wf function itself comes from `workforest shell-init`)
27
+ install -Dm644 src/workforest/shell/completion.bash \
28
+ "$pkgdir/usr/share/bash-completion/completions/workforest"
29
+ install -Dm644 completions/_workforest \
30
+ "$pkgdir/usr/share/zsh/site-functions/_workforest"
31
+
32
+ # Reference configs (DESIGN §4.3)
33
+ install -Dm644 src/workforest/examples/config.yaml \
34
+ "$pkgdir/usr/share/doc/$pkgname/examples/config.yaml"
35
+ install -Dm644 src/workforest/examples/.workforest.yaml \
36
+ "$pkgdir/usr/share/doc/$pkgname/examples/workforest.project.yaml"
37
+ }