@botbuddy/cli 1.63.40 → 1.63.41
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/daemon/bin/darwin-arm64/botbuddy-daemon +0 -0
- package/daemon/bin/linux-x64/botbuddy-daemon +0 -0
- package/daemon-release/darwin-arm64.json +4 -4
- package/daemon-release/linux-x64.json +4 -4
- package/daemon-release/manifest.json +5 -5
- package/package.json +1 -1
- package/src/pw/staging-auth.mjs +6 -1
- package/src/staging-pool/cli.mjs +12 -0
- package/src/staging-pool/errors.mjs +5 -3
- package/src/staging-pool/pool.mjs +2 -2
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"release_version": "1.63.
|
|
3
|
-
"source_commit": "
|
|
4
|
-
"source_sha256": "
|
|
2
|
+
"release_version": "1.63.41",
|
|
3
|
+
"source_commit": "89653c3c1d5a7144abd8bdab27a9496900cdb1d0",
|
|
4
|
+
"source_sha256": "d524b98618977c153c57ae009f9cbab3da72f0255fb9a0b01e840a7c78550dc3",
|
|
5
5
|
"target": "darwin-arm64",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "ffee8ba3b0a0b849075f06f5186ca2aa8f14fca124c1460a396f410b95a655d7"
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"release_version": "1.63.
|
|
3
|
-
"source_commit": "
|
|
4
|
-
"source_sha256": "
|
|
2
|
+
"release_version": "1.63.41",
|
|
3
|
+
"source_commit": "89653c3c1d5a7144abd8bdab27a9496900cdb1d0",
|
|
4
|
+
"source_sha256": "d524b98618977c153c57ae009f9cbab3da72f0255fb9a0b01e840a7c78550dc3",
|
|
5
5
|
"target": "linux-x64",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "594d96944fbea3354a6d26186d92e989470ee75734fd7fd53f5eb681eab1f43d"
|
|
7
7
|
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
|
-
"release_version": "1.63.
|
|
4
|
-
"source_commit": "
|
|
5
|
-
"source_sha256": "
|
|
3
|
+
"release_version": "1.63.41",
|
|
4
|
+
"source_commit": "89653c3c1d5a7144abd8bdab27a9496900cdb1d0",
|
|
5
|
+
"source_sha256": "d524b98618977c153c57ae009f9cbab3da72f0255fb9a0b01e840a7c78550dc3",
|
|
6
6
|
"targets": {
|
|
7
7
|
"darwin-arm64": {
|
|
8
8
|
"goos": "darwin",
|
|
9
9
|
"goarch": "arm64",
|
|
10
10
|
"binary": "daemon/bin/darwin-arm64/botbuddy-daemon",
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "ffee8ba3b0a0b849075f06f5186ca2aa8f14fca124c1460a396f410b95a655d7",
|
|
12
12
|
"mode": "0755"
|
|
13
13
|
},
|
|
14
14
|
"linux-x64": {
|
|
15
15
|
"goos": "linux",
|
|
16
16
|
"goarch": "amd64",
|
|
17
17
|
"binary": "daemon/bin/linux-x64/botbuddy-daemon",
|
|
18
|
-
"sha256": "
|
|
18
|
+
"sha256": "594d96944fbea3354a6d26186d92e989470ee75734fd7fd53f5eb681eab1f43d",
|
|
19
19
|
"mode": "0755"
|
|
20
20
|
}
|
|
21
21
|
}
|
package/package.json
CHANGED
package/src/pw/staging-auth.mjs
CHANGED
|
@@ -295,6 +295,8 @@ export async function runStagingAuth({ plan, host, env, deps, socketRun, resolve
|
|
|
295
295
|
}
|
|
296
296
|
const found = { binding: ctxPool.poolBinding };
|
|
297
297
|
Object.assign(vars, { allowed: Object.keys(found.binding.personas ?? {}), tenant: ctxPool.tenant ?? undefined, poolId: ctxPool.poolId ?? undefined });
|
|
298
|
+
// BOT-2836: a retry addresses the same pool when one was named (several installed).
|
|
299
|
+
if (plan.pool) vars.retry = `${authLine} --pool ${ctxPool.poolId}`;
|
|
298
300
|
const { findPersona } = await loadBinding();
|
|
299
301
|
const persona = findPersona(found.binding, plan.persona);
|
|
300
302
|
if (!persona) return refuse(io, "persona_not_allowlisted", 2, {}, vars);
|
|
@@ -317,7 +319,10 @@ export async function runStagingAuth({ plan, host, env, deps, socketRun, resolve
|
|
|
317
319
|
// The refusal's code is the pool's health reason when it is unhealthy (e.g. a
|
|
318
320
|
// count-0 persona is persona_not_configured), so code, message and help agree.
|
|
319
321
|
const reasonCode = typeof error.reason === "string" && error.reason !== "healthy" && isKnownCode(error.reason) ? error.reason : "pool_empty";
|
|
320
|
-
|
|
322
|
+
// BOT-2836: a healthy empty pool is the agent's own wait-and-retry, so it is
|
|
323
|
+
// rendered here with this lane; an unhealthy pool keeps the pool's health guidance.
|
|
324
|
+
const forwarded = reasonCode === "pool_empty" ? ["reason", "detail"] : ["reason", "detail", ...GUIDED_FIELDS];
|
|
325
|
+
return refuse(io, reasonCode, 3, Object.fromEntries(forwarded.filter((key) => error[key] !== undefined).map((key) => [key, error[key]])), vars);
|
|
321
326
|
}
|
|
322
327
|
const code = typeof error?.code === "string" && isKnownCode(error.code) ? error.code : "pool_take_failed";
|
|
323
328
|
return refuse(io, code, 3, { detail: String(error?.message ?? error).slice(0, 300) }, vars);
|
package/src/staging-pool/cli.mjs
CHANGED
|
@@ -236,6 +236,16 @@ export function resolveInstalledPool({ home = homedir(), poolId = null, tenantHi
|
|
|
236
236
|
throw Object.assign(new ConfigError(`Several staging session pools are installed: ${installed.map((pool) => pool.poolId).join(", ")}.`, "pool_ambiguous"), { poolIds: installed.map((pool) => pool.poolId) });
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
+
// BOT-2836: after a take, ask the installed launchd job to run its tick now, so the
|
|
240
|
+
// pool refills without waiting for the interval or a human `tick`. The job signs in
|
|
241
|
+
// (with its own backoff); the agent never does. No -k: a running tick is never killed.
|
|
242
|
+
// Best effort: an unloaded job surfaces through health, and never fails the take.
|
|
243
|
+
async function requestRefill({ ctx, exec, uid }) {
|
|
244
|
+
const label = ctx.poolBinding?.launchdLabel;
|
|
245
|
+
if (!label) return;
|
|
246
|
+
await createLaunchctl({ exec, uid }).kickstart(label).catch(() => {});
|
|
247
|
+
}
|
|
248
|
+
|
|
239
249
|
/**
|
|
240
250
|
* Agent path, used by `bb pw … auth`: claim one verified session for a persona
|
|
241
251
|
* (alias or email) of the installed pool. Returns { taken, target, binding,
|
|
@@ -263,9 +273,11 @@ export async function takeForLane({
|
|
|
263
273
|
const pool = buildPool({ ctx, target, now, logger, intervalSeconds, fetchImpl });
|
|
264
274
|
try {
|
|
265
275
|
const taken = await pool.take({ persona: entry.email, owner });
|
|
276
|
+
await requestRefill({ ctx, exec, uid });
|
|
266
277
|
return { taken, target, binding: ctx.poolBinding, persona: entry, discard: () => pool.discardTaken(taken.slotId) };
|
|
267
278
|
} catch (error) {
|
|
268
279
|
if (!(error instanceof PoolEmptyError)) throw error;
|
|
280
|
+
await requestRefill({ ctx, exec, uid });
|
|
269
281
|
const health = await assessHealth({ ctx, pool, now, exec, uid, requestedPersona: entry.email });
|
|
270
282
|
let effective = health;
|
|
271
283
|
if (health.ok) {
|
|
@@ -131,10 +131,12 @@ export const ERROR_CODES = Object.freeze({
|
|
|
131
131
|
`${AUTH} # once; if it repeats, report this code and detail`, "retry_once"),
|
|
132
132
|
|
|
133
133
|
// ── the pool's health (human repairs; agents report once and stop)
|
|
134
|
-
|
|
134
|
+
// BOT-2836: a healthy pool emptied between ticks is a wait, not a repair. The take
|
|
135
|
+
// already asked the human-installed job to refill now, so the agent waits once and retries.
|
|
136
|
+
pool_empty: entry("agent", "take",
|
|
135
137
|
"The staging session pool is healthy but has no ready session for {persona}.",
|
|
136
|
-
"Agents took every ready session since the last tick, or the ready ones were dead or AAL1 (factor rotated) and were discarded.",
|
|
137
|
-
"{
|
|
138
|
+
"Agents took every ready session since the last tick, or the ready ones were dead or AAL1 (factor rotated) and were discarded; the pool job was asked to refill now.",
|
|
139
|
+
"bb wait 'timer:duration=60' && {retry} # once; if it repeats, report this code", "retry_once"),
|
|
138
140
|
job_not_loaded: entry("human", "install",
|
|
139
141
|
"The staging session pool is not installed (or not loaded) on this Mac.",
|
|
140
142
|
"The one-time install has not been run here, or the Mac was migrated.",
|
|
@@ -30,8 +30,8 @@ import {
|
|
|
30
30
|
export class PoolEmptyError extends Error {
|
|
31
31
|
constructor(persona, intervalHint) {
|
|
32
32
|
super(
|
|
33
|
-
`No ready ${persona} session in the pool. The human-owned pool job refills on its next tick${intervalHint}
|
|
34
|
-
"
|
|
33
|
+
`No ready ${persona} session in the pool. The human-owned pool job refills on its next tick${intervalHint} ` +
|
|
34
|
+
"and was asked to refill now; wait once, retry once, and report it if it repeats. " +
|
|
35
35
|
"Agents never sign in to staging themselves.",
|
|
36
36
|
);
|
|
37
37
|
this.name = "PoolEmptyError";
|