@botbuddy/cli 1.8.1 → 1.8.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/pw/coordinator.mjs +1 -1
- package/src/pw/run.mjs +17 -9
package/package.json
CHANGED
package/src/pw/coordinator.mjs
CHANGED
|
@@ -8,5 +8,5 @@ export function createProfileCoordinator({ profile, identity, fetchImpl = fetch
|
|
|
8
8
|
const json = await response.json(); if (json.error) throw new Error(json.error.message || "BotBuddy lock verification failed");
|
|
9
9
|
const text = json.result?.content?.find((item) => item.type === "text")?.text; try { return text ? JSON.parse(text) : {}; } catch { throw new Error("BotBuddy lock verification returned invalid JSON"); }
|
|
10
10
|
}
|
|
11
|
-
return { kind: "profile", async status({ host, slot }) { const result = await call("list_resources", { host, subtype: "playwright_lane" }); const list = Array.isArray(result) ? result : result.resources ?? []; const resource = list.find((item) => item.name === `playwright_lane:${host}:${slot}` || String(item.slot) === String(slot)); return resource ? { held: resource.status !== "free", heldBy: resource.owner_agent_id ?? null, heldByName: resource.agents?.name ?? null, host: resource.host ?? null, name: resource.name ?? null, slot: resource.slot ?? null } : { held: false, heldBy: null, heldByName: null, host: null, name: null, slot: null }; }, async emit(event) { await call("record_lane_event", event); }, agentId: identity.agentId };
|
|
11
|
+
return { kind: "profile", async status({ host, slot }) { const result = await call("list_resources", { host, subtype: "playwright_lane" }); const list = Array.isArray(result) ? result : result.resources ?? []; const resource = list.find((item) => item.name === `playwright_lane:${host}:${slot}` || String(item.slot) === String(slot)); /* BOT-1490: canonical_host is a TOP-LEVEL field the server echoes even on an empty page (not-held lane); owner_is_caller is per-row. Older servers send neither → null. */ const canonicalHost = (result && !Array.isArray(result) ? result.canonical_host : null) ?? null; return resource ? { held: resource.status !== "free", heldBy: resource.owner_agent_id ?? null, heldByName: resource.agents?.name ?? null, host: resource.host ?? null, name: resource.name ?? null, slot: resource.slot ?? null, canonicalHost, ownerIsCaller: resource.owner_is_caller ?? null } : { held: false, heldBy: null, heldByName: null, host: null, name: null, slot: null, canonicalHost, ownerIsCaller: null }; }, async emit(event) { await call("record_lane_event", event); }, agentId: identity.agentId };
|
|
12
12
|
}
|
package/src/pw/run.mjs
CHANGED
|
@@ -43,16 +43,24 @@ async function gate({ env, host, lane, deps }) {
|
|
|
43
43
|
try {
|
|
44
44
|
const status = await coordinator.status({ host, slot: lane });
|
|
45
45
|
// The server's alias map can collapse the locally-normalized host further
|
|
46
|
-
// (jonos-macbook-pro -> jonos-mbp).
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
46
|
+
// (jonos-macbook-pro -> jonos-mbp). BOT-1490: the lock service now echoes that
|
|
47
|
+
// canonical host as a top-level field EVEN on a not-held lane (empty page), so
|
|
48
|
+
// prefer it for every lane name/message; fall back to the resource host
|
|
49
|
+
// (BOT-1488, only present when a resource was returned) then the local string —
|
|
50
|
+
// without replicating the alias map here.
|
|
51
|
+
const canonicalHost = status.canonicalHost ?? status.host ?? host;
|
|
52
|
+
const foundLaneName = status.name ?? `playwright_lane:${canonicalHost}:${lane}`;
|
|
53
|
+
// Allow when a local id matches the holder (BOT-1488: profile / --session-id /
|
|
54
|
+
// $BOTBUDDY_SESSION_ID / ~/.botbuddy/config.json) OR the lock service attributes
|
|
55
|
+
// the holder to the caller's owner (BOT-1490 owner_is_caller — server-authoritative,
|
|
56
|
+
// closing the shared-hostname gap without trusting a local file). The local paths
|
|
57
|
+
// stay as fallbacks for older servers that do not send owner_is_caller.
|
|
58
|
+
if (status.held && (selfAgentIds.has(status.heldBy) || status.ownerIsCaller === true)) return { allowed: true, coordinator, canonicalHost };
|
|
53
59
|
// Distinguish an expired/free lane from one another operator holds so the
|
|
54
|
-
// operator knows whether to re-acquire vs. wait for a handover (BOT-660).
|
|
55
|
-
|
|
60
|
+
// operator knows whether to re-acquire vs. wait for a handover (BOT-660). Name it
|
|
61
|
+
// by the server's canonical host so a not-held message matches the dashboard even
|
|
62
|
+
// when local normalization cannot reach the alias-collapsed key (BOT-1490 AC-5).
|
|
63
|
+
if (!status.held) return { allowed: false, message: `bb-pw: lane lock ${foundLaneName} is not held (caller ${identity.agentId}). Acquire it via BotBuddy first, or set BB_PW_NO_LOCK=1 for local-only work.` };
|
|
56
64
|
const holder = status.heldBy ?? "unknown";
|
|
57
65
|
const holderName = status.heldByName ? ` (${status.heldByName})` : "";
|
|
58
66
|
return { allowed: false, message: `bb-pw: lane lock ${foundLaneName} is held by ${holder}${holderName}, not you (caller ${identity.agentId}). Acquire it first or set BB_PW_NO_LOCK=1 for local-only work.` };
|