@botbuddy/cli 1.64.33 → 1.64.34

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.
@@ -1,7 +1,7 @@
1
1
  {
2
- "release_version": "1.64.33",
3
- "source_commit": "644a0f64f3b74a556a821c8a8997ea4e8910f282",
4
- "source_sha256": "1da5f11e7e2200acf29d273111d3550497ea0fa16ea3a570083273995c9d22de",
2
+ "release_version": "1.64.34",
3
+ "source_commit": "512513a6c1887db44c8a1743abb0f10ff844c1b0",
4
+ "source_sha256": "f6675485098c6bc62cab5119a356db6c12f4247e153f241584f0a349c09d9454",
5
5
  "target": "darwin-arm64",
6
- "sha256": "49b0b67a0e368a26b4f205881120a4dbc114e246e84413d77c108adbbd0ec8de"
6
+ "sha256": "5fba031a897c73f93e078e0aca1c4e8338926dc3501e512b3a9f0d706f39708c"
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
- "release_version": "1.64.33",
3
- "source_commit": "644a0f64f3b74a556a821c8a8997ea4e8910f282",
4
- "source_sha256": "1da5f11e7e2200acf29d273111d3550497ea0fa16ea3a570083273995c9d22de",
2
+ "release_version": "1.64.34",
3
+ "source_commit": "512513a6c1887db44c8a1743abb0f10ff844c1b0",
4
+ "source_sha256": "f6675485098c6bc62cab5119a356db6c12f4247e153f241584f0a349c09d9454",
5
5
  "target": "linux-x64",
6
- "sha256": "75b79c530c451304354c4bdffe23f373a7de6824f203cba9a7acb7e1bc0cfb2e"
6
+ "sha256": "7d722a654dd8da0794024fc6c0dba71034d631e1de87f434e5fbd8399f0d08af"
7
7
  }
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "schema_version": 1,
3
- "release_version": "1.64.33",
4
- "source_commit": "644a0f64f3b74a556a821c8a8997ea4e8910f282",
5
- "source_sha256": "1da5f11e7e2200acf29d273111d3550497ea0fa16ea3a570083273995c9d22de",
3
+ "release_version": "1.64.34",
4
+ "source_commit": "512513a6c1887db44c8a1743abb0f10ff844c1b0",
5
+ "source_sha256": "f6675485098c6bc62cab5119a356db6c12f4247e153f241584f0a349c09d9454",
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": "49b0b67a0e368a26b4f205881120a4dbc114e246e84413d77c108adbbd0ec8de",
11
+ "sha256": "5fba031a897c73f93e078e0aca1c4e8338926dc3501e512b3a9f0d706f39708c",
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": "75b79c530c451304354c4bdffe23f373a7de6824f203cba9a7acb7e1bc0cfb2e",
18
+ "sha256": "7d722a654dd8da0794024fc6c0dba71034d631e1de87f434e5fbd8399f0d08af",
19
19
  "mode": "0755"
20
20
  }
21
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbuddy/cli",
3
- "version": "1.64.33",
3
+ "version": "1.64.34",
4
4
  "description": "BotBuddy \u2014 Swarm coordination CLI for multi-agent workflows",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api.mjs CHANGED
