@senad-d/branchme 0.1.8 → 0.2.0
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 +8 -5
- package/README.md +87 -14
- package/SECURITY.md +38 -4
- package/docs/PROJECT_DEFINITION_BRIEF.md +51 -17
- package/docs/SMOKE_TEST.md +10 -7
- package/docs/STRUCTURE.md +30 -18
- package/docs/TUI_CAPTURE.md +91 -32
- package/package.json +2 -2
- package/src/commands/branchme-command.ts +16 -2
- package/src/constants.ts +11 -0
- package/src/git-context.ts +81 -16
- package/src/git-integration.ts +673 -0
- package/src/git-retirement.ts +681 -0
- package/src/git.ts +313 -7
- package/src/tools/branchme-tools.ts +159 -4
- package/src/types.ts +191 -0
- package/src/ui/branchme-panel.ts +19 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.2.0 - 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 thirteen strict BranchMe tools: `branch_status`, `change_branch`, `fetch_branch`, `pull_branch`, `rebase_branch`, `integrate_branch`, `retire_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 `retire_branch` for explicit deletion of one exact unoccupied local branch ref after full expected-`HEAD` matching and captured target-ancestry verification. It uses `git update-ref --no-deref -d` with an expected-old-value lease, requires explicit force authorization for unmerged history, leaves branch configuration and remote/remote-tracking refs untouched, and reports uncertain postconditions for manual inspection without reset rollback.
|
|
10
|
+
- Added optional targeted `branch_status.ancestry` verification for captured local source/target commits without changing automatic Git context.
|
|
8
11
|
- 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
12
|
- 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
13
|
- 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 +15,5 @@
|
|
|
12
15
|
- 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
16
|
- 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
17
|
- 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
|
|
16
|
-
- Updated public documentation for automatic context
|
|
18
|
+
- Added unit tests with mocked `pi.exec` and `fetch` for Git context collection and prompt safety, git, branch-integration, branch-retirement, and worktree helpers, GitHub helpers, command behavior, strict tool schemas, prompt metadata, and extension registration, plus isolated temporary-repository worktree, merge, and leased local-ref retirement lifecycle coverage.
|
|
19
|
+
- Updated public documentation for automatic and targeted ancestry context, authenticated lookup and prompt-insertion security boundaries, specialized Git-subagent worktree handoff, verified branch integration and retirement, Git extension-point risk including `reference-transaction` hooks, conflict and uncertain-outcome workflows, 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,
|
|
13
|
+
Current-repository branch, worktree, integration, retirement, and pull request tools for <a href="https://pi.dev">pi</a>.
|
|
14
|
+
<br />Inspect branch state, manage verified linked worktrees, integrate or retire local 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
|
|
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 thirteen agent-callable tools that refresh state, manage, integrate, and retire 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,
|
|
37
|
-
- **Strict tools:** tool schemas reject
|
|
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
|
+
- **Strict tools:** tool schemas reject undocumented properties such as `stash`, `discard`, `owner`, `repo`, `path`, or `baseRef`; the only force decision is the required boolean on `retire_branch`, and every tool accepts only its 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 or retire one exact local branch ref, 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—including `reference-transaction` hooks invoked by retirement—merge drivers, filters, and signing policy 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
|
|
|
@@ -97,8 +97,9 @@ For isolated work, a specialized Git subagent can use the explicit worktree work
|
|
|
97
97
|
3. Wait for the result and require `details.handoff.ready === true`.
|
|
98
98
|
4. Have the caller or orchestrator start a **separate** Pi session or subagent with its working directory set to the returned absolute `details.handoff.cwd`.
|
|
99
99
|
5. After that session finishes, remove or preserve any staged, unstaged, untracked, unmerged, or ignored local files, then explicitly call `remove_worktree` if removal was requested. Removal retains the local branch.
|
|
100
|
+
6. If the user separately asks to retire that retained branch, obtain its fresh exact `HEAD`, verify it against an exact local target, and call `retire_branch` only after worktree removal has completed.
|
|
100
101
|
|
|
101
|
-
BranchMe does not change the active Pi process's cwd, start Pi or other processes, create sessions, copy `.env` or other ignored/untracked files, or
|
|
102
|
+
BranchMe does not change the active Pi process's cwd, start Pi or other processes, create sessions, copy `.env` or other ignored/untracked files, or automatically retire a branch when removing its worktree. For credentials needed by agents in linked worktrees, prefer process-level environment variables rather than copying repository-root secrets.
|
|
102
103
|
|
|
103
104
|
To refresh the current branch's configured remote-tracking ref without changing the local branch or working tree, use `fetch_branch`. To reconcile the clean current branch by rewriting its local commits, run `fetch_branch`, wait for it to complete, and then run `rebase_branch`. Both tools require a configured upstream; `rebase_branch` automatically attempts `git rebase --abort` if rebasing fails.
|
|
104
105
|
|
|
@@ -223,19 +224,21 @@ Commands are informational only. BranchMe actions are performed by agent-callabl
|
|
|
223
224
|
|
|
224
225
|
| Tool | Schema | Behavior |
|
|
225
226
|
| --- | --- | --- |
|
|
226
|
-
| `branch_status` | `{}` | Explicitly refreshes the same bounded context used at agent start
|
|
227
|
+
| `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
228
|
| `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
229
|
| `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
230
|
| `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
|
+
| `retire_branch` | `{ "branchName": string, "expectedHead": string, "targetBranch": string, "force": boolean }` | Deletes only the exact unoccupied local branch ref when its direct ref matches the supplied full commit ID and its relationship to the exact local target has been verified. Unmerged retirement requires explicit `force: true`; remote and remote-tracking refs are untouched. |
|
|
230
232
|
| `change_branch` | `{ "branchName": string }` | Validates `branchName`, requires `refs/heads/<branchName>` to exist locally, rejects dirty worktrees, and runs `git switch <branchName>`. |
|
|
231
233
|
| `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
234
|
| `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
235
|
| `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. |
|
|
236
|
+
| `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
237
|
| `create_branch` | `{ "branchName": string }` | Validates `branchName`, rejects existing local branches, and runs `git switch -c <branchName>` from current `HEAD`. |
|
|
235
238
|
| `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
239
|
| `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
240
|
|
|
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`.
|
|
241
|
+
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. `retire_branch` requires exactly `branchName`, a full 40- or 64-hex-character `expectedHead`, a distinct local `targetBranch`, and the boolean `force` decision; it accepts no repository, path, remote, refspec, pattern, branch list, prune, remote-delete, worktree-removal, or inferred-target control. `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
242
|
|
|
240
243
|
---
|
|
241
244
|
|
|
@@ -254,7 +257,7 @@ Before each agent run, BranchMe appends an **Automatic Git Context** snapshot to
|
|
|
254
257
|
|
|
255
258
|
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
259
|
|
|
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.
|
|
260
|
+
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
261
|
|
|
259
262
|
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
263
|
|
|
@@ -272,6 +275,37 @@ After push_branch completes, create a draft pull request from feature/docs-refre
|
|
|
272
275
|
If pull request field autofill is enabled, after push_branch completes create a pull request and fill any details I did not provide.
|
|
273
276
|
```
|
|
274
277
|
|
|
278
|
+
### Verified local branch integration
|
|
279
|
+
|
|
280
|
+
`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.
|
|
281
|
+
|
|
282
|
+
For a source not already reachable from the target, BranchMe runs this fixed normal-merge policy from the verified worktree root:
|
|
283
|
+
|
|
284
|
+
```text
|
|
285
|
+
git -c rerere.enabled=false merge --ff --no-edit --no-autostash --no-rerere-autoupdate --no-overwrite-ignore refs/heads/<sourceBranch>
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
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.
|
|
289
|
+
|
|
290
|
+
The structured status is one of:
|
|
291
|
+
|
|
292
|
+
- `already_integrated`: no merge ran and both branch refs remained stable;
|
|
293
|
+
- `fast_forward`: the target advanced exactly to the captured source commit;
|
|
294
|
+
- `merge_commit`: Git created an exact normal two-parent merge whose parents are the captured prior target and source;
|
|
295
|
+
- `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.
|
|
296
|
+
|
|
297
|
+
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.
|
|
298
|
+
|
|
299
|
+
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.
|
|
300
|
+
|
|
301
|
+
For an independent read-only proof after integration, call:
|
|
302
|
+
|
|
303
|
+
```json
|
|
304
|
+
{ "ancestry": { "sourceBranch": "feature/example", "targetBranch": "main" } }
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
with `branch_status` only after `integrate_branch` has returned. Do not batch the calls.
|
|
308
|
+
|
|
275
309
|
### Linked worktree verification and handoff
|
|
276
310
|
|
|
277
311
|
`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.
|
|
@@ -310,6 +344,35 @@ The full details also distinguish requested input from verified before/after sta
|
|
|
310
344
|
|
|
311
345
|
Ignored and untracked files—including a repository-root `.env`—are not copied into a new linked worktree. Prefer credentials inherited through the new agent process environment. Git documents support for multiple worktrees of a superproject containing submodules as incomplete; BranchMe adds no force-based submodule cleanup. There is no force, move, prune, repair, lock, unlock, detached, orphan, or remote-inference worktree behavior.
|
|
312
346
|
|
|
347
|
+
### Verified local branch retirement
|
|
348
|
+
|
|
349
|
+
`retire_branch` is a separate, explicit lifecycle step after integration and any linked-worktree removal. It accepts exactly:
|
|
350
|
+
|
|
351
|
+
```json
|
|
352
|
+
{
|
|
353
|
+
"branchName": "feature/example",
|
|
354
|
+
"expectedHead": "<full-40-or-64-hex-commit-id>",
|
|
355
|
+
"targetBranch": "main",
|
|
356
|
+
"force": false
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Obtain or supply a fresh exact `HEAD` for `branchName` and verify its ancestry against the exact local `targetBranch`; `branch_status.ancestry` can provide both captured commit IDs and the read-only proof. Run that refresh and `retire_branch` sequentially, never in the same parallel tool batch. The retiring and target names must be distinct direct local refs. Any registered worktree that names the retiring branch blocks deletion, including main, current, linked, locked, prunable, or missing records. Removing an occupying linked worktree is a separate explicit `remove_worktree` call; wait for its verified result before retirement.
|
|
361
|
+
|
|
362
|
+
Merged retirement uses `force: false`. If the retiring commit is not an ancestor of the captured target, retirement fails unless the user explicitly authorizes unmerged data loss with `force: true`. Forced unmerged retirement can remove that commit's last local branch reference. Object recovery is not guaranteed: normal reflog expiry and Git garbage collection can eventually make the commit unreachable.
|
|
363
|
+
|
|
364
|
+
After validating the expected commit, complete worktree inventory, target ancestry, and repository identity, BranchMe deletes only the exact local ref with an expected-old-value lease:
|
|
365
|
+
|
|
366
|
+
```text
|
|
367
|
+
git update-ref --no-deref -d refs/heads/<branchName> <capturedRetiringHead>
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
The captured commit lease prevents deletion if the retiring ref moves after preflight. BranchMe does not use `git branch -d` or `git branch -D` because those commands do not provide this expected-`HEAD` lease and their default merge target does not satisfy the explicit `targetBranch` contract. Retirement never performs bulk or pattern deletion, infers a target, removes a worktree, fetches, pushes, deletes a remote branch or local remote-tracking ref, or recreates/resets a ref as rollback. Local `branch.<branchName>.*` configuration remains untouched in the initial contract; it can affect a later branch recreated with the same name.
|
|
371
|
+
|
|
372
|
+
The retirement preflight, immediate reinspection, leased deletion, and postcondition verification share a process-local mutation-queue window keyed by the canonical active worktree root. That queue coordinates BranchMe mutations invoked from the same active checkout, but it does not lock another active worktree, Pi process, or external Git process. The expected-old-value lease protects the retiring ref; target and worktree checks detect other observable movement. After deletion is attempted, BranchMe verifies repository identity, target stability, local-ref absence, and zero occupancy without using a cancelled caller signal. Contradictory or inconclusive outcomes produce a bounded uncertain error stating retirement may have completed; inspect the repository, target ref, retiring ref, and complete worktree inventory manually before retrying. BranchMe does not automatically recreate, reset, switch, merge, or force-update a branch as rollback.
|
|
373
|
+
|
|
374
|
+
Repository-configured `reference-transaction` hooks can run during `git update-ref`. Such hooks are inside the repository trust boundary and can execute arbitrary commands or contact networks; that behavior is distinct from BranchMe's direct local-only, no-remote-delete argv contract.
|
|
375
|
+
|
|
313
376
|
BranchMe operates only on the repository where pi is running:
|
|
314
377
|
|
|
315
378
|
- Automatic collection and `branch_status` run bounded, read-only Git commands from the verified git root.
|
|
@@ -318,15 +381,17 @@ BranchMe operates only on the repository where pi is running:
|
|
|
318
381
|
- `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
382
|
- `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
383
|
- `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.
|
|
384
|
+
- `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
385
|
- `create_branch` creates from the current `HEAD` only and has no `baseRef` input.
|
|
322
386
|
- `list_worktrees` is an explicit, read-only repository inventory; it is intentionally absent from automatic active-worktree context.
|
|
323
387
|
- `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.
|
|
324
388
|
- `remove_worktree` passes Git only a freshly verified canonical linked-worktree path, never uses force, and retains the branch.
|
|
389
|
+
- `retire_branch` deletes only one exact unoccupied direct local ref with the supplied expected-`HEAD` lease after captured target ancestry verification; it leaves remote refs, remote-tracking refs, worktrees, and branch configuration untouched.
|
|
325
390
|
- `push_branch` pushes only the current branch, uses no bare upstream `git push`, and has no `branchName` input.
|
|
326
391
|
- `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
392
|
- If local `origin` and `GITHUB_REPOSITORY` both resolve but disagree, `pull_request` fails closed.
|
|
328
393
|
|
|
329
|
-
BranchMe intentionally does **not** stage files, create user-authored commits, force checkout, stash changes, discard changes, force-push,
|
|
394
|
+
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; one exact local ref can be deleted only through explicit `retire_branch` under the leased boundary above.
|
|
330
395
|
|
|
331
396
|
---
|
|
332
397
|
|
|
@@ -376,10 +441,18 @@ Ensure the token and Git credentials have permission for the branch and pull req
|
|
|
376
441
|
| 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
442
|
| 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
443
|
| 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
|
|
444
|
+
| 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
445
|
| Fetch, pull, or rebase has no upstream | Configure the current branch upstream outside BranchMe, then retry the tool. |
|
|
381
446
|
| 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
447
|
| Rebase fails or conflicts | `rebase_branch` automatically attempts `git rebase --abort`. Inspect repository state before continuing if automatic cleanup also fails. |
|
|
448
|
+
| 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. |
|
|
449
|
+
| 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. |
|
|
450
|
+
| 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. |
|
|
451
|
+
| 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. |
|
|
452
|
+
| Retirement expected `HEAD` is stale | Refresh the exact local branch commit and target ancestry, confirm the intended commit, then make a new sequential `retire_branch` call. Never reuse a stale commit identity. |
|
|
453
|
+
| Retirement branch is occupied | Remove the occupying linked worktree separately only after its own safety checks pass. Current, main, locked, prunable/missing, and any other registered occupancy block retirement. |
|
|
454
|
+
| Retirement rejects unmerged history | Preserve or integrate the commits, or obtain explicit user authorization for the data-loss risk before a separate call with `force: true`. |
|
|
455
|
+
| Retirement outcome is uncertain | Retirement may have completed. Manually inspect the repository identity, target ref, retiring local ref, and complete worktree inventory before retrying; do not recreate or reset a branch as automatic rollback. |
|
|
383
456
|
| Push fails | Confirm the current branch is correct and your normal Git remote credentials can push. |
|
|
384
457
|
| 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
458
|
| 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 +461,7 @@ Ensure the token and Git credentials have permission for the branch and pull req
|
|
|
388
461
|
| 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
462
|
| 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
463
|
| Repository mismatch | Make `origin` and `GITHUB_REPOSITORY` refer to the same `owner/repo`. |
|
|
391
|
-
| Need a commit | Use
|
|
464
|
+
| 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
465
|
| Other extensions interfere | Test with `pi --no-extensions -e .`. |
|
|
393
466
|
|
|
394
467
|
---
|
|
@@ -403,7 +476,7 @@ npm run check:pack
|
|
|
403
476
|
printf '/branchme help\n/quit\n' | pi --no-extensions -e .
|
|
404
477
|
```
|
|
405
478
|
|
|
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
|
|
479
|
+
Validation covers TypeScript typechecking, formatting checks, automatic context collection and prompt injection, mocked GitHub lookup, isolated real-Git worktree, branch-integration, and leased branch-retirement 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 thirteen BranchMe tools are visible through `pi.getAllTools()` with strict schemas and prompt metadata, including `integrate_branch`, `retire_branch`, and targeted `branch_status.ancestry`, with no merge-continuation tool. Runtime smoke inspects retirement registration and schema but never executes branch retirement. 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
480
|
|
|
408
481
|
Refresh TUI captures intentionally with:
|
|
409
482
|
|
package/SECURITY.md
CHANGED
|
@@ -20,17 +20,25 @@ 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.
|
|
27
|
+
- `retire_branch`: `git update-ref --no-deref -d refs/heads/<branchName> <capturedRetiringHead>` only for one exact unoccupied direct local ref whose commit matches the required full `expectedHead`. The exact local target commit and ancestry are captured first; unmerged retirement requires explicit `force: true` authorization.
|
|
26
28
|
|
|
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.
|
|
29
|
+
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
30
|
|
|
29
|
-
Branch switching, worktree creation/removal, fast-forward pulls,
|
|
31
|
+
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, and retirement deletes one verified local branch ref. 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; `retire_branch` holds one active-worktree-keyed window across preflight, immediate reinspection, leased deletion, and postcondition verification; `pull_request` uses the queue around PR preflight and creation. This in-memory queue is process-local: it coordinates BranchMe calls using the same active checkout but does not lock a different active worktree, another Pi process, or an external Git process. Integration refs are captured and re-verified. Retirement additionally uses an expected-old-value ref lease and rechecks its captured target and complete worktree occupancy. Unexpected or inconclusive movement produces a bounded uncertain error with manual inspection guidance and no reset-based rollback.
|
|
32
|
+
|
|
33
|
+
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. Retirement does not require an unrelated active worktree to be clean, but every registered worktree record is inspected and any occupancy of the retiring branch blocks deletion. 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 or retirement mutation begins, cleanup/postcondition inspection ignores caller cancellation and uses 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. After retirement is attempted, contradictory or inconclusive repository, target-ref, retiring-ref, or occupancy state is an uncertain error stating that retirement may have completed and requiring manual inspection before retry.
|
|
34
|
+
|
|
35
|
+
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. Explicit `retire_branch` is the only local branch-deletion surface; it has no bulk, pattern, inferred-target, remote-delete, remote-tracking-delete, automatic worktree-removal, or rollback-ref control.
|
|
30
36
|
|
|
31
37
|
## Network behavior
|
|
32
38
|
|
|
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`
|
|
39
|
+
`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`, `integrate_branch`, and `retire_branch` use locally available refs; BranchMe's direct retirement argv never fetches, pulls, pushes, or names a remote or remote-tracking ref for deletion.
|
|
40
|
+
|
|
41
|
+
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`. Retirement's `git update-ref` can invoke repository-configured `reference-transaction` hooks. Those configurations may execute arbitrary local commands, mutate other state, or contact networks under the user's identity. BranchMe's fixed argv, direct no-network contract, and direct no-remote-delete guarantees cannot constrain hook behavior.
|
|
34
42
|
|
|
35
43
|
BranchMe's GitHub helpers use these REST API requests:
|
|
36
44
|
|
|
@@ -54,10 +62,13 @@ BranchMe operates on the current repository only.
|
|
|
54
62
|
- `list_worktrees` is read-only and returns a bounded inventory collected from `git worktree list --porcelain -z`; automatic Git context remains focused on the active worktree.
|
|
55
63
|
- `create_worktree` accepts exactly `worktreePath`, `branchName`, and `branchMode` (`new` or `existing`). New mode uses current `HEAD` only; existing mode requires an existing local branch not checked out elsewhere and does not infer remote branches.
|
|
56
64
|
- `remove_worktree` accepts exactly `worktreePath`, requires an exact canonical match in a fresh current-repository inventory, removes no branch, and does not accept force.
|
|
65
|
+
- `retire_branch` accepts exactly `branchName`, a full 40- or 64-hex-character `expectedHead`, a distinct exact local `targetBranch`, and boolean `force`. Both names must resolve to direct local refs. Paths, repositories, remotes, remote-only or full refs, refspecs, patterns, arrays, inferred targets, worktree controls, and bulk deletion are rejected.
|
|
57
66
|
- `change_branch` accepts only `branchName` and never creates branches, checks out remote branches, forces, stashes, or discards changes.
|
|
58
67
|
- `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
68
|
- `pull_branch` accepts no parameters, updates only the clean current branch from its configured upstream, and uses fast-forward-only semantics.
|
|
60
69
|
- `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.
|
|
70
|
+
- `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.
|
|
71
|
+
- 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
72
|
- If local `origin` and `GITHUB_REPOSITORY` both resolve but disagree, PR creation and related-PR lookup fail closed.
|
|
62
73
|
- 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
74
|
- 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`.
|
|
@@ -72,6 +83,26 @@ Paths, branch names, lock/prune reasons, and Git output are untrusted metadata.
|
|
|
72
83
|
|
|
73
84
|
BranchMe does not copy ignored or untracked files, including repository-root `.env` files, into linked worktrees. If a caller creates ignored local files in a linked checkout, those files block removal until they are removed or preserved outside the checkout. Git documents support for multiple worktrees of a superproject containing submodules as incomplete; BranchMe does not add force-based submodule cleanup.
|
|
74
85
|
|
|
86
|
+
## Local branch-retirement boundary
|
|
87
|
+
|
|
88
|
+
`retire_branch` requires explicit intent to delete one exact local branch and exactly four fields: `branchName`, full commit identity `expectedHead`, distinct exact local `targetBranch`, and boolean `force`. Callers should obtain a fresh expected commit and captured target ancestry with `branch_status.ancestry` unless the exact commit is already supplied. The read-only proof and mutation run sequentially, and retirement runs by itself rather than beside another Git mutation.
|
|
89
|
+
|
|
90
|
+
Preflight resolves the canonical active worktree and common Git directory, requires both branch names to be existing direct `refs/heads/*` refs, and requires the retiring ref to match `expectedHead` case-insensitively. It captures both commit IDs, inspects the complete bounded NUL-delimited worktree inventory rather than the public display subset, and rejects the retiring branch if any registered record names it. Main, current, linked, locked, prunable, missing, and other registered occupancy all block retirement. Removing an occupying linked worktree is a separate explicit operation with its own safety contract; retirement never removes one automatically.
|
|
91
|
+
|
|
92
|
+
BranchMe checks `git merge-base --is-ancestor <retiringHead> <targetHead>` against the captured immutable commits. Negative ancestry is rejected unless `force` is exactly `true`, and force bypasses no identity, expected-`HEAD`, direct-ref, or occupancy check. Forced unmerged retirement can remove the commit's last local branch reference. Reflog-based or object recovery is not guaranteed, and normal Git expiry and garbage collection can eventually make the commit unreachable.
|
|
93
|
+
|
|
94
|
+
Deletion uses only:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
git update-ref --no-deref -d refs/heads/<branchName> <capturedRetiringHead>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The expected-old-value argument is an atomic lease on the retiring ref, so movement after preflight prevents deletion. BranchMe does not use `git branch -d` or `git branch -D`: neither supplies the required expected-`HEAD` lease, and their default merge target is not the explicit captured target required by this contract. The operation does not directly delete remote refs or local `refs/remotes/*` refs and has no bulk, wildcard, inferred-target, fetch, pull, push, prune, automatic worktree-removal, or arbitrary ref-update path.
|
|
101
|
+
|
|
102
|
+
One process-local queue window, keyed by the canonical active worktree root, covers preflight, immediate repository/ref/occupancy reinspection, deletion, and verification. This serializes BranchMe mutations invoked through that same active checkout only. It cannot lock a different active worktree, another Pi process, or an external Git process. The expected-old-value lease protects the retiring ref; target and worktree reinspection detect other observable concurrent movement. Once deletion is attempted, bounded final inspection continues without the caller's abort signal and verifies repository identity, target stability, retiring-ref absence, and zero occupancy. If those facts are contradictory or inconclusive, BranchMe throws a bounded uncertain error that says retirement may have completed and requires manual inspection before retrying. It never recreates, resets, switches, merges, or force-updates a branch as automatic rollback.
|
|
103
|
+
|
|
104
|
+
Only the local branch ref is deleted. Local `branch.<branchName>.*` configuration remains untouched because removing it would be a separate non-atomic mutation; those settings may affect a later branch recreated with the same name. Repository-configured `reference-transaction` hooks may run during `git update-ref` and remain part of the repository trust boundary. They can violate BranchMe's direct no-network/no-remote-delete expectations through arbitrary hook behavior, so sensitive repositories must review hook configuration separately.
|
|
105
|
+
|
|
75
106
|
## Credentials
|
|
76
107
|
|
|
77
108
|
Git fetch, pull, and push authentication is handled by the user's configured Git credential and transport setup. BranchMe never passes GitHub API tokens to Git commands.
|
|
@@ -89,7 +120,7 @@ A newly created linked worktree does not receive the source checkout's `.env` or
|
|
|
89
120
|
|
|
90
121
|
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
122
|
|
|
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.
|
|
123
|
+
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
124
|
|
|
94
125
|
## Telemetry
|
|
95
126
|
|
|
@@ -110,6 +141,9 @@ Do not open public issues for security-sensitive reports that include exploit de
|
|
|
110
141
|
- Do not commit secrets, tokens, local `.env`, local `.pi/` state, or generated artifacts.
|
|
111
142
|
- Keep tool schemas strict and reject unsupported fields.
|
|
112
143
|
- Keep all git calls argv-style through `pi.exec("git", args)`.
|
|
144
|
+
- 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.
|
|
145
|
+
- Preserve `retire_branch` expected-`HEAD` leasing, complete occupancy checks, exact target ancestry, explicit unmerged force authorization, local-only ref scope, cancellation-safe final inspection, and uncertain-error behavior; never add bulk, inferred, remote, remote-tracking, or automatic worktree deletion.
|
|
146
|
+
- Treat `reference-transaction` hooks as arbitrary repository-controlled code outside BranchMe's direct retirement argv guarantees.
|
|
113
147
|
- Treat worktree paths as a filesystem security boundary; canonicalize them, verify current-repository membership before removal, and never add force cleanup.
|
|
114
148
|
- 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
149
|
- 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.
|
|
3
|
+
Originally approved on 2026-06-30. Updated to describe the implemented `0.2.0` package.
|
|
4
4
|
|
|
5
5
|
## 1. Bootstrap history
|
|
6
6
|
|
|
@@ -14,25 +14,28 @@ 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:
|
|
17
|
+
- One-sentence pitch: Verified current-repository Pi tools for branch, integration, retirement, linked-worktree, push, and GitHub pull request workflows.
|
|
18
|
+
- Tool count: thirteen 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.
|
|
28
29
|
- Remove an exact verified linked worktree only when it is clean and contains no ignored entries, while retaining its local branch.
|
|
30
|
+
- Retire one exact unoccupied local branch ref only when it matches a full expected `HEAD` and its relationship to one exact local target has been verified; unmerged retirement requires explicit force authorization.
|
|
29
31
|
- Switch to an existing local branch after a clean-worktree preflight or create a new branch from current `HEAD`.
|
|
30
32
|
- Fetch a configured upstream tracking ref, fast-forward the current branch, or explicitly rebase it.
|
|
31
33
|
- Push the current branch to its configured upstream, or publish it to `origin` when no upstream exists.
|
|
32
34
|
- Create a pull request in the resolved current GitHub repository through the REST API.
|
|
33
35
|
- Non-goals:
|
|
34
|
-
- No staging, direct working-tree edits, user-authored commits, diff generation, stashing, resets, force pushes
|
|
36
|
+
- 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
37
|
- No automatic Pi cwd changes, process/session creation, or copying of `.env` and other ignored/untracked files into linked worktrees.
|
|
38
|
+
- No bulk or pattern branch deletion, inferred retirement targets, remote or remote-tracking deletion, automatic worktree removal during retirement, or reset-based retirement rollback.
|
|
36
39
|
- No GitHub CLI dependency or cross-repository pull requests.
|
|
37
40
|
- No labels, reviewers, projects, or issue-linking behavior.
|
|
38
41
|
|
|
@@ -42,10 +45,12 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
|
|
|
42
45
|
| --- | --- | --- | --- |
|
|
43
46
|
| Command | `/branchme` | Compact TUI status and workflow panel | Informational; no Git or GitHub mutations |
|
|
44
47
|
| 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 |
|
|
48
|
+
| 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 |
|
|
49
|
+
| 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
50
|
| Tool | `list_worktrees` | List bounded main/linked worktree inventory | Read-only and explicit |
|
|
47
51
|
| Tool | `create_worktree` | Create and verify a linked worktree | Exact absolute handoff cwd; new/existing local branch modes only |
|
|
48
52
|
| Tool | `remove_worktree` | Remove an exact verified clean linked worktree | Force-free; ignored entries block removal; branch retained |
|
|
53
|
+
| Tool | `retire_branch` | Delete one exact verified local branch ref | Expected-`HEAD` lease; exact target ancestry; explicit force for unmerged history; local-only |
|
|
49
54
|
| Tool | `change_branch` | Switch to an existing local branch | Rejects dirty worktrees |
|
|
50
55
|
| Tool | `fetch_branch` | Refresh the current branch's configured tracking ref | Explicit fetch refspec; no checkout change |
|
|
51
56
|
| Tool | `pull_branch` | Fast-forward the clean current branch | No rebase, merge commit, or autostash |
|
|
@@ -68,14 +73,18 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
|
|
|
68
73
|
- `src/commands/branchme-command.ts`
|
|
69
74
|
- `src/tools/branchme-tools.ts`
|
|
70
75
|
- `src/git.ts`
|
|
76
|
+
- `src/git-integration.ts`
|
|
77
|
+
- `src/git-retirement.ts`
|
|
71
78
|
- `src/github.ts`
|
|
72
79
|
- `src/ui/branchme-panel.ts`
|
|
73
80
|
- Module boundaries:
|
|
74
|
-
- The extension entry point registers the informational command,
|
|
75
|
-
- The context module owns bounded read-only collection, prompt formatting, and the `before_agent_start` hook.
|
|
81
|
+
- The extension entry point registers the informational command, thirteen tools, and automatic context hook.
|
|
82
|
+
- 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
83
|
- The command and UI modules own mode-safe informational help/status behavior and never invoke mutations.
|
|
77
84
|
- 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.
|
|
85
|
+
- 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.
|
|
86
|
+
- 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.
|
|
87
|
+
- The retirement module owns exact request validation, direct-ref and expected-`HEAD` preflight, complete worktree occupancy checks, target ancestry, leased local-ref deletion, cancellation-safe verification, and bounded uncertain outcomes without absorbing that state machine into the general helper.
|
|
79
88
|
- The GitHub helper owns repository resolution, token/autofill configuration, related-PR lookup, branch visibility and commit preflight, and pull request REST calls.
|
|
80
89
|
- The redaction module owns shared credential redaction for display and prompt-bound metadata.
|
|
81
90
|
- Shared public details remain JSON-serializable and contain no runtime objects or abort signals.
|
|
@@ -88,10 +97,10 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
|
|
|
88
97
|
## 6. Configuration, state, and filesystem boundary
|
|
89
98
|
|
|
90
99
|
- 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
|
|
100
|
+
- 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.
|
|
101
|
+
- Active-checkout mutations: explicit branch switching, creation, pull, rebase, and integration operations can update Git metadata and working-tree files through Git. Explicit retirement can delete one exact local branch ref. Push and fetch operations can update remote or remote-tracking refs through Git.
|
|
93
102
|
- 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.
|
|
103
|
+
- 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; `retire_branch` may delete one exact local branch ref only under the separate leased boundary below.
|
|
95
104
|
|
|
96
105
|
## 7. Worktree handoff contract
|
|
97
106
|
|
|
@@ -105,28 +114,51 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
|
|
|
105
114
|
- 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
115
|
- 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
116
|
|
|
108
|
-
## 8.
|
|
117
|
+
## 8. Branch integration contract
|
|
118
|
+
|
|
119
|
+
- `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.
|
|
120
|
+
- 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.
|
|
121
|
+
- 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.
|
|
122
|
+
- 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.
|
|
123
|
+
- 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.
|
|
124
|
+
- 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.
|
|
125
|
+
- 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.
|
|
126
|
+
- `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.
|
|
127
|
+
|
|
128
|
+
## 9. Local branch-retirement contract
|
|
129
|
+
|
|
130
|
+
- `retire_branch` accepts exactly `{ "branchName": string, "expectedHead": string, "targetBranch": string, "force": boolean }`. `expectedHead` is a full 40- or 64-hex-character commit identity; both distinct branch names must resolve to direct local refs in the current repository.
|
|
131
|
+
- Callers obtain or supply a fresh exact retiring `HEAD` and verify captured ancestry against the exact local target. `branch_status.ancestry` and retirement run sequentially. Any main, current, linked, locked, prunable/missing, or otherwise registered worktree occupancy blocks retirement; linked-worktree removal is a separate operation that must complete first.
|
|
132
|
+
- Merged retirement uses the captured positive ancestry proof. Negative ancestry fails unless `force` is exactly `true` with explicit user authorization. Forced unmerged retirement can remove a commit's last local branch reference; object recovery is not guaranteed, and normal Git expiry and garbage collection can eventually make it unreachable.
|
|
133
|
+
- Deletion uses exactly `git update-ref --no-deref -d refs/heads/<branchName> <capturedRetiringHead>`. The expected-old-value lease protects a moved retiring ref. `git branch -d/-D` is not used because it lacks the required lease and does not enforce this contract's explicit target.
|
|
134
|
+
- Retirement deletes no remote or remote-tracking ref, performs no bulk or inferred-target deletion, removes no worktree automatically, and creates/resets no branch as rollback. Local `branch.<branchName>.*` configuration remains untouched and may affect a later same-name branch.
|
|
135
|
+
- One process-local queue window keyed by the canonical active worktree root covers preflight, immediate reinspection, deletion, and final verification. It does not lock another active worktree, Pi process, or external Git process. After deletion is attempted, bounded inspection without the caller's cancelled signal verifies repository identity, target stability, local-ref absence, and zero occupancy. Contradictory or inconclusive state produces an uncertain error requiring manual inspection because retirement may have completed.
|
|
136
|
+
- Repository-configured `reference-transaction` hooks may execute arbitrary commands or contact networks during `git update-ref`; they are separate from BranchMe's direct local-only, no-network/no-remote-delete argv guarantee.
|
|
137
|
+
|
|
138
|
+
## 10. Security and privacy
|
|
109
139
|
|
|
110
140
|
- Every Git command uses `pi.exec("git", args, { cwd, signal, timeout })` with an argv array rather than shell interpolation.
|
|
111
141
|
- Paths, branch names, Git output, commit subjects, and pull request metadata are treated as untrusted. Display and prompt surfaces are escaped, redacted, and bounded separately from prevalidated exact handoff identities.
|
|
112
142
|
- Worktree paths are canonicalized and checked against a fresh current-repository inventory or the common Git directory before mutation. User-supplied removal paths are never passed directly to Git.
|
|
113
143
|
- Worktree removal has no force path and rejects dirty, ignored-entry-containing, detached, locked, prunable/missing, bare, main, current, and foreign entries before mutation.
|
|
114
144
|
- 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.
|
|
145
|
+
- Retirement requires exact direct local refs, full expected-`HEAD` leasing, complete worktree occupancy inspection, captured target ancestry, and explicit unmerged force authorization. Final verification is cancellation-safe and bounded; uncertain state requires manual inspection and no rollback mutation.
|
|
115
146
|
- 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
147
|
- `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.
|
|
148
|
+
- BranchMe's direct integration and retirement commands are local-only, but repository-configured hooks—including `reference-transaction` hooks during retirement—merge drivers, filters, and signing policy may execute arbitrary commands or network operations under the user's identity outside BranchMe's argv guarantees.
|
|
117
149
|
- Tokens are resolved from supported process or verified-root `.env` keys and redacted from prompts, errors, content, and details. BranchMe collects no telemetry.
|
|
118
150
|
- 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
151
|
|
|
120
|
-
##
|
|
152
|
+
## 11. Documentation and packaging
|
|
121
153
|
|
|
122
154
|
- `README.md` is the primary public workflow and tool reference.
|
|
123
155
|
- `SECURITY.md` documents local filesystem, Git, GitHub, credential, and prompt-insertion boundaries.
|
|
124
156
|
- `docs/STRUCTURE.md` describes the implemented source and test layout.
|
|
125
157
|
- `docs/SMOKE_TEST.md` records isolated checkout, handoff, and installed-package smoke behavior.
|
|
126
|
-
- `CHANGELOG.md` tracks the active `0.
|
|
158
|
+
- `CHANGELOG.md` tracks the active `0.2.0` unreleased changes.
|
|
127
159
|
- npm distribution uses package `@senad-d/branchme`; package-content checks exclude private specs, credentials, generated files, caches, and local state.
|
|
128
160
|
|
|
129
|
-
##
|
|
161
|
+
## 12. Validation plan
|
|
130
162
|
|
|
131
163
|
- Typecheck: `npm run typecheck`
|
|
132
164
|
- Formatting and documentation checks: `npm run format:check`
|
|
@@ -138,12 +170,14 @@ Originally approved on 2026-06-30. Updated to describe the implemented `0.1.8` p
|
|
|
138
170
|
- Installed-artifact smoke: `npm run smoke:pi:packed`
|
|
139
171
|
- Canonical local and automated release gate: `npm run release:check`
|
|
140
172
|
|
|
141
|
-
##
|
|
173
|
+
## 13. Current decisions
|
|
142
174
|
|
|
143
175
|
- Slash commands remain informational; tools perform all Git and GitHub actions.
|
|
144
176
|
- Automatic context remains focused on the active worktree; inventory is available only through `list_worktrees`.
|
|
145
177
|
- `create_worktree` returns a verified target for a caller-managed session but does not change cwd or create processes.
|
|
178
|
+
- `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
179
|
- Worktree removal remains force-free, blocks ignored entries, and preserves the local branch.
|
|
180
|
+
- Local branch retirement remains a separate explicit operation requiring a fresh expected `HEAD`, exact target ancestry, zero complete-inventory occupancy, and an explicit boolean force decision; it deletes only the leased local ref and leaves branch configuration and remote/remote-tracking refs untouched.
|
|
147
181
|
- `push_branch` uses `origin` only when the current branch has no configured upstream.
|
|
148
182
|
- `pull_request` infers owner/repository from the current checkout or matching `GITHUB_REPOSITORY`, never accepts owner/repository tool inputs, and requires local branch refs with the head matching GitHub.
|
|
149
183
|
- Pull request fields remain explicit unless `BRANCHME_PR_AUTOFILL=true`; explicit values always take precedence.
|