@senad-d/branchme 0.1.8 → 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.
package/CHANGELOG.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.8 - Unreleased
3
+ ## 0.1.9 - Unreleased
4
4
 
5
5
  - Implemented the `branchme` informational slash command with help aliases.
6
- - Added strict BranchMe tools: `branch_status`, `change_branch`, `fetch_branch`, `pull_branch`, `rebase_branch`, `create_branch`, `push_branch`, `pull_request`, `list_worktrees`, `create_worktree`, and `remove_worktree`.
7
- - Added argv-style git helpers for repository status, branch validation/creation/switching, clean-worktree preflight, upstream detection, configured-upstream fetch, fast-forward-only current-branch pull, current-branch rebase with automatic abort on failure, current-branch push/publish, and bounded NUL-delimited worktree discovery.
6
+ - Added twelve strict BranchMe tools: `branch_status`, `change_branch`, `fetch_branch`, `pull_branch`, `rebase_branch`, `integrate_branch`, `create_branch`, `push_branch`, `pull_request`, `list_worktrees`, `create_worktree`, and `remove_worktree`; merge-continuation tools are intentionally absent.
7
+ - Added argv-style git helpers for repository status, branch validation/creation/switching, clean-worktree preflight, upstream detection, configured-upstream fetch, fast-forward-only current-branch pull, current-branch rebase with automatic abort on failure, verified local branch integration, current-branch push/publish, and bounded NUL-delimited worktree discovery.
8
+ - Added `integrate_branch` for exact local source-to-target integration from a clean already-current target control worktree. It rejects branch-specific target merge options that could alter the fixed policy and supports already-integrated, fast-forward, verified normal merge-commit, and automatically aborted/restored conflict outcomes with before/after ref and ancestry proofs, while exposing no fetch, push, reset, merge-message, or continuation controls.
9
+ - Added optional targeted `branch_status.ancestry` verification for captured local source/target commits without changing automatic Git context.
8
10
  - Added verified linked-worktree creation for a new branch from current `HEAD` or an unoccupied existing local branch, returning a structured ready handoff with the exact canonical absolute cwd and local branch for a caller-managed separate agent session.
9
11
  - Added force-free removal for exact, verified, clean linked worktrees while preserving and re-verifying the local branch at its captured commit; main, current, dirty, ignored-entry-containing, detached, locked, prunable/missing, bare, and foreign worktrees are rejected.
10
12
  - Added canonical absolute-path and lossless-identity validation before worktree mutations, including existing-destination, nested-worktree, common-Git-directory, repository-membership, redaction, escaping, and truncation boundaries. BranchMe does not copy ignored/untracked files or start/switch Pi sessions.
@@ -12,5 +14,5 @@
12
14
  - Added opt-in `BRANCHME_PR_AUTOFILL` support for omitted PR fields, including current/default branch inference, bounded, Markdown-safe, and token-redacted title/body generation from commit subjects, and a non-draft default.
13
15
  - Added bounded automatic Git context before each agent run with branch/upstream state, working-tree counts and unstaged paths, authenticated related-open-PR lookup, and recent commits.
14
16
  - Expanded `branch_status` into a shared, explicit, read-only context refresh for state that may change during a run.
15
- - Added unit tests with mocked `pi.exec` and `fetch` for Git context collection and prompt safety, git and worktree helpers, GitHub helpers, command behavior, strict tool schemas, prompt metadata, and extension registration, plus isolated temporary-repository worktree lifecycle integration coverage.
16
- - Updated public documentation for automatic context behavior, authenticated lookup and prompt-insertion security boundaries, specialized Git-subagent worktree handoff, package structure, and validation commands.
17
+ - Added unit tests with mocked `pi.exec` and `fetch` for Git context collection and prompt safety, git, branch-integration and worktree helpers, GitHub helpers, command behavior, strict tool schemas, prompt metadata, and extension registration, plus isolated temporary-repository worktree and merge lifecycle coverage.
18
+ - Updated public documentation for automatic and targeted ancestry context, authenticated lookup and prompt-insertion security boundaries, specialized Git-subagent worktree handoff, verified branch integration, Git extension-point risk, conflict workflow, package structure, and validation commands.
package/README.md CHANGED
@@ -10,13 +10,13 @@
10
10
  </p>
11
11
 
12
12
  <p align="center">
13
- Current-repository branch, worktree, and pull request tools for <a href="https://pi.dev">pi</a>.
14
- <br />Inspect branch state, manage verified linked worktrees, update branches, push, and open GitHub PRs from pi prompts.
13
+ Current-repository branch, worktree, integration, and pull request tools for <a href="https://pi.dev">pi</a>.
14
+ <br />Inspect branch state, manage verified linked worktrees, update or integrate branches, push, and open GitHub PRs from pi prompts.
15
15
  </p>
16
16
 
17
17
  ---
18
18
 
19
- BranchMe is a Pi extension for safe branch and worktree workflow automation. Before each agent run, it appends a bounded, read-only snapshot of the current Git repository to the system prompt. It also adds an informational `/branchme` command and eleven agent-callable tools that refresh state, manage branches, inspect/create/remove linked worktrees, push the current branch, and create GitHub pull requests.
19
+ BranchMe is a Pi extension for safe branch and worktree workflow automation. Before each agent run, it appends a bounded, read-only snapshot of the current Git repository to the system prompt. It also adds an informational `/branchme` command and twelve agent-callable tools that refresh state, manage and integrate local branches, inspect/create/remove linked worktrees, push the current branch, and create GitHub pull requests.
20
20
 
21
21
  <table align="center">
22
22
  <tr>
@@ -33,11 +33,11 @@ BranchMe is a Pi extension for safe branch and worktree workflow automation. Bef
33
33
  - **Repository-scoped:** Git and GitHub operations resolve from the checkout where pi is running. Linked worktree directories may be outside that checkout, but must be verified members of the same repository.
