@brainbase-labs/cli 0.9.0 → 0.10.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 (2) hide show
  1. package/dist/index.js +299 -137
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -29449,7 +29449,7 @@ function padStart(s, n) {
29449
29449
  // package.json
29450
29450
  var package_default = {
29451
29451
  name: "@brainbase-labs/cli",
29452
- version: "0.9.0",
29452
+ version: "0.10.0",
29453
29453
  description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
29454
29454
  type: "module",
29455
29455
  bin: {
@@ -29921,6 +29921,73 @@ function scopePaths(cwd, scope) {
29921
29921
  return scope === "global" ? globalPaths() : projectPaths(cwd);
29922
29922
  }
29923
29923
 
29924
+ // src/harnesses/claude-code/settings.ts
29925
+ function readSettings(file) {
29926
+ return readJsonOr(file, {});
29927
+ }
29928
+ function writeSettings(file, settings) {
29929
+ writeJson(file, settings);
29930
+ }
29931
+ function setMcpServer(file, name, entry) {
29932
+ const s = readSettings(file);
29933
+ if (!s.mcpServers)
29934
+ s.mcpServers = {};
29935
+ s.mcpServers[name] = entry;
29936
+ writeSettings(file, s);
29937
+ }
29938
+ function removeMcpServer(file, name) {
29939
+ if (!exists(file))
29940
+ return;
29941
+ const s = readSettings(file);
29942
+ if (s.mcpServers && name in s.mcpServers) {
29943
+ delete s.mcpServers[name];
29944
+ writeSettings(file, s);
29945
+ }
29946
+ }
29947
+ function getMcpServer(file, name) {
29948
+ const s = readSettings(file);
29949
+ return s.mcpServers?.[name];
29950
+ }
29951
+ function listMcpServers(file) {
29952
+ return readSettings(file).mcpServers ?? {};
29953
+ }
29954
+ function normalizeMcpPayload(payload) {
29955
+ const out = { ...payload };
29956
+ delete out.is_enabled;
29957
+ const hasUrl = typeof out.url === "string" && out.url.length > 0;
29958
+ const hasCommand = typeof out.command === "string" && out.command.length > 0;
29959
+ if (!out.type) {
29960
+ if (hasUrl)
29961
+ out.type = "http";
29962
+ else if (hasCommand)
29963
+ out.type = "stdio";
29964
+ }
29965
+ if (out.type === "http" || out.type === "sse") {
29966
+ if (Array.isArray(out.args) && out.args.length === 0)
29967
+ delete out.args;
29968
+ if (out.env && typeof out.env === "object" && Object.keys(out.env).length === 0) {
29969
+ delete out.env;
29970
+ }
29971
+ if (out.headers && typeof out.headers === "object" && Object.keys(out.headers).length === 0) {
29972
+ delete out.headers;
29973
+ }
29974
+ }
29975
+ if (out.type === "stdio") {
29976
+ delete out.url;
29977
+ delete out.headers;
29978
+ }
29979
+ return out;
29980
+ }
29981
+ function listMcpServersFromMcpJson(file) {
29982
+ return readJsonOr(file, {}).mcpServers ?? {};
29983
+ }
29984
+ function listMcpServersFromClaudeJson(file, projectKey) {
29985
+ const data = readJsonOr(file, {});
29986
+ if (projectKey)
29987
+ return data.projects?.[projectKey]?.mcpServers ?? {};
29988
+ return data.mcpServers ?? {};
29989
+ }
29990
+
29924
29991
  // src/harnesses/claude-code/inventory.ts
29925
29992
  import fs4 from "node:fs";
29926
29993
  import path6 from "node:path";
@@ -33961,73 +34028,6 @@ function manifestSourceForPack(source) {
33961
34028
  return source.type === "local" ? { type: "inline" } : source;
33962
34029
  }
33963
34030
 
33964
- // src/harnesses/claude-code/settings.ts
33965
- function readSettings(file) {
33966
- return readJsonOr(file, {});
33967
- }
33968
- function writeSettings(file, settings) {
33969
- writeJson(file, settings);
33970
- }
33971
- function setMcpServer(file, name, entry) {
33972
- const s = readSettings(file);
33973
- if (!s.mcpServers)
33974
- s.mcpServers = {};
33975
- s.mcpServers[name] = entry;
33976
- writeSettings(file, s);
33977
- }
33978
- function removeMcpServer(file, name) {
33979
- if (!exists(file))
33980
- return;
33981
- const s = readSettings(file);
33982
- if (s.mcpServers && name in s.mcpServers) {
33983
- delete s.mcpServers[name];
33984
- writeSettings(file, s);
33985
- }
33986
- }
33987
- function getMcpServer(file, name) {
33988
- const s = readSettings(file);
33989
- return s.mcpServers?.[name];
33990
- }
33991
- function listMcpServers(file) {
33992
- return readSettings(file).mcpServers ?? {};
33993
- }
33994
- function normalizeMcpPayload(payload) {
33995
- const out = { ...payload };
33996
- delete out.is_enabled;
33997
- const hasUrl = typeof out.url === "string" && out.url.length > 0;
33998
- const hasCommand = typeof out.command === "string" && out.command.length > 0;
33999
- if (!out.type) {
34000
- if (hasUrl)
34001
- out.type = "http";
34002
- else if (hasCommand)
34003
- out.type = "stdio";
34004
- }
34005
- if (out.type === "http" || out.type === "sse") {
34006
- if (Array.isArray(out.args) && out.args.length === 0)
34007
- delete out.args;
34008
- if (out.env && typeof out.env === "object" && Object.keys(out.env).length === 0) {
34009
- delete out.env;
34010
- }
34011
- if (out.headers && typeof out.headers === "object" && Object.keys(out.headers).length === 0) {
34012
- delete out.headers;
34013
- }
34014
- }
34015
- if (out.type === "stdio") {
34016
- delete out.url;
34017
- delete out.headers;
34018
- }
34019
- return out;
34020
- }
34021
- function listMcpServersFromMcpJson(file) {
34022
- return readJsonOr(file, {}).mcpServers ?? {};
34023
- }
34024
- function listMcpServersFromClaudeJson(file, projectKey) {
34025
- const data = readJsonOr(file, {});
34026
- if (projectKey)
34027
- return data.projects?.[projectKey]?.mcpServers ?? {};
34028
- return data.mcpServers ?? {};
34029
- }
34030
-
34031
34031
  // src/harnesses/claude-code/inventory.ts
34032
34032
  function firstLine(file, max = 200) {
34033
34033
  try {
@@ -35070,6 +35070,11 @@ var claudeCode = {
35070
35070
  async function installClaudeCodeWithCtx(components, opts, templateName) {
35071
35071
  return installClaudeCode(components, opts, { templateName });
35072
35072
  }
35073
+ function removeClaudeCodeMcp(slugs, opts) {
35074
+ const { mcpStore } = scopePaths(opts.cwd, opts.scope);
35075
+ for (const slug of slugs)
35076
+ removeMcpServer(mcpStore, slug);
35077
+ }
35073
35078
 
35074
35079
  // src/harnesses/codex/paths.ts
35075
35080
  import path13 from "node:path";
@@ -35101,10 +35106,6 @@ function isBundledSkillDir(name) {
35101
35106
  return name === ".system" || name.startsWith(".");
35102
35107
  }
35103
35108
 
35104
- // src/harnesses/codex/inventory.ts
35105
- import fs12 from "node:fs";
35106
- import path15 from "node:path";
35107
-
35108
35109
  // src/harnesses/codex/config-toml.ts
35109
35110
  import fs11 from "node:fs";
35110
35111
 
@@ -36269,6 +36270,8 @@ function listMcpServers2(file) {
36269
36270
  }
36270
36271
 
36271
36272
  // src/harnesses/codex/inventory.ts
36273
+ import fs12 from "node:fs";
36274
+ import path15 from "node:path";
36272
36275
  function firstLine2(file, max = 200) {
36273
36276
  try {
36274
36277
  const head = fs12.readFileSync(file, "utf8").slice(0, 2000);
@@ -36882,6 +36885,11 @@ var codex = {
36882
36885
  async function installCodexWithCtx(components, opts, templateName) {
36883
36886
  return installCodex(components, opts, { templateName });
36884
36887
  }
36888
+ function removeCodexMcp(slugs, opts) {
36889
+ const { config } = scopePaths2(opts.cwd, opts.scope);
36890
+ for (const slug of slugs)
36891
+ removeMcpServer2(config, slug);
36892
+ }
36885
36893
 
36886
36894
  // src/harnesses/kafka/paths.ts
36887
36895
  import path19 from "node:path";
@@ -36919,10 +36927,6 @@ function scopePaths3(cwd, scope) {
36919
36927
  return scope === "global" ? globalPaths3() : projectPaths3(cwd);
36920
36928
  }
36921
36929
 
36922
- // src/harnesses/kafka/inventory.ts
36923
- import fs15 from "node:fs";
36924
- import path20 from "node:path";
36925
-
36926
36930
  // src/harnesses/kafka/settings.ts
36927
36931
  function readSettings2(file) {
36928
36932
  return readJsonOr(file, {});
@@ -36972,6 +36976,22 @@ function setMcpServer3(file, name, entry) {
36972
36976
  }
36973
36977
  writeSettings2(file, s);
36974
36978
  }
36979
+ function removeMcpServer3(file, name) {
36980
+ if (!exists(file))
36981
+ return;
36982
+ const s = readSettings2(file);
36983
+ const raw = s.mcp_servers ?? s.mcpServers;
36984
+ if (!raw)
36985
+ return;
36986
+ if (Array.isArray(raw)) {
36987
+ s.mcp_servers = raw.filter((e2) => e2.name !== name);
36988
+ } else {
36989
+ delete raw[name];
36990
+ s.mcp_servers = raw;
36991
+ }
36992
+ delete s.mcpServers;
36993
+ writeSettings2(file, s);
36994
+ }
36975
36995
  function normalizeMcpPayload2(payload) {
36976
36996
  const out = { ...payload };
36977
36997
  delete out.is_enabled;
@@ -37001,6 +37021,8 @@ function normalizeMcpPayload2(payload) {
37001
37021
  }
37002
37022
 
37003
37023
  // src/harnesses/kafka/inventory.ts
37024
+ import fs15 from "node:fs";
37025
+ import path20 from "node:path";
37004
37026
  function firstLine3(file, max = 200) {
37005
37027
  try {
37006
37028
  const head = fs15.readFileSync(file, "utf8").slice(0, 2000);
@@ -37650,6 +37672,11 @@ var kafka = {
37650
37672
  async function installKafkaWithCtx(components, opts, templateName) {
37651
37673
  return installKafka(components, opts, { templateName });
37652
37674
  }
37675
+ function removeKafkaMcp(slugs, opts) {
37676
+ const { mcpStore } = scopePaths3(opts.cwd, opts.scope);
37677
+ for (const slug of slugs)
37678
+ removeMcpServer3(mcpStore, slug);
37679
+ }
37653
37680
 
37654
37681
  // src/harnesses/index.ts
37655
37682
  var adapters = [claudeCode, codex, kafka];
@@ -37679,6 +37706,17 @@ async function detectHarnesses(cwd) {
37679
37706
  }
37680
37707
  return out;
37681
37708
  }
37709
+ function runHarnessRemoveMcp(harnessId, slugs, opts) {
37710
+ if (slugs.length === 0)
37711
+ return;
37712
+ const canonical = normalizeHarnessId(harnessId);
37713
+ if (canonical === "claude-code")
37714
+ return removeClaudeCodeMcp(slugs, opts);
37715
+ if (canonical === "codex")
37716
+ return removeCodexMcp(slugs, opts);
37717
+ if (canonical === "kafka")
37718
+ return removeKafkaMcp(slugs, opts);
37719
+ }
37682
37720
 
37683
37721
  // src/core/registry.ts
37684
37722
  import fs18 from "node:fs";
@@ -48632,6 +48670,8 @@ async function runRemove(cwd2, args) {
48632
48670
  if (c2.type === "mcp" && c2.settingsFile && c2.embeddedKey) {
48633
48671
  if (inst.harness === "codex")
48634
48672
  removeMcpServer2(c2.settingsFile, c2.embeddedKey);
48673
+ else if (inst.harness === "kafka")
48674
+ removeMcpServer3(c2.settingsFile, c2.embeddedKey);
48635
48675
  else
48636
48676
  removeMcpServer(c2.settingsFile, c2.embeddedKey);
48637
48677
  } else if (c2.type === "instruction") {
@@ -51098,6 +51138,11 @@ var McpEntrySchema = exports_external.object({
51098
51138
  headers: exports_external.record(exports_external.string()).optional(),
51099
51139
  is_enabled: exports_external.boolean().optional()
51100
51140
  });
51141
+ var CapabilitiesSchema = exports_external.object({
51142
+ memory: exports_external.boolean().optional(),
51143
+ browser: exports_external.boolean().optional(),
51144
+ slack: exports_external.boolean().optional()
51145
+ });
51101
51146
  var AgentManifestSchema = exports_external.object({
51102
51147
  schema: exports_external.literal(1),
51103
51148
  id: exports_external.string().min(1).optional(),
@@ -51108,6 +51153,7 @@ var AgentManifestSchema = exports_external.object({
51108
51153
  playbooks: exports_external.array(PlaybookSchema).default([]),
51109
51154
  skills: exports_external.array(SkillEntrySchema).default([]),
51110
51155
  mcp: exports_external.array(McpEntrySchema).default([]),
51156
+ capabilities: CapabilitiesSchema.optional(),
51111
51157
  commands: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
51112
51158
  hooks: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
51113
51159
  files: exports_external.array(exports_external.record(exports_external.unknown())).optional()
@@ -51894,6 +51940,39 @@ import os11 from "node:os";
51894
51940
  import crypto3 from "node:crypto";
51895
51941
  var import_picocolors24 = __toESM(require_picocolors(), 1);
51896
51942
 
51943
+ // src/core/memory-mcp.ts
51944
+ var DEFAULT_MEMORY_MCP_BASE = "https://brainbase-memory-mcp.onrender.com";
51945
+ var MEMORY_MCP_SLUG = "brainbase-memory";
51946
+ function memoryMcpBaseUrl() {
51947
+ const envOverride = process.env.BRAINBASE_MEMORY_MCP_URL;
51948
+ if (envOverride)
51949
+ return envOverride.replace(/\/+$/, "");
51950
+ return DEFAULT_MEMORY_MCP_BASE;
51951
+ }
51952
+ function memoryMcpUrl() {
51953
+ return `${memoryMcpBaseUrl()}/t/\${BRAINBASE_THREAD_ID}/mcp`;
51954
+ }
51955
+ function memoryMcpPayload() {
51956
+ return {
51957
+ url: memoryMcpUrl(),
51958
+ headers: {
51959
+ Authorization: "Bearer ${BRAINBASE_TOKEN}"
51960
+ }
51961
+ };
51962
+ }
51963
+ function buildMemoryMcpComponent(scope) {
51964
+ return {
51965
+ type: "mcp",
51966
+ slug: MEMORY_MCP_SLUG,
51967
+ scope,
51968
+ rootDir: "",
51969
+ description: "This agent's persistent SQL memory database (provision, query, " + "inspect schema). Scoped to this agent only.",
51970
+ meta: { mcp: memoryMcpPayload() },
51971
+ payload: memoryMcpPayload(),
51972
+ checksum: "builtin:brainbase-memory:v1"
51973
+ };
51974
+ }
51975
+
51897
51976
  // src/core/orchestration-mcp.ts
51898
51977
  var DEFAULT_ORCHESTRATION_MCP_BASE = "https://brainbase-orchestration-mcp.onrender.com";
51899
51978
  var ORCHESTRATION_MCP_SLUG = "brainbase-orchestration";
@@ -51927,39 +52006,109 @@ function buildOrchestrationMcpComponent(scope) {
51927
52006
  };
51928
52007
  }
51929
52008
 
51930
- // src/core/memory-mcp.ts
51931
- var DEFAULT_MEMORY_MCP_BASE = "https://brainbase-memory-mcp.onrender.com";
51932
- var MEMORY_MCP_SLUG = "brainbase-memory";
51933
- function memoryMcpBaseUrl() {
51934
- const envOverride = process.env.BRAINBASE_MEMORY_MCP_URL;
52009
+ // src/core/slack-mcp.ts
52010
+ var DEFAULT_SLACK_MCP_BASE = "https://brainbase-slack-mcp.onrender.com";
52011
+ var SLACK_MCP_SLUG = "brainbase-slack";
52012
+ function slackMcpBaseUrl() {
52013
+ const envOverride = process.env.BRAINBASE_SLACK_MCP_URL;
51935
52014
  if (envOverride)
51936
52015
  return envOverride.replace(/\/+$/, "");
51937
- return DEFAULT_MEMORY_MCP_BASE;
52016
+ return DEFAULT_SLACK_MCP_BASE;
51938
52017
  }
51939
- function memoryMcpUrl() {
51940
- return `${memoryMcpBaseUrl()}/t/\${BRAINBASE_THREAD_ID}/mcp`;
52018
+ function slackMcpUrl() {
52019
+ return `${slackMcpBaseUrl()}/t/\${BRAINBASE_THREAD_ID}/mcp`;
51941
52020
  }
51942
- function memoryMcpPayload() {
52021
+ function slackMcpPayload() {
51943
52022
  return {
51944
- url: memoryMcpUrl(),
52023
+ url: slackMcpUrl(),
51945
52024
  headers: {
51946
52025
  Authorization: "Bearer ${BRAINBASE_TOKEN}"
51947
52026
  }
51948
52027
  };
51949
52028
  }
51950
- function buildMemoryMcpComponent(scope) {
52029
+ function buildSlackMcpComponent(scope) {
51951
52030
  return {
51952
52031
  type: "mcp",
51953
- slug: MEMORY_MCP_SLUG,
52032
+ slug: SLACK_MCP_SLUG,
51954
52033
  scope,
51955
52034
  rootDir: "",
51956
- description: "This agent's persistent SQL memory database (provision, query, " + "inspect schema). Scoped to this agent only.",
51957
- meta: { mcp: memoryMcpPayload() },
51958
- payload: memoryMcpPayload(),
51959
- checksum: "builtin:brainbase-memory:v1"
52035
+ description: "This agent's Slack connector (read channels, send messages, manage " + "the workspace it is installed in). Scoped to this agent only.",
52036
+ meta: { mcp: slackMcpPayload() },
52037
+ payload: slackMcpPayload(),
52038
+ checksum: "builtin:brainbase-slack:v1"
52039
+ };
52040
+ }
52041
+
52042
+ // src/core/browser-mcp.ts
52043
+ var DEFAULT_BROWSER_MCP_BASE = "https://brainbase-browser-mcp.onrender.com";
52044
+ var BROWSER_MCP_SLUG = "brainbase-browser";
52045
+ function browserMcpBaseUrl() {
52046
+ const envOverride = process.env.BRAINBASE_BROWSER_MCP_URL;
52047
+ if (envOverride)
52048
+ return envOverride.replace(/\/+$/, "");
52049
+ return DEFAULT_BROWSER_MCP_BASE;
52050
+ }
52051
+ function browserMcpUrl() {
52052
+ return `${browserMcpBaseUrl()}/t/\${BRAINBASE_THREAD_ID}/mcp`;
52053
+ }
52054
+ function browserMcpPayload() {
52055
+ return {
52056
+ url: browserMcpUrl(),
52057
+ headers: {
52058
+ Authorization: "Bearer ${BRAINBASE_TOKEN}"
52059
+ }
52060
+ };
52061
+ }
52062
+ function buildBrowserMcpComponent(scope) {
52063
+ return {
52064
+ type: "mcp",
52065
+ slug: BROWSER_MCP_SLUG,
52066
+ scope,
52067
+ rootDir: "",
52068
+ description: "This agent's headless browser (navigate, read pages, fill forms). " + "Scoped to this agent only.",
52069
+ meta: { mcp: browserMcpPayload() },
52070
+ payload: browserMcpPayload(),
52071
+ checksum: "builtin:brainbase-browser:v1"
51960
52072
  };
51961
52073
  }
51962
52074
 
52075
+ // src/core/builtin-mcps.ts
52076
+ function capabilitiesFromAgent(agent) {
52077
+ return {
52078
+ memory: agent.memory_enabled !== false,
52079
+ browser: agent.browser_enabled !== false,
52080
+ slack: agent.slack_connected === true
52081
+ };
52082
+ }
52083
+ function capabilitiesFromManifest(manifest) {
52084
+ const c2 = manifest?.capabilities ?? {};
52085
+ return {
52086
+ memory: c2.memory !== false,
52087
+ browser: c2.browser !== false,
52088
+ slack: c2.slack === true
52089
+ };
52090
+ }
52091
+ function resolveBuiltinMcps(input) {
52092
+ const { caps, declaredSlugs, scope } = input;
52093
+ const gated = [
52094
+ { slug: ORCHESTRATION_MCP_SLUG, enabled: true, build: buildOrchestrationMcpComponent },
52095
+ { slug: MEMORY_MCP_SLUG, enabled: caps.memory, build: buildMemoryMcpComponent },
52096
+ { slug: BROWSER_MCP_SLUG, enabled: caps.browser, build: buildBrowserMcpComponent },
52097
+ { slug: SLACK_MCP_SLUG, enabled: caps.slack, build: buildSlackMcpComponent }
52098
+ ];
52099
+ const install = [];
52100
+ const removeSlugs = [];
52101
+ for (const g3 of gated) {
52102
+ if (declaredSlugs.has(g3.slug))
52103
+ continue;
52104
+ if (g3.enabled)
52105
+ install.push(g3.build(scope));
52106
+ else
52107
+ removeSlugs.push(g3.slug);
52108
+ }
52109
+ return { install, removeSlugs };
52110
+ }
52111
+
51963
52112
  // src/cli/sync.ts
51964
52113
  async function runSync(cwd2, args) {
51965
52114
  banner("sync — bring in the latest changes from your team");
@@ -51986,11 +52135,21 @@ async function runSync(cwd2, args) {
51986
52135
  }
51987
52136
  const prevState = readSyncState(cwd2);
51988
52137
  const diff2 = computeDiff(manifest.components, prevState);
51989
- const cloudHasOrchestrationMcp = manifest.components.some((c2) => c2.type === "mcp" && c2.slug === ORCHESTRATION_MCP_SLUG);
51990
- const needOrchestrationMcpInstall = !cloudHasOrchestrationMcp;
51991
- const cloudHasMemoryMcp = manifest.components.some((c2) => c2.type === "mcp" && c2.slug === MEMORY_MCP_SLUG);
51992
- const needMemoryMcpInstall = !cloudHasMemoryMcp;
51993
- if (diff2.added.length === 0 && diff2.upstreamUpdated.length === 0 && diff2.localModified.length === 0 && diff2.deletedUpstream.length === 0 && !needOrchestrationMcpInstall && !needMemoryMcpInstall) {
52138
+ const scope = args.scope ?? "project";
52139
+ let caps;
52140
+ try {
52141
+ caps = capabilitiesFromManifest(readManifest(cwd2));
52142
+ } catch (err) {
52143
+ f2.error(err.message);
52144
+ return;
52145
+ }
52146
+ const declaredMcpSlugs = new Set(manifest.components.filter((c2) => c2.type === "mcp").map((c2) => c2.slug));
52147
+ const { install: builtinInstall, removeSlugs: builtinRemoveSlugs } = resolveBuiltinMcps({
52148
+ caps,
52149
+ declaredSlugs: declaredMcpSlugs,
52150
+ scope
52151
+ });
52152
+ if (diff2.added.length === 0 && diff2.upstreamUpdated.length === 0 && diff2.localModified.length === 0 && diff2.deletedUpstream.length === 0 && builtinInstall.length === 0 && builtinRemoveSlugs.length === 0) {
51994
52153
  f2.info(`${sym.same} You're up to date.`);
51995
52154
  writeSyncState(cwd2, {
51996
52155
  schemaVersion: 1,
@@ -52054,7 +52213,6 @@ async function runSync(cwd2, args) {
52054
52213
  });
52055
52214
  }
52056
52215
  const adapter = getAdapter(adapterId);
52057
- const scope = args.scope ?? "project";
52058
52216
  const keepLocal = new Set;
52059
52217
  if (diff2.localModified.length > 0) {
52060
52218
  requireInteractive(`${diff2.localModified.length} component(s) changed both locally and in the cloud — run \`brainbase sync\` in an interactive terminal to resolve them (or revert your local changes).`);
@@ -52092,14 +52250,7 @@ async function runSync(cwd2, args) {
52092
52250
  payload: proxifyMcpPayload(c2.meta?.mcp),
52093
52251
  checksum: c2.hash
52094
52252
  }));
52095
- const hasUserOrchestrationMcp = toInstall.some((c2) => c2.type === "mcp" && c2.slug === ORCHESTRATION_MCP_SLUG);
52096
- if (!hasUserOrchestrationMcp) {
52097
- toInstall.push(buildOrchestrationMcpComponent(scope));
52098
- }
52099
- const hasUserMemoryMcp = toInstall.some((c2) => c2.type === "mcp" && c2.slug === MEMORY_MCP_SLUG);
52100
- if (!hasUserMemoryMcp) {
52101
- toInstall.push(buildMemoryMcpComponent(scope));
52102
- }
52253
+ toInstall.push(...builtinInstall);
52103
52254
  const justInstalledPaths = new Map;
52104
52255
  if (toInstall.length > 0) {
52105
52256
  const installSpinner = de();
@@ -52119,6 +52270,9 @@ async function runSync(cwd2, args) {
52119
52270
  f2.warn(`Skipped: ${result2.skipped.map((s3) => `${s3.type}/${s3.slug} (${s3.reason})`).join(", ")}`);
52120
52271
  }
52121
52272
  }
52273
+ if (builtinRemoveSlugs.length > 0) {
52274
+ runHarnessRemoveMcp(adapter.id, builtinRemoveSlugs, { cwd: cwd2, scope });
52275
+ }
52122
52276
  if (diff2.deletedUpstream.length > 0) {
52123
52277
  for (const removed of diff2.deletedUpstream) {
52124
52278
  let goAhead = autoProceed(args.yes);
@@ -52708,11 +52862,14 @@ async function runAgentPull(cwd2, args) {
52708
52862
  else
52709
52863
  toInstallKeys.add(r2.key);
52710
52864
  }
52711
- const cloudHasOrchestrationMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === ORCHESTRATION_MCP_SLUG);
52712
- const needOrchestrationMcpInstall = !cloudHasOrchestrationMcp;
52713
- const cloudHasMemoryMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === MEMORY_MCP_SLUG);
52714
- const needMemoryMcpInstall = !cloudHasMemoryMcp;
52715
- if (toInstallKeys.size === 0 && toRemoveKeys.size === 0 && !needOrchestrationMcpInstall && !needMemoryMcpInstall && !override) {
52865
+ const caps = capabilitiesFromAgent(cloudAgent);
52866
+ const declaredMcpSlugs = new Set(cloud.components.filter((c2) => c2.type === "mcp").map((c2) => c2.slug));
52867
+ const { install: builtinInstall, removeSlugs: builtinRemoveSlugs } = resolveBuiltinMcps({
52868
+ caps,
52869
+ declaredSlugs: declaredMcpSlugs,
52870
+ scope: args.scope ?? "project"
52871
+ });
52872
+ if (toInstallKeys.size === 0 && toRemoveKeys.size === 0 && builtinInstall.length === 0 && builtinRemoveSlugs.length === 0 && !override) {
52716
52873
  f2.info(`You're up to date.`);
52717
52874
  writeLink(cwd2, buildLinkFromAgent(cloudAgent, harness, readLink(cwd2)));
52718
52875
  writeSyncState(cwd2, buildLockFromCloud(agentId, cloud, lock, cloudAgent));
@@ -52766,7 +52923,7 @@ async function runAgentPull(cwd2, args) {
52766
52923
  const stageRoot = stageManifestComponents(installComponents);
52767
52924
  const justInstalledPaths = new Map;
52768
52925
  try {
52769
- if (installComponents.length > 0 || needOrchestrationMcpInstall || needMemoryMcpInstall) {
52926
+ if (installComponents.length > 0 || builtinInstall.length > 0) {
52770
52927
  const installSpinner = de();
52771
52928
  installSpinner.start("Applying updates…");
52772
52929
  const toInstall = installComponents.map((c2) => ({
@@ -52780,12 +52937,7 @@ async function runAgentPull(cwd2, args) {
52780
52937
  checksum: c2.hash,
52781
52938
  source: skillSourceFromMeta(c2)
52782
52939
  }));
52783
- if (needOrchestrationMcpInstall) {
52784
- toInstall.push(buildOrchestrationMcpComponent(scope));
52785
- }
52786
- if (needMemoryMcpInstall) {
52787
- toInstall.push(buildMemoryMcpComponent(scope));
52788
- }
52940
+ toInstall.push(...builtinInstall);
52789
52941
  const opts = {
52790
52942
  cwd: cwd2,
52791
52943
  scope,
@@ -52801,6 +52953,9 @@ async function runAgentPull(cwd2, args) {
52801
52953
  f2.warn(`Skipped: ${result2.skipped.map((s3) => `${s3.type}/${s3.slug} (${s3.reason})`).join(", ")}`);
52802
52954
  }
52803
52955
  }
52956
+ if (builtinRemoveSlugs.length > 0) {
52957
+ runHarnessRemoveMcp(harness, builtinRemoveSlugs, { cwd: cwd2, scope });
52958
+ }
52804
52959
  for (const r2 of removeRows) {
52805
52960
  const prior = lock?.components.find((c2) => c2.type === r2.type && c2.slug === r2.slug);
52806
52961
  if (!prior)
@@ -53053,6 +53208,7 @@ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
53053
53208
  entry.is_enabled = payload.is_enabled;
53054
53209
  return entry;
53055
53210
  });
53211
+ const caps = capabilitiesFromAgent(cloudAgent);
53056
53212
  return {
53057
53213
  schema: 1,
53058
53214
  id: cloudAgent.id,
@@ -53065,7 +53221,8 @@ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
53065
53221
  ...entrypoint ? { entrypoint } : {},
53066
53222
  playbooks,
53067
53223
  skills,
53068
- mcp
53224
+ mcp,
53225
+ capabilities: { memory: caps.memory, browser: caps.browser, slack: caps.slack }
53069
53226
  };
53070
53227
  }
53071
53228
  function materializeEntrypoint(cwd2, cloudEntrypoint, prev) {
@@ -54366,12 +54523,14 @@ async function runAgentUnpack(cwd2, args) {
54366
54523
  checksum: ""
54367
54524
  });
54368
54525
  }
54369
- const haveOrchMcp = (manifest.mcp ?? []).some((m3) => m3.name === ORCHESTRATION_MCP_SLUG);
54370
- const haveMemoryMcp = (manifest.mcp ?? []).some((m3) => m3.name === MEMORY_MCP_SLUG);
54371
- if (!haveOrchMcp)
54372
- toInstall.push(buildOrchestrationMcpComponent(scope));
54373
- if (!haveMemoryMcp)
54374
- toInstall.push(buildMemoryMcpComponent(scope));
54526
+ const caps = capabilitiesFromManifest(manifest);
54527
+ const declaredMcpSlugs = new Set((manifest.mcp ?? []).map((m3) => m3.name));
54528
+ const { install: builtinInstall, removeSlugs: builtinRemoveSlugs } = resolveBuiltinMcps({
54529
+ caps,
54530
+ declaredSlugs: declaredMcpSlugs,
54531
+ scope
54532
+ });
54533
+ toInstall.push(...builtinInstall);
54375
54534
  const opts = {
54376
54535
  cwd: cwd2,
54377
54536
  scope,
@@ -54385,6 +54544,9 @@ async function runAgentUnpack(cwd2, args) {
54385
54544
  if (result2.skipped.length) {
54386
54545
  f2.warn(`Skipped: ${result2.skipped.map((s3) => `${s3.type}/${s3.slug} (${s3.reason})`).join(", ")}`);
54387
54546
  }
54547
+ if (builtinRemoveSlugs.length > 0) {
54548
+ runHarnessRemoveMcp(harness, builtinRemoveSlugs, { cwd: cwd2, scope });
54549
+ }
54388
54550
  } catch (err) {
54389
54551
  f2.error(`Install failed: ${err.message}`);
54390
54552
  return;
@@ -54813,12 +54975,15 @@ async function installAgentFresh(input) {
54813
54975
  ensureDir(cwd2);
54814
54976
  const stageRoot = stageManifestComponents2(cloud.components);
54815
54977
  const justInstalledPaths = new Map;
54816
- const cloudHasOrchestrationMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === ORCHESTRATION_MCP_SLUG);
54817
- const needOrchestrationMcpInstall = !cloudHasOrchestrationMcp;
54818
- const cloudHasMemoryMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === MEMORY_MCP_SLUG);
54819
- const needMemoryMcpInstall = !cloudHasMemoryMcp;
54978
+ const caps = capabilitiesFromAgent(agent);
54979
+ const declaredMcpSlugs = new Set(cloud.components.filter((c2) => c2.type === "mcp").map((c2) => c2.slug));
54980
+ const { install: builtinInstall } = resolveBuiltinMcps({
54981
+ caps,
54982
+ declaredSlugs: declaredMcpSlugs,
54983
+ scope
54984
+ });
54820
54985
  try {
54821
- if (cloud.components.length > 0 || needOrchestrationMcpInstall || needMemoryMcpInstall) {
54986
+ if (cloud.components.length > 0 || builtinInstall.length > 0) {
54822
54987
  const toInstall = cloud.components.map((c2) => ({
54823
54988
  type: c2.type,
54824
54989
  slug: c2.slug,
@@ -54829,12 +54994,7 @@ async function installAgentFresh(input) {
54829
54994
  payload: proxifyMcpPayload(c2.meta?.mcp),
54830
54995
  checksum: c2.hash
54831
54996
  }));
54832
- if (needOrchestrationMcpInstall) {
54833
- toInstall.push(buildOrchestrationMcpComponent(scope));
54834
- }
54835
- if (needMemoryMcpInstall) {
54836
- toInstall.push(buildMemoryMcpComponent(scope));
54837
- }
54997
+ toInstall.push(...builtinInstall);
54838
54998
  const installOpts = {
54839
54999
  cwd: cwd2,
54840
55000
  scope,
@@ -54952,6 +55112,7 @@ function buildManifestFromCloud(cloud, agent) {
54952
55112
  entry.is_enabled = payload.is_enabled;
54953
55113
  return entry;
54954
55114
  });
55115
+ const caps = capabilitiesFromAgent(agent);
54955
55116
  return {
54956
55117
  schema: 1,
54957
55118
  agent: {
@@ -54961,7 +55122,8 @@ function buildManifestFromCloud(cloud, agent) {
54961
55122
  ...hasInstructions ? { instructions: { file: DEFAULT_INSTRUCTIONS_FILE } } : {},
54962
55123
  playbooks: [],
54963
55124
  skills,
54964
- mcp
55125
+ mcp,
55126
+ capabilities: { memory: caps.memory, browser: caps.browser, slack: caps.slack }
54965
55127
  };
54966
55128
  }
54967
55129
  async function pullAgentSecrets(cwd2, agentId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainbase-labs/cli",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
5
5
  "type": "module",
6
6
  "bin": {