@senad-d/branchme 0.1.7 → 0.1.9

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.9` 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,153 @@ 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, integration, linked-worktree, push, and GitHub pull request workflows.
18
+ - Tool count: twelve 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, with an optional explicit local source/target ancestry proof.
25
+ - Integrate one exact existing local source branch into the already-current clean local target, returning verified no-op, fast-forward, merge-commit, or restored-conflict details.
26
+ - List the current repository's main and linked worktrees explicitly.
27
+ - Create and verify a linked worktree for a new branch from current `HEAD` or an unoccupied existing local branch.
28
+ - Return an exact, absolute, machine-readable worktree handoff for a caller-managed separate Pi session or subagent.
29
+ - Remove an exact verified linked worktree only when it is clean and contains no ignored entries, while retaining its local branch.
30
+ - Switch to an existing local branch after a clean-worktree preflight or create a new branch from current `HEAD`.
31
+ - Fetch a configured upstream tracking ref, fast-forward the current branch, or explicitly rebase it.
26
32
  - 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.
33
+ - Create a pull request in the resolved current GitHub repository through the REST API.
28
34
  - Non-goals:
29
- - No commit, staging, or diff generation behavior. Optional PR title/body autofill may summarize bounded commit subjects.
30
- - No GitHub CLI dependency.
31
- - No cross-repository PR creation.
32
- - No labels, reviewers, projects, or issue linking in v1.
35
+ - No staging, direct working-tree edits, user-authored commits, commit-message input/generation, diff generation, stashing, resets, or force pushes. Explicit `integrate_branch` may let Git create its standard merge commit for divergent histories.
36
+ - No automatic Pi cwd changes, process/session creation, or copying of `.env` and other ignored/untracked files into linked worktrees.
37
+ - No GitHub CLI dependency or cross-repository pull requests.
38
+ - No labels, reviewers, projects, or issue-linking behavior.
33
39
 
34
40
  ## 4. Pi integration surface
35
41
 
36
42
  | Surface | Name | Purpose | Notes |
37
43
  | --- | --- | --- | --- |
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 | PR fields are explicit by default and may be omitted only with configured autofill; 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 |
44
+ | Command | `/branchme` | Compact TUI status and workflow panel | Informational; no Git or GitHub mutations |
45
+ | Command | `/branchme help` | Runtime requirements and workflow guidance | Informational; no actions |
46
+ | Tool | `branch_status` | Refresh bounded current-worktree Git and related-PR context; optionally prove captured local-branch ancestry | Read-only; targeted ancestry is absent from automatic context |
47
+ | Tool | `integrate_branch` | Integrate one exact local source into the already-current clean local target | Fixed normal-merge policy; verified automatic abort/restoration on conflict |
48
+ | Tool | `list_worktrees` | List bounded main/linked worktree inventory | Read-only and explicit |
49
+ | Tool | `create_worktree` | Create and verify a linked worktree | Exact absolute handoff cwd; new/existing local branch modes only |
50
+ | Tool | `remove_worktree` | Remove an exact verified clean linked worktree | Force-free; ignored entries block removal; branch retained |
51
+ | Tool | `change_branch` | Switch to an existing local branch | Rejects dirty worktrees |
52
+ | Tool | `fetch_branch` | Refresh the current branch's configured tracking ref | Explicit fetch refspec; no checkout change |
53
+ | Tool | `pull_branch` | Fast-forward the clean current branch | No rebase, merge commit, or autostash |
54
+ | Tool | `rebase_branch` | Rebase the clean current branch onto its upstream | Explicit history rewrite; automatic abort attempt on failure |
55
+ | Tool | `create_branch` | Create and check out a new branch from current `HEAD` | Fails when invalid or already present |
56
+ | Tool | `push_branch` | Push or publish the current branch | Explicit remote/refspec behavior |
57
+ | Tool | `pull_request` | Preflight branch state and create a GitHub pull request | Current repository only; autofill is opt-in |
58
+ | Event | `before_agent_start` | Append fresh bounded Git context to the system prompt | Read-only collection; no worktree inventory |
59
+ | UI | TUI panel | Compact BranchMe workflow/configuration view | Responsive and width-bounded |
60
+ | Resource | none | No bundled skills, prompts, or themes | Package remains extension-focused |
48
61
 
49
62
  ## 5. Architecture
50
63
 
51
- - Planned files:
64
+ - Implemented source layout:
52
65
  - `src/extension.ts`
53
66
  - `src/constants.ts`
67
+ - `src/types.ts`
68
+ - `src/redaction.ts`
69
+ - `src/git-context.ts`
54
70
  - `src/commands/branchme-command.ts`
55
71
  - `src/tools/branchme-tools.ts`
56
72
  - `src/git.ts`
73
+ - `src/git-integration.ts`
57
74
  - `src/github.ts`
58
- - `src/types.ts`
75
+ - `src/ui/branchme-panel.ts`
59
76
  - 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.
77
+ - The extension entry point registers the informational command, twelve tools, and automatic context hook.
78
+ - The context module owns bounded read-only collection, prompt formatting, targeted ancestry rendering, and the `before_agent_start` hook; automatic context never runs ancestry queries.
79
+ - The command and UI modules own mode-safe informational help/status behavior and never invoke mutations.
80
+ - The tools module owns strict TypeBox schemas, descriptions, prompt metadata, bounded display content, and serializable result details.
81
+ - The general Git helper owns reusable argv-style current-repository inspection, branch/ref/ancestry and operation-state primitives, branch/upstream workflows, worktree parsing/path validation/create/remove verification, and process-local same-repository mutation serialization.
82
+ - The integration module owns the clean-control preflight, fixed merge mutation, automatic conflict abort, outcome classification, and repository/ref/worktree/ancestry verification without absorbing that state machine into the general helper.
83
+ - The GitHub helper owns repository resolution, token/autofill configuration, related-PR lookup, branch visibility and commit preflight, and pull request REST calls.
84
+ - The redaction module owns shared credential redaction for display and prompt-bound metadata.
85
+ - Shared public details remain JSON-serializable and contain no runtime objects or abort signals.
64
86
  - 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 separate BranchMe config file; `/branchme` displays runtime status and workflow notes. GitHub tokens and `BRANCHME_PR_AUTOFILL` 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
87
+ - `@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.
88
+ - `@earendil-works/pi-ai` supplies `StringEnum` for the strict `create_worktree.branchMode` schema.
89
+ - `@earendil-works/pi-tui` supplies panel width and key utilities.
90
+ - Node 22 supplies `fetch`; BranchMe does not depend on Octokit or GitHub CLI.
91
+
92
+ ## 6. Configuration, state, and filesystem boundary
93
+
94
+ - 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.
95
+ - Session state: no persisted BranchMe state. Tool calls return serializable details, and mutation/PR coordination is in-memory and process-local only; other Pi sessions and external Git processes are not locked.
96
+ - Active-checkout mutations: explicit branch switching, creation, pull, rebase, and integration operations can update Git metadata and working-tree files through Git. Push and fetch operations can update remote or remote-tracking refs through Git.
97
+ - 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.
98
+ - BranchMe does not directly edit project files, stage content, create user-authored commits, accept commit messages, copy local-only files into new worktrees, delete the retained branch during removal, or mutate worktrees through slash commands. `integrate_branch` may cause Git to create a standard merge commit under the verified boundary below.
99
+
100
+ ## 7. Worktree handoff contract
101
+
102
+ - `list_worktrees` reads bounded NUL-delimited porcelain inventory and keeps worktree discovery out of automatic active-worktree context.
103
+ - `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.
104
+ - 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.
105
+ - Before mutation, canonical cwd and branch identity must fit documented limits and remain unchanged by redaction, escaping, Unicode handling, or truncation.
106
+ - 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 }`.
107
+ - Removal accepts only an exact fresh inventory match that is linked, present, unlocked, non-prunable, non-bare, branch-attached, and neither main nor current.
108
+ - Staged, unstaged, untracked, unmerged, and ignored entries all block removal. The bounded ignored-entry preflight does not disclose ignored paths or contents.
109
+ - 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 }`.
110
+ - 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.
111
+
112
+ ## 8. Branch integration contract
113
+
114
+ - `integrate_branch` accepts exactly `sourceBranch` and `targetBranch`. They must identify distinct existing local refs in the current repository; remote-only refs, full refs, commit IDs, paths, repositories, remotes, and owner-prefixed refs are rejected.
115
+ - The active Pi worktree is the control worktree and must already have the target checked out, be clean, and have no merge/rebase/cherry-pick/revert/sequencer state. The source may be checked out in another dirty worktree because only its captured commit ref is read.
116
+ - Before mutation, BranchMe rejects a non-empty `branch.<targetBranch>.mergeOptions` setting so branch-specific defaults cannot change the policy. The fixed command is `git -c rerere.enabled=false merge --ff --no-edit --no-autostash --no-rerere-autoupdate --no-overwrite-ignore refs/heads/<sourceBranch>`. It does not fetch or push, disables autostash and rerere, protects ignored files, and preserves hooks, custom merge drivers, clean/smudge filters, and signing policy.
117
+ - Results distinguish `already_integrated`, `fast_forward`, `merge_commit`, and `conflict`. Before/after source and target commit IDs, repository/control-worktree identity, clean/operation state, and source/prior-target ancestry are verified. Merge-commit classification requires exact captured target/source parents.
118
+ - Conflict paths are exact bounded repository-relative identities. `conflict` is returned only after `git merge --abort` succeeds and exact ref, repository, branch, operation-state, and clean-worktree restoration is verified. Failed non-conflict merges remain errors.
119
+ - There is no reset-based rollback, `continue_merge`, `abort_merge`, custom merge message, strategy, squash, unrelated-history, signing, force, or commit control. Unexpected ref movement or inconclusive cleanup produces an uncertain error and manual inspection guidance.
120
+ - The mutation queue covers the complete operation but is process-local. BranchMe neither starts agents nor resolves semantic conflicts; Mission or another orchestrator may separately decide whether to delegate conflict analysis to an integration agent or ask the developer about intent.
121
+ - `branch_status` may receive `{ "ancestry": { "sourceBranch": string, "targetBranch": string } }` for an independent read-only proof. It must run after integration completes, not in the same parallel tool batch; automatic context remains unchanged.
122
+
123
+ ## 9. Security and privacy
124
+
125
+ - Every Git command uses `pi.exec("git", args, { cwd, signal, timeout })` with an argv array rather than shell interpolation.
126
+ - 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.
127
+ - 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.
128
+ - Worktree removal has no force path and rejects dirty, ignored-entry-containing, detached, locked, prunable/missing, bare, main, current, and foreign entries before mutation.
129
+ - 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.
130
+ - 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.
131
+ - `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.
132
+ - BranchMe's direct integration command is local-only, but repository-configured hooks, merge drivers, filters, and signing policy may execute arbitrary commands or network operations under the user's identity outside BranchMe's argv guarantees.
133
+ - Tokens are resolved from supported process or verified-root `.env` keys and redacted from prompts, errors, content, and details. BranchMe collects no telemetry.
134
+ - 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.
135
+
136
+ ## 10. Documentation and packaging
137
+
138
+ - `README.md` is the primary public workflow and tool reference.
139
+ - `SECURITY.md` documents local filesystem, Git, GitHub, credential, and prompt-insertion boundaries.
140
+ - `docs/STRUCTURE.md` describes the implemented source and test layout.
141
+ - `docs/SMOKE_TEST.md` records isolated checkout, handoff, and installed-package smoke behavior.
142
+ - `CHANGELOG.md` tracks the active `0.1.9` unreleased changes.
143
+ - npm distribution uses package `@senad-d/branchme`; package-content checks exclude private specs, credentials, generated files, caches, and local state.
144
+
145
+ ## 11. Validation plan
94
146
 
