Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,45 @@ For tools installed as dependencies (like `gh`), you can run them via:
- `pixi run gh <args>` - works in any shell
- `gh <args>` - works in login shells (`bash -l -c '...'`)

## Two installs: `dl` and `dl-next`

`dl` and `aid` on PATH are the **released** build, installed by pixi global from
the `blooop` channel (`~/.pixi/bin/dl`). Leave them alone: they are what keeps
working while this checkout is mid-change, and what actually opens the user's
workspaces.

`dl-next` and `aid-next` are **this working tree**, installed by `./dev.sh` into
`~/.local/share/devlaunch-dev` and symlinked from `~/.local/bin`. Both builds are
on PATH at once under names that cannot collide, so running the wrong one is not
possible by accident.

```
./dev.sh
```

Two things to know about it:

- **The install is editable, so there is no build step and no snapshot.**
`dl-next` is whatever the tree looks like at the moment you run it — a
half-finished edit is live as soon as it is saved. (`wf-next` in
blooop/wayfinder is the same idea with the opposite trade: a compiled copy that
only moves when you rebuild it.) `dl-next --version` reports the package
version, not its provenance — it says the same thing a released build of that
version would — so the name is the only thing distinguishing the two.
- **It touches real state.** `dl` mutates `metadata.json`, the bare clone cache
and live devpod workspaces, which is how a half-finished change costs someone
their workspace list. Everything it stores resolves through `XDG_CACHE_HOME`
and `XDG_CONFIG_HOME`, so point those at a scratch directory when the change
being tested is anywhere near storage:

```
XDG_CACHE_HOME=/tmp/dl-scratch/cache XDG_CONFIG_HOME=/tmp/dl-scratch/config dl-next owner/repo
```

That isolates the bookkeeping, not the machine — `dl` drives devpod and docker
on the host either way, so the workspaces a scratch run creates are real ones
that `devpod list` shows and that need deleting like any other.

## Documentation Maintenance

- **Keep README up to date**: When modifying CLI commands, flags, or usage patterns, update the README.md to reflect the current tool behavior. Run `pixi run dl --help` to see the current help output and ensure the README matches.
92 changes: 75 additions & 17 deletions dev.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
#!/bin/bash
# Development installation script for DevLaunch
# Installs DevLaunch globally in editable mode using uv
# Installs this working tree as `dl-next` and `aid-next`, beside the released
# `dl` and `aid` rather than on top of them, so both are on PATH at once and
# running the wrong one is not possible by accident. The released build is what
# keeps working while this checkout is mid-change; it is installed by pixi
# global from the blooop channel and this script never touches it.
#
# Editable, so `dl-next` is whatever the tree looks like right now — there is no
# build step to forget, and equally no snapshot: a half-finished edit is live the
# moment it is saved. Run it against throwaway state when that matters; dl
# resolves everything it stores through XDG_CACHE_HOME and XDG_CONFIG_HOME, so
#
# XDG_CACHE_HOME=/tmp/dl-scratch/cache XDG_CONFIG_HOME=/tmp/dl-scratch/config dl-next ...
#
# leaves the real workspace list alone.

set -e # Exit on error

Expand Down Expand Up @@ -35,21 +48,60 @@ uv pip install -e "${SCRIPT_DIR}" --python "${VENV_DIR}/bin/python"
# Ensure ~/.local/bin exists
mkdir -p "${BIN_DIR}"

# Create symlink for the dl command
DL_TARGET="${VENV_DIR}/bin/dl"
DL_LINK="${BIN_DIR}/dl"
# Symlink every entry point under a -next name. Console scripts do not care what
# they are called -- the shebang points at the venv's python either way -- so the
# only thing the name decides is which build you get when you type it.
#
# The names are read out of pyproject.toml rather than listed here, because a
# list here is one somebody has to remember: `aid` was added as a second entry
# point and this script knew nothing about it. A missing -next does not announce
# itself -- `aid` would keep resolving to the released build while its change sat
# in the tree untested.
mapfile -t COMMANDS < <(
"${VENV_DIR}/bin/python" - "${SCRIPT_DIR}/pyproject.toml" <<'PY'
import pathlib
import sys

if [ -L "${DL_LINK}" ]; then
rm "${DL_LINK}"
fi
try:
import tomllib
except ModuleNotFoundError: # python 3.10, where tomllib is not yet stdlib
import tomli as tomllib

if [ -e "${DL_LINK}" ]; then
echo "Warning: ${DL_LINK} exists and is not a symlink. Skipping symlink creation."
else
ln -s "${DL_TARGET}" "${DL_LINK}"
echo "Created symlink: ${DL_LINK} -> ${DL_TARGET}"
data = tomllib.loads(pathlib.Path(sys.argv[1]).read_text())
# .get, so a pyproject.toml declaring no entry points is reported by the check
# below rather than as a KeyError traceback from in here.
print("\n".join(data.get("project", {}).get("scripts", {})))
PY
)

if [ ${#COMMANDS[@]} -eq 0 ]; then
echo "Error: no [project.scripts] entry points found in pyproject.toml" >&2
exit 1
fi

for cmd in "${COMMANDS[@]}"; do
target="${VENV_DIR}/bin/${cmd}"
link="${BIN_DIR}/${cmd}-next"

# A declared script that did not make it into the venv would otherwise get a
# dangling symlink on PATH, which fails at the point of use rather than here.
if [ ! -x "${target}" ]; then
echo "Warning: ${target} was not installed. Skipping ${link}."
continue
fi

if [ -L "${link}" ]; then
rm "${link}"
fi

if [ -e "${link}" ]; then
echo "Warning: ${link} exists and is not a symlink. Skipping symlink creation."
else
ln -s "${target}" "${link}"
echo "Created symlink: ${link} -> ${target}"
fi
done

# Verify installation
echo ""
echo "Verifying installation..."
Expand All @@ -66,8 +118,14 @@ if [[ ":$PATH:" != *":${BIN_DIR}:"* ]]; then
echo ""
fi

echo "You can now test DevLaunch with:"
echo " dl --help"
echo " dl --version"
echo " dl owner/repo # clone + DevPod workspace (default branch)"
echo " dl owner/repo@branch # clone + DevPod workspace (specific branch)"
echo "You can now test this working tree with:"
echo " dl-next --help"
echo " dl-next --version"
echo " dl-next owner/repo # clone + DevPod workspace (default branch)"
echo " dl-next owner/repo@branch # clone + DevPod workspace (specific branch)"
echo " aid-next owner/repo@branch # ...with a coding agent started in it"
echo ""
echo "Against throwaway state, leaving the real workspace list alone:"
echo " XDG_CACHE_HOME=/tmp/dl-scratch/cache XDG_CONFIG_HOME=/tmp/dl-scratch/config dl-next ..."
echo ""
echo "Plain 'dl' and 'aid' remain the released build, untouched by this script."
Loading