@brainbase-labs/cli 0.21.2 → 0.23.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.
Files changed (3) hide show
  1. package/README.md +23 -5
  2. package/dist/index.js +1233 -410
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -35128,12 +35128,12 @@ var require_dist2 = __commonJS((exports, module) => {
35128
35128
  throw new Error(`Unknown format "${name}"`);
35129
35129
  return f4;
35130
35130
  };
35131
- function addFormats(ajv, list, fs80, exportName) {
35131
+ function addFormats(ajv, list, fs81, exportName) {
35132
35132
  var _a;
35133
35133
  var _b;
35134
35134
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== undefined || (_b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`);
35135
35135
  for (const f4 of list)
35136
- ajv.addFormat(f4, fs80[f4]);
35136
+ ajv.addFormat(f4, fs81[f4]);
35137
35137
  }
35138
35138
  module.exports = exports = formatsPlugin;
35139
35139
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -35141,9 +35141,9 @@ var require_dist2 = __commonJS((exports, module) => {
35141
35141
  });
35142
35142
 
35143
35143
  // src/index.ts
35144
- var import_picocolors49 = __toESM(require_picocolors(), 1);
35144
+ var import_picocolors52 = __toESM(require_picocolors(), 1);
35145
35145
  import process14 from "node:process";
35146
- import fs82 from "node:fs";
35146
+ import fs83 from "node:fs";
35147
35147
 
35148
35148
  // src/cli/template.ts
35149
35149
  var import_picocolors12 = __toESM(require_picocolors(), 1);
@@ -36008,7 +36008,7 @@ function padStart(s, n) {
36008
36008
  // package.json
36009
36009
  var package_default = {
36010
36010
  name: "@brainbase-labs/cli",
36011
- version: "0.21.2",
36011
+ version: "0.23.0",
36012
36012
  description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
36013
36013
  type: "module",
36014
36014
  bin: {
@@ -53931,6 +53931,76 @@ function clearTokenIfMatches(prefix) {
53931
53931
  });
53932
53932
  }
53933
53933
 
53934
+ // src/core/credentials.ts
53935
+ var REGISTRY_COMMANDS = "template, skill, token";
53936
+ var CONTROL_PLANE_COMMANDS = "agent, orchestration, link, unlink, sync, status, team";
53937
+ var NOT_A_PAT = "(not a bbpat_… token)";
53938
+ function maskPat(token) {
53939
+ if (!isValidTokenFormat(token))
53940
+ return NOT_A_PAT;
53941
+ return token.slice(0, TOKEN_PREFIX_LEN);
53942
+ }
53943
+ function readEnvPat() {
53944
+ const value = process.env.BRAINBASE_TOKEN?.trim();
53945
+ if (!value)
53946
+ return null;
53947
+ return { prefix: maskPat(value), malformed: !isValidTokenFormat(value) };
53948
+ }
53949
+ function storedPatIgnoredHint(client) {
53950
+ const setEnv = `Set BRAINBASE_TOKEN to that token's value to authenticate with it here, ` + "or run `brainbase login` to refresh the session";
53951
+ switch (client) {
53952
+ case "control-plane":
53953
+ return `The PAT saved in ${TOKEN_FILE} is never used by control-plane ` + `commands (${CONTROL_PLANE_COMMANDS}). ${setEnv}.`;
53954
+ case "managed-task":
53955
+ return `The PAT saved in ${TOKEN_FILE} is not used while a login session is ` + `configured. ${setEnv} — or \`brainbase logout\`, which leaves the ` + "PAT as the only credential.";
53956
+ default: {
53957
+ const exhaustive = client;
53958
+ throw new Error(`unhandled credential client: ${String(exhaustive)}`);
53959
+ }
53960
+ }
53961
+ }
53962
+ function withStoredPatHint(reason, client) {
53963
+ if (!readToken())
53964
+ return reason;
53965
+ const trimmed = reason.trimEnd();
53966
+ const separator = /[.!?:]$/.test(trimmed) ? " " : ". ";
53967
+ return `${trimmed}${separator}${storedPatIgnoredHint(client)}`;
53968
+ }
53969
+ function withRejectedSessionHint(message, source, client) {
53970
+ if (source !== "session")
53971
+ return message;
53972
+ return withStoredPatHint(message, client);
53973
+ }
53974
+ function isRefreshable(session) {
53975
+ return Boolean(session.refresh_token && session.supabase_url && session.supabase_anon_key);
53976
+ }
53977
+ function describeCredentials() {
53978
+ const env3 = readEnvPat();
53979
+ const status = authStatus();
53980
+ const stored = readToken();
53981
+ const refreshable = Boolean(status.session && !status.ok && isRefreshable(status.session));
53982
+ const session = status.session ? {
53983
+ email: status.session.email ?? null,
53984
+ userId: status.session.user_id,
53985
+ expiresAt: status.session.expires_at ?? null,
53986
+ expired: !status.ok,
53987
+ refreshable
53988
+ } : null;
53989
+ let active = null;
53990
+ if (env3)
53991
+ active = "env_pat";
53992
+ else if (status.ok || refreshable)
53993
+ active = "session";
53994
+ else if (stored)
53995
+ active = "stored_pat";
53996
+ return {
53997
+ active,
53998
+ envPat: env3,
53999
+ session,
54000
+ storedPat: stored ? { name: stored.name ?? null, prefix: stored.prefix } : null
54001
+ };
54002
+ }
54003
+
53934
54004
  // src/core/api.ts
53935
54005
  var DEFAULT_CONTROL_PLANE_BASE = "https://api.brainbaselabs.com";
53936
54006
  var DEFAULT_PROXY_BASE = "https://api.v1.brainbaselabs.com";
@@ -54005,7 +54075,7 @@ function legacyScheduleError() {
54005
54075
  function legacyAgentConfigError() {
54006
54076
  return new ApiError("Declarative machine/model config requires the MAS control plane. Set BRAINBASE_CONTROL_PLANE_URL or unset the legacy BRAINBASE_API_URL override.", 400);
54007
54077
  }
54008
- async function resolveCredential() {
54078
+ async function resolveCredential(storedPatHint = "control-plane") {
54009
54079
  const envToken = process.env.BRAINBASE_TOKEN;
54010
54080
  if (envToken && envToken.trim()) {
54011
54081
  return {
@@ -54023,19 +54093,20 @@ async function resolveCredential() {
54023
54093
  };
54024
54094
  }
54025
54095
  const status = authStatus();
54026
- throw new ApiError(status.ok ? "CLI authentication changed while this command was starting; retry it" : status.reason ?? "not logged in", 401);
54096
+ const reason = status.reason ?? "not logged in";
54097
+ throw new ApiError(status.ok ? "CLI authentication changed while this command was starting; retry it" : storedPatHint ? withStoredPatHint(reason, storedPatHint) : reason, 401);
54027
54098
  }
54028
54099
  async function resolveMasCredential() {
54029
54100
  const configuredSession = readAuth();
54030
54101
  try {
54031
- return await resolveCredential();
54102
+ return await resolveCredential(null);
54032
54103
  } catch (error) {
54033
54104
  if (!(error instanceof ApiError && error.status === 401)) {
54034
54105
  throw error;
54035
54106
  }
54036
54107
  if (configuredSession || readAuth()) {
54037
54108
  if (readToken()) {
54038
- throw new ApiError(`${error.message}. A stored PAT is available but will not be used while a login session is configured. Run \`brainbase logout\` to use the stored PAT, or \`brainbase login\` to refresh the session.`, 401);
54109
+ throw new ApiError(`${error.message}. ${storedPatIgnoredHint("managed-task")}`, 401);
54039
54110
  }
54040
54111
  throw error;
54041
54112
  }
@@ -54134,7 +54205,8 @@ async function request(pathname, init = {}) {
54134
54205
  body = text2 ? JSON.parse(text2) : null;
54135
54206
  } catch {}
54136
54207
  if (!res.ok) {
54137
- throw new ApiError(apiErrorMessage(body, res.status), res.status, body);
54208
+ const message = apiErrorMessage(body, res.status);
54209
+ throw new ApiError(res.status === 401 ? withRejectedSessionHint(message, credential.source, "control-plane") : message, res.status, body);
54138
54210
  }
54139
54211
  return body;
54140
54212
  }
@@ -54277,7 +54349,7 @@ async function masRequest(pathname, init) {
54277
54349
  }
54278
54350
  if (!res.ok) {
54279
54351
  const message = masApiErrorMessage(body, res.status);
54280
- throw new ApiError(res.status >= 500 ? `${message} Task creation may still be processing; check your tasks before running this command again.` : message, res.status, body);
54352
+ throw new ApiError(res.status >= 500 ? `${message} Task creation may still be processing; check your tasks before running this command again.` : res.status === 401 ? withRejectedSessionHint(message, credential.source, "managed-task") : message, res.status, body);
54281
54353
  }
54282
54354
  return body;
54283
54355
  }
@@ -54292,6 +54364,19 @@ var masApi = {
54292
54364
  return parseMasTaskCreateResponse(body);
54293
54365
  }
54294
54366
  };
54367
+ function isUnroutedPath(body) {
54368
+ return !!body && typeof body === "object" && body.detail === "Not Found";
54369
+ }
54370
+ async function connectionsRequest(pathname, init) {
54371
+ try {
54372
+ return await request(pathname, init);
54373
+ } catch (err) {
54374
+ if (err instanceof ApiError && err.status === 404 && isUnroutedPath(err.body)) {
54375
+ throw new ApiError("This control plane does not support reading or changing connections yet. Update the server, or use the web app.", 404, err.body);
54376
+ }
54377
+ throw err;
54378
+ }
54379
+ }
54295
54380
  var api = {
54296
54381
  listOrgs() {
54297
54382
  return request("/orgs");
@@ -54379,6 +54464,21 @@ var api = {
54379
54464
  method: "DELETE"
54380
54465
  });
54381
54466
  },
54467
+ getAgentConnections(agentId) {
54468
+ return connectionsRequest(`/agents/${encodeURIComponent(agentId)}/connections`);
54469
+ },
54470
+ connectSlack(agentId, input) {
54471
+ return connectionsRequest(`/agents/${encodeURIComponent(agentId)}/connections/slack`, { method: "PUT", body: JSON.stringify(input) });
54472
+ },
54473
+ connectMeeting(agentId, input) {
54474
+ return connectionsRequest(`/agents/${encodeURIComponent(agentId)}/connections/meeting`, { method: "PUT", body: JSON.stringify(input) });
54475
+ },
54476
+ disconnectIntegration(agentId, integration) {
54477
+ return connectionsRequest(`/agents/${encodeURIComponent(agentId)}/connections/${encodeURIComponent(integration)}`, { method: "DELETE" });
54478
+ },
54479
+ listAgentMcpServers(agentId) {
54480
+ return connectionsRequest(`/agents/${encodeURIComponent(agentId)}/mcp-servers`);
54481
+ },
54382
54482
  listOrchestrations(orgId, teamId) {
54383
54483
  return request(`/orgs/${encodeURIComponent(orgId)}/teams/${encodeURIComponent(teamId)}/orchestrations`);
54384
54484
  },
@@ -61630,12 +61730,13 @@ async function runLogin(_cwd, args) {
61630
61730
  // src/ui/ink/IdentityCard.tsx
61631
61731
  var jsx_dev_runtime15 = __toESM(require_jsx_dev_runtime(), 1);
61632
61732
  function IdentityCard(props) {
61733
+ const hasRows = Boolean(props.rows?.length || props.controlPlaneUrl || props.expiresAt);
61633
61734
  return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Card, {
61634
61735
  title: props.title,
61635
61736
  tone: props.tone ?? "info",
61636
61737
  children: [
61637
61738
  props.email && /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
61638
- marginBottom: props.controlPlaneUrl || props.expiresAt ? 1 : 0,
61739
+ marginBottom: hasRows ? 1 : 0,
61639
61740
  children: /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
61640
61741
  bold: true,
61641
61742
  children: props.email
@@ -61644,6 +61745,20 @@ function IdentityCard(props) {
61644
61745
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
61645
61746
  flexDirection: "column",
61646
61747
  children: [
61748
+ props.rows?.map(([label, value]) => /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
61749
+ children: [
61750
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
61751
+ width: 15,
61752
+ children: /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
61753
+ dimColor: true,
61754
+ children: label
61755
+ }, undefined, false, undefined, this)
61756
+ }, undefined, false, undefined, this),
61757
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
61758
+ children: value
61759
+ }, undefined, false, undefined, this)
61760
+ ]
61761
+ }, label, true, undefined, this)),
61647
61762
  props.controlPlaneUrl && /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
61648
61763
  children: [
61649
61764
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
@@ -61711,22 +61826,117 @@ async function runLogout() {
61711
61826
  }
61712
61827
 
61713
61828
  // src/cli/whoami.ts
61714
- async function runWhoami() {
61715
- const { ok, session, reason } = authStatus();
61716
- if (!ok || !session) {
61717
- await showIdentityCard({
61718
- title: "NOT SIGNED IN",
61719
- tone: "warn",
61720
- message: `${reason ?? "not logged in"}. Run \`brainbase login\` to connect this device.`
61721
- });
61722
- process.exit(1);
61829
+ function usableForControlPlane(report) {
61830
+ switch (report.active) {
61831
+ case "env_pat":
61832
+ return !report.envPat?.malformed;
61833
+ case "session":
61834
+ return true;
61835
+ case "stored_pat":
61836
+ case null:
61837
+ return false;
61838
+ default: {
61839
+ const exhaustive = report.active;
61840
+ throw new Error(`unhandled credential: ${String(exhaustive)}`);
61841
+ }
61842
+ }
61843
+ }
61844
+ function exitCodeFor(report) {
61845
+ return usableForControlPlane(report) ? 0 : 1;
61846
+ }
61847
+ function reasonFor(report) {
61848
+ switch (report.active) {
61849
+ case "env_pat":
61850
+ return report.envPat?.malformed ? "BRAINBASE_TOKEN is set to something that is not a `bbpat_…` token, " + "and it outranks every other credential — so every request will fail " + "until it is corrected or unset. Mint one with `brainbase token create`." : null;
61851
+ case "session":
61852
+ return null;
61853
+ case "stored_pat":
61854
+ return `The stored PAT authenticates registry commands (${REGISTRY_COMMANDS}) only. ` + `Set BRAINBASE_TOKEN to its value for ${CONTROL_PLANE_COMMANDS}, ` + "or run `brainbase login`.";
61855
+ case null:
61856
+ return report.session?.expired ? "Session expired. Run `brainbase login` to connect this device." : "Not logged in. Run `brainbase login` to connect this device.";
61857
+ default: {
61858
+ const exhaustive = report.active;
61859
+ throw new Error(`unhandled credential: ${String(exhaustive)}`);
61860
+ }
61861
+ }
61862
+ }
61863
+ function toJson(report, reason) {
61864
+ const usingSession = report.active === "session";
61865
+ return {
61866
+ credential: report.active,
61867
+ authenticated: report.active !== null && !report.envPat?.malformed,
61868
+ control_plane: usableForControlPlane(report),
61869
+ email: usingSession ? report.session?.email ?? null : null,
61870
+ user_id: usingSession ? report.session?.userId ?? null : null,
61871
+ expires_at: usingSession ? report.session?.expiresAt ?? null : null,
61872
+ token_prefix: report.active === "env_pat" ? report.envPat?.prefix ?? null : report.active === "stored_pat" ? report.storedPat?.prefix ?? null : null,
61873
+ control_plane_url: controlPlaneBaseUrl(usingSession ? readAuth() : null),
61874
+ session: report.session ? {
61875
+ present: true,
61876
+ expired: report.session.expired,
61877
+ refreshable: report.session.refreshable
61878
+ } : { present: false, expired: false, refreshable: false },
61879
+ stored_pat: report.storedPat ? { present: true, name: report.storedPat.name } : { present: false, name: null },
61880
+ reason
61881
+ };
61882
+ }
61883
+ function displayPrefix(prefix) {
61884
+ return prefix === NOT_A_PAT ? prefix : `${prefix}…`;
61885
+ }
61886
+ function cardRows(report) {
61887
+ const rows = [];
61888
+ switch (report.active) {
61889
+ case "env_pat":
61890
+ rows.push(["credential", "BRAINBASE_TOKEN (env PAT)"]);
61891
+ if (report.envPat) {
61892
+ rows.push(["token", displayPrefix(report.envPat.prefix)]);
61893
+ }
61894
+ break;
61895
+ case "session":
61896
+ rows.push([
61897
+ "credential",
61898
+ report.session?.refreshable ? "login session (auth.json) — expired, renews on next use" : "login session (auth.json)"
61899
+ ]);
61900
+ break;
61901
+ case "stored_pat":
61902
+ rows.push(["credential", "stored PAT (token.json)"]);
61903
+ rows.push([
61904
+ "token",
61905
+ report.storedPat?.name ? `${displayPrefix(report.storedPat.prefix)} (${report.storedPat.name})` : displayPrefix(report.storedPat?.prefix ?? "?")
61906
+ ]);
61907
+ break;
61908
+ case null:
61909
+ break;
61910
+ default: {
61911
+ const exhaustive = report.active;
61912
+ throw new Error(`unhandled credential: ${String(exhaustive)}`);
61913
+ }
61723
61914
  }
61915
+ if (report.session && report.active !== "session") {
61916
+ rows.push([
61917
+ "session",
61918
+ `${report.session.email ?? report.session.userId} (${report.session.expired ? "expired" : "not used — env PAT wins"})`
61919
+ ]);
61920
+ }
61921
+ return rows;
61922
+ }
61923
+ async function runWhoami(args = {}) {
61924
+ const report = describeCredentials();
61925
+ const reason = reasonFor(report);
61926
+ process.exitCode = exitCodeFor(report);
61927
+ if (args.json) {
61928
+ console.log(JSON.stringify(toJson(report, reason), null, 2));
61929
+ return;
61930
+ }
61931
+ const signedIn = report.active !== null;
61724
61932
  await showIdentityCard({
61725
- title: "WHOAMI",
61726
- tone: "ok",
61727
- email: session.email ?? session.user_id,
61728
- controlPlaneUrl: controlPlaneBaseUrl(session),
61729
- expiresAt: session.expires_at
61933
+ title: signedIn ? "WHOAMI" : "NOT SIGNED IN",
61934
+ tone: process.exitCode === 0 ? "ok" : "warn",
61935
+ email: report.active === "session" ? report.session?.email ?? report.session?.userId ?? null : null,
61936
+ controlPlaneUrl: signedIn ? controlPlaneBaseUrl(report.active === "session" ? readAuth() : null) : null,
61937
+ expiresAt: report.active === "session" ? report.session?.expiresAt : null,
61938
+ rows: cardRows(report),
61939
+ message: reason ?? undefined
61730
61940
  });
61731
61941
  }
61732
61942
 
@@ -63308,7 +63518,7 @@ function runHarnessInstall(harnessId, components, opts, agentName) {
63308
63518
  }
63309
63519
 
63310
63520
  // src/cli/agent.ts
63311
- var import_picocolors34 = __toESM(require_picocolors(), 1);
63521
+ var import_picocolors37 = __toESM(require_picocolors(), 1);
63312
63522
 
63313
63523
  // src/cli/agent-pull.ts
63314
63524
  import { spawn as spawn2 } from "node:child_process";
@@ -66421,6 +66631,396 @@ function formatAgentList(agents, labels) {
66421
66631
  `);
66422
66632
  }
66423
66633
 
66634
+ // src/cli/agent-connections.ts
66635
+ var import_picocolors35 = __toESM(require_picocolors(), 1);
66636
+
66637
+ // src/core/integrations.ts
66638
+ var IMPLEMENTED_INTEGRATIONS = ["slack", "meeting"];
66639
+ function isImplemented(name) {
66640
+ return IMPLEMENTED_INTEGRATIONS.includes(name);
66641
+ }
66642
+ function actionability(state) {
66643
+ if (!state.manageable_from_cli) {
66644
+ return { kind: "web-only", ...state.unmanageable_reason ? { reason: state.unmanageable_reason } : {} };
66645
+ }
66646
+ return isImplemented(state.name) ? { kind: "connectable" } : { kind: "needs-newer-cli" };
66647
+ }
66648
+ var GENERIC_WEB_ONLY_REASON = "This integration cannot be connected from the terminal. Use the web app.";
66649
+ var UPGRADE_HINT = "This control plane supports connecting it, but this version of the CLI does not. Upgrade the CLI.";
66650
+ function explain(state) {
66651
+ const action = actionability(state);
66652
+ switch (action.kind) {
66653
+ case "connectable":
66654
+ return `brainbase agent connect ${state.name}`;
66655
+ case "needs-newer-cli":
66656
+ return UPGRADE_HINT;
66657
+ case "web-only":
66658
+ return action.reason ?? GENERIC_WEB_ONLY_REASON;
66659
+ default: {
66660
+ const exhaustive = action;
66661
+ return exhaustive;
66662
+ }
66663
+ }
66664
+ }
66665
+
66666
+ // src/cli/agent-connect.ts
66667
+ var import_picocolors34 = __toESM(require_picocolors(), 1);
66668
+
66669
+ // src/core/secret-input.ts
66670
+ import fs74 from "node:fs";
66671
+ function clean(value) {
66672
+ if (typeof value !== "string")
66673
+ return;
66674
+ const trimmed = value.trim();
66675
+ return trimmed ? trimmed : undefined;
66676
+ }
66677
+ var STDIN_IDLE_TIMEOUT_MS = 5000;
66678
+ var STDIN_TIMEOUT_MIN_MS = 100;
66679
+ var STDIN_TIMEOUT_MAX_MS = 600000;
66680
+ function stdinTimeoutMs(env3) {
66681
+ const raw = Number(env3.BRAINBASE_STDIN_TIMEOUT_MS);
66682
+ if (!Number.isFinite(raw) || raw <= 0)
66683
+ return STDIN_IDLE_TIMEOUT_MS;
66684
+ return Math.min(Math.max(raw, STDIN_TIMEOUT_MIN_MS), STDIN_TIMEOUT_MAX_MS);
66685
+ }
66686
+
66687
+ class StdinTimeoutError extends Error {
66688
+ constructor(idleTimeoutMs, bytesRead) {
66689
+ super(`stdin went quiet for ${idleTimeoutMs}ms after ${bytesRead} byte(s), before it was closed. ` + "Refusing to use a partial value. If the source is slow, raise " + "BRAINBASE_STDIN_TIMEOUT_MS; if it will not close its end of the pipe, " + "pass the value with a flag or an environment variable instead.");
66690
+ this.name = "StdinTimeoutError";
66691
+ }
66692
+ }
66693
+ function readPipeUntilEof(stream, idleTimeoutMs) {
66694
+ return new Promise((resolve, reject2) => {
66695
+ const chunks = [];
66696
+ let received = 0;
66697
+ let timer;
66698
+ const stopTimer = () => {
66699
+ if (timer !== undefined) {
66700
+ clearTimeout(timer);
66701
+ timer = undefined;
66702
+ }
66703
+ };
66704
+ const restartTimer = () => {
66705
+ stopTimer();
66706
+ timer = setTimeout(onIdle, idleTimeoutMs);
66707
+ };
66708
+ const detach = () => {
66709
+ stopTimer();
66710
+ stream.removeListener("data", onData);
66711
+ stream.removeListener("end", onEnd);
66712
+ stream.removeListener("error", onError);
66713
+ stream.pause();
66714
+ stream.unref?.();
66715
+ };
66716
+ function onIdle() {
66717
+ if (received > 0) {
66718
+ detach();
66719
+ reject2(new StdinTimeoutError(idleTimeoutMs, received));
66720
+ return;
66721
+ }
66722
+ detach();
66723
+ resolve("");
66724
+ }
66725
+ function onData(chunk2) {
66726
+ const buf = Buffer.from(chunk2);
66727
+ received += buf.length;
66728
+ chunks.push(buf);
66729
+ restartTimer();
66730
+ }
66731
+ function onEnd() {
66732
+ detach();
66733
+ resolve(Buffer.concat(chunks).toString("utf8"));
66734
+ }
66735
+ function onError(err) {
66736
+ detach();
66737
+ reject2(err);
66738
+ }
66739
+ stream.on("data", onData);
66740
+ stream.on("end", onEnd);
66741
+ stream.on("error", onError);
66742
+ restartTimer();
66743
+ });
66744
+ }
66745
+ async function defaultReadStdin(env3 = process.env) {
66746
+ if (process.stdin.isTTY)
66747
+ return null;
66748
+ let isRegularFile = false;
66749
+ try {
66750
+ isRegularFile = fs74.fstatSync(0).isFile();
66751
+ } catch {
66752
+ return "";
66753
+ }
66754
+ if (isRegularFile) {
66755
+ try {
66756
+ return fs74.readFileSync(0, "utf8");
66757
+ } catch {
66758
+ return "";
66759
+ }
66760
+ }
66761
+ try {
66762
+ return await readPipeUntilEof(process.stdin, stdinTimeoutMs(env3));
66763
+ } catch (err) {
66764
+ if (err instanceof StdinTimeoutError)
66765
+ throw err;
66766
+ return "";
66767
+ }
66768
+ }
66769
+ async function defaultPrompt(field) {
66770
+ const answer = await re({
66771
+ message: field.label,
66772
+ validate: (v3) => v3 && v3.trim() ? undefined : "Required"
66773
+ });
66774
+ return String(ensureNotCancelled(answer)).trim();
66775
+ }
66776
+ function parseStdinSecrets(raw, missing) {
66777
+ const body = raw.trim();
66778
+ if (!body)
66779
+ return {};
66780
+ if (body.startsWith("{")) {
66781
+ let source;
66782
+ try {
66783
+ source = JSON.parse(body);
66784
+ } catch {
66785
+ throw new Error('stdin looked like JSON but could not be parsed. Pass an object such as {"bot_token":"…","signing_secret":"…"}.');
66786
+ }
66787
+ const out = {};
66788
+ for (const field of missing) {
66789
+ const value = clean(source[field.key]);
66790
+ if (value)
66791
+ out[field.key] = value;
66792
+ }
66793
+ return out;
66794
+ }
66795
+ if (missing.length === 1) {
66796
+ return { [missing[0].key]: body };
66797
+ }
66798
+ throw new Error(`stdin supplies one value, but ${missing.length} are still missing (${missing.map((f4) => f4.key).join(", ")}). Pipe a JSON object instead, or pass the rest as flags.`);
66799
+ }
66800
+ async function resolveSecrets(fields, deps = {}) {
66801
+ const env3 = deps.env ?? process.env;
66802
+ const readStdin = deps.readStdin ?? (() => defaultReadStdin(env3));
66803
+ const prompt = deps.prompt ?? defaultPrompt;
66804
+ const interactive = deps.interactive ?? isInteractive;
66805
+ const resolved = {};
66806
+ for (const field of fields) {
66807
+ const value = clean(field.value) ?? clean(env3[field.envVar]);
66808
+ if (value)
66809
+ resolved[field.key] = value;
66810
+ }
66811
+ let missing = fields.filter((f4) => !resolved[f4.key]);
66812
+ if (missing.length > 0) {
66813
+ const raw = await readStdin();
66814
+ if (raw !== null) {
66815
+ Object.assign(resolved, parseStdinSecrets(raw, missing));
66816
+ missing = fields.filter((f4) => !resolved[f4.key]);
66817
+ }
66818
+ }
66819
+ for (const field of missing) {
66820
+ if (!interactive()) {
66821
+ throw new NonInteractiveError(`${field.label} is required. Pass ${field.flag}, set ${field.envVar}, or pipe it on stdin.`);
66822
+ }
66823
+ resolved[field.key] = await prompt(field);
66824
+ }
66825
+ return resolved;
66826
+ }
66827
+
66828
+ // src/cli/agent-connect.ts
66829
+ async function runAgentConnect(cwd2, target, args, deps = {}) {
66830
+ const json = Boolean(args.json);
66831
+ try {
66832
+ report(await connect(cwd2, target, args, deps, json), json);
66833
+ } catch (err) {
66834
+ if (!json)
66835
+ throw err;
66836
+ reportFailure(err);
66837
+ }
66838
+ }
66839
+ async function connect(cwd2, target, args, deps, json) {
66840
+ if (!target) {
66841
+ throw new Error(`Which integration? Try: ${IMPLEMENTED_INTEGRATIONS.join(", ")}.`);
66842
+ }
66843
+ if (!json)
66844
+ banner(`agent connect ${target}`);
66845
+ const link2 = readLink(cwd2);
66846
+ if (!link2) {
66847
+ throw new Error("This folder is not linked to any agent. Run `brainbase link` first.");
66848
+ }
66849
+ await assertConnectable(link2.agent_id, target, deps);
66850
+ return target === "slack" ? connectSlack(link2.agent_id, args, deps, json) : connectMeeting(link2.agent_id, args, deps, json);
66851
+ }
66852
+ async function assertConnectable(agentId, target, deps) {
66853
+ const fetchConnections = deps.fetchConnections ?? ((id) => api.getAgentConnections(id));
66854
+ const { integrations } = await fetchConnections(agentId);
66855
+ const state = integrations.find((i) => i.name === target);
66856
+ if (!state) {
66857
+ const known = integrations.map((i) => i.name).join(", ");
66858
+ throw new Error(`Unknown integration ${JSON.stringify(target)}. This agent has: ${known}.`);
66859
+ }
66860
+ const action = actionability(state);
66861
+ if (action.kind === "connectable")
66862
+ return;
66863
+ throw new Error(explain(state));
66864
+ }
66865
+ async function connectSlack(agentId, args, deps, json) {
66866
+ const secrets = await resolveSecrets([
66867
+ {
66868
+ key: "bot_token",
66869
+ flag: "--bot-token",
66870
+ envVar: "BRAINBASE_SLACK_BOT_TOKEN",
66871
+ label: "Slack bot token (xoxb-…)",
66872
+ value: args.botToken
66873
+ },
66874
+ {
66875
+ key: "signing_secret",
66876
+ flag: "--signing-secret",
66877
+ envVar: "BRAINBASE_SLACK_SIGNING_SECRET",
66878
+ label: "Slack signing secret",
66879
+ value: args.signingSecret
66880
+ }
66881
+ ], { ...deps.secrets, ...json ? { interactive: () => false } : {} });
66882
+ return api.connectSlack(agentId, {
66883
+ bot_token: secrets.bot_token,
66884
+ signing_secret: secrets.signing_secret,
66885
+ ...args.appId ? { app_id: args.appId } : {},
66886
+ ...args.appName ? { app_name: args.appName } : {}
66887
+ });
66888
+ }
66889
+ async function connectMeeting(agentId, args, deps, json) {
66890
+ const ask = deps.askBotName ?? (() => text({
66891
+ message: "Name for the meeting bot",
66892
+ placeholder: "Notetaker",
66893
+ flagHint: "Pass --bot-name <name>."
66894
+ }));
66895
+ let botName = args.botName?.trim();
66896
+ if (!botName) {
66897
+ if (json) {
66898
+ throw new Error("A meeting bot name is required. Pass --bot-name <name>.");
66899
+ }
66900
+ botName = (await ask()).trim();
66901
+ }
66902
+ if (!botName)
66903
+ throw new Error("A meeting bot name is required. Pass --bot-name <name>.");
66904
+ return api.connectMeeting(agentId, {
66905
+ bot_name: botName,
66906
+ ...args.botImageUrl ? { bot_image_url: args.botImageUrl } : {}
66907
+ });
66908
+ }
66909
+ function reportFailure(err) {
66910
+ console.log(JSON.stringify({ error: err.message }, null, 2));
66911
+ process.exitCode = 1;
66912
+ }
66913
+ function report(result2, json) {
66914
+ if (json) {
66915
+ console.log(JSON.stringify(result2, null, 2));
66916
+ return;
66917
+ }
66918
+ const detail = result2.detail ? ` ${import_picocolors34.default.dim(`(${result2.detail})`)}` : "";
66919
+ f2.success(`${result2.name} connected${detail}`);
66920
+ f2.info(`Run ${import_picocolors34.default.cyan("brainbase agent pull")} to pick up the built-in ${result2.name} MCP server.`);
66921
+ }
66922
+
66923
+ // src/cli/agent-connections.ts
66924
+ async function runAgentConnections(cwd2, args) {
66925
+ const json = Boolean(args.json);
66926
+ if (!json)
66927
+ banner("agent connections — what this agent is wired to");
66928
+ const link2 = readLink(cwd2);
66929
+ if (!link2) {
66930
+ if (json) {
66931
+ console.log(JSON.stringify({ linked: false, integrations: [] }, null, 2));
66932
+ process.exitCode = 1;
66933
+ return;
66934
+ }
66935
+ f2.warn("This folder is not linked to any agent.");
66936
+ f2.info(`Run ${import_picocolors35.default.cyan("brainbase link")} first.`);
66937
+ process.exitCode = 1;
66938
+ return;
66939
+ }
66940
+ let connections;
66941
+ try {
66942
+ connections = await api.getAgentConnections(link2.agent_id);
66943
+ } catch (err) {
66944
+ if (!json)
66945
+ throw err;
66946
+ reportFailure(err);
66947
+ return;
66948
+ }
66949
+ if (json) {
66950
+ console.log(JSON.stringify({ linked: true, ...connections }, null, 2));
66951
+ return;
66952
+ }
66953
+ console.log(formatConnections(connections));
66954
+ }
66955
+ function formatConnections(connections) {
66956
+ const lines = [""];
66957
+ for (const integration of connections.integrations) {
66958
+ lines.push(` ${statusMark(integration)} ${import_picocolors35.default.bold(integration.name)}${describe(integration)}`);
66959
+ const hint = hintFor(integration);
66960
+ if (hint)
66961
+ lines.push(` ${import_picocolors35.default.dim(hint)}`);
66962
+ }
66963
+ lines.push("");
66964
+ return lines.join(`
66965
+ `);
66966
+ }
66967
+ function statusMark(integration) {
66968
+ return integration.connected ? import_picocolors35.default.green("✓") : import_picocolors35.default.dim("·");
66969
+ }
66970
+ function describe(integration) {
66971
+ if (!integration.connected)
66972
+ return ` ${import_picocolors35.default.dim("not connected")}`;
66973
+ return integration.detail ? ` ${import_picocolors35.default.dim(integration.detail)}` : ` ${import_picocolors35.default.dim("connected")}`;
66974
+ }
66975
+ function hintFor(integration) {
66976
+ const action = actionability(integration);
66977
+ if (integration.connected) {
66978
+ return action.kind === "connectable" ? `brainbase agent disconnect ${integration.name}` : undefined;
66979
+ }
66980
+ return explain(integration);
66981
+ }
66982
+
66983
+ // src/cli/agent-disconnect.ts
66984
+ var import_picocolors36 = __toESM(require_picocolors(), 1);
66985
+ async function runAgentDisconnect(cwd2, target, args) {
66986
+ const json = Boolean(args.json);
66987
+ try {
66988
+ await disconnect(cwd2, target, args, json);
66989
+ } catch (err) {
66990
+ if (!json)
66991
+ throw err;
66992
+ reportFailure(err);
66993
+ }
66994
+ }
66995
+ async function disconnect(cwd2, target, args, json) {
66996
+ if (!target) {
66997
+ throw new Error(`Which integration? Try: ${IMPLEMENTED_INTEGRATIONS.join(", ")}.`);
66998
+ }
66999
+ if (!isImplemented(target)) {
67000
+ throw new Error(`Cannot disconnect ${JSON.stringify(target)} from the CLI. Try: ${IMPLEMENTED_INTEGRATIONS.join(", ")}.`);
67001
+ }
67002
+ if (!json)
67003
+ banner(`agent disconnect ${target}`);
67004
+ const link2 = readLink(cwd2);
67005
+ if (!link2) {
67006
+ throw new Error("This folder is not linked to any agent. Run `brainbase link` first.");
67007
+ }
67008
+ if (!json && !autoProceed(args.yes)) {
67009
+ const ok = ensureNotCancelled(await se({ message: `Disconnect ${target} from ${link2.name}?` }));
67010
+ if (!ok) {
67011
+ f2.info("Nothing changed.");
67012
+ return;
67013
+ }
67014
+ }
67015
+ const result2 = await api.disconnectIntegration(link2.agent_id, target);
67016
+ if (json) {
67017
+ console.log(JSON.stringify(result2, null, 2));
67018
+ return;
67019
+ }
67020
+ f2.success(`${target} disconnected`);
67021
+ f2.info(`Run ${import_picocolors36.default.cyan("brainbase agent pull")} to drop the built-in ${target} MCP server locally.`);
67022
+ }
67023
+
66424
67024
  // src/cli/agent.ts
66425
67025
  async function runAgent(cwd2, sub, args, opts) {
66426
67026
  if (args.some((arg) => arg === "--help" || arg === "-h")) {
@@ -66471,6 +67071,23 @@ async function runAgent(cwd2, sub, args, opts) {
66471
67071
  case "status":
66472
67072
  await runAgentStatus(cwd2, { json: opts.json });
66473
67073
  return;
67074
+ case "connections":
67075
+ await runAgentConnections(cwd2, { json: opts.json });
67076
+ return;
67077
+ case "connect":
67078
+ await runAgentConnect(cwd2, args[0], {
67079
+ botToken: opts.botToken,
67080
+ signingSecret: opts.signingSecret,
67081
+ appId: opts.appId,
67082
+ appName: opts.appName,
67083
+ botName: opts.botName,
67084
+ botImageUrl: opts.botImageUrl,
67085
+ json: opts.json
67086
+ });
67087
+ return;
67088
+ case "disconnect":
67089
+ await runAgentDisconnect(cwd2, args[0], { yes: opts.yes, json: opts.json });
67090
+ return;
66474
67091
  case "env":
66475
67092
  await runAgentEnv(cwd2, { shell: opts.shell });
66476
67093
  return;
@@ -66490,25 +67107,31 @@ async function runAgent(cwd2, sub, args, opts) {
66490
67107
  function printHelp() {
66491
67108
  const out = [];
66492
67109
  out.push("");
66493
- out.push(` ${import_picocolors34.default.bold("brainbase agent")} ${import_picocolors34.default.dim("<sub> [options]")}`);
67110
+ out.push(` ${import_picocolors37.default.bold("brainbase agent")} ${import_picocolors37.default.dim("<sub> [options]")}`);
67111
+ out.push("");
67112
+ out.push(` ${import_picocolors37.default.cyan("list")} ${import_picocolors37.default.dim("show the agents in a team, with the ids `brainbase link` takes (--json for scripts)")}`);
67113
+ out.push(` ${import_picocolors37.default.cyan("create")} ${import_picocolors37.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
67114
+ out.push(` ${import_picocolors37.default.cyan("pull")} ${import_picocolors37.default.dim("[<id>]")} ${import_picocolors37.default.dim("apply cloud changes into this folder — pass <id> to switch (--force to override); --run-entrypoint to also execute the agent entrypoint")}`);
67115
+ out.push(` ${import_picocolors37.default.cyan("push")} ${import_picocolors37.default.dim("send local changes to the cloud — instructions, playbooks, skills, MCPs, entrypoint (--force to overwrite cloud-side conflicts with local)")}`);
67116
+ out.push(` ${import_picocolors37.default.cyan("unpack")} ${import_picocolors37.default.dim("install the claimed agent into a harness layout (--harness to override)")}`);
67117
+ out.push(` ${import_picocolors37.default.cyan("status")} ${import_picocolors37.default.dim("show what would push, what would pull, and which manifest blocks are ignored (--json for scripts)")}`);
67118
+ out.push(` ${import_picocolors37.default.cyan("connections")} ${import_picocolors37.default.dim("show which integrations this agent is wired to (--json for scripts)")}`);
67119
+ out.push(` ${import_picocolors37.default.cyan("connect")} ${import_picocolors37.default.dim("<name>")} ${import_picocolors37.default.dim("connect slack or meeting — credentials come from flags, env, or stdin")}`);
67120
+ out.push(` ${import_picocolors37.default.cyan("disconnect")} ${import_picocolors37.default.dim("<name>")} ${import_picocolors37.default.dim("revoke a slack or meeting install")}`);
67121
+ out.push(` ${import_picocolors37.default.cyan("env")} ${import_picocolors37.default.dim('print export statements — use with `eval "$(brainbase agent env)"`')}`);
66494
67122
  out.push("");
66495
- out.push(` ${import_picocolors34.default.cyan("list")} ${import_picocolors34.default.dim("show the agents in a team, with the ids `brainbase link` takes (--json for scripts)")}`);
66496
- out.push(` ${import_picocolors34.default.cyan("create")} ${import_picocolors34.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
66497
- out.push(` ${import_picocolors34.default.cyan("pull")} ${import_picocolors34.default.dim("[<id>]")} ${import_picocolors34.default.dim("apply cloud changes into this folder — pass <id> to switch (--force to override); --run-entrypoint to also execute the agent entrypoint")}`);
66498
- out.push(` ${import_picocolors34.default.cyan("push")} ${import_picocolors34.default.dim("send local changes to the cloud — instructions, playbooks, skills, MCPs, entrypoint (--force to overwrite cloud-side conflicts with local)")}`);
66499
- out.push(` ${import_picocolors34.default.cyan("unpack")} ${import_picocolors34.default.dim("install the claimed agent into a harness layout (--harness to override)")}`);
66500
- out.push(` ${import_picocolors34.default.cyan("status")} ${import_picocolors34.default.dim("show what would push, what would pull, and which manifest blocks are ignored (--json for scripts)")}`);
66501
- out.push(` ${import_picocolors34.default.cyan("env")} ${import_picocolors34.default.dim('print export statements — use with `eval "$(brainbase agent env)"`')}`);
67123
+ out.push(` ${import_picocolors37.default.dim("Slack credentials:")} ${import_picocolors37.default.dim("--bot-token / BRAINBASE_SLACK_BOT_TOKEN, --signing-secret / BRAINBASE_SLACK_SIGNING_SECRET,")}`);
67124
+ out.push(` ${import_picocolors37.default.dim('or pipe {"bot_token":"…","signing_secret":"…"} on stdin to keep them out of argv.')}`);
66502
67125
  out.push("");
66503
67126
  console.log(out.join(`
66504
67127
  `));
66505
67128
  }
66506
67129
 
66507
67130
  // src/cli/team.ts
66508
- var import_picocolors36 = __toESM(require_picocolors(), 1);
67131
+ var import_picocolors39 = __toESM(require_picocolors(), 1);
66509
67132
 
66510
67133
  // src/cli/team-list.ts
66511
- var import_picocolors35 = __toESM(require_picocolors(), 1);
67134
+ var import_picocolors38 = __toESM(require_picocolors(), 1);
66512
67135
  async function runTeamList(args) {
66513
67136
  if (!args.json)
66514
67137
  banner("team list — teams you can put agents in");
@@ -66528,25 +67151,25 @@ async function runTeamList(args) {
66528
67151
  function formatTeamList(grouped) {
66529
67152
  const lines = [""];
66530
67153
  if (grouped.length === 0) {
66531
- lines.push(` ${import_picocolors35.default.dim("You are not a member of any organization.")}`, "");
67154
+ lines.push(` ${import_picocolors38.default.dim("You are not a member of any organization.")}`, "");
66532
67155
  return lines.join(`
66533
67156
  `);
66534
67157
  }
66535
67158
  const nameWidth = Math.max(...grouped.flatMap(({ teams }) => teams.map((t) => t.name.length)), 0);
66536
67159
  for (const { org, teams, error } of grouped) {
66537
- const slug = org.slug ? ` ${import_picocolors35.default.dim(org.slug)}` : "";
66538
- lines.push(` ${import_picocolors35.default.bold(org.name)}${slug}`);
67160
+ const slug = org.slug ? ` ${import_picocolors38.default.dim(org.slug)}` : "";
67161
+ lines.push(` ${import_picocolors38.default.bold(org.name)}${slug}`);
66539
67162
  if (error) {
66540
- lines.push(` ${import_picocolors35.default.red(`could not load teams: ${error}`)}`);
67163
+ lines.push(` ${import_picocolors38.default.red(`could not load teams: ${error}`)}`);
66541
67164
  } else if (teams.length === 0) {
66542
- lines.push(` ${import_picocolors35.default.dim("no teams yet — create one in the web app")}`);
67165
+ lines.push(` ${import_picocolors38.default.dim("no teams yet — create one in the web app")}`);
66543
67166
  }
66544
67167
  for (const team of teams) {
66545
- lines.push(` ${team.name.padEnd(nameWidth)} ${import_picocolors35.default.dim(team.id)}`);
67168
+ lines.push(` ${team.name.padEnd(nameWidth)} ${import_picocolors38.default.dim(team.id)}`);
66546
67169
  }
66547
67170
  lines.push("");
66548
67171
  }
66549
- lines.push(` ${import_picocolors35.default.dim("list a team’s agents with")} ${import_picocolors35.default.cyan("brainbase agent list --team <id>")}`, "");
67172
+ lines.push(` ${import_picocolors38.default.dim("list a team’s agents with")} ${import_picocolors38.default.cyan("brainbase agent list --team <id>")}`, "");
66550
67173
  return lines.join(`
66551
67174
  `);
66552
67175
  }
@@ -66577,28 +67200,28 @@ async function runTeam(sub, args, opts) {
66577
67200
  function printHelp2() {
66578
67201
  const out = [];
66579
67202
  out.push("");
66580
- out.push(` ${import_picocolors36.default.bold("brainbase team")} ${import_picocolors36.default.dim("<sub> [options]")}`);
67203
+ out.push(` ${import_picocolors39.default.bold("brainbase team")} ${import_picocolors39.default.dim("<sub> [options]")}`);
66581
67204
  out.push("");
66582
- out.push(` ${import_picocolors36.default.cyan("list")} ${import_picocolors36.default.dim("show the teams you can create agents in, grouped by organization")}`);
67205
+ out.push(` ${import_picocolors39.default.cyan("list")} ${import_picocolors39.default.dim("show the teams you can create agents in, grouped by organization")}`);
66583
67206
  out.push("");
66584
- out.push(` ${import_picocolors36.default.dim("--org <id-or-slug>")} ${import_picocolors36.default.dim("limit to one organization")}`);
66585
- out.push(` ${import_picocolors36.default.dim("--json")} ${import_picocolors36.default.dim("machine-readable output")}`);
67207
+ out.push(` ${import_picocolors39.default.dim("--org <id-or-slug>")} ${import_picocolors39.default.dim("limit to one organization")}`);
67208
+ out.push(` ${import_picocolors39.default.dim("--json")} ${import_picocolors39.default.dim("machine-readable output")}`);
66586
67209
  out.push("");
66587
67210
  console.log(out.join(`
66588
67211
  `));
66589
67212
  }
66590
67213
 
66591
67214
  // src/cli/orchestration.ts
66592
- var import_picocolors43 = __toESM(require_picocolors(), 1);
67215
+ var import_picocolors46 = __toESM(require_picocolors(), 1);
66593
67216
 
66594
67217
  // src/cli/orchestration-pull.ts
66595
67218
  import path86 from "node:path";
66596
- import fs77 from "node:fs";
66597
- var import_picocolors37 = __toESM(require_picocolors(), 1);
67219
+ import fs78 from "node:fs";
67220
+ var import_picocolors40 = __toESM(require_picocolors(), 1);
66598
67221
 
66599
67222
  // src/core/orchestration-manifest.ts
66600
67223
  import path83 from "node:path";
66601
- import fs74 from "node:fs";
67224
+ import fs75 from "node:fs";
66602
67225
  var import_yaml4 = __toESM(require_dist(), 1);
66603
67226
  var ORCH_MANIFEST_FILE = "brainbase-orchestration.yaml";
66604
67227
  var ORCH_MEMBERS_DIR = "agents";
@@ -66654,13 +67277,13 @@ function orchManifestPath(cwd2) {
66654
67277
  return path83.join(cwd2, ORCH_MANIFEST_FILE);
66655
67278
  }
66656
67279
  function hasOrchManifest(cwd2) {
66657
- return fs74.existsSync(orchManifestPath(cwd2));
67280
+ return fs75.existsSync(orchManifestPath(cwd2));
66658
67281
  }
66659
67282
  function readOrchManifest(cwd2) {
66660
67283
  const p2 = orchManifestPath(cwd2);
66661
- if (!fs74.existsSync(p2))
67284
+ if (!fs75.existsSync(p2))
66662
67285
  return null;
66663
- const raw = fs74.readFileSync(p2, "utf8");
67286
+ const raw = fs75.readFileSync(p2, "utf8");
66664
67287
  let parsed;
66665
67288
  try {
66666
67289
  parsed = import_yaml4.default.parse(raw);
@@ -66681,7 +67304,7 @@ function writeOrchManifest(cwd2, manifest) {
66681
67304
  ` + " `brainbase orchestration push`. Member agents live under ./agents/." + `
66682
67305
  Schedule triggers are writable. App/Pipedream triggers are preserved
66683
67306
  ` + " as read-only context and ignored by `orchestration push`.";
66684
- fs74.writeFileSync(orchManifestPath(cwd2), String(doc), "utf8");
67307
+ fs75.writeFileSync(orchManifestPath(cwd2), String(doc), "utf8");
66685
67308
  }
66686
67309
  function memberDir(cwd2, slug) {
66687
67310
  return path83.join(cwd2, ORCH_MEMBERS_DIR, slug);
@@ -66719,7 +67342,7 @@ function resolveMemberSlugs(members) {
66719
67342
 
66720
67343
  // src/core/orchestration-link.ts
66721
67344
  import path84 from "node:path";
66722
- import fs75 from "node:fs";
67345
+ import fs76 from "node:fs";
66723
67346
  var ORCH_LINK_FILE = "orchestration-link.json";
66724
67347
  var ORCH_SYNC_STATE_FILE = "orchestration-sync-state.json";
66725
67348
  var OrchestrationLinkSchema = exports_external.object({
@@ -66770,12 +67393,12 @@ function readOrchLink(cwd2) {
66770
67393
  }
66771
67394
  function writeOrchLink(cwd2, link2) {
66772
67395
  ensureDir(path84.join(cwd2, LINK_DIR));
66773
- const clean = {};
67396
+ const clean2 = {};
66774
67397
  for (const [k3, v3] of Object.entries(link2)) {
66775
67398
  if (v3 !== null && v3 !== undefined)
66776
- clean[k3] = v3;
67399
+ clean2[k3] = v3;
66777
67400
  }
66778
- writeJson(orchLinkPath(cwd2), clean);
67401
+ writeJson(orchLinkPath(cwd2), clean2);
66779
67402
  ensureGitignore2(cwd2);
66780
67403
  }
66781
67404
  function readOrchSyncState(cwd2) {
@@ -66799,12 +67422,12 @@ function ensureGitignore2(cwd2) {
66799
67422
  `;
66800
67423
  try {
66801
67424
  if (!exists(ignorePath)) {
66802
- fs75.writeFileSync(ignorePath, desired);
67425
+ fs76.writeFileSync(ignorePath, desired);
66803
67426
  return;
66804
67427
  }
66805
- const current = fs75.readFileSync(ignorePath, "utf8");
67428
+ const current = fs76.readFileSync(ignorePath, "utf8");
66806
67429
  if (!current.split(/\r?\n/).some((l2) => l2.trim() === ORCH_SYNC_STATE_FILE)) {
66807
- fs75.writeFileSync(ignorePath, current.endsWith(`
67430
+ fs76.writeFileSync(ignorePath, current.endsWith(`
66808
67431
  `) ? current + desired : current + `
66809
67432
  ` + desired);
66810
67433
  }
@@ -66813,7 +67436,7 @@ function ensureGitignore2(cwd2) {
66813
67436
 
66814
67437
  // src/core/agent-fresh-install.ts
66815
67438
  import path85 from "node:path";
66816
- import fs76 from "node:fs";
67439
+ import fs77 from "node:fs";
66817
67440
  import os15 from "node:os";
66818
67441
  async function installAgentFresh(input) {
66819
67442
  const { cwd: cwd2, agent, cloud, harness } = input;
@@ -66904,19 +67527,19 @@ async function installAgentFresh(input) {
66904
67527
  };
66905
67528
  } finally {
66906
67529
  try {
66907
- fs76.rmSync(stageRoot, { recursive: true, force: true });
67530
+ fs77.rmSync(stageRoot, { recursive: true, force: true });
66908
67531
  } catch {}
66909
67532
  }
66910
67533
  }
66911
67534
  function stageManifestComponents2(components) {
66912
- const root = fs76.mkdtempSync(path85.join(os15.tmpdir(), "brainbase-orch-pull-"));
67535
+ const root = fs77.mkdtempSync(path85.join(os15.tmpdir(), "brainbase-orch-pull-"));
66913
67536
  for (const c2 of components) {
66914
67537
  const compDir = path85.join(root, c2.type, c2.slug);
66915
67538
  ensureDir(compDir);
66916
67539
  for (const f4 of c2.files) {
66917
67540
  const target = path85.join(compDir, f4.path);
66918
67541
  ensureDir(path85.dirname(target));
66919
- fs76.writeFileSync(target, f4.content);
67542
+ fs77.writeFileSync(target, f4.content);
66920
67543
  }
66921
67544
  }
66922
67545
  return root;
@@ -66951,7 +67574,7 @@ function materializeInstructions2(cwd2, cloud) {
66951
67574
  continue;
66952
67575
  const target = path85.join(cwd2, DEFAULT_INSTRUCTIONS_FILE);
66953
67576
  ensureDir(path85.dirname(target));
66954
- fs76.writeFileSync(target, normalizeInstructionBody(body), "utf8");
67577
+ fs77.writeFileSync(target, normalizeInstructionBody(body), "utf8");
66955
67578
  return;
66956
67579
  }
66957
67580
  }
@@ -66965,7 +67588,7 @@ function materializePlaybooks2(cwd2, cloud) {
66965
67588
  const { body } = stripPlaybookFrontmatter(raw);
66966
67589
  const target = path85.join(cwd2, DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`);
66967
67590
  ensureDir(path85.dirname(target));
66968
- fs76.writeFileSync(target, body, "utf8");
67591
+ fs77.writeFileSync(target, body, "utf8");
66969
67592
  }
66970
67593
  }
66971
67594
  function buildManifestFromCloud(cloud, agent, localOnly = {}) {
@@ -67114,8 +67737,8 @@ async function runOrchestrationPull(cwd2, args) {
67114
67737
  orchId = args.orchestrationId;
67115
67738
  } else {
67116
67739
  f2.warn("This folder is not linked to any orchestration.");
67117
- f2.info(`Run ${import_picocolors37.default.cyan("brainbase orchestration pull <id>")} with an orchestration id,
67118
- or ${import_picocolors37.default.cyan("brainbase orchestration list")} to find one.`);
67740
+ f2.info(`Run ${import_picocolors40.default.cyan("brainbase orchestration pull <id>")} with an orchestration id,
67741
+ or ${import_picocolors40.default.cyan("brainbase orchestration list")} to find one.`);
67119
67742
  return;
67120
67743
  }
67121
67744
  const sp = de();
@@ -67134,24 +67757,24 @@ async function runOrchestrationPull(cwd2, args) {
67134
67757
  const slugFor = (agentId) => slugByAgent.get(agentId) ?? agentId;
67135
67758
  const planLines = [];
67136
67759
  planLines.push("");
67137
- planLines.push(` ${import_picocolors37.default.bold(cloud.name)} ${import_picocolors37.default.dim(`(${cloud.id})`)}`);
67760
+ planLines.push(` ${import_picocolors40.default.bold(cloud.name)} ${import_picocolors40.default.dim(`(${cloud.id})`)}`);
67138
67761
  if (cloud.description)
67139
- planLines.push(` ${import_picocolors37.default.dim(cloud.description)}`);
67762
+ planLines.push(` ${import_picocolors40.default.dim(cloud.description)}`);
67140
67763
  planLines.push("");
67141
- planLines.push(` ${import_picocolors37.default.dim("members:")}`);
67764
+ planLines.push(` ${import_picocolors40.default.dim("members:")}`);
67142
67765
  for (const m3 of cloud.members) {
67143
67766
  const skipped = !m3.manifest;
67144
- const tail2 = skipped ? import_picocolors37.default.red(" (manifest unavailable — skipped)") : "";
67145
- planLines.push(` ${import_picocolors37.default.cyan("•")} ${import_picocolors37.default.bold(slugFor(m3.agent_id))} ${import_picocolors37.default.dim(`(${m3.name})`)}${tail2}`);
67767
+ const tail2 = skipped ? import_picocolors40.default.red(" (manifest unavailable — skipped)") : "";
67768
+ planLines.push(` ${import_picocolors40.default.cyan("•")} ${import_picocolors40.default.bold(slugFor(m3.agent_id))} ${import_picocolors40.default.dim(`(${m3.name})`)}${tail2}`);
67146
67769
  }
67147
67770
  if (cloud.edges.length) {
67148
67771
  planLines.push("");
67149
- planLines.push(` ${import_picocolors37.default.dim("edges:")}`);
67772
+ planLines.push(` ${import_picocolors40.default.dim("edges:")}`);
67150
67773
  for (const e2 of cloud.edges) {
67151
67774
  const from = slugFor(e2.from_agent_id);
67152
67775
  const to2 = slugFor(e2.to_agent_id);
67153
- const desc = e2.description ? ` ${import_picocolors37.default.dim("— " + e2.description)}` : "";
67154
- planLines.push(` ${import_picocolors37.default.cyan(from)} ${import_picocolors37.default.dim("→")} ${import_picocolors37.default.cyan(to2)}${desc}`);
67776
+ const desc = e2.description ? ` ${import_picocolors40.default.dim("— " + e2.description)}` : "";
67777
+ planLines.push(` ${import_picocolors40.default.cyan(from)} ${import_picocolors40.default.dim("→")} ${import_picocolors40.default.cyan(to2)}${desc}`);
67155
67778
  }
67156
67779
  }
67157
67780
  planLines.push("");
@@ -67160,7 +67783,7 @@ async function runOrchestrationPull(cwd2, args) {
67160
67783
  const isRefresh = !!existingLink;
67161
67784
  if (!autoProceed(args.yes) && !isRefresh) {
67162
67785
  const ok = await se({
67163
- message: `Pull into ${import_picocolors37.default.bold(cwd2)}?`,
67786
+ message: `Pull into ${import_picocolors40.default.bold(cwd2)}?`,
67164
67787
  initialValue: true
67165
67788
  });
67166
67789
  if (!ensureNotCancelled(ok)) {
@@ -67169,7 +67792,7 @@ async function runOrchestrationPull(cwd2, args) {
67169
67792
  }
67170
67793
  }
67171
67794
  const fallbackHarness = args.harness ?? "claude-code";
67172
- fs77.mkdirSync(cwd2, { recursive: true });
67795
+ fs78.mkdirSync(cwd2, { recursive: true });
67173
67796
  if (hasOrchManifest(cwd2) && existingLink && existingLink.orchestration_id !== orchId) {
67174
67797
  f2.error(`This folder is linked to orchestration ${existingLink.orchestration_id}, not ${orchId}. Move to a fresh directory or unlink first.`);
67175
67798
  return;
@@ -67204,7 +67827,7 @@ async function runOrchestrationPull(cwd2, args) {
67204
67827
  scope: "project",
67205
67828
  pullSecrets: true
67206
67829
  });
67207
- memberSp.stop(`Installed ${import_picocolors37.default.bold(slug)} ${import_picocolors37.default.dim(`(${m3.manifest.components.length} components)`)}.`);
67830
+ memberSp.stop(`Installed ${import_picocolors40.default.bold(slug)} ${import_picocolors40.default.dim(`(${m3.manifest.components.length} components)`)}.`);
67208
67831
  installedMembers.push({
67209
67832
  agent_id: m3.agent_id,
67210
67833
  slug,
@@ -67265,7 +67888,7 @@ async function runOrchestrationPull(cwd2, args) {
67265
67888
  payload_schema: e2.payload_schema ?? {}
67266
67889
  }))
67267
67890
  });
67268
- $e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path86.basename(cwd2)}/ ${import_picocolors37.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
67891
+ $e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path86.basename(cwd2)}/ ${import_picocolors40.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
67269
67892
  }
67270
67893
  function handleApiError5(err) {
67271
67894
  if (err instanceof ApiError) {
@@ -67282,7 +67905,7 @@ function handleApiError5(err) {
67282
67905
  }
67283
67906
 
67284
67907
  // src/cli/orchestration-push.ts
67285
- var import_picocolors38 = __toESM(require_picocolors(), 1);
67908
+ var import_picocolors41 = __toESM(require_picocolors(), 1);
67286
67909
 
67287
67910
  // src/core/orchestration-outgoing.ts
67288
67911
  function buildOrchestrationGraphPayload(manifest, slugToAgentId) {
@@ -67365,7 +67988,7 @@ function findUnpushableMembers(cwd2, members) {
67365
67988
  continue;
67366
67989
  }
67367
67990
  if (!memberManifest.id) {
67368
- f2.error(`${m3.slug}: ${AGENT_MANIFEST_FILE} is unclaimed (no ${import_picocolors38.default.cyan("id")}), so there is nothing to push to.`);
67991
+ f2.error(`${m3.slug}: ${AGENT_MANIFEST_FILE} is unclaimed (no ${import_picocolors41.default.cyan("id")}), so there is nothing to push to.`);
67369
67992
  blocked.push(m3.slug);
67370
67993
  continue;
67371
67994
  }
@@ -67380,12 +68003,12 @@ async function runOrchestrationPush(cwd2, args) {
67380
68003
  const link2 = readOrchLink(cwd2);
67381
68004
  if (!link2) {
67382
68005
  f2.warn("This folder is not linked to any orchestration.");
67383
- f2.info(`Run ${import_picocolors38.default.cyan("brainbase orchestration pull <id>")} first.`);
68006
+ f2.info(`Run ${import_picocolors41.default.cyan("brainbase orchestration pull <id>")} first.`);
67384
68007
  return;
67385
68008
  }
67386
68009
  if (!hasOrchManifest(cwd2)) {
67387
- f2.warn(`No ${import_picocolors38.default.bold(ORCH_MANIFEST_FILE)} here.`);
67388
- f2.info(`Run ${import_picocolors38.default.cyan("brainbase orchestration pull")} to materialise the manifest before pushing.`);
68010
+ f2.warn(`No ${import_picocolors41.default.bold(ORCH_MANIFEST_FILE)} here.`);
68011
+ f2.info(`Run ${import_picocolors41.default.cyan("brainbase orchestration pull")} to materialise the manifest before pushing.`);
67389
68012
  return;
67390
68013
  }
67391
68014
  let manifest;
@@ -67409,7 +68032,7 @@ async function runOrchestrationPush(cwd2, args) {
67409
68032
  }
67410
68033
  if (missing.length) {
67411
68034
  f2.error(`Missing local checkouts for: ${missing.join(", ")}.`);
67412
- f2.info(`Run ${import_picocolors38.default.cyan("brainbase orchestration pull")} to materialise the missing folders.`);
68035
+ f2.info(`Run ${import_picocolors41.default.cyan("brainbase orchestration pull")} to materialise the missing folders.`);
67413
68036
  process.exitCode = 1;
67414
68037
  return;
67415
68038
  }
@@ -67430,13 +68053,13 @@ async function runOrchestrationPush(cwd2, args) {
67430
68053
  }
67431
68054
  }
67432
68055
  const plan = [""];
67433
- plan.push(` ${import_picocolors38.default.bold(link2.name)} ${import_picocolors38.default.dim(`(${link2.orchestration_id})`)}`);
67434
- plan.push(` ${import_picocolors38.default.dim(`${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}, ${graph.triggers.length} trigger${graph.triggers.length === 1 ? "" : "s"}`)}`);
68056
+ plan.push(` ${import_picocolors41.default.bold(link2.name)} ${import_picocolors41.default.dim(`(${link2.orchestration_id})`)}`);
68057
+ plan.push(` ${import_picocolors41.default.dim(`${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}, ${graph.triggers.length} trigger${graph.triggers.length === 1 ? "" : "s"}`)}`);
67435
68058
  plan.push("");
67436
68059
  if (!args.graphOnly) {
67437
- plan.push(` ${import_picocolors38.default.dim("per-member agent push:")}`);
68060
+ plan.push(` ${import_picocolors41.default.dim("per-member agent push:")}`);
67438
68061
  for (const m3 of manifest.members) {
67439
- plan.push(` ${import_picocolors38.default.cyan("•")} ${import_picocolors38.default.bold(m3.slug)}`);
68062
+ plan.push(` ${import_picocolors41.default.cyan("•")} ${import_picocolors41.default.bold(m3.slug)}`);
67440
68063
  }
67441
68064
  plan.push("");
67442
68065
  }
@@ -67456,7 +68079,7 @@ async function runOrchestrationPush(cwd2, args) {
67456
68079
  for (const m3 of manifest.members) {
67457
68080
  const dir = memberDir(cwd2, m3.slug);
67458
68081
  console.log("");
67459
- console.log(`${import_picocolors38.default.dim("───")} ${import_picocolors38.default.bold(m3.slug)} ${import_picocolors38.default.dim("───")}`);
68082
+ console.log(`${import_picocolors41.default.dim("───")} ${import_picocolors41.default.bold(m3.slug)} ${import_picocolors41.default.dim("───")}`);
67460
68083
  const exitCodeBeforePush = process.exitCode;
67461
68084
  try {
67462
68085
  await runAgentPush(dir, { yes: true });
@@ -67520,7 +68143,7 @@ function handleApiError6(err) {
67520
68143
  f2.error("You do not have access to this orchestration.");
67521
68144
  } else if (err.status === 409) {
67522
68145
  f2.error(err.message);
67523
- f2.info(`Run ${import_picocolors38.default.cyan("brainbase orchestration pull")} to reconcile, then push again.`);
68146
+ f2.info(`Run ${import_picocolors41.default.cyan("brainbase orchestration pull")} to reconcile, then push again.`);
67524
68147
  } else {
67525
68148
  f2.error(err.message);
67526
68149
  }
@@ -67530,13 +68153,13 @@ function handleApiError6(err) {
67530
68153
  }
67531
68154
 
67532
68155
  // src/cli/orchestration-status.ts
67533
- var import_picocolors39 = __toESM(require_picocolors(), 1);
68156
+ var import_picocolors42 = __toESM(require_picocolors(), 1);
67534
68157
  async function runOrchestrationStatus(cwd2) {
67535
68158
  banner("orchestration status — what changed locally, remotely, both");
67536
68159
  const link2 = readOrchLink(cwd2);
67537
68160
  if (!link2) {
67538
68161
  f2.warn("This folder is not linked to any orchestration.");
67539
- f2.info(`Run ${import_picocolors39.default.cyan("brainbase orchestration pull <id>")} first.`);
68162
+ f2.info(`Run ${import_picocolors42.default.cyan("brainbase orchestration pull <id>")} first.`);
67540
68163
  return;
67541
68164
  }
67542
68165
  const localManifest = hasOrchManifest(cwd2) ? readOrchManifest(cwd2) : null;
@@ -67559,8 +68182,8 @@ async function runOrchestrationStatus(cwd2) {
67559
68182
  }
67560
68183
  const lines = [];
67561
68184
  lines.push("");
67562
- lines.push(` ${import_picocolors39.default.bold(link2.name)} ${import_picocolors39.default.dim(`(${link2.orchestration_id})`)}`);
67563
- lines.push(` ${import_picocolors39.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
68185
+ lines.push(` ${import_picocolors42.default.bold(link2.name)} ${import_picocolors42.default.dim(`(${link2.orchestration_id})`)}`);
68186
+ lines.push(` ${import_picocolors42.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
67564
68187
  lines.push("");
67565
68188
  const localSlugByAgentId = new Map;
67566
68189
  for (const m3 of localManifest?.members ?? []) {
@@ -67574,12 +68197,12 @@ async function runOrchestrationStatus(cwd2) {
67574
68197
  const membersAdded = [...localMemberSet].filter((s3) => !cloudMemberSet.has(s3));
67575
68198
  const membersRemoved = [...cloudMemberSet].filter((s3) => !localMemberSet.has(s3));
67576
68199
  if (membersAdded.length || membersRemoved.length) {
67577
- lines.push(` ${import_picocolors39.default.bold("members")}`);
68200
+ lines.push(` ${import_picocolors42.default.bold("members")}`);
67578
68201
  for (const slug of membersAdded) {
67579
- lines.push(` ${import_picocolors39.default.yellow("→ push")} added in yaml: ${import_picocolors39.default.bold(slug)}`);
68202
+ lines.push(` ${import_picocolors42.default.yellow("→ push")} added in yaml: ${import_picocolors42.default.bold(slug)}`);
67580
68203
  }
67581
68204
  for (const slug of membersRemoved) {
67582
- lines.push(` ${import_picocolors39.default.cyan("← pull")} added on cloud: ${import_picocolors39.default.bold(slug)}`);
68205
+ lines.push(` ${import_picocolors42.default.cyan("← pull")} added on cloud: ${import_picocolors42.default.bold(slug)}`);
67583
68206
  }
67584
68207
  lines.push("");
67585
68208
  }
@@ -67594,11 +68217,11 @@ async function runOrchestrationStatus(cwd2) {
67594
68217
  const edgesAdded = [...localEdges.keys()].filter((k3) => !cloudEdges.has(k3));
67595
68218
  const edgesRemoved = [...cloudEdges.keys()].filter((k3) => !localEdges.has(k3));
67596
68219
  if (edgesAdded.length || edgesRemoved.length) {
67597
- lines.push(` ${import_picocolors39.default.bold("edges")}`);
68220
+ lines.push(` ${import_picocolors42.default.bold("edges")}`);
67598
68221
  for (const k3 of edgesAdded)
67599
- lines.push(` ${import_picocolors39.default.yellow("→ push")} added in yaml: ${k3}`);
68222
+ lines.push(` ${import_picocolors42.default.yellow("→ push")} added in yaml: ${k3}`);
67600
68223
  for (const k3 of edgesRemoved)
67601
- lines.push(` ${import_picocolors39.default.cyan("← pull")} added on cloud: ${k3}`);
68224
+ lines.push(` ${import_picocolors42.default.cyan("← pull")} added on cloud: ${k3}`);
67602
68225
  lines.push("");
67603
68226
  }
67604
68227
  const cloudTriggerKey = (t) => {
@@ -67636,11 +68259,11 @@ async function runOrchestrationStatus(cwd2) {
67636
68259
  const triggersAdded = [...localTriggers.keys()].filter((k3) => !cloudTriggers.has(k3));
67637
68260
  const triggersRemoved = [...cloudTriggers.keys()].filter((k3) => !localTriggers.has(k3));
67638
68261
  if (triggersAdded.length || triggersRemoved.length) {
67639
- lines.push(` ${import_picocolors39.default.bold("schedule triggers")}`);
68262
+ lines.push(` ${import_picocolors42.default.bold("schedule triggers")}`);
67640
68263
  for (const k3 of triggersAdded)
67641
- lines.push(` ${import_picocolors39.default.yellow("→ push")} added/changed in yaml: ${localTriggers.get(k3) ?? k3}`);
68264
+ lines.push(` ${import_picocolors42.default.yellow("→ push")} added/changed in yaml: ${localTriggers.get(k3) ?? k3}`);
67642
68265
  for (const k3 of triggersRemoved)
67643
- lines.push(` ${import_picocolors39.default.cyan("← pull")} added/changed on cloud: ${cloudTriggers.get(k3) ?? k3}`);
68266
+ lines.push(` ${import_picocolors42.default.cyan("← pull")} added/changed on cloud: ${cloudTriggers.get(k3) ?? k3}`);
67644
68267
  lines.push("");
67645
68268
  }
67646
68269
  const lockByAgentId = new Map((lock?.members ?? []).map((m3) => [m3.agent_id, m3]));
@@ -67663,27 +68286,27 @@ async function runOrchestrationStatus(cwd2) {
67663
68286
  }
67664
68287
  }
67665
68288
  if (memberDrift.length) {
67666
- lines.push(` ${import_picocolors39.default.bold("member content drift")}`);
68289
+ lines.push(` ${import_picocolors42.default.bold("member content drift")}`);
67667
68290
  for (const d3 of memberDrift) {
67668
- lines.push(` ${import_picocolors39.default.cyan("?")} ${import_picocolors39.default.bold(d3.slug)} ${import_picocolors39.default.dim("— " + d3.reason)}`);
68291
+ lines.push(` ${import_picocolors42.default.cyan("?")} ${import_picocolors42.default.bold(d3.slug)} ${import_picocolors42.default.dim("— " + d3.reason)}`);
67669
68292
  }
67670
- lines.push(` ${import_picocolors39.default.dim("cd into each member folder and run")} ${import_picocolors39.default.cyan("brainbase agent status")}`);
68293
+ lines.push(` ${import_picocolors42.default.dim("cd into each member folder and run")} ${import_picocolors42.default.cyan("brainbase agent status")}`);
67671
68294
  lines.push("");
67672
68295
  }
67673
68296
  const revisionDrift = lock?.revision != null && cloud.revision !== lock.revision;
67674
68297
  if (revisionDrift) {
67675
- lines.push(` ${import_picocolors39.default.bold("cloud revision")}`);
67676
- lines.push(` ${import_picocolors39.default.cyan("← pull")} cloud changed since last pull: ${import_picocolors39.default.dim(`lock ${lock.revision} → cloud ${cloud.revision}`)}`);
68298
+ lines.push(` ${import_picocolors42.default.bold("cloud revision")}`);
68299
+ lines.push(` ${import_picocolors42.default.cyan("← pull")} cloud changed since last pull: ${import_picocolors42.default.dim(`lock ${lock.revision} → cloud ${cloud.revision}`)}`);
67677
68300
  lines.push("");
67678
68301
  }
67679
68302
  if (!membersAdded.length && !membersRemoved.length && !edgesAdded.length && !edgesRemoved.length && !triggersAdded.length && !triggersRemoved.length && !memberDrift.length && !revisionDrift) {
67680
- lines.push(` ${import_picocolors39.default.green("✓")} everything is in sync`);
68303
+ lines.push(` ${import_picocolors42.default.green("✓")} everything is in sync`);
67681
68304
  lines.push("");
67682
68305
  console.log(lines.join(`
67683
68306
  `));
67684
68307
  return;
67685
68308
  }
67686
- lines.push(` ${import_picocolors39.default.dim("run")} ${import_picocolors39.default.cyan("brainbase orchestration pull")} ${import_picocolors39.default.dim("to apply cloud changes,")} ${import_picocolors39.default.cyan("brainbase orchestration push")} ${import_picocolors39.default.dim("to send yours")}`);
68309
+ lines.push(` ${import_picocolors42.default.dim("run")} ${import_picocolors42.default.cyan("brainbase orchestration pull")} ${import_picocolors42.default.dim("to apply cloud changes,")} ${import_picocolors42.default.cyan("brainbase orchestration push")} ${import_picocolors42.default.dim("to send yours")}`);
67687
68310
  lines.push("");
67688
68311
  console.log(lines.join(`
67689
68312
  `));
@@ -67698,7 +68321,7 @@ function stableJson(value) {
67698
68321
  }
67699
68322
 
67700
68323
  // src/cli/orchestration-list.ts
67701
- var import_picocolors40 = __toESM(require_picocolors(), 1);
68324
+ var import_picocolors43 = __toESM(require_picocolors(), 1);
67702
68325
  async function runOrchestrationList(args) {
67703
68326
  banner("orchestration list — orchestrations under a team");
67704
68327
  const { org, team } = await resolveOrgAndTeam({
@@ -67722,21 +68345,21 @@ async function runOrchestrationList(args) {
67722
68345
  }
67723
68346
  const lines = [""];
67724
68347
  for (const o2 of items) {
67725
- lines.push(` ${import_picocolors40.default.bold(o2.name)} ${import_picocolors40.default.dim(o2.id)}`);
68348
+ lines.push(` ${import_picocolors43.default.bold(o2.name)} ${import_picocolors43.default.dim(o2.id)}`);
67726
68349
  if (o2.description)
67727
- lines.push(` ${import_picocolors40.default.dim(o2.description)}`);
67728
- lines.push(` ${import_picocolors40.default.dim(`${o2.member_count} member${o2.member_count === 1 ? "" : "s"} · ${o2.edge_count} edge${o2.edge_count === 1 ? "" : "s"}`)}`);
68350
+ lines.push(` ${import_picocolors43.default.dim(o2.description)}`);
68351
+ lines.push(` ${import_picocolors43.default.dim(`${o2.member_count} member${o2.member_count === 1 ? "" : "s"} · ${o2.edge_count} edge${o2.edge_count === 1 ? "" : "s"}`)}`);
67729
68352
  lines.push("");
67730
68353
  }
67731
- lines.push(` ${import_picocolors40.default.dim("pull one with")} ${import_picocolors40.default.cyan("brainbase orchestration pull <id>")}`);
68354
+ lines.push(` ${import_picocolors43.default.dim("pull one with")} ${import_picocolors43.default.cyan("brainbase orchestration pull <id>")}`);
67732
68355
  lines.push("");
67733
68356
  console.log(lines.join(`
67734
68357
  `));
67735
68358
  }
67736
68359
 
67737
68360
  // src/cli/orchestration-add-agent.ts
67738
- import fs78 from "node:fs";
67739
- var import_picocolors41 = __toESM(require_picocolors(), 1);
68361
+ import fs79 from "node:fs";
68362
+ var import_picocolors44 = __toESM(require_picocolors(), 1);
67740
68363
 
67741
68364
  // src/core/orchestration-add.ts
67742
68365
  function resolveOrgIdForGroup(groupId, orgsWithTeams) {
@@ -67801,7 +68424,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
67801
68424
  const link2 = readOrchLink(cwd2);
67802
68425
  if (!link2 || !hasOrchManifest(cwd2)) {
67803
68426
  f2.warn("This folder is not a linked orchestration.");
67804
- f2.info(`Run ${import_picocolors41.default.cyan("brainbase orchestration pull <id>")} first.`);
68427
+ f2.info(`Run ${import_picocolors44.default.cyan("brainbase orchestration pull <id>")} first.`);
67805
68428
  return;
67806
68429
  }
67807
68430
  let manifest;
@@ -67821,13 +68444,13 @@ async function runOrchestrationAddAgent(cwd2, args) {
67821
68444
  })).trim();
67822
68445
  }
67823
68446
  let slug = slugifyMemberName(name);
67824
- if (manifest.members.some((m3) => m3.slug === slug) || fs78.existsSync(memberDir(cwd2, slug))) {
68447
+ if (manifest.members.some((m3) => m3.slug === slug) || fs79.existsSync(memberDir(cwd2, slug))) {
67825
68448
  let n = 2;
67826
68449
  let candidate = `${slug}-${n}`;
67827
- while (manifest.members.some((m3) => m3.slug === candidate) || fs78.existsSync(memberDir(cwd2, candidate))) {
68450
+ while (manifest.members.some((m3) => m3.slug === candidate) || fs79.existsSync(memberDir(cwd2, candidate))) {
67828
68451
  candidate = `${slug}-${++n}`;
67829
68452
  }
67830
- f2.info(`Slug ${import_picocolors41.default.bold(slug)} is taken — using ${import_picocolors41.default.bold(candidate)}.`);
68453
+ f2.info(`Slug ${import_picocolors44.default.bold(slug)} is taken — using ${import_picocolors44.default.bold(candidate)}.`);
67831
68454
  slug = candidate;
67832
68455
  }
67833
68456
  let payloadSchema;
@@ -67851,7 +68474,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
67851
68474
  const resolved = resolveOrgIdForGroup(link2.group_id, orgsWithTeams);
67852
68475
  if (!resolved) {
67853
68476
  sp.stop("Failed.");
67854
- f2.error(`Could not find an org that owns group ${import_picocolors41.default.bold(link2.group_id)}. ` + `Pass ${import_picocolors41.default.cyan("--org <id>")} explicitly.`);
68477
+ f2.error(`Could not find an org that owns group ${import_picocolors44.default.bold(link2.group_id)}. ` + `Pass ${import_picocolors44.default.cyan("--org <id>")} explicitly.`);
67855
68478
  return;
67856
68479
  }
67857
68480
  orgId = resolved;
@@ -67868,14 +68491,14 @@ async function runOrchestrationAddAgent(cwd2, args) {
67868
68491
  if (from.length === 0 && to2.length === 0 && isInteractive() && manifest.members.length > 0) {
67869
68492
  const memberOptions = manifest.members.map((m3) => ({ value: m3.slug, label: m3.slug }));
67870
68493
  const pickedFrom = await ae({
67871
- message: `Connect ${import_picocolors41.default.bold(slug)} FROM which member(s)? — edges INTO ${slug} (space to select, enter to skip)`,
68494
+ message: `Connect ${import_picocolors44.default.bold(slug)} FROM which member(s)? — edges INTO ${slug} (space to select, enter to skip)`,
67872
68495
  options: memberOptions,
67873
68496
  required: false
67874
68497
  });
67875
68498
  if (Array.isArray(pickedFrom))
67876
68499
  from = pickedFrom;
67877
68500
  const pickedTo = await ae({
67878
- message: `Connect ${import_picocolors41.default.bold(slug)} TO which member(s)? — edges OUT of ${slug} (space to select, enter to skip)`,
68501
+ message: `Connect ${import_picocolors44.default.bold(slug)} TO which member(s)? — edges OUT of ${slug} (space to select, enter to skip)`,
67879
68502
  options: memberOptions,
67880
68503
  required: false
67881
68504
  });
@@ -67896,7 +68519,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
67896
68519
  }
67897
68520
  const dest = memberDir(cwd2, slug);
67898
68521
  try {
67899
- fs78.mkdirSync(dest, { recursive: true });
68522
+ fs79.mkdirSync(dest, { recursive: true });
67900
68523
  await runAgentCreate(dest, {
67901
68524
  name,
67902
68525
  orgId,
@@ -67907,30 +68530,30 @@ async function runOrchestrationAddAgent(cwd2, args) {
67907
68530
  });
67908
68531
  } catch (err) {
67909
68532
  try {
67910
- fs78.rmSync(dest, { recursive: true, force: true });
68533
+ fs79.rmSync(dest, { recursive: true, force: true });
67911
68534
  } catch {}
67912
68535
  f2.error(`Failed to create ${slug}: ${err.message}`);
67913
68536
  return;
67914
68537
  }
67915
68538
  writeOrchManifest(cwd2, updated);
67916
68539
  if (args.noPush) {
67917
- f2.info(`Manifest updated. Run ${import_picocolors41.default.cyan("brainbase orchestration push")} to apply.`);
68540
+ f2.info(`Manifest updated. Run ${import_picocolors44.default.cyan("brainbase orchestration push")} to apply.`);
67918
68541
  return;
67919
68542
  }
67920
68543
  await runOrchestrationPush(cwd2, { yes: true, graphOnly: true });
67921
68544
  }
67922
68545
 
67923
68546
  // src/cli/orchestration-create.ts
67924
- var import_picocolors42 = __toESM(require_picocolors(), 1);
68547
+ var import_picocolors45 = __toESM(require_picocolors(), 1);
67925
68548
  async function runOrchestrationCreate(cwd2, args) {
67926
68549
  banner("orchestration create — claim a brainbase-orchestration.yaml");
67927
68550
  if (readOrchLink(cwd2)) {
67928
68551
  f2.warn("This folder is already linked to an orchestration.");
67929
- f2.info(`Run ${import_picocolors42.default.cyan("brainbase orchestration push")} to update it.`);
68552
+ f2.info(`Run ${import_picocolors45.default.cyan("brainbase orchestration push")} to update it.`);
67930
68553
  return;
67931
68554
  }
67932
68555
  if (!hasOrchManifest(cwd2)) {
67933
- f2.warn(`No ${import_picocolors42.default.bold(ORCH_MANIFEST_FILE)} here.`);
68556
+ f2.warn(`No ${import_picocolors45.default.bold(ORCH_MANIFEST_FILE)} here.`);
67934
68557
  f2.info(`Create one, or pull an existing orchestration first.`);
67935
68558
  return;
67936
68559
  }
@@ -67963,10 +68586,10 @@ async function runOrchestrationCreate(cwd2, args) {
67963
68586
  });
67964
68587
  const plan = [
67965
68588
  "",
67966
- ` ${import_picocolors42.default.bold(manifest.orchestration.name)}`,
67967
- ` ${import_picocolors42.default.dim("org")} ${import_picocolors42.default.bold(target.org.name)}`,
67968
- ` ${import_picocolors42.default.dim("team")} ${import_picocolors42.default.bold(target.team.name)}`,
67969
- ` ${import_picocolors42.default.dim("graph")} ${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}, ${graph.triggers.length} trigger${graph.triggers.length === 1 ? "" : "s"}`,
68589
+ ` ${import_picocolors45.default.bold(manifest.orchestration.name)}`,
68590
+ ` ${import_picocolors45.default.dim("org")} ${import_picocolors45.default.bold(target.org.name)}`,
68591
+ ` ${import_picocolors45.default.dim("team")} ${import_picocolors45.default.bold(target.team.name)}`,
68592
+ ` ${import_picocolors45.default.dim("graph")} ${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}, ${graph.triggers.length} trigger${graph.triggers.length === 1 ? "" : "s"}`,
67970
68593
  ""
67971
68594
  ];
67972
68595
  console.log(plan.join(`
@@ -67996,7 +68619,7 @@ async function runOrchestrationCreate(cwd2, args) {
67996
68619
  edges: graph.edges,
67997
68620
  triggers: graph.triggers
67998
68621
  });
67999
- sp.stop(`Created ${import_picocolors42.default.bold(created.name)}.`);
68622
+ sp.stop(`Created ${import_picocolors45.default.bold(created.name)}.`);
68000
68623
  writeOrchLink(cwd2, {
68001
68624
  schemaVersion: 1,
68002
68625
  orchestration_id: created.id,
@@ -68109,21 +68732,21 @@ async function runOrchestration(cwd2, sub, args, opts) {
68109
68732
  function printHelp3() {
68110
68733
  const out = [];
68111
68734
  out.push("");
68112
- out.push(` ${import_picocolors43.default.bold("brainbase orchestration")} ${import_picocolors43.default.dim("<sub> [options]")}`);
68735
+ out.push(` ${import_picocolors46.default.bold("brainbase orchestration")} ${import_picocolors46.default.dim("<sub> [options]")}`);
68113
68736
  out.push("");
68114
- out.push(` ${import_picocolors43.default.cyan("create")} ${import_picocolors43.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
68115
- out.push(` ${import_picocolors43.default.cyan("pull")} ${import_picocolors43.default.dim("<id>")} ${import_picocolors43.default.dim("fetch orchestration + every member agent into this folder")}`);
68116
- out.push(` ${import_picocolors43.default.cyan("push")} ${import_picocolors43.default.dim("push each member, then update the orchestration graph")}`);
68117
- out.push(` ${import_picocolors43.default.cyan("add-agent")} ${import_picocolors43.default.dim("<name>")} ${import_picocolors43.default.dim("create a member agent, wire edges (--from/--to), and push")}`);
68118
- out.push(` ${import_picocolors43.default.cyan("status")} ${import_picocolors43.default.dim("show what would push and what would pull")}`);
68119
- out.push(` ${import_picocolors43.default.cyan("list")} ${import_picocolors43.default.dim("list orchestrations under a team")}`);
68737
+ out.push(` ${import_picocolors46.default.cyan("create")} ${import_picocolors46.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
68738
+ out.push(` ${import_picocolors46.default.cyan("pull")} ${import_picocolors46.default.dim("<id>")} ${import_picocolors46.default.dim("fetch orchestration + every member agent into this folder")}`);
68739
+ out.push(` ${import_picocolors46.default.cyan("push")} ${import_picocolors46.default.dim("push each member, then update the orchestration graph")}`);
68740
+ out.push(` ${import_picocolors46.default.cyan("add-agent")} ${import_picocolors46.default.dim("<name>")} ${import_picocolors46.default.dim("create a member agent, wire edges (--from/--to), and push")}`);
68741
+ out.push(` ${import_picocolors46.default.cyan("status")} ${import_picocolors46.default.dim("show what would push and what would pull")}`);
68742
+ out.push(` ${import_picocolors46.default.cyan("list")} ${import_picocolors46.default.dim("list orchestrations under a team")}`);
68120
68743
  out.push("");
68121
- out.push(` ${import_picocolors43.default.bold("Flags")}`);
68122
- out.push(` ${import_picocolors43.default.dim("--yes, -y")} skip confirmations`);
68123
- out.push(` ${import_picocolors43.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
68124
- out.push(` ${import_picocolors43.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`);
68125
- out.push(` ${import_picocolors43.default.dim("--org <id>")} for create/list: org id or slug (CLI vocab — DB teams.id)`);
68126
- out.push(` ${import_picocolors43.default.dim("--team <id>")} for create/list: team id (CLI vocab — DB groups.id)`);
68744
+ out.push(` ${import_picocolors46.default.bold("Flags")}`);
68745
+ out.push(` ${import_picocolors46.default.dim("--yes, -y")} skip confirmations`);
68746
+ out.push(` ${import_picocolors46.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
68747
+ out.push(` ${import_picocolors46.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`);
68748
+ out.push(` ${import_picocolors46.default.dim("--org <id>")} for create/list: org id or slug (CLI vocab — DB teams.id)`);
68749
+ out.push(` ${import_picocolors46.default.dim("--team <id>")} for create/list: team id (CLI vocab — DB groups.id)`);
68127
68750
  out.push("");
68128
68751
  console.log(out.join(`
68129
68752
  `));
@@ -68168,11 +68791,11 @@ async function runRun(cwd2, args) {
68168
68791
  }
68169
68792
 
68170
68793
  // src/cli/publish.ts
68171
- var import_picocolors44 = __toESM(require_picocolors(), 1);
68794
+ var import_picocolors47 = __toESM(require_picocolors(), 1);
68172
68795
  function runPublish() {
68173
68796
  banner("publish — moved");
68174
- f2.error(`${import_picocolors44.default.bold("brainbase publish")} does not exist.`);
68175
- f2.info(`Use ${import_picocolors44.default.cyan("brainbase agent push")} to send your local changes to the cloud.`);
68797
+ f2.error(`${import_picocolors47.default.bold("brainbase publish")} does not exist.`);
68798
+ f2.info(`Use ${import_picocolors47.default.cyan("brainbase agent push")} to send your local changes to the cloud.`);
68176
68799
  process.exit(1);
68177
68800
  }
68178
68801
 
@@ -68471,7 +69094,7 @@ async function runStatus(cwd2) {
68471
69094
  }
68472
69095
 
68473
69096
  // src/cli/token.ts
68474
- var import_picocolors45 = __toESM(require_picocolors(), 1);
69097
+ var import_picocolors48 = __toESM(require_picocolors(), 1);
68475
69098
 
68476
69099
  // src/ui/ink/TokenCards.tsx
68477
69100
  var jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
@@ -68481,14 +69104,6 @@ function TokenCreatedCard(props) {
68481
69104
  tone: "warn",
68482
69105
  subtitle: "shown ONCE — copy it now",
68483
69106
  children: [
68484
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
68485
- marginBottom: 1,
68486
- children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
68487
- bold: true,
68488
- color: "yellow",
68489
- children: props.token
68490
- }, undefined, false, undefined, this)
68491
- }, undefined, false, undefined, this),
68492
69107
  /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
68493
69108
  flexDirection: "column",
68494
69109
  marginBottom: 1,
@@ -68549,20 +69164,22 @@ function TokenCreatedCard(props) {
68549
69164
  /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
68550
69165
  dimColor: true,
68551
69166
  children: [
68552
- "saved locally to ",
69167
+ "saved to ",
68553
69168
  props.storedAt,
68554
- " (mode 0600)"
69169
+ " (mode 0600) — covers ",
69170
+ REGISTRY_COMMANDS
68555
69171
  ]
68556
69172
  }, undefined, true, undefined, this),
68557
69173
  /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
68558
69174
  dimColor: true,
68559
69175
  children: [
68560
- "for CI: set ",
69176
+ CONTROL_PLANE_COMMANDS,
69177
+ " do ",
68561
69178
  /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
68562
69179
  bold: true,
68563
- children: "BRAINBASE_TOKEN"
69180
+ children: "not"
68564
69181
  }, undefined, false, undefined, this),
68565
- " instead of relying on token.json"
69182
+ " read that file export it instead:"
68566
69183
  ]
68567
69184
  }, undefined, true, undefined, this)
68568
69185
  ]
@@ -68571,9 +69188,12 @@ function TokenCreatedCard(props) {
68571
69188
  }, undefined, true, undefined, this);
68572
69189
  }
68573
69190
  async function showTokenCreatedCard(props) {
69191
+ const { token, ...card } = props;
68574
69192
  await renderStatic(/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(TokenCreatedCard, {
68575
- ...props
69193
+ ...card
68576
69194
  }, undefined, false, undefined, this));
69195
+ console.log(` export BRAINBASE_TOKEN=${token}`);
69196
+ console.log("");
68577
69197
  }
68578
69198
  function TokenListCard(props) {
68579
69199
  if (props.active.length === 0) {
@@ -68739,11 +69359,32 @@ function isAllowedScope(value) {
68739
69359
  function isExpired2(token) {
68740
69360
  return Boolean(token.expires_at && Date.parse(token.expires_at) <= Date.now());
68741
69361
  }
69362
+ function isJwtRequired(body) {
69363
+ if (!body || typeof body !== "object")
69364
+ return false;
69365
+ const detail = body.detail;
69366
+ if (!detail || typeof detail !== "object")
69367
+ return false;
69368
+ return detail.code === "jwt_required";
69369
+ }
69370
+ function sessionWouldBeUsed() {
69371
+ const { ok, session } = authStatus();
69372
+ if (ok)
69373
+ return true;
69374
+ return Boolean(session?.refresh_token && session.supabase_url && session.supabase_anon_key);
69375
+ }
68742
69376
  function withLoginHint(error) {
68743
- if (error instanceof ApiError && error.status === 403) {
68744
- return new Error("Managing tokens needs a logged-in session; a PAT (BRAINBASE_TOKEN) cannot. " + "Run `brainbase login` and try again.");
68745
- }
68746
- return error;
69377
+ if (!(error instanceof ApiError) || error.status !== 403)
69378
+ return error;
69379
+ if (!isJwtRequired(error.body))
69380
+ return error;
69381
+ if (!process.env.BRAINBASE_TOKEN?.trim()) {
69382
+ if (sessionWouldBeUsed() || !readToken())
69383
+ return error;
69384
+ return new Error("Managing tokens needs a logged-in session; the stored PAT cannot. " + "Run `brainbase login` and try again.");
69385
+ }
69386
+ const lead = "Managing tokens needs a logged-in session, and BRAINBASE_TOKEN is set — " + "that PAT is being used instead.";
69387
+ return new Error(sessionWouldBeUsed() ? `${lead} Run \`unset BRAINBASE_TOKEN\` and try again.` : `${lead} Run \`unset BRAINBASE_TOKEN\`, then \`brainbase login\`.`);
68747
69388
  }
68748
69389
  async function runTokenCreate(args) {
68749
69390
  banner("token create — make a long-lived CLI key");
@@ -68766,10 +69407,16 @@ async function runTokenCreate(args) {
68766
69407
  }
68767
69408
  const spinner = de();
68768
69409
  spinner.start("Creating token…");
68769
- const created = await registryApi.createCliToken({
68770
- name,
68771
- scopes
68772
- });
69410
+ let created;
69411
+ try {
69412
+ created = await registryApi.createCliToken({
69413
+ name,
69414
+ scopes
69415
+ });
69416
+ } catch (error) {
69417
+ spinner.stop("Could not create token.");
69418
+ throw withLoginHint(error);
69419
+ }
68773
69420
  spinner.stop("Token created.");
68774
69421
  try {
68775
69422
  writeToken(created.token, name);
@@ -68790,7 +69437,12 @@ async function runTokenCreate(args) {
68790
69437
  }
68791
69438
  async function runTokenList() {
68792
69439
  banner("tokens");
68793
- const tokens = await registryApi.listCliTokens();
69440
+ let tokens;
69441
+ try {
69442
+ tokens = await registryApi.listCliTokens();
69443
+ } catch (error) {
69444
+ throw withLoginHint(error);
69445
+ }
68794
69446
  const active = tokens.filter((t) => !t.revoked_at);
68795
69447
  const revoked = tokens.filter((t) => t.revoked_at);
68796
69448
  const local = readToken();
@@ -68864,7 +69516,7 @@ async function runTokenRename(args) {
68864
69516
  }
68865
69517
  }
68866
69518
  if (name === target.name.trim()) {
68867
- console.log(`${sym.ok} ${import_picocolors45.default.bold(target.name.trim())} already has that label; nothing to do.`);
69519
+ console.log(`${sym.ok} ${import_picocolors48.default.bold(target.name.trim())} already has that label; nothing to do.`);
68868
69520
  return;
68869
69521
  }
68870
69522
  try {
@@ -68872,7 +69524,7 @@ async function runTokenRename(args) {
68872
69524
  } catch (error) {
68873
69525
  throw withLoginHint(error);
68874
69526
  }
68875
- console.log(`${sym.ok} Renamed ${import_picocolors45.default.dim(target.name)} → ${import_picocolors45.default.bold(name)}`);
69527
+ console.log(`${sym.ok} Renamed ${import_picocolors48.default.dim(target.name)} → ${import_picocolors48.default.bold(name)}`);
68876
69528
  }
68877
69529
  async function runTokenRevoke(args) {
68878
69530
  if (!args.id) {
@@ -68890,14 +69542,14 @@ async function runTokenRevoke(args) {
68890
69542
  throw new Error(`No token with id ${args.id}. Run \`brainbase token list\` to see yours.`);
68891
69543
  }
68892
69544
  if (target.revoked_at) {
68893
- reconcileDeadToken(target, `${import_picocolors45.default.bold(target.name)} is already revoked.`);
69545
+ reconcileDeadToken(target, `${import_picocolors48.default.bold(target.name)} is already revoked.`);
68894
69546
  return;
68895
69547
  }
68896
69548
  const stored = readToken();
68897
69549
  const isLocalToken = Boolean(stored && stored.token.startsWith(target.prefix));
68898
69550
  if (!autoProceed(args.yes)) {
68899
69551
  const ok = await se({
68900
- message: isLocalToken ? `Revoke ${import_picocolors45.default.bold(target.name)} (${args.id})? This is the token this CLI is using, so it will stop working here too.` : `Revoke ${import_picocolors45.default.bold(target.name)} (${args.id})? CIs and machines using it will stop working.`,
69552
+ message: isLocalToken ? `Revoke ${import_picocolors48.default.bold(target.name)} (${args.id})? This is the token this CLI is using, so it will stop working here too.` : `Revoke ${import_picocolors48.default.bold(target.name)} (${args.id})? CIs and machines using it will stop working.`,
68901
69553
  initialValue: false
68902
69554
  });
68903
69555
  if (!ensureNotCancelled(ok))
@@ -68908,14 +69560,14 @@ async function runTokenRevoke(args) {
68908
69560
  } catch (error) {
68909
69561
  if (error instanceof ApiError && error.status === 404) {
68910
69562
  if (isExpired2(target)) {
68911
- reconcileDeadToken(target, `${import_picocolors45.default.bold(target.name)} had already expired.`);
69563
+ reconcileDeadToken(target, `${import_picocolors48.default.bold(target.name)} had already expired.`);
68912
69564
  return;
68913
69565
  }
68914
69566
  throw new Error(`The server reported no active token with id ${args.id}, but it listed one a moment ago. ` + "The local token has been left alone, since that key may still work. " + "If this server predates `DELETE /v1/registry/cli-tokens/{id}`, revoke from the web app instead.");
68915
69567
  }
68916
- throw error;
69568
+ throw withLoginHint(error);
68917
69569
  }
68918
- reconcileDeadToken(target, `Revoked ${import_picocolors45.default.bold(target.name)}.`);
69570
+ reconcileDeadToken(target, `Revoked ${import_picocolors48.default.bold(target.name)}.`);
68919
69571
  }
68920
69572
  function reconcileDeadToken(target, headline) {
68921
69573
  let outcome;
@@ -68949,7 +69601,7 @@ function reportLocalToken(headline, outcome) {
68949
69601
  }
68950
69602
  async function runTokenClear() {
68951
69603
  if (!readToken()) {
68952
- console.log(import_picocolors45.default.dim("No local token stored."));
69604
+ console.log(import_picocolors48.default.dim("No local token stored."));
68953
69605
  return;
68954
69606
  }
68955
69607
  clearToken();
@@ -69049,32 +69701,32 @@ async function runToken(sub, rest2, args) {
69049
69701
  function printTokenHelp() {
69050
69702
  const out = [];
69051
69703
  out.push("");
69052
- out.push(` ${import_picocolors45.default.bold("brainbase token")} ${import_picocolors45.default.dim("<command>")}`);
69704
+ out.push(` ${import_picocolors48.default.bold("brainbase token")} ${import_picocolors48.default.dim("<command>")}`);
69053
69705
  out.push("");
69054
- out.push(` ${import_picocolors45.default.cyan("create")} ${import_picocolors45.default.dim("issue a new long-lived CLI key (PAT)")}`);
69055
- out.push(` ${import_picocolors45.default.cyan("list")} ${import_picocolors45.default.dim("show your tokens")}`);
69056
- out.push(` ${import_picocolors45.default.cyan("rename")} ${import_picocolors45.default.dim("<id>")} ${import_picocolors45.default.dim("relabel a token by id")}`);
69057
- out.push(` ${import_picocolors45.default.cyan("revoke")} ${import_picocolors45.default.dim("<id>")} ${import_picocolors45.default.dim("revoke a token by id")}`);
69058
- out.push(` ${import_picocolors45.default.cyan("clear")} ${import_picocolors45.default.dim("forget the local token (does not revoke)")}`);
69706
+ out.push(` ${import_picocolors48.default.cyan("create")} ${import_picocolors48.default.dim("issue a new long-lived CLI key (PAT)")}`);
69707
+ out.push(` ${import_picocolors48.default.cyan("list")} ${import_picocolors48.default.dim("show your tokens")}`);
69708
+ out.push(` ${import_picocolors48.default.cyan("rename")} ${import_picocolors48.default.dim("<id>")} ${import_picocolors48.default.dim("relabel a token by id")}`);
69709
+ out.push(` ${import_picocolors48.default.cyan("revoke")} ${import_picocolors48.default.dim("<id>")} ${import_picocolors48.default.dim("revoke a token by id")}`);
69710
+ out.push(` ${import_picocolors48.default.cyan("clear")} ${import_picocolors48.default.dim("forget the local token (does not revoke)")}`);
69059
69711
  out.push("");
69060
- out.push(` ${import_picocolors45.default.bold("create flags")}`);
69061
- out.push(` ${import_picocolors45.default.cyan("--name, -n")} ${import_picocolors45.default.dim("<label>")} ${import_picocolors45.default.dim("token label (prompted if omitted)")}`);
69062
- out.push(` ${import_picocolors45.default.cyan("--scopes")} ${import_picocolors45.default.dim("<list>")} ${import_picocolors45.default.dim("comma-separated; allowed: read, publish, admin")}`);
69063
- out.push(` ${import_picocolors45.default.dim("default: read,publish")}`);
69712
+ out.push(` ${import_picocolors48.default.bold("create flags")}`);
69713
+ out.push(` ${import_picocolors48.default.cyan("--name, -n")} ${import_picocolors48.default.dim("<label>")} ${import_picocolors48.default.dim("token label (prompted if omitted)")}`);
69714
+ out.push(` ${import_picocolors48.default.cyan("--scopes")} ${import_picocolors48.default.dim("<list>")} ${import_picocolors48.default.dim("comma-separated; allowed: read, publish, admin")}`);
69715
+ out.push(` ${import_picocolors48.default.dim("default: read,publish")}`);
69064
69716
  out.push("");
69065
- out.push(` ${import_picocolors45.default.bold("rename flags")}`);
69066
- out.push(` ${import_picocolors45.default.cyan("--name, -n")} ${import_picocolors45.default.dim("<label>")} ${import_picocolors45.default.dim("new label (prompted if omitted)")}`);
69717
+ out.push(` ${import_picocolors48.default.bold("rename flags")}`);
69718
+ out.push(` ${import_picocolors48.default.cyan("--name, -n")} ${import_picocolors48.default.dim("<label>")} ${import_picocolors48.default.dim("new label (prompted if omitted)")}`);
69067
69719
  out.push("");
69068
69720
  console.log(out.join(`
69069
69721
  `));
69070
69722
  }
69071
69723
 
69072
69724
  // src/cli/mcp.ts
69073
- var import_picocolors46 = __toESM(require_picocolors(), 1);
69725
+ var import_picocolors49 = __toESM(require_picocolors(), 1);
69074
69726
 
69075
69727
  // src/core/mcp-check/collect-servers.ts
69076
69728
  import path87 from "node:path";
69077
- import fs79 from "node:fs";
69729
+ import fs80 from "node:fs";
69078
69730
  function collectServers(cwd2, env3 = process.env) {
69079
69731
  const out = [];
69080
69732
  const seen = new Set;
@@ -69128,7 +69780,7 @@ function* readResolvedMcps(cwd2) {
69128
69780
  const p2 = path87.join(cwd2, ".brainbase", "resolved-mcps.json");
69129
69781
  let raw;
69130
69782
  try {
69131
- raw = fs79.readFileSync(p2, "utf-8");
69783
+ raw = fs80.readFileSync(p2, "utf-8");
69132
69784
  } catch {
69133
69785
  return;
69134
69786
  }
@@ -69188,10 +69840,19 @@ function classifyError(err) {
69188
69840
  }
69189
69841
  return "protocol_error";
69190
69842
  }
69843
+ var CREDENTIAL_NAMES = "(x-api-key|api[-_]?key|auth[-_]?token|access[-_]?token|private[-_]?token|secret)";
69191
69844
  var REDACTIONS = [
69192
69845
  [/https?:\/\/[^\s'"`]+/gi, "[url]"],
69193
69846
  [/Bearer\s+\S+/gi, "Bearer [redacted]"],
69194
- [/\bbb(?:pat|_live)_[A-Za-z0-9._-]+/g, "[redacted]"]
69847
+ [/\bbb(?:pat|_live)_[A-Za-z0-9._-]+/g, "[redacted]"],
69848
+ [
69849
+ new RegExp(`\\b${CREDENTIAL_NAMES}\\b([\\s:=]*)(["'])[^"']+\\3`, "gi"),
69850
+ "$1$2$3[redacted]$3"
69851
+ ],
69852
+ [
69853
+ new RegExp(`\\b${CREDENTIAL_NAMES}\\b(\\s*[:=]\\s*)["']?[^\\s,;"'}]+`, "gi"),
69854
+ "$1$2[redacted]"
69855
+ ]
69195
69856
  ];
69196
69857
  function redactSecrets2(msg) {
69197
69858
  let out = msg;
@@ -77318,11 +77979,11 @@ function withTimeout(inner, ms2, label) {
77318
77979
  function isTransient(status) {
77319
77980
  return status === "unreachable";
77320
77981
  }
77321
- async function probeWithConnector(server, connect, opts) {
77982
+ async function probeWithConnector(server, connect2, opts) {
77322
77983
  let lastErr;
77323
77984
  for (let attempt2 = 0;attempt2 < 2; attempt2++) {
77324
77985
  try {
77325
- const { toolCount } = await connect(server, opts.timeoutMs);
77986
+ const { toolCount } = await connect2(server, opts.timeoutMs);
77326
77987
  return { name: server.name, status: "ok", tool_count: toolCount, error: null };
77327
77988
  } catch (err) {
77328
77989
  lastErr = err;
@@ -77398,42 +78059,177 @@ async function runMcpCheck(cwd2, options) {
77398
78059
  }
77399
78060
  }));
77400
78061
  results.sort((a3, b4) => a3.name.localeCompare(b4.name));
77401
- const report = {
78062
+ const report2 = {
77402
78063
  check_status: deriveCheckStatus(results),
77403
78064
  servers: results
77404
78065
  };
77405
78066
  if (options.json) {
77406
- write(JSON.stringify(report) + `
78067
+ write(JSON.stringify(report2) + `
77407
78068
  `);
77408
78069
  } else {
77409
- write(renderHuman(report));
78070
+ write(renderHuman(report2));
77410
78071
  }
77411
- return { exitCode: 0, report };
78072
+ return { exitCode: 0, report: report2 };
77412
78073
  } catch (err) {
77413
78074
  writeErr(`brainbase mcp check failed to run: ${truncateError(err) ?? "unknown error"}
77414
78075
  `);
77415
78076
  return { exitCode: 1 };
77416
78077
  }
77417
78078
  }
77418
- function renderHuman(report) {
78079
+ function renderHuman(report2) {
77419
78080
  const lines = [];
77420
- if (report.check_status === "skipped") {
77421
- lines.push(import_picocolors46.default.dim("No MCP servers configured — nothing to check."));
78081
+ if (report2.check_status === "skipped") {
78082
+ lines.push(import_picocolors49.default.dim("No MCP servers configured — nothing to check."));
77422
78083
  return lines.join(`
77423
78084
  `) + `
77424
78085
  `;
77425
78086
  }
77426
- for (const s3 of report.servers) {
77427
- const mark = s3.status === "ok" ? import_picocolors46.default.green("✓") : s3.status === "auth_failed" ? import_picocolors46.default.red("✗") : import_picocolors46.default.yellow("⚠");
77428
- const detail = s3.status === "ok" ? import_picocolors46.default.dim(`${s3.tool_count} tool${s3.tool_count === 1 ? "" : "s"}`) : import_picocolors46.default.dim(s3.status + (s3.error ? ` — ${s3.error}` : ""));
78087
+ for (const s3 of report2.servers) {
78088
+ const mark = s3.status === "ok" ? import_picocolors49.default.green("✓") : s3.status === "auth_failed" ? import_picocolors49.default.red("✗") : import_picocolors49.default.yellow("⚠");
78089
+ const detail = s3.status === "ok" ? import_picocolors49.default.dim(`${s3.tool_count} tool${s3.tool_count === 1 ? "" : "s"}`) : import_picocolors49.default.dim(s3.status + (s3.error ? ` — ${s3.error}` : ""));
77429
78090
  lines.push(` ${mark} ${s3.name} ${detail}`);
77430
78091
  }
77431
- const summary = report.check_status === "ok" ? import_picocolors46.default.green("All MCP servers connected.") : import_picocolors46.default.yellow("Some MCP servers are unhealthy.");
78092
+ const summary = report2.check_status === "ok" ? import_picocolors49.default.green("All MCP servers connected.") : import_picocolors49.default.yellow("Some MCP servers are unhealthy.");
77432
78093
  lines.push("", summary);
77433
78094
  return lines.join(`
77434
78095
  `) + `
77435
78096
  `;
77436
78097
  }
78098
+ async function runMcpList(cwd2, options) {
78099
+ const write = options.write ?? ((s3) => process.stdout.write(s3));
78100
+ const writeErr = options.writeErr ?? ((s3) => process.stderr.write(s3));
78101
+ const fetchServers = options.fetchServers ?? ((id) => api.listAgentMcpServers(id));
78102
+ const resolveAgentId = options.resolveAgentId ?? ((dir) => readLink(dir)?.agent_id ?? null);
78103
+ const agentId = resolveAgentId(cwd2);
78104
+ if (!agentId) {
78105
+ if (options.json) {
78106
+ write(JSON.stringify({ linked: false, servers: [] }) + `
78107
+ `);
78108
+ } else {
78109
+ writeErr("This folder is not linked to any agent. Run `brainbase link` first.\n");
78110
+ }
78111
+ return 1;
78112
+ }
78113
+ let report2;
78114
+ try {
78115
+ report2 = await fetchServers(agentId);
78116
+ } catch (err) {
78117
+ if (options.json) {
78118
+ write(JSON.stringify({ error: err.message }) + `
78119
+ `);
78120
+ } else {
78121
+ writeErr(`brainbase mcp list failed: ${err.message}
78122
+ `);
78123
+ }
78124
+ return 1;
78125
+ }
78126
+ if (options.json) {
78127
+ write(JSON.stringify({ linked: true, ...sanitizeReport(report2) }) + `
78128
+ `);
78129
+ } else {
78130
+ write(renderServerList(report2.servers));
78131
+ }
78132
+ return 0;
78133
+ }
78134
+ function sanitizeReport(report2) {
78135
+ return {
78136
+ ...report2,
78137
+ servers: report2.servers.map((s3) => ({
78138
+ ...s3,
78139
+ url: sanitizeUrl(s3.url),
78140
+ command: sanitizeCommand(s3.command),
78141
+ last_error: s3.last_error ? truncateError(s3.last_error) : s3.last_error
78142
+ }))
78143
+ };
78144
+ }
78145
+ function sanitizeUrl(url2) {
78146
+ if (!url2)
78147
+ return url2;
78148
+ try {
78149
+ const parsed = new URL(url2);
78150
+ parsed.search = "";
78151
+ parsed.hash = "";
78152
+ parsed.username = "";
78153
+ parsed.password = "";
78154
+ return parsed.toString();
78155
+ } catch {
78156
+ return null;
78157
+ }
78158
+ }
78159
+ function sanitizeCommand(command) {
78160
+ if (!command)
78161
+ return command;
78162
+ return command.trim().split(/\s+/)[0] ?? null;
78163
+ }
78164
+ var AUTH_LABEL = {
78165
+ none: "",
78166
+ oauth_required: "needs authorization",
78167
+ oauth_connected: "authorized",
78168
+ oauth_expired: "authorization expired — reconnect"
78169
+ };
78170
+ var HEALTH_LABEL = {
78171
+ unreachable: "unreachable",
78172
+ protocol_error: "connection error",
78173
+ auth_failed: "last check failed to authenticate",
78174
+ expired: "last check saw an expired token",
78175
+ unknown: "last check inconclusive"
78176
+ };
78177
+ function healthLabel(server) {
78178
+ const status = server.last_status;
78179
+ if (!status || status === "ok")
78180
+ return;
78181
+ return HEALTH_LABEL[status] ?? `last check: ${status}`;
78182
+ }
78183
+ function isUnhealthy(server) {
78184
+ return Boolean(server.last_status) && server.last_status !== "ok";
78185
+ }
78186
+ function renderServerList(servers) {
78187
+ if (servers.length === 0) {
78188
+ return import_picocolors49.default.dim("No MCP servers configured for this agent.") + `
78189
+ `;
78190
+ }
78191
+ const lines = [""];
78192
+ for (const s3 of servers) {
78193
+ const mark = s3.auth === "oauth_expired" ? import_picocolors49.default.red("✗") : s3.auth === "oauth_required" || isUnhealthy(s3) ? import_picocolors49.default.yellow("!") : !s3.is_enabled ? import_picocolors49.default.dim("·") : import_picocolors49.default.green("✓");
78194
+ const bits = [s3.transport];
78195
+ if (!s3.is_enabled)
78196
+ bits.push("disabled");
78197
+ const label = AUTH_LABEL[s3.auth];
78198
+ if (label)
78199
+ bits.push(label);
78200
+ const health = healthLabel(s3);
78201
+ if (health)
78202
+ bits.push(health);
78203
+ const expiry = describeExpiry(s3);
78204
+ if (expiry)
78205
+ bits.push(expiry);
78206
+ lines.push(` ${mark} ${import_picocolors49.default.bold(s3.name)} ${import_picocolors49.default.dim(bits.join(" · "))}`);
78207
+ }
78208
+ if (servers.some((s3) => s3.auth === "oauth_required" || s3.auth === "oauth_expired")) {
78209
+ lines.push("", import_picocolors49.default.dim("Authorize OAuth-backed servers in the web app; the CLI cannot run that flow yet."));
78210
+ }
78211
+ lines.push("");
78212
+ return lines.join(`
78213
+ `);
78214
+ }
78215
+ var MAX_EXPIRY_DAYS = 90;
78216
+ function describeExpiry(server, now2 = Date.now()) {
78217
+ if (server.auth !== "oauth_connected" || !server.oauth_token_expires_at)
78218
+ return;
78219
+ const at3 = Date.parse(server.oauth_token_expires_at);
78220
+ if (!Number.isFinite(at3))
78221
+ return;
78222
+ const minutes = Math.round((at3 - now2) / 60000);
78223
+ if (minutes <= 0)
78224
+ return;
78225
+ if (minutes < 60)
78226
+ return `expires in ${minutes}m`;
78227
+ const hours = Math.round(minutes / 60);
78228
+ if (hours < 48)
78229
+ return `expires in ${hours}h`;
78230
+ const days = Math.round(hours / 24);
78231
+ return days > MAX_EXPIRY_DAYS ? `expires in >${MAX_EXPIRY_DAYS}d` : `expires in ${days}d`;
78232
+ }
77437
78233
  async function runMcp(cwd2, sub, _argv, options) {
77438
78234
  const writeErr = options.writeErr ?? ((s3) => process.stderr.write(s3));
77439
78235
  switch (sub) {
@@ -77441,17 +78237,19 @@ async function runMcp(cwd2, sub, _argv, options) {
77441
78237
  const { exitCode } = await runMcpCheck(cwd2, options);
77442
78238
  return exitCode;
77443
78239
  }
78240
+ case "list":
78241
+ return runMcpList(cwd2, options);
77444
78242
  default:
77445
78243
  writeErr(`Unknown mcp subcommand: ${sub ?? "(none)"}
77446
78244
  `);
77447
- writeErr(`Usage: brainbase mcp check [--json]
78245
+ writeErr(`Usage: brainbase mcp <check|list> [--json]
77448
78246
  `);
77449
78247
  return 1;
77450
78248
  }
77451
78249
  }
77452
78250
 
77453
78251
  // src/cli/task.ts
77454
- var import_picocolors47 = __toESM(require_picocolors(), 1);
78252
+ var import_picocolors50 = __toESM(require_picocolors(), 1);
77455
78253
 
77456
78254
  // src/cli/task-create.ts
77457
78255
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -77637,31 +78435,31 @@ async function runTask(cwd2, sub, args) {
77637
78435
  function printHelp4() {
77638
78436
  const out = [];
77639
78437
  out.push("");
77640
- out.push(` ${import_picocolors47.default.bold("brainbase task")} ${import_picocolors47.default.dim("<sub> [options]")}`);
78438
+ out.push(` ${import_picocolors50.default.bold("brainbase task")} ${import_picocolors50.default.dim("<sub> [options]")}`);
77641
78439
  out.push("");
77642
- out.push(` ${import_picocolors47.default.cyan("create")} ${import_picocolors47.default.dim("--message <text>")} ${import_picocolors47.default.dim("create a task and start its first run")}`);
78440
+ out.push(` ${import_picocolors50.default.cyan("create")} ${import_picocolors50.default.dim("--message <text>")} ${import_picocolors50.default.dim("create a task and start its first run")}`);
77643
78441
  out.push("");
77644
- out.push(` ${import_picocolors47.default.bold("create flags")}`);
77645
- out.push(` ${import_picocolors47.default.dim("--message <text>")} required first user message`);
77646
- out.push(` ${import_picocolors47.default.dim("--agent <id>")} override the claimed agent in brainbase.agent.yaml`);
77647
- out.push(` ${import_picocolors47.default.dim("--title <text>")} optional task title`);
77648
- out.push(` ${import_picocolors47.default.dim("--model <id>")} optional model override`);
77649
- out.push(` ${import_picocolors47.default.dim("--json")} print task_id, agent_id, and status as JSON`);
78442
+ out.push(` ${import_picocolors50.default.bold("create flags")}`);
78443
+ out.push(` ${import_picocolors50.default.dim("--message <text>")} required first user message`);
78444
+ out.push(` ${import_picocolors50.default.dim("--agent <id>")} override the claimed agent in brainbase.agent.yaml`);
78445
+ out.push(` ${import_picocolors50.default.dim("--title <text>")} optional task title`);
78446
+ out.push(` ${import_picocolors50.default.dim("--model <id>")} optional model override`);
78447
+ out.push(` ${import_picocolors50.default.dim("--json")} print task_id, agent_id, and status as JSON`);
77650
78448
  out.push("");
77651
- out.push(` ${import_picocolors47.default.dim("Flag-like values:")} use ${import_picocolors47.default.cyan("--flag=value")} or ${import_picocolors47.default.cyan("--flag -- <value>")}`);
78449
+ out.push(` ${import_picocolors50.default.dim("Flag-like values:")} use ${import_picocolors50.default.cyan("--flag=value")} or ${import_picocolors50.default.cyan("--flag -- <value>")}`);
77652
78450
  out.push("");
77653
78451
  console.log(out.join(`
77654
78452
  `));
77655
78453
  }
77656
78454
 
77657
78455
  // src/cli/benchmark.ts
77658
- var import_picocolors48 = __toESM(require_picocolors(), 1);
78456
+ var import_picocolors51 = __toESM(require_picocolors(), 1);
77659
78457
  import {
77660
78458
  execFileSync as execFileSync3,
77661
78459
  spawn as spawn5
77662
78460
  } from "node:child_process";
77663
78461
  import crypto7 from "node:crypto";
77664
- import fs81 from "node:fs";
78462
+ import fs82 from "node:fs";
77665
78463
  import os17 from "node:os";
77666
78464
  import path89 from "node:path";
77667
78465
 
@@ -77671,7 +78469,7 @@ import {
77671
78469
  spawn as spawn4
77672
78470
  } from "node:child_process";
77673
78471
  import crypto6 from "node:crypto";
77674
- import fs80 from "node:fs";
78472
+ import fs81 from "node:fs";
77675
78473
  import os16 from "node:os";
77676
78474
  import path88 from "node:path";
77677
78475
  import { pipeline as pipeline2 } from "node:stream/promises";
@@ -77921,19 +78719,19 @@ function canonicalFuturePath(input) {
77921
78719
  const resolved = path88.resolve(input);
77922
78720
  const suffix = [];
77923
78721
  let current = resolved;
77924
- while (!fs80.existsSync(current)) {
78722
+ while (!fs81.existsSync(current)) {
77925
78723
  const parent = path88.dirname(current);
77926
78724
  if (parent === current)
77927
78725
  break;
77928
78726
  suffix.unshift(path88.basename(current));
77929
78727
  current = parent;
77930
78728
  }
77931
- const canonicalBase = fs80.realpathSync(current);
78729
+ const canonicalBase = fs81.realpathSync(current);
77932
78730
  return path88.join(canonicalBase, ...suffix);
77933
78731
  }
77934
78732
  function validateRoots(spec) {
77935
78733
  const workspace = path88.resolve(spec.workspace_root);
77936
- if (!fs80.existsSync(workspace) || fs80.lstatSync(workspace).isSymbolicLink() || !fs80.lstatSync(workspace).isDirectory()) {
78734
+ if (!fs81.existsSync(workspace) || fs81.lstatSync(workspace).isSymbolicLink() || !fs81.lstatSync(workspace).isDirectory()) {
77937
78735
  throw new BenchmarkPhaseError("invalid_workspace_root", "workspace_root must be an existing real directory");
77938
78736
  }
77939
78737
  const canonicalWorkspace = canonicalFuturePath(workspace);
@@ -77942,7 +78740,7 @@ function validateRoots(spec) {
77942
78740
  if (staging !== expectedStaging) {
77943
78741
  throw new BenchmarkPhaseError("invalid_staging_root", `staging_root must be ${expectedStaging}`);
77944
78742
  }
77945
- if (!fs80.existsSync(staging) || fs80.lstatSync(staging).isSymbolicLink() || !fs80.lstatSync(staging).isDirectory() || fs80.realpathSync(staging) !== path88.join(canonicalWorkspace, ".brainbase", "benchmark", spec.attempt_id, "incoming")) {
78743
+ if (!fs81.existsSync(staging) || fs81.lstatSync(staging).isSymbolicLink() || !fs81.lstatSync(staging).isDirectory() || fs81.realpathSync(staging) !== path88.join(canonicalWorkspace, ".brainbase", "benchmark", spec.attempt_id, "incoming")) {
77946
78744
  throw new BenchmarkPhaseError("invalid_staging_root", "staging_root must be a real directory under workspace_root");
77947
78745
  }
77948
78746
  const canonicalLogs = validateExternalRoot("logs_root", spec.logs_root, canonicalWorkspace);
@@ -77958,7 +78756,7 @@ function validateExternalRoot(label, input, canonicalWorkspace) {
77958
78756
  if (candidate === path88.parse(candidate).root) {
77959
78757
  throw new BenchmarkPhaseError(`invalid_${label}`, `${label} cannot be a filesystem root`);
77960
78758
  }
77961
- if (fs80.existsSync(candidate) && fs80.lstatSync(candidate).isSymbolicLink()) {
78759
+ if (fs81.existsSync(candidate) && fs81.lstatSync(candidate).isSymbolicLink()) {
77962
78760
  throw new BenchmarkPhaseError(`invalid_${label}`, `${label} cannot be a symlink`);
77963
78761
  }
77964
78762
  const canonicalCandidate = canonicalFuturePath(candidate);
@@ -77988,9 +78786,9 @@ function assertNoSymlinkTraversal(root, relative) {
77988
78786
  let current = path88.resolve(root);
77989
78787
  for (const segment of rel.split("/").slice(0, -1)) {
77990
78788
  current = path88.join(current, segment);
77991
- if (!fs80.existsSync(current))
78789
+ if (!fs81.existsSync(current))
77992
78790
  continue;
77993
- if (fs80.lstatSync(current).isSymbolicLink()) {
78791
+ if (fs81.lstatSync(current).isSymbolicLink()) {
77994
78792
  throw new BenchmarkPhaseError("unsafe_path", `path traverses symlink: ${relative}`);
77995
78793
  }
77996
78794
  }
@@ -78000,9 +78798,9 @@ function assertOpenedFileWithinRoot(root, filePath, openedStat, label) {
78000
78798
  let canonicalFile;
78001
78799
  let currentStat;
78002
78800
  try {
78003
- canonicalRoot = fs80.realpathSync(root);
78004
- canonicalFile = fs80.realpathSync(filePath);
78005
- currentStat = fs80.statSync(filePath);
78801
+ canonicalRoot = fs81.realpathSync(root);
78802
+ canonicalFile = fs81.realpathSync(filePath);
78803
+ currentStat = fs81.statSync(filePath);
78006
78804
  } catch {
78007
78805
  throw new BenchmarkPhaseError("unsafe_path", `${label} changed while it was opened`);
78008
78806
  }
@@ -78011,10 +78809,10 @@ function assertOpenedFileWithinRoot(root, filePath, openedStat, label) {
78011
78809
  }
78012
78810
  }
78013
78811
  function openRegularFileNoFollow(filePath, label, root) {
78014
- const noFollow = typeof fs80.constants.O_NOFOLLOW === "number" ? fs80.constants.O_NOFOLLOW : 0;
78812
+ const noFollow = typeof fs81.constants.O_NOFOLLOW === "number" ? fs81.constants.O_NOFOLLOW : 0;
78015
78813
  let fd;
78016
78814
  try {
78017
- fd = fs80.openSync(filePath, fs80.constants.O_RDONLY | noFollow);
78815
+ fd = fs81.openSync(filePath, fs81.constants.O_RDONLY | noFollow);
78018
78816
  } catch (error2) {
78019
78817
  const code = error2.code;
78020
78818
  if (code === "ELOOP") {
@@ -78022,16 +78820,16 @@ function openRegularFileNoFollow(filePath, label, root) {
78022
78820
  }
78023
78821
  throw error2;
78024
78822
  }
78025
- const stat = fs80.fstatSync(fd);
78823
+ const stat = fs81.fstatSync(fd);
78026
78824
  if (!stat.isFile()) {
78027
- fs80.closeSync(fd);
78825
+ fs81.closeSync(fd);
78028
78826
  throw new BenchmarkPhaseError("invalid_input", `${label} must be a regular file`);
78029
78827
  }
78030
78828
  if (root) {
78031
78829
  try {
78032
78830
  assertOpenedFileWithinRoot(root, filePath, stat, label);
78033
78831
  } catch (error2) {
78034
- fs80.closeSync(fd);
78832
+ fs81.closeSync(fd);
78035
78833
  throw error2;
78036
78834
  }
78037
78835
  }
@@ -78039,7 +78837,7 @@ function openRegularFileNoFollow(filePath, label, root) {
78039
78837
  }
78040
78838
  async function sha256OfDescriptor(fd) {
78041
78839
  const hash = crypto6.createHash("sha256");
78042
- const stream = fs80.createReadStream("", {
78840
+ const stream = fs81.createReadStream("", {
78043
78841
  fd,
78044
78842
  autoClose: false,
78045
78843
  start: 0
@@ -78050,7 +78848,7 @@ async function sha256OfDescriptor(fd) {
78050
78848
  return hash.digest("hex");
78051
78849
  }
78052
78850
  function readDescriptor(fd) {
78053
- return fs80.readFileSync(fd);
78851
+ return fs81.readFileSync(fd);
78054
78852
  }
78055
78853
  function assertWritableDestination(root, relative) {
78056
78854
  const rel = normalizedRootRelative(relative);
@@ -78060,9 +78858,9 @@ function assertWritableDestination(root, relative) {
78060
78858
  const segments = rel.split("/");
78061
78859
  for (const segment of segments.slice(0, -1)) {
78062
78860
  current = path88.join(current, segment);
78063
- if (!fs80.existsSync(current))
78861
+ if (!fs81.existsSync(current))
78064
78862
  continue;
78065
- const stat = fs80.lstatSync(current);
78863
+ const stat = fs81.lstatSync(current);
78066
78864
  if (stat.isSymbolicLink()) {
78067
78865
  throw new BenchmarkPhaseError("unsafe_path", `path traverses symlink: ${relative}`);
78068
78866
  }
@@ -78071,7 +78869,7 @@ function assertWritableDestination(root, relative) {
78071
78869
  }
78072
78870
  }
78073
78871
  const destination = path88.resolve(root, rel);
78074
- if (fs80.existsSync(destination) && fs80.lstatSync(destination).isDirectory()) {
78872
+ if (fs81.existsSync(destination) && fs81.lstatSync(destination).isDirectory()) {
78075
78873
  throw new BenchmarkPhaseError("destination_conflict", `file destination is an existing directory: ${relative}`);
78076
78874
  }
78077
78875
  }
@@ -78103,7 +78901,7 @@ function sourcePath(stagingRoot, relative) {
78103
78901
  assertNoSymlinkTraversal(stagingRoot, rel);
78104
78902
  let stat;
78105
78903
  try {
78106
- stat = fs80.lstatSync(source);
78904
+ stat = fs81.lstatSync(source);
78107
78905
  } catch {
78108
78906
  throw new BenchmarkPhaseError("missing_input", `staged input does not exist: ${relative}`);
78109
78907
  }
@@ -78132,12 +78930,12 @@ async function verifyRecordsUnchanged(records, spec) {
78132
78930
  const relative = safeRelPath(record3.path);
78133
78931
  assertNoSymlinkTraversal(root, relative);
78134
78932
  const candidate = path88.resolve(root, relative);
78135
- if (!isWithin(root, candidate) || !fs80.existsSync(candidate)) {
78933
+ if (!isWithin(root, candidate) || !fs81.existsSync(candidate)) {
78136
78934
  throw new BenchmarkPhaseError("evidence_tampered", `evidence was removed during evaluation: ${record3.root}:${record3.path}`);
78137
78935
  }
78138
- const stat = fs80.lstatSync(candidate);
78936
+ const stat = fs81.lstatSync(candidate);
78139
78937
  if (record3.kind === "symlink") {
78140
- const target = stat.isSymbolicLink() ? fs80.readlinkSync(candidate) : null;
78938
+ const target = stat.isSymbolicLink() ? fs81.readlinkSync(candidate) : null;
78141
78939
  if (target === null || Buffer.byteLength(target) !== record3.size || sha256(target) !== record3.sha256) {
78142
78940
  throw new BenchmarkPhaseError("evidence_tampered", `evidence changed during evaluation: ${record3.root}:${record3.path}`);
78143
78941
  }
@@ -78152,7 +78950,7 @@ async function verifyRecordsUnchanged(records, spec) {
78152
78950
  throw new BenchmarkPhaseError("evidence_tampered", `evidence changed during evaluation: ${record3.root}:${record3.path}`);
78153
78951
  }
78154
78952
  } finally {
78155
- fs80.closeSync(opened.fd);
78953
+ fs81.closeSync(opened.fd);
78156
78954
  }
78157
78955
  }
78158
78956
  }
@@ -78168,35 +78966,35 @@ async function verifyInput(stagingRoot, material) {
78168
78966
  throw new BenchmarkPhaseError("digest_mismatch", `checksum mismatch for ${material.source}`, { expected: material.sha256, actual });
78169
78967
  }
78170
78968
  } finally {
78171
- fs80.closeSync(opened.fd);
78969
+ fs81.closeSync(opened.fd);
78172
78970
  }
78173
78971
  return source;
78174
78972
  }
78175
78973
  async function atomicCopy(source, destination, mode, sourceRoot) {
78176
- fs80.mkdirSync(path88.dirname(destination), { recursive: true });
78974
+ fs81.mkdirSync(path88.dirname(destination), { recursive: true });
78177
78975
  const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
78178
78976
  const opened = openRegularFileNoFollow(source, `copy source ${source}`, sourceRoot);
78179
78977
  try {
78180
- await pipeline2(fs80.createReadStream("", {
78978
+ await pipeline2(fs81.createReadStream("", {
78181
78979
  fd: opened.fd,
78182
78980
  autoClose: false,
78183
78981
  start: 0
78184
- }), fs80.createWriteStream(temporary, {
78982
+ }), fs81.createWriteStream(temporary, {
78185
78983
  flags: "wx",
78186
78984
  mode: 384
78187
78985
  }));
78188
- fs80.chmodSync(temporary, mode ?? opened.stat.mode & 511);
78189
- fs80.renameSync(temporary, destination);
78986
+ fs81.chmodSync(temporary, mode ?? opened.stat.mode & 511);
78987
+ fs81.renameSync(temporary, destination);
78190
78988
  } finally {
78191
- fs80.closeSync(opened.fd);
78192
- fs80.rmSync(temporary, { force: true });
78989
+ fs81.closeSync(opened.fd);
78990
+ fs81.rmSync(temporary, { force: true });
78193
78991
  }
78194
78992
  }
78195
78993
  async function recordFile(root, filePath, rootName, kind = "file") {
78196
78994
  const relative = path88.relative(root, filePath).replace(/\\/g, "/");
78197
78995
  if (kind === "symlink") {
78198
- const stat = fs80.lstatSync(filePath);
78199
- const target = fs80.readlinkSync(filePath);
78996
+ const stat = fs81.lstatSync(filePath);
78997
+ const target = fs81.readlinkSync(filePath);
78200
78998
  return {
78201
78999
  root: rootName,
78202
79000
  path: relative,
@@ -78216,7 +79014,7 @@ async function recordFile(root, filePath, rootName, kind = "file") {
78216
79014
  mode: opened.stat.mode & 511
78217
79015
  };
78218
79016
  } finally {
78219
- fs80.closeSync(opened.fd);
79017
+ fs81.closeSync(opened.fd);
78220
79018
  }
78221
79019
  }
78222
79020
  async function copyMaterial(material, sourceRoot, destinationRoot, destinationRootName, protectWorkspace) {
@@ -78238,7 +79036,7 @@ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRo
78238
79036
  }
78239
79037
  return [record3];
78240
79038
  }
78241
- const temporary = fs80.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-"));
79039
+ const temporary = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-"));
78242
79040
  try {
78243
79041
  const verifiedArchive = path88.join(temporary, "material.tar.gz");
78244
79042
  await atomicCopy(source, verifiedArchive, 384, sourceRoot);
@@ -78256,7 +79054,7 @@ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRo
78256
79054
  const outputs = [];
78257
79055
  for (const extractedRel of extracted.sort()) {
78258
79056
  const sourceFile = path88.resolve(extractedRoot, safeRelPath(extractedRel));
78259
- const stat = fs80.lstatSync(sourceFile);
79057
+ const stat = fs81.lstatSync(sourceFile);
78260
79058
  if (!stat.isFile())
78261
79059
  continue;
78262
79060
  const combined = destinationRel === "." ? safeRelPath(extractedRel) : safeRelPath(path88.posix.join(destinationRel, extractedRel));
@@ -78271,7 +79069,7 @@ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRo
78271
79069
  }
78272
79070
  return outputs;
78273
79071
  } finally {
78274
- fs80.rmSync(temporary, { recursive: true, force: true });
79072
+ fs81.rmSync(temporary, { recursive: true, force: true });
78275
79073
  }
78276
79074
  }
78277
79075
  async function preflightMaterial(material, sourceRoot, destinationRoot, protectWorkspace) {
@@ -78287,7 +79085,7 @@ async function preflightMaterial(material, sourceRoot, destinationRoot, protectW
78287
79085
  assertWritableDestination(destinationRoot, destinationRel);
78288
79086
  return [destinationRel];
78289
79087
  }
78290
- const temporary = fs80.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-preflight-"));
79088
+ const temporary = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-preflight-"));
78291
79089
  try {
78292
79090
  const verifiedArchive = path88.join(temporary, "material.tar.gz");
78293
79091
  await atomicCopy(source, verifiedArchive, 384, sourceRoot);
@@ -78314,34 +79112,34 @@ async function preflightMaterial(material, sourceRoot, destinationRoot, protectW
78314
79112
  }
78315
79113
  return planned;
78316
79114
  } finally {
78317
- fs80.rmSync(temporary, { recursive: true, force: true });
79115
+ fs81.rmSync(temporary, { recursive: true, force: true });
78318
79116
  }
78319
79117
  }
78320
79118
  function ownerMarker(root) {
78321
79119
  return path88.join(root, ".brainbase-benchmark-owner.json");
78322
79120
  }
78323
79121
  function verifyOwnedDirectory(root, role, spec) {
78324
- if (!fs80.existsSync(root) || fs80.lstatSync(root).isSymbolicLink())
79122
+ if (!fs81.existsSync(root) || fs81.lstatSync(root).isSymbolicLink())
78325
79123
  return false;
78326
79124
  try {
78327
- const marker = JSON.parse(fs80.readFileSync(ownerMarker(root), "utf8"));
79125
+ const marker = JSON.parse(fs81.readFileSync(ownerMarker(root), "utf8"));
78328
79126
  return marker.attempt_id === spec.attempt_id && marker.phase === spec.phase && marker.phase_id === spec.phase_id && marker.role === role;
78329
79127
  } catch {
78330
79128
  return false;
78331
79129
  }
78332
79130
  }
78333
79131
  function prepareOwnedDirectory(root, role, spec) {
78334
- if (fs80.existsSync(root)) {
79132
+ if (fs81.existsSync(root)) {
78335
79133
  if (!verifyOwnedDirectory(root, role, spec)) {
78336
- const stat = fs80.lstatSync(root);
78337
- if (!stat.isDirectory() || fs80.readdirSync(root).length > 0) {
79134
+ const stat = fs81.lstatSync(root);
79135
+ if (!stat.isDirectory() || fs81.readdirSync(root).length > 0) {
78338
79136
  throw new BenchmarkPhaseError(`unowned_${role}_root`, `${role}_root exists without a matching attempt ownership marker`);
78339
79137
  }
78340
79138
  } else {
78341
- fs80.rmSync(root, { recursive: true, force: true });
79139
+ fs81.rmSync(root, { recursive: true, force: true });
78342
79140
  }
78343
79141
  }
78344
- fs80.mkdirSync(root, { recursive: true, mode: 448 });
79142
+ fs81.mkdirSync(root, { recursive: true, mode: 448 });
78345
79143
  writeJsonAtomic(ownerMarker(root), {
78346
79144
  schema_version: SCHEMA_VERSION,
78347
79145
  attempt_id: spec.attempt_id,
@@ -78433,7 +79231,7 @@ async function runCommand(command, root, spec, context, additions = {}) {
78433
79231
  const cwd2 = path88.resolve(root, cwdRel);
78434
79232
  let cwdStat;
78435
79233
  try {
78436
- cwdStat = fs80.lstatSync(cwd2);
79234
+ cwdStat = fs81.lstatSync(cwd2);
78437
79235
  } catch {
78438
79236
  throw new BenchmarkPhaseError("invalid_command_cwd", `command cwd is invalid: ${command.cwd}`);
78439
79237
  }
@@ -78505,27 +79303,27 @@ async function runCommand(command, root, spec, context, additions = {}) {
78505
79303
  }
78506
79304
  async function writeLog(root, name, data, spec) {
78507
79305
  const destination = path88.join(root, name);
78508
- fs80.mkdirSync(path88.dirname(destination), { recursive: true });
79306
+ fs81.mkdirSync(path88.dirname(destination), { recursive: true });
78509
79307
  const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
78510
79308
  try {
78511
- fs80.writeFileSync(temporary, redactCommandOutput(data, spec), {
79309
+ fs81.writeFileSync(temporary, redactCommandOutput(data, spec), {
78512
79310
  flag: "wx",
78513
79311
  mode: 384
78514
79312
  });
78515
- fs80.renameSync(temporary, destination);
79313
+ fs81.renameSync(temporary, destination);
78516
79314
  } finally {
78517
- fs80.rmSync(temporary, { force: true });
79315
+ fs81.rmSync(temporary, { force: true });
78518
79316
  }
78519
79317
  return await recordFile(root, destination, "logs");
78520
79318
  }
78521
79319
  function writeBufferAtomic(destination, data) {
78522
- fs80.mkdirSync(path88.dirname(destination), { recursive: true });
79320
+ fs81.mkdirSync(path88.dirname(destination), { recursive: true });
78523
79321
  const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
78524
79322
  try {
78525
- fs80.writeFileSync(temporary, data, { flag: "wx", mode: 384 });
78526
- fs80.renameSync(temporary, destination);
79323
+ fs81.writeFileSync(temporary, data, { flag: "wx", mode: 384 });
79324
+ fs81.renameSync(temporary, destination);
78527
79325
  } finally {
78528
- fs80.rmSync(temporary, { force: true });
79326
+ fs81.rmSync(temporary, { force: true });
78529
79327
  }
78530
79328
  }
78531
79329
  function assertBudget(context) {
@@ -78534,7 +79332,7 @@ function assertBudget(context) {
78534
79332
  }
78535
79333
  }
78536
79334
  async function executeHydrate(spec, context) {
78537
- fs80.mkdirSync(spec.workspace_root, { recursive: true });
79335
+ fs81.mkdirSync(spec.workspace_root, { recursive: true });
78538
79336
  prepareOwnedDirectory(spec.logs_root, "logs", spec);
78539
79337
  context.logsOwned = true;
78540
79338
  const outputs = [];
@@ -78615,9 +79413,9 @@ async function executeHydrate(spec, context) {
78615
79413
  }
78616
79414
  const candidate = path88.resolve(spec.workspace_root, safeRelPath(output.path));
78617
79415
  assertNoSymlinkTraversal(spec.workspace_root, output.path);
78618
- if (!fs80.existsSync(candidate))
79416
+ if (!fs81.existsSync(candidate))
78619
79417
  continue;
78620
- const stat = fs80.lstatSync(candidate);
79418
+ const stat = fs81.lstatSync(candidate);
78621
79419
  if (!stat.isFile() && !stat.isSymbolicLink())
78622
79420
  continue;
78623
79421
  finalOutputs.push(await recordFile(spec.workspace_root, candidate, "workspace", stat.isSymbolicLink() ? "symlink" : "file"));
@@ -78651,7 +79449,7 @@ async function readEvidence(stagingRoot, evidence) {
78651
79449
  }
78652
79450
  };
78653
79451
  } finally {
78654
- fs80.closeSync(opened.fd);
79452
+ fs81.closeSync(opened.fd);
78655
79453
  }
78656
79454
  }
78657
79455
  async function workspaceManifest(spec, context) {
@@ -78660,7 +79458,7 @@ async function workspaceManifest(spec, context) {
78660
79458
  const stack = [path88.resolve(spec.workspace_root)];
78661
79459
  while (stack.length > 0) {
78662
79460
  const directory = stack.pop();
78663
- const entries = fs80.readdirSync(directory, { withFileTypes: true }).sort((a3, b4) => a3.name.localeCompare(b4.name));
79461
+ const entries = fs81.readdirSync(directory, { withFileTypes: true }).sort((a3, b4) => a3.name.localeCompare(b4.name));
78664
79462
  for (const entry of entries) {
78665
79463
  assertBudget(context);
78666
79464
  const full = path88.join(directory, entry.name);
@@ -78769,7 +79567,7 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
78769
79567
  const candidate = path88.resolve(spec.workspace_root, relative);
78770
79568
  let stat = null;
78771
79569
  try {
78772
- stat = fs80.lstatSync(candidate);
79570
+ stat = fs81.lstatSync(candidate);
78773
79571
  } catch (error2) {
78774
79572
  const code = error2.code;
78775
79573
  if (code !== "ENOENT" && code !== "ENOTDIR")
@@ -78790,7 +79588,7 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
78790
79588
  try {
78791
79589
  verdict2 = await sha256OfDescriptor(opened.fd) === evaluator.assertion.expected;
78792
79590
  } finally {
78793
- fs80.closeSync(opened.fd);
79591
+ fs81.closeSync(opened.fd);
78794
79592
  }
78795
79593
  }
78796
79594
  }
@@ -78800,7 +79598,7 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
78800
79598
  try {
78801
79599
  verdict2 = readDescriptor(opened.fd).toString("utf8").includes(evaluator.assertion.expected);
78802
79600
  } finally {
78803
- fs80.closeSync(opened.fd);
79601
+ fs81.closeSync(opened.fd);
78804
79602
  }
78805
79603
  }
78806
79604
  }
@@ -78881,7 +79679,7 @@ async function executeEvaluate(spec, context) {
78881
79679
  assertNoSymlinkTraversal(spec.workspace_root, artifactRel);
78882
79680
  const source = path88.resolve(spec.workspace_root, artifactRel);
78883
79681
  const frozenArtifact = manifest.find((entry) => entry.path === artifactRel && entry.kind !== "symlink");
78884
- if (!frozenArtifact || !fs80.existsSync(source) || !fs80.lstatSync(source).isFile()) {
79682
+ if (!frozenArtifact || !fs81.existsSync(source) || !fs81.lstatSync(source).isFile()) {
78885
79683
  throw new BenchmarkPhaseError("missing_artifact", `candidate artifact is missing: ${artifactRel}`);
78886
79684
  }
78887
79685
  const destination = path88.resolve(spec.logs_root, "candidate-artifacts", artifactRel);
@@ -78899,9 +79697,9 @@ async function executeEvaluate(spec, context) {
78899
79697
  const temporary = `${archive}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
78900
79698
  try {
78901
79699
  await pack({ rootDir: spec.workspace_root, outFile: temporary, files: regularFiles });
78902
- fs80.renameSync(temporary, archive);
79700
+ fs81.renameSync(temporary, archive);
78903
79701
  } finally {
78904
- fs80.rmSync(temporary, { force: true });
79702
+ fs81.rmSync(temporary, { force: true });
78905
79703
  }
78906
79704
  const archiveRecord = await recordFile(spec.logs_root, archive, "logs");
78907
79705
  outputs.push(archiveRecord);
@@ -79001,21 +79799,21 @@ function rawIdentity(value) {
79001
79799
  }
79002
79800
  function readSpecBytes(specPathInput) {
79003
79801
  const specPath = path88.resolve(specPathInput);
79004
- const noFollow = typeof fs80.constants.O_NOFOLLOW === "number" ? fs80.constants.O_NOFOLLOW : 0;
79802
+ const noFollow = typeof fs81.constants.O_NOFOLLOW === "number" ? fs81.constants.O_NOFOLLOW : 0;
79005
79803
  let fd;
79006
79804
  try {
79007
- fd = fs80.openSync(specPath, fs80.constants.O_RDONLY | noFollow);
79805
+ fd = fs81.openSync(specPath, fs81.constants.O_RDONLY | noFollow);
79008
79806
  } catch {
79009
79807
  throw new BenchmarkPhaseError("spec_read_failed", "spec file could not be read");
79010
79808
  }
79011
79809
  try {
79012
- const stat = fs80.fstatSync(fd);
79810
+ const stat = fs81.fstatSync(fd);
79013
79811
  if (!stat.isFile() || stat.size > MAX_SPEC_BYTES) {
79014
79812
  throw new BenchmarkPhaseError("invalid_spec_file", "spec must be a regular JSON file no larger than 20 MiB");
79015
79813
  }
79016
79814
  return readDescriptor(fd);
79017
79815
  } finally {
79018
- fs80.closeSync(fd);
79816
+ fs81.closeSync(fd);
79019
79817
  }
79020
79818
  }
79021
79819
  function validateBenchmarkInvocationBytes(bytes, resultPathInput, expectedPhase) {
@@ -79059,9 +79857,9 @@ function prepareBenchmarkPhaseInvocation(specPathInput, resultPathInput, expecte
79059
79857
  spec_digest: digest,
79060
79858
  timeout_ms: spec.budget.timeout_ms
79061
79859
  };
79062
- if (fs80.existsSync(resultPath)) {
79860
+ if (fs81.existsSync(resultPath)) {
79063
79861
  try {
79064
- const cached2 = JSON.parse(fs80.readFileSync(resultPath, "utf8"));
79862
+ const cached2 = JSON.parse(fs81.readFileSync(resultPath, "utf8"));
79065
79863
  if (cached2.schema_version === SCHEMA_VERSION && cached2.phase === spec.phase && cached2.attempt_id === spec.attempt_id && cached2.phase_id === spec.phase_id && cached2.spec_digest === digest && cached2.status === "succeeded") {
79066
79864
  return {
79067
79865
  ok: true,
@@ -79168,9 +79966,9 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
79168
79966
  throw new BenchmarkPhaseError("invalid_result_path", `result path must be ${expectedResultPath}`);
79169
79967
  }
79170
79968
  resultPathValidated = true;
79171
- if (fs80.existsSync(resultPath)) {
79969
+ if (fs81.existsSync(resultPath)) {
79172
79970
  try {
79173
- const cached2 = JSON.parse(fs80.readFileSync(resultPath, "utf8"));
79971
+ const cached2 = JSON.parse(fs81.readFileSync(resultPath, "utf8"));
79174
79972
  if (cached2.schema_version === SCHEMA_VERSION && cached2.phase === spec.phase && cached2.attempt_id === spec.attempt_id && cached2.phase_id === spec.phase_id && cached2.spec_digest === digest && cached2.status === "succeeded") {
79175
79973
  return { exitCode: 0, result: cached2 };
79176
79974
  }
@@ -79367,13 +80165,13 @@ function terminatePhase(child) {
79367
80165
  }
79368
80166
  function createAnonymousSpecFd(bytes) {
79369
80167
  const temporary = path89.join(os17.tmpdir(), `brainbase-benchmark-spec-${process.pid}-${crypto7.randomBytes(12).toString("hex")}`);
79370
- fs81.writeFileSync(temporary, bytes, { flag: "wx", mode: 384 });
80168
+ fs82.writeFileSync(temporary, bytes, { flag: "wx", mode: 384 });
79371
80169
  try {
79372
- const fd = fs81.openSync(temporary, "r");
79373
- fs81.unlinkSync(temporary);
80170
+ const fd = fs82.openSync(temporary, "r");
80171
+ fs82.unlinkSync(temporary);
79374
80172
  return fd;
79375
80173
  } catch (error2) {
79376
- fs81.rmSync(temporary, { force: true });
80174
+ fs82.rmSync(temporary, { force: true });
79377
80175
  throw error2;
79378
80176
  }
79379
80177
  }
@@ -79442,13 +80240,13 @@ async function runSupervisedPhase(phase, parsed, write) {
79442
80240
  detached: process.platform !== "win32"
79443
80241
  });
79444
80242
  } catch {
79445
- fs81.closeSync(specFd);
80243
+ fs82.closeSync(specFd);
79446
80244
  const failure = phaseFailure(invocation, startedAt, started, "phase_supervisor_failed", "benchmark phase child process could not be started");
79447
80245
  write(`${JSON.stringify(failure)}
79448
80246
  `);
79449
80247
  return 1;
79450
80248
  }
79451
- fs81.closeSync(specFd);
80249
+ fs82.closeSync(specFd);
79452
80250
  return await new Promise((resolve) => {
79453
80251
  const stdout = [];
79454
80252
  let settled = false;
@@ -79530,7 +80328,7 @@ async function runBenchmark(sub, args, write = (value) => process.stdout.write(v
79530
80328
  if (phase !== "hydrate" && phase !== "evaluate" || resultFlag !== "--result" || !resultPath || specFdFlag !== "--spec-fd" || !Number.isInteger(specFd) || specFd < 3 || tokenFlag !== "--token" || !token || token !== process.env.BRAINBASE_BENCHMARK_PHASE_CHILD_TOKEN) {
79531
80329
  throw new Error("Invalid internal benchmark phase invocation");
79532
80330
  }
79533
- const specBytes = fs81.readFileSync(specFd);
80331
+ const specBytes = fs82.readFileSync(specFd);
79534
80332
  const { exitCode, result: result2 } = await runBenchmarkPhase("", resultPath, phase, specBytes);
79535
80333
  write(`${JSON.stringify(result2)}
79536
80334
  `);
@@ -79570,13 +80368,13 @@ async function runBenchmark(sub, args, write = (value) => process.stdout.write(v
79570
80368
  function printHelp5() {
79571
80369
  const out = [];
79572
80370
  out.push("");
79573
- out.push(` ${import_picocolors48.default.bold("brainbase benchmark")} ${import_picocolors48.default.dim("<sub> [options]")}`);
80371
+ out.push(` ${import_picocolors51.default.bold("brainbase benchmark")} ${import_picocolors51.default.dim("<sub> [options]")}`);
79574
80372
  out.push("");
79575
- out.push(` ${import_picocolors48.default.cyan("hydrate")} ${import_picocolors48.default.dim("--spec <path> --result <path> --json")}`);
79576
- out.push(` ${import_picocolors48.default.cyan("evaluate")} ${import_picocolors48.default.dim("--spec <path> --result <path> --json")}`);
79577
- out.push(` ${import_picocolors48.default.cyan("capabilities")} ${import_picocolors48.default.dim("--json")}`);
80373
+ out.push(` ${import_picocolors51.default.cyan("hydrate")} ${import_picocolors51.default.dim("--spec <path> --result <path> --json")}`);
80374
+ out.push(` ${import_picocolors51.default.cyan("evaluate")} ${import_picocolors51.default.dim("--spec <path> --result <path> --json")}`);
80375
+ out.push(` ${import_picocolors51.default.cyan("capabilities")} ${import_picocolors51.default.dim("--json")}`);
79578
80376
  out.push("");
79579
- out.push(` ${import_picocolors48.default.dim("These machine-only commands execute versioned benchmark phase specs inside a task sandbox.")}`);
80377
+ out.push(` ${import_picocolors51.default.dim("These machine-only commands execute versioned benchmark phase specs inside a task sandbox.")}`);
79580
80378
  out.push("");
79581
80379
  console.log(out.join(`
79582
80380
  `));
@@ -79603,130 +80401,137 @@ var SUBCOMMAND_OWNED_FLAGS = {
79603
80401
  function help() {
79604
80402
  const out = [];
79605
80403
  out.push("");
79606
- out.push(` ${brandTint("◆")} ${import_picocolors49.default.bold("brainbase")} ${import_picocolors49.default.dim(`v${VERSION}`)}`);
79607
- out.push(` ${import_picocolors49.default.dim("connect your local agent to the brainbase platform")}`);
80404
+ out.push(` ${brandTint("◆")} ${import_picocolors52.default.bold("brainbase")} ${import_picocolors52.default.dim(`v${VERSION}`)}`);
80405
+ out.push(` ${import_picocolors52.default.dim("connect your local agent to the brainbase platform")}`);
79608
80406
  out.push("");
79609
80407
  out.push(divider("USAGE"));
79610
80408
  out.push("");
79611
- out.push(` ${import_picocolors49.default.bold("brainbase")} ${import_picocolors49.default.dim("<command> [options]")}`);
80409
+ out.push(` ${import_picocolors52.default.bold("brainbase")} ${import_picocolors52.default.dim("<command> [options]")}`);
79612
80410
  out.push("");
79613
80411
  out.push(divider("AUTH"));
79614
80412
  out.push("");
79615
- out.push(` ${import_picocolors49.default.cyan("login")} ${import_picocolors49.default.dim(" open the web app and connect this device")}`);
79616
- out.push(` ${import_picocolors49.default.cyan("logout")} ${import_picocolors49.default.dim(" clear the local session")}`);
79617
- out.push(` ${import_picocolors49.default.cyan("whoami")} ${import_picocolors49.default.dim(" show the current user")}`);
80413
+ out.push(` ${import_picocolors52.default.cyan("login")} ${import_picocolors52.default.dim(" open the web app and connect this device")}`);
80414
+ out.push(` ${import_picocolors52.default.cyan("logout")} ${import_picocolors52.default.dim(" clear the local session")}`);
80415
+ out.push(` ${import_picocolors52.default.cyan("whoami")} ${import_picocolors52.default.dim("[--json]")} ${import_picocolors52.default.dim(" show which credential is in use and what it covers")}`);
79618
80416
  out.push("");
79619
80417
  out.push(divider("DISCOVERY"));
79620
80418
  out.push("");
79621
- out.push(` ${import_picocolors49.default.cyan("team list")} ${import_picocolors49.default.dim("show the teams you can create agents in")}`);
79622
- out.push(` ${import_picocolors49.default.cyan("agent list")} ${import_picocolors49.default.dim("show a team's agents and their ids")}`);
80419
+ out.push(` ${import_picocolors52.default.cyan("team list")} ${import_picocolors52.default.dim("show the teams you can create agents in")}`);
80420
+ out.push(` ${import_picocolors52.default.cyan("agent list")} ${import_picocolors52.default.dim("show a team's agents and their ids")}`);
79623
80421
  out.push("");
79624
80422
  out.push(divider("LINKED AGENT"));
79625
80423
  out.push("");
79626
- out.push(` ${import_picocolors49.default.cyan("agent create")} ${import_picocolors49.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
79627
- out.push(` ${import_picocolors49.default.cyan("agent pull")} ${import_picocolors49.default.dim("[<id>]")} ${import_picocolors49.default.dim("bring cloud changes into this folder (--force to override; --run-entrypoint to also execute the agent entrypoint)")}`);
79628
- out.push(` ${import_picocolors49.default.cyan("agent push")} ${import_picocolors49.default.dim("send local changes to the cloud (--force to overwrite cloud-side conflicts with local)")}`);
79629
- out.push(` ${import_picocolors49.default.cyan("agent unpack")} ${import_picocolors49.default.dim("install the claimed agent into a harness layout")}`);
79630
- out.push(` ${import_picocolors49.default.cyan("link")} ${import_picocolors49.default.dim("attach this folder to an existing agent")}`);
79631
- out.push(` ${import_picocolors49.default.cyan("agent status")} ${import_picocolors49.default.dim("show what would pull and what would push")}`);
79632
- out.push(` ${import_picocolors49.default.cyan("agent env")} ${import_picocolors49.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
79633
- out.push(` ${import_picocolors49.default.cyan("run")} ${import_picocolors49.default.dim("<cmd> [args...]")} ${import_picocolors49.default.dim("run <cmd> with secrets.env loaded into env")}`);
79634
- out.push(` ${import_picocolors49.default.cyan("status")} ${import_picocolors49.default.dim("show what this folder is linked to")}`);
79635
- out.push(` ${import_picocolors49.default.cyan("unlink")} ${import_picocolors49.default.dim("disconnect this folder")}`);
80424
+ out.push(` ${import_picocolors52.default.cyan("agent create")} ${import_picocolors52.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
80425
+ out.push(` ${import_picocolors52.default.cyan("agent pull")} ${import_picocolors52.default.dim("[<id>]")} ${import_picocolors52.default.dim("bring cloud changes into this folder (--force to override; --run-entrypoint to also execute the agent entrypoint)")}`);
80426
+ out.push(` ${import_picocolors52.default.cyan("agent push")} ${import_picocolors52.default.dim("send local changes to the cloud (--force to overwrite cloud-side conflicts with local)")}`);
80427
+ out.push(` ${import_picocolors52.default.cyan("agent unpack")} ${import_picocolors52.default.dim("install the claimed agent into a harness layout")}`);
80428
+ out.push(` ${import_picocolors52.default.cyan("link")} ${import_picocolors52.default.dim("attach this folder to an existing agent")}`);
80429
+ out.push(` ${import_picocolors52.default.cyan("agent status")} ${import_picocolors52.default.dim("show what would pull and what would push")}`);
80430
+ out.push(` ${import_picocolors52.default.cyan("agent connections")} ${import_picocolors52.default.dim("show which integrations this agent is wired to (--json for CI)")}`);
80431
+ out.push(` ${import_picocolors52.default.cyan("agent connect")} ${import_picocolors52.default.dim("<name>")} ${import_picocolors52.default.dim("connect slack or meeting from the terminal")}`);
80432
+ out.push(` ${import_picocolors52.default.cyan("agent disconnect")} ${import_picocolors52.default.dim("<name>")} ${import_picocolors52.default.dim("revoke a slack or meeting install")}`);
80433
+ out.push(` ${import_picocolors52.default.cyan("agent env")} ${import_picocolors52.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
80434
+ out.push(` ${import_picocolors52.default.cyan("run")} ${import_picocolors52.default.dim("<cmd> [args...]")} ${import_picocolors52.default.dim("run <cmd> with secrets.env loaded into env")}`);
80435
+ out.push(` ${import_picocolors52.default.cyan("status")} ${import_picocolors52.default.dim("show what this folder is linked to")}`);
80436
+ out.push(` ${import_picocolors52.default.cyan("unlink")} ${import_picocolors52.default.dim("disconnect this folder")}`);
79636
80437
  out.push("");
79637
80438
  out.push(divider("TASKS"));
79638
80439
  out.push("");
79639
- out.push(` ${import_picocolors49.default.cyan("task create")} ${import_picocolors49.default.dim("--message <text>")} ${import_picocolors49.default.dim("create a managed task and start its first run")}`);
80440
+ out.push(` ${import_picocolors52.default.cyan("task create")} ${import_picocolors52.default.dim("--message <text>")} ${import_picocolors52.default.dim("create a managed task and start its first run")}`);
79640
80441
  out.push("");
79641
80442
  out.push(divider("BENCHMARK RUNTIME"));
79642
80443
  out.push("");
79643
- out.push(` ${import_picocolors49.default.cyan("benchmark hydrate")} ${import_picocolors49.default.dim("--spec <path> --result <path> --json")}`);
79644
- out.push(` ${import_picocolors49.default.cyan("benchmark evaluate")} ${import_picocolors49.default.dim("--spec <path> --result <path> --json")}`);
79645
- out.push(` ${import_picocolors49.default.cyan("benchmark capabilities")} ${import_picocolors49.default.dim("--json")}`);
80444
+ out.push(` ${import_picocolors52.default.cyan("benchmark hydrate")} ${import_picocolors52.default.dim("--spec <path> --result <path> --json")}`);
80445
+ out.push(` ${import_picocolors52.default.cyan("benchmark evaluate")} ${import_picocolors52.default.dim("--spec <path> --result <path> --json")}`);
80446
+ out.push(` ${import_picocolors52.default.cyan("benchmark capabilities")} ${import_picocolors52.default.dim("--json")}`);
79646
80447
  out.push("");
79647
80448
  out.push(divider("ORCHESTRATIONS"));
79648
80449
  out.push("");
79649
- out.push(` ${import_picocolors49.default.cyan("orchestration create")} ${import_picocolors49.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
79650
- out.push(` ${import_picocolors49.default.cyan("orchestration list")} ${import_picocolors49.default.dim("list orchestrations under a team")}`);
79651
- out.push(` ${import_picocolors49.default.cyan("orchestration pull")} ${import_picocolors49.default.dim("<id>")} ${import_picocolors49.default.dim("recursively fetch an orchestration + every member agent")}`);
79652
- out.push(` ${import_picocolors49.default.cyan("orchestration push")} ${import_picocolors49.default.dim("recursively push each member, then update the graph")}`);
79653
- out.push(` ${import_picocolors49.default.cyan("orchestration status")} ${import_picocolors49.default.dim("show what would push and what would pull")}`);
80450
+ out.push(` ${import_picocolors52.default.cyan("orchestration create")} ${import_picocolors52.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
80451
+ out.push(` ${import_picocolors52.default.cyan("orchestration list")} ${import_picocolors52.default.dim("list orchestrations under a team")}`);
80452
+ out.push(` ${import_picocolors52.default.cyan("orchestration pull")} ${import_picocolors52.default.dim("<id>")} ${import_picocolors52.default.dim("recursively fetch an orchestration + every member agent")}`);
80453
+ out.push(` ${import_picocolors52.default.cyan("orchestration push")} ${import_picocolors52.default.dim("recursively push each member, then update the graph")}`);
80454
+ out.push(` ${import_picocolors52.default.cyan("orchestration status")} ${import_picocolors52.default.dim("show what would push and what would pull")}`);
79654
80455
  out.push("");
79655
80456
  out.push(divider("TEMPLATES"));
79656
80457
  out.push("");
79657
- out.push(` ${import_picocolors49.default.cyan("template pack")} ${import_picocolors49.default.dim("bundle the current agent into a template")}`);
79658
- out.push(` ${import_picocolors49.default.cyan("template publish")} ${import_picocolors49.default.dim("upload a template to the registry")}`);
79659
- out.push(` ${import_picocolors49.default.cyan("template search")} ${import_picocolors49.default.dim("[query]")} ${import_picocolors49.default.dim("search the registry")}`);
79660
- out.push(` ${import_picocolors49.default.cyan("template info")} ${import_picocolors49.default.dim("<creator/slug>")} ${import_picocolors49.default.dim("show registry details for a template")}`);
79661
- out.push(` ${import_picocolors49.default.cyan("template onboard")} ${import_picocolors49.default.dim("<creator/slug>")} ${import_picocolors49.default.dim("install (or refresh) a template")}`);
79662
- out.push(` ${import_picocolors49.default.cyan("template list")} ${import_picocolors49.default.dim("show installed templates")}`);
79663
- out.push(` ${import_picocolors49.default.cyan("template remove")} ${import_picocolors49.default.dim("<creator/slug>")} ${import_picocolors49.default.dim("uninstall a template")}`);
80458
+ out.push(` ${import_picocolors52.default.cyan("template pack")} ${import_picocolors52.default.dim("bundle the current agent into a template")}`);
80459
+ out.push(` ${import_picocolors52.default.cyan("template publish")} ${import_picocolors52.default.dim("upload a template to the registry")}`);
80460
+ out.push(` ${import_picocolors52.default.cyan("template search")} ${import_picocolors52.default.dim("[query]")} ${import_picocolors52.default.dim("search the registry")}`);
80461
+ out.push(` ${import_picocolors52.default.cyan("template info")} ${import_picocolors52.default.dim("<creator/slug>")} ${import_picocolors52.default.dim("show registry details for a template")}`);
80462
+ out.push(` ${import_picocolors52.default.cyan("template onboard")} ${import_picocolors52.default.dim("<creator/slug>")} ${import_picocolors52.default.dim("install (or refresh) a template")}`);
80463
+ out.push(` ${import_picocolors52.default.cyan("template list")} ${import_picocolors52.default.dim("show installed templates")}`);
80464
+ out.push(` ${import_picocolors52.default.cyan("template remove")} ${import_picocolors52.default.dim("<creator/slug>")} ${import_picocolors52.default.dim("uninstall a template")}`);
79664
80465
  out.push("");
79665
80466
  out.push(divider("SKILLS"));
79666
80467
  out.push("");
79667
- out.push(` ${import_picocolors49.default.cyan("skill add")} ${import_picocolors49.default.dim("<source>")} ${import_picocolors49.default.dim("install a skill (github / git / brainbase)")}`);
79668
- out.push(` ${import_picocolors49.default.cyan("skill list")} ${import_picocolors49.default.dim("show locally installed skills + their source")}`);
79669
- out.push(` ${import_picocolors49.default.cyan("skill update")} ${import_picocolors49.default.dim("<slug>")} ${import_picocolors49.default.dim("re-fetch a skill from its recorded source")}`);
79670
- out.push(` ${import_picocolors49.default.cyan("skill remove")} ${import_picocolors49.default.dim("<slug>")} ${import_picocolors49.default.dim("uninstall a skill")}`);
79671
- out.push(` ${import_picocolors49.default.cyan("skill search")} ${import_picocolors49.default.dim("[query]")} ${import_picocolors49.default.dim("search the brainbase skill registry")}`);
79672
- out.push(` ${import_picocolors49.default.cyan("skill info")} ${import_picocolors49.default.dim("<creator/slug>")} ${import_picocolors49.default.dim("show registry details for a skill")}`);
79673
- out.push(` ${import_picocolors49.default.cyan("skill publish")} ${import_picocolors49.default.dim("[dir]")} ${import_picocolors49.default.dim("publish a SKILL.md folder (defaults to .)")}`);
80468
+ out.push(` ${import_picocolors52.default.cyan("skill add")} ${import_picocolors52.default.dim("<source>")} ${import_picocolors52.default.dim("install a skill (github / git / brainbase)")}`);
80469
+ out.push(` ${import_picocolors52.default.cyan("skill list")} ${import_picocolors52.default.dim("show locally installed skills + their source")}`);
80470
+ out.push(` ${import_picocolors52.default.cyan("skill update")} ${import_picocolors52.default.dim("<slug>")} ${import_picocolors52.default.dim("re-fetch a skill from its recorded source")}`);
80471
+ out.push(` ${import_picocolors52.default.cyan("skill remove")} ${import_picocolors52.default.dim("<slug>")} ${import_picocolors52.default.dim("uninstall a skill")}`);
80472
+ out.push(` ${import_picocolors52.default.cyan("skill search")} ${import_picocolors52.default.dim("[query]")} ${import_picocolors52.default.dim("search the brainbase skill registry")}`);
80473
+ out.push(` ${import_picocolors52.default.cyan("skill info")} ${import_picocolors52.default.dim("<creator/slug>")} ${import_picocolors52.default.dim("show registry details for a skill")}`);
80474
+ out.push(` ${import_picocolors52.default.cyan("skill publish")} ${import_picocolors52.default.dim("[dir]")} ${import_picocolors52.default.dim("publish a SKILL.md folder (defaults to .)")}`);
79674
80475
  out.push("");
79675
80476
  out.push(divider("CLI TOKENS"));
79676
80477
  out.push("");
79677
- out.push(` ${import_picocolors49.default.cyan("token create")} ${import_picocolors49.default.dim("issue a long-lived CLI key for CI / scripts")}`);
79678
- out.push(` ${import_picocolors49.default.cyan("token list")} ${import_picocolors49.default.dim("show your tokens")}`);
79679
- out.push(` ${import_picocolors49.default.cyan("token rename")} ${import_picocolors49.default.dim("<id>")} ${import_picocolors49.default.dim("relabel a token")}`);
79680
- out.push(` ${import_picocolors49.default.cyan("token revoke")} ${import_picocolors49.default.dim("<id>")} ${import_picocolors49.default.dim("revoke a token")}`);
80478
+ out.push(` ${import_picocolors52.default.cyan("token create")} ${import_picocolors52.default.dim("issue a long-lived CLI key for CI / scripts")}`);
80479
+ out.push(` ${import_picocolors52.default.cyan("token list")} ${import_picocolors52.default.dim("show your tokens")}`);
80480
+ out.push(` ${import_picocolors52.default.cyan("token rename")} ${import_picocolors52.default.dim("<id>")} ${import_picocolors52.default.dim("relabel a token")}`);
80481
+ out.push(` ${import_picocolors52.default.cyan("token revoke")} ${import_picocolors52.default.dim("<id>")} ${import_picocolors52.default.dim("revoke a token")}`);
79681
80482
  out.push("");
79682
80483
  out.push(divider("MCP"));
79683
80484
  out.push("");
79684
- out.push(` ${import_picocolors49.default.cyan("mcp check")} ${import_picocolors49.default.dim("[--json]")} ${import_picocolors49.default.dim("verify MCP server connectivity through the brainbase proxy (runs at sandbox bootstrap)")}`);
80485
+ out.push(` ${import_picocolors52.default.cyan("mcp check")} ${import_picocolors52.default.dim("[--json]")} ${import_picocolors52.default.dim("verify MCP server connectivity through the brainbase proxy (runs at sandbox bootstrap)")}`);
80486
+ out.push(` ${import_picocolors52.default.cyan("mcp list")} ${import_picocolors52.default.dim("[--json]")} ${import_picocolors52.default.dim("show configured servers with OAuth state and expiry")}`);
79685
80487
  out.push("");
79686
80488
  out.push(divider("FLAGS"));
79687
80489
  out.push("");
79688
- out.push(` ${import_picocolors49.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
79689
- out.push(` ${import_picocolors49.default.dim("--scope <s>")} force scope: global | project`);
79690
- out.push(` ${import_picocolors49.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
79691
- out.push(` ${import_picocolors49.default.dim("--agent <id>")} for link/task create: use this agent id explicitly`);
79692
- out.push(` ${import_picocolors49.default.dim("--message <text>")} for task create: required first user message`);
79693
- out.push(` ${import_picocolors49.default.dim("--title <text>")} for task create: optional task title`);
79694
- out.push(` ${import_picocolors49.default.dim("--model <id>")} for task create: optional model override`);
79695
- out.push(` ${import_picocolors49.default.dim("--org <id-or-slug>")} pick the organization (team/agent list, agent create, orchestration create/list)`);
79696
- out.push(` ${import_picocolors49.default.dim("--team <id>")} pick the team, same commands (works without --org)`);
79697
- out.push(` ${import_picocolors49.default.dim("--json")} machine-readable output for supported commands`);
79698
- out.push(` ${import_picocolors49.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
79699
- out.push(` ${import_picocolors49.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
79700
- out.push(` ${import_picocolors49.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
79701
- out.push(` ${import_picocolors49.default.dim("--all")} for template list: include installs from other folders`);
79702
- out.push(` ${import_picocolors49.default.dim("--web <url>")} for login: web app URL (default https://app.brainbaselabs.com)`);
80490
+ out.push(` ${import_picocolors52.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
80491
+ out.push(` ${import_picocolors52.default.dim("--scope <s>")} force scope: global | project`);
80492
+ out.push(` ${import_picocolors52.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
80493
+ out.push(` ${import_picocolors52.default.dim("--agent <id>")} for link/task create: use this agent id explicitly`);
80494
+ out.push(` ${import_picocolors52.default.dim("--message <text>")} for task create: required first user message`);
80495
+ out.push(` ${import_picocolors52.default.dim("--title <text>")} for task create: optional task title`);
80496
+ out.push(` ${import_picocolors52.default.dim("--model <id>")} for task create: optional model override`);
80497
+ out.push(` ${import_picocolors52.default.dim("--org <id-or-slug>")} pick the organization (team/agent list, agent create, orchestration create/list)`);
80498
+ out.push(` ${import_picocolors52.default.dim("--team <id>")} pick the team, same commands (works without --org)`);
80499
+ out.push(` ${import_picocolors52.default.dim("--json")} machine-readable output for supported commands`);
80500
+ out.push(` ${import_picocolors52.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
80501
+ out.push(` ${import_picocolors52.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
80502
+ out.push(` ${import_picocolors52.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
80503
+ out.push(` ${import_picocolors52.default.dim("--bot-token <t>")} for agent connect slack (or BRAINBASE_SLACK_BOT_TOKEN, or stdin)`);
80504
+ out.push(` ${import_picocolors52.default.dim("--signing-secret <s>")} for agent connect slack (or BRAINBASE_SLACK_SIGNING_SECRET, or stdin)`);
80505
+ out.push(` ${import_picocolors52.default.dim("--bot-name <name>")} for agent connect meeting: the bot's display name`);
80506
+ out.push(` ${import_picocolors52.default.dim("--all")} for template list: include installs from other folders`);
80507
+ out.push(` ${import_picocolors52.default.dim("--web <url>")} for login: web app URL (default https://app.brainbaselabs.com)`);
79703
80508
  out.push("");
79704
80509
  out.push(divider("ENV"));
79705
80510
  out.push("");
79706
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
79707
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_DEBUG")} print full stack traces on error (any value; unset to disable)`);
79708
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
79709
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_CONTROL_PLANE_URL")} override the MAS host (/v2/cli; task create uses /v2/tasks)`);
79710
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_API_URL")} legacy KLS host override (uses /api/cli; proxy/registry fallback)`);
79711
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_PROXY_URL")} override the model-proxy URL used by harness traffic (default https://api.v1.brainbaselabs.com)`);
79712
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL (default https://api.v1.brainbaselabs.com)`);
79713
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
79714
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
79715
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
79716
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 → agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
80511
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
80512
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_DEBUG")} print full stack traces on error (any value; unset to disable)`);
80513
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
80514
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_CONTROL_PLANE_URL")} override the MAS host (/v2/cli; task create uses /v2/tasks)`);
80515
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_API_URL")} legacy KLS host override (uses /api/cli; proxy/registry fallback)`);
80516
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_PROXY_URL")} override the model-proxy URL used by harness traffic (default https://api.v1.brainbaselabs.com)`);
80517
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL (default https://api.v1.brainbaselabs.com)`);
80518
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT; the only PAT control-plane commands accept (token.json is not read there)`);
80519
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
80520
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
80521
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 → agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
79717
80522
  out.push("");
79718
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_MEMORY_MCP_URL")} override the built-in memory MCP host`);
79719
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_BROWSER_MCP_URL")} override the built-in browser MCP host`);
79720
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_SLACK_MCP_URL")} override the built-in Slack MCP host`);
79721
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_MEETING_MCP_URL")} override the built-in meeting MCP host`);
79722
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_GITHUB_MCP_URL")} override the built-in GitHub MCP host`);
79723
- out.push(` ${import_picocolors49.default.dim("BRAINBASE_ORCHESTRATION_MCP_URL")} override the built-in orchestration MCP host`);
80523
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_MEMORY_MCP_URL")} override the built-in memory MCP host`);
80524
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_BROWSER_MCP_URL")} override the built-in browser MCP host`);
80525
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_SLACK_MCP_URL")} override the built-in Slack MCP host`);
80526
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_MEETING_MCP_URL")} override the built-in meeting MCP host`);
80527
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_GITHUB_MCP_URL")} override the built-in GitHub MCP host`);
80528
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_ORCHESTRATION_MCP_URL")} override the built-in orchestration MCP host`);
79724
80529
  out.push("");
79725
80530
  out.push(divider("HARNESSES"));
79726
80531
  out.push("");
79727
- out.push(` ${import_picocolors49.default.dim("•")} ${import_picocolors49.default.bold("claude-code")} ${import_picocolors49.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
79728
- out.push(` ${import_picocolors49.default.dim("•")} ${import_picocolors49.default.bold("codex")} ${import_picocolors49.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
79729
- out.push(` ${import_picocolors49.default.dim("•")} ${import_picocolors49.default.bold("kafka")} ${import_picocolors49.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
80532
+ out.push(` ${import_picocolors52.default.dim("•")} ${import_picocolors52.default.bold("claude-code")} ${import_picocolors52.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
80533
+ out.push(` ${import_picocolors52.default.dim("•")} ${import_picocolors52.default.bold("codex")} ${import_picocolors52.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
80534
+ out.push(` ${import_picocolors52.default.dim("•")} ${import_picocolors52.default.bold("kafka")} ${import_picocolors52.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
79730
80535
  out.push("");
79731
80536
  console.log(out.join(`
79732
80537
  `));
@@ -79751,7 +80556,13 @@ var VALUE_TAKING_FLAGS = new Set([
79751
80556
  "--description",
79752
80557
  "--schema",
79753
80558
  "--from",
79754
- "--to"
80559
+ "--to",
80560
+ "--bot-token",
80561
+ "--signing-secret",
80562
+ "--app-id",
80563
+ "--app-name",
80564
+ "--bot-name",
80565
+ "--bot-image-url"
79755
80566
  ]);
79756
80567
  function isValueOfPriorFlag2(args, index) {
79757
80568
  return index > 0 && VALUE_TAKING_FLAGS.has(args[index - 1]);
@@ -79872,13 +80683,13 @@ async function requireAuth(cmd) {
79872
80683
  if (STORED_PAT_COMMANDS.has(cmd) && readToken())
79873
80684
  return;
79874
80685
  console.error("");
79875
- console.error(` ${brandTint("◆")} ${import_picocolors49.default.bold("brainbase")}`);
80686
+ console.error(` ${brandTint("◆")} ${import_picocolors52.default.bold("brainbase")}`);
79876
80687
  console.error("");
79877
- console.error(` ${import_picocolors49.default.red("✗")} You need to sign in to use ${import_picocolors49.default.bold("brainbase " + cmd)}.`);
80688
+ console.error(` ${import_picocolors52.default.red("✗")} You need to sign in to use ${import_picocolors52.default.bold("brainbase " + cmd)}.`);
79878
80689
  if (status.reason)
79879
- console.error(` ${import_picocolors49.default.dim(status.reason)}`);
80690
+ console.error(` ${import_picocolors52.default.dim(status.reason)}`);
79880
80691
  console.error("");
79881
- console.error(` Run ${import_picocolors49.default.cyan("brainbase login")} to connect this device.`);
80692
+ console.error(` Run ${import_picocolors52.default.cyan("brainbase login")} to connect this device.`);
79882
80693
  console.error("");
79883
80694
  process14.exit(1);
79884
80695
  }
@@ -79888,7 +80699,7 @@ async function main() {
79888
80699
  const rawCwd = process14.cwd();
79889
80700
  const cwd2 = (() => {
79890
80701
  try {
79891
- return fs82.realpathSync(rawCwd);
80702
+ return fs83.realpathSync(rawCwd);
79892
80703
  } catch {
79893
80704
  return rawCwd;
79894
80705
  }
@@ -79937,6 +80748,12 @@ async function main() {
79937
80748
  const noPushFlag = hasFlag2(sharedArgs, "--no-push");
79938
80749
  const jsonFlag = hasFlag2(sharedArgs, "--json");
79939
80750
  const acpFlag = hasFlag2(sharedArgs, "--acp");
80751
+ const botTokenFlag = getFlag(sharedArgs, "--bot-token");
80752
+ const signingSecretFlag = getFlag(sharedArgs, "--signing-secret");
80753
+ const appIdFlag = getFlag(sharedArgs, "--app-id");
80754
+ const appNameFlag = getFlag(sharedArgs, "--app-name");
80755
+ const botNameFlag = getFlag(sharedArgs, "--bot-name");
80756
+ const botImageUrlFlag = getFlag(sharedArgs, "--bot-image-url");
79940
80757
  ensureSkillResolversRegistered();
79941
80758
  await requireAuth(cmd);
79942
80759
  try {
@@ -79950,7 +80767,7 @@ async function main() {
79950
80767
  break;
79951
80768
  }
79952
80769
  case "whoami": {
79953
- await runWhoami();
80770
+ await runWhoami({ json: jsonFlag });
79954
80771
  break;
79955
80772
  }
79956
80773
  case "template": {
@@ -80020,7 +80837,13 @@ async function main() {
80020
80837
  track,
80021
80838
  force: forceFlag,
80022
80839
  runEntrypoint: runEntrypointFlag,
80023
- acp: acpFlag
80840
+ acp: acpFlag,
80841
+ botToken: botTokenFlag,
80842
+ signingSecret: signingSecretFlag,
80843
+ appId: appIdFlag,
80844
+ appName: appNameFlag,
80845
+ botName: botNameFlag,
80846
+ botImageUrl: botImageUrlFlag
80024
80847
  });
80025
80848
  break;
80026
80849
  }
@@ -80079,10 +80902,10 @@ async function main() {
80079
80902
  process14.exit(1);
80080
80903
  }
80081
80904
  } catch (err) {
80082
- console.error(import_picocolors49.default.red(`
80905
+ console.error(import_picocolors52.default.red(`
80083
80906
  ${err.message}`));
80084
80907
  if (err instanceof ApiError && err.status === 401) {
80085
- console.error(` Run ${import_picocolors49.default.cyan("brainbase login")} to connect this device.`);
80908
+ console.error(` Run ${import_picocolors52.default.cyan("brainbase login")} to connect this device.`);
80086
80909
  }
80087
80910
  if (process14.env.BRAINBASE_DEBUG)
80088
80911
  console.error(err.stack);