95
147
  - 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 unless `BRANCHME_PR_AUTOFILL=true`; explicit values always take precedence.
148
+ - Formatting and documentation checks: `npm run format:check`
149
+ - Unit and isolated real-Git integration tests: `npm run test`
150
+ - Checkout Pi runtime/context smoke: `npm run smoke:pi`
151
+ - Isolated specialized-agent handoff smoke: `npm run smoke:worktree-handoff`
152
+ - Package dry-run/content boundary: `npm run check:pack`
153
+ - Complete checkout validation: `npm run validate`
154
+ - Installed-artifact smoke: `npm run smoke:pi:packed`
155
+ - Canonical local and automated release gate: `npm run release:check`
156
+
157
+ ## 12. Current decisions
158
+
159
+ - Slash commands remain informational; tools perform all Git and GitHub actions.
160
+ - Automatic context remains focused on the active worktree; inventory is available only through `list_worktrees`.
161
+ - `create_worktree` returns a verified target for a caller-managed session but does not change cwd or create processes.
162
+ - `integrate_branch` is the only merge surface; it uses normal local merge semantics, automatically aborts initial conflicts, and exposes no merge continuation or semantic-resolution workflow.
163
+ - Worktree removal remains force-free, blocks ignored entries, and preserves the local branch.
164
+ - `push_branch` uses `origin` only when the current branch has no configured upstream.
165
+ - `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.
166
+ - 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,31 @@ 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.
22
- - 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.
26
+ - The temporary command verifier calls `pi.getAllTools()` after BranchMe loads and confirms exactly twelve tools—`branch_status`, `change_branch`, `create_branch`, `create_worktree`, `fetch_branch`, `integrate_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. It also proves `continue_merge` and `abort_merge` are absent.
27
+ - Runtime schema inspection verifies that `integrate_branch` has exactly the required `sourceBranch` and `targetBranch` fields. It also verifies that `branch_status` has only an optional top-level `ancestry` object whose required nested `sourceBranch` and `targetBranch` fields reject additional nested or top-level properties.
28
+ - 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. It expects all twelve tools but forbids `integrate_branch` and every remote or worktree mutation tool from executing.
29
+ - The Pi runtime smoke validates worktree and integration tool registration, strict schemas, and prompt contracts only; it never creates or removes a worktree and never runs a merge. Real-Git lifecycle coverage runs under `npm run test` in isolated temporary local repositories with no remote contact.
30
+ - Isolated real-Git integration tests cover `already_integrated`, `fast_forward`, exact two-parent `merge_commit`, and conflict-path capture followed by verified automatic abort/restoration. They also cover target mismatch, dirty control state, rejection of branch-specific target merge options, unrelated histories, ignored-file overwrite protection, preserved repository hooks, and a committed source ref checked out in another dirty linked worktree. The recorded merge argv proves autostash and rerere are disabled, ignored-file protection is enabled, and `--no-verify` is absent.
31
+ - `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.
32
+ - 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.
33
+ - `npm run validate` includes the isolated handoff smoke after package-content checks.
23
34
  - The checkout command smoke accepts either `/branchme help` text or the read-only BranchMe status fallback as equivalent non-mutating command output.
24
35
  - `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.
