pi-odd-worktree 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,224 +1,235 @@
1
- # odd-worktree
1
+ # pi-odd-worktree
2
+
3
+ A Pi extension package for agent worktrees, ODD documents and GitHub issues.
4
+ Four agent tools, three panels, one extension entry point. It works in Pi
5
+ alone; Herdr is optional.
6
+
7
+ ## What It Does
8
+
9
+ `package.json` declares one Pi extension,
10
+ `./extensions/odd-worktree-tools.ts`, and that file registers everything below.
11
+
12
+ | Surface | Kind | What it does |
13
+ | --- | --- | --- |
14
+ | `worktree_list` | tool | Lists the principal checkout, then this session's own checkout, then the rest, cross-checked against live git checkouts. Rows whose path is gone are excluded and pruned from the registry. |
15
+ | `worktree_create` | tool | Creates a branch and its checkout from the **local** `main`, registers it, runs the creation hooks, and copies the pending changes you name. |
16
+ | `worktree_warp` | tool | Queues the session move to another checkout as a `/warp` handoff; the command performs the move when the turn ends. |
17
+ | `worktree_close` | tool | Removes a registered checkout with `git worktree remove`, keeping the branch, and refuses while a live Pi session is working in it. |
18
+ | `/warp` | panel | Moves this session to another checkout: no argument opens the selector (list, create, delete, extended list); `/warp <name>` jumps straight there. |
19
+ | `/odd-list` | panel | Two-pane reader of this checkout's `odd/tasks/*.md`: list on the left, styled markdown on the right. |
20
+ | `/issues` | panel | Full-screen reader of this checkout's repository issues — My issues / Assigned / Involved / All — with preview, comments, labels, assignees and close, gated on your repository role. |
21
+
22
+ A checkout's **name** is the slug of its branch, and its path is
23
+ `<repo-parent>/<repo-name>-worktrees/<slug>`: the slug lowercases the branch and
24
+ turns every non-alphanumeric run into `-` (`feat/login` → `feat-login`). The
25
+ principal checkout is `principal`. Names, paths and branches are accepted
26
+ interchangeably by `worktree_close`, and by `/warp`.
27
+
28
+ ## Quick Start
29
+
30
+ | Requirement | Why it is needed |
31
+ | --- | --- |
32
+ | Pi (`@earendil-works/pi-coding-agent`, `@earendil-works/pi-tui`) | Peer dependencies at `*`, supplied by the host. The package installs no runtime dependencies. |
33
+ | Node.js >= 18 and `git` | `engines` declares 18 as the floor, and every repository operation is a git child process. |
34
+ | `herdr` — optional | Not required: only `worktree_create` tries a Herdr workspace association, and it falls back to plain `git`. |
35
+ | `gh`, authenticated (`gh auth login`) | `/issues` only. Without it the command stays registered, says once per session what is missing, and never opens. |
36
+ | Gentle Shell — recommended | Supplies the presence and transport records the deletion guard reads to see sessions other than this one. |
2
37
 
3
- [![CI](https://github.com/jonasotoaguilar/odd-worktree/actions/workflows/ci.yml/badge.svg)](https://github.com/jonasotoaguilar/odd-worktree/actions/workflows/ci.yml)
4
-
5
- A Pi package for agent worktrees, ODD documents and GitHub issues:
6
- create/list/close/warp checkouts from the agent, drive the same work from the
7
- `/warp` panel, read the project's `odd/` documents with `/odd-list`, and read
8
- this checkout's GitHub issues with `/issues`.
9
-
10
- It runs in Pi alone. Herdr is optional, and only `worktree_create` uses it (the
11
- best-effort workspace association): every Herdr call there is attempted first
12
- and falls back to plain `git`, so nothing here requires a Herdr install. Removal
13
- never touches Herdr at all — a close never closes, opens or removes a Herdr
14
- workspace, and it removes the checkout with `git worktree remove`.
15
-
16
- ## Surface
17
-
18
- Three commands:
19
-
20
- | Command | What it does |
21
- |---|---|
22
- | `/warp` | Move this session to another checkout of the project. No argument opens the selector (list, create, delete); `/warp <name>` jumps straight to the flattened branch slug or `principal`. |
23
- | `/odd-list` | Two-pane viewer of this checkout's `odd/` documents: list on the left, styled markdown on the right. |
24
- | `/issues` | Full-screen reader of this checkout's repository issues: My issues / Assigned / Involved / All, live server search, issue preview with comments, and label/assignee, comment and close actions when the repository permits them. |
25
-
26
- Four agent tools:
27
-
28
- | Tool | What it does |
29
- |---|---|
30
- | `worktree_create` | Create a branch and its checkout from local `main`, register it, run the creation hooks, optionally copy pending changes. |
31
- | `worktree_list` | Read-only listing: principal first, then the session's own checkout, then the rest. Prunes rows whose checkout is gone. |
32
- | `worktree_close` | Remove a registered checkout and keep the branch. Needs `force: true` for a dirty checkout. Refuses while a live Pi session is working in that checkout — this session (warp first) or another (let it finish, close it, or warp it away). |
33
- | `worktree_warp` | Queue the session move to another checkout. The tool only queues it as `/warp <handoff>`; the command performs the move when the turn ends. |
34
-
35
- Create and close ask for approval when the host offers dialog UI. `list` never
36
- mutates anything.
38
+ ```bash
39
+ pi install npm:pi-odd-worktree
40
+ ```
37
41
 
38
- ## Install
42
+ Inside a Gentle Shell session, the same package is installed through the shell's
43
+ launcher:
39
44
 
40
45
  ```bash
41
- pi install . # from this directory
46
+ gentle-shell install npm:pi-odd-worktree
42
47
  ```
43
48
 
44
- `package.json` declares `pi.extensions`, so Pi loads
45
- `extensions/odd-worktree-tools.ts` on its own.
46
-
47
- ## Requirements
48
-
49
- - Node.js >= 18 and `git`.
50
- - Pi (`@earendil-works/pi-coding-agent`, `@earendil-works/pi-tui`) — peer
51
- dependencies, provided by the host.
52
- - Optional: `herdr` for the create's workspace association; `codegraph` for the
53
- create hook's index step. Both are detected at runtime and skipped when
54
- absent. Gentle Shell's published presence store (when Gentle Shell is
55
- installed) is what makes the active-session check see *other* sessions; without
56
- it, only this session's own checkout is detected.
57
- - `/issues` needs the GitHub CLI (`gh`) installed and authenticated
58
- (`gh auth login`). Without it the command stays registered, says once per
59
- session what is missing and never opens the reader.
60
-
61
- ## Where state lives
62
-
63
- The registry is per repository at `<git-common-dir>/pi-worktrees.json`, so a
64
- worktree of the same clone sees the same rows. Session names derived from an
65
- ODD write and the warp's fork/resume bookkeeping travel in the Pi session files
66
- the host already owns. Nothing is written to user config.
67
-
68
- ## Contract worth knowing
69
-
70
- - A new branch is born from the LOCAL `main` ref. A repository without a local
71
- `main` is refused before anything is written, rather than seeding the branch
72
- from whatever the invoking checkout had.
73
- - `worktree_create` requires `changes`: `"all"`, `"none"`, or an explicit list
74
- of checkout-relative paths. The create never guesses.
75
- - Paths, branches and arguments reach `git`/`herdr`/`gh` as fixed argv
76
- arrays, never as a shell string.
77
- - Deleting a checkout is refused while a live Pi session is working in it, and
78
- the SAME check runs for the `worktree_close` tool and for the warp panel's
79
- `ctrl+d` — before the pending-change question, and again immediately before
80
- the removal. This session's own checkout is refused with "warp first"; another
81
- session's is refused naming its REAL session id — the guard joins the
82
- presence hash to Gentle Shell's published transport activation record for that
83
- session. When no record joins (a peer that has not published one, an over-cap
84
- or unreadable registry), the refusal shows the presence hash and says the
85
- session id could not be resolved; it never invents one from a label. Nothing
86
- is auto-warped and nothing is closed on the human's behalf: the history is
87
- theirs to move.
88
- - That check is BEST EFFORT, not a guarantee. It reads Gentle Shell's published
89
- presence records (heartbeat plus workspace) and transport activation records
90
- (the raw session id) when Gentle Shell is installed and running, and it always
91
- catches the checkout this session stands on. A record whose heartbeat is older
92
- than 15 s cannot prove a session is gone, so it is disclosed in the close
93
- output as a stale record instead of blocking the removal forever; the same
94
- close output also discloses live records that published no workspace (so they
95
- could not be attributed to a checkout) and a presence or transport scan that
96
- hit its bound. A presence store that is absent or unreadable blocks nothing
97
- and is disclosed. Gentle Shell's scratch ledger is deliberately not used: it
98
- records what a session *created*, not where it is working.
99
- - Removal is `git worktree remove <absolute path>`, with `--force` only when the
100
- caller asked for it. The branch is kept, and no Herdr panel is closed, opened
101
- or removed on any path.
102
- - The `/warp` selector never offers the checkout the session already stands in:
103
- warping there would move the session to the route it is already on. The
104
- exclusion is by checkout identity (the resolved real path), not by spelling,
105
- so a symlinked or otherwise differently-spelled path to the current checkout
106
- is excluded too, while a checkout whose name merely shares a prefix is still
107
- offered.
108
- - `/issues` pins the repository identity (`<host>/<owner>/<repo>`) when the
109
- list loads. Every page, detail, label and assignee read binds it, and so do
110
- the actions and the `o` browser opener (`gh issue view <n> --web -R`). If the
111
- checkout's remote moves while the reader is open, mutations refuse and the
112
- reads keep the displayed repository, so an issue number on screen can never
113
- be sent to another repository.
114
- - `/issues` resolves the viewer's permission for that pinned repository before
115
- an action editor opens, not when the write is sent. The evidence is the
116
- repository role the issue detail already reads (`viewerPermission`), it is
117
- cached for the panel session, and `r` re-reads it. Anything but a confirmed
118
- capability fails closed — the footer hint is absent, the key refuses with the
119
- reason on screen, and no editor opens and no mutation is attempted:
120
-
121
- | Action | Minimum role |
122
- | --- | --- |
123
- | close / reopen an issue | triage |
124
- | apply or remove an existing label | triage |
125
- | assign or unassign | triage |
126
- | create a repository label | write |
127
- | comment | none beyond read access |
128
-
129
- Creating a label is a SEPARATE, write-level capability, so a triage-only
130
- viewer opens the labels editor normally and sees neither a create row nor its
131
- `n` keybinding. Commenting is deliberately ungated: GitHub lets anyone with
132
- read access to the repository comment, so demanding triage would hide an
133
- action the viewer is allowed to take.
134
- - Refusals are reported, not swallowed: a rejected name, a dirty checkout, a
135
- failed move, or a denied GitHub capability names the reason and leaves the
136
- repository as it was.
137
-
138
- ## Deliberately absent
139
-
140
- This package is the worktree/ODD/issues surface only. It has no customize
141
- panel, no plugin-tools toggles, no Herdr plugin management, and no
142
- worktree↔issue association — there is nothing to configure, and the three
143
- commands above are always on.
49
+ From a local clone, `pi install .` installs the working copy instead. Neither
50
+ command takes a version, so the install tracks whatever npm publishes.
51
+
52
+ Herdr is not required; Gentle Shell is recommended for the live-session deletion
53
+ guard.
54
+
55
+ `pi.extensions` in `package.json` points at
56
+ `./extensions/odd-worktree-tools.ts`, so Pi loads it without any extra
57
+ registration. Expected result: `/warp`, `/odd-list` and `/issues` are available
58
+ as commands, and the four `worktree_*` tools are offered to the agent.
59
+
60
+ ## Core Workflow
61
+
62
+ 1. **Create** — ask the agent for a worktree, or press `c` in `/warp`.
63
+ `worktree_create` needs a `branch` and a mandatory `changes` selection:
64
+ `"all"`, `"none"`, or a list of checkout-relative paths. It never guesses,
65
+ and a repository with no local `main` is refused before anything is written.
66
+ An existing branch is adopted as-is instead of being recreated.
67
+ 2. **List** — `worktree_list`, or open `/warp`. Pass `all: true` to the tool (or
68
+ `v` in the panel) to also see live checkouts the registry does not know.
69
+ 3. **Move** — `/warp <name>`, the selector's `enter`, or `worktree_warp`. The
70
+ selector never offers the checkout you are already in; the exclusion is by
71
+ resolved real path, so a differently-spelled path to the same checkout is
72
+ excluded too.
73
+ 4. **Close** — `worktree_close` with exactly one of `name`, `path` or `branch`,
74
+ plus `force: true` for a dirty checkout. Closing asks for approval when the
75
+ host offers dialog UI; creating never does, because it touches no existing
76
+ data.
77
+
78
+ ## Key Features You Should Know About
79
+
80
+ ### Panel keys
81
+
82
+ `/warp` selector — the footer legend is the key reference.
83
+
84
+ | Key | Action |
85
+ | --- | --- |
86
+ | `↑`/`↓`, `j`/`k` | Move the selection |
87
+ | `enter` | Warp to the focused checkout (`enter` on the `view all worktrees` row opens the extended list) |
88
+ | `c` | Open the create flow |
89
+ | `ctrl+d` | Ask to delete the focused checkout; the extension owns the confirmation, the evidence and the removal |
90
+ | `v` | Open the extended list of every other checkout (`↑`/`↓`, `pgUp`/`pgDn`, `enter`, `T` or `/` to filter, `esc` back) |
91
+ | `r` | Reload the listing |
92
+ | `esc`, `ctrl+c` | Close the panel |
93
+
94
+ `/odd-list` — `↑`/`↓` select, `t` search (`T` and `/` also open the box), `o`
95
+ open the document in `$VISUAL`/`$EDITOR`, `s` toggles the order between `recent`
96
+ and `name`, `r` reload, `esc` close. `←`/`→` and `[`/`]` scroll the list; the
97
+ document pane pages with `ctrl+j`/`ctrl+k`.
98
+
99
+ `/issues` — bucket tabs are `My issues`, `Assigned`, `Involved` and `All`.
100
+
101
+ | Key | Action | Needs |
102
+ | --- | --- | --- |
103
+ | `↑`/`↓`, `j`/`k` | Move the selection | — |
104
+ | `←`/`→` (also `tab`/`shift+tab`) | Switch bucket | — |
105
+ | `]`/`[` | Scroll the list one page; the hint is deliberately absent from the footer | — |
106
+ | `ctrl+j`/`ctrl+k` | Scroll the preview a page (`ctrl+shift+j/k`, `shift+J/K` and `pgUp`/`pgDn` also work; `ctrl+d`/`ctrl+u` scroll half a page) | — |
107
+ | `t` | Open the search box (`T` and `/` also open it) | — |
108
+ | `o` | Open the issue in the browser through `gh issue view <n> --web -R` | — |
109
+ | `r` | Re-read the list and the preview freshly, and re-read your repository role | — |
110
+ | `l` | Labels editor: apply or remove an existing label | triage |
111
+ | `a` | Assignee editor | triage |
112
+ | `c` | Comment | read access |
113
+ | `x` (and `X`) | Close the issue, after the host's confirmation; only `x` rides the legend | triage |
114
+ | `esc`, `q`, `ctrl+c` | Close the reader | — |
115
+
116
+ Creating a **new** label is a separate capability inside the labels editor and
117
+ needs `write`, so a triage-only viewer opens the editor normally and sees
118
+ neither a create row nor its `n` keybinding. Commenting is deliberately ungated:
119
+ GitHub lets anyone with read access comment, so requiring triage would hide an
120
+ action the viewer is allowed to take. Anything but a confirmed capability fails
121
+ closed — no hint, the key refuses on screen, no editor opens, no mutation is
122
+ attempted.
123
+
124
+ ### The deletion guard, and its honest limit
125
+
126
+ Deleting a checkout is refused while a live Pi session is working in it, and
127
+ the **same** check runs for `worktree_close` and for the panel's `ctrl+d`, both
128
+ before the pending-change question and again immediately before the removal.
129
+ This session's own checkout is refused with "warp first"; another session's is
130
+ refused naming its real session id, resolved by joining the published presence
131
+ hash to Gentle Shell's transport activation record. When no record joins, the
132
+ refusal shows the presence hash and says the id could not be resolved — it never
133
+ invents one from a label. Nothing is auto-warped and nothing is closed on your
134
+ behalf.
135
+
136
+ That check is **best effort, not a guarantee**:
137
+
138
+ - It reads Gentle Shell's presence records (heartbeat plus workspace) and its
139
+ transport activation records when Gentle Shell is installed and running, and
140
+ it always catches the checkout this session stands on.
141
+ - A heartbeat older than 15 s cannot prove a session is gone, so it is reported
142
+ in the close output as a stale record instead of blocking the removal forever.
143
+ - Live records that published no workspace, and a scan that hit its bound, are
144
+ disclosed too. An absent or unreadable presence store blocks nothing and is
145
+ disclosed as unavailable.
146
+ - Gentle Shell's scratch ledger is deliberately not consulted: it records what a
147
+ session *created*, not where it is working.
148
+
149
+ Removal is `git worktree remove <absolute path>`, with `--force` only when the
150
+ caller asked for it. The branch is kept, and **no Herdr workspace is closed,
151
+ opened or removed** on any path.
152
+
153
+ ### `/issues` pins the repository
154
+
155
+ The repository identity (`<host>/<owner>/<repo>`) is pinned when the list loads,
156
+ and the host is part of it. Every page, detail, label, assignee and comment read
157
+ binds that pin, and so do every action and the `o` browser opener. If
158
+ the checkout's remote moves while the reader is open, mutations refuse with
159
+ `the checkout's repository changed since this issue list loaded (now … instead of
160
+ …); reopen /issues`, and the reads keep the displayed repository. An issue
161
+ number on screen can never be sent to another repository.
162
+
163
+ ### Where state lives
164
+
165
+ The worktree registry is per repository at `<git-common-dir>/pi-worktrees.json`,
166
+ so every worktree of the same clone sees the same rows. Session names derived
167
+ from an ODD write, and the warp's fork/resume bookkeeping, travel in the Pi
168
+ session files the host already owns. Nothing is written to user configuration.
169
+
170
+ ### Deliberately absent
171
+
172
+ This package is the worktree / ODD / issues surface only: no customize panel, no
173
+ plugin-tools toggles, no Herdr plugin management, and no worktree↔issue
174
+ association. There is nothing to configure, and the three commands are always on.
175
+ Paths, branches and arguments reach `git`, `herdr` and `gh` as fixed argv arrays,
176
+ never as a shell string.
144
177
 
145
178
  ## Tests
146
179
 
147
180
  ```bash
148
- node --test tools/*.test.js
181
+ node --test tools/*.test.js # package.json `test`
149
182
  ```
150
183
 
151
- `tools/package-surface.test.js`, `tools/worktree-tools.test.js`,
152
- `tools/commands.test.js` and `tools/issues-command.test.js` cover this
153
- package's own surface: registration, manifest, the three checkout tools against
154
- a real temporary repository with a deliberately unusable Herdr, the three
155
- command handlers, and `/issues` end to end against an injected `gh` runner (no
156
- network, no real GitHub mutation). `tools/worktree-session-guard.test.js` pins
157
- the active-session guard against synthetic presence stores (live, stale,
158
- malformed and linked records), `tools/worktree-close-herdr-async.test.js` pins
159
- that a close removes with git and spawns no Herdr at all, and
160
- `tools/warp-delete-confirm.test.js` drives the real `/warp` command to prove the
161
- session check runs before the deletion question and again after it. The
162
- remaining suites cover the shared `lib/` modules (the warp create panel, warp
163
- selector view, ODD viewer and document reader, the GitHub issue client and
164
- view, delete evidence, change transfer, registry, session bookkeeping).
165
-
166
- Tests keep every temporary repository, stub binary and extension copy under the
167
- system temp directory and remove them on exit.
184
+ The suite uses Node builtins only — no install step, no lockfile, no network.
185
+ Every temporary repository, stub binary and extension copy lives under the
186
+ system temp directory and is removed on exit. `tools/fixtures/load-extension.js`
187
+ copies the extension to a scratch `.mjs` with the two Pi imports stubbed and
188
+ loads it against a fake host, which is how the registered commands, tools and
189
+ manifest are asserted from the outside.
168
190
 
169
191
  ## CI and releases
170
192
 
171
193
  | Workflow | Trigger | What it runs |
172
- |---|---|---|
194
+ | --- | --- | --- |
173
195
  | `ci.yml` | push to `main`, every pull request | `node --test tools/*.test.js` on Node 18, 20, 22 and 24 — the range `engines` declares, 18 as its floor |
174
- | `pr-check.yml` | pull request opened, edited, reopened or updated | the PR title and every non-merge commit subject must follow [Conventional Commits](https://www.conventionalcommits.org/), plus one test run on Node 22 |
196
+ | `pr-check.yml` | pull request opened, edited, reopened or synchronized | the PR title and every non-merge commit subject must follow [Conventional Commits](https://www.conventionalcommits.org/), plus one suite run on Node 22 |
175
197
  | `release.yml` | tag `v*` push, or a manual dispatch naming an existing tag | tag/`package.json` version parity, the suite, the GitHub Release, then `npm publish`, then verification |
176
198
 
177
- The suite uses Node builtins only, so CI installs nothing and needs no lockfile.
178
- No workflow stores a registry credential: npm publication uses
179
- [Trusted Publishing](https://docs.npmjs.com/trusted-publishers), with
180
- `id-token: write` granted to the `release` job and nowhere else.
181
-
182
- ### Cutting a release
183
-
184
- 1. Set `version` in `package.json`, then tag the exact commit:
185
- `git tag -a v0.2.0 -m v0.2.0 && git push origin v0.2.0`. The tag must be `v`
186
- plus the `package.json` version, or the run stops in preflight.
187
- 2. The workflow creates the GitHub Release with generated base notes. Curate the
188
- title and body afterwards by editing the published release
189
- (`gh release edit v0.2.0 --title ... --notes-file ...`); notes are never
190
- committed to the repository.
191
- 3. A version npm already serves is reported and left alone; a version npm does
192
- not have is published with provenance. A published version is immutable — fix
193
- the cause and cut the next patch tag.
194
-
195
- ### npm publication prerequisites
196
-
197
- `pi-odd-worktree` is not on npm yet, and OIDC cannot publish a
198
- package's first version, so the npm step of `release.yml` fails visibly until
199
- these are done by hand. It is never silently skipped.
200
-
201
- - Publish the first version by hand (`npm publish --access public`, 2FA, no
202
- stored token).
203
- - Bind the trusted publisher to this repository, workflow file `release.yml`
204
- and the `release` environment, then cut the next version within two days — npm
205
- expires a configuration that has not completed a publish in that window.
206
- - Add a `repository` field to `package.json` before the first publish: the
207
- provenance attestation binds to the public repository it names,
208
- case-sensitively, and published version metadata is immutable. This repository
209
- is currently private, and provenance requires a public repository, so that has
210
- to be resolved (make it public, or decide not to publish attestations) before
211
- `--provenance` can succeed.
212
- - Create the `release` environment (Settings → Environments) and attach required
213
- reviewers if a release should pause for approval.
214
- - Confirm `files[]` still lists every shipped surface with
215
- `npm pack --dry-run` before the first publish.
216
-
217
- ### Enforcement still manual
218
-
219
- Workflow presence is not enforcement. Required status checks on `main`
220
- (`CI / Test (Node …)` and the `PR Check` gates) need a branch protection rule or
221
- ruleset, which this repository cannot currently apply: it is private, and GitHub
222
- only offers those settings to public repositories or GitHub Pro.
223
- `.github/CODEOWNERS` names the owner for review requests; review-from-code-owners
224
- is part of the same protection rule.
199
+ The npm package is `pi-odd-worktree`, published at 0.1.0. A release is the tag
200
+ `v` plus the exact `package.json` version — the 1.0.0 release is `v1.0.0` — and
201
+ preflight stops the run when the two disagree. Publication uses
202
+ [Trusted Publishing](https://docs.npmjs.com/trusted-publishers): `id-token:
203
+ write` is granted to the `release` job and nowhere else, and no npm credential
204
+ exists in the workflow or in the protected environment. A version npm already
205
+ serves is reported and left alone; a published version is immutable.
206
+
207
+ The `release` environment is where a release pauses for approval when reviewers
208
+ are attached to it, and the trusted publisher binds to this workflow file plus
209
+ that environment name. Publication therefore needs the trusted publisher bound
210
+ to this repository, this workflow file and the `release` environment, and the
211
+ provenance attestation binds to the public `repository` `package.json` names,
212
+ case-sensitively.
213
+
214
+ Release notes are generated when the GitHub Release is created and curated
215
+ afterwards by editing the published release (`gh release edit`); no notes file is
216
+ committed.
217
+
218
+ Cutting a release, contributor rules and the repository invariants are in
219
+ [`AGENTS.md`](AGENTS.md).
220
+
221
+ ## Documentation
222
+
223
+ | Your task | Start here |
224
+ | --- | --- |
225
+ | Change the package, run the suite, cut a release | [`AGENTS.md`](AGENTS.md) |
226
+ | Report a bug or request a feature | [`.github/ISSUE_TEMPLATE/`](.github/ISSUE_TEMPLATE/) |
227
+ | Open a pull request | [`.github/PULL_REQUEST_TEMPLATE.md`](.github/PULL_REQUEST_TEMPLATE.md) |
228
+
229
+ ## Next Steps
230
+
231
+ - Run `/warp` in a repository with at least one other checkout to see the
232
+ selector, then `worktree_list` from the agent to confirm both surfaces agree.
233
+ - Install `gh` and authenticate if you want `/issues`; run `gh auth login` once.
234
+ - Install Gentle Shell if the deletion guard should see sessions other than the
235
+ one you are in.
@@ -149,7 +149,7 @@ const FOOTER_KEYS = [
149
149
  // because selection already drags the list window, so it left the row.
150
150
  // S16: an editor entry carries the capability it needs, and the render
151
151
  // drops the whole hint when that capability is not confirmed true.
152
- { key: 'L', text: 'L labels', short: 'L', priority: 50, requires: 'canEditLabels' },
152
+ { key: 'l', text: 'l labels', short: 'l', priority: 50, requires: 'canEditLabels' },
153
153
  { key: 'a', text: 'a assign', short: 'a', priority: 48, requires: 'canEditAssignees' },
154
154
  { key: 'c', text: 'c comment', short: 'c', priority: 45 },
155
155
  // Closing (and reopening) is a TRIAGE-level repository capability like the two
@@ -2165,7 +2165,7 @@ function createIssuesView(options = {}) {
2165
2165
  repaint();
2166
2166
  return;
2167
2167
  }
2168
- if (keyMatches(helpers, data, ['L'])) {
2168
+ if (keyMatches(helpers, data, ['l', 'L'])) {
2169
2169
  openLabelEditor();
2170
2170
  return;
2171
2171
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-odd-worktree",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
4
  "description": "Pi package for odd-worktree: the Agent Worktree tools (create, list, close, warp), the /warp worktree panel, the /odd-list ODD viewer, and the /issues GitHub issue reader. Works in Pi alone; Herdr is optional.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -633,7 +633,7 @@ describe('/issues actions (S3,S4)', () => {
633
633
  const triage = makeIssuesRunner({ role: 'TRIAGE' });
634
634
  const { component: triaged } = await openIssues(triageRoot, { runner: triage.runner });
635
635
  const triageFrame = () => clean(triaged.render(200).join('\n'));
636
- assert.ok(await waitFor(() => triageFrame().includes('L labels')), 'triage may open the label editor');
636
+ assert.ok(await waitFor(() => triageFrame().includes('l labels')), 'triage may open the label editor');
637
637
 
638
638
  triaged.handleInput('L');
639
639
  assert.equal(triaged.state.mode, 'labels', 'the triage viewer reaches the editor');
@@ -2034,7 +2034,7 @@ describe('S16: repository permissions gate the label and assignee editors', () =
2034
2034
  });
2035
2035
  await tick();
2036
2036
  const body = bodyOf(view, 220);
2037
- assert.equal(body.includes('L labels'), shown, `labels hint for ${JSON.stringify(permissions)}`);
2037
+ assert.equal(body.includes('l labels'), shown, `labels hint for ${JSON.stringify(permissions)}`);
2038
2038
  assert.equal(body.includes('a assign'), shown, `assignees hint for ${JSON.stringify(permissions)}`);
2039
2039
  }
2040
2040
  });
@@ -2162,7 +2162,7 @@ describe('S16: repository permissions gate the label and assignee editors', () =
2162
2162
  loadAssignees: () => { calls.push('loadAssignees'); return users(); },
2163
2163
  });
2164
2164
  await tick();
2165
- assert.match(bodyOf(view, 220), /L labels/, 'the permitted issue shows the hint');
2165
+ assert.match(bodyOf(view, 220), /l labels/, 'the permitted issue shows the hint');
2166
2166
  view.handleInput('j');
2167
2167
  await tick();
2168
2168
  const body = bodyOf(view, 220);