devlaunch 0.0.6__tar.gz → 0.0.8__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.
- {devlaunch-0.0.6 → devlaunch-0.0.8}/.gitignore +4 -11
- devlaunch-0.0.6/README.md → devlaunch-0.0.8/PKG-INFO +108 -1
- devlaunch-0.0.6/PKG-INFO → devlaunch-0.0.8/README.md +85 -22
- {devlaunch-0.0.6 → devlaunch-0.0.8}/devlaunch/completions/dl.bash +21 -2
- {devlaunch-0.0.6 → devlaunch-0.0.8}/devlaunch/dl.py +553 -178
- devlaunch-0.0.8/devlaunch/gh_auth.py +171 -0
- devlaunch-0.0.8/devlaunch/worktree/__init__.py +19 -0
- devlaunch-0.0.8/devlaunch/worktree/branch_manager.py +188 -0
- devlaunch-0.0.8/devlaunch/worktree/config.py +106 -0
- devlaunch-0.0.8/devlaunch/worktree/models.py +88 -0
- devlaunch-0.0.8/devlaunch/worktree/repo_manager.py +297 -0
- devlaunch-0.0.8/devlaunch/worktree/storage.py +348 -0
- devlaunch-0.0.8/devlaunch/worktree/workspace_clone.py +357 -0
- {devlaunch-0.0.6 → devlaunch-0.0.8}/pyproject.toml +21 -9
- {devlaunch-0.0.6 → devlaunch-0.0.8}/LICENSE +0 -0
- {devlaunch-0.0.6 → devlaunch-0.0.8}/devlaunch/__init__.py +0 -0
- {devlaunch-0.0.6 → devlaunch-0.0.8}/devlaunch/completion.py +0 -0
- {devlaunch-0.0.6 → devlaunch-0.0.8}/devlaunch/completion_loader.py +0 -0
- {devlaunch-0.0.6 → devlaunch-0.0.8}/devlaunch/completions/__init__.py +0 -0
|
@@ -50,6 +50,7 @@ coverage.xml
|
|
|
50
50
|
.hypothesis/
|
|
51
51
|
.pytest_cache/
|
|
52
52
|
cover/
|
|
53
|
+
test/docker/results/
|
|
53
54
|
|
|
54
55
|
# Translations
|
|
55
56
|
*.mo
|
|
@@ -178,16 +179,8 @@ test_suite_analysis/metadata.json
|
|
|
178
179
|
# Claude Code local settings (personal, not shared)
|
|
179
180
|
.claude/settings.local.json
|
|
180
181
|
|
|
181
|
-
# Ralph autonomous agent state files
|
|
182
|
-
.call_count
|
|
183
|
-
.circuit_breaker_history
|
|
184
|
-
.circuit_breaker_state
|
|
185
|
-
.exit_signals
|
|
186
|
-
.last_reset
|
|
187
|
-
.ralph_session
|
|
188
|
-
.ralph_session_history
|
|
189
|
-
.response_analysis
|
|
190
182
|
.claude_session_id
|
|
191
|
-
progress.json
|
|
192
|
-
status.json
|
|
193
183
|
logs/
|
|
184
|
+
|
|
185
|
+
# uv is not this project's package manager (pixi.lock is authoritative)
|
|
186
|
+
uv.lock
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: devlaunch
|
|
3
|
+
Version: 0.0.8
|
|
4
|
+
Summary: DevLaunch - A streamlined CLI for devpod workspaces
|
|
5
|
+
Project-URL: Source, https://github.com/blooop/devlaunch
|
|
6
|
+
Project-URL: Home, https://github.com/blooop/devlaunch
|
|
7
|
+
Author-email: Austin Gregg-Smith <blooop@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: iterfzf>=1.0.0
|
|
11
|
+
Requires-Dist: tomli-w>=1.0.0
|
|
12
|
+
Requires-Dist: tomli>=2.0.0
|
|
13
|
+
Provides-Extra: test
|
|
14
|
+
Requires-Dist: coverage<=7.14.1,>=7.5.4; extra == 'test'
|
|
15
|
+
Requires-Dist: hypothesis<=6.155.1,>=6.104.2; extra == 'test'
|
|
16
|
+
Requires-Dist: prek<0.5.0,>=0.2.28; extra == 'test'
|
|
17
|
+
Requires-Dist: pylint<=4.0.5,>=3.2.5; extra == 'test'
|
|
18
|
+
Requires-Dist: pytest-cov<=7.1.0,>=4.1; extra == 'test'
|
|
19
|
+
Requires-Dist: pytest<=9.0.3,>=7.4; extra == 'test'
|
|
20
|
+
Requires-Dist: ruff<=0.15.15,>=0.5.0; extra == 'test'
|
|
21
|
+
Requires-Dist: ty<=0.0.19,>=0.0.12; extra == 'test'
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
1
24
|
# devlaunch
|
|
2
25
|
|
|
3
26
|
A streamlined CLI for [devpod](https://devpod.sh) with intuitive autocomplete and fzf fuzzy selection.
|
|
@@ -10,7 +33,7 @@ A streamlined CLI for [devpod](https://devpod.sh) with intuitive autocomplete an
|
|
|
10
33
|
[](https://github.com/blooop/devlaunch/pulls?q=is%3Amerged)
|
|
11
34
|
[](https://GitHub.com/blooop/devlaunch/releases/)
|
|
12
35
|
[](https://pypi.org/project/devlaunch/)
|
|
13
|
-
[](https://prefix.dev/channels/blooop/packages/devlaunch)
|
|
14
37
|
[](https://opensource.org/license/mit/)
|
|
15
38
|
[](https://www.python.org/downloads/)
|
|
16
39
|
[](https://pixi.sh)
|
|
@@ -32,6 +55,8 @@ pip install devlaunch
|
|
|
32
55
|
```
|
|
33
56
|
|
|
34
57
|
Note: When using pip, you must install [devpod](https://devpod.sh/docs/getting-started/install) separately.
|
|
58
|
+
If `devpod` is not on `PATH`, every command that needs it prints a single install hint on stderr and exits `127`
|
|
59
|
+
(the shell's "command not found" code). `dl --help` and `dl --version` keep working without it.
|
|
35
60
|
|
|
36
61
|
### Shell Completions
|
|
37
62
|
|
|
@@ -72,12 +97,69 @@ dl ./path # Create from local path
|
|
|
72
97
|
| `dl <user/repo> reset` | Clean slate (remove all, recreate) |
|
|
73
98
|
| `dl <user/repo> -- <command>` | Run shell command in workspace |
|
|
74
99
|
|
|
100
|
+
## Options
|
|
101
|
+
|
|
102
|
+
| Option | Description |
|
|
103
|
+
|--------|-------------|
|
|
104
|
+
| `--devcontainer <variant\|path>` | Use a non-default `devcontainer.json`. A bare name means `.devcontainer/<name>/devcontainer.json`. Stored with the workspace, so pass it once. |
|
|
105
|
+
|
|
106
|
+
Projects with demanding devcontainers — several variants, compose sidecars, or a
|
|
107
|
+
host-side `initializeCommand` that has to tell branch workspaces apart — are
|
|
108
|
+
covered in [docs/devcontainer-projects.md](docs/devcontainer-projects.md).
|
|
109
|
+
|
|
110
|
+
## GitHub Authentication
|
|
111
|
+
|
|
112
|
+
Every workspace `dl` opens inherits the host's GitHub login, so `gh` is already
|
|
113
|
+
authenticated inside the container and the devcontainer.json does not have to
|
|
114
|
+
arrange anything for it. devpod forwards the ssh agent and git credentials on its
|
|
115
|
+
own, but nothing else carries `gh`.
|
|
116
|
+
|
|
117
|
+
devlaunch takes the token from `GH_TOKEN`, `GITHUB_TOKEN`, or `gh auth token`,
|
|
118
|
+
whichever answers first, and hands it to the container as `GH_TOKEN`. That reaches
|
|
119
|
+
any image and any container user, unlike a bind-mount of `~/.config/gh`, and it
|
|
120
|
+
works whether the host keeps its token in `hosts.yml` or in a keyring. The token
|
|
121
|
+
is passed to devpod through a private file and through devpod's own environment,
|
|
122
|
+
never on a command line, so it does not appear in `ps`. The container still needs
|
|
123
|
+
`gh` installed for the login to be of any use. Check a workspace with:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
dl <workspace> -- gh auth status
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Who gets the token
|
|
130
|
+
|
|
131
|
+
Everything running in the container does — including a `postCreateCommand` from a
|
|
132
|
+
repo you did not write. `dl someone/repo` builds and runs that project's
|
|
133
|
+
devcontainer with your GitHub token in its environment, and a `gh auth login` token
|
|
134
|
+
usually carries `repo`, `workflow`, `gist` and `read:org` scopes. devpod already
|
|
135
|
+
forwards the ssh agent to every workspace, so this is not a new trust boundary, but
|
|
136
|
+
it is a wider one. Skip it for a repo you have not read:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
DEVLAUNCH_NO_GH_TOKEN=1 dl someone/repo
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
| Variable | Description |
|
|
143
|
+
|----------|-------------|
|
|
144
|
+
| `DEVLAUNCH_NO_GH_TOKEN=1` | Do not forward the host's GitHub login into workspaces |
|
|
145
|
+
|
|
146
|
+
### When the token changes
|
|
147
|
+
|
|
148
|
+
`dl` refreshes the token on every start, so rotating it on the host is enough for
|
|
149
|
+
any workspace that gets started or restarted afterwards. Attaching to a workspace
|
|
150
|
+
that is *already running* skips that step, and the token it was given at startup
|
|
151
|
+
stays in place — including one it was given before you set
|
|
152
|
+
`DEVLAUNCH_NO_GH_TOKEN`. Run `dl <workspace> restart` to replace it.
|
|
153
|
+
|
|
75
154
|
## Global Commands
|
|
76
155
|
|
|
77
156
|
| Command | Description |
|
|
78
157
|
|---------|-------------|
|
|
79
158
|
| `dl --ls` | List all workspaces |
|
|
80
159
|
| `dl --install` | Install shell completions |
|
|
160
|
+
| `dl --purge [-y]` | Remove all devlaunch data |
|
|
161
|
+
| `dl --prune-worktrees [days]` | Remove unused worktrees (default: 30 days) |
|
|
162
|
+
| `dl --refresh` | Refresh completion cache |
|
|
81
163
|
| `dl --help, -h` | Show this help |
|
|
82
164
|
| `dl --version` | Show version |
|
|
83
165
|
|
|
@@ -102,6 +184,31 @@ dl blooop/devlaunch stop # Stop workspace
|
|
|
102
184
|
- **Branch Support**: Specify branches with `owner/repo@branch` syntax
|
|
103
185
|
- **Fast Autocomplete**: Completion cache for ~3ms response time (vs ~700ms without cache)
|
|
104
186
|
|
|
187
|
+
## Worktree Backend
|
|
188
|
+
|
|
189
|
+
For git repositories, devlaunch uses an efficient worktree backend by default:
|
|
190
|
+
|
|
191
|
+
- **Efficient Storage**: Repos are cloned once to `~/.cache/devlaunch/repos/owner/repo/`, then git worktrees are created for each branch
|
|
192
|
+
- **Shared Git Objects**: All branches share git objects, saving disk space
|
|
193
|
+
- **Lazy Fetch**: Remote updates are only fetched if the configured interval has elapsed (default: 1 hour)
|
|
194
|
+
|
|
195
|
+
### Container Sharing Mode
|
|
196
|
+
|
|
197
|
+
Use `--shared` to share a single container across multiple branches of the same repo:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
dl --shared owner/repo@branch1 # Creates container "owner-repo"
|
|
201
|
+
dl --shared owner/repo@branch2 # Reuses "owner-repo" container
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Pre-warming
|
|
205
|
+
|
|
206
|
+
Use `--warm` to prepare a workspace without attaching a shell:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
dl --warm owner/repo@branch # Creates container in background
|
|
210
|
+
```
|
|
211
|
+
|
|
105
212
|
## Shell Completion
|
|
106
213
|
|
|
107
214
|
After running `dl --install`, you get intelligent tab completion:
|
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: devlaunch
|
|
3
|
-
Version: 0.0.6
|
|
4
|
-
Summary: DevLaunch - A streamlined CLI for devpod workspaces
|
|
5
|
-
Project-URL: Source, https://github.com/blooop/devlaunch
|
|
6
|
-
Project-URL: Home, https://github.com/blooop/devlaunch
|
|
7
|
-
Author-email: Austin Gregg-Smith <blooop@gmail.com>
|
|
8
|
-
License-Expression: MIT
|
|
9
|
-
License-File: LICENSE
|
|
10
|
-
Requires-Dist: iterfzf>=1.0.0
|
|
11
|
-
Provides-Extra: test
|
|
12
|
-
Requires-Dist: coverage<=7.13.1,>=7.5.4; extra == 'test'
|
|
13
|
-
Requires-Dist: hypothesis<=6.150.2,>=6.104.2; extra == 'test'
|
|
14
|
-
Requires-Dist: prek<0.3.0,>=0.2.28; extra == 'test'
|
|
15
|
-
Requires-Dist: pylint<=4.0.4,>=3.2.5; extra == 'test'
|
|
16
|
-
Requires-Dist: pytest-cov<=7.0.0,>=4.1; extra == 'test'
|
|
17
|
-
Requires-Dist: pytest<=9.0.2,>=7.4; extra == 'test'
|
|
18
|
-
Requires-Dist: ruff<=0.14.13,>=0.5.0; extra == 'test'
|
|
19
|
-
Requires-Dist: ty<=0.0.12,>=0.0.12; extra == 'test'
|
|
20
|
-
Description-Content-Type: text/markdown
|
|
21
|
-
|
|
22
1
|
# devlaunch
|
|
23
2
|
|
|
24
3
|
A streamlined CLI for [devpod](https://devpod.sh) with intuitive autocomplete and fzf fuzzy selection.
|
|
@@ -31,7 +10,7 @@ A streamlined CLI for [devpod](https://devpod.sh) with intuitive autocomplete an
|
|
|
31
10
|
[](https://github.com/blooop/devlaunch/pulls?q=is%3Amerged)
|
|
32
11
|
[](https://GitHub.com/blooop/devlaunch/releases/)
|
|
33
12
|
[](https://pypi.org/project/devlaunch/)
|
|
34
|
-
[](https://prefix.dev/channels/blooop/packages/devlaunch)
|
|
35
14
|
[](https://opensource.org/license/mit/)
|
|
36
15
|
[](https://www.python.org/downloads/)
|
|
37
16
|
[](https://pixi.sh)
|
|
@@ -53,6 +32,8 @@ pip install devlaunch
|
|
|
53
32
|
```
|
|
54
33
|
|
|
55
34
|
Note: When using pip, you must install [devpod](https://devpod.sh/docs/getting-started/install) separately.
|
|
35
|
+
If `devpod` is not on `PATH`, every command that needs it prints a single install hint on stderr and exits `127`
|
|
36
|
+
(the shell's "command not found" code). `dl --help` and `dl --version` keep working without it.
|
|
56
37
|
|
|
57
38
|
### Shell Completions
|
|
58
39
|
|
|
@@ -93,12 +74,69 @@ dl ./path # Create from local path
|
|
|
93
74
|
| `dl <user/repo> reset` | Clean slate (remove all, recreate) |
|
|
94
75
|
| `dl <user/repo> -- <command>` | Run shell command in workspace |
|
|
95
76
|
|
|
77
|
+
## Options
|
|
78
|
+
|
|
79
|
+
| Option | Description |
|
|
80
|
+
|--------|-------------|
|
|
81
|
+
| `--devcontainer <variant\|path>` | Use a non-default `devcontainer.json`. A bare name means `.devcontainer/<name>/devcontainer.json`. Stored with the workspace, so pass it once. |
|
|
82
|
+
|
|
83
|
+
Projects with demanding devcontainers — several variants, compose sidecars, or a
|
|
84
|
+
host-side `initializeCommand` that has to tell branch workspaces apart — are
|
|
85
|
+
covered in [docs/devcontainer-projects.md](docs/devcontainer-projects.md).
|
|
86
|
+
|
|
87
|
+
## GitHub Authentication
|
|
88
|
+
|
|
89
|
+
Every workspace `dl` opens inherits the host's GitHub login, so `gh` is already
|
|
90
|
+
authenticated inside the container and the devcontainer.json does not have to
|
|
91
|
+
arrange anything for it. devpod forwards the ssh agent and git credentials on its
|
|
92
|
+
own, but nothing else carries `gh`.
|
|
93
|
+
|
|
94
|
+
devlaunch takes the token from `GH_TOKEN`, `GITHUB_TOKEN`, or `gh auth token`,
|
|
95
|
+
whichever answers first, and hands it to the container as `GH_TOKEN`. That reaches
|
|
96
|
+
any image and any container user, unlike a bind-mount of `~/.config/gh`, and it
|
|
97
|
+
works whether the host keeps its token in `hosts.yml` or in a keyring. The token
|
|
98
|
+
is passed to devpod through a private file and through devpod's own environment,
|
|
99
|
+
never on a command line, so it does not appear in `ps`. The container still needs
|
|
100
|
+
`gh` installed for the login to be of any use. Check a workspace with:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
dl <workspace> -- gh auth status
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Who gets the token
|
|
107
|
+
|
|
108
|
+
Everything running in the container does — including a `postCreateCommand` from a
|
|
109
|
+
repo you did not write. `dl someone/repo` builds and runs that project's
|
|
110
|
+
devcontainer with your GitHub token in its environment, and a `gh auth login` token
|
|
111
|
+
usually carries `repo`, `workflow`, `gist` and `read:org` scopes. devpod already
|
|
112
|
+
forwards the ssh agent to every workspace, so this is not a new trust boundary, but
|
|
113
|
+
it is a wider one. Skip it for a repo you have not read:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
DEVLAUNCH_NO_GH_TOKEN=1 dl someone/repo
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| Variable | Description |
|
|
120
|
+
|----------|-------------|
|
|
121
|
+
| `DEVLAUNCH_NO_GH_TOKEN=1` | Do not forward the host's GitHub login into workspaces |
|
|
122
|
+
|
|
123
|
+
### When the token changes
|
|
124
|
+
|
|
125
|
+
`dl` refreshes the token on every start, so rotating it on the host is enough for
|
|
126
|
+
any workspace that gets started or restarted afterwards. Attaching to a workspace
|
|
127
|
+
that is *already running* skips that step, and the token it was given at startup
|
|
128
|
+
stays in place — including one it was given before you set
|
|
129
|
+
`DEVLAUNCH_NO_GH_TOKEN`. Run `dl <workspace> restart` to replace it.
|
|
130
|
+
|
|
96
131
|
## Global Commands
|
|
97
132
|
|
|
98
133
|
| Command | Description |
|
|
99
134
|
|---------|-------------|
|
|
100
135
|
| `dl --ls` | List all workspaces |
|
|
101
136
|
| `dl --install` | Install shell completions |
|
|
137
|
+
| `dl --purge [-y]` | Remove all devlaunch data |
|
|
138
|
+
| `dl --prune-worktrees [days]` | Remove unused worktrees (default: 30 days) |
|
|
139
|
+
| `dl --refresh` | Refresh completion cache |
|
|
102
140
|
| `dl --help, -h` | Show this help |
|
|
103
141
|
| `dl --version` | Show version |
|
|
104
142
|
|
|
@@ -123,6 +161,31 @@ dl blooop/devlaunch stop # Stop workspace
|
|
|
123
161
|
- **Branch Support**: Specify branches with `owner/repo@branch` syntax
|
|
124
162
|
- **Fast Autocomplete**: Completion cache for ~3ms response time (vs ~700ms without cache)
|
|
125
163
|
|
|
164
|
+
## Worktree Backend
|
|
165
|
+
|
|
166
|
+
For git repositories, devlaunch uses an efficient worktree backend by default:
|
|
167
|
+
|
|
168
|
+
- **Efficient Storage**: Repos are cloned once to `~/.cache/devlaunch/repos/owner/repo/`, then git worktrees are created for each branch
|
|
169
|
+
- **Shared Git Objects**: All branches share git objects, saving disk space
|
|
170
|
+
- **Lazy Fetch**: Remote updates are only fetched if the configured interval has elapsed (default: 1 hour)
|
|
171
|
+
|
|
172
|
+
### Container Sharing Mode
|
|
173
|
+
|
|
174
|
+
Use `--shared` to share a single container across multiple branches of the same repo:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
dl --shared owner/repo@branch1 # Creates container "owner-repo"
|
|
178
|
+
dl --shared owner/repo@branch2 # Reuses "owner-repo" container
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Pre-warming
|
|
182
|
+
|
|
183
|
+
Use `--warm` to prepare a workspace without attaching a shell:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
dl --warm owner/repo@branch # Creates container in background
|
|
187
|
+
```
|
|
188
|
+
|
|
126
189
|
## Shell Completion
|
|
127
190
|
|
|
128
191
|
After running `dl --install`, you get intelligent tab completion:
|
|
@@ -45,13 +45,32 @@ _dl_completion() {
|
|
|
45
45
|
fi
|
|
46
46
|
|
|
47
47
|
# Global command options (only valid as first arg)
|
|
48
|
-
local global_opts="--ls --install --help -h --version"
|
|
48
|
+
local global_opts="--ls --install --help -h --version --devcontainer"
|
|
49
49
|
|
|
50
50
|
# Workspace subcommands
|
|
51
51
|
local ws_cmds="stop rm code restart recreate reset --"
|
|
52
52
|
|
|
53
|
+
# Options that take a value; a variant name or a path follows them.
|
|
54
|
+
local value_opts="--devcontainer"
|
|
55
|
+
|
|
56
|
+
# After --devcontainer, offer the repo's variant directories (and paths).
|
|
57
|
+
if [[ " ${value_opts} " == *" ${prev} "* ]]; then
|
|
58
|
+
local variants=""
|
|
59
|
+
if [[ -d .devcontainer ]]; then
|
|
60
|
+
local d
|
|
61
|
+
for d in .devcontainer/*/devcontainer.json; do
|
|
62
|
+
[[ -f "$d" ]] || continue
|
|
63
|
+
d="${d#.devcontainer/}"
|
|
64
|
+
variants+=" ${d%/devcontainer.json}"
|
|
65
|
+
done
|
|
66
|
+
fi
|
|
67
|
+
COMPREPLY=( $(compgen -W "${variants}" -- ${cur}) )
|
|
68
|
+
compopt -o default 2>/dev/null
|
|
69
|
+
return 0
|
|
70
|
+
fi
|
|
71
|
+
|
|
53
72
|
# Cache file location (honors XDG_CACHE_HOME)
|
|
54
|
-
local cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/
|
|
73
|
+
local cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/devlaunch"
|
|
55
74
|
local cache_file="$cache_dir/completions.bash"
|
|
56
75
|
|
|
57
76
|
# Initialize completion variables
|