refactor(cli)!: rename all skills and agents to consistent ce- prefix (#503)
Some checks failed
CI / pr-title (push) Has been cancelled
CI / test (push) Has been cancelled
Release PR / release-pr (push) Has been cancelled
Release PR / publish-cli (push) Has been cancelled

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trevin Chow
2026-04-18 15:44:22 -07:00
committed by GitHub
parent 49249d7317
commit 5c0ec9137a
233 changed files with 3199 additions and 936 deletions

View File

@@ -0,0 +1,310 @@
---
name: ce-worktree
description: This skill manages Git worktrees for isolated parallel development. It handles creating, listing, switching, and cleaning up worktrees with a simple interactive interface, following KISS principles.
---
# Git Worktree Manager
This skill provides a unified interface for managing Git worktrees across your development workflow. Whether you're reviewing PRs in isolation or working on features in parallel, this skill handles all the complexity.
## What This Skill Does
- **Create worktrees** from main branch with clear branch names
- **List worktrees** with current status
- **Switch between worktrees** for parallel work
- **Clean up completed worktrees** automatically
- **Interactive confirmations** at each step
- **Automatic .gitignore management** for worktree directory
- **Automatic .env file copying** from main repo to new worktrees
- **Automatic dev tool trusting** for mise and direnv configs with review-safe guardrails
## CRITICAL: Always Use the Manager Script
**NEVER call `git worktree add` directly.** Always use the `worktree-manager.sh` script.
The script handles critical setup that raw git commands don't:
1. Copies `.env`, `.env.local`, `.env.test`, etc. from main repo
2. Trusts dev tool configs with branch-aware safety rules:
- mise: auto-trust only when unchanged from a trusted baseline branch
- direnv: auto-allow only for trusted base branches; review worktrees stay manual
3. Ensures `.worktrees` is in `.gitignore`
4. Creates consistent directory structure
```bash
# ✅ CORRECT - Always use the script
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh create feature-name
# ❌ WRONG - Never do this directly
git worktree add .worktrees/feature-name -b feature-name main
```
## When to Use This Skill
Use this skill in these scenarios:
1. **Code Review (`/ce-code-review`)**: If NOT already on the target branch (PR branch or requested branch), offer worktree for isolated review
2. **Feature Work (`/ce-work`)**: Always ask if user wants parallel worktree or live branch work
3. **Parallel Development**: When working on multiple features simultaneously
4. **Cleanup**: After completing work in a worktree
## How to Use
### In Claude Code Workflows
The skill is automatically called from `/ce-code-review` and `/ce-work` commands:
```
# For review: offers worktree if not on PR branch
# For work: always asks - new branch or worktree?
```
### Manual Usage
You can also invoke the skill directly from bash:
```bash
# Create a new worktree (copies .env files automatically)
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh create feature-login
# List all worktrees
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh list
# Switch to a worktree
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh switch feature-login
# Copy .env files to an existing worktree (if they weren't copied)
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh copy-env feature-login
# Clean up completed worktrees
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh cleanup
```
## Commands
### `create <branch-name> [from-branch]`
Creates a new worktree with the given branch name.
**Options:**
- `branch-name` (required): The name for the new branch and worktree
- `from-branch` (optional): Base branch to create from (defaults to `main`)
**Example:**
```bash
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh create feature-login
```
**What happens:**
1. Checks if worktree already exists
2. Updates the base branch from remote
3. Creates new worktree and branch
4. **Copies all .env files from main repo** (.env, .env.local, .env.test, etc.)
5. **Trusts dev tool configs** with branch-aware safety rules:
- trusted bases (`main`, `develop`, `dev`, `trunk`, `staging`, `release/*`) compare against themselves
- other branches compare against the default branch
- direnv auto-allow is skipped on non-trusted bases because `.envrc` can source unchecked files
6. Shows path for cd-ing to the worktree
### `list` or `ls`
Lists all available worktrees with their branches and current status.
**Example:**
```bash
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh list
```
**Output shows:**
- Worktree name
- Branch name
- Which is current (marked with ✓)
- Main repo status
### `switch <name>` or `go <name>`
Switches to an existing worktree and cd's into it.
**Example:**
```bash
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh switch feature-login
```
**Optional:**
- If name not provided, lists available worktrees and prompts for selection
### `cleanup` or `clean`
Interactively cleans up inactive worktrees with confirmation.
**Example:**
```bash
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh cleanup
```
**What happens:**
1. Lists all inactive worktrees
2. Asks for confirmation
3. Removes selected worktrees
4. Cleans up empty directories
## Workflow Examples
### Code Review with Worktree
```bash
# Claude Code recognizes you're not on the PR branch
# Offers: "Use worktree for isolated review? (y/n)"
# You respond: yes
# Script runs (copies .env files automatically):
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh create pr-123-feature-name
# You're now in isolated worktree for review with all env vars
cd .worktrees/pr-123-feature-name
# After review, return to main:
cd ../..
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh cleanup
```
### Parallel Feature Development
```bash
# For first feature (copies .env files):
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh create feature-login
# Later, start second feature (also copies .env files):
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh create feature-notifications
# List what you have:
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh list
# Switch between them as needed:
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh switch feature-login
# Return to main and cleanup when done:
cd .
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh cleanup
```
## Key Design Principles
### KISS (Keep It Simple, Stupid)
- **One manager script** handles all worktree operations
- **Simple commands** with sensible defaults
- **Interactive prompts** prevent accidental operations
- **Clear naming** using branch names directly
### Opinionated Defaults
- Worktrees always created from **main** (unless specified)
- Worktrees stored in **.worktrees/** directory
- Branch name becomes worktree name
- **.gitignore** automatically managed
### Safety First
- **Confirms before creating** worktrees
- **Confirms before cleanup** to prevent accidental removal
- **Won't remove current worktree**
- **Clear error messages** for issues
## Integration with Workflows
### `/ce-code-review`
Instead of always creating a worktree:
```
1. Check current branch
2. If ALREADY on target branch (PR branch or requested branch) → stay there, no worktree needed
3. If DIFFERENT branch than the review target → offer worktree:
"Use worktree for isolated review? (y/n)"
- yes → call ce-worktree skill
- no → proceed with PR diff on current branch
```
### `/ce-work`
Always offer choice:
```
1. Ask: "How do you want to work?
1. New branch on current worktree (live work)
2. Worktree (parallel work)"
2. If choice 1 → create new branch normally
3. If choice 2 → call ce-worktree skill to create from main
```
## Troubleshooting
### "Worktree already exists"
If you see this, the script will ask if you want to switch to it instead.
### "Cannot remove worktree: it is the current worktree"
Switch out of the worktree first (to main repo), then cleanup:
```bash
cd $(git rev-parse --show-toplevel)
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh cleanup
```
### Lost in a worktree?
See where you are:
```bash
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh list
```
### .env files missing in worktree?
If a worktree was created without .env files (e.g., via raw `git worktree add`), copy them:
```bash
bash ${CLAUDE_PLUGIN_ROOT}/skills/ce-worktree/scripts/worktree-manager.sh copy-env feature-name
```
Navigate back to main:
```bash
cd $(git rev-parse --show-toplevel)
```
## Technical Details
### Directory Structure
```
.worktrees/
├── feature-login/ # Worktree 1
│ ├── .git
│ ├── app/
│ └── ...
├── feature-notifications/ # Worktree 2
│ ├── .git
│ ├── app/
│ └── ...
└── ...
.gitignore (updated to include .worktrees)
```
### How It Works
- Uses `git worktree add` for isolated environments
- Each worktree has its own branch
- Changes in one worktree don't affect others
- Share git history with main repo
- Can push from any worktree
### Performance
- Worktrees are lightweight (just file system links)
- No repository duplication
- Shared git objects for efficiency
- Much faster than cloning or stashing/switching

View File

@@ -0,0 +1,500 @@
#!/bin/bash
# Git Worktree Manager
# Handles creating, listing, switching, and cleaning up Git worktrees
# KISS principle: Simple, interactive, opinionated
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Get repo root
GIT_ROOT=$(git rev-parse --show-toplevel)
WORKTREE_DIR="$GIT_ROOT/.worktrees"
# Ensure .worktrees is in .gitignore
ensure_gitignore() {
if ! grep -q "^\.worktrees$" "$GIT_ROOT/.gitignore" 2>/dev/null; then
echo ".worktrees" >> "$GIT_ROOT/.gitignore"
fi
}
# Copy .env files from main repo to worktree
copy_env_files() {
local worktree_path="$1"
echo -e "${BLUE}Copying environment files...${NC}"
# Find all .env* files in root (excluding .env.example which should be in git)
local env_files=()
for f in "$GIT_ROOT"/.env*; do
if [[ -f "$f" ]]; then
local basename=$(basename "$f")
# Skip .env.example (that's typically committed to git)
if [[ "$basename" != ".env.example" ]]; then
env_files+=("$basename")
fi
fi
done
if [[ ${#env_files[@]} -eq 0 ]]; then
echo -e " ${YELLOW} No .env files found in main repository${NC}"
return
fi
local copied=0
for env_file in "${env_files[@]}"; do
local source="$GIT_ROOT/$env_file"
local dest="$worktree_path/$env_file"
if [[ -f "$dest" ]]; then
echo -e " ${YELLOW}⚠️ $env_file already exists, backing up to ${env_file}.backup${NC}"
cp "$dest" "${dest}.backup"
fi
cp "$source" "$dest"
echo -e " ${GREEN}✓ Copied $env_file${NC}"
copied=$((copied + 1))
done
echo -e " ${GREEN}✓ Copied $copied environment file(s)${NC}"
}
# Resolve the repository default branch, falling back to main when origin/HEAD
# is unavailable (for example in single-branch clones).
get_default_branch() {
local head_ref
head_ref=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null || true)
if [[ -n "$head_ref" ]]; then
echo "${head_ref#refs/remotes/origin/}"
else
echo "main"
fi
}
# Auto-trust is only safe when the worktree is created from a long-lived branch
# the developer already controls. Review/PR branches should fall back to the
# default branch baseline and require manual direnv approval.
is_trusted_base_branch() {
local branch="$1"
local default_branch="$2"
[[ "$branch" == "$default_branch" ]] && return 0
case "$branch" in
develop|dev|trunk|staging|release/*)
return 0
;;
*)
return 1
;;
esac
}
# Trust development tool configs in a new worktree.
# Worktrees get a new filesystem path that tools like mise and direnv
# have never seen. Without trusting, these tools block with interactive
# prompts or refuse to load configs, which breaks hooks and scripts.
#
# Safety: auto-trusts only configs unchanged from a trusted baseline branch.
# Review/PR branches fall back to the default-branch baseline, and direnv
# auto-allow is limited to trusted base branches because .envrc can source
# additional files that direnv does not validate.
#
# TOCTOU between hash-check and trust is acceptable for local dev use.
trust_dev_tools() {
local worktree_path="$1"
local base_ref="$2"
local allow_direnv_auto="$3"
local trusted=0
local skipped_messages=()
local manual_commands=()
# mise: trust the specific config file if present and unchanged
if command -v mise &>/dev/null; then
for f in .mise.toml mise.toml .tool-versions; do
if [[ -f "$worktree_path/$f" ]]; then
if _config_unchanged "$f" "$base_ref" "$worktree_path"; then
if (cd "$worktree_path" && mise trust "$f" --quiet); then
trusted=$((trusted + 1))
else
echo -e " ${YELLOW}Warning: 'mise trust $f' failed -- run manually in $worktree_path${NC}"
fi
else
skipped_messages+=("mise trust $f (config differs from $base_ref)")
manual_commands+=("mise trust $f")
fi
break
fi
done
fi
# direnv: allow .envrc
if command -v direnv &>/dev/null; then
if [[ -f "$worktree_path/.envrc" ]]; then
if [[ "$allow_direnv_auto" != "true" ]]; then
skipped_messages+=("direnv allow (.envrc auto-allow is disabled for non-trusted base branches)")
manual_commands+=("direnv allow")
elif _config_unchanged ".envrc" "$base_ref" "$worktree_path"; then
if (cd "$worktree_path" && direnv allow); then
trusted=$((trusted + 1))
else
echo -e " ${YELLOW}Warning: 'direnv allow' failed -- run manually in $worktree_path${NC}"
fi
else
skipped_messages+=("direnv allow (.envrc differs from $base_ref)")
manual_commands+=("direnv allow")
fi
fi
fi
if [[ $trusted -gt 0 ]]; then
echo -e " ${GREEN}✓ Trusted $trusted dev tool config(s)${NC}"
fi
if [[ ${#skipped_messages[@]} -gt 0 ]]; then
echo -e " ${YELLOW}Skipped auto-trust for config(s) requiring manual review:${NC}"
for item in "${skipped_messages[@]}"; do
echo -e " - $item"
done
if [[ ${#manual_commands[@]} -gt 0 ]]; then
local joined
joined=$(printf ' && %s' "${manual_commands[@]}")
echo -e " ${BLUE}Review the diff, then run manually: cd $worktree_path${joined}${NC}"
fi
fi
}
# Check if a config file is unchanged from the base branch.
# Returns 0 (true) if the file is identical to the base branch version.
# Returns 1 (false) if the file was added or modified by this branch.
#
# Note: rev-parse returns the stored blob hash; hash-object on a path applies
# gitattributes filters. A mismatch causes a false negative (trust skipped),
# which is the safe direction.
_config_unchanged() {
local file="$1"
local base_ref="$2"
local worktree_path="$3"
# Reject symlinks -- trust only regular files with verifiable content
[[ -L "$worktree_path/$file" ]] && return 1
# Get the blob hash directly from git's object database via rev-parse
local base_hash
base_hash=$(git rev-parse "$base_ref:$file" 2>/dev/null) || return 1
local worktree_hash
worktree_hash=$(git hash-object "$worktree_path/$file") || return 1
[[ "$base_hash" == "$worktree_hash" ]]
}
# Create a new worktree
create_worktree() {
local branch_name="$1"
local from_branch="${2:-main}"
if [[ -z "$branch_name" ]]; then
echo -e "${RED}Error: Branch name required${NC}"
exit 1
fi
local worktree_path="$WORKTREE_DIR/$branch_name"
# Check if worktree already exists
if [[ -d "$worktree_path" ]]; then
echo -e "${YELLOW}Worktree already exists at: $worktree_path${NC}"
echo -e "Switch to it instead? (y/n)"
read -r response
if [[ "$response" == "y" ]]; then
switch_worktree "$branch_name"
fi
return
fi
echo -e "${BLUE}Creating worktree: $branch_name${NC}"
echo " From: $from_branch"
echo " Path: $worktree_path"
# Update main branch
echo -e "${BLUE}Updating $from_branch...${NC}"
git checkout "$from_branch"
git pull origin "$from_branch" || true
# Create worktree
mkdir -p "$WORKTREE_DIR"
ensure_gitignore
echo -e "${BLUE}Creating worktree...${NC}"
git worktree add -b "$branch_name" "$worktree_path" "$from_branch"
# Copy environment files
copy_env_files "$worktree_path"
# Trust dev tool configs (mise, direnv) so hooks and scripts work immediately.
# Long-lived integration branches can use themselves as the trust baseline,
# while review/PR branches fall back to the default branch and require manual
# direnv approval.
local default_branch
default_branch=$(get_default_branch)
local trust_branch="$default_branch"
local allow_direnv_auto="false"
if is_trusted_base_branch "$from_branch" "$default_branch"; then
trust_branch="$from_branch"
allow_direnv_auto="true"
fi
if ! git fetch origin "$trust_branch" --quiet; then
echo -e " ${YELLOW}Warning: could not fetch origin/$trust_branch -- trust check may use stale data${NC}"
fi
# Skip trust entirely if the baseline ref doesn't exist locally.
if git rev-parse --verify "origin/$trust_branch" &>/dev/null; then
trust_dev_tools "$worktree_path" "origin/$trust_branch" "$allow_direnv_auto"
else
echo -e " ${YELLOW}Skipping dev tool trust -- origin/$trust_branch not found locally${NC}"
fi
echo -e "${GREEN}✓ Worktree created successfully!${NC}"
echo ""
echo "To switch to this worktree:"
echo -e "${BLUE}cd $worktree_path${NC}"
echo ""
}
# List all worktrees
list_worktrees() {
echo -e "${BLUE}Available worktrees:${NC}"
echo ""
if [[ ! -d "$WORKTREE_DIR" ]]; then
echo -e "${YELLOW}No worktrees found${NC}"
return
fi
local count=0
for worktree_path in "$WORKTREE_DIR"/*; do
if [[ -d "$worktree_path" && -e "$worktree_path/.git" ]]; then
count=$((count + 1))
local worktree_name=$(basename "$worktree_path")
local branch=$(git -C "$worktree_path" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
if [[ "$PWD" == "$worktree_path" ]]; then
echo -e "${GREEN}$worktree_name${NC} (current) → branch: $branch"
else
echo -e " $worktree_name → branch: $branch"
fi
fi
done
if [[ $count -eq 0 ]]; then
echo -e "${YELLOW}No worktrees found${NC}"
else
echo ""
echo -e "${BLUE}Total: $count worktree(s)${NC}"
fi
echo ""
echo -e "${BLUE}Main repository:${NC}"
local main_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
echo " Branch: $main_branch"
echo " Path: $GIT_ROOT"
}
# Switch to a worktree
switch_worktree() {
local worktree_name="$1"
if [[ -z "$worktree_name" ]]; then
list_worktrees
echo -e "${BLUE}Switch to which worktree? (enter name)${NC}"
read -r worktree_name
fi
local worktree_path="$WORKTREE_DIR/$worktree_name"
if [[ ! -d "$worktree_path" ]]; then
echo -e "${RED}Error: Worktree not found: $worktree_name${NC}"
echo ""
list_worktrees
exit 1
fi
echo -e "${GREEN}Switching to worktree: $worktree_name${NC}"
cd "$worktree_path"
echo -e "${BLUE}Now in: $(pwd)${NC}"
}
# Copy env files to an existing worktree (or current directory if in a worktree)
copy_env_to_worktree() {
local worktree_name="$1"
local worktree_path
if [[ -z "$worktree_name" ]]; then
# Check if we're currently in a worktree
local current_dir=$(pwd)
if [[ "$current_dir" == "$WORKTREE_DIR"/* ]]; then
worktree_path="$current_dir"
worktree_name=$(basename "$worktree_path")
echo -e "${BLUE}Detected current worktree: $worktree_name${NC}"
else
echo -e "${YELLOW}Usage: worktree-manager.sh copy-env [worktree-name]${NC}"
echo "Or run from within a worktree to copy to current directory"
list_worktrees
return 1
fi
else
worktree_path="$WORKTREE_DIR/$worktree_name"
if [[ ! -d "$worktree_path" ]]; then
echo -e "${RED}Error: Worktree not found: $worktree_name${NC}"
list_worktrees
return 1
fi
fi
copy_env_files "$worktree_path"
echo ""
}
# Clean up completed worktrees
cleanup_worktrees() {
if [[ ! -d "$WORKTREE_DIR" ]]; then
echo -e "${YELLOW}No worktrees to clean up${NC}"
return
fi
echo -e "${BLUE}Checking for completed worktrees...${NC}"
echo ""
local found=0
local to_remove=()
for worktree_path in "$WORKTREE_DIR"/*; do
if [[ -d "$worktree_path" && -e "$worktree_path/.git" ]]; then
local worktree_name=$(basename "$worktree_path")
# Skip if current worktree
if [[ "$PWD" == "$worktree_path" ]]; then
echo -e "${YELLOW}(skip) $worktree_name - currently active${NC}"
continue
fi
found=$((found + 1))
to_remove+=("$worktree_path")
echo -e "${YELLOW}$worktree_name${NC}"
fi
done
if [[ $found -eq 0 ]]; then
echo -e "${GREEN}No inactive worktrees to clean up${NC}"
return
fi
echo ""
echo -e "Remove $found worktree(s)? (y/n)"
read -r response
if [[ "$response" != "y" ]]; then
echo -e "${YELLOW}Cleanup cancelled${NC}"
return
fi
echo -e "${BLUE}Cleaning up worktrees...${NC}"
for worktree_path in "${to_remove[@]}"; do
local worktree_name=$(basename "$worktree_path")
git worktree remove "$worktree_path" --force 2>/dev/null || true
echo -e "${GREEN}✓ Removed: $worktree_name${NC}"
done
# Clean up empty directory if nothing left
if [[ -z "$(ls -A "$WORKTREE_DIR" 2>/dev/null)" ]]; then
rmdir "$WORKTREE_DIR" 2>/dev/null || true
fi
echo -e "${GREEN}Cleanup complete!${NC}"
}
# Main command handler
main() {
local command="${1:-list}"
case "$command" in
create)
create_worktree "$2" "$3"
;;
list|ls)
list_worktrees
;;
switch|go)
switch_worktree "$2"
;;
copy-env|env)
copy_env_to_worktree "$2"
;;
cleanup|clean)
cleanup_worktrees
;;
help)
show_help
;;
*)
echo -e "${RED}Unknown command: $command${NC}"
echo ""
show_help
exit 1
;;
esac
}
show_help() {
cat << EOF
Git Worktree Manager
Usage: worktree-manager.sh <command> [options]
Commands:
create <branch-name> [from-branch] Create new worktree (copies .env files automatically)
(from-branch defaults to main)
list | ls List all worktrees
switch | go [name] Switch to worktree
copy-env | env [name] Copy .env files from main repo to worktree
(if name omitted, uses current worktree)
cleanup | clean Clean up inactive worktrees
help Show this help message
Environment Files:
- Automatically copies .env, .env.local, .env.test, etc. on create
- Skips .env.example (should be in git)
- Creates .backup files if destination already exists
- Use 'copy-env' to refresh env files after main repo changes
Dev Tool Trust:
- Trusts mise config (.mise.toml, mise.toml, .tool-versions) and direnv (.envrc)
- Uses trusted base branches directly (main, develop, dev, trunk, staging, release/*)
- Other branches fall back to the default branch as the trust baseline
- direnv auto-allow is skipped on non-trusted base branches; review manually first
- Modified configs are flagged for manual review
- Only runs if the tool is installed and config exists
- Prevents hooks/scripts from hanging on interactive trust prompts
Examples:
worktree-manager.sh create feature-login
worktree-manager.sh create feature-auth develop
worktree-manager.sh switch feature-login
worktree-manager.sh copy-env feature-login
worktree-manager.sh copy-env # copies to current worktree
worktree-manager.sh cleanup
worktree-manager.sh list
EOF
}
# Run
main "$@"