@henryqw/pi-herdr-tools 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/LICENSE +21 -0
- package/README.md +204 -0
- package/docs/btw-merge-sequence.html +156 -0
- package/docs/btw-merge-sequence.svg +138 -0
- package/docs/clone-flow.html +170 -0
- package/docs/clone-flow.svg +131 -0
- package/docs/done-flow.html +212 -0
- package/docs/done-flow.svg +166 -0
- package/docs/workflow-overview.html +114 -0
- package/docs/workflow-overview.svg +105 -0
- package/extensions/index.ts +12 -0
- package/internal/btw.ts +836 -0
- package/internal/clone-tab.ts +405 -0
- package/internal/config.ts +103 -0
- package/internal/context-store.ts +286 -0
- package/internal/core.ts +411 -0
- package/internal/done.ts +99 -0
- package/internal/merge.ts +317 -0
- package/internal/rename.ts +442 -0
- package/internal/router.ts +42 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Henry Wang
|
|
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,204 @@
|
|
|
1
|
+
# `@henryqw/pi-herdr-tools`
|
|
2
|
+
|
|
3
|
+
Clone a conversation into a Herdr tab or worktree, ask a side question and merge its answer back, name the conversation, and finish the worktree safely. One package and one extension entry point provide `/clone-tab`, `/clone-worktree`, `/btw`, `/rename`, and `/done`.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pi install npm:@henryqw/pi-task-models
|
|
11
|
+
pi install npm:@henryqw/pi-herdr-tools
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Requires Herdr 0.7.4+. Herdr operations require a Herdr-managed Pi pane; outside Herdr, rename still sets the Pi session title. Run `/task-models`, configure `fast`, and verify it no longer says `not configured` before using title generation or side threads.
|
|
15
|
+
|
|
16
|
+
### Migrating from the merged packages
|
|
17
|
+
|
|
18
|
+
`@henryqw/pi-herdr-btw`, `@henryqw/pi-herdr-clone`, and `@henryqw/pi-herdr-rename` are retired. `pi-herdr-clone` previously absorbed `pi-herdr-done`; that package is retired too. Install the replacement first, then remove any old installs before restarting Pi:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
pi install npm:@henryqw/pi-herdr-tools
|
|
22
|
+
pi remove npm:@henryqw/pi-herdr-btw
|
|
23
|
+
pi remove npm:@henryqw/pi-herdr-clone
|
|
24
|
+
pi remove npm:@henryqw/pi-herdr-rename
|
|
25
|
+
# Only if the older standalone completion package is still installed:
|
|
26
|
+
pi remove npm:@henryqw/pi-herdr-done
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Only remove sources you have installed. For project-local installs, use `--local` on each command. Remove manually configured old entry-point paths as well; loading an old package alongside this one duplicates commands. The harness installer removes retired personal npm sources only after the selected replacement installs successfully.
|
|
30
|
+
|
|
31
|
+
No data migration is needed. Commands and safety behavior are unchanged. Existing `pi-herdr-btw/btw` and `pi-herdr-rename/rename` task-model assignments, `pi-herdr-rename/title` session entries, BTW payload flags, and pending deliveries keep their identifiers. BTW configuration remains at `~/.pi/agent/config/pi-herdr-btw/config.json` despite the new package name. Individual features are internal modules, not separately selectable extension resources.
|
|
32
|
+
|
|
33
|
+
## Works with
|
|
34
|
+
|
|
35
|
+
| Package | Relationship | Purpose |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| [`@henryqw/pi-memory`](https://pi.henry.wang/extensions/pi-memory) | Improves | Recognizes side-thread children and suppresses parent-only memory injection and dream advice. |
|
|
38
|
+
| [`@henryqw/pi-task-models`](https://pi.henry.wang/extensions/pi-task-models) | Required | Shared profiles for title generation and side-thread routes. |
|
|
39
|
+
|
|
40
|
+
The shared [`@henryqw/pi-herdr`](https://pi.henry.wang/packages/pi-herdr) CLI library remains separate. Side questions are inspired by [Claude Code](https://github.com/anthropics/claude-code); this package also merges their transcripts back into Main.
|
|
41
|
+
|
|
42
|
+
## Use
|
|
43
|
+
|
|
44
|
+
Run `/clone-tab` to open a new Herdr tab with a clone of the active conversation path; the original session remains open.
|
|
45
|
+
|
|
46
|
+
| Surface | Type | Purpose |
|
|
47
|
+
| --- | --- | --- |
|
|
48
|
+
| `/clone-tab` | command | Clone the current conversation into a new tab of the current Herdr workspace. |
|
|
49
|
+
| `/clone-worktree` | command | Clone the current conversation into a new Herdr Git worktree workspace. |
|
|
50
|
+
| `/done [--force]` | command | Remove the current worktree and close its Herdr workspace tabs; `--force` skips confirmation and permits forced removal without checking for tabs in other workspaces. |
|
|
51
|
+
| `/btw [<question...>]` | command | For humans in Main: open an empty side pane or start with an editable question draft. |
|
|
52
|
+
| `/btw ask <question...>` | command | For humans in Main: ask a question whose first word is `ask`, `config`, `merge`, or `help`. |
|
|
53
|
+
| `/btw config [option value]` | command | For humans: show values, set `auto-submit` to `on` or `off`, set `tools` to `inherit`, `all`, `read-only`, or `none`, set `split` to `right` or `down`, or reset defaults. |
|
|
54
|
+
| `/btw merge [<prompt...>]` | command | For humans: in a side pane, queue its transcript and next prompt for Main (`/btw merge` opens the prompt editor); in Main, scan for pending side-thread deliveries. |
|
|
55
|
+
| `/btw help` | command | For humans: show the command grammar. |
|
|
56
|
+
| `/rename` | command | For people: generate a new title from up to five recent user messages. |
|
|
57
|
+
| First real user prompt | ui | In a new, untitled conversation, starts title generation once the expanded prompt is ready. |
|
|
58
|
+
| `pi-herdr-rename/rename` | model task | Title-generation route; users configure its profile through `/task-models`. |
|
|
59
|
+
|
|
60
|
+
### Clone conversations and finish worktrees
|
|
61
|
+
|
|
62
|
+
The active path runs from the session root to its current leaf when the command is invoked. Sibling branches and still-streaming assistant output are excluded. Both clone commands require a Pi session in a Herdr pane (`HERDR_ENV=1` and `HERDR_PANE_ID`) and validate the pane, session path, and current leaf before creating a target. If Pi has not written the session file yet, the commands clone the live session state. Neither command has configuration, and the original Pi session is not switched.
|
|
63
|
+
|
|
64
|
+
Commit or discard changes in a Herdr-managed linked worktree, then run `/done` and confirm. Normal removal refuses dirty worktrees and worktrees in use by another Herdr workspace. **`/done --force` can irreversibly delete uncommitted work and leave other workspaces' tabs pointing at the removed checkout.**
|
|
65
|
+
|
|
66
|
+
### Ask and merge side questions
|
|
67
|
+
|
|
68
|
+
From a Herdr-managed Pi pane with a conversation, run `/btw Why is this test failing?` to open a side pane with the question as an editable draft. Submit it there; after the answer, run `/btw merge Apply the smallest safe fix`. Main receives the side transcript, regains focus, and continues with the merge prompt.
|
|
69
|
+
|
|
70
|
+
### Name conversations
|
|
71
|
+
|
|
72
|
+
In a new, untitled conversation, send the first real prompt. Pi generates a title in the background without delaying the reply.
|
|
73
|
+
|
|
74
|
+
## Flow
|
|
75
|
+
|
|
76
|
+
### Clone conversations and finish worktrees
|
|
77
|
+
|
|
78
|
+

|
|
79
|
+
|
|
80
|
+
#### Clone a tab
|
|
81
|
+
|
|
82
|
+
1. Create an unfocused Herdr tab in the current workspace with the current working directory.
|
|
83
|
+
2. Start Pi in the tab's root pane with `--session <absolute-clone-file>`.
|
|
84
|
+
3. Focus the new tab after Pi starts successfully.
|
|
85
|
+
|
|
86
|
+
#### Clone a worktree
|
|
87
|
+
|
|
88
|
+
1. Create a Git worktree-backed workspace with `herdr worktree create --workspace <current-workspace> --no-focus`. Herdr creates the branch from `HEAD` unless the name exists, checks out the worktree under its configured `worktrees.directory`, and opens it as a grouped workspace. If the current workspace is already a linked worktree, the command targets its repository's parent workspace because Herdr creates worktrees from the parent.
|
|
89
|
+
2. Wait briefly for a worktree-layout plugin, such as `herdr-plus`, to start its agent in the new workspace's root pane.
|
|
90
|
+
3. If the root pane is occupied, create an additional unfocused tab in the new workspace with the checkout as its working directory. The plugin's agent and the clone then coexist. Otherwise, use the root pane.
|
|
91
|
+
4. Copy the active path into a clone session stamped with the fresh checkout path as its working directory.
|
|
92
|
+
5. Start Pi in the chosen pane with `--session <absolute-clone-file>`.
|
|
93
|
+
6. Focus the clone's tab after Pi starts successfully.
|
|
94
|
+
|
|
95
|
+
#### Finish a worktree
|
|
96
|
+
|
|
97
|
+

|
|
98
|
+
|
|
99
|
+
Normal `/done` asks for confirmation before waiting for Pi to become idle; declining leaves the checkout untouched. `/done --force` skips confirmation. Both wait for Pi to become idle before cleanup.
|
|
100
|
+
|
|
101
|
+
Normal cleanup checks whether a tab in another Herdr workspace is using the checkout, removes it with `git worktree remove <checkout>`, closes every other tab in the current Herdr workspace, and runs `git pull --ff-only` from the primary checkout when this was a linked worktree and the primary is non-bare. It closes the current tab last. Tabs using the primary checkout do not block removal or the pull. Concurrent completions serialize on locks around the worktree and primary checkout; clone creation shares the worktree lock.
|
|
102
|
+
|
|
103
|
+
### Side questions
|
|
104
|
+
|
|
105
|
+
#### Launch
|
|
106
|
+
|
|
107
|
+
- `ask`, `config`, `merge`, and `help` route only when they are exact first words. Other input is a question.
|
|
108
|
+
- A provided question is an editable draft by default.
|
|
109
|
+
- `/btw` gives the side pane a static snapshot of Main's compaction-aware context and shares Main's working directory.
|
|
110
|
+
- The consumer-owned `pi-herdr-btw/btw` task defaults to `fast`.
|
|
111
|
+
- Before pane launch, it selects the first authenticated viable effective profile route.
|
|
112
|
+
|
|
113
|
+
`~/.pi/agent/config/pi-task-models/config.json` is shared and owned by `@henryqw/pi-task-models`. A task entry is an explicit user override, and routes resolve before pane launch. BTW warns once per session if this file is missing.
|
|
114
|
+
|
|
115
|
+
#### Merge delivery
|
|
116
|
+
|
|
117
|
+

|
|
118
|
+
|
|
119
|
+
- In the side pane, a merge stores the user/assistant transcript and next prompt as pending delivery.
|
|
120
|
+
- Herdr then refocuses Main and closes the side pane.
|
|
121
|
+
- Pending delivery survives side-pane shutdown. It waits for Main to settle and for current model authentication.
|
|
122
|
+
- Main appends the transcript without starting a turn, then submits the prompt.
|
|
123
|
+
- Pending delivery remains available until consumed or 24-hour stale cleanup.
|
|
124
|
+
|
|
125
|
+
### Conversation titles
|
|
126
|
+
|
|
127
|
+
#### Trigger
|
|
128
|
+
|
|
129
|
+
In a new, untitled session, the first real user prompt generates a title in the background after Pi expands skill and prompt-template shorthand. It does not delay the main reply. Extension-injected prompts, empty prompts, and image-only input are ignored.
|
|
130
|
+
|
|
131
|
+
#### Title and branch rules
|
|
132
|
+
|
|
133
|
+
A semantic branch is a Git-safe branch name made from a task kind and the display-title words. The model replies with one JSON object holding `kind` and `subject`; that classification stays internal. For example, `{"kind":"refactor","subject":"update task logic"}` displays as `Update task logic` and maps to `refactor/update-task-logic`. A reply that does not fit the shape is sent back once with the rejection before the route gives up on it, so a valid title still comes from the first route.
|
|
134
|
+
|
|
135
|
+
- In a linked worktree, a detached checkout or Herdr `worktree/...` branch is renamed. An existing non-generated branch stays.
|
|
136
|
+
- A linked worktree's generated workspace label, such as `worktree-brave-meadow-4aa8`, becomes the display title automatically. A manual `/rename` can also replace a custom workspace name.
|
|
137
|
+
- The pane is renamed in Herdr. The enclosing tab updates only when this pane is the tab's only pane.
|
|
138
|
+
- Outside Herdr, only the Pi session name changes. Herdr is required for pane, tab, workspace, and linked-worktree branch updates.
|
|
139
|
+
|
|
140
|
+
#### Model route
|
|
141
|
+
|
|
142
|
+
The task `pi-herdr-rename/rename` uses `fast` only when it has no explicit assignment. To use another configured profile, assign the task to that profile in `/task-models`; the shared [`pi-task-models` config](https://pi.henry.wang/extensions/pi-task-models#config) stores the assignment under `tasks` at `~/.pi/agent/config/pi-task-models/config.json`.
|
|
143
|
+
|
|
144
|
+
The extension tries the assigned profile's primary route, then its fallback, while honoring the configured thinking level. Within one route a reply that fails the title shape is retried once with the rejected text; only a second failure moves on to the fallback. It never substitutes the current session model.
|
|
145
|
+
|
|
146
|
+
## Config
|
|
147
|
+
|
|
148
|
+
Package-owned: `~/.pi/agent/config/pi-herdr-btw/config.json`
|
|
149
|
+
|
|
150
|
+
| Name | Description | Values | Default |
|
|
151
|
+
| --- | --- | --- | --- |
|
|
152
|
+
| `autoSubmit` | Submits the draft question instead of leaving it editable in the side pane. | Boolean. | `false` |
|
|
153
|
+
| `tools` | Selects the tools available in the side pane. | `inherit` (parent's active tools), `all`, `read-only` (built-in read-only tools), or `none`. | `inherit` |
|
|
154
|
+
| `split` | Sets the side-pane placement. | `right` or `down`. | `right` |
|
|
155
|
+
|
|
156
|
+
- All fields are optional.
|
|
157
|
+
- Unknown keys and non-object files are rejected.
|
|
158
|
+
- `/btw config show` prints effective values.
|
|
159
|
+
- `/btw config reset` saves the defaults.
|
|
160
|
+
- The config file is optional. Missing config uses defaults.
|
|
161
|
+
- Malformed config fails visibly and remains unchanged.
|
|
162
|
+
|
|
163
|
+
## State and storage
|
|
164
|
+
|
|
165
|
+
### Clones
|
|
166
|
+
|
|
167
|
+
Each clone is a separate Pi session file in Pi's session directory, containing only the active path. A tab clone uses the current working directory; a worktree clone uses the fresh checkout. Pi's session manager chooses the session directory. For a persisted source session, Pi names the clone file; before the source session has been written to disk, the extension creates and names the clone file in that directory.
|
|
168
|
+
|
|
169
|
+
### Conversation titles
|
|
170
|
+
|
|
171
|
+
The Pi session stores each generated display title and semantic branch in a `pi-herdr-rename/title` session entry. When resuming a session created by this version, the extension reapplies the saved title and branch without another model request.
|
|
172
|
+
|
|
173
|
+
## Limits and recovery
|
|
174
|
+
|
|
175
|
+
### Cloning
|
|
176
|
+
|
|
177
|
+
| Outcome | What remains and how to recover |
|
|
178
|
+
| --- | --- |
|
|
179
|
+
| Definitive target creation failure | A failed `/clone-tab` tab creation removes its clone session when cleanup succeeds; if cleanup also fails, the error names the leftover file. A `/clone-worktree` worktree-creation or pre-launch extra-tab-creation failure happens before a clone session is created. |
|
|
180
|
+
| Killed or incomplete worktree creation | Herdr may have retained partial workspace state. The error reports any returned IDs and suggests inspecting `herdr workspace list`. No clone session has been created yet. |
|
|
181
|
+
| Incomplete tab-creation response | The error reports known IDs. For `/clone-tab`, the clone session is retained and its path is reported. For `/clone-worktree`, the worktree is retained and no clone session exists yet. Inspect the target before manual cleanup. |
|
|
182
|
+
| Agent start attempted | The launch outcome may be unknown. Retain the target tab, panes, and session file; the error reports known IDs for recovery. |
|
|
183
|
+
| Focus failed after Pi started | Show a warning, but do not report the already-started clone as failed. Focus the clone tab in Herdr if needed. |
|
|
184
|
+
|
|
185
|
+
### Worktree completion
|
|
186
|
+
|
|
187
|
+
- `/done` refuses to remove a dirty worktree. Commit or discard changes first. `/done --force` passes `--force` to Git and can irreversibly delete uncommitted work.
|
|
188
|
+
- A tab in another Herdr workspace that uses this checkout blocks normal removal. `/done` lists the tab label, or its ID when no label is available. Close the tab and retry, or use `/done --force` only if you accept removing the checkout while that tab still refers to it. Tabs in other workspaces are not closed.
|
|
189
|
+
- The command requires Pi inside Herdr with `HERDR_ENV=1`, `HERDR_WORKSPACE_ID`, and `HERDR_TAB_ID` set.
|
|
190
|
+
- The primary checkout update runs only after worktree removal. If `git pull --ff-only` fails, for example because the primary has diverged or has local changes, the worktree is already gone and the current tab still closes. Resolve the primary checkout issue, then retry with `git -C <primary-checkout> pull --ff-only`.
|
|
191
|
+
|
|
192
|
+
### Side questions
|
|
193
|
+
|
|
194
|
+
The side pane shares Main's working directory, so enabled tools can change parent-visible files. Choose `read-only` or `none` when the side question should not make changes.
|
|
195
|
+
|
|
196
|
+
Large parent contexts can exceed child context limits; shorten Main's context and retry.
|
|
197
|
+
|
|
198
|
+
### Conversation titles
|
|
199
|
+
|
|
200
|
+
Display titles are natural task phrases, preferably two or three words, and always at most four words and 20 characters. Models that answer in another language still produce English titles.
|
|
201
|
+
|
|
202
|
+
A missing shared task-model config warns once at session start. Run `/task-models` to configure rename routing. No viable route leaves titles unchanged. `/rename` warns if the session has no user text to rename.
|
|
203
|
+
|
|
204
|
+
Herdr and Git synchronization failures appear as warnings. Fix the reported issue, then run `/rename` to try again. Cancellation by a newer rename remains silent. Older titles receive no migration.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>From /btw side question to Main</title>
|
|
7
|
+
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
8
|
+
<style>
|
|
9
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
10
|
+
body { min-height: 100vh; display: grid; place-items: center; background: #f0eee9; }
|
|
11
|
+
figure { width: min(1280px, 100%); }
|
|
12
|
+
svg { display: block; width: 100%; height: auto; }
|
|
13
|
+
</style>
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<figure>
|
|
17
|
+
<svg width="1280" height="720" viewBox="0 0 1280 720" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="btw-merge-sequence-title btw-merge-sequence-desc">
|
|
18
|
+
<title id="btw-merge-sequence-title">From /btw side question to Main</title>
|
|
19
|
+
<desc id="btw-merge-sequence-desc">Sequence diagram showing Main launching an editable Herdr side thread from a static context snapshot while shared working-directory effects remain live. The side pane runs /btw merge with its text transcript and next prompt, which immediately establishes pending delivery. Herdr then refocuses Main and closes the side pane. The pending delivery survives side-pane shutdown and waits for Main to become idle with current model authentication before appending the transcript without starting a turn and submitting the next prompt.</desc>
|
|
20
|
+
<defs>
|
|
21
|
+
<style>
|
|
22
|
+
@import url('https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap');
|
|
23
|
+
.eyebrow { fill: #4c5665; font: 500 10px 'Geist Mono', monospace; letter-spacing: .18em; }
|
|
24
|
+
.diagram-title { fill: #101828; font: 400 28px 'Instrument Serif', serif; }
|
|
25
|
+
.diagram-subtitle { fill: #4c5665; font: 400 14px 'Geist', sans-serif; }
|
|
26
|
+
.lifeline { stroke: rgba(16,24,40,.22); stroke-width: 1; stroke-dasharray: 4 4; }
|
|
27
|
+
.activation { fill: rgba(16,24,40,.06); stroke: #4c5665; stroke-width: .8; }
|
|
28
|
+
.message { fill: none; stroke: #4c5665; stroke-width: 1.2; marker-end: url(#btw-arrow); }
|
|
29
|
+
.message-live { fill: none; stroke: #4c5665; stroke-width: 1.2; stroke-dasharray: 4 4; marker-end: url(#btw-arrow-open); }
|
|
30
|
+
.message-focal { fill: none; stroke: #1d4ed8; stroke-width: 1.4; marker-end: url(#btw-arrow-accent); }
|
|
31
|
+
.label-mask { fill: #f0eee9; }
|
|
32
|
+
.label { fill: #4c5665; font: 500 10px 'Geist Mono', monospace; letter-spacing: .06em; text-anchor: middle; }
|
|
33
|
+
.label-focal { fill: #1d4ed8; font: 500 10px 'Geist Mono', monospace; letter-spacing: .06em; text-anchor: middle; }
|
|
34
|
+
.note { fill: #4c5665; font: 400 14px 'Geist', sans-serif; }
|
|
35
|
+
.actor { fill: #fff; stroke: #101828; stroke-width: 1; }
|
|
36
|
+
.actor-tag { fill: none; stroke: rgba(16,24,40,.32); stroke-width: .8; }
|
|
37
|
+
.tag { fill: #4c5665; font: 500 10px 'Geist Mono', monospace; letter-spacing: .08em; text-anchor: middle; }
|
|
38
|
+
.name { fill: #101828; font: 600 14px 'Geist', sans-serif; text-anchor: middle; }
|
|
39
|
+
.sub { fill: #4c5665; font: 400 10px 'Geist Mono', monospace; text-anchor: middle; }
|
|
40
|
+
.pending { fill: #e5e3df; stroke: #4c5665; stroke-width: 1; }
|
|
41
|
+
.legend { fill: #4c5665; font: 400 10px 'Geist', sans-serif; }
|
|
42
|
+
</style>
|
|
43
|
+
<marker id="btw-arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
44
|
+
<polygon points="0 0,8 3,0 6" fill="#4c5665"/>
|
|
45
|
+
</marker>
|
|
46
|
+
<marker id="btw-arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
47
|
+
<polygon points="0 0,8 3,0 6" fill="#1d4ed8"/>
|
|
48
|
+
</marker>
|
|
49
|
+
<marker id="btw-arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
50
|
+
<polygon points="0 0,8 3,0 6" fill="#1d4ed8"/>
|
|
51
|
+
</marker>
|
|
52
|
+
<marker id="btw-arrow-open" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
53
|
+
<polyline points="0 0,8 3,0 6" fill="none" stroke="#4c5665" stroke-width="1.2"/>
|
|
54
|
+
</marker>
|
|
55
|
+
</defs>
|
|
56
|
+
|
|
57
|
+
<rect width="1280" height="720" fill="#f0eee9"/>
|
|
58
|
+
|
|
59
|
+
<text class="eyebrow" x="48" y="24">SEQUENCE · BTW MERGE DELIVERY</text>
|
|
60
|
+
<text class="diagram-title" x="48" y="56">From /btw side question to Main</text>
|
|
61
|
+
<text class="diagram-subtitle" x="48" y="80">The conversation snapshot stays fixed. File changes in the shared working directory do not.</text>
|
|
62
|
+
|
|
63
|
+
<!-- Lifelines -->
|
|
64
|
+
<line class="lifeline" x1="184" y1="164" x2="184" y2="684"/>
|
|
65
|
+
<line class="lifeline" x1="640" y1="164" x2="640" y2="684"/>
|
|
66
|
+
<line class="lifeline" x1="1096" y1="164" x2="1096" y2="684"/>
|
|
67
|
+
|
|
68
|
+
<!-- Activations -->
|
|
69
|
+
<rect class="activation" x="180" y="176" width="8" height="108"/>
|
|
70
|
+
<rect class="activation" x="636" y="264" width="8" height="396"/>
|
|
71
|
+
<rect class="activation" x="1092" y="312" width="8" height="272"/>
|
|
72
|
+
<rect class="activation" x="180" y="652" width="8" height="32"/>
|
|
73
|
+
|
|
74
|
+
<!-- Messages -->
|
|
75
|
+
<path class="message" d="M188 184 H240 Q248 184 248 192 V212 Q248 220 240 220 H188"/>
|
|
76
|
+
<line class="message" x1="188" y1="276" x2="636" y2="276"/>
|
|
77
|
+
<line class="message" x1="644" y1="320" x2="1092" y2="320"/>
|
|
78
|
+
<path class="message" d="M1100 348 H1152 Q1160 348 1160 356 V372 Q1160 380 1152 380 H1100"/>
|
|
79
|
+
<line class="message-live" x1="1092" y1="400" x2="188" y2="400"/>
|
|
80
|
+
<line class="message" x1="1092" y1="456" x2="644" y2="456"/>
|
|
81
|
+
<line class="message" x1="636" y1="540" x2="188" y2="540"/>
|
|
82
|
+
<line class="message" x1="644" y1="576" x2="1092" y2="576"/>
|
|
83
|
+
<line class="message-focal" x1="636" y1="660" x2="188" y2="660"/>
|
|
84
|
+
<path class="message" d="M188 676 H240 Q248 676 248 680 Q248 684 240 684 H188"/>
|
|
85
|
+
|
|
86
|
+
<!-- Message labels -->
|
|
87
|
+
<rect class="label-mask" x="264" y="172" width="264" height="84" rx="4"/>
|
|
88
|
+
<text class="label" x="280" y="188" style="text-anchor:start">PREPARE</text>
|
|
89
|
+
<text class="note" x="272" y="208">Snapshot compaction-aware context</text>
|
|
90
|
+
<text class="note" x="272" y="228">Capture cwd and active tools</text>
|
|
91
|
+
<text class="note" x="272" y="248">Resolve an authenticated route</text>
|
|
92
|
+
|
|
93
|
+
<rect class="label-mask" x="344" y="260" width="136" height="20" rx="2"/>
|
|
94
|
+
<text class="label" x="412" y="274">STATIC CONTEXT</text>
|
|
95
|
+
<rect class="label-mask" x="800" y="304" width="136" height="20" rx="2"/>
|
|
96
|
+
<text class="label" x="868" y="318">OPEN SIDE PANE</text>
|
|
97
|
+
<rect class="label-mask" x="1156" y="332" width="104" height="20" rx="2"/>
|
|
98
|
+
<text class="label" x="1208" y="346">SIDE ANSWER</text>
|
|
99
|
+
<rect class="label-mask" x="808" y="384" width="120" height="20" rx="2"/>
|
|
100
|
+
<text class="label" x="868" y="398">SHARED CWD</text>
|
|
101
|
+
<text class="note" x="868" y="428" text-anchor="middle">Tool writes are immediately visible to Main</text>
|
|
102
|
+
<rect class="label-mask" x="816" y="440" width="104" height="20" rx="2"/>
|
|
103
|
+
<text class="label" x="868" y="454">/BTW MERGE</text>
|
|
104
|
+
<text class="note" x="904" y="480" text-anchor="middle">Text transcript + next prompt</text>
|
|
105
|
+
<rect class="label-mask" x="352" y="524" width="120" height="20" rx="2"/>
|
|
106
|
+
<text class="label" x="412" y="538">REFOCUS MAIN</text>
|
|
107
|
+
<rect class="label-mask" x="816" y="560" width="104" height="20" rx="2"/>
|
|
108
|
+
<text class="label" x="868" y="574">CLOSE PANE</text>
|
|
109
|
+
<rect class="label-mask" x="336" y="648" width="152" height="20" rx="2"/>
|
|
110
|
+
<text class="label-focal" x="412" y="662">APPEND WITHOUT TURN</text>
|
|
111
|
+
<rect class="label-mask" x="264" y="668" width="128" height="20" rx="2"/>
|
|
112
|
+
<text class="label" x="328" y="682">SUBMIT PROMPT</text>
|
|
113
|
+
|
|
114
|
+
<!-- Durable state and actors -->
|
|
115
|
+
<rect class="pending" x="496" y="468" width="288" height="56" rx="6"/>
|
|
116
|
+
<text class="name" x="640" y="488">Pending delivery established</text>
|
|
117
|
+
<text class="sub" x="640" y="508">DURABLE BEFORE REFOCUS / CLOSE</text>
|
|
118
|
+
|
|
119
|
+
<rect class="pending" x="496" y="584" width="288" height="60" rx="6"/>
|
|
120
|
+
<text class="name" x="640" y="608">Pending delivery waits</text>
|
|
121
|
+
<text class="sub" x="640" y="624">MAIN IDLE + AUTH</text>
|
|
122
|
+
<text class="sub" x="640" y="640">SURVIVES SIDE-PANE SHUTDOWN</text>
|
|
123
|
+
|
|
124
|
+
<rect class="actor" x="64" y="96" width="240" height="68" rx="6"/>
|
|
125
|
+
<rect class="actor-tag" x="72" y="104" width="40" height="16" rx="2"/>
|
|
126
|
+
<text class="tag" x="92" y="116">MAIN</text>
|
|
127
|
+
<text class="name" x="184" y="140">Main</text>
|
|
128
|
+
<text class="sub" x="184" y="156">USER RUNS /BTW</text>
|
|
129
|
+
|
|
130
|
+
<rect class="actor" x="520" y="96" width="240" height="68" rx="6"/>
|
|
131
|
+
<rect class="actor-tag" x="528" y="104" width="56" height="16" rx="2"/>
|
|
132
|
+
<text class="tag" x="556" y="116">HERDR</text>
|
|
133
|
+
<text class="name" x="640" y="140">Herdr / BTW transport</text>
|
|
134
|
+
<text class="sub" x="640" y="156">DURABLE HANDOFF</text>
|
|
135
|
+
|
|
136
|
+
<rect class="actor" x="976" y="96" width="240" height="68" rx="6"/>
|
|
137
|
+
<rect class="actor-tag" x="984" y="104" width="40" height="16" rx="2"/>
|
|
138
|
+
<text class="tag" x="1004" y="116">SIDE</text>
|
|
139
|
+
<text class="name" x="1096" y="140">Side Pane</text>
|
|
140
|
+
<text class="sub" x="1096" y="156">EDITABLE DRAFT</text>
|
|
141
|
+
|
|
142
|
+
<!-- Legend -->
|
|
143
|
+
<line x1="48" y1="692" x2="1232" y2="692" stroke="rgba(16,24,40,.141)" stroke-width=".8"/>
|
|
144
|
+
<text class="eyebrow" x="48" y="712">LEGEND</text>
|
|
145
|
+
<rect class="activation" x="132" y="700" width="8" height="16"/>
|
|
146
|
+
<text class="legend" x="152" y="712">Active</text>
|
|
147
|
+
<line class="message-live" x1="248" y1="708" x2="288" y2="708"/>
|
|
148
|
+
<text class="legend" x="300" y="712">Live cwd effect</text>
|
|
149
|
+
<rect class="pending" x="444" y="700" width="24" height="16" rx="4"/>
|
|
150
|
+
<text class="legend" x="480" y="712">Durable pending</text>
|
|
151
|
+
<line class="message-focal" x1="640" y1="708" x2="680" y2="708"/>
|
|
152
|
+
<text class="legend" x="692" y="712">Merge delivery</text>
|
|
153
|
+
</svg>
|
|
154
|
+
</figure>
|
|
155
|
+
</body>
|
|
156
|
+
</html>
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg width="1280" height="720" viewBox="0 0 1280 720" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="btw-merge-sequence-title btw-merge-sequence-desc">
|
|
3
|
+
<title id="btw-merge-sequence-title">From /btw side question to Main</title>
|
|
4
|
+
<desc id="btw-merge-sequence-desc">Sequence diagram showing Main launching an editable Herdr side thread from a static context snapshot while shared working-directory effects remain live. The side pane runs /btw merge with its text transcript and next prompt, which immediately establishes pending delivery. Herdr then refocuses Main and closes the side pane. The pending delivery survives side-pane shutdown and waits for Main to become idle with current model authentication before appending the transcript without starting a turn and submitting the next prompt.</desc>
|
|
5
|
+
<defs>
|
|
6
|
+
<style>
|
|
7
|
+
@import url('https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap');
|
|
8
|
+
.eyebrow { fill: #4c5665; font: 500 10px 'Geist Mono', monospace; letter-spacing: .18em; }
|
|
9
|
+
.diagram-title { fill: #101828; font: 400 28px 'Instrument Serif', serif; }
|
|
10
|
+
.diagram-subtitle { fill: #4c5665; font: 400 14px 'Geist', sans-serif; }
|
|
11
|
+
.lifeline { stroke: rgba(16,24,40,.22); stroke-width: 1; stroke-dasharray: 4 4; }
|
|
12
|
+
.activation { fill: rgba(16,24,40,.06); stroke: #4c5665; stroke-width: .8; }
|
|
13
|
+
.message { fill: none; stroke: #4c5665; stroke-width: 1.2; marker-end: url(#btw-arrow); }
|
|
14
|
+
.message-live { fill: none; stroke: #4c5665; stroke-width: 1.2; stroke-dasharray: 4 4; marker-end: url(#btw-arrow-open); }
|
|
15
|
+
.message-focal { fill: none; stroke: #1d4ed8; stroke-width: 1.4; marker-end: url(#btw-arrow-accent); }
|
|
16
|
+
.label-mask { fill: #f0eee9; }
|
|
17
|
+
.label { fill: #4c5665; font: 500 10px 'Geist Mono', monospace; letter-spacing: .06em; text-anchor: middle; }
|
|
18
|
+
.label-focal { fill: #1d4ed8; font: 500 10px 'Geist Mono', monospace; letter-spacing: .06em; text-anchor: middle; }
|
|
19
|
+
.note { fill: #4c5665; font: 400 14px 'Geist', sans-serif; }
|
|
20
|
+
.actor { fill: #fff; stroke: #101828; stroke-width: 1; }
|
|
21
|
+
.actor-tag { fill: none; stroke: rgba(16,24,40,.32); stroke-width: .8; }
|
|
22
|
+
.tag { fill: #4c5665; font: 500 10px 'Geist Mono', monospace; letter-spacing: .08em; text-anchor: middle; }
|
|
23
|
+
.name { fill: #101828; font: 600 14px 'Geist', sans-serif; text-anchor: middle; }
|
|
24
|
+
.sub { fill: #4c5665; font: 400 10px 'Geist Mono', monospace; text-anchor: middle; }
|
|
25
|
+
.pending { fill: #e5e3df; stroke: #4c5665; stroke-width: 1; }
|
|
26
|
+
.legend { fill: #4c5665; font: 400 10px 'Geist', sans-serif; }
|
|
27
|
+
</style>
|
|
28
|
+
<marker id="btw-arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
29
|
+
<polygon points="0 0,8 3,0 6" fill="#4c5665"/>
|
|
30
|
+
</marker>
|
|
31
|
+
<marker id="btw-arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
32
|
+
<polygon points="0 0,8 3,0 6" fill="#1d4ed8"/>
|
|
33
|
+
</marker>
|
|
34
|
+
<marker id="btw-arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
35
|
+
<polygon points="0 0,8 3,0 6" fill="#1d4ed8"/>
|
|
36
|
+
</marker>
|
|
37
|
+
<marker id="btw-arrow-open" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
38
|
+
<polyline points="0 0,8 3,0 6" fill="none" stroke="#4c5665" stroke-width="1.2"/>
|
|
39
|
+
</marker>
|
|
40
|
+
</defs>
|
|
41
|
+
|
|
42
|
+
<rect width="1280" height="720" fill="#f0eee9"/>
|
|
43
|
+
|
|
44
|
+
<text class="eyebrow" x="48" y="24">SEQUENCE · BTW MERGE DELIVERY</text>
|
|
45
|
+
<text class="diagram-title" x="48" y="56">From /btw side question to Main</text>
|
|
46
|
+
<text class="diagram-subtitle" x="48" y="80">The conversation snapshot stays fixed. File changes in the shared working directory do not.</text>
|
|
47
|
+
|
|
48
|
+
<!-- Lifelines -->
|
|
49
|
+
<line class="lifeline" x1="184" y1="164" x2="184" y2="684"/>
|
|
50
|
+
<line class="lifeline" x1="640" y1="164" x2="640" y2="684"/>
|
|
51
|
+
<line class="lifeline" x1="1096" y1="164" x2="1096" y2="684"/>
|
|
52
|
+
|
|
53
|
+
<!-- Activations -->
|
|
54
|
+
<rect class="activation" x="180" y="176" width="8" height="108"/>
|
|
55
|
+
<rect class="activation" x="636" y="264" width="8" height="396"/>
|
|
56
|
+
<rect class="activation" x="1092" y="312" width="8" height="272"/>
|
|
57
|
+
<rect class="activation" x="180" y="652" width="8" height="32"/>
|
|
58
|
+
|
|
59
|
+
<!-- Messages -->
|
|
60
|
+
<path class="message" d="M188 184 H240 Q248 184 248 192 V212 Q248 220 240 220 H188"/>
|
|
61
|
+
<line class="message" x1="188" y1="276" x2="636" y2="276"/>
|
|
62
|
+
<line class="message" x1="644" y1="320" x2="1092" y2="320"/>
|
|
63
|
+
<path class="message" d="M1100 348 H1152 Q1160 348 1160 356 V372 Q1160 380 1152 380 H1100"/>
|
|
64
|
+
<line class="message-live" x1="1092" y1="400" x2="188" y2="400"/>
|
|
65
|
+
<line class="message" x1="1092" y1="456" x2="644" y2="456"/>
|
|
66
|
+
<line class="message" x1="636" y1="540" x2="188" y2="540"/>
|
|
67
|
+
<line class="message" x1="644" y1="576" x2="1092" y2="576"/>
|
|
68
|
+
<line class="message-focal" x1="636" y1="660" x2="188" y2="660"/>
|
|
69
|
+
<path class="message" d="M188 676 H240 Q248 676 248 680 Q248 684 240 684 H188"/>
|
|
70
|
+
|
|
71
|
+
<!-- Message labels -->
|
|
72
|
+
<rect class="label-mask" x="264" y="172" width="264" height="84" rx="4"/>
|
|
73
|
+
<text class="label" x="280" y="188" style="text-anchor:start">PREPARE</text>
|
|
74
|
+
<text class="note" x="272" y="208">Snapshot compaction-aware context</text>
|
|
75
|
+
<text class="note" x="272" y="228">Capture cwd and active tools</text>
|
|
76
|
+
<text class="note" x="272" y="248">Resolve an authenticated route</text>
|
|
77
|
+
|
|
78
|
+
<rect class="label-mask" x="344" y="260" width="136" height="20" rx="2"/>
|
|
79
|
+
<text class="label" x="412" y="274">STATIC CONTEXT</text>
|
|
80
|
+
<rect class="label-mask" x="800" y="304" width="136" height="20" rx="2"/>
|
|
81
|
+
<text class="label" x="868" y="318">OPEN SIDE PANE</text>
|
|
82
|
+
<rect class="label-mask" x="1156" y="332" width="104" height="20" rx="2"/>
|
|
83
|
+
<text class="label" x="1208" y="346">SIDE ANSWER</text>
|
|
84
|
+
<rect class="label-mask" x="808" y="384" width="120" height="20" rx="2"/>
|
|
85
|
+
<text class="label" x="868" y="398">SHARED CWD</text>
|
|
86
|
+
<text class="note" x="868" y="428" text-anchor="middle">Tool writes are immediately visible to Main</text>
|
|
87
|
+
<rect class="label-mask" x="816" y="440" width="104" height="20" rx="2"/>
|
|
88
|
+
<text class="label" x="868" y="454">/BTW MERGE</text>
|
|
89
|
+
<text class="note" x="904" y="480" text-anchor="middle">Text transcript + next prompt</text>
|
|
90
|
+
<rect class="label-mask" x="352" y="524" width="120" height="20" rx="2"/>
|
|
91
|
+
<text class="label" x="412" y="538">REFOCUS MAIN</text>
|
|
92
|
+
<rect class="label-mask" x="816" y="560" width="104" height="20" rx="2"/>
|
|
93
|
+
<text class="label" x="868" y="574">CLOSE PANE</text>
|
|
94
|
+
<rect class="label-mask" x="336" y="648" width="152" height="20" rx="2"/>
|
|
95
|
+
<text class="label-focal" x="412" y="662">APPEND WITHOUT TURN</text>
|
|
96
|
+
<rect class="label-mask" x="264" y="668" width="128" height="20" rx="2"/>
|
|
97
|
+
<text class="label" x="328" y="682">SUBMIT PROMPT</text>
|
|
98
|
+
|
|
99
|
+
<!-- Durable state and actors -->
|
|
100
|
+
<rect class="pending" x="496" y="468" width="288" height="56" rx="6"/>
|
|
101
|
+
<text class="name" x="640" y="488">Pending delivery established</text>
|
|
102
|
+
<text class="sub" x="640" y="508">DURABLE BEFORE REFOCUS / CLOSE</text>
|
|
103
|
+
|
|
104
|
+
<rect class="pending" x="496" y="584" width="288" height="60" rx="6"/>
|
|
105
|
+
<text class="name" x="640" y="608">Pending delivery waits</text>
|
|
106
|
+
<text class="sub" x="640" y="624">MAIN IDLE + AUTH</text>
|
|
107
|
+
<text class="sub" x="640" y="640">SURVIVES SIDE-PANE SHUTDOWN</text>
|
|
108
|
+
|
|
109
|
+
<rect class="actor" x="64" y="96" width="240" height="68" rx="6"/>
|
|
110
|
+
<rect class="actor-tag" x="72" y="104" width="40" height="16" rx="2"/>
|
|
111
|
+
<text class="tag" x="92" y="116">MAIN</text>
|
|
112
|
+
<text class="name" x="184" y="140">Main</text>
|
|
113
|
+
<text class="sub" x="184" y="156">USER RUNS /BTW</text>
|
|
114
|
+
|
|
115
|
+
<rect class="actor" x="520" y="96" width="240" height="68" rx="6"/>
|
|
116
|
+
<rect class="actor-tag" x="528" y="104" width="56" height="16" rx="2"/>
|
|
117
|
+
<text class="tag" x="556" y="116">HERDR</text>
|
|
118
|
+
<text class="name" x="640" y="140">Herdr / BTW transport</text>
|
|
119
|
+
<text class="sub" x="640" y="156">DURABLE HANDOFF</text>
|
|
120
|
+
|
|
121
|
+
<rect class="actor" x="976" y="96" width="240" height="68" rx="6"/>
|
|
122
|
+
<rect class="actor-tag" x="984" y="104" width="40" height="16" rx="2"/>
|
|
123
|
+
<text class="tag" x="1004" y="116">SIDE</text>
|
|
124
|
+
<text class="name" x="1096" y="140">Side Pane</text>
|
|
125
|
+
<text class="sub" x="1096" y="156">EDITABLE DRAFT</text>
|
|
126
|
+
|
|
127
|
+
<!-- Legend -->
|
|
128
|
+
<line x1="48" y1="692" x2="1232" y2="692" stroke="rgba(16,24,40,.141)" stroke-width=".8"/>
|
|
129
|
+
<text class="eyebrow" x="48" y="712">LEGEND</text>
|
|
130
|
+
<rect class="activation" x="132" y="700" width="8" height="16"/>
|
|
131
|
+
<text class="legend" x="152" y="712">Active</text>
|
|
132
|
+
<line class="message-live" x1="248" y1="708" x2="288" y2="708"/>
|
|
133
|
+
<text class="legend" x="300" y="712">Live cwd effect</text>
|
|
134
|
+
<rect class="pending" x="444" y="700" width="24" height="16" rx="4"/>
|
|
135
|
+
<text class="legend" x="480" y="712">Durable pending</text>
|
|
136
|
+
<line class="message-focal" x1="640" y1="708" x2="680" y2="708"/>
|
|
137
|
+
<text class="legend" x="692" y="712">Merge delivery</text>
|
|
138
|
+
</svg>
|