pi-odd-worktree 0.1.0 → 1.1.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 +282 -205
- package/extensions/odd-worktree-tools.ts +84 -0
- package/lib/codegraph-commands.js +165 -0
- package/lib/codegraph-session.js +438 -0
- package/lib/issues-view.js +2 -2
- package/lib/odd-worktrees-prompt.js +109 -0
- package/lib/worktree-hooks.js +23 -4
- package/package.json +1 -1
- package/tools/codegraph-commands.test.js +371 -0
- package/tools/codegraph-session.test.js +457 -0
- package/tools/issues-command.test.js +1 -1
- package/tools/issues-view.test.js +2 -2
- package/tools/odd-worktrees-prompt.test.js +170 -0
- package/tools/package-surface.test.js +13 -4
package/README.md
CHANGED
|
@@ -1,224 +1,301 @@
|
|
|
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
|
+
| `/codegraph-hook` | command | **Only when the CodeGraph CLI is installed.** Turns the edit/write sync on or off for the session. |
|
|
22
|
+
| `/codegraph-init` | command | **Only when the CLI is installed.** Runs `codegraph init` at the session's current directory and says what happened: `initialized <path> — 1 file, 3 nodes, 3 edges`, or `already initialized at <path> — nothing to do`. |
|
|
23
|
+
| `/codegraph-sync` | command | **Only when the CLI is installed.** Runs `codegraph sync` at the session's current directory and says what happened: `already up to date — nothing to sync`, `synced 3 changed files — 12 nodes`, or `no index in this checkout — run /codegraph-init first`. |
|
|
24
|
+
|
|
25
|
+
A checkout's **name** is the slug of its branch, and its path is
|
|
26
|
+
`<repo-parent>/<repo-name>-worktrees/<slug>`: the slug lowercases the branch and
|
|
27
|
+
turns every non-alphanumeric run into `-` (`feat/login` → `feat-login`). The
|
|
28
|
+
principal checkout is `principal`. Names, paths and branches are accepted
|
|
29
|
+
interchangeably by `worktree_close`, and by `/warp`.
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
| Requirement | Why it is needed |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| Pi (`@earendil-works/pi-coding-agent`, `@earendil-works/pi-tui`) | Peer dependencies at `*`, supplied by the host. The package installs no runtime dependencies. |
|
|
36
|
+
| Node.js >= 18 and `git` | `engines` declares 18 as the floor, and every repository operation is a git child process. |
|
|
37
|
+
| `herdr` — optional | Not required: only `worktree_create` tries a Herdr workspace association, and it falls back to plain `git`. |
|
|
38
|
+
| `gh`, authenticated (`gh auth login`) | `/issues` only. Without it the command stays registered, says once per session what is missing, and never opens. |
|
|
39
|
+
| `codegraph` — optional | Keeps each checkout's index fresh: `codegraph init` when a checkout is created, and a background `codegraph sync` after edits and writes. Absent, both stay off for the whole session. |
|
|
40
|
+
| Gentle Shell — recommended | Supplies the presence and transport records the deletion guard reads to see sessions other than this one. |
|
|
2
41
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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.
|
|
42
|
+
```bash
|
|
43
|
+
pi install npm:pi-odd-worktree
|
|
44
|
+
```
|
|
37
45
|
|
|
38
|
-
|
|
46
|
+
Inside a Gentle Shell session, the same package is installed through the shell's
|
|
47
|
+
launcher:
|
|
39
48
|
|
|
40
49
|
```bash
|
|
41
|
-
|
|
50
|
+
gentle-shell install npm:pi-odd-worktree
|
|
42
51
|
```
|
|
43
52
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
53
|
+
From a local clone, `pi install .` installs the working copy instead. Neither
|
|
54
|
+
command takes a version, so the install tracks whatever npm publishes.
|
|
55
|
+
|
|
56
|
+
Herdr is not required; Gentle Shell is recommended for the live-session deletion
|
|
57
|
+
guard.
|
|
58
|
+
|
|
59
|
+
`pi.extensions` in `package.json` points at
|
|
60
|
+
`./extensions/odd-worktree-tools.ts`, so Pi loads it without any extra
|
|
61
|
+
registration. Expected result: `/warp`, `/odd-list` and `/issues` are available
|
|
62
|
+
as commands, and the four `worktree_*` tools are offered to the agent.
|
|
63
|
+
|
|
64
|
+
## Core Workflow
|
|
65
|
+
|
|
66
|
+
1. **Create** — ask the agent for a worktree, or press `c` in `/warp`.
|
|
67
|
+
`worktree_create` needs a `branch` and a mandatory `changes` selection:
|
|
68
|
+
`"all"`, `"none"`, or a list of checkout-relative paths. It never guesses,
|
|
69
|
+
and a repository with no local `main` is refused before anything is written.
|
|
70
|
+
An existing branch is adopted as-is instead of being recreated.
|
|
71
|
+
2. **List** — `worktree_list`, or open `/warp`. Pass `all: true` to the tool (or
|
|
72
|
+
`v` in the panel) to also see live checkouts the registry does not know.
|
|
73
|
+
3. **Move** — `/warp <name>`, the selector's `enter`, or `worktree_warp`. The
|
|
74
|
+
selector never offers the checkout you are already in; the exclusion is by
|
|
75
|
+
resolved real path, so a differently-spelled path to the same checkout is
|
|
76
|
+
excluded too.
|
|
77
|
+
4. **Close** — `worktree_close` with exactly one of `name`, `path` or `branch`,
|
|
78
|
+
plus `force: true` for a dirty checkout. Closing asks for approval when the
|
|
79
|
+
host offers dialog UI; creating never does, because it touches no existing
|
|
80
|
+
data.
|
|
81
|
+
|
|
82
|
+
## Key Features You Should Know About
|
|
83
|
+
|
|
84
|
+
### Panel keys
|
|
85
|
+
|
|
86
|
+
`/warp` selector — the footer legend is the key reference.
|
|
87
|
+
|
|
88
|
+
| Key | Action |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `↑`/`↓`, `j`/`k` | Move the selection |
|
|
91
|
+
| `enter` | Warp to the focused checkout (`enter` on the `view all worktrees` row opens the extended list) |
|
|
92
|
+
| `c` | Open the create flow |
|
|
93
|
+
| `ctrl+d` | Ask to delete the focused checkout; the extension owns the confirmation, the evidence and the removal |
|
|
94
|
+
| `v` | Open the extended list of every other checkout (`↑`/`↓`, `pgUp`/`pgDn`, `enter`, `T` or `/` to filter, `esc` back) |
|
|
95
|
+
| `r` | Reload the listing |
|
|
96
|
+
| `esc`, `ctrl+c` | Close the panel |
|
|
97
|
+
|
|
98
|
+
`/odd-list` — `↑`/`↓` select, `t` search (`T` and `/` also open the box), `o`
|
|
99
|
+
open the document in `$VISUAL`/`$EDITOR`, `s` toggles the order between `recent`
|
|
100
|
+
and `name`, `r` reload, `esc` close. `←`/`→` and `[`/`]` scroll the list; the
|
|
101
|
+
document pane pages with `ctrl+j`/`ctrl+k`.
|
|
102
|
+
|
|
103
|
+
`/issues` — bucket tabs are `My issues`, `Assigned`, `Involved` and `All`.
|
|
104
|
+
|
|
105
|
+
| Key | Action | Needs |
|
|
106
|
+
| --- | --- | --- |
|
|
107
|
+
| `↑`/`↓`, `j`/`k` | Move the selection | — |
|
|
108
|
+
| `←`/`→` (also `tab`/`shift+tab`) | Switch bucket | — |
|
|
109
|
+
| `]`/`[` | Scroll the list one page; the hint is deliberately absent from the footer | — |
|
|
110
|
+
| `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) | — |
|
|
111
|
+
| `t` | Open the search box (`T` and `/` also open it) | — |
|
|
112
|
+
| `o` | Open the issue in the browser through `gh issue view <n> --web -R` | — |
|
|
113
|
+
| `r` | Re-read the list and the preview freshly, and re-read your repository role | — |
|
|
114
|
+
| `l` | Labels editor: apply or remove an existing label | triage |
|
|
115
|
+
| `a` | Assignee editor | triage |
|
|
116
|
+
| `c` | Comment | read access |
|
|
117
|
+
| `x` (and `X`) | Close the issue, after the host's confirmation; only `x` rides the legend | triage |
|
|
118
|
+
| `esc`, `q`, `ctrl+c` | Close the reader | — |
|
|
119
|
+
|
|
120
|
+
Creating a **new** label is a separate capability inside the labels editor and
|
|
121
|
+
needs `write`, so a triage-only viewer opens the editor normally and sees
|
|
122
|
+
neither a create row nor its `n` keybinding. Commenting is deliberately ungated:
|
|
123
|
+
GitHub lets anyone with read access comment, so requiring triage would hide an
|
|
124
|
+
action the viewer is allowed to take. Anything but a confirmed capability fails
|
|
125
|
+
closed — no hint, the key refuses on screen, no editor opens, no mutation is
|
|
126
|
+
attempted.
|
|
127
|
+
|
|
128
|
+
### The deletion guard, and its honest limit
|
|
129
|
+
|
|
130
|
+
Deleting a checkout is refused while a live Pi session is working in it, and
|
|
131
|
+
the **same** check runs for `worktree_close` and for the panel's `ctrl+d`, both
|
|
132
|
+
before the pending-change question and again immediately before the removal.
|
|
133
|
+
This session's own checkout is refused with "warp first"; another session's is
|
|
134
|
+
refused naming its real session id, resolved by joining the published presence
|
|
135
|
+
hash to Gentle Shell's transport activation record. When no record joins, the
|
|
136
|
+
refusal shows the presence hash and says the id could not be resolved — it never
|
|
137
|
+
invents one from a label. Nothing is auto-warped and nothing is closed on your
|
|
138
|
+
behalf.
|
|
139
|
+
|
|
140
|
+
That check is **best effort, not a guarantee**:
|
|
141
|
+
|
|
142
|
+
- It reads Gentle Shell's presence records (heartbeat plus workspace) and its
|
|
143
|
+
transport activation records when Gentle Shell is installed and running, and
|
|
144
|
+
it always catches the checkout this session stands on.
|
|
145
|
+
- A heartbeat older than 15 s cannot prove a session is gone, so it is reported
|
|
146
|
+
in the close output as a stale record instead of blocking the removal forever.
|
|
147
|
+
- Live records that published no workspace, and a scan that hit its bound, are
|
|
148
|
+
disclosed too. An absent or unreadable presence store blocks nothing and is
|
|
149
|
+
disclosed as unavailable.
|
|
150
|
+
- Gentle Shell's scratch ledger is deliberately not consulted: it records what a
|
|
151
|
+
session *created*, not where it is working.
|
|
152
|
+
|
|
153
|
+
Removal is `git worktree remove <absolute path>`, with `--force` only when the
|
|
154
|
+
caller asked for it. The branch is kept, and **no Herdr workspace is closed,
|
|
155
|
+
opened or removed** on any path.
|
|
156
|
+
|
|
157
|
+
### `/issues` pins the repository
|
|
158
|
+
|
|
159
|
+
The repository identity (`<host>/<owner>/<repo>`) is pinned when the list loads,
|
|
160
|
+
and the host is part of it. Every page, detail, label, assignee and comment read
|
|
161
|
+
binds that pin, and so do every action and the `o` browser opener. If
|
|
162
|
+
the checkout's remote moves while the reader is open, mutations refuse with
|
|
163
|
+
`the checkout's repository changed since this issue list loaded (now … instead of
|
|
164
|
+
…); reopen /issues`, and the reads keep the displayed repository. An issue
|
|
165
|
+
number on screen can never be sent to another repository.
|
|
166
|
+
|
|
167
|
+
### CodeGraph stays fresh, when the CLI is installed
|
|
168
|
+
|
|
169
|
+
The probe for `codegraph` on `PATH` runs **once per session** and is cached for
|
|
170
|
+
everything below. Install the CLI mid-session and nothing changes until the next
|
|
171
|
+
start, unless you set `CODEGRAPH_FORCE=1`, which answers "present" without
|
|
172
|
+
probing.
|
|
173
|
+
|
|
174
|
+
- **On creation**, `worktree_create` runs `codegraph init` inside the new
|
|
175
|
+
checkout, so it starts with its own index. A session where the gate answered
|
|
176
|
+
false reports that step as `skipped` and names the gate as the reason; it never
|
|
177
|
+
silently pretends to have indexed anything.
|
|
178
|
+
- **On edits**, a successful `edit` or `write` schedules `codegraph sync` for the
|
|
179
|
+
git toplevel of the file touched, so a worktree syncs that worktree. The sync is
|
|
180
|
+
detached: the tool result never waits for it, and a failure never reaches you.
|
|
181
|
+
- **Debounced and coalesced.** Rapid edits collapse into one sync after ~2s, and
|
|
182
|
+
an edit that lands while a sync runs starts exactly one more when it ends —
|
|
183
|
+
never a queue.
|
|
184
|
+
- **One sync at a time across sessions**, guarded by
|
|
185
|
+
`<root>/.codegraph/pi-sync.lock` holding `{pid, startedAt}`. A lock held by a
|
|
186
|
+
live process means skip (the other session's sync already covers that tree),
|
|
187
|
+
with one bounded retry so the edit that raced it still lands. A dead pid or an
|
|
188
|
+
expired lock is taken over.
|
|
189
|
+
- **Skipped when it would be wasted**: no `.codegraph/` in that checkout, or a
|
|
190
|
+
live CodeGraph daemon (`<root>/.codegraph/daemon.pid`, either the JSON record
|
|
191
|
+
1.6 writes or the older bare pid), whose own watcher is already syncing that
|
|
192
|
+
tree.
|
|
193
|
+
- **Bounded**: a sync that never finishes is terminated after two minutes so a
|
|
194
|
+
checkout can never be wedged for the rest of the session.
|
|
195
|
+
|
|
196
|
+
Three commands exist **only when the CLI is present**, and they do not appear at
|
|
197
|
+
all otherwise:
|
|
198
|
+
|
|
199
|
+
| Command | What it does |
|
|
200
|
+
| --- | --- |
|
|
201
|
+
| `/codegraph-hook` | Turns the edit/write sync on or off for the whole process. No argument toggles; `on`, `off` and `status` say it explicitly. It starts enabled. |
|
|
202
|
+
| `/codegraph-init` | Runs `codegraph init` at the session's current directory. |
|
|
203
|
+
| `/codegraph-sync` | Runs `codegraph sync` at the session's current directory. |
|
|
204
|
+
|
|
205
|
+
The toggle lasts for the session — this package writes nothing to user
|
|
206
|
+
configuration — so `CODEGRAPH_HOOK=0` is how you start a session with it off.
|
|
207
|
+
|
|
208
|
+
### The `## ODD worktrees` block in the system prompt
|
|
209
|
+
|
|
210
|
+
The primary session's system prompt gains a short section telling the agent where
|
|
211
|
+
worktrees live, to resume an ODD in its assigned one, and — when `codegraph` is
|
|
212
|
+
present — that creation indexes the checkout and edits sync it.
|
|
213
|
+
|
|
214
|
+
It is **appended**, never substituted: the block rides
|
|
215
|
+
`systemPromptOptions.appendSystemPrompt`, so whatever Gentle Shell (or any other
|
|
216
|
+
extension) put there is preserved verbatim and our text lands after it. Two
|
|
217
|
+
variants exist, with and without the CodeGraph sentences, chosen by the same
|
|
218
|
+
session gate. Child and named-agent sessions get nothing, because their own
|
|
219
|
+
instructions are already the bounded task they received. `ODD_WORKTREE_PROMPT=0`
|
|
220
|
+
suppresses the block.
|
|
221
|
+
|
|
222
|
+
One limit, stated plainly: a string has no "must be last" flag, so the block's
|
|
223
|
+
position follows extension load order. It can sit before a later extension's
|
|
224
|
+
short hint; it can never land inside or in place of another extension's text.
|
|
225
|
+
|
|
226
|
+
### Where state lives
|
|
227
|
+
|
|
228
|
+
The worktree registry is per repository at `<git-common-dir>/pi-worktrees.json`,
|
|
229
|
+
so every worktree of the same clone sees the same rows. Session names derived
|
|
230
|
+
from an ODD write, and the warp's fork/resume bookkeeping, travel in the Pi
|
|
231
|
+
session files the host already owns. The only other file this package writes is
|
|
232
|
+
the short-lived `<root>/.codegraph/pi-sync.lock`. Nothing is written to user
|
|
233
|
+
configuration.
|
|
234
|
+
|
|
235
|
+
### Deliberately absent
|
|
236
|
+
|
|
237
|
+
This package is the worktree / ODD / issues surface only: no customize panel, no
|
|
238
|
+
plugin-tools toggles, no Herdr plugin management, and no worktree↔issue
|
|
239
|
+
association. There is nothing to configure, and `/warp`, `/odd-list` and
|
|
240
|
+
`/issues` are always on (the three `/codegraph-*` commands follow the CLI).
|
|
241
|
+
Paths, branches and arguments reach `git`, `herdr` and `gh` as fixed argv arrays,
|
|
242
|
+
never as a shell string.
|
|
144
243
|
|
|
145
244
|
## Tests
|
|
146
245
|
|
|
147
246
|
```bash
|
|
148
|
-
node --test tools/*.test.js
|
|
247
|
+
node --test tools/*.test.js # package.json `test`
|
|
149
248
|
```
|
|
150
249
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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.
|
|
250
|
+
The suite uses Node builtins only — no install step, no lockfile, no network.
|
|
251
|
+
Every temporary repository, stub binary and extension copy lives under the
|
|
252
|
+
system temp directory and is removed on exit. `tools/fixtures/load-extension.js`
|
|
253
|
+
copies the extension to a scratch `.mjs` with the two Pi imports stubbed and
|
|
254
|
+
loads it against a fake host, which is how the registered commands, tools and
|
|
255
|
+
manifest are asserted from the outside.
|
|
168
256
|
|
|
169
257
|
## CI and releases
|
|
170
258
|
|
|
171
259
|
| Workflow | Trigger | What it runs |
|
|
172
|
-
|
|
260
|
+
| --- | --- | --- |
|
|
173
261
|
| `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
|
|
262
|
+
| `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
263
|
| `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
264
|
|
|
177
|
-
The
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
`id-token:
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
`
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
-
|
|
213
|
-
|
|
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.
|
|
265
|
+
The npm package is `pi-odd-worktree`, published at 0.1.0. A release is the tag
|
|
266
|
+
`v` plus the exact `package.json` version — the 1.0.0 release is `v1.0.0` — and
|
|
267
|
+
preflight stops the run when the two disagree. Publication uses
|
|
268
|
+
[Trusted Publishing](https://docs.npmjs.com/trusted-publishers): `id-token:
|
|
269
|
+
write` is granted to the `release` job and nowhere else, and no npm credential
|
|
270
|
+
exists in the workflow or in the protected environment. A version npm already
|
|
271
|
+
serves is reported and left alone; a published version is immutable.
|
|
272
|
+
|
|
273
|
+
The `release` environment is where a release pauses for approval when reviewers
|
|
274
|
+
are attached to it, and the trusted publisher binds to this workflow file plus
|
|
275
|
+
that environment name. Publication therefore needs the trusted publisher bound
|
|
276
|
+
to this repository, this workflow file and the `release` environment, and the
|
|
277
|
+
provenance attestation binds to the public `repository` `package.json` names,
|
|
278
|
+
case-sensitively.
|
|
279
|
+
|
|
280
|
+
Release notes are generated when the GitHub Release is created and curated
|
|
281
|
+
afterwards by editing the published release (`gh release edit`); no notes file is
|
|
282
|
+
committed.
|
|
283
|
+
|
|
284
|
+
Cutting a release, contributor rules and the repository invariants are in
|
|
285
|
+
[`AGENTS.md`](AGENTS.md).
|
|
286
|
+
|
|
287
|
+
## Documentation
|
|
288
|
+
|
|
289
|
+
| Your task | Start here |
|
|
290
|
+
| --- | --- |
|
|
291
|
+
| Change the package, run the suite, cut a release | [`AGENTS.md`](AGENTS.md) |
|
|
292
|
+
| Report a bug or request a feature | [`.github/ISSUE_TEMPLATE/`](.github/ISSUE_TEMPLATE/) |
|
|
293
|
+
| Open a pull request | [`.github/PULL_REQUEST_TEMPLATE.md`](.github/PULL_REQUEST_TEMPLATE.md) |
|
|
294
|
+
|
|
295
|
+
## Next Steps
|
|
296
|
+
|
|
297
|
+
- Run `/warp` in a repository with at least one other checkout to see the
|
|
298
|
+
selector, then `worktree_list` from the agent to confirm both surfaces agree.
|
|
299
|
+
- Install `gh` and authenticate if you want `/issues`; run `gh auth login` once.
|
|
300
|
+
- Install Gentle Shell if the deletion guard should see sessions other than the
|
|
301
|
+
one you are in.
|