gitstow 0.2.8__tar.gz → 0.4.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.
- {gitstow-0.2.8 → gitstow-0.4.0}/.github/workflows/ci.yml +5 -1
- gitstow-0.4.0/BACKLOG.md +43 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/CHANGELOG.md +54 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/CLAUDE.md +19 -18
- {gitstow-0.2.8 → gitstow-0.4.0}/PKG-INFO +20 -18
- {gitstow-0.2.8 → gitstow-0.4.0}/README.md +8 -10
- {gitstow-0.2.8 → gitstow-0.4.0}/docs/building/audit-2026-07-06.md +22 -22
- gitstow-0.4.0/docs/building/plans/2026-07-12-ui-wave-a-make-it-real.md +831 -0
- gitstow-0.4.0/docs/building/plans/2026-07-12-ui-wave-b-polish.md +455 -0
- gitstow-0.4.0/docs/building/ui-audit-2026-07-12.md +57 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/docs/user/commands.md +39 -32
- {gitstow-0.2.8 → gitstow-0.4.0}/docs/user/getting-started.md +5 -1
- {gitstow-0.2.8 → gitstow-0.4.0}/pyproject.toml +13 -9
- {gitstow-0.2.8 → gitstow-0.4.0}/scripts/release.sh +6 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/__init__.py +1 -1
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/add.py +100 -34
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/config_cmd.py +6 -4
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/doctor.py +17 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/exec_cmd.py +4 -1
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/export_cmd.py +38 -70
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/fetch.py +31 -68
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/helpers.py +22 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/list_cmd.py +4 -1
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/main.py +0 -2
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/manage.py +4 -1
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/onboard.py +2 -1
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/open_cmd.py +25 -11
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/pull.py +52 -74
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/search.py +43 -30
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/serve.py +3 -2
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/status.py +43 -30
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/workspace_cmd.py +9 -0
- gitstow-0.4.0/src/gitstow/core/collection_io.py +98 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/core/config.py +3 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/core/discovery.py +11 -7
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/core/git.py +22 -5
- gitstow-0.4.0/src/gitstow/core/operations.py +98 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/core/repo.py +32 -1
- gitstow-0.4.0/src/gitstow/core/status_model.py +126 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/mcp/server.py +85 -43
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/skill/SKILL.md +5 -3
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/routes/collection.py +19 -74
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/routes/dashboard.py +101 -37
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/routes/pages.py +76 -8
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/routes/repos.py +60 -28
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/server.py +2 -2
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/static/app.css +105 -9
- gitstow-0.4.0/src/gitstow/web/static/dashboard.js +97 -0
- gitstow-0.4.0/src/gitstow/web/static/fonts/bricolage-grotesque-latin-ext-var.woff2 +0 -0
- gitstow-0.4.0/src/gitstow/web/static/fonts/bricolage-grotesque-latin-var.woff2 +0 -0
- gitstow-0.4.0/src/gitstow/web/static/fonts/fonts.css +81 -0
- gitstow-0.4.0/src/gitstow/web/static/fonts/jetbrains-mono-latin-ext-var.woff2 +0 -0
- gitstow-0.4.0/src/gitstow/web/static/fonts/jetbrains-mono-latin-var.woff2 +0 -0
- gitstow-0.4.0/src/gitstow/web/static/vendor/VENDORED.md +39 -0
- gitstow-0.4.0/src/gitstow/web/static/vendor/htmx.min.js +1 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/templates/_repo_drawer.html +5 -12
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/templates/add_repo.html +20 -2
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/templates/base.html +73 -1
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/templates/dashboard.html +25 -18
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/templates/partials/pull_summary.html +12 -1
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/templates/partials/repo_row.html +6 -6
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/templates/settings.html +46 -13
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/templates/workspaces.html +4 -2
- gitstow-0.4.0/tests/test_cli.py +902 -0
- gitstow-0.4.0/tests/test_collection_io.py +33 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/tests/test_config.py +9 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/tests/test_git.py +22 -0
- gitstow-0.4.0/tests/test_mcp.py +138 -0
- gitstow-0.4.0/tests/test_operations.py +67 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/tests/test_repo.py +51 -0
- gitstow-0.4.0/tests/test_serve.py +962 -0
- gitstow-0.4.0/tests/test_status_model.py +87 -0
- gitstow-0.2.8/BACKLOG.md +0 -18
- gitstow-0.2.8/src/gitstow/cli/tui.py +0 -27
- gitstow-0.2.8/src/gitstow/tui/__init__.py +0 -1
- gitstow-0.2.8/src/gitstow/tui/app.py +0 -384
- gitstow-0.2.8/tests/test_cli.py +0 -266
- gitstow-0.2.8/tests/test_serve.py +0 -435
- {gitstow-0.2.8 → gitstow-0.4.0}/.claude/settings.json +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/.github/workflows/publish.yml +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/.gitignore +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/AGENTS.md +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/CODE_OF_CONDUCT.md +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/CONTRIBUTING.md +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/LICENSE +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/SECURITY.md +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/demo.gif +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/demo.tape +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/docs/building/implementation-plan.md +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/docs/building/plans/2026-07-06-wave-1-correctness-safety.md +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/docs/building/plans/2026-07-06-wave-2-status-model.md +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/docs/building/plans/2026-07-06-wave-3-structure-polish.md +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/docs/user/concepts.md +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/docs/user/configuration.md +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/__main__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/__init__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/migrate.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/remove.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/setup_ai.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/shell.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/skill_cmd.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/stats.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/cli/update.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/core/__init__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/core/locking.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/core/parallel.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/core/paths.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/core/url_parser.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/mcp/__init__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/__init__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/routes/__init__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/routes/system.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/routes/workspaces.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/templates/partials/dashboard_rows.html +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/src/gitstow/web/templates/partials/fetch_summary.html +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/tests/__init__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/tests/conftest.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/tests/test_locking.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/tests/test_onboard.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/tests/test_setup_ai.py +0 -0
- {gitstow-0.2.8 → gitstow-0.4.0}/tests/test_url_parser.py +0 -0
|
@@ -8,10 +8,14 @@ on:
|
|
|
8
8
|
|
|
9
9
|
jobs:
|
|
10
10
|
test:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
11
|
strategy:
|
|
13
12
|
matrix:
|
|
13
|
+
os: [ubuntu-latest]
|
|
14
14
|
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
15
|
+
include:
|
|
16
|
+
- os: macos-latest
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
runs-on: ${{ matrix.os }}
|
|
15
19
|
|
|
16
20
|
steps:
|
|
17
21
|
- uses: actions/checkout@v4
|
gitstow-0.4.0/BACKLOG.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Backlog
|
|
2
|
+
|
|
3
|
+
Post-v0.1.0 improvements tracked here. See [GitHub Issues](https://github.com/rishmadaan/gitstow/issues) for discussion.
|
|
4
|
+
|
|
5
|
+
## Enhancements
|
|
6
|
+
|
|
7
|
+
- [x] **TUI: expand beyond read-only dashboard** (#1) — Added pull selected (P), workspace cycling (w), tag cycling (t)
|
|
8
|
+
- [x] **Shell completion for repo names** (#2) — `gitstow shell completions` for bash/zsh/fish; `--quiet` on list/tags/workspace list
|
|
9
|
+
- [x] **Network retry/resume for batch operations** (#3) — `--retry N` flag on add and pull; cleans up partial clones before retry
|
|
10
|
+
- [x] **Export format versioning and checksums** (#4) — Added `version: 1` to YAML/JSON exports; validates on import; backward-compatible with unversioned files
|
|
11
|
+
- [x] **Progress indication during long clones** (#5) — `git clone --progress`; pull shows live counter `[5/47]`
|
|
12
|
+
- [x] **Publish to PyPI** (#6) — Release workflow created (`.github/workflows/publish.yml`); publish on GitHub release
|
|
13
|
+
- [x] **Web dashboard (`gitstow ui`)** — Dark local browser UI wrapping core/ for daily repo management. FastAPI + Jinja2 + HTMX, dark + ember accent aesthetic. See [CHANGELOG.md](CHANGELOG.md) v0.2.0.
|
|
14
|
+
- [x] **Fix TUI breakage** — Resolved by retirement: the Textual TUI was removed in v0.3.0; `gitstow ui` (web dashboard) is the visual surface going forward.
|
|
15
|
+
|
|
16
|
+
## Documentation
|
|
17
|
+
|
|
18
|
+
- [x] **Record demo GIF for README** (#7) — Recorded with VHS, embedded in README
|
|
19
|
+
|
|
20
|
+
## Post-0.3.0 follow-ups
|
|
21
|
+
|
|
22
|
+
Triaged non-blocking items from the 2026-07 audit remediation (see
|
|
23
|
+
[docs/building/audit-2026-07-06.md](docs/building/audit-2026-07-06.md) for the full effort).
|
|
24
|
+
|
|
25
|
+
- [ ] **URL parser: schemeless multi-dot hosts** — `dev.azure.com/org/project/_git/repo` without
|
|
26
|
+
`https://` parses as owner/repo shorthand and builds a garbage clone URL (`_LOOKS_LIKE_HOST`
|
|
27
|
+
regex can't match a multi-dot first segment). Pre-existing; 0.3.1 candidate.
|
|
28
|
+
- [ ] **Route search subprocesses through a hardened runner** — `git grep`/`rg` in `cli/search.py`
|
|
29
|
+
and `mcp/server.py` shell raw `subprocess.run` without the `GIT_TERMINAL_PROMPT=0`/`LC_ALL=C`
|
|
30
|
+
env applied to all other git calls. Local-only operations, negligible risk — consistency cleanup.
|
|
31
|
+
- [ ] **Test strengthening batch** — frozen-collapse MCP test needs two frozen same-named repos;
|
|
32
|
+
`run_bulk` missing-status retry + `on_attempt` callback untested; locking mutual-exclusion test
|
|
33
|
+
passes without a lock (use an event-based barrier); status JSON legacy-key test covers 3/13 keys.
|
|
34
|
+
- [ ] **Small edges** — `add` on an on-disk repo with no remote falls through to a doomed clone;
|
|
35
|
+
whitespace-only `$EDITOR` raises IndexError; fully-untracked workspaces never get the untracked
|
|
36
|
+
hint (early return; `doctor` covers); dashboard vs single-row-refresh number sources diverge for
|
|
37
|
+
orphaned-workspace repos.
|
|
38
|
+
- [ ] **Product call: `pull --force` escape hatch** — CLI explicit args follow the bulk skip rule
|
|
39
|
+
while a web single-row Pull click pulls unconditionally; a `--force` flag would reconcile the
|
|
40
|
+
"explicit intent" asymmetry.
|
|
41
|
+
- [ ] **Product call: frozen + diverged + `--include-frozen`** — surfaces as an ff-only error row
|
|
42
|
+
instead of a clean "diverged" skip (check `remote_state` directly in the worker if the messaging
|
|
43
|
+
matters).
|
|
@@ -4,6 +4,60 @@ All notable changes to gitstow will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [0.4.0] - 2026-07-12
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Dashboard filters that actually filter.** The search box, workspace dropdown, and Hide-frozen toggle now work — instant client-side filtering that survives auto-refresh and pull updates.
|
|
12
|
+
- **Settings save.** The Settings page persists changes for real (and gains Parallel limit + Clone timeout fields).
|
|
13
|
+
- **`local` badge.** Repos without an upstream remote show a `local` Remote Δ badge; bulk pulls skip them with a clear reason instead of failing every run.
|
|
14
|
+
- **Responsive dashboard.** Works down to half-monitor width — columns collapse by priority, the table scrolls within its own container, and row menus flip upward when space runs out.
|
|
15
|
+
- **Last-fetched visibility.** The repo detail page shows when each repo was last pulled AND last fetched (hover for exact times); Remote Δ tooltips state which fetch the counts reflect.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **Fully offline dashboard.** htmx and both fonts are now bundled — no CDN, no network needed for the UI itself.
|
|
20
|
+
- **Styled confirmations.** Native browser confirm/alert dialogs replaced with an in-app dialog (also makes the dashboard automatable).
|
|
21
|
+
- **Web collection import honors recorded workspaces**, sharing one implementation with the CLI.
|
|
22
|
+
- **Honest metrics chips.** Diverged and missing repos get their own hero chips instead of hiding inside 'conflict'; the pull summary reads 'N attempted' with exclusions stated.
|
|
23
|
+
- **Cleaner micro-interactions.** Styled file picker, a LIVE dot that actually goes red when the server is unreachable, keyboard-visible focus rings, Escape closes menus, add-repo shows a Cloning… state.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **Pull all / Fetch all spinners stop when the operation completes** (htmx indicator/disable double-count).
|
|
28
|
+
- **Repo detail timestamps** no longer render raw machine format.
|
|
29
|
+
|
|
30
|
+
## [0.3.0] - 2026-07-12
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- **Composition-aware status everywhere.** `gitstow status` now shows a Local Changes column (modified/staged/untracked counts) and a separate Remote column (in-sync/ahead/behind/diverged). The web dashboard rows, repo drawer, and help legend all use the same shared classifier — a repo with only staged or untracked files can no longer display as "clean". JSON output gains additive `local` and `remote` keys (all existing keys preserved).
|
|
35
|
+
- **`gitstow fetch_repos` MCP tool** and a `last_fetched` timestamp in all JSON outputs — MCP clients can now see fetch state, matching the CLI and web dashboard.
|
|
36
|
+
- **Untracked-repo hints on `list` and `status`.** Repos found on disk but not in the registry are now surfaced with a hint pointing at `workspace scan`, instead of being silently invisible.
|
|
37
|
+
- **`doctor` detects orphaned workspaces**, and `workspace remove` now warns when repos would be left pointing at a removed workspace.
|
|
38
|
+
- **`clone_timeout` setting** (`gitstow config set clone_timeout <seconds>`) — clone operations on very large repos no longer fail on a hardcoded 300s limit.
|
|
39
|
+
- **macOS added to the CI test matrix**, matching the packaging classifiers.
|
|
40
|
+
- **CHANGELOG gate in the release script** — `scripts/release.sh` now refuses to cut a release without a corresponding changelog entry.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- **`add` clones multiple repos in parallel** and now detects remote mismatches and duplicate URLs before cloning, instead of silently registering whatever is already on disk.
|
|
45
|
+
- **`search` now runs across repos in parallel**, matching `exec`.
|
|
46
|
+
- **Pull, fetch, and the MCP server share one operations layer.** The MCP server now follows the same bulk-pull rule as the CLI and web dashboard (modified/staged skip, diverged skip, untracked-only pulls).
|
|
47
|
+
- **`open` prefers `$VISUAL`/`$EDITOR`** over guessing an editor, and runs terminal editors in the foreground so they actually get a usable TTY.
|
|
48
|
+
- **Disk sizing (`stats`, `repo info`) now shells out to `du`** instead of walking every file in Python — much faster on large repos.
|
|
49
|
+
- **`collection import` honors each entry's recorded workspace** instead of dumping everything into one workspace, and now fails loudly (with a printed error) on newer file versions instead of exiting silently.
|
|
50
|
+
- **The web dashboard's dependencies (FastAPI, uvicorn, Jinja2) moved to the optional `[ui]` extra.** Existing installs keep working; fresh CLI-only installs are ~15 packages lighter. Install with `pip install "gitstow[ui]"` to keep the dashboard.
|
|
51
|
+
- **Bulk pull rule unified and refined (behavior change).** CLI `pull` and the dashboard's Pull-all now follow one rule: repos with modified or staged files are skipped (with the composition shown), diverged repos are skipped (fast-forward pull cannot succeed), and repos with only untracked files ARE pulled — previously the CLI skipped them forever while the web pulled everything.
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- **`search`, `exec`, and `status` `--json` now emit pure JSON on an empty filter match** — previously they printed a "no repos match" banner and no payload at all, even with `--json` set.
|
|
56
|
+
|
|
57
|
+
### Removed
|
|
58
|
+
|
|
59
|
+
- **The Textual TUI (`gitstow tui`).** The web dashboard (`gitstow ui`) replaced it as the visual surface in v0.2.0; the TUI had been broken and parked since. Git history preserves it.
|
|
60
|
+
|
|
7
61
|
## [0.2.8] - 2026-07-12
|
|
8
62
|
|
|
9
63
|
### Fixed
|
|
@@ -25,21 +25,20 @@ src/gitstow/
|
|
|
25
25
|
│ ├── exec_cmd.py, search.py, open_cmd.py, stats.py # Power commands
|
|
26
26
|
│ ├── export_cmd.py # export/import collection
|
|
27
27
|
│ ├── shell.py # Shell integration (fzf, aliases)
|
|
28
|
-
│ ├── tui.py # TUI launcher
|
|
29
28
|
│ ├── serve.py # Web dashboard launcher
|
|
30
29
|
│ ├── migrate.py, config_cmd.py, onboard.py, doctor.py, skill_cmd.py
|
|
31
30
|
│ └── __init__.py
|
|
32
31
|
├── core/ # Business logic (git ops, URL parsing, state)
|
|
33
|
-
│ ├── paths.py
|
|
34
|
-
│ ├── config.py
|
|
35
|
-
│ ├── repo.py
|
|
36
|
-
│ ├── url_parser.py
|
|
37
|
-
│ ├── git.py
|
|
38
|
-
│ ├── discovery.py
|
|
39
|
-
│ ├── parallel.py
|
|
40
|
-
│
|
|
41
|
-
├──
|
|
42
|
-
│ ├──
|
|
32
|
+
│ ├── paths.py # Path constants, central repos.yaml resolution
|
|
33
|
+
│ ├── config.py # Workspace + Settings dataclasses, load/save
|
|
34
|
+
│ ├── repo.py # Repo dataclass + RepoStore (nested YAML CRUD)
|
|
35
|
+
│ ├── url_parser.py # URL → (host, owner, repo) extraction
|
|
36
|
+
│ ├── git.py # All git subprocess calls
|
|
37
|
+
│ ├── discovery.py # Walk directory tree (structured + flat), reconcile
|
|
38
|
+
│ ├── parallel.py # Async execution with semaphore
|
|
39
|
+
│ ├── status_model.py # Shared repo-state classifier — local composition vs remote relationship
|
|
40
|
+
│ ├── operations.py # Shared filter + bulk-runner layer (pull/fetch/MCP)
|
|
41
|
+
│ ├── locking.py # Cross-process file lock guarding repos.yaml writes
|
|
43
42
|
│ └── __init__.py
|
|
44
43
|
├── web/ # FastAPI browser dashboard (gitstow ui)
|
|
45
44
|
│ ├── server.py # FastAPI app, uvicorn runner, app.state.server stash
|
|
@@ -64,15 +63,18 @@ src/gitstow/
|
|
|
64
63
|
- `core/url_parser.py` — URL parsing (the hardest part). Test changes here thoroughly.
|
|
65
64
|
- `core/git.py` — All git subprocess calls. Uses `git status --porcelain=v2 --branch` for single-call efficiency.
|
|
66
65
|
- `core/parallel.py` — Async execution with semaphore (max 6 concurrent).
|
|
66
|
+
- `core/status_model.py` — `RepoState` — the single source of truth for local (modified/staged/untracked) vs remote (in-sync/ahead/behind/diverged) classification, consumed by CLI, web, and JSON.
|
|
67
|
+
- `core/operations.py` — Shared `filter_repo_pairs()` + bulk-runner used by `pull`, `fetch`, and the MCP server so surfaces can't drift.
|
|
68
|
+
- `core/locking.py` — `file_lock()` cross-process advisory lock guarding `repos.yaml` against concurrent CLI/web writes.
|
|
67
69
|
- `cli/helpers.py` — Shared workspace resolution used by all CLI commands.
|
|
68
70
|
- `cli/workspace_cmd.py` — workspace list/add/remove/scan subcommands.
|
|
69
71
|
- `cli/main.py` — Typer app, global `-w/--workspace` option, command registration.
|
|
70
|
-
- `tui/app.py` — Textual dashboard with DataTable, filter, pull, freeze toggle.
|
|
71
72
|
|
|
72
73
|
## Data Files
|
|
73
74
|
|
|
74
75
|
- `~/.gitstow/config.yaml` — Settings (workspaces list, default host, SSH pref).
|
|
75
76
|
- `~/.gitstow/repos.yaml` — Repo metadata nested by workspace label. Central location.
|
|
77
|
+
- `~/.gitstow/repos.lock` — Cross-process advisory lock file (`core/locking.py`) held during `repos.yaml` writes. Not user-facing data; safe to ignore/delete if orphaned.
|
|
76
78
|
|
|
77
79
|
### repos.yaml format
|
|
78
80
|
```yaml
|
|
@@ -86,14 +88,14 @@ active:
|
|
|
86
88
|
tags: [active]
|
|
87
89
|
```
|
|
88
90
|
|
|
89
|
-
## All Commands (
|
|
91
|
+
## All Commands (37)
|
|
90
92
|
|
|
91
93
|
**Core:** `add`, `pull`, `fetch`, `list`, `status`, `remove`, `migrate`
|
|
92
94
|
**Workspace:** `workspace list`, `workspace add`, `workspace remove`, `workspace scan`
|
|
93
95
|
**Repo management:** `repo freeze`, `repo unfreeze`, `repo tag`, `repo untag`, `repo tags`, `repo info`
|
|
94
96
|
**Power:** `exec`, `search`, `open`, `stats`
|
|
95
97
|
**Sharing:** `collection export`, `collection import`
|
|
96
|
-
**Shell:** `shell pick`, `shell init`, `shell completions`, `shell setup`, `
|
|
98
|
+
**Shell:** `shell pick`, `shell init`, `shell completions`, `shell setup`, `ui`
|
|
97
99
|
**Setup:** `onboard`, `config show/set/path/migrate-root`, `doctor`, `install-skill`, `setup-ai`, `update`
|
|
98
100
|
|
|
99
101
|
## Development
|
|
@@ -101,9 +103,8 @@ active:
|
|
|
101
103
|
```bash
|
|
102
104
|
cd ~/labs/projects/gitstow
|
|
103
105
|
pip install -e ".[dev]"
|
|
104
|
-
pytest #
|
|
106
|
+
pytest # full suite — keep green
|
|
105
107
|
ruff check src/
|
|
106
|
-
pip install -e ".[tui]" # For TUI development
|
|
107
108
|
```
|
|
108
109
|
|
|
109
110
|
## Patterns
|
|
@@ -123,7 +124,7 @@ pip install -e ".[tui]" # For TUI development
|
|
|
123
124
|
|
|
124
125
|
- Prefer proper long-term solutions over shortcut patches. If a feature is incomplete in one surface, build the feature into that surface instead of papering over it with wording, partial conditionals, or one-off display logic.
|
|
125
126
|
- Do not recommend quick fixes, temporary patches, or narrow workarounds unless the user explicitly asks for a shortcut.
|
|
126
|
-
- Keep CLI,
|
|
127
|
+
- Keep CLI, web dashboard, JSON output, docs, and tests semantically aligned when changing user-facing status behavior.
|
|
127
128
|
- For repo state presentation, avoid using "dirty" as a broad user-facing bucket for every local change. Present it as local/uncommitted changes with the composition visible: modified, staged, and untracked counts.
|
|
128
129
|
- Keep local working-tree state separate from remote relationship state. For example: local changes, clean, ahead, behind, diverged, frozen, missing.
|
|
129
130
|
- When improving the web dashboard, implement the actual missing dashboard feature and shared classification/model behavior instead of copying a CLI-only assumption into the template.
|
|
@@ -139,6 +140,6 @@ pip install -e ".[tui]" # For TUI development
|
|
|
139
140
|
**Optional: MCP server** (`src/gitstow/mcp/server.py`)
|
|
140
141
|
- For non-Claude-Code AI tools (Claude Desktop, Cursor, Windsurf)
|
|
141
142
|
- Install: `pip install gitstow[mcp]`, entry point: `gitstow-mcp`
|
|
142
|
-
-
|
|
143
|
+
- 14 tools + 3 resources, wraps same `core/` modules as CLI
|
|
143
144
|
- **Tradeoff:** MCP tools are always loaded into context (costs tokens even when idle).
|
|
144
145
|
The skill has no such cost. Only use MCP for dedicated repo-management setups.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitstow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A git repository library manager — clone, organize, and maintain collections of repos you learn from
|
|
5
5
|
Project-URL: Homepage, https://github.com/rishmadaan/gitstow
|
|
6
6
|
Project-URL: Repository, https://github.com/rishmadaan/gitstow
|
|
@@ -26,21 +26,25 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
26
26
|
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
27
27
|
Requires-Python: >=3.10
|
|
28
28
|
Requires-Dist: beaupy>=3.0
|
|
29
|
-
Requires-Dist: fastapi>=0.110
|
|
30
|
-
Requires-Dist: jinja2>=3.1
|
|
31
|
-
Requires-Dist: python-multipart>=0.0.9
|
|
32
29
|
Requires-Dist: pyyaml>=6.0
|
|
33
30
|
Requires-Dist: rich>=13.0
|
|
34
|
-
Requires-Dist: typer
|
|
35
|
-
Requires-Dist: uvicorn>=0.27
|
|
31
|
+
Requires-Dist: typer>=0.9
|
|
36
32
|
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: fastapi>=0.110; extra == 'dev'
|
|
37
34
|
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
35
|
+
Requires-Dist: jinja2>=3.1; extra == 'dev'
|
|
36
|
+
Requires-Dist: mcp>=1.0; extra == 'dev'
|
|
38
37
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: python-multipart>=0.0.9; extra == 'dev'
|
|
39
39
|
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
40
|
+
Requires-Dist: uvicorn>=0.27; extra == 'dev'
|
|
40
41
|
Provides-Extra: mcp
|
|
41
42
|
Requires-Dist: mcp>=1.0; extra == 'mcp'
|
|
42
|
-
Provides-Extra:
|
|
43
|
-
Requires-Dist:
|
|
43
|
+
Provides-Extra: ui
|
|
44
|
+
Requires-Dist: fastapi>=0.110; extra == 'ui'
|
|
45
|
+
Requires-Dist: jinja2>=3.1; extra == 'ui'
|
|
46
|
+
Requires-Dist: python-multipart>=0.0.9; extra == 'ui'
|
|
47
|
+
Requires-Dist: uvicorn>=0.27; extra == 'ui'
|
|
44
48
|
Description-Content-Type: text/markdown
|
|
45
49
|
|
|
46
50
|
# gitstow
|
|
@@ -62,8 +66,8 @@ Existing tools solve parts of this:
|
|
|
62
66
|
## Quick Start
|
|
63
67
|
|
|
64
68
|
```bash
|
|
65
|
-
pipx install gitstow # recommended
|
|
66
|
-
# or: pip install gitstow
|
|
69
|
+
pipx install "gitstow[ui]" # recommended — CLI + browser dashboard
|
|
70
|
+
# or: pip install gitstow # CLI only; add [ui] for the dashboard
|
|
67
71
|
|
|
68
72
|
# First-run setup (optional — works without it)
|
|
69
73
|
gitstow onboard
|
|
@@ -99,6 +103,8 @@ gitstow workspace scan active
|
|
|
99
103
|
```bash
|
|
100
104
|
gitstow add anthropic/claude-code facebook/react torvalds/linux
|
|
101
105
|
```
|
|
106
|
+
Multiple URLs clone concurrently (bounded by `parallel_limit`, default 6) — a mismatched remote on an existing path errors instead of silently registering, and duplicate URLs in the same invocation are deduped.
|
|
107
|
+
|
|
102
108
|
Creates (in a structured workspace):
|
|
103
109
|
```
|
|
104
110
|
~/oss/
|
|
@@ -117,8 +123,9 @@ gitstow -w oss pull # Only update oss workspace
|
|
|
117
123
|
gitstow pull --tag ai # Only repos tagged 'ai'
|
|
118
124
|
gitstow pull --exclude-tag stale # Everything except stale repos
|
|
119
125
|
gitstow status # Git status dashboard
|
|
120
|
-
gitstow -w active status --dirty #
|
|
126
|
+
gitstow -w active status --dirty # Repos with local changes in active workspace
|
|
121
127
|
```
|
|
128
|
+
`status` shows local changes as a composition (e.g. "2 modified · 1 staged · 3 untracked") rather than a single "dirty" bucket, and keeps the remote relationship (ahead/behind/diverged) in its own column.
|
|
122
129
|
|
|
123
130
|
### Freeze & Tags
|
|
124
131
|
```bash
|
|
@@ -182,17 +189,13 @@ gsp # gitstow pull shorthand
|
|
|
182
189
|
|
|
183
190
|
### Browser Dashboard
|
|
184
191
|
```bash
|
|
185
|
-
gitstow
|
|
192
|
+
pip install "gitstow[ui]" # if you installed CLI-only
|
|
193
|
+
gitstow ui # opens http://127.0.0.1:7853 in your browser
|
|
186
194
|
gitstow ui --port 8080
|
|
187
195
|
gitstow ui --no-browser
|
|
188
196
|
```
|
|
189
197
|
Persistent local web dashboard for daily repo management — a tab you leave open. Shows dirty state across your library, pulls single repos or all-of-them with a parallel summary panel, adds/removes repos, edits tags, freezes stale ones. Auto-refreshes row status every 30 seconds. Binds `127.0.0.1` only (arbitrary git execution must not be LAN-reachable). Click **Shutdown** in the footer — or Ctrl+C — to stop.
|
|
190
198
|
|
|
191
|
-
### Interactive Dashboard (TUI)
|
|
192
|
-
```bash
|
|
193
|
-
gitstow tui # Keyboard-driven terminal dashboard (SSH-friendly)
|
|
194
|
-
```
|
|
195
|
-
|
|
196
199
|
### JSON Output
|
|
197
200
|
Every command supports `--json` for scripting and AI consumption:
|
|
198
201
|
```bash
|
|
@@ -237,7 +240,6 @@ gitstow status --json
|
|
|
237
240
|
| `gitstow shell init` | Print shell functions to source in rc file |
|
|
238
241
|
| `gitstow shell pick` | fzf-powered repo picker |
|
|
239
242
|
| `gitstow shell completions` | Tab completion for repo names, workspaces, tags |
|
|
240
|
-
| `gitstow tui` | Interactive terminal dashboard |
|
|
241
243
|
| `gitstow fetch` | Fetch all remotes — update ahead/behind counts without merging |
|
|
242
244
|
| `gitstow ui` | Launch local browser dashboard (http://127.0.0.1:7853) |
|
|
243
245
|
| `gitstow update` | Upgrade gitstow itself from PyPI (detects pipx / pip / editable) |
|
|
@@ -17,8 +17,8 @@ Existing tools solve parts of this:
|
|
|
17
17
|
## Quick Start
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
pipx install gitstow # recommended
|
|
21
|
-
# or: pip install gitstow
|
|
20
|
+
pipx install "gitstow[ui]" # recommended — CLI + browser dashboard
|
|
21
|
+
# or: pip install gitstow # CLI only; add [ui] for the dashboard
|
|
22
22
|
|
|
23
23
|
# First-run setup (optional — works without it)
|
|
24
24
|
gitstow onboard
|
|
@@ -54,6 +54,8 @@ gitstow workspace scan active
|
|
|
54
54
|
```bash
|
|
55
55
|
gitstow add anthropic/claude-code facebook/react torvalds/linux
|
|
56
56
|
```
|
|
57
|
+
Multiple URLs clone concurrently (bounded by `parallel_limit`, default 6) — a mismatched remote on an existing path errors instead of silently registering, and duplicate URLs in the same invocation are deduped.
|
|
58
|
+
|
|
57
59
|
Creates (in a structured workspace):
|
|
58
60
|
```
|
|
59
61
|
~/oss/
|
|
@@ -72,8 +74,9 @@ gitstow -w oss pull # Only update oss workspace
|
|
|
72
74
|
gitstow pull --tag ai # Only repos tagged 'ai'
|
|
73
75
|
gitstow pull --exclude-tag stale # Everything except stale repos
|
|
74
76
|
gitstow status # Git status dashboard
|
|
75
|
-
gitstow -w active status --dirty #
|
|
77
|
+
gitstow -w active status --dirty # Repos with local changes in active workspace
|
|
76
78
|
```
|
|
79
|
+
`status` shows local changes as a composition (e.g. "2 modified · 1 staged · 3 untracked") rather than a single "dirty" bucket, and keeps the remote relationship (ahead/behind/diverged) in its own column.
|
|
77
80
|
|
|
78
81
|
### Freeze & Tags
|
|
79
82
|
```bash
|
|
@@ -137,17 +140,13 @@ gsp # gitstow pull shorthand
|
|
|
137
140
|
|
|
138
141
|
### Browser Dashboard
|
|
139
142
|
```bash
|
|
140
|
-
gitstow
|
|
143
|
+
pip install "gitstow[ui]" # if you installed CLI-only
|
|
144
|
+
gitstow ui # opens http://127.0.0.1:7853 in your browser
|
|
141
145
|
gitstow ui --port 8080
|
|
142
146
|
gitstow ui --no-browser
|
|
143
147
|
```
|
|
144
148
|
Persistent local web dashboard for daily repo management — a tab you leave open. Shows dirty state across your library, pulls single repos or all-of-them with a parallel summary panel, adds/removes repos, edits tags, freezes stale ones. Auto-refreshes row status every 30 seconds. Binds `127.0.0.1` only (arbitrary git execution must not be LAN-reachable). Click **Shutdown** in the footer — or Ctrl+C — to stop.
|
|
145
149
|
|
|
146
|
-
### Interactive Dashboard (TUI)
|
|
147
|
-
```bash
|
|
148
|
-
gitstow tui # Keyboard-driven terminal dashboard (SSH-friendly)
|
|
149
|
-
```
|
|
150
|
-
|
|
151
150
|
### JSON Output
|
|
152
151
|
Every command supports `--json` for scripting and AI consumption:
|
|
153
152
|
```bash
|
|
@@ -192,7 +191,6 @@ gitstow status --json
|
|
|
192
191
|
| `gitstow shell init` | Print shell functions to source in rc file |
|
|
193
192
|
| `gitstow shell pick` | fzf-powered repo picker |
|
|
194
193
|
| `gitstow shell completions` | Tab completion for repo names, workspaces, tags |
|
|
195
|
-
| `gitstow tui` | Interactive terminal dashboard |
|
|
196
194
|
| `gitstow fetch` | Fetch all remotes — update ahead/behind counts without merging |
|
|
197
195
|
| `gitstow ui` | Launch local browser dashboard (http://127.0.0.1:7853) |
|
|
198
196
|
| `gitstow update` | Upgrade gitstow itself from PyPI (detects pipx / pip / editable) |
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Date:** 2026-07-06
|
|
4
4
|
**Auditor:** Claude (Fable 5), full read of all source (~9.5k lines Python), planning docs, tests, CI, packaging
|
|
5
5
|
**Baseline:** commit `1aefe9a`, 139 tests passing
|
|
6
|
-
**Status:**
|
|
6
|
+
**Status:** COMPLETE — all three waves shipped (Wave 1 → 0.2.8; Waves 2+3 → 0.3.0)
|
|
7
7
|
|
|
8
8
|
This document is the working tracker for the post-audit improvement effort. Each finding
|
|
9
9
|
has an ID for reference. Check items off as waves land.
|
|
@@ -119,27 +119,27 @@ Opus (substantial) / Sonnet (mechanical) subagents.
|
|
|
119
119
|
- [x] B12 path-containment check in CLI `remove --delete`
|
|
120
120
|
- [x] B11 workspace label validation
|
|
121
121
|
|
|
122
|
-
### Wave 2 — Shared status model (Opus) —
|
|
123
|
-
- [
|
|
124
|
-
- [
|
|
125
|
-
- [
|
|
126
|
-
- [
|
|
127
|
-
- [
|
|
128
|
-
- [
|
|
129
|
-
- [
|
|
130
|
-
|
|
131
|
-
### Wave 3 — Structure & polish (Sonnet-heavy, Opus for A3/A4) —
|
|
132
|
-
- [
|
|
133
|
-
- [
|
|
134
|
-
- [
|
|
135
|
-
- [
|
|
136
|
-
- [
|
|
137
|
-
- [
|
|
138
|
-
- [
|
|
139
|
-
- [
|
|
140
|
-
- [
|
|
141
|
-
- [
|
|
142
|
-
- [
|
|
122
|
+
### Wave 2 — Shared status model (Opus) — COMPLETE (2026-07-12)
|
|
123
|
+
- [x] P5 retire the Textual TUI (decision: retire; clears the third surface before the refactor)
|
|
124
|
+
- [x] A1/P4 `core/status_model.py`: one classifier separating local composition (modified/staged/untracked counts) from remote relationship (in-sync/ahead/behind/diverged) + frozen/missing overlays
|
|
125
|
+
- [x] Consume from CLI `status`, web dashboard, and `--json` payloads (per CLAUDE.md standards)
|
|
126
|
+
- [x] B6 one pull rule on both surfaces: modified/staged skip, untracked-only pulls (decision locked)
|
|
127
|
+
- [x] E1 parallelize web status gathering via `run_parallel` (off the event loop)
|
|
128
|
+
- [x] E2 batch RepoStore updates — `bulk()` (single save per bulk op)
|
|
129
|
+
- [x] Tests covering the classifier matrix
|
|
130
|
+
|
|
131
|
+
### Wave 3 — Structure & polish (Sonnet-heavy, Opus for A3/A4) — COMPLETE (2026-07-12)
|
|
132
|
+
- [x] P1/E3 parallel `add` clones; P2 remote-mismatch conflict error
|
|
133
|
+
- [x] E4 parallel `search`
|
|
134
|
+
- [x] A4 `core/operations.py` extraction (filters + bulk runner); collapse pull/fetch duplication
|
|
135
|
+
- [x] A3 MCP server consumes operations layer; add `last_fetched` everywhere (DOC3); new `fetch_repos` tool
|
|
136
|
+
- [x] P3 reconciliation hints surfacing untracked repos in `list`/`status` (human output only; JSON shapes unchanged)
|
|
137
|
+
- [x] B7 import preserves workspace; loud version error. B8 orphaned-workspace detection in doctor + workspace remove warning
|
|
138
|
+
- [x] B9 `$VISUAL`/`$EDITOR`-first open logic; terminal editors run foreground
|
|
139
|
+
- [x] A2 web stack → `[ui]` extra (decision locked; ships 0.3.0)
|
|
140
|
+
- [x] E5 `du`-backed disk sizing; E6 configurable `clone_timeout` setting
|
|
141
|
+
- [x] D2 macOS CI; D3 changelog gate in release.sh; D4 typer extra; D5 fetch/MCP tests
|
|
142
|
+
- [x] DOC1/DOC2 docs sync
|
|
143
143
|
|
|
144
144
|
## Verification notes
|
|
145
145
|
|