34
34
  - **Explicit history rewrites:** `rebase_branch` runs only when explicitly requested, requires a clean current branch with an upstream, disables autostash and multi-ref updates, and automatically attempts to abort on failure.
35
35
  - **Verified worktree handoff:** `create_worktree` verifies path, branch, `HEAD`, and cleanliness before returning an absolute `handoff.cwd`; starting another Pi session or subagent there remains the caller's responsibility.
36
- - **Commit-safe:** context collection is read-only, and BranchMe never stages files, creates user-authored commits, generates commit messages, force-pushes, creates merge commits, resets, or edits files directly.
36
+ - **Commit-safe:** context collection is read-only, and BranchMe never stages files, creates user-authored commits, accepts or generates commit messages, force-pushes, resets, or edits files directly. An explicit `integrate_branch` call may let Git create its standard merge commit for divergent local histories.
37
37
  - **Strict tools:** tool schemas reject extra properties such as `force`, `stash`, `discard`, `owner`, `repo`, `path`, or `baseRef`; worktree tools accept only their documented fields.
38
38
  - **PR-ready:** create GitHub pull requests from existing local branches after verifying the `headBranch` matches GitHub and the base is visible. PR fields can stay explicit, or configured autofill can derive omitted fields from the current branch, default branch, and commit subjects.
39
39
 
40
- > **Security:** pi packages run with your full system permissions. BranchMe runs local `git` commands, may create or remove verified linked-worktree directories outside the active checkout, may make an automatic authenticated GitHub request to find a related open pull request, can update branches and remotes, and can create GitHub pull requests. Read [`SECURITY.md`](SECURITY.md).
40
+ > **Security:** pi packages run with your full system permissions. BranchMe runs local `git` commands, may create or remove verified linked-worktree directories outside the active checkout, may integrate local history, may make an automatic authenticated GitHub request to find a related open pull request, can update branches and remotes, and can create GitHub pull requests. Repository-configured hooks, merge drivers, filters, and signing policy remain active during integration and may run commands or contact networks outside BranchMe's direct argv guarantees. Read [`SECURITY.md`](SECURITY.md).
41
41
 
42
42
  ## Table of Contents
43
43
 
@@ -223,7 +223,7 @@ Commands are informational only. BranchMe actions are performed by agent-callabl
223
223
 
224
224
  | Tool | Schema | Behavior |
225
225
  | --- | --- | --- |
226
- | `branch_status` | `{}` | Explicitly refreshes the same bounded context used at agent start: repo root in structured details, branch/detached state, upstream and ahead/behind counts, working-tree counts and unstaged/untracked paths, related open PR, and recent commits. It is read-only. |
226
+ | `branch_status` | `{ "ancestry"?: { "sourceBranch": string, "targetBranch": string } }` | Explicitly refreshes the same bounded context used at agent start. An optional strict ancestry query captures both exact local branch HEADs and reports whether the source commit is an ancestor of the target commit. It is read-only; automatic Git context does not run ancestry queries. |
227
227
  | `list_worktrees` | `{}` | Runs a bounded, read-only inventory of the current repository's main and linked worktrees, including path, branch/detached state, `HEAD`, current/main, locked, prunable, and omitted-entry details. Automatic Git context does not include this inventory. |
228
228
  | `create_worktree` | `{ "worktreePath": string, "branchName": string, "branchMode": "new" \| "existing" }` | Creates and verifies a linked worktree at an explicitly approved absolute path. `new` creates a local branch from current `HEAD`; `existing` requires an existing local branch not checked out elsewhere. It returns a ready handoff with the exact canonical absolute cwd and local branch identity. |
229
229
  | `remove_worktree` | `{ "worktreePath": string }` | Force-free removal of an explicitly selected, verified clean linked worktree. It rejects the main/current, detached, locked, prunable/missing, dirty, ignored-file-containing, or foreign worktree and verifies that the local branch remains at the same commit. |
@@ -231,11 +231,12 @@ Commands are informational only. BranchMe actions are performed by agent-callabl
231
231
  | `fetch_branch` | `{}` | Requires a current branch with a configured upstream and runs `git fetch --no-tags --no-recurse-submodules <upstream-remote> <upstream-branch-ref>:<remote-tracking-ref>`; only that tracking ref is refreshed without changing local branches or working-tree files. |
232
232
  | `pull_branch` | `{}` | Requires a clean current branch with a configured upstream and runs `git pull --ff-only --no-rebase --no-autostash <upstream-remote> <upstream-branch-ref>`; divergence fails without rebasing or creating a merge commit. |
233
233
  | `rebase_branch` | `{}` | Requires a clean current branch with a configured upstream and runs `git rebase --no-autostash --no-update-refs <upstream>`; it rewrites local commits and automatically attempts `git rebase --abort` on failure. |
234
+ | `integrate_branch` | `{ "sourceBranch": string, "targetBranch": string }` | Integrates one exact existing local source branch into one distinct existing local target branch. The clean active control worktree must already have the target checked out. It returns `already_integrated`, `fast_forward`, `merge_commit`, or a `conflict` only after automatic abort and verified restoration. It never fetches or pushes. |
234
235
  | `create_branch` | `{ "branchName": string }` | Validates `branchName`, rejects existing local branches, and runs `git switch -c <branchName>` from current `HEAD`. |
235
236
  | `push_branch` | `{}` | Pushes the current branch to its configured upstream remote with an explicit `HEAD:<upstream-branch-ref>` refspec, or publishes it with `git push --set-upstream origin <currentBranch>` when no upstream exists. |
236
237
  | `pull_request` | `{ "headBranch"?: string, "baseBranch"?: string, "title"?: string, "body"?: string, "draft"?: boolean }` | Preflights GitHub branch visibility and verifies the GitHub `headBranch` commit matches the local branch, then creates a pull request in the resolved current repository. Omitted fields require `BRANCHME_PR_AUTOFILL=true`; branch refs must be distinct, exist locally, and cannot use `owner:branch`. |
