@brainbase-labs/cli 0.8.3 → 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 +645 -232
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -28582,9 +28582,9 @@ var require_jsx_dev_runtime = __commonJS((exports, module) => {
28582
28582
  });
28583
28583
 
28584
28584
  // src/index.ts
28585
- var import_picocolors40 = __toESM(require_picocolors(), 1);
28585
+ var import_picocolors41 = __toESM(require_picocolors(), 1);
28586
28586
  import process14 from "node:process";
28587
- import fs51 from "node:fs";
28587
+ import fs52 from "node:fs";
28588
28588
 
28589
28589
  // src/cli/template.ts
28590
28590
  var import_picocolors12 = __toESM(require_picocolors(), 1);
@@ -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.8.3",
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;
@@ -54595,7 +54757,7 @@ function printHelp() {
54595
54757
  }
54596
54758
 
54597
54759
  // src/cli/orchestration.ts
54598
- var import_picocolors37 = __toESM(require_picocolors(), 1);
54760
+ var import_picocolors38 = __toESM(require_picocolors(), 1);
54599
54761
 
54600
54762
  // src/cli/orchestration-pull.ts
54601
54763
  import path54 from "node:path";
@@ -54625,11 +54787,24 @@ var EdgeSchema = exports_external.object({
54625
54787
  description: exports_external.string().optional(),
54626
54788
  payload_schema: exports_external.record(exports_external.unknown()).optional()
54627
54789
  });
54790
+ var TriggerEdgeSchema = exports_external.object({
54791
+ agent: exports_external.string(),
54792
+ description: exports_external.string().optional(),
54793
+ payload_schema: exports_external.record(exports_external.unknown()).optional()
54794
+ });
54795
+ var TriggerSchema = exports_external.object({
54796
+ type: exports_external.string(),
54797
+ node_id: exports_external.string(),
54798
+ is_active: exports_external.boolean().optional(),
54799
+ config: exports_external.record(exports_external.unknown()).optional(),
54800
+ to: exports_external.array(TriggerEdgeSchema).default([])
54801
+ });
54628
54802
  var OrchestrationManifestSchema = exports_external.object({
54629
54803
  schema: exports_external.literal(1),
54630
54804
  orchestration: OrchMetaSchema,
54631
54805
  members: exports_external.array(MemberSchema).default([]),
54632
- edges: exports_external.array(EdgeSchema).default([])
54806
+ edges: exports_external.array(EdgeSchema).default([]),
54807
+ triggers: exports_external.array(TriggerSchema).optional()
54633
54808
  });
