@senad-d/branchme 0.1.6 → 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,12 +1,12 @@
1
1
  # Project Definition Brief
2
2
 
3
- Approved on 2026-06-30.
3
+ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` package.
4
4
 
5
- ## 1. Bootstrap
5
+ ## 1. Bootstrap history
6
6
 
7
7
  - Template source: `/Users/senad/Documents/Code/Moj_git/pi-tmp`
8
8
  - Target directory: `/Users/senad/Documents/Code/Moj_git/pi-branchme`
9
- - Copy status: copied; target only had `.git/` and `.pi/`, both preserved/excluded.
9
+ - Copy status: copied; the target's existing `.git/` and `.pi/` directories were preserved and excluded from the copy.
10
10
 
11
11
  ## 2. Project identity
12
12
 
@@ -14,101 +14,136 @@ Approved on 2026-06-30.
14
14
  - Display name: `BranchMe`
15
15
  - Exported extension function: `branchMeExtension`
16
16
  - Repository URL: `https://github.com/senad-d/branchme`
17
- - One-sentence pitch: Minimal Pi tools for changing/creating current-repo branches, publishing the current branch, and opening a GitHub pull request.
17
+ - One-sentence pitch: Verified current-repository Pi tools for branch, linked-worktree, push, and GitHub pull request workflows.
18
+ - Tool count: eleven strict agent-callable tools.
18
19
 
19
20
  ## 3. Users and use cases
20
21
 
21
- - Primary users: Pi users and CI/GitHub Actions workflows.
22
+ - Primary users: Pi users, specialized Git subagents, orchestrators, and CI/GitHub Actions workflows.
22
23
  - Primary use cases:
23
- - Check current git branch/repo status.
24
- - Switch to an existing local branch after clean-worktree preflight.
25
- - Create and checkout a new branch from current `HEAD`.
24
+ - Inspect bounded current-repository branch, upstream, working-tree, related-PR, and recent-commit state.
25
+ - List the current repository's main and linked worktrees explicitly.
26
+ - Create and verify a linked worktree for a new branch from current `HEAD` or an unoccupied existing local branch.
27
+ - Return an exact, absolute, machine-readable worktree handoff for a caller-managed separate Pi session or subagent.
28
+ - Remove an exact verified linked worktree only when it is clean and contains no ignored entries, while retaining its local branch.
29
+ - Switch to an existing local branch after a clean-worktree preflight or create a new branch from current `HEAD`.
30
+ - Fetch a configured upstream tracking ref, fast-forward the current branch, or explicitly rebase it.
26
31
  - Push the current branch to its configured upstream, or publish it to `origin` when no upstream exists.
27
- - Create a PR in the current GitHub repo via REST API.
32
+ - Create a pull request in the resolved current GitHub repository through the REST API.
28
33
  - Non-goals:
29
- - No commit, staging, diff, or message generation behavior.
30
- - No GitHub CLI dependency.
31
- - No cross-repository PR creation.
32
- - No labels, reviewers, projects, or issue linking in v1.
34
+ - No staging, direct working-tree edits, user-authored commits, diff generation, stashing, resets, force pushes, or merge commits.
35
+ - No automatic Pi cwd changes, process/session creation, or copying of `.env` and other ignored/untracked files into linked worktrees.
36
+ - No GitHub CLI dependency or cross-repository pull requests.
37
+ - No labels, reviewers, projects, or issue-linking behavior.
33
38
 
34
39
  ## 4. Pi integration surface
35
40
 
36
41
  | Surface | Name | Purpose | Notes |
37
42
  | --- | --- | --- | --- |