237
238
 
238
- All schemas reject additional properties. `change_branch` never accepts `baseRef`, `force`, `stash`, `discard`, `create`, `owner`, `repo`, or path inputs. `fetch_branch`, `pull_branch`, and `rebase_branch` have strict empty schemas and never accept a branch, remote, refspec, force, autostash, or arbitrary rebase target. `create_worktree` requires exactly `worktreePath`, `branchName`, and `branchMode`; `remove_worktree` requires exactly `worktreePath`. No worktree tool accepts force, move, prune, repair, lock, unlock, detached, orphan, remote, refspec, or arbitrary start-point controls. `pull_request` never accepts `owner`, `repo`, or owner-prefixed branch refs; BranchMe resolves the repository from local `origin` and/or matching `GITHUB_REPOSITORY`.
239
+ All schemas reject additional properties. `change_branch` never accepts `baseRef`, `force`, `stash`, `discard`, `create`, `owner`, `repo`, or path inputs. `fetch_branch`, `pull_branch`, and `rebase_branch` have strict empty schemas and never accept a branch, remote, refspec, force, autostash, or arbitrary rebase target. `integrate_branch` requires exactly `sourceBranch` and `targetBranch`; it accepts no repository, path, remote, strategy, message, squash, signing, commit, continuation, abort, force, fetch, push, deletion, or worktree controls. `create_worktree` requires exactly `worktreePath`, `branchName`, and `branchMode`; `remove_worktree` requires exactly `worktreePath`. No worktree tool accepts force, move, prune, repair, lock, unlock, detached, orphan, remote, refspec, or arbitrary start-point controls. `pull_request` never accepts `owner`, `repo`, or owner-prefixed branch refs; BranchMe resolves the repository from local `origin` and/or matching `GITHUB_REPOSITORY`. `continue_merge` and `abort_merge` are not available.
239
240
 
240
241
  ---
241
242
 
@@ -254,7 +255,7 @@ Before each agent run, BranchMe appends an **Automatic Git Context** snapshot to
254
255
 
255
256
  Collection defaults are a 5-second timeout per local Git command, a 4-second related-PR lookup timeout, at most 512 characters per metadata value, and at most 4,000 characters for the rendered snapshot. GitHub response bodies are limited to 64 KiB. The formatter can further shorten values or omit entries to stay within the total limit.
256
257
 
257
- The snapshot is fresh at agent start but is not live. A fetch, branch switch, pull, rebase, commit, file change, push, or other mutation later in the same run can make it stale. `branch_status` performs an explicit current-state refresh through the same shared collector and remains read-only; it does not mutate files, Git state, or GitHub state.
258
+ The snapshot is fresh at agent start but is not live. A fetch, branch switch, pull, rebase, integration, commit, file change, push, or other mutation later in the same run can make it stale. `branch_status` performs an explicit current-state refresh through the same shared collector and remains read-only; it does not mutate files, Git state, or GitHub state. Its optional `ancestry` object requires exact `sourceBranch` and `targetBranch` fields together, captures both local branch commit IDs, and reports `isAncestor`. This targeted proof is explicit only: automatic Git context remains unchanged. Run it after `integrate_branch` completes, never in the same parallel tool batch.
258
259
 
259
260
  Related-PR metadata does not come from Git alone. When repository, branch, and credentials resolve, automatic collection and explicit `branch_status` may make an authenticated `GET /repos/{owner}/{repo}/pulls?state=open&head={owner}:{branch}&per_page=1` request. Without a token there is no unauthenticated fallback or GitHub request; the PR field is reported as unavailable while local Git context remains usable.
260
261
 
@@ -272,6 +273,37 @@ After push_branch completes, create a draft pull request from feature/docs-refre
272
273
  If pull request field autofill is enabled, after push_branch completes create a pull request and fill any details I did not provide.
