@botbuddy/cli 1.8.4 → 1.8.5
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 +1 -1
- package/src/botbuddy-release-repair.json +1 -1
- package/src/wait-core.mjs +46 -5
- package/src/wait.mjs +7 -1
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"schema_version":1,"source_version":"1.8.3","source_identity":"
|
|
1
|
+
{"schema_version":1,"source_version":"1.8.3","source_identity":"a3c85408868d913b2ab265f910ab062916c1c394895cec71cae0f79fc99f5a6c"}
|
package/src/wait-core.mjs
CHANGED
|
@@ -196,20 +196,44 @@ const VALIDATORS = {
|
|
|
196
196
|
// BOT-1066 — ci: wake when a PR's CI reaches a terminal conclusion. Exactly one
|
|
197
197
|
// selector: scope=latest (follows the PR's latest run — needs pr=), run_id=<id>
|
|
198
198
|
// (pinned to one run), or sha=<sha> (pinned to a commit). repo= is always required.
|
|
199
|
+
// BOT-1507 — scope=next adds a fourth, LIVE-ONLY selector: it names no run, sha,
|
|
200
|
+
// or PR (they must all already exist at arm time) and wakes on the first terminal
|
|
201
|
+
// CI run for the repo delivered AFTER the wait was armed — the post-merge / cron
|
|
202
|
+
// train case. Optional branch=/workflow= filter that first run; both are valid
|
|
203
|
+
// ONLY with scope=next (a run_id/sha/latest wait already names its run).
|
|
199
204
|
ci(p) {
|
|
200
205
|
const repo = p.repo != null ? String(p.repo).trim() : null;
|
|
201
206
|
if (!repo || !repo.includes("/")) throw new Error("ci needs repo=<owner/repo>");
|
|
202
207
|
const selectors = ["scope", "run_id", "sha"].filter((k) => p[k] !== undefined);
|
|
203
208
|
if (selectors.length !== 1) {
|
|
204
|
-
throw new Error("ci needs exactly one of scope=latest | run_id=<id> | sha=<sha>");
|
|
209
|
+
throw new Error("ci needs exactly one of scope=latest|next | run_id=<id> | sha=<sha>");
|
|
205
210
|
}
|
|
211
|
+
const hasFilter = p.branch !== undefined || p.workflow !== undefined;
|
|
206
212
|
if (p.scope !== undefined) {
|
|
207
|
-
if (p.scope
|
|
208
|
-
|
|
209
|
-
|
|
213
|
+
if (p.scope === "latest") {
|
|
214
|
+
if (hasFilter) throw new Error("ci branch=/workflow= are only valid with scope=next");
|
|
215
|
+
if (p.pr === undefined || !/^\d+$/.test(String(p.pr).trim())) {
|
|
216
|
+
throw new Error("ci scope=latest needs pr=<number>");
|
|
217
|
+
}
|
|
218
|
+
return { repo, scope: "latest", pr: String(p.pr).trim() };
|
|
219
|
+
}
|
|
220
|
+
if (p.scope === "next") {
|
|
221
|
+
// A future run has no PR head to follow — pr= is meaningless (and run_id/sha
|
|
222
|
+
// are already excluded by the single-selector check above).
|
|
223
|
+
if (p.pr !== undefined) {
|
|
224
|
+
throw new Error("ci scope=next takes no pr= (it targets a future run, not a PR head)");
|
|
225
|
+
}
|
|
226
|
+
const filter = (key) => {
|
|
227
|
+
if (p[key] === undefined) return null;
|
|
228
|
+
const v = String(p[key]).trim();
|
|
229
|
+
if (v === "") throw new Error(`ci ${key}= must be non-empty`);
|
|
230
|
+
return v;
|
|
231
|
+
};
|
|
232
|
+
return { repo, scope: "next", branch: filter("branch"), workflow: filter("workflow"), pr: null };
|
|
210
233
|
}
|
|
211
|
-
|
|
234
|
+
throw new Error("ci scope must be 'latest' or 'next' (or use run_id=/sha=)");
|
|
212
235
|
}
|
|
236
|
+
if (hasFilter) throw new Error("ci branch=/workflow= are only valid with scope=next");
|
|
213
237
|
if (p.run_id !== undefined) {
|
|
214
238
|
if (!String(p.run_id).trim()) throw new Error("ci run_id must be non-empty");
|
|
215
239
|
return { repo, scope: "run_id", runId: String(p.run_id).trim(), pr: p.pr != null ? String(p.pr).trim() : null };
|
|
@@ -679,6 +703,23 @@ function conditionMatchesSignal(condition, signal, waitSessionId) {
|
|
|
679
703
|
if (String(signal.payload?.repo ?? "").toLowerCase() !== params.repo.toLowerCase()) return false;
|
|
680
704
|
if (params.scope === "run_id") return String(signal.payload?.run_id) === params.runId;
|
|
681
705
|
if (params.scope === "sha") return signal.payload?.head_sha === params.sha;
|
|
706
|
+
if (params.scope === "next") {
|
|
707
|
+
// BOT-1507 — live-only: the first TERMINAL run for the repo. Never keys on
|
|
708
|
+
// subject_key (it is run:<id> for post-merge runs and owner/repo#n for PR
|
|
709
|
+
// runs — both are legitimate wakes); a null/empty conclusion is an
|
|
710
|
+
// in-progress signal and never terminal. Optional branch/workflow filters:
|
|
711
|
+
// branch is exact, workflow is the GitHub display name (case/space-insensitive).
|
|
712
|
+
const conclusion = signal.payload?.conclusion;
|
|
713
|
+
if (typeof conclusion !== "string" || conclusion.trim() === "") return false;
|
|
714
|
+
if (params.branch != null && signal.payload?.head_branch !== params.branch) return false;
|
|
715
|
+
if (params.workflow != null) {
|
|
716
|
+
const wf = signal.payload?.workflow_name;
|
|
717
|
+
if (typeof wf !== "string" || wf.trim().toLowerCase() !== params.workflow.trim().toLowerCase()) {
|
|
718
|
+
return false;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
return true;
|
|
722
|
+
}
|
|
682
723
|
// scope=latest: the PR's run (by subject owner/repo#pr or payload pr_number).
|
|
683
724
|
return signal.subject_key === `${params.repo}#${params.pr}` ||
|
|
684
725
|
(signal.payload?.pr_number != null && String(signal.payload.pr_number) === params.pr);
|
package/src/wait.mjs
CHANGED
|
@@ -75,10 +75,16 @@ CONDITIONS (TYPE:key=val,key=val — repeat for several; --any wakes on the fir
|
|
|
75
75
|
Host-shared; a silently-dead host is detected server-side
|
|
76
76
|
(capacity_source_stale) via a host beacon — the client
|
|
77
77
|
grace (default 900s) is a backstop, no longer the only guard.
|
|
78
|
-
ci:repo=<owner/repo>,{scope=latest,pr=<n> | run_id=<id> | sha=<sha>
|
|
78
|
+
ci:repo=<owner/repo>,{scope=latest,pr=<n> | run_id=<id> | sha=<sha>
|
|
79
|
+
| scope=next[,branch=<name>][,workflow=<name>]}
|
|
79
80
|
a PR's CI reaching a terminal conclusion (owner-scoped);
|
|
80
81
|
GitHub Actions or an external check_suite provider.
|
|
81
82
|
A repo with no CI feed is rejected (no_signal_source).
|
|
83
|
+
scope=next is LIVE-ONLY: it wakes on the first terminal
|
|
84
|
+
run delivered AFTER arm (post-merge / cron / scheduled),
|
|
85
|
+
never replays a finished run, and needs no run_id/sha/pr.
|
|
86
|
+
Optional branch= (exact) / workflow= (GitHub workflow
|
|
87
|
+
DISPLAY name, case-insensitive) narrow that first run.
|
|
82
88
|
staging-green:repo=<owner/repo> verified automatic recovery of an enabled staging gate.
|
|
83
89
|
Wakes only after a complete non-vacuous workflow success;
|
|
84
90
|
manual resolutions, overrides, skipped, and neutral runs do not match.
|