@brainbase-labs/cli 0.5.0 → 0.6.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 (2) hide show
  1. package/dist/index.js +583 -257
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -28566,7 +28566,7 @@ var require_jsx_dev_runtime = __commonJS((exports, module) => {
28566
28566
  // src/index.ts
28567
28567
  var import_picocolors40 = __toESM(require_picocolors(), 1);
28568
28568
  import process13 from "node:process";
28569
- import fs50 from "node:fs";
28569
+ import fs51 from "node:fs";
28570
28570
 
28571
28571
  // src/cli/template.ts
28572
28572
  var import_picocolors12 = __toESM(require_picocolors(), 1);
@@ -50768,8 +50768,9 @@ import fs39 from "node:fs";
50768
50768
  var import_yaml2 = __toESM(require_dist(), 1);
50769
50769
  var AGENT_MANIFEST_FILE = "brainbase.agent.yaml";
50770
50770
  var LEGACY_AGENT_MANIFEST_FILE = "brainbase.yaml";
50771
- var DEFAULT_INSTRUCTIONS_FILE = "instructions.md";
50772
- var DEFAULT_ENTRYPOINT_FILE = "entrypoint.sh";
50771
+ var DEFAULT_INSTRUCTIONS_FILE = ".brainbase/instructions.md";
50772
+ var DEFAULT_ENTRYPOINT_FILE = ".brainbase/entrypoint.sh";
50773
+ var DEFAULT_PLAYBOOKS_DIR = ".brainbase/playbooks";
50773
50774
  var REGISTRY_SOURCE_RE = /^registry:(?:([a-z0-9_-]+)\/)?([a-z0-9_-]+)(?:@(.+))?$/i;
50774
50775
  function parseSkillSource2(raw) {
50775
50776
  if (!raw || typeof raw !== "string") {
@@ -50809,6 +50810,17 @@ var EntrypointSchema = exports_external.object({
50809
50810
  }, {
50810
50811
  message: "entrypoint must set exactly one of `file`, `commands`, or `text`"
50811
50812
  });
50813
+ var PlaybookContentSchema = exports_external.object({
50814
+ file: exports_external.string().min(1).optional(),
50815
+ text: exports_external.string().optional()
50816
+ }).refine((v3) => v3.file !== undefined || v3.text !== undefined, {
50817
+ message: "playbook content must set either `file` or `text`"
50818
+ });
50819
+ var PlaybookSchema = exports_external.object({
50820
+ title: exports_external.string().min(1),
50821
+ description: exports_external.string().optional(),
50822
+ content: PlaybookContentSchema
50823
+ });
50812
50824
  var SkillEntrySchema = exports_external.object({
50813
50825
  source: exports_external.string().min(1)
50814
50826
  });
@@ -50828,6 +50840,7 @@ var AgentManifestSchema = exports_external.object({
50828
50840
  agent: AgentMetaSchema,
50829
50841
  instructions: InstructionsSchema.optional(),
50830
50842
  entrypoint: EntrypointSchema.optional(),
50843
+ playbooks: exports_external.array(PlaybookSchema).default([]),
50831
50844
  skills: exports_external.array(SkillEntrySchema).default([]),
50832
50845
  mcp: exports_external.array(McpEntrySchema).default([]),
50833
50846
  commands: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
@@ -50911,6 +50924,21 @@ function resolveEntrypoint(cwd2, manifest) {
50911
50924
  }
50912
50925
  return null;
50913
50926
  }
50927
+ function resolvePlaybookContent(cwd2, entry) {
50928
+ const c2 = entry.content;
50929
+ if (typeof c2.text === "string")
50930
+ return c2.text;
50931
+ if (typeof c2.file === "string") {
50932
+ const p2 = path42.resolve(cwd2, c2.file);
50933
+ if (!fs39.existsSync(p2))
50934
+ return null;
50935
+ return fs39.readFileSync(p2, "utf8");
50936
+ }
50937
+ return null;
50938
+ }
50939
+ function slugifyPlaybookTitle(title) {
50940
+ return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "playbook";
50941
+ }
50914
50942
 
50915
50943
  // src/core/link.ts
50916
50944
  var LINK_DIR = ".brainbase";
@@ -51064,6 +51092,7 @@ function writeLink(cwd2, link2) {
51064
51092
  manifest = readManifest(cwd2) ?? {
51065
51093
  schema: 1,
51066
51094
  agent: { name: link2.name },
51095
+ playbooks: [],
51067
51096
  skills: [],
51068
51097
  mcp: []
51069
51098
  };
@@ -51071,6 +51100,7 @@ function writeLink(cwd2, link2) {
51071
51100
  manifest = {
51072
51101
  schema: 1,
51073
51102
  agent: { name: link2.name },
51103
+ playbooks: [],
51074
51104
  skills: [],
51075
51105
  mcp: []
51076
51106
  };
@@ -51973,6 +52003,7 @@ import path48 from "node:path";
51973
52003
  import fs45 from "node:fs";
51974
52004
  import os12 from "node:os";
51975
52005
  var import_picocolors25 = __toESM(require_picocolors(), 1);
52006
+ var import_yaml3 = __toESM(require_dist(), 1);
51976
52007
 
51977
52008
  // src/core/agent-diff.ts
51978
52009
  import path46 from "node:path";
@@ -52119,8 +52150,34 @@ function readLocalComponents(cwd2, manifest) {
52119
52150
  hash: hashMcpEntry(entry)
52120
52151
  });
52121
52152
  }
52153
+ for (const entry of manifest.playbooks ?? []) {
52154
+ const body = resolvePlaybookContent(cwd2, entry);
52155
+ if (body === null) {
52156
+ out.push({
52157
+ type: "playbook",
52158
+ slug: slugifyPlaybookTitle(entry.title),
52159
+ hash: null
52160
+ });
52161
+ continue;
52162
+ }
52163
+ const wireBody = /^---\s*\n/.test(body) ? body : `---
52164
+ title: ${jsonOrPlain(entry.title)}` + (entry.description ? `
52165
+ description: ${jsonOrPlain(entry.description)}` : "") + `
52166
+ ---
52167
+ ${body.replace(/^\n+/, "")}`;
52168
+ out.push({
52169
+ type: "playbook",
52170
+ slug: slugifyPlaybookTitle(entry.title),
52171
+ hash: componentHashFromFileHashes([hashString(wireBody)])
52172
+ });
52173
+ }
52122
52174
  return out;
52123
52175
  }
52176
+ function jsonOrPlain(s3) {
52177
+ if (!/[\n":#&*!|>'%@`{}[\]]/.test(s3) && s3.trim() === s3 && s3 !== "")
52178
+ return s3;
52179
+ return JSON.stringify(s3);
52180
+ }
52124
52181
  function threeWayDiff(input) {
52125
52182
  const lockMap = new Map;
52126
52183
  for (const c2 of input.lock)
@@ -52489,12 +52546,14 @@ async function runAgentPull(cwd2, args) {
52489
52546
  }
52490
52547
  }
52491
52548
  }
52492
- materializeInstructions(cwd2, cloud, toInstallKeys, keepLocalKeys);
52549
+ materializeInstructions(cwd2, cloud, toInstallKeys, keepLocalKeys, existingManifest);
52493
52550
  materializeEntrypoint(cwd2, cloudAgent.entrypoint ?? "", existingManifest);
52551
+ materializePlaybooks(cwd2, cloud, toInstallKeys, keepLocalKeys, existingManifest);
52494
52552
  const yaml = mergeManifest(cwd2, existingManifest, cloud, cloudAgent, harness);
52495
52553
  writeManifest(cwd2, yaml);
52496
52554
  writeLink(cwd2, buildLinkFromAgent(cloudAgent, harness, readLink(cwd2)));
52497
52555
  const lockComponents = buildLockComponents({
52556
+ cwd: cwd2,
52498
52557
  cloud,
52499
52558
  prevLock: lock,
52500
52559
  justInstalledPaths,
@@ -52510,7 +52569,7 @@ async function runAgentPull(cwd2, args) {
52510
52569
  agentMeta: {
52511
52570
  name: cloudAgent.name,
52512
52571
  tagline: cloudAgent.tagline,
52513
- ...cloudAgent.entrypoint ? { entrypoint: cloudAgent.entrypoint } : {}
52572
+ ...cloudAgent.entrypoint ? { entrypoint: cloudAgent.entrypoint.trim() } : {}
52514
52573
  }
52515
52574
  };
52516
52575
  writeSyncState(cwd2, newState);
@@ -52595,7 +52654,7 @@ function runHarnessInstall2(harnessId, components, opts, agentName) {
52595
52654
  return installKafkaWithCtx(components, opts, agentName);
52596
52655
  return getAdapter(harnessId).install(components, opts);
52597
52656
  }
52598
- function materializeInstructions(cwd2, cloud, toInstall, keepLocal) {
52657
+ function materializeInstructions(cwd2, cloud, toInstall, keepLocal, existingManifest) {
52599
52658
  for (const c2 of cloud.components) {
52600
52659
  if (c2.type !== "instruction")
52601
52660
  continue;
@@ -52607,8 +52666,52 @@ function materializeInstructions(cwd2, cloud, toInstall, keepLocal) {
52607
52666
  const body = c2.files[0]?.content ?? "";
52608
52667
  if (!body.trim())
52609
52668
  continue;
52610
- fs45.writeFileSync(path48.join(cwd2, DEFAULT_INSTRUCTIONS_FILE), body, "utf8");
52669
+ if (existingManifest?.instructions?.text !== undefined)
52670
+ continue;
52671
+ const targetRel = existingManifest?.instructions?.file ?? DEFAULT_INSTRUCTIONS_FILE;
52672
+ const target = path48.resolve(cwd2, targetRel);
52673
+ ensureDir(path48.dirname(target));
52674
+ fs45.writeFileSync(target, body, "utf8");
52675
+ }
52676
+ }
52677
+ function materializePlaybooks(cwd2, cloud, toInstall, keepLocal, existingManifest) {
52678
+ for (const c2 of cloud.components) {
52679
+ if (c2.type !== "playbook")
52680
+ continue;
52681
+ const key2 = `${c2.type}/${c2.slug}`;
52682
+ if (keepLocal.has(key2))
52683
+ continue;
52684
+ if (!toInstall.has(key2))
52685
+ continue;
52686
+ const raw = c2.files[0]?.content ?? "";
52687
+ if (!raw.trim())
52688
+ continue;
52689
+ const { body } = stripFrontmatter(raw);
52690
+ const existing = existingManifest?.playbooks?.find((p2) => slugifyForCompare(p2.title) === c2.slug);
52691
+ if (existing?.content?.text !== undefined)
52692
+ continue;
52693
+ const targetRel = existing?.content?.file ?? path48.join(DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`);
52694
+ const target = path48.resolve(cwd2, targetRel);
52695
+ ensureDir(path48.dirname(target));
52696
+ fs45.writeFileSync(target, body, "utf8");
52697
+ }
52698
+ }
52699
+ function slugifyForCompare(s3) {
52700
+ return s3.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "playbook";
52701
+ }
52702
+ function stripFrontmatter(raw) {
52703
+ const m3 = /^---\s*\n([\s\S]*?)\n---\s*\n?/.exec(raw);
52704
+ if (!m3)
52705
+ return { frontmatter: {}, body: raw };
52706
+ let fm = {};
52707
+ try {
52708
+ const parsed = import_yaml3.default.parse(m3[1] ?? "");
52709
+ if (parsed && typeof parsed === "object")
52710
+ fm = parsed;
52711
+ } catch {
52712
+ return { frontmatter: {}, body: raw };
52611
52713
  }
52714
+ return { frontmatter: fm, body: raw.slice(m3[0].length) };
52612
52715
  }
52613
52716
  function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
52614
52717
  const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
@@ -52645,6 +52748,21 @@ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
52645
52748
  else
52646
52749
  entrypoint = { file: prev?.entrypoint?.file ?? DEFAULT_ENTRYPOINT_FILE };
52647
52750
  }
52751
+ const playbooks = cloud.components.filter((c2) => c2.type === "playbook").map((c2) => {
52752
+ const raw = c2.files[0]?.content ?? "";
52753
+ const { frontmatter } = stripFrontmatter(raw);
52754
+ const local = prev?.playbooks?.find((pb) => slugifyForCompare(pb.title) === c2.slug);
52755
+ const title = local?.title ?? (typeof frontmatter.title === "string" && frontmatter.title || c2.slug);
52756
+ const description = local?.description ?? (typeof frontmatter.description === "string" ? frontmatter.description : undefined);
52757
+ const content = local?.content?.text !== undefined ? { text: local.content.text } : {
52758
+ file: local?.content?.file ?? path48.join(DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`)
52759
+ };
52760
+ return {
52761
+ title,
52762
+ ...description ? { description } : {},
52763
+ content
52764
+ };
52765
+ });
52648
52766
  const mcp = cloud.components.filter((c2) => c2.type === "mcp").map((c2) => {
52649
52767
  const payload = (c2.meta ?? {}).mcp ?? {};
52650
52768
  const entry = { name: c2.slug };
@@ -52672,6 +52790,7 @@ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
52672
52790
  },
52673
52791
  ...instructions ? { instructions } : {},
52674
52792
  ...entrypoint ? { entrypoint } : {},
52793
+ playbooks,
52675
52794
  skills,
52676
52795
  mcp
52677
52796
  };
@@ -52707,6 +52826,11 @@ function parseSourceLoose(raw) {
52707
52826
  }
52708
52827
  function buildLockComponents(input) {
52709
52828
  const prevByKey = new Map((input.prevLock?.components ?? []).map((c2) => [`${c2.type}/${c2.slug}`, c2]));
52829
+ const localHashByKey = new Map;
52830
+ for (const lc of readLocalComponents(input.cwd, input.localManifest)) {
52831
+ if (lc.hash)
52832
+ localHashByKey.set(`${lc.type}/${lc.slug}`, lc.hash);
52833
+ }
52710
52834
  const out = [];
52711
52835
  for (const m3 of input.cloud.components) {
52712
52836
  const key2 = `${m3.type}/${m3.slug}`;
@@ -52721,10 +52845,11 @@ function buildLockComponents(input) {
52721
52845
  const parsed = parseSourceLoose(s3.source);
52722
52846
  return parsed?.slug === m3.slug;
52723
52847
  })?.source : undefined;
52848
+ const localHash = localHashByKey.get(key2);
52724
52849
  out.push({
52725
52850
  type: m3.type,
52726
52851
  slug: m3.slug,
52727
- hash: m3.hash,
52852
+ hash: localHash ?? m3.hash,
52728
52853
  installedPaths: input.justInstalledPaths.get(key2) ?? prevByKey.get(key2)?.installedPaths ?? [],
52729
52854
  ...sourceDecl ? { source: sourceDecl } : {}
52730
52855
  });
@@ -52746,7 +52871,7 @@ function buildLockFromCloud(agent_id, cloud, prev, cloudAgent) {
52746
52871
  agentMeta: cloudAgent ? {
52747
52872
  name: cloudAgent.name,
52748
52873
  tagline: cloudAgent.tagline,
52749
- ...cloudAgent.entrypoint ? { entrypoint: cloudAgent.entrypoint } : {}
52874
+ ...cloudAgent.entrypoint ? { entrypoint: cloudAgent.entrypoint.trim() } : {}
52750
52875
  } : prev?.agentMeta
52751
52876
  };
52752
52877
  }
@@ -52910,6 +53035,42 @@ async function buildOutgoingComponents(cwd2, manifest, cloud) {
52910
53035
  }
52911
53036
  });
52912
53037
  }
53038
+ const seenPlaybookSlugs = new Set;
53039
+ for (const entry of manifest.playbooks ?? []) {
53040
+ if (entry.content.text !== undefined && entry.content.file !== undefined) {
53041
+ f2.error(`Playbook ${import_picocolors26.default.bold(entry.title)} sets both ${import_picocolors26.default.cyan("text")} and ${import_picocolors26.default.cyan("file")} — pick one.`);
53042
+ return null;
53043
+ }
53044
+ const body = resolvePlaybookContent(cwd2, entry);
53045
+ if (body === null) {
53046
+ if (entry.content.file) {
53047
+ f2.error(`Playbook ${import_picocolors26.default.bold(entry.title)} content file ${import_picocolors26.default.bold(entry.content.file)} not found.`);
53048
+ } else {
53049
+ f2.error(`Playbook ${import_picocolors26.default.bold(entry.title)} content is empty.`);
53050
+ }
53051
+ return null;
53052
+ }
53053
+ const slug = slugifyPlaybookTitle(entry.title);
53054
+ if (seenPlaybookSlugs.has(slug)) {
53055
+ f2.error(`Two playbooks resolve to the same slug ${import_picocolors26.default.bold(slug)} (from title ${import_picocolors26.default.bold(entry.title)}). Pick distinct titles.`);
53056
+ return null;
53057
+ }
53058
+ seenPlaybookSlugs.add(slug);
53059
+ const wireBody = assemblePlaybookBody(entry, body);
53060
+ const fileName = `${slug}.md`;
53061
+ const fileHash2 = hashString(wireBody);
53062
+ out.push({
53063
+ type: "playbook",
53064
+ slug,
53065
+ description: entry.description,
53066
+ hash: componentHashFromFileHashes([fileHash2]),
53067
+ files: [{ path: fileName, content: wireBody, hash: fileHash2 }],
53068
+ meta: {
53069
+ title: entry.title,
53070
+ ...entry.description ? { description: entry.description } : {}
53071
+ }
53072
+ });
53073
+ }
52913
53074
  for (const entry of manifest.mcp ?? []) {
52914
53075
  if (!entry.url && !entry.command) {
52915
53076
  f2.error(`MCP ${import_picocolors26.default.bold(entry.name)} needs either ${import_picocolors26.default.cyan("url")} or ${import_picocolors26.default.cyan("command")}.`);
@@ -52937,6 +53098,23 @@ async function buildOutgoingComponents(cwd2, manifest, cloud) {
52937
53098
  }
52938
53099
  return out;
52939
53100
  }
53101
+ function assemblePlaybookBody(entry, body) {
53102
+ if (/^---\s*\n/.test(body))
53103
+ return body;
53104
+ const lines = ["---", `title: ${yamlScalar(entry.title)}`];
53105
+ if (entry.description) {
53106
+ lines.push(`description: ${yamlScalar(entry.description)}`);
53107
+ }
53108
+ lines.push("---", "");
53109
+ return lines.join(`
53110
+ `) + body.replace(/^\n+/, "");
53111
+ }
53112
+ function yamlScalar(s3) {
53113
+ if (!/[\n":#&*!|>'%@`{}[\]]/.test(s3) && s3.trim() === s3 && s3 !== "") {
53114
+ return s3;
53115
+ }
53116
+ return JSON.stringify(s3);
53117
+ }
52940
53118
 
52941
53119
  // src/cli/agent-push.ts
52942
53120
  async function runAgentPush(cwd2, args) {
@@ -53001,10 +53179,10 @@ async function runAgentPush(cwd2, args) {
53001
53179
  resolvedEntrypoint = "";
53002
53180
  }
53003
53181
  }
53004
- const entrypointChanged = resolvedEntrypoint !== undefined && resolvedEntrypoint !== (lock?.agentMeta?.entrypoint ?? "");
53182
+ const entrypointChanged = resolvedEntrypoint !== undefined && (resolvedEntrypoint ?? "").trim() !== (lock?.agentMeta?.entrypoint ?? "").trim();
53005
53183
  for (const r2 of rows) {
53006
- if (r2.type !== "instruction" && r2.type !== "skill" && r2.type !== "mcp") {
53007
- f2.error(`Component ${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)} can't be pushed yet — the server accepts instructions, skills, and mcps in this version.`);
53184
+ if (r2.type !== "instruction" && r2.type !== "skill" && r2.type !== "mcp" && r2.type !== "playbook") {
53185
+ f2.error(`Component ${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)} can't be pushed yet — the server accepts instructions, skills, mcps, and playbooks in this version.`);
53008
53186
  return;
53009
53187
  }
53010
53188
  }
@@ -53137,6 +53315,11 @@ async function runAgentPush(cwd2, args) {
53137
53315
  tagline: manifest.agent.tagline
53138
53316
  });
53139
53317
  }
53318
+ const localHashByKey = new Map;
53319
+ for (const lc of localComponents) {
53320
+ if (lc.hash)
53321
+ localHashByKey.set(`${lc.type}/${lc.slug}`, lc.hash);
53322
+ }
53140
53323
  const newLock = {
53141
53324
  schemaVersion: 1,
53142
53325
  agent_id: agentId,
@@ -53152,10 +53335,11 @@ async function runAgentPush(cwd2, args) {
53152
53335
  }
53153
53336
  })?.source;
53154
53337
  const prior = lock?.components.find((pc26) => pc26.type === c2.type && pc26.slug === c2.slug);
53338
+ const localHash = localHashByKey.get(`${c2.type}/${c2.slug}`);
53155
53339
  return {
53156
53340
  type: c2.type,
53157
53341
  slug: c2.slug,
53158
- hash: c2.hash,
53342
+ hash: localHash ?? c2.hash,
53159
53343
  installedPaths: prior?.installedPaths ?? [],
53160
53344
  ...decl ? { source: decl } : {}
53161
53345
  };
@@ -53163,7 +53347,7 @@ async function runAgentPush(cwd2, args) {
53163
53347
  agentMeta: {
53164
53348
  name: manifest.agent.name,
53165
53349
  tagline: manifest.agent.tagline,
53166
- entrypoint: resolvedEntrypoint !== undefined ? resolvedEntrypoint : lock?.agentMeta?.entrypoint
53350
+ entrypoint: resolvedEntrypoint !== undefined ? resolvedEntrypoint.trim() : lock?.agentMeta?.entrypoint
53167
53351
  }
53168
53352
  };
53169
53353
  writeSyncState(cwd2, newLock);
@@ -53667,10 +53851,15 @@ async function runAgentCreate(cwd2, args) {
53667
53851
  }
53668
53852
  }
53669
53853
  if (updatedCloud) {
53854
+ const localHashByKey = new Map;
53855
+ for (const lc of readLocalComponents(cwd2, manifest)) {
53856
+ if (lc.hash)
53857
+ localHashByKey.set(`${lc.type}/${lc.slug}`, lc.hash);
53858
+ }
53670
53859
  const syncedComponents = updatedCloud.components.map((c2) => ({
53671
53860
  type: c2.type,
53672
53861
  slug: c2.slug,
53673
- hash: c2.hash,
53862
+ hash: localHashByKey.get(`${c2.type}/${c2.slug}`) ?? c2.hash,
53674
53863
  installedPaths: []
53675
53864
  }));
53676
53865
  const state = {
@@ -53682,7 +53871,7 @@ async function runAgentCreate(cwd2, args) {
53682
53871
  agentMeta: {
53683
53872
  name: agent.name,
53684
53873
  tagline: agent.tagline,
53685
- ...resolvedEntrypoint ? { entrypoint: resolvedEntrypoint } : {}
53874
+ ...resolvedEntrypoint ? { entrypoint: resolvedEntrypoint.trim() } : {}
53686
53875
  }
53687
53876
  };
53688
53877
  writeSyncState(cwd2, state);
@@ -53731,6 +53920,7 @@ async function loadOrScaffoldManifest(cwd2, args) {
53731
53920
  schema: 1,
53732
53921
  ...seedHarness ? { harness: seedHarness } : {},
53733
53922
  agent: { name: seedName, ...args.tagline ? { tagline: args.tagline } : {} },
53923
+ playbooks: [],
53734
53924
  skills: [],
53735
53925
  mcp: []
53736
53926
  };
@@ -53774,183 +53964,10 @@ function handleApiError4(err) {
53774
53964
  }
53775
53965
 
53776
53966
  // src/cli/agent-unpack.ts
53777
- var import_picocolors31 = __toESM(require_picocolors(), 1);
53778
-
53779
- // src/core/agent-fresh-install.ts
53780
53967
  import path50 from "node:path";
53781
53968
  import fs46 from "node:fs";
53782
53969
  import os13 from "node:os";
53783
- async function installAgentFresh(input) {
53784
- const { cwd: cwd2, agent, cloud, harness } = input;
53785
- const scope = input.scope ?? "project";
53786
- ensureDir(cwd2);
53787
- const stageRoot = stageManifestComponents2(cloud.components);
53788
- const justInstalledPaths = new Map;
53789
- const cloudHasOrchestrationMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === ORCHESTRATION_MCP_SLUG);
53790
- const needOrchestrationMcpInstall = !cloudHasOrchestrationMcp;
53791
- const cloudHasMemoryMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === MEMORY_MCP_SLUG);
53792
- const needMemoryMcpInstall = !cloudHasMemoryMcp;
53793
- try {
53794
- if (cloud.components.length > 0 || needOrchestrationMcpInstall || needMemoryMcpInstall) {
53795
- const toInstall = cloud.components.map((c2) => ({
53796
- type: c2.type,
53797
- slug: c2.slug,
53798
- scope,
53799
- rootDir: path50.join(stageRoot, c2.type, c2.slug),
53800
- description: c2.description,
53801
- meta: c2.meta,
53802
- payload: c2.meta?.mcp,
53803
- checksum: c2.hash
53804
- }));
53805
- if (needOrchestrationMcpInstall) {
53806
- toInstall.push(buildOrchestrationMcpComponent(scope));
53807
- }
53808
- if (needMemoryMcpInstall) {
53809
- toInstall.push(buildMemoryMcpComponent(scope));
53810
- }
53811
- const installOpts = {
53812
- cwd: cwd2,
53813
- scope,
53814
- resolveConflict: async (_c) => "overwrite",
53815
- resolveSecret: async () => null
53816
- };
53817
- const result = await runHarnessInstall3(harness, toInstall, installOpts, agent.name);
53818
- for (const o2 of result.installed) {
53819
- justInstalledPaths.set(`${o2.type}/${o2.slug}`, o2.installedPaths);
53820
- }
53821
- }
53822
- materializeInstructions2(cwd2, cloud);
53823
- const manifest = input.preserveManifest ? null : buildManifestFromCloud(cloud, agent);
53824
- if (manifest)
53825
- writeManifest(cwd2, manifest);
53826
- writeLink(cwd2, {
53827
- schemaVersion: 1,
53828
- agent_id: agent.id,
53829
- org_id: agent.org_id,
53830
- team_id: agent.team_id,
53831
- slug: agent.slug,
53832
- name: agent.name,
53833
- tagline: agent.tagline,
53834
- url: agent.url,
53835
- linked_at: new Date().toISOString(),
53836
- harness
53837
- });
53838
- const syncedComponents = cloud.components.map((c2) => ({
53839
- type: c2.type,
53840
- slug: c2.slug,
53841
- hash: c2.hash,
53842
- installedPaths: justInstalledPaths.get(`${c2.type}/${c2.slug}`) ?? []
53843
- }));
53844
- writeSyncState(cwd2, {
53845
- schemaVersion: 1,
53846
- agent_id: agent.id,
53847
- revision: cloud.revision,
53848
- synced_at: new Date().toISOString(),
53849
- components: syncedComponents,
53850
- agentMeta: { name: agent.name, tagline: agent.tagline }
53851
- });
53852
- if (input.pullSecrets !== false) {
53853
- await pullAgentSecrets(cwd2, agent.id);
53854
- }
53855
- const returnedManifest = manifest ?? buildManifestFromCloud(cloud, agent);
53856
- return {
53857
- installedPaths: justInstalledPaths,
53858
- manifest: returnedManifest,
53859
- syncedComponents
53860
- };
53861
- } finally {
53862
- try {
53863
- fs46.rmSync(stageRoot, { recursive: true, force: true });
53864
- } catch {}
53865
- }
53866
- }
53867
- function stageManifestComponents2(components) {
53868
- const root = fs46.mkdtempSync(path50.join(os13.tmpdir(), "brainbase-orch-pull-"));
53869
- for (const c2 of components) {
53870
- const compDir = path50.join(root, c2.type, c2.slug);
53871
- ensureDir(compDir);
53872
- for (const f4 of c2.files) {
53873
- const target = path50.join(compDir, f4.path);
53874
- ensureDir(path50.dirname(target));
53875
- fs46.writeFileSync(target, f4.content);
53876
- }
53877
- }
53878
- return root;
53879
- }
53880
- function runHarnessInstall3(harnessId, components, opts, agentName) {
53881
- if (harnessId === "claude-code")
53882
- return installClaudeCodeWithCtx(components, opts, agentName);
53883
- if (harnessId === "codex")
53884
- return installCodexWithCtx(components, opts, agentName);
53885
- if (harnessId === "kafka")
53886
- return installKafkaWithCtx(components, opts, agentName);
53887
- return getAdapter(harnessId).install(components, opts);
53888
- }
53889
- function materializeInstructions2(cwd2, cloud) {
53890
- for (const c2 of cloud.components) {
53891
- if (c2.type !== "instruction")
53892
- continue;
53893
- const body = c2.files[0]?.content ?? "";
53894
- if (!body.trim())
53895
- continue;
53896
- fs46.writeFileSync(path50.join(cwd2, DEFAULT_INSTRUCTIONS_FILE), body, "utf8");
53897
- return;
53898
- }
53899
- }
53900
- function buildManifestFromCloud(cloud, agent) {
53901
- const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
53902
- const meta = c2.meta ?? {};
53903
- if (meta.name && meta.name.includes("/")) {
53904
- return {
53905
- source: meta.version ? `registry:${meta.name}@${meta.version}` : `registry:${meta.name}`
53906
- };
53907
- }
53908
- return { source: `registry:${c2.slug}` };
53909
- });
53910
- const hasInstructions = cloud.components.some((c2) => c2.type === "instruction" && c2.files[0]?.content?.trim());
53911
- const mcp = cloud.components.filter((c2) => c2.type === "mcp").map((c2) => {
53912
- const payload = (c2.meta ?? {}).mcp ?? {};
53913
- const entry = { name: c2.slug };
53914
- if (typeof payload.url === "string")
53915
- entry.url = payload.url;
53916
- if (typeof payload.command === "string")
53917
- entry.command = payload.command;
53918
- if (Array.isArray(payload.args))
53919
- entry.args = payload.args.map(String);
53920
- if (payload.env && typeof payload.env === "object")
53921
- entry.env = payload.env;
53922
- if (payload.headers && typeof payload.headers === "object")
53923
- entry.headers = payload.headers;
53924
- if (typeof payload.is_enabled === "boolean")
53925
- entry.is_enabled = payload.is_enabled;
53926
- return entry;
53927
- });
53928
- return {
53929
- schema: 1,
53930
- agent: {
53931
- name: agent.name,
53932
- ...agent.tagline ? { tagline: agent.tagline } : {}
53933
- },
53934
- ...hasInstructions ? { instructions: { file: DEFAULT_INSTRUCTIONS_FILE } } : {},
53935
- skills,
53936
- mcp
53937
- };
53938
- }
53939
- async function pullAgentSecrets(cwd2, agentId) {
53940
- try {
53941
- const res = await api.getAgentSecrets(agentId);
53942
- const secrets = res.secrets ?? {};
53943
- if (Object.keys(secrets).length > 0) {
53944
- writeLocalSecrets(cwd2, secrets);
53945
- }
53946
- } catch (err) {
53947
- if (err instanceof ApiError && err.status !== 404) {
53948
- f2.warn(`Skipped secrets for agent ${agentId}: ${err.message}`);
53949
- }
53950
- }
53951
- }
53952
-
53953
- // src/cli/agent-unpack.ts
53970
+ var import_picocolors31 = __toESM(require_picocolors(), 1);
53954
53971
  async function runAgentUnpack(cwd2, args) {
53955
53972
  banner("agent unpack — install this agent into a harness layout");
53956
53973
  if (!hasManifest(cwd2)) {
@@ -53982,22 +53999,9 @@ async function runAgentUnpack(cwd2, args) {
53982
53999
  } else {
53983
54000
  harness = await pickHarness2(manifest.harness);
53984
54001
  }
53985
- const sp = de();
53986
- sp.start("Fetching agent…");
53987
- let cloudAgent;
53988
- let cloud;
53989
- try {
53990
- cloudAgent = await api.getAgent(manifest.id);
53991
- cloud = await api.getAgentManifest(manifest.id);
53992
- sp.stop(`Cloud revision ${cloud.revision}.`);
53993
- } catch (err) {
53994
- sp.stop("Failed.");
53995
- handleApiError5(err);
53996
- return;
53997
- }
53998
54002
  if (!args.yes) {
53999
54003
  const ok = await se({
54000
- message: `Install ${import_picocolors31.default.bold(cloudAgent.name)} as ${import_picocolors31.default.bold(harness)} here?`,
54004
+ message: `Install ${import_picocolors31.default.bold(manifest.agent.name)} as ${import_picocolors31.default.bold(harness)} here?`,
54001
54005
  initialValue: true
54002
54006
  });
54003
54007
  if (!ensureNotCancelled(ok)) {
@@ -54005,46 +54009,206 @@ async function runAgentUnpack(cwd2, args) {
54005
54009
  return;
54006
54010
  }
54007
54011
  }
54008
- const prevLink = readLink(cwd2);
54012
+ const scope = args.scope ?? "project";
54013
+ const stageRoot = fs46.mkdtempSync(path50.join(os13.tmpdir(), "brainbase-unpack-"));
54009
54014
  try {
54010
- await installAgentFresh({
54011
- cwd: cwd2,
54012
- agent: {
54013
- id: cloudAgent.id,
54014
- name: cloudAgent.name,
54015
- slug: cloudAgent.slug,
54016
- tagline: cloudAgent.tagline,
54017
- org_id: cloudAgent.org_id ?? prevLink?.org_id ?? "",
54018
- team_id: cloudAgent.team_id ?? prevLink?.team_id ?? "",
54019
- url: cloudAgent.url,
54020
- harness
54021
- },
54022
- cloud,
54023
- harness,
54024
- scope: args.scope ?? "project",
54025
- preserveManifest: true
54026
- });
54015
+ const toInstall = [];
54016
+ const instructionsBody = readInstructions(cwd2, manifest);
54017
+ if (instructionsBody && instructionsBody.trim()) {
54018
+ const compDir = path50.join(stageRoot, "instruction", "agent-instructions");
54019
+ ensureDir(compDir);
54020
+ fs46.writeFileSync(path50.join(compDir, "instructions.md"), instructionsBody, "utf8");
54021
+ toInstall.push({
54022
+ type: "instruction",
54023
+ slug: "agent-instructions",
54024
+ scope,
54025
+ rootDir: compDir,
54026
+ description: "Agent instructions",
54027
+ checksum: ""
54028
+ });
54029
+ }
54030
+ for (const entry of manifest.playbooks ?? []) {
54031
+ const issue = stageLocalPlaybook(entry, cwd2, stageRoot, scope, toInstall);
54032
+ if (issue) {
54033
+ f2.warn(issue);
54034
+ }
54035
+ }
54036
+ for (const entry of manifest.skills ?? []) {
54037
+ const issue = stageLocalSkill(entry.source, cwd2, stageRoot, scope, toInstall);
54038
+ if (issue) {
54039
+ f2.warn(issue);
54040
+ }
54041
+ }
54042
+ for (const entry of manifest.mcp ?? []) {
54043
+ const compDir = path50.join(stageRoot, "mcp", entry.name);
54044
+ ensureDir(compDir);
54045
+ const payload = {};
54046
+ if (entry.url !== undefined)
54047
+ payload.url = entry.url;
54048
+ if (entry.command !== undefined)
54049
+ payload.command = entry.command;
54050
+ if (entry.args !== undefined)
54051
+ payload.args = entry.args;
54052
+ if (entry.env !== undefined)
54053
+ payload.env = entry.env;
54054
+ if (entry.headers !== undefined)
54055
+ payload.headers = entry.headers;
54056
+ payload.is_enabled = entry.is_enabled ?? true;
54057
+ toInstall.push({
54058
+ type: "mcp",
54059
+ slug: entry.name,
54060
+ scope,
54061
+ rootDir: compDir,
54062
+ payload,
54063
+ checksum: ""
54064
+ });
54065
+ }
54066
+ const haveOrchMcp = (manifest.mcp ?? []).some((m3) => m3.name === ORCHESTRATION_MCP_SLUG);
54067
+ const haveMemoryMcp = (manifest.mcp ?? []).some((m3) => m3.name === MEMORY_MCP_SLUG);
54068
+ if (!haveOrchMcp)
54069
+ toInstall.push(buildOrchestrationMcpComponent(scope));
54070
+ if (!haveMemoryMcp)
54071
+ toInstall.push(buildMemoryMcpComponent(scope));
54072
+ const opts = {
54073
+ cwd: cwd2,
54074
+ scope,
54075
+ resolveConflict: async (_c) => "overwrite",
54076
+ resolveSecret: async () => null
54077
+ };
54078
+ const sp = de();
54079
+ sp.start("Installing harness layout…");
54080
+ const result = await runHarnessInstall3(harness, toInstall, opts, manifest.agent.name);
54081
+ sp.stop("Installed.");
54082
+ if (result.skipped.length) {
54083
+ f2.warn(`Skipped: ${result.skipped.map((s3) => `${s3.type}/${s3.slug} (${s3.reason})`).join(", ")}`);
54084
+ }
54027
54085
  } catch (err) {
54028
54086
  f2.error(`Install failed: ${err.message}`);
54029
54087
  return;
54088
+ } finally {
54089
+ try {
54090
+ fs46.rmSync(stageRoot, { recursive: true, force: true });
54091
+ } catch {}
54030
54092
  }
54031
- manifest = readManifest(cwd2);
54032
54093
  if (manifest.harness !== harness) {
54033
54094
  manifest.harness = harness;
54034
54095
  writeManifest(cwd2, manifest);
54035
54096
  }
54036
- $e(`Unpacked ${import_picocolors31.default.bold(cloudAgent.name)} as ${import_picocolors31.default.bold(harness)}.`);
54097
+ $e(`Unpacked ${import_picocolors31.default.bold(manifest.agent.name)} as ${import_picocolors31.default.bold(harness)}.`);
54037
54098
  await showResultCard({
54038
54099
  title: "UNPACKED",
54039
54100
  tone: "ok",
54040
- subtitle: cloudAgent.name,
54101
+ subtitle: manifest.agent.name,
54041
54102
  meta: [
54042
54103
  ["harness", harness],
54043
- ["agent", cloudAgent.id],
54044
- ...cloudAgent.url ? [["url", cloudAgent.url]] : []
54104
+ ["agent", manifest.id]
54045
54105
  ]
54046
54106
  });
54047
54107
  }
54108
+ function stageLocalPlaybook(entry, cwd2, stageRoot, scope, toInstall) {
54109
+ if (entry.content.text !== undefined && entry.content.file !== undefined) {
54110
+ return `Playbook ${entry.title}: both text and file set — skipped.`;
54111
+ }
54112
+ const body = resolvePlaybookContent(cwd2, entry);
54113
+ if (body === null) {
54114
+ return entry.content.file ? `Playbook ${entry.title}: file ${entry.content.file} not found — skipped.` : `Playbook ${entry.title}: content empty — skipped.`;
54115
+ }
54116
+ const slug = slugifyPlaybookTitle(entry.title);
54117
+ const compDir = path50.join(stageRoot, "playbook", slug);
54118
+ ensureDir(compDir);
54119
+ const wireBody = /^---\s*\n/.test(body) ? body : assembleFrontmatter(entry.title, entry.description) + body.replace(/^\n+/, "");
54120
+ fs46.writeFileSync(path50.join(compDir, `${slug}.md`), wireBody, "utf8");
54121
+ toInstall.push({
54122
+ type: "playbook",
54123
+ slug,
54124
+ scope,
54125
+ rootDir: compDir,
54126
+ description: entry.description,
54127
+ checksum: ""
54128
+ });
54129
+ return null;
54130
+ }
54131
+ function stageLocalSkill(source, cwd2, stageRoot, scope, toInstall) {
54132
+ if (source.startsWith("./") || source.startsWith("../") || source.startsWith("/")) {
54133
+ const abs = path50.resolve(cwd2, source);
54134
+ if (!fs46.existsSync(abs)) {
54135
+ return `Skill ${source}: not found on disk — skipped.`;
54136
+ }
54137
+ const slug = path50.basename(abs);
54138
+ const compDir = path50.join(stageRoot, "skill", slug);
54139
+ ensureDir(compDir);
54140
+ copyDirRecursive(abs, compDir);
54141
+ toInstall.push({
54142
+ type: "skill",
54143
+ slug,
54144
+ scope,
54145
+ rootDir: compDir,
54146
+ checksum: ""
54147
+ });
54148
+ return null;
54149
+ }
54150
+ try {
54151
+ const parsed = parseSkillSource(source);
54152
+ if (parsed.type === "local" || parsed.type === "inline")
54153
+ return null;
54154
+ const slug = defaultSlugForSource(source);
54155
+ const compDir = path50.join(stageRoot, "skill", slug);
54156
+ ensureDir(compDir);
54157
+ toInstall.push({
54158
+ type: "skill",
54159
+ slug,
54160
+ scope,
54161
+ rootDir: compDir,
54162
+ source: parsed,
54163
+ checksum: ""
54164
+ });
54165
+ return null;
54166
+ } catch (err) {
54167
+ return `Skill ${source}: ${err.message} — skipped.`;
54168
+ }
54169
+ }
54170
+ function defaultSlugForSource(source) {
54171
+ const reg = /^registry:(?:[a-z0-9_-]+\/)?([a-z0-9_-]+)/i.exec(source);
54172
+ if (reg)
54173
+ return reg[1].toLowerCase();
54174
+ const gh = /^(?:github|git):[^/]*\/?([a-z0-9_-]+)/i.exec(source);
54175
+ if (gh)
54176
+ return gh[1].toLowerCase();
54177
+ return source.replace(/[^a-z0-9_-]/gi, "-").slice(0, 60) || "skill";
54178
+ }
54179
+ function copyDirRecursive(src, dest) {
54180
+ ensureDir(dest);
54181
+ for (const entry of fs46.readdirSync(src, { withFileTypes: true })) {
54182
+ const s3 = path50.join(src, entry.name);
54183
+ const d3 = path50.join(dest, entry.name);
54184
+ if (entry.isDirectory())
54185
+ copyDirRecursive(s3, d3);
54186
+ else if (entry.isFile())
54187
+ fs46.copyFileSync(s3, d3);
54188
+ }
54189
+ }
54190
+ function assembleFrontmatter(title, description) {
54191
+ const lines = ["---", `title: ${yamlScalar2(title)}`];
54192
+ if (description)
54193
+ lines.push(`description: ${yamlScalar2(description)}`);
54194
+ lines.push("---", "");
54195
+ return lines.join(`
54196
+ `);
54197
+ }
54198
+ function yamlScalar2(s3) {
54199
+ if (!/[\n":#&*!|>'%@`{}[\]]/.test(s3) && s3.trim() === s3 && s3 !== "")
54200
+ return s3;
54201
+ return JSON.stringify(s3);
54202
+ }
54203
+ function runHarnessInstall3(harnessId, components, opts, agentName) {
54204
+ if (harnessId === "claude-code")
54205
+ return installClaudeCodeWithCtx(components, opts, agentName);
54206
+ if (harnessId === "codex")
54207
+ return installCodexWithCtx(components, opts, agentName);
54208
+ if (harnessId === "kafka")
54209
+ return installKafkaWithCtx(components, opts, agentName);
54210
+ return getAdapter(harnessId).install(components, opts);
54211
+ }
54048
54212
  async function pickHarness2(current) {
54049
54213
  const initial = current ? normalizeHarnessId(current) : undefined;
54050
54214
  const choice = await ie({
@@ -54058,19 +54222,6 @@ async function pickHarness2(current) {
54058
54222
  });
54059
54223
  return ensureNotCancelled(choice);
54060
54224
  }
54061
- function handleApiError5(err) {
54062
- if (err instanceof ApiError) {
54063
- if (err.status === 401) {
54064
- f2.error("Your session is invalid. Run `brainbase login` and try again.");
54065
- } else if (err.status === 404) {
54066
- f2.error(`Agent not found, or you don't have access. The id in ${import_picocolors31.default.bold(AGENT_MANIFEST_FILE)} may be stale.`);
54067
- } else {
54068
- f2.error(err.message);
54069
- }
54070
- } else {
54071
- f2.error(err.message);
54072
- }
54073
- }
54074
54225
 
54075
54226
  // src/cli/agent.ts
54076
54227
  async function runAgent(cwd2, sub, args, opts) {
@@ -54143,14 +54294,14 @@ function printHelp() {
54143
54294
  var import_picocolors37 = __toESM(require_picocolors(), 1);
54144
54295
 
54145
54296
  // src/cli/orchestration-pull.ts
54146
- import path53 from "node:path";
54147
- import fs49 from "node:fs";
54297
+ import path54 from "node:path";
54298
+ import fs50 from "node:fs";
54148
54299
  var import_picocolors33 = __toESM(require_picocolors(), 1);
54149
54300
 
54150
54301
  // src/core/orchestration-manifest.ts
54151
54302
  import path51 from "node:path";
54152
54303
  import fs47 from "node:fs";
54153
- var import_yaml3 = __toESM(require_dist(), 1);
54304
+ var import_yaml4 = __toESM(require_dist(), 1);
54154
54305
  var ORCH_MANIFEST_FILE = "brainbase-orchestration.yaml";
54155
54306
  var ORCH_MEMBERS_DIR = "agents";
54156
54307
  var OrchMetaSchema = exports_external.object({
@@ -54189,7 +54340,7 @@ function readOrchManifest(cwd2) {
54189
54340
  const raw = fs47.readFileSync(p2, "utf8");
54190
54341
  let parsed;
54191
54342
  try {
54192
- parsed = import_yaml3.default.parse(raw);
54343
+ parsed = import_yaml4.default.parse(raw);
54193
54344
  } catch (err) {
54194
54345
  throw new Error(`${ORCH_MANIFEST_FILE} is not valid YAML: ${err.message}`);
54195
54346
  }
@@ -54200,7 +54351,7 @@ function readOrchManifest(cwd2) {
54200
54351
  return result.data;
54201
54352
  }
54202
54353
  function writeOrchManifest(cwd2, manifest) {
54203
- const doc = new import_yaml3.default.Document;
54354
+ const doc = new import_yaml4.default.Document;
54204
54355
  doc.contents = manifest;
54205
54356
  doc.commentBefore = ` brainbase-orchestration.yaml — declarative orchestration manifest.
54206
54357
  ` + ` Committed to source control. Edit by hand, then
@@ -54305,6 +54456,181 @@ function ensureGitignore2(cwd2) {
54305
54456
  } catch {}
54306
54457
  }
54307
54458
 
54459
+ // src/core/agent-fresh-install.ts
54460
+ import path53 from "node:path";
54461
+ import fs49 from "node:fs";
54462
+ import os14 from "node:os";
54463
+ async function installAgentFresh(input) {
54464
+ const { cwd: cwd2, agent, cloud, harness } = input;
54465
+ const scope = input.scope ?? "project";
54466
+ ensureDir(cwd2);
54467
+ const stageRoot = stageManifestComponents2(cloud.components);
54468
+ const justInstalledPaths = new Map;
54469
+ const cloudHasOrchestrationMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === ORCHESTRATION_MCP_SLUG);
54470
+ const needOrchestrationMcpInstall = !cloudHasOrchestrationMcp;
54471
+ const cloudHasMemoryMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === MEMORY_MCP_SLUG);
54472
+ const needMemoryMcpInstall = !cloudHasMemoryMcp;
54473
+ try {
54474
+ if (cloud.components.length > 0 || needOrchestrationMcpInstall || needMemoryMcpInstall) {
54475
+ const toInstall = cloud.components.map((c2) => ({
54476
+ type: c2.type,
54477
+ slug: c2.slug,
54478
+ scope,
54479
+ rootDir: path53.join(stageRoot, c2.type, c2.slug),
54480
+ description: c2.description,
54481
+ meta: c2.meta,
54482
+ payload: c2.meta?.mcp,
54483
+ checksum: c2.hash
54484
+ }));
54485
+ if (needOrchestrationMcpInstall) {
54486
+ toInstall.push(buildOrchestrationMcpComponent(scope));
54487
+ }
54488
+ if (needMemoryMcpInstall) {
54489
+ toInstall.push(buildMemoryMcpComponent(scope));
54490
+ }
54491
+ const installOpts = {
54492
+ cwd: cwd2,
54493
+ scope,
54494
+ resolveConflict: async (_c) => "overwrite",
54495
+ resolveSecret: async () => null
54496
+ };
54497
+ const result = await runHarnessInstall4(harness, toInstall, installOpts, agent.name);
54498
+ for (const o2 of result.installed) {
54499
+ justInstalledPaths.set(`${o2.type}/${o2.slug}`, o2.installedPaths);
54500
+ }
54501
+ }
54502
+ materializeInstructions2(cwd2, cloud);
54503
+ const manifest = input.preserveManifest ? null : buildManifestFromCloud(cloud, agent);
54504
+ if (manifest)
54505
+ writeManifest(cwd2, manifest);
54506
+ writeLink(cwd2, {
54507
+ schemaVersion: 1,
54508
+ agent_id: agent.id,
54509
+ org_id: agent.org_id,
54510
+ team_id: agent.team_id,
54511
+ slug: agent.slug,
54512
+ name: agent.name,
54513
+ tagline: agent.tagline,
54514
+ url: agent.url,
54515
+ linked_at: new Date().toISOString(),
54516
+ harness
54517
+ });
54518
+ const syncedComponents = cloud.components.map((c2) => ({
54519
+ type: c2.type,
54520
+ slug: c2.slug,
54521
+ hash: c2.hash,
54522
+ installedPaths: justInstalledPaths.get(`${c2.type}/${c2.slug}`) ?? []
54523
+ }));
54524
+ writeSyncState(cwd2, {
54525
+ schemaVersion: 1,
54526
+ agent_id: agent.id,
54527
+ revision: cloud.revision,
54528
+ synced_at: new Date().toISOString(),
54529
+ components: syncedComponents,
54530
+ agentMeta: { name: agent.name, tagline: agent.tagline }
54531
+ });
54532
+ if (input.pullSecrets !== false) {
54533
+ await pullAgentSecrets(cwd2, agent.id);
54534
+ }
54535
+ const returnedManifest = manifest ?? buildManifestFromCloud(cloud, agent);
54536
+ return {
54537
+ installedPaths: justInstalledPaths,
54538
+ manifest: returnedManifest,
54539
+ syncedComponents
54540
+ };
54541
+ } finally {
54542
+ try {
54543
+ fs49.rmSync(stageRoot, { recursive: true, force: true });
54544
+ } catch {}
54545
+ }
54546
+ }
54547
+ function stageManifestComponents2(components) {
54548
+ const root = fs49.mkdtempSync(path53.join(os14.tmpdir(), "brainbase-orch-pull-"));
54549
+ for (const c2 of components) {
54550
+ const compDir = path53.join(root, c2.type, c2.slug);
54551
+ ensureDir(compDir);
54552
+ for (const f4 of c2.files) {
54553
+ const target = path53.join(compDir, f4.path);
54554
+ ensureDir(path53.dirname(target));
54555
+ fs49.writeFileSync(target, f4.content);
54556
+ }
54557
+ }
54558
+ return root;
54559
+ }
54560
+ function runHarnessInstall4(harnessId, components, opts, agentName) {
54561
+ if (harnessId === "claude-code")
54562
+ return installClaudeCodeWithCtx(components, opts, agentName);
54563
+ if (harnessId === "codex")
54564
+ return installCodexWithCtx(components, opts, agentName);
54565
+ if (harnessId === "kafka")
54566
+ return installKafkaWithCtx(components, opts, agentName);
54567
+ return getAdapter(harnessId).install(components, opts);
54568
+ }
54569
+ function materializeInstructions2(cwd2, cloud) {
54570
+ for (const c2 of cloud.components) {
54571
+ if (c2.type !== "instruction")
54572
+ continue;
54573
+ const body = c2.files[0]?.content ?? "";
54574
+ if (!body.trim())
54575
+ continue;
54576
+ fs49.writeFileSync(path53.join(cwd2, DEFAULT_INSTRUCTIONS_FILE), body, "utf8");
54577
+ return;
54578
+ }
54579
+ }
54580
+ function buildManifestFromCloud(cloud, agent) {
54581
+ const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
54582
+ const meta = c2.meta ?? {};
54583
+ if (meta.name && meta.name.includes("/")) {
54584
+ return {
54585
+ source: meta.version ? `registry:${meta.name}@${meta.version}` : `registry:${meta.name}`
54586
+ };
54587
+ }
54588
+ return { source: `registry:${c2.slug}` };
54589
+ });
54590
+ const hasInstructions = cloud.components.some((c2) => c2.type === "instruction" && c2.files[0]?.content?.trim());
54591
+ const mcp = cloud.components.filter((c2) => c2.type === "mcp").map((c2) => {
54592
+ const payload = (c2.meta ?? {}).mcp ?? {};
54593
+ const entry = { name: c2.slug };
54594
+ if (typeof payload.url === "string")
54595
+ entry.url = payload.url;
54596
+ if (typeof payload.command === "string")
54597
+ entry.command = payload.command;
54598
+ if (Array.isArray(payload.args))
54599
+ entry.args = payload.args.map(String);
54600
+ if (payload.env && typeof payload.env === "object")
54601
+ entry.env = payload.env;
54602
+ if (payload.headers && typeof payload.headers === "object")
54603
+ entry.headers = payload.headers;
54604
+ if (typeof payload.is_enabled === "boolean")
54605
+ entry.is_enabled = payload.is_enabled;
54606
+ return entry;
54607
+ });
54608
+ return {
54609
+ schema: 1,
54610
+ agent: {
54611
+ name: agent.name,
54612
+ ...agent.tagline ? { tagline: agent.tagline } : {}
54613
+ },
54614
+ ...hasInstructions ? { instructions: { file: DEFAULT_INSTRUCTIONS_FILE } } : {},
54615
+ playbooks: [],
54616
+ skills,
54617
+ mcp
54618
+ };
54619
+ }
54620
+ async function pullAgentSecrets(cwd2, agentId) {
54621
+ try {
54622
+ const res = await api.getAgentSecrets(agentId);
54623
+ const secrets = res.secrets ?? {};
54624
+ if (Object.keys(secrets).length > 0) {
54625
+ writeLocalSecrets(cwd2, secrets);
54626
+ }
54627
+ } catch (err) {
54628
+ if (err instanceof ApiError && err.status !== 404) {
54629
+ f2.warn(`Skipped secrets for agent ${agentId}: ${err.message}`);
54630
+ }
54631
+ }
54632
+ }
54633
+
54308
54634
  // src/cli/orchestration-pull.ts
54309
54635
  async function runOrchestrationPull(cwd2, args) {
54310
54636
  banner("orchestration pull — fetch orchestration + all member agents");
@@ -54328,7 +54654,7 @@ async function runOrchestrationPull(cwd2, args) {
54328
54654
  sp.stop(`Cloud revision ${cloud.revision} — ${cloud.members.length} member${cloud.members.length === 1 ? "" : "s"}, ${cloud.edges.length} edge${cloud.edges.length === 1 ? "" : "s"}.`);
54329
54655
  } catch (err) {
54330
54656
  sp.stop("Failed.");
54331
- handleApiError6(err);
54657
+ handleApiError5(err);
54332
54658
  return;
54333
54659
  }
54334
54660
  const planLines = [];
@@ -54368,7 +54694,7 @@ async function runOrchestrationPull(cwd2, args) {
54368
54694
  }
54369
54695
  }
54370
54696
  const fallbackHarness = args.harness ?? "claude-code";
54371
- fs49.mkdirSync(cwd2, { recursive: true });
54697
+ fs50.mkdirSync(cwd2, { recursive: true });
54372
54698
  if (hasOrchManifest(cwd2) && existingLink && existingLink.orchestration_id !== orchId) {
54373
54699
  f2.error(`This folder is linked to orchestration ${existingLink.orchestration_id}, not ${orchId}. Move to a fresh directory or unlink first.`);
54374
54700
  return;
@@ -54455,9 +54781,9 @@ async function runOrchestrationPull(cwd2, args) {
54455
54781
  payload_schema: e2.payload_schema ?? {}
54456
54782
  }))
54457
54783
  });
54458
- $e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path53.basename(cwd2)}/ ${import_picocolors33.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
54784
+ $e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path54.basename(cwd2)}/ ${import_picocolors33.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
54459
54785
  }
54460
- function handleApiError6(err) {
54786
+ function handleApiError5(err) {
54461
54787
  if (err instanceof ApiError) {
54462
54788
  if (err.status === 401) {
54463
54789
  f2.error("Your session is invalid. Run `brainbase login` and try again.");
@@ -54602,10 +54928,10 @@ async function runOrchestrationPush(cwd2, args) {
54602
54928
  $e(`Pushed ${link2.name} at revision ${updated.revision}.`);
54603
54929
  } catch (err) {
54604
54930
  sp.stop("Failed.");
54605
- handleApiError7(err);
54931
+ handleApiError6(err);
54606
54932
  }
54607
54933
  }
54608
- function handleApiError7(err) {
54934
+ function handleApiError6(err) {
54609
54935
  if (err instanceof ApiError) {
54610
54936
  if (err.status === 401) {
54611
54937
  f2.error("Your session is invalid. Run `brainbase login` and try again.");
@@ -54736,7 +55062,7 @@ async function runOrchestrationList(args) {
54736
55062
  try {
54737
55063
  orgs = await api.listOrgs();
54738
55064
  } catch (err) {
54739
- handleApiError8(err);
55065
+ handleApiError7(err);
54740
55066
  return;
54741
55067
  }
54742
55068
  if (orgs.length === 0) {
@@ -54758,7 +55084,7 @@ async function runOrchestrationList(args) {
54758
55084
  try {
54759
55085
  teams = await api.listTeams(orgId);
54760
55086
  } catch (err) {
54761
- handleApiError8(err);
55087
+ handleApiError7(err);
54762
55088
  return;
54763
55089
  }
54764
55090
  if (teams.length === 0) {
@@ -54783,7 +55109,7 @@ async function runOrchestrationList(args) {
54783
55109
  sp.stop(`${items.length} orchestration${items.length === 1 ? "" : "s"}.`);
54784
55110
  } catch (err) {
54785
55111
  sp.stop("Failed.");
54786
- handleApiError8(err);
55112
+ handleApiError7(err);
54787
55113
  return;
54788
55114
  }
54789
55115
  if (items.length === 0) {
@@ -54803,7 +55129,7 @@ async function runOrchestrationList(args) {
54803
55129
  console.log(lines.join(`
54804
55130
  `));
54805
55131
  }
54806
- function handleApiError8(err) {
55132
+ function handleApiError7(err) {
54807
55133
  if (err instanceof ApiError) {
54808
55134
  if (err.status === 401) {
54809
55135
  f2.error("Your session is invalid. Run `brainbase login` and try again.");
@@ -55608,7 +55934,7 @@ var PROTECTED = new Set([
55608
55934
  function help() {
55609
55935
  const out = [];
55610
55936
  out.push("");
55611
- out.push(` ${brandTint("◆")} ${import_picocolors40.default.bold("brainbase")} ${import_picocolors40.default.dim("v0.5.0")}`);
55937
+ out.push(` ${brandTint("◆")} ${import_picocolors40.default.bold("brainbase")} ${import_picocolors40.default.dim("v0.6.1")}`);
55612
55938
  out.push(` ${import_picocolors40.default.dim("connect your local agent to the brainbase platform")}`);
55613
55939
  out.push("");
55614
55940
  out.push(divider("USAGE"));
@@ -55751,7 +56077,7 @@ async function main() {
55751
56077
  const rawCwd = process13.cwd();
55752
56078
  const cwd2 = (() => {
55753
56079
  try {
55754
- return fs50.realpathSync(rawCwd);
56080
+ return fs51.realpathSync(rawCwd);
55755
56081
  } catch {
55756
56082
  return rawCwd;
55757
56083
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainbase-labs/cli",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
5
5
  "type": "module",
6
6
  "bin": {