@henryqw/pi-herdr-tools 1.0.0 → 1.0.3
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 +12 -9
- package/docs/clone-flow.html +70 -69
- package/docs/clone-flow.svg +91 -76
- package/docs/done-flow.html +58 -57
- package/docs/done-flow.svg +94 -64
- package/internal/done.ts +5 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -47,21 +47,23 @@ Run `/clone-tab` to open a new Herdr tab with a clone of the active conversation
|
|
|
47
47
|
| --- | --- | --- |
|
|
48
48
|
| `/clone-tab` | command | Clone the current conversation into a new tab of the current Herdr workspace. |
|
|
49
49
|
| `/clone-worktree` | command | Clone the current conversation into a new Herdr Git worktree workspace. |
|
|
50
|
-
| `/done [
|
|
50
|
+
| `/done [-f]` | command | Remove the current worktree and close its Herdr workspace tabs; `-f` (alias `--force`) skips confirmation and permits forced removal without checking for tabs in other workspaces. |
|
|
51
51
|
| `/btw [<question...>]` | command | For humans in Main: open an empty side pane or start with an editable question draft. |
|
|
52
52
|
| `/btw ask <question...>` | command | For humans in Main: ask a question whose first word is `ask`, `config`, `merge`, or `help`. |
|
|
53
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
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
55
|
| `/btw help` | command | For humans: show the command grammar. |
|
|
56
|
+
| BTW capability widget | ui | For people in a side pane: shows `tool-free`, `read-only`, or `tool-enabled`. If parent context cannot load, shows the error and recovery steps instead. |
|
|
56
57
|
| `/rename` | command | For people: generate a new title from up to five recent user messages. |
|
|
57
|
-
|
|
|
58
|
+
| Rename progress and result widgets | ui | For people who run `/rename`: shows `renaming...`, then `renamed to <title>` for two seconds on success. |
|
|
59
|
+
| First real user prompt | ui | For people in a new, untitled conversation: starts title generation once the expanded prompt is ready. |
|
|
58
60
|
| `pi-herdr-rename/rename` | model task | Title-generation route; users configure its profile through `/task-models`. |
|
|
59
61
|
|
|
60
62
|
### Clone conversations and finish worktrees
|
|
61
63
|
|
|
62
64
|
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
65
|
|
|
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
|
|
66
|
+
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 -f` can irreversibly delete uncommitted work and leave other workspaces' tabs pointing at the removed checkout.**
|
|
65
67
|
|
|
66
68
|
### Ask and merge side questions
|
|
67
69
|
|
|
@@ -79,9 +81,10 @@ In a new, untitled conversation, send the first real prompt. Pi generates a titl
|
|
|
79
81
|
|
|
80
82
|
#### Clone a tab
|
|
81
83
|
|
|
82
|
-
1.
|
|
83
|
-
2.
|
|
84
|
-
3.
|
|
84
|
+
1. Save the active path as a separate clone session with the current working directory.
|
|
85
|
+
2. Create an unfocused Herdr tab in the current workspace with that working directory.
|
|
86
|
+
3. Start Pi in the tab's root pane with `--session <absolute-clone-file>`.
|
|
87
|
+
4. Focus the new tab after Pi starts successfully.
|
|
85
88
|
|
|
86
89
|
#### Clone a worktree
|
|
87
90
|
|
|
@@ -96,7 +99,7 @@ In a new, untitled conversation, send the first real prompt. Pi generates a titl
|
|
|
96
99
|
|
|
97
100
|

|
|
98
101
|
|
|
99
|
-
Normal `/done` asks for confirmation before waiting for Pi to become idle; declining leaves the checkout untouched. `/done
|
|
102
|
+
Normal `/done` asks for confirmation before waiting for Pi to become idle; declining leaves the checkout untouched. `/done -f` skips confirmation. Both wait for Pi to become idle before cleanup.
|
|
100
103
|
|
|
101
104
|
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
105
|
|
|
@@ -184,8 +187,8 @@ The Pi session stores each generated display title and semantic branch in a `pi-
|
|
|
184
187
|
|
|
185
188
|
### Worktree completion
|
|
186
189
|
|
|
187
|
-
- `/done` refuses to remove a dirty worktree. Commit or discard changes first. `/done
|
|
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
|
|
190
|
+
- `/done` refuses to remove a dirty worktree. Commit or discard changes first. `/done -f` passes `--force` to Git and can irreversibly delete uncommitted work.
|
|
191
|
+
- 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 -f` only if you accept removing the checkout while that tab still refers to it. Tabs in other workspaces are not closed.
|
|
189
192
|
- The command requires Pi inside Herdr with `HERDR_ENV=1`, `HERDR_WORKSPACE_ID`, and `HERDR_TAB_ID` set.
|
|
190
193
|
- 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
194
|
|
package/docs/clone-flow.html
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
color: #101828;
|
|
17
17
|
font-family: 'Geist', system-ui, sans-serif;
|
|
18
18
|
}
|
|
19
|
-
main { width: min(1280px, 100%); }
|
|
19
|
+
main { width: min(1280px, 100%); min-width: 0; }
|
|
20
20
|
header { margin-bottom: 24px; }
|
|
21
21
|
header p {
|
|
22
22
|
margin: 0 0 8px;
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
text-transform: uppercase;
|
|
27
27
|
}
|
|
28
28
|
h1 { margin: 0; font: 400 28px/1.2 'Instrument Serif', serif; }
|
|
29
|
-
|
|
29
|
+
.diagram-container { overflow-x: auto; }
|
|
30
|
+
svg { display: block; width: 100%; min-width: 1280px; height: auto; }
|
|
30
31
|
</style>
|
|
31
32
|
</head>
|
|
32
33
|
<body>
|
|
@@ -36,9 +37,10 @@
|
|
|
36
37
|
<h1>How Pi Herdr clone creates and recovers a target</h1>
|
|
37
38
|
</header>
|
|
38
39
|
|
|
40
|
+
<div class="diagram-container" tabindex="0" role="region" aria-label="Scrollable diagram">
|
|
39
41
|
<svg width="1280" height="720" viewBox="0 0 1280 720" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="clone-flow-title clone-flow-desc">
|
|
40
42
|
<title id="clone-flow-title">Pi Herdr clone flow</title>
|
|
41
|
-
<desc id="clone-flow-desc">
|
|
43
|
+
<desc id="clone-flow-desc">The tab route saves its clone session before creating a tab; the worktree route creates its workspace and selects a pane before saving its clone session, and both routes start Pi before focusing the tab with separate recovery rules.</desc>
|
|
42
44
|
<defs>
|
|
43
45
|
<style>
|
|
44
46
|
.lane-rule { stroke: rgba(16,24,40,.141); stroke-width: 1; }
|
|
@@ -72,13 +74,13 @@
|
|
|
72
74
|
<rect width="1280" height="720" fill="#f0eee9"/>
|
|
73
75
|
|
|
74
76
|
<text class="eyebrow" x="40" y="56">ACTIVE-PATH CLONE</text>
|
|
75
|
-
<text class="meta" x="1240" y="56" text-anchor="end">STATIC · TWO TARGETS ·
|
|
77
|
+
<text class="meta" x="1240" y="56" text-anchor="end">STATIC · TWO TARGETS · SEPARATE SAVE ORDER</text>
|
|
76
78
|
|
|
77
79
|
<!-- Swimlanes -->
|
|
78
80
|
<line class="lane-rule-strong" x1="40" y1="80" x2="1240" y2="80"/>
|
|
79
81
|
<line class="lane-rule" x1="40" y1="192" x2="1240" y2="192"/>
|
|
80
82
|
<line class="lane-rule" x1="40" y1="320" x2="1240" y2="320"/>
|
|
81
|
-
<line class="lane-rule" x1="40" y1="
|
|
83
|
+
<line class="lane-rule" x1="40" y1="516" x2="1240" y2="516"/>
|
|
82
84
|
<line class="lane-rule-strong" x1="40" y1="620" x2="1240" y2="620"/>
|
|
83
85
|
<line class="lane-rule-strong" x1="176" y1="80" x2="176" y2="620"/>
|
|
84
86
|
|
|
@@ -87,84 +89,83 @@
|
|
|
87
89
|
<text class="eyebrow" x="56" y="420">HERDR TARGET</text>
|
|
88
90
|
<text class="eyebrow" x="56" y="572">RECOVERY</text>
|
|
89
91
|
|
|
90
|
-
<!--
|
|
91
|
-
<path class="edge" d="
|
|
92
|
-
<path class="edge" d="
|
|
93
|
-
<path class="edge" d="
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
<path class="edge" d="
|
|
97
|
-
<path class="edge
|
|
98
|
-
<path
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
<path class="edge-failure" d="M916 368 H928 Q936 368 936 376 V500 Q936 508 928 508 H584 Q576 508 576 516 V548"/>
|
|
102
|
-
<path class="edge-failure" d="M916 476 H992 Q1000 476 1000 484 V512 Q1000 520 992 520 H632 Q624 520 624 528 V548"/>
|
|
103
|
-
<path class="edge-failure" d="M1128 384 H1112 Q1104 384 1104 392 V524 Q1104 532 1096 532 H920 Q912 532 912 540 V548"/>
|
|
104
|
-
<path class="edge-failure" d="M1184 488 V548"/>
|
|
92
|
+
<!-- Worktree route comes first so the tab-route bridge masks its crossing. -->
|
|
93
|
+
<path class="edge" d="M264 172 V456 Q264 464 272 464 H400"/>
|
|
94
|
+
<path class="edge" d="M624 464 H776 Q784 464 784 456 V264 Q784 256 792 256 H800"/>
|
|
95
|
+
<path class="edge" d="M984 256 H1136 Q1144 256 1144 264 V336"/>
|
|
96
|
+
|
|
97
|
+
<!-- Tab route saves the session before creating the tab. -->
|
|
98
|
+
<path class="edge" d="M344 140 H360 Q368 140 368 148 V248 Q368 256 376 256 H400"/>
|
|
99
|
+
<path class="edge" d="M480 288 V360 Q480 368 488 368 H592"/>
|
|
100
|
+
<path d="M776 368 Q776 360 784 360 Q792 360 792 368" fill="none" stroke="#f0eee9" stroke-width="6"/>
|
|
101
|
+
<path class="edge-focal" d="M752 368 H776 Q776 360 784 360 Q792 360 792 368 H1040"/>
|
|
102
|
+
<path class="edge" d="M1144 400 V440"/>
|
|
105
103
|
|
|
106
104
|
<!-- Process nodes -->
|
|
107
105
|
<rect class="node" x="184" y="108" width="160" height="64" rx="6"/>
|
|
108
106
|
<text class="name" x="264" y="132">Validate source</text>
|
|
109
|
-
<text class="sub" x="264" y="148">
|
|
110
|
-
<text class="sub" x="264" y="160">
|
|
111
|
-
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
<
|
|
115
|
-
<text class="
|
|
116
|
-
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
<
|
|
122
|
-
<text class="
|
|
123
|
-
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
<
|
|
127
|
-
<text class="
|
|
128
|
-
<text class="sub" x="
|
|
129
|
-
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
<
|
|
133
|
-
<text class="
|
|
134
|
-
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
<
|
|
138
|
-
<text class="
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
<
|
|
142
|
-
<text class="
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
<
|
|
147
|
-
<line class="lane-rule" x1="
|
|
148
|
-
<
|
|
149
|
-
<text class="
|
|
150
|
-
<text class="
|
|
151
|
-
<text class="
|
|
152
|
-
<text class="
|
|
153
|
-
<text class="
|
|
154
|
-
<text class="
|
|
155
|
-
<text class="
|
|
107
|
+
<text class="sub" x="264" y="148">PANE · SESSION · ACTIVE LEAF</text>
|
|
108
|
+
<text class="sub" x="264" y="160">LIVE STATE IF NOT ON DISK</text>
|
|
109
|
+
<text class="meta" x="400" y="128">ACTIVE PATH: ROOT → CURRENT LEAF</text>
|
|
110
|
+
<text class="meta" x="400" y="148">NO SIBLINGS · NO STILL-STREAMING OUTPUT</text>
|
|
111
|
+
|
|
112
|
+
<rect class="node" x="400" y="224" width="160" height="64" rx="6"/>
|
|
113
|
+
<text class="name" x="480" y="248">Save tab clone session</text>
|
|
114
|
+
<text class="sub" x="480" y="264">ACTIVE PATH ONLY</text>
|
|
115
|
+
<text class="sub" x="480" y="276">CURRENT CWD</text>
|
|
116
|
+
|
|
117
|
+
<rect class="node" x="592" y="336" width="160" height="64" rx="6"/>
|
|
118
|
+
<text class="name" x="672" y="360">Create clone tab</text>
|
|
119
|
+
<text class="sub" x="672" y="376">CURRENT WORKSPACE + CWD</text>
|
|
120
|
+
<text class="sub" x="672" y="388">NO FOCUS</text>
|
|
121
|
+
|
|
122
|
+
<rect class="node" x="400" y="424" width="224" height="80" rx="6"/>
|
|
123
|
+
<text class="name" x="512" y="444">Create worktree workspace</text>
|
|
124
|
+
<text class="sub" x="512" y="460">FRESH CHECKOUT · NO FOCUS</text>
|
|
125
|
+
<text class="sub" x="512" y="476">WAIT FOR LAYOUT AGENT</text>
|
|
126
|
+
<text class="sub" x="512" y="492">ROOT PANE OR EXTRA TAB IF BUSY</text>
|
|
127
|
+
|
|
128
|
+
<rect class="node" x="800" y="224" width="184" height="64" rx="6"/>
|
|
129
|
+
<text class="name" x="892" y="248">Save worktree clone session</text>
|
|
130
|
+
<text class="sub" x="892" y="264">ACTIVE PATH ONLY</text>
|
|
131
|
+
<text class="sub" x="892" y="276">FRESH CHECKOUT CWD</text>
|
|
132
|
+
|
|
133
|
+
<rect class="node-focal" x="1040" y="336" width="200" height="64" rx="6"/>
|
|
134
|
+
<text class="name" x="1140" y="356">Start Pi</text>
|
|
135
|
+
<text class="sub" x="1140" y="372">--session <absolute-clone-file></text>
|
|
136
|
+
<text class="sub" x="1140" y="388">WORKTREE ROOT BUSY → EXTRA TAB</text>
|
|
137
|
+
|
|
138
|
+
<rect class="node" x="1040" y="440" width="200" height="56" rx="6"/>
|
|
139
|
+
<text class="name" x="1140" y="464">Focus clone tab</text>
|
|
140
|
+
<text class="sub" x="1140" y="480">ONLY AFTER PI STARTS</text>
|
|
141
|
+
|
|
142
|
+
<!-- Recovery details are grouped by the operation that failed. -->
|
|
143
|
+
<rect class="recovery" x="184" y="528" width="1056" height="88" rx="8"/>
|
|
144
|
+
<line class="lane-rule" x1="800" y1="528" x2="800" y2="616"/>
|
|
145
|
+
<line class="lane-rule" x1="1024" y1="528" x2="1024" y2="616"/>
|
|
146
|
+
<text class="sub-left" x="200" y="544">BEFORE START</text>
|
|
147
|
+
<text class="legend" x="200" y="560">Tab creation fails: delete the clone; if cleanup fails, report the file. Incomplete reply: retain clone + known IDs.</text>
|
|
148
|
+
<text class="legend" x="200" y="576">Worktree creation or early extra-tab failure: no clone yet. Partial worktree: inspect herdr workspace list.</text>
|
|
149
|
+
<text class="legend" x="200" y="592">Worktree clone save fails: retain the worktree. Inspect known target IDs before manual cleanup.</text>
|
|
150
|
+
<text class="legend" x="200" y="608">A worktree layout agent stays in its pane; the clone uses an extra tab when needed.</text>
|
|
151
|
+
<text class="sub-left" x="816" y="544">START ATTEMPTED</text>
|
|
152
|
+
<text class="name-left" x="816" y="568">Retain target + session file</text>
|
|
153
|
+
<text class="legend" x="816" y="588">Launch may be unconfirmed.</text>
|
|
154
|
+
<text class="legend" x="816" y="604">The error reports known IDs.</text>
|
|
155
|
+
<text class="sub-left" x="1040" y="544">FOCUS FAILS</text>
|
|
156
|
+
<text class="name-left" x="1040" y="568">Warn; clone keeps running</text>
|
|
157
|
+
<text class="legend" x="1040" y="588">Focus the clone tab in Herdr.</text>
|
|
156
158
|
|
|
157
159
|
<!-- Legend -->
|
|
158
160
|
<line class="lane-rule" x1="40" y1="640" x2="1240" y2="640"/>
|
|
159
161
|
<text class="eyebrow" x="40" y="668">KEY</text>
|
|
160
162
|
<line x1="104" y1="664" x2="140" y2="664" stroke="#4c5665" stroke-width="1.2" marker-end="url(#clone-flow-arrow)"/>
|
|
161
163
|
<text class="legend" x="152" y="668">Main flow</text>
|
|
162
|
-
<line x1="268" y1="664" x2="304" y2="664" stroke="#6a7282" stroke-width="1.2" stroke-dasharray="5 4" marker-end="url(#clone-flow-arrow)"/>
|
|
163
|
-
<text class="legend" x="316" y="668">Failure outcome</text>
|
|
164
164
|
<rect x="464" y="656" width="24" height="16" rx="4" fill="rgba(29,78,216,.08)" stroke="#1d4ed8" stroke-width="1.2"/>
|
|
165
165
|
<text class="legend" x="500" y="668">Launch boundary</text>
|
|
166
166
|
<text class="meta" x="1240" y="668" text-anchor="end">ORIGINAL SESSION STAYS ACTIVE</text>
|
|
167
167
|
</svg>
|
|
168
|
+
</div>
|
|
168
169
|
</main>
|
|
169
170
|
</body>
|
|
170
171
|
</html>
|
package/docs/clone-flow.svg
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
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="clone-flow-title clone-flow-desc">
|
|
2
|
+
<svg width="1280" height="720" viewBox="0 0 1280 720" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="clone-flow-title clone-flow-desc" id="clone-flow-root">
|
|
3
3
|
<title id="clone-flow-title">Pi Herdr clone flow</title>
|
|
4
|
-
<desc id="clone-flow-desc">
|
|
4
|
+
<desc id="clone-flow-desc">The tab route saves its clone session before creating a tab; the worktree route creates its workspace and selects a pane before saving its clone session, and both routes start Pi before focusing the tab with separate recovery rules.</desc>
|
|
5
5
|
<defs>
|
|
6
|
-
|
|
6
|
+
<style>@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&family=Noto+Serif:ital@0;1&family=Noto+Sans+KR:wght@400;500;600&family=Noto+Serif+KR:wght@400&family=Noto+Sans+TC:wght@400;500;600&family=Noto+Serif+TC:wght@400&display=swap');
|
|
7
|
+
#clone-flow-root { color: #101828; font-family: 'Geist', system-ui, sans-serif; }
|
|
8
|
+
#clone-flow-root .diagram-container { overflow-x: auto; }
|
|
9
|
+
#clone-flow-root .lane-rule { stroke: rgba(16,24,40,.141); stroke-width: 1; }
|
|
10
|
+
#clone-flow-root .lane-rule-strong { stroke: #d5d8db; stroke-width: 1; }
|
|
11
|
+
#clone-flow-root .meta { fill: #6a7282; font: 400 8px 'Geist Mono', monospace; letter-spacing: .08em; }
|
|
12
|
+
#clone-flow-root .node { fill: #fff; stroke: #101828; stroke-width: 1; }
|
|
13
|
+
#clone-flow-root .node-focal { fill: rgba(29,78,216,.08); stroke: #1d4ed8; stroke-width: 1.2; }
|
|
14
|
+
#clone-flow-root .decision { fill: #fff; stroke: #101828; stroke-width: 1; }
|
|
15
|
+
#clone-flow-root .recovery { fill: rgba(16,24,40,.05); stroke: #4c5665; stroke-width: 1; }
|
|
16
|
+
#clone-flow-root .name { fill: #101828; font: 600 12px 'Geist', sans-serif; text-anchor: middle; }
|
|
17
|
+
#clone-flow-root .name-left { fill: #101828; font: 600 12px 'Geist', sans-serif; }
|
|
18
|
+
#clone-flow-root .sub { fill: #4c5665; font: 400 9px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .02em; }
|
|
19
|
+
#clone-flow-root .sub-left { fill: #4c5665; font: 500 9px 'Geist Mono', monospace; letter-spacing: .08em; }
|
|
20
|
+
#clone-flow-root .edge { fill: none; stroke: #4c5665; stroke-width: 1.2; marker-end: url(#clone-flow-clone-flow-arrow); }
|
|
21
|
+
#clone-flow-root .edge-focal { fill: none; stroke: #1d4ed8; stroke-width: 1.4; marker-end: url(#clone-flow-clone-flow-arrow-accent); }
|
|
22
|
+
#clone-flow-root .edge-failure { fill: none; stroke: #6a7282; stroke-width: 1.2; stroke-dasharray: 5 4; marker-end: url(#clone-flow-clone-flow-arrow); }
|
|
23
|
+
#clone-flow-root .legend { fill: #4c5665; font: 400 8px 'Geist', sans-serif; }</style>
|
|
7
24
|
<style>
|
|
8
25
|
.lane-rule { stroke: rgba(16,24,40,.141); stroke-width: 1; }
|
|
9
26
|
.lane-rule-strong { stroke: #d5d8db; stroke-width: 1; }
|
|
@@ -17,18 +34,18 @@
|
|
|
17
34
|
.name-left { fill: #101828; font: 600 12px 'Geist', sans-serif; }
|
|
18
35
|
.sub { fill: #4c5665; font: 400 9px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .02em; }
|
|
19
36
|
.sub-left { fill: #4c5665; font: 500 9px 'Geist Mono', monospace; letter-spacing: .08em; }
|
|
20
|
-
.edge { fill: none; stroke: #4c5665; stroke-width: 1.2; marker-end: url(#clone-flow-arrow); }
|
|
21
|
-
.edge-focal { fill: none; stroke: #1d4ed8; stroke-width: 1.4; marker-end: url(#clone-flow-arrow-accent); }
|
|
22
|
-
.edge-failure { fill: none; stroke: #6a7282; stroke-width: 1.2; stroke-dasharray: 5 4; marker-end: url(#clone-flow-arrow); }
|
|
37
|
+
.edge { fill: none; stroke: #4c5665; stroke-width: 1.2; marker-end: url(#clone-flow-clone-flow-arrow); }
|
|
38
|
+
.edge-focal { fill: none; stroke: #1d4ed8; stroke-width: 1.4; marker-end: url(#clone-flow-clone-flow-arrow-accent); }
|
|
39
|
+
.edge-failure { fill: none; stroke: #6a7282; stroke-width: 1.2; stroke-dasharray: 5 4; marker-end: url(#clone-flow-clone-flow-arrow); }
|
|
23
40
|
.legend { fill: #4c5665; font: 400 8px 'Geist', sans-serif; }
|
|
24
41
|
</style>
|
|
25
|
-
<marker id="clone-flow-arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
42
|
+
<marker id="clone-flow-clone-flow-arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
26
43
|
<polygon points="0 0,8 3,0 6" fill="#4c5665"/>
|
|
27
44
|
</marker>
|
|
28
|
-
<marker id="clone-flow-arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
45
|
+
<marker id="clone-flow-clone-flow-arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
29
46
|
<polygon points="0 0,8 3,0 6" fill="#1d4ed8"/>
|
|
30
47
|
</marker>
|
|
31
|
-
<marker id="clone-flow-arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
48
|
+
<marker id="clone-flow-clone-flow-arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
32
49
|
<polygon points="0 0,8 3,0 6" fill="#1d4ed8"/>
|
|
33
50
|
</marker>
|
|
34
51
|
</defs>
|
|
@@ -36,13 +53,13 @@
|
|
|
36
53
|
<rect width="1280" height="720" fill="#f0eee9"/>
|
|
37
54
|
|
|
38
55
|
<text class="eyebrow" x="40" y="56">ACTIVE-PATH CLONE</text>
|
|
39
|
-
<text class="meta" x="1240" y="56" text-anchor="end">STATIC · TWO TARGETS ·
|
|
56
|
+
<text class="meta" x="1240" y="56" text-anchor="end">STATIC · TWO TARGETS · SEPARATE SAVE ORDER</text>
|
|
40
57
|
|
|
41
58
|
<!-- Swimlanes -->
|
|
42
59
|
<line class="lane-rule-strong" x1="40" y1="80" x2="1240" y2="80"/>
|
|
43
60
|
<line class="lane-rule" x1="40" y1="192" x2="1240" y2="192"/>
|
|
44
61
|
<line class="lane-rule" x1="40" y1="320" x2="1240" y2="320"/>
|
|
45
|
-
<line class="lane-rule" x1="40" y1="
|
|
62
|
+
<line class="lane-rule" x1="40" y1="516" x2="1240" y2="516"/>
|
|
46
63
|
<line class="lane-rule-strong" x1="40" y1="620" x2="1240" y2="620"/>
|
|
47
64
|
<line class="lane-rule-strong" x1="176" y1="80" x2="176" y2="620"/>
|
|
48
65
|
|
|
@@ -51,81 +68,79 @@
|
|
|
51
68
|
<text class="eyebrow" x="56" y="420">HERDR TARGET</text>
|
|
52
69
|
<text class="eyebrow" x="56" y="572">RECOVERY</text>
|
|
53
70
|
|
|
54
|
-
<!--
|
|
55
|
-
<path class="edge" d="
|
|
56
|
-
<path class="edge" d="
|
|
57
|
-
<path class="edge" d="
|
|
58
|
-
<path class="edge" d="M612 304 V448 Q612 456 620 456 H716"/>
|
|
59
|
-
<path class="edge" d="M828 336 V312 Q828 304 836 304 H960 Q968 304 968 296 V288"/>
|
|
60
|
-
<path class="edge" d="M916 460 H1024 Q1032 460 1032 452 V288"/>
|
|
61
|
-
<path class="edge-focal" d="M1096 256 H1112 Q1120 256 1120 264 V360 Q1120 368 1128 368"/>
|
|
62
|
-
<path class="edge" d="M1184 400 V424"/>
|
|
71
|
+
<!-- Worktree route comes first so the tab-route bridge masks its crossing. -->
|
|
72
|
+
<path class="edge" d="M264 172 V456 Q264 464 272 464 H400"/>
|
|
73
|
+
<path class="edge" d="M624 464 H776 Q784 464 784 456 V264 Q784 256 792 256 H800"/>
|
|
74
|
+
<path class="edge" d="M984 256 H1136 Q1144 256 1144 264 V336"/>
|
|
63
75
|
|
|
64
|
-
<!--
|
|
65
|
-
<path class="edge
|
|
66
|
-
<path class="edge
|
|
67
|
-
<path
|
|
68
|
-
<path class="edge-
|
|
76
|
+
<!-- Tab route saves the session before creating the tab. -->
|
|
77
|
+
<path class="edge" d="M344 140 H360 Q368 140 368 148 V248 Q368 256 376 256 H400"/>
|
|
78
|
+
<path class="edge" d="M480 288 V360 Q480 368 488 368 H592"/>
|
|
79
|
+
<path d="M776 368 Q776 360 784 360 Q792 360 792 368" fill="none" stroke="#f0eee9" stroke-width="6"/>
|
|
80
|
+
<path class="edge-focal" d="M752 368 H776 Q776 360 784 360 Q792 360 792 368 H1040"/>
|
|
81
|
+
<path class="edge" d="M1144 400 V440"/>
|
|
69
82
|
|
|
70
83
|
<!-- Process nodes -->
|
|
71
84
|
<rect class="node" x="184" y="108" width="160" height="64" rx="6"/>
|
|
72
85
|
<text class="name" x="264" y="132">Validate source</text>
|
|
73
|
-
<text class="sub" x="264" y="148">
|
|
74
|
-
<text class="sub" x="264" y="160">
|
|
75
|
-
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
<
|
|
79
|
-
<text class="
|
|
80
|
-
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
<
|
|
86
|
-
<text class="
|
|
87
|
-
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
<
|
|
91
|
-
<text class="
|
|
92
|
-
<text class="sub" x="
|
|
93
|
-
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
<
|
|
97
|
-
<text class="
|
|
98
|
-
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
<
|
|
102
|
-
<text class="
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
<
|
|
106
|
-
<text class="
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
<
|
|
111
|
-
<line class="lane-rule" x1="
|
|
112
|
-
<
|
|
113
|
-
<text class="
|
|
114
|
-
<text class="
|
|
115
|
-
<text class="
|
|
116
|
-
<text class="
|
|
117
|
-
<text class="
|
|
118
|
-
<text class="
|
|
119
|
-
<text class="
|
|
86
|
+
<text class="sub" x="264" y="148">PANE · SESSION · ACTIVE LEAF</text>
|
|
87
|
+
<text class="sub" x="264" y="160">LIVE STATE IF NOT ON DISK</text>
|
|
88
|
+
<text class="meta" x="400" y="128">ACTIVE PATH: ROOT → CURRENT LEAF</text>
|
|
89
|
+
<text class="meta" x="400" y="148">NO SIBLINGS · NO STILL-STREAMING OUTPUT</text>
|
|
90
|
+
|
|
91
|
+
<rect class="node" x="400" y="224" width="160" height="64" rx="6"/>
|
|
92
|
+
<text class="name" x="480" y="248">Save tab clone session</text>
|
|
93
|
+
<text class="sub" x="480" y="264">ACTIVE PATH ONLY</text>
|
|
94
|
+
<text class="sub" x="480" y="276">CURRENT CWD</text>
|
|
95
|
+
|
|
96
|
+
<rect class="node" x="592" y="336" width="160" height="64" rx="6"/>
|
|
97
|
+
<text class="name" x="672" y="360">Create clone tab</text>
|
|
98
|
+
<text class="sub" x="672" y="376">CURRENT WORKSPACE + CWD</text>
|
|
99
|
+
<text class="sub" x="672" y="388">NO FOCUS</text>
|
|
100
|
+
|
|
101
|
+
<rect class="node" x="400" y="424" width="224" height="80" rx="6"/>
|
|
102
|
+
<text class="name" x="512" y="444">Create worktree workspace</text>
|
|
103
|
+
<text class="sub" x="512" y="460">FRESH CHECKOUT · NO FOCUS</text>
|
|
104
|
+
<text class="sub" x="512" y="476">WAIT FOR LAYOUT AGENT</text>
|
|
105
|
+
<text class="sub" x="512" y="492">ROOT PANE OR EXTRA TAB IF BUSY</text>
|
|
106
|
+
|
|
107
|
+
<rect class="node" x="800" y="224" width="184" height="64" rx="6"/>
|
|
108
|
+
<text class="name" x="892" y="248">Save worktree clone session</text>
|
|
109
|
+
<text class="sub" x="892" y="264">ACTIVE PATH ONLY</text>
|
|
110
|
+
<text class="sub" x="892" y="276">FRESH CHECKOUT CWD</text>
|
|
111
|
+
|
|
112
|
+
<rect class="node-focal" x="1040" y="336" width="200" height="64" rx="6"/>
|
|
113
|
+
<text class="name" x="1140" y="356">Start Pi</text>
|
|
114
|
+
<text class="sub" x="1140" y="372">--session <absolute-clone-file></text>
|
|
115
|
+
<text class="sub" x="1140" y="388">WORKTREE ROOT BUSY → EXTRA TAB</text>
|
|
116
|
+
|
|
117
|
+
<rect class="node" x="1040" y="440" width="200" height="56" rx="6"/>
|
|
118
|
+
<text class="name" x="1140" y="464">Focus clone tab</text>
|
|
119
|
+
<text class="sub" x="1140" y="480">ONLY AFTER PI STARTS</text>
|
|
120
|
+
|
|
121
|
+
<!-- Recovery details are grouped by the operation that failed. -->
|
|
122
|
+
<rect class="recovery" x="184" y="528" width="1056" height="88" rx="8"/>
|
|
123
|
+
<line class="lane-rule" x1="800" y1="528" x2="800" y2="616"/>
|
|
124
|
+
<line class="lane-rule" x1="1024" y1="528" x2="1024" y2="616"/>
|
|
125
|
+
<text class="sub-left" x="200" y="544">BEFORE START</text>
|
|
126
|
+
<text class="legend" x="200" y="560">Tab creation fails: delete the clone; if cleanup fails, report the file. Incomplete reply: retain clone + known IDs.</text>
|
|
127
|
+
<text class="legend" x="200" y="576">Worktree creation or early extra-tab failure: no clone yet. Partial worktree: inspect herdr workspace list.</text>
|
|
128
|
+
<text class="legend" x="200" y="592">Worktree clone save fails: retain the worktree. Inspect known target IDs before manual cleanup.</text>
|
|
129
|
+
<text class="legend" x="200" y="608">A worktree layout agent stays in its pane; the clone uses an extra tab when needed.</text>
|
|
130
|
+
<text class="sub-left" x="816" y="544">START ATTEMPTED</text>
|
|
131
|
+
<text class="name-left" x="816" y="568">Retain target + session file</text>
|
|
132
|
+
<text class="legend" x="816" y="588">Launch may be unconfirmed.</text>
|
|
133
|
+
<text class="legend" x="816" y="604">The error reports known IDs.</text>
|
|
134
|
+
<text class="sub-left" x="1040" y="544">FOCUS FAILS</text>
|
|
135
|
+
<text class="name-left" x="1040" y="568">Warn; clone keeps running</text>
|
|
136
|
+
<text class="legend" x="1040" y="588">Focus the clone tab in Herdr.</text>
|
|
120
137
|
|
|
121
138
|
<!-- Legend -->
|
|
122
139
|
<line class="lane-rule" x1="40" y1="640" x2="1240" y2="640"/>
|
|
123
140
|
<text class="eyebrow" x="40" y="668">KEY</text>
|
|
124
|
-
<line x1="104" y1="664" x2="140" y2="664" stroke="#4c5665" stroke-width="1.2" marker-end="url(#clone-flow-arrow)"/>
|
|
141
|
+
<line x1="104" y1="664" x2="140" y2="664" stroke="#4c5665" stroke-width="1.2" marker-end="url(#clone-flow-clone-flow-arrow)"/>
|
|
125
142
|
<text class="legend" x="152" y="668">Main flow</text>
|
|
126
|
-
<
|
|
127
|
-
<text class="legend" x="316" y="668">Failure outcome</text>
|
|
128
|
-
<rect x="464" y="656" width="24" height="16" rx="4" fill="rgba(29,78,216,.08)" stroke="#1d4ed8" stroke-width="1.2"/>
|
|
143
|
+
<rect x="464" y="656" width="24" height="16" rx="4" fill="#1d4ed8" fill-opacity=".08" stroke="#1d4ed8" stroke-width="1.2"/>
|
|
129
144
|
<text class="legend" x="500" y="668">Launch boundary</text>
|
|
130
145
|
<text class="meta" x="1240" y="668" text-anchor="end">ORIGINAL SESSION STAYS ACTIVE</text>
|
|
131
146
|
</svg>
|
package/docs/done-flow.html
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
color: var(--ink);
|
|
24
24
|
font-family: var(--sans);
|
|
25
25
|
}
|
|
26
|
-
main { width:
|
|
26
|
+
main { width: min(1280px, 100%); min-width: 0; margin: 0 auto; }
|
|
27
27
|
.eyebrow {
|
|
28
28
|
margin-bottom: 8px;
|
|
29
29
|
color: var(--muted);
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
margin-bottom: 24px;
|
|
36
36
|
font: 400 28px/1.2 var(--serif);
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
.diagram-container { overflow-x: auto; }
|
|
39
|
+
svg { display: block; width: 100%; min-width: 1280px; height: auto; }
|
|
39
40
|
</style>
|
|
40
41
|
</head>
|
|
41
42
|
<body>
|
|
@@ -43,9 +44,10 @@
|
|
|
43
44
|
<p class="eyebrow">Sequence · /done safety and cleanup</p>
|
|
44
45
|
<h1>Safe worktree completion</h1>
|
|
45
46
|
|
|
47
|
+
<div class="diagram-container" tabindex="0" role="region" aria-label="Scrollable diagram">
|
|
46
48
|
<svg width="1280" height="720" viewBox="0 0 1280 720" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="done-flow-title done-flow-desc">
|
|
47
49
|
<title id="done-flow-title">Safe worktree completion</title>
|
|
48
|
-
<desc id="done-flow-desc">
|
|
50
|
+
<desc id="done-flow-desc">Normal /done asks for confirmation before waiting for Pi to become idle, then checks tab use and removes the worktree before tab cleanup and a conditional parent update; explicit force skips confirmation and the tab-use check.</desc>
|
|
49
51
|
<defs>
|
|
50
52
|
<style>
|
|
51
53
|
.lifeline { stroke: rgba(16,24,40,.20); stroke-width: 1; stroke-dasharray: 4 4; }
|
|
@@ -85,66 +87,62 @@
|
|
|
85
87
|
|
|
86
88
|
<rect width="1280" height="720" fill="#f0eee9"/>
|
|
87
89
|
|
|
88
|
-
<!--
|
|
89
|
-
<rect class="fragment" x="120" y="
|
|
90
|
-
<
|
|
90
|
+
<!-- Optional normal-mode gates; both modes wait before cleanup. -->
|
|
91
|
+
<rect class="fragment" x="120" y="144" width="364" height="144" rx="4"/>
|
|
92
|
+
<rect class="fragment" x="388" y="352" width="292" height="92" rx="4"/>
|
|
91
93
|
|
|
92
|
-
<!-- Lifelines -->
|
|
94
|
+
<!-- Lifelines and activation bars -->
|
|
93
95
|
<line class="lifeline" x1="136" y1="96" x2="136" y2="624"/>
|
|
94
96
|
<line class="lifeline" x1="404" y1="96" x2="404" y2="624"/>
|
|
95
97
|
<line class="lifeline" x1="652" y1="96" x2="652" y2="624"/>
|
|
96
98
|
<line class="lifeline" x1="1124" y1="96" x2="1124" y2="624"/>
|
|
97
|
-
|
|
98
|
-
<!-- Activation bars -->
|
|
99
99
|
<rect class="activation" x="400" y="124" width="8" height="476"/>
|
|
100
|
-
<rect class="activation" x="648" y="
|
|
100
|
+
<rect class="activation" x="648" y="396" width="8" height="28"/>
|
|
101
101
|
<rect class="activation" x="648" y="456" width="8" height="16"/>
|
|
102
102
|
<rect class="activation" x="1120" y="544" width="8" height="24"/>
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
<
|
|
106
|
-
<
|
|
107
|
-
<
|
|
108
|
-
<
|
|
109
|
-
<
|
|
110
|
-
<text class="guard" x="
|
|
111
|
-
<text class="guard" x="260" y="232">CONFIRM; DIRTY OR OTHER-WORKSPACE TAB USING CHECKOUT → REFUSE</text>
|
|
112
|
-
<rect class="label-mask" x="128" y="360" width="528" height="16"/>
|
|
113
|
-
<text class="guard" x="132" y="372">[explicit --force]</text>
|
|
114
|
-
<text class="guard" x="260" y="372">PERMITS FORCED REMOVAL · IRREVERSIBLE</text>
|
|
104
|
+
<rect class="fragment-tab" x="120" y="144" width="40" height="16" rx="4"/>
|
|
105
|
+
<text class="fragment-label" x="140" y="156">OPT</text>
|
|
106
|
+
<rect class="label-mask" x="128" y="164" width="344" height="16"/>
|
|
107
|
+
<text class="guard" x="132" y="176">[normal /done; --force skips confirmation]</text>
|
|
108
|
+
<rect class="fragment-tab" x="388" y="352" width="40" height="16" rx="4"/>
|
|
109
|
+
<text class="fragment-label" x="408" y="364">OPT</text>
|
|
110
|
+
<text class="guard" x="440" y="364">[normal /done]</text>
|
|
115
111
|
|
|
116
112
|
<!-- Messages: time flows downward -->
|
|
117
113
|
<line class="message" x1="136" y1="124" x2="400" y2="124"/>
|
|
118
|
-
<rect class="label-mask" x="
|
|
119
|
-
<text class="message-label" x="268" y="112">RUN /DONE
|
|
120
|
-
|
|
121
|
-
<
|
|
122
|
-
<rect class="label-mask" x="
|
|
123
|
-
<text class="message-label" x="
|
|
124
|
-
|
|
125
|
-
<
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
<
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
<
|
|
134
|
-
<
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
<
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
<
|
|
142
|
-
<
|
|
143
|
-
<text class="
|
|
114
|
+
<rect class="label-mask" x="224" y="104" width="88" height="12" rx="4"/>
|
|
115
|
+
<text class="message-label" x="268" y="112">RUN /DONE</text>
|
|
116
|
+
|
|
117
|
+
<line class="message" x1="400" y1="208" x2="136" y2="208"/>
|
|
118
|
+
<rect class="label-mask" x="224" y="188" width="88" height="12" rx="4"/>
|
|
119
|
+
<text class="message-label" x="268" y="196">CONFIRM?</text>
|
|
120
|
+
<line class="message-return" x1="136" y1="244" x2="400" y2="244"/>
|
|
121
|
+
<rect class="label-mask" x="224" y="224" width="88" height="12" rx="4"/>
|
|
122
|
+
<text class="message-label" x="268" y="232">YES / STOP</text>
|
|
123
|
+
|
|
124
|
+
<path class="message" d="M408 308 H452 Q460 308 460 316 V332 Q460 340 452 340 H412"/>
|
|
125
|
+
<rect class="label-mask" x="468" y="316" width="112" height="12" rx="4"/>
|
|
126
|
+
<text class="message-label" x="524" y="324">WAIT FOR IDLE</text>
|
|
127
|
+
|
|
128
|
+
<line class="message" x1="408" y1="396" x2="648" y2="396"/>
|
|
129
|
+
<rect class="label-mask" x="480" y="376" width="96" height="12" rx="4"/>
|
|
130
|
+
<text class="message-label" x="528" y="384">CHECK TAB USE</text>
|
|
131
|
+
<line class="message-return" x1="648" y1="424" x2="408" y2="424"/>
|
|
132
|
+
<rect class="label-mask" x="484" y="404" width="88" height="12" rx="4"/>
|
|
133
|
+
<text class="message-label" x="528" y="412">CLEAR / REFUSE</text>
|
|
134
|
+
|
|
135
|
+
<!-- Safety details apply to the current flow, not a proposed flow. -->
|
|
136
|
+
<text class="guard" x="744" y="180">Decline: stop without waiting or changing the checkout.</text>
|
|
137
|
+
<text class="guard" x="744" y="204">Both modes wait for Pi to become idle before cleanup.</text>
|
|
138
|
+
<text class="guard" x="744" y="372">Normal: another workspace using this checkout blocks removal.</text>
|
|
139
|
+
<text class="guard" x="744" y="396">Git refuses dirty worktrees unless --force is set.</text>
|
|
140
|
+
<text class="guard" x="744" y="420">--force skips the tab-use check; data loss is irreversible.</text>
|
|
141
|
+
<text class="guard" x="744" y="444">Locks serialize worktree removal and primary-checkout updates.</text>
|
|
144
142
|
|
|
145
143
|
<line class="message-accent" x1="408" y1="464" x2="648" y2="464"/>
|
|
146
144
|
<rect class="label-mask" x="448" y="436" width="160" height="20" rx="4"/>
|
|
147
|
-
<text class="message-label-accent" x="528" y="444">
|
|
145
|
+
<text class="message-label-accent" x="528" y="444">CLEAN / FORCE</text>
|
|
148
146
|
<text class="message-label-accent" x="528" y="452">REMOVE WORKTREE</text>
|
|
149
147
|
|
|
150
148
|
<!-- Successful removal is the partial-success boundary -->
|
|
@@ -154,26 +152,26 @@
|
|
|
154
152
|
|
|
155
153
|
<line class="message" x1="400" y1="516" x2="136" y2="516"/>
|
|
156
154
|
<rect class="label-mask" x="180" y="496" width="176" height="12" rx="4"/>
|
|
157
|
-
<text class="message-label" x="268" y="504">CLOSE
|
|
155
|
+
<text class="message-label" x="268" y="504">CLOSE SIBLINGS</text>
|
|
158
156
|
|
|
159
157
|
<line class="message" x1="408" y1="544" x2="1120" y2="544"/>
|
|
160
158
|
<rect class="label-mask" x="684" y="516" width="160" height="20" rx="4"/>
|
|
161
|
-
<text class="message-label" x="764" y="524">
|
|
162
|
-
<text class="message-label" x="764" y="532">
|
|
159
|
+
<text class="message-label" x="764" y="524">LINKED PRIMARY</text>
|
|
160
|
+
<text class="message-label" x="764" y="532">PULL --FF-ONLY</text>
|
|
163
161
|
|
|
164
162
|
<line class="message-return" x1="1120" y1="568" x2="408" y2="568"/>
|
|
165
163
|
<rect class="label-mask" x="696" y="548" width="136" height="12" rx="4"/>
|
|
166
|
-
<text class="message-label" x="764" y="556">
|
|
164
|
+
<text class="message-label" x="764" y="556">DONE / FAILED</text>
|
|
167
165
|
|
|
168
166
|
<line class="message" x1="400" y1="600" x2="136" y2="600"/>
|
|
169
167
|
<rect class="label-mask" x="184" y="580" width="168" height="12" rx="4"/>
|
|
170
|
-
<text class="message-label" x="268" y="588">
|
|
168
|
+
<text class="message-label" x="268" y="588">CLOSE THIS TAB</text>
|
|
171
169
|
|
|
172
170
|
<!-- Actors are drawn after messages -->
|
|
173
171
|
<rect x="56" y="40" width="160" height="56" rx="6" fill="#f0eee9"/>
|
|
174
172
|
<rect class="actor-input" x="56" y="40" width="160" height="56" rx="6"/>
|
|
175
173
|
<text class="actor-name" x="136" y="68">Herdr workspace</text>
|
|
176
|
-
<text class="actor-sub" x="136" y="84">
|
|
174
|
+
<text class="actor-sub" x="136" y="84">THIS WORKSPACE</text>
|
|
177
175
|
|
|
178
176
|
<rect x="324" y="40" width="160" height="56" rx="6" fill="#f0eee9"/>
|
|
179
177
|
<rect class="actor" x="324" y="40" width="160" height="56" rx="6"/>
|
|
@@ -188,7 +186,9 @@
|
|
|
188
186
|
<rect x="1044" y="40" width="160" height="56" rx="6" fill="#f0eee9"/>
|
|
189
187
|
<rect class="actor" x="1044" y="40" width="160" height="56" rx="6"/>
|
|
190
188
|
<text class="actor-name" x="1124" y="68">Parent checkout</text>
|
|
191
|
-
<text class="actor-sub" x="1124" y="84">
|
|
189
|
+
<text class="actor-sub" x="1124" y="84">LINKED + NON-BARE</text>
|
|
190
|
+
|
|
191
|
+
<text class="guard" x="744" y="604">Close this tab last, even if sibling cleanup or pull fails.</text>
|
|
192
192
|
|
|
193
193
|
<!-- Legend strip -->
|
|
194
194
|
<line x1="40" y1="640" x2="1240" y2="640" stroke="rgba(16,24,40,.141)" stroke-width=".8"/>
|
|
@@ -201,12 +201,13 @@
|
|
|
201
201
|
<text class="legend-label" x="312" y="668">Return or result</text>
|
|
202
202
|
|
|
203
203
|
<rect class="fragment" x="448" y="656" width="32" height="16" rx="4"/>
|
|
204
|
-
<text class="fragment-label" x="464" y="668">
|
|
205
|
-
<text class="legend-label" x="492" y="668">
|
|
204
|
+
<text class="fragment-label" x="464" y="668">OPT</text>
|
|
205
|
+
<text class="legend-label" x="492" y="668">Normal-mode gate</text>
|
|
206
206
|
|
|
207
207
|
<line class="message-accent" x1="624" y1="664" x2="660" y2="664"/>
|
|
208
208
|
<text class="legend-label" x="672" y="668">Successful removal</text>
|
|
209
209
|
</svg>
|
|
210
|
+
</div>
|
|
210
211
|
</main>
|
|
211
212
|
</body>
|
|
212
213
|
</html>
|
package/docs/done-flow.svg
CHANGED
|
@@ -1,9 +1,41 @@
|
|
|
1
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="done-flow-title done-flow-desc">
|
|
2
|
+
<svg width="1280" height="720" viewBox="0 0 1280 720" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="done-flow-title done-flow-desc" id="done-flow-root">
|
|
3
3
|
<title id="done-flow-title">Safe worktree completion</title>
|
|
4
|
-
<desc id="done-flow-desc">
|
|
4
|
+
<desc id="done-flow-desc">Normal /done asks for confirmation before waiting for Pi to become idle, then checks tab use and removes the worktree before tab cleanup and a conditional parent update; explicit force skips confirmation and the tab-use check.</desc>
|
|
5
5
|
<defs>
|
|
6
|
-
|
|
6
|
+
<style>@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&family=Noto+Serif:ital@0;1&family=Noto+Sans+KR:wght@400;500;600&family=Noto+Serif+KR:wght@400&family=Noto+Sans+TC:wght@400;500;600&family=Noto+Serif+TC:wght@400&display=swap');
|
|
7
|
+
#done-flow-root { --paper: #f0eee9;
|
|
8
|
+
--ink: #101828;
|
|
9
|
+
--muted: #4c5665;
|
|
10
|
+
--accent: #1d4ed8;
|
|
11
|
+
--sans: 'Geist', system-ui, sans-serif;
|
|
12
|
+
--serif: 'Instrument Serif', serif;
|
|
13
|
+
--mono: 'Geist Mono', ui-monospace, monospace; }
|
|
14
|
+
#done-flow-root { color: var(--ink); font-family: var(--sans); }
|
|
15
|
+
#done-flow-root .diagram-container { overflow-x: auto; }
|
|
16
|
+
#done-flow-root .lifeline { stroke: rgba(16,24,40,.20); stroke-width: 1; stroke-dasharray: 4 4; }
|
|
17
|
+
#done-flow-root .activation { fill: rgba(16,24,40,.06); stroke: #4c5665; stroke-width: .8; }
|
|
18
|
+
#done-flow-root .fragment { fill: rgba(16,24,40,.02); stroke: rgba(16,24,40,.24); stroke-width: 1; }
|
|
19
|
+
#done-flow-root .fragment-tab { fill: #f0eee9; stroke: rgba(16,24,40,.24); stroke-width: 1; }
|
|
20
|
+
#done-flow-root .fragment-label { fill: #4c5665; font: 500 8px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .12em; }
|
|
21
|
+
#done-flow-root .guard { fill: #4c5665; font: 400 8px 'Geist Mono', monospace; letter-spacing: .04em; }
|
|
22
|
+
#done-flow-root .gate-badge { fill: rgba(29,78,216,.08); stroke: #1d4ed8; stroke-width: 1; }
|
|
23
|
+
#done-flow-root .gate-label { fill: #1d4ed8; font: 500 8px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .08em; }
|
|
24
|
+
#done-flow-root .message { fill: none; stroke: #4c5665; stroke-width: 1.2; marker-end: url(#done-flow-done-flow-arrow); }
|
|
25
|
+
#done-flow-root .message-return { fill: none; stroke: #4c5665; stroke-width: 1.2; stroke-dasharray: 4 4; marker-end: url(#done-flow-done-flow-arrow); }
|
|
26
|
+
#done-flow-root .message-accent { fill: none; stroke: #1d4ed8; stroke-width: 1.4; marker-end: url(#done-flow-done-flow-arrow-accent); }
|
|
27
|
+
#done-flow-root .label-mask { fill: #f0eee9; }
|
|
28
|
+
#done-flow-root .message-label { fill: #4c5665; font: 400 8px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .04em; }
|
|
29
|
+
#done-flow-root .message-label-accent { fill: #1d4ed8; font: 500 8px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .04em; }
|
|
30
|
+
#done-flow-root .actor { fill: #fff; stroke: #101828; stroke-width: 1; }
|
|
31
|
+
#done-flow-root .actor-input { fill: rgba(76,86,101,.10); stroke: #6a7282; stroke-width: 1; }
|
|
32
|
+
#done-flow-root .actor-state { fill: rgba(16,24,40,.05); stroke: #4c5665; stroke-width: 1; }
|
|
33
|
+
#done-flow-root .actor-name { fill: #101828; font: 600 12px 'Geist', sans-serif; text-anchor: middle; }
|
|
34
|
+
#done-flow-root .actor-sub { fill: #4c5665; font: 400 9px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .04em; }
|
|
35
|
+
#done-flow-root .boundary { stroke: rgba(16,24,40,.24); stroke-width: 1; stroke-dasharray: 4 4; }
|
|
36
|
+
#done-flow-root .boundary-label { fill: #4c5665; font: 500 8px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .08em; }
|
|
37
|
+
#done-flow-root .legend-label { fill: #4c5665; font: 400 8px 'Geist', sans-serif; }
|
|
38
|
+
#done-flow-root .legend-title { fill: #6a7282; font: 500 8px 'Geist Mono', monospace; letter-spacing: .16em; }</style>
|
|
7
39
|
<style>
|
|
8
40
|
.lifeline { stroke: rgba(16,24,40,.20); stroke-width: 1; stroke-dasharray: 4 4; }
|
|
9
41
|
.activation { fill: rgba(16,24,40,.06); stroke: #4c5665; stroke-width: .8; }
|
|
@@ -13,9 +45,9 @@
|
|
|
13
45
|
.guard { fill: #4c5665; font: 400 8px 'Geist Mono', monospace; letter-spacing: .04em; }
|
|
14
46
|
.gate-badge { fill: rgba(29,78,216,.08); stroke: #1d4ed8; stroke-width: 1; }
|
|
15
47
|
.gate-label { fill: #1d4ed8; font: 500 8px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .08em; }
|
|
16
|
-
.message { fill: none; stroke: #4c5665; stroke-width: 1.2; marker-end: url(#done-flow-arrow); }
|
|
17
|
-
.message-return { fill: none; stroke: #4c5665; stroke-width: 1.2; stroke-dasharray: 4 4; marker-end: url(#done-flow-arrow); }
|
|
18
|
-
.message-accent { fill: none; stroke: #1d4ed8; stroke-width: 1.4; marker-end: url(#done-flow-arrow-accent); }
|
|
48
|
+
.message { fill: none; stroke: #4c5665; stroke-width: 1.2; marker-end: url(#done-flow-done-flow-arrow); }
|
|
49
|
+
.message-return { fill: none; stroke: #4c5665; stroke-width: 1.2; stroke-dasharray: 4 4; marker-end: url(#done-flow-done-flow-arrow); }
|
|
50
|
+
.message-accent { fill: none; stroke: #1d4ed8; stroke-width: 1.4; marker-end: url(#done-flow-done-flow-arrow-accent); }
|
|
19
51
|
.label-mask { fill: #f0eee9; }
|
|
20
52
|
.message-label { fill: #4c5665; font: 400 8px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .04em; }
|
|
21
53
|
.message-label-accent { fill: #1d4ed8; font: 500 8px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .04em; }
|
|
@@ -29,79 +61,75 @@
|
|
|
29
61
|
.legend-label { fill: #4c5665; font: 400 8px 'Geist', sans-serif; }
|
|
30
62
|
.legend-title { fill: #6a7282; font: 500 8px 'Geist Mono', monospace; letter-spacing: .16em; }
|
|
31
63
|
</style>
|
|
32
|
-
<marker id="done-flow-arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
64
|
+
<marker id="done-flow-done-flow-arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
33
65
|
<polygon points="0 0,8 3,0 6" fill="#4c5665"/>
|
|
34
66
|
</marker>
|
|
35
|
-
<marker id="done-flow-arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
67
|
+
<marker id="done-flow-done-flow-arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
36
68
|
<polygon points="0 0,8 3,0 6" fill="#1d4ed8"/>
|
|
37
69
|
</marker>
|
|
38
|
-
<marker id="done-flow-arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
70
|
+
<marker id="done-flow-done-flow-arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
39
71
|
<polygon points="0 0,8 3,0 6" fill="#1d4ed8"/>
|
|
40
72
|
</marker>
|
|
41
73
|
</defs>
|
|
42
74
|
|
|
43
75
|
<rect width="1280" height="720" fill="#f0eee9"/>
|
|
44
76
|
|
|
45
|
-
<!--
|
|
46
|
-
<rect class="fragment" x="120" y="
|
|
47
|
-
<
|
|
77
|
+
<!-- Optional normal-mode gates; both modes wait before cleanup. -->
|
|
78
|
+
<rect class="fragment" x="120" y="144" width="364" height="144" rx="4"/>
|
|
79
|
+
<rect class="fragment" x="388" y="352" width="292" height="92" rx="4"/>
|
|
48
80
|
|
|
49
|
-
<!-- Lifelines -->
|
|
81
|
+
<!-- Lifelines and activation bars -->
|
|
50
82
|
<line class="lifeline" x1="136" y1="96" x2="136" y2="624"/>
|
|
51
83
|
<line class="lifeline" x1="404" y1="96" x2="404" y2="624"/>
|
|
52
84
|
<line class="lifeline" x1="652" y1="96" x2="652" y2="624"/>
|
|
53
85
|
<line class="lifeline" x1="1124" y1="96" x2="1124" y2="624"/>
|
|
54
|
-
|
|
55
|
-
<!-- Activation bars -->
|
|
56
86
|
<rect class="activation" x="400" y="124" width="8" height="476"/>
|
|
57
|
-
<rect class="activation" x="648" y="
|
|
87
|
+
<rect class="activation" x="648" y="396" width="8" height="28"/>
|
|
58
88
|
<rect class="activation" x="648" y="456" width="8" height="16"/>
|
|
59
89
|
<rect class="activation" x="1120" y="544" width="8" height="24"/>
|
|
60
90
|
|
|
61
|
-
|
|
62
|
-
<
|
|
63
|
-
<
|
|
64
|
-
<
|
|
65
|
-
<
|
|
66
|
-
<
|
|
67
|
-
<text class="guard" x="
|
|
68
|
-
<text class="guard" x="260" y="232">CONFIRM; DIRTY OR OTHER-WORKSPACE TAB USING CHECKOUT → REFUSE</text>
|
|
69
|
-
<rect class="label-mask" x="128" y="360" width="528" height="16"/>
|
|
70
|
-
<text class="guard" x="132" y="372">[explicit --force]</text>
|
|
71
|
-
<text class="guard" x="260" y="372">PERMITS FORCED REMOVAL · IRREVERSIBLE</text>
|
|
91
|
+
<rect class="fragment-tab" x="120" y="144" width="40" height="16" rx="4"/>
|
|
92
|
+
<text class="fragment-label" x="140" y="156">OPT</text>
|
|
93
|
+
<rect class="label-mask" x="128" y="164" width="344" height="16"/>
|
|
94
|
+
<text class="guard" x="132" y="176">[normal /done; --force skips confirmation]</text>
|
|
95
|
+
<rect class="fragment-tab" x="388" y="352" width="40" height="16" rx="4"/>
|
|
96
|
+
<text class="fragment-label" x="408" y="364">OPT</text>
|
|
97
|
+
<text class="guard" x="440" y="364">[normal /done]</text>
|
|
72
98
|
|
|
73
99
|
<!-- Messages: time flows downward -->
|
|
74
100
|
<line class="message" x1="136" y1="124" x2="400" y2="124"/>
|
|
75
|
-
<rect class="label-mask" x="
|
|
76
|
-
<text class="message-label" x="268" y="112">RUN /DONE
|
|
77
|
-
|
|
78
|
-
<
|
|
79
|
-
<rect class="label-mask" x="
|
|
80
|
-
<text class="message-label" x="
|
|
81
|
-
|
|
82
|
-
<
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
<
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<
|
|
91
|
-
<
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
<
|
|
99
|
-
<
|
|
100
|
-
<text class="
|
|
101
|
+
<rect class="label-mask" x="224" y="104" width="88" height="12" rx="4"/>
|
|
102
|
+
<text class="message-label" x="268" y="112">RUN /DONE</text>
|
|
103
|
+
|
|
104
|
+
<line class="message" x1="400" y1="208" x2="136" y2="208"/>
|
|
105
|
+
<rect class="label-mask" x="224" y="188" width="88" height="12" rx="4"/>
|
|
106
|
+
<text class="message-label" x="268" y="196">CONFIRM?</text>
|
|
107
|
+
<line class="message-return" x1="136" y1="244" x2="400" y2="244"/>
|
|
108
|
+
<rect class="label-mask" x="224" y="224" width="88" height="12" rx="4"/>
|
|
109
|
+
<text class="message-label" x="268" y="232">YES / STOP</text>
|
|
110
|
+
|
|
111
|
+
<path class="message" d="M408 308 H452 Q460 308 460 316 V332 Q460 340 452 340 H412"/>
|
|
112
|
+
<rect class="label-mask" x="468" y="316" width="112" height="12" rx="4"/>
|
|
113
|
+
<text class="message-label" x="524" y="324">WAIT FOR IDLE</text>
|
|
114
|
+
|
|
115
|
+
<line class="message" x1="408" y1="396" x2="648" y2="396"/>
|
|
116
|
+
<rect class="label-mask" x="480" y="376" width="96" height="12" rx="4"/>
|
|
117
|
+
<text class="message-label" x="528" y="384">CHECK TAB USE</text>
|
|
118
|
+
<line class="message-return" x1="648" y1="424" x2="408" y2="424"/>
|
|
119
|
+
<rect class="label-mask" x="484" y="404" width="88" height="12" rx="4"/>
|
|
120
|
+
<text class="message-label" x="528" y="412">CLEAR / REFUSE</text>
|
|
121
|
+
|
|
122
|
+
<!-- Safety details apply to the current flow, not a proposed flow. -->
|
|
123
|
+
<text class="guard" x="744" y="180">Decline: stop without waiting or changing the checkout.</text>
|
|
124
|
+
<text class="guard" x="744" y="204">Both modes wait for Pi to become idle before cleanup.</text>
|
|
125
|
+
<text class="guard" x="744" y="372">Normal: another workspace using this checkout blocks removal.</text>
|
|
126
|
+
<text class="guard" x="744" y="396">Git refuses dirty worktrees unless --force is set.</text>
|
|
127
|
+
<text class="guard" x="744" y="420">--force skips the tab-use check; data loss is irreversible.</text>
|
|
128
|
+
<text class="guard" x="744" y="444">Locks serialize worktree removal and primary-checkout updates.</text>
|
|
101
129
|
|
|
102
130
|
<line class="message-accent" x1="408" y1="464" x2="648" y2="464"/>
|
|
103
131
|
<rect class="label-mask" x="448" y="436" width="160" height="20" rx="4"/>
|
|
104
|
-
<text class="message-label-accent" x="528" y="444">
|
|
132
|
+
<text class="message-label-accent" x="528" y="444">CLEAN / FORCE</text>
|
|
105
133
|
<text class="message-label-accent" x="528" y="452">REMOVE WORKTREE</text>
|
|
106
134
|
|
|
107
135
|
<!-- Successful removal is the partial-success boundary -->
|
|
@@ -111,26 +139,26 @@
|
|
|
111
139
|
|
|
112
140
|
<line class="message" x1="400" y1="516" x2="136" y2="516"/>
|
|
113
141
|
<rect class="label-mask" x="180" y="496" width="176" height="12" rx="4"/>
|
|
114
|
-
<text class="message-label" x="268" y="504">CLOSE
|
|
142
|
+
<text class="message-label" x="268" y="504">CLOSE SIBLINGS</text>
|
|
115
143
|
|
|
116
144
|
<line class="message" x1="408" y1="544" x2="1120" y2="544"/>
|
|
117
145
|
<rect class="label-mask" x="684" y="516" width="160" height="20" rx="4"/>
|
|
118
|
-
<text class="message-label" x="764" y="524">
|
|
119
|
-
<text class="message-label" x="764" y="532">
|
|
146
|
+
<text class="message-label" x="764" y="524">LINKED PRIMARY</text>
|
|
147
|
+
<text class="message-label" x="764" y="532">PULL --FF-ONLY</text>
|
|
120
148
|
|
|
121
149
|
<line class="message-return" x1="1120" y1="568" x2="408" y2="568"/>
|
|
122
150
|
<rect class="label-mask" x="696" y="548" width="136" height="12" rx="4"/>
|
|
123
|
-
<text class="message-label" x="764" y="556">
|
|
151
|
+
<text class="message-label" x="764" y="556">DONE / FAILED</text>
|
|
124
152
|
|
|
125
153
|
<line class="message" x1="400" y1="600" x2="136" y2="600"/>
|
|
126
154
|
<rect class="label-mask" x="184" y="580" width="168" height="12" rx="4"/>
|
|
127
|
-
<text class="message-label" x="268" y="588">
|
|
155
|
+
<text class="message-label" x="268" y="588">CLOSE THIS TAB</text>
|
|
128
156
|
|
|
129
157
|
<!-- Actors are drawn after messages -->
|
|
130
158
|
<rect x="56" y="40" width="160" height="56" rx="6" fill="#f0eee9"/>
|
|
131
159
|
<rect class="actor-input" x="56" y="40" width="160" height="56" rx="6"/>
|
|
132
160
|
<text class="actor-name" x="136" y="68">Herdr workspace</text>
|
|
133
|
-
<text class="actor-sub" x="136" y="84">
|
|
161
|
+
<text class="actor-sub" x="136" y="84">THIS WORKSPACE</text>
|
|
134
162
|
|
|
135
163
|
<rect x="324" y="40" width="160" height="56" rx="6" fill="#f0eee9"/>
|
|
136
164
|
<rect class="actor" x="324" y="40" width="160" height="56" rx="6"/>
|
|
@@ -145,10 +173,12 @@
|
|
|
145
173
|
<rect x="1044" y="40" width="160" height="56" rx="6" fill="#f0eee9"/>
|
|
146
174
|
<rect class="actor" x="1044" y="40" width="160" height="56" rx="6"/>
|
|
147
175
|
<text class="actor-name" x="1124" y="68">Parent checkout</text>
|
|
148
|
-
<text class="actor-sub" x="1124" y="84">
|
|
176
|
+
<text class="actor-sub" x="1124" y="84">LINKED + NON-BARE</text>
|
|
177
|
+
|
|
178
|
+
<text class="guard" x="744" y="604">Close this tab last, even if sibling cleanup or pull fails.</text>
|
|
149
179
|
|
|
150
180
|
<!-- Legend strip -->
|
|
151
|
-
<line x1="40" y1="640" x2="1240" y2="640" stroke="
|
|
181
|
+
<line x1="40" y1="640" x2="1240" y2="640" stroke="#101828" stroke-opacity=".141" stroke-width=".8"/>
|
|
152
182
|
<text class="legend-title" x="40" y="668">LEGEND</text>
|
|
153
183
|
|
|
154
184
|
<line class="message" x1="128" y1="664" x2="164" y2="664"/>
|
|
@@ -158,8 +188,8 @@
|
|
|
158
188
|
<text class="legend-label" x="312" y="668">Return or result</text>
|
|
159
189
|
|
|
160
190
|
<rect class="fragment" x="448" y="656" width="32" height="16" rx="4"/>
|
|
161
|
-
<text class="fragment-label" x="464" y="668">
|
|
162
|
-
<text class="legend-label" x="492" y="668">
|
|
191
|
+
<text class="fragment-label" x="464" y="668">OPT</text>
|
|
192
|
+
<text class="legend-label" x="492" y="668">Normal-mode gate</text>
|
|
163
193
|
|
|
164
194
|
<line class="message-accent" x1="624" y1="664" x2="660" y2="664"/>
|
|
165
195
|
<text class="legend-label" x="672" y="668">Successful removal</text>
|
package/internal/done.ts
CHANGED
|
@@ -20,7 +20,8 @@ export default function herdrDoneExtension(pi: ExtensionAPI): void {
|
|
|
20
20
|
description: "Remove the current Herdr worktree and close its workspace tabs",
|
|
21
21
|
handler: async (args, ctx) => {
|
|
22
22
|
const option = args.trim();
|
|
23
|
-
|
|
23
|
+
const force = option === "--force" || option === "-f";
|
|
24
|
+
if (option && !force) throw new Error("Usage: /done [--force|-f]");
|
|
24
25
|
if (process.env.HERDR_ENV !== "1") {
|
|
25
26
|
throw new Error("/done requires the current Pi session inside Herdr (HERDR_ENV=1).");
|
|
26
27
|
}
|
|
@@ -29,7 +30,7 @@ export default function herdrDoneExtension(pi: ExtensionAPI): void {
|
|
|
29
30
|
const workspaceId = process.env.HERDR_WORKSPACE_ID?.trim();
|
|
30
31
|
if (!workspaceId) throw new Error("HERDR_WORKSPACE_ID is missing.");
|
|
31
32
|
|
|
32
|
-
if (
|
|
33
|
+
if (!force) {
|
|
33
34
|
const confirmed = await ctx.ui.confirm("Done", "Close its Herdr tabs and remove the current worktree?");
|
|
34
35
|
if (!confirmed) return;
|
|
35
36
|
}
|
|
@@ -48,7 +49,7 @@ export default function herdrDoneExtension(pi: ExtensionAPI): void {
|
|
|
48
49
|
const siblingTabIds = await withWorktreeLock(checkout, async () => {
|
|
49
50
|
// With --force, skip the dependents check entirely and let git remove the checkout.
|
|
50
51
|
let dependentIds: string[] = [];
|
|
51
|
-
if (
|
|
52
|
+
if (!force) {
|
|
52
53
|
const snapshot = await herdr.json(["api", "snapshot"], { cwd: ctx.cwd });
|
|
53
54
|
const panes = (snapshot.result as { snapshot?: { panes?: SnapshotPane[] } } | undefined)?.snapshot?.panes;
|
|
54
55
|
if (!Array.isArray(panes)) throw new Error("herdr api snapshot returned no panes.");
|
|
@@ -79,7 +80,7 @@ export default function herdrDoneExtension(pi: ExtensionAPI): void {
|
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
await execOrThrow("git", [
|
|
82
|
-
"worktree", "remove", ...(
|
|
83
|
+
"worktree", "remove", ...(force ? ["--force"] : []), checkout,
|
|
83
84
|
], ctx.cwd);
|
|
84
85
|
return siblingTabIds;
|
|
85
86
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@henryqw/pi-herdr-tools",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Clone, name, and finish Pi conversations in Herdr, with mergeable side questions.",
|
|
5
5
|
"keywords": ["pi-package", "pi", "herdr", "session", "clone", "side-thread", "title"],
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@henryqw/pi-config-store": "^2.0.0",
|
|
21
|
-
"@henryqw/pi-herdr": "^0.4.
|
|
21
|
+
"@henryqw/pi-herdr": "^0.4.9",
|
|
22
22
|
"@henryqw/pi-task-models": "^7.0.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|