273
274
  ```
274
275
 
276
+ ### Verified local branch integration
277
+
278
+ `integrate_branch` requires explicit intent and exactly two distinct existing local branch names: `sourceBranch` and `targetBranch`. The active Pi worktree is the control worktree; it must be clean, have no merge/rebase/cherry-pick/revert/sequencer operation in progress, and already have `targetBranch` checked out. BranchMe never switches to the target or infers one. A source checked out in another dirty linked worktree is allowed because integration reads only its committed local ref. Remote-only refs, commit IDs, paths, repositories, remotes, and owner-prefixed refs are rejected.
279
+
280
+ For a source not already reachable from the target, BranchMe runs this fixed normal-merge policy from the verified worktree root:
281
+
282
+ ```text
283
+ git -c rerere.enabled=false merge --ff --no-edit --no-autostash --no-rerere-autoupdate --no-overwrite-ignore refs/heads/<sourceBranch>
284
+ ```
285
+
286
+ This policy permits a fast-forward or lets Git create a standard two-parent merge commit for divergent histories. BranchMe does not create user-authored commits, accept a merge message, or expose strategy, squash, unrelated-history, signing, force, or commit controls. Before mutation, it rejects a non-empty `branch.<targetBranch>.mergeOptions` setting because those branch-specific defaults could silently change the fixed policy. Autostash is disabled, rerere is disabled so recorded resolutions are not applied or updated, and ignored files may not be overwritten. Repository-configured hooks, custom merge drivers, clean/smudge filters, and signing policy remain active; those Git extension points may execute arbitrary local commands or network operations under the user's identity.
287
+
288
+ The structured status is one of:
289
+
290
+ - `already_integrated`: no merge ran and both branch refs remained stable;
291
+ - `fast_forward`: the target advanced exactly to the captured source commit;
292
+ - `merge_commit`: Git created an exact normal two-parent merge whose parents are the captured prior target and source;
293
+ - `conflict`: bounded, exact repository-relative conflict paths were captured, `git merge --abort` succeeded, and repository identity, current target, exact source/target refs, clean state, and absence of operation state were verified.
294
+
295
+ All outcomes include captured before/after source and target commit IDs plus final source and prior-target ancestry proof. Failed non-conflict merges remain errors after cleanup. BranchMe uses no reset-based rollback; if abort or postcondition checks are inconclusive, or a ref moves unexpectedly, it reports that integration may have completed and tells the caller to inspect the repository before retrying.
296
+
297
+ The same-repository mutation queue covers preflight, merge, cleanup, and verification, but it exists only inside the current BranchMe process. It does not lock another Pi session or an external Git process. `integrate_branch` itself does not fetch, pull, push, delete branches, remove worktrees, start agents, ask questions, continue a merge, or resolve semantic conflicts. A Mission or other orchestrator may explicitly call it; after a verified `conflict`, that separate workflow decides whether to delegate analysis to an integration agent or ask the developer about semantic intent.
298
+
299
+ For an independent read-only proof after integration, call:
300
+
301
+ ```json
302
+ { "ancestry": { "sourceBranch": "feature/example", "targetBranch": "main" } }
303
+ ```
304
+
305
+ with `branch_status` only after `integrate_branch` has returned. Do not batch the calls.
306
+
275
307
  ### Linked worktree verification and handoff
276
308
 
277
309
  `create_worktree` requires a non-blank absolute path with no control characters. Its immediate parent must already be a directory. BranchMe resolves that parent to build a canonical destination, rejects any existing file, directory, or symlink there, and rejects destinations inside a registered worktree or the repository's common Git directory. Before mutation, the canonical path and local branch must be returnable without redaction, escaping, Unicode alteration, or truncation: canonical paths are limited to 4,096 characters and branch identities to 512 characters, and credential-like token text is rejected. A dirty source worktree is allowed because creation does not switch or overwrite it.
@@ -318,6 +350,7 @@ BranchMe operates only on the repository where pi is running:
318
350
  - `fetch_branch` requires a configured upstream, uses an explicit source-to-remote-tracking refspec with tags and submodule recursion disabled, and does not change local branches or working-tree files.
319
351
  - `pull_branch` requires a clean worktree and configured upstream, updates only the current branch with `git pull --ff-only --no-rebase --no-autostash`, and has no branch, remote, force, or rebase input.
320
352
  - `rebase_branch` requires a clean worktree and configured upstream, rewrites only the current branch onto the locally available upstream with autostash and multi-ref updates disabled, and automatically attempts to abort on failure.
353
+ - `integrate_branch` merges one captured local source ref into the already-current clean local target with the fixed policy documented above. It verifies repository identity, refs, ancestry, clean state, and cleanup without fetching or pushing.
321
354
  - `create_branch` creates from the current `HEAD` only and has no `baseRef` input.
322
355
  - `list_worktrees` is an explicit, read-only repository inventory; it is intentionally absent from automatic active-worktree context.
323
356
  - `create_worktree` may create a linked checkout outside the active checkout only after canonical path and current-repository boundary checks; dependent worktree calls must wait for its verified handoff.
@@ -326,7 +359,7 @@ BranchMe operates only on the repository where pi is running:
326
359
  - `pull_request` creates PRs only for the resolved current GitHub repository, requires resolved `headBranch` and `baseBranch` values to be distinct and exist locally, requires the GitHub `headBranch` commit to match the local branch, queues behind in-flight same-repository git mutation windows when possible, and rejects `owner:branch` head refs. Missing PR fields fail unless `BRANCHME_PR_AUTOFILL=true`.
327
360
  - If local `origin` and `GITHUB_REPOSITORY` both resolve but disagree, `pull_request` fails closed.
328
361
 
329
- BranchMe intentionally does **not** stage files, create user-authored commits, force checkout, stash changes, discard changes, force-push, create merge commits, edit files directly, copy ignored/untracked files between worktrees, delete branches during worktree removal, or generate commit messages. Rebase-driven commit rewriting occurs only through explicit `rebase_branch` calls.
362
+ BranchMe intentionally does **not** stage files, create user-authored commits, accept or generate commit messages, force checkout, stash changes, discard changes, force-push, reset, edit files directly, copy ignored/untracked files between worktrees, or delete branches during worktree removal. Rebase-driven rewriting occurs only through explicit `rebase_branch`; a Git-generated standard merge commit is possible only through explicit `integrate_branch` for divergent histories.
330
363
 
331
364
  ---
332
365
 
@@ -376,10 +409,14 @@ Ensure the token and Git credentials have permission for the branch and pull req
376
409
  | Existing worktree branch is occupied | Choose another existing local branch or remove its other linked checkout after cleaning it; BranchMe does not force multiple checkouts. |
377
410
  | Worktree removal rejected | Use `list_worktrees`, select a non-main/non-current linked worktree, and remove or preserve staged, unstaged, untracked, unmerged, and ignored files outside the checkout. Locked, detached, prunable/missing, bare, and foreign paths are not removable. |
378
411
  | Linked-worktree agent cannot find credentials | Pass credentials through the process environment. BranchMe does not copy repository-root `.env` or other ignored/untracked files. |
379
- | Dirty worktree before branch switch, pull, or rebase | Commit, stash, or discard changes outside BranchMe before using `change_branch`, `pull_branch`, or `rebase_branch`. |
412
+ | Dirty worktree before branch switch, pull, rebase, or integration | Commit, stash, or discard changes outside BranchMe before using `change_branch`, `pull_branch`, `rebase_branch`, or a target control worktree for `integrate_branch`. |
380
413
  | Fetch, pull, or rebase has no upstream | Configure the current branch upstream outside BranchMe, then retry the tool. |
381
414
  | Pull is not a fast-forward | Run `fetch_branch`, wait for it to complete, then explicitly run `rebase_branch` if rewriting local commits is intended; otherwise reconcile outside BranchMe. |
382
415
  | Rebase fails or conflicts | `rebase_branch` automatically attempts `git rebase --abort`. Inspect repository state before continuing if automatic cleanup also fails. |
416
+ | Integration target mismatch or missing local branch | Check out the exact local `targetBranch` in the active control worktree and ensure both distinct branch refs already exist locally; `integrate_branch` never switches, fetches, or accepts remote-only refs. |
417
+ | Integration rejects branch-specific merge options | Clear `branch.<targetBranch>.mergeOptions` outside BranchMe before retrying; options such as `--no-commit`, `--squash`, `--no-verify`, or a custom strategy would change the fixed policy. |
418
+ | Integration reports `conflict` | The initial merge was automatically aborted and exact restoration was verified. Use the returned conflict paths for separate analysis; BranchMe has no `continue_merge` tool and does not resolve semantic conflicts. |
419
+ | Integration is uncertain or cleanup fails | Inspect branch refs, `HEAD`, worktree status, and Git operation state manually before retrying. BranchMe does not use reset-based rollback. |
383
420
  | Push fails | Confirm the current branch is correct and your normal Git remote credentials can push. |
384
421
  | Related PR is unavailable | Set `GITHUB_TOKEN` or `GH_TOKEN` before starting pi if related-PR context is wanted. Without a token, BranchMe keeps local context and intentionally makes no unauthenticated GitHub request. |
385
422
  | PR auth fails | Set `GITHUB_TOKEN` or `GH_TOKEN` before starting pi, or copy `.env.example` to `.env` and fill in one token. |
@@ -388,7 +425,7 @@ Ensure the token and Git credentials have permission for the branch and pull req
388
425
  | PR branch does not exist locally | Create or fetch/check out the local `headBranch` and `baseBranch` branches first; BranchMe does not use remote-only or cross-repository PR refs. |
389
426
  | PR branch is not visible or is stale on GitHub | Run `push_branch`, wait for it to complete, then retry `pull_request`; do not batch `push_branch` and `pull_request` in the same assistant tool call. |
390
427
  | Repository mismatch | Make `origin` and `GITHUB_REPOSITORY` refer to the same `owner/repo`. |
391
- | Need a commit | Use BranchMe or normal git commands; BranchMe never commits. |
428
+ | Need a user-authored commit | Use CommitMe or normal Git commands. BranchMe does not stage files, accept commit messages, or create user-authored commits; only `integrate_branch` may let Git create a standard merge commit. |
392
429
  | Other extensions interfere | Test with `pi --no-extensions -e .`. |
393
430
 
394
431
  ---
@@ -403,7 +440,7 @@ npm run check:pack
403
440
  printf '/branchme help\n/quit\n' | pi --no-extensions -e .
404
441
  ```