38
- | Command | `/branchme` | Simple TUI config/status/help panel | No git/GitHub mutations |
39
- | Command | `/branchme help` | Workflow notes | No actions |
40
- | Tool | `branch_status` | Read current repo/branch/upstream/dirty/push state | Read-only |
41
- | Tool | `change_branch` | Switch to an existing local branch | Required `branchName`; rejects dirty worktrees |
42
- | Tool | `create_branch` | Create + checkout new branch from current `HEAD` | Required `branchName`; fail if exists/invalid |
43
- | Tool | `push_branch` | Push current branch with explicit upstream target; publish with upstream if needed | No commits/staging |
44
- | Tool | `pull_request` | Preflight branch visibility/commit state and create PR via GitHub REST API | Required `headBranch`, `baseBranch`, `title`, `body`, `draft`; repo inferred from current checkout |
45
- | Event | `session_start/session_shutdown` | Optional status footer cleanup | No long-lived resources |
46
- | UI | TUI panel | Compact BranchMe workflow/config view | No persisted config assumed |
47
- | Resource | none | No skills/prompts/themes planned | Keep package minimal |
43
+ | Command | `/branchme` | Compact TUI status and workflow panel | Informational; no Git or GitHub mutations |
44
+ | Command | `/branchme help` | Runtime requirements and workflow guidance | Informational; no actions |
45
+ | Tool | `branch_status` | Refresh bounded current-worktree Git and related-PR context | Read-only |
46
+ | Tool | `list_worktrees` | List bounded main/linked worktree inventory | Read-only and explicit |
47
+ | Tool | `create_worktree` | Create and verify a linked worktree | Exact absolute handoff cwd; new/existing local branch modes only |
48
+ | Tool | `remove_worktree` | Remove an exact verified clean linked worktree | Force-free; ignored entries block removal; branch retained |
49
+ | Tool | `change_branch` | Switch to an existing local branch | Rejects dirty worktrees |
50
+ | Tool | `fetch_branch` | Refresh the current branch's configured tracking ref | Explicit fetch refspec; no checkout change |
51
+ | Tool | `pull_branch` | Fast-forward the clean current branch | No rebase, merge commit, or autostash |
52
+ | Tool | `rebase_branch` | Rebase the clean current branch onto its upstream | Explicit history rewrite; automatic abort attempt on failure |
53
+ | Tool | `create_branch` | Create and check out a new branch from current `HEAD` | Fails when invalid or already present |
54
+ | Tool | `push_branch` | Push or publish the current branch | Explicit remote/refspec behavior |
55
+ | Tool | `pull_request` | Preflight branch state and create a GitHub pull request | Current repository only; autofill is opt-in |
56
+ | Event | `before_agent_start` | Append fresh bounded Git context to the system prompt | Read-only collection; no worktree inventory |
57
+ | UI | TUI panel | Compact BranchMe workflow/configuration view | Responsive and width-bounded |
58
+ | Resource | none | No bundled skills, prompts, or themes | Package remains extension-focused |
48
59
 
49
60
  ## 5. Architecture
50
61
 
51
- - Planned files:
62
+ - Implemented source layout:
52
63
  - `src/extension.ts`
53
64
  - `src/constants.ts`
65
+ - `src/types.ts`
66
+ - `src/redaction.ts`
67
+ - `src/git-context.ts`
54
68
  - `src/commands/branchme-command.ts`
55
69
  - `src/tools/branchme-tools.ts`
56
70
  - `src/git.ts`
57
71
  - `src/github.ts`
58
- - `src/types.ts`
72
+ - `src/ui/branchme-panel.ts`
59
73
  - Module boundaries:
60
- - Extension entrypoint only registers command/tools/events.
61
- - Git helper owns `pi.exec("git", args)` calls and branch/repo validation.
62
- - GitHub helper owns env token lookup, branch visibility/commit preflight, and REST requests.
63
- - Tools expose precise TypeBox schemas and structured details.
74
+ - The extension entry point registers the informational command, eleven tools, and automatic context hook.
75
+ - The context module owns bounded read-only collection, prompt formatting, and the `before_agent_start` hook.
76
+ - The command and UI modules own mode-safe informational help/status behavior and never invoke mutations.
77
+ - The tools module owns strict TypeBox schemas, descriptions, prompt metadata, bounded display content, and serializable result details.
78
+ - The Git helper owns argv-style current-repository inspection, branch/upstream workflows, worktree parsing/path validation/create/remove verification, and same-repository mutation serialization.
79
+ - The GitHub helper owns repository resolution, token/autofill configuration, related-PR lookup, branch visibility and commit preflight, and pull request REST calls.
80
+ - The redaction module owns shared credential redaction for display and prompt-bound metadata.
81
+ - Shared public details remain JSON-serializable and contain no runtime objects or abort signals.
64
82
  - Dependencies:
65
- - Pi core packages as peer deps with `"*"`.
66
- - `@earendil-works/pi-tui` is a peer/dev dependency because the TUI panel imports width and key utilities.
67
- - No Octokit; use Node 22 `fetch`.
68
-
69
- ## 6. Config, state, and persistence
70
-
71
- - Config source: no BranchMe config file; `/branchme` displays runtime status and workflow notes. GitHub tokens may come from process environment or a small regular `.env` fallback in the verified git root.
72
- - Session state: none; tool results include useful `details`.
73
- - Files written: none by extension code, except normal git metadata changes from branch checkout/push.
74
- - Cleanup behavior: clear any footer/status key on `session_shutdown` if used.
75
-
76
- ## 7. Security and privacy
77
-
78
- - Shell execution: only `git` via argv-style `pi.exec`, not shell strings.
79
- - File access/mutation: no working-tree file edits; git metadata changes only.
80
- - Network access: `pull_request` calls `https://api.github.com/repos/{owner}/{repo}/branches/{branch}` before `https://api.github.com/repos/{owner}/{repo}/pulls`.
81
- - Credentials/secrets: `GITHUB_TOKEN` / `GH_TOKEN` from process env or hardened local `.env` fallback; never log token.
82
- - Telemetry/retention: none.
83
- - User confirmations: no extra confirmation by default, to support automation; tools rely on explicit arguments.
84
-
85
- ## 8. Documentation and packaging
86
-
87
- - README changes: describe implemented behavior, workflow, tools, CI env usage.
88
- - SECURITY changes: document git mutation, GitHub API, token behavior.
89
- - CHANGELOG changes: rename initial unreleased entry to BranchMe.
90
- - package.json changes: set package identity/URLs/keywords/peer deps.
91
- - npm/git distribution plan: npm package `@senad-d/branchme`, repo `senad-d/branchme`.
92
-
93
- ## 9. Validation plan
83
+ - `@earendil-works/pi-coding-agent`, `@earendil-works/pi-ai`, `@earendil-works/pi-tui`, and `typebox` are direct peer/development dependencies; Pi peers use `"*"` for host compatibility.
84
+ - `@earendil-works/pi-ai` supplies `StringEnum` for the strict `create_worktree.branchMode` schema.
85
+ - `@earendil-works/pi-tui` supplies panel width and key utilities.
86
+ - Node 22 supplies `fetch`; BranchMe does not depend on Octokit or GitHub CLI.
87
+
88
+ ## 6. Configuration, state, and filesystem boundary
89
+
90
+ - Config source: no separate BranchMe config file. `GITHUB_TOKEN`, `GH_TOKEN`, and `BRANCHME_PR_AUTOFILL` use process-environment values first and may fall back to supported keys in a hardened regular `.env` file at the verified Git root.
91
+ - Session state: no persisted BranchMe state. Tool calls return serializable details, and mutation/PR coordination is in-memory only.
92
+ - Active-checkout mutations: explicit branch switching, creation, pull, and rebase operations can update Git metadata and working-tree files through Git. Push and fetch operations can update remote or remote-tracking refs through Git.
93
+ - Linked-worktree mutations: `create_worktree` can create a checkout directory outside the active checkout after canonical destination and repository-boundary validation. `remove_worktree` can recursively remove only an exact verified linked-worktree directory after clean and ignored-entry preflights.
94
+ - BranchMe does not directly edit project files, stage content, create user-authored commits, copy local-only files into new worktrees, delete the retained branch during removal, or mutate worktrees through slash commands.
95
+
96
+ ## 7. Worktree handoff contract
97
+
98
+ - `list_worktrees` reads bounded NUL-delimited porcelain inventory and keeps worktree discovery out of automatic active-worktree context.
99
+ - `create_worktree` requires an explicitly approved absolute destination whose immediate parent exists. It rejects existing destinations and locations inside registered worktrees or the repository's common Git directory.
100
+ - New mode creates a local branch from current `HEAD` only. Existing mode accepts only an existing local branch not checked out in another worktree; no remote branch is inferred.
101
+ - Before mutation, canonical cwd and branch identity must fit documented limits and remain unchanged by redaction, escaping, Unicode handling, or truncation.
102
+ - Successful creation verifies canonical path, local branch, full `HEAD`, and clean state, then returns the exact canonical absolute cwd and local branch in `handoff: { cwd, branch, head, ready: true, summary }`.
103
+ - Removal accepts only an exact fresh inventory match that is linked, present, unlocked, non-prunable, non-bare, branch-attached, and neither main nor current.
104
+ - Staged, unstaged, untracked, unmerged, and ignored entries all block removal. The bounded ignored-entry preflight does not disclose ignored paths or contents.
105
+ - Successful force-free removal verifies that the worktree entry is absent and the retained local branch still points to its captured commit, then returns `handoff: { cwd: null, branch: <exact retained branch>, head, ready: false, summary }`.
106
+ - BranchMe never returns a ready handoff containing `[REDACTED]`, escaped control sequences, or a BranchMe-introduced truncation ellipsis in machine-readable cwd or branch identity fields.
107
+
108
+ ## 8. Security and privacy
109
+
110
+ - Every Git command uses `pi.exec("git", args, { cwd, signal, timeout })` with an argv array rather than shell interpolation.
111
+ - Paths, branch names, Git output, commit subjects, and pull request metadata are treated as untrusted. Display and prompt surfaces are escaped, redacted, and bounded separately from prevalidated exact handoff identities.
112
+ - Worktree paths are canonicalized and checked against a fresh current-repository inventory or the common Git directory before mutation. User-supplied removal paths are never passed directly to Git.
113
+ - Worktree removal has no force path and rejects dirty, ignored-entry-containing, detached, locked, prunable/missing, bare, main, current, and foreign entries before mutation.
114
+ - Worktree tools expose no force, move, prune, repair, lock, unlock, detached, orphan, remote-inference, arbitrary refspec, or arbitrary start-point controls. Git's incomplete submodule worktree support is not bypassed with force cleanup.
115
+ - Automatic context and `branch_status` never collect diffs or file contents. Related-PR lookup may make a bounded authenticated GitHub request only when credentials and repository identity resolve; there is no unauthenticated fallback.
116
+ - `pull_request` uses the resolved current GitHub repository, preflights local and GitHub branch identity, and rejects cross-repository head refs. Git fetch/pull/push use the user's normal Git credentials.
117
+ - Tokens are resolved from supported process or verified-root `.env` keys and redacted from prompts, errors, content, and details. BranchMe collects no telemetry.
118
+ - Creation and removal require explicit user intent and an exact approved path. BranchMe does not silently infer worktree destinations or start a separate agent session.
119
+
120
+ ## 9. Documentation and packaging
121
+
122
+ - `README.md` is the primary public workflow and tool reference.
123
+ - `SECURITY.md` documents local filesystem, Git, GitHub, credential, and prompt-insertion boundaries.
124
+ - `docs/STRUCTURE.md` describes the implemented source and test layout.
125
+ - `docs/SMOKE_TEST.md` records isolated checkout, handoff, and installed-package smoke behavior.
126
+ - `CHANGELOG.md` tracks the active `0.1.8` unreleased changes.
127
+ - npm distribution uses package `@senad-d/branchme`; package-content checks exclude private specs, credentials, generated files, caches, and local state.
128
+
129
+ ## 10. Validation plan
94
130
 