36
+ - `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.
37
+ - Both Pi smoke runs disable discovered extensions, skills, prompt templates, themes, context files, persistent sessions, telemetry, startup network checks, and GitHub token environment variables.
38
+ - 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.
39
+ - 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
40
  - 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
41
  - 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
42
 
32
43
  ## Result
33
44
 
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.
45
+ - `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.
46
+ - `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.
47
+ - `npm run smoke:pi` loaded BranchMe through Pi, verified exactly twelve BranchMe tools (including strict `integrate_branch` and nested `branch_status.ancestry` schemas), proved merge-continuation tools absent, and confirmed non-mutating BranchMe command output.
36
48
  - 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
49
  - `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`.
50
+ - `npm run check:pack` confirmed the package contents are limited to public docs (including worktree, local integration, and security boundaries), images, source, license, package metadata, `.env.example`, and `tsconfig.json`; private planning specs and generated files remain excluded.
39
51
  - The isolated Pi smoke command loaded BranchMe and displayed BranchMe help or status output instead of template behavior.
40
52
  - The bare `pi --no-extensions -e .` smoke command exited cleanly in this non-interactive validation environment.
41
53
  - 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 branch-integration, linked-worktree, push, and GitHub pull request workflows.
4
4
 
5
5
  ## Source layout
6
6
 
@@ -13,8 +13,9 @@ 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 twelve branch/integration/worktree/GitHub tools
17
+ ├── git.ts # shared argv-style Git primitives and per-repo mutation queue
18
+ ├── git-integration.ts # integration preflight, merge, cleanup, and verification state machine
18
19
  ├── github.ts # GitHub repo resolution, env/.env tokens, branch preflight, REST calls, redaction
19
20
  └── ui/
20
21
  └── branchme-panel.ts # compact /branchme status panel renderer
@@ -22,26 +23,28 @@ src/
22
23
 
23
24
  ## Module boundaries
24
25
 
25
- 1. `src/extension.ts` stays small and registers the command, eight tools, and one `before_agent_start` context hook.
26
+ 1. `src/extension.ts` stays small and registers the command, twelve tools, and one `before_agent_start` context hook.
26
27
  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
28
  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.
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
- 7. `src/redaction.ts` owns shared credential redaction for Git, GitHub, and prompt-bound metadata.
32
- 8. `src/types.ts` keeps serializable details shared by helpers, context, and tools.
33
- 9. `src/ui/branchme-panel.ts` renders a compact status panel and clips lines to terminal width.
29
+ 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 and optional ancestry verifier; `integrate_branch` delegates to the focused integration state machine; worktree tools expose explicit inventory and verified handoff operations.
30
+ 5. `src/git.ts` owns reusable current-repository Git primitives: root and canonical common-Git-directory identity, branch/ref validation, local commit ancestry, operation-state and working-tree inspection, branch/upstream workflows, worktree parsing/path validation/create/remove verification, and the process-local per-repository mutation queue.
31
+ 6. `src/git-integration.ts` owns the integration preflight, one-window merge mutation, conflict-path capture, automatic abort, outcome classification, and repository/ref/worktree/ancestry postcondition verification. It never fetches, pushes, resets, switches branches, or continues merges.
32
+ 7. `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.
33
+ 8. `src/redaction.ts` owns shared credential redaction for Git, GitHub, and prompt-bound metadata.
34
+ 9. `src/types.ts` keeps serializable details shared by helpers, context, and tools.
35
+ 10. `src/ui/branchme-panel.ts` renders a compact status panel and clips lines to terminal width.
34
36
 
