@senad-d/branchme 0.1.1

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/.env.example ADDED
@@ -0,0 +1,5 @@
1
+ # BranchMe GitHub token template.
2
+ # Copy this file to .env only when you need pull_request support.
3
+ # Keep committed placeholders empty; put real tokens only in your local .env file.
4
+ GITHUB_TOKEN=
5
+ GH_TOKEN=
package/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 - Unreleased
4
+
5
+ - Implemented the `branchme` informational slash command with help aliases.
6
+ - Added strict BranchMe tools: `branch_status`, `change_branch`, `create_branch`, `push_branch`, and `pull_request`.
7
+ - Added argv-style git helpers for repository status, branch validation/creation/switching, clean-worktree preflight, upstream detection, and current-branch push/publish.
8
+ - Added GitHub repository resolution, environment-token and local `.env` token fallback handling, REST pull request creation, response validation, and token redaction.
9
+ - Added unit tests with mocked `pi.exec` and `fetch` for git helpers, GitHub helpers, command behavior, tool schemas, prompt metadata, and extension registration.
10
+ - Updated public documentation for implemented behavior, security boundaries, package structure, and validation commands.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Senad Dizdarević
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,347 @@
1
+ <p align="center">
2
+ <img alt="BranchMe logo" src="img/icon.svg" width="128">
3
+ </p>
4
+
5
+ <p align="center">
6
+ <a href="https://pi.dev"><img alt="pi package" src="https://img.shields.io/badge/pi-package-6f42c1?style=flat-square" /></a>
7
+ <a href="https://www.npmjs.com/package/@senad-d/branchme"><img alt="npm" src="https://img.shields.io/npm/v/%40senad-d%2Fbranchme?style=flat-square" /></a>
8
+ <a href="LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" /></a>
9
+ </p>
10
+
11
+ <p align="center">
12
+ Current-repository branch and pull request tools for <a href="https://pi.dev">pi</a>.
13
+ <br />Inspect branch state, switch/create branches, push, and open GitHub PRs from pi prompts.
14
+ </p>
15
+
16
+ ---
17
+
18
+ BranchMe is a Pi extension for safe branch workflow automation. It adds an informational `/branchme` command and five agent-callable tools that inspect the current repository, switch to an existing local branch, create a branch from the current `HEAD`, push the current branch, and create a GitHub pull request.
19
+
20
+ <table align="center">
21
+ <tr>
22
+ <th>BranchMe demo</th>
23
+ </tr>
24
+ <tr>
25
+ <td align="center">
26
+ <img src="img/demo.gif" alt="BranchMe demo: inspect branch status and use branch workflow tools in pi" title="BranchMe demo" width="760">
27
+ </td>
28
+ </tr>
29
+ </table>
30
+
31
+ - **Current-repository only:** Git and GitHub operations are scoped to the checkout where pi is running.
32
+ - **Commit-safe:** BranchMe never stages files, creates commits, generates commit messages, rebases, merges, resets, or edits files directly.
33
+ - **Strict tools:** tool schemas reject extra properties such as `force`, `stash`, `discard`, `owner`, `repo`, `path`, or `baseRef`.
34
+ - **PR-ready:** create GitHub pull requests from existing local branches after verifying the `headBranch` matches GitHub and the base is visible, with explicit PR fields and `GITHUB_TOKEN` or `GH_TOKEN` from the process environment or a local `.env` fallback.
35
+
36
+ > **Security:** pi packages run with your full system permissions. BranchMe can run local `git` commands, switch/create branches, push the current branch, and call the GitHub REST API to create pull requests. Read [`SECURITY.md`](SECURITY.md).
37
+
38
+ ## Table of Contents
39
+
40
+ - [Quick Start](#quick-start)
41
+ - [Installation](#installation)
42
+ - [Repository and GitHub Setup](#repository-and-github-setup)
43
+ - [Configuration](#configuration)
44
+ - [Commands](#commands)
45
+ - [Tools](#tools)
46
+ - [Workflow and Boundaries](#workflow-and-boundaries)
47
+ - [GitHub Actions](#github-actions)
48
+ - [Troubleshooting](#troubleshooting)
49
+ - [Diagnostics](#diagnostics)
50
+ - [Update and Uninstall](#update-and-uninstall)
51
+ - [Development](#development)
52
+ - [Publishing](#publishing)
53
+ - [License](#license)
54
+
55
+ ---
56
+
57
+ ## Quick Start
58
+
59
+ ```bash
60
+ pi install npm:@senad-d/branchme
61
+ cd /path/to/your/git/repo
62
+ pi
63
+ ```
64
+
65
+ Inside pi:
66
+
67
+ ```text
68
+ /branchme
69
+ /branchme help
70
+ ```
71
+
72
+ Ask the agent to use BranchMe tools explicitly, for example:
73
+
74
+ ```text
75
+ Use branch_status, then create a branch named feature/update-docs with create_branch.
76
+ ```
77
+
78
+ A typical BranchMe flow is:
79
+
80
+ 1. Inspect state with `branch_status`.
81
+ 2. Switch with `change_branch` or create from current `HEAD` with `create_branch`.
82
+ 3. Make edits and commit outside BranchMe.
83
+ 4. Push the current branch with `push_branch`.
84
+ 5. After `push_branch` completes and GitHub can see the branches, create a pull request with `pull_request`.
85
+
86
+ BranchMe is tool-based. The slash command is informational only and never changes branches, pushes, commits, stages, edits files, or opens pull requests.
87
+
88
+ ---
89
+
90
+ ## Installation
91
+
92
+ | Scope | Command | Notes |
93
+ | --- | --- | --- |
94
+ | Global | `pi install npm:@senad-d/branchme` | Loads in every trusted pi project. |
95
+ | Project-local | `pi install npm:@senad-d/branchme -l` | Writes to `.pi/settings.json` in the current project. |
96
+ | One run | `pi -e npm:@senad-d/branchme` | Try without changing settings. |
97
+ | Git | `pi install git:github.com/senad-d/branchme@<tag>` | Pin a tag or commit. |
98
+ | Local checkout | `pi --no-extensions -e .` | Develop or test this repository in isolation. |
99
+
100
+ Source checkout:
101
+
102
+ ```bash
103
+ git clone https://github.com/senad-d/branchme.git
104
+ cd branchme
105
+ npm install --ignore-scripts
106
+ npm run validate
107
+ pi --no-extensions -e .
108
+ ```
109
+
110
+ Use the checkout globally while developing:
111
+
112
+ ```bash
113
+ pi install /absolute/path/to/branchme
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Repository and GitHub Setup
119
+
120
+ BranchMe does not bundle Git and does not create repositories. Start pi from inside the repository you want BranchMe to manage:
121
+
122
+ ```bash
123
+ cd /path/to/your/git/repo
124
+ git status
125
+ git remote get-url origin
126
+ pi
127
+ ```
128
+
129
+ For pull requests, the repository must resolve to GitHub from local `origin` and/or `GITHUB_REPOSITORY`:
130
+
131
+ ```bash
132
+ git remote set-url origin git@github.com:OWNER/REPO.git
133
+ # or
134
+ export GITHUB_REPOSITORY=OWNER/REPO
135
+ ```
136
+
137
+ For `pull_request`, set a token in the process environment before starting pi:
138
+
139
+ ```bash
140
+ export GITHUB_TOKEN=github_pat_...
141
+ # or
142
+ export GH_TOKEN=ghp_...
143
+ pi
144
+ ```
145
+
146
+ Or copy `.env.example` to `.env` in the repository root and fill in one token value:
147
+
148
+ ```bash
149
+ cp .env.example .env
150
+ $EDITOR .env
151
+ pi
152
+ ```
153
+
154
+ `push_branch` uses your normal Git remote credentials. BranchMe does not inject `GITHUB_TOKEN` into `git push`.
155
+ When the current branch already has an upstream, BranchMe pushes an explicit `HEAD:<upstream-branch-ref>` refspec to the configured upstream remote instead of relying on a bare `git push`.
156
+ Run `pull_request` only after `push_branch` has completed; `pull_request` preflights the GitHub `headBranch` and `baseBranch` before creating the PR and fails with retry guidance if a branch is not visible yet or the GitHub `headBranch` commit does not match the local branch.
157
+
158
+ ---
159
+
160
+ ## Configuration
161
+
162
+ BranchMe has no project config file. It reads process environment variables for GitHub pull request creation and optional repository boundary checks, with a local `.env` token fallback when no process token is set. Token lookup checks `process.env.GITHUB_TOKEN`, then `process.env.GH_TOKEN`; if neither is set, BranchMe reads `.env` from the verified git root and checks `GITHUB_TOKEN`, then `GH_TOKEN`.
163
+
164
+ | Variable | Meaning |
165
+ | --- | --- |
166
+ | `GITHUB_TOKEN` | Preferred token for `pull_request`; process environment first, then local `.env` fallback. |
167
+ | `GH_TOKEN` | Fallback token for `pull_request`; process environment first, then local `.env` fallback. |
168
+ | `GITHUB_REPOSITORY=owner/repo` | Optional CI fallback and boundary check for the current GitHub repository; process environment only. |
169
+
170
+ BranchMe reads only `GITHUB_TOKEN` and `GH_TOKEN` from a small regular `.env` file; it rejects directories, symlinks, special files, and oversized files. BranchMe does not import other `.env` keys, read shell profiles, GitHub CLI credentials, or local credential stores. Token values are redacted from errors, tool content, and tool details.
171
+
172
+ If local `origin` and `GITHUB_REPOSITORY` both resolve but disagree, `pull_request` fails closed.
173
+
174
+ ---
175
+
176
+ ## Commands
177
+
178
+ | Command | Description |
179
+ | --- | --- |
180
+ | `/branchme` | Show a compact status panel or fallback message with current branch, GitHub repository resolution, token presence, and workflow notes. |
181
+ | `/branchme help` | Show concise BranchMe workflow help and runtime requirements. |
182
+ | `/branchme --help` | Alias for `/branchme help`. |
183
+ | `/branchme -h` | Alias for `/branchme help`. |
184
+
185
+ Commands are informational only. BranchMe actions are performed by agent-callable tools. `/branchme` uses the TUI panel in TUI mode, notifications in RPC mode, plain text only in print mode, and stays stdout-silent in JSON mode to avoid corrupting protocol output. Unsupported non-empty `/branchme` arguments return guidance to use `/branchme help` where the current mode can display it safely.
186
+
187
+ ---
188
+
189
+ ## Tools
190
+
191
+ | Tool | Schema | Behavior |
192
+ | --- | --- | --- |
193
+ | `branch_status` | `{}` | Read-only git status: repo root, current branch or detached state, upstream, dirty state, ahead/behind counts, and GitHub repository when resolvable. |
194
+ | `change_branch` | `{ "branchName": string }` | Validates `branchName`, requires `refs/heads/<branchName>` to exist locally, rejects dirty worktrees, and runs `git switch <branchName>`. |
195
+ | `create_branch` | `{ "branchName": string }` | Validates `branchName`, rejects existing local branches, and runs `git switch -c <branchName>` from current `HEAD`. |
196
+ | `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. |
197
+ | `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 via `POST /repos/{owner}/{repo}/pulls`; branch refs must exist locally and cannot use `owner:branch`. |
198
+
199
+ All schemas reject additional properties. `change_branch` never accepts `baseRef`, `force`, `stash`, `discard`, `create`, `owner`, `repo`, or path inputs. `pull_request` never accepts `owner`, `repo`, or owner-prefixed branch refs; BranchMe resolves the repository from local `origin` and/or matching `GITHUB_REPOSITORY`.
200
+
201
+ ---
202
+
203
+ ## Workflow and Boundaries
204
+
205
+ Use BranchMe from pi prompts or automation that drives pi with explicit tool calls:
206
+
207
+ ```text
208
+ Use branch_status.
209
+ Create branch feature/docs-refresh from the current HEAD with create_branch.
210
+ Push the current branch with push_branch.
211
+ After push_branch completes, create a draft pull request from feature/docs-refresh to main titled "Refresh docs" with this body: "...".
212
+ ```
213
+
214
+ BranchMe operates only on the repository where pi is running:
215
+
216
+ - Git commands use `pi.exec("git", args, { cwd, signal, timeout })` with argv arrays; repository mutations run from the verified git root.
217
+ - `change_branch` switches only to existing local branches and has no `force`, `stash`, `discard`, remote, or path input.
218
+ - `create_branch` creates from the current `HEAD` only and has no `baseRef` input.
219
+ - `push_branch` pushes only the current branch, uses no bare upstream `git push`, and has no `branchName` input.
220
+ - `pull_request` creates PRs only for the resolved current GitHub repository, requires `headBranch` and `baseBranch` to 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.
221
+ - If local `origin` and `GITHUB_REPOSITORY` both resolve but disagree, `pull_request` fails closed.
222
+
223
+ BranchMe intentionally does **not** stage files, create commits, force checkout, stash changes, discard changes, edit files directly, or generate commit messages.
224
+
225
+ ---
226
+
227
+ ## GitHub Actions
228
+
229
+ GitHub Actions example:
230
+
231
+ ```yaml
232
+ name: branchme-smoke
233
+ on:
234
+ workflow_dispatch:
235
+
236
+ permissions:
237
+ contents: write
238
+ pull-requests: write
239
+
240
+ jobs:
241
+ branchme:
242
+ runs-on: ubuntu-latest
243
+ env:
244
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
245
+ GITHUB_REPOSITORY: ${{ github.repository }}
246
+ steps:
247
+ - uses: actions/checkout@v4
248
+ with:
249
+ fetch-depth: 0
250
+ - uses: actions/setup-node@v4
251
+ with:
252
+ node-version: 22
253
+ - run: npm install -g --ignore-scripts @earendil-works/pi-coding-agent
254
+ - run: pi --no-extensions -e npm:@senad-d/branchme --help
255
+ ```
256
+
257
+ Ensure the token and Git credentials have permission for the branch and pull request operation you ask BranchMe to perform.
258
+
259
+ ---
260
+
261
+ ## Troubleshooting
262
+
263
+ | Problem | Try |
264
+ | --- | --- |
265
+ | Not a git repository | Start pi from inside a git checkout. |
266
+ | Detached `HEAD` | Use `change_branch` to switch to an existing local branch, or checkout a branch before `create_branch` or `push_branch`. |
267
+ | Branch already exists | Choose a new local branch name for `create_branch`, or use `change_branch` to switch to it. |
268
+ | Branch does not exist locally | Create a local branch first; `change_branch` does not checkout remote branches. |
269
+ | Dirty worktree before branch switch | Commit, stash, or discard changes outside BranchMe before using `change_branch`. |
270
+ | Push fails | Confirm the current branch is correct and your normal Git remote credentials can push. |
271
+ | PR auth fails | Set `GITHUB_TOKEN` or `GH_TOKEN` before starting pi, or copy `.env.example` to `.env` and fill in one token. |
272
+ | 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. |
273
+ | 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. |
274
+ | Repository mismatch | Make `origin` and `GITHUB_REPOSITORY` refer to the same `owner/repo`. |
275
+ | Need a commit | Use CommitMe or normal git commands; BranchMe never commits. |
276
+ | Other extensions interfere | Test with `pi --no-extensions -e .`. |
277
+
278
+ ---
279
+
280
+ ## Diagnostics
281
+
282
+ From a source checkout:
283
+
284
+ ```bash
285
+ npm run validate
286
+ npm run check:pack
287
+ printf '/branchme help\n/quit\n' | pi --no-extensions -e .
288
+ ```
289
+
290
+ Validation covers TypeScript typechecking, formatting checks, unit 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 five BranchMe tools are visible through `pi.getAllTools()` with strict schemas and prompt metadata. Smoke-test notes are recorded in [`docs/SMOKE_TEST.md`](docs/SMOKE_TEST.md), and TUI/help captures are stored in [`docs/TUI_CAPTURE.md`](docs/TUI_CAPTURE.md).
291
+
292
+ Refresh TUI captures intentionally with:
293
+
294
+ ```bash
295
+ UPDATE_TUI_CAPTURE=1 node --test test/tui-capture.test.mjs
296
+ ```
297
+
298
+ ---
299
+
300
+ ## Update and Uninstall
301
+
302
+ ```bash
303
+ pi update --extensions # update installed pi packages
304
+ pi update npm:@senad-d/branchme # update BranchMe only
305
+ pi remove npm:@senad-d/branchme # remove global install
306
+ pi remove npm:@senad-d/branchme -l # remove project-local install
307
+ ```
308
+
309
+ ---
310
+
311
+ ## Development
312
+
313
+ ```bash
314
+ npm install
315
+ npm run typecheck
316
+ npm run format:check
317
+ npm run test
318
+ npm run check:pack
319
+ npm run validate
320
+ npm run smoke:pi:packed
321
+ pi --no-extensions -e .
322
+ ```
323
+
324
+ `npm run check:pack` verifies the npm package does not include local state, specs, caches, `node_modules`, real environment files, or other private development artifacts. The safe `.env.example` template is included.
325
+ `npm run smoke:pi` is the checkout runtime smoke and verifies BranchMe command output plus real Pi tool registration metadata.
326
+ `npm run smoke:pi:packed` is the release-gate smoke: it packs the npm artifact into a temporary directory, installs it with production dependency settings, and runs pi against the installed package.
327
+
328
+ ---
329
+
330
+ ## Publishing
331
+
332
+ BranchMe publishes to npm as `@senad-d/branchme`. You need an npm account with publish access to the `@senad-d` scope.
333
+
334
+ ```bash
335
+ npm login
336
+ npm whoami
337
+ npm run release:check # optional preflight; the publish script runs this too
338
+ node scripts/publish-npm.mjs
339
+ ```
340
+
341
+ The publish script requires a clean working tree, asks for the version number, runs `npm run release:check` (validation plus installed-package smoke), 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.
342
+
343
+ Run it only from a clean working tree after updating `CHANGELOG.md`.
344
+
345
+ ## License
346
+
347
+ MIT
package/SECURITY.md ADDED
@@ -0,0 +1,77 @@
1
+ # Security Policy
2
+
3
+ ## Trust model
4
+
5
+ Pi packages and extensions run with the full local permissions of the user account that starts Pi. Review BranchMe source before installing it, pin versions in sensitive environments, and install only from trusted sources.
6
+
7
+ ```bash
8
+ pi install npm:@senad-d/branchme@<version>
9
+ pi install git:https://github.com/senad-d/branchme@<tag>
10
+ ```
11
+
12
+ ## Git behavior
13
+
14
+ BranchMe runs local `git` commands through Pi's extension API with argv-style arguments. Repository mutations first resolve the git root and then run from that verified root.
15
+
16
+ Implemented git mutations are limited to:
17
+
18
+ - `change_branch`: `git switch <branchName>` after branch-name validation, local `refs/heads/<branchName>` verification, and clean-worktree preflight.
19
+ - `create_branch`: `git switch -c <branchName>` from current `HEAD` after branch-name validation and existing-branch checks.
20
+ - `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.
21
+
22
+ Branch switching can update working-tree files as normal Git checkout behavior. Mutating branch operations for the same repository are serialized to avoid same-turn branch races. `pull_request` also uses the same repository queue around PR preflight and creation so it can wait behind an already-started same-repository push. BranchMe rejects dirty worktrees before `change_branch` and does not force checkout, stash, stage files, create commits, reset, rebase, merge, or edit files directly.
23
+
24
+ ## Network behavior
25
+
26
+ BranchMe makes network requests only for `pull_request`, which calls the GitHub REST API:
27
+
28
+ ```text
29
+ GET https://api.github.com/repos/{owner}/{repo}/branches/{headBranch}
30
+ GET https://api.github.com/repos/{owner}/{repo}/branches/{baseBranch}
31
+ POST https://api.github.com/repos/{owner}/{repo}/pulls
32
+ ```
33
+
34
+ The branch preflight requests have no body. BranchMe uses the `headBranch` preflight response to compare GitHub's branch commit with the local branch commit before creating the PR. The PR request body contains only the explicit PR fields supplied to the tool: title, head branch, base branch, body, and draft flag.
35
+
36
+ ## Repository boundary
37
+
38
+ BranchMe operates on the current repository only.
39
+
40
+ - The GitHub repository is inferred from local `origin` and/or `GITHUB_REPOSITORY`.
41
+ - Tool inputs never accept filesystem paths, `owner`, `repo`, or owner-prefixed `owner:branch` PR refs.
42
+ - `change_branch` accepts only `branchName` and never creates branches, checks out remote branches, forces, stashes, or discards changes.
43
+ - If local `origin` and `GITHUB_REPOSITORY` both resolve but disagree, PR creation fails closed.
44
+ - PR branch inputs are validated as existing local branch-name refs; missing local branches and cross-repository `head` values are rejected before token lookup or any GitHub request.
45
+ - 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`.
46
+
47
+ ## Credentials
48
+
49
+ `pull_request` checks `process.env.GITHUB_TOKEN`, then `process.env.GH_TOKEN`. If neither process token is set, BranchMe reads a local `.env` file from the verified git root and checks:
50
+
51
+ - `GITHUB_TOKEN` (preferred)
52
+ - `GH_TOKEN` (fallback)
53
+
54
+ Only these two token keys are read from `.env`; other `.env` keys are ignored. The fallback uses async file I/O, requires `.env` to be 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, tool content, and tool details.
55
+
56
+ ## Telemetry
57
+
58
+ BranchMe does not collect telemetry and does not send repository contents to any service beyond the explicit GitHub pull request fields provided to `pull_request`.
59
+
60
+ ## Reporting vulnerabilities
61
+
62
+ Please report suspected security vulnerabilities privately by email: <senad.dizdarevic@proton.me>.
63
+
64
+ For non-sensitive issues, use the repository issue tracker:
65
+
66
+ <https://github.com/senad-d/branchme/issues>
67
+
68
+ Do not open public issues for security-sensitive reports that include exploit details, private repository contents, secrets, or credentials.
69
+
70
+ ## Secure development checklist
71
+
72
+ - Do not commit secrets, tokens, local `.env`, local `.pi/` state, or generated artifacts.
73
+ - Keep tool schemas strict and reject unsupported fields.
74
+ - Keep all git calls argv-style through `pi.exec("git", args)`.
75
+ - Mock `pi.exec` and `fetch` in tests; do not touch real remotes.
76
+ - Keep package contents minimal with `npm run check:pack`.
77
+ - Use isolated smoke tests with `pi --no-extensions -e .`.
@@ -0,0 +1,114 @@
1
+ # Project Definition Brief
2
+
3
+ Approved on 2026-06-30.
4
+
5
+ ## 1. Bootstrap
6
+
7
+ - Template source: `/Users/senad/Documents/Code/Moj_git/pi-tmp`
8
+ - Target directory: `/Users/senad/Documents/Code/Moj_git/pi-branchme`
9
+ - Copy status: copied; target only had `.git/` and `.pi/`, both preserved/excluded.
10
+
11
+ ## 2. Project identity
12
+
13
+ - Package name: `@senad-d/branchme`
14
+ - Display name: `BranchMe`
15
+ - Exported extension function: `branchMeExtension`
16
+ - Repository URL: `https://github.com/senad-d/branchme`
17
+ - One-sentence pitch: Minimal Pi tools for changing/creating current-repo branches, publishing the current branch, and opening a GitHub pull request.
18
+
19
+ ## 3. Users and use cases
20
+
21
+ - Primary users: Pi users and CI/GitHub Actions workflows.
22
+ - Primary use cases:
23
+ - Check current git branch/repo status.
24
+ - Switch to an existing local branch after clean-worktree preflight.
25
+ - Create and checkout a new branch from current `HEAD`.
26
+ - Push the current branch to its configured upstream, or publish it to `origin` when no upstream exists.
27
+ - Create a PR in the current GitHub repo via REST API.
28
+ - Non-goals:
29
+ - No commit, staging, diff, or message generation behavior.
30
+ - No GitHub CLI dependency.
31
+ - No cross-repository PR creation.
32
+ - No labels, reviewers, projects, or issue linking in v1.
33
+
34
+ ## 4. Pi integration surface
35
+
36
+ | Surface | Name | Purpose | Notes |
37
+ | --- | --- | --- | --- |
38
+ | Command | `/branchme` | Simple TUI config/status/help panel | No git/GitHub mutations |
39
+ | Command | `/branchme help` | Workflow notes | No actions |
40
+ | Tool | `branch_status` | Read current repo/branch/upstream/dirty/push state | Read-only |
41
+ | Tool | `change_branch` | Switch to an existing local branch | Required `branchName`; rejects dirty worktrees |
42
+ | Tool | `create_branch` | Create + checkout new branch from current `HEAD` | Required `branchName`; fail if exists/invalid |
43
+ | Tool | `push_branch` | Push current branch with explicit upstream target; publish with upstream if needed | No commits/staging |
44
+ | Tool | `pull_request` | Preflight branch visibility/commit state and create PR via GitHub REST API | Required `headBranch`, `baseBranch`, `title`, `body`, `draft`; repo inferred from current checkout |
45
+ | Event | `session_start/session_shutdown` | Optional status footer cleanup | No long-lived resources |
46
+ | UI | TUI panel | Compact BranchMe workflow/config view | No persisted config assumed |
47
+ | Resource | none | No skills/prompts/themes planned | Keep package minimal |
48
+
49
+ ## 5. Architecture
50
+
51
+ - Planned files:
52
+ - `src/extension.ts`
53
+ - `src/constants.ts`
54
+ - `src/commands/branchme-command.ts`
55
+ - `src/tools/branchme-tools.ts`
56
+ - `src/git.ts`
57
+ - `src/github.ts`
58
+ - `src/types.ts`
59
+ - Module boundaries:
60
+ - Extension entrypoint only registers command/tools/events.
61
+ - Git helper owns `pi.exec("git", args)` calls and branch/repo validation.
62
+ - GitHub helper owns env token lookup, branch visibility/commit preflight, and REST requests.
63
+ - Tools expose precise TypeBox schemas and structured details.
64
+ - Dependencies:
65
+ - Pi core packages as peer deps with `"*"`.
66
+ - `@earendil-works/pi-tui` is a peer/dev dependency because the TUI panel imports width and key utilities.
67
+ - No Octokit; use Node 22 `fetch`.
68
+
69
+ ## 6. Config, state, and persistence
70
+
71
+ - Config source: no BranchMe config file; `/branchme` displays runtime status and workflow notes. GitHub tokens may come from process environment or a small regular `.env` fallback in the verified git root.
72
+ - Session state: none; tool results include useful `details`.
73
+ - Files written: none by extension code, except normal git metadata changes from branch checkout/push.
74
+ - Cleanup behavior: clear any footer/status key on `session_shutdown` if used.
75
+
76
+ ## 7. Security and privacy
77
+
78
+ - Shell execution: only `git` via argv-style `pi.exec`, not shell strings.
79
+ - File access/mutation: no working-tree file edits; git metadata changes only.
80
+ - Network access: `pull_request` calls `https://api.github.com/repos/{owner}/{repo}/branches/{branch}` before `https://api.github.com/repos/{owner}/{repo}/pulls`.
81
+ - Credentials/secrets: `GITHUB_TOKEN` / `GH_TOKEN` from process env or hardened local `.env` fallback; never log token.
82
+ - Telemetry/retention: none.
83
+ - User confirmations: no extra confirmation by default, to support automation; tools rely on explicit arguments.
84
+
85
+ ## 8. Documentation and packaging
86
+
87
+ - README changes: describe implemented behavior, workflow, tools, CI env usage.
88
+ - SECURITY changes: document git mutation, GitHub API, token behavior.
89
+ - CHANGELOG changes: rename initial unreleased entry to BranchMe.
90
+ - package.json changes: set package identity/URLs/keywords/peer deps.
91
+ - npm/git distribution plan: npm package `@senad-d/branchme`, repo `senad-d/branchme`.
92
+
93
+ ## 9. Validation plan
94
+
95
+ - Typecheck: `npm run typecheck`
96
+ - Tests: unit and isolated integration tests for commands, tools, git/GitHub helpers, package metadata, and TUI captures.
97
+ - Package dry-run: `npm run check:pack`
98
+ - Formatting: `npm run format:check`
99
+ - Full validation: `npm run validate`
100
+ - Checkout Pi smoke test: `npm run smoke:pi` / `pi --no-extensions -e .`
101
+ - Installed-artifact release smoke: `npm run smoke:pi:packed`
102
+
103
+ ## 10. Open questions and assumptions
104
+
105
+ - Questions:
106
+ - None blocking.
107
+ - Assumptions:
108
+ - `/branchme` has no persisted config in v1.
109
+ - `push_branch` uses `origin` when current branch has no upstream.
110
+ - `pull_request` infers owner/repo from current GitHub checkout or `GITHUB_REPOSITORY`, but never accepts owner/repo as tool input and requires local branch refs with `headBranch` matching GitHub.
111
+ - Decisions:
112
+ - No commit functionality.
113
+ - Tools perform all actions; slash commands are help/config only.
114
+ - PR tool requires all PR fields explicitly.
@@ -0,0 +1,41 @@
1
+ # BranchMe Smoke Test Notes
2
+
3
+ Date: 2026-06-30
4
+
5
+ Validated from the repository checkout with no discovered extensions enabled.
6
+
7
+ ## Commands
8
+
9
+ ```bash
10
+ npm run validate
11
+ npm run smoke:pi
12
+ npm run smoke:pi:packed
13
+ npm run check:pack
14
+ printf '/branchme help\n/quit\n' | pi --no-extensions -e .
15
+ pi --no-extensions -e .
16
+ ```
17
+
18
+ ## Automated smoke behavior
19
+
20
+ - `npm run smoke:pi` runs isolated checkout Pi processes from a temporary working directory: one with `pi --no-extensions -e <package> -e <temporary verifier>` and `/branchmeverify verify`, then one with `pi --no-extensions -e <package>` and `/branchme help`.
21
+ - The temporary verifier is a non-LLM Pi extension command that calls `pi.getAllTools()` after BranchMe loads and confirms `branch_status`, `change_branch`, `create_branch`, `push_branch`, and `pull_request` are active runtime tools with strict schemas, prompt guidelines, descriptions, and extension source metadata.
22
+ - The checkout smoke accepts either `/branchme help` text or the read-only BranchMe status fallback as equivalent non-mutating command output.
23
+ - `npm run smoke:pi:packed` creates an npm tarball under a temporary directory, installs that tarball into a separate temporary package with `npm install --omit=dev`, and runs pi against the installed package instead of the source checkout.
24
+ - `npm run smoke:pi:packed` is the release gate for packaged runtime imports and required packaged files; `npm run release:check` and `node scripts/publish-npm.mjs` run it before publish, while everyday `npm run validate` keeps the faster checkout smoke.
25
+ - Both smoke runs disable discovered extensions, skills, prompt templates, themes, context files, persistent sessions, telemetry, startup network checks, and GitHub token environment variables.
26
+ - Both smoke runs are credential-free, allow documented credential variable names in help text, reject credential value patterns, do not call BranchMe mutation tools, and do not contact GitHub.
27
+ - Pi's documented `getAllTools()` metadata currently exposes parameter schemas and prompt guidelines, but not `promptSnippet`, and the ExtensionAPI does not expose a safe non-LLM tool invocation method. The checkout runtime smoke therefore gates real Pi tool registration metadata; isolated `branch_status` execution remains covered by mocked unit tests and real-git helper tests until Pi exposes a direct runtime invocation API.
28
+ - Set `BRANCHME_SKIP_PI_SMOKE=1` to skip intentionally, or `BRANCHME_PI_BIN=/path/to/pi` to test a specific Pi binary for the checkout smoke.
29
+ - If no Pi binary is available, the checkout smoke script prints an explicit skip message; default CI installs the Pi dev dependency, so `npm run validate` exercises the real Pi loading path.
30
+
31
+ ## Result
32
+
33
+ - `npm run validate` passed.
34
+ - `npm run smoke:pi` loaded BranchMe through Pi, verified all five BranchMe tools through the real `pi.getAllTools()` runtime surface, and confirmed non-mutating BranchMe command output.
35
+ - `npm run smoke:pi:packed` packed BranchMe outside the repository, installed the artifact in a temporary production workspace, loaded the installed package through Pi, and confirmed non-mutating BranchMe command output.
36
+ - `npm run check:pack` confirmed the package contents are limited to public docs, images, source, license, package metadata, `.env.example`, and `tsconfig.json`.
37
+ - The isolated Pi smoke command loaded BranchMe and displayed BranchMe help or status output instead of template behavior.
38
+ - The bare `pi --no-extensions -e .` smoke command exited cleanly in this non-interactive validation environment.
39
+ - No template command or template tool output was observed.
40
+
41
+ The piped `pi --no-extensions -e .` form was also used so the smoke test could exit without leaving an interactive TUI session open.