gitstow 0.3.0__tar.gz → 0.5.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.3.0 → gitstow-0.5.0}/AGENTS.md +48 -43
- gitstow-0.5.0/BACKLOG.md +43 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/CHANGELOG.md +30 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/CLAUDE.md +4 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/PKG-INFO +1 -1
- gitstow-0.5.0/docs/building/plans/2026-07-12-ui-wave-a-make-it-real.md +831 -0
- gitstow-0.5.0/docs/building/plans/2026-07-12-ui-wave-b-polish.md +455 -0
- gitstow-0.5.0/docs/building/plans/2026-07-16-move-repo-between-workspaces.md +95 -0
- gitstow-0.5.0/docs/building/ui-audit-2026-07-12.md +57 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/docs/user/commands.md +1 -1
- {gitstow-0.3.0 → gitstow-0.5.0}/pyproject.toml +1 -1
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/__init__.py +1 -1
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/export_cmd.py +3 -89
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/manage.py +31 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/pull.py +6 -0
- gitstow-0.5.0/src/gitstow/core/collection_io.py +98 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/core/git.py +11 -0
- gitstow-0.5.0/src/gitstow/core/operations.py +349 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/core/status_model.py +8 -1
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/routes/collection.py +14 -73
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/routes/dashboard.py +45 -10
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/routes/pages.py +76 -8
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/routes/repos.py +30 -3
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/server.py +2 -2
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/static/app.css +105 -9
- gitstow-0.5.0/src/gitstow/web/static/dashboard.js +97 -0
- gitstow-0.5.0/src/gitstow/web/static/fonts/bricolage-grotesque-latin-ext-var.woff2 +0 -0
- gitstow-0.5.0/src/gitstow/web/static/fonts/bricolage-grotesque-latin-var.woff2 +0 -0
- gitstow-0.5.0/src/gitstow/web/static/fonts/fonts.css +81 -0
- gitstow-0.5.0/src/gitstow/web/static/fonts/jetbrains-mono-latin-ext-var.woff2 +0 -0
- gitstow-0.5.0/src/gitstow/web/static/fonts/jetbrains-mono-latin-var.woff2 +0 -0
- gitstow-0.5.0/src/gitstow/web/static/vendor/VENDORED.md +39 -0
- gitstow-0.5.0/src/gitstow/web/static/vendor/htmx.min.js +1 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/templates/_repo_drawer.html +26 -3
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/templates/add_repo.html +20 -2
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/templates/base.html +73 -1
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/templates/dashboard.html +19 -12
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/templates/partials/pull_summary.html +1 -1
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/templates/partials/repo_row.html +6 -6
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/templates/settings.html +46 -13
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/templates/workspaces.html +4 -2
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/test_cli.py +70 -2
- gitstow-0.5.0/tests/test_collection_io.py +33 -0
- gitstow-0.5.0/tests/test_move.py +600 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/test_serve.py +426 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/test_status_model.py +6 -2
- gitstow-0.3.0/BACKLOG.md +0 -18
- gitstow-0.3.0/src/gitstow/core/operations.py +0 -98
- {gitstow-0.3.0 → gitstow-0.5.0}/.claude/settings.json +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/.github/workflows/ci.yml +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/.github/workflows/publish.yml +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/.gitignore +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/CODE_OF_CONDUCT.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/CONTRIBUTING.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/LICENSE +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/README.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/SECURITY.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/demo.gif +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/demo.tape +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/docs/building/audit-2026-07-06.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/docs/building/implementation-plan.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/docs/building/plans/2026-07-06-wave-1-correctness-safety.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/docs/building/plans/2026-07-06-wave-2-status-model.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/docs/building/plans/2026-07-06-wave-3-structure-polish.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/docs/user/concepts.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/docs/user/configuration.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/docs/user/getting-started.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/scripts/release.sh +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/__main__.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/__init__.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/add.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/config_cmd.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/doctor.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/exec_cmd.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/fetch.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/helpers.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/list_cmd.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/main.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/migrate.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/onboard.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/open_cmd.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/remove.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/search.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/serve.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/setup_ai.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/shell.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/skill_cmd.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/stats.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/status.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/update.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/cli/workspace_cmd.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/core/__init__.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/core/config.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/core/discovery.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/core/locking.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/core/parallel.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/core/paths.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/core/repo.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/core/url_parser.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/mcp/__init__.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/mcp/server.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/skill/SKILL.md +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/__init__.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/routes/__init__.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/routes/system.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/routes/workspaces.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/templates/partials/dashboard_rows.html +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/src/gitstow/web/templates/partials/fetch_summary.html +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/__init__.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/conftest.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/test_config.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/test_git.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/test_locking.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/test_mcp.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/test_onboard.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/test_operations.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/test_repo.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/test_setup_ai.py +0 -0
- {gitstow-0.3.0 → gitstow-0.5.0}/tests/test_url_parser.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# gitstow
|
|
1
|
+
# gitstow — AI Developer Guide
|
|
2
2
|
|
|
3
3
|
## What is this?
|
|
4
4
|
|
|
5
|
-
A CLI tool that manages collections of git repositories across multiple workspaces. Think "package manager for repos"
|
|
5
|
+
A CLI tool that manages collections of git repositories across multiple workspaces. Think "package manager for repos" — whether they're open-source projects you learn from or active projects you work on.
|
|
6
6
|
|
|
7
7
|
## Operating Contract
|
|
8
8
|
|
|
@@ -14,14 +14,15 @@ A CLI tool that manages collections of git repositories across multiple workspac
|
|
|
14
14
|
|
|
15
15
|
## Product Standards
|
|
16
16
|
|
|
17
|
-
- Keep CLI,
|
|
17
|
+
- Keep CLI, web dashboard, JSON output, docs, and tests semantically aligned when changing user-facing status behavior.
|
|
18
18
|
- 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.
|
|
19
19
|
- Keep local working-tree state separate from remote relationship state. For example: local changes, clean, ahead, behind, diverged, frozen, missing.
|
|
20
20
|
- 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.
|
|
21
|
+
- For `web/` changes, HTTP-level tests (TestClient, curl) are necessary but not sufficient — they pass on bugs below the HTTP layer. Before calling a `web/` change done, verify form structure against the parsed DOM (browsers silently drop nested `<form>` tags) and verify layout/geometry in a real browser (`overflow-x: auto` clips absolutely-positioned children even without horizontal overflow).
|
|
21
22
|
|
|
22
23
|
## Key Concept: Workspaces
|
|
23
24
|
|
|
24
|
-
Repos are organized into **workspaces**
|
|
25
|
+
Repos are organized into **workspaces** — directories with a label and layout mode:
|
|
25
26
|
- **structured** layout: `workspace/owner/repo/` (open-source collections)
|
|
26
27
|
- **flat** layout: `workspace/repo/` (active projects, no owner subdirectory)
|
|
27
28
|
|
|
@@ -40,60 +41,62 @@ src/gitstow/
|
|
|
40
41
|
│ ├── exec_cmd.py, search.py, open_cmd.py, stats.py # Power commands
|
|
41
42
|
│ ├── export_cmd.py # export/import collection
|
|
42
43
|
│ ├── shell.py # Shell integration (fzf, aliases)
|
|
43
|
-
│ ├── tui.py # TUI launcher
|
|
44
44
|
│ ├── serve.py # Web dashboard launcher
|
|
45
45
|
│ ├── migrate.py, config_cmd.py, onboard.py, doctor.py, skill_cmd.py
|
|
46
46
|
│ └── __init__.py
|
|
47
47
|
├── core/ # Business logic (git ops, URL parsing, state)
|
|
48
|
-
│ ├── paths.py
|
|
49
|
-
│ ├── config.py
|
|
50
|
-
│ ├── repo.py
|
|
51
|
-
│ ├── url_parser.py
|
|
52
|
-
│ ├── git.py
|
|
53
|
-
│ ├── discovery.py
|
|
54
|
-
│ ├── parallel.py
|
|
55
|
-
│
|
|
56
|
-
├──
|
|
57
|
-
│ ├──
|
|
48
|
+
│ ├── paths.py # Path constants, central repos.yaml resolution
|
|
49
|
+
│ ├── config.py # Workspace + Settings dataclasses, load/save
|
|
50
|
+
│ ├── repo.py # Repo dataclass + RepoStore (nested YAML CRUD)
|
|
51
|
+
│ ├── url_parser.py # URL → (host, owner, repo) extraction
|
|
52
|
+
│ ├── git.py # All git subprocess calls
|
|
53
|
+
│ ├── discovery.py # Walk directory tree (structured + flat), reconcile
|
|
54
|
+
│ ├── parallel.py # Async execution with semaphore
|
|
55
|
+
│ ├── status_model.py # Shared repo-state classifier — local composition vs remote relationship
|
|
56
|
+
│ ├── operations.py # Shared filter + bulk-runner layer (pull/fetch/MCP)
|
|
57
|
+
│ ├── locking.py # Cross-process file lock guarding repos.yaml writes
|
|
58
58
|
│ └── __init__.py
|
|
59
59
|
├── web/ # FastAPI browser dashboard (gitstow ui)
|
|
60
60
|
│ ├── server.py # FastAPI app, uvicorn runner, app.state.server stash
|
|
61
61
|
│ ├── static/app.css # Dark theme, Bricolage Grotesque + JetBrains Mono
|
|
62
62
|
│ ├── templates/ # Jinja2 — base.html + page templates + partials/
|
|
63
63
|
│ └── routes/ # dashboard.py, repos.py, workspaces.py, collection.py, pages.py, system.py
|
|
64
|
-
└── skill/ #
|
|
64
|
+
└── skill/ # Claude Code skill (SKILL.md)
|
|
65
65
|
└── SKILL.md
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
**Key rules:**
|
|
69
|
-
1. CLI never touches git directly
|
|
69
|
+
1. CLI never touches git directly — it calls `core/git.py`
|
|
70
70
|
2. `core/repo.py` (RepoStore) is the only module that reads/writes `repos.yaml`
|
|
71
|
-
3. `core/config.py` defines Workspace dataclass
|
|
71
|
+
3. `core/config.py` defines Workspace dataclass — all workspace logic flows from here
|
|
72
72
|
4. `cli/helpers.py` provides `resolve_workspaces()`, `resolve_repo()`, `iter_repos_with_workspace()`
|
|
73
73
|
|
|
74
74
|
## Key Files
|
|
75
75
|
|
|
76
|
-
- `core/config.py`
|
|
77
|
-
- `core/repo.py`
|
|
78
|
-
- `core/discovery.py`
|
|
79
|
-
- `core/url_parser.py`
|
|
80
|
-
- `core/git.py`
|
|
81
|
-
- `core/parallel.py`
|
|
82
|
-
- `
|
|
83
|
-
- `
|
|
84
|
-
- `
|
|
85
|
-
- `
|
|
76
|
+
- `core/config.py` — Workspace + Settings dataclasses. `get_workspaces()` with legacy migration shim.
|
|
77
|
+
- `core/repo.py` — Repo with workspace field, RepoStore with nested YAML format, legacy auto-migration.
|
|
78
|
+
- `core/discovery.py` — `discover_repos(root, layout)` supports structured and flat layouts.
|
|
79
|
+
- `core/url_parser.py` — URL parsing (the hardest part). Test changes here thoroughly.
|
|
80
|
+
- `core/git.py` — All git subprocess calls. Uses `git status --porcelain=v2 --branch` for single-call efficiency.
|
|
81
|
+
- `core/parallel.py` — Async execution with semaphore (max 6 concurrent).
|
|
82
|
+
- `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.
|
|
83
|
+
- `core/operations.py` — Shared `filter_repo_pairs()` + bulk-runner used by `pull`, `fetch`, and the MCP server so surfaces can't drift.
|
|
84
|
+
- `core/locking.py` — `file_lock()` cross-process advisory lock guarding `repos.yaml` against concurrent CLI/web writes.
|
|
85
|
+
- `cli/helpers.py` — Shared workspace resolution used by all CLI commands.
|
|
86
|
+
- `cli/workspace_cmd.py` — workspace list/add/remove/scan subcommands.
|
|
87
|
+
- `cli/main.py` — Typer app, global `-w/--workspace` option, command registration.
|
|
86
88
|
|
|
87
89
|
## Data Files
|
|
88
90
|
|
|
89
|
-
- `~/.gitstow/config.yaml`
|
|
90
|
-
- `~/.gitstow/repos.yaml`
|
|
91
|
+
- `~/.gitstow/config.yaml` — Settings (workspaces list, default host, SSH pref).
|
|
92
|
+
- `~/.gitstow/repos.yaml` — Repo metadata nested by workspace label. Central location.
|
|
93
|
+
- `~/.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.
|
|
91
94
|
|
|
92
95
|
### repos.yaml format
|
|
93
96
|
```yaml
|
|
94
97
|
oss:
|
|
95
|
-
anthropic/
|
|
96
|
-
remote_url: https://github.com/anthropic/
|
|
98
|
+
anthropic/claude-code:
|
|
99
|
+
remote_url: https://github.com/anthropic/claude-code.git
|
|
97
100
|
tags: [ai]
|
|
98
101
|
active:
|
|
99
102
|
gitstow:
|
|
@@ -101,14 +104,14 @@ active:
|
|
|
101
104
|
tags: [active]
|
|
102
105
|
```
|
|
103
106
|
|
|
104
|
-
## All Commands (
|
|
107
|
+
## All Commands (37)
|
|
105
108
|
|
|
106
109
|
**Core:** `add`, `pull`, `fetch`, `list`, `status`, `remove`, `migrate`
|
|
107
110
|
**Workspace:** `workspace list`, `workspace add`, `workspace remove`, `workspace scan`
|
|
108
111
|
**Repo management:** `repo freeze`, `repo unfreeze`, `repo tag`, `repo untag`, `repo tags`, `repo info`
|
|
109
112
|
**Power:** `exec`, `search`, `open`, `stats`
|
|
110
113
|
**Sharing:** `collection export`, `collection import`
|
|
111
|
-
**Shell:** `shell pick`, `shell init`, `shell completions`, `shell setup`, `
|
|
114
|
+
**Shell:** `shell pick`, `shell init`, `shell completions`, `shell setup`, `ui`
|
|
112
115
|
**Setup:** `onboard`, `config show/set/path/migrate-root`, `doctor`, `install-skill`, `setup-ai`, `update`
|
|
113
116
|
|
|
114
117
|
## Development
|
|
@@ -116,11 +119,13 @@ active:
|
|
|
116
119
|
```bash
|
|
117
120
|
cd ~/labs/projects/gitstow
|
|
118
121
|
pip install -e ".[dev]"
|
|
119
|
-
pytest #
|
|
122
|
+
pytest # full suite — keep green
|
|
120
123
|
ruff check src/
|
|
121
|
-
pip install -e ".[tui]" # For TUI development
|
|
122
124
|
```
|
|
123
125
|
|
|
126
|
+
- **Worktree gotcha:** tests run from a git worktree silently exercise the main checkout (the editable install points at the primary clone). From a worktree, run `PYTHONPATH=<worktree>/src .venv/bin/python -m pytest -q`.
|
|
127
|
+
- **Releasing publishes to PyPI.** `scripts/release.sh X.Y.Z` tags and pushes; the tag triggers a public PyPI publish. Require the user's explicit in-session instruction to release — plan approval or a "let's go" on implementation does not cover it.
|
|
128
|
+
|
|
124
129
|
## Patterns
|
|
125
130
|
|
|
126
131
|
- `--json -j` and `--quiet -q` on all main commands
|
|
@@ -132,19 +137,19 @@ pip install -e ".[tui]" # For TUI development
|
|
|
132
137
|
- asyncio with semaphore for parallel git ops
|
|
133
138
|
- `git status --porcelain=v2 --branch` for single-call status (vs gita's 4-5 calls)
|
|
134
139
|
- Repo.global_key (`workspace:key`) for unique identification across workspaces
|
|
135
|
-
- Legacy format auto-migration (flat repos.yaml
|
|
140
|
+
- Legacy format auto-migration (flat repos.yaml → nested, root_path → workspaces)
|
|
136
141
|
|
|
137
142
|
## AI Integration
|
|
138
143
|
|
|
139
|
-
**Primary:
|
|
140
|
-
- Installed to `~/.
|
|
144
|
+
**Primary: Claude Code skill** (`src/gitstow/skill/SKILL.md`)
|
|
145
|
+
- Installed to `~/.claude/skills/gitstow/` via `gitstow install-skill` or `gitstow onboard`
|
|
141
146
|
- Auto-updates on version bumps (checks `.version` marker on every CLI invocation)
|
|
142
|
-
- Zero context cost when inactive
|
|
143
|
-
-
|
|
147
|
+
- Zero context cost when inactive — only loaded when task matches the skill description
|
|
148
|
+
- Claude runs gitstow CLI commands via Bash — full access to all commands
|
|
144
149
|
|
|
145
150
|
**Optional: MCP server** (`src/gitstow/mcp/server.py`)
|
|
146
|
-
- For non-
|
|
151
|
+
- For non-Claude-Code AI tools (Claude Desktop, Cursor, Windsurf)
|
|
147
152
|
- Install: `pip install gitstow[mcp]`, entry point: `gitstow-mcp`
|
|
148
|
-
-
|
|
153
|
+
- 14 tools + 3 resources, wraps same `core/` modules as CLI
|
|
149
154
|
- **Tradeoff:** MCP tools are always loaded into context (costs tokens even when idle).
|
|
150
155
|
The skill has no such cost. Only use MCP for dedicated repo-management setups.
|
gitstow-0.5.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,36 @@ 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.5.0] - 2026-07-16
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Move repos between workspaces.** From the dashboard's repo detail page (new Workspace section: pick a target, confirm, done) or the new `gitstow repo move <repo> <workspace>` command. The folder physically relocates on disk following the target workspace's layout (structured `owner/repo` vs flat), the catalog updates in the same locked operation, existing tags are kept and the target's auto-tags merge in, and repos that own linked git worktrees get `git worktree repair` run automatically after the move.
|
|
12
|
+
- **Move safety net.** Collisions are refused before anything is touched (catalog, disk, even dangling symlinks); sources that can't move safely are refused with actionable errors (symlinked repos, linked-worktree gitfiles, relative `.git` symlinks, non-repo directories squatting on a tracked path); catalog keys can never escape their workspace on disk; and if anything fails mid-move, the rollback restores the folder without ever deleting data it can't prove is its own.
|
|
13
|
+
|
|
14
|
+
## [0.4.0] - 2026-07-12
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **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.
|
|
19
|
+
- **Settings save.** The Settings page persists changes for real (and gains Parallel limit + Clone timeout fields).
|
|
20
|
+
- **`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.
|
|
21
|
+
- **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.
|
|
22
|
+
- **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.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- **Fully offline dashboard.** htmx and both fonts are now bundled — no CDN, no network needed for the UI itself.
|
|
27
|
+
- **Styled confirmations.** Native browser confirm/alert dialogs replaced with an in-app dialog (also makes the dashboard automatable).
|
|
28
|
+
- **Web collection import honors recorded workspaces**, sharing one implementation with the CLI.
|
|
29
|
+
- **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.
|
|
30
|
+
- **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.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **Pull all / Fetch all spinners stop when the operation completes** (htmx indicator/disable double-count).
|
|
35
|
+
- **Repo detail timestamps** no longer render raw machine format.
|
|
36
|
+
|
|
7
37
|
## [0.3.0] - 2026-07-12
|
|
8
38
|
|
|
9
39
|
### Added
|
|
@@ -107,6 +107,9 @@ pytest # full suite — keep green
|
|
|
107
107
|
ruff check src/
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
+
- **Worktree gotcha:** tests run from a git worktree silently exercise the main checkout (the editable install points at the primary clone). From a worktree, run `PYTHONPATH=<worktree>/src .venv/bin/python -m pytest -q`.
|
|
111
|
+
- **Releasing publishes to PyPI.** `scripts/release.sh X.Y.Z` tags and pushes; the tag triggers a public PyPI publish. Require the user's explicit in-session instruction to release — plan approval or a "let's go" on implementation does not cover it.
|
|
112
|
+
|
|
110
113
|
## Patterns
|
|
111
114
|
|
|
112
115
|
- `--json -j` and `--quiet -q` on all main commands
|
|
@@ -128,6 +131,7 @@ ruff check src/
|
|
|
128
131
|
- 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.
|
|
129
132
|
- Keep local working-tree state separate from remote relationship state. For example: local changes, clean, ahead, behind, diverged, frozen, missing.
|
|
130
133
|
- 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.
|
|
134
|
+
- For `web/` changes, HTTP-level tests (pytest TestClient, curl) are necessary but not sufficient — they pass on bugs that live below the HTTP layer. Before calling a UI change done, verify form structure against the parsed DOM (browsers silently drop nested `<form>` tags) and verify layout/geometry in a real browser (e.g. `overflow-x: auto` clips absolutely-positioned children even without horizontal overflow).
|
|
131
135
|
|
|
132
136
|
## AI Integration
|
|
133
137
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitstow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.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
|