35
37
  ## Pi extension conventions
36
38
 
37
39
  - No long-lived processes, watchers, timers, sockets, or background jobs start in the extension factory.
38
40
  - 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`.
41
+ - Slash commands are informational; tools perform branch, integration, worktree, push, and PR actions. Commands never create/remove worktrees, merge branches, change cwd, or start Pi sessions. There is no context command.
42
+ - Every tool uses a strict TypeBox object schema with `additionalProperties: false`; `integrate_branch` requires exactly `sourceBranch` and `targetBranch`, worktree creation requires exactly `worktreePath`, `branchName`, and `branchMode`, listing is empty, and removal accepts only `worktreePath`.
41
43
  - 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.
44
- - 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.
44
+ - 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. The queue is process-local and does not lock other Pi or Git processes.
45
+ - 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`.
46
+ - Tool details avoid token values, abort signals, runtime objects, and unbounded raw command/API output.
47
+ - 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. Explicit `branch_status` may additionally verify one strict local source/target ancestry query; automatic context never does. Metadata values default to 512 characters and rendered context to 4,000 characters.
45
48
  - Pi core packages, including `@earendil-works/pi-tui` for key/width utilities, remain in `peerDependencies` with `"*"`.
46
49
 
47
50
  ## Security-sensitive areas