54634
54809
  function orchManifestPath(cwd2) {
54635
54810
  return path51.join(cwd2, ORCH_MANIFEST_FILE);
@@ -54659,7 +54834,7 @@ function writeOrchManifest(cwd2, manifest) {
54659
54834
  doc.contents = manifest;
54660
54835
  doc.commentBefore = ` brainbase-orchestration.yaml — declarative orchestration manifest.
54661
54836
  ` + ` Committed to source control. Edit by hand, then
54662
- ` + " `brainbase orchestration push`. Member agents live under ./agents/.";
54837
+ ` + " `brainbase orchestration push`. Member agents live under ./agents/." + "\n A `triggers:` block (if present) is READ-ONLY — managed in the web app\n" + " and ignored by `orchestration push`.";
54663
54838
  fs47.writeFileSync(orchManifestPath(cwd2), String(doc), "utf8");
54664
54839
  }
54665
54840
  function memberDir(cwd2, slug) {
@@ -54669,6 +54844,9 @@ var MEMBER_SLUG_MAX = 50;
54669
54844
  function slugifyRaw(raw) {
54670
54845
  return (raw || "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
54671
54846
  }
54847
+ function slugifyMemberName(raw) {
54848
+ return slugifyRaw(raw) || "agent";
54849
+ }
54672
54850
  function resolveMemberSlugs(members) {
54673
54851
  const SAFE = /^[a-z0-9][a-z0-9-]*$/;
54674
54852
  const used = new Set;
@@ -54797,12 +54975,15 @@ async function installAgentFresh(input) {
54797
54975
  ensureDir(cwd2);
54798
54976
  const stageRoot = stageManifestComponents2(cloud.components);
54799
54977
  const justInstalledPaths = new Map;
54800
- const cloudHasOrchestrationMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === ORCHESTRATION_MCP_SLUG);
54801
- const needOrchestrationMcpInstall = !cloudHasOrchestrationMcp;
54802
- const cloudHasMemoryMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === MEMORY_MCP_SLUG);
54803
- 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
+ });
54804
54985
  try {
54805
- if (cloud.components.length > 0 || needOrchestrationMcpInstall || needMemoryMcpInstall) {
54986
+ if (cloud.components.length > 0 || builtinInstall.length > 0) {
54806
54987
  const toInstall = cloud.components.map((c2) => ({
54807
54988
  type: c2.type,
54808
54989
  slug: c2.slug,
@@ -54813,12 +54994,7 @@ async function installAgentFresh(input) {
54813
54994
  payload: proxifyMcpPayload(c2.meta?.mcp),
54814
54995
  checksum: c2.hash
54815
54996
  }));
54816
- if (needOrchestrationMcpInstall) {
54817
- toInstall.push(buildOrchestrationMcpComponent(scope));
54818
- }
54819
- if (needMemoryMcpInstall) {
54820
- toInstall.push(buildMemoryMcpComponent(scope));
54821
- }
54997
+ toInstall.push(...builtinInstall);
54822
54998
  const installOpts = {
54823
54999
  cwd: cwd2,
54824
55000
  scope,
@@ -54936,6 +55112,7 @@ function buildManifestFromCloud(cloud, agent) {
54936
55112
  entry.is_enabled = payload.is_enabled;
54937
55113
  return entry;
54938
55114
  });
55115
+ const caps = capabilitiesFromAgent(agent);
54939
55116
  return {
54940
55117
  schema: 1,
54941
55118
  agent: {
@@ -54945,7 +55122,8 @@ function buildManifestFromCloud(cloud, agent) {
54945
55122
  ...hasInstructions ? { instructions: { file: DEFAULT_INSTRUCTIONS_FILE } } : {},
54946
55123
  playbooks: [],
54947
55124
  skills,
54948
- mcp
55125
+ mcp,
55126
+ capabilities: { memory: caps.memory, browser: caps.browser, slack: caps.slack }
54949
55127
  };
54950
55128
  }
54951
55129
  async function pullAgentSecrets(cwd2, agentId) {
@@ -55092,7 +55270,20 @@ async function runOrchestrationPull(cwd2, args) {
55092
55270
  to: slugFor(e2.to_agent_id),
55093
55271
  ...e2.description ? { description: e2.description } : {},
55094
55272
  ...e2.payload_schema && Object.keys(e2.payload_schema).length ? { payload_schema: e2.payload_schema } : {}
55095
- }))
55273
+ })),
55274
+ ...cloud.triggers && cloud.triggers.length ? {
55275
+ triggers: cloud.triggers.map((t) => ({
55276
+ type: t.trigger_type,
55277
+ node_id: t.node_id,
55278
+ is_active: t.is_active,
55279
+ ...t.config && Object.keys(t.config).length ? { config: t.config } : {},
55280
+ to: t.edges.map((e2) => ({
55281
+ agent: slugFor(e2.to_agent_id),
55282
+ ...e2.description ? { description: e2.description } : {},
55283
+ ...e2.payload_schema && Object.keys(e2.payload_schema).length ? { payload_schema: e2.payload_schema } : {}
55284
+ }))
55285
+ }))
55286
+ } : {}
55096
55287
  };
55097
55288
  writeOrchManifest(cwd2, manifest);
55098
55289
  writeOrchLink(cwd2, {
@@ -55478,6 +55669,192 @@ function handleApiError7(err) {
55478
55669
  }
55479
55670
  }
55480
55671
 
55672
+ // src/cli/orchestration-add-agent.ts
55673
+ import fs51 from "node:fs";
55674
+ var import_picocolors37 = __toESM(require_picocolors(), 1);
55675
+
55676
+ // src/core/orchestration-add.ts
55677
+ function resolveOrgIdForGroup(groupId, orgsWithTeams) {
55678
+ for (const o2 of orgsWithTeams) {
55679
+ if (o2.teamIds.includes(groupId))
55680
+ return o2.orgId;
55681
+ }
55682
+ return null;
55683
+ }
55684
+ function parseEdgeSchema(raw) {
55685
+ if (!raw || !raw.trim())
55686
+ return;
55687
+ let parsed;
55688
+ try {
55689
+ parsed = JSON.parse(raw);
55690
+ } catch {
55691
+ throw new Error(`--schema is not valid JSON: ${raw}`);
55692
+ }
55693
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
55694
+ throw new Error(`--schema must be a JSON object, e.g. '{"field":"type"}'`);
55695
+ }
55696
+ return parsed;
55697
+ }
55698
+ function mergeMemberAndEdges(manifest, input) {
55699
+ const members = manifest.members.slice();
55700
+ if (!members.some((m3) => m3.slug === input.slug)) {
55701
+ members.push({
55702
+ slug: input.slug,
55703
+ ...input.name && input.name !== input.slug ? { name: input.name } : {}
55704
+ });
55705
+ }
55706
+ const memberSlugs = new Set(members.map((m3) => m3.slug));
55707
+ const newEdges = [];
55708
+ const addEdge = (from, to2) => {
55709
+ if (from === to2)
55710
+ throw new Error(`Edge ${from} → ${to2}: self-loops are not allowed.`);
55711
+ for (const slug of [from, to2]) {
55712
+ if (!memberSlugs.has(slug)) {
55713
+ throw new Error(`Edge endpoint "${slug}" is not a member. Members: ${[...memberSlugs].join(", ")}.`);
55714
+ }
55715
+ }
55716
+ const duplicate = manifest.edges.some((e2) => e2.from === from && e2.to === to2) || newEdges.some((e2) => e2.from === from && e2.to === to2);
55717
+ if (duplicate)
55718
+ return;
55719
+ newEdges.push({
55720
+ from,
55721
+ to: to2,
55722
+ ...input.description ? { description: input.description } : {},
55723
+ ...input.payloadSchema ? { payload_schema: input.payloadSchema } : {}
55724
+ });
55725
+ };
55726
+ for (const f4 of input.from)
55727
+ addEdge(f4, input.slug);
55728
+ for (const t of input.to)
55729
+ addEdge(input.slug, t);
55730
+ return { ...manifest, members, edges: [...manifest.edges, ...newEdges] };
55731
+ }
55732
+
55733
+ // src/cli/orchestration-add-agent.ts
55734
+ async function runOrchestrationAddAgent(cwd2, args) {
55735
+ banner("orchestration add-agent — create a member agent and wire it into the graph");
55736
+ const link2 = readOrchLink(cwd2);
55737
+ if (!link2 || !hasOrchManifest(cwd2)) {
55738
+ f2.warn("This folder is not a linked orchestration.");
55739
+ f2.info(`Run ${import_picocolors37.default.cyan("brainbase orchestration pull <id>")} first.`);
55740
+ return;
55741
+ }
55742
+ let manifest;
55743
+ try {
55744
+ manifest = readOrchManifest(cwd2);
55745
+ } catch (err) {
55746
+ f2.error(err.message);
55747
+ return;
55748
+ }
55749
+ let name = args.name?.trim();
55750
+ if (!name) {
55751
+ name = (await text({
55752
+ message: "New agent name",
55753
+ placeholder: "e.g. Refund Bot",
55754
+ validate: (v3) => !v3?.trim() ? "Required" : undefined,
55755
+ flagHint: "Pass the name positionally or with --name."
55756
+ })).trim();
55757
+ }
55758
+ let slug = slugifyMemberName(name);
55759
+ if (manifest.members.some((m3) => m3.slug === slug) || fs51.existsSync(memberDir(cwd2, slug))) {
55760
+ let n = 2;
55761
+ let candidate = `${slug}-${n}`;
55762
+ while (manifest.members.some((m3) => m3.slug === candidate) || fs51.existsSync(memberDir(cwd2, candidate))) {
55763
+ candidate = `${slug}-${++n}`;
55764
+ }
55765
+ f2.info(`Slug ${import_picocolors37.default.bold(slug)} is taken — using ${import_picocolors37.default.bold(candidate)}.`);
55766
+ slug = candidate;
55767
+ }
55768
+ let payloadSchema;
55769
+ try {
55770
+ payloadSchema = parseEdgeSchema(args.schema);
55771
+ } catch (err) {
55772
+ f2.error(err.message);
55773
+ return;
55774
+ }
55775
+ let orgId = args.orgId;
55776
+ if (!orgId) {
55777
+ const sp = de();
55778
+ sp.start("Resolving org for this orchestration…");
55779
+ try {
55780
+ const orgs = await api.listOrgs();
55781
+ const orgsWithTeams = [];
55782
+ for (const o2 of orgs) {
55783
+ const teams = await api.listTeams(o2.id);
55784
+ orgsWithTeams.push({ orgId: o2.id, teamIds: teams.map((t) => t.id) });
55785
+ }
55786
+ const resolved = resolveOrgIdForGroup(link2.group_id, orgsWithTeams);
55787
+ if (!resolved) {
55788
+ sp.stop("Failed.");
55789
+ f2.error(`Could not find an org that owns group ${import_picocolors37.default.bold(link2.group_id)}. ` + `Pass ${import_picocolors37.default.cyan("--org <id>")} explicitly.`);
55790
+ return;
55791
+ }
55792
+ orgId = resolved;
55793
+ sp.stop("Resolved org.");
55794
+ } catch (err) {
55795
+ sp.stop("Failed.");
55796
+ f2.error(err.message);
55797
+ return;
55798
+ }
55799
+ }
55800
+ let from = args.from ?? [];
55801
+ let to2 = args.to ?? [];
55802
+ let description = args.description;
55803
+ if (from.length === 0 && to2.length === 0 && isInteractive() && manifest.members.length > 0) {
55804
+ const memberOptions = manifest.members.map((m3) => ({ value: m3.slug, label: m3.slug }));
55805
+ const pickedFrom = await ae({
55806
+ message: `Connect ${import_picocolors37.default.bold(slug)} FROM which member(s)? — edges INTO ${slug} (space to select, enter to skip)`,
55807
+ options: memberOptions,
55808
+ required: false
55809
+ });
55810
+ if (Array.isArray(pickedFrom))
55811
+ from = pickedFrom;
55812
+ const pickedTo = await ae({
55813
+ message: `Connect ${import_picocolors37.default.bold(slug)} TO which member(s)? — edges OUT of ${slug} (space to select, enter to skip)`,
55814
+ options: memberOptions,
55815
+ required: false
55816
+ });
55817
+ if (Array.isArray(pickedTo))
55818
+ to2 = pickedTo;
55819
+ if ((from.length > 0 || to2.length > 0) && description === undefined) {
55820
+ const d3 = await te({ message: "Edge description (optional)" });
55821
+ if (typeof d3 === "string" && d3.trim())
55822
+ description = d3.trim();
55823
+ }
55824
+ }
55825
+ let updated;
55826
+ try {
55827
+ updated = mergeMemberAndEdges(manifest, { slug, name, from, to: to2, description, payloadSchema });
55828
+ } catch (err) {
55829
+ f2.error(err.message);
55830
+ return;
55831
+ }
55832
+ const dest = memberDir(cwd2, slug);
55833
+ try {
55834
+ fs51.mkdirSync(dest, { recursive: true });
55835
+ await runAgentCreate(dest, {
55836
+ name,
55837
+ orgId,
55838
+ teamId: link2.group_id,
55839
+ harness: args.harness,
55840
+ yes: true,
55841
+ noTracking: true
55842
+ });
55843
+ } catch (err) {
55844
+ try {
55845
+ fs51.rmSync(dest, { recursive: true, force: true });
55846
+ } catch {}
55847
+ f2.error(`Failed to create ${slug}: ${err.message}`);
55848
+ return;
55849
+ }
55850
+ writeOrchManifest(cwd2, updated);
55851
+ if (args.noPush) {
55852
+ f2.info(`Manifest updated. Run ${import_picocolors37.default.cyan("brainbase orchestration push")} to apply.`);
55853
+ return;
55854
+ }
55855
+ await runOrchestrationPush(cwd2, { yes: true, graphOnly: true });
55856
+ }
55857
+
55481
55858
  // src/cli/orchestration.ts
55482
55859
  async function runOrchestration(cwd2, sub, args, opts) {
55483
55860
  switch (sub) {
@@ -55501,6 +55878,20 @@ async function runOrchestration(cwd2, sub, args, opts) {
55501
55878
  case "ls":
55502
55879
  await runOrchestrationList({ orgId: opts.orgId, teamId: opts.teamId });
55503
55880
  return;
55881
+ case "add-agent":
55882
+ case "add":
55883
+ await runOrchestrationAddAgent(cwd2, {
55884
+ name: args[0] ?? opts.name,
55885
+ from: opts.from,
55886
+ to: opts.to,
55887
+ description: opts.description,
55888
+ schema: opts.schema,
55889
+ harness: opts.harness,
55890
+ orgId: opts.orgId,
55891
+ noPush: opts.noPush,
55892
+ yes: opts.yes
55893
+ });
55894
+ return;
55504
55895
  case undefined:
55505
55896
  case "help":
55506
55897
  case "-h":
@@ -55517,19 +55908,20 @@ async function runOrchestration(cwd2, sub, args, opts) {
55517
55908
  function printHelp2() {
55518
55909
  const out = [];
55519
55910
  out.push("");
55520
- out.push(` ${import_picocolors37.default.bold("brainbase orchestration")} ${import_picocolors37.default.dim("<sub> [options]")}`);
55911
+ out.push(` ${import_picocolors38.default.bold("brainbase orchestration")} ${import_picocolors38.default.dim("<sub> [options]")}`);
55521
55912
  out.push("");
55522
- out.push(` ${import_picocolors37.default.cyan("pull")} ${import_picocolors37.default.dim("<id>")} ${import_picocolors37.default.dim("fetch orchestration + every member agent into this folder")}`);
55523
- out.push(` ${import_picocolors37.default.cyan("push")} ${import_picocolors37.default.dim("push each member, then update the orchestration graph")}`);
55524
- out.push(` ${import_picocolors37.default.cyan("status")} ${import_picocolors37.default.dim("show what would push and what would pull")}`);
55525
- out.push(` ${import_picocolors37.default.cyan("list")} ${import_picocolors37.default.dim("list orchestrations under a team")}`);
55913
+ out.push(` ${import_picocolors38.default.cyan("pull")} ${import_picocolors38.default.dim("<id>")} ${import_picocolors38.default.dim("fetch orchestration + every member agent into this folder")}`);
55914
+ out.push(` ${import_picocolors38.default.cyan("push")} ${import_picocolors38.default.dim("push each member, then update the orchestration graph")}`);
55915
+ out.push(` ${import_picocolors38.default.cyan("add-agent")} ${import_picocolors38.default.dim("<name>")} ${import_picocolors38.default.dim("create a member agent, wire edges (--from/--to), and push")}`);
55916
+ out.push(` ${import_picocolors38.default.cyan("status")} ${import_picocolors38.default.dim("show what would push and what would pull")}`);
55917
+ out.push(` ${import_picocolors38.default.cyan("list")} ${import_picocolors38.default.dim("list orchestrations under a team")}`);
55526
55918
  out.push("");
55527
- out.push(` ${import_picocolors37.default.bold("Flags")}`);
55528
- out.push(` ${import_picocolors37.default.dim("--yes, -y")} skip confirmations`);
55529
- out.push(` ${import_picocolors37.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
55530
- out.push(` ${import_picocolors37.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`);
55531
- out.push(` ${import_picocolors37.default.dim("--org <id>")} for list: org id (CLI vocab — DB teams.id)`);
55532
- out.push(` ${import_picocolors37.default.dim("--team <id>")} for list: team id (CLI vocab — DB groups.id)`);
55919
+ out.push(` ${import_picocolors38.default.bold("Flags")}`);
55920
+ out.push(` ${import_picocolors38.default.dim("--yes, -y")} skip confirmations`);
55921
+ out.push(` ${import_picocolors38.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
55922
+ out.push(` ${import_picocolors38.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`);
55923
+ out.push(` ${import_picocolors38.default.dim("--org <id>")} for list: org id (CLI vocab — DB teams.id)`);
55924
+ out.push(` ${import_picocolors38.default.dim("--team <id>")} for list: team id (CLI vocab — DB groups.id)`);
55533
55925
  out.push("");
55534
55926
  console.log(out.join(`
55535
55927
  `));
@@ -55574,16 +55966,16 @@ async function runRun(cwd2, args) {
55574
55966
  }
55575
55967
 
55576
55968
  // src/cli/publish.ts
55577
- var import_picocolors38 = __toESM(require_picocolors(), 1);
55969
+ var import_picocolors39 = __toESM(require_picocolors(), 1);
55578
55970
  async function runPublish(cwd2, _args) {
55579
55971
  banner("publish — send your changes to the team");
55580
55972
  const link2 = readLink(cwd2);
55581
55973
  if (!link2) {
55582
55974
  f2.warn("This folder is not linked to any agent.");
55583
- f2.info(`Run ${import_picocolors38.default.cyan("brainbase link")} first.`);
55975
+ f2.info(`Run ${import_picocolors39.default.cyan("brainbase link")} first.`);
55584
55976
  return;
55585
55977
  }
55586
- f2.info(`${import_picocolors38.default.bold("publish")} is coming soon — for now, edit the agent on the web app and run ${import_picocolors38.default.cyan("brainbase sync")} to bring changes here.`);
55978
+ f2.info(`${import_picocolors39.default.bold("publish")} is coming soon — for now, edit the agent on the web app and run ${import_picocolors39.default.cyan("brainbase sync")} to bring changes here.`);
55587
55979
  }
55588
55980
 
55589
55981
  // src/ui/ink/StatusCard.tsx
@@ -55881,7 +56273,7 @@ async function runStatus(cwd2) {
55881
56273
  }
55882
56274
 
55883
56275
  // src/cli/token.ts
55884
- var import_picocolors39 = __toESM(require_picocolors(), 1);
56276
+ var import_picocolors40 = __toESM(require_picocolors(), 1);
55885
56277
 
55886
56278
  // src/ui/ink/TokenCards.tsx
55887
56279
  var jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
@@ -56175,7 +56567,7 @@ async function runTokenRevoke(args) {
56175
56567
  }
56176
56568
  if (!autoProceed(args.yes)) {
56177
56569
  const ok = await se({
56178
- message: `Revoke token ${import_picocolors39.default.bold(args.id)}? CIs and machines using it will stop working.`,
56570
+ message: `Revoke token ${import_picocolors40.default.bold(args.id)}? CIs and machines using it will stop working.`,
56179
56571
  initialValue: false
56180
56572
  });
56181
56573
  if (!ensureNotCancelled(ok))
@@ -56190,7 +56582,7 @@ async function runTokenRevoke(args) {
56190
56582
  }
56191
56583
  async function runTokenClear() {
56192
56584
  if (!readToken()) {
56193
- console.log(import_picocolors39.default.dim("No local token stored."));
56585
+ console.log(import_picocolors40.default.dim("No local token stored."));
56194
56586
  return;
56195
56587
  }
56196
56588
  clearToken();
@@ -56241,17 +56633,17 @@ async function runToken(sub, rest2, args) {
56241
56633
  function printTokenHelp() {
56242
56634
  const out = [];
56243
56635
  out.push("");
56244
- out.push(` ${import_picocolors39.default.bold("brainbase token")} ${import_picocolors39.default.dim("<command>")}`);
56636
+ out.push(` ${import_picocolors40.default.bold("brainbase token")} ${import_picocolors40.default.dim("<command>")}`);
56245
56637
  out.push("");
56246
- out.push(` ${import_picocolors39.default.cyan("create")} ${import_picocolors39.default.dim("issue a new long-lived CLI key (PAT)")}`);
56247
- out.push(` ${import_picocolors39.default.cyan("list")} ${import_picocolors39.default.dim("show your active tokens")}`);
56248
- out.push(` ${import_picocolors39.default.cyan("revoke")} ${import_picocolors39.default.dim("<id>")} ${import_picocolors39.default.dim("revoke a token by id")}`);
56249
- out.push(` ${import_picocolors39.default.cyan("clear")} ${import_picocolors39.default.dim("forget the local token (does not revoke)")}`);
56638
+ out.push(` ${import_picocolors40.default.cyan("create")} ${import_picocolors40.default.dim("issue a new long-lived CLI key (PAT)")}`);
56639
+ out.push(` ${import_picocolors40.default.cyan("list")} ${import_picocolors40.default.dim("show your active tokens")}`);
56640
+ out.push(` ${import_picocolors40.default.cyan("revoke")} ${import_picocolors40.default.dim("<id>")} ${import_picocolors40.default.dim("revoke a token by id")}`);
56641
+ out.push(` ${import_picocolors40.default.cyan("clear")} ${import_picocolors40.default.dim("forget the local token (does not revoke)")}`);
56250
56642
  out.push("");
56251
- out.push(` ${import_picocolors39.default.bold("create flags")}`);
56252
- out.push(` ${import_picocolors39.default.cyan("--name, -n")} ${import_picocolors39.default.dim("<label>")} ${import_picocolors39.default.dim("token label (prompted if omitted)")}`);
56253
- out.push(` ${import_picocolors39.default.cyan("--scopes")} ${import_picocolors39.default.dim("<list>")} ${import_picocolors39.default.dim("comma-separated; allowed: read, publish, admin")}`);
56254
- out.push(` ${import_picocolors39.default.dim("default: read,publish")}`);
56643
+ out.push(` ${import_picocolors40.default.bold("create flags")}`);
56644
+ out.push(` ${import_picocolors40.default.cyan("--name, -n")} ${import_picocolors40.default.dim("<label>")} ${import_picocolors40.default.dim("token label (prompted if omitted)")}`);
56645
+ out.push(` ${import_picocolors40.default.cyan("--scopes")} ${import_picocolors40.default.dim("<list>")} ${import_picocolors40.default.dim("comma-separated; allowed: read, publish, admin")}`);
56646
+ out.push(` ${import_picocolors40.default.dim("default: read,publish")}`);
56255
56647
  out.push("");
56256
56648
  console.log(out.join(`
56257
56649
  `));
@@ -56271,92 +56663,92 @@ var PROTECTED = new Set([
56271
56663
  function help() {
56272
56664
  const out = [];
56273
56665
  out.push("");
56274
- out.push(` ${brandTint("◆")} ${import_picocolors40.default.bold("brainbase")} ${import_picocolors40.default.dim(`v${VERSION}`)}`);
56275
- out.push(` ${import_picocolors40.default.dim("connect your local agent to the brainbase platform")}`);
56666
+ out.push(` ${brandTint("◆")} ${import_picocolors41.default.bold("brainbase")} ${import_picocolors41.default.dim(`v${VERSION}`)}`);
56667
+ out.push(` ${import_picocolors41.default.dim("connect your local agent to the brainbase platform")}`);
56276
56668
  out.push("");
56277
56669
  out.push(divider("USAGE"));
56278
56670
  out.push("");
56279
- out.push(` ${import_picocolors40.default.bold("brainbase")} ${import_picocolors40.default.dim("<command> [options]")}`);
56671
+ out.push(` ${import_picocolors41.default.bold("brainbase")} ${import_picocolors41.default.dim("<command> [options]")}`);
56280
56672
  out.push("");
56281
56673
  out.push(divider("AUTH"));
56282
56674
  out.push("");
56283
- out.push(` ${import_picocolors40.default.cyan("login")} ${import_picocolors40.default.dim(" open the web app and connect this device")}`);
56284
- out.push(` ${import_picocolors40.default.cyan("logout")} ${import_picocolors40.default.dim(" clear the local session")}`);
56285
- out.push(` ${import_picocolors40.default.cyan("whoami")} ${import_picocolors40.default.dim(" show the current user")}`);
56675
+ out.push(` ${import_picocolors41.default.cyan("login")} ${import_picocolors41.default.dim(" open the web app and connect this device")}`);
56676
+ out.push(` ${import_picocolors41.default.cyan("logout")} ${import_picocolors41.default.dim(" clear the local session")}`);
56677
+ out.push(` ${import_picocolors41.default.cyan("whoami")} ${import_picocolors41.default.dim(" show the current user")}`);
56286
56678
  out.push("");
56287
56679
  out.push(divider("LINKED AGENT"));
56288
56680
  out.push("");
56289
- out.push(` ${import_picocolors40.default.cyan("agent create")} ${import_picocolors40.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
56290
- out.push(` ${import_picocolors40.default.cyan("agent pull")} ${import_picocolors40.default.dim("[<id>]")} ${import_picocolors40.default.dim("bring cloud changes into this folder (--force to override)")}`);
56291
- out.push(` ${import_picocolors40.default.cyan("agent push")} ${import_picocolors40.default.dim("send local changes to the cloud")}`);
56292
- out.push(` ${import_picocolors40.default.cyan("agent unpack")} ${import_picocolors40.default.dim("install the claimed agent into a harness layout")}`);
56293
- out.push(` ${import_picocolors40.default.cyan("link")} ${import_picocolors40.default.dim("attach this folder to an existing agent")}`);
56294
- out.push(` ${import_picocolors40.default.cyan("agent status")} ${import_picocolors40.default.dim("show what would pull and what would push")}`);
56295
- out.push(` ${import_picocolors40.default.cyan("agent env")} ${import_picocolors40.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
56296
- out.push(` ${import_picocolors40.default.cyan("run")} ${import_picocolors40.default.dim("<cmd> [args...]")} ${import_picocolors40.default.dim("run <cmd> with secrets.env loaded into env")}`);
56297
- out.push(` ${import_picocolors40.default.cyan("status")} ${import_picocolors40.default.dim("show what this folder is linked to")}`);
56298
- out.push(` ${import_picocolors40.default.cyan("unlink")} ${import_picocolors40.default.dim("disconnect this folder")}`);
56681
+ out.push(` ${import_picocolors41.default.cyan("agent create")} ${import_picocolors41.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
56682
+ out.push(` ${import_picocolors41.default.cyan("agent pull")} ${import_picocolors41.default.dim("[<id>]")} ${import_picocolors41.default.dim("bring cloud changes into this folder (--force to override)")}`);
56683
+ out.push(` ${import_picocolors41.default.cyan("agent push")} ${import_picocolors41.default.dim("send local changes to the cloud")}`);
56684
+ out.push(` ${import_picocolors41.default.cyan("agent unpack")} ${import_picocolors41.default.dim("install the claimed agent into a harness layout")}`);
56685
+ out.push(` ${import_picocolors41.default.cyan("link")} ${import_picocolors41.default.dim("attach this folder to an existing agent")}`);
56686
+ out.push(` ${import_picocolors41.default.cyan("agent status")} ${import_picocolors41.default.dim("show what would pull and what would push")}`);
56687
+ out.push(` ${import_picocolors41.default.cyan("agent env")} ${import_picocolors41.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
56688
+ out.push(` ${import_picocolors41.default.cyan("run")} ${import_picocolors41.default.dim("<cmd> [args...]")} ${import_picocolors41.default.dim("run <cmd> with secrets.env loaded into env")}`);
56689
+ out.push(` ${import_picocolors41.default.cyan("status")} ${import_picocolors41.default.dim("show what this folder is linked to")}`);
56690
+ out.push(` ${import_picocolors41.default.cyan("unlink")} ${import_picocolors41.default.dim("disconnect this folder")}`);
56299
56691
  out.push("");
56300
56692
  out.push(divider("ORCHESTRATIONS"));
56301
56693
  out.push("");
56302
- out.push(` ${import_picocolors40.default.cyan("orchestration list")} ${import_picocolors40.default.dim("list orchestrations under a team")}`);
56303
- out.push(` ${import_picocolors40.default.cyan("orchestration pull")} ${import_picocolors40.default.dim("<id>")} ${import_picocolors40.default.dim("recursively fetch an orchestration + every member agent")}`);
56304
- out.push(` ${import_picocolors40.default.cyan("orchestration push")} ${import_picocolors40.default.dim("recursively push each member, then update the graph")}`);
56305
- out.push(` ${import_picocolors40.default.cyan("orchestration status")} ${import_picocolors40.default.dim("show what would push and what would pull")}`);
56694
+ out.push(` ${import_picocolors41.default.cyan("orchestration list")} ${import_picocolors41.default.dim("list orchestrations under a team")}`);
56695
+ out.push(` ${import_picocolors41.default.cyan("orchestration pull")} ${import_picocolors41.default.dim("<id>")} ${import_picocolors41.default.dim("recursively fetch an orchestration + every member agent")}`);
56696
+ out.push(` ${import_picocolors41.default.cyan("orchestration push")} ${import_picocolors41.default.dim("recursively push each member, then update the graph")}`);
56697
+ out.push(` ${import_picocolors41.default.cyan("orchestration status")} ${import_picocolors41.default.dim("show what would push and what would pull")}`);
56306
56698
  out.push("");
56307
56699
  out.push(divider("TEMPLATES"));
56308
56700
  out.push("");
56309
- out.push(` ${import_picocolors40.default.cyan("template pack")} ${import_picocolors40.default.dim("bundle the current agent into a template")}`);
56310
- out.push(` ${import_picocolors40.default.cyan("template publish")} ${import_picocolors40.default.dim("upload a template to the registry")}`);
56311
- out.push(` ${import_picocolors40.default.cyan("template search")} ${import_picocolors40.default.dim("[query]")} ${import_picocolors40.default.dim("search the registry")}`);
56312
- out.push(` ${import_picocolors40.default.cyan("template info")} ${import_picocolors40.default.dim("<creator/slug>")} ${import_picocolors40.default.dim("show registry details for a template")}`);
56313
- out.push(` ${import_picocolors40.default.cyan("template onboard")} ${import_picocolors40.default.dim("<creator/slug>")} ${import_picocolors40.default.dim("install (or refresh) a template")}`);
56314
- out.push(` ${import_picocolors40.default.cyan("template list")} ${import_picocolors40.default.dim("show installed templates")}`);
56315
- out.push(` ${import_picocolors40.default.cyan("template remove")} ${import_picocolors40.default.dim("<creator/slug>")} ${import_picocolors40.default.dim("uninstall a template")}`);
56701
+ out.push(` ${import_picocolors41.default.cyan("template pack")} ${import_picocolors41.default.dim("bundle the current agent into a template")}`);
56702
+ out.push(` ${import_picocolors41.default.cyan("template publish")} ${import_picocolors41.default.dim("upload a template to the registry")}`);
56703
+ out.push(` ${import_picocolors41.default.cyan("template search")} ${import_picocolors41.default.dim("[query]")} ${import_picocolors41.default.dim("search the registry")}`);
56704
+ out.push(` ${import_picocolors41.default.cyan("template info")} ${import_picocolors41.default.dim("<creator/slug>")} ${import_picocolors41.default.dim("show registry details for a template")}`);
56705
+ out.push(` ${import_picocolors41.default.cyan("template onboard")} ${import_picocolors41.default.dim("<creator/slug>")} ${import_picocolors41.default.dim("install (or refresh) a template")}`);
56706
+ out.push(` ${import_picocolors41.default.cyan("template list")} ${import_picocolors41.default.dim("show installed templates")}`);
56707
+ out.push(` ${import_picocolors41.default.cyan("template remove")} ${import_picocolors41.default.dim("<creator/slug>")} ${import_picocolors41.default.dim("uninstall a template")}`);
56316
56708
  out.push("");
56317
56709
  out.push(divider("SKILLS"));
56318
56710
  out.push("");
56319
- out.push(` ${import_picocolors40.default.cyan("skill add")} ${import_picocolors40.default.dim("<source>")} ${import_picocolors40.default.dim("install a skill (github / git / brainbase)")}`);
56320
- out.push(` ${import_picocolors40.default.cyan("skill list")} ${import_picocolors40.default.dim("show locally installed skills + their source")}`);
56321
- out.push(` ${import_picocolors40.default.cyan("skill update")} ${import_picocolors40.default.dim("<slug>")} ${import_picocolors40.default.dim("re-fetch a skill from its recorded source")}`);
56322
- out.push(` ${import_picocolors40.default.cyan("skill remove")} ${import_picocolors40.default.dim("<slug>")} ${import_picocolors40.default.dim("uninstall a skill")}`);
56323
- out.push(` ${import_picocolors40.default.cyan("skill search")} ${import_picocolors40.default.dim("[query]")} ${import_picocolors40.default.dim("search the brainbase skill registry")}`);
56324
- out.push(` ${import_picocolors40.default.cyan("skill info")} ${import_picocolors40.default.dim("<creator/slug>")} ${import_picocolors40.default.dim("show registry details for a skill")}`);
56325
- out.push(` ${import_picocolors40.default.cyan("skill publish")} ${import_picocolors40.default.dim("[dir]")} ${import_picocolors40.default.dim("publish a SKILL.md folder (defaults to .)")}`);
56711
+ out.push(` ${import_picocolors41.default.cyan("skill add")} ${import_picocolors41.default.dim("<source>")} ${import_picocolors41.default.dim("install a skill (github / git / brainbase)")}`);
56712
+ out.push(` ${import_picocolors41.default.cyan("skill list")} ${import_picocolors41.default.dim("show locally installed skills + their source")}`);
56713
+ out.push(` ${import_picocolors41.default.cyan("skill update")} ${import_picocolors41.default.dim("<slug>")} ${import_picocolors41.default.dim("re-fetch a skill from its recorded source")}`);
56714
+ out.push(` ${import_picocolors41.default.cyan("skill remove")} ${import_picocolors41.default.dim("<slug>")} ${import_picocolors41.default.dim("uninstall a skill")}`);
56715
+ out.push(` ${import_picocolors41.default.cyan("skill search")} ${import_picocolors41.default.dim("[query]")} ${import_picocolors41.default.dim("search the brainbase skill registry")}`);
56716
+ out.push(` ${import_picocolors41.default.cyan("skill info")} ${import_picocolors41.default.dim("<creator/slug>")} ${import_picocolors41.default.dim("show registry details for a skill")}`);
56717
+ out.push(` ${import_picocolors41.default.cyan("skill publish")} ${import_picocolors41.default.dim("[dir]")} ${import_picocolors41.default.dim("publish a SKILL.md folder (defaults to .)")}`);
56326
56718
  out.push("");
56327
56719
  out.push(divider("CLI TOKENS"));
56328
56720
  out.push("");
56329
- out.push(` ${import_picocolors40.default.cyan("token create")} ${import_picocolors40.default.dim("issue a long-lived CLI key for CI / scripts")}`);
56330
- out.push(` ${import_picocolors40.default.cyan("token list")} ${import_picocolors40.default.dim("show your active tokens")}`);
56331
- out.push(` ${import_picocolors40.default.cyan("token revoke")} ${import_picocolors40.default.dim("<id>")} ${import_picocolors40.default.dim("revoke a token")}`);
56721
+ out.push(` ${import_picocolors41.default.cyan("token create")} ${import_picocolors41.default.dim("issue a long-lived CLI key for CI / scripts")}`);
56722
+ out.push(` ${import_picocolors41.default.cyan("token list")} ${import_picocolors41.default.dim("show your active tokens")}`);
56723
+ out.push(` ${import_picocolors41.default.cyan("token revoke")} ${import_picocolors41.default.dim("<id>")} ${import_picocolors41.default.dim("revoke a token")}`);
56332
56724
  out.push("");
56333
56725
  out.push(divider("FLAGS"));
56334
56726
  out.push("");
56335
- out.push(` ${import_picocolors40.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
56336
- out.push(` ${import_picocolors40.default.dim("--scope <s>")} force scope: global | project`);
56337
- out.push(` ${import_picocolors40.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
56338
- out.push(` ${import_picocolors40.default.dim("--agent <id>")} for link: attach this folder to an existing agent non-interactively`);
56339
- out.push(` ${import_picocolors40.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
56340
- out.push(` ${import_picocolors40.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
56341
- out.push(` ${import_picocolors40.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
56342
- out.push(` ${import_picocolors40.default.dim("--all")} for template list: include installs from other folders`);
56343
- out.push(` ${import_picocolors40.default.dim("--web <url>")} for login: web app URL (default https://new.usekafka.com)`);
56727
+ out.push(` ${import_picocolors41.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
56728
+ out.push(` ${import_picocolors41.default.dim("--scope <s>")} force scope: global | project`);
56729
+ out.push(` ${import_picocolors41.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
56730
+ out.push(` ${import_picocolors41.default.dim("--agent <id>")} for link: attach this folder to an existing agent non-interactively`);
56731
+ out.push(` ${import_picocolors41.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
56732
+ out.push(` ${import_picocolors41.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
56733
+ out.push(` ${import_picocolors41.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
56734
+ out.push(` ${import_picocolors41.default.dim("--all")} for template list: include installs from other folders`);
56735
+ out.push(` ${import_picocolors41.default.dim("--web <url>")} for login: web app URL (default https://new.usekafka.com)`);
56344
56736
  out.push("");
56345
56737
  out.push(divider("ENV"));
56346
56738
  out.push("");
56347
- out.push(` ${import_picocolors40.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
56348
- out.push(` ${import_picocolors40.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
56349
- out.push(` ${import_picocolors40.default.dim("BRAINBASE_API_URL")} override the API URL used by link / sync`);
56350
- out.push(` ${import_picocolors40.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL`);
56351
- out.push(` ${import_picocolors40.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
56352
- out.push(` ${import_picocolors40.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
56353
- out.push(` ${import_picocolors40.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
56739
+ out.push(` ${import_picocolors41.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
56740
+ out.push(` ${import_picocolors41.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
56741
+ out.push(` ${import_picocolors41.default.dim("BRAINBASE_API_URL")} override the API URL used by link / sync`);
56742
+ out.push(` ${import_picocolors41.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL`);
56743
+ out.push(` ${import_picocolors41.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
56744
+ out.push(` ${import_picocolors41.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
56745
+ out.push(` ${import_picocolors41.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
56354
56746
  out.push("");
56355
56747
  out.push(divider("HARNESSES"));
56356
56748
  out.push("");
56357
- out.push(` ${import_picocolors40.default.dim("•")} ${import_picocolors40.default.bold("claude-code")} ${import_picocolors40.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
56358
- out.push(` ${import_picocolors40.default.dim("•")} ${import_picocolors40.default.bold("codex")} ${import_picocolors40.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
56359
- out.push(` ${import_picocolors40.default.dim("•")} ${import_picocolors40.default.bold("kafka")} ${import_picocolors40.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
56749
+ out.push(` ${import_picocolors41.default.dim("•")} ${import_picocolors41.default.bold("claude-code")} ${import_picocolors41.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
56750
+ out.push(` ${import_picocolors41.default.dim("•")} ${import_picocolors41.default.bold("codex")} ${import_picocolors41.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
56751
+ out.push(` ${import_picocolors41.default.dim("•")} ${import_picocolors41.default.bold("kafka")} ${import_picocolors41.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
56360
56752
  out.push("");
56361
56753
  console.log(out.join(`
56362
56754
  `));
@@ -56372,6 +56764,16 @@ function getFlag(args, ...names) {
56372
56764
  }
56373
56765
  return;
56374
56766
  }
56767
+ function getFlagAll(args, ...names) {
56768
+ const out = [];
56769
+ let v3 = getFlag(args, ...names);
56770
+ while (v3 !== undefined) {
56771
+ if (v3)
56772
+ out.push(v3);
56773
+ v3 = getFlag(args, ...names);
56774
+ }
56775
+ return out;
56776
+ }
56375
56777
  function hasFlag2(args, ...names) {
56376
56778
  for (const n of names) {
56377
56779
  const i = args.indexOf(n);
@@ -56400,13 +56802,13 @@ async function requireAuth(cmd) {
56400
56802
  if (status.ok)
56401
56803
  return;
56402
56804
  console.error("");
56403
- console.error(` ${brandTint("◆")} ${import_picocolors40.default.bold("brainbase")}`);
56805
+ console.error(` ${brandTint("◆")} ${import_picocolors41.default.bold("brainbase")}`);
56404
56806
  console.error("");
56405
- console.error(` ${import_picocolors40.default.red("✗")} You need to sign in to use ${import_picocolors40.default.bold("brainbase " + cmd)}.`);
56807
+ console.error(` ${import_picocolors41.default.red("✗")} You need to sign in to use ${import_picocolors41.default.bold("brainbase " + cmd)}.`);
56406
56808
  if (status.reason)
56407
- console.error(` ${import_picocolors40.default.dim(status.reason)}`);
56809
+ console.error(` ${import_picocolors41.default.dim(status.reason)}`);
56408
56810
  console.error("");
56409
- console.error(` Run ${import_picocolors40.default.cyan("brainbase login")} to connect this device.`);
56811
+ console.error(` Run ${import_picocolors41.default.cyan("brainbase login")} to connect this device.`);
56410
56812
  console.error("");
56411
56813
  process14.exit(1);
56412
56814
  }
@@ -56416,7 +56818,7 @@ async function main() {
56416
56818
  const rawCwd = process14.cwd();
56417
56819
  const cwd2 = (() => {
56418
56820
  try {
56419
- return fs51.realpathSync(rawCwd);
56821
+ return fs52.realpathSync(rawCwd);
56420
56822
  } catch {
56421
56823
  return rawCwd;
56422
56824
  }
@@ -56451,6 +56853,11 @@ async function main() {
56451
56853
  const taglineFlag = getFlag(argv, "--tagline");
56452
56854
  const orgIdFlag = getFlag(argv, "--org");
56453
56855
  const teamIdFlag = getFlag(argv, "--team");
56856
+ const fromFlags = getFlagAll(argv, "--from");
56857
+ const toFlags = getFlagAll(argv, "--to");
56858
+ const descriptionFlag = getFlag(argv, "--description");
56859
+ const schemaFlag = getFlag(argv, "--schema");
56860
+ const noPushFlag = hasFlag2(argv, "--no-push");
56454
56861
  ensureSkillResolversRegistered();
56455
56862
  await requireAuth(cmd);
56456
56863
  try {
@@ -56543,7 +56950,13 @@ async function main() {
56543
56950
  harness,
56544
56951
  orgId: orgIdFlag,
56545
56952
  teamId: teamIdFlag,
56546
- graphOnly: graphOnlyFlag
56953
+ graphOnly: graphOnlyFlag,
56954
+ name: nameFlag,
56955
+ from: fromFlags,
56956
+ to: toFlags,
56957
+ description: descriptionFlag,
56958
+ schema: schemaFlag,
56959
+ noPush: noPushFlag
56547
56960
  });
56548
56961
  break;
56549
56962
  }
@@ -56562,7 +56975,7 @@ async function main() {
56562
56975
  process14.exit(1);
56563
56976
  }
56564
56977
  } catch (err) {
56565
- console.error(import_picocolors40.default.red(`
56978
+ console.error(import_picocolors41.default.red(`
56566
56979
  ${err.message}`));
56567
56980
  if (process14.env.BRAINBASE_DEBUG)
56568
56981
  console.error(err.stack);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainbase-labs/cli",
3
- "version": "0.8.3",
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": {