Move docs into main/ subdirectory
This commit is contained in:
parent
cd51baa2c1
commit
3f7ccd0f34
7 changed files with 1 additions and 980 deletions
71
AGENTS.md
71
AGENTS.md
|
|
@ -1,71 +0,0 @@
|
|||
# AGENTS.md — pi-worktree Extension
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
.pi/extensions/pi-worktree.ts # Single-file extension (all tool + command logic)
|
||||
README.md # User-facing documentation
|
||||
DESIGN.md # Architecture and design decisions
|
||||
DOMAIN.md # Domain concepts and terminology
|
||||
```
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **Language**: TypeScript
|
||||
- **Schema**: TypeBox (`@sinclair/typebox`) for tool parameter schemas
|
||||
- **Runtime**: pi coding agent extension API (`ExtensionAPI`, `ExtensionContext`)
|
||||
- **Git**: native via `pi.exec("git", [...])` — no external git packages
|
||||
- **No npm dependencies** in v1 beyond what pi provides
|
||||
|
||||
## Extension Entry Point
|
||||
|
||||
The extension is a single default-exported function:
|
||||
|
||||
```typescript
|
||||
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||
import { Type } from "typebox";
|
||||
|
||||
export default function (pi: ExtensionAPI) {
|
||||
// register tools and commands here
|
||||
}
|
||||
```
|
||||
|
||||
## Tool Conventions
|
||||
|
||||
- Each tool is a `Type.Object` schema + async execute function.
|
||||
- Execute signature: `(toolCallId, params, signal, onUpdate, ctx)`
|
||||
- Always check `result.exitCode !== 0` for git failures — surface the message with suggested fixes.
|
||||
- **Fail fast**: refuse dangerous operations (existing paths, current branch, uncommitted changes) with clear messages and suggestions. No silent auto-correction.
|
||||
|
||||
## Command Conventions
|
||||
|
||||
- Register via `pi.registerCommand("name", { description, handler })`.
|
||||
- Use `ctx.ui.select()` for interactive pickers.
|
||||
- Parse structured data from tool results (not raw text).
|
||||
|
||||
## State Management
|
||||
|
||||
- Tools are **stateless** — each call works independently based on current git state.
|
||||
- Session memory is ephemeral (per pi process lifetime) for back-switching behavior only.
|
||||
|
||||
## Error Handling Pattern
|
||||
|
||||
```typescript
|
||||
if (result.exitCode !== 0) {
|
||||
return {
|
||||
content: [{ type: "text", text: `Error: ${result.stderr}. Suggestion: <fix>` }],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Always include a suggested fix in error messages.
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
- [ ] Extension loads without errors when pi starts
|
||||
- [ ] All four tools registered with correct signatures
|
||||
- [ ] Error paths return `isError: true` with helpful messages
|
||||
- [ ] `/worktree` command shows interactive picker
|
||||
- [ ] Branch display updates after switching worktrees
|
||||
- [ ] No external dependencies beyond TypeBox + pi SDK
|
||||
61
DESIGN.md
61
DESIGN.md
|
|
@ -1,61 +0,0 @@
|
|||
# DESIGN.md — Architecture & Design Decisions
|
||||
|
||||
## Overview
|
||||
|
||||
A pi extension that manages git worktrees through tool commands and an interactive `/worktree` command, with tight session integration.
|
||||
|
||||
## v1 Scope
|
||||
|
||||
- Four tools: `git_worktree_create`, `git_worktree_list`, `git_worktree_switch`, `git_worktree_remove`
|
||||
- One command: `/worktree` (interactive picker)
|
||||
- Session hooks: branch display update + offer new session after switch
|
||||
- **Out of scope**: auto-worktree creation, smart defaults, persistent state
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
pi-worktree.ts
|
||||
├── Tools
|
||||
│ ├── git_worktree_create(path, branch?, create_branch?)
|
||||
│ ├── git_worktree_list()
|
||||
│ ├── git_worktree_switch(target)
|
||||
│ └── git_worktree_remove(path)
|
||||
├── Command: /worktree (interactive picker)
|
||||
└── Session hooks
|
||||
├── Update pi's git branch display on switch
|
||||
└── Offer new session creation after switch
|
||||
```
|
||||
|
||||
## Key Design Decisions
|
||||
|
||||
### Stateless Tools, Ephemeral Memory
|
||||
Tools are stateless; only in-memory mapping of worktree→session during a process lifetime for back-switching. Lost on restart.
|
||||
|
||||
### Fail Fast, No Auto-Correction
|
||||
Refuse dangerous operations (existing path, current branch, uncommitted changes) with clear messages and suggested fixes. Never silently auto-correct.
|
||||
|
||||
### Session Integration Depth (v1)
|
||||
Update branch display + offer new session creation. No automatic worktree creation per branch — keeps complexity down and avoids assumptions about workflow.
|
||||
|
||||
## Tool Behaviors
|
||||
|
||||
| Tool | Key Behavior | Fail Conditions |
|
||||
|------|-------------|-----------------|
|
||||
| `create` | `git worktree add <path> [branch]`, `-b` for new branches | Path exists, branch is current |
|
||||
| `list` | Parses `git worktree list` output into structured data | No git repo present |
|
||||
| `switch` | Changes cwd to target worktree path | Already there, uncommitted changes in source |
|
||||
| `remove` | `git worktree remove <path>` | Target is main repo, uncommitted changes |
|
||||
|
||||
## Edge Cases
|
||||
|
||||
1. **Nested worktrees**: Not supported by git — surface native error
|
||||
2. **Detached HEAD**: Use path for identification instead of branch name
|
||||
3. **Untracked files on removal**: Suggest removing/moving them first
|
||||
4. **Same-branch worktrees**: Let git handle it, surface the error
|
||||
|
||||
## Rollout Phases
|
||||
|
||||
1. Core tools (create, list, switch, remove) with error handling
|
||||
2. `/worktree` interactive command with picker + back-switching
|
||||
3. Session integration hooks (branch display, new session offer)
|
||||
4. Polish: edge cases, README, user testing
|
||||
45
DOMAIN.md
45
DOMAIN.md
|
|
@ -1,45 +0,0 @@
|
|||
# DOMAIN.md — Git Worktree Concepts
|
||||
|
||||
## Git Worktrees
|
||||
|
||||
A git worktree is a linked working directory that shares the same repository but checks out a different branch. Multiple worktrees can exist simultaneously, each on its own branch, without switching branches in any of them.
|
||||
|
||||
### Key Commands
|
||||
|
||||
- `git worktree list` — show all linked worktrees with paths and branches
|
||||
- `git worktree add <path> [branch]` — create a new linked worktree
|
||||
- `git worktree add -b <new-branch> <path>` — create with a new branch
|
||||
- `git worktree remove <path>` — remove a linked worktree (refuses if uncommitted changes)
|
||||
- `git worktree prune` — clean up stale entries for deleted worktrees
|
||||
|
||||
### Terminology
|
||||
|
||||
| Term | Definition |
|
||||
|------|-----------|
|
||||
| **Main repo** | The original repository directory (where `.git/` lives for non-bare repos) |
|
||||
| **Linked worktree** | An additional working directory linked to the same repo via `git worktree add` |
|
||||
| **Bare repo** | A `.git/` without a working tree — used as the central store when all worktrees are linked |
|
||||
| **Detached HEAD** | When a worktree checks out a commit directly instead of a branch |
|
||||
|
||||
### Constraints (from git itself)
|
||||
|
||||
- You cannot create a nested worktree (worktree inside a worktree).
|
||||
- Multiple worktrees on the same branch is possible with `-f` but dangerous and not recommended.
|
||||
- `git worktree remove` refuses if there are uncommitted or untracked changes.
|
||||
- The main repo counts as a "worktree" in `git worktree list`.
|
||||
|
||||
## pi Session Concepts
|
||||
|
||||
| Term | Definition |
|
||||
|------|-----------|
|
||||
| **Session** | A conversation context within pi, tied to a specific cwd/branch |
|
||||
| **Cwd change** | When pi changes its working directory (e.g., switching worktrees) |
|
||||
| **Branch display** | The footer indicator showing which git branch pi is tracking |
|
||||
| **Back-switching** | Restoring the previous session when returning to the main repo from a worktree |
|
||||
|
||||
### How Sessions Relate to Worktrees
|
||||
|
||||
- Each worktree can have its own session for focused context.
|
||||
- Switching worktrees updates the branch display automatically (pi reads HEAD from the new cwd).
|
||||
- Users are offered a choice: create a fresh session or keep the current one.
|
||||
- Back-switching restores the session that was active before leaving the main repo.
|
||||
81
README.md
81
README.md
|
|
@ -1,81 +0,0 @@
|
|||
# pi-worktree
|
||||
|
||||
A pi extension for managing git worktrees through intuitive tool commands and an interactive picker.
|
||||
|
||||
## Tools
|
||||
|
||||
### `git_worktree_create`
|
||||
|
||||
Create a linked worktree for a branch in the current repo.
|
||||
|
||||
```typescript
|
||||
{
|
||||
path: string, // Path for the new worktree
|
||||
branch?: string, // Branch name (new or existing). Defaults to 'main'.
|
||||
create_branch?: boolean // Create a new branch? Defaults to true if branch doesn't exist.
|
||||
}
|
||||
```
|
||||
|
||||
**Example**: `git_worktree_create({ path: "./feature-x", branch: "feature-x" })`
|
||||
|
||||
### `git_worktree_list`
|
||||
|
||||
List all linked worktrees in the current repo.
|
||||
|
||||
```typescript
|
||||
// No parameters required
|
||||
```
|
||||
|
||||
Returns structured data with `branch`, `path`, and `isCurrent` for each worktree.
|
||||
|
||||
**Example output**:
|
||||
```
|
||||
main — /home/user/repo (current)
|
||||
feature-x — /home/user/repo/feature-x
|
||||
```
|
||||
|
||||
### `git_worktree_switch`
|
||||
|
||||
Switch pi's working directory to a linked worktree.
|
||||
|
||||
```typescript
|
||||
{
|
||||
target: string // Path or branch name of the target worktree
|
||||
}
|
||||
```
|
||||
|
||||
**Example**: `git_worktree_switch({ target: "./feature-x" })`
|
||||
|
||||
After switching, you'll be offered the option to create a new session for that worktree context.
|
||||
|
||||
### `git_worktree_remove`
|
||||
|
||||
Remove a linked worktree.
|
||||
|
||||
```typescript
|
||||
{
|
||||
path: string // Path of the worktree to remove
|
||||
}
|
||||
```
|
||||
|
||||
**Example**: `git_worktree_remove({ path: "./feature-x" })`
|
||||
|
||||
## Command
|
||||
|
||||
### `/worktree`
|
||||
|
||||
Interactive picker to switch between linked worktrees.
|
||||
|
||||
Lists all worktrees with a branch-first display and lets you select one to switch to. Automatically updates pi's branch display after switching.
|
||||
|
||||
## Behavior
|
||||
|
||||
- **Fail fast**: Refuses dangerous operations (existing paths, current branch, uncommitted changes) with clear messages and suggested fixes.
|
||||
- **Stateless tools**: Each call works independently based on current git state.
|
||||
- **Session integration**: Branch display updates automatically; you're offered a new session after switching worktrees.
|
||||
- **Back-switching**: When returning to the main repo, pi restores the previous session.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Git 2.x with worktree support (all modern versions)
|
||||
- No external npm dependencies — uses only pi's extension API and TypeBox schemas.
|
||||
1
main
Submodule
1
main
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit cd51baa2c1ae7e5554e6796417a5950128190feb
|
||||
|
|
@ -1,288 +0,0 @@
|
|||
# pi-worktree Extension Design Document
|
||||
|
||||
## Overview
|
||||
|
||||
A pi extension that manages git worktrees through pi's tool/command system, providing full CRUD operations plus interactive switching with tight session integration.
|
||||
|
||||
## Goals
|
||||
|
||||
- Enable users to manage git worktrees without typing `git worktree` commands manually
|
||||
- Provide an intuitive interface for the common feature branch workflow (create → use → remove)
|
||||
- Keep pi's mental model of the current context in sync when switching worktrees
|
||||
- Fail fast with clear error messages and suggested fixes
|
||||
|
||||
## Constraints
|
||||
|
||||
- **v1 Scope**: Full CRUD + switch command only. No auto-worktree creation per branch, no smart defaults, no persistent state between tool calls.
|
||||
- **Error Handling**: Refuse dangerous operations with helpful suggestions. No silent auto-correction.
|
||||
- **State Management**: Stateless tools — each call works independently based on current git state.
|
||||
- **Integration Depth**: Session awareness in v1 (update branch display, offer new sessions) but no automatic worktree creation or session branching logic.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Extension Structure
|
||||
|
||||
```
|
||||
.pi/extensions/pi-worktree.ts
|
||||
├── Tool implementations
|
||||
│ ├── git_worktree_create(path, branch?)
|
||||
│ ├── git_worktree_list()
|
||||
│ ├── git_worktree_switch(target)
|
||||
│ └── git_worktree_remove(path)
|
||||
├── Command registration
|
||||
│ └── /worktree — interactive picker
|
||||
└── Session integration hooks
|
||||
├── Update pi's git branch display on switch
|
||||
└── Offer new session creation after switch
|
||||
```
|
||||
|
||||
### Tool Signatures
|
||||
|
||||
#### `git_worktree_create`
|
||||
|
||||
```typescript
|
||||
{
|
||||
name: "git_worktree_create",
|
||||
label: "Create Worktree",
|
||||
description: "Create a linked worktree for a branch in the current repo.",
|
||||
parameters: Type.Object({
|
||||
path: Type.String({ description: "Path for the new worktree" }),
|
||||
branch?: Type.Optional(Type.String({
|
||||
description: "Branch name (new or existing). Defaults to 'main'."
|
||||
})),
|
||||
create_branch?: Type.Optional(Type.Boolean({
|
||||
description: "Create a new branch? Defaults to true if branch doesn't exist.",
|
||||
default: true
|
||||
}))
|
||||
}),
|
||||
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
||||
// Implementation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Behavior**:
|
||||
- Run `git worktree add <path> [branch]` to create the linked worktree.
|
||||
- If branch doesn't exist and `create_branch: true`, use `git worktree add -b <path> <branch>` to create a new branch.
|
||||
- **Error handling**:
|
||||
- If path already exists: refuse with "Path '<path>' already exists. Choose a different location."
|
||||
- If branch is current branch: refuse with "Can't create worktree on the current branch — switch first."
|
||||
- If git fails, surface the error message and suggest fixes.
|
||||
|
||||
#### `git_worktree_list`
|
||||
|
||||
```typescript
|
||||
{
|
||||
name: "git_worktree_list",
|
||||
label: "List Worktrees",
|
||||
description: "List all linked worktrees in the current repo.",
|
||||
parameters: Type.Object({}),
|
||||
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
||||
// Implementation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Behavior**:
|
||||
- Run `git worktree list` to get the list.
|
||||
- Parse output and format as "branch — path" (e.g., "feature-x — /home/user/repo/feature-x").
|
||||
- Mark the current branch/worktree with an indicator (e.g., `(current)`).
|
||||
- Return structured data for the LLM to display or use in other operations.
|
||||
|
||||
#### `git_worktree_switch`
|
||||
|
||||
```typescript
|
||||
{
|
||||
name: "git_worktree_switch",
|
||||
label: "Switch Worktree",
|
||||
description: "Switch pi's working directory to a linked worktree.",
|
||||
parameters: Type.Object({
|
||||
target: Type.String({
|
||||
description: "Path or branch name of the target worktree."
|
||||
})
|
||||
}),
|
||||
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
||||
// Implementation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Behavior**:
|
||||
- Resolve `target` to a path (if it's a branch name, look up the worktree path).
|
||||
- If target is the current worktree: refuse with "Already in this worktree."
|
||||
- If target has uncommitted changes and you're switching away: **fail fast** with "Worktree '<path>' has uncommitted changes. Stash them first?" (no auto-stashing).
|
||||
- Change pi's cwd to the target path using `ctx.cwd` or equivalent mechanism.
|
||||
- Trigger session integration hooks (see below).
|
||||
|
||||
#### `git_worktree_remove`
|
||||
|
||||
```typescript
|
||||
{
|
||||
name: "git_worktree_remove",
|
||||
label: "Remove Worktree",
|
||||
description: "Remove a linked worktree.",
|
||||
parameters: Type.Object({
|
||||
path: Type.String({
|
||||
description: "Path of the worktree to remove."
|
||||
})
|
||||
}),
|
||||
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
||||
// Implementation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Behavior**:
|
||||
- If target is the main repo: refuse with "Can't remove the main repository. Use 'git worktree prune' instead."
|
||||
- If target has uncommitted changes: refuse with "Worktree '<path>' has uncommitted changes. Stash or commit them first?"
|
||||
- Run `git worktree remove <path>` to remove it.
|
||||
- If git fails (e.g., due to open files), surface the error and suggest fixes.
|
||||
|
||||
### Command Registration
|
||||
|
||||
#### `/worktree` Interactive Picker
|
||||
|
||||
```typescript
|
||||
pi.registerCommand("worktree", {
|
||||
description: "Switch between linked worktrees interactively.",
|
||||
handler: async (_args, ctx) => {
|
||||
// 1. List all worktrees using git_worktree_list
|
||||
// 2. Display as a picker (branch-first with path)
|
||||
// 3. On selection, call git_worktree_switch with the target
|
||||
// 4. Trigger session integration hooks
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Behavior**:
|
||||
- Use `ctx.ui.select()` to show an interactive picker of worktrees.
|
||||
- Display format: "feature-x — /home/user/repo/feature-x (current)" or similar.
|
||||
- When user selects a target, call `git_worktree_switch` with the resolved path.
|
||||
- After switch, trigger session integration hooks.
|
||||
|
||||
### Session Integration Hooks
|
||||
|
||||
#### Update Branch Display
|
||||
|
||||
When switching worktrees:
|
||||
1. Notify pi that the cwd has changed so it refreshes git branch tracking.
|
||||
2. Update the footer to show the new branch.
|
||||
|
||||
**Implementation**: Use `ctx.ui.notify()` or similar mechanism to signal cwd change. Pi's existing footer data provider will pick up the new HEAD file and update the branch display automatically when the cwd changes.
|
||||
|
||||
#### Offer New Session Creation
|
||||
|
||||
After switching worktrees:
|
||||
1. Ask user if they want to create a new pi session for this worktree context.
|
||||
2. If yes, call `ctx.newSession()` with an appropriate setup message.
|
||||
3. If no, stay in current session (but branch display is updated).
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
const choice = await ctx.ui.select("Create a new session?", [
|
||||
"Yes, start fresh for this worktree",
|
||||
"No, keep the current session"
|
||||
]);
|
||||
|
||||
if (choice?.startsWith("Yes")) {
|
||||
await ctx.newSession({
|
||||
setup: async (sm) => {
|
||||
sm.appendMessage({
|
||||
role: "user",
|
||||
content: [{ type: "text", text: `Switched to worktree for branch <branch>. Context from previous session...` }],
|
||||
timestamp: Date.now()
|
||||
});
|
||||
},
|
||||
withSession: async (newCtx) => {
|
||||
newCtx.ui.notify("New session created for this worktree.", "info");
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### Back-Switching Behavior
|
||||
|
||||
When switching back to the main repo from a worktree:
|
||||
- Auto-restore the previous session that was active before creating/using the worktree.
|
||||
|
||||
**Implementation**: Track which sessions were used with which branches/worktrees in memory (not persisted). When switching back to main, switch pi's session back to the one that was active for main.
|
||||
|
||||
## Tradeoffs
|
||||
|
||||
### Stateless vs Stateful Tools
|
||||
|
||||
**Decision**: Stateless tools, but remember recent sessions in memory during a pi process lifetime.
|
||||
|
||||
**Rationale**:
|
||||
- Stateless tools are simpler and more predictable — each call works independently based on current git state.
|
||||
- Memory of recent sessions is necessary for back-switching behavior (auto-restore previous session when returning to main).
|
||||
- This memory is ephemeral (lost on pi restart) and doesn't complicate the tool API.
|
||||
|
||||
### Auto-Correction vs Fail Fast
|
||||
|
||||
**Decision**: Fail fast with helpful errors, no auto-correction.
|
||||
|
||||
**Rationale**:
|
||||
- Users want control over their git state — stashing changes should be explicit.
|
||||
- Auto-correction can hide problems (e.g., silently dropping uncommitted work).
|
||||
- Clear error messages + suggested fixes give users the information to make informed decisions.
|
||||
|
||||
### Session Integration Depth in v1
|
||||
|
||||
**Decision**: Update branch display AND offer new session creation, but no automatic worktree creation per branch.
|
||||
|
||||
**Rationale**:
|
||||
- Branch display update is essential — pi needs to know which branch it's tracking.
|
||||
- Offering new sessions gives users the choice without forcing a context switch.
|
||||
- Auto-worktree creation adds complexity and assumptions about workflow that we haven't validated.
|
||||
|
||||
## Risks
|
||||
|
||||
### Edge Cases
|
||||
|
||||
1. **Nested worktrees**: Git doesn't support nested linked worktrees (worktrees within worktrees). Our tools will fail with standard git errors — no special handling needed in v1.
|
||||
|
||||
2. **Detached HEAD states**: If a worktree is on a detached HEAD, `git worktree list` still works but branch display might show "detached". Tools should handle this gracefully (e.g., use path instead of branch name for identification).
|
||||
|
||||
3. **Untracked files in worktrees**: `git worktree remove` will refuse if there are untracked files. Error message should suggest removing or moving them first.
|
||||
|
||||
4. **Worktrees on the same branch**: Git allows multiple worktrees on the same branch (with `-f` force flag), but it's dangerous. Our tools won't allow this by default — git will error out, and we'll surface that error clearly.
|
||||
|
||||
### Performance Considerations
|
||||
|
||||
- `git worktree list` is fast and doesn't require network access.
|
||||
- Switching cwd should be nearly instantaneous (just a chdir).
|
||||
- No background processes or watchers needed in v1.
|
||||
|
||||
## Rollout Strategy
|
||||
|
||||
### Phase 1: Core Tools (v1)
|
||||
|
||||
1. Implement the four tools: create, list, switch, remove.
|
||||
2. Register error handling with clear messages and suggested fixes.
|
||||
3. Test each tool individually with various scenarios.
|
||||
|
||||
### Phase 2: Interactive Command (v1)
|
||||
|
||||
4. Implement `/worktree` command with interactive picker.
|
||||
5. Wire up branch-first display format.
|
||||
6. Add back-switching behavior (auto-restore previous session).
|
||||
|
||||
### Phase 3: Session Integration (v1)
|
||||
|
||||
7. Add session integration hooks to switch operations.
|
||||
8. Update pi's git branch display on cwd change.
|
||||
9. Offer new session creation after switching worktrees.
|
||||
|
||||
### Phase 4: Polish and Documentation (v1)
|
||||
|
||||
10. Write README.md with usage examples.
|
||||
11. Add error handling for edge cases discovered during testing.
|
||||
12. Gather feedback from early users.
|
||||
|
||||
## Future Considerations (Post-v1)
|
||||
|
||||
- **Auto-worktree creation**: When switching branches in pi, automatically create a worktree if one doesn't exist.
|
||||
- **Smart defaults**: Stash changes before switching (with confirmation), offer to delete branch when removing worktree.
|
||||
- **Persistent state**: Remember recent worktrees/branches for quick access, even after pi restarts.
|
||||
- **Session branching**: Automatically create a new session when entering a worktree on a feature branch, preserving the main repo's session.
|
||||
|
|
@ -1,434 +0,0 @@
|
|||
# pi-worktree Implementation Plan
|
||||
|
||||
## Overview
|
||||
|
||||
Step-by-step engineering plan for building the `pi-worktree` extension. Breaks down into discrete implementable units with milestones, sequencing, dependencies, and validation tasks.
|
||||
|
||||
## Milestones
|
||||
|
||||
### Milestone 1: Foundation (Day 1-2)
|
||||
|
||||
**Goal**: Set up extension structure and register basic tools.
|
||||
|
||||
#### Task 1.1: Create Extension File
|
||||
|
||||
```bash
|
||||
mkdir -p .pi/extensions
|
||||
touch .pi/extensions/pi-worktree.ts
|
||||
```
|
||||
|
||||
**Deliverable**: Empty extension file with correct imports and structure.
|
||||
|
||||
**Validation**: Extension loads without errors when pi starts.
|
||||
|
||||
---
|
||||
|
||||
#### Task 1.2: Register Tool Scaffolding
|
||||
|
||||
Register all four tools with minimal implementations (return placeholder responses).
|
||||
|
||||
```typescript
|
||||
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||
import { Type } from "typebox";
|
||||
|
||||
export default function (pi: ExtensionAPI) {
|
||||
// Register tools here
|
||||
}
|
||||
```
|
||||
|
||||
**Deliverable**: Four tool registrations with correct signatures but placeholder execute functions.
|
||||
|
||||
**Validation**:
|
||||
- `pi.getAllTools()` includes all four tools after loading extension.
|
||||
- Calling each tool returns a response (even if just "not implemented").
|
||||
|
||||
---
|
||||
|
||||
#### Task 1.3: Implement `git_worktree_list`
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
async function executeGitWorktreeList(toolCallId, params, signal, onUpdate, ctx) {
|
||||
const result = await pi.exec("git", ["worktree", "list"], { cwd: ctx.cwd });
|
||||
|
||||
if (result.exitCode !== 0) {
|
||||
return {
|
||||
content: [{ type: "text", text: `Error listing worktrees: ${result.stdout}` }],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
|
||||
// Parse output into structured format
|
||||
const lines = result.stdout.trim().split("\n");
|
||||
const worktrees = lines.map(line => {
|
||||
const parts = line.split(/\s+/);
|
||||
return {
|
||||
path: parts[0],
|
||||
branch: parts[1] || "detached",
|
||||
isCurrent: line.includes("(current)")
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: worktrees.map(w => `${w.branch} — ${w.path}${w.isCurrent ? " (current)" : ""}`).join("\n")
|
||||
}],
|
||||
details: { worktrees }
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**Deliverable**: Tool that lists all linked worktrees with branch and path.
|
||||
|
||||
**Validation**:
|
||||
- Run in a repo with multiple worktrees — verify output matches `git worktree list`.
|
||||
- Test error case (no git repo) — should return clear error message.
|
||||
|
||||
---
|
||||
|
||||
### Milestone 2: Create and Remove Operations (Day 3-5)
|
||||
|
||||
**Goal**: Implement create and remove operations with error handling.
|
||||
|
||||
#### Task 2.1: Implement `git_worktree_create`
|
||||
|
||||
**Implementation Steps**:
|
||||
1. Validate input parameters.
|
||||
2. Check if path already exists — refuse if so.
|
||||
3. Determine whether to use `-b` flag (create new branch) or not.
|
||||
4. Run `git worktree add <path> [branch]`.
|
||||
5. Handle errors with clear messages.
|
||||
|
||||
**Error Handling**:
|
||||
- Path exists: "Path '<path>' already exists. Choose a different location."
|
||||
- Branch is current: "Can't create worktree on the current branch — switch first."
|
||||
- Git error: Surface git's message and suggest fixes (e.g., "Git reported 'fatal: ...'. Check if you have permissions or if there's a naming conflict.").
|
||||
|
||||
**Deliverable**: Tool that creates linked worktrees with proper validation.
|
||||
|
||||
**Validation**:
|
||||
- Create worktree on new branch — verify it appears in `git worktree list`.
|
||||
- Try to create at existing path — should refuse with clear error.
|
||||
- Try to create on current branch — should refuse with clear error.
|
||||
|
||||
---
|
||||
|
||||
#### Task 2.2: Implement `git_worktree_remove`
|
||||
|
||||
**Implementation Steps**:
|
||||
1. Validate input parameters.
|
||||
2. Check if target is the main repo — refuse if so (suggest `git worktree prune`).
|
||||
3. Check for uncommitted changes — refuse with message if found.
|
||||
4. Run `git worktree remove <path>`.
|
||||
5. Handle errors with clear messages.
|
||||
|
||||
**Error Handling**:
|
||||
- Main repo: "Can't remove the main repository. Use 'git worktree prune' instead."
|
||||
- Uncommitted changes: "Worktree '<path>' has uncommitted changes. Stash or commit them first?"
|
||||
- Git error: Surface git's message and suggest fixes (e.g., "Git reported 'fatal: ...'. Check if you have permissions or if there are open files.").
|
||||
|
||||
**Deliverable**: Tool that removes linked worktrees with proper validation.
|
||||
|
||||
**Validation**:
|
||||
- Remove a worktree with no changes — verify it disappears from `git worktree list`.
|
||||
- Try to remove main repo — should refuse with clear error.
|
||||
- Try to remove worktree with uncommitted changes — should refuse with clear error.
|
||||
|
||||
---
|
||||
|
||||
### Milestone 3: Switch Operation (Day 6-7)
|
||||
|
||||
**Goal**: Implement switch operation with cwd change and session integration hooks.
|
||||
|
||||
#### Task 3.1: Implement `git_worktree_switch`
|
||||
|
||||
**Implementation Steps**:
|
||||
1. Validate input parameters.
|
||||
2. Resolve target to a path (if it's a branch name, look up the worktree path).
|
||||
3. Check if already in that worktree — refuse if so.
|
||||
4. Check for uncommitted changes in target — fail fast with message if switching away from it.
|
||||
5. Change pi's cwd to the target path.
|
||||
6. Trigger session integration hooks (see Milestone 4).
|
||||
|
||||
**Error Handling**:
|
||||
- Already there: "Already in this worktree."
|
||||
- Uncommitted changes in source: "Worktree '<path>' has uncommitted changes. Stash them first?"
|
||||
- Target not found: "No worktree found at '<target>'. Run 'git_worktree_list' to see available worktrees."
|
||||
|
||||
**Deliverable**: Tool that switches pi's working directory to a linked worktree.
|
||||
|
||||
**Validation**:
|
||||
- Switch to an existing worktree — verify cwd changes and branch display updates.
|
||||
- Try to switch to non-existent target — should refuse with clear error.
|
||||
- Verify session integration hooks fire after successful switch.
|
||||
|
||||
---
|
||||
|
||||
### Milestone 4: Session Integration (Day 8-9)
|
||||
|
||||
**Goal**: Wire up session integration hooks for switch operations.
|
||||
|
||||
#### Task 4.1: Update Branch Display on Cwd Change
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
// In git_worktree_switch execute function, after changing cwd:
|
||||
ctx.ui.notify(`Switched to worktree at ${targetPath}`, "info");
|
||||
// Pi's footer data provider will pick up the new HEAD file automatically
|
||||
// when it detects the cwd change. No additional code needed for branch display.
|
||||
```
|
||||
|
||||
**Deliverable**: Branch display updates automatically after switching worktrees.
|
||||
|
||||
**Validation**:
|
||||
- Switch to a worktree on `feature-x` — verify pi's footer shows `feature-x`.
|
||||
- Switch back to main — verify pi's footer shows `main` (or whatever the main branch is).
|
||||
|
||||
---
|
||||
|
||||
#### Task 4.2: Offer New Session Creation
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
// In git_worktree_switch execute function, after successful switch:
|
||||
const choice = await ctx.ui.select("Create a new session?", [
|
||||
"Yes, start fresh for this worktree",
|
||||
"No, keep the current session"
|
||||
]);
|
||||
|
||||
if (choice?.startsWith("Yes")) {
|
||||
await ctx.newSession({
|
||||
setup: async (sm) => {
|
||||
sm.appendMessage({
|
||||
role: "user",
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Switched to worktree for branch ${branchName}. Context from previous session...`
|
||||
}],
|
||||
timestamp: Date.now()
|
||||
});
|
||||
},
|
||||
withSession: async (newCtx) => {
|
||||
newCtx.ui.notify("New session created for this worktree.", "info");
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**Deliverable**: After switching worktrees, user is offered the option to create a new pi session.
|
||||
|
||||
**Validation**:
|
||||
- Switch to a worktree and choose "Yes" — verify new session is created with appropriate context message.
|
||||
- Switch to a worktree and choose "No" — verify current session continues unchanged (except branch display).
|
||||
|
||||
---
|
||||
|
||||
#### Task 4.3: Implement Back-Switching Behavior
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
// Track previous sessions in memory during pi process lifetime:
|
||||
const worktreeSessionMap = new Map<string, string>(); // worktree path -> session file
|
||||
let mainRepoSessionFile: string | undefined;
|
||||
|
||||
// When switching TO a worktree:
|
||||
worktreeSessionMap.set(targetPath, ctx.sessionManager.getSessionFile());
|
||||
|
||||
// When switching TO the main repo (detected by checking if target is the original cwd):
|
||||
if (mainRepoSessionFile) {
|
||||
await ctx.switchSession(mainRepoSessionFile);
|
||||
} else {
|
||||
// No previous session tracked — stay in current session
|
||||
mainRepoSessionFile = ctx.sessionManager.getSessionFile();
|
||||
}
|
||||
```
|
||||
|
||||
**Deliverable**: Switching back to the main repo auto-restores the previous session.
|
||||
|
||||
**Validation**:
|
||||
- Start a session, switch to a worktree (create new session), then switch back to main — verify pi returns to the original session.
|
||||
- Verify that the `worktreeSessionMap` is cleared on pi restart (stateless tools).
|
||||
|
||||
---
|
||||
|
||||
### Milestone 5: Interactive Command (Day 10)
|
||||
|
||||
**Goal**: Implement `/worktree` command with interactive picker.
|
||||
|
||||
#### Task 5.1: Register and Implement `/worktree` Command
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
pi.registerCommand("worktree", {
|
||||
description: "Switch between linked worktrees interactively.",
|
||||
handler: async (args, ctx) => {
|
||||
// 1. List all worktrees
|
||||
const listResult = await pi.callTool("git_worktree_list");
|
||||
if (listResult.isError) {
|
||||
ctx.ui.notify(`Error listing worktrees: ${listResult.content}`, "error");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Parse the structured data and display as picker
|
||||
const worktrees = listResult.details.worktrees as Array<{
|
||||
path: string;
|
||||
branch: string;
|
||||
isCurrent: boolean;
|
||||
}>;
|
||||
|
||||
if (worktrees.length === 0) {
|
||||
ctx.ui.notify("No linked worktrees found.", "info");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Show interactive picker
|
||||
const choice = await ctx.ui.select("Pick a worktree:",
|
||||
worktrees.map(w => `${w.branch} — ${w.path}${w.isCurrent ? " (current)" : ""}`)
|
||||
);
|
||||
|
||||
if (!choice) return;
|
||||
|
||||
// 4. Find the selected worktree and switch to it
|
||||
const selected = worktrees.find(w =>
|
||||
choice.startsWith(`${w.branch} — ${w.path}`)
|
||||
);
|
||||
|
||||
if (selected) {
|
||||
await pi.callTool("git_worktree_switch", { target: selected.path });
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Deliverable**: `/worktree` command shows an interactive picker and switches to the selected worktree.
|
||||
|
||||
**Validation**:
|
||||
- Run `/worktree` in a repo with multiple worktrees — verify picker shows all options with correct format.
|
||||
- Select a worktree — verify pi switches to it and branch display updates.
|
||||
- Cancel the picker (Esc) — verify no switch occurs.
|
||||
|
||||
---
|
||||
|
||||
### Milestone 6: Polish and Documentation (Day 11-12)
|
||||
|
||||
**Goal**: Add final polish, edge case handling, and documentation.
|
||||
|
||||
#### Task 6.1: Handle Edge Cases
|
||||
|
||||
Add error handling for:
|
||||
- Nested worktrees (git will error — surface the error clearly).
|
||||
- Detached HEAD states in worktrees (use path instead of branch name for identification).
|
||||
- Untracked files preventing removal (suggest removing or moving them first).
|
||||
- Worktrees on the same branch (let git handle it, surface the error if it fails).
|
||||
|
||||
**Deliverable**: Robust error handling for all common edge cases.
|
||||
|
||||
**Validation**:
|
||||
- Test each edge case scenario manually and verify appropriate error messages.
|
||||
|
||||
---
|
||||
|
||||
#### Task 6.2: Write README.md
|
||||
|
||||
Create `.pi/extensions/README.md` (or update existing) with:
|
||||
- Extension name and purpose.
|
||||
- Installation instructions (project-local auto-discovery).
|
||||
- Tool descriptions with examples for each of the four tools.
|
||||
- Command description with example usage.
|
||||
- Session integration behavior.
|
||||
- Error handling strategy.
|
||||
|
||||
**Deliverable**: Complete documentation for users and developers.
|
||||
|
||||
**Validation**:
|
||||
- Review README for clarity, completeness, and accuracy.
|
||||
- Verify all examples work as documented.
|
||||
|
||||
---
|
||||
|
||||
#### Task 6.3: Final Testing and Cleanup
|
||||
|
||||
- Test the complete workflow end-to-end: create → switch → remove.
|
||||
- Verify error messages are clear and actionable.
|
||||
- Check that session integration works correctly in all scenarios.
|
||||
- Clean up any debug logging or TODO comments.
|
||||
|
||||
**Deliverable**: Production-ready extension with no known issues.
|
||||
|
||||
**Validation**:
|
||||
- Run through the complete workflow multiple times to catch any regressions.
|
||||
- Review code for quality, readability, and maintainability.
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
### External Dependencies
|
||||
|
||||
- **Node.js built-ins**: `child_process` (for exec), `fs`, `path`. No external npm packages needed in v1.
|
||||
- **Git**: Requires git 2.x with worktree support (available in all modern git versions).
|
||||
- **TypeBox**: Already available as a pi dependency for tool parameter schemas.
|
||||
|
||||
### Internal Dependencies
|
||||
|
||||
- Pi's extension API (`ExtensionAPI`, `ExtensionContext`).
|
||||
- Pi's session management (`ctx.sessionManager`, `ctx.newSession()`, `ctx.switchSession()`).
|
||||
- Pi's UI methods (`ctx.ui.select()`, `ctx.ui.notify()`, etc.).
|
||||
|
||||
---
|
||||
|
||||
## Validation Strategy
|
||||
|
||||
### Unit Testing (Manual)
|
||||
|
||||
Test each tool in isolation with various inputs:
|
||||
- Valid inputs — verify correct behavior.
|
||||
- Invalid inputs (missing params, non-existent paths/branches) — verify clear error messages.
|
||||
- Edge cases (existing path, current branch, uncommitted changes) — verify appropriate refusals.
|
||||
|
||||
### Integration Testing (Manual)
|
||||
|
||||
Test the complete workflow:
|
||||
1. Create a worktree on a new branch.
|
||||
2. Switch to it via `/worktree` command or `git_worktree_switch`.
|
||||
3. Verify branch display updates correctly.
|
||||
4. Choose "Yes" when offered a new session — verify new session is created.
|
||||
5. Switch back to main — verify auto-restore of previous session.
|
||||
6. Remove the worktree — verify it disappears from list.
|
||||
|
||||
### User Acceptance Testing (Manual)
|
||||
|
||||
Have early users run through typical workflows:
|
||||
- Feature branch development cycle (create → use → remove).
|
||||
- Switching between multiple worktrees frequently.
|
||||
- Handling errors and edge cases.
|
||||
|
||||
Gather feedback on clarity, usability, and any missing features or confusing behavior.
|
||||
|
||||
---
|
||||
|
||||
## Timeline Summary
|
||||
|
||||
| Milestone | Days | Deliverables |
|
||||
|-----------|------|--------------|
|
||||
| 1: Foundation | Day 1-2 | Extension structure, tool scaffolding, `git_worktree_list` implemented |
|
||||
| 2: Create/Remove | Day 3-5 | `git_worktree_create` and `git_worktree_remove` with error handling |
|
||||
| 3: Switch Operation | Day 6-7 | `git_worktree_switch` with cwd change |
|
||||
| 4: Session Integration | Day 8-9 | Branch display updates, new session offering, back-switching behavior |
|
||||
| 5: Interactive Command | Day 10 | `/worktree` command with interactive picker |
|
||||
| 6: Polish and Documentation | Day 11-12 | Edge case handling, README.md, final testing |
|
||||
|
||||
**Total Estimated Time**: ~12 days (assuming part-time development on top of other work).
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
The extension is ready for release when:
|
||||
- All four tools (`create`, `list`, `switch`, `remove`) work correctly with clear error messages.
|
||||
- `/worktree` command provides an intuitive interactive picker with branch-first display.
|
||||
- Session integration works: branch display updates on switch, new session offered after switch, auto-restore of previous session when returning to main.
|
||||
- Edge cases (existing path, current branch, uncommitted changes) are handled gracefully with helpful error messages.
|
||||
- Documentation is complete and accurate.
|
||||
- No known regressions or critical bugs remain.
|
||||
Loading…
Add table
Reference in a new issue