tasktree-manager 2.13.1__tar.gz → 2.13.3__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.
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.github/workflows/release.yml +17 -2
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.gitignore +1 -2
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/CHANGELOG.md +24 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/CONTRIBUTING.md +7 -10
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/PKG-INFO +1 -1
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/README.md +26 -17
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/docs/configuration.md +9 -2
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/docs/troubleshooting.md +1 -1
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/docs/user-guide.md +9 -2
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/pyproject.toml +1 -1
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/scripts/bump_version.py +17 -4
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/_version.py +2 -2
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/app.py +217 -50
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/cli.py +103 -28
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/agent_sessions.py +1 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/claude_hooks.py +64 -26
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/config.py +73 -22
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/forge.py +1 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/git_ops.py +14 -5
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/models.py +19 -1
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/task_manager.py +535 -68
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/create_modal.py +9 -4
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/setup_modal.py +8 -4
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/task_list.py +9 -12
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/worktree_list.py +9 -2
- tasktree_manager-2.13.3/tests/test_agent_sessions_decode.py +31 -0
- tasktree_manager-2.13.3/tests/test_app_review_fixes.py +606 -0
- tasktree_manager-2.13.3/tests/test_bump_version.py +135 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_claude_hooks.py +142 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_claude_sessions.py +21 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_cli.py +241 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_config.py +131 -1
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_forge.py +21 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_git_ops.py +64 -0
- tasktree_manager-2.13.3/tests/test_list_selection.py +130 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_medium_fixes.py +1 -1
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_modals.py +78 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_task_manager.py +781 -8
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_worktree_badges.py +1 -1
- tasktree_manager-2.13.1/OPENSPEC.md +0 -457
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/SKILL.md +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/assets/README.md +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/assets/dashboard_app.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/assets/data_viewer.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/assets/todo_app.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/assets/worker_demo.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/references/layouts.md +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/references/official-guides-index.md +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/references/styling.md +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/references/widgets.md +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.github/templates/CHANGELOG.md.j2 +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.github/workflows/ci.yml +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/LICENSE +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/ROADMAP.md +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/docs/claude-code-integration-spec.md +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/docs/installation.md +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/mise.toml +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/__init__.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/commands.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/__init__.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/claude_sessions.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/themes.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/__init__.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/app_header.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/messages_panel.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/status_panel.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/__init__.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/conftest.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_agent_sessions.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_app.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_commands.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_integration_git.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_memory.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_messages_panel.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_safety_fixes.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_setup_modal.py +0 -0
- {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_status_panel.py +0 -0
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
# - Manual dispatch: choose release type, pre-release, and draft options.
|
|
15
15
|
# Both `draft` and `pre_release` skip the PyPI upload (the pipeline can
|
|
16
16
|
# only produce final X.Y.Z versions) and only shape the GitHub release.
|
|
17
|
+
# workflow_dispatch can target ANY branch, not just main (branch
|
|
18
|
+
# protection also has enforce_admins=false), so prepare-release and
|
|
19
|
+
# tag-release both refuse to run off main — see their `if:` guards.
|
|
17
20
|
|
|
18
21
|
name: Release
|
|
19
22
|
|
|
@@ -46,6 +49,12 @@ on:
|
|
|
46
49
|
jobs:
|
|
47
50
|
prepare-release:
|
|
48
51
|
name: Prepare Release
|
|
52
|
+
# workflow_dispatch can target any branch; the push trigger is already
|
|
53
|
+
# restricted to main via `on.push.branches`, so this only closes the
|
|
54
|
+
# workflow_dispatch path. Everything downstream (lint/test/tag-release/
|
|
55
|
+
# build/publish-pypi) needs this job and is skipped by cascade when it
|
|
56
|
+
# is; github-release guards itself separately via needs.build.result.
|
|
57
|
+
if: github.ref == 'refs/heads/main'
|
|
49
58
|
runs-on: ubuntu-latest
|
|
50
59
|
outputs:
|
|
51
60
|
new_version: ${{ steps.determine_version.outputs.new_version }}
|
|
@@ -174,6 +183,10 @@ jobs:
|
|
|
174
183
|
tag-release:
|
|
175
184
|
name: Commit and Tag
|
|
176
185
|
needs: [prepare-release, lint, test]
|
|
186
|
+
# Belt and suspenders: this is the job that pushes to main and pushes
|
|
187
|
+
# the tag using the owner PAT, so it gets its own explicit ref guard
|
|
188
|
+
# rather than relying only on the cascade from prepare-release.
|
|
189
|
+
if: github.ref == 'refs/heads/main'
|
|
177
190
|
runs-on: ubuntu-latest
|
|
178
191
|
steps:
|
|
179
192
|
- name: Checkout code
|
|
@@ -206,8 +219,10 @@ jobs:
|
|
|
206
219
|
git diff --cached --quiet && echo "No changes to commit" || \
|
|
207
220
|
git commit -m "chore(release): ${new_version} [skip ci]"
|
|
208
221
|
git tag -a "v${new_version}" -m "Release v${new_version}"
|
|
209
|
-
|
|
210
|
-
|
|
222
|
+
# Atomic: one push carrying both refs, so a rejected tag (already
|
|
223
|
+
# exists, race with another push) can never leave main bumped
|
|
224
|
+
# without the tag that's supposed to go with it.
|
|
225
|
+
git push --atomic origin HEAD:main "v${new_version}"
|
|
211
226
|
|
|
212
227
|
build:
|
|
213
228
|
name: Build Package
|
|
@@ -49,11 +49,10 @@ Thumbs.db
|
|
|
49
49
|
|
|
50
50
|
# Project specific
|
|
51
51
|
*.log
|
|
52
|
-
|
|
52
|
+
tasktree_manager/_version.py
|
|
53
53
|
|
|
54
54
|
# Documentation (tracked separately)
|
|
55
55
|
PRD.md
|
|
56
|
-
specs/
|
|
57
56
|
CLAUDE.md
|
|
58
57
|
|
|
59
58
|
# uv project-mode lockfile — tooling installs via `uv pip`/pip from pyproject.toml,
|
|
@@ -15,6 +15,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
15
15
|
- Git hooks support
|
|
16
16
|
- Custom task metadata
|
|
17
17
|
|
|
18
|
+
## [2.13.3] - 2026-10-16
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- Remove unused specs and refresh the README roadmap
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- **archive**: Keep task-folder files when a task is finished
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## [2.13.2] - 2026-09-28
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- Document list error state, config value types and task name rules
|
|
31
|
+
- **release**: Release only from main and push main and tag atomically
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- **tui**: Harden workers, refresh and selection handling
|
|
35
|
+
- **cli**: Report status errors, setup failures and missing git correctly
|
|
36
|
+
- **claude**: Resolve symlinked paths and write settings atomically
|
|
37
|
+
- **config**: Validate booleans and section tables in config.toml
|
|
38
|
+
- **git**: Count partially staged files as staged and modified
|
|
39
|
+
- **tasks**: Protect existing branches and unchecked worktrees on create/delete
|
|
40
|
+
|
|
41
|
+
|
|
18
42
|
## [2.13.1] - 2026-09-16
|
|
19
43
|
|
|
20
44
|
### Fixed
|
|
@@ -18,7 +18,7 @@ Be respectful, inclusive, and constructive. We're all here to build something us
|
|
|
18
18
|
|
|
19
19
|
1. **Fork and clone**
|
|
20
20
|
```bash
|
|
21
|
-
git clone https://github.com/
|
|
21
|
+
git clone https://github.com/ruslanfialkovskii/tasktree-manager.git
|
|
22
22
|
cd tasktree-manager
|
|
23
23
|
```
|
|
24
24
|
|
|
@@ -149,7 +149,7 @@ def create_task(name: str, repos: list[str]) -> Task:
|
|
|
149
149
|
- Add docstrings to all public functions/classes
|
|
150
150
|
- Use Google-style docstrings
|
|
151
151
|
- Update README.md for user-facing changes
|
|
152
|
-
- Update
|
|
152
|
+
- Update the Architecture section of CLAUDE.md for architecture changes
|
|
153
153
|
|
|
154
154
|
Example docstring:
|
|
155
155
|
```python
|
|
@@ -206,18 +206,15 @@ tasktree-manager/
|
|
|
206
206
|
│ ├── themes/ # Color themes
|
|
207
207
|
│ └── app.py # Main app
|
|
208
208
|
├── tests/ # Test suite
|
|
209
|
-
├── specs/ # Technical specs
|
|
210
209
|
└── docs/ # Documentation
|
|
211
210
|
```
|
|
212
211
|
|
|
213
212
|
### Adding New Features
|
|
214
213
|
|
|
215
|
-
1. **
|
|
216
|
-
2. **
|
|
217
|
-
3. **
|
|
218
|
-
4. **
|
|
219
|
-
5. **Document**: Update README/specs
|
|
220
|
-
6. **PR**: Submit for review
|
|
214
|
+
1. **Write tests**: Add tests first (TDD approach)
|
|
215
|
+
2. **Implement**: Write the code
|
|
216
|
+
3. **Document**: Update README.md and `docs/`
|
|
217
|
+
4. **PR**: Submit for review
|
|
221
218
|
|
|
222
219
|
## Submitting Issues
|
|
223
220
|
|
|
@@ -260,7 +257,7 @@ Include:
|
|
|
260
257
|
|
|
261
258
|
## Questions?
|
|
262
259
|
|
|
263
|
-
- Open a [Discussion](https://github.com/
|
|
260
|
+
- Open a [Discussion](https://github.com/ruslanfialkovskii/tasktree-manager/discussions)
|
|
264
261
|
- Ask in Pull Request
|
|
265
262
|
- Check existing issues
|
|
266
263
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://www.python.org/downloads/)
|
|
7
|
-
[](./tests/)
|
|
8
8
|
|
|
9
9
|
**tasktree-manager** is a terminal user interface (TUI) application for managing development tasks that span multiple git repositories. Create tasks, organize worktrees, and track status across your entire codebase—all from a beautiful, keyboard-driven interface inspired by [lazygit](https://github.com/jesseduffield/lazygit).
|
|
10
10
|
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
- 🛰️ **Agent Dashboard** - Live Claude Code session state per worktree (from `claude agents`), plus one-key background-agent dispatch — the multi-repo agent view Claude Code lacks natively
|
|
23
23
|
- ✻ **Session Recap** - The Info panel shows each task's latest Claude Code session: title, last turn duration, and Claude's own idle recap of what was done and what comes next — read straight from the transcript, no CLI call
|
|
24
24
|
- 🔀 **Forge-Aware Safety** - MR/PR and CI state via `glab`/`gh`; squash- and rebase-merged branches count as merged instead of blocking deletion forever
|
|
25
|
-
- 📦 **Finish Flow with Archives** - Ending a task saves its combined diff (committed-but-unmerged + uncommitted) to an archive before deleting
|
|
25
|
+
- 📦 **Finish Flow with Archives** - Ending a task saves its combined diff (committed-but-unmerged + uncommitted) and the task-folder files outside the worktrees (plans, ADRs, notes) to an archive before deleting
|
|
26
26
|
|
|
27
27
|
## 📊 Status Indicators
|
|
28
28
|
|
|
@@ -78,17 +78,27 @@ workflows (e.g. a skill that creates a Jira ticket and then the matching task):
|
|
|
78
78
|
|
|
79
79
|
```bash
|
|
80
80
|
tasktree-manager create DIC-1901-argocd-tls --repos backend,frontend # --base overrides the default base branch
|
|
81
|
-
tasktree-manager list --json # tasks with repos and dirty
|
|
81
|
+
tasktree-manager list --json # tasks with repos and state: clean / dirty / error (plain text without --json)
|
|
82
82
|
tasktree-manager repos # available repos in REPOS_DIR
|
|
83
83
|
tasktree-manager add-repo DIC-1901-argocd-tls infra
|
|
84
84
|
tasktree-manager status # current task inferred from $PWD; also --json / --oneline / --forge
|
|
85
|
-
tasktree-manager finish DIC-1901-argocd-tls # safety sweep -> archive diff -> delete; --push / --no-archive / --force
|
|
86
|
-
tasktree-manager delete DIC-1901-argocd-tls # archive diff -> delete; refuses on unfinished work; --force overrides
|
|
85
|
+
tasktree-manager finish DIC-1901-argocd-tls # safety sweep -> archive diff + task files -> delete; --push / --no-archive / --force
|
|
86
|
+
tasktree-manager delete DIC-1901-argocd-tls # archive diff + task files -> delete; refuses on unfinished work; --force overrides
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
Exit code is 0 on success, 1 on failure with the reason on stderr. `delete` and `finish` run
|
|
90
90
|
the same safety check as the TUI (uncommitted, unpushed, or unmerged work blocks deletion);
|
|
91
|
-
with `glab`/`gh` installed, squash/rebase-merged branches are recognized as merged.
|
|
91
|
+
with `glab`/`gh` installed, squash/rebase-merged branches are recognized as merged. If the
|
|
92
|
+
diff cannot be archived for any repo, the CLI stops before deleting and prints the path of
|
|
93
|
+
the partial archive; the TUI warns and deletes anyway. Files in the task folder outside the
|
|
94
|
+
worktrees are copied to `<task>-<timestamp>.files/` next to the patch:
|
|
95
|
+
|
|
96
|
+
- Skipped silently: hidden files, symlinks, `node_modules`/`vendor`/`.terraform` folders and
|
|
97
|
+
an unedited generated `CLAUDE.md`.
|
|
98
|
+
- Left out with a warning: key material (`*.pem`, `*.key`, `id_rsa`, kubeconfigs,
|
|
99
|
+
`*.tfstate`, `credentials*.json`), files over 10 MB and files past 100 MB in total.
|
|
100
|
+
- A file that cannot be read or copied stops `delete`/`finish` before anything is removed,
|
|
101
|
+
unless `--force`; the TUI warns and deletes anyway.
|
|
92
102
|
`status --oneline` emits a compact `TASK repoA✓ repoB●2↑1` summary that slots straight into
|
|
93
103
|
a Claude Code statusline or shell prompt.
|
|
94
104
|
|
|
@@ -145,7 +155,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed development setup and guidel
|
|
|
145
155
|
|
|
146
156
|
**Quick Start:**
|
|
147
157
|
```bash
|
|
148
|
-
git clone https://github.com/
|
|
158
|
+
git clone https://github.com/ruslanfialkovskii/tasktree-manager.git
|
|
149
159
|
cd tasktree-manager
|
|
150
160
|
mise install
|
|
151
161
|
mise run install
|
|
@@ -195,14 +205,13 @@ For comprehensive troubleshooting, see the [Troubleshooting Guide](docs/troubles
|
|
|
195
205
|
|
|
196
206
|
Recently shipped: agent dashboard (per-worktree Claude session badges + background dispatch),
|
|
197
207
|
forge-aware merged detection (glab/gh, squash/rebase merges), MR/CI status badges,
|
|
198
|
-
guided `finish` flow
|
|
208
|
+
guided `finish` flow that archives the diff and the task-folder files, `status` subcommand
|
|
209
|
+
for scripts and statuslines, Claude session recap in the Info panel.
|
|
199
210
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
- **v0.4.0** - JIRA status column, git hooks, automation
|
|
203
|
-
- **v1.0.0** - Stable release
|
|
211
|
+
Next: epics, a layer that groups related tasks (for example a Jira epic and its child
|
|
212
|
+
tasks) in the task list.
|
|
204
213
|
|
|
205
|
-
See [
|
|
214
|
+
See [CHANGELOG.md](CHANGELOG.md) for the release history.
|
|
206
215
|
|
|
207
216
|
## 📄 License
|
|
208
217
|
|
|
@@ -216,11 +225,11 @@ MIT License - see [LICENSE](./LICENSE) for details.
|
|
|
216
225
|
|
|
217
226
|
## 💬 Support & Community
|
|
218
227
|
|
|
219
|
-
- 🐛 [Bug Reports](https://github.com/
|
|
220
|
-
- 💡 [Feature Requests](https://github.com/
|
|
221
|
-
- 💬 [Discussions](https://github.com/
|
|
228
|
+
- 🐛 [Bug Reports](https://github.com/ruslanfialkovskii/tasktree-manager/issues)
|
|
229
|
+
- 💡 [Feature Requests](https://github.com/ruslanfialkovskii/tasktree-manager/issues)
|
|
230
|
+
- 💬 [Discussions](https://github.com/ruslanfialkovskii/tasktree-manager/discussions)
|
|
222
231
|
- 📖 [Documentation](docs/)
|
|
223
232
|
|
|
224
233
|
---
|
|
225
234
|
|
|
226
|
-
**Made with ❤️ by developers, for developers** | [⭐ Star this repo](https://github.com/
|
|
235
|
+
**Made with ❤️ by developers, for developers** | [⭐ Star this repo](https://github.com/ruslanfialkovskii/tasktree-manager)
|
|
@@ -59,6 +59,13 @@ rm ~/.config/tasktree-manager/config.toml
|
|
|
59
59
|
tasktree-manager
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
### Value Types
|
|
63
|
+
|
|
64
|
+
Boolean settings take TOML `true`/`false`; the quoted strings `"true"`/`"yes"`/`"1"`
|
|
65
|
+
and `"false"`/`"no"`/`"0"` (any case) are accepted too. Any other value, or a section such
|
|
66
|
+
as `[keybindings]` set to a plain value instead of a table, stops startup with an error that
|
|
67
|
+
names the key.
|
|
68
|
+
|
|
62
69
|
## Complete Configuration Example
|
|
63
70
|
|
|
64
71
|
Here's a fully annotated `config.toml` with all available options:
|
|
@@ -79,7 +86,7 @@ repos_dir = "/Users/username/repos"
|
|
|
79
86
|
# Created automatically if it doesn't exist
|
|
80
87
|
tasks_dir = "/Users/username/tasks"
|
|
81
88
|
|
|
82
|
-
# Directory for finished-task
|
|
89
|
+
# Directory for finished-task archives (diffs and task-folder files)
|
|
83
90
|
# Relative paths resolve under tasks_dir (never the current directory)
|
|
84
91
|
# Default: "" (uses <tasks_dir>/.archive)
|
|
85
92
|
archive_dir = ""
|
|
@@ -298,7 +305,7 @@ blocklist = [
|
|
|
298
305
|
|------------|------|-----------|---------------------|------------------------------------------------|
|
|
299
306
|
| `repos_dir` | path | `~/repos` | `REPOS_DIR` | Directory containing your git repositories |
|
|
300
307
|
| `tasks_dir` | path | `~/tasks` | `TASKS_DIR` | Directory where task worktrees will be created |
|
|
301
|
-
| `archive_dir` | path | `""` (`<tasks_dir>/.archive`) | - | Directory for finished-task
|
|
308
|
+
| `archive_dir` | path | `""` (`<tasks_dir>/.archive`) | - | Directory for finished-task archives (diffs and task-folder files) |
|
|
302
309
|
|
|
303
310
|
### Details
|
|
304
311
|
|
|
@@ -921,7 +921,7 @@ Yes! Each task creates its own worktree and branch:
|
|
|
921
921
|
|
|
922
922
|
- Worktrees are removed from `TASKS_DIR`
|
|
923
923
|
- The local task branch is deleted from the main repository (`git branch -D`);
|
|
924
|
-
the remaining diff
|
|
924
|
+
the remaining diff and the task-folder files are archived under `archive_dir` first
|
|
925
925
|
- Remote branches remain on GitHub/GitLab (if pushed)
|
|
926
926
|
|
|
927
927
|
**Manual cleanup (only for branches created outside tasktree):**
|
|
@@ -328,8 +328,9 @@ what is displayed. Press `?` for the full reference at any time.
|
|
|
328
328
|
6. Tab to "Create" button, press `Enter`
|
|
329
329
|
|
|
330
330
|
Task names may contain letters, numbers, `.`, `_` and `-`. The name becomes a
|
|
331
|
-
single directory under your tasks dir (and a git branch), so `/`,
|
|
332
|
-
|
|
331
|
+
single directory under your tasks dir (and a git branch), so `/`, a leading `.`
|
|
332
|
+
(hidden from the task list, and `.archive` is the archive dir) and a leading `-`
|
|
333
|
+
are rejected; base branch names must be plain branch names too (no
|
|
333
334
|
leading `-`/`+`, no `:` refspecs, none of the characters git forbids in refs).
|
|
334
335
|
|
|
335
336
|
**Clone task workflow:**
|
|
@@ -686,6 +687,12 @@ d (delete task)
|
|
|
686
687
|
- ✅ The task's remaining diff (committed-but-unmerged + uncommitted work) is archived to
|
|
687
688
|
`archive_dir` (default `<tasks_dir>/.archive/<task>-<timestamp>.patch`) before anything
|
|
688
689
|
is removed — the messages panel (`m`) shows the archive path
|
|
690
|
+
- ✅ Files in the task folder outside the worktrees (`PLAN.md`, ADRs, notes, scripts) are
|
|
691
|
+
copied to `<task>-<timestamp>.files/` next to the patch. Hidden files, symlinks,
|
|
692
|
+
`node_modules`/`vendor`/`.terraform` folders and an unedited generated `CLAUDE.md` are
|
|
693
|
+
skipped silently. Key material (`*.pem`, `*.key`, `id_rsa`, kubeconfigs, `*.tfstate`,
|
|
694
|
+
`credentials*.json`), files over 10 MB, files past 100 MB in total and files that cannot
|
|
695
|
+
be read or copied are listed in the messages panel
|
|
689
696
|
- ✅ Worktrees removed from `TASKS_DIR`
|
|
690
697
|
- ✅ Branches remain on remote (if pushed)
|
|
691
698
|
- ✅ Original repos in `REPOS_DIR` untouched
|
|
@@ -71,7 +71,7 @@ version-file = "tasktree_manager/_version.py"
|
|
|
71
71
|
# Semantic Release Configuration
|
|
72
72
|
[tool.semantic_release]
|
|
73
73
|
version_toml = ["pyproject.toml:tool.semantic_release.version"]
|
|
74
|
-
version = "2.13.
|
|
74
|
+
version = "2.13.3"
|
|
75
75
|
tag_format = "v{version}"
|
|
76
76
|
branch = "main"
|
|
77
77
|
commit_message = "chore(release): {version} [skip ci]"
|
|
@@ -117,8 +117,14 @@ def update_pyproject_version(current_version: str, new_version: str, dry_run: bo
|
|
|
117
117
|
if in_section and re.match(
|
|
118
118
|
r'^version\s*=\s*"' + re.escape(current_version) + '"', stripped
|
|
119
119
|
):
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
new_line = line.replace(f'"{current_version}"', f'"{new_version}"')
|
|
121
|
+
# A `--set` to the version that's already current (e.g. a retried
|
|
122
|
+
# release re-running against an already-bumped commit) makes the
|
|
123
|
+
# regex match but shouldn't count as a change — only the text
|
|
124
|
+
# actually differing does.
|
|
125
|
+
if new_line != line:
|
|
126
|
+
changed = True
|
|
127
|
+
line = new_line
|
|
122
128
|
|
|
123
129
|
updated_lines.append(line)
|
|
124
130
|
|
|
@@ -236,6 +242,15 @@ def update_changelog(new_version: str, message: str = "", dry_run: bool = False)
|
|
|
236
242
|
"and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n"
|
|
237
243
|
)
|
|
238
244
|
|
|
245
|
+
content = CHANGELOG_PATH.read_text() if CHANGELOG_PATH.exists() else ""
|
|
246
|
+
|
|
247
|
+
# A retried release (e.g. re-running after tag-release failed partway)
|
|
248
|
+
# can call this again for a version that's already documented — don't
|
|
249
|
+
# insert a second copy of its section.
|
|
250
|
+
if f"## [{new_version}]" in content:
|
|
251
|
+
print(f"CHANGELOG.md already has an entry for version {new_version}, skipping")
|
|
252
|
+
return False
|
|
253
|
+
|
|
239
254
|
today = datetime.now().strftime("%Y-%m-%d")
|
|
240
255
|
|
|
241
256
|
if message:
|
|
@@ -252,8 +267,6 @@ def update_changelog(new_version: str, message: str = "", dry_run: bool = False)
|
|
|
252
267
|
print(f"Would add new entry to CHANGELOG.md for version {new_version}")
|
|
253
268
|
return True
|
|
254
269
|
|
|
255
|
-
content = CHANGELOG_PATH.read_text()
|
|
256
|
-
|
|
257
270
|
# Insert after [Unreleased] section or at top after header
|
|
258
271
|
if "## [Unreleased]" in content:
|
|
259
272
|
# Find [Unreleased] section and insert new version after it
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2.13.
|
|
22
|
-
__version_tuple__ = version_tuple = (2, 13,
|
|
21
|
+
__version__ = version = '2.13.3'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 13, 3)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|