405
442
 
406
- Validation covers TypeScript typechecking, formatting checks, automatic context collection and prompt injection, mocked GitHub lookup, isolated real-Git worktree lifecycle tests, package checks, checkout Pi runtime smoke, and package-content verification. The checkout smoke loads BranchMe through Pi, then uses a temporary verifier command to confirm all eleven BranchMe tools are visible through `pi.getAllTools()` with strict schemas and prompt metadata. Smoke-test notes are recorded in [`docs/SMOKE_TEST.md`](docs/SMOKE_TEST.md), and TUI/help captures are stored in [`docs/TUI_CAPTURE.md`](docs/TUI_CAPTURE.md).
443
+ Validation covers TypeScript typechecking, formatting checks, automatic context collection and prompt injection, mocked GitHub lookup, isolated real-Git worktree and branch-integration lifecycle tests, package checks, checkout Pi runtime smoke, and package-content verification. The checkout smoke loads BranchMe through Pi, then uses a temporary verifier command to confirm all twelve BranchMe tools are visible through `pi.getAllTools()` with strict schemas and prompt metadata, including `integrate_branch` and targeted `branch_status.ancestry`, with no merge-continuation tool. Smoke-test notes are recorded in [`docs/SMOKE_TEST.md`](docs/SMOKE_TEST.md), and TUI/help captures are stored in [`docs/TUI_CAPTURE.md`](docs/TUI_CAPTURE.md).
407
444
 
408
445
  Refresh TUI captures intentionally with:
409
446
 
package/SECURITY.md CHANGED
@@ -20,17 +20,24 @@ Implemented git mutations are limited to:
20
20
  - `fetch_branch`: `git fetch --no-tags --no-recurse-submodules <upstreamRemote> <upstreamBranchRef>:<remoteTrackingRef>` after validating the current branch's configured upstream target. The explicit destination is limited to that upstream's remote-tracking ref, so local branches and working-tree files are not changed.
21
21
  - `pull_branch`: `git pull --ff-only --no-rebase --no-autostash <upstreamRemote> <upstreamBranchRef>` for the clean current branch after validating its configured upstream target.
22
22
  - `rebase_branch`: `git rebase --no-autostash --no-update-refs <upstream>` for the clean current branch after validating its configured upstream target. It rewrites local commits and automatically attempts `git rebase --abort` without the cancelled caller signal if the rebase fails or is killed.
23
+ - `integrate_branch`: after rejecting a non-empty `branch.<targetBranch>.mergeOptions` setting, runs `git -c rerere.enabled=false merge --ff --no-edit --no-autostash --no-rerere-autoupdate --no-overwrite-ignore refs/heads/<sourceBranch>` from the verified clean control worktree, which must already have the distinct existing local `targetBranch` checked out. It uses normal merge semantics: no-op, fast-forward, or a Git-generated standard two-parent merge commit for divergent histories.
23
24
  - `push_branch`: `git push <upstreamRemote> HEAD:<upstreamBranchRef>` for the current branch when an upstream exists, or `git push --set-upstream origin <currentBranch>` when no upstream exists.
