@botbuddy/cli 1.55.0 → 1.56.0
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
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ticket": "BOT-2403",
|
|
3
|
+
"captured_at": "2026-10-16T20:43:49Z",
|
|
4
|
+
"provenance": "Actual Docker Desktop container inspect .Mounts and context inspect on owned MacBook lease 0c68ff71-3a1a-4d3c-b7d2-d06617609772; requester and container destination both contained43 entries; actual MCP readyz HTTP200/version2.97.1. No environment/credentials captured.",
|
|
5
|
+
"project_id": "bbbot240305b549",
|
|
6
|
+
"host_functions_dir": "/Users/jono/Developer/botbuddy-web/.claude/worktrees/bot-2402/.botbuddy/stacks/bbbot240305b549/supabase/functions",
|
|
7
|
+
"docker_context": "desktop-linux",
|
|
8
|
+
"docker_endpoint": "unix:///Users/jono/.docker/run/docker.sock",
|
|
9
|
+
"mounts": [
|
|
10
|
+
{
|
|
11
|
+
"Type": "volume",
|
|
12
|
+
"Name": "supabase_edge_runtime_bbbot240305b549",
|
|
13
|
+
"Source": "/var/lib/docker/volumes/supabase_edge_runtime_bbbot240305b549/_data",
|
|
14
|
+
"Destination": "/root/.cache/deno",
|
|
15
|
+
"Driver": "local",
|
|
16
|
+
"Mode": "rw",
|
|
17
|
+
"RW": true,
|
|
18
|
+
"Propagation": ""
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"Type": "bind",
|
|
22
|
+
"Source": "/host_mnt/Users/jono/Developer/botbuddy-web/.claude/worktrees/bot-2402/.botbuddy/stacks/bbbot240305b549/supabase/functions",
|
|
23
|
+
"Destination": "/Users/jono/Developer/botbuddy-web/.claude/worktrees/bot-2402/.botbuddy/stacks/bbbot240305b549/supabase/functions",
|
|
24
|
+
"Mode": "ro",
|
|
25
|
+
"RW": false,
|
|
26
|
+
"Propagation": "rprivate"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
@@ -38,20 +38,41 @@ export function runDocker(args, { timeoutMs = MOUNT_CHECK_TIMEOUT_MS } = {}) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/** The container path the functions directory is mounted at, or null (from `docker inspect … .Mounts`). */
|
|
41
|
-
export function functionsMountDestination(mountsJson, hostFunctionsDir) {
|
|
41
|
+
export function functionsMountDestination(mountsJson, hostFunctionsDir, { dockerDesktop = false } = {}) {
|
|
42
42
|
let mounts;
|
|
43
43
|
try { mounts = JSON.parse(String(mountsJson ?? "").trim()); } catch { return null; }
|
|
44
44
|
if (!Array.isArray(mounts)) return null;
|
|
45
|
-
const mount = mounts.find((m) => m?.Type === "bind" &&
|
|
45
|
+
const mount = mounts.find((m) => m?.Type === "bind" && (
|
|
46
|
+
m?.Source === hostFunctionsDir || (
|
|
47
|
+
dockerDesktop === true && hostFunctionsDir.startsWith("/Users/") &&
|
|
48
|
+
m?.Source === `/host_mnt${hostFunctionsDir}`
|
|
49
|
+
)
|
|
50
|
+
));
|
|
46
51
|
return typeof mount?.Destination === "string" && mount.Destination ? mount.Destination : null;
|
|
47
52
|
}
|
|
48
53
|
|
|
54
|
+
// Docker Desktop exposes a macOS bind through its VM's /host_mnt alias.
|
|
55
|
+
// Authorize that alias only for the selected engine, never an arbitrary remote
|
|
56
|
+
// daemon or another VM. Explicit context selection wins over endpoint metadata,
|
|
57
|
+
// exactly as dockerSelectorArgs does. A failed probe keeps the gate closed.
|
|
58
|
+
async function isSelectedDockerDesktop(target, run, platform) {
|
|
59
|
+
if (platform !== "darwin") return false;
|
|
60
|
+
const context = typeof target?.context === "string" && target.context ? target.context : null;
|
|
61
|
+
let endpoint = context ? null : target?.resolved_endpoint ?? target?.endpoint;
|
|
62
|
+
if (!endpoint) {
|
|
63
|
+
const result = await run(["context", "inspect", ...(context ? [context] : []), "--format", "{{.Endpoints.docker.Host}}"]);
|
|
64
|
+
if (result.code !== 0 || result.timedOut) return false;
|
|
65
|
+
endpoint = String(result.stdout ?? "").trim();
|
|
66
|
+
}
|
|
67
|
+
return typeof endpoint === "string" && /^unix:\/\/\/Users\/[^/]+\/\.docker\/run\/docker\.sock$/.test(endpoint);
|
|
68
|
+
}
|
|
69
|
+
|
|
49
70
|
/**
|
|
50
71
|
* Check (and once repair) the functions mount of a re-adopted idle lease.
|
|
51
72
|
* `lease` is the re-adoption answer: `{ execution_mode, connection: { project_id, botbuddy_docker_target? } }`.
|
|
52
73
|
* Returns `{ ok: true, skipped? , restarted? }` or `{ ok: false, restarted, reason }`. Never throws.
|
|
53
74
|
*/
|
|
54
|
-
export async function checkReadoptedStackMounts(lease, stackDir, { run = runDocker, listHost = (dir) => readdirSync(dir), log = () => {} } = {}) {
|
|
75
|
+
export async function checkReadoptedStackMounts(lease, stackDir, { run = runDocker, listHost = (dir) => readdirSync(dir), log = () => {}, platform = process.platform } = {}) {
|
|
55
76
|
if (!CO_LOCATED_MODES.has(lease?.execution_mode)) return { ok: true, skipped: "remote" };
|
|
56
77
|
const projectId = lease?.connection?.project_id;
|
|
57
78
|
if (typeof projectId !== "string" || !PROJECT_ID_RE.test(projectId)) return { ok: true, skipped: "no_project_id" };
|
|
@@ -72,7 +93,13 @@ export async function checkReadoptedStackMounts(lease, stackDir, { run = runDock
|
|
|
72
93
|
if (!inspect.timedOut && /No such (container|object)/i.test(inspect.stderr ?? "")) return { ok: true, skipped: "no_edge_runtime" };
|
|
73
94
|
return { ok: false, restarted: false, reason: `could not inspect ${container} (exit ${inspect.code}${inspect.timedOut ? ", timed out" : ""})` };
|
|
74
95
|
}
|
|
75
|
-
|
|
96
|
+
let destination = functionsMountDestination(inspect.stdout, hostFunctions);
|
|
97
|
+
if (!destination) {
|
|
98
|
+
const desktopDestination = functionsMountDestination(inspect.stdout, hostFunctions, { dockerDesktop: true });
|
|
99
|
+
if (desktopDestination && await isSelectedDockerDesktop(lease.connection.botbuddy_docker_target, run, platform)) {
|
|
100
|
+
destination = desktopDestination;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
76
103
|
if (!destination) return { ok: false, restarted: false, reason: `${container} does not bind-mount ${hostFunctions}` };
|
|
77
104
|
|
|
78
105
|
const mountedEntries = async () => {
|