@@ -49,16 +52,22 @@ src/
49
52
  - Automatic context and `branch_status` share bounded, read-only collection. They run no mutations and capture repository metadata only—never diffs or file contents.
50
53
  - Repository-controlled paths, branch names, commit subjects, and PR fields are escaped, quoted, redacted, bounded, and labeled untrusted before system-prompt insertion.
51
54
  - Related-PR lookup may issue an authenticated `GET /pulls` before every agent run and on explicit refresh. It has a 4-second timeout and 64 KiB response limit, and makes no unauthenticated fallback request.
52
- - The start-of-run snapshot may be stale after a mutation in that same run; `branch_status` is the explicit read-only refresh.
55
+ - The start-of-run snapshot may be stale after a mutation in that same run; `branch_status` is the explicit read-only refresh. Its optional targeted ancestry proof must run after `integrate_branch`, not in the same parallel tool batch.
53
56
  - `change_branch` mutates local HEAD and working-tree files only through `git switch <branchName>` for existing local branches after a clean-worktree preflight.
54
57
  - `fetch_branch` requires a configured upstream and runs `git fetch --no-tags --no-recurse-submodules <remote> <remote-ref>:<remote-tracking-ref>`; its explicit refspec updates only that tracking ref without changing local branches or working-tree files.
55
58
  - `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
59
  - `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.