24
25
  - `create_worktree`: `git worktree add -b <branchName> <canonicalPath> HEAD` for a new local branch, or `git worktree add <canonicalPath> <existingLocalBranch>` for an existing unoccupied local branch, after destination and repository-boundary validation.
25
26
  - `remove_worktree`: `git worktree remove <verifiedCanonicalPath>` without force, only after fresh repository-membership, safety-state, path, tracked/untracked status, and ignored-entry checks. The local branch is retained and verified at the same commit.
26
27
 
27
- Before each agent run, BranchMe also runs bounded, read-only Git commands to collect branch/upstream/ahead-behind state, working-tree counts, up to 20 unstaged or untracked path entries, and up to 5 recent commits. The same collector runs when `branch_status` explicitly refreshes context. Collection does not run `fetch`, `switch`, `pull`, `rebase`, `push`, `add`, `commit`, or any other mutation, and it never reads diffs or file contents.
28
+ Before each agent run, BranchMe also runs bounded, read-only Git commands to collect branch/upstream/ahead-behind state, working-tree counts, up to 20 unstaged or untracked path entries, and up to 5 recent commits. The same collector runs when `branch_status` explicitly refreshes context. An explicit optional `branch_status.ancestry` query captures exact local source/target commit IDs and uses `git merge-base --is-ancestor` against those commits; automatic Git context never runs this query and remains unchanged. Collection does not run `fetch`, `switch`, `pull`, `rebase`, `merge`, `push`, `add`, `commit`, or any other mutation, and it never reads diffs or file contents.
28
29
 
29
- Branch switching, worktree creation/removal, fast-forward pulls, and successful rebases can update or remove filesystem content as normal Git behavior; fetch updates one validated remote-tracking ref without changing local branches or the working tree. Mutating operations for the same repository are serialized to avoid same-turn races. `pull_request` also uses the same repository queue around PR preflight and creation so it can wait behind an already-started same-repository mutation. BranchMe rejects dirty worktrees before `change_branch`, `pull_branch`, and `rebase_branch`, and rejects any staged, unstaged, untracked, unmerged, or ignored entry in a linked worktree before removal. It does not force checkout/removal, stash, stage files, create user-authored commits, reset, force-push, create merge commits, or edit files directly. Rebase-driven commit rewriting occurs only through an explicit `rebase_branch` call.
30
+ Branch switching, worktree creation/removal, fast-forward pulls, successful rebases, and branch integration can update or remove filesystem content as normal Git behavior; fetch updates one validated remote-tracking ref without changing local branches or the working tree. Mutating operations for the same repository are serialized to avoid same-turn races. `integrate_branch` holds one queue window across preflight, merge, cleanup, and final verification; `pull_request` uses the queue around PR preflight and creation. This in-memory queue is process-local: it does not lock other Pi sessions or external Git processes. Both integration refs are captured and re-verified; unexpected movement produces a bounded uncertain error with manual inspection guidance and no reset-based rollback.
31
+
32
+ BranchMe rejects a dirty control worktree before `change_branch`, `pull_branch`, `rebase_branch`, and `integrate_branch`, and rejects any staged, unstaged, untracked, unmerged, or ignored entry in a linked worktree before removal. Integration also rejects an existing merge, rebase, cherry-pick, revert, or sequencer state and any non-empty target-branch `mergeOptions` setting that could alter the fixed command policy. After merge execution begins, cleanup and post-mutation verification ignore caller cancellation and use their own bounded timeouts. A `conflict` result is returned only after exact repository-relative conflict paths are captured, `git merge --abort` succeeds, source and target refs are restored, repository/control-worktree identity is preserved, operation state is cleared, and the control worktree is clean. Failed non-conflict merges remain errors; inconclusive cleanup or verification is never reported as success.
33
+
34
+ BranchMe does not force checkout/removal, stash, stage files, create user-authored commits, accept commit messages, reset, force-push, or edit files directly. Rebase-driven rewriting occurs only through explicit `rebase_branch`. Explicit `integrate_branch` may let Git create its standard merge commit for divergent histories, but BranchMe exposes no strategy, squash, unrelated-history, signing, force, commit, `continue_merge`, or `abort_merge` control.
30
35
 
31
36
  ## Network behavior
32
37
 
33
- `fetch_branch`, `pull_branch`, and `push_branch` contact the configured Git remote through the user's normal Git transport and credentials. They do not use or inject `GITHUB_TOKEN` or `GH_TOKEN`. `rebase_branch` uses the locally available upstream ref and makes no network request.
38
+ `fetch_branch`, `pull_branch`, and `push_branch` contact the configured Git remote through the user's normal Git transport and credentials. They do not use or inject `GITHUB_TOKEN` or `GH_TOKEN`. `rebase_branch` and `integrate_branch` use locally available refs and BranchMe's direct commands do not fetch, pull, push, or otherwise contact a remote during those operations.
39
+
40
+ Git extension points are a separate trust boundary. `integrate_branch` preserves repository-configured hooks, custom merge drivers, clean/smudge filters, and signature policy; it does not pass `--no-verify`. Those configurations may execute arbitrary local commands or network operations under the user's identity. BranchMe's fixed argv and direct no-network guarantees cannot constrain those external effects.
34
41
 
35
42
  BranchMe's GitHub helpers use these REST API requests:
36
43
 
@@ -58,6 +65,8 @@ BranchMe operates on the current repository only.
58
65
  - `fetch_branch` accepts no parameters, resolves the current branch's configured upstream remote and branch, constructs a source-to-remote-tracking refspec internally, disables tag fetching and submodule recursion, and does not prune or accept arbitrary refspecs.
59
66
  - `pull_branch` accepts no parameters, updates only the clean current branch from its configured upstream, and uses fast-forward-only semantics.
60
67
  - `rebase_branch` accepts no parameters, rebases only the clean current branch onto its configured upstream, disables autostash and multi-ref updates, never pushes, and attempts to abort on failure.
