@senad-d/branchme 0.1.7 → 0.1.8
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 +74 -13
- package/SECURITY.md +21 -3
- package/docs/PROJECT_DEFINITION_BRIEF.md +112 -77
- package/docs/SMOKE_TEST.md +21 -11
- package/docs/STRUCTURE.md +19 -14
- package/docs/TUI_CAPTURE.md +52 -22
- package/package.json +9 -5
- package/src/commands/branchme-command.ts +9 -1
- package/src/constants.ts +12 -0
- package/src/git.ts +1027 -2
- package/src/tools/branchme-tools.ts +190 -0
- package/src/types.ts +111 -0
- package/src/ui/branchme-panel.ts +14 -3
package/docs/SMOKE_TEST.md
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
# BranchMe Smoke Test Notes
|
|
2
2
|
|
|
3
|
-
Date: 2026-
|
|
3
|
+
Date: 2026-08-23
|
|
4
4
|
|
|
5
5
|
Validated from the repository checkout with no discovered extensions enabled.
|
|
6
6
|
|
|
7
7
|
## Commands
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npm run
|
|
10
|
+
npm run typecheck
|
|
11
|
+
npm run format:check
|
|
12
|
+
npm run test
|
|
11
13
|
npm run smoke:pi
|
|
12
|
-
npm run smoke:pi:packed
|
|
13
14
|
npm run check:pack
|
|
15
|
+
npm run smoke:worktree-handoff
|
|
16
|
+
npm run validate
|
|
17
|
+
npm run smoke:pi:packed
|
|
18
|
+
npm run release:check
|
|
14
19
|
printf '/branchme help\n/quit\n' | pi --no-extensions -e .
|
|
15
20
|
pi --no-extensions -e .
|
|
16
21
|
```
|
|
@@ -18,24 +23,29 @@ pi --no-extensions -e .
|
|
|
18
23
|
## Automated smoke behavior
|
|
19
24
|
|
|
20
25
|
- `npm run smoke:pi` first runs isolated checkout Pi processes from a temporary non-Git working directory: one with `pi --no-extensions -e <package> -e <temporary verifier>` and `/branchmeverify verify`, then one with `pi --no-extensions -e <package>` and `/branchme help`.
|
|
21
|
-
- The temporary command verifier calls `pi.getAllTools()` after BranchMe loads and confirms `branch_status`, `change_branch`, `fetch_branch`, `
|
|
26
|
+
- The temporary command verifier calls `pi.getAllTools()` after BranchMe loads and confirms `branch_status`, `change_branch`, `create_branch`, `create_worktree`, `fetch_branch`, `list_worktrees`, `pull_branch`, `pull_request`, `push_branch`, `rebase_branch`, and `remove_worktree` are each registered exactly once and active with strict schemas, named prompt guidelines, descriptions, and extension source metadata.
|
|
22
27
|
- A second temporary verifier registers a deterministic local smoke model, blocks `fetch`, and runs normal prompts through real Pi lifecycle handling. It verifies automatic no-tool Git context in a temporary repository, one real `branch_status` tool refresh after a verifier-created local change, safe credential-free related-PR status with no request, and non-Git startup fallback.
|
|
28
|
+
- The Pi runtime smoke validates worktree tool registration, strict schemas, and prompt contracts only; it never creates or removes a worktree. Real-Git `list_worktrees`/`create_worktree`/`remove_worktree` lifecycle coverage runs under `npm run test` in temporary local repositories with sibling destinations under the same temporary root and no remotes.
|
|
29
|
+
- `npm run smoke:worktree-handoff` loads only BranchMe into a deterministic extension host backed by real local Git, creates a new-branch linked worktree through the registered `create_worktree` tool, and launches a separate Node verification process with the returned absolute `handoff.cwd`. That process verifies its cwd, branch, full `HEAD`, and lack of remotes. The smoke then calls the registered `remove_worktree` tool, verifies the directory is absent, and verifies the retained local branch remains at the original commit.
|
|
30
|
+
- The handoff smoke uses only a freshly created temporary source repository and sibling worktree, an empty Git config, a minimal credential-free environment, no remotes, offline Pi flags, and a fetch guard that fails on any network request. Cleanup recursively removes the isolated temporary root even on failure.
|
|
31
|
+
- `npm run validate` includes the isolated handoff smoke after package-content checks.
|
|
23
32
|
- The checkout command smoke accepts either `/branchme help` text or the read-only BranchMe status fallback as equivalent non-mutating command output.
|
|
24
33
|
- `npm run smoke:pi:packed` creates an npm tarball under a temporary directory, installs that tarball into a separate temporary package with `npm install --omit=dev`, and runs pi against the installed package instead of the source checkout.
|
|
25
|
-
- `npm run
|
|
26
|
-
- Both smoke runs disable discovered extensions, skills, prompt templates, themes, context files, persistent sessions, telemetry, startup network checks, and GitHub token environment variables.
|
|
27
|
-
- Both smoke runs are credential-free, allow documented credential variable names in help text, reject credential value patterns, do not call BranchMe mutation tools, and do not contact GitHub.
|
|
28
|
-
- Pi's documented `getAllTools()` metadata
|
|
34
|
+
- `npm run release:check` is the canonical release gate: it runs `npm run validate` and then `npm run smoke:pi:packed`. Both `node scripts/publish-npm.mjs` and the GitHub `Publish to npm` workflow run it before npm publication; a packed install/load failure stops publication and the workflow's Git tag step. Everyday `npm run validate` keeps the faster checkout smoke.
|
|
35
|
+
- Both Pi smoke runs disable discovered extensions, skills, prompt templates, themes, context files, persistent sessions, telemetry, startup network checks, and GitHub token environment variables.
|
|
36
|
+
- Both Pi smoke runs are credential-free, allow documented credential variable names in help text, reject credential value patterns, do not call BranchMe mutation or remote tools, and do not contact GitHub.
|
|
37
|
+
- Pi's documented `getAllTools()` metadata exposes parameter schemas, descriptions, prompt guidelines, and source metadata, while command context exposes active `promptSnippet` values through `getSystemPromptOptions().toolSnippets`; the runtime verifier checks both surfaces. The deterministic local smoke model exercises `branch_status` through Pi's normal model tool-call loop without provider or GitHub network access.
|
|
29
38
|
- Set `BRANCHME_SKIP_PI_SMOKE=1` to skip intentionally, or `BRANCHME_PI_BIN=/path/to/pi` to test a specific Pi binary for the checkout smoke.
|
|
30
39
|
- If no Pi binary is available, the checkout smoke script prints an explicit skip message; default CI installs the Pi dev dependency, so `npm run validate` exercises the real Pi loading path.
|
|
31
40
|
|
|
32
41
|
## Result
|
|
33
42
|
|
|
34
|
-
- `npm run validate` passed.
|
|
35
|
-
- `npm run smoke:
|
|
43
|
+
- `npm run typecheck`, `npm run format:check`, `npm run test`, `npm run smoke:pi`, `npm run check:pack`, `npm run validate`, and `npm run smoke:pi:packed` passed.
|
|
44
|
+
- `npm run smoke:worktree-handoff` returned `ok: true`, an absolute ready cwd, the expected `feature/isolated-handoff-smoke` branch and full commit ID from a separate process, `branchRetained: true` after force-free removal, zero network requests, and an isolated empty credential source.
|
|
45
|
+
- `npm run smoke:pi` loaded BranchMe through Pi, verified the complete BranchMe tool set and prompt metadata through real Pi runtime APIs, and confirmed non-mutating BranchMe command output.
|
|
36
46
|
- The isolated Git-context prompt smoke observed the `before_agent_start` snapshot, answered branch and dirty-tree state without a tool call, refreshed a verifier-created local change through one real `branch_status` call, returned safe unavailable context without credentials or outside Git, and attempted no network request.
|
|
37
47
|
- `npm run smoke:pi:packed` packed BranchMe outside the repository, installed the artifact in a temporary production workspace, loaded the installed package through Pi, and confirmed non-mutating BranchMe command output.
|
|
38
|
-
- `npm run check:pack` confirmed the package contents are limited to public docs, images, source, license, package metadata, `.env.example`, and `tsconfig.json
|
|
48
|
+
- `npm run check:pack` confirmed the package contents are limited to public docs (including worktree behavior and security boundaries), images, source, license, package metadata, `.env.example`, and `tsconfig.json`; private planning specs and generated files remain excluded.
|
|
39
49
|
- The isolated Pi smoke command loaded BranchMe and displayed BranchMe help or status output instead of template behavior.
|
|
40
50
|
- The bare `pi --no-extensions -e .` smoke command exited cleanly in this non-interactive validation environment.
|
|
41
51
|
- No template command or template tool output was observed.
|
package/docs/STRUCTURE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# BranchMe Structure Guide
|
|
2
2
|
|
|
3
|
-
BranchMe is a TypeScript Pi extension package for current-repository
|
|
3
|
+
BranchMe is a TypeScript Pi extension package for current-repository Git branch, verified linked-worktree, push, and GitHub pull request workflows.
|
|
4
4
|
|
|
5
5
|
## Source layout
|
|
6
6
|
|
|
@@ -13,8 +13,8 @@ src/
|
|
|
13
13
|
├── commands/
|
|
14
14
|
│ └── branchme-command.ts # /branchme status/help command; informational only
|
|
15
15
|
├── tools/
|
|
16
|
-
│ └── branchme-tools.ts # registration for
|
|
17
|
-
├── git.ts # argv-style
|
|
16
|
+
│ └── branchme-tools.ts # registration for eleven branch/worktree/GitHub workflow tools
|
|
17
|
+
├── git.ts # argv-style branch/worktree helpers and per-repo workflow queue
|
|
18
18
|
├── github.ts # GitHub repo resolution, env/.env tokens, branch preflight, REST calls, redaction
|
|
19
19
|
└── ui/
|
|
20
20
|
└── branchme-panel.ts # compact /branchme status panel renderer
|
|
@@ -22,11 +22,11 @@ src/
|
|
|
22
22
|
|
|
23
23
|
## Module boundaries
|
|
24
24
|
|
|
25
|
-
1. `src/extension.ts` stays small and registers the command,
|
|
25
|
+
1. `src/extension.ts` stays small and registers the command, eleven tools, and one `before_agent_start` context hook.
|
|
26
26
|
2. `src/git-context.ts` owns the shared read-only collector, escaped/bounded formatter, automatic system-prompt append, and the current-state output used by `branch_status`.
|
|
27
27
|
3. `src/commands/branchme-command.ts` parses `/branchme`, `/branchme help`, `--help`, and `-h`; it never performs git or GitHub mutations and avoids raw stdout in JSON mode.
|
|
28
|
-
4. `src/tools/branchme-tools.ts` owns TypeBox schemas, prompt metadata, tool content, and safe structured details. `branch_status` delegates to the shared context collector
|
|
29
|
-
5. `src/git.ts` owns current-repository
|
|
28
|
+
4. `src/tools/branchme-tools.ts` owns strict TypeBox schemas, prompt metadata, bounded tool content, and safe structured details. `branch_status` delegates to the shared context collector; `list_worktrees`, `create_worktree`, and `remove_worktree` expose explicit repository inventory and verified handoff operations.
|
|
29
|
+
5. `src/git.ts` owns current-repository Git behavior: root and common-Git-directory detection, branch/upstream/ahead-behind inspection, working-tree parsing, recent-commit collection, PR base/commit-subject inference, branch validation and branch workflows, NUL-delimited worktree parsing/inventory, canonical worktree path validation, verified create/remove postconditions, and the per-repository workflow queue.
|
|
30
30
|
6. `src/github.ts` owns GitHub `owner/repo` parsing, repository boundary checks, `GITHUB_TOKEN`/`GH_TOKEN` and `BRANCHME_PR_AUTOFILL` process-env/hardened git-root `.env` resolution, authenticated related-open-PR lookup, PR branch-name syntax validation, GitHub branch visibility/commit preflight, PR REST calls, bounded response validation, and redacted errors.
|
|
31
31
|
7. `src/redaction.ts` owns shared credential redaction for Git, GitHub, and prompt-bound metadata.
|
|
32
32
|
8. `src/types.ts` keeps serializable details shared by helpers, context, and tools.
|
|
@@ -36,11 +36,12 @@ src/
|
|
|
36
36
|
|
|
37
37
|
- No long-lived processes, watchers, timers, sockets, or background jobs start in the extension factory.
|
|
38
38
|
- A single `before_agent_start` handler synchronously collects a fresh snapshot for each agent run and appends it to the existing system prompt; failures degrade to bounded unavailable context rather than blocking startup.
|
|
39
|
-
- Slash commands are informational; tools perform branch
|
|
40
|
-
- Every tool uses a strict TypeBox object schema with `additionalProperties: false`.
|
|
39
|
+
- Slash commands are informational; tools perform branch, worktree, push, and PR actions. Commands never create/remove worktrees, change cwd, or start Pi sessions. There is no context command.
|
|
40
|
+
- Every tool uses a strict TypeBox object schema with `additionalProperties: false`; worktree creation requires exactly `worktreePath`, `branchName`, and `branchMode`, while listing is empty and removal accepts only `worktreePath`.
|
|
41
41
|
- Every tool defines a description, `promptSnippet`, and tool-specific `promptGuidelines` that explicitly name the tool.
|
|
42
|
-
- Git commands use `pi.exec("git", args, { cwd, signal, timeout })` with argv arrays; repository mutations run from
|
|
43
|
-
-
|
|
42
|
+
- Git commands use `pi.exec("git", args, { cwd, signal, timeout })` with argv arrays; repository mutations run from verified locations and same-repository mutation/PR windows are serialized per repository.
|
|
43
|
+
- Worktree results expose serializable requested and verified before/after state. Create returns `handoff: { cwd: <absolute>, branch, head, ready: true, summary }`; remove returns the retained branch/HEAD with `cwd: null` and `ready: false`.
|
|
44
|
+
- Tool details avoid token values, abort signals, runtime objects, and unbounded raw command/API output.
|
|
44
45
|
- Automatic and explicit context include branch/upstream/ahead-behind state, working-tree counts, up to 20 unstaged/untracked entries, related open PR state, and up to 5 recent commits. Metadata values default to 512 characters and rendered context to 4,000 characters.
|
|
45
46
|
- Pi core packages, including `@earendil-works/pi-tui` for key/width utilities, remain in `peerDependencies` with `"*"`.
|
|
46
47
|
|
|
@@ -55,10 +56,13 @@ src/
|
|
|
55
56
|
- `pull_branch` requires a clean worktree and configured upstream, then updates only the current branch with an explicit `git pull --ff-only --no-rebase --no-autostash <remote> <remote-ref>` command; divergence fails without a rebase or merge commit.
|
|
56
57
|
- `rebase_branch` requires a clean worktree and configured upstream, then rebases only the current branch with `git rebase --no-autostash --no-update-refs <upstream>`; it rewrites local commits and automatically attempts `git rebase --abort` on failure.
|
|
57
58
|
- `create_branch` mutates local branch/HEAD only with `git switch -c`.
|
|
59
|
+
- `list_worktrees` reads a bounded `git worktree list --porcelain -z` inventory and remains explicit rather than expanding automatic active-worktree context.
|
|
60
|
+
- `create_worktree` requires an explicitly approved absolute destination, canonicalizes its existing parent, rejects existing or nested/common-Git-directory destinations, and creates only from current `HEAD` or an unoccupied existing local branch. It verifies canonical path, branch, `HEAD`, and cleanliness before returning a ready handoff.
|
|
61
|
+
- `remove_worktree` resolves an exact fresh current-repository inventory match, rejects main/current/dirty/ignored-entry-containing/detached/locked/prunable/missing/bare entries, runs a bounded removal-specific ignored-entry scan, performs force-free removal with the verified path, and confirms that the local branch remains at the same commit.
|
|
58
62
|
- `push_branch` mutates remote refs only for the current branch and uses an explicit upstream remote/refspec instead of bare `git push` when an upstream exists.
|
|
59
63
|
- `pull_request` requires resolved `headBranch` and `baseBranch` values to be distinct and exist locally, requires `headBranch` to match the GitHub-visible branch commit, queues behind already-started same-repository git mutation windows, makes GitHub REST API calls for the resolved current repository only, and rejects owner-prefixed or unsafe branch refs before the request. Omitted fields require configured autofill.
|
|
60
64
|
- `pull_request` reads `GITHUB_TOKEN` or `GH_TOKEN` from process environment first; only when neither process token is set does it read those token keys from a small regular `.env` file in the verified git root as a fallback. `BRANCHME_PR_AUTOFILL` uses the same process-first, `.env`-fallback precedence and defaults off.
|
|
61
|
-
- BranchMe does not force checkout, stash, stage, create user-authored commits, reset, force-push, create merge commits, directly edit files, read unsupported `.env` keys, follow unsafe `.env` file types, depend on GitHub CLI, or collect telemetry.
|
|
65
|
+
- BranchMe does not force checkout/removal, move/prune/repair/lock/unlock worktrees, create detached/orphan worktrees, infer remote worktree branches, copy ignored/untracked files such as `.env`, remove linked worktrees that contain ignored entries, delete retained worktree branches, change Pi's cwd, or start Pi sessions. It also does not stash, stage, create user-authored commits, reset, force-push, create merge commits, directly edit files, read unsupported `.env` keys, follow unsafe `.env` file types, depend on GitHub CLI, or collect telemetry. Git documents submodule worktree support as incomplete; BranchMe adds no force-based submodule cleanup.
|
|
62
66
|
|
|
63
67
|
## Documentation
|
|
64
68
|
|
|
@@ -73,11 +77,12 @@ src/
|
|
|
73
77
|
test/
|
|
74
78
|
├── command.test.mjs # /branchme parsing, help, fallback, panel width
|
|
75
79
|
├── git-context.test.mjs # collection, prompt hook, formatting, safety, and output bounds
|
|
76
|
-
├── git.test.mjs #
|
|
77
|
-
├── git-integration.test.mjs # isolated real-
|
|
80
|
+
├── git.test.mjs # branch/worktree parsing, validation, command construction, postconditions, failures
|
|
81
|
+
├── git-integration.test.mjs # isolated real-Git context, branch, and worktree lifecycle coverage
|
|
78
82
|
├── github.test.mjs # GitHub parsing, token resolution, related-PR lookup, redaction
|
|
79
83
|
├── preparation.test.mjs # package/docs/source metadata checks
|
|
80
|
-
├──
|
|
84
|
+
├── schema-validation.test.mjs # strict TypeBox schema validation, including worktree fields/modes
|
|
85
|
+
├── tools.test.mjs # extension registration, prompt metadata, shared refresh, tool behavior
|
|
81
86
|
└── tui-capture.test.mjs # generated text capture for TUI/help visual baselines
|
|
82
87
|
```
|
|
83
88
|
|
package/docs/TUI_CAPTURE.md
CHANGED
|
@@ -16,7 +16,7 @@ UPDATE_TUI_CAPTURE=1 node --test test/tui-capture.test.mjs
|
|
|
16
16
|
```text
|
|
17
17
|
# BranchMe
|
|
18
18
|
|
|
19
|
-
Current-repository
|
|
19
|
+
Current-repository Git workflow tools for Pi.
|
|
20
20
|
|
|
21
21
|
Commands only show info; BranchMe tools perform actions.
|
|
22
22
|
|
|
@@ -31,6 +31,14 @@ Commands only show info; BranchMe tools perform actions.
|
|
|
31
31
|
7. `push_branch` — push the current branch.
|
|
32
32
|
8. `pull_request` — open a PR after `push_branch` completes and GitHub sees the branches.
|
|
33
33
|
|
|
34
|
+
## Worktree handoff
|
|
35
|
+
|
|
36
|
+
- `list_worktrees` — inspect the main and linked worktrees in the current repository.
|
|
37
|
+
- `create_worktree` — create a linked worktree and return a ready handoff with an absolute `handoff.cwd`.
|
|
38
|
+
- A separate orchestrator starts the next Pi session or subagent in `handoff.cwd`.
|
|
39
|
+
- `remove_worktree` — remove a verified clean linked worktree while retaining its local branch.
|
|
40
|
+
- BranchMe does not change cwd, start Pi, copy `.env`, or remove branches automatically.
|
|
41
|
+
|
|
34
42
|
## Requirements
|
|
35
43
|
|
|
36
44
|
- Run inside a Git repo with `git` available.
|
|
@@ -72,7 +80,7 @@ Width: 40
|
|
|
72
80
|
│ │
|
|
73
81
|
│ │
|
|
74
82
|
├──────────────────────────────────────┤
|
|
75
|
-
│ 1/
|
|
83
|
+
│ 1/3 • status • current repository on…│
|
|
76
84
|
╰──────────────────────────────────────╯
|
|
77
85
|
```
|
|
78
86
|
|
|
@@ -86,7 +94,7 @@ Width: 80
|
|
|
86
94
|
├─────────────────────┬────────────────────────────────────────────────────────┤
|
|
87
95
|
│▶ Status │ STATUS │
|
|
88
96
|
│ Workflow │ Current branch: feature/current │
|
|
89
|
-
│
|
|
97
|
+
│ Worktrees │ GitHub repository: senad-d/branchme │
|
|
90
98
|
│ │ GitHub token: present │
|
|
91
99
|
│ │ │
|
|
92
100
|
│ │ │
|
|
@@ -94,7 +102,7 @@ Width: 80
|
|
|
94
102
|
│ │ │
|
|
95
103
|
│ │ │
|
|
96
104
|
├─────────────────────┴────────────────────────────────────────────────────────┤
|
|
97
|
-
│ 1/
|
|
105
|
+
│ 1/3 • status • current repository only • tools perform actions │
|
|
98
106
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
99
107
|
```
|
|
100
108
|
|
|
@@ -107,16 +115,38 @@ Width: 80
|
|
|
107
115
|
│ ↑↓ section • q quit • /branchme help │
|
|
108
116
|
├─────────────────────┬────────────────────────────────────────────────────────┤
|
|
109
117
|
│ Status │ WORKFLOW │
|
|
110
|
-
│▶ Workflow │ branch_status
|
|
111
|
-
│
|
|
112
|
-
│ │ fetch_branch
|
|
113
|
-
│ │ pull_branch
|
|
114
|
-
│ │ rebase_branch
|
|
115
|
-
│ │ create_branch
|
|
116
|
-
│ │ push_branch
|
|
117
|
-
│ │ pull_request
|
|
118
|
+
│▶ Workflow │ branch_status -> inspect │
|
|
119
|
+
│ Worktrees │ change_branch -> existing local │
|
|
120
|
+
│ │ fetch_branch -> upstream remote │
|
|
121
|
+
│ │ pull_branch -> fast-forward │
|
|
122
|
+
│ │ rebase_branch -> onto upstream │
|
|
123
|
+
│ │ create_branch -> from HEAD │
|
|
124
|
+
│ │ push_branch -> current branch │
|
|
125
|
+
│ │ pull_request -> after push │
|
|
126
|
+
├─────────────────────┴────────────────────────────────────────────────────────┤
|
|
127
|
+
│ 2/3 • workflow • inspect → change → fetch/pull/rebase → create → push → PR │
|
|
128
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Panel: Wide mode: Worktrees selected
|
|
132
|
+
|
|
133
|
+
Width: 80
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
╭ BranchMe ───────────────────────────────────────────────────────── Worktrees ╮
|
|
137
|
+
│ ↑↓ section • q quit • /branchme help │
|
|
138
|
+
├─────────────────────┬────────────────────────────────────────────────────────┤
|
|
139
|
+
│ Status │ WORKTREES │
|
|
140
|
+
│ Workflow │ list_worktrees -> inspect inventory │
|
|
141
|
+
│▶ Worktrees │ create_worktree -> ready handoff.cwd │
|
|
142
|
+
│ │ remove_worktree -> clean linked; branch retained │
|
|
143
|
+
│ │ │
|
|
144
|
+
│ │ │
|
|
145
|
+
│ │ │
|
|
146
|
+
│ │ │
|
|
147
|
+
│ │ │
|
|
118
148
|
├─────────────────────┴────────────────────────────────────────────────────────┤
|
|
119
|
-
│
|
|
149
|
+
│ 3/3 • worktrees • create → handoff cwd → next session • remove retains branch│
|
|
120
150
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
121
151
|
```
|
|
122
152
|
|
|
@@ -130,7 +160,7 @@ Width: 112
|
|
|
130
160
|
├──────────────────────┬───────────────────────────────────────────────────────────────────────┤
|
|
131
161
|
│▶ Status │ STATUS │
|
|
132
162
|
│ Workflow │ Current branch: main │
|
|
133
|
-
│
|
|
163
|
+
│ Worktrees │ GitHub repository: senad-d/BranchMe │
|
|
134
164
|
│ │ GitHub token: not set │
|
|
135
165
|
│ │ │
|
|
136
166
|
│ │ │
|
|
@@ -138,7 +168,7 @@ Width: 112
|
|
|
138
168
|
│ │ │
|
|
139
169
|
│ │ │
|
|
140
170
|
├──────────────────────┴───────────────────────────────────────────────────────────────────────┤
|
|
141
|
-
│ 1/
|
|
171
|
+
│ 1/3 • status • current repository only • tools perform actions │
|
|
142
172
|
╰──────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
143
173
|
```
|
|
144
174
|
|
|
@@ -161,7 +191,7 @@ Width: 50
|
|
|
161
191
|
│ │
|
|
162
192
|
│ │
|
|
163
193
|
├────────────────────────────────────────────────┤
|
|
164
|
-
│ 1/
|
|
194
|
+
│ 1/3 • warning • Unable to resolve a GitHub rep…│
|
|
165
195
|
╰────────────────────────────────────────────────╯
|
|
166
196
|
```
|
|
167
197
|
|
|
@@ -175,7 +205,7 @@ Width: 80
|
|
|
175
205
|
├─────────────────────┬────────────────────────────────────────────────────────┤
|
|
176
206
|
│▶ Status │ STATUS │
|
|
177
207
|
│ Workflow │ Current branch: main │
|
|
178
|
-
│
|
|
208
|
+
│ Worktrees │ GitHub repository: warning: Repository boundary misma…│
|
|
179
209
|
│ │ GitHub token: present │
|
|
180
210
|
│ │ │
|
|
181
211
|
│ │ │
|
|
@@ -183,7 +213,7 @@ Width: 80
|
|
|
183
213
|
│ │ │
|
|
184
214
|
│ │ │
|
|
185
215
|
├─────────────────────┴────────────────────────────────────────────────────────┤
|
|
186
|
-
│ 1/
|
|
216
|
+
│ 1/3 • warning • Repository boundary mismatch: local origin resolves to senad…│
|
|
187
217
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
188
218
|
```
|
|
189
219
|
|
|
@@ -197,7 +227,7 @@ Width: 72
|
|
|
197
227
|
├───────────────────┬──────────────────────────────────────────────────┤
|
|
198
228
|
│▶ Status │ STATUS │
|
|
199
229
|
│ Workflow │ Current branch: main │
|
|
200
|
-
│
|
|
230
|
+
│ Worktrees │ GitHub repository: senad-d/branchme │
|
|
201
231
|
│ │ GitHub token: warning: Unable to read .env…│
|
|
202
232
|
│ │ │
|
|
203
233
|
│ │ │
|
|
@@ -205,7 +235,7 @@ Width: 72
|
|
|
205
235
|
│ │ │
|
|
206
236
|
│ │ │
|
|
207
237
|
├───────────────────┴──────────────────────────────────────────────────┤
|
|
208
|
-
│ 1/
|
|
238
|
+
│ 1/3 • warning • Unable to read .env file for GitHub token fallback: …│
|
|
209
239
|
╰──────────────────────────────────────────────────────────────────────╯
|
|
210
240
|
```
|
|
211
241
|
|
|
@@ -219,7 +249,7 @@ Width: 72
|
|
|
219
249
|
├───────────────────┬──────────────────────────────────────────────────┤
|
|
220
250
|
│▶ Status │ STATUS │
|
|
221
251
|
│ Workflow │ Current branch: feature/super-long-branch-na…│
|
|
222
|
-
│
|
|
252
|
+
│ Worktrees │ GitHub repository: very-long-owner-name/very-lo…│
|
|
223
253
|
│ │ GitHub token: present │
|
|
224
254
|
│ │ │
|
|
225
255
|
│ │ │
|
|
@@ -227,6 +257,6 @@ Width: 72
|
|
|
227
257
|
│ │ │
|
|
228
258
|
│ │ │
|
|
229
259
|
├───────────────────┴──────────────────────────────────────────────────┤
|
|
230
|
-
│ 1/
|
|
260
|
+
│ 1/3 • warning • This deliberately long status note is captured to de…│
|
|
231
261
|
╰──────────────────────────────────────────────────────────────────────╯
|
|
232
262
|
```
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@senad-d/branchme",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Pi extension for verified current-repository Git branch, worktree, push, and pull request workflows.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Senad Dizdarević <112484166+senad-d@users.noreply.github.com>",
|
|
8
8
|
"repository": {
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"branchme",
|
|
22
22
|
"git",
|
|
23
23
|
"git-branch",
|
|
24
|
+
"git-worktree",
|
|
24
25
|
"git-workflow",
|
|
25
26
|
"github",
|
|
26
27
|
"github-pr",
|
|
@@ -52,10 +53,11 @@
|
|
|
52
53
|
"test:coverage": "mkdir -p coverage && node --test --experimental-test-coverage --test-reporter=spec --test-reporter=lcov --test-reporter-destination=stdout --test-reporter-destination=coverage/lcov.info test/*.test.mjs",
|
|
53
54
|
"smoke:pi": "node scripts/smoke-pi-runtime.mjs && node scripts/smoke-pi-git-context.mjs",
|
|
54
55
|
"smoke:pi:packed": "node scripts/smoke-pi-installed-package.mjs",
|
|
55
|
-
"
|
|
56
|
+
"smoke:worktree-handoff": "node scripts/smoke-worktree-handoff.mjs",
|
|
57
|
+
"check": "node --check scripts/check-format.mjs && node --check scripts/check-package-contents.mjs && node --check scripts/publish-npm.mjs && node --check scripts/smoke-pi-git-context.mjs && node --check scripts/smoke-pi-installed-package.mjs && node --check scripts/smoke-pi-runtime.mjs && node --check scripts/smoke-worktree-handoff.mjs",
|
|
56
58
|
"pack:dry-run": "npm pack --dry-run --json",
|
|
57
59
|
"check:pack": "node scripts/check-package-contents.mjs",
|
|
58
|
-
"validate": "npm run typecheck && npm run format:check && npm run test && npm run smoke:pi && npm run check && npm run check:pack",
|
|
60
|
+
"validate": "npm run typecheck && npm run format:check && npm run test && npm run smoke:pi && npm run check && npm run check:pack && npm run smoke:worktree-handoff",
|
|
59
61
|
"release:check": "npm run validate && npm run smoke:pi:packed"
|
|
60
62
|
},
|
|
61
63
|
"pi": {
|
|
@@ -65,13 +67,15 @@
|
|
|
65
67
|
"image": "https://raw.githubusercontent.com/senad-d/BranchMe/main/img/demo.gif"
|
|
66
68
|
},
|
|
67
69
|
"peerDependencies": {
|
|
70
|
+
"@earendil-works/pi-ai": "*",
|
|
68
71
|
"@earendil-works/pi-coding-agent": "*",
|
|
69
72
|
"@earendil-works/pi-tui": "*",
|
|
70
73
|
"typebox": "*"
|
|
71
74
|
},
|
|
72
75
|
"devDependencies": {
|
|
76
|
+
"@earendil-works/pi-ai": "^0.84.1",
|
|
73
77
|
"@earendil-works/pi-coding-agent": "^0.84.1",
|
|
74
|
-
"@earendil-works/pi-tui": "^0.
|
|
78
|
+
"@earendil-works/pi-tui": "^0.84.1",
|
|
75
79
|
"@types/node": "^26.0.1",
|
|
76
80
|
"typebox": "^1.2.18",
|
|
77
81
|
"typescript": "^7.0.2"
|
|
@@ -25,7 +25,7 @@ export function getBranchMeHelpText(): string {
|
|
|
25
25
|
return [
|
|
26
26
|
"# BranchMe",
|
|
27
27
|
"",
|
|
28
|
-
"Current-repository
|
|
28
|
+
"Current-repository Git workflow tools for Pi.",
|
|
29
29
|
"",
|
|
30
30
|
"Commands only show info; BranchMe tools perform actions.",
|
|
31
31
|
"",
|
|
@@ -40,6 +40,14 @@ export function getBranchMeHelpText(): string {
|
|
|
40
40
|
"7. `push_branch` — push the current branch.",
|
|
41
41
|
"8. `pull_request` — open a PR after `push_branch` completes and GitHub sees the branches.",
|
|
42
42
|
"",
|
|
43
|
+
"## Worktree handoff",
|
|
44
|
+
"",
|
|
45
|
+
"- `list_worktrees` — inspect the main and linked worktrees in the current repository.",
|
|
46
|
+
"- `create_worktree` — create a linked worktree and return a ready handoff with an absolute `handoff.cwd`.",
|
|
47
|
+
"- A separate orchestrator starts the next Pi session or subagent in `handoff.cwd`.",
|
|
48
|
+
"- `remove_worktree` — remove a verified clean linked worktree while retaining its local branch.",
|
|
49
|
+
"- BranchMe does not change cwd, start Pi, copy `.env`, or remove branches automatically.",
|
|
50
|
+
"",
|
|
43
51
|
"## Requirements",
|
|
44
52
|
"",
|
|
45
53
|
"- Run inside a Git repo with `git` available.",
|
package/src/constants.ts
CHANGED
|
@@ -9,6 +9,9 @@ export const PULL_BRANCH_TOOL_NAME = "pull_branch";
|
|
|
9
9
|
export const REBASE_BRANCH_TOOL_NAME = "rebase_branch";
|
|
10
10
|
export const PUSH_BRANCH_TOOL_NAME = "push_branch";
|
|
11
11
|
export const PULL_REQUEST_TOOL_NAME = "pull_request";
|
|
12
|
+
export const LIST_WORKTREES_TOOL_NAME = "list_worktrees";
|
|
13
|
+
export const CREATE_WORKTREE_TOOL_NAME = "create_worktree";
|
|
14
|
+
export const REMOVE_WORKTREE_TOOL_NAME = "remove_worktree";
|
|
12
15
|
export const PULL_REQUEST_AUTOFILL_ENV_NAME = "BRANCHME_PR_AUTOFILL";
|
|
13
16
|
|
|
14
17
|
export const BRANCHME_TOOL_NAMES = [
|
|
@@ -20,6 +23,9 @@ export const BRANCHME_TOOL_NAMES = [
|
|
|
20
23
|
REBASE_BRANCH_TOOL_NAME,
|
|
21
24
|
PUSH_BRANCH_TOOL_NAME,
|
|
22
25
|
PULL_REQUEST_TOOL_NAME,
|
|
26
|
+
LIST_WORKTREES_TOOL_NAME,
|
|
27
|
+
CREATE_WORKTREE_TOOL_NAME,
|
|
28
|
+
REMOVE_WORKTREE_TOOL_NAME,
|
|
23
29
|
] as const;
|
|
24
30
|
|
|
25
31
|
export const GIT_STATUS_TIMEOUT_MS = 5_000;
|
|
@@ -28,6 +34,7 @@ export const GIT_FETCH_TIMEOUT_MS = 120_000;
|
|
|
28
34
|
export const GIT_PULL_TIMEOUT_MS = 120_000;
|
|
29
35
|
export const GIT_REBASE_TIMEOUT_MS = 120_000;
|
|
30
36
|
export const GIT_PUSH_TIMEOUT_MS = 120_000;
|
|
37
|
+
export const GIT_WORKTREE_MUTATION_TIMEOUT_MS = 120_000;
|
|
31
38
|
export const GITHUB_RELATED_PR_TIMEOUT_MS = 4_000;
|
|
32
39
|
|
|
33
40
|
export const GIT_CONTEXT_RECENT_COMMIT_LIMIT = 5;
|
|
@@ -36,6 +43,11 @@ export const GIT_CONTEXT_VALUE_LIMIT_CHARS = 512;
|
|
|
36
43
|
export const GIT_CONTEXT_SUMMARY_LIMIT_CHARS = 4_000;
|
|
37
44
|
export const PULL_REQUEST_AUTOFILL_COMMIT_LIMIT = 20;
|
|
38
45
|
export const PULL_REQUEST_AUTOFILL_SUBJECT_LIMIT_CHARS = 256;
|
|
46
|
+
export const GIT_WORKTREE_RAW_OUTPUT_LIMIT_BYTES = 128 * 1024;
|
|
47
|
+
export const GIT_WORKTREE_ENTRY_LIMIT = 100;
|
|
48
|
+
export const GIT_WORKTREE_PATH_LIMIT_CHARS = 4_096;
|
|
49
|
+
export const GIT_WORKTREE_REASON_LIMIT_CHARS = 512;
|
|
50
|
+
export const GIT_WORKTREE_SUMMARY_LIMIT_CHARS = 4_000;
|
|
39
51
|
|
|
40
52
|
export const GITHUB_API_BASE_URL = "https://api.github.com";
|
|
41
53
|
export const GITHUB_API_VERSION = "2022-11-28";
|