60
+ - `integrate_branch` requires distinct existing local refs and a clean control worktree already on the target. It rejects non-empty target-branch `mergeOptions`, runs `git -c rerere.enabled=false merge --ff --no-edit --no-autostash --no-rerere-autoupdate --no-overwrite-ignore refs/heads/<sourceBranch>`, verifies before/after refs and ancestry, and classifies already-integrated, fast-forward, exact two-parent merge-commit, or conflict.
61
+ - Conflict status is emitted only after bounded lossless paths are captured, `git merge --abort` succeeds, and repository identity, exact refs, target checkout, absent operation state, and clean worktree restoration are verified. Failed or uncertain postconditions throw; no reset rollback or continuation tool exists.
62
+ - Git hooks, custom merge drivers, clean/smudge filters, and signing policy stay active during integration and may execute commands or network operations outside BranchMe's direct argv boundary.
57
63
  - `create_branch` mutates local branch/HEAD only with `git switch -c`.
64
+ - `list_worktrees` reads a bounded `git worktree list --porcelain -z` inventory and remains explicit rather than expanding automatic active-worktree context.
65
+ - `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.
66
+ - `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
67
  - `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
68
  - `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
69
  - `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.
70
+ - 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, accept commit messages, reset, force-push, directly edit files, read unsupported `.env` keys, follow unsafe `.env` file types, depend on GitHub CLI, or collect telemetry. Only explicit `integrate_branch` may let Git create a standard merge commit for divergent histories; it does not fetch, push, continue merges, or resolve semantic conflicts. Git documents submodule worktree support as incomplete; BranchMe adds no force-based submodule cleanup.
62
71
 
63
72
  ## Documentation
64
73
 
@@ -73,11 +82,12 @@ src/
73
82
  test/
74
83
  ├── command.test.mjs # /branchme parsing, help, fallback, panel width
75
84
  ├── 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
85
+ ├── git.test.mjs # branch/worktree parsing, validation, command construction, postconditions, failures
86
+ ├── git-integration.test.mjs # isolated real-Git context, branch integration, and worktree lifecycle coverage
78
87
  ├── github.test.mjs # GitHub parsing, token resolution, related-PR lookup, redaction
79
88
  ├── preparation.test.mjs # package/docs/source metadata checks
80
- ├── tools.test.mjs # extension registration, schemas, shared refresh, tool behavior
89
+ ├── schema-validation.test.mjs # strict TypeBox schema validation, including worktree fields/modes
90
+ ├── tools.test.mjs # extension registration, prompt metadata, shared refresh, tool behavior
81
91
  └── tui-capture.test.mjs # generated text capture for TUI/help visual baselines
82
92
  ```
83
93