@senad-d/branchme 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,21 @@
1
1
  # BranchMe Smoke Test Notes
2
2
 
3
- Date: 2026-07-15
3
+ Date: 2026-08-23
4
4
 
5
5
  Validated from the repository checkout with no discovered extensions enabled.
6
6
 
7
7
  ## Commands
8
8
 
9
9
  ```bash
10
- npm run validate
10
+ npm run typecheck
11
+ npm run format:check
12
+ npm run test
11
13
  npm run smoke:pi
12
- npm run smoke:pi:packed
13
14
  npm run check:pack
15
+ npm run smoke:worktree-handoff
16
+ npm run validate
17
+ npm run smoke:pi:packed
18
+ npm run release:check
14
19
  printf '/branchme help\n/quit\n' | pi --no-extensions -e .
15
20
  pi --no-extensions -e .
16
21
  ```
@@ -18,24 +23,29 @@ pi --no-extensions -e .
18
23
  ## Automated smoke behavior
19
24
 
20
25
  - `npm run smoke:pi` first runs isolated checkout Pi processes from a temporary non-Git working directory: one with `pi --no-extensions -e <package> -e <temporary verifier>` and `/branchmeverify verify`, then one with `pi --no-extensions -e <package>` and `/branchme help`.
21
- - The temporary command verifier calls `pi.getAllTools()` after BranchMe loads and confirms `branch_status`, `change_branch`, `fetch_branch`, `pull_branch`, `rebase_branch`, `create_branch`, `push_branch`, and `pull_request` are active runtime tools with strict schemas, prompt guidelines, descriptions, and extension source metadata.
26
+ - The temporary command verifier calls `pi.getAllTools()` after BranchMe loads and confirms `branch_status`, `change_branch`, `create_branch`, `create_worktree`, `fetch_branch`, `list_worktrees`, `pull_branch`, `pull_request`, `push_branch`, `rebase_branch`, and `remove_worktree` are each registered exactly once and active with strict schemas, named prompt guidelines, descriptions, and extension source metadata.
22
27
  - A second temporary verifier registers a deterministic local smoke model, blocks `fetch`, and runs normal prompts through real Pi lifecycle handling. It verifies automatic no-tool Git context in a temporary repository, one real `branch_status` tool refresh after a verifier-created local change, safe credential-free related-PR status with no request, and non-Git startup fallback.
28
+ - The Pi runtime smoke validates worktree tool registration, strict schemas, and prompt contracts only; it never creates or removes a worktree. Real-Git `list_worktrees`/`create_worktree`/`remove_worktree` lifecycle coverage runs under `npm run test` in temporary local repositories with sibling destinations under the same temporary root and no remotes.
29
+ - `npm run smoke:worktree-handoff` loads only BranchMe into a deterministic extension host backed by real local Git, creates a new-branch linked worktree through the registered `create_worktree` tool, and launches a separate Node verification process with the returned absolute `handoff.cwd`. That process verifies its cwd, branch, full `HEAD`, and lack of remotes. The smoke then calls the registered `remove_worktree` tool, verifies the directory is absent, and verifies the retained local branch remains at the original commit.
30
+ - The handoff smoke uses only a freshly created temporary source repository and sibling worktree, an empty Git config, a minimal credential-free environment, no remotes, offline Pi flags, and a fetch guard that fails on any network request. Cleanup recursively removes the isolated temporary root even on failure.
31
+ - `npm run validate` includes the isolated handoff smoke after package-content checks.
23
32
  - The checkout command smoke accepts either `/branchme help` text or the read-only BranchMe status fallback as equivalent non-mutating command output.
24
33
  - `npm run smoke:pi:packed` creates an npm tarball under a temporary directory, installs that tarball into a separate temporary package with `npm install --omit=dev`, and runs pi against the installed package instead of the source checkout.