@@ -415,6 +415,8 @@ export function containerHostRegisterEndpoint(serverUrl = SERVER_URL) {
415
415
  */
416
416
  export function registerContainerHost(body, options = {}) { return postContainerHostControl(body, options, "register", "container_host_register"); }
417
417
  export function daemonHandoverRequest(body, options = {}) { return postContainerHostControl(body, options, "handover", "daemon_handover"); }
418
+ // BOT-3127: the owner-only automatic-update describe read (same auth as handover).
419
+ export function daemonAutomaticUpdateRequest(body, options = {}) { return postContainerHostControl(body, options, "automatic-update", "daemon_handover"); }
418
420
  async function postContainerHostControl(body, {
419
421
  fetchImpl = fetch,
420
422
  auth: pinnedAuth = null,
@@ -1,4 +1,4 @@
1
- import { callToolJson, resolveCallAuth } from "../api.mjs";
1
+ import { callToolJson, daemonAutomaticUpdateRequest, resolveCallAuth } from "../api.mjs";
2
2
  import {
3
3
  assertSshHost,
4
4
  installedBinaryPath,
@@ -11,13 +11,20 @@ const fail = (code) => {
11
11
  };
12
12
  // One explicit administrator installation grants only the fixed native
13
13
  // coordinator/schedule. Persisted operator opt-in remains a separate drawer act.
14
+ // BOT-3127: user-scoped. The spec names no tenant; the host's owner asks the
15
+ // server for the host's inert rollout label and the root binding pins that.
14
16
  export async function installAutomaticDaemonUpdater(spec, {
15
17
  validateRelease = validateDaemonRelease,
16
18
  resolveAuth = resolveCallAuth,
17
19
  identity = callToolJson,
20
+ describe = daemonAutomaticUpdateRequest,
18
21
  stage = stageRemoteDaemonRelease,
19
22
  native = nativeHandoverCommand,
20
23
  } = {}) {
24
+ if (spec && typeof spec === "object" && Object.hasOwn(spec, "tenant")) {
25
+ // Automatic updates belong to the host's owner, not a project.
26
+ fail("daemon_automatic_install_tenant_not_used");
27
+ }
21
28
  if (
22
29
  !spec || typeof spec !== "object" || Array.isArray(spec) ||
23
30
  Object.keys(spec).some((key) =>
@@ -28,13 +35,11 @@ export async function installAutomaticDaemonUpdater(spec, {
28
35
  "serviceUser",
29
36
  "releaseRoot",
30
37
  "expectedHostKey",
31
- "tenant",
32
38
  ].includes(key)
33
39
  ) || !["linux", "darwin"].includes(spec.platform) ||
34
40
  typeof spec.serviceUser !== "string" || spec.serviceUser === "root" ||
35
41
  !/^[a-z_][a-z0-9_-]*$/i.test(spec.serviceUser) ||
36
- !/^bbh-[0-9a-f]{24}$/.test(spec.expectedHostKey) ||
37
- typeof spec.tenant !== "string" || !spec.tenant
42
+ !/^bbh-[0-9a-f]{24}$/.test(spec.expectedHostKey)
38
43
  ) fail("daemon_automatic_install_spec_invalid");
39
44
  assertSshHost(spec.sshHost);
40
45
  const release = await validateRelease({ releaseRoot: spec.releaseRoot }, {
@@ -48,14 +53,30 @@ export async function installAutomaticDaemonUpdater(spec, {
48
53
  if (resolved?.error || !resolved?.auth) {
49
54
  fail("daemon_automatic_install_auth_required");
50
55
  }
51
- const who = await identity("whoami", {}, {
52
- auth: resolved.auth,
53
- tenant: spec.tenant,
54
- });
56
+ const who = await identity("whoami", {}, { auth: resolved.auth });
55
57
  if (
56
58
  !who?.ok || who.isError || typeof who.data?.owner_email !== "string" ||
57
- !who.data.owner_email.includes("@") || who.data.tenant_id !== spec.tenant
59
+ !who.data.owner_email.includes("@")
58
60
  ) fail("daemon_automatic_install_owner_unavailable");
61
+ const described = await describe({
62
+ action: "describe",
63
+ host_key: spec.expectedHostKey,
64
+ }, { auth: resolved.auth });
65
+ const owner = described?.data?.owner_email, label = described?.data?.tenant_id;
66
+ if (
67
+ !described?.ok || described.data?.success !== true ||
68
+ described.data.host_key !== spec.expectedHostKey ||
69
+ typeof owner !== "string" || owner.toLowerCase() !== who.data.owner_email.toLowerCase() ||
70
+ typeof label !== "string" || !label
71
+ ) {
72
+ // A 4xx answer carries its code in `error` (e.g. daemon_host_scope).
73
+ const code = described?.data?.code ?? described?.error;
74
+ fail(
75
+ typeof code === "string" && /^(?:[A-Z_]{1,64}|[a-z_]{1,64})$/.test(code)
76
+ ? `daemon_automatic_install_owner_refused: ${code}`
77
+ : "daemon_automatic_install_owner_refused",
78
+ );
79
+ }
59
80
  const staged = await stage({
60
81
  platform: spec.platform,
61
82
  host: spec.sshHost,
@@ -70,8 +91,8 @@ export async function installAutomaticDaemonUpdater(spec, {
70
91
  mode: "automatic-install",
71
92
  input: {
72
93
  host_key: spec.expectedHostKey,
73
- owner_email: who.data.owner_email,
74
- tenant_id: who.data.tenant_id,
94
+ owner_email: owner,
95
+ tenant_id: label,
75
96
  },
76
97
  });
77
98
  if (result?.installed !== true || result.protocol !== 2) {