@brainbase-labs/cli 0.15.0 → 0.16.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +29 -3
  2. package/dist/index.js +1083 -290
  3. package/package.json +4 -2
package/dist/index.js CHANGED
@@ -35141,7 +35141,7 @@ var require_dist2 = __commonJS((exports, module) => {
35141
35141
  });
35142
35142
 
35143
35143
  // src/index.ts
35144
- var import_picocolors42 = __toESM(require_picocolors(), 1);
35144
+ var import_picocolors43 = __toESM(require_picocolors(), 1);
35145
35145
  import process14 from "node:process";
35146
35146
  import fs76 from "node:fs";
35147
35147
 
@@ -36008,7 +36008,7 @@ function padStart(s, n) {
36008
36008
  // package.json
36009
36009
  var package_default = {
36010
36010
  name: "@brainbase-labs/cli",
36011
- version: "0.15.0",
36011
+ version: "0.16.0-rc.1",
36012
36012
  description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
36013
36013
  type: "module",
36014
36014
  bin: {
@@ -36022,8 +36022,10 @@ var package_default = {
36022
36022
  scripts: {
36023
36023
  dev: "bun run src/index.ts",
36024
36024
  build: "bun run scripts/build.ts",
36025
+ test: "bun test",
36025
36026
  typecheck: "tsc --noEmit",
36026
- prepublishOnly: "bun run typecheck && bun run build"
36027
+ verify: "bun run typecheck && bun test && bun run build",
36028
+ prepublishOnly: "bun run verify"
36027
36029
  },
36028
36030
  repository: {
36029
36031
  type: "git",
@@ -53348,7 +53350,8 @@ function apiErrorMessage(body, status) {
53348
53350
  }
53349
53351
 
53350
53352
  // src/core/api.ts
53351
- var DEFAULT_API_BASE = "https://kafka-llm-service.onrender.com";
53353
+ var DEFAULT_CONTROL_PLANE_BASE = "https://api.brainbaselabs.com";
53354
+ var DEFAULT_PROXY_BASE = "https://api.v1.brainbaselabs.com";
53352
53355
 
53353
53356
  class ApiError extends Error {
53354
53357
  status;
@@ -53360,13 +53363,25 @@ class ApiError extends Error {
53360
53363
  this.name = "ApiError";
53361
53364
  }
53362
53365
  }
53363
- function apiBase(session) {
53364
- const envOverride = process.env.BRAINBASE_API_URL;
53365
- if (envOverride)
53366
- return envOverride.replace(/\/+$/, "");
53367
- if (session?.server)
53368
- return session.server.replace(/\/+$/, "");
53369
- return DEFAULT_API_BASE.replace(/\/+$/, "");
53366
+ function apiBase(_session) {
53367
+ const controlPlane = process.env.BRAINBASE_CONTROL_PLANE_URL;
53368
+ if (controlPlane) {
53369
+ return `${controlPlane.replace(/\/+$/, "")}/v2/cli`;
53370
+ }
53371
+ const legacyApi = process.env.BRAINBASE_API_URL;
53372
+ if (legacyApi) {
53373
+ return `${legacyApi.replace(/\/+$/, "")}/api/cli`;
53374
+ }
53375
+ return `${DEFAULT_CONTROL_PLANE_BASE}/v2/cli`;
53376
+ }
53377
+ function usesLegacyControlPlane() {
53378
+ return !process.env.BRAINBASE_CONTROL_PLANE_URL && !!process.env.BRAINBASE_API_URL;
53379
+ }
53380
+ function legacyScheduleError() {
53381
+ return new ApiError("Schedule-trigger writes require the MAS control plane. Set BRAINBASE_CONTROL_PLANE_URL or unset the legacy BRAINBASE_API_URL override.", 400);
53382
+ }
53383
+ function legacyAgentConfigError() {
53384
+ return new ApiError("Declarative machine/model config requires the MAS control plane. Set BRAINBASE_CONTROL_PLANE_URL or unset the legacy BRAINBASE_API_URL override.", 400);
53370
53385
  }
53371
53386
  function requireSession() {
53372
53387
  const status = authStatus();
@@ -53412,87 +53427,113 @@ async function request(pathname, init = {}) {
53412
53427
  }
53413
53428
  var api = {
53414
53429
  listOrgs() {
53415
- return request("/api/cli/orgs");
53430
+ return request("/orgs");
53416
53431
  },
53417
53432
  listTeams(orgId) {
53418
- return request(`/api/cli/orgs/${encodeURIComponent(orgId)}/teams`);
53433
+ return request(`/orgs/${encodeURIComponent(orgId)}/teams`);
53419
53434
  },
53420
53435
  createTeam(orgId, name) {
53421
- return request(`/api/cli/orgs/${encodeURIComponent(orgId)}/teams`, {
53436
+ return request(`/orgs/${encodeURIComponent(orgId)}/teams`, {
53422
53437
  method: "POST",
53423
53438
  body: JSON.stringify({ name })
53424
53439
  });
53425
53440
  },
53426
53441
  createAgent(input) {
53427
- return request("/api/cli/agents", {
53442
+ if (usesLegacyControlPlane() && (input.machine_kind !== undefined || input.default_model !== undefined)) {
53443
+ return Promise.reject(legacyAgentConfigError());
53444
+ }
53445
+ return request("/agents", {
53428
53446
  method: "POST",
53429
53447
  body: JSON.stringify(input)
53430
53448
  });
53431
53449
  },
53432
53450
  getAgent(agentId) {
53433
- return request(`/api/cli/agents/${encodeURIComponent(agentId)}`);
53451
+ return request(`/agents/${encodeURIComponent(agentId)}`);
53434
53452
  },
53435
53453
  getAgentRevision(agentId) {
53436
- return request(`/api/cli/agents/${encodeURIComponent(agentId)}/revision`);
53454
+ return request(`/agents/${encodeURIComponent(agentId)}/revision`);
53437
53455
  },
53438
53456
  getAgentManifest(agentId) {
53439
- return request(`/api/cli/agents/${encodeURIComponent(agentId)}/manifest`);
53457
+ return request(`/agents/${encodeURIComponent(agentId)}/manifest`);
53440
53458
  },
53441
53459
  updateAgent(agentId, input) {
53442
- return request(`/api/cli/agents/${encodeURIComponent(agentId)}`, {
53460
+ if (usesLegacyControlPlane() && (input.machine_kind !== undefined || input.default_model !== undefined)) {
53461
+ return Promise.reject(legacyAgentConfigError());
53462
+ }
53463
+ return request(`/agents/${encodeURIComponent(agentId)}`, {
53443
53464
  method: "PUT",
53444
53465
  body: JSON.stringify(input)
53445
53466
  });
53446
53467
  },
53447
53468
  pushAgentManifest(agentId, input) {
53448
- return request(`/api/cli/agents/${encodeURIComponent(agentId)}/manifest`, {
53469
+ return request(`/agents/${encodeURIComponent(agentId)}/manifest`, {
53449
53470
  method: "PUT",
53450
53471
  body: JSON.stringify(input)
53451
53472
  });
53452
53473
  },
53453
53474
  getAgentSecrets(agentId) {
53454
- return request(`/api/cli/agents/${encodeURIComponent(agentId)}/secrets`);
53475
+ return request(`/agents/${encodeURIComponent(agentId)}/secrets`);
53455
53476
  },
53456
53477
  putAgentSecrets(agentId, secrets) {
53457
- return request(`/api/cli/agents/${encodeURIComponent(agentId)}/secrets`, {
53478
+ return request(`/agents/${encodeURIComponent(agentId)}/secrets`, {
53458
53479
  method: "PUT",
53459
53480
  body: JSON.stringify({ secrets })
53460
53481
  });
53461
53482
  },
53462
53483
  createCliKey(agentId, input) {
53463
- return request(`/api/cli/agents/${encodeURIComponent(agentId)}/keys`, {
53484
+ return request(`/agents/${encodeURIComponent(agentId)}/keys`, {
53464
53485
  method: "POST",
53465
53486
  body: JSON.stringify(input)
53466
53487
  });
53467
53488
  },
53468
53489
  revokeCliKey(keyId) {
53469
- return request(`/api/cli/keys/${encodeURIComponent(keyId)}`, {
53490
+ return request(`/keys/${encodeURIComponent(keyId)}`, {
53470
53491
  method: "DELETE"
53471
53492
  });
53472
53493
  },
53473
53494
  listOrchestrations(orgId, teamId) {
53474
- return request(`/api/cli/orgs/${encodeURIComponent(orgId)}/teams/${encodeURIComponent(teamId)}/orchestrations`);
53495
+ return request(`/orgs/${encodeURIComponent(orgId)}/teams/${encodeURIComponent(teamId)}/orchestrations`);
53496
+ },
53497
+ createOrchestration(input) {
53498
+ if (usesLegacyControlPlane()) {
53499
+ return Promise.reject(new ApiError("Orchestration creation requires the MAS control plane. Set BRAINBASE_CONTROL_PLANE_URL or unset the legacy BRAINBASE_API_URL override.", 400));
53500
+ }
53501
+ return request("/orchestrations", {
53502
+ method: "POST",
53503
+ body: JSON.stringify(input)
53504
+ });
53475
53505
  },
53476
53506
  getOrchestration(orchId) {
53477
- return request(`/api/cli/orchestrations/${encodeURIComponent(orchId)}`);
53507
+ return request(`/orchestrations/${encodeURIComponent(orchId)}`);
53478
53508
  },
53479
53509
  getOrchestrationManifest(orchId) {
53480
- return request(`/api/cli/orchestrations/${encodeURIComponent(orchId)}/manifest`);
53510
+ return request(`/orchestrations/${encodeURIComponent(orchId)}/manifest`);
53481
53511
  },
53482
- updateOrchestration(orchId, input) {
53483
- return request(`/api/cli/orchestrations/${encodeURIComponent(orchId)}`, {
53512
+ async updateOrchestration(orchId, input) {
53513
+ let payload = input;
53514
+ if (usesLegacyControlPlane() && input.triggers !== undefined) {
53515
+ if (input.triggers.length > 0)
53516
+ throw legacyScheduleError();
53517
+ const current = await request(`/orchestrations/${encodeURIComponent(orchId)}`);
53518
+ if ((current.triggers ?? []).some((trigger) => trigger.trigger_type === "schedule")) {
53519
+ throw legacyScheduleError();
53520
+ }
53521
+ const { triggers: _unsupported, ...legacyPayload } = input;
53522
+ payload = legacyPayload;
53523
+ }
53524
+ return request(`/orchestrations/${encodeURIComponent(orchId)}`, {
53484
53525
  method: "PUT",
53485
- body: JSON.stringify(input)
53526
+ body: JSON.stringify(payload)
53486
53527
  });
53487
53528
  }
53488
53529
  };
53489
53530
  function proxyBaseUrl(session) {
53490
- const envOverride = process.env.BRAINBASE_API_URL;
53531
+ const envOverride = process.env.BRAINBASE_PROXY_URL || process.env.BRAINBASE_API_URL;
53491
53532
  if (envOverride)
53492
53533
  return envOverride.replace(/\/+$/, "");
53493
53534
  if (session?.server)
53494
53535
  return session.server.replace(/\/+$/, "");
53495
- return DEFAULT_API_BASE.replace(/\/+$/, "");
53536
+ return DEFAULT_PROXY_BASE.replace(/\/+$/, "");
53496
53537
  }
53497
53538
 
53498
53539
  // src/core/token.ts
@@ -53554,9 +53595,9 @@ function clearToken() {
53554
53595
  }
53555
53596
 
53556
53597
  // src/core/registry-client.ts
53557
- var DEFAULT_BASE = "https://kafka-llm-service.onrender.com";
53598
+ var DEFAULT_BASE = "https://api.v1.brainbaselabs.com";
53558
53599
  function baseUrl(session) {
53559
- const env3 = process.env.BRAINBASE_REGISTRY_URL ?? process.env.BRAINBASE_API_URL;
53600
+ const env3 = process.env.BRAINBASE_REGISTRY_URL || process.env.BRAINBASE_API_URL;
53560
53601
  if (env3)
53561
53602
  return env3.replace(/\/+$/, "");
53562
53603
  if (session?.server)
@@ -53564,7 +53605,7 @@ function baseUrl(session) {
53564
53605
  return DEFAULT_BASE.replace(/\/+$/, "");
53565
53606
  }
53566
53607
  function registryHost() {
53567
- const env3 = process.env.BRAINBASE_REGISTRY_URL ?? process.env.BRAINBASE_API_URL;
53608
+ const env3 = process.env.BRAINBASE_REGISTRY_URL || process.env.BRAINBASE_API_URL;
53568
53609
  if (env3)
53569
53610
  return env3.replace(/\/+$/, "");
53570
53611
  const s = readAuth();
@@ -60799,10 +60840,13 @@ var EvalSchema = exports_external.object({
60799
60840
  message: "classification_values must not contain duplicate labels",
60800
60841
  path: ["classification_values"]
60801
60842
  });
60843
+ var MODEL_ID_RE = /^[A-Za-z0-9._:/-]{1,128}$/;
60802
60844
  var AgentManifestSchema = exports_external.object({
60803
60845
  schema: exports_external.literal(1),
60804
60846
  id: exports_external.string().min(1).optional(),
60805
60847
  harness: exports_external.string().min(1).optional(),
60848
+ machine_kind: exports_external.string().trim().min(1).optional(),
60849
+ default_model: exports_external.string().trim().regex(MODEL_ID_RE, "default_model must use letters, digits, and . _ - : / only (max 128)").nullable().optional(),
60806
60850
  agent: AgentMetaSchema,
60807
60851
  instructions: InstructionsSchema.optional(),
60808
60852
  entrypoint: EntrypointSchema.optional(),
@@ -61037,7 +61081,9 @@ var SyncedComponentSchema = exports_external.object({
61037
61081
  var AgentMetaSnapshotSchema = exports_external.object({
61038
61082
  name: exports_external.string(),
61039
61083
  tagline: exports_external.string().nullish().transform((v3) => v3 ?? undefined),
61040
- entrypoint: exports_external.string().optional()
61084
+ entrypoint: exports_external.string().optional(),
61085
+ machine_kind: exports_external.string().min(1).optional(),
61086
+ default_model: exports_external.string().nullable().optional()
61041
61087
  });
61042
61088
  var SyncStateSchema = exports_external.object({
61043
61089
  schemaVersion: exports_external.literal(1),
@@ -61933,7 +61979,8 @@ async function runSync(cwd2, args) {
61933
61979
  agent_id: link2.agent_id,
61934
61980
  revision: manifest.revision,
61935
61981
  synced_at: new Date().toISOString(),
61936
- components: prevState?.components ?? []
61982
+ components: prevState?.components ?? [],
61983
+ agentMeta: prevState?.agentMeta
61937
61984
  });
61938
61985
  return;
61939
61986
  }
@@ -62102,7 +62149,8 @@ async function runSync(cwd2, args) {
62102
62149
  agent_id: link2.agent_id,
62103
62150
  revision: manifest.revision,
62104
62151
  synced_at: new Date().toISOString(),
62105
- components: nextComponents
62152
+ components: nextComponents,
62153
+ agentMeta: prevState?.agentMeta
62106
62154
  };
62107
62155
  writeSyncState(cwd2, newState);
62108
62156
  $e(`Synced ${link2.name} to revision ${manifest.revision}.`);
@@ -62241,17 +62289,15 @@ function canonicalJson(value) {
62241
62289
  throw new Error(`Unsupported value in canonicalJson: ${typeof value}`);
62242
62290
  }
62243
62291
  function hashMcpEntry(entry) {
62244
- const payload = {};
62292
+ const payload = {
62293
+ args: entry.args ?? [],
62294
+ env: entry.env ?? {},
62295
+ headers: entry.headers ?? {}
62296
+ };
62245
62297
  if (entry.url !== undefined)
62246
62298
  payload.url = entry.url;
62247
62299
  if (entry.command !== undefined)
62248
62300
  payload.command = entry.command;
62249
- if (entry.args !== undefined)
62250
- payload.args = entry.args;
62251
- if (entry.env !== undefined)
62252
- payload.env = entry.env;
62253
- if (entry.headers !== undefined)
62254
- payload.headers = entry.headers;
62255
62301
  payload.is_enabled = entry.is_enabled ?? true;
62256
62302
  return crypto4.createHash("sha256").update(canonicalJson(payload)).digest("hex");
62257
62303
  }
@@ -62422,7 +62468,10 @@ function threeWayDiff(input) {
62422
62468
  const sourceChanged = !!local && local.hash === null && !!local.declaredSource && lock?.source !== undefined && lock.source !== local.declaredSource;
62423
62469
  const localChanged = sourceChanged || localHash !== null && lockHash !== undefined && localHash !== lockHash;
62424
62470
  const cloudChanged = cloudHash !== undefined && lockHash !== undefined && cloudHash !== lockHash;
62425
- if (localChanged && cloudChanged)
62471
+ const converged = !sourceChanged && localHash !== null && cloudHash !== undefined && localHash === cloudHash;
62472
+ if (converged)
62473
+ status = "in-sync";
62474
+ else if (localChanged && cloudChanged)
62426
62475
  status = "modified-both";
62427
62476
  else if (localChanged)
62428
62477
  status = "modified-local";
@@ -62489,6 +62538,60 @@ function diffAgentMeta(manifestMeta, lockMeta, cloudMeta) {
62489
62538
  cloudChanged: !!cloudMeta && !!lockMeta && !eq(cloudMeta, lockMeta)
62490
62539
  };
62491
62540
  }
62541
+ function hasOwn(value, key2) {
62542
+ return !!value && Object.prototype.hasOwnProperty.call(value, key2);
62543
+ }
62544
+ function diffAgentConfig(manifest, lock, cloud) {
62545
+ const unsupported = [];
62546
+ const machineSupported = cloud.machine_kind !== undefined;
62547
+ const defaultModelSupported = hasOwn(cloud, "default_model");
62548
+ if (manifest.machine_kind !== undefined && !machineSupported) {
62549
+ unsupported.push("machine_kind");
62550
+ }
62551
+ if (manifest.default_model !== undefined && !defaultModelSupported) {
62552
+ unsupported.push("default_model");
62553
+ }
62554
+ const machineMismatch = manifest.machine_kind !== undefined && machineSupported && manifest.machine_kind !== cloud.machine_kind;
62555
+ const machineLocalChanged = manifest.machine_kind !== undefined && machineSupported && (lock?.machine_kind !== undefined ? manifest.machine_kind !== lock.machine_kind && manifest.machine_kind !== cloud.machine_kind : manifest.machine_kind !== cloud.machine_kind);
62556
+ const machineCloudChanged = lock?.machine_kind !== undefined && machineSupported && lock.machine_kind !== cloud.machine_kind && manifest.machine_kind !== cloud.machine_kind;
62557
+ const machineConverged = manifest.machine_kind !== undefined && machineSupported && manifest.machine_kind === cloud.machine_kind && (lock?.machine_kind === undefined || lock.machine_kind !== cloud.machine_kind);
62558
+ let defaultModelLocalChanged = false;
62559
+ let defaultModelCloudChanged = false;
62560
+ let defaultModelConflict = false;
62561
+ let defaultModelConverged = false;
62562
+ if (defaultModelSupported) {
62563
+ const cloudValue = cloud.default_model ?? null;
62564
+ const localAuthored = manifest.default_model !== undefined;
62565
+ const lockSupported = hasOwn(lock, "default_model");
62566
+ if (localAuthored) {
62567
+ const localValue = manifest.default_model ?? null;
62568
+ if (lockSupported) {
62569
+ const lockValue = lock?.default_model ?? null;
62570
+ const localMoved = localValue !== lockValue;
62571
+ const cloudMoved = cloudValue !== lockValue;
62572
+ defaultModelConflict = localMoved && cloudMoved && localValue !== cloudValue;
62573
+ defaultModelLocalChanged = localMoved && localValue !== cloudValue;
62574
+ defaultModelCloudChanged = cloudMoved && localValue !== cloudValue;
62575
+ defaultModelConverged = localMoved && cloudMoved && localValue === cloudValue;
62576
+ } else {
62577
+ defaultModelLocalChanged = localValue !== cloudValue;
62578
+ defaultModelConverged = localValue === cloudValue;
62579
+ }
62580
+ } else if (lockSupported) {
62581
+ defaultModelCloudChanged = cloudValue !== (lock?.default_model ?? null);
62582
+ }
62583
+ }
62584
+ return {
62585
+ unsupported,
62586
+ machineMismatch,
62587
+ machineLocalChanged,
62588
+ machineCloudChanged,
62589
+ defaultModelLocalChanged,
62590
+ defaultModelCloudChanged,
62591
+ defaultModelConflict,
62592
+ baselineConverged: machineConverged || defaultModelConverged
62593
+ };
62594
+ }
62492
62595
 
62493
62596
  // src/core/secrets-env.ts
62494
62597
  import path75 from "node:path";
@@ -62714,7 +62817,7 @@ async function runAgentUnpack(cwd2, args) {
62714
62817
  cwd: cwd2,
62715
62818
  scope,
62716
62819
  resolveConflict: async (_c) => "overwrite",
62717
- resolveSecret: async () => null
62820
+ resolveSecret: makeLocalSecretResolver(cwd2)
62718
62821
  };
62719
62822
  const sp = de();
62720
62823
  sp.start("Installing harness layout…");
@@ -62799,10 +62902,10 @@ function stageLocalSkill(source, cwd2, stageRoot, scope, toInstall) {
62799
62902
  return null;
62800
62903
  }
62801
62904
  try {
62802
- const parsed = parseSkillSource(source);
62905
+ const parsed = resolveSkillSourceForUnpack(source);
62803
62906
  if (parsed.type === "local" || parsed.type === "inline")
62804
62907
  return null;
62805
- const slug = defaultSlugForSource(source);
62908
+ const slug = skillComponentSlugForUnpack(source);
62806
62909
  const compDir = path76.join(stageRoot, "skill", slug);
62807
62910
  ensureDir(compDir);
62808
62911
  toInstall.push({
@@ -62818,10 +62921,35 @@ function stageLocalSkill(source, cwd2, stageRoot, scope, toInstall) {
62818
62921
  return `Skill ${source}: ${err.message} — skipped.`;
62819
62922
  }
62820
62923
  }
62924
+ function resolveSkillSourceForUnpack(source) {
62925
+ if (source.startsWith("registry:")) {
62926
+ const parsed = parseSkillSource2(source);
62927
+ if (parsed.kind !== "registry" || !parsed.creator) {
62928
+ throw new Error(`Registry skill source must include a creator: ${source}`);
62929
+ }
62930
+ return {
62931
+ type: "brainbase",
62932
+ creator: parsed.creator,
62933
+ slug: parsed.slug,
62934
+ version: parsed.version
62935
+ };
62936
+ }
62937
+ return parseSkillSource(source);
62938
+ }
62939
+ function makeLocalSecretResolver(cwd2) {
62940
+ const secrets = readLocalSecrets(cwd2);
62941
+ return async (key2) => secrets[key2] ?? null;
62942
+ }
62943
+ function skillComponentSlugForUnpack(source) {
62944
+ if (source.startsWith("registry:")) {
62945
+ const parsed = parseSkillSource2(source);
62946
+ if (parsed.kind === "registry") {
62947
+ return registrySkillComponentSlug(parsed);
62948
+ }
62949
+ }
62950
+ return defaultSlugForSource(source);
62951
+ }
62821
62952
  function defaultSlugForSource(source) {
62822
- const reg = /^registry:(?:[a-z0-9_-]+\/)?([a-z0-9_-]+)/i.exec(source);
62823
- if (reg)
62824
- return reg[1].toLowerCase();
62825
62953
  const gh = /^(?:github|git):[^/]*\/?([a-z0-9_-]+)/i.exec(source);
62826
62954
  if (gh)
62827
62955
  return gh[1].toLowerCase();
@@ -62915,6 +63043,23 @@ async function runAgentPull(cwd2, args) {
62915
63043
  lock: lock?.components ?? [],
62916
63044
  cloud: cloud.components
62917
63045
  });
63046
+ const config = diffAgentConfig(existingManifest ?? {}, lock?.agentMeta, cloudAgent);
63047
+ const localRuntimeConfigChanged = config.machineLocalChanged || config.defaultModelLocalChanged;
63048
+ if (localRuntimeConfigChanged && !args.force) {
63049
+ f2.error(`Runtime config has local edits that pull would overwrite: ${[
63050
+ ...config.machineLocalChanged ? ["machine_kind"] : [],
63051
+ ...config.defaultModelLocalChanged ? ["default_model"] : []
63052
+ ].join(", ")}.`);
63053
+ if (config.machineLocalChanged) {
63054
+ f2.info(`machine_kind cannot change on an existing agent. Run ${import_picocolors26.default.cyan("brainbase agent pull --force")} to discard the edit, or create a new agent for that provider.`);
63055
+ }
63056
+ if (config.defaultModelLocalChanged) {
63057
+ f2.info(`Push the default_model edit first, or run ${import_picocolors26.default.cyan("brainbase agent pull --force")} to discard it.`);
63058
+ }
63059
+ process.exitCode = 1;
63060
+ return;
63061
+ }
63062
+ const runtimeConfigChanged = config.machineCloudChanged || config.defaultModelCloudChanged || !!args.force && localRuntimeConfigChanged;
62918
63063
  const toInstallKeys = new Set;
62919
63064
  const toRemoveKeys = new Set;
62920
63065
  const conflicts = [];
@@ -62968,7 +63113,7 @@ async function runAgentPull(cwd2, args) {
62968
63113
  declaredSlugs: declaredMcpSlugs,
62969
63114
  scope: args.scope ?? "project"
62970
63115
  });
62971
- if (toInstallKeys.size === 0 && toRemoveKeys.size === 0 && builtinInstall.length === 0 && builtinRemoveSlugs.length === 0 && !override) {
63116
+ if (toInstallKeys.size === 0 && toRemoveKeys.size === 0 && builtinInstall.length === 0 && builtinRemoveSlugs.length === 0 && !runtimeConfigChanged && !override) {
62972
63117
  f2.info(`You're up to date.`);
62973
63118
  writeLink(cwd2, buildLinkFromAgent(cloudAgent, harness, readLink(cwd2)));
62974
63119
  writeSyncState(cwd2, buildLockFromCloud(agentId, cloud, lock, cloudAgent));
@@ -63002,6 +63147,13 @@ async function runAgentPull(cwd2, args) {
63002
63147
  text: String(keepLocalKeys.size)
63003
63148
  });
63004
63149
  }
63150
+ if (runtimeConfigChanged) {
63151
+ resultRows.push({
63152
+ type: "upd",
63153
+ label: "runtime config",
63154
+ text: "machine/model from cloud"
63155
+ });
63156
+ }
63005
63157
  await showResultCard({
63006
63158
  title: override ? "PULL (FORCE)" : "PULL",
63007
63159
  tone: override ? "warn" : "info",
@@ -63022,6 +63174,7 @@ async function runAgentPull(cwd2, args) {
63022
63174
  const stageRoot = stageManifestComponents(installComponents);
63023
63175
  const justInstalledPaths = new Map;
63024
63176
  try {
63177
+ const availableSecrets = await pullSecrets(cwd2, agentId);
63025
63178
  if (installComponents.length > 0 || builtinInstall.length > 0) {
63026
63179
  const installSpinner = de();
63027
63180
  installSpinner.start("Applying updates…");
@@ -63032,7 +63185,7 @@ async function runAgentPull(cwd2, args) {
63032
63185
  rootDir: path77.join(stageRoot, c2.type, c2.slug),
63033
63186
  description: c2.description,
63034
63187
  meta: c2.meta,
63035
- payload: proxifyMcpPayload(c2.meta?.mcp),
63188
+ payload: proxifyMcpPayload(structuredClone(c2.meta?.mcp)),
63036
63189
  checksum: c2.hash,
63037
63190
  source: skillSourceFromMeta(c2)
63038
63191
  }));
@@ -63041,7 +63194,7 @@ async function runAgentPull(cwd2, args) {
63041
63194
  cwd: cwd2,
63042
63195
  scope,
63043
63196
  resolveConflict: async (_c) => "overwrite",
63044
- resolveSecret: async () => null
63197
+ resolveSecret: async (name) => availableSecrets[name] ?? null
63045
63198
  };
63046
63199
  const result2 = await runHarnessInstall3(adapter.id, componentsForNativeInstall(toInstall, !!args.acp), opts, cloudAgent.name);
63047
63200
  installSpinner.stop("Applied.");
@@ -63096,11 +63249,12 @@ async function runAgentPull(cwd2, args) {
63096
63249
  agentMeta: {
63097
63250
  name: cloudAgent.name,
63098
63251
  tagline: cloudAgent.tagline,
63099
- ...cloudAgent.entrypoint ? { entrypoint: cloudAgent.entrypoint.trim() } : {}
63252
+ ...cloudAgent.entrypoint ? { entrypoint: cloudAgent.entrypoint.trim() } : {},
63253
+ ...cloudAgent.machine_kind ? { machine_kind: cloudAgent.machine_kind } : lock?.agentMeta?.machine_kind ? { machine_kind: lock.agentMeta.machine_kind } : {},
63254
+ ...Object.prototype.hasOwnProperty.call(cloudAgent, "default_model") ? { default_model: cloudAgent.default_model ?? null } : Object.prototype.hasOwnProperty.call(lock?.agentMeta ?? {}, "default_model") ? { default_model: lock.agentMeta.default_model ?? null } : {}
63100
63255
  }
63101
63256
  };
63102
63257
  writeSyncState(cwd2, newState);
63103
- await pullSecrets(cwd2, agentId);
63104
63258
  await runEntrypointIfPresent(cwd2, yaml, entrypointExecutionAllowed({ flag: args.runEntrypoint, env: process.env }));
63105
63259
  $e(`Pulled ${cloudAgent.name} at revision ${cloud.revision}.`);
63106
63260
  } finally {
@@ -63299,10 +63453,14 @@ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
63299
63453
  return entry;
63300
63454
  });
63301
63455
  const caps = capabilitiesFromAgent(cloudAgent);
63456
+ const machineKind = cloudAgent.machine_kind ?? prev?.machine_kind;
63457
+ const defaultModelSupported = Object.prototype.hasOwnProperty.call(cloudAgent, "default_model");
63302
63458
  return {
63303
63459
  schema: 1,
63304
63460
  id: cloudAgent.id,
63305
63461
  harness,
63462
+ ...machineKind ? { machine_kind: machineKind } : {},
63463
+ ...defaultModelSupported ? cloudAgent.default_model ? { default_model: cloudAgent.default_model } : prev?.default_model === null ? { default_model: null } : {} : prev?.default_model !== undefined ? { default_model: prev.default_model } : {},
63306
63464
  agent: {
63307
63465
  name: cloudAgent.name,
63308
63466
  ...cloudAgent.tagline ? { tagline: cloudAgent.tagline } : {}
@@ -63379,7 +63537,9 @@ function buildLockFromCloud(agent_id, cloud, prev, cloudAgent) {
63379
63537
  agentMeta: cloudAgent ? {
63380
63538
  name: cloudAgent.name,
63381
63539
  tagline: cloudAgent.tagline,
63382
- ...cloudAgent.entrypoint ? { entrypoint: cloudAgent.entrypoint.trim() } : {}
63540
+ ...cloudAgent.entrypoint ? { entrypoint: cloudAgent.entrypoint.trim() } : {},
63541
+ ...cloudAgent.machine_kind ? { machine_kind: cloudAgent.machine_kind } : prev?.agentMeta?.machine_kind ? { machine_kind: prev.agentMeta.machine_kind } : {},
63542
+ ...Object.prototype.hasOwnProperty.call(cloudAgent, "default_model") ? { default_model: cloudAgent.default_model ?? null } : Object.prototype.hasOwnProperty.call(prev?.agentMeta ?? {}, "default_model") ? { default_model: prev.agentMeta.default_model ?? null } : {}
63383
63543
  } : prev?.agentMeta
63384
63544
  };
63385
63545
  }
@@ -63449,6 +63609,7 @@ async function runEntrypointIfPresent(cwd2, manifest, execute) {
63449
63609
  }
63450
63610
  }
63451
63611
  async function pullSecrets(cwd2, agentId) {
63612
+ const localSecrets = readLocalSecrets(cwd2);
63452
63613
  let cloudSecrets;
63453
63614
  const sp = de();
63454
63615
  sp.start("Fetching secrets…");
@@ -63461,9 +63622,8 @@ async function pullSecrets(cwd2, agentId) {
63461
63622
  if (err instanceof ApiError && err.status !== 404) {
63462
63623
  f2.warn(`Skipped secrets: ${err.message}`);
63463
63624
  }
63464
- return;
63625
+ return localSecrets;
63465
63626
  }
63466
- const localSecrets = readLocalSecrets(cwd2);
63467
63627
  const diff2 = diffSecrets(localSecrets, cloudSecrets);
63468
63628
  if (diff2.localOnly.length > 0 || diff2.changed.length > 0) {
63469
63629
  if (diff2.localOnly.length) {
@@ -63475,6 +63635,7 @@ async function pullSecrets(cwd2, agentId) {
63475
63635
  }
63476
63636
  const merged = { ...cloudSecrets, ...localSecrets };
63477
63637
  writeLocalSecrets(cwd2, merged);
63638
+ return merged;
63478
63639
  }
63479
63640
  function handleApiError2(err) {
63480
63641
  if (err instanceof ApiError) {
@@ -63703,8 +63864,12 @@ async function runAgentPush(cwd2, args) {
63703
63864
  const sp = de();
63704
63865
  sp.start(`Fetching cloud state…`);
63705
63866
  let cloud;
63867
+ let cloudAgent;
63706
63868
  try {
63707
- cloud = await api.getAgentManifest(agentId);
63869
+ [cloud, cloudAgent] = await Promise.all([
63870
+ api.getAgentManifest(agentId),
63871
+ api.getAgent(agentId)
63872
+ ]);
63708
63873
  sp.stop(`Cloud revision ${cloud.revision}.`);
63709
63874
  } catch (err) {
63710
63875
  sp.stop("Failed.");
@@ -63717,6 +63882,33 @@ async function runAgentPush(cwd2, args) {
63717
63882
  lock: lock?.components ?? [],
63718
63883
  cloud: cloud.components
63719
63884
  });
63885
+ const config = diffAgentConfig(manifest, lock?.agentMeta, cloudAgent);
63886
+ if (config.unsupported.length > 0) {
63887
+ f2.error(`This control plane does not support declarative ${config.unsupported.join(" / ")} config.`);
63888
+ f2.info(`Use the MAS control plane, then run ${import_picocolors28.default.cyan("brainbase agent pull")} before retrying.`);
63889
+ process.exitCode = 1;
63890
+ return;
63891
+ }
63892
+ if (config.machineMismatch) {
63893
+ if (config.machineCloudChanged && !config.machineLocalChanged) {
63894
+ f2.error("Cannot push: machine_kind changed on the cloud.");
63895
+ f2.info(`Run ${import_picocolors28.default.cyan("brainbase agent pull")} to accept the cloud provider.`);
63896
+ } else {
63897
+ f2.error(`Cannot change machine_kind on an existing agent (${import_picocolors28.default.dim(cloudAgent.machine_kind ?? "unknown")} → ${import_picocolors28.default.bold(manifest.machine_kind)}).`);
63898
+ f2.info("machine_kind applies when the agent is created; create a new agent to use a different provider.");
63899
+ }
63900
+ process.exitCode = 1;
63901
+ return;
63902
+ }
63903
+ if (config.defaultModelConflict && !args.force) {
63904
+ f2.error("Cannot push: default_model changed both locally and on the cloud.");
63905
+ f2.info(`Run ${import_picocolors28.default.cyan("brainbase agent pull")} first to reconcile, or ${import_picocolors28.default.cyan("brainbase agent push --force")} to keep the local model.`);
63906
+ process.exitCode = 1;
63907
+ return;
63908
+ }
63909
+ if (config.defaultModelConflict && args.force) {
63910
+ f2.warn(`${import_picocolors28.default.yellow("--force")}: overwriting the cloud default_model with the local value.`);
63911
+ }
63720
63912
  const registryRefs = new Map;
63721
63913
  for (const entry of manifest.skills) {
63722
63914
  try {
@@ -63775,14 +63967,7 @@ async function runAgentPush(cwd2, args) {
63775
63967
  row.status = "modified-local";
63776
63968
  }
63777
63969
  }
63778
- let cloudMeta = lock?.agentMeta;
63779
- if (!cloudMeta) {
63780
- try {
63781
- const a3 = await api.getAgent(agentId);
63782
- cloudMeta = { name: a3.name, tagline: a3.tagline, entrypoint: a3.entrypoint };
63783
- } catch {}
63784
- }
63785
- const meta = diffAgentMeta(manifest.agent, lock?.agentMeta, cloudMeta);
63970
+ const meta = diffAgentMeta(manifest.agent, lock?.agentMeta, cloudAgent);
63786
63971
  let resolvedEntrypoint;
63787
63972
  if (manifest.entrypoint) {
63788
63973
  const body = resolveEntrypoint(cwd2, manifest);
@@ -63832,10 +64017,6 @@ async function runAgentPush(cwd2, args) {
63832
64017
  }
63833
64018
  const { toSend, conflicts, upstreamOnly } = partitionPushRows(rows, !!args.force);
63834
64019
  const forcedOverrides = args.force ? rows.filter((r2) => r2.status === "modified-both") : [];
63835
- if (!meta.localChanged && !entrypointChanged && toSend.length === 0 && conflicts.length === 0) {
63836
- f2.info("Nothing to push — local is in sync with the cloud.");
63837
- return;
63838
- }
63839
64020
  if (conflicts.length > 0) {
63840
64021
  f2.error(`Cannot push: ${conflicts.length} component${conflicts.length === 1 ? "" : "s"} changed both locally and on the cloud:`);
63841
64022
  for (const r2 of conflicts) {
@@ -63857,6 +64038,61 @@ async function runAgentPush(cwd2, args) {
63857
64038
  }
63858
64039
  f2.info(`If you push now, your push targets revision ${cloud.revision} and may race. Consider \`brainbase agent pull\` first.`);
63859
64040
  }
64041
+ if (config.defaultModelCloudChanged || config.machineCloudChanged) {
64042
+ f2.warn(`Cloud runtime config changed since the last sync. Run ${import_picocolors28.default.cyan("brainbase agent pull")} to accept it locally.`);
64043
+ }
64044
+ const shouldPushManifest = meta.localChanged || entrypointChanged || toSend.length > 0;
64045
+ const shouldUpdateAgent = meta.localChanged || entrypointChanged || config.defaultModelLocalChanged;
64046
+ const hasAgentChanges = shouldPushManifest || shouldUpdateAgent;
64047
+ const outgoing = hasAgentChanges ? await buildOutgoingComponents(cwd2, manifest, cloud, resolvedVersions) : null;
64048
+ if (hasAgentChanges && outgoing === null) {
64049
+ process.exitCode = 1;
64050
+ return;
64051
+ }
64052
+ let secretPlan = null;
64053
+ try {
64054
+ secretPlan = await planSecretPush(cwd2, agentId);
64055
+ } catch (err) {
64056
+ if (!hasAgentChanges) {
64057
+ handleApiError3(err);
64058
+ return;
64059
+ }
64060
+ f2.warn(`Couldn't read cloud secrets to diff: ${err.message}. Skipping secret push.`);
64061
+ }
64062
+ if (!hasAgentChanges && config.baselineConverged) {
64063
+ writeSyncState(cwd2, lock ? {
64064
+ ...lock,
64065
+ synced_at: new Date().toISOString(),
64066
+ agentMeta: buildAgentMetaAfterPush({
64067
+ manifest,
64068
+ lock,
64069
+ cloudAgent,
64070
+ resolvedEntrypoint,
64071
+ config
64072
+ })
64073
+ } : {
64074
+ schemaVersion: 1,
64075
+ agent_id: agentId,
64076
+ revision: cloud.revision,
64077
+ synced_at: new Date().toISOString(),
64078
+ components: [],
64079
+ agentMeta: buildAgentMetaAfterPush({
64080
+ manifest,
64081
+ lock,
64082
+ cloudAgent,
64083
+ resolvedEntrypoint,
64084
+ config
64085
+ })
64086
+ });
64087
+ }
64088
+ if (!hasAgentChanges && !secretPlan) {
64089
+ if (config.defaultModelCloudChanged || config.machineCloudChanged) {
64090
+ f2.info("Nothing local to push; cloud runtime config is awaiting pull.");
64091
+ return;
64092
+ }
64093
+ f2.info("Nothing to push — local is in sync with the cloud.");
64094
+ return;
64095
+ }
63860
64096
  const sendKeys = new Set(toSend.map((r2) => r2.key));
63861
64097
  for (const u2 of skillUpdates) {
63862
64098
  if (!sendKeys.has(compKey("skill", u2.componentSlug)))
@@ -63882,6 +64118,13 @@ async function runAgentPush(cwd2, args) {
63882
64118
  text: resolvedEntrypoint === "" ? "cleared" : "updated"
63883
64119
  });
63884
64120
  }
64121
+ if (config.defaultModelLocalChanged) {
64122
+ resultRows.push({
64123
+ type: "upd",
64124
+ label: "default model",
64125
+ text: manifest.default_model === null ? "cleared" : manifest.default_model
64126
+ });
64127
+ }
63885
64128
  if (toSend.length) {
63886
64129
  resultRows.push({
63887
64130
  type: "add",
@@ -63889,6 +64132,13 @@ async function runAgentPush(cwd2, args) {
63889
64132
  text: `${toSend.length} · ${toSend.map((r2) => `${r2.type}/${r2.slug}`).join(", ")}`
63890
64133
  });
63891
64134
  }
64135
+ if (secretPlan) {
64136
+ resultRows.push({
64137
+ type: "upd",
64138
+ label: "secrets",
64139
+ text: secretDiffSummary(secretPlan.diff)
64140
+ });
64141
+ }
63892
64142
  await showResultCard({
63893
64143
  title: "PUSH",
63894
64144
  tone: "info",
@@ -63902,9 +64152,15 @@ async function runAgentPush(cwd2, args) {
63902
64152
  return;
63903
64153
  }
63904
64154
  }
63905
- if (meta.localChanged || entrypointChanged) {
64155
+ if (!hasAgentChanges) {
64156
+ if (!secretPlan || !await pushSecrets(agentId, secretPlan))
64157
+ return;
64158
+ $e(`Pushed secrets for ${manifest.agent.name}.`);
64159
+ return;
64160
+ }
64161
+ if (meta.localChanged || entrypointChanged || config.defaultModelLocalChanged) {
63906
64162
  const metaSpinner = de();
63907
- metaSpinner.start("Updating agent metadata…");
64163
+ metaSpinner.start("Updating agent config…");
63908
64164
  try {
63909
64165
  const update2 = {};
63910
64166
  if (meta.localChanged) {
@@ -63914,16 +64170,37 @@ async function runAgentPush(cwd2, args) {
63914
64170
  if (entrypointChanged) {
63915
64171
  update2.entrypoint = resolvedEntrypoint;
63916
64172
  }
63917
- await api.updateAgent(agentId, update2);
63918
- metaSpinner.stop("Metadata updated.");
64173
+ if (config.defaultModelLocalChanged) {
64174
+ update2.default_model = manifest.default_model ?? null;
64175
+ }
64176
+ cloudAgent = await api.updateAgent(agentId, update2);
64177
+ metaSpinner.stop("Agent config updated.");
63919
64178
  } catch (err) {
63920
64179
  metaSpinner.stop("Failed.");
63921
64180
  return handleApiError3(err);
63922
64181
  }
63923
64182
  }
63924
- const outgoing = await buildOutgoingComponents(cwd2, manifest, cloud, resolvedVersions);
63925
- if (outgoing === null)
64183
+ if (!shouldPushManifest) {
64184
+ const state = {
64185
+ schemaVersion: 1,
64186
+ agent_id: agentId,
64187
+ revision: cloud.revision,
64188
+ synced_at: new Date().toISOString(),
64189
+ components: lock?.components ?? [],
64190
+ agentMeta: buildAgentMetaAfterPush({
64191
+ manifest,
64192
+ lock,
64193
+ cloudAgent,
64194
+ resolvedEntrypoint,
64195
+ config
64196
+ })
64197
+ };
64198
+ writeSyncState(cwd2, state);
64199
+ if (secretPlan && !await pushSecrets(agentId, secretPlan))
64200
+ return;
64201
+ $e(`Pushed agent config for ${manifest.agent.name}.`);
63926
64202
  return;
64203
+ }
63927
64204
  const pushSpinner = de();
63928
64205
  pushSpinner.start("Pushing…");
63929
64206
  let updatedCloud;
@@ -63939,6 +64216,7 @@ async function runAgentPush(cwd2, args) {
63939
64216
  if (err instanceof ApiError && err.status === 409) {
63940
64217
  f2.error(err.message);
63941
64218
  f2.info(`Run ${import_picocolors28.default.cyan("brainbase agent pull")} and try again.`);
64219
+ process.exitCode = 1;
63942
64220
  return;
63943
64221
  }
63944
64222
  return handleApiError3(err);
@@ -63985,43 +64263,67 @@ async function runAgentPush(cwd2, args) {
63985
64263
  ...decl ? { source: decl } : {}
63986
64264
  };
63987
64265
  }),
63988
- agentMeta: {
63989
- name: manifest.agent.name,
63990
- tagline: manifest.agent.tagline,
63991
- entrypoint: resolvedEntrypoint !== undefined ? resolvedEntrypoint.trim() : lock?.agentMeta?.entrypoint
63992
- }
64266
+ agentMeta: buildAgentMetaAfterPush({
64267
+ manifest,
64268
+ lock,
64269
+ cloudAgent,
64270
+ resolvedEntrypoint,
64271
+ config
64272
+ })
63993
64273
  };
63994
64274
  writeSyncState(cwd2, newLock);
63995
- await pushSecrets(cwd2, agentId);
64275
+ if (secretPlan && !await pushSecrets(agentId, secretPlan)) {
64276
+ return;
64277
+ }
63996
64278
  $e(`Pushed ${manifest.agent.name} at revision ${updatedCloud.revision}.`);
63997
64279
  }
63998
- async function pushSecrets(cwd2, agentId) {
64280
+ function buildAgentMetaAfterPush({
64281
+ manifest,
64282
+ lock,
64283
+ cloudAgent,
64284
+ resolvedEntrypoint,
64285
+ config
64286
+ }) {
64287
+ return {
64288
+ name: manifest.agent.name,
64289
+ tagline: manifest.agent.tagline,
64290
+ entrypoint: resolvedEntrypoint !== undefined ? resolvedEntrypoint.trim() : lock?.agentMeta?.entrypoint,
64291
+ ...config.machineCloudChanged ? lock?.agentMeta?.machine_kind ? { machine_kind: lock.agentMeta.machine_kind } : {} : cloudAgent.machine_kind ? { machine_kind: cloudAgent.machine_kind } : lock?.agentMeta?.machine_kind ? { machine_kind: lock.agentMeta.machine_kind } : {},
64292
+ ...config.defaultModelCloudChanged && !config.defaultModelLocalChanged ? Object.prototype.hasOwnProperty.call(lock?.agentMeta ?? {}, "default_model") ? { default_model: lock.agentMeta.default_model ?? null } : {} : Object.prototype.hasOwnProperty.call(cloudAgent, "default_model") ? { default_model: cloudAgent.default_model ?? null } : Object.prototype.hasOwnProperty.call(lock?.agentMeta ?? {}, "default_model") ? { default_model: lock.agentMeta.default_model ?? null } : {}
64293
+ };
64294
+ }
64295
+ async function planSecretPush(cwd2, agentId) {
64296
+ if (!exists(secretsPath(cwd2)))
64297
+ return null;
63999
64298
  const localSecrets = readLocalSecrets(cwd2);
64000
64299
  if (Object.keys(localSecrets).length === 0)
64001
- return;
64002
- let cloudSecrets = {};
64003
- try {
64004
- const res = await api.getAgentSecrets(agentId);
64005
- cloudSecrets = res.secrets ?? {};
64006
- } catch (err) {
64007
- f2.warn(`Couldn't read cloud secrets to diff: ${err.message}. Skipping secret push.`);
64008
- return;
64009
- }
64300
+ return null;
64301
+ const res = await api.getAgentSecrets(agentId);
64302
+ const cloudSecrets = res.secrets ?? {};
64010
64303
  const diff2 = diffSecrets(localSecrets, cloudSecrets);
64011
64304
  if (diff2.localOnly.length === 0 && diff2.changed.length === 0 && diff2.cloudOnly.length === 0) {
64012
- return;
64305
+ return null;
64013
64306
  }
64307
+ return { secrets: localSecrets, diff: diff2 };
64308
+ }
64309
+ async function pushSecrets(agentId, plan) {
64014
64310
  const sp = de();
64015
64311
  sp.start("Pushing secrets…");
64016
64312
  try {
64017
- await api.putAgentSecrets(agentId, localSecrets);
64018
- sp.stop(`Secrets pushed (${diff2.localOnly.length} added, ${diff2.changed.length} updated, ${diff2.cloudOnly.length} removed).`);
64313
+ await api.putAgentSecrets(agentId, plan.secrets);
64314
+ sp.stop(`Secrets pushed (${secretDiffSummary(plan.diff)}).`);
64315
+ return true;
64019
64316
  } catch (err) {
64020
64317
  sp.stop("Failed.");
64021
64318
  handleApiError3(err);
64319
+ return false;
64022
64320
  }
64023
64321
  }
64322
+ function secretDiffSummary(diff2) {
64323
+ return `${diff2.localOnly.length} added, ${diff2.changed.length} updated, ${diff2.cloudOnly.length} removed`;
64324
+ }
64024
64325
  function handleApiError3(err) {
64326
+ process.exitCode = 1;
64025
64327
  if (err instanceof ApiError) {
64026
64328
  if (err.status === 401) {
64027
64329
  f2.error("Your session is invalid. Run `brainbase login` and try again.");
@@ -64046,10 +64348,14 @@ async function runAgentStatus(cwd2) {
64046
64348
  const manifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
64047
64349
  const lock = readSyncState(cwd2);
64048
64350
  let cloud = null;
64351
+ let cloudAgent = null;
64049
64352
  const sp = de();
64050
64353
  sp.start(`Fetching ${link2.name}…`);
64051
64354
  try {
64052
- cloud = await api.getAgentManifest(link2.agent_id);
64355
+ [cloud, cloudAgent] = await Promise.all([
64356
+ api.getAgentManifest(link2.agent_id),
64357
+ api.getAgent(link2.agent_id)
64358
+ ]);
64053
64359
  sp.stop(`Cloud revision ${cloud.revision}.`);
64054
64360
  } catch (err) {
64055
64361
  sp.stop("Failed to reach brainbase.");
@@ -64071,7 +64377,8 @@ async function runAgentStatus(cwd2) {
64071
64377
  lock: lock?.components ?? [],
64072
64378
  cloud: cloud.components
64073
64379
  });
64074
- const meta = diffAgentMeta(manifest.agent, lock?.agentMeta, { name: link2.name, tagline: link2.tagline });
64380
+ const meta = diffAgentMeta(manifest.agent, lock?.agentMeta, cloudAgent);
64381
+ const config = diffAgentConfig(manifest, lock?.agentMeta, cloudAgent);
64075
64382
  const toPush = [];
64076
64383
  const toPull = [];
64077
64384
  const conflicts = [];
@@ -64115,6 +64422,29 @@ async function runAgentStatus(cwd2) {
64115
64422
  }
64116
64423
  lines.push("");
64117
64424
  }
64425
+ if (config.unsupported.length > 0 || config.machineMismatch || config.machineCloudChanged || config.defaultModelLocalChanged || config.defaultModelCloudChanged) {
64426
+ lines.push(` ${import_picocolors29.default.bold("runtime config")}`);
64427
+ if (config.unsupported.length > 0) {
64428
+ lines.push(` ${import_picocolors29.default.red("! unsupported")} ${config.unsupported.join(", ")} not exposed by this control plane`);
64429
+ }
64430
+ if (config.machineMismatch && !(config.machineCloudChanged && !config.machineLocalChanged)) {
64431
+ lines.push(` ${import_picocolors29.default.red("! blocked")} machine_kind differs; provider changes require a new agent`);
64432
+ }
64433
+ if (config.machineCloudChanged && !config.machineLocalChanged) {
64434
+ lines.push(` ${import_picocolors29.default.cyan("← pull")} machine_kind changed on cloud`);
64435
+ }
64436
+ if (config.defaultModelConflict) {
64437
+ lines.push(` ${import_picocolors29.default.red("! conflict")} default_model changed locally and on cloud`);
64438
+ } else {
64439
+ if (config.defaultModelLocalChanged) {
64440
+ lines.push(` ${import_picocolors29.default.yellow("→ push")} default_model edited locally`);
64441
+ }
64442
+ if (config.defaultModelCloudChanged) {
64443
+ lines.push(` ${import_picocolors29.default.cyan("← pull")} default_model changed on cloud`);
64444
+ }
64445
+ }
64446
+ lines.push("");
64447
+ }
64118
64448
  try {
64119
64449
  const localSecrets = readLocalSecrets(cwd2);
64120
64450
  const cloudRes = await api.getAgentSecrets(link2.agent_id);
@@ -64131,7 +64461,7 @@ async function runAgentStatus(cwd2) {
64131
64461
  lines.push("");
64132
64462
  }
64133
64463
  } catch {}
64134
- if (conflicts.length === 0 && toPush.length === 0 && toPull.length === 0) {
64464
+ if (conflicts.length === 0 && toPush.length === 0 && toPull.length === 0 && !meta.localChanged && !meta.cloudChanged && config.unsupported.length === 0 && !config.machineMismatch && !config.machineCloudChanged && !config.defaultModelLocalChanged && !config.defaultModelCloudChanged) {
64135
64465
  lines.push(` ${import_picocolors29.default.green("✓")} everything is in sync`);
64136
64466
  lines.push("");
64137
64467
  console.log(lines.join(`
@@ -64272,7 +64602,7 @@ async function runAgentCreate(cwd2, args) {
64272
64602
  }
64273
64603
  let org;
64274
64604
  if (args.orgId) {
64275
- const found = orgs.find((o2) => o2.id === args.orgId);
64605
+ const found = orgs.find((o2) => o2.id === args.orgId || o2.slug === args.orgId);
64276
64606
  if (!found) {
64277
64607
  f2.error(`Org ${args.orgId} not found or you're not a member.`);
64278
64608
  return;
@@ -64285,7 +64615,7 @@ async function runAgentCreate(cwd2, args) {
64285
64615
  const orgId = await select({
64286
64616
  message: "Pick an organization",
64287
64617
  options: orgs.map((o2) => ({ value: o2.id, label: o2.name, hint: o2.role })),
64288
- flagHint: "Pass --org <id> to choose non-interactively."
64618
+ flagHint: "Pass --org <id-or-slug> to choose non-interactively."
64289
64619
  });
64290
64620
  org = orgs.find((o2) => o2.id === orgId);
64291
64621
  }
@@ -64405,7 +64735,9 @@ async function runAgentCreate(cwd2, args) {
64405
64735
  name: agentName,
64406
64736
  tagline,
64407
64737
  harness,
64408
- ...resolvedEntrypoint !== undefined ? { entrypoint: resolvedEntrypoint } : {}
64738
+ ...resolvedEntrypoint !== undefined ? { entrypoint: resolvedEntrypoint } : {},
64739
+ ...manifest.machine_kind !== undefined ? { machine_kind: manifest.machine_kind } : {},
64740
+ ...manifest.default_model !== undefined ? { default_model: manifest.default_model } : {}
64409
64741
  });
64410
64742
  createSpinner.stop(`Created ${import_picocolors31.default.bold(agent.name)}.`);
64411
64743
  } catch (err) {
@@ -64413,6 +64745,29 @@ async function runAgentCreate(cwd2, args) {
64413
64745
  handleApiError4(err);
64414
64746
  return;
64415
64747
  }
64748
+ const machineConfigMissing = manifest.machine_kind !== undefined && agent.machine_kind !== manifest.machine_kind;
64749
+ const modelConfigMissing = manifest.default_model !== undefined && (!Object.prototype.hasOwnProperty.call(agent, "default_model") || (agent.default_model ?? null) !== (manifest.default_model ?? null));
64750
+ if (machineConfigMissing || modelConfigMissing) {
64751
+ manifest.id = agent.id;
64752
+ manifest.harness = harness;
64753
+ writeManifest(cwd2, manifest);
64754
+ const fields = [
64755
+ ...machineConfigMissing ? ["machine_kind"] : [],
64756
+ ...modelConfigMissing ? ["default_model"] : []
64757
+ ];
64758
+ f2.error(`Agent ${import_picocolors31.default.bold(agent.id)} was created, but this control plane did not apply ${fields.join(" / ")}.`);
64759
+ if (machineConfigMissing) {
64760
+ if (agent.machine_kind) {
64761
+ f2.info(`machine_kind is immutable. Run ${import_picocolors31.default.cyan("brainbase agent pull --force")} to accept ${agent.machine_kind}, or delete this agent and recreate it after upgrading the control plane.`);
64762
+ } else {
64763
+ f2.info("machine_kind is immutable and this server did not report the provider it created. Upgrade the control plane, delete this agent, and recreate it.");
64764
+ }
64765
+ } else {
64766
+ f2.info(`Upgrade the control plane, then run ${import_picocolors31.default.cyan("brainbase agent push")} to apply default_model.`);
64767
+ }
64768
+ process.exitCode = 1;
64769
+ return;
64770
+ }
64416
64771
  const session = authStatus().session;
64417
64772
  let tracking;
64418
64773
  const adapter = getRouteAdapter(harness);
@@ -64514,31 +64869,33 @@ async function runAgentCreate(cwd2, args) {
64514
64869
  manifest.playbooks = backfill.playbooks;
64515
64870
  writeManifest(cwd2, manifest);
64516
64871
  }
64517
- const localHashByKey = new Map;
64518
- for (const lc of readLocalComponents(cwd2, manifest)) {
64519
- if (lc.hash)
64520
- localHashByKey.set(`${lc.type}/${lc.slug}`, lc.hash);
64521
- }
64522
- const syncedComponents = updatedCloud.components.map((c2) => ({
64523
- type: c2.type,
64524
- slug: c2.slug,
64525
- hash: localHashByKey.get(`${c2.type}/${c2.slug}`) ?? c2.hash,
64526
- installedPaths: []
64527
- }));
64528
- const state = {
64529
- schemaVersion: 1,
64530
- agent_id: agent.id,
64531
- revision: updatedCloud.revision,
64532
- synced_at: new Date().toISOString(),
64533
- components: syncedComponents,
64534
- agentMeta: {
64535
- name: agent.name,
64536
- tagline: agent.tagline,
64537
- ...resolvedEntrypoint ? { entrypoint: resolvedEntrypoint.trim() } : {}
64538
- }
64539
- };
64540
- writeSyncState(cwd2, state);
64541
64872
  }
64873
+ const localHashByKey = new Map;
64874
+ for (const lc of readLocalComponents(cwd2, manifest)) {
64875
+ if (lc.hash)
64876
+ localHashByKey.set(`${lc.type}/${lc.slug}`, lc.hash);
64877
+ }
64878
+ const syncedComponents = (updatedCloud?.components ?? []).map((c2) => ({
64879
+ type: c2.type,
64880
+ slug: c2.slug,
64881
+ hash: localHashByKey.get(`${c2.type}/${c2.slug}`) ?? c2.hash,
64882
+ installedPaths: []
64883
+ }));
64884
+ const state = {
64885
+ schemaVersion: 1,
64886
+ agent_id: agent.id,
64887
+ revision: updatedCloud?.revision ?? agent.revision ?? 0,
64888
+ synced_at: new Date().toISOString(),
64889
+ components: syncedComponents,
64890
+ agentMeta: {
64891
+ name: agent.name,
64892
+ tagline: agent.tagline,
64893
+ ...resolvedEntrypoint ? { entrypoint: resolvedEntrypoint.trim() } : {},
64894
+ ...agent.machine_kind ? { machine_kind: agent.machine_kind } : {},
64895
+ ...Object.prototype.hasOwnProperty.call(agent, "default_model") ? { default_model: agent.default_model ?? null } : {}
64896
+ }
64897
+ };
64898
+ writeSyncState(cwd2, state);
64542
64899
  $e(`Created ${import_picocolors31.default.bold(agent.name)} and linked this folder.`);
64543
64900
  await showResultCard({
64544
64901
  title: "CREATED",
@@ -64632,6 +64989,10 @@ function handleApiError4(err) {
64632
64989
 
64633
64990
  // src/cli/agent.ts
64634
64991
  async function runAgent(cwd2, sub, args, opts) {
64992
+ if (args.some((arg) => arg === "--help" || arg === "-h")) {
64993
+ printHelp();
64994
+ return;
64995
+ }
64635
64996
  switch (sub) {
64636
64997
  case "create":
64637
64998
  await runAgentCreate(cwd2, {
@@ -64702,7 +65063,7 @@ function printHelp() {
64702
65063
  }
64703
65064
 
64704
65065
  // src/cli/orchestration.ts
64705
- var import_picocolors38 = __toESM(require_picocolors(), 1);
65066
+ var import_picocolors39 = __toESM(require_picocolors(), 1);
64706
65067
 
64707
65068
  // src/cli/orchestration-pull.ts
64708
65069
  import path82 from "node:path";
@@ -64730,20 +65091,32 @@ var EdgeSchema = exports_external.object({
64730
65091
  from: exports_external.string().min(1),
64731
65092
  to: exports_external.string().min(1),
64732
65093
  description: exports_external.string().optional(),
64733
- payload_schema: exports_external.record(exports_external.unknown()).optional()
65094
+ payload_schema: exports_external.record(exports_external.unknown()).optional(),
65095
+ settings: exports_external.record(exports_external.unknown()).optional()
64734
65096
  });
64735
65097
  var TriggerEdgeSchema = exports_external.object({
64736
65098
  agent: exports_external.string(),
64737
65099
  description: exports_external.string().optional(),
64738
65100
  payload_schema: exports_external.record(exports_external.unknown()).optional()
64739
65101
  });
64740
- var TriggerSchema = exports_external.object({
64741
- type: exports_external.string(),
64742
- node_id: exports_external.string(),
65102
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
65103
+ var ScheduleTriggerSchema = exports_external.object({
65104
+ type: exports_external.literal("schedule"),
65105
+ node_id: exports_external.string().regex(UUID_RE, "must be a UUID"),
65106
+ is_active: exports_external.boolean().optional(),
65107
+ config: exports_external.record(exports_external.unknown()).optional(),
65108
+ to: exports_external.array(TriggerEdgeSchema).default([])
65109
+ });
65110
+ var ReadOnlyTriggerSchema = exports_external.object({
65111
+ type: exports_external.string().refine((value) => value !== "schedule", {
65112
+ message: "schedule triggers must use a UUID node_id"
65113
+ }),
65114
+ node_id: exports_external.string().min(1),
64743
65115
  is_active: exports_external.boolean().optional(),
64744
65116
  config: exports_external.record(exports_external.unknown()).optional(),
64745
65117
  to: exports_external.array(TriggerEdgeSchema).default([])
64746
65118
  });
65119
+ var TriggerSchema = exports_external.union([ScheduleTriggerSchema, ReadOnlyTriggerSchema]);
64747
65120
  var OrchestrationManifestSchema = exports_external.object({
64748
65121
  schema: exports_external.literal(1),
64749
65122
  orchestration: OrchMetaSchema,
@@ -64779,7 +65152,9 @@ function writeOrchManifest(cwd2, manifest) {
64779
65152
  doc.contents = manifest;
64780
65153
  doc.commentBefore = ` brainbase-orchestration.yaml — declarative orchestration manifest.
64781
65154
  ` + ` Committed to source control. Edit by hand, then
64782
- ` + " `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`.";
65155
+ ` + " `brainbase orchestration push`. Member agents live under ./agents/." + `
65156
+ Schedule triggers are writable. App/Pipedream triggers are preserved
65157
+ ` + " as read-only context and ignored by `orchestration push`.";
64783
65158
  fs70.writeFileSync(orchManifestPath(cwd2), String(doc), "utf8");
64784
65159
  }
64785
65160
  function memberDir(cwd2, slug) {
@@ -64918,6 +65293,7 @@ async function installAgentFresh(input) {
64918
65293
  const { cwd: cwd2, agent, cloud, harness } = input;
64919
65294
  const scope = input.scope ?? "project";
64920
65295
  ensureDir(cwd2);
65296
+ const availableSecrets = input.pullSecrets === false ? {} : await pullAgentSecrets(cwd2, agent.id);
64921
65297
  const stageRoot = stageManifestComponents2(cloud.components);
64922
65298
  const justInstalledPaths = new Map;
64923
65299
  const caps = capabilitiesFromAgent(agent);
@@ -64936,7 +65312,7 @@ async function installAgentFresh(input) {
64936
65312
  rootDir: path81.join(stageRoot, c2.type, c2.slug),
64937
65313
  description: c2.description,
64938
65314
  meta: c2.meta,
64939
- payload: proxifyMcpPayload(c2.meta?.mcp),
65315
+ payload: proxifyMcpPayload(structuredClone(c2.meta?.mcp)),
64940
65316
  checksum: c2.hash
64941
65317
  }));
64942
65318
  toInstall.push(...builtinInstall);
@@ -64944,7 +65320,7 @@ async function installAgentFresh(input) {
64944
65320
  cwd: cwd2,
64945
65321
  scope,
64946
65322
  resolveConflict: async (_c) => "overwrite",
64947
- resolveSecret: async () => null
65323
+ resolveSecret: async (name) => availableSecrets[name] ?? null
64948
65324
  };
64949
65325
  const result2 = await runHarnessInstall4(harness, toInstall, installOpts, agent.name);
64950
65326
  for (const o2 of result2.installed) {
@@ -64952,6 +65328,7 @@ async function installAgentFresh(input) {
64952
65328
  }
64953
65329
  }
64954
65330
  materializeInstructions2(cwd2, cloud);
65331
+ materializePlaybooks2(cwd2, cloud);
64955
65332
  const manifest = input.preserveManifest ? null : buildManifestFromCloud(cloud, agent);
64956
65333
  if (manifest)
64957
65334
  writeManifest(cwd2, manifest);
@@ -64979,11 +65356,13 @@ async function installAgentFresh(input) {
64979
65356
  revision: cloud.revision,
64980
65357
  synced_at: new Date().toISOString(),
64981
65358
  components: syncedComponents,
64982
- agentMeta: { name: agent.name, tagline: agent.tagline }
65359
+ agentMeta: {
65360
+ name: agent.name,
65361
+ tagline: agent.tagline,
65362
+ ...agent.machine_kind ? { machine_kind: agent.machine_kind } : {},
65363
+ ...Object.prototype.hasOwnProperty.call(agent, "default_model") ? { default_model: agent.default_model ?? null } : {}
65364
+ }
64983
65365
  });
64984
- if (input.pullSecrets !== false) {
64985
- await pullAgentSecrets(cwd2, agent.id);
64986
- }
64987
65366
  const returnedManifest = manifest ?? buildManifestFromCloud(cloud, agent);
64988
65367
  return {
64989
65368
  installedPaths: justInstalledPaths,
@@ -65043,6 +65422,19 @@ function materializeInstructions2(cwd2, cloud) {
65043
65422
  return;
65044
65423
  }
65045
65424
  }
65425
+ function materializePlaybooks2(cwd2, cloud) {
65426
+ for (const c2 of cloud.components) {
65427
+ if (c2.type !== "playbook")
65428
+ continue;
65429
+ const raw = c2.files[0]?.content ?? "";
65430
+ if (!raw.trim())
65431
+ continue;
65432
+ const { body } = stripPlaybookFrontmatter(raw);
65433
+ const target = path81.join(cwd2, DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`);
65434
+ ensureDir(path81.dirname(target));
65435
+ fs72.writeFileSync(target, body, "utf8");
65436
+ }
65437
+ }
65046
65438
  function buildManifestFromCloud(cloud, agent) {
65047
65439
  const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
65048
65440
  const meta = c2.meta ?? {};
@@ -65071,15 +65463,31 @@ function buildManifestFromCloud(cloud, agent) {
65071
65463
  entry.is_enabled = payload.is_enabled;
65072
65464
  return entry;
65073
65465
  });
65466
+ const playbooks = cloud.components.filter((c2) => c2.type === "playbook").map((c2) => {
65467
+ const raw = c2.files[0]?.content ?? "";
65468
+ const { frontmatter } = stripPlaybookFrontmatter(raw);
65469
+ const pbMeta = c2.meta ?? {};
65470
+ const title = typeof frontmatter.title === "string" && frontmatter.title || c2.slug;
65471
+ const description = typeof frontmatter.description === "string" ? frontmatter.description : undefined;
65472
+ return {
65473
+ ...typeof pbMeta.playbook_id === "string" && pbMeta.playbook_id ? { id: pbMeta.playbook_id } : {},
65474
+ title,
65475
+ ...description ? { description } : {},
65476
+ ...typeof pbMeta.icon === "string" && pbMeta.icon ? { icon: pbMeta.icon } : {},
65477
+ content: { file: path81.join(DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`) }
65478
+ };
65479
+ });
65074
65480
  const caps = capabilitiesFromAgent(agent);
65075
65481
  return {
65076
65482
  schema: 1,
65483
+ ...agent.machine_kind ? { machine_kind: agent.machine_kind } : {},
65484
+ ...agent.default_model ? { default_model: agent.default_model } : {},
65077
65485
  agent: {
65078
65486
  name: agent.name,
65079
65487
  ...agent.tagline ? { tagline: agent.tagline } : {}
65080
65488
  },
65081
65489
  ...hasInstructions ? { instructions: { file: DEFAULT_INSTRUCTIONS_FILE } } : {},
65082
- playbooks: [],
65490
+ playbooks,
65083
65491
  evals: [],
65084
65492
  skills,
65085
65493
  mcp,
@@ -65098,14 +65506,58 @@ async function pullAgentSecrets(cwd2, agentId) {
65098
65506
  if (Object.keys(secrets).length > 0) {
65099
65507
  writeLocalSecrets(cwd2, secrets);
65100
65508
  }
65509
+ return secrets;
65101
65510
  } catch (err) {
65102
65511
  if (err instanceof ApiError && err.status !== 404) {
65103
65512
  f2.warn(`Skipped secrets for agent ${agentId}: ${err.message}`);
65104
65513
  }
65514
+ return {};
65105
65515
  }
65106
65516
  }
65107
65517
 
65518
+ // src/core/orchestration-trigger-config.ts
65519
+ function normalizeScheduleTriggerConfig(config) {
65520
+ const cron = config?.cron_expression;
65521
+ const result2 = {};
65522
+ if (typeof cron === "string" && cron.trim()) {
65523
+ result2.cron_expression = cron.trim();
65524
+ }
65525
+ const configuredProps = config?.configured_props;
65526
+ if (configuredProps && typeof configuredProps === "object" && !Array.isArray(configuredProps) && Object.keys(configuredProps).length > 0) {
65527
+ result2.configured_props = configuredProps;
65528
+ }
65529
+ return result2;
65530
+ }
65531
+ function scheduleTriggerConfigForManifest(config) {
65532
+ const normalized = normalizeScheduleTriggerConfig(config);
65533
+ return Object.keys(normalized).length ? normalized : undefined;
65534
+ }
65535
+ function formatScheduleTriggerLabel(input) {
65536
+ const config = normalizeScheduleTriggerConfig(input.config);
65537
+ const cron = typeof config.cron_expression === "string" ? config.cron_expression : "missing cron";
65538
+ const state = input.isActive ?? false ? "active" : "inactive";
65539
+ const targetText = input.targets.length ? ` -> ${input.targets.join(", ")}` : "";
65540
+ return `schedule ${input.nodeId} (${cron}, ${state})${targetText}`;
65541
+ }
65542
+
65108
65543
  // src/cli/orchestration-pull.ts
65544
+ function triggersForManifest(triggers, slugFor) {
65545
+ return triggers.map((trigger) => {
65546
+ const schedule = trigger.trigger_type === "schedule";
65547
+ const config = schedule ? scheduleTriggerConfigForManifest(trigger.config) : trigger.config;
65548
+ return {
65549
+ type: trigger.trigger_type,
65550
+ node_id: trigger.node_id,
65551
+ is_active: trigger.is_active,
65552
+ ...config && Object.keys(config).length ? { config } : {},
65553
+ to: trigger.edges.map((edge) => ({
65554
+ agent: slugFor(edge.to_agent_id),
65555
+ ...edge.description ? { description: edge.description } : {},
65556
+ ...edge.payload_schema && Object.keys(edge.payload_schema).length ? { payload_schema: edge.payload_schema } : {}
65557
+ }))
65558
+ };
65559
+ });
65560
+ }
65109
65561
  async function runOrchestrationPull(cwd2, args) {
65110
65562
  banner("orchestration pull — fetch orchestration + all member agents");
65111
65563
  let orchId = null;
@@ -65129,6 +65581,7 @@ async function runOrchestrationPull(cwd2, args) {
65129
65581
  } catch (err) {
65130
65582
  sp.stop("Failed.");
65131
65583
  handleApiError5(err);
65584
+ process.exitCode = 1;
65132
65585
  return;
65133
65586
  }
65134
65587
  const slugByAgent = resolveMemberSlugs(cloud.members);
@@ -65196,7 +65649,9 @@ async function runOrchestrationPull(cwd2, args) {
65196
65649
  org_id: cloud.group_id,
65197
65650
  team_id: cloud.group_id,
65198
65651
  url: undefined,
65199
- harness: fallbackHarness
65652
+ harness: fallbackHarness,
65653
+ machine_kind: m3.machine_kind,
65654
+ default_model: m3.default_model
65200
65655
  },
65201
65656
  cloud: m3.manifest,
65202
65657
  harness: fallbackHarness,
@@ -65214,6 +65669,7 @@ async function runOrchestrationPull(cwd2, args) {
65214
65669
  f2.error(err.message);
65215
65670
  }
65216
65671
  }
65672
+ const manifestTriggers = triggersForManifest(cloud.triggers ?? [], slugFor);
65217
65673
  const manifest = {
65218
65674
  schema: 1,
65219
65675
  orchestration: {
@@ -65234,21 +65690,10 @@ async function runOrchestrationPull(cwd2, args) {
65234
65690
  from: slugFor(e2.from_agent_id),
65235
65691
  to: slugFor(e2.to_agent_id),
65236
65692
  ...e2.description ? { description: e2.description } : {},
65237
- ...e2.payload_schema && Object.keys(e2.payload_schema).length ? { payload_schema: e2.payload_schema } : {}
65693
+ ...e2.payload_schema && Object.keys(e2.payload_schema).length ? { payload_schema: e2.payload_schema } : {},
65694
+ ...e2.settings && Object.keys(e2.settings).length ? { settings: e2.settings } : {}
65238
65695
  })),
65239
- ...cloud.triggers && cloud.triggers.length ? {
65240
- triggers: cloud.triggers.map((t) => ({
65241
- type: t.trigger_type,
65242
- node_id: t.node_id,
65243
- is_active: t.is_active,
65244
- ...t.config && Object.keys(t.config).length ? { config: t.config } : {},
65245
- to: t.edges.map((e2) => ({
65246
- agent: slugFor(e2.to_agent_id),
65247
- ...e2.description ? { description: e2.description } : {},
65248
- ...e2.payload_schema && Object.keys(e2.payload_schema).length ? { payload_schema: e2.payload_schema } : {}
65249
- }))
65250
- }))
65251
- } : {}
65696
+ ...manifestTriggers.length ? { triggers: manifestTriggers } : {}
65252
65697
  };
65253
65698
  writeOrchManifest(cwd2, manifest);
65254
65699
  writeOrchLink(cwd2, {
@@ -65292,6 +65737,70 @@ function handleApiError5(err) {
65292
65737
 
65293
65738
  // src/cli/orchestration-push.ts
65294
65739
  var import_picocolors34 = __toESM(require_picocolors(), 1);
65740
+
65741
+ // src/core/orchestration-outgoing.ts
65742
+ function buildOrchestrationGraphPayload(manifest, slugToAgentId) {
65743
+ const memberSlugs = new Set(manifest.members.map((m3) => m3.slug));
65744
+ for (const e2 of manifest.edges) {
65745
+ if (!memberSlugs.has(e2.from)) {
65746
+ throw new Error(`Edge from "${e2.from}" references a slug that isn't in members.`);
65747
+ }
65748
+ if (!memberSlugs.has(e2.to)) {
65749
+ throw new Error(`Edge to "${e2.to}" references a slug that isn't in members.`);
65750
+ }
65751
+ if (e2.from === e2.to) {
65752
+ throw new Error(`Edge ${e2.from} -> ${e2.to}: self-loops are not allowed.`);
65753
+ }
65754
+ }
65755
+ const scheduleTriggers = (manifest.triggers ?? []).filter((t) => t.type === "schedule");
65756
+ const seenTriggerNodeIds = new Set;
65757
+ for (const t of scheduleTriggers) {
65758
+ if (seenTriggerNodeIds.has(t.node_id)) {
65759
+ throw new Error(`Schedule trigger ${t.node_id} is duplicated.`);
65760
+ }
65761
+ seenTriggerNodeIds.add(t.node_id);
65762
+ const config = normalizeScheduleTriggerConfig(t.config);
65763
+ const cron = config.cron_expression;
65764
+ if (typeof cron !== "string" || !cron.trim()) {
65765
+ throw new Error(`Schedule trigger ${t.node_id} is missing cron_expression.`);
65766
+ }
65767
+ if (cron.trim().split(/\s+/).length !== 5) {
65768
+ throw new Error(`Schedule trigger ${t.node_id} cron_expression must use standard 5-field cron syntax.`);
65769
+ }
65770
+ for (const e2 of t.to) {
65771
+ if (!memberSlugs.has(e2.agent)) {
65772
+ throw new Error(`Trigger ${t.node_id} points to "${e2.agent}", which isn't in members.`);
65773
+ }
65774
+ }
65775
+ }
65776
+ const missing = manifest.members.map((m3) => m3.slug).filter((slug) => !slugToAgentId.has(slug));
65777
+ if (missing.length) {
65778
+ throw new Error(`These members have no local checkout (expected at agents/<slug>/brainbase.agent.yaml): ${missing.join(", ")}.`);
65779
+ }
65780
+ return {
65781
+ memberIds: manifest.members.map((m3) => slugToAgentId.get(m3.slug)),
65782
+ edges: manifest.edges.map((e2) => ({
65783
+ from_agent_id: slugToAgentId.get(e2.from),
65784
+ to_agent_id: slugToAgentId.get(e2.to),
65785
+ description: e2.description ?? "",
65786
+ payload_schema: e2.payload_schema ?? {},
65787
+ settings: e2.settings ?? {}
65788
+ })),
65789
+ triggers: scheduleTriggers.map((t) => ({
65790
+ node_id: t.node_id,
65791
+ type: "schedule",
65792
+ is_active: t.is_active ?? false,
65793
+ config: normalizeScheduleTriggerConfig(t.config),
65794
+ edges: t.to.map((e2) => ({
65795
+ to_agent_id: slugToAgentId.get(e2.agent),
65796
+ description: e2.description ?? "",
65797
+ payload_schema: e2.payload_schema ?? {}
65798
+ }))
65799
+ }))
65800
+ };
65801
+ }
65802
+
65803
+ // src/cli/orchestration-push.ts
65295
65804
  async function runOrchestrationPush(cwd2, args) {
65296
65805
  banner("orchestration push — recursively push each member, then update the graph");
65297
65806
  const link2 = readOrchLink(cwd2);
@@ -65310,23 +65819,9 @@ async function runOrchestrationPush(cwd2, args) {
65310
65819
  manifest = readOrchManifest(cwd2);
65311
65820
  } catch (err) {
65312
65821
  f2.error(err.message);
65822
+ process.exitCode = 1;
65313
65823
  return;
65314
65824
  }
65315
- const memberSlugs = new Set(manifest.members.map((m3) => m3.slug));
65316
- for (const e2 of manifest.edges) {
65317
- if (!memberSlugs.has(e2.from)) {
65318
- f2.error(`Edge from "${import_picocolors34.default.bold(e2.from)}" references a slug that isn't in members.`);
65319
- return;
65320
- }
65321
- if (!memberSlugs.has(e2.to)) {
65322
- f2.error(`Edge to "${import_picocolors34.default.bold(e2.to)}" references a slug that isn't in members.`);
65323
- return;
65324
- }
65325
- if (e2.from === e2.to) {
65326
- f2.error(`Edge ${import_picocolors34.default.bold(e2.from)} → ${import_picocolors34.default.bold(e2.to)}: self-loops are not allowed.`);
65327
- return;
65328
- }
65329
- }
65330
65825
  const slugToAgentId = new Map;
65331
65826
  const missing = [];
65332
65827
  for (const m3 of manifest.members) {
@@ -65339,13 +65834,21 @@ async function runOrchestrationPush(cwd2, args) {
65339
65834
  slugToAgentId.set(m3.slug, memberLink.agent_id);
65340
65835
  }
65341
65836
  if (missing.length) {
65342
- f2.error(`These members have no local checkout (expected at agents/<slug>/brainbase.agent.yaml): ${missing.join(", ")}.`);
65837
+ f2.error(`Missing local checkouts for: ${missing.join(", ")}.`);
65343
65838
  f2.info(`Run ${import_picocolors34.default.cyan("brainbase orchestration pull")} to materialise the missing folders.`);
65344
65839
  return;
65345
65840
  }
65841
+ let graph;
65842
+ try {
65843
+ graph = buildOrchestrationGraphPayload(manifest, slugToAgentId);
65844
+ } catch (err) {
65845
+ f2.error(err.message);
65846
+ process.exitCode = 1;
65847
+ return;
65848
+ }
65346
65849
  const plan = [""];
65347
65850
  plan.push(` ${import_picocolors34.default.bold(link2.name)} ${import_picocolors34.default.dim(`(${link2.orchestration_id})`)}`);
65348
- plan.push(` ${import_picocolors34.default.dim(`${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}`)}`);
65851
+ plan.push(` ${import_picocolors34.default.dim(`${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}, ${graph.triggers.length} trigger${graph.triggers.length === 1 ? "" : "s"}`)}`);
65349
65852
  plan.push("");
65350
65853
  if (!args.graphOnly) {
65351
65854
  plan.push(` ${import_picocolors34.default.dim("per-member agent push:")}`);
@@ -65358,7 +65861,7 @@ async function runOrchestrationPush(cwd2, args) {
65358
65861
  `));
65359
65862
  if (!autoProceed(args.yes)) {
65360
65863
  const ok = await se({
65361
- message: args.graphOnly ? "Push graph (members + edges) only?" : "Push each member, then update the graph?",
65864
+ message: args.graphOnly ? "Push graph (members, edges + triggers) only?" : "Push each member, then update the graph?",
65362
65865
  initialValue: true
65363
65866
  });
65364
65867
  if (!ensureNotCancelled(ok)) {
@@ -65375,17 +65878,11 @@ async function runOrchestrationPush(cwd2, args) {
65375
65878
  await runAgentPush(dir, { yes: true });
65376
65879
  } catch (err) {
65377
65880
  f2.error(`Failed to push ${m3.slug}: ${err.message}`);
65881
+ process.exitCode = 1;
65378
65882
  return;
65379
65883
  }
65380
65884
  }
65381
65885
  }
65382
- const memberIds = manifest.members.map((m3) => slugToAgentId.get(m3.slug));
65383
- const edges = manifest.edges.map((e2) => ({
65384
- from_agent_id: slugToAgentId.get(e2.from),
65385
- to_agent_id: slugToAgentId.get(e2.to),
65386
- description: e2.description ?? "",
65387
- payload_schema: e2.payload_schema ?? {}
65388
- }));
65389
65886
  const sp = de();
65390
65887
  sp.start("Updating orchestration graph…");
65391
65888
  const lock = readOrchSyncState(cwd2);
@@ -65396,8 +65893,9 @@ async function runOrchestrationPush(cwd2, args) {
65396
65893
  icon: manifest.orchestration.icon,
65397
65894
  icon_color: manifest.orchestration.icon_color,
65398
65895
  credit_limit: manifest.orchestration.credit_limit,
65399
- members: memberIds,
65400
- edges,
65896
+ members: graph.memberIds,
65897
+ edges: graph.edges,
65898
+ triggers: graph.triggers,
65401
65899
  ...lock?.revision != null ? { base_revision: lock.revision } : {}
65402
65900
  });
65403
65901
  sp.stop(`Graph updated. New cloud revision ${updated.revision}.`);
@@ -65408,7 +65906,7 @@ async function runOrchestrationPush(cwd2, args) {
65408
65906
  synced_at: new Date().toISOString(),
65409
65907
  members: updated.members.map((m3) => ({
65410
65908
  agent_id: m3.agent_id,
65411
- slug: m3.slug,
65909
+ slug: manifest.members.find((member) => slugToAgentId.get(member.slug) === m3.agent_id)?.slug ?? m3.slug,
65412
65910
  revision: m3.revision ?? 0
65413
65911
  })),
65414
65912
  edges: updated.edges.map((e2) => ({
@@ -65422,6 +65920,7 @@ async function runOrchestrationPush(cwd2, args) {
65422
65920
  } catch (err) {
65423
65921
  sp.stop("Failed.");
65424
65922
  handleApiError6(err);
65923
+ process.exitCode = 1;
65425
65924
  }
65426
65925
  }
65427
65926
  function handleApiError6(err) {
@@ -65466,6 +65965,7 @@ async function runOrchestrationStatus(cwd2) {
65466
65965
  } else {
65467
65966
  f2.error(err.message);
65468
65967
  }
65968
+ process.exitCode = 1;
65469
65969
  return;
65470
65970
  }
65471
65971
  const lines = [];
@@ -65473,7 +65973,14 @@ async function runOrchestrationStatus(cwd2) {
65473
65973
  lines.push(` ${import_picocolors35.default.bold(link2.name)} ${import_picocolors35.default.dim(`(${link2.orchestration_id})`)}`);
65474
65974
  lines.push(` ${import_picocolors35.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
65475
65975
  lines.push("");
65476
- const cloudMemberSet = new Set(cloud.members.map((m3) => m3.slug));
65976
+ const localSlugByAgentId = new Map;
65977
+ for (const m3 of localManifest?.members ?? []) {
65978
+ const link3 = readLink(memberDir(cwd2, m3.slug));
65979
+ if (link3)
65980
+ localSlugByAgentId.set(link3.agent_id, m3.slug);
65981
+ }
65982
+ const slugForAgent = (agentId, fallback) => localSlugByAgentId.get(agentId) ?? fallback;
65983
+ const cloudMemberSet = new Set(cloud.members.map((m3) => slugForAgent(m3.agent_id, m3.slug)));
65477
65984
  const localMemberSet = new Set((localManifest?.members ?? []).map((m3) => m3.slug));
65478
65985
  const membersAdded = [...localMemberSet].filter((s3) => !cloudMemberSet.has(s3));
65479
65986
  const membersRemoved = [...cloudMemberSet].filter((s3) => !localMemberSet.has(s3));
@@ -65487,8 +65994,8 @@ async function runOrchestrationStatus(cwd2) {
65487
65994
  }
65488
65995
  lines.push("");
65489
65996
  }
65490
- const cloudEdgeKey = (e2) => `${e2.from_slug ?? e2.from_agent_id}->${e2.to_slug ?? e2.to_agent_id}|${e2.description ?? ""}`;
65491
- const localEdgeKey = (e2) => `${e2.from}->${e2.to}|${e2.description ?? ""}`;
65997
+ const cloudEdgeKey = (e2) => `${slugForAgent(e2.from_agent_id, e2.from_slug ?? e2.from_agent_id)}->${slugForAgent(e2.to_agent_id, e2.to_slug ?? e2.to_agent_id)}|${e2.description ?? ""}|${stableJson(e2.payload_schema ?? {})}|${stableJson(e2.settings ?? {})}`;
65998
+ const localEdgeKey = (e2) => `${e2.from}->${e2.to}|${e2.description ?? ""}|${stableJson(e2.payload_schema ?? {})}|${stableJson(e2.settings ?? {})}`;
65492
65999
  const cloudEdges = new Map;
65493
66000
  for (const e2 of cloud.edges)
65494
66001
  cloudEdges.set(cloudEdgeKey(e2), true);
@@ -65505,20 +66012,63 @@ async function runOrchestrationStatus(cwd2) {
65505
66012
  lines.push(` ${import_picocolors35.default.cyan("← pull")} added on cloud: ${k3}`);
65506
66013
  lines.push("");
65507
66014
  }
66015
+ const cloudTriggerKey = (t) => {
66016
+ const edges = t.edges.map((e2) => `${slugForAgent(e2.to_agent_id, e2.to_slug ?? e2.to_agent_id)}|${e2.description ?? ""}|${stableJson(e2.payload_schema ?? {})}`).sort().join(",");
66017
+ return `${t.node_id}|${t.is_active ?? false}|${stableJson(normalizeScheduleTriggerConfig(t.config))}|${edges}`;
66018
+ };
66019
+ const cloudTriggerLabel = (t) => formatScheduleTriggerLabel({
66020
+ nodeId: t.node_id,
66021
+ isActive: t.is_active ?? false,
66022
+ config: t.config,
66023
+ targets: t.edges.map((e2) => slugForAgent(e2.to_agent_id, e2.to_slug ?? e2.to_agent_id))
66024
+ });
66025
+ const localTriggerKey = (t) => {
66026
+ const edges = t.to.map((e2) => `${e2.agent}|${e2.description ?? ""}|${stableJson(e2.payload_schema ?? {})}`).sort().join(",");
66027
+ return `${t.node_id}|${t.is_active ?? false}|${stableJson(normalizeScheduleTriggerConfig(t.config))}|${edges}`;
66028
+ };
66029
+ const localTriggerLabel = (t) => formatScheduleTriggerLabel({
66030
+ nodeId: t.node_id,
66031
+ isActive: t.is_active ?? false,
66032
+ config: t.config,
66033
+ targets: t.to.map((e2) => e2.agent)
66034
+ });
66035
+ const cloudTriggers = new Map;
66036
+ for (const t of cloud.triggers ?? []) {
66037
+ if (t.trigger_type === "schedule") {
66038
+ cloudTriggers.set(cloudTriggerKey(t), cloudTriggerLabel(t));
66039
+ }
66040
+ }
66041
+ const localTriggers = new Map;
66042
+ for (const t of localManifest?.triggers ?? []) {
66043
+ if (t.type === "schedule") {
66044
+ localTriggers.set(localTriggerKey(t), localTriggerLabel(t));
66045
+ }
66046
+ }
66047
+ const triggersAdded = [...localTriggers.keys()].filter((k3) => !cloudTriggers.has(k3));
66048
+ const triggersRemoved = [...cloudTriggers.keys()].filter((k3) => !localTriggers.has(k3));
66049
+ if (triggersAdded.length || triggersRemoved.length) {
66050
+ lines.push(` ${import_picocolors35.default.bold("schedule triggers")}`);
66051
+ for (const k3 of triggersAdded)
66052
+ lines.push(` ${import_picocolors35.default.yellow("→ push")} added/changed in yaml: ${localTriggers.get(k3) ?? k3}`);
66053
+ for (const k3 of triggersRemoved)
66054
+ lines.push(` ${import_picocolors35.default.cyan("← pull")} added/changed on cloud: ${cloudTriggers.get(k3) ?? k3}`);
66055
+ lines.push("");
66056
+ }
65508
66057
  const lockByAgentId = new Map((lock?.members ?? []).map((m3) => [m3.agent_id, m3]));
65509
66058
  const memberDrift = [];
65510
66059
  for (const m3 of cloud.members) {
65511
- const dir = memberDir(cwd2, m3.slug);
66060
+ const slug = slugForAgent(m3.agent_id, m3.slug);
66061
+ const dir = memberDir(cwd2, slug);
65512
66062
  const memberSync = readSyncState(dir);
65513
66063
  if (!memberSync) {
65514
- memberDrift.push({ slug: m3.slug, reason: "no local checkout" });
66064
+ memberDrift.push({ slug, reason: "no local checkout" });
65515
66065
  continue;
65516
66066
  }
65517
66067
  const lockEntry = lockByAgentId.get(m3.agent_id);
65518
66068
  const lockedRev = lockEntry?.revision;
65519
66069
  if (m3.revision != null && lockedRev != null && m3.revision !== lockedRev) {
65520
66070
  memberDrift.push({
65521
- slug: m3.slug,
66071
+ slug,
65522
66072
  reason: `cloud rev ${m3.revision} ≠ lock ${lockedRev}`
65523
66073
  });
65524
66074
  }
@@ -65531,7 +66081,13 @@ async function runOrchestrationStatus(cwd2) {
65531
66081
  lines.push(` ${import_picocolors35.default.dim("cd into each member folder and run")} ${import_picocolors35.default.cyan("brainbase agent status")}`);
65532
66082
  lines.push("");
65533
66083
  }
65534
- if (!membersAdded.length && !membersRemoved.length && !edgesAdded.length && !edgesRemoved.length && !memberDrift.length) {
66084
+ const revisionDrift = lock?.revision != null && cloud.revision !== lock.revision;
66085
+ if (revisionDrift) {
66086
+ lines.push(` ${import_picocolors35.default.bold("cloud revision")}`);
66087
+ lines.push(` ${import_picocolors35.default.cyan("← pull")} cloud changed since last pull: ${import_picocolors35.default.dim(`lock ${lock.revision} → cloud ${cloud.revision}`)}`);
66088
+ lines.push("");
66089
+ }
66090
+ if (!membersAdded.length && !membersRemoved.length && !edgesAdded.length && !edgesRemoved.length && !triggersAdded.length && !triggersRemoved.length && !memberDrift.length && !revisionDrift) {
65535
66091
  lines.push(` ${import_picocolors35.default.green("✓")} everything is in sync`);
65536
66092
  lines.push("");
65537
66093
  console.log(lines.join(`
@@ -65543,6 +66099,14 @@ async function runOrchestrationStatus(cwd2) {
65543
66099
  console.log(lines.join(`
65544
66100
  `));
65545
66101
  }
66102
+ function stableJson(value) {
66103
+ if (value == null || typeof value !== "object")
66104
+ return JSON.stringify(value);
66105
+ if (Array.isArray(value))
66106
+ return `[${value.map(stableJson).join(",")}]`;
66107
+ const obj = value;
66108
+ return `{${Object.keys(obj).sort().map((key2) => `${JSON.stringify(key2)}:${stableJson(obj[key2])}`).join(",")}}`;
66109
+ }
65546
66110
 
65547
66111
  // src/cli/orchestration-list.ts
65548
66112
  var import_picocolors36 = __toESM(require_picocolors(), 1);
@@ -65550,7 +66114,7 @@ async function runOrchestrationList(args) {
65550
66114
  banner("orchestration list — orchestrations under a team");
65551
66115
  let orgId = args.orgId;
65552
66116
  let teamId = args.teamId;
65553
- if (!orgId) {
66117
+ if (!orgId || !isUuid(orgId)) {
65554
66118
  let orgs;
65555
66119
  try {
65556
66120
  orgs = await api.listOrgs();
@@ -65562,13 +66126,20 @@ async function runOrchestrationList(args) {
65562
66126
  f2.warn("You are not a member of any organization.");
65563
66127
  return;
65564
66128
  }
65565
- if (orgs.length === 1) {
66129
+ if (orgId) {
66130
+ const found = orgs.find((o2) => o2.id === orgId || o2.slug === orgId);
66131
+ if (!found) {
66132
+ f2.error(`Org ${orgId} not found or you're not a member.`);
66133
+ return;
66134
+ }
66135
+ orgId = found.id;
66136
+ } else if (orgs.length === 1) {
65566
66137
  orgId = orgs[0].id;
65567
66138
  } else {
65568
66139
  orgId = await select({
65569
66140
  message: "Which organization?",
65570
- options: orgs.map((o2) => ({ value: o2.id, label: o2.name })),
65571
- flagHint: "Pass --org <id>."
66141
+ options: orgs.map((o2) => ({ value: o2.id, label: o2.name, hint: o2.role })),
66142
+ flagHint: "Pass --org <id-or-slug>."
65572
66143
  });
65573
66144
  }
65574
66145
  }
@@ -65622,6 +66193,9 @@ async function runOrchestrationList(args) {
65622
66193
  console.log(lines.join(`
65623
66194
  `));
65624
66195
  }
66196
+ function isUuid(value) {
66197
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-9a-f][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
66198
+ }
65625
66199
  function handleApiError7(err) {
65626
66200
  if (err instanceof ApiError) {
65627
66201
  if (err.status === 401) {
@@ -65820,9 +66394,224 @@ async function runOrchestrationAddAgent(cwd2, args) {
65820
66394
  await runOrchestrationPush(cwd2, { yes: true, graphOnly: true });
65821
66395
  }
65822
66396
 
66397
+ // src/cli/orchestration-create.ts
66398
+ var import_picocolors38 = __toESM(require_picocolors(), 1);
66399
+ async function runOrchestrationCreate(cwd2, args) {
66400
+ banner("orchestration create — claim a brainbase-orchestration.yaml");
66401
+ if (readOrchLink(cwd2)) {
66402
+ f2.warn("This folder is already linked to an orchestration.");
66403
+ f2.info(`Run ${import_picocolors38.default.cyan("brainbase orchestration push")} to update it.`);
66404
+ return;
66405
+ }
66406
+ if (!hasOrchManifest(cwd2)) {
66407
+ f2.warn(`No ${import_picocolors38.default.bold(ORCH_MANIFEST_FILE)} here.`);
66408
+ f2.info(`Create one, or pull an existing orchestration first.`);
66409
+ return;
66410
+ }
66411
+ let manifest;
66412
+ try {
66413
+ manifest = readOrchManifest(cwd2);
66414
+ } catch (err) {
66415
+ f2.error(err.message);
66416
+ process.exitCode = 1;
66417
+ return;
66418
+ }
66419
+ const slugToAgentId = new Map;
66420
+ for (const m3 of manifest.members) {
66421
+ const link2 = readLink(memberDir(cwd2, m3.slug));
66422
+ if (link2)
66423
+ slugToAgentId.set(m3.slug, link2.agent_id);
66424
+ }
66425
+ let graph;
66426
+ try {
66427
+ graph = buildOrchestrationGraphPayload(manifest, slugToAgentId);
66428
+ } catch (err) {
66429
+ f2.error(err.message);
66430
+ process.exitCode = 1;
66431
+ return;
66432
+ }
66433
+ const target = await resolveOrgAndTeam(args);
66434
+ if (!target)
66435
+ return;
66436
+ const plan = [
66437
+ "",
66438
+ ` ${import_picocolors38.default.bold(manifest.orchestration.name)}`,
66439
+ ` ${import_picocolors38.default.dim("org")} ${import_picocolors38.default.bold(target.org.name)}`,
66440
+ ` ${import_picocolors38.default.dim("team")} ${import_picocolors38.default.bold(target.team.name)}`,
66441
+ ` ${import_picocolors38.default.dim("graph")} ${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}, ${graph.triggers.length} trigger${graph.triggers.length === 1 ? "" : "s"}`,
66442
+ ""
66443
+ ];
66444
+ console.log(plan.join(`
66445
+ `));
66446
+ if (!autoProceed(args.yes)) {
66447
+ const ok = await se({
66448
+ message: "Create this orchestration?",
66449
+ initialValue: true
66450
+ });
66451
+ if (!ensureNotCancelled(ok)) {
66452
+ $e("Aborted.");
66453
+ return;
66454
+ }
66455
+ }
66456
+ const sp = de();
66457
+ sp.start("Creating orchestration…");
66458
+ try {
66459
+ const created = await api.createOrchestration({
66460
+ org_id: target.org.id,
66461
+ team_id: target.team.id,
66462
+ name: manifest.orchestration.name,
66463
+ description: manifest.orchestration.description ?? "",
66464
+ icon: manifest.orchestration.icon,
66465
+ icon_color: manifest.orchestration.icon_color,
66466
+ credit_limit: manifest.orchestration.credit_limit,
66467
+ members: graph.memberIds,
66468
+ edges: graph.edges,
66469
+ triggers: graph.triggers
66470
+ });
66471
+ sp.stop(`Created ${import_picocolors38.default.bold(created.name)}.`);
66472
+ writeOrchLink(cwd2, {
66473
+ schemaVersion: 1,
66474
+ orchestration_id: created.id,
66475
+ group_id: created.group_id,
66476
+ org_id: target.org.id,
66477
+ team_id: target.team.id,
66478
+ name: created.name,
66479
+ description: created.description || undefined,
66480
+ linked_at: new Date().toISOString()
66481
+ });
66482
+ writeOrchSyncState(cwd2, {
66483
+ schemaVersion: 1,
66484
+ orchestration_id: created.id,
66485
+ revision: created.revision,
66486
+ synced_at: new Date().toISOString(),
66487
+ members: created.members.map((m3) => ({
66488
+ agent_id: m3.agent_id,
66489
+ slug: manifest.members.find((member) => slugToAgentId.get(member.slug) === m3.agent_id)?.slug ?? m3.slug,
66490
+ revision: m3.revision ?? 0
66491
+ })),
66492
+ edges: created.edges.map((e2) => ({
66493
+ from_slug: e2.from_slug ?? e2.from_agent_id,
66494
+ to_slug: e2.to_slug ?? e2.to_agent_id,
66495
+ description: e2.description ?? "",
66496
+ payload_schema: e2.payload_schema ?? {}
66497
+ }))
66498
+ });
66499
+ $e(`Created ${created.name} at revision ${created.revision}.`);
66500
+ } catch (err) {
66501
+ sp.stop("Failed.");
66502
+ handleApiError8(err);
66503
+ process.exitCode = 1;
66504
+ }
66505
+ }
66506
+ async function resolveOrgAndTeam(args) {
66507
+ const orgsSpinner = de();
66508
+ orgsSpinner.start("Loading your organizations…");
66509
+ let orgs;
66510
+ try {
66511
+ orgs = await api.listOrgs();
66512
+ } catch (err) {
66513
+ orgsSpinner.stop("Failed.");
66514
+ handleApiError8(err);
66515
+ process.exitCode = 1;
66516
+ return null;
66517
+ }
66518
+ orgsSpinner.stop(`Found ${orgs.length} organization${orgs.length === 1 ? "" : "s"}.`);
66519
+ if (orgs.length === 0) {
66520
+ f2.warn("You are not in any organizations yet.");
66521
+ process.exitCode = 1;
66522
+ return null;
66523
+ }
66524
+ let org;
66525
+ if (args.orgId) {
66526
+ const found = orgs.find((o2) => o2.id === args.orgId || o2.slug === args.orgId);
66527
+ if (!found) {
66528
+ f2.error(`Org ${args.orgId} not found or you're not a member.`);
66529
+ process.exitCode = 1;
66530
+ return null;
66531
+ }
66532
+ org = found;
66533
+ } else if (orgs.length === 1) {
66534
+ org = orgs[0];
66535
+ f2.info(`Using organization ${import_picocolors38.default.bold(org.name)}.`);
66536
+ } else if (!isInteractive()) {
66537
+ throw new NonInteractiveError("Multiple organizations. Pass --org <id-or-slug> to choose non-interactively.");
66538
+ } else {
66539
+ const orgId = await select({
66540
+ message: "Pick an organization",
66541
+ options: orgs.map((o2) => ({ value: o2.id, label: o2.name, hint: o2.role })),
66542
+ flagHint: "Pass --org <id-or-slug> to choose non-interactively."
66543
+ });
66544
+ org = orgs.find((o2) => o2.id === orgId);
66545
+ }
66546
+ const teamsSpinner = de();
66547
+ teamsSpinner.start(`Loading teams in ${org.name}…`);
66548
+ let teams;
66549
+ try {
66550
+ teams = await api.listTeams(org.id);
66551
+ } catch (err) {
66552
+ teamsSpinner.stop("Failed.");
66553
+ handleApiError8(err);
66554
+ process.exitCode = 1;
66555
+ return null;
66556
+ }
66557
+ teamsSpinner.stop(`Found ${teams.length} team${teams.length === 1 ? "" : "s"}.`);
66558
+ if (teams.length === 0) {
66559
+ f2.warn(`No teams in ${org.name} yet.`);
66560
+ process.exitCode = 1;
66561
+ return null;
66562
+ }
66563
+ let team;
66564
+ if (args.teamId) {
66565
+ const found = teams.find((t) => t.id === args.teamId);
66566
+ if (!found) {
66567
+ f2.error(`Team ${args.teamId} not found in this org.`);
66568
+ process.exitCode = 1;
66569
+ return null;
66570
+ }
66571
+ team = found;
66572
+ } else if (teams.length === 1) {
66573
+ team = teams[0];
66574
+ f2.info(`Using team ${import_picocolors38.default.bold(team.name)}.`);
66575
+ } else if (!isInteractive()) {
66576
+ throw new NonInteractiveError("Multiple teams. Pass --team <id> to choose non-interactively.");
66577
+ } else {
66578
+ const teamId = await select({
66579
+ message: "Pick a team",
66580
+ options: teams.map((t) => ({ value: t.id, label: t.name, hint: t.role })),
66581
+ flagHint: "Pass --team <id> to choose non-interactively."
66582
+ });
66583
+ team = teams.find((t) => t.id === teamId);
66584
+ }
66585
+ return { org, team };
66586
+ }
66587
+ function handleApiError8(err) {
66588
+ if (err instanceof ApiError) {
66589
+ if (err.status === 401) {
66590
+ f2.error("Your session is invalid. Run `brainbase login` and try again.");
66591
+ } else if (err.status === 403) {
66592
+ f2.error("You do not have access to create this orchestration.");
66593
+ } else {
66594
+ f2.error(err.message);
66595
+ }
66596
+ } else {
66597
+ f2.error(err.message);
66598
+ }
66599
+ }
66600
+
65823
66601
  // src/cli/orchestration.ts
65824
66602
  async function runOrchestration(cwd2, sub, args, opts) {
66603
+ if (args.some((arg) => arg === "--help" || arg === "-h")) {
66604
+ printHelp2();
66605
+ return;
66606
+ }
65825
66607
  switch (sub) {
66608
+ case "create":
66609
+ await runOrchestrationCreate(cwd2, {
66610
+ yes: opts.yes,
66611
+ orgId: opts.orgId,
66612
+ teamId: opts.teamId
66613
+ });
66614
+ return;
65826
66615
  case "pull":
65827
66616
  await runOrchestrationPull(cwd2, {
65828
66617
  orchestrationId: args[0],
@@ -65873,20 +66662,21 @@ async function runOrchestration(cwd2, sub, args, opts) {
65873
66662
  function printHelp2() {
65874
66663
  const out = [];
65875
66664
  out.push("");
65876
- out.push(` ${import_picocolors38.default.bold("brainbase orchestration")} ${import_picocolors38.default.dim("<sub> [options]")}`);
66665
+ out.push(` ${import_picocolors39.default.bold("brainbase orchestration")} ${import_picocolors39.default.dim("<sub> [options]")}`);
65877
66666
  out.push("");
65878
- out.push(` ${import_picocolors38.default.cyan("pull")} ${import_picocolors38.default.dim("<id>")} ${import_picocolors38.default.dim("fetch orchestration + every member agent into this folder")}`);
65879
- out.push(` ${import_picocolors38.default.cyan("push")} ${import_picocolors38.default.dim("push each member, then update the orchestration graph")}`);
65880
- 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")}`);
65881
- out.push(` ${import_picocolors38.default.cyan("status")} ${import_picocolors38.default.dim("show what would push and what would pull")}`);
65882
- out.push(` ${import_picocolors38.default.cyan("list")} ${import_picocolors38.default.dim("list orchestrations under a team")}`);
66667
+ out.push(` ${import_picocolors39.default.cyan("create")} ${import_picocolors39.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
66668
+ out.push(` ${import_picocolors39.default.cyan("pull")} ${import_picocolors39.default.dim("<id>")} ${import_picocolors39.default.dim("fetch orchestration + every member agent into this folder")}`);
66669
+ out.push(` ${import_picocolors39.default.cyan("push")} ${import_picocolors39.default.dim("push each member, then update the orchestration graph")}`);
66670
+ out.push(` ${import_picocolors39.default.cyan("add-agent")} ${import_picocolors39.default.dim("<name>")} ${import_picocolors39.default.dim("create a member agent, wire edges (--from/--to), and push")}`);
66671
+ out.push(` ${import_picocolors39.default.cyan("status")} ${import_picocolors39.default.dim("show what would push and what would pull")}`);
66672
+ out.push(` ${import_picocolors39.default.cyan("list")} ${import_picocolors39.default.dim("list orchestrations under a team")}`);
65883
66673
  out.push("");
65884
- out.push(` ${import_picocolors38.default.bold("Flags")}`);
65885
- out.push(` ${import_picocolors38.default.dim("--yes, -y")} skip confirmations`);
65886
- out.push(` ${import_picocolors38.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
65887
- out.push(` ${import_picocolors38.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`);
65888
- out.push(` ${import_picocolors38.default.dim("--org <id>")} for list: org id (CLI vocab — DB teams.id)`);
65889
- out.push(` ${import_picocolors38.default.dim("--team <id>")} for list: team id (CLI vocab — DB groups.id)`);
66674
+ out.push(` ${import_picocolors39.default.bold("Flags")}`);
66675
+ out.push(` ${import_picocolors39.default.dim("--yes, -y")} skip confirmations`);
66676
+ out.push(` ${import_picocolors39.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
66677
+ out.push(` ${import_picocolors39.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`);
66678
+ out.push(` ${import_picocolors39.default.dim("--org <id>")} for create/list: org id or slug (CLI vocab — DB teams.id)`);
66679
+ out.push(` ${import_picocolors39.default.dim("--team <id>")} for create/list: team id (CLI vocab — DB groups.id)`);
65890
66680
  out.push("");
65891
66681
  console.log(out.join(`
65892
66682
  `));
@@ -65931,16 +66721,16 @@ async function runRun(cwd2, args) {
65931
66721
  }
65932
66722
 
65933
66723
  // src/cli/publish.ts
65934
- var import_picocolors39 = __toESM(require_picocolors(), 1);
66724
+ var import_picocolors40 = __toESM(require_picocolors(), 1);
65935
66725
  async function runPublish(cwd2, _args) {
65936
66726
  banner("publish — send your changes to the team");
65937
66727
  const link2 = readLink(cwd2);
65938
66728
  if (!link2) {
65939
66729
  f2.warn("This folder is not linked to any agent.");
65940
- f2.info(`Run ${import_picocolors39.default.cyan("brainbase link")} first.`);
66730
+ f2.info(`Run ${import_picocolors40.default.cyan("brainbase link")} first.`);
65941
66731
  return;
65942
66732
  }
65943
- 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.`);
66733
+ f2.info(`${import_picocolors40.default.bold("publish")} is coming soon — for now, edit the agent on the web app and run ${import_picocolors40.default.cyan("brainbase sync")} to bring changes here.`);
65944
66734
  }
65945
66735
 
65946
66736
  // src/ui/ink/StatusCard.tsx
@@ -66238,7 +67028,7 @@ async function runStatus(cwd2) {
66238
67028
  }
66239
67029
 
66240
67030
  // src/cli/token.ts
66241
- var import_picocolors40 = __toESM(require_picocolors(), 1);
67031
+ var import_picocolors41 = __toESM(require_picocolors(), 1);
66242
67032
 
66243
67033
  // src/ui/ink/TokenCards.tsx
66244
67034
  var jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
@@ -66532,7 +67322,7 @@ async function runTokenRevoke(args) {
66532
67322
  }
66533
67323
  if (!autoProceed(args.yes)) {
66534
67324
  const ok = await se({
66535
- message: `Revoke token ${import_picocolors40.default.bold(args.id)}? CIs and machines using it will stop working.`,
67325
+ message: `Revoke token ${import_picocolors41.default.bold(args.id)}? CIs and machines using it will stop working.`,
66536
67326
  initialValue: false
66537
67327
  });
66538
67328
  if (!ensureNotCancelled(ok))
@@ -66547,7 +67337,7 @@ async function runTokenRevoke(args) {
66547
67337
  }
66548
67338
  async function runTokenClear() {
66549
67339
  if (!readToken()) {
66550
- console.log(import_picocolors40.default.dim("No local token stored."));
67340
+ console.log(import_picocolors41.default.dim("No local token stored."));
66551
67341
  return;
66552
67342
  }
66553
67343
  clearToken();
@@ -66598,24 +67388,24 @@ async function runToken(sub, rest2, args) {
66598
67388
  function printTokenHelp() {
66599
67389
  const out = [];
66600
67390
  out.push("");
66601
- out.push(` ${import_picocolors40.default.bold("brainbase token")} ${import_picocolors40.default.dim("<command>")}`);
67391
+ out.push(` ${import_picocolors41.default.bold("brainbase token")} ${import_picocolors41.default.dim("<command>")}`);
66602
67392
  out.push("");
66603
- out.push(` ${import_picocolors40.default.cyan("create")} ${import_picocolors40.default.dim("issue a new long-lived CLI key (PAT)")}`);
66604
- out.push(` ${import_picocolors40.default.cyan("list")} ${import_picocolors40.default.dim("show your active tokens")}`);
66605
- out.push(` ${import_picocolors40.default.cyan("revoke")} ${import_picocolors40.default.dim("<id>")} ${import_picocolors40.default.dim("revoke a token by id")}`);
66606
- out.push(` ${import_picocolors40.default.cyan("clear")} ${import_picocolors40.default.dim("forget the local token (does not revoke)")}`);
67393
+ out.push(` ${import_picocolors41.default.cyan("create")} ${import_picocolors41.default.dim("issue a new long-lived CLI key (PAT)")}`);
67394
+ out.push(` ${import_picocolors41.default.cyan("list")} ${import_picocolors41.default.dim("show your active tokens")}`);
67395
+ out.push(` ${import_picocolors41.default.cyan("revoke")} ${import_picocolors41.default.dim("<id>")} ${import_picocolors41.default.dim("revoke a token by id")}`);
67396
+ out.push(` ${import_picocolors41.default.cyan("clear")} ${import_picocolors41.default.dim("forget the local token (does not revoke)")}`);
66607
67397
  out.push("");
66608
- out.push(` ${import_picocolors40.default.bold("create flags")}`);
66609
- out.push(` ${import_picocolors40.default.cyan("--name, -n")} ${import_picocolors40.default.dim("<label>")} ${import_picocolors40.default.dim("token label (prompted if omitted)")}`);
66610
- out.push(` ${import_picocolors40.default.cyan("--scopes")} ${import_picocolors40.default.dim("<list>")} ${import_picocolors40.default.dim("comma-separated; allowed: read, publish, admin")}`);
66611
- out.push(` ${import_picocolors40.default.dim("default: read,publish")}`);
67398
+ out.push(` ${import_picocolors41.default.bold("create flags")}`);
67399
+ out.push(` ${import_picocolors41.default.cyan("--name, -n")} ${import_picocolors41.default.dim("<label>")} ${import_picocolors41.default.dim("token label (prompted if omitted)")}`);
67400
+ out.push(` ${import_picocolors41.default.cyan("--scopes")} ${import_picocolors41.default.dim("<list>")} ${import_picocolors41.default.dim("comma-separated; allowed: read, publish, admin")}`);
67401
+ out.push(` ${import_picocolors41.default.dim("default: read,publish")}`);
66612
67402
  out.push("");
66613
67403
  console.log(out.join(`
66614
67404
  `));
66615
67405
  }
66616
67406
 
66617
67407
  // src/cli/mcp.ts
66618
- var import_picocolors41 = __toESM(require_picocolors(), 1);
67408
+ var import_picocolors42 = __toESM(require_picocolors(), 1);
66619
67409
 
66620
67410
  // src/core/mcp-check/collect-servers.ts
66621
67411
  import path83 from "node:path";
@@ -74963,17 +75753,17 @@ async function runMcpCheck(cwd2, options) {
74963
75753
  function renderHuman(report) {
74964
75754
  const lines = [];
74965
75755
  if (report.check_status === "skipped") {
74966
- lines.push(import_picocolors41.default.dim("No MCP servers configured — nothing to check."));
75756
+ lines.push(import_picocolors42.default.dim("No MCP servers configured — nothing to check."));
74967
75757
  return lines.join(`
74968
75758
  `) + `
74969
75759
  `;
74970
75760
  }
74971
75761
  for (const s3 of report.servers) {
74972
- const mark = s3.status === "ok" ? import_picocolors41.default.green("✓") : s3.status === "auth_failed" ? import_picocolors41.default.red("✗") : import_picocolors41.default.yellow("⚠");
74973
- const detail = s3.status === "ok" ? import_picocolors41.default.dim(`${s3.tool_count} tool${s3.tool_count === 1 ? "" : "s"}`) : import_picocolors41.default.dim(s3.status + (s3.error ? ` — ${s3.error}` : ""));
75762
+ const mark = s3.status === "ok" ? import_picocolors42.default.green("✓") : s3.status === "auth_failed" ? import_picocolors42.default.red("✗") : import_picocolors42.default.yellow("⚠");
75763
+ const detail = s3.status === "ok" ? import_picocolors42.default.dim(`${s3.tool_count} tool${s3.tool_count === 1 ? "" : "s"}`) : import_picocolors42.default.dim(s3.status + (s3.error ? ` — ${s3.error}` : ""));
74974
75764
  lines.push(` ${mark} ${s3.name} ${detail}`);
74975
75765
  }
74976
- const summary = report.check_status === "ok" ? import_picocolors41.default.green("All MCP servers connected.") : import_picocolors41.default.yellow("Some MCP servers are unhealthy.");
75766
+ const summary = report.check_status === "ok" ? import_picocolors42.default.green("All MCP servers connected.") : import_picocolors42.default.yellow("Some MCP servers are unhealthy.");
74977
75767
  lines.push("", summary);
74978
75768
  return lines.join(`
74979
75769
  `) + `
@@ -75009,97 +75799,100 @@ var PROTECTED = new Set([
75009
75799
  function help() {
75010
75800
  const out = [];
75011
75801
  out.push("");
75012
- out.push(` ${brandTint("◆")} ${import_picocolors42.default.bold("brainbase")} ${import_picocolors42.default.dim(`v${VERSION}`)}`);
75013
- out.push(` ${import_picocolors42.default.dim("connect your local agent to the brainbase platform")}`);
75802
+ out.push(` ${brandTint("◆")} ${import_picocolors43.default.bold("brainbase")} ${import_picocolors43.default.dim(`v${VERSION}`)}`);
75803
+ out.push(` ${import_picocolors43.default.dim("connect your local agent to the brainbase platform")}`);
75014
75804
  out.push("");
75015
75805
  out.push(divider("USAGE"));
75016
75806
  out.push("");
75017
- out.push(` ${import_picocolors42.default.bold("brainbase")} ${import_picocolors42.default.dim("<command> [options]")}`);
75807
+ out.push(` ${import_picocolors43.default.bold("brainbase")} ${import_picocolors43.default.dim("<command> [options]")}`);
75018
75808
  out.push("");
75019
75809
  out.push(divider("AUTH"));
75020
75810
  out.push("");
75021
- out.push(` ${import_picocolors42.default.cyan("login")} ${import_picocolors42.default.dim(" open the web app and connect this device")}`);
75022
- out.push(` ${import_picocolors42.default.cyan("logout")} ${import_picocolors42.default.dim(" clear the local session")}`);
75023
- out.push(` ${import_picocolors42.default.cyan("whoami")} ${import_picocolors42.default.dim(" show the current user")}`);
75811
+ out.push(` ${import_picocolors43.default.cyan("login")} ${import_picocolors43.default.dim(" open the web app and connect this device")}`);
75812
+ out.push(` ${import_picocolors43.default.cyan("logout")} ${import_picocolors43.default.dim(" clear the local session")}`);
75813
+ out.push(` ${import_picocolors43.default.cyan("whoami")} ${import_picocolors43.default.dim(" show the current user")}`);
75024
75814
  out.push("");
75025
75815
  out.push(divider("LINKED AGENT"));
75026
75816
  out.push("");
75027
- out.push(` ${import_picocolors42.default.cyan("agent create")} ${import_picocolors42.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
75028
- out.push(` ${import_picocolors42.default.cyan("agent pull")} ${import_picocolors42.default.dim("[<id>]")} ${import_picocolors42.default.dim("bring cloud changes into this folder (--force to override; --run-entrypoint to also execute the agent entrypoint)")}`);
75029
- out.push(` ${import_picocolors42.default.cyan("agent push")} ${import_picocolors42.default.dim("send local changes to the cloud (--force to overwrite cloud-side conflicts with local)")}`);
75030
- out.push(` ${import_picocolors42.default.cyan("agent unpack")} ${import_picocolors42.default.dim("install the claimed agent into a harness layout")}`);
75031
- out.push(` ${import_picocolors42.default.cyan("link")} ${import_picocolors42.default.dim("attach this folder to an existing agent")}`);
75032
- out.push(` ${import_picocolors42.default.cyan("agent status")} ${import_picocolors42.default.dim("show what would pull and what would push")}`);
75033
- out.push(` ${import_picocolors42.default.cyan("agent env")} ${import_picocolors42.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
75034
- out.push(` ${import_picocolors42.default.cyan("run")} ${import_picocolors42.default.dim("<cmd> [args...]")} ${import_picocolors42.default.dim("run <cmd> with secrets.env loaded into env")}`);
75035
- out.push(` ${import_picocolors42.default.cyan("status")} ${import_picocolors42.default.dim("show what this folder is linked to")}`);
75036
- out.push(` ${import_picocolors42.default.cyan("unlink")} ${import_picocolors42.default.dim("disconnect this folder")}`);
75817
+ out.push(` ${import_picocolors43.default.cyan("agent create")} ${import_picocolors43.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
75818
+ out.push(` ${import_picocolors43.default.cyan("agent pull")} ${import_picocolors43.default.dim("[<id>]")} ${import_picocolors43.default.dim("bring cloud changes into this folder (--force to override; --run-entrypoint to also execute the agent entrypoint)")}`);
75819
+ out.push(` ${import_picocolors43.default.cyan("agent push")} ${import_picocolors43.default.dim("send local changes to the cloud (--force to overwrite cloud-side conflicts with local)")}`);
75820
+ out.push(` ${import_picocolors43.default.cyan("agent unpack")} ${import_picocolors43.default.dim("install the claimed agent into a harness layout")}`);
75821
+ out.push(` ${import_picocolors43.default.cyan("link")} ${import_picocolors43.default.dim("attach this folder to an existing agent")}`);
75822
+ out.push(` ${import_picocolors43.default.cyan("agent status")} ${import_picocolors43.default.dim("show what would pull and what would push")}`);
75823
+ out.push(` ${import_picocolors43.default.cyan("agent env")} ${import_picocolors43.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
75824
+ out.push(` ${import_picocolors43.default.cyan("run")} ${import_picocolors43.default.dim("<cmd> [args...]")} ${import_picocolors43.default.dim("run <cmd> with secrets.env loaded into env")}`);
75825
+ out.push(` ${import_picocolors43.default.cyan("status")} ${import_picocolors43.default.dim("show what this folder is linked to")}`);
75826
+ out.push(` ${import_picocolors43.default.cyan("unlink")} ${import_picocolors43.default.dim("disconnect this folder")}`);
75037
75827
  out.push("");
75038
75828
  out.push(divider("ORCHESTRATIONS"));
75039
75829
  out.push("");
75040
- out.push(` ${import_picocolors42.default.cyan("orchestration list")} ${import_picocolors42.default.dim("list orchestrations under a team")}`);
75041
- out.push(` ${import_picocolors42.default.cyan("orchestration pull")} ${import_picocolors42.default.dim("<id>")} ${import_picocolors42.default.dim("recursively fetch an orchestration + every member agent")}`);
75042
- out.push(` ${import_picocolors42.default.cyan("orchestration push")} ${import_picocolors42.default.dim("recursively push each member, then update the graph")}`);
75043
- out.push(` ${import_picocolors42.default.cyan("orchestration status")} ${import_picocolors42.default.dim("show what would push and what would pull")}`);
75830
+ out.push(` ${import_picocolors43.default.cyan("orchestration create")} ${import_picocolors43.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
75831
+ out.push(` ${import_picocolors43.default.cyan("orchestration list")} ${import_picocolors43.default.dim("list orchestrations under a team")}`);
75832
+ out.push(` ${import_picocolors43.default.cyan("orchestration pull")} ${import_picocolors43.default.dim("<id>")} ${import_picocolors43.default.dim("recursively fetch an orchestration + every member agent")}`);
75833
+ out.push(` ${import_picocolors43.default.cyan("orchestration push")} ${import_picocolors43.default.dim("recursively push each member, then update the graph")}`);
75834
+ out.push(` ${import_picocolors43.default.cyan("orchestration status")} ${import_picocolors43.default.dim("show what would push and what would pull")}`);
75044
75835
  out.push("");
75045
75836
  out.push(divider("TEMPLATES"));
75046
75837
  out.push("");
75047
- out.push(` ${import_picocolors42.default.cyan("template pack")} ${import_picocolors42.default.dim("bundle the current agent into a template")}`);
75048
- out.push(` ${import_picocolors42.default.cyan("template publish")} ${import_picocolors42.default.dim("upload a template to the registry")}`);
75049
- out.push(` ${import_picocolors42.default.cyan("template search")} ${import_picocolors42.default.dim("[query]")} ${import_picocolors42.default.dim("search the registry")}`);
75050
- out.push(` ${import_picocolors42.default.cyan("template info")} ${import_picocolors42.default.dim("<creator/slug>")} ${import_picocolors42.default.dim("show registry details for a template")}`);
75051
- out.push(` ${import_picocolors42.default.cyan("template onboard")} ${import_picocolors42.default.dim("<creator/slug>")} ${import_picocolors42.default.dim("install (or refresh) a template")}`);
75052
- out.push(` ${import_picocolors42.default.cyan("template list")} ${import_picocolors42.default.dim("show installed templates")}`);
75053
- out.push(` ${import_picocolors42.default.cyan("template remove")} ${import_picocolors42.default.dim("<creator/slug>")} ${import_picocolors42.default.dim("uninstall a template")}`);
75838
+ out.push(` ${import_picocolors43.default.cyan("template pack")} ${import_picocolors43.default.dim("bundle the current agent into a template")}`);
75839
+ out.push(` ${import_picocolors43.default.cyan("template publish")} ${import_picocolors43.default.dim("upload a template to the registry")}`);
75840
+ out.push(` ${import_picocolors43.default.cyan("template search")} ${import_picocolors43.default.dim("[query]")} ${import_picocolors43.default.dim("search the registry")}`);
75841
+ out.push(` ${import_picocolors43.default.cyan("template info")} ${import_picocolors43.default.dim("<creator/slug>")} ${import_picocolors43.default.dim("show registry details for a template")}`);
75842
+ out.push(` ${import_picocolors43.default.cyan("template onboard")} ${import_picocolors43.default.dim("<creator/slug>")} ${import_picocolors43.default.dim("install (or refresh) a template")}`);
75843
+ out.push(` ${import_picocolors43.default.cyan("template list")} ${import_picocolors43.default.dim("show installed templates")}`);
75844
+ out.push(` ${import_picocolors43.default.cyan("template remove")} ${import_picocolors43.default.dim("<creator/slug>")} ${import_picocolors43.default.dim("uninstall a template")}`);
75054
75845
  out.push("");
75055
75846
  out.push(divider("SKILLS"));
75056
75847
  out.push("");
75057
- out.push(` ${import_picocolors42.default.cyan("skill add")} ${import_picocolors42.default.dim("<source>")} ${import_picocolors42.default.dim("install a skill (github / git / brainbase)")}`);
75058
- out.push(` ${import_picocolors42.default.cyan("skill list")} ${import_picocolors42.default.dim("show locally installed skills + their source")}`);
75059
- out.push(` ${import_picocolors42.default.cyan("skill update")} ${import_picocolors42.default.dim("<slug>")} ${import_picocolors42.default.dim("re-fetch a skill from its recorded source")}`);
75060
- out.push(` ${import_picocolors42.default.cyan("skill remove")} ${import_picocolors42.default.dim("<slug>")} ${import_picocolors42.default.dim("uninstall a skill")}`);
75061
- out.push(` ${import_picocolors42.default.cyan("skill search")} ${import_picocolors42.default.dim("[query]")} ${import_picocolors42.default.dim("search the brainbase skill registry")}`);
75062
- out.push(` ${import_picocolors42.default.cyan("skill info")} ${import_picocolors42.default.dim("<creator/slug>")} ${import_picocolors42.default.dim("show registry details for a skill")}`);
75063
- out.push(` ${import_picocolors42.default.cyan("skill publish")} ${import_picocolors42.default.dim("[dir]")} ${import_picocolors42.default.dim("publish a SKILL.md folder (defaults to .)")}`);
75848
+ out.push(` ${import_picocolors43.default.cyan("skill add")} ${import_picocolors43.default.dim("<source>")} ${import_picocolors43.default.dim("install a skill (github / git / brainbase)")}`);
75849
+ out.push(` ${import_picocolors43.default.cyan("skill list")} ${import_picocolors43.default.dim("show locally installed skills + their source")}`);
75850
+ out.push(` ${import_picocolors43.default.cyan("skill update")} ${import_picocolors43.default.dim("<slug>")} ${import_picocolors43.default.dim("re-fetch a skill from its recorded source")}`);
75851
+ out.push(` ${import_picocolors43.default.cyan("skill remove")} ${import_picocolors43.default.dim("<slug>")} ${import_picocolors43.default.dim("uninstall a skill")}`);
75852
+ out.push(` ${import_picocolors43.default.cyan("skill search")} ${import_picocolors43.default.dim("[query]")} ${import_picocolors43.default.dim("search the brainbase skill registry")}`);
75853
+ out.push(` ${import_picocolors43.default.cyan("skill info")} ${import_picocolors43.default.dim("<creator/slug>")} ${import_picocolors43.default.dim("show registry details for a skill")}`);
75854
+ out.push(` ${import_picocolors43.default.cyan("skill publish")} ${import_picocolors43.default.dim("[dir]")} ${import_picocolors43.default.dim("publish a SKILL.md folder (defaults to .)")}`);
75064
75855
  out.push("");
75065
75856
  out.push(divider("CLI TOKENS"));
75066
75857
  out.push("");
75067
- out.push(` ${import_picocolors42.default.cyan("token create")} ${import_picocolors42.default.dim("issue a long-lived CLI key for CI / scripts")}`);
75068
- out.push(` ${import_picocolors42.default.cyan("token list")} ${import_picocolors42.default.dim("show your active tokens")}`);
75069
- out.push(` ${import_picocolors42.default.cyan("token revoke")} ${import_picocolors42.default.dim("<id>")} ${import_picocolors42.default.dim("revoke a token")}`);
75858
+ out.push(` ${import_picocolors43.default.cyan("token create")} ${import_picocolors43.default.dim("issue a long-lived CLI key for CI / scripts")}`);
75859
+ out.push(` ${import_picocolors43.default.cyan("token list")} ${import_picocolors43.default.dim("show your active tokens")}`);
75860
+ out.push(` ${import_picocolors43.default.cyan("token revoke")} ${import_picocolors43.default.dim("<id>")} ${import_picocolors43.default.dim("revoke a token")}`);
75070
75861
  out.push("");
75071
75862
  out.push(divider("MCP"));
75072
75863
  out.push("");
75073
- out.push(` ${import_picocolors42.default.cyan("mcp check")} ${import_picocolors42.default.dim("[--json]")} ${import_picocolors42.default.dim("verify MCP server connectivity through the brainbase proxy (runs at sandbox bootstrap)")}`);
75864
+ out.push(` ${import_picocolors43.default.cyan("mcp check")} ${import_picocolors43.default.dim("[--json]")} ${import_picocolors43.default.dim("verify MCP server connectivity through the brainbase proxy (runs at sandbox bootstrap)")}`);
75074
75865
  out.push("");
75075
75866
  out.push(divider("FLAGS"));
75076
75867
  out.push("");
75077
- out.push(` ${import_picocolors42.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
75078
- out.push(` ${import_picocolors42.default.dim("--scope <s>")} force scope: global | project`);
75079
- out.push(` ${import_picocolors42.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
75080
- out.push(` ${import_picocolors42.default.dim("--agent <id>")} for link: attach this folder to an existing agent non-interactively`);
75081
- out.push(` ${import_picocolors42.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
75082
- out.push(` ${import_picocolors42.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
75083
- out.push(` ${import_picocolors42.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
75084
- out.push(` ${import_picocolors42.default.dim("--all")} for template list: include installs from other folders`);
75085
- out.push(` ${import_picocolors42.default.dim("--web <url>")} for login: web app URL (default https://new.usekafka.com)`);
75868
+ out.push(` ${import_picocolors43.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
75869
+ out.push(` ${import_picocolors43.default.dim("--scope <s>")} force scope: global | project`);
75870
+ out.push(` ${import_picocolors43.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
75871
+ out.push(` ${import_picocolors43.default.dim("--agent <id>")} for link: attach this folder to an existing agent non-interactively`);
75872
+ out.push(` ${import_picocolors43.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
75873
+ out.push(` ${import_picocolors43.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
75874
+ out.push(` ${import_picocolors43.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
75875
+ out.push(` ${import_picocolors43.default.dim("--all")} for template list: include installs from other folders`);
75876
+ out.push(` ${import_picocolors43.default.dim("--web <url>")} for login: web app URL (default https://new.usekafka.com)`);
75086
75877
  out.push("");
75087
75878
  out.push(divider("ENV"));
75088
75879
  out.push("");
75089
- out.push(` ${import_picocolors42.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
75090
- out.push(` ${import_picocolors42.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
75091
- out.push(` ${import_picocolors42.default.dim("BRAINBASE_API_URL")} override the API URL used by link / sync`);
75092
- out.push(` ${import_picocolors42.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL`);
75093
- out.push(` ${import_picocolors42.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
75094
- out.push(` ${import_picocolors42.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
75095
- out.push(` ${import_picocolors42.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode skip/auto-default prompts (CI & agents)`);
75096
- out.push(` ${import_picocolors42.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 → agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
75880
+ out.push(` ${import_picocolors43.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
75881
+ out.push(` ${import_picocolors43.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
75882
+ out.push(` ${import_picocolors43.default.dim("BRAINBASE_CONTROL_PLANE_URL")} override the MAS control-plane host (uses /v2/cli)`);
75883
+ out.push(` ${import_picocolors43.default.dim("BRAINBASE_API_URL")} legacy KLS host override (uses /api/cli; proxy/registry fallback)`);
75884
+ out.push(` ${import_picocolors43.default.dim("BRAINBASE_PROXY_URL")} override the model-proxy URL used by harness traffic (default https://api.v1.brainbaselabs.com)`);
75885
+ out.push(` ${import_picocolors43.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL (default https://api.v1.brainbaselabs.com)`);
75886
+ out.push(` ${import_picocolors43.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
75887
+ out.push(` ${import_picocolors43.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
75888
+ out.push(` ${import_picocolors43.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
75889
+ out.push(` ${import_picocolors43.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 → agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
75097
75890
  out.push("");
75098
75891
  out.push(divider("HARNESSES"));
75099
75892
  out.push("");
75100
- out.push(` ${import_picocolors42.default.dim("•")} ${import_picocolors42.default.bold("claude-code")} ${import_picocolors42.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
75101
- out.push(` ${import_picocolors42.default.dim("•")} ${import_picocolors42.default.bold("codex")} ${import_picocolors42.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
75102
- out.push(` ${import_picocolors42.default.dim("•")} ${import_picocolors42.default.bold("kafka")} ${import_picocolors42.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
75893
+ out.push(` ${import_picocolors43.default.dim("•")} ${import_picocolors43.default.bold("claude-code")} ${import_picocolors43.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
75894
+ out.push(` ${import_picocolors43.default.dim("•")} ${import_picocolors43.default.bold("codex")} ${import_picocolors43.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
75895
+ out.push(` ${import_picocolors43.default.dim("•")} ${import_picocolors43.default.bold("kafka")} ${import_picocolors43.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
75103
75896
  out.push("");
75104
75897
  console.log(out.join(`
75105
75898
  `));
@@ -75153,13 +75946,13 @@ async function requireAuth(cmd) {
75153
75946
  if (status.ok)
75154
75947
  return;
75155
75948
  console.error("");
75156
- console.error(` ${brandTint("◆")} ${import_picocolors42.default.bold("brainbase")}`);
75949
+ console.error(` ${brandTint("◆")} ${import_picocolors43.default.bold("brainbase")}`);
75157
75950
  console.error("");
75158
- console.error(` ${import_picocolors42.default.red("✗")} You need to sign in to use ${import_picocolors42.default.bold("brainbase " + cmd)}.`);
75951
+ console.error(` ${import_picocolors43.default.red("✗")} You need to sign in to use ${import_picocolors43.default.bold("brainbase " + cmd)}.`);
75159
75952
  if (status.reason)
75160
- console.error(` ${import_picocolors42.default.dim(status.reason)}`);
75953
+ console.error(` ${import_picocolors43.default.dim(status.reason)}`);
75161
75954
  console.error("");
75162
- console.error(` Run ${import_picocolors42.default.cyan("brainbase login")} to connect this device.`);
75955
+ console.error(` Run ${import_picocolors43.default.cyan("brainbase login")} to connect this device.`);
75163
75956
  console.error("");
75164
75957
  process14.exit(1);
75165
75958
  }
@@ -75337,7 +76130,7 @@ async function main() {
75337
76130
  process14.exit(1);
75338
76131
  }
75339
76132
  } catch (err) {
75340
- console.error(import_picocolors42.default.red(`
76133
+ console.error(import_picocolors43.default.red(`
75341
76134
  ${err.message}`));
75342
76135
  if (process14.env.BRAINBASE_DEBUG)
75343
76136
  console.error(err.stack);