25
- - `npm run smoke:pi:packed` is the release gate for packaged runtime imports and required packaged files; `npm run release:check` and `node scripts/publish-npm.mjs` run it before publish, while everyday `npm run validate` keeps the faster checkout smoke.
26
- - Both smoke runs disable discovered extensions, skills, prompt templates, themes, context files, persistent sessions, telemetry, startup network checks, and GitHub token environment variables.
27
- - Both smoke runs are credential-free, allow documented credential variable names in help text, reject credential value patterns, do not call BranchMe mutation tools, and do not contact GitHub.
28
- - Pi's documented `getAllTools()` metadata currently exposes parameter schemas and prompt guidelines, but not `promptSnippet`. The deterministic local smoke model exercises `branch_status` through Pi's normal model tool-call loop without provider or GitHub network access.
34
+ - `npm run release:check` is the canonical release gate: it runs `npm run validate` and then `npm run smoke:pi:packed`. Both `node scripts/publish-npm.mjs` and the GitHub `Publish to npm` workflow run it before npm publication; a packed install/load failure stops publication and the workflow's Git tag step. Everyday `npm run validate` keeps the faster checkout smoke.
35
+ - Both Pi smoke runs disable discovered extensions, skills, prompt templates, themes, context files, persistent sessions, telemetry, startup network checks, and GitHub token environment variables.
36
+ - Both Pi smoke runs are credential-free, allow documented credential variable names in help text, reject credential value patterns, do not call BranchMe mutation or remote tools, and do not contact GitHub.
37
+ - Pi's documented `getAllTools()` metadata exposes parameter schemas, descriptions, prompt guidelines, and source metadata, while command context exposes active `promptSnippet` values through `getSystemPromptOptions().toolSnippets`; the runtime verifier checks both surfaces. The deterministic local smoke model exercises `branch_status` through Pi's normal model tool-call loop without provider or GitHub network access.
29
38
  - Set `BRANCHME_SKIP_PI_SMOKE=1` to skip intentionally, or `BRANCHME_PI_BIN=/path/to/pi` to test a specific Pi binary for the checkout smoke.
30
39
  - If no Pi binary is available, the checkout smoke script prints an explicit skip message; default CI installs the Pi dev dependency, so `npm run validate` exercises the real Pi loading path.
31
40
 
32
41
  ## Result
33
42
 
34
- - `npm run validate` passed.
35
- - `npm run smoke:pi` loaded BranchMe through Pi, verified all eight BranchMe tools through the real `pi.getAllTools()` runtime surface, and confirmed non-mutating BranchMe command output.
43
+ - `npm run typecheck`, `npm run format:check`, `npm run test`, `npm run smoke:pi`, `npm run check:pack`, `npm run validate`, and `npm run smoke:pi:packed` passed.
44
+ - `npm run smoke:worktree-handoff` returned `ok: true`, an absolute ready cwd, the expected `feature/isolated-handoff-smoke` branch and full commit ID from a separate process, `branchRetained: true` after force-free removal, zero network requests, and an isolated empty credential source.
45
+ - `npm run smoke:pi` loaded BranchMe through Pi, verified the complete BranchMe tool set and prompt metadata through real Pi runtime APIs, and confirmed non-mutating BranchMe command output.
36
46
  - The isolated Git-context prompt smoke observed the `before_agent_start` snapshot, answered branch and dirty-tree state without a tool call, refreshed a verifier-created local change through one real `branch_status` call, returned safe unavailable context without credentials or outside Git, and attempted no network request.
37
47
  - `npm run smoke:pi:packed` packed BranchMe outside the repository, installed the artifact in a temporary production workspace, loaded the installed package through Pi, and confirmed non-mutating BranchMe command output.
38
- - `npm run check:pack` confirmed the package contents are limited to public docs, images, source, license, package metadata, `.env.example`, and `tsconfig.json`.
48
+ - `npm run check:pack` confirmed the package contents are limited to public docs (including worktree behavior and security boundaries), images, source, license, package metadata, `.env.example`, and `tsconfig.json`; private planning specs and generated files remain excluded.
39
49
  - The isolated Pi smoke command loaded BranchMe and displayed BranchMe help or status output instead of template behavior.
40
50
  - The bare `pi --no-extensions -e .` smoke command exited cleanly in this non-interactive validation environment.
41
51
  - No template command or template tool output was observed.
package/docs/STRUCTURE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # BranchMe Structure Guide
2
2
 
3
- BranchMe is a TypeScript Pi extension package for current-repository git branch fetch/update/rebase, push, and GitHub pull request workflows.
3
+ BranchMe is a TypeScript Pi extension package for current-repository Git branch, verified linked-worktree, push, and GitHub pull request workflows.
4
4
 
5
5
  ## Source layout
6
6
 
@@ -13,8 +13,8 @@ src/
13
13
  ├── commands/
14
14
  │ └── branchme-command.ts # /branchme status/help command; informational only
15
15
  ├── tools/
16
- │ └── branchme-tools.ts # registration for eight branch/GitHub workflow tools
17
- ├── git.ts # argv-style git helpers and per-repo workflow queue
16
+ │ └── branchme-tools.ts # registration for eleven branch/worktree/GitHub workflow tools
17
+ ├── git.ts # argv-style branch/worktree helpers and per-repo workflow queue
18
18
  ├── github.ts # GitHub repo resolution, env/.env tokens, branch preflight, REST calls, redaction
19
19
  └── ui/
20
20
  └── branchme-panel.ts # compact /branchme status panel renderer
@@ -22,11 +22,11 @@ src/
22
22
 
23
23
  ## Module boundaries
24
24
 
25
- 1. `src/extension.ts` stays small and registers the command, eight tools, and one `before_agent_start` context hook.
25
+ 1. `src/extension.ts` stays small and registers the command, eleven tools, and one `before_agent_start` context hook.
26
26
  2. `src/git-context.ts` owns the shared read-only collector, escaped/bounded formatter, automatic system-prompt append, and the current-state output used by `branch_status`.
27
27
  3. `src/commands/branchme-command.ts` parses `/branchme`, `/branchme help`, `--help`, and `-h`; it never performs git or GitHub mutations and avoids raw stdout in JSON mode.
28
- 4. `src/tools/branchme-tools.ts` owns TypeBox schemas, prompt metadata, tool content, and safe structured details. `branch_status` delegates to the shared context collector for an explicit refresh.
29
- 5. `src/git.ts` owns current-repository git behavior: root detection, branch/upstream/ahead-behind inspection, working-tree parsing, recent-commit collection, PR base/commit-subject inference, branch validation, branch creation, existing-local-branch switching, configured-upstream fetch, clean-worktree preflight, fast-forward-only current-branch pull, current-branch rebase with automatic abort on failure, current-branch push/publish, and the per-repository workflow queue.
28
+ 4. `src/tools/branchme-tools.ts` owns strict TypeBox schemas, prompt metadata, bounded tool content, and safe structured details. `branch_status` delegates to the shared context collector; `list_worktrees`, `create_worktree`, and `remove_worktree` expose explicit repository inventory and verified handoff operations.
29
+ 5. `src/git.ts` owns current-repository Git behavior: root and common-Git-directory detection, branch/upstream/ahead-behind inspection, working-tree parsing, recent-commit collection, PR base/commit-subject inference, branch validation and branch workflows, NUL-delimited worktree parsing/inventory, canonical worktree path validation, verified create/remove postconditions, and the per-repository workflow queue.
30
30
  6. `src/github.ts` owns GitHub `owner/repo` parsing, repository boundary checks, `GITHUB_TOKEN`/`GH_TOKEN` and `BRANCHME_PR_AUTOFILL` process-env/hardened git-root `.env` resolution, authenticated related-open-PR lookup, PR branch-name syntax validation, GitHub branch visibility/commit preflight, PR REST calls, bounded response validation, and redacted errors.
31
31
  7. `src/redaction.ts` owns shared credential redaction for Git, GitHub, and prompt-bound metadata.
32
32
  8. `src/types.ts` keeps serializable details shared by helpers, context, and tools.
@@ -36,11 +36,12 @@ src/
36
36
 
37
37
  - No long-lived processes, watchers, timers, sockets, or background jobs start in the extension factory.
38
38
  - A single `before_agent_start` handler synchronously collects a fresh snapshot for each agent run and appends it to the existing system prompt; failures degrade to bounded unavailable context rather than blocking startup.
39
- - Slash commands are informational; tools perform branch fetch/update/rebase, push, and PR actions. There is no context command.
40
- - Every tool uses a strict TypeBox object schema with `additionalProperties: false`.
39
+ - Slash commands are informational; tools perform branch, worktree, push, and PR actions. Commands never create/remove worktrees, change cwd, or start Pi sessions. There is no context command.
40
+ - Every tool uses a strict TypeBox object schema with `additionalProperties: false`; worktree creation requires exactly `worktreePath`, `branchName`, and `branchMode`, while listing is empty and removal accepts only `worktreePath`.
41
41
  - Every tool defines a description, `promptSnippet`, and tool-specific `promptGuidelines` that explicitly name the tool.
42
- - Git commands use `pi.exec("git", args, { cwd, signal, timeout })` with argv arrays; repository mutations run from the verified git root and same-repository mutation/PR windows are serialized per repository.
43
- - Tool details avoid token values and unbounded raw command/API output.
42
+ - Git commands use `pi.exec("git", args, { cwd, signal, timeout })` with argv arrays; repository mutations run from verified locations and same-repository mutation/PR windows are serialized per repository.
43
+ - Worktree results expose serializable requested and verified before/after state. Create returns `handoff: { cwd: <absolute>, branch, head, ready: true, summary }`; remove returns the retained branch/HEAD with `cwd: null` and `ready: false`.
44
+ - Tool details avoid token values, abort signals, runtime objects, and unbounded raw command/API output.
44
45
  - Automatic and explicit context include branch/upstream/ahead-behind state, working-tree counts, up to 20 unstaged/untracked entries, related open PR state, and up to 5 recent commits. Metadata values default to 512 characters and rendered context to 4,000 characters.
45
46
  - Pi core packages, including `@earendil-works/pi-tui` for key/width utilities, remain in `peerDependencies` with `"*"`.
46
47
 
@@ -55,10 +56,13 @@ src/
55
56
  - `pull_branch` requires a clean worktree and configured upstream, then updates only the current branch with an explicit `git pull --ff-only --no-rebase --no-autostash <remote> <remote-ref>` command; divergence fails without a rebase or merge commit.
56
57
  - `rebase_branch` requires a clean worktree and configured upstream, then rebases only the current branch with `git rebase --no-autostash --no-update-refs <upstream>`; it rewrites local commits and automatically attempts `git rebase --abort` on failure.
57
58
  - `create_branch` mutates local branch/HEAD only with `git switch -c`.
59
+ - `list_worktrees` reads a bounded `git worktree list --porcelain -z` inventory and remains explicit rather than expanding automatic active-worktree context.
60
+ - `create_worktree` requires an explicitly approved absolute destination, canonicalizes its existing parent, rejects existing or nested/common-Git-directory destinations, and creates only from current `HEAD` or an unoccupied existing local branch. It verifies canonical path, branch, `HEAD`, and cleanliness before returning a ready handoff.
61
+ - `remove_worktree` resolves an exact fresh current-repository inventory match, rejects main/current/dirty/ignored-entry-containing/detached/locked/prunable/missing/bare entries, runs a bounded removal-specific ignored-entry scan, performs force-free removal with the verified path, and confirms that the local branch remains at the same commit.
58
62
  - `push_branch` mutates remote refs only for the current branch and uses an explicit upstream remote/refspec instead of bare `git push` when an upstream exists.
59
63
  - `pull_request` requires resolved `headBranch` and `baseBranch` values to be distinct and exist locally, requires `headBranch` to match the GitHub-visible branch commit, queues behind already-started same-repository git mutation windows, makes GitHub REST API calls for the resolved current repository only, and rejects owner-prefixed or unsafe branch refs before the request. Omitted fields require configured autofill.
60
64
  - `pull_request` reads `GITHUB_TOKEN` or `GH_TOKEN` from process environment first; only when neither process token is set does it read those token keys from a small regular `.env` file in the verified git root as a fallback. `BRANCHME_PR_AUTOFILL` uses the same process-first, `.env`-fallback precedence and defaults off.
61
- - BranchMe does not force checkout, stash, stage, create user-authored commits, reset, force-push, create merge commits, directly edit files, read unsupported `.env` keys, follow unsafe `.env` file types, depend on GitHub CLI, or collect telemetry. Rebase-driven commit rewriting occurs only through explicit `rebase_branch` calls.
65
+ - BranchMe does not force checkout/removal, move/prune/repair/lock/unlock worktrees, create detached/orphan worktrees, infer remote worktree branches, copy ignored/untracked files such as `.env`, remove linked worktrees that contain ignored entries, delete retained worktree branches, change Pi's cwd, or start Pi sessions. It also does not stash, stage, create user-authored commits, reset, force-push, create merge commits, directly edit files, read unsupported `.env` keys, follow unsafe `.env` file types, depend on GitHub CLI, or collect telemetry. Git documents submodule worktree support as incomplete; BranchMe adds no force-based submodule cleanup.
62
66
 
63
67
  ## Documentation
64
68
 
@@ -73,11 +77,12 @@ src/
73
77
  test/
74
78
  ├── command.test.mjs # /branchme parsing, help, fallback, panel width
75
79
  ├── git-context.test.mjs # collection, prompt hook, formatting, safety, and output bounds
76
- ├── git.test.mjs # git helper command construction and failures
77
- ├── git-integration.test.mjs # isolated real-git context and branch helper coverage
80
+ ├── git.test.mjs # branch/worktree parsing, validation, command construction, postconditions, failures
81
+ ├── git-integration.test.mjs # isolated real-Git context, branch, and worktree lifecycle coverage
78
82
  ├── github.test.mjs # GitHub parsing, token resolution, related-PR lookup, redaction
79
83
  ├── preparation.test.mjs # package/docs/source metadata checks
80
- ├── tools.test.mjs # extension registration, schemas, shared refresh, tool behavior
84
+ ├── schema-validation.test.mjs # strict TypeBox schema validation, including worktree fields/modes
85
+ ├── tools.test.mjs # extension registration, prompt metadata, shared refresh, tool behavior
81
86
  └── tui-capture.test.mjs # generated text capture for TUI/help visual baselines
82
87
  ```
83
88
 
@@ -16,7 +16,7 @@ UPDATE_TUI_CAPTURE=1 node --test test/tui-capture.test.mjs
16
16
  ```text
17
17
  # BranchMe
18
18
 
19
- Current-repository branch workflow tools for Pi.
19
+ Current-repository Git workflow tools for Pi.
20
20
 
21
21
  Commands only show info; BranchMe tools perform actions.
22
22
 
@@ -31,6 +31,14 @@ Commands only show info; BranchMe tools perform actions.
31
31
  7. `push_branch` — push the current branch.
32
32
  8. `pull_request` — open a PR after `push_branch` completes and GitHub sees the branches.
33
33
 
34
+ ## Worktree handoff
35
+
36
+ - `list_worktrees` — inspect the main and linked worktrees in the current repository.
37
+ - `create_worktree` — create a linked worktree and return a ready handoff with an absolute `handoff.cwd`.
38
+ - A separate orchestrator starts the next Pi session or subagent in `handoff.cwd`.
39
+ - `remove_worktree` — remove a verified clean linked worktree while retaining its local branch.
40
+ - BranchMe does not change cwd, start Pi, copy `.env`, or remove branches automatically.
41
+
34
42
  ## Requirements
35
43
 
36
44
  - Run inside a Git repo with `git` available.
@@ -72,7 +80,7 @@ Width: 40
72
80
  │ │
73
81
  │ │
74
82
  ├──────────────────────────────────────┤
75
- │ 1/2 • status • current repository on…│
83
+ │ 1/3 • status • current repository on…│
76
84
  ╰──────────────────────────────────────╯
77
85
  ```
78
86
 
@@ -86,7 +94,7 @@ Width: 80
86
94
  ├─────────────────────┬────────────────────────────────────────────────────────┤
87
95
  │▶ Status │ STATUS │
88
96
  │ Workflow │ Current branch: feature/current │
89
- │ │ GitHub repository: senad-d/branchme │
97
+ │ Worktrees │ GitHub repository: senad-d/branchme │
90
98
  │ │ GitHub token: present │
91
99
  │ │ │
92
100
  │ │ │
@@ -94,7 +102,7 @@ Width: 80
94
102
  │ │ │
95
103
  │ │ │
96
104
  ├─────────────────────┴────────────────────────────────────────────────────────┤
97
- │ 1/2 • status • current repository only • tools perform actions │
105
+ │ 1/3 • status • current repository only • tools perform actions │
98
106
  ╰──────────────────────────────────────────────────────────────────────────────╯
99
107
  ```
100
108
 
@@ -107,16 +115,38 @@ Width: 80
107
115
  │ ↑↓ section • q quit • /branchme help │
108
116
  ├─────────────────────┬────────────────────────────────────────────────────────┤
109
117
  │ Status │ WORKFLOW │
110
- │▶ Workflow │ branch_status -> inspect │
111
- │ │ change_branch -> existing local │
112
- │ │ fetch_branch -> upstream remote │
113
- │ │ pull_branch -> fast-forward │
114
- │ │ rebase_branch -> onto upstream │
115
- │ │ create_branch -> from HEAD │
116
- │ │ push_branch -> current branch │
117
- │ │ pull_request -> after push │
118
+ │▶ Workflow │ branch_status -> inspect │
119
+ │ Worktrees │ change_branch -> existing local │
120
+ │ │ fetch_branch -> upstream remote │
121
+ │ │ pull_branch -> fast-forward │
122
+ │ │ rebase_branch -> onto upstream │
123
+ │ │ create_branch -> from HEAD │
124
+ │ │ push_branch -> current branch │
125
+ │ │ pull_request -> after push │
126
+ ├─────────────────────┴────────────────────────────────────────────────────────┤
127
+ │ 2/3 • workflow • inspect → change → fetch/pull/rebase → create → push → PR │
128
+ ╰──────────────────────────────────────────────────────────────────────────────╯
129
+ ```
130
+
131
+ ## Panel: Wide mode: Worktrees selected
132
+
133
+ Width: 80
134
+
135
+ ```text
136
+ ╭ BranchMe ───────────────────────────────────────────────────────── Worktrees ╮
137
+ │ ↑↓ section • q quit • /branchme help │
138
+ ├─────────────────────┬────────────────────────────────────────────────────────┤
139
+ │ Status │ WORKTREES │
140
+ │ Workflow │ list_worktrees -> inspect inventory │
141
+ │▶ Worktrees │ create_worktree -> ready handoff.cwd │
142
+ │ │ remove_worktree -> clean linked; branch retained │
143
+ │ │ │
144
+ │ │ │
145
+ │ │ │
146
+ │ │ │
147
+ │ │ │
118
148
  ├─────────────────────┴────────────────────────────────────────────────────────┤
119
- │ 2/2 • workflow • inspect → change → fetch/pull/rebase → create → push → PR │
149
+ │ 3/3 • worktrees • create → handoff cwd → next session • remove retains branch│
120
150
  ╰──────────────────────────────────────────────────────────────────────────────╯
121
151
  ```
122
152
 
@@ -130,7 +160,7 @@ Width: 112
130
160
  ├──────────────────────┬───────────────────────────────────────────────────────────────────────┤
131
161
  │▶ Status │ STATUS │
132
162
  │ Workflow │ Current branch: main │
133
- │ │ GitHub repository: senad-d/BranchMe │
163
+ │ Worktrees │ GitHub repository: senad-d/BranchMe │
134
164
  │ │ GitHub token: not set │
135
165
  │ │ │
136
166
  │ │ │
@@ -138,7 +168,7 @@ Width: 112
138
168
  │ │ │
139
169
  │ │ │
140
170
  ├──────────────────────┴───────────────────────────────────────────────────────────────────────┤
141
- │ 1/2 • status • current repository only • tools perform actions │
171
+ │ 1/3 • status • current repository only • tools perform actions │
142
172
  ╰──────────────────────────────────────────────────────────────────────────────────────────────╯
143
173
  ```
144
174
 
@@ -161,7 +191,7 @@ Width: 50
161
191
  │ │
162
192
  │ │
163
193
  ├────────────────────────────────────────────────┤
164
- │ 1/2 • warning • Unable to resolve a GitHub rep…│
194
+ │ 1/3 • warning • Unable to resolve a GitHub rep…│
165
195
  ╰────────────────────────────────────────────────╯
166
196
  ```
167
197
 
@@ -175,7 +205,7 @@ Width: 80
175
205
  ├─────────────────────┬────────────────────────────────────────────────────────┤
176
206
  │▶ Status │ STATUS │
177
207
  │ Workflow │ Current branch: main │
178
- │ │ GitHub repository: warning: Repository boundary misma…│
208
+ │ Worktrees │ GitHub repository: warning: Repository boundary misma…│
179
209
  │ │ GitHub token: present │
180
210
  │ │ │
181
211
  │ │ │
@@ -183,7 +213,7 @@ Width: 80
183
213
  │ │ │
184
214
  │ │ │
185
215
  ├─────────────────────┴────────────────────────────────────────────────────────┤
186
- │ 1/2 • warning • Repository boundary mismatch: local origin resolves to senad…│
216
+ │ 1/3 • warning • Repository boundary mismatch: local origin resolves to senad…│
187
217
  ╰──────────────────────────────────────────────────────────────────────────────╯
188
218
  ```
189
219
 
@@ -197,7 +227,7 @@ Width: 72
197
227
  ├───────────────────┬──────────────────────────────────────────────────┤
198
228
  │▶ Status │ STATUS │
199
229
  │ Workflow │ Current branch: main │
200
- │ │ GitHub repository: senad-d/branchme │
230
+ │ Worktrees │ GitHub repository: senad-d/branchme │
201
231
  │ │ GitHub token: warning: Unable to read .env…│
202
232
  │ │ │
203
233
  │ │ │
@@ -205,7 +235,7 @@ Width: 72
205
235
  │ │ │
206
236
  │ │ │
207
237
  ├───────────────────┴──────────────────────────────────────────────────┤
208
- │ 1/2 • warning • Unable to read .env file for GitHub token fallback: …│
238
+ │ 1/3 • warning • Unable to read .env file for GitHub token fallback: …│
209
239
  ╰──────────────────────────────────────────────────────────────────────╯
210
240
  ```
211
241
 
@@ -219,7 +249,7 @@ Width: 72
219
249
  ├───────────────────┬──────────────────────────────────────────────────┤
220
250
  │▶ Status │ STATUS │
221
251
  │ Workflow │ Current branch: feature/super-long-branch-na…│
222
- │ │ GitHub repository: very-long-owner-name/very-lo…│
252
+ │ Worktrees │ GitHub repository: very-long-owner-name/very-lo…│
223
253
  │ │ GitHub token: present │
224
254
  │ │ │
225
255
  │ │ │
@@ -227,6 +257,6 @@ Width: 72
227
257
  │ │ │
228
258
  │ │ │
229
259
  ├───────────────────┴──────────────────────────────────────────────────┤
230
- │ 1/2 • warning • This deliberately long status note is captured to de…│
260
+ │ 1/3 • warning • This deliberately long status note is captured to de…│
231
261
  ╰──────────────────────────────────────────────────────────────────────╯
232
262
  ```
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@senad-d/branchme",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "type": "module",
5
- "description": "Minimal Pi extension for current-repository git branch, push, and pull request workflows.",
5
+ "description": "Pi extension for verified current-repository Git branch, worktree, push, and pull request workflows.",
6
6
  "license": "MIT",
7
7
  "author": "Senad Dizdarević <112484166+senad-d@users.noreply.github.com>",
8
8
  "repository": {
@@ -21,6 +21,7 @@
21
21
  "branchme",
22
22
  "git",
23
23
  "git-branch",
24
+ "git-worktree",
24
25
  "git-workflow",
25
26
  "github",
26
27
  "github-pr",
@@ -52,10 +53,11 @@
52
53
  "test:coverage": "mkdir -p coverage && node --test --experimental-test-coverage --test-reporter=spec --test-reporter=lcov --test-reporter-destination=stdout --test-reporter-destination=coverage/lcov.info test/*.test.mjs",
53
54
  "smoke:pi": "node scripts/smoke-pi-runtime.mjs && node scripts/smoke-pi-git-context.mjs",
54
55
  "smoke:pi:packed": "node scripts/smoke-pi-installed-package.mjs",
55
- "check": "node --check scripts/check-format.mjs && node --check scripts/check-package-contents.mjs && node --check scripts/publish-npm.mjs && node --check scripts/smoke-pi-git-context.mjs && node --check scripts/smoke-pi-installed-package.mjs && node --check scripts/smoke-pi-runtime.mjs",
56
+ "smoke:worktree-handoff": "node scripts/smoke-worktree-handoff.mjs",
57
+ "check": "node --check scripts/check-format.mjs && node --check scripts/check-package-contents.mjs && node --check scripts/publish-npm.mjs && node --check scripts/smoke-pi-git-context.mjs && node --check scripts/smoke-pi-installed-package.mjs && node --check scripts/smoke-pi-runtime.mjs && node --check scripts/smoke-worktree-handoff.mjs",
56
58
  "pack:dry-run": "npm pack --dry-run --json",
57
59
  "check:pack": "node scripts/check-package-contents.mjs",
58
- "validate": "npm run typecheck && npm run format:check && npm run test && npm run smoke:pi && npm run check && npm run check:pack",
60
+ "validate": "npm run typecheck && npm run format:check && npm run test && npm run smoke:pi && npm run check && npm run check:pack && npm run smoke:worktree-handoff",
59
61
  "release:check": "npm run validate && npm run smoke:pi:packed"
60
62
  },
61
63
  "pi": {
@@ -65,13 +67,15 @@
65
67
  "image": "https://raw.githubusercontent.com/senad-d/BranchMe/main/img/demo.gif"
66
68
  },
67
69
  "peerDependencies": {
70
+ "@earendil-works/pi-ai": "*",
68
71
  "@earendil-works/pi-coding-agent": "*",
69
72
  "@earendil-works/pi-tui": "*",
70
73
  "typebox": "*"
71
74
  },
72
75
  "devDependencies": {
76
+ "@earendil-works/pi-ai": "^0.84.1",
73
77
  "@earendil-works/pi-coding-agent": "^0.84.1",
74
- "@earendil-works/pi-tui": "^0.80.2",
78
+ "@earendil-works/pi-tui": "^0.84.1",
75
79
  "@types/node": "^26.0.1",
76
80
  "typebox": "^1.2.18",
77
81
  "typescript": "^7.0.2"
@@ -25,7 +25,7 @@ export function getBranchMeHelpText(): string {
25
25
  return [
26
26
  "# BranchMe",
27
27
  "",
28
- "Current-repository branch workflow tools for Pi.",
28
+ "Current-repository Git workflow tools for Pi.",
29
29
  "",
30
30
  "Commands only show info; BranchMe tools perform actions.",
31
31
  "",
@@ -40,6 +40,14 @@ export function getBranchMeHelpText(): string {
40
40
  "7. `push_branch` — push the current branch.",
41
41
  "8. `pull_request` — open a PR after `push_branch` completes and GitHub sees the branches.",
42
42
  "",
43
+ "## Worktree handoff",
44
+ "",
45
+ "- `list_worktrees` — inspect the main and linked worktrees in the current repository.",
46
+ "- `create_worktree` — create a linked worktree and return a ready handoff with an absolute `handoff.cwd`.",
47
+ "- A separate orchestrator starts the next Pi session or subagent in `handoff.cwd`.",
48
+ "- `remove_worktree` — remove a verified clean linked worktree while retaining its local branch.",
49
+ "- BranchMe does not change cwd, start Pi, copy `.env`, or remove branches automatically.",
50
+ "",
43
51
  "## Requirements",
44
52
  "",
45
53
  "- Run inside a Git repo with `git` available.",
package/src/constants.ts CHANGED
@@ -9,6 +9,9 @@ export const PULL_BRANCH_TOOL_NAME = "pull_branch";
9
9
  export const REBASE_BRANCH_TOOL_NAME = "rebase_branch";
10
10
  export const PUSH_BRANCH_TOOL_NAME = "push_branch";
11
11
  export const PULL_REQUEST_TOOL_NAME = "pull_request";
12
+ export const LIST_WORKTREES_TOOL_NAME = "list_worktrees";
13
+ export const CREATE_WORKTREE_TOOL_NAME = "create_worktree";
14
+ export const REMOVE_WORKTREE_TOOL_NAME = "remove_worktree";
12
15
  export const PULL_REQUEST_AUTOFILL_ENV_NAME = "BRANCHME_PR_AUTOFILL";
13
16
 
14
17
  export const BRANCHME_TOOL_NAMES = [
@@ -20,6 +23,9 @@ export const BRANCHME_TOOL_NAMES = [
20
23
  REBASE_BRANCH_TOOL_NAME,
21
24
  PUSH_BRANCH_TOOL_NAME,
22
25
  PULL_REQUEST_TOOL_NAME,
26
+ LIST_WORKTREES_TOOL_NAME,
27
+ CREATE_WORKTREE_TOOL_NAME,
28
+ REMOVE_WORKTREE_TOOL_NAME,
23
29
  ] as const;
24
30
 
25
31
  export const GIT_STATUS_TIMEOUT_MS = 5_000;
@@ -28,6 +34,7 @@ export const GIT_FETCH_TIMEOUT_MS = 120_000;
28
34
  export const GIT_PULL_TIMEOUT_MS = 120_000;
29
35
  export const GIT_REBASE_TIMEOUT_MS = 120_000;
30
36
  export const GIT_PUSH_TIMEOUT_MS = 120_000;
37
+ export const GIT_WORKTREE_MUTATION_TIMEOUT_MS = 120_000;
31
38
  export const GITHUB_RELATED_PR_TIMEOUT_MS = 4_000;
32
39
 
33
40
  export const GIT_CONTEXT_RECENT_COMMIT_LIMIT = 5;
@@ -36,6 +43,11 @@ export const GIT_CONTEXT_VALUE_LIMIT_CHARS = 512;
36
43
  export const GIT_CONTEXT_SUMMARY_LIMIT_CHARS = 4_000;
37
44
  export const PULL_REQUEST_AUTOFILL_COMMIT_LIMIT = 20;
38
45
  export const PULL_REQUEST_AUTOFILL_SUBJECT_LIMIT_CHARS = 256;
46
+ export const GIT_WORKTREE_RAW_OUTPUT_LIMIT_BYTES = 128 * 1024;
47
+ export const GIT_WORKTREE_ENTRY_LIMIT = 100;
48
+ export const GIT_WORKTREE_PATH_LIMIT_CHARS = 4_096;
49
+ export const GIT_WORKTREE_REASON_LIMIT_CHARS = 512;
50
+ export const GIT_WORKTREE_SUMMARY_LIMIT_CHARS = 4_000;
39
51
 
40
52
  export const GITHUB_API_BASE_URL = "https://api.github.com";
41
53
  export const GITHUB_API_VERSION = "2022-11-28";