Update CLAUDE.md to reflect expanded command structure, new modules, and implementation details
This commit is contained in:
parent
1e71b3b4a4
commit
7854db5b93
72
CLAUDE.md
72
CLAUDE.md
|
|
@ -28,12 +28,32 @@ No build step. TypeScript runs directly via Bun. There are no tests.
|
|||
|
||||
```
|
||||
src/
|
||||
cli.ts # CLI entry point, all command handlers (Commander.js)
|
||||
git.ts # Git operations: worktrees, branches, merge
|
||||
vm.ts # Container lifecycle: create, provision, exec, shell, claude
|
||||
state.ts # Per-repo session persistence (.sandlot/state.json)
|
||||
config.ts # Load optional sandlot.json config from repo root
|
||||
spinner.ts # CLI progress spinner (braille frames)
|
||||
cli.ts # CLI entry point, command registration (Commander.js)
|
||||
git.ts # Git operations: worktrees, branches, merge, rebase
|
||||
vm.ts # Container lifecycle: create, provision, exec, shell, claude
|
||||
state.ts # Per-repo session persistence (.sandlot/state.json)
|
||||
env.ts # Read ANTHROPIC_API_KEY from ~/.env
|
||||
fmt.ts # ANSI escape codes, die/success/info helpers, pager
|
||||
markdown.ts # Terminal markdown renderer (headings, bold, links, code blocks)
|
||||
spinner.ts # CLI progress spinner (braille frames)
|
||||
commands/
|
||||
new.ts # Create session, derive branch name from prompt
|
||||
open.ts # Re-enter existing session
|
||||
close.ts # Remove worktree and clean up session
|
||||
list.ts # Show all active sessions with status
|
||||
save.ts # Stage all changes and commit
|
||||
merge.ts # Merge branch into main with conflict resolution
|
||||
rebase.ts # Rebase branch onto main with conflict resolution
|
||||
review.ts # Launch grumpy code review with Claude
|
||||
diff.ts # Show uncommitted changes or full branch diff
|
||||
show.ts # Show prompt and full diff for a branch
|
||||
log.ts # Show commits on branch not on main
|
||||
dir.ts # Print worktree path for a session
|
||||
shell.ts # Open fish shell in container
|
||||
cleanup.ts # Remove stale sessions
|
||||
vm.ts # VM subcommands (create, start, stop, destroy, status, info)
|
||||
completions.ts # Fish shell completions generator
|
||||
helpers.ts # Shared: requireSession, resolveConflicts, saveChanges
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
|
@ -46,6 +66,7 @@ Each module has a single responsibility. No classes — only exported async func
|
|||
3. `vm.ensure()` → start/create/provision the container
|
||||
4. `state.setSession()` → write to `.sandlot/state.json`
|
||||
5. `vm.claude()` → launch Claude Code in container at worktree path
|
||||
6. `saveChanges()` → auto-save on exit (stage all, AI-generated commit message) unless `--no-save`
|
||||
|
||||
**Worktree location**: `~/.sandlot/<repo-name>/<branch>/` (outside the repo)
|
||||
**Symlink in repo**: `<repo-root>/.sandlot/<branch>` → worktree
|
||||
|
|
@ -57,9 +78,10 @@ Each module has a single responsibility. No classes — only exported async func
|
|||
- Image: `ubuntu:24.04`
|
||||
- User: `ubuntu`
|
||||
- Mounts: `~/dev` and `~/.sandlot` from host
|
||||
- Provisioned once on first use: installs `curl git neofetch fish`, Claude Code, git identity, API key helper
|
||||
- API key: read from `~/.env` on host (`ANTHROPIC_API_KEY=...`), written as `~/.claude/api-key-helper.sh` in the container (never passed as a process argument)
|
||||
- Claude settings: `skipDangerousModePermissionPrompt: true` in container
|
||||
- Provisioned once on first use: installs `curl git neofetch fish unzip`, Bun, Claude Code, git identity, API key helper, activity tracking hook
|
||||
- API key: read from `~/.env` on host (`ANTHROPIC_API_KEY=...`), written to a temp file and copied as `~/.claude/api-key-helper.sh` in the container (never passed as a process argument)
|
||||
- Claude settings: `skipDangerousModePermissionPrompt: true`, activity tracking hooks (`UserPromptSubmit` / `Stop`) in container
|
||||
- Also writes `~/.claude.json` with `hasCompletedOnboarding: true` to skip first-run prompts
|
||||
|
||||
## Shell Command Pattern
|
||||
|
||||
|
|
@ -81,23 +103,6 @@ if (result.exitCode === 0) { ... }
|
|||
|
||||
Always use `.nothrow()` for commands that may fail non-fatally. Use `.quiet()` to suppress stdout/stderr.
|
||||
|
||||
## Configuration
|
||||
|
||||
Optional `sandlot.json` at repo root (loaded by `config.ts`):
|
||||
|
||||
```json
|
||||
{
|
||||
"vm": {
|
||||
"cpus": 4,
|
||||
"memory": "8GB",
|
||||
"image": "ubuntu:24.04",
|
||||
"mounts": { "/host/path": "/container/path" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note: `config.ts` loads this but `vm.ts` does not yet use it — the container is hardcoded with `-m 4G` and `ubuntu:24.04`.
|
||||
|
||||
## State Schema
|
||||
|
||||
`.sandlot/state.json` (per repo, gitignored):
|
||||
|
|
@ -108,7 +113,8 @@ Note: `config.ts` loads this but `vm.ts` does not yet use it — the container i
|
|||
"branch-name": {
|
||||
"branch": "branch-name",
|
||||
"worktree": "/Users/you/.sandlot/repo/branch-name",
|
||||
"created_at": "2026-02-16T10:30:00Z"
|
||||
"created_at": "2026-02-16T10:30:00Z",
|
||||
"prompt": "optional initial prompt text"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -117,14 +123,20 @@ Note: `config.ts` loads this but `vm.ts` does not yet use it — the container i
|
|||
## Error Handling Conventions
|
||||
|
||||
- Throw `Error` with descriptive messages from git/vm modules
|
||||
- CLI commands catch and display errors, then `process.exit(1)`
|
||||
- Command handlers use `die()` from `fmt.ts` for user-facing errors (writes to stderr, exits 1)
|
||||
- On `new` failure, roll back: remove worktree, delete branch, unlink symlink
|
||||
- Non-fatal cleanup steps use `.catch(() => {})` to continue past failures
|
||||
|
||||
## Key Implementation Notes
|
||||
|
||||
- `vm.exec()` prepends `export PATH=$HOME/.local/bin:$PATH` so `claude` binary is found
|
||||
- `vm.claude()` uses `Bun.spawn` with `stdin/stdout/stderr: "inherit"` for interactive TTY
|
||||
- `vm.claude()` uses `Bun.spawn` with `stdin/stdout/stderr: "inherit"` for interactive TTY; in print mode (`-p`), captures stdout via pipe and returns the output
|
||||
- `vm.claudePipe()` writes input to a temp file in `~/.sandlot/`, pipes it to `claude -p` inside the container, and returns the result — used for commit message generation and conflict resolution
|
||||
- `vm.isClaudeActive()` reads activity marker files written by the in-container `sandlot-activity` hook script
|
||||
- Branch creation in `createWorktree()` handles three cases: local branch, remote branch (tracks origin), new branch from HEAD
|
||||
- `sandlot save` uses Claude (`claude -p "..."`) inside the container to generate commit messages
|
||||
- `sandlot new` accepts a prompt instead of a branch name — derives a 2-word branch name via the Anthropic API (Haiku), falling back to simple text munging
|
||||
- `sandlot save` uses `vm.claudePipe()` to generate commit messages from the staged diff
|
||||
- `sandlot merge` and `sandlot rebase` use `vm.claudePipe()` to resolve merge conflicts automatically
|
||||
- `sandlot new` and `sandlot open` auto-save changes when Claude exits (disable with `--no-save`)
|
||||
- Default behavior (no subcommand): shows `list` if sessions exist, otherwise shows help
|
||||
- `.sandlot/` should be in the repo's `.gitignore`
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user