68
+ - `integrate_branch` accepts exactly `sourceBranch` and `targetBranch`. Both must be distinct existing local refs in the current repository, and the active clean control worktree must already be on the target. Remote-only refs, full refs, commit IDs, paths, repository/remotes, owner-prefixed refs, and merge controls are rejected. A source branch may be checked out in another dirty linked worktree because only its captured committed ref is read.
69
+ - Targeted `branch_status.ancestry` accepts only a nested object containing both exact local branch names; it is read-only, must run after integration completes, and must not share the same parallel tool batch.
61
70
  - If local `origin` and `GITHUB_REPOSITORY` both resolve but disagree, PR creation and related-PR lookup fail closed.
62
71
  - Resolved PR branches are validated as distinct, existing local branch-name refs; identical or missing local branches and cross-repository `head` values are rejected before any GitHub request.
63
72
  - PR branch inputs must also be visible on GitHub before the PR is created, and `headBranch` must match the local branch commit; unpublished or stale `headBranch` values fail with guidance to run `push_branch`, wait for it to complete, and retry `pull_request`.
@@ -89,7 +98,7 @@ A newly created linked worktree does not receive the source checkout's `.env` or
89
98
 
90
99
  Automatic context is appended to Pi's system prompt before each agent run. Branch names, paths, Git status values, commit subjects, and GitHub PR metadata are repository-controlled, untrusted data and must never be interpreted as instructions. BranchMe redacts recognized token values, escapes control and format characters, quotes metadata, limits individual values to 512 characters by default, and limits the complete rendered snapshot to 4,000 characters. It further shortens values or omits entries when needed to enforce the total bound.
91
100
 
92
- The automatic snapshot can become stale after a Git or filesystem mutation during the same run. `branch_status` is the explicit, read-only refresh path. Neither automatic collection nor `branch_status` captures diff hunks or file contents; staged paths are not listed, although the staged file count is included.
101
+ The automatic snapshot can become stale after a Git or filesystem mutation during the same run. `branch_status` is the explicit, read-only refresh path. Neither automatic collection nor `branch_status` captures diff hunks or file contents; staged paths are not listed, although the staged file count is included. Optional targeted ancestry details appear only when explicitly requested and are never added to automatic context.
93
102
 
94
103
  ## Telemetry
95
104
 
@@ -110,6 +119,7 @@ Do not open public issues for security-sensitive reports that include exploit de
110
119
  - Do not commit secrets, tokens, local `.env`, local `.pi/` state, or generated artifacts.
111
120
  - Keep tool schemas strict and reject unsupported fields.
112
121
  - Keep all git calls argv-style through `pi.exec("git", args)`.
122
+ - Preserve the fixed `integrate_branch` merge policy, verified automatic abort/restoration contract, and process-local queue caveat; never add reset-based rollback or merge-continuation controls.
113
123
  - Treat worktree paths as a filesystem security boundary; canonicalize them, verify current-repository membership before removal, and never add force cleanup.
114
124
  - Mock `pi.exec` and `fetch` in unit tests; use only temporary local repositories and directories for real-Git integration tests, and do not touch real remotes.
115
125
  - Keep package contents minimal with `npm run check:pack`.
@@ -1,6 +1,6 @@
1
1
  # Project Definition Brief
2
2
 
3
- Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` package.
3
+ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.9` package.
4
4
 
5
5
  ## 1. Bootstrap history
6
6
 
@@ -14,14 +14,15 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
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: Verified current-repository Pi tools for branch, linked-worktree, push, and GitHub pull request workflows.
18
- - Tool count: eleven strict agent-callable tools.
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.
19
19
 
20
20
  ## 3. Users and use cases
21
21
 
22
22
  - Primary users: Pi users, specialized Git subagents, orchestrators, and CI/GitHub Actions workflows.
23
23
  - Primary use cases:
24
- - Inspect bounded current-repository branch, upstream, working-tree, related-PR, and recent-commit state.
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.
25
26
  - List the current repository's main and linked worktrees explicitly.
26
27
  - Create and verify a linked worktree for a new branch from current `HEAD` or an unoccupied existing local branch.
27
28
  - Return an exact, absolute, machine-readable worktree handoff for a caller-managed separate Pi session or subagent.
@@ -31,7 +32,7 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
31
32
  - Push the current branch to its configured upstream, or publish it to `origin` when no upstream exists.
32
33
  - Create a pull request in the resolved current GitHub repository through the REST API.
33
34
  - Non-goals:
34
- - No staging, direct working-tree edits, user-authored commits, diff generation, stashing, resets, force pushes, or merge commits.
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.
35
36
  - No automatic Pi cwd changes, process/session creation, or copying of `.env` and other ignored/untracked files into linked worktrees.
36
37
  - No GitHub CLI dependency or cross-repository pull requests.
37
38
  - No labels, reviewers, projects, or issue-linking behavior.
@@ -42,7 +43,8 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
42
43
  | --- | --- | --- | --- |
43
44
  | Command | `/branchme` | Compact TUI status and workflow panel | Informational; no Git or GitHub mutations |
44
45
  | 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 | `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 |
46
48
  | Tool | `list_worktrees` | List bounded main/linked worktree inventory | Read-only and explicit |
47
49
  | Tool | `create_worktree` | Create and verify a linked worktree | Exact absolute handoff cwd; new/existing local branch modes only |
48
50
  | Tool | `remove_worktree` | Remove an exact verified clean linked worktree | Force-free; ignored entries block removal; branch retained |
@@ -68,14 +70,16 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
68
70
  - `src/commands/branchme-command.ts`
69
71
  - `src/tools/branchme-tools.ts`
70
72
  - `src/git.ts`
73
+ - `src/git-integration.ts`
71
74
  - `src/github.ts`
72
75
  - `src/ui/branchme-panel.ts`
73
76
  - Module boundaries:
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.
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.
76
79
  - The command and UI modules own mode-safe informational help/status behavior and never invoke mutations.
77
80
  - 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.
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.
79
83
  - The GitHub helper owns repository resolution, token/autofill configuration, related-PR lookup, branch visibility and commit preflight, and pull request REST calls.
80
84
  - The redaction module owns shared credential redaction for display and prompt-bound metadata.
81
85
  - Shared public details remain JSON-serializable and contain no runtime objects or abort signals.
@@ -88,10 +92,10 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
88
92
  ## 6. Configuration, state, and filesystem boundary
89
93
 
90
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.
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.
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.
93
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.
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.
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.
95
99
 
96
100
  ## 7. Worktree handoff contract
97
101
 
@@ -105,7 +109,18 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
105
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 }`.
106
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.
107
111
 
108
- ## 8. Security and privacy
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
109
124
 
110
125
  - Every Git command uses `pi.exec("git", args, { cwd, signal, timeout })` with an argv array rather than shell interpolation.
111
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.
@@ -114,19 +129,20 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
114
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.
115
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.
116
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.
117
133
  - Tokens are resolved from supported process or verified-root `.env` keys and redacted from prompts, errors, content, and details. BranchMe collects no telemetry.
118
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.
119
135
 
120
- ## 9. Documentation and packaging
136
+ ## 10. Documentation and packaging
121
137
 
122
138
  - `README.md` is the primary public workflow and tool reference.
123
139
  - `SECURITY.md` documents local filesystem, Git, GitHub, credential, and prompt-insertion boundaries.
124
140
  - `docs/STRUCTURE.md` describes the implemented source and test layout.
125
141
  - `docs/SMOKE_TEST.md` records isolated checkout, handoff, and installed-package smoke behavior.
126
- - `CHANGELOG.md` tracks the active `0.1.8` unreleased changes.
142
+ - `CHANGELOG.md` tracks the active `0.1.9` unreleased changes.
127
143
  - npm distribution uses package `@senad-d/branchme`; package-content checks exclude private specs, credentials, generated files, caches, and local state.
128
144
 
129
- ## 10. Validation plan
145
+ ## 11. Validation plan
130
146
 
131
147
  - Typecheck: `npm run typecheck`
132
148
  - Formatting and documentation checks: `npm run format:check`
@@ -138,11 +154,12 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
138
154
  - Installed-artifact smoke: `npm run smoke:pi:packed`
139
155
  - Canonical local and automated release gate: `npm run release:check`
140
156
 
141
- ## 11. Current decisions
157
+ ## 12. Current decisions
142
158
 
143
159
  - Slash commands remain informational; tools perform all Git and GitHub actions.
144
160
  - Automatic context remains focused on the active worktree; inventory is available only through `list_worktrees`.
145
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.
146
163
  - Worktree removal remains force-free, blocks ignored entries, and preserves the local branch.
147
164
  - `push_branch` uses `origin` only when the current branch has no configured upstream.
148
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.
@@ -23,9 +23,11 @@ pi --no-extensions -e .
23
23
  ## Automated smoke behavior
24
24
 
25
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`.
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.
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.
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.
29
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.
30
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.
31
33
  - `npm run validate` includes the isolated handoff smoke after package-content checks.
@@ -42,10 +44,10 @@ pi --no-extensions -e .
42
44
 
43
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.
44
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.
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.
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.
46
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.
47
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.
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.
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.
49
51
  - The isolated Pi smoke command loaded BranchMe and displayed BranchMe help or status output instead of template behavior.
50
52
  - The bare `pi --no-extensions -e .` smoke command exited cleanly in this non-interactive validation environment.
51
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, verified linked-worktree, 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 eleven branch/worktree/GitHub workflow tools
17
- ├── git.ts # argv-style branch/worktree 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,27 +23,28 @@ src/
22
23
 
23
24
  ## Module boundaries
24
25
 
25
- 1. `src/extension.ts` stays small and registers the command, eleven 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 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
- 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, 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
+ - 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 verified locations and same-repository mutation/PR windows are serialized per repository.
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.
43
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`.
44
46
  - Tool details avoid token values, abort signals, runtime objects, and unbounded raw command/API output.
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.
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.
46
48
  - Pi core packages, including `@earendil-works/pi-tui` for key/width utilities, remain in `peerDependencies` with `"*"`.
47
49
 
48
50
  ## Security-sensitive areas
@@ -50,11 +52,14 @@ src/
50
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.
51
53
  - Repository-controlled paths, branch names, commit subjects, and PR fields are escaped, quoted, redacted, bounded, and labeled untrusted before system-prompt insertion.
52
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.
53
- - 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.
54
56
  - `change_branch` mutates local HEAD and working-tree files only through `git switch <branchName>` for existing local branches after a clean-worktree preflight.
55
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.
56
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.
57
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.
58
63
  - `create_branch` mutates local branch/HEAD only with `git switch -c`.
59
64
  - `list_worktrees` reads a bounded `git worktree list --porcelain -z` inventory and remains explicit rather than expanding automatic active-worktree context.
60
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.
@@ -62,7 +67,7 @@ src/
62
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.
63
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.
64
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.
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.
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.
66
71
 
67
72
  ## Documentation
68
73
 
@@ -78,7 +83,7 @@ test/
78
83
  ├── command.test.mjs # /branchme parsing, help, fallback, panel width
79
84
  ├── git-context.test.mjs # collection, prompt hook, formatting, safety, and output bounds
80
85
  ├── 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
86
+ ├── git-integration.test.mjs # isolated real-Git context, branch integration, and worktree lifecycle coverage
82
87
  ├── github.test.mjs # GitHub parsing, token resolution, related-PR lookup, redaction
83
88
  ├── preparation.test.mjs # package/docs/source metadata checks
84
89
  ├── schema-validation.test.mjs # strict TypeBox schema validation, including worktree fields/modes