diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 7cc49a4..0000000 --- a/AGENTS.md +++ /dev/null @@ -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: ` }], - 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 diff --git a/DESIGN.md b/DESIGN.md deleted file mode 100644 index 0d8c2f9..0000000 --- a/DESIGN.md +++ /dev/null @@ -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 [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 ` | 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 diff --git a/DOMAIN.md b/DOMAIN.md deleted file mode 100644 index 5b1bed5..0000000 --- a/DOMAIN.md +++ /dev/null @@ -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 [branch]` — create a new linked worktree -- `git worktree add -b ` — create with a new branch -- `git worktree remove ` — 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. diff --git a/README.md b/README.md deleted file mode 100644 index 9503861..0000000 --- a/README.md +++ /dev/null @@ -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. diff --git a/main b/main new file mode 160000 index 0000000..cd51baa --- /dev/null +++ b/main @@ -0,0 +1 @@ +Subproject commit cd51baa2c1ae7e5554e6796417a5950128190feb diff --git a/pi-worktree-design.md b/pi-worktree-design.md deleted file mode 100644 index 1cb53ec..0000000 --- a/pi-worktree-design.md +++ /dev/null @@ -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 [branch]` to create the linked worktree. -- If branch doesn't exist and `create_branch: true`, use `git worktree add -b ` to create a new branch. -- **Error handling**: - - If path already exists: refuse with "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 '' 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 '' has uncommitted changes. Stash or commit them first?" -- Run `git worktree remove ` 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 . 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. diff --git a/pi-worktree-implementation-plan.md b/pi-worktree-implementation-plan.md deleted file mode 100644 index e055c14..0000000 --- a/pi-worktree-implementation-plan.md +++ /dev/null @@ -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 [branch]`. -5. Handle errors with clear messages. - -**Error Handling**: -- Path exists: "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 `. -5. Handle errors with clear messages. - -**Error Handling**: -- Main repo: "Can't remove the main repository. Use 'git worktree prune' instead." -- Uncommitted changes: "Worktree '' 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 '' has uncommitted changes. Stash them first?" -- Target not found: "No worktree found at ''. 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(); // 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.