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.
Files changed (77) hide show
  1. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.github/workflows/release.yml +17 -2
  2. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.gitignore +1 -2
  3. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/CHANGELOG.md +24 -0
  4. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/CONTRIBUTING.md +7 -10
  5. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/PKG-INFO +1 -1
  6. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/README.md +26 -17
  7. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/docs/configuration.md +9 -2
  8. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/docs/troubleshooting.md +1 -1
  9. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/docs/user-guide.md +9 -2
  10. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/pyproject.toml +1 -1
  11. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/scripts/bump_version.py +17 -4
  12. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/_version.py +2 -2
  13. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/app.py +217 -50
  14. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/cli.py +103 -28
  15. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/agent_sessions.py +1 -0
  16. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/claude_hooks.py +64 -26
  17. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/config.py +73 -22
  18. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/forge.py +1 -0
  19. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/git_ops.py +14 -5
  20. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/models.py +19 -1
  21. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/task_manager.py +535 -68
  22. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/create_modal.py +9 -4
  23. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/setup_modal.py +8 -4
  24. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/task_list.py +9 -12
  25. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/worktree_list.py +9 -2
  26. tasktree_manager-2.13.3/tests/test_agent_sessions_decode.py +31 -0
  27. tasktree_manager-2.13.3/tests/test_app_review_fixes.py +606 -0
  28. tasktree_manager-2.13.3/tests/test_bump_version.py +135 -0
  29. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_claude_hooks.py +142 -0
  30. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_claude_sessions.py +21 -0
  31. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_cli.py +241 -0
  32. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_config.py +131 -1
  33. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_forge.py +21 -0
  34. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_git_ops.py +64 -0
  35. tasktree_manager-2.13.3/tests/test_list_selection.py +130 -0
  36. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_medium_fixes.py +1 -1
  37. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_modals.py +78 -0
  38. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_task_manager.py +781 -8
  39. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_worktree_badges.py +1 -1
  40. tasktree_manager-2.13.1/OPENSPEC.md +0 -457
  41. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/SKILL.md +0 -0
  42. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/assets/README.md +0 -0
  43. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/assets/dashboard_app.py +0 -0
  44. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/assets/data_viewer.py +0 -0
  45. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/assets/todo_app.py +0 -0
  46. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/assets/worker_demo.py +0 -0
  47. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/references/layouts.md +0 -0
  48. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/references/official-guides-index.md +0 -0
  49. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/references/styling.md +0 -0
  50. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.claude/skills/textual-tui/references/widgets.md +0 -0
  51. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.github/templates/CHANGELOG.md.j2 +0 -0
  52. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/.github/workflows/ci.yml +0 -0
  53. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/LICENSE +0 -0
  54. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/ROADMAP.md +0 -0
  55. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/docs/claude-code-integration-spec.md +0 -0
  56. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/docs/installation.md +0 -0
  57. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/mise.toml +0 -0
  58. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/__init__.py +0 -0
  59. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/commands.py +0 -0
  60. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/__init__.py +0 -0
  61. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/services/claude_sessions.py +0 -0
  62. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/themes.py +0 -0
  63. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/__init__.py +0 -0
  64. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/app_header.py +0 -0
  65. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/messages_panel.py +0 -0
  66. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tasktree_manager/widgets/status_panel.py +0 -0
  67. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/__init__.py +0 -0
  68. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/conftest.py +0 -0
  69. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_agent_sessions.py +0 -0
  70. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_app.py +0 -0
  71. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_commands.py +0 -0
  72. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_integration_git.py +0 -0
  73. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_memory.py +0 -0
  74. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_messages_panel.py +0 -0
  75. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_safety_fixes.py +0 -0
  76. {tasktree_manager-2.13.1 → tasktree_manager-2.13.3}/tests/test_setup_modal.py +0 -0
  77. {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
- git push origin HEAD:main
210
- git push origin "v${new_version}"
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
- tasktree/_version.py
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/yourusername/tasktree-manager.git
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 OPENSPEC.md for architecture changes
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. **Check specs**: Review existing specs in `specs/`
216
- 2. **Create spec**: Write a new spec (SPEC-XXX) if needed
217
- 3. **Write tests**: Add tests first (TDD approach)
218
- 4. **Implement**: Write the code
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/yourusername/tasktree-manager/discussions)
260
+ - Open a [Discussion](https://github.com/ruslanfialkovskii/tasktree-manager/discussions)
264
261
  - Ask in Pull Request
265
262
  - Check existing issues
266
263
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tasktree-manager
3
- Version: 2.13.1
3
+ Version: 2.13.3
4
4
  Summary: TUI application for managing worktree-based tasks
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.10
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
7
- [![Tests](https://img.shields.io/badge/tests-228%20passed-green.svg)](./tests/)
7
+ [![Tests](https://img.shields.io/badge/tests-pytest-green.svg)](./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 state (plain text without --json)
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/yourusername/tasktree-manager.git
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 with diff archiving, `status` subcommand for scripts and statuslines.
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
- Upcoming:
201
- - **v0.3.0** - Search/filter, task templates
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 [ROADMAP.md](ROADMAP.md) and [CHANGELOG.md](CHANGELOG.md) for details.
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/yourusername/tasktree-manager/issues)
220
- - 💡 [Feature Requests](https://github.com/yourusername/tasktree-manager/issues)
221
- - 💬 [Discussions](https://github.com/yourusername/tasktree-manager/discussions)
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/yourusername/tasktree-manager)
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 diff archives
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 diff archives |
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 is archived under `archive_dir` first
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 `/`, `.`, `..` and a
332
- leading `-` are rejected; base branch names must be plain branch names too (no
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.1"
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
- line = line.replace(f'"{current_version}"', f'"{new_version}"')
121
- changed = True
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.1'
22
- __version_tuple__ = version_tuple = (2, 13, 1)
21
+ __version__ = version = '2.13.3'
22
+ __version_tuple__ = version_tuple = (2, 13, 3)
23
23
 
24
24
  __commit_id__ = commit_id = None