@senad-d/branchme 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -5
- package/README.md +116 -18
- package/SECURITY.md +34 -6
- package/docs/PROJECT_DEFINITION_BRIEF.md +129 -77
- package/docs/SMOKE_TEST.md +24 -12
- package/docs/STRUCTURE.md +30 -20
- package/docs/TUI_CAPTURE.md +109 -28
- package/package.json +9 -5
- package/src/commands/branchme-command.ts +16 -2
- package/src/constants.ts +19 -0
- package/src/git-context.ts +81 -16
- package/src/git-integration.ts +673 -0
- package/src/git.ts +1175 -2
- package/src/tools/branchme-tools.ts +296 -4
- package/src/types.ts +226 -0
- package/src/ui/branchme-panel.ts +27 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
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`, and `
|
|
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,
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
8
13
|
- Added GitHub repository resolution, environment-token and local `.env` token fallback handling, REST pull request creation, response validation, and token redaction.
|
|
9
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.
|
|
10
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.
|
|
11
16
|
- Expanded `branch_status` into a shared, explicit, read-only context refresh for state that may change during a run.
|
|
12
|
-
- Added unit tests with mocked `pi.exec` and `fetch` for Git context collection and prompt safety, git helpers, GitHub helpers, command behavior, tool schemas, prompt metadata, and extension registration.
|
|
13
|
-
- Updated public documentation for automatic context
|
|
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 and pull request tools for <a href="https://pi.dev">pi</a>.
|
|
14
|
-
<br />Inspect branch state,
|
|
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 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 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>
|
|
@@ -30,13 +30,14 @@ BranchMe is a Pi extension for safe branch workflow automation. Before each agen
|
|
|
30
30
|
</table>
|
|
31
31
|
|
|
32
32
|
- **Context-aware:** every agent run starts with bounded branch, working-tree, related-PR, and recent-commit metadata; repository metadata is untrusted data, not instructions.
|
|
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
|
-
- **
|
|
36
|
-
- **
|
|
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, 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 extra properties such as `force`, `stash`, `discard`, `owner`, `repo`, `path`, or `baseRef`; worktree tools accept only their documented fields.
|
|
37
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.
|
|
38
39
|
|
|
39
|
-
> **Security:** pi packages run with your full system permissions. BranchMe runs local `git` commands, may make an automatic authenticated GitHub request to find a related open pull request, can
|
|
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).
|
|
40
41
|
|
|
41
42
|
## Table of Contents
|
|
42
43
|
|
|
@@ -89,9 +90,19 @@ A typical BranchMe flow is:
|
|
|
89
90
|
7. Push the current branch with `push_branch`.
|
|
90
91
|
8. After `push_branch` completes and GitHub can see the branches, create a pull request with `pull_request`.
|
|
91
92
|
|
|
93
|
+
For isolated work, a specialized Git subagent can use the explicit worktree workflow:
|
|
94
|
+
|
|
95
|
+
1. Call `list_worktrees` to inspect the current repository's bounded worktree inventory.
|
|
96
|
+
2. Ask the user to provide or approve an exact absolute destination and call `create_worktree` with `branchMode: "new"` or `"existing"`.
|
|
97
|
+
3. Wait for the result and require `details.handoff.ready === true`.
|
|
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
|
+
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
|
+
|
|
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 delete branches. For credentials needed by agents in linked worktrees, prefer process-level environment variables rather than copying repository-root secrets.
|
|
102
|
+
|
|
92
103
|
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.
|
|
93
104
|
|
|
94
|
-
BranchMe is tool-based. The slash command is informational only and never changes or updates branches, fetches, rebases, pushes, commits, stages, edits files, or opens pull requests.
|
|
105
|
+
BranchMe is tool-based. The slash command is informational only and never changes or updates branches, creates or removes worktrees, changes cwd, starts processes/sessions, fetches, rebases, pushes, commits, stages, edits files, or opens pull requests.
|
|
95
106
|
|
|
96
107
|
---
|
|
97
108
|
|
|
@@ -212,16 +223,20 @@ Commands are informational only. BranchMe actions are performed by agent-callabl
|
|
|
212
223
|
|
|
213
224
|
| Tool | Schema | Behavior |
|
|
214
225
|
| --- | --- | --- |
|
|
215
|
-
| `branch_status` | `{}` | Explicitly refreshes the same bounded context used at agent start
|
|
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
|
+
| `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
|
+
| `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
|
+
| `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. |
|
|
216
230
|
| `change_branch` | `{ "branchName": string }` | Validates `branchName`, requires `refs/heads/<branchName>` to exist locally, rejects dirty worktrees, and runs `git switch <branchName>`. |
|
|
217
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. |
|
|
218
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. |
|
|
219
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. |
|
|
220
235
|
| `create_branch` | `{ "branchName": string }` | Validates `branchName`, rejects existing local branches, and runs `git switch -c <branchName>` from current `HEAD`. |
|
|
221
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. |
|
|
222
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`. |
|
|
223
238
|
|
|
224
|
-
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. `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.
|
|
225
240
|
|
|
226
241
|
---
|
|
227
242
|
|
|
@@ -240,7 +255,7 @@ Before each agent run, BranchMe appends an **Automatic Git Context** snapshot to
|
|
|
240
255
|
|
|
241
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.
|
|
242
257
|
|
|
243
|
-
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.
|
|
244
259
|
|
|
245
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.
|
|
246
261
|
|
|
@@ -258,6 +273,75 @@ After push_branch completes, create a draft pull request from feature/docs-refre
|
|
|
258
273
|
If pull request field autofill is enabled, after push_branch completes create a pull request and fill any details I did not provide.
|
|
259
274
|
```
|
|
260
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
|
+
|
|
307
|
+
### Linked worktree verification and handoff
|
|
308
|
+
|
|
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.
|
|
310
|
+
|
|
311
|
+
For `branchMode: "new"`, BranchMe creates the requested local branch from the current `HEAD` only. For `branchMode: "existing"`, it uses only an existing local branch that is not checked out in another worktree; it never infers a local branch from a remote. After Git succeeds, BranchMe re-lists worktrees and verifies the canonical path, local branch, `HEAD`, and clean checkout. A representative structured result subset is:
|
|
312
|
+
|
|
313
|
+
```json
|
|
314
|
+
{
|
|
315
|
+
"action": "create_worktree",
|
|
316
|
+
"handoff": {
|
|
317
|
+
"cwd": "/absolute/path/to/branchme-feature",
|
|
318
|
+
"branch": "feature/worktree-docs",
|
|
319
|
+
"head": "<full-commit-id>",
|
|
320
|
+
"ready": true,
|
|
321
|
+
"summary": "Worktree ready at /absolute/path/to/branchme-feature on branch feature/worktree-docs at <full-commit-id>."
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
The full details also distinguish requested input from verified before/after state. Successful `handoff.cwd` and `handoff.branch` values are the exact identities verified against Git; BranchMe never substitutes `[REDACTED]`, escaped control sequences, or a truncation ellipsis in these machine-readable fields. Display content, summaries, and worktree inventory remain sanitized and bounded separately. An orchestrator may use `handoff.cwd` only after `ready` is `true`, and must start the next Pi session or subagent itself with that exact working directory. BranchMe never changes the active process's cwd or starts another process/session.
|
|
327
|
+
|
|
328
|
+
`remove_worktree` canonicalizes the approved absolute path and requires an exact match in a fresh inventory for the current repository. It accepts only a present, unlocked, non-prunable, non-bare, branch-attached linked worktree that is neither main nor current, then rejects staged, unstaged, untracked, unmerged, or ignored entries. The canonical path and retained branch must pass the same pre-mutation lossless-identity checks used for creation. The ignored-entry preflight is bounded and does not return ignored paths. Removal uses `git worktree remove <verified-path>` without force, verifies the entry is gone, and returns the exact retained branch identity after confirming it still points to the captured commit:
|
|
329
|
+
|
|
330
|
+
```json
|
|
331
|
+
{
|
|
332
|
+
"action": "remove_worktree",
|
|
333
|
+
"handoff": {
|
|
334
|
+
"cwd": null,
|
|
335
|
+
"branch": "feature/worktree-docs",
|
|
336
|
+
"head": "<full-commit-id>",
|
|
337
|
+
"ready": false,
|
|
338
|
+
"summary": "Worktree directory /absolute/path/to/branchme-feature was removed; local branch feature/worktree-docs was retained at <full-commit-id>."
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
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.
|
|
344
|
+
|
|
261
345
|
BranchMe operates only on the repository where pi is running:
|
|
262
346
|
|
|
263
347
|
- Automatic collection and `branch_status` run bounded, read-only Git commands from the verified git root.
|
|
@@ -266,12 +350,16 @@ BranchMe operates only on the repository where pi is running:
|
|
|
266
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.
|
|
267
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.
|
|
268
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.
|
|
269
354
|
- `create_branch` creates from the current `HEAD` only and has no `baseRef` input.
|
|
355
|
+
- `list_worktrees` is an explicit, read-only repository inventory; it is intentionally absent from automatic active-worktree context.
|
|
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.
|
|
357
|
+
- `remove_worktree` passes Git only a freshly verified canonical linked-worktree path, never uses force, and retains the branch.
|
|
270
358
|
- `push_branch` pushes only the current branch, uses no bare upstream `git push`, and has no `branchName` input.
|
|
271
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`.
|
|
272
360
|
- If local `origin` and `GITHUB_REPOSITORY` both resolve but disagree, `pull_request` fails closed.
|
|
273
361
|
|
|
274
|
-
BranchMe intentionally does **not** stage files, create user-authored commits, force checkout, stash changes, discard changes, force-push,
|
|
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.
|
|
275
363
|
|
|
276
364
|
---
|
|
277
365
|
|
|
@@ -316,11 +404,19 @@ Ensure the token and Git credentials have permission for the branch and pull req
|
|
|
316
404
|
| Not a git repository | Start pi from inside a git checkout. |
|
|
317
405
|
| Detached `HEAD` | Use `change_branch` to switch to an existing local branch, or checkout a branch before `fetch_branch`, `pull_branch`, `rebase_branch`, `create_branch`, or `push_branch`. |
|
|
318
406
|
| Branch already exists | Choose a new local branch name for `create_branch`, or use `change_branch` to switch to it. |
|
|
319
|
-
| Branch does not exist locally | Create a local branch first; `change_branch`
|
|
320
|
-
|
|
|
407
|
+
| Branch does not exist locally | Create a local branch first; `change_branch` and `create_worktree` existing mode do not infer local branches from remote branches. |
|
|
408
|
+
| Worktree destination rejected | Provide an exact absolute path whose immediate parent exists; the destination must not exist or be inside another registered worktree or the repository's common Git directory. Its canonical path and branch identity must also fit the documented limits without credential-like token text or characters that require escaping. |
|
|
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. |
|
|
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. |
|
|
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. |
|
|
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`. |
|
|
321
413
|
| Fetch, pull, or rebase has no upstream | Configure the current branch upstream outside BranchMe, then retry the tool. |
|
|
322
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. |
|
|
323
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. |
|
|
324
420
|
| Push fails | Confirm the current branch is correct and your normal Git remote credentials can push. |
|
|
325
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. |
|
|
326
422
|
| PR auth fails | Set `GITHUB_TOKEN` or `GH_TOKEN` before starting pi, or copy `.env.example` to `.env` and fill in one token. |
|
|
@@ -329,7 +425,7 @@ Ensure the token and Git credentials have permission for the branch and pull req
|
|
|
329
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. |
|
|
330
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. |
|
|
331
427
|
| Repository mismatch | Make `origin` and `GITHUB_REPOSITORY` refer to the same `owner/repo`. |
|
|
332
|
-
| Need a commit | Use
|
|
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. |
|
|
333
429
|
| Other extensions interfere | Test with `pi --no-extensions -e .`. |
|
|
334
430
|
|
|
335
431
|
---
|
|
@@ -344,7 +440,7 @@ npm run check:pack
|
|
|
344
440
|
printf '/branchme help\n/quit\n' | pi --no-extensions -e .
|
|
345
441
|
```
|
|
346
442
|
|
|
347
|
-
Validation covers TypeScript typechecking, formatting checks, automatic context collection and prompt injection, mocked GitHub lookup,
|
|
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).
|
|
348
444
|
|
|
349
445
|
Refresh TUI captures intentionally with:
|
|
350
446
|
|
|
@@ -391,11 +487,13 @@ BranchMe publishes to npm as `@senad-d/branchme`. You need an npm account with p
|
|
|
391
487
|
```bash
|
|
392
488
|
npm login
|
|
393
489
|
npm whoami
|
|
394
|
-
npm run release:check # optional preflight;
|
|
490
|
+
npm run release:check # optional preflight; every publish path runs this gate
|
|
395
491
|
node scripts/publish-npm.mjs
|
|
396
492
|
```
|
|
397
493
|
|
|
398
|
-
|
|
494
|
+
`npm run release:check` is the canonical release gate: it runs checkout validation and then installs and loads the packed npm artifact in isolation. Both the local publish script and the GitHub `Publish to npm` workflow run this gate before npm publication; a failure prevents publication and the workflow's Git tag creation.
|
|
495
|
+
|
|
496
|
+
The publish script requires a clean working tree, asks for the version number, runs `npm run release:check`, runs `npm version <version>` to update `package.json` and `package-lock.json`, creates the `v<version>` git tag, publishes with `npm publish --access public`, and then offers to push the release commit and tag.
|
|
399
497
|
|
|
400
498
|
Run it only from a clean working tree after updating `CHANGELOG.md`.
|
|
401
499
|
|
package/SECURITY.md
CHANGED
|
@@ -20,15 +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.
|
|
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.
|
|
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.
|
|
24
27
|
|
|
25
|
-
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.
|
|
26
29
|
|
|
27
|
-
Branch switching, fast-forward pulls,
|
|
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.
|
|
28
35
|
|
|
29
36
|
## Network behavior
|
|
30
37
|
|
|
31
|
-
`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`
|
|
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.
|
|
32
41
|
|
|
33
42
|
BranchMe's GitHub helpers use these REST API requests:
|
|
34
43
|
|
|
@@ -48,15 +57,30 @@ The branch preflight requests have no body. BranchMe uses the resolved `headBran
|
|
|
48
57
|
BranchMe operates on the current repository only.
|
|
49
58
|
|
|
50
59
|
- The GitHub repository is inferred from local `origin` and/or `GITHUB_REPOSITORY`.
|
|
51
|
-
-
|
|
60
|
+
- Branch and PR tools never accept filesystem paths, `owner`, `repo`, or owner-prefixed `owner:branch` PR refs. Worktree mutations accept only an explicitly approved absolute `worktreePath`, with `branchName` and `branchMode` additionally required for creation.
|
|
61
|
+
- `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.
|
|
62
|
+
- `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.
|
|
63
|
+
- `remove_worktree` accepts exactly `worktreePath`, requires an exact canonical match in a fresh current-repository inventory, removes no branch, and does not accept force.
|
|
52
64
|
- `change_branch` accepts only `branchName` and never creates branches, checks out remote branches, forces, stashes, or discards changes.
|
|
53
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.
|
|
54
66
|
- `pull_branch` accepts no parameters, updates only the clean current branch from its configured upstream, and uses fast-forward-only semantics.
|
|
55
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.
|
|
56
70
|
- If local `origin` and `GITHUB_REPOSITORY` both resolve but disagree, PR creation and related-PR lookup fail closed.
|
|
57
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.
|
|
58
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`.
|
|
59
73
|
|
|
74
|
+
## Worktree filesystem boundary
|
|
75
|
+
|
|
76
|
+
Linked worktree management expands the mutation boundary beyond the active checkout. `create_worktree` may create a directory anywhere the user can write when the explicitly supplied destination passes all checks. BranchMe requires a non-blank absolute path without control characters, requires the immediate parent to exist as a directory, resolves that parent with `realpath`, and rejects any existing destination—including a symlink. It also rejects a destination inside any registered worktree or inside the current repository's common Git directory. Before mutation, the resulting canonical path and local branch must remain exactly identical as JavaScript strings after BranchMe's redaction, control/format escaping, Unicode-safe truncation, and size checks; the path limit is 4,096 characters and the branch limit is 512 characters.
|
|
77
|
+
|
|
78
|
+
`remove_worktree` never passes an unverified user path to Git. It canonicalizes the supplied absolute path, requires an exact match in a fresh inventory belonging to the current repository, applies the same lossless checks to the canonical path and retained branch, and rejects the main worktree, the worktree containing the active Pi session, bare, detached, locked, prunable/missing, dirty, and ignored-entry-containing worktrees. A separate bounded porcelain scan detects ignored files and directories without exposing their paths or contents. After force-free removal, BranchMe verifies the worktree is no longer registered and that its local branch remains at the captured `HEAD`.
|
|
79
|
+
|
|
80
|
+
Paths, branch names, lock/prune reasons, and Git output are untrusted metadata. Informational inventory, prose, summaries, and non-identity details are escaped, redacted, and bounded. Successful machine-readable `handoff.cwd` and handoff branch fields instead contain exact verified identities, so BranchMe rejects any identity that would require display transformation before mutation. This also applies to the retained branch returned after removal. Creation failures do not trigger automatic deletion of a possibly created directory or branch; the caller is told to inspect the repository and destination. No force, move, prune, repair, lock, unlock, detached, orphan, or remote-inference worktree operation is implemented.
|
|
81
|
+
|
|
82
|
+
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.
|
|
83
|
+
|
|
60
84
|
## Credentials
|
|
61
85
|
|
|
62
86
|
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.
|
|
@@ -68,11 +92,13 @@ Git fetch, pull, and push authentication is handled by the user's configured Git
|
|
|
68
92
|
|
|
69
93
|
BranchMe also reads the non-secret `BRANCHME_PR_AUTOFILL` setting from the process environment or verified-root `.env`; all other `.env` keys are ignored. The `.env` reader uses async file I/O, requires a small regular file, and rejects directories, symlinks, special files, and oversized files. BranchMe does not read shell profiles, GitHub CLI credentials, or local credential stores. Token values are redacted from thrown errors, automatic context, generated PR text, tool content, and tool details.
|
|
70
94
|
|
|
95
|
+
A newly created linked worktree does not receive the source checkout's `.env` or other ignored/untracked files. Start the separate agent with required credentials in its process environment rather than copying secrets into the linked checkout.
|
|
96
|
+
|
|
71
97
|
## System prompt boundary
|
|
72
98
|
|
|
73
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.
|
|
74
100
|
|
|
75
|
-
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.
|
|
76
102
|
|
|
77
103
|
## Telemetry
|
|
78
104
|
|
|
@@ -93,6 +119,8 @@ Do not open public issues for security-sensitive reports that include exploit de
|
|
|
93
119
|
- Do not commit secrets, tokens, local `.env`, local `.pi/` state, or generated artifacts.
|
|
94
120
|
- Keep tool schemas strict and reject unsupported fields.
|
|
95
121
|
- Keep all git calls argv-style through `pi.exec("git", args)`.
|
|
96
|
-
-
|
|
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.
|
|
123
|
+
- Treat worktree paths as a filesystem security boundary; canonicalize them, verify current-repository membership before removal, and never add force cleanup.
|
|
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.
|
|
97
125
|
- Keep package contents minimal with `npm run check:pack`.
|
|
98
126
|
- Use isolated smoke tests with `pi --no-extensions -e .`.
|