95
131
  - Typecheck: `npm run typecheck`
96
- - Tests: unit and isolated integration tests for commands, tools, git/GitHub helpers, package metadata, and TUI captures.
97
- - Package dry-run: `npm run check:pack`
98
- - Formatting: `npm run format:check`
99
- - Full validation: `npm run validate`
100
- - Checkout Pi smoke test: `npm run smoke:pi` / `pi --no-extensions -e .`
101
- - Installed-artifact release smoke: `npm run smoke:pi:packed`
102
-
103
- ## 10. Open questions and assumptions
104
-
105
- - Questions:
106
- - None blocking.
107
- - Assumptions:
108
- - `/branchme` has no persisted config in v1.
109
- - `push_branch` uses `origin` when current branch has no upstream.
110
- - `pull_request` infers owner/repo from current GitHub checkout or `GITHUB_REPOSITORY`, but never accepts owner/repo as tool input and requires local branch refs with `headBranch` matching GitHub.
111
- - Decisions:
112
- - No commit functionality.
113
- - Tools perform all actions; slash commands are help/config only.
114
- - PR tool requires all PR fields explicitly.
132
+ - Formatting and documentation checks: `npm run format:check`
133
+ - Unit and isolated real-Git integration tests: `npm run test`
134
+ - Checkout Pi runtime/context smoke: `npm run smoke:pi`
135
+ - Isolated specialized-agent handoff smoke: `npm run smoke:worktree-handoff`
136
+ - Package dry-run/content boundary: `npm run check:pack`
137
+ - Complete checkout validation: `npm run validate`
138
+ - Installed-artifact smoke: `npm run smoke:pi:packed`
139
+ - Canonical local and automated release gate: `npm run release:check`
140
+
141
+ ## 11. Current decisions
142
+
143
+ - Slash commands remain informational; tools perform all Git and GitHub actions.
144
+ - Automatic context remains focused on the active worktree; inventory is available only through `list_worktrees`.
145
+ - `create_worktree` returns a verified target for a caller-managed session but does not change cwd or create processes.
146
+ - Worktree removal remains force-free, blocks ignored entries, and preserves the local branch.
147
+ - `push_branch` uses `origin` only when the current branch has no configured upstream.
148
+ - `pull_request` infers owner/repository from the current checkout or matching `GITHUB_REPOSITORY`, never accepts owner/repository tool inputs, and requires local branch refs with the head matching GitHub.
149
+ - Pull request fields remain explicit unless `BRANCHME_PR_AUTOFILL=true`; explicit values always take precedence.
@@ -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,12 +22,12 @@ 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, 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.
30
- 6. `src/github.ts` owns GitHub `owner/repo` parsing, repository boundary checks, `GITHUB_TOKEN`/`GH_TOKEN` process-env and hardened git-root `.env` fallback 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.
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
+ 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.
33
33
  9. `src/ui/branchme-panel.ts` renders a compact status panel and clips lines to terminal width.
@@ -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
- - `pull_request` requires `headBranch` and `baseBranch` to 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 missing, owner-prefixed, or unsafe branch refs before token lookup or the request.
60
- - `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.
61
- - BranchMe does not force checkout, stash, stage, create user-authored commits, reset, force-push, create merge commits, directly edit files, read non-token `.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.
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.
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.
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,10 +31,19 @@ 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.
37
45
  - For PRs: GitHub `origin` and `GITHUB_TOKEN` or `GH_TOKEN` (environment or `.env`).
46
+ - Optional: set `BRANCHME_PR_AUTOFILL=true` in the environment or `.env` to generate omitted PR fields.
38
47
  - `fetch_branch`, `pull_branch`, and `rebase_branch` require a configured upstream.
39
48
  - `pull_branch` and `rebase_branch` require a clean working tree.
40
49
  - `rebase_branch` rewrites local commits only when explicitly requested and auto-aborts on failure.
@@ -71,7 +80,7 @@ Width: 40
71
80
  │ │
72
81
  │ │
73
82
  ├──────────────────────────────────────┤
74
- │ 1/2 • status • current repository on…│
83
+ │ 1/3 • status • current repository on…│
75
84
  ╰──────────────────────────────────────╯
76
85
  ```
77
86
 
@@ -85,7 +94,7 @@ Width: 80
85
94
  ├─────────────────────┬────────────────────────────────────────────────────────┤
86
95
  │▶ Status │ STATUS │
87
96
  │ Workflow │ Current branch: feature/current │
88
- │ │ GitHub repository: senad-d/branchme │
97
+ │ Worktrees │ GitHub repository: senad-d/branchme │
89
98
  │ │ GitHub token: present │
90
99
  │ │ │
91
100
  │ │ │
@@ -93,7 +102,7 @@ Width: 80
93
102
  │ │ │
94
103
  │ │ │
95
104
  ├─────────────────────┴────────────────────────────────────────────────────────┤
96
- │ 1/2 • status • current repository only • tools perform actions │
105
+ │ 1/3 • status • current repository only • tools perform actions │
97
106
  ╰──────────────────────────────────────────────────────────────────────────────╯
98
107
  ```
99
108
 
@@ -106,16 +115,38 @@ Width: 80
106
115
  │ ↑↓ section • q quit • /branchme help │
107
116
  ├─────────────────────┬────────────────────────────────────────────────────────┤
108
117
  │ Status │ WORKFLOW │
109
- │▶ Workflow │ branch_status -> inspect │
110
- │ │ change_branch -> existing local │
111
- │ │ fetch_branch -> upstream remote │
112
- │ │ pull_branch -> fast-forward │
113
- │ │ rebase_branch -> onto upstream │
114
- │ │ create_branch -> from HEAD │
115
- │ │ push_branch -> current branch │
116
- │ │ 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
+ │ │ │
117
148
  ├─────────────────────┴────────────────────────────────────────────────────────┤
118
- │ 2/2 • workflow • inspect → change → fetch/pull/rebase → create → push → PR │
149
+ │ 3/3 • worktrees • create → handoff cwd → next session • remove retains branch│
119
150
  ╰──────────────────────────────────────────────────────────────────────────────╯
120
151
  ```
121
152
 
@@ -129,7 +160,7 @@ Width: 112
129
160
  ├──────────────────────┬───────────────────────────────────────────────────────────────────────┤
130
161
  │▶ Status │ STATUS │
131
162
  │ Workflow │ Current branch: main │
132
- │ │ GitHub repository: senad-d/BranchMe │
163
+ │ Worktrees │ GitHub repository: senad-d/BranchMe │
133
164
  │ │ GitHub token: not set │
134
165
  │ │ │
135
166
  │ │ │
@@ -137,7 +168,7 @@ Width: 112
137
168
  │ │ │
138
169
  │ │ │
139
170
  ├──────────────────────┴───────────────────────────────────────────────────────────────────────┤
140
- │ 1/2 • status • current repository only • tools perform actions │
171
+ │ 1/3 • status • current repository only • tools perform actions │
141
172
  ╰──────────────────────────────────────────────────────────────────────────────────────────────╯
142
173
  ```
143
174
 
@@ -160,7 +191,7 @@ Width: 50
160
191
  │ │
161
192
  │ │
162
193
  ├────────────────────────────────────────────────┤
163
- │ 1/2 • warning • Unable to resolve a GitHub rep…│
194
+ │ 1/3 • warning • Unable to resolve a GitHub rep…│
164
195
  ╰────────────────────────────────────────────────╯
165
196
  ```
166
197
 
@@ -174,7 +205,7 @@ Width: 80
174
205
  ├─────────────────────┬────────────────────────────────────────────────────────┤
175
206
  │▶ Status │ STATUS │
176
207
  │ Workflow │ Current branch: main │
177
- │ │ GitHub repository: warning: Repository boundary misma…│
208
+ │ Worktrees │ GitHub repository: warning: Repository boundary misma…│
178
209
  │ │ GitHub token: present │
179
210
  │ │ │
180
211
  │ │ │
@@ -182,7 +213,7 @@ Width: 80
182
213
  │ │ │
183
214
  │ │ │
184
215
  ├─────────────────────┴────────────────────────────────────────────────────────┤
185
- │ 1/2 • warning • Repository boundary mismatch: local origin resolves to senad…│
216
+ │ 1/3 • warning • Repository boundary mismatch: local origin resolves to senad…│
186
217
  ╰──────────────────────────────────────────────────────────────────────────────╯
187
218
  ```
188
219
 
@@ -196,7 +227,7 @@ Width: 72
196
227
  ├───────────────────┬──────────────────────────────────────────────────┤
197
228
  │▶ Status │ STATUS │
198
229
  │ Workflow │ Current branch: main │
199
- │ │ GitHub repository: senad-d/branchme │
230
+ │ Worktrees │ GitHub repository: senad-d/branchme │
200
231
  │ │ GitHub token: warning: Unable to read .env…│
201
232
  │ │ │
202
233
  │ │ │
@@ -204,7 +235,7 @@ Width: 72
204
235
  │ │ │
205
236
  │ │ │
206
237
  ├───────────────────┴──────────────────────────────────────────────────┤
207
- │ 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: …│
208
239
  ╰──────────────────────────────────────────────────────────────────────╯
209
240
  ```
210
241
 
@@ -218,7 +249,7 @@ Width: 72
218
249
  ├───────────────────┬──────────────────────────────────────────────────┤
219
250
  │▶ Status │ STATUS │
220
251
  │ Workflow │ Current branch: feature/super-long-branch-na…│
221
- │ │ GitHub repository: very-long-owner-name/very-lo…│
252
+ │ Worktrees │ GitHub repository: very-long-owner-name/very-lo…│
222
253
  │ │ GitHub token: present │
223
254
  │ │ │
224
255
  │ │ │
@@ -226,6 +257,6 @@ Width: 72
226
257
  │ │ │
227
258
  │ │ │
228
259
  ├───────────────────┴──────────────────────────────────────────────────┤
229
- │ 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…│
230
261
  ╰──────────────────────────────────────────────────────────────────────╯
231
262
  ```