@brainbase-labs/cli 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1081 -100
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  // src/index.ts
4
4
  import process2 from "node:process";
5
- import fs40 from "node:fs";
6
- import pc31 from "picocolors";
5
+ import fs44 from "node:fs";
6
+ import pc36 from "picocolors";
7
7
 
8
8
  // src/cli/template.ts
9
9
  import pc10 from "picocolors";
@@ -398,11 +398,13 @@ function globalPaths() {
398
398
  agents: path4.join(GLOBAL_ROOT, "agents"),
399
399
  settings: path4.join(GLOBAL_ROOT, "settings.json"),
400
400
  claudeMd: path4.join(GLOBAL_ROOT, "CLAUDE.md"),
401
- userClaudeJson: USER_CLAUDE_JSON
401
+ userClaudeJson: USER_CLAUDE_JSON,
402
+ mcpStore: USER_CLAUDE_JSON
402
403
  };
403
404
  }
404
405
  function projectPaths(cwd) {
405
406
  const root = projectRoot(cwd);
407
+ const mcpJson = projectMcpJson(cwd);
406
408
  return {
407
409
  root,
408
410
  skills: path4.join(root, "skills"),
@@ -410,8 +412,9 @@ function projectPaths(cwd) {
410
412
  agents: path4.join(root, "agents"),
411
413
  settings: path4.join(root, "settings.json"),
412
414
  claudeMd: path4.join(cwd, "CLAUDE.md"),
413
- mcpJson: projectMcpJson(cwd),
414
- userClaudeJson: USER_CLAUDE_JSON
415
+ mcpJson,
416
+ userClaudeJson: USER_CLAUDE_JSON,
417
+ mcpStore: mcpJson
415
418
  };
416
419
  }
417
420
  function scopePaths(cwd, scope) {
@@ -491,10 +494,6 @@ function readSettings(file) {
491
494
  function writeSettings(file, settings) {
492
495
  writeJson(file, settings);
493
496
  }
494
- function ensureSettings(file) {
495
- if (!exists(file))
496
- writeSettings(file, {});
497
- }
498
497
  function setMcpServer(file, name, entry) {
499
498
  const s = readSettings(file);
500
499
  if (!s.mcpServers)
@@ -518,6 +517,33 @@ function getMcpServer(file, name) {
518
517
  function listMcpServers(file) {
519
518
  return readSettings(file).mcpServers ?? {};
520
519
  }
520
+ function normalizeMcpPayload(payload) {
521
+ const out = { ...payload };
522
+ delete out.is_enabled;
523
+ const hasUrl = typeof out.url === "string" && out.url.length > 0;
524
+ const hasCommand = typeof out.command === "string" && out.command.length > 0;
525
+ if (!out.type) {
526
+ if (hasUrl)
527
+ out.type = "http";
528
+ else if (hasCommand)
529
+ out.type = "stdio";
530
+ }
531
+ if (out.type === "http" || out.type === "sse") {
532
+ if (Array.isArray(out.args) && out.args.length === 0)
533
+ delete out.args;
534
+ if (out.env && typeof out.env === "object" && Object.keys(out.env).length === 0) {
535
+ delete out.env;
536
+ }
537
+ if (out.headers && typeof out.headers === "object" && Object.keys(out.headers).length === 0) {
538
+ delete out.headers;
539
+ }
540
+ }
541
+ if (out.type === "stdio") {
542
+ delete out.url;
543
+ delete out.headers;
544
+ }
545
+ return out;
546
+ }
521
547
  function listMcpServersFromMcpJson(file) {
522
548
  return readJsonOr(file, {}).mcpServers ?? {};
523
549
  }
@@ -1028,14 +1054,13 @@ async function installAgent(comp, opts) {
1028
1054
  return installSingleFileComponent(comp, agents, `${comp.slug}.md`, opts);
1029
1055
  }
1030
1056
  async function installMcp(comp, opts, ctx) {
1031
- const { settings } = scopePaths(opts.cwd, opts.scope);
1032
- ensureSettings(settings);
1033
- const existing = getMcpServer(settings, comp.slug);
1057
+ const { mcpStore } = scopePaths(opts.cwd, opts.scope);
1058
+ const existing = getMcpServer(mcpStore, comp.slug);
1034
1059
  if (existing) {
1035
1060
  const choice = await opts.resolveConflict({
1036
1061
  type: "mcp",
1037
1062
  slug: comp.slug,
1038
- existingPath: settings
1063
+ existingPath: mcpStore
1039
1064
  });
1040
1065
  if (choice === "skip")
1041
1066
  return { skip: "user skipped existing mcp" };
@@ -1064,15 +1089,15 @@ async function installMcp(comp, opts, ctx) {
1064
1089
  }
1065
1090
  }
1066
1091
  }
1067
- setMcpServer(settings, comp.slug, payload);
1092
+ setMcpServer(mcpStore, comp.slug, normalizeMcpPayload(payload));
1068
1093
  return {
1069
1094
  type: "mcp",
1070
1095
  slug: comp.slug,
1071
- installedPaths: [settings],
1096
+ installedPaths: [mcpStore],
1072
1097
  sourceChecksum: comp.checksum,
1073
1098
  scope: opts.scope,
1074
1099
  embeddedKey: comp.slug,
1075
- settingsFile: settings
1100
+ settingsFile: mcpStore
1076
1101
  };
1077
1102
  }
1078
1103
  async function installInstruction(comp, opts, ctx) {
@@ -1296,8 +1321,8 @@ async function diffClaudeCode(components, opts) {
1296
1321
  break;
1297
1322
  }
1298
1323
  case "mcp": {
1299
- if (exists(sp.settings)) {
1300
- const servers = listMcpServers(sp.settings);
1324
+ if (exists(sp.mcpStore)) {
1325
+ const servers = listMcpServers(sp.mcpStore);
1301
1326
  const cur = servers[comp.slug];
1302
1327
  if (cur)
1303
1328
  installedChecksum = sha256(JSON.stringify(cur));
@@ -2880,6 +2905,21 @@ var api = {
2880
2905
  return request(`/api/cli/keys/${encodeURIComponent(keyId)}`, {
2881
2906
  method: "DELETE"
2882
2907
  });
2908
+ },
2909
+ listOrchestrations(orgId, teamId) {
2910
+ return request(`/api/cli/orgs/${encodeURIComponent(orgId)}/teams/${encodeURIComponent(teamId)}/orchestrations`);
2911
+ },
2912
+ getOrchestration(orchId) {
2913
+ return request(`/api/cli/orchestrations/${encodeURIComponent(orchId)}`);
2914
+ },
2915
+ getOrchestrationManifest(orchId) {
2916
+ return request(`/api/cli/orchestrations/${encodeURIComponent(orchId)}/manifest`);
2917
+ },
2918
+ updateOrchestration(orchId, input) {
2919
+ return request(`/api/cli/orchestrations/${encodeURIComponent(orchId)}`, {
2920
+ method: "PUT",
2921
+ body: JSON.stringify(input)
2922
+ });
2883
2923
  }
2884
2924
  };
2885
2925
  function proxyBaseUrl(session) {
@@ -6974,12 +7014,25 @@ function ensureGitignore(cwd) {
6974
7014
 
6975
7015
  // src/core/route-adapters.ts
6976
7016
  import path37 from "node:path";
7017
+ import os7 from "node:os";
6977
7018
  import fs34 from "node:fs";
6978
7019
  import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
6979
7020
  var CLAUDE_ENV_KEYS = ["ANTHROPIC_BASE_URL", "ANTHROPIC_AUTH_TOKEN"];
6980
7021
  function claudeSettingsPath(cwd) {
6981
7022
  return path37.join(cwd, ".claude", "settings.json");
6982
7023
  }
7024
+ function claudeUserConfigPath() {
7025
+ return path37.join(os7.homedir(), ".claude.json");
7026
+ }
7027
+ function ensureClaudeOnboarded() {
7028
+ const file = claudeUserConfigPath();
7029
+ const cfg = readJsonOr(file, {});
7030
+ if (cfg.hasCompletedOnboarding === true)
7031
+ return false;
7032
+ cfg.hasCompletedOnboarding = true;
7033
+ writeJson(file, cfg);
7034
+ return true;
7035
+ }
6983
7036
  var claudeRouteAdapter = {
6984
7037
  id: "claude-code",
6985
7038
  async enable(cwd, target) {
@@ -6995,7 +7048,11 @@ var claudeRouteAdapter = {
6995
7048
  settings.env.ANTHROPIC_AUTH_TOKEN = target.apiKey;
6996
7049
  ensureDir(path37.dirname(file));
6997
7050
  writeJson(file, settings);
6998
- return { data: snap };
7051
+ const notes = [];
7052
+ if (ensureClaudeOnboarded()) {
7053
+ notes.push("Marked claude as onboarded in ~/.claude.json so it picks up the proxy on first run.");
7054
+ }
7055
+ return { data: snap, notes };
6999
7056
  },
7000
7057
  async disable(cwd, snapshot) {
7001
7058
  const file = claudeSettingsPath(cwd);
@@ -7252,6 +7309,8 @@ async function attachToExistingAgent(cwd, agentId, args, existing) {
7252
7309
  cfg.start(`Configuring ${harness}…`);
7253
7310
  const snap = await adapter.enable(cwd, { apiBase: apiBase2, apiKey: keyPlain });
7254
7311
  cfg.stop(`${harness} pointed at brainbase.`);
7312
+ for (const note3 of snap.notes ?? [])
7313
+ p13.log.info(note3);
7255
7314
  tracking = {
7256
7315
  harness,
7257
7316
  key_id: keyId,
@@ -7394,7 +7453,7 @@ async function runUnlink(cwd, args) {
7394
7453
  // src/cli/sync.ts
7395
7454
  import path38 from "node:path";
7396
7455
  import fs35 from "node:fs";
7397
- import os7 from "node:os";
7456
+ import os8 from "node:os";
7398
7457
  import crypto3 from "node:crypto";
7399
7458
  import * as p15 from "@clack/prompts";
7400
7459
  import pc22 from "picocolors";
@@ -7666,7 +7725,7 @@ function computeLocalHash(paths) {
7666
7725
  return h.digest("hex");
7667
7726
  }
7668
7727
  function stageManifest(components) {
7669
- const root = fs35.mkdtempSync(path38.join(os7.tmpdir(), "brainbase-sync-"));
7728
+ const root = fs35.mkdtempSync(path38.join(os8.tmpdir(), "brainbase-sync-"));
7670
7729
  for (const c of components) {
7671
7730
  const compDir = path38.join(root, c.type, c.slug);
7672
7731
  ensureDir(compDir);
@@ -7692,7 +7751,7 @@ import pc28 from "picocolors";
7692
7751
  // src/cli/agent-pull.ts
7693
7752
  import path42 from "node:path";
7694
7753
  import fs39 from "node:fs";
7695
- import os8 from "node:os";
7754
+ import os9 from "node:os";
7696
7755
  import * as p16 from "@clack/prompts";
7697
7756
  import pc23 from "picocolors";
7698
7757
 
@@ -8309,7 +8368,7 @@ async function runAgentPull(cwd, args) {
8309
8368
  }
8310
8369
  }
8311
8370
  function stageManifestComponents(components) {
8312
- const root = fs39.mkdtempSync(path42.join(os8.tmpdir(), "brainbase-pull-"));
8371
+ const root = fs39.mkdtempSync(path42.join(os9.tmpdir(), "brainbase-pull-"));
8313
8372
  for (const c of components) {
8314
8373
  const compDir = path42.join(root, c.type, c.slug);
8315
8374
  ensureDir(compDir);
@@ -9157,6 +9216,8 @@ async function runAgentCreate(cwd, args) {
9157
9216
  apiKey: created.key
9158
9217
  });
9159
9218
  cfgSpinner.stop(`${harness} pointed at brainbase.`);
9219
+ for (const note4 of snap.notes ?? [])
9220
+ p19.log.info(note4);
9160
9221
  tracking = {
9161
9222
  harness,
9162
9223
  key_id: created.id,
@@ -9289,6 +9350,906 @@ function printHelp() {
9289
9350
  `));
9290
9351
  }
9291
9352
 
9353
+ // src/cli/orchestration.ts
9354
+ import pc33 from "picocolors";
9355
+
9356
+ // src/cli/orchestration-pull.ts
9357
+ import path46 from "node:path";
9358
+ import fs43 from "node:fs";
9359
+ import * as p21 from "@clack/prompts";
9360
+ import pc29 from "picocolors";
9361
+
9362
+ // src/core/orchestration-manifest.ts
9363
+ import path43 from "node:path";
9364
+ import fs40 from "node:fs";
9365
+ import { z as z8 } from "zod";
9366
+ import YAML2 from "yaml";
9367
+ var ORCH_MANIFEST_FILE = "brainbase-orchestration.yaml";
9368
+ var ORCH_MEMBERS_DIR = "agents";
9369
+ var OrchMetaSchema = z8.object({
9370
+ name: z8.string().min(1),
9371
+ description: z8.string().optional(),
9372
+ icon: z8.string().optional(),
9373
+ icon_color: z8.string().optional(),
9374
+ credit_limit: z8.number().optional()
9375
+ });
9376
+ var MemberSchema = z8.object({
9377
+ slug: z8.string().min(1),
9378
+ name: z8.string().optional()
9379
+ });
9380
+ var EdgeSchema = z8.object({
9381
+ from: z8.string().min(1),
9382
+ to: z8.string().min(1),
9383
+ description: z8.string().optional(),
9384
+ payload_schema: z8.record(z8.unknown()).optional()
9385
+ });
9386
+ var OrchestrationManifestSchema = z8.object({
9387
+ schema: z8.literal(1),
9388
+ orchestration: OrchMetaSchema,
9389
+ members: z8.array(MemberSchema).default([]),
9390
+ edges: z8.array(EdgeSchema).default([])
9391
+ });
9392
+ function orchManifestPath(cwd) {
9393
+ return path43.join(cwd, ORCH_MANIFEST_FILE);
9394
+ }
9395
+ function hasOrchManifest(cwd) {
9396
+ return fs40.existsSync(orchManifestPath(cwd));
9397
+ }
9398
+ function readOrchManifest(cwd) {
9399
+ const p20 = orchManifestPath(cwd);
9400
+ if (!fs40.existsSync(p20))
9401
+ return null;
9402
+ const raw = fs40.readFileSync(p20, "utf8");
9403
+ let parsed;
9404
+ try {
9405
+ parsed = YAML2.parse(raw);
9406
+ } catch (err) {
9407
+ throw new Error(`${ORCH_MANIFEST_FILE} is not valid YAML: ${err.message}`);
9408
+ }
9409
+ const result = OrchestrationManifestSchema.safeParse(parsed);
9410
+ if (!result.success) {
9411
+ throw new Error(`${ORCH_MANIFEST_FILE} is invalid: ${result.error.issues.map((i) => `${i.path.join(".") || "(root)"} — ${i.message}`).join("; ")}`);
9412
+ }
9413
+ return result.data;
9414
+ }
9415
+ function writeOrchManifest(cwd, manifest) {
9416
+ const doc = new YAML2.Document;
9417
+ doc.contents = manifest;
9418
+ doc.commentBefore = ` brainbase-orchestration.yaml — declarative orchestration manifest.
9419
+ ` + ` Committed to source control. Edit by hand, then
9420
+ ` + " `brainbase orchestration push`. Member agents live under ./agents/.";
9421
+ fs40.writeFileSync(orchManifestPath(cwd), String(doc), "utf8");
9422
+ }
9423
+ function memberDir(cwd, slug) {
9424
+ return path43.join(cwd, ORCH_MEMBERS_DIR, slug);
9425
+ }
9426
+
9427
+ // src/core/orchestration-link.ts
9428
+ import path44 from "node:path";
9429
+ import fs41 from "node:fs";
9430
+ import { z as z9 } from "zod";
9431
+ var ORCH_LINK_FILE = "orchestration-link.json";
9432
+ var ORCH_SYNC_STATE_FILE = "orchestration-sync-state.json";
9433
+ var OrchestrationLinkSchema = z9.object({
9434
+ schemaVersion: z9.literal(1),
9435
+ orchestration_id: z9.string(),
9436
+ group_id: z9.string(),
9437
+ org_id: z9.string(),
9438
+ team_id: z9.string(),
9439
+ name: z9.string(),
9440
+ description: z9.string().nullish().transform((v) => v ?? undefined),
9441
+ linked_at: z9.string(),
9442
+ linked_by: z9.string().nullish().transform((v) => v ?? undefined)
9443
+ });
9444
+ var SyncedMemberSchema = z9.object({
9445
+ agent_id: z9.string(),
9446
+ slug: z9.string(),
9447
+ revision: z9.number()
9448
+ });
9449
+ var SyncedEdgeSchema = z9.object({
9450
+ from_slug: z9.string(),
9451
+ to_slug: z9.string(),
9452
+ description: z9.string().default(""),
9453
+ payload_schema: z9.record(z9.unknown()).default({})
9454
+ });
9455
+ var OrchestrationSyncStateSchema = z9.object({
9456
+ schemaVersion: z9.literal(1),
9457
+ orchestration_id: z9.string(),
9458
+ revision: z9.number(),
9459
+ synced_at: z9.string(),
9460
+ members: z9.array(SyncedMemberSchema),
9461
+ edges: z9.array(SyncedEdgeSchema)
9462
+ });
9463
+ function orchLinkPath(cwd) {
9464
+ return path44.join(cwd, LINK_DIR, ORCH_LINK_FILE);
9465
+ }
9466
+ function orchSyncStatePath(cwd) {
9467
+ return path44.join(cwd, LINK_DIR, ORCH_SYNC_STATE_FILE);
9468
+ }
9469
+ function readOrchLink(cwd) {
9470
+ const p20 = orchLinkPath(cwd);
9471
+ if (!exists(p20))
9472
+ return null;
9473
+ try {
9474
+ return OrchestrationLinkSchema.parse(readJson(p20));
9475
+ } catch {
9476
+ return null;
9477
+ }
9478
+ }
9479
+ function writeOrchLink(cwd, link) {
9480
+ ensureDir(path44.join(cwd, LINK_DIR));
9481
+ const clean = {};
9482
+ for (const [k, v] of Object.entries(link)) {
9483
+ if (v !== null && v !== undefined)
9484
+ clean[k] = v;
9485
+ }
9486
+ writeJson(orchLinkPath(cwd), clean);
9487
+ ensureGitignore2(cwd);
9488
+ }
9489
+ function readOrchSyncState(cwd) {
9490
+ const p20 = orchSyncStatePath(cwd);
9491
+ if (!exists(p20))
9492
+ return null;
9493
+ try {
9494
+ return OrchestrationSyncStateSchema.parse(readJson(p20));
9495
+ } catch {
9496
+ return null;
9497
+ }
9498
+ }
9499
+ function writeOrchSyncState(cwd, state) {
9500
+ ensureDir(path44.join(cwd, LINK_DIR));
9501
+ writeJson(orchSyncStatePath(cwd), state);
9502
+ ensureGitignore2(cwd);
9503
+ }
9504
+ function ensureGitignore2(cwd) {
9505
+ const ignorePath = path44.join(cwd, LINK_DIR, ".gitignore");
9506
+ const desired = `${ORCH_SYNC_STATE_FILE}
9507
+ `;
9508
+ try {
9509
+ if (!exists(ignorePath)) {
9510
+ fs41.writeFileSync(ignorePath, desired);
9511
+ return;
9512
+ }
9513
+ const current = fs41.readFileSync(ignorePath, "utf8");
9514
+ if (!current.split(/\r?\n/).some((l) => l.trim() === ORCH_SYNC_STATE_FILE)) {
9515
+ fs41.writeFileSync(ignorePath, current.endsWith(`
9516
+ `) ? current + desired : current + `
9517
+ ` + desired);
9518
+ }
9519
+ } catch {}
9520
+ }
9521
+
9522
+ // src/core/agent-fresh-install.ts
9523
+ import path45 from "node:path";
9524
+ import fs42 from "node:fs";
9525
+ import os10 from "node:os";
9526
+ import * as p20 from "@clack/prompts";
9527
+ async function installAgentFresh(input) {
9528
+ const { cwd, agent, cloud, harness } = input;
9529
+ const scope = input.scope ?? "project";
9530
+ ensureDir(cwd);
9531
+ const stageRoot = stageManifestComponents2(cloud.components);
9532
+ const justInstalledPaths = new Map;
9533
+ try {
9534
+ if (cloud.components.length > 0) {
9535
+ const toInstall = cloud.components.map((c) => ({
9536
+ type: c.type,
9537
+ slug: c.slug,
9538
+ scope,
9539
+ rootDir: path45.join(stageRoot, c.type, c.slug),
9540
+ description: c.description,
9541
+ meta: c.meta,
9542
+ payload: c.meta?.mcp,
9543
+ checksum: c.hash
9544
+ }));
9545
+ const installOpts = {
9546
+ cwd,
9547
+ scope,
9548
+ resolveConflict: async (_c) => "overwrite",
9549
+ resolveSecret: async () => null
9550
+ };
9551
+ const result = await runHarnessInstall3(harness, toInstall, installOpts, agent.name);
9552
+ for (const o of result.installed) {
9553
+ justInstalledPaths.set(`${o.type}/${o.slug}`, o.installedPaths);
9554
+ }
9555
+ }
9556
+ materializeInstructions2(cwd, cloud);
9557
+ const manifest = buildManifestFromCloud(cloud, agent);
9558
+ writeManifest(cwd, manifest);
9559
+ writeLink(cwd, {
9560
+ schemaVersion: 1,
9561
+ agent_id: agent.id,
9562
+ org_id: agent.org_id,
9563
+ team_id: agent.team_id,
9564
+ slug: agent.slug,
9565
+ name: agent.name,
9566
+ tagline: agent.tagline,
9567
+ url: agent.url,
9568
+ linked_at: new Date().toISOString(),
9569
+ harness
9570
+ });
9571
+ const syncedComponents = cloud.components.map((c) => ({
9572
+ type: c.type,
9573
+ slug: c.slug,
9574
+ hash: c.hash,
9575
+ installedPaths: justInstalledPaths.get(`${c.type}/${c.slug}`) ?? []
9576
+ }));
9577
+ writeSyncState(cwd, {
9578
+ schemaVersion: 1,
9579
+ agent_id: agent.id,
9580
+ revision: cloud.revision,
9581
+ synced_at: new Date().toISOString(),
9582
+ components: syncedComponents,
9583
+ agentMeta: { name: agent.name, tagline: agent.tagline }
9584
+ });
9585
+ if (input.pullSecrets !== false) {
9586
+ await pullAgentSecrets(cwd, agent.id);
9587
+ }
9588
+ return {
9589
+ installedPaths: justInstalledPaths,
9590
+ manifest,
9591
+ syncedComponents
9592
+ };
9593
+ } finally {
9594
+ try {
9595
+ fs42.rmSync(stageRoot, { recursive: true, force: true });
9596
+ } catch {}
9597
+ }
9598
+ }
9599
+ function stageManifestComponents2(components) {
9600
+ const root = fs42.mkdtempSync(path45.join(os10.tmpdir(), "brainbase-orch-pull-"));
9601
+ for (const c of components) {
9602
+ const compDir = path45.join(root, c.type, c.slug);
9603
+ ensureDir(compDir);
9604
+ for (const f of c.files) {
9605
+ const target = path45.join(compDir, f.path);
9606
+ ensureDir(path45.dirname(target));
9607
+ fs42.writeFileSync(target, f.content);
9608
+ }
9609
+ }
9610
+ return root;
9611
+ }
9612
+ function runHarnessInstall3(harnessId, components, opts, agentName) {
9613
+ if (harnessId === "claude-code")
9614
+ return installClaudeCodeWithCtx(components, opts, agentName);
9615
+ if (harnessId === "codex")
9616
+ return installCodexWithCtx(components, opts, agentName);
9617
+ return getAdapter(harnessId).install(components, opts);
9618
+ }
9619
+ function materializeInstructions2(cwd, cloud) {
9620
+ for (const c of cloud.components) {
9621
+ if (c.type !== "instruction")
9622
+ continue;
9623
+ const body = c.files[0]?.content ?? "";
9624
+ if (!body.trim())
9625
+ continue;
9626
+ fs42.writeFileSync(path45.join(cwd, DEFAULT_INSTRUCTIONS_FILE), body, "utf8");
9627
+ return;
9628
+ }
9629
+ }
9630
+ function buildManifestFromCloud(cloud, agent) {
9631
+ const skills = cloud.components.filter((c) => c.type === "skill").map((c) => {
9632
+ const meta = c.meta ?? {};
9633
+ if (meta.name && meta.name.includes("/")) {
9634
+ return {
9635
+ source: meta.version ? `registry:${meta.name}@${meta.version}` : `registry:${meta.name}`
9636
+ };
9637
+ }
9638
+ return { source: `registry:${c.slug}` };
9639
+ });
9640
+ const hasInstructions = cloud.components.some((c) => c.type === "instruction" && c.files[0]?.content?.trim());
9641
+ const mcp = cloud.components.filter((c) => c.type === "mcp").map((c) => {
9642
+ const payload = (c.meta ?? {}).mcp ?? {};
9643
+ const entry = { name: c.slug };
9644
+ if (typeof payload.url === "string")
9645
+ entry.url = payload.url;
9646
+ if (typeof payload.command === "string")
9647
+ entry.command = payload.command;
9648
+ if (Array.isArray(payload.args))
9649
+ entry.args = payload.args.map(String);
9650
+ if (payload.env && typeof payload.env === "object")
9651
+ entry.env = payload.env;
9652
+ if (payload.headers && typeof payload.headers === "object")
9653
+ entry.headers = payload.headers;
9654
+ if (typeof payload.is_enabled === "boolean")
9655
+ entry.is_enabled = payload.is_enabled;
9656
+ return entry;
9657
+ });
9658
+ return {
9659
+ schema: 1,
9660
+ agent: {
9661
+ name: agent.name,
9662
+ ...agent.tagline ? { tagline: agent.tagline } : {}
9663
+ },
9664
+ ...hasInstructions ? { instructions: { file: DEFAULT_INSTRUCTIONS_FILE } } : {},
9665
+ skills,
9666
+ mcp
9667
+ };
9668
+ }
9669
+ async function pullAgentSecrets(cwd, agentId) {
9670
+ try {
9671
+ const res = await api.getAgentSecrets(agentId);
9672
+ const secrets = res.secrets ?? {};
9673
+ if (Object.keys(secrets).length > 0) {
9674
+ writeLocalSecrets(cwd, secrets);
9675
+ }
9676
+ } catch (err) {
9677
+ if (err instanceof ApiError && err.status !== 404) {
9678
+ p20.log.warn(`Skipped secrets for agent ${agentId}: ${err.message}`);
9679
+ }
9680
+ }
9681
+ }
9682
+
9683
+ // src/cli/orchestration-pull.ts
9684
+ async function runOrchestrationPull(cwd, args) {
9685
+ banner("orchestration pull — fetch orchestration + all member agents");
9686
+ let orchId = null;
9687
+ const existingLink = readOrchLink(cwd);
9688
+ if (existingLink) {
9689
+ orchId = existingLink.orchestration_id;
9690
+ } else if (args.orchestrationId) {
9691
+ orchId = args.orchestrationId;
9692
+ } else {
9693
+ p21.log.warn("This folder is not linked to any orchestration.");
9694
+ p21.log.info(`Run ${pc29.cyan("brainbase orchestration pull <id>")} with an orchestration id,
9695
+ or ${pc29.cyan("brainbase orchestration list")} to find one.`);
9696
+ return;
9697
+ }
9698
+ const sp = p21.spinner();
9699
+ sp.start(`Fetching orchestration ${orchId}…`);
9700
+ let cloud;
9701
+ try {
9702
+ cloud = await api.getOrchestrationManifest(orchId);
9703
+ sp.stop(`Cloud revision ${cloud.revision} — ${cloud.members.length} member${cloud.members.length === 1 ? "" : "s"}, ${cloud.edges.length} edge${cloud.edges.length === 1 ? "" : "s"}.`);
9704
+ } catch (err) {
9705
+ sp.stop("Failed.");
9706
+ handleApiError5(err);
9707
+ return;
9708
+ }
9709
+ const planLines = [];
9710
+ planLines.push("");
9711
+ planLines.push(` ${pc29.bold(cloud.name)} ${pc29.dim(`(${cloud.id})`)}`);
9712
+ if (cloud.description)
9713
+ planLines.push(` ${pc29.dim(cloud.description)}`);
9714
+ planLines.push("");
9715
+ planLines.push(` ${pc29.dim("members:")}`);
9716
+ for (const m of cloud.members) {
9717
+ const skipped = !m.manifest;
9718
+ const tail = skipped ? pc29.red(" (manifest unavailable — skipped)") : "";
9719
+ planLines.push(` ${pc29.cyan("•")} ${pc29.bold(m.slug)} ${pc29.dim(`(${m.name})`)}${tail}`);
9720
+ }
9721
+ if (cloud.edges.length) {
9722
+ planLines.push("");
9723
+ planLines.push(` ${pc29.dim("edges:")}`);
9724
+ for (const e of cloud.edges) {
9725
+ const from = e.from_slug ?? e.from_agent_id;
9726
+ const to = e.to_slug ?? e.to_agent_id;
9727
+ const desc = e.description ? ` ${pc29.dim("— " + e.description)}` : "";
9728
+ planLines.push(` ${pc29.cyan(from)} ${pc29.dim("→")} ${pc29.cyan(to)}${desc}`);
9729
+ }
9730
+ }
9731
+ planLines.push("");
9732
+ console.log(planLines.join(`
9733
+ `));
9734
+ const isRefresh = !!existingLink;
9735
+ if (!args.yes && !isRefresh) {
9736
+ const ok = await p21.confirm({
9737
+ message: `Pull into ${pc29.bold(cwd)}?`,
9738
+ initialValue: true
9739
+ });
9740
+ if (!ensureNotCancelled(ok)) {
9741
+ p21.outro("Aborted.");
9742
+ return;
9743
+ }
9744
+ }
9745
+ const fallbackHarness = args.harness ?? "claude-code";
9746
+ fs43.mkdirSync(cwd, { recursive: true });
9747
+ if (hasOrchManifest(cwd) && existingLink && existingLink.orchestration_id !== orchId) {
9748
+ p21.log.error(`This folder is linked to orchestration ${existingLink.orchestration_id}, not ${orchId}. Move to a fresh directory or unlink first.`);
9749
+ return;
9750
+ }
9751
+ const installedMembers = [];
9752
+ for (const m of cloud.members) {
9753
+ if (!m.manifest) {
9754
+ p21.log.warn(`Skipping member ${m.slug}: server did not return a manifest.`);
9755
+ continue;
9756
+ }
9757
+ const dest = memberDir(cwd, m.slug);
9758
+ const memberSp = p21.spinner();
9759
+ memberSp.start(`Installing ${m.slug}…`);
9760
+ try {
9761
+ await installAgentFresh({
9762
+ cwd: dest,
9763
+ agent: {
9764
+ id: m.agent_id,
9765
+ name: m.name || m.slug,
9766
+ slug: m.slug,
9767
+ tagline: undefined,
9768
+ org_id: cloud.group_id,
9769
+ team_id: cloud.group_id,
9770
+ url: undefined,
9771
+ harness: fallbackHarness
9772
+ },
9773
+ cloud: m.manifest,
9774
+ harness: fallbackHarness,
9775
+ scope: "project",
9776
+ pullSecrets: true
9777
+ });
9778
+ memberSp.stop(`Installed ${pc29.bold(m.slug)} ${pc29.dim(`(${m.manifest.components.length} components)`)}.`);
9779
+ installedMembers.push({
9780
+ agent_id: m.agent_id,
9781
+ slug: m.slug,
9782
+ revision: m.manifest.revision
9783
+ });
9784
+ } catch (err) {
9785
+ memberSp.stop(`Failed to install ${m.slug}.`);
9786
+ p21.log.error(err.message);
9787
+ }
9788
+ }
9789
+ const manifest = {
9790
+ schema: 1,
9791
+ orchestration: {
9792
+ name: cloud.name,
9793
+ ...cloud.description ? { description: cloud.description } : {},
9794
+ ...cloud.icon ? { icon: cloud.icon } : {},
9795
+ ...cloud.icon_color ? { icon_color: cloud.icon_color } : {},
9796
+ ...cloud.credit_limit != null ? { credit_limit: cloud.credit_limit } : {}
9797
+ },
9798
+ members: cloud.members.map((m) => ({
9799
+ slug: m.slug,
9800
+ ...m.name && m.name !== m.slug ? { name: m.name } : {}
9801
+ })),
9802
+ edges: cloud.edges.map((e) => ({
9803
+ from: e.from_slug ?? e.from_agent_id,
9804
+ to: e.to_slug ?? e.to_agent_id,
9805
+ ...e.description ? { description: e.description } : {},
9806
+ ...e.payload_schema && Object.keys(e.payload_schema).length ? { payload_schema: e.payload_schema } : {}
9807
+ }))
9808
+ };
9809
+ writeOrchManifest(cwd, manifest);
9810
+ writeOrchLink(cwd, {
9811
+ schemaVersion: 1,
9812
+ orchestration_id: cloud.id,
9813
+ group_id: cloud.group_id,
9814
+ org_id: cloud.group_id,
9815
+ team_id: cloud.group_id,
9816
+ name: cloud.name,
9817
+ description: cloud.description || undefined,
9818
+ linked_at: new Date().toISOString()
9819
+ });
9820
+ writeOrchSyncState(cwd, {
9821
+ schemaVersion: 1,
9822
+ orchestration_id: cloud.id,
9823
+ revision: cloud.revision,
9824
+ synced_at: new Date().toISOString(),
9825
+ members: installedMembers,
9826
+ edges: cloud.edges.map((e) => ({
9827
+ from_slug: e.from_slug ?? e.from_agent_id,
9828
+ to_slug: e.to_slug ?? e.to_agent_id,
9829
+ description: e.description ?? "",
9830
+ payload_schema: e.payload_schema ?? {}
9831
+ }))
9832
+ });
9833
+ p21.outro(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path46.basename(cwd)}/ ${pc29.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
9834
+ }
9835
+ function handleApiError5(err) {
9836
+ if (err instanceof ApiError) {
9837
+ if (err.status === 401) {
9838
+ p21.log.error("Your session is invalid. Run `brainbase login` and try again.");
9839
+ } else if (err.status === 403) {
9840
+ p21.log.error("You do not have access to this orchestration. Ask the team owner to grant you access via `group_memberships`.");
9841
+ } else {
9842
+ p21.log.error(err.message);
9843
+ }
9844
+ } else {
9845
+ p21.log.error(err.message);
9846
+ }
9847
+ }
9848
+
9849
+ // src/cli/orchestration-push.ts
9850
+ import * as p22 from "@clack/prompts";
9851
+ import pc30 from "picocolors";
9852
+ async function runOrchestrationPush(cwd, args) {
9853
+ banner("orchestration push — recursively push each member, then update the graph");
9854
+ const link = readOrchLink(cwd);
9855
+ if (!link) {
9856
+ p22.log.warn("This folder is not linked to any orchestration.");
9857
+ p22.log.info(`Run ${pc30.cyan("brainbase orchestration pull <id>")} first.`);
9858
+ return;
9859
+ }
9860
+ if (!hasOrchManifest(cwd)) {
9861
+ p22.log.warn(`No ${pc30.bold(ORCH_MANIFEST_FILE)} here.`);
9862
+ p22.log.info(`Run ${pc30.cyan("brainbase orchestration pull")} to materialise the manifest before pushing.`);
9863
+ return;
9864
+ }
9865
+ let manifest;
9866
+ try {
9867
+ manifest = readOrchManifest(cwd);
9868
+ } catch (err) {
9869
+ p22.log.error(err.message);
9870
+ return;
9871
+ }
9872
+ const memberSlugs = new Set(manifest.members.map((m) => m.slug));
9873
+ for (const e of manifest.edges) {
9874
+ if (!memberSlugs.has(e.from)) {
9875
+ p22.log.error(`Edge from "${pc30.bold(e.from)}" references a slug that isn't in members.`);
9876
+ return;
9877
+ }
9878
+ if (!memberSlugs.has(e.to)) {
9879
+ p22.log.error(`Edge to "${pc30.bold(e.to)}" references a slug that isn't in members.`);
9880
+ return;
9881
+ }
9882
+ if (e.from === e.to) {
9883
+ p22.log.error(`Edge ${pc30.bold(e.from)} → ${pc30.bold(e.to)}: self-loops are not allowed.`);
9884
+ return;
9885
+ }
9886
+ }
9887
+ const slugToAgentId = new Map;
9888
+ const missing = [];
9889
+ for (const m of manifest.members) {
9890
+ const dir = memberDir(cwd, m.slug);
9891
+ const memberLink = readLink(dir);
9892
+ if (!memberLink) {
9893
+ missing.push(m.slug);
9894
+ continue;
9895
+ }
9896
+ slugToAgentId.set(m.slug, memberLink.agent_id);
9897
+ }
9898
+ if (missing.length) {
9899
+ p22.log.error(`These members have no local checkout (expected at agents/<slug>/.brainbase/link.json): ${missing.join(", ")}.`);
9900
+ p22.log.info(`Run ${pc30.cyan("brainbase orchestration pull")} to materialise the missing folders.`);
9901
+ return;
9902
+ }
9903
+ const plan = [""];
9904
+ plan.push(` ${pc30.bold(link.name)} ${pc30.dim(`(${link.orchestration_id})`)}`);
9905
+ plan.push(` ${pc30.dim(`${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}`)}`);
9906
+ plan.push("");
9907
+ if (!args.graphOnly) {
9908
+ plan.push(` ${pc30.dim("per-member agent push:")}`);
9909
+ for (const m of manifest.members) {
9910
+ plan.push(` ${pc30.cyan("•")} ${pc30.bold(m.slug)}`);
9911
+ }
9912
+ plan.push("");
9913
+ }
9914
+ console.log(plan.join(`
9915
+ `));
9916
+ if (!args.yes) {
9917
+ const ok = await p22.confirm({
9918
+ message: args.graphOnly ? "Push graph (members + edges) only?" : "Push each member, then update the graph?",
9919
+ initialValue: true
9920
+ });
9921
+ if (!ensureNotCancelled(ok)) {
9922
+ p22.outro("Aborted.");
9923
+ return;
9924
+ }
9925
+ }
9926
+ if (!args.graphOnly) {
9927
+ for (const m of manifest.members) {
9928
+ const dir = memberDir(cwd, m.slug);
9929
+ console.log("");
9930
+ console.log(`${pc30.dim("───")} ${pc30.bold(m.slug)} ${pc30.dim("───")}`);
9931
+ try {
9932
+ await runAgentPush(dir, { yes: true });
9933
+ } catch (err) {
9934
+ p22.log.error(`Failed to push ${m.slug}: ${err.message}`);
9935
+ return;
9936
+ }
9937
+ }
9938
+ }
9939
+ const memberIds = manifest.members.map((m) => slugToAgentId.get(m.slug));
9940
+ const edges = manifest.edges.map((e) => ({
9941
+ from_agent_id: slugToAgentId.get(e.from),
9942
+ to_agent_id: slugToAgentId.get(e.to),
9943
+ description: e.description ?? "",
9944
+ payload_schema: e.payload_schema ?? {}
9945
+ }));
9946
+ const sp = p22.spinner();
9947
+ sp.start("Updating orchestration graph…");
9948
+ const lock = readOrchSyncState(cwd);
9949
+ try {
9950
+ const updated = await api.updateOrchestration(link.orchestration_id, {
9951
+ name: manifest.orchestration.name,
9952
+ description: manifest.orchestration.description ?? "",
9953
+ icon: manifest.orchestration.icon,
9954
+ icon_color: manifest.orchestration.icon_color,
9955
+ credit_limit: manifest.orchestration.credit_limit,
9956
+ members: memberIds,
9957
+ edges,
9958
+ ...lock?.revision != null ? { base_revision: lock.revision } : {}
9959
+ });
9960
+ sp.stop(`Graph updated. New cloud revision ${updated.revision}.`);
9961
+ writeOrchSyncState(cwd, {
9962
+ schemaVersion: 1,
9963
+ orchestration_id: updated.id,
9964
+ revision: updated.revision,
9965
+ synced_at: new Date().toISOString(),
9966
+ members: updated.members.map((m) => ({
9967
+ agent_id: m.agent_id,
9968
+ slug: m.slug,
9969
+ revision: m.revision ?? 0
9970
+ })),
9971
+ edges: updated.edges.map((e) => ({
9972
+ from_slug: e.from_slug ?? e.from_agent_id,
9973
+ to_slug: e.to_slug ?? e.to_agent_id,
9974
+ description: e.description ?? "",
9975
+ payload_schema: e.payload_schema ?? {}
9976
+ }))
9977
+ });
9978
+ p22.outro(`Pushed ${link.name} at revision ${updated.revision}.`);
9979
+ } catch (err) {
9980
+ sp.stop("Failed.");
9981
+ handleApiError6(err);
9982
+ }
9983
+ }
9984
+ function handleApiError6(err) {
9985
+ if (err instanceof ApiError) {
9986
+ if (err.status === 401) {
9987
+ p22.log.error("Your session is invalid. Run `brainbase login` and try again.");
9988
+ } else if (err.status === 403) {
9989
+ p22.log.error("You do not have access to this orchestration.");
9990
+ } else if (err.status === 409) {
9991
+ p22.log.error(err.message);
9992
+ p22.log.info(`Run ${pc30.cyan("brainbase orchestration pull")} to reconcile, then push again.`);
9993
+ } else {
9994
+ p22.log.error(err.message);
9995
+ }
9996
+ } else {
9997
+ p22.log.error(err.message);
9998
+ }
9999
+ }
10000
+
10001
+ // src/cli/orchestration-status.ts
10002
+ import * as p23 from "@clack/prompts";
10003
+ import pc31 from "picocolors";
10004
+ async function runOrchestrationStatus(cwd) {
10005
+ banner("orchestration status — what changed locally, remotely, both");
10006
+ const link = readOrchLink(cwd);
10007
+ if (!link) {
10008
+ p23.log.warn("This folder is not linked to any orchestration.");
10009
+ p23.log.info(`Run ${pc31.cyan("brainbase orchestration pull <id>")} first.`);
10010
+ return;
10011
+ }
10012
+ const localManifest = hasOrchManifest(cwd) ? readOrchManifest(cwd) : null;
10013
+ const lock = readOrchSyncState(cwd);
10014
+ let cloud;
10015
+ const sp = p23.spinner();
10016
+ sp.start(`Fetching ${link.name}…`);
10017
+ try {
10018
+ cloud = await api.getOrchestration(link.orchestration_id);
10019
+ sp.stop(`Cloud revision ${cloud.revision}.`);
10020
+ } catch (err) {
10021
+ sp.stop("Failed to reach brainbase.");
10022
+ if (err instanceof ApiError && err.status === 401) {
10023
+ p23.log.error("Your session is invalid. Run `brainbase login` and try again.");
10024
+ } else {
10025
+ p23.log.error(err.message);
10026
+ }
10027
+ return;
10028
+ }
10029
+ const lines = [];
10030
+ lines.push("");
10031
+ lines.push(` ${pc31.bold(link.name)} ${pc31.dim(`(${link.orchestration_id})`)}`);
10032
+ lines.push(` ${pc31.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
10033
+ lines.push("");
10034
+ const cloudMemberSet = new Set(cloud.members.map((m) => m.slug));
10035
+ const localMemberSet = new Set((localManifest?.members ?? []).map((m) => m.slug));
10036
+ const membersAdded = [...localMemberSet].filter((s) => !cloudMemberSet.has(s));
10037
+ const membersRemoved = [...cloudMemberSet].filter((s) => !localMemberSet.has(s));
10038
+ if (membersAdded.length || membersRemoved.length) {
10039
+ lines.push(` ${pc31.bold("members")}`);
10040
+ for (const slug of membersAdded) {
10041
+ lines.push(` ${pc31.yellow("→ push")} added in yaml: ${pc31.bold(slug)}`);
10042
+ }
10043
+ for (const slug of membersRemoved) {
10044
+ lines.push(` ${pc31.cyan("← pull")} added on cloud: ${pc31.bold(slug)}`);
10045
+ }
10046
+ lines.push("");
10047
+ }
10048
+ const cloudEdgeKey = (e) => `${e.from_slug ?? e.from_agent_id}->${e.to_slug ?? e.to_agent_id}|${e.description ?? ""}`;
10049
+ const localEdgeKey = (e) => `${e.from}->${e.to}|${e.description ?? ""}`;
10050
+ const cloudEdges = new Map;
10051
+ for (const e of cloud.edges)
10052
+ cloudEdges.set(cloudEdgeKey(e), true);
10053
+ const localEdges = new Map;
10054
+ for (const e of localManifest?.edges ?? [])
10055
+ localEdges.set(localEdgeKey(e), true);
10056
+ const edgesAdded = [...localEdges.keys()].filter((k) => !cloudEdges.has(k));
10057
+ const edgesRemoved = [...cloudEdges.keys()].filter((k) => !localEdges.has(k));
10058
+ if (edgesAdded.length || edgesRemoved.length) {
10059
+ lines.push(` ${pc31.bold("edges")}`);
10060
+ for (const k of edgesAdded)
10061
+ lines.push(` ${pc31.yellow("→ push")} added in yaml: ${k}`);
10062
+ for (const k of edgesRemoved)
10063
+ lines.push(` ${pc31.cyan("← pull")} added on cloud: ${k}`);
10064
+ lines.push("");
10065
+ }
10066
+ const lockByAgentId = new Map((lock?.members ?? []).map((m) => [m.agent_id, m]));
10067
+ const memberDrift = [];
10068
+ for (const m of cloud.members) {
10069
+ const dir = memberDir(cwd, m.slug);
10070
+ const memberSync = readSyncState(dir);
10071
+ if (!memberSync) {
10072
+ memberDrift.push({ slug: m.slug, reason: "no local checkout" });
10073
+ continue;
10074
+ }
10075
+ const lockEntry = lockByAgentId.get(m.agent_id);
10076
+ const lockedRev = lockEntry?.revision;
10077
+ if (m.revision != null && lockedRev != null && m.revision !== lockedRev) {
10078
+ memberDrift.push({
10079
+ slug: m.slug,
10080
+ reason: `cloud rev ${m.revision} ≠ lock ${lockedRev}`
10081
+ });
10082
+ }
10083
+ }
10084
+ if (memberDrift.length) {
10085
+ lines.push(` ${pc31.bold("member content drift")}`);
10086
+ for (const d of memberDrift) {
10087
+ lines.push(` ${pc31.cyan("?")} ${pc31.bold(d.slug)} ${pc31.dim("— " + d.reason)}`);
10088
+ }
10089
+ lines.push(` ${pc31.dim("cd into each member folder and run")} ${pc31.cyan("brainbase agent status")}`);
10090
+ lines.push("");
10091
+ }
10092
+ if (!membersAdded.length && !membersRemoved.length && !edgesAdded.length && !edgesRemoved.length && !memberDrift.length) {
10093
+ lines.push(` ${pc31.green("✓")} everything is in sync`);
10094
+ lines.push("");
10095
+ console.log(lines.join(`
10096
+ `));
10097
+ return;
10098
+ }
10099
+ lines.push(` ${pc31.dim("run")} ${pc31.cyan("brainbase orchestration pull")} ${pc31.dim("to apply cloud changes,")} ${pc31.cyan("brainbase orchestration push")} ${pc31.dim("to send yours")}`);
10100
+ lines.push("");
10101
+ console.log(lines.join(`
10102
+ `));
10103
+ }
10104
+
10105
+ // src/cli/orchestration-list.ts
10106
+ import * as p24 from "@clack/prompts";
10107
+ import pc32 from "picocolors";
10108
+ async function runOrchestrationList(args) {
10109
+ banner("orchestration list — orchestrations under a team");
10110
+ let orgId = args.orgId;
10111
+ let teamId = args.teamId;
10112
+ if (!orgId) {
10113
+ let orgs;
10114
+ try {
10115
+ orgs = await api.listOrgs();
10116
+ } catch (err) {
10117
+ handleApiError7(err);
10118
+ return;
10119
+ }
10120
+ if (orgs.length === 0) {
10121
+ p24.log.warn("You are not a member of any organization.");
10122
+ return;
10123
+ }
10124
+ if (orgs.length === 1) {
10125
+ orgId = orgs[0].id;
10126
+ } else {
10127
+ const choice = await p24.select({
10128
+ message: "Which organization?",
10129
+ options: orgs.map((o) => ({ value: o.id, label: o.name }))
10130
+ });
10131
+ orgId = ensureNotCancelled(choice);
10132
+ }
10133
+ }
10134
+ if (!teamId) {
10135
+ let teams;
10136
+ try {
10137
+ teams = await api.listTeams(orgId);
10138
+ } catch (err) {
10139
+ handleApiError7(err);
10140
+ return;
10141
+ }
10142
+ if (teams.length === 0) {
10143
+ p24.log.warn("No teams under this organization. Create one in the web app first.");
10144
+ return;
10145
+ }
10146
+ if (teams.length === 1) {
10147
+ teamId = teams[0].id;
10148
+ } else {
10149
+ const choice = await p24.select({
10150
+ message: "Which team?",
10151
+ options: teams.map((t) => ({ value: t.id, label: t.name }))
10152
+ });
10153
+ teamId = ensureNotCancelled(choice);
10154
+ }
10155
+ }
10156
+ let items;
10157
+ const sp = p24.spinner();
10158
+ sp.start("Fetching orchestrations…");
10159
+ try {
10160
+ items = await api.listOrchestrations(orgId, teamId);
10161
+ sp.stop(`${items.length} orchestration${items.length === 1 ? "" : "s"}.`);
10162
+ } catch (err) {
10163
+ sp.stop("Failed.");
10164
+ handleApiError7(err);
10165
+ return;
10166
+ }
10167
+ if (items.length === 0) {
10168
+ p24.log.info("This team has no orchestrations yet.");
10169
+ return;
10170
+ }
10171
+ const lines = [""];
10172
+ for (const o of items) {
10173
+ lines.push(` ${pc32.bold(o.name)} ${pc32.dim(o.id)}`);
10174
+ if (o.description)
10175
+ lines.push(` ${pc32.dim(o.description)}`);
10176
+ lines.push(` ${pc32.dim(`${o.member_count} member${o.member_count === 1 ? "" : "s"} · ${o.edge_count} edge${o.edge_count === 1 ? "" : "s"}`)}`);
10177
+ lines.push("");
10178
+ }
10179
+ lines.push(` ${pc32.dim("pull one with")} ${pc32.cyan("brainbase orchestration pull <id>")}`);
10180
+ lines.push("");
10181
+ console.log(lines.join(`
10182
+ `));
10183
+ }
10184
+ function handleApiError7(err) {
10185
+ if (err instanceof ApiError) {
10186
+ if (err.status === 401) {
10187
+ p24.log.error("Your session is invalid. Run `brainbase login` and try again.");
10188
+ } else {
10189
+ p24.log.error(err.message);
10190
+ }
10191
+ } else {
10192
+ p24.log.error(err.message);
10193
+ }
10194
+ }
10195
+
10196
+ // src/cli/orchestration.ts
10197
+ async function runOrchestration(cwd, sub, args, opts) {
10198
+ switch (sub) {
10199
+ case "pull":
10200
+ await runOrchestrationPull(cwd, {
10201
+ orchestrationId: args[0],
10202
+ yes: opts.yes,
10203
+ harness: opts.harness
10204
+ });
10205
+ return;
10206
+ case "push":
10207
+ await runOrchestrationPush(cwd, {
10208
+ yes: opts.yes,
10209
+ graphOnly: opts.graphOnly
10210
+ });
10211
+ return;
10212
+ case "status":
10213
+ await runOrchestrationStatus(cwd);
10214
+ return;
10215
+ case "list":
10216
+ case "ls":
10217
+ await runOrchestrationList({ orgId: opts.orgId, teamId: opts.teamId });
10218
+ return;
10219
+ case undefined:
10220
+ case "help":
10221
+ case "-h":
10222
+ case "--help":
10223
+ printHelp2();
10224
+ return;
10225
+ default:
10226
+ console.error(`Unknown orchestration subcommand: ${sub}
10227
+ `);
10228
+ printHelp2();
10229
+ process.exit(1);
10230
+ }
10231
+ }
10232
+ function printHelp2() {
10233
+ const out = [];
10234
+ out.push("");
10235
+ out.push(` ${pc33.bold("brainbase orchestration")} ${pc33.dim("<sub> [options]")}`);
10236
+ out.push("");
10237
+ out.push(` ${pc33.cyan("pull")} ${pc33.dim("<id>")} ${pc33.dim("fetch orchestration + every member agent into this folder")}`);
10238
+ out.push(` ${pc33.cyan("push")} ${pc33.dim("push each member, then update the orchestration graph")}`);
10239
+ out.push(` ${pc33.cyan("status")} ${pc33.dim("show what would push and what would pull")}`);
10240
+ out.push(` ${pc33.cyan("list")} ${pc33.dim("list orchestrations under a team")}`);
10241
+ out.push("");
10242
+ out.push(` ${pc33.bold("Flags")}`);
10243
+ out.push(` ${pc33.dim("--yes, -y")} skip confirmations`);
10244
+ out.push(` ${pc33.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
10245
+ out.push(` ${pc33.dim("--graph-only")} for push: only update members + edges, skip per-member push`);
10246
+ out.push(` ${pc33.dim("--org <id>")} for list: org id (CLI vocab — DB teams.id)`);
10247
+ out.push(` ${pc33.dim("--team <id>")} for list: team id (CLI vocab — DB groups.id)`);
10248
+ out.push("");
10249
+ console.log(out.join(`
10250
+ `));
10251
+ }
10252
+
9292
10253
  // src/cli/run.ts
9293
10254
  import { spawn as spawn2 } from "node:child_process";
9294
10255
  async function runRun(cwd, args) {
@@ -9328,17 +10289,17 @@ async function runRun(cwd, args) {
9328
10289
  }
9329
10290
 
9330
10291
  // src/cli/publish.ts
9331
- import * as p20 from "@clack/prompts";
9332
- import pc29 from "picocolors";
10292
+ import * as p25 from "@clack/prompts";
10293
+ import pc34 from "picocolors";
9333
10294
  async function runPublish(cwd, _args) {
9334
10295
  banner("publish — send your changes to the team");
9335
10296
  const link = readLink(cwd);
9336
10297
  if (!link) {
9337
- p20.log.warn("This folder is not linked to any agent.");
9338
- p20.log.info(`Run ${pc29.cyan("brainbase link")} first.`);
10298
+ p25.log.warn("This folder is not linked to any agent.");
10299
+ p25.log.info(`Run ${pc34.cyan("brainbase link")} first.`);
9339
10300
  return;
9340
10301
  }
9341
- p20.log.info(`${pc29.bold("publish")} is coming soon — for now, edit the agent on the web app and run ${pc29.cyan("brainbase sync")} to bring changes here.`);
10302
+ p25.log.info(`${pc34.bold("publish")} is coming soon — for now, edit the agent on the web app and run ${pc34.cyan("brainbase sync")} to bring changes here.`);
9342
10303
  }
9343
10304
 
9344
10305
  // src/ui/ink/StatusCard.tsx
@@ -9637,8 +10598,8 @@ async function runStatus(cwd) {
9637
10598
  }
9638
10599
 
9639
10600
  // src/cli/token.ts
9640
- import * as p21 from "@clack/prompts";
9641
- import pc30 from "picocolors";
10601
+ import * as p26 from "@clack/prompts";
10602
+ import pc35 from "picocolors";
9642
10603
 
9643
10604
  // src/ui/ink/TokenCards.tsx
9644
10605
  import { Box as Box15, Text as Text16 } from "ink";
@@ -9884,7 +10845,7 @@ async function runTokenCreate(args) {
9884
10845
  banner("token create — make a long-lived CLI key");
9885
10846
  let name = args.name;
9886
10847
  if (!name) {
9887
- const ans = await p21.text({
10848
+ const ans = await p26.text({
9888
10849
  message: "Token label",
9889
10850
  placeholder: "my-laptop or ci-runner",
9890
10851
  validate: (v) => v.length === 0 ? "Required." : undefined
@@ -9892,13 +10853,13 @@ async function runTokenCreate(args) {
9892
10853
  name = ensureNotCancelled(ans);
9893
10854
  }
9894
10855
  const scopes = args.scopes && args.scopes.length > 0 ? args.scopes : DEFAULT_SCOPES;
9895
- const spinner17 = p21.spinner();
9896
- spinner17.start("Creating token…");
10856
+ const spinner21 = p26.spinner();
10857
+ spinner21.start("Creating token…");
9897
10858
  const created = await registryApi.createCliToken({
9898
10859
  name,
9899
10860
  scopes
9900
10861
  });
9901
- spinner17.stop("Token created.");
10862
+ spinner21.stop("Token created.");
9902
10863
  writeToken(created.token, name);
9903
10864
  await showTokenCreatedCard({
9904
10865
  token: created.token,
@@ -9932,8 +10893,8 @@ async function runTokenRevoke(args) {
9932
10893
  process.exit(1);
9933
10894
  }
9934
10895
  if (!args.yes) {
9935
- const ok = await p21.confirm({
9936
- message: `Revoke token ${pc30.bold(args.id)}? CIs and machines using it will stop working.`,
10896
+ const ok = await p26.confirm({
10897
+ message: `Revoke token ${pc35.bold(args.id)}? CIs and machines using it will stop working.`,
9937
10898
  initialValue: false
9938
10899
  });
9939
10900
  if (!ensureNotCancelled(ok))
@@ -9948,7 +10909,7 @@ async function runTokenRevoke(args) {
9948
10909
  }
9949
10910
  async function runTokenClear() {
9950
10911
  if (!readToken()) {
9951
- console.log(pc30.dim("No local token stored."));
10912
+ console.log(pc35.dim("No local token stored."));
9952
10913
  return;
9953
10914
  }
9954
10915
  clearToken();
@@ -9999,17 +10960,17 @@ async function runToken(sub, rest, args) {
9999
10960
  function printTokenHelp() {
10000
10961
  const out = [];
10001
10962
  out.push("");
10002
- out.push(` ${pc30.bold("brainbase token")} ${pc30.dim("<command>")}`);
10963
+ out.push(` ${pc35.bold("brainbase token")} ${pc35.dim("<command>")}`);
10003
10964
  out.push("");
10004
- out.push(` ${pc30.cyan("create")} ${pc30.dim("issue a new long-lived CLI key (PAT)")}`);
10005
- out.push(` ${pc30.cyan("list")} ${pc30.dim("show your active tokens")}`);
10006
- out.push(` ${pc30.cyan("revoke")} ${pc30.dim("<id>")} ${pc30.dim("revoke a token by id")}`);
10007
- out.push(` ${pc30.cyan("clear")} ${pc30.dim("forget the local token (does not revoke)")}`);
10965
+ out.push(` ${pc35.cyan("create")} ${pc35.dim("issue a new long-lived CLI key (PAT)")}`);
10966
+ out.push(` ${pc35.cyan("list")} ${pc35.dim("show your active tokens")}`);
10967
+ out.push(` ${pc35.cyan("revoke")} ${pc35.dim("<id>")} ${pc35.dim("revoke a token by id")}`);
10968
+ out.push(` ${pc35.cyan("clear")} ${pc35.dim("forget the local token (does not revoke)")}`);
10008
10969
  out.push("");
10009
- out.push(` ${pc30.bold("create flags")}`);
10010
- out.push(` ${pc30.cyan("--name, -n")} ${pc30.dim("<label>")} ${pc30.dim("token label (prompted if omitted)")}`);
10011
- out.push(` ${pc30.cyan("--scopes")} ${pc30.dim("<list>")} ${pc30.dim("comma-separated; allowed: read, publish, admin")}`);
10012
- out.push(` ${pc30.dim("default: read,publish")}`);
10970
+ out.push(` ${pc35.bold("create flags")}`);
10971
+ out.push(` ${pc35.cyan("--name, -n")} ${pc35.dim("<label>")} ${pc35.dim("token label (prompted if omitted)")}`);
10972
+ out.push(` ${pc35.cyan("--scopes")} ${pc35.dim("<list>")} ${pc35.dim("comma-separated; allowed: read, publish, admin")}`);
10973
+ out.push(` ${pc35.dim("default: read,publish")}`);
10013
10974
  out.push("");
10014
10975
  console.log(out.join(`
10015
10976
  `));
@@ -10029,81 +10990,88 @@ var PROTECTED = new Set([
10029
10990
  function help() {
10030
10991
  const out = [];
10031
10992
  out.push("");
10032
- out.push(` ${brandTint("◆")} ${pc31.bold("brainbase")} ${pc31.dim("v0.2.0")}`);
10033
- out.push(` ${pc31.dim("connect your local agent to the brainbase platform")}`);
10993
+ out.push(` ${brandTint("◆")} ${pc36.bold("brainbase")} ${pc36.dim("v0.2.0")}`);
10994
+ out.push(` ${pc36.dim("connect your local agent to the brainbase platform")}`);
10034
10995
  out.push("");
10035
10996
  out.push(divider("USAGE"));
10036
10997
  out.push("");
10037
- out.push(` ${pc31.bold("brainbase")} ${pc31.dim("<command> [options]")}`);
10998
+ out.push(` ${pc36.bold("brainbase")} ${pc36.dim("<command> [options]")}`);
10038
10999
  out.push("");
10039
11000
  out.push(divider("AUTH"));
10040
11001
  out.push("");
10041
- out.push(` ${pc31.cyan("login")} ${pc31.dim(" open the web app and connect this device")}`);
10042
- out.push(` ${pc31.cyan("logout")} ${pc31.dim(" clear the local session")}`);
10043
- out.push(` ${pc31.cyan("whoami")} ${pc31.dim(" show the current user")}`);
11002
+ out.push(` ${pc36.cyan("login")} ${pc36.dim(" open the web app and connect this device")}`);
11003
+ out.push(` ${pc36.cyan("logout")} ${pc36.dim(" clear the local session")}`);
11004
+ out.push(` ${pc36.cyan("whoami")} ${pc36.dim(" show the current user")}`);
10044
11005
  out.push("");
10045
11006
  out.push(divider("LINKED AGENT"));
10046
11007
  out.push("");
10047
- out.push(` ${pc31.cyan("agent create")} ${pc31.dim("make a new agent on the cloud and link this folder")}`);
10048
- out.push(` ${pc31.cyan("link")} ${pc31.dim("attach this folder to an existing agent")}`);
10049
- out.push(` ${pc31.cyan("agent pull")} ${pc31.dim("bring cloud changes into this folder")}`);
10050
- out.push(` ${pc31.cyan("agent push")} ${pc31.dim("send local changes to the cloud")}`);
10051
- out.push(` ${pc31.cyan("agent status")} ${pc31.dim("show what would pull and what would push")}`);
10052
- out.push(` ${pc31.cyan("agent env")} ${pc31.dim("print export lines for `eval $(brainbase agent env)`")}`);
10053
- out.push(` ${pc31.cyan("run")} ${pc31.dim("<cmd> [args...]")} ${pc31.dim("run <cmd> with secrets.env loaded into env")}`);
10054
- out.push(` ${pc31.cyan("status")} ${pc31.dim("show what this folder is linked to")}`);
10055
- out.push(` ${pc31.cyan("unlink")} ${pc31.dim("disconnect this folder")}`);
11008
+ out.push(` ${pc36.cyan("agent create")} ${pc36.dim("make a new agent on the cloud and link this folder")}`);
11009
+ out.push(` ${pc36.cyan("link")} ${pc36.dim("attach this folder to an existing agent")}`);
11010
+ out.push(` ${pc36.cyan("agent pull")} ${pc36.dim("bring cloud changes into this folder")}`);
11011
+ out.push(` ${pc36.cyan("agent push")} ${pc36.dim("send local changes to the cloud")}`);
11012
+ out.push(` ${pc36.cyan("agent status")} ${pc36.dim("show what would pull and what would push")}`);
11013
+ out.push(` ${pc36.cyan("agent env")} ${pc36.dim("print export lines for `eval $(brainbase agent env)`")}`);
11014
+ out.push(` ${pc36.cyan("run")} ${pc36.dim("<cmd> [args...]")} ${pc36.dim("run <cmd> with secrets.env loaded into env")}`);
11015
+ out.push(` ${pc36.cyan("status")} ${pc36.dim("show what this folder is linked to")}`);
11016
+ out.push(` ${pc36.cyan("unlink")} ${pc36.dim("disconnect this folder")}`);
11017
+ out.push("");
11018
+ out.push(divider("ORCHESTRATIONS"));
11019
+ out.push("");
11020
+ out.push(` ${pc36.cyan("orchestration list")} ${pc36.dim("list orchestrations under a team")}`);
11021
+ out.push(` ${pc36.cyan("orchestration pull")} ${pc36.dim("<id>")} ${pc36.dim("recursively fetch an orchestration + every member agent")}`);
11022
+ out.push(` ${pc36.cyan("orchestration push")} ${pc36.dim("recursively push each member, then update the graph")}`);
11023
+ out.push(` ${pc36.cyan("orchestration status")} ${pc36.dim("show what would push and what would pull")}`);
10056
11024
  out.push("");
10057
11025
  out.push(divider("TEMPLATES"));
10058
11026
  out.push("");
10059
- out.push(` ${pc31.cyan("template pack")} ${pc31.dim("bundle the current agent into a template")}`);
10060
- out.push(` ${pc31.cyan("template publish")} ${pc31.dim("upload a template to the registry")}`);
10061
- out.push(` ${pc31.cyan("template search")} ${pc31.dim("[query]")} ${pc31.dim("search the registry")}`);
10062
- out.push(` ${pc31.cyan("template info")} ${pc31.dim("<creator/slug>")} ${pc31.dim("show registry details for a template")}`);
10063
- out.push(` ${pc31.cyan("template onboard")} ${pc31.dim("<creator/slug>")} ${pc31.dim("install (or refresh) a template")}`);
10064
- out.push(` ${pc31.cyan("template list")} ${pc31.dim("show installed templates")}`);
10065
- out.push(` ${pc31.cyan("template remove")} ${pc31.dim("<creator/slug>")} ${pc31.dim("uninstall a template")}`);
11027
+ out.push(` ${pc36.cyan("template pack")} ${pc36.dim("bundle the current agent into a template")}`);
11028
+ out.push(` ${pc36.cyan("template publish")} ${pc36.dim("upload a template to the registry")}`);
11029
+ out.push(` ${pc36.cyan("template search")} ${pc36.dim("[query]")} ${pc36.dim("search the registry")}`);
11030
+ out.push(` ${pc36.cyan("template info")} ${pc36.dim("<creator/slug>")} ${pc36.dim("show registry details for a template")}`);
11031
+ out.push(` ${pc36.cyan("template onboard")} ${pc36.dim("<creator/slug>")} ${pc36.dim("install (or refresh) a template")}`);
11032
+ out.push(` ${pc36.cyan("template list")} ${pc36.dim("show installed templates")}`);
11033
+ out.push(` ${pc36.cyan("template remove")} ${pc36.dim("<creator/slug>")} ${pc36.dim("uninstall a template")}`);
10066
11034
  out.push("");
10067
11035
  out.push(divider("SKILLS"));
10068
11036
  out.push("");
10069
- out.push(` ${pc31.cyan("skill add")} ${pc31.dim("<source>")} ${pc31.dim("install a skill (github / git / brainbase)")}`);
10070
- out.push(` ${pc31.cyan("skill list")} ${pc31.dim("show locally installed skills + their source")}`);
10071
- out.push(` ${pc31.cyan("skill update")} ${pc31.dim("<slug>")} ${pc31.dim("re-fetch a skill from its recorded source")}`);
10072
- out.push(` ${pc31.cyan("skill remove")} ${pc31.dim("<slug>")} ${pc31.dim("uninstall a skill")}`);
10073
- out.push(` ${pc31.cyan("skill search")} ${pc31.dim("[query]")} ${pc31.dim("search the brainbase skill registry")}`);
10074
- out.push(` ${pc31.cyan("skill info")} ${pc31.dim("<creator/slug>")} ${pc31.dim("show registry details for a skill")}`);
10075
- out.push(` ${pc31.cyan("skill publish")} ${pc31.dim("[creator/slug][@v]")} ${pc31.dim("publish a local skill to the registry")}`);
11037
+ out.push(` ${pc36.cyan("skill add")} ${pc36.dim("<source>")} ${pc36.dim("install a skill (github / git / brainbase)")}`);
11038
+ out.push(` ${pc36.cyan("skill list")} ${pc36.dim("show locally installed skills + their source")}`);
11039
+ out.push(` ${pc36.cyan("skill update")} ${pc36.dim("<slug>")} ${pc36.dim("re-fetch a skill from its recorded source")}`);
11040
+ out.push(` ${pc36.cyan("skill remove")} ${pc36.dim("<slug>")} ${pc36.dim("uninstall a skill")}`);
11041
+ out.push(` ${pc36.cyan("skill search")} ${pc36.dim("[query]")} ${pc36.dim("search the brainbase skill registry")}`);
11042
+ out.push(` ${pc36.cyan("skill info")} ${pc36.dim("<creator/slug>")} ${pc36.dim("show registry details for a skill")}`);
11043
+ out.push(` ${pc36.cyan("skill publish")} ${pc36.dim("[creator/slug][@v]")} ${pc36.dim("publish a local skill to the registry")}`);
10076
11044
  out.push("");
10077
11045
  out.push(divider("CLI TOKENS"));
10078
11046
  out.push("");
10079
- out.push(` ${pc31.cyan("token create")} ${pc31.dim("issue a long-lived CLI key for CI / scripts")}`);
10080
- out.push(` ${pc31.cyan("token list")} ${pc31.dim("show your active tokens")}`);
10081
- out.push(` ${pc31.cyan("token revoke")} ${pc31.dim("<id>")} ${pc31.dim("revoke a token")}`);
11047
+ out.push(` ${pc36.cyan("token create")} ${pc36.dim("issue a long-lived CLI key for CI / scripts")}`);
11048
+ out.push(` ${pc36.cyan("token list")} ${pc36.dim("show your active tokens")}`);
11049
+ out.push(` ${pc36.cyan("token revoke")} ${pc36.dim("<id>")} ${pc36.dim("revoke a token")}`);
10082
11050
  out.push("");
10083
11051
  out.push(divider("FLAGS"));
10084
11052
  out.push("");
10085
- out.push(` ${pc31.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
10086
- out.push(` ${pc31.dim("--scope <s>")} force scope: global | project`);
10087
- out.push(` ${pc31.dim("--yes, -y")} skip confirmations / auto-overwrite`);
10088
- out.push(` ${pc31.dim("--agent <id>")} for link: attach this folder to an existing agent non-interactively`);
10089
- out.push(` ${pc31.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
10090
- out.push(` ${pc31.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
10091
- out.push(` ${pc31.dim("--all")} for template list: include installs from other folders`);
10092
- out.push(` ${pc31.dim("--web <url>")} for login: web app URL (default https://new.usekafka.com)`);
11053
+ out.push(` ${pc36.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
11054
+ out.push(` ${pc36.dim("--scope <s>")} force scope: global | project`);
11055
+ out.push(` ${pc36.dim("--yes, -y")} skip confirmations / auto-overwrite`);
11056
+ out.push(` ${pc36.dim("--agent <id>")} for link: attach this folder to an existing agent non-interactively`);
11057
+ out.push(` ${pc36.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
11058
+ out.push(` ${pc36.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
11059
+ out.push(` ${pc36.dim("--all")} for template list: include installs from other folders`);
11060
+ out.push(` ${pc36.dim("--web <url>")} for login: web app URL (default https://new.usekafka.com)`);
10093
11061
  out.push("");
10094
11062
  out.push(divider("ENV"));
10095
11063
  out.push("");
10096
- out.push(` ${pc31.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
10097
- out.push(` ${pc31.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
10098
- out.push(` ${pc31.dim("BRAINBASE_API_URL")} override the API URL used by link / sync`);
10099
- out.push(` ${pc31.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL`);
10100
- out.push(` ${pc31.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
10101
- out.push(` ${pc31.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
11064
+ out.push(` ${pc36.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
11065
+ out.push(` ${pc36.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
11066
+ out.push(` ${pc36.dim("BRAINBASE_API_URL")} override the API URL used by link / sync`);
11067
+ out.push(` ${pc36.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL`);
11068
+ out.push(` ${pc36.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
11069
+ out.push(` ${pc36.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
10102
11070
  out.push("");
10103
11071
  out.push(divider("HARNESSES"));
10104
11072
  out.push("");
10105
- out.push(` ${pc31.dim("•")} ${pc31.bold("claude-code")} ${pc31.dim("skills, mcps, agents, commands, instructions, files")}`);
10106
- out.push(` ${pc31.dim("•")} ${pc31.bold("codex")} ${pc31.dim("skills, mcps, commands, instructions, files")}`);
11073
+ out.push(` ${pc36.dim("•")} ${pc36.bold("claude-code")} ${pc36.dim("skills, mcps, agents, commands, instructions, files")}`);
11074
+ out.push(` ${pc36.dim("•")} ${pc36.bold("codex")} ${pc36.dim("skills, mcps, commands, instructions, files")}`);
10107
11075
  out.push("");
10108
11076
  console.log(out.join(`
10109
11077
  `));
@@ -10147,13 +11115,13 @@ async function requireAuth(cmd) {
10147
11115
  if (status.ok)
10148
11116
  return;
10149
11117
  console.error("");
10150
- console.error(` ${brandTint("◆")} ${pc31.bold("brainbase")}`);
11118
+ console.error(` ${brandTint("◆")} ${pc36.bold("brainbase")}`);
10151
11119
  console.error("");
10152
- console.error(` ${pc31.red("✗")} You need to sign in to use ${pc31.bold("brainbase " + cmd)}.`);
11120
+ console.error(` ${pc36.red("✗")} You need to sign in to use ${pc36.bold("brainbase " + cmd)}.`);
10153
11121
  if (status.reason)
10154
- console.error(` ${pc31.dim(status.reason)}`);
11122
+ console.error(` ${pc36.dim(status.reason)}`);
10155
11123
  console.error("");
10156
- console.error(` Run ${pc31.cyan("brainbase login")} to connect this device.`);
11124
+ console.error(` Run ${pc36.cyan("brainbase login")} to connect this device.`);
10157
11125
  console.error("");
10158
11126
  process2.exit(1);
10159
11127
  }
@@ -10163,7 +11131,7 @@ async function main() {
10163
11131
  const rawCwd = process2.cwd();
10164
11132
  const cwd = (() => {
10165
11133
  try {
10166
- return fs40.realpathSync(rawCwd);
11134
+ return fs44.realpathSync(rawCwd);
10167
11135
  } catch {
10168
11136
  return rawCwd;
10169
11137
  }
@@ -10190,6 +11158,7 @@ async function main() {
10190
11158
  const agentFlag = getFlag(argv, "--agent");
10191
11159
  const shellFlag = getFlag(argv, "--shell");
10192
11160
  const noTracking = hasFlag(argv, "--no-tracking");
11161
+ const graphOnlyFlag = hasFlag(argv, "--graph-only");
10193
11162
  const nameFlag = getFlag(argv, "--name");
10194
11163
  const taglineFlag = getFlag(argv, "--tagline");
10195
11164
  const orgIdFlag = getFlag(argv, "--org");
@@ -10274,6 +11243,18 @@ async function main() {
10274
11243
  });
10275
11244
  break;
10276
11245
  }
11246
+ case "orchestration":
11247
+ case "orch": {
11248
+ const sub = argv.shift();
11249
+ await runOrchestration(cwd, sub, argv, {
11250
+ yes,
11251
+ harness,
11252
+ orgId: orgIdFlag,
11253
+ teamId: teamIdFlag,
11254
+ graphOnly: graphOnlyFlag
11255
+ });
11256
+ break;
11257
+ }
10277
11258
  case "publish": {
10278
11259
  await runPublish(cwd, { yes });
10279
11260
  break;
@@ -10289,7 +11270,7 @@ async function main() {
10289
11270
  process2.exit(1);
10290
11271
  }
10291
11272
  } catch (err) {
10292
- console.error(pc31.red(`
11273
+ console.error(pc36.red(`
10293
11274
  ${err.message}`));
10294
11275
  if (process2.env.BRAINBASE_DEBUG)
10295
11276
  console.error(err.stack);