@botbuddy/cli 1.53.0 → 1.53.1

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbuddy/cli",
3
- "version": "1.53.0",
3
+ "version": "1.53.1",
4
4
  "description": "BotBuddy — Swarm coordination CLI for multi-agent workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -83,6 +83,11 @@ export function repairFailureRecovery(code, error = null) {
83
83
  if (code === "agent_tenant_immutable") {
84
84
  return "this worktree's agent identity belongs to another tenant; run `bb setup` to register this tenant, then `bb doctor --fix`";
85
85
  }
86
+ // BOT-2415: the cached session names a different agent than the one holding this
87
+ // worktree's technical name. Deterministic: a retry repeats the same conflict.
88
+ if (code === "agent_name_conflict") {
89
+ return "this worktree's cached session (.botbuddy/agent-state.json) names a different agent than the one holding the worktree's technical name; move that file aside, then run `bb doctor --fix`";
90
+ }
86
91
  // BOT-1750 (Codex R9 P2): `session_mint_unauthorized` means a locally-unexpired
87
92
  // client key was revoked/rejected server-side — only a fresh login replaces it, so
88
93
  // point at `bb login`, not a binding repair (the binding is valid).
@@ -345,6 +345,9 @@ export async function selfHealAgentSession({
345
345
  branch: currentBranch || undefined,
346
346
  ticket_id: ticketFromBranch(currentBranch),
347
347
  agent_id: presentedAgentId ?? undefined,
348
+ // A rejected-token renewal may still own locks or leases under this agent.
349
+ // Ask the server to keep it; ordinary setup/doctor repair may adopt a holder.
350
+ ...(renewal ? { preserve_agent_identity: true } : {}),
348
351
  harness_session_id: presentedHarness ?? undefined,
349
352
  harness: env.CLAUDE_CODE || env.CLAUDECODE ? "claude-code" : Object.keys(env).some((key) => key.startsWith("CODEX_")) ? "codex" : "cli",
350
353
  model: env.BOTBUDDY_MODEL || undefined,
@@ -372,8 +375,14 @@ export async function selfHealAgentSession({
372
375
  const typedCode = typeof response?.code === "string"
373
376
  ? response.code
374
377
  : typeof data.code === "string" ? data.code : null;
375
- const code = typedCode === "agent_tenant_immutable"
378
+ // BOT-2415: a technical-name conflict is deterministic (the cached agent_id
379
+ // names a different agent than the one holding this worktree's name), so no
380
+ // retry fixes it. Recognise the typed refusal and an older server's raw 23505.
381
+ const nameConflict = typedCode === "agent_name_taken"
382
+ || /agents_name_key/.test(String(response?.error ?? data.error ?? ""));
383
+ const code = ["agent_tenant_immutable", "session_identity_mismatch"].includes(typedCode)
376
384
  ? typedCode
385
+ : nameConflict ? "agent_name_conflict"
377
386
  : response?.auth ? "session_mint_unauthorized" : "session_mint_failed";
378
387
  // BOT-1891: name the credential (never its value) so `bb doctor` can point a
379
388
  // rejected tier-2 key at rotation instead of `bb login`.
package/src/commands.mjs CHANGED
@@ -568,7 +568,7 @@ function setupFailureRecovery(error) {
568
568
  if (code === "tenant_binding_required" || code === "invalid_binding") {
569
569
  return "fix the committed .botbuddy-agent.json binding, then retry `bb setup`";
570
570
  }
571
- if (code === "client_key_unavailable" || code === "session_mint_unauthorized") return repairFailureRecovery(code, error);
571
+ if (code === "client_key_unavailable" || code === "session_mint_unauthorized" || code === "agent_name_conflict") return repairFailureRecovery(code, error);
572
572
  return "retry `bb setup`";
573
573
  }
574
574
 
package/src/stack.mjs CHANGED
@@ -985,7 +985,7 @@ export function retryingStackCall({
985
985
  // taxonomy so automation sees AUTH/BACKEND, not a CLI-defect INTERNAL. Credential
986
986
  // problems are AUTH (3); a transport/server mint failure is BACKEND (5); anything
987
987
  // unrecognized stays INTERNAL (7).
988
- const AUTH_ERROR_CODES = new Set(["client_key_required", "client_key_unavailable", "tenant_binding_required", "session_token_malformed", "session_mint_unauthorized", "session_identity_mismatch"]);
988
+ const AUTH_ERROR_CODES = new Set(["client_key_required", "client_key_unavailable", "tenant_binding_required", "session_token_malformed", "session_mint_unauthorized", "session_identity_mismatch", "agent_name_conflict"]);
989
989
  // BOT-1750 (Codex R11 P2): `session_mint_invalid` is an incompatible/malformed SERVER
990
990
  // response, not a credential problem — classify it with the transport/server failures.
991
991
  const BACKEND_ERROR_CODES = new Set(["session_mint_failed", "session_mint_invalid"]);
@@ -1423,6 +1423,7 @@ export const PARK_AUTH_BUDGET_MS = 5 * 60_000;
1423
1423
  // the regular auth budget; it is not evidence that the lease changed owner.
1424
1424
  const DEFINITIVE_REAUTH_CODES = new Set([
1425
1425
  "session_identity_mismatch", "client_key_required", "tenant_binding_required", "session_token_malformed", "agent_tenant_immutable",
1426
+ "agent_name_conflict",
1426
1427
  ]);
1427
1428
 
1428
1429
  function abortableSleep(ms, signal) {
package/src/wait.mjs CHANGED
@@ -20,6 +20,7 @@ import { fileURLToPath } from "node:url";
20
20
  import { latestPublicCliCommand } from "./public-invocation.mjs";
21
21
  import { AGENT_KEY_RE, readAgentSessionTokenEnv, legacyAgentAliasHint } from "./agent-key.mjs";
22
22
  import { clearAgentState, hasAgentSessionRuntime, isRejectedCachedSession, resolveAgentSessionCredential, selfHealAgentSession } from "./agent-session.mjs";
23
+ import { repairFailureRecovery } from "./agent-doctor.mjs";
23
24
  import { touchAgentStateExpiry } from "./agent-state.mjs";
24
25
  import { SETUP_BLOCK } from "./setup-block.mjs";
25
26
  import { createWaitCheckpointStore, WaitCheckpointError } from "./wait-checkpoint.mjs";
@@ -1679,7 +1680,10 @@ export async function runWait(argv, { recoveryLocalWaitId = null } = {}) {
1679
1680
  opts.credentialSource = credential.source;
1680
1681
  } catch (error) {
1681
1682
  const code = error?.code ?? "session_mint_failed";
1682
- const recovery = code === "client_key_required"
1683
+ // BOT-2415: a stale cache naming another agent is not fixed by `bb setup` + retry.
1684
+ const recovery = code === "agent_name_conflict"
1685
+ ? repairFailureRecovery(code)
1686
+ : code === "client_key_required"
1683
1687
  ? "run `bb setup` from this project worktree, then retry"
1684
1688
  : code === "tenant_binding_required"
1685
1689
  ? "run from a configured project worktree, then run `bb setup` and retry"