@feigi/fleet-ctl 3.23.13 → 3.23.15
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/package.json
CHANGED
|
@@ -499,7 +499,16 @@ const FILES = [
|
|
|
499
499
|
// other number straight back in, and this file already carried the
|
|
500
500
|
// identical stale number at two independent sites.
|
|
501
501
|
path: ["scripts", "fleet-heartbeat.mjs"],
|
|
502
|
-
|
|
502
|
+
// #2667. The header once said run-merge-bot.md's CI gate holds its wait
|
|
503
|
+
// "and re-issuing it", and the several-holds paragraph once called the
|
|
504
|
+
// heartbeat "the same remedy the CI gate reached for". The CI wait holds
|
|
505
|
+
// in one `eval` cell and re-issues nothing. Tolerant of a re-wrap: the
|
|
506
|
+
// comment is hard-wrapped, so either phrase can break across a `//` line.
|
|
507
|
+
stale: [
|
|
508
|
+
/run-merge-bot\.md:\d+/,
|
|
509
|
+
/re-issuing\s+(?:\/\/\s*)?it\b/,
|
|
510
|
+
/same remedy the\s+(?:\/\/\s*)?CI gate/,
|
|
511
|
+
],
|
|
503
512
|
// One needle per SITE — either can revert independently of the other.
|
|
504
513
|
live: [
|
|
505
514
|
"run-merge-bot.md's CI wait rule already states",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// roughly two hours; neither ever woke it. run-merge-bot.md's CI gate states
|
|
19
19
|
// the same rule as a rule — "whatever wakes you is external and may never
|
|
20
20
|
// come" — and cures it the same way this file does, by holding the wait
|
|
21
|
-
// inside one blocking
|
|
21
|
+
// inside one blocking call.
|
|
22
22
|
//
|
|
23
23
|
// So the heartbeat is not a Monitor, not a cron entry and not a paragraph of
|
|
24
24
|
// prose. A cron entry that ran the reconcile would print its rows to nobody:
|
|
@@ -66,9 +66,8 @@ export function interval({ quiet, base, ceiling, multiplier }) {
|
|
|
66
66
|
// rule already states.
|
|
67
67
|
//
|
|
68
68
|
// So a long interval is served by SEVERAL holds, and the elapsed total is
|
|
69
|
-
// persisted rather than counted in prose
|
|
70
|
-
//
|
|
71
|
-
// controller re-issues without tracking arithmetic across turns.
|
|
69
|
+
// persisted rather than counted in prose: the script says how much remains, so
|
|
70
|
+
// the controller re-issues without tracking arithmetic across turns.
|
|
72
71
|
export function heldThisCall({ elapsed, target, hold }) {
|
|
73
72
|
return Math.min(hold, Math.max(0, target - elapsed));
|
|
74
73
|
}
|
|
@@ -48,7 +48,7 @@ import { test } from "node:test";
|
|
|
48
48
|
import assert from "node:assert/strict";
|
|
49
49
|
import { readFileSync } from "node:fs";
|
|
50
50
|
import { join } from "node:path";
|
|
51
|
-
import { between, phrase, stripHashGutter } from "./prose-pin.mjs";
|
|
51
|
+
import { between, paragraph, phrase, stripHashGutter } from "./prose-pin.mjs";
|
|
52
52
|
|
|
53
53
|
const REPO = join(import.meta.dirname, "..");
|
|
54
54
|
const REAPING = readFileSync(
|
|
@@ -141,6 +141,58 @@ test("run-team/SKILL.md: the release deletes the branch with update-ref's compar
|
|
|
141
141
|
);
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
+
// The reap paragraph's twin of the release pin above. reap.sh deletes a
|
|
145
|
+
// `[gone]` branch with `git update-ref --no-deref -d refs/heads/<b> <tip>`,
|
|
146
|
+
// never `-D`, and keeps a branch the cherry check cleared whenever a fresh
|
|
147
|
+
// worktree check finds it held — so naming `-D`, or the cherry check as the
|
|
148
|
+
// delete's only authorizer, is false as written.
|
|
149
|
+
const reapParagraph = () =>
|
|
150
|
+
paragraph(RUN_TEAM, "`~/.fleet/bin/fleet-run reap.sh --apply` recomputes every precondition", "run-team/SKILL.md's reap paragraph");
|
|
151
|
+
|
|
152
|
+
test("run-team/SKILL.md: reap's cherry check authorizes the update-ref delete, with the fresh worktree check beside it", () => {
|
|
153
|
+
const p = reapParagraph();
|
|
154
|
+
assert.match(
|
|
155
|
+
p,
|
|
156
|
+
phrase("`git cherry origin/main` to authorize the `git update-ref -d` delete"),
|
|
157
|
+
"SKILL.md's reap paragraph no longer names the cherry check as authorizing the `git update-ref -d` delete",
|
|
158
|
+
);
|
|
159
|
+
assert.match(
|
|
160
|
+
p,
|
|
161
|
+
phrase("a fresh check that no worktree holds the branch"),
|
|
162
|
+
"SKILL.md's reap paragraph no longer names the fresh worktree check — reap.sh keeps a branch the cherry check cleared whenever a worktree holds it",
|
|
163
|
+
);
|
|
164
|
+
assert.doesNotMatch(p, /(?:^|[\s`])(?:git\s+branch\s+)?-D\b/, "SKILL.md's reap paragraph names `-D` — reap.sh deletes with `git update-ref -d`");
|
|
165
|
+
assert.doesNotMatch(
|
|
166
|
+
p,
|
|
167
|
+
/\bonly\s+by\b|\bnothing\s+else\b|\bsolely\b|\balone\b/i,
|
|
168
|
+
"SKILL.md's reap paragraph makes one check the delete's only authorizer — reap.sh's worktree check stops that delete too",
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("run-team/SKILL.md: the reap paragraph keeps the preconditions it already named", () => {
|
|
173
|
+
// Input the assertions above must ACCEPT: the corrected clause sits in a
|
|
174
|
+
// list whose other entries stay as they were.
|
|
175
|
+
const p = reapParagraph();
|
|
176
|
+
assert.match(p, phrase("`for-each-ref` for `[gone]`"));
|
|
177
|
+
assert.match(p, phrase("worktree removal without `--force`"));
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("reap.sh: the worktree check the reap paragraph names runs before the delete", () => {
|
|
181
|
+
// Live lines only: both names recur in comments, and a comment hit would
|
|
182
|
+
// read as the code.
|
|
183
|
+
const lines = readFileSync(join(REPO, "scripts", "reap.sh"), "utf8")
|
|
184
|
+
.split("\n")
|
|
185
|
+
.filter((l) => !/^\s*(?:#|echo\b)/.test(l));
|
|
186
|
+
const only = (re, what) => {
|
|
187
|
+
const hits = lines.flatMap((l, i) => (re.test(l) ? [i] : []));
|
|
188
|
+
assert.equal(hits.length, 1, `reap.sh: expected exactly one live line that ${what}, found ${hits.length}`);
|
|
189
|
+
return hits[0];
|
|
190
|
+
};
|
|
191
|
+
const check = only(/^\s*if\s+wt_holding\s+"refs\/heads\/\$b"/, "runs wt_holding on the branch");
|
|
192
|
+
const del = only(/\bgit\s+update-ref\s+--no-deref\s+-d\s+"refs\/heads\/\$b"\s+"\$tip"/, "runs `git update-ref -d` on the branch at its tip");
|
|
193
|
+
assert.ok(check < del, "reap.sh runs its worktree check after the delete, not before it");
|
|
194
|
+
});
|
|
195
|
+
|
|
144
196
|
test("run-team/SKILL.md: the by-hand fallback names worktree-audit.sh's no-argument contract", () => {
|
|
145
197
|
// #525. The by-hand fallback for a claim `release-ticket.sh` refused sends
|
|
146
198
|
// the reader to `worktree-audit.sh`, which takes NO argument and audits
|
package/skills/run-team/SKILL.md
CHANGED
|
@@ -3101,9 +3101,10 @@ included (phase 3, **Merge-bot pass reports done**). See references/reaping.md.
|
|
|
3101
3101
|
|
|
3102
3102
|
`~/.fleet/bin/fleet-run reap.sh --apply` recomputes every precondition
|
|
3103
3103
|
inside the same invocation as the delete — `for-each-ref` for `[gone]`, `git
|
|
3104
|
-
cherry origin/main` to authorize
|
|
3105
|
-
|
|
3106
|
-
|
|
3104
|
+
cherry origin/main` to authorize the `git update-ref -d` delete (plus a fresh
|
|
3105
|
+
check that no worktree holds the branch), worktree removal without `--force` —
|
|
3106
|
+
and reports reaped and kept-with-reason counts. Update the reaped tickets' ledger
|
|
3107
|
+
rows in the same step. See references/reaping.md.
|
|
3107
3108
|
|
|
3108
3109
|
**It sweeps detached worktrees too — the shape a `[gone]` walk structurally
|
|
3109
3110
|
cannot see.** Bounded to `.worktrees/`, so a checkout of yours outside it is
|