@botbuddy/cli 1.45.0 → 1.45.2
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 -0
- package/src/stack.mjs +21 -3
- package/src/wait-core.mjs +6 -3
- package/src/wait.mjs +3 -3
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"schema_version":1,"source_version":"1.45.1","source_identity":"2fa051c4d0ee5cb09fda8d9e15c4952af94d701a6a43e98c8831912040cb41f2"}
|
package/src/stack.mjs
CHANGED
|
@@ -320,7 +320,7 @@ export function parseStackArgs(argv) {
|
|
|
320
320
|
case "--idle-ttl": {
|
|
321
321
|
if (need(a, rest[i + 1])) {
|
|
322
322
|
const n = Number(rest[++i]);
|
|
323
|
-
if (!Number.isFinite(n) || !Number.isInteger(n) || n
|
|
323
|
+
if (!Number.isFinite(n) || !Number.isInteger(n) || n < 2) errors.push("--idle-ttl must be an integer of at least 2 seconds so the one-second heartbeat can keep the lease alive");
|
|
324
324
|
else opts.idleTtl = n;
|
|
325
325
|
}
|
|
326
326
|
break;
|
|
@@ -1766,6 +1766,20 @@ function readStackIdentity(dir, read = readFileSync) {
|
|
|
1766
1766
|
* is best-effort (unreadable config ⇒ treated as isolated, since the parse+provision
|
|
1767
1767
|
* guards already blocked a same-project subdir at `up`). Never mutates.
|
|
1768
1768
|
*/
|
|
1769
|
+
// BOT-1935: every local-exec lease has persisted `connection.botbuddy_docker_target`
|
|
1770
|
+
// since CLI 1.5.0, so a TARGETLESS lease activated on/after this instant was provisioned
|
|
1771
|
+
// by the Helper, not by a pre-1.5.0 client (prod 069096a4, 2026-09-29). The server names
|
|
1772
|
+
// the Helper as `provisioner` only when it holds the Helper's succeeded receipt; this is
|
|
1773
|
+
// the diagnosis for the rest. It never authorizes anything: the lease stays fenced.
|
|
1774
|
+
export const HELPER_ERA_ACTIVATED_AT = Date.parse("2026-09-01T00:00:00Z");
|
|
1775
|
+
|
|
1776
|
+
export function targetlessHelperLeaseRefusal(lease, leaseId) {
|
|
1777
|
+
const activatedAt = Date.parse(lease?.activated_at ?? "");
|
|
1778
|
+
if (lease?.connection?.botbuddy_docker_target || !(activatedAt >= HELPER_ERA_ACTIVATED_AT)) return null;
|
|
1779
|
+
return `this lease was provisioned by the Helper; release it with \`bb stack done ${leaseId}\` (no --local-exec) ` +
|
|
1780
|
+
"from the owning session, or ask the operator; lease and slot remain fenced";
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1769
1783
|
export function localExecTeardownIsNonIsolated(lease, read = readFileSync) {
|
|
1770
1784
|
const stackPath = lease?.stack_path || ".";
|
|
1771
1785
|
if (stackPath === ".") return true;
|
|
@@ -2580,16 +2594,20 @@ export async function cmdDone(leaseId, opts, {
|
|
|
2580
2594
|
// the compatibility contract still pins them there, so keep this path OrbStack-only:
|
|
2581
2595
|
// a Docker Desktop daemon (newly admitted by the preflight allowlist for MODERN
|
|
2582
2596
|
// leases) must never authorize teardown of a targetless legacy OrbStack lease.
|
|
2597
|
+
// BOT-1935: a targetless lease activated after the 1.5.0 era is not legacy — the
|
|
2598
|
+
// Helper provisioned it (local-exec has persisted a target since 1.5.0). Same fence,
|
|
2599
|
+
// same exit code; only the diagnosis names the release path that actually works.
|
|
2600
|
+
const helperLeaseRefusal = targetlessHelperLeaseRefusal(current.data, leaseId);
|
|
2583
2601
|
if (dockerTarget?.validation !== "orbstack") {
|
|
2584
2602
|
return emitResult(buildReceipt({ command: "done", outcome: "refused", lease_id: leaseId,
|
|
2585
|
-
error: `pre-1.5.0 lease has no persisted Docker target; only an OrbStack daemon may authorize legacy teardown, not ${dockerTarget?.validation || "an unverified engine"}; lease and slot remain fenced`,
|
|
2603
|
+
error: helperLeaseRefusal ?? `pre-1.5.0 lease has no persisted Docker target; only an OrbStack daemon may authorize legacy teardown, not ${dockerTarget?.validation || "an unverified engine"}; lease and slot remain fenced`,
|
|
2586
2604
|
expected_docker_target: null, observed_docker_target: dockerTarget,
|
|
2587
2605
|
}), opts, EXIT.LEASE_FAILED);
|
|
2588
2606
|
}
|
|
2589
2607
|
const proof = proveLegacyTarget(current.data, dockerTarget, opts);
|
|
2590
2608
|
if (!proof?.ok) {
|
|
2591
2609
|
return emitResult(buildReceipt({ command: "done", outcome: "refused", lease_id: leaseId,
|
|
2592
|
-
error: `pre-1.5.0 lease has no persisted Docker target and compatibility proof failed: ${proof?.error || "unknown proof failure"}; lease and slot remain fenced`,
|
|
2610
|
+
error: helperLeaseRefusal ?? `pre-1.5.0 lease has no persisted Docker target and compatibility proof failed: ${proof?.error || "unknown proof failure"}; lease and slot remain fenced`,
|
|
2593
2611
|
expected_docker_target: null, observed_docker_target: dockerTarget,
|
|
2594
2612
|
}), opts, EXIT.LEASE_FAILED);
|
|
2595
2613
|
}
|
package/src/wait-core.mjs
CHANGED
|
@@ -436,10 +436,13 @@ function prSubjectMatches(subjectKey, params) {
|
|
|
436
436
|
return subjectKey.startsWith(`${params.repo}#`);
|
|
437
437
|
}
|
|
438
438
|
|
|
439
|
-
// Does a commit field on a signal payload
|
|
440
|
-
//
|
|
439
|
+
// Does a commit field on a signal payload identify the same commit as the
|
|
440
|
+
// condition's SHA? GitHub may send either side as a 7–40-character prefix, so
|
|
441
|
+
// accept either prefix direction while refusing malformed payload values.
|
|
441
442
|
function shaPrefixMatches(value, sha) {
|
|
442
|
-
|
|
443
|
+
if (typeof value !== "string") return false;
|
|
444
|
+
const candidate = value.trim().toLowerCase();
|
|
445
|
+
return /^[0-9a-f]{7,40}$/.test(candidate) && (candidate.startsWith(sha) || sha.startsWith(candidate));
|
|
443
446
|
}
|
|
444
447
|
|
|
445
448
|
// BOT-1975: optional head scoping for pr-state. pr_state signals carry the PR
|
package/src/wait.mjs
CHANGED
|
@@ -78,8 +78,8 @@ CONDITIONS (TYPE:key=val,key=val — repeat for several; --any wakes on the fir
|
|
|
78
78
|
by the PR read model. Omit pr= to wake on ANY of your PRs
|
|
79
79
|
in the repo; or pass pr=<owner/repo#n> in one value. A
|
|
80
80
|
conflict/clean flip sets payload.mergeable_changed. The
|
|
81
|
-
payload carries head_ref_oid; sha=<head> (7-40 hex
|
|
82
|
-
|
|
81
|
+
payload carries head_ref_oid; sha=<head> (7-40 hex; either
|
|
82
|
+
side may be an abbreviated prefix) wakes only on signals for that head, so a
|
|
83
83
|
previous head's check result can't wake you. A push alone
|
|
84
84
|
emits nothing — the head rides on the next transition.
|
|
85
85
|
pr-review:repo=<owner/repo>[,pr=<n>][,reviewer=<login>][,sha=<commit>]
|
|
@@ -96,7 +96,7 @@ CONDITIONS (TYPE:key=val,key=val — repeat for several; --any wakes on the fir
|
|
|
96
96
|
existing review will not re-wake it.
|
|
97
97
|
reviewer=<login> wakes only on that reviewer (case-
|
|
98
98
|
insensitive; a trailing [bot] is ignored). sha=<commit>
|
|
99
|
-
wakes only on verdicts for that commit (submitted reviews
|
|
99
|
+
wakes only on verdicts for that commit (either side may be an abbreviated prefix; submitted reviews
|
|
100
100
|
and clean passes carry commit_sha; thread comments do not,
|
|
101
101
|
so they never match sha=); the usage-limit decline always
|
|
102
102
|
passes sha=. Any other key is refused (exit 4).
|