@brainbase-labs/cli 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1426 -773
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -28564,7 +28564,7 @@ var require_jsx_dev_runtime = __commonJS((exports, module) => {
28564
28564
  });
28565
28565
 
28566
28566
  // src/index.ts
28567
- var import_picocolors38 = __toESM(require_picocolors(), 1);
28567
+ var import_picocolors40 = __toESM(require_picocolors(), 1);
28568
28568
  import process13 from "node:process";
28569
28569
  import fs50 from "node:fs";
28570
28570
 
@@ -33782,7 +33782,7 @@ var BrainbaseSourceSchema = exports_external.object({
33782
33782
  type: exports_external.literal("brainbase"),
33783
33783
  creator: exports_external.string().regex(/^[a-z0-9_-]+$/i),
33784
33784
  slug: exports_external.string().regex(/^[a-z0-9_-]+$/i),
33785
- version: exports_external.string().regex(/^\d+\.\d+\.\d+$/)
33785
+ version: exports_external.string().regex(/^\d+\.\d+\.\d+$/).optional()
33786
33786
  });
33787
33787
  var InlineSourceSchema = exports_external.object({ type: exports_external.literal("inline") });
33788
33788
  var LocalSourceSchema = exports_external.object({ type: exports_external.literal("local") });
@@ -48541,7 +48541,7 @@ function parseSkillSource(input) {
48541
48541
  type: "brainbase",
48542
48542
  creator: bb[1],
48543
48543
  slug: bb[2],
48544
- version: bb[3] ?? "0.0.0"
48544
+ version: bb[3]
48545
48545
  };
48546
48546
  }
48547
48547
  if (s3.startsWith("file://") || s3.startsWith("./") || s3.startsWith("../") || s3.startsWith("/") || s3.startsWith("~")) {
@@ -48616,7 +48616,7 @@ function describeSource(source) {
48616
48616
  case "git":
48617
48617
  return `git:${source.url}${source.ref ? "@" + source.ref : ""}${source.subpath ? " (" + source.subpath + ")" : ""}`;
48618
48618
  case "brainbase":
48619
- return `brainbase://${source.creator}/${source.slug}@${source.version}`;
48619
+ return `brainbase://${source.creator}/${source.slug}${source.version ? "@" + source.version : " (latest)"}`;
48620
48620
  }
48621
48621
  }
48622
48622
 
@@ -49722,14 +49722,24 @@ var brainbaseResolver = {
49722
49722
  if (source.type !== "brainbase") {
49723
49723
  throw new Error("expected brainbase source");
49724
49724
  }
49725
- const remoteVersion = await skillsApi.getVersion(source.creator, source.slug, source.version);
49725
+ let version = source.version;
49726
+ if (!version) {
49727
+ const pkg = await skillsApi.getPackage(source.creator, source.slug);
49728
+ const latest = pkg.latest_version;
49729
+ if (!latest) {
49730
+ throw new Error(`${source.creator}/${source.slug} has no published versions`);
49731
+ }
49732
+ version = latest.version;
49733
+ source.version = version;
49734
+ }
49735
+ const remoteVersion = await skillsApi.getVersion(source.creator, source.slug, version);
49726
49736
  if (remoteVersion.yanked) {
49727
- throw new Error(`${source.creator}/${source.slug}@${source.version} has been yanked${remoteVersion.yanked_reason ? ": " + remoteVersion.yanked_reason : ""}`);
49737
+ throw new Error(`${source.creator}/${source.slug}@${version} has been yanked${remoteVersion.yanked_reason ? ": " + remoteVersion.yanked_reason : ""}`);
49728
49738
  }
49729
49739
  const tmp = fs33.mkdtempSync(path36.join(os8.tmpdir(), "bb-skill-"));
49730
49740
  const tarPath = path36.join(tmp, "skill.tgz");
49731
49741
  try {
49732
- await skillsApi.downloadTarball(source.creator, source.slug, source.version, tarPath);
49742
+ await skillsApi.downloadTarball(source.creator, source.slug, version, tarPath);
49733
49743
  await verifyTarball(tarPath, remoteVersion.bundle_sha256);
49734
49744
  ensureDir(destDir);
49735
49745
  await extract({ tarFile: tarPath, outDir: destDir });
@@ -50749,11 +50759,164 @@ async function runWhoami() {
50749
50759
  var import_picocolors22 = __toESM(require_picocolors(), 1);
50750
50760
 
50751
50761
  // src/core/link.ts
50762
+ import path43 from "node:path";
50763
+ import fs40 from "node:fs";
50764
+
50765
+ // src/core/agent-manifest.ts
50752
50766
  import path42 from "node:path";
50753
50767
  import fs39 from "node:fs";
50768
+ var import_yaml2 = __toESM(require_dist(), 1);
50769
+ var AGENT_MANIFEST_FILE = "brainbase.agent.yaml";
50770
+ var LEGACY_AGENT_MANIFEST_FILE = "brainbase.yaml";
50771
+ var DEFAULT_INSTRUCTIONS_FILE = "instructions.md";
50772
+ var DEFAULT_ENTRYPOINT_FILE = "entrypoint.sh";
50773
+ var REGISTRY_SOURCE_RE = /^registry:(?:([a-z0-9_-]+)\/)?([a-z0-9_-]+)(?:@(.+))?$/i;
50774
+ function parseSkillSource2(raw) {
50775
+ if (!raw || typeof raw !== "string") {
50776
+ throw new Error("Skill source must be a non-empty string");
50777
+ }
50778
+ const m3 = raw.match(REGISTRY_SOURCE_RE);
50779
+ if (m3) {
50780
+ return {
50781
+ kind: "registry",
50782
+ ...m3[1] ? { creator: m3[1] } : {},
50783
+ slug: m3[2],
50784
+ version: m3[3]
50785
+ };
50786
+ }
50787
+ if (raw.startsWith("./") || raw.startsWith("../") || raw.startsWith("/")) {
50788
+ return { kind: "local", path: raw };
50789
+ }
50790
+ throw new Error(`Unrecognized skill source "${raw}". Expected "registry:creator/slug[@version]", "registry:slug", or a relative path starting with "./".`);
50791
+ }
50792
+ var AgentMetaSchema = exports_external.object({
50793
+ name: exports_external.string().min(1),
50794
+ tagline: exports_external.string().optional()
50795
+ });
50796
+ var InstructionsSchema = exports_external.object({
50797
+ file: exports_external.string().min(1).optional(),
50798
+ text: exports_external.string().optional()
50799
+ }).refine((v3) => v3.file !== undefined || v3.text !== undefined, {
50800
+ message: "instructions must set either `file` or `text`"
50801
+ });
50802
+ var EntrypointSchema = exports_external.object({
50803
+ file: exports_external.string().min(1).optional(),
50804
+ commands: exports_external.array(exports_external.string().min(1)).optional(),
50805
+ text: exports_external.string().optional()
50806
+ }).refine((v3) => {
50807
+ const set = [v3.file, v3.commands, v3.text].filter((x3) => x3 !== undefined);
50808
+ return set.length === 1;
50809
+ }, {
50810
+ message: "entrypoint must set exactly one of `file`, `commands`, or `text`"
50811
+ });
50812
+ var SkillEntrySchema = exports_external.object({
50813
+ source: exports_external.string().min(1)
50814
+ });
50815
+ var McpEntrySchema = exports_external.object({
50816
+ name: exports_external.string().min(1),
50817
+ url: exports_external.string().optional(),
50818
+ command: exports_external.string().optional(),
50819
+ args: exports_external.array(exports_external.string()).optional(),
50820
+ env: exports_external.record(exports_external.string()).optional(),
50821
+ headers: exports_external.record(exports_external.string()).optional(),
50822
+ is_enabled: exports_external.boolean().optional()
50823
+ });
50824
+ var AgentManifestSchema = exports_external.object({
50825
+ schema: exports_external.literal(1),
50826
+ id: exports_external.string().min(1).optional(),
50827
+ harness: exports_external.string().min(1).optional(),
50828
+ agent: AgentMetaSchema,
50829
+ instructions: InstructionsSchema.optional(),
50830
+ entrypoint: EntrypointSchema.optional(),
50831
+ skills: exports_external.array(SkillEntrySchema).default([]),
50832
+ mcp: exports_external.array(McpEntrySchema).default([]),
50833
+ commands: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
50834
+ hooks: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
50835
+ files: exports_external.array(exports_external.record(exports_external.unknown())).optional()
50836
+ });
50837
+ function manifestPath(cwd2) {
50838
+ return path42.join(cwd2, AGENT_MANIFEST_FILE);
50839
+ }
50840
+ function existingManifestPath(cwd2) {
50841
+ const newPath = path42.join(cwd2, AGENT_MANIFEST_FILE);
50842
+ if (fs39.existsSync(newPath))
50843
+ return newPath;
50844
+ const legacy = path42.join(cwd2, LEGACY_AGENT_MANIFEST_FILE);
50845
+ if (fs39.existsSync(legacy))
50846
+ return legacy;
50847
+ return null;
50848
+ }
50849
+ function hasManifest(cwd2) {
50850
+ return existingManifestPath(cwd2) !== null;
50851
+ }
50852
+ function readManifest(cwd2) {
50853
+ const p2 = existingManifestPath(cwd2);
50854
+ if (!p2)
50855
+ return null;
50856
+ const raw = fs39.readFileSync(p2, "utf8");
50857
+ let parsed;
50858
+ try {
50859
+ parsed = import_yaml2.default.parse(raw);
50860
+ } catch (err) {
50861
+ throw new Error(`${path42.basename(p2)} is not valid YAML: ${err.message}`);
50862
+ }
50863
+ const result = AgentManifestSchema.safeParse(parsed);
50864
+ if (!result.success) {
50865
+ throw new Error(`${path42.basename(p2)} is invalid: ${result.error.issues.map((i) => `${i.path.join(".") || "(root)"} — ${i.message}`).join("; ")}`);
50866
+ }
50867
+ return result.data;
50868
+ }
50869
+ function writeManifest(cwd2, manifest) {
50870
+ const doc = new import_yaml2.default.Document;
50871
+ doc.contents = manifest;
50872
+ doc.commentBefore = ` brainbase.agent.yaml — declarative agent manifest.
50873
+ ` + " Committed to source control. Edit by hand, then `brainbase agent push`.";
50874
+ const out = String(doc);
50875
+ fs39.writeFileSync(manifestPath(cwd2), out, "utf8");
50876
+ }
50877
+ function resolveInstructionsPath(cwd2, manifest) {
50878
+ if (!manifest.instructions?.file)
50879
+ return null;
50880
+ return path42.resolve(cwd2, manifest.instructions.file);
50881
+ }
50882
+ function readInstructions(cwd2, manifest) {
50883
+ if (!manifest.instructions)
50884
+ return null;
50885
+ if (typeof manifest.instructions.text === "string") {
50886
+ return manifest.instructions.text;
50887
+ }
50888
+ const p2 = resolveInstructionsPath(cwd2, manifest);
50889
+ if (!p2 || !fs39.existsSync(p2))
50890
+ return null;
50891
+ return fs39.readFileSync(p2, "utf8");
50892
+ }
50893
+ function resolveEntrypoint(cwd2, manifest) {
50894
+ const ep = manifest.entrypoint;
50895
+ if (!ep)
50896
+ return null;
50897
+ if (typeof ep.text === "string")
50898
+ return ep.text;
50899
+ if (Array.isArray(ep.commands)) {
50900
+ if (ep.commands.length === 0)
50901
+ return null;
50902
+ return ["set -euo pipefail", ...ep.commands].join(`
50903
+ `) + `
50904
+ `;
50905
+ }
50906
+ if (typeof ep.file === "string") {
50907
+ const p2 = path42.resolve(cwd2, ep.file);
50908
+ if (!fs39.existsSync(p2))
50909
+ return null;
50910
+ return fs39.readFileSync(p2, "utf8");
50911
+ }
50912
+ return null;
50913
+ }
50914
+
50915
+ // src/core/link.ts
50754
50916
  var LINK_DIR = ".brainbase";
50755
- var LINK_FILE = "link.json";
50917
+ var STATE_FILE = "state.json";
50756
50918
  var SYNC_STATE_FILE = "sync-state.json";
50919
+ var LEGACY_LINK_FILE = "link.json";
50757
50920
  var TrackingSchema = exports_external.object({
50758
50921
  harness: exports_external.string(),
50759
50922
  key_id: exports_external.string(),
@@ -50776,6 +50939,16 @@ var LinkSchema = exports_external.object({
50776
50939
  harness: exports_external.string().nullish().transform((v3) => v3 ?? undefined),
50777
50940
  tracking: TrackingSchema.nullish().transform((v3) => v3 ?? undefined)
50778
50941
  });
50942
+ var LinkStateSchema = exports_external.object({
50943
+ schemaVersion: exports_external.literal(1),
50944
+ org_id: exports_external.string().default(""),
50945
+ team_id: exports_external.string().default(""),
50946
+ slug: exports_external.string().default(""),
50947
+ url: exports_external.string().nullish().transform((v3) => v3 ?? undefined),
50948
+ linked_at: exports_external.string(),
50949
+ linked_by: exports_external.string().nullish().transform((v3) => v3 ?? undefined),
50950
+ tracking: TrackingSchema.nullish().transform((v3) => v3 ?? undefined)
50951
+ });
50779
50952
  var SyncedComponentSchema = exports_external.object({
50780
50953
  type: exports_external.string(),
50781
50954
  slug: exports_external.string(),
@@ -50785,7 +50958,8 @@ var SyncedComponentSchema = exports_external.object({
50785
50958
  });
50786
50959
  var AgentMetaSnapshotSchema = exports_external.object({
50787
50960
  name: exports_external.string(),
50788
- tagline: exports_external.string().optional()
50961
+ tagline: exports_external.string().optional(),
50962
+ entrypoint: exports_external.string().optional()
50789
50963
  });
50790
50964
  var SyncStateSchema = exports_external.object({
50791
50965
  schemaVersion: exports_external.literal(1),
@@ -50795,39 +50969,157 @@ var SyncStateSchema = exports_external.object({
50795
50969
  components: exports_external.array(SyncedComponentSchema),
50796
50970
  agentMeta: AgentMetaSnapshotSchema.optional()
50797
50971
  });
50798
- function linkPath(cwd2) {
50799
- return path42.join(cwd2, LINK_DIR, LINK_FILE);
50972
+ function statePath(cwd2) {
50973
+ return path43.join(cwd2, LINK_DIR, STATE_FILE);
50800
50974
  }
50801
50975
  function syncStatePath(cwd2) {
50802
- return path42.join(cwd2, LINK_DIR, SYNC_STATE_FILE);
50976
+ return path43.join(cwd2, LINK_DIR, SYNC_STATE_FILE);
50977
+ }
50978
+ function legacyLinkPath(cwd2) {
50979
+ return path43.join(cwd2, LINK_DIR, LEGACY_LINK_FILE);
50980
+ }
50981
+ function readState(cwd2) {
50982
+ const p2 = statePath(cwd2);
50983
+ if (exists(p2)) {
50984
+ try {
50985
+ return LinkStateSchema.parse(readJson(p2));
50986
+ } catch {
50987
+ return null;
50988
+ }
50989
+ }
50990
+ const legacy = legacyLinkPath(cwd2);
50991
+ if (exists(legacy)) {
50992
+ try {
50993
+ const raw = readJson(legacy);
50994
+ const lifted = {
50995
+ schemaVersion: 1,
50996
+ org_id: String(raw.org_id ?? ""),
50997
+ team_id: String(raw.team_id ?? ""),
50998
+ slug: String(raw.slug ?? ""),
50999
+ url: typeof raw.url === "string" ? raw.url : undefined,
51000
+ linked_at: typeof raw.linked_at === "string" ? raw.linked_at : new Date().toISOString(),
51001
+ linked_by: typeof raw.linked_by === "string" ? raw.linked_by : undefined,
51002
+ tracking: (() => {
51003
+ try {
51004
+ return TrackingSchema.parse(raw.tracking);
51005
+ } catch {
51006
+ return;
51007
+ }
51008
+ })()
51009
+ };
51010
+ try {
51011
+ ensureDir(path43.join(cwd2, LINK_DIR));
51012
+ writeJson(statePath(cwd2), lifted);
51013
+ ensureGitignore(cwd2);
51014
+ } catch {}
51015
+ return lifted;
51016
+ } catch {
51017
+ return null;
51018
+ }
51019
+ }
51020
+ return null;
51021
+ }
51022
+ function writeState(cwd2, state) {
51023
+ ensureDir(path43.join(cwd2, LINK_DIR));
51024
+ writeJson(statePath(cwd2), state);
51025
+ ensureGitignore(cwd2);
50803
51026
  }
50804
51027
  function readLink(cwd2) {
50805
- const p2 = linkPath(cwd2);
50806
- if (!exists(p2))
50807
- return null;
51028
+ let manifest = null;
50808
51029
  try {
50809
- return LinkSchema.parse(readJson(p2));
51030
+ manifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
50810
51031
  } catch {
50811
- return null;
51032
+ manifest = null;
51033
+ }
51034
+ const state = readState(cwd2);
51035
+ if (manifest?.id) {
51036
+ return {
51037
+ schemaVersion: 1,
51038
+ agent_id: manifest.id,
51039
+ org_id: state?.org_id ?? "",
51040
+ team_id: state?.team_id ?? "",
51041
+ slug: state?.slug ?? "",
51042
+ name: manifest.agent.name,
51043
+ tagline: manifest.agent.tagline,
51044
+ url: state?.url,
51045
+ linked_at: state?.linked_at ?? new Date().toISOString(),
51046
+ linked_by: state?.linked_by,
51047
+ harness: manifest.harness,
51048
+ tracking: state?.tracking
51049
+ };
51050
+ }
51051
+ const legacy = legacyLinkPath(cwd2);
51052
+ if (exists(legacy)) {
51053
+ try {
51054
+ return LinkSchema.parse(readJson(legacy));
51055
+ } catch {
51056
+ return null;
51057
+ }
50812
51058
  }
51059
+ return null;
50813
51060
  }
50814
51061
  function writeLink(cwd2, link2) {
50815
- ensureDir(path42.join(cwd2, LINK_DIR));
50816
- const clean = {};
50817
- for (const [k3, v3] of Object.entries(link2)) {
50818
- if (v3 !== null && v3 !== undefined)
50819
- clean[k3] = v3;
51062
+ let manifest;
51063
+ try {
51064
+ manifest = readManifest(cwd2) ?? {
51065
+ schema: 1,
51066
+ agent: { name: link2.name },
51067
+ skills: [],
51068
+ mcp: []
51069
+ };
51070
+ } catch {
51071
+ manifest = {
51072
+ schema: 1,
51073
+ agent: { name: link2.name },
51074
+ skills: [],
51075
+ mcp: []
51076
+ };
51077
+ }
51078
+ manifest.id = link2.agent_id;
51079
+ if (link2.harness)
51080
+ manifest.harness = link2.harness;
51081
+ manifest.agent.name = link2.name;
51082
+ if (link2.tagline)
51083
+ manifest.agent.tagline = link2.tagline;
51084
+ else
51085
+ delete manifest.agent.tagline;
51086
+ writeManifest(cwd2, manifest);
51087
+ const state = {
51088
+ schemaVersion: 1,
51089
+ org_id: link2.org_id,
51090
+ team_id: link2.team_id,
51091
+ slug: link2.slug,
51092
+ url: link2.url,
51093
+ linked_at: link2.linked_at,
51094
+ linked_by: link2.linked_by,
51095
+ tracking: link2.tracking
51096
+ };
51097
+ writeState(cwd2, state);
51098
+ const legacy = legacyLinkPath(cwd2);
51099
+ if (exists(legacy)) {
51100
+ try {
51101
+ fs40.rmSync(legacy);
51102
+ } catch {}
50820
51103
  }
50821
- writeJson(linkPath(cwd2), clean);
50822
- ensureGitignore(cwd2);
50823
51104
  }
50824
51105
  function clearLink(cwd2) {
50825
- const p2 = linkPath(cwd2);
51106
+ try {
51107
+ const m3 = hasManifest(cwd2) ? readManifest(cwd2) : null;
51108
+ if (m3) {
51109
+ delete m3.id;
51110
+ delete m3.harness;
51111
+ writeManifest(cwd2, m3);
51112
+ }
51113
+ } catch {}
51114
+ const p2 = statePath(cwd2);
50826
51115
  if (exists(p2))
50827
- fs39.rmSync(p2);
51116
+ fs40.rmSync(p2);
50828
51117
  const sp = syncStatePath(cwd2);
50829
51118
  if (exists(sp))
50830
- fs39.rmSync(sp);
51119
+ fs40.rmSync(sp);
51120
+ const legacy = legacyLinkPath(cwd2);
51121
+ if (exists(legacy))
51122
+ fs40.rmSync(legacy);
50831
51123
  }
50832
51124
  function readSyncState(cwd2) {
50833
51125
  const p2 = syncStatePath(cwd2);
@@ -50840,22 +51132,22 @@ function readSyncState(cwd2) {
50840
51132
  }
50841
51133
  }
50842
51134
  function writeSyncState(cwd2, state) {
50843
- ensureDir(path42.join(cwd2, LINK_DIR));
51135
+ ensureDir(path43.join(cwd2, LINK_DIR));
50844
51136
  writeJson(syncStatePath(cwd2), state);
50845
51137
  ensureGitignore(cwd2);
50846
51138
  }
50847
51139
  function ensureGitignore(cwd2) {
50848
- const ignorePath = path42.join(cwd2, LINK_DIR, ".gitignore");
50849
- const desired = `${SYNC_STATE_FILE}
50850
- `;
51140
+ const ignorePath = path43.join(cwd2, LINK_DIR, ".gitignore");
51141
+ const desired = ["*", `!.gitignore`, ""].join(`
51142
+ `);
50851
51143
  try {
50852
51144
  if (!exists(ignorePath)) {
50853
- fs39.writeFileSync(ignorePath, desired);
51145
+ fs40.writeFileSync(ignorePath, desired);
50854
51146
  return;
50855
51147
  }
50856
- const current = fs39.readFileSync(ignorePath, "utf8");
50857
- if (!current.split(/\r?\n/).some((l2) => l2.trim() === SYNC_STATE_FILE)) {
50858
- fs39.writeFileSync(ignorePath, current.endsWith(`
51148
+ const current = fs40.readFileSync(ignorePath, "utf8");
51149
+ if (!current.split(/\r?\n/).some((l2) => l2.trim() === "*")) {
51150
+ fs40.writeFileSync(ignorePath, current.endsWith(`
50859
51151
  `) ? current + desired : current + `
50860
51152
  ` + desired);
50861
51153
  }
@@ -50863,15 +51155,15 @@ function ensureGitignore(cwd2) {
50863
51155
  }
50864
51156
 
50865
51157
  // src/core/route-adapters.ts
50866
- import path43 from "node:path";
51158
+ import path44 from "node:path";
50867
51159
  import os10 from "node:os";
50868
- import fs40 from "node:fs";
51160
+ import fs41 from "node:fs";
50869
51161
  var CLAUDE_ENV_KEYS = ["ANTHROPIC_BASE_URL", "ANTHROPIC_AUTH_TOKEN"];
50870
51162
  function claudeSettingsPath(cwd2) {
50871
- return path43.join(cwd2, ".claude", "settings.json");
51163
+ return path44.join(cwd2, ".claude", "settings.json");
50872
51164
  }
50873
51165
  function claudeUserConfigPath() {
50874
- return path43.join(os10.homedir(), ".claude.json");
51166
+ return path44.join(os10.homedir(), ".claude.json");
50875
51167
  }
50876
51168
  function ensureClaudeOnboarded() {
50877
51169
  const file = claudeUserConfigPath();
@@ -50895,7 +51187,7 @@ var claudeRouteAdapter = {
50895
51187
  settings.env = { ...settings.env ?? {} };
50896
51188
  settings.env.ANTHROPIC_BASE_URL = target.apiBase;
50897
51189
  settings.env.ANTHROPIC_AUTH_TOKEN = target.apiKey;
50898
- ensureDir(path43.dirname(file));
51190
+ ensureDir(path44.dirname(file));
50899
51191
  writeJson(file, settings);
50900
51192
  const notes = [];
50901
51193
  if (ensureClaudeOnboarded()) {
@@ -50922,11 +51214,11 @@ var claudeRouteAdapter = {
50922
51214
  delete settings.env;
50923
51215
  }
50924
51216
  if (snap && !snap.fileExisted && Object.keys(settings).length === 0) {
50925
- fs40.rmSync(file);
50926
- const dir = path43.dirname(file);
51217
+ fs41.rmSync(file);
51218
+ const dir = path44.dirname(file);
50927
51219
  try {
50928
- if (fs40.readdirSync(dir).length === 0)
50929
- fs40.rmdirSync(dir);
51220
+ if (fs41.readdirSync(dir).length === 0)
51221
+ fs41.rmdirSync(dir);
50930
51222
  } catch {}
50931
51223
  return;
50932
51224
  }
@@ -50936,20 +51228,20 @@ var claudeRouteAdapter = {
50936
51228
  var CODEX_PROVIDER_KEY = "brainbase";
50937
51229
  var CODEX_AUTH_HEADER = "Authorization";
50938
51230
  function codexConfigPath(cwd2) {
50939
- return path43.join(cwd2, ".codex", "config.toml");
51231
+ return path44.join(cwd2, ".codex", "config.toml");
50940
51232
  }
50941
51233
  function readCodexConfig2(file) {
50942
51234
  if (!exists(file))
50943
51235
  return {};
50944
51236
  try {
50945
- return parse(fs40.readFileSync(file, "utf8"));
51237
+ return parse(fs41.readFileSync(file, "utf8"));
50946
51238
  } catch {
50947
51239
  return {};
50948
51240
  }
50949
51241
  }
50950
51242
  function writeCodexConfig2(file, value) {
50951
- ensureDir(path43.dirname(file));
50952
- fs40.writeFileSync(file, stringify(value) + `
51243
+ ensureDir(path44.dirname(file));
51244
+ fs41.writeFileSync(file, stringify(value) + `
50953
51245
  `);
50954
51246
  }
50955
51247
  function ensureV1(base2) {
@@ -51005,11 +51297,11 @@ var codexRouteAdapter = {
51005
51297
  }
51006
51298
  }
51007
51299
  if (snap && !snap.fileExisted && Object.keys(cfg).length === 0) {
51008
- fs40.rmSync(file);
51009
- const dir = path43.dirname(file);
51300
+ fs41.rmSync(file);
51301
+ const dir = path44.dirname(file);
51010
51302
  try {
51011
- if (fs40.readdirSync(dir).length === 0)
51012
- fs40.rmdirSync(dir);
51303
+ if (fs41.readdirSync(dir).length === 0)
51304
+ fs41.rmdirSync(dir);
51013
51305
  } catch {}
51014
51306
  return;
51015
51307
  }
@@ -51299,8 +51591,8 @@ async function runUnlink(cwd2, args) {
51299
51591
  }
51300
51592
 
51301
51593
  // src/cli/sync.ts
51302
- import path44 from "node:path";
51303
- import fs41 from "node:fs";
51594
+ import path45 from "node:path";
51595
+ import fs42 from "node:fs";
51304
51596
  import os11 from "node:os";
51305
51597
  import crypto3 from "node:crypto";
51306
51598
  var import_picocolors24 = __toESM(require_picocolors(), 1);
@@ -51494,7 +51786,7 @@ async function runSync(cwd2, args) {
51494
51786
  type: c2.type,
51495
51787
  slug: c2.slug,
51496
51788
  scope,
51497
- rootDir: path44.join(stageRoot, c2.type, c2.slug),
51789
+ rootDir: path45.join(stageRoot, c2.type, c2.slug),
51498
51790
  description: c2.description,
51499
51791
  meta: c2.meta,
51500
51792
  payload: c2.meta?.mcp,
@@ -51543,11 +51835,11 @@ async function runSync(cwd2, args) {
51543
51835
  if (!exists(filePath))
51544
51836
  continue;
51545
51837
  try {
51546
- const stat = fs41.statSync(filePath);
51838
+ const stat = fs42.statSync(filePath);
51547
51839
  if (stat.isDirectory())
51548
- fs41.rmSync(filePath, { recursive: true, force: true });
51840
+ fs42.rmSync(filePath, { recursive: true, force: true });
51549
51841
  else
51550
- fs41.rmSync(filePath);
51842
+ fs42.rmSync(filePath);
51551
51843
  } catch (err) {
51552
51844
  f2.warn(`Failed to remove ${filePath}: ${err.message}`);
51553
51845
  }
@@ -51585,7 +51877,7 @@ async function runSync(cwd2, args) {
51585
51877
  $e(`Synced ${link2.name} to revision ${manifest.revision}.`);
51586
51878
  } finally {
51587
51879
  try {
51588
- fs41.rmSync(stageRoot, { recursive: true, force: true });
51880
+ fs42.rmSync(stageRoot, { recursive: true, force: true });
51589
51881
  } catch {}
51590
51882
  }
51591
51883
  }
@@ -51633,14 +51925,14 @@ function computeLocalHash(paths) {
51633
51925
  if (!exists(filePath))
51634
51926
  return null;
51635
51927
  try {
51636
- const stat = fs41.statSync(filePath);
51928
+ const stat = fs42.statSync(filePath);
51637
51929
  if (stat.isFile()) {
51638
51930
  h2.update("F " + filePath + " ");
51639
- h2.update(fs41.readFileSync(filePath));
51931
+ h2.update(fs42.readFileSync(filePath));
51640
51932
  h2.update(`
51641
51933
  `);
51642
51934
  } else if (stat.isDirectory()) {
51643
- for (const name of fs41.readdirSync(filePath).sort()) {
51935
+ for (const name of fs42.readdirSync(filePath).sort()) {
51644
51936
  h2.update("E " + name + `
51645
51937
  `);
51646
51938
  }
@@ -51652,14 +51944,14 @@ function computeLocalHash(paths) {
51652
51944
  return h2.digest("hex");
51653
51945
  }
51654
51946
  function stageManifest(components) {
51655
- const root = fs41.mkdtempSync(path44.join(os11.tmpdir(), "brainbase-sync-"));
51947
+ const root = fs42.mkdtempSync(path45.join(os11.tmpdir(), "brainbase-sync-"));
51656
51948
  for (const c2 of components) {
51657
- const compDir = path44.join(root, c2.type, c2.slug);
51949
+ const compDir = path45.join(root, c2.type, c2.slug);
51658
51950
  ensureDir(compDir);
51659
51951
  for (const f4 of c2.files) {
51660
- const target = path44.join(compDir, f4.path);
51661
- ensureDir(path44.dirname(target));
51662
- fs41.writeFileSync(target, f4.content);
51952
+ const target = path45.join(compDir, f4.path);
51953
+ ensureDir(path45.dirname(target));
51954
+ fs42.writeFileSync(target, f4.content);
51663
51955
  }
51664
51956
  }
51665
51957
  return root;
@@ -51673,142 +51965,46 @@ function runHarnessInstall(harnessId, components, opts, agentName) {
51673
51965
  }
51674
51966
 
51675
51967
  // src/cli/agent.ts
51676
- var import_picocolors30 = __toESM(require_picocolors(), 1);
51968
+ var import_picocolors32 = __toESM(require_picocolors(), 1);
51677
51969
 
51678
51970
  // src/cli/agent-pull.ts
51971
+ import { spawn as spawn2 } from "node:child_process";
51679
51972
  import path48 from "node:path";
51680
51973
  import fs45 from "node:fs";
51681
51974
  import os12 from "node:os";
51682
51975
  var import_picocolors25 = __toESM(require_picocolors(), 1);
51683
51976
 
51684
- // src/core/agent-manifest.ts
51685
- import path45 from "node:path";
51686
- import fs42 from "node:fs";
51687
- var import_yaml2 = __toESM(require_dist(), 1);
51688
- var AGENT_MANIFEST_FILE = "brainbase.yaml";
51689
- var DEFAULT_INSTRUCTIONS_FILE = "instructions.md";
51690
- var REGISTRY_SOURCE_RE = /^registry:(?:([a-z0-9_-]+)\/)?([a-z0-9_-]+)(?:@(.+))?$/i;
51691
- function parseSkillSource2(raw) {
51692
- if (!raw || typeof raw !== "string") {
51693
- throw new Error("Skill source must be a non-empty string");
51977
+ // src/core/agent-diff.ts
51978
+ import path46 from "node:path";
51979
+ import fs43 from "node:fs";
51980
+ import crypto4 from "node:crypto";
51981
+ function compKey(type, slug) {
51982
+ return `${type}/${slug}`;
51983
+ }
51984
+ function hashString(s3) {
51985
+ return crypto4.createHash("sha256").update(s3).digest("hex");
51986
+ }
51987
+ function canonicalJson(value) {
51988
+ if (value === null)
51989
+ return "null";
51990
+ if (typeof value === "boolean")
51991
+ return value ? "true" : "false";
51992
+ if (typeof value === "number") {
51993
+ if (!Number.isFinite(value))
51994
+ throw new Error("Non-finite numbers are not JSON");
51995
+ return String(value);
51694
51996
  }
51695
- const m3 = raw.match(REGISTRY_SOURCE_RE);
51696
- if (m3) {
51697
- return {
51698
- kind: "registry",
51699
- ...m3[1] ? { creator: m3[1] } : {},
51700
- slug: m3[2],
51701
- version: m3[3]
51702
- };
51997
+ if (typeof value === "string")
51998
+ return JSON.stringify(value);
51999
+ if (Array.isArray(value)) {
52000
+ return "[" + value.map(canonicalJson).join(",") + "]";
51703
52001
  }
51704
- if (raw.startsWith("./") || raw.startsWith("../") || raw.startsWith("/")) {
51705
- return { kind: "local", path: raw };
52002
+ if (typeof value === "object") {
52003
+ const obj = value;
52004
+ const keys = Object.keys(obj).sort();
52005
+ return "{" + keys.map((k3) => `${JSON.stringify(k3)}:${canonicalJson(obj[k3])}`).join(",") + "}";
51706
52006
  }
51707
- throw new Error(`Unrecognized skill source "${raw}". Expected "registry:creator/slug[@version]", "registry:slug", or a relative path starting with "./".`);
51708
- }
51709
- var AgentMetaSchema = exports_external.object({
51710
- name: exports_external.string().min(1),
51711
- tagline: exports_external.string().optional()
51712
- });
51713
- var InstructionsSchema = exports_external.object({
51714
- file: exports_external.string().min(1)
51715
- });
51716
- var SkillEntrySchema = exports_external.object({
51717
- source: exports_external.string().min(1)
51718
- });
51719
- var McpEntrySchema = exports_external.object({
51720
- name: exports_external.string().min(1),
51721
- url: exports_external.string().optional(),
51722
- command: exports_external.string().optional(),
51723
- args: exports_external.array(exports_external.string()).optional(),
51724
- env: exports_external.record(exports_external.string()).optional(),
51725
- headers: exports_external.record(exports_external.string()).optional(),
51726
- is_enabled: exports_external.boolean().optional()
51727
- });
51728
- var AgentManifestSchema = exports_external.object({
51729
- schema: exports_external.literal(1),
51730
- agent: AgentMetaSchema,
51731
- instructions: InstructionsSchema.optional(),
51732
- skills: exports_external.array(SkillEntrySchema).default([]),
51733
- mcp: exports_external.array(McpEntrySchema).default([]),
51734
- commands: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
51735
- hooks: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
51736
- files: exports_external.array(exports_external.record(exports_external.unknown())).optional()
51737
- });
51738
- function manifestPath(cwd2) {
51739
- return path45.join(cwd2, AGENT_MANIFEST_FILE);
51740
- }
51741
- function hasManifest(cwd2) {
51742
- return fs42.existsSync(manifestPath(cwd2));
51743
- }
51744
- function readManifest(cwd2) {
51745
- const p2 = manifestPath(cwd2);
51746
- if (!fs42.existsSync(p2))
51747
- return null;
51748
- const raw = fs42.readFileSync(p2, "utf8");
51749
- let parsed;
51750
- try {
51751
- parsed = import_yaml2.default.parse(raw);
51752
- } catch (err) {
51753
- throw new Error(`${AGENT_MANIFEST_FILE} is not valid YAML: ${err.message}`);
51754
- }
51755
- const result = AgentManifestSchema.safeParse(parsed);
51756
- if (!result.success) {
51757
- throw new Error(`${AGENT_MANIFEST_FILE} is invalid: ${result.error.issues.map((i) => `${i.path.join(".") || "(root)"} — ${i.message}`).join("; ")}`);
51758
- }
51759
- return result.data;
51760
- }
51761
- function writeManifest(cwd2, manifest) {
51762
- const doc = new import_yaml2.default.Document;
51763
- doc.contents = manifest;
51764
- doc.commentBefore = ` brainbase.yaml — declarative agent manifest.
51765
- ` + " Committed to source control. Edit by hand, then `brainbase agent push`.";
51766
- const out = String(doc);
51767
- fs42.writeFileSync(manifestPath(cwd2), out, "utf8");
51768
- }
51769
- function resolveInstructionsPath(cwd2, manifest) {
51770
- if (!manifest.instructions)
51771
- return null;
51772
- return path45.resolve(cwd2, manifest.instructions.file);
51773
- }
51774
- function readInstructions(cwd2, manifest) {
51775
- const p2 = resolveInstructionsPath(cwd2, manifest);
51776
- if (!p2 || !fs42.existsSync(p2))
51777
- return null;
51778
- return fs42.readFileSync(p2, "utf8");
51779
- }
51780
-
51781
- // src/core/agent-diff.ts
51782
- import path46 from "node:path";
51783
- import fs43 from "node:fs";
51784
- import crypto4 from "node:crypto";
51785
- function compKey(type, slug) {
51786
- return `${type}/${slug}`;
51787
- }
51788
- function hashString(s3) {
51789
- return crypto4.createHash("sha256").update(s3).digest("hex");
51790
- }
51791
- function canonicalJson(value) {
51792
- if (value === null)
51793
- return "null";
51794
- if (typeof value === "boolean")
51795
- return value ? "true" : "false";
51796
- if (typeof value === "number") {
51797
- if (!Number.isFinite(value))
51798
- throw new Error("Non-finite numbers are not JSON");
51799
- return String(value);
51800
- }
51801
- if (typeof value === "string")
51802
- return JSON.stringify(value);
51803
- if (Array.isArray(value)) {
51804
- return "[" + value.map(canonicalJson).join(",") + "]";
51805
- }
51806
- if (typeof value === "object") {
51807
- const obj = value;
51808
- const keys = Object.keys(obj).sort();
51809
- return "{" + keys.map((k3) => `${JSON.stringify(k3)}:${canonicalJson(obj[k3])}`).join(",") + "}";
51810
- }
51811
- throw new Error(`Unsupported value in canonicalJson: ${typeof value}`);
52007
+ throw new Error(`Unsupported value in canonicalJson: ${typeof value}`);
51812
52008
  }
51813
52009
  function hashMcpEntry(entry) {
51814
52010
  const payload = {};
@@ -52113,26 +52309,27 @@ function diffSecrets(local, cloud) {
52113
52309
  // src/cli/agent-pull.ts
52114
52310
  async function runAgentPull(cwd2, args) {
52115
52311
  banner("agent pull — bring cloud changes into this folder");
52116
- const link2 = readLink(cwd2);
52117
- if (!link2) {
52118
- f2.warn("This folder is not linked to any agent.");
52119
- f2.info(`Run ${import_picocolors25.default.cyan("brainbase link")} first.`);
52312
+ const resolution = resolveTargetAgentId(cwd2, args);
52313
+ if (!resolution)
52120
52314
  return;
52121
- }
52315
+ const { agentId, override } = resolution;
52122
52316
  const sp = de();
52123
- sp.start(`Fetching ${link2.name}…`);
52317
+ sp.start("Fetching agent…");
52318
+ let cloudAgent;
52124
52319
  let cloud;
52125
52320
  try {
52126
- cloud = await api.getAgentManifest(link2.agent_id);
52321
+ cloudAgent = await api.getAgent(agentId);
52322
+ cloud = await api.getAgentManifest(agentId);
52127
52323
  sp.stop(`Cloud revision ${cloud.revision}.`);
52128
52324
  } catch (err) {
52129
52325
  sp.stop("Failed.");
52130
52326
  handleApiError2(err);
52131
52327
  return;
52132
52328
  }
52133
- const lock = readSyncState(cwd2);
52134
- const localManifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
52135
- const localComponents = localManifest ? readLocalComponents(cwd2, localManifest) : [];
52329
+ const harness = normalizeHarnessId(cloudAgent.harness ?? "claude-code");
52330
+ const existingManifest = !override && hasManifest(cwd2) ? safeReadManifest(cwd2) : null;
52331
+ const lock = override ? null : readSyncState(cwd2);
52332
+ const localComponents = existingManifest ? readLocalComponents(cwd2, existingManifest) : [];
52136
52333
  const rows = threeWayDiff({
52137
52334
  local: localComponents,
52138
52335
  lock: lock?.components ?? [],
@@ -52157,7 +52354,11 @@ async function runAgentPull(cwd2, args) {
52157
52354
  break;
52158
52355
  case "modified-both":
52159
52356
  case "modified-local":
52160
- conflicts.push(r2);
52357
+ if (override) {
52358
+ toInstallKeys.add(r2.key);
52359
+ } else {
52360
+ conflicts.push(r2);
52361
+ }
52161
52362
  break;
52162
52363
  }
52163
52364
  }
@@ -52181,11 +52382,12 @@ async function runAgentPull(cwd2, args) {
52181
52382
  const needOrchestrationMcpInstall = !cloudHasOrchestrationMcp;
52182
52383
  const cloudHasMemoryMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === MEMORY_MCP_SLUG);
52183
52384
  const needMemoryMcpInstall = !cloudHasMemoryMcp;
52184
- if (toInstallKeys.size === 0 && toRemoveKeys.size === 0 && !needOrchestrationMcpInstall && !needMemoryMcpInstall) {
52385
+ if (toInstallKeys.size === 0 && toRemoveKeys.size === 0 && !needOrchestrationMcpInstall && !needMemoryMcpInstall && !override) {
52185
52386
  f2.info(`You're up to date.`);
52186
- writeSyncState(cwd2, buildLockFromCloud(link2.agent_id, cloud, lock));
52187
- if (!localManifest) {
52188
- writeBrainbaseYamlFromCloud(cwd2, link2, cloud);
52387
+ writeLink(cwd2, buildLinkFromAgent(cloudAgent, harness, readLink(cwd2)));
52388
+ writeSyncState(cwd2, buildLockFromCloud(agentId, cloud, lock, cloudAgent));
52389
+ if (!existingManifest) {
52390
+ writeManifest(cwd2, mergeManifest(cwd2, null, cloud, cloudAgent, harness));
52189
52391
  f2.info(`Wrote ${import_picocolors25.default.bold(AGENT_MANIFEST_FILE)}.`);
52190
52392
  }
52191
52393
  return;
@@ -52215,20 +52417,20 @@ async function runAgentPull(cwd2, args) {
52215
52417
  });
52216
52418
  }
52217
52419
  await showResultCard({
52218
- title: "PULL",
52219
- tone: "info",
52220
- subtitle: `updates for ${link2.name}`,
52420
+ title: override ? "PULL (FORCE)" : "PULL",
52421
+ tone: override ? "warn" : "info",
52422
+ subtitle: `updates for ${cloudAgent.name}`,
52221
52423
  rows: resultRows
52222
52424
  });
52223
52425
  if (!args.yes) {
52224
- const ok = await se({ message: "Apply these changes?", initialValue: true });
52426
+ const msg = override ? "Apply these changes? Local edits to overlapping components will be discarded." : "Apply these changes?";
52427
+ const ok = await se({ message: msg, initialValue: true });
52225
52428
  if (!ensureNotCancelled(ok)) {
52226
52429
  $e("Aborted.");
52227
52430
  return;
52228
52431
  }
52229
52432
  }
52230
- const adapterId = link2.harness ?? link2.tracking?.harness ?? "claude-code";
52231
- const adapter = getAdapter(adapterId);
52433
+ const adapter = getAdapter(harness);
52232
52434
  const scope = args.scope ?? "project";
52233
52435
  const installComponents = cloud.components.filter((c2) => toInstallKeys.has(`${c2.type}/${c2.slug}`));
52234
52436
  const stageRoot = stageManifestComponents(installComponents);
@@ -52260,7 +52462,7 @@ async function runAgentPull(cwd2, args) {
52260
52462
  resolveConflict: async (_c) => "overwrite",
52261
52463
  resolveSecret: async () => null
52262
52464
  };
52263
- const result = await runHarnessInstall2(adapter.id, toInstall, opts, link2.name);
52465
+ const result = await runHarnessInstall2(adapter.id, toInstall, opts, cloudAgent.name);
52264
52466
  installSpinner.stop("Applied.");
52265
52467
  for (const o2 of result.installed) {
52266
52468
  justInstalledPaths.set(`${o2.type}/${o2.slug}`, o2.installedPaths);
@@ -52288,8 +52490,10 @@ async function runAgentPull(cwd2, args) {
52288
52490
  }
52289
52491
  }
52290
52492
  materializeInstructions(cwd2, cloud, toInstallKeys, keepLocalKeys);
52291
- const yaml = mergeManifest(cwd2, localManifest, cloud, link2);
52493
+ materializeEntrypoint(cwd2, cloudAgent.entrypoint ?? "", existingManifest);
52494
+ const yaml = mergeManifest(cwd2, existingManifest, cloud, cloudAgent, harness);
52292
52495
  writeManifest(cwd2, yaml);
52496
+ writeLink(cwd2, buildLinkFromAgent(cloudAgent, harness, readLink(cwd2)));
52293
52497
  const lockComponents = buildLockComponents({
52294
52498
  cloud,
52295
52499
  prevLock: lock,
@@ -52299,21 +52503,64 @@ async function runAgentPull(cwd2, args) {
52299
52503
  });
52300
52504
  const newState = {
52301
52505
  schemaVersion: 1,
52302
- agent_id: link2.agent_id,
52506
+ agent_id: agentId,
52303
52507
  revision: cloud.revision,
52304
52508
  synced_at: new Date().toISOString(),
52305
52509
  components: lockComponents,
52306
- agentMeta: { name: link2.name, tagline: link2.tagline }
52510
+ agentMeta: {
52511
+ name: cloudAgent.name,
52512
+ tagline: cloudAgent.tagline,
52513
+ ...cloudAgent.entrypoint ? { entrypoint: cloudAgent.entrypoint } : {}
52514
+ }
52307
52515
  };
52308
52516
  writeSyncState(cwd2, newState);
52309
- await pullSecrets(cwd2, link2.agent_id);
52310
- $e(`Pulled ${link2.name} at revision ${cloud.revision}.`);
52517
+ await pullSecrets(cwd2, agentId);
52518
+ await runEntrypointIfPresent(cwd2, yaml);
52519
+ $e(`Pulled ${cloudAgent.name} at revision ${cloud.revision}.`);
52311
52520
  } finally {
52312
52521
  try {
52313
52522
  fs45.rmSync(stageRoot, { recursive: true, force: true });
52314
52523
  } catch {}
52315
52524
  }
52316
52525
  }
52526
+ function resolveTargetAgentId(cwd2, args) {
52527
+ const arg = args.agentIdArg?.trim() || undefined;
52528
+ let manifest = null;
52529
+ try {
52530
+ manifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
52531
+ } catch (err) {
52532
+ f2.error(err.message);
52533
+ return null;
52534
+ }
52535
+ const manifestId = manifest?.id;
52536
+ if (arg && manifestId && arg !== manifestId) {
52537
+ if (!args.force) {
52538
+ f2.error(`This folder is already linked to a different agent (${import_picocolors25.default.dim(manifestId)}).`);
52539
+ f2.info(`Run ${import_picocolors25.default.cyan(`brainbase agent pull ${arg} --force`)} to override. ` + import_picocolors25.default.yellow("This will overwrite brainbase.agent.yaml and any local progress will be lost."));
52540
+ return null;
52541
+ }
52542
+ return { agentId: arg, override: true };
52543
+ }
52544
+ if (arg)
52545
+ return { agentId: arg, override: false };
52546
+ if (manifestId)
52547
+ return { agentId: manifestId, override: false };
52548
+ if (manifest) {
52549
+ f2.error(`${import_picocolors25.default.bold(AGENT_MANIFEST_FILE)} is unclaimed (no ${import_picocolors25.default.cyan("id")}).`);
52550
+ f2.info(`Run ${import_picocolors25.default.cyan("brainbase agent create")} to create a new agent from this manifest, ` + `or ${import_picocolors25.default.cyan("brainbase agent pull <id>")} to pull an existing one.`);
52551
+ } else {
52552
+ f2.error(`No ${import_picocolors25.default.bold(AGENT_MANIFEST_FILE)} here and no ${import_picocolors25.default.cyan("<id>")} given.`);
52553
+ f2.info(`Run ${import_picocolors25.default.cyan("brainbase agent pull <id>")} to pull an existing agent into this folder.`);
52554
+ }
52555
+ return null;
52556
+ }
52557
+ function safeReadManifest(cwd2) {
52558
+ try {
52559
+ return readManifest(cwd2);
52560
+ } catch {
52561
+ return null;
52562
+ }
52563
+ }
52317
52564
  function skillSourceFromMeta(c2) {
52318
52565
  if (c2.type !== "skill")
52319
52566
  return;
@@ -52363,7 +52610,7 @@ function materializeInstructions(cwd2, cloud, toInstall, keepLocal) {
52363
52610
  fs45.writeFileSync(path48.join(cwd2, DEFAULT_INSTRUCTIONS_FILE), body, "utf8");
52364
52611
  }
52365
52612
  }
52366
- function mergeManifest(cwd2, prev, cloud, link2) {
52613
+ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
52367
52614
  const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
52368
52615
  const localDecl = prev?.skills.find((s3) => {
52369
52616
  try {
@@ -52386,7 +52633,18 @@ function mergeManifest(cwd2, prev, cloud, link2) {
52386
52633
  }
52387
52634
  return { source: `registry:${c2.slug}` };
52388
52635
  });
52389
- const hasInstructions = cloud.components.some((c2) => c2.type === "instruction" && c2.files[0]?.content?.trim());
52636
+ const cloudInstrComp = cloud.components.find((c2) => c2.type === "instruction" && c2.files[0]?.content?.trim());
52637
+ const instructions = cloudInstrComp ? prev?.instructions?.text !== undefined ? { text: cloudInstrComp.files[0].content } : { file: prev?.instructions?.file ?? DEFAULT_INSTRUCTIONS_FILE } : undefined;
52638
+ const cloudEntrypoint = (cloudAgent.entrypoint ?? "").trim();
52639
+ let entrypoint;
52640
+ if (cloudEntrypoint.length > 0) {
52641
+ if (prev?.entrypoint?.commands)
52642
+ entrypoint = { commands: prev.entrypoint.commands };
52643
+ else if (prev?.entrypoint?.text !== undefined)
52644
+ entrypoint = { text: cloudAgent.entrypoint };
52645
+ else
52646
+ entrypoint = { file: prev?.entrypoint?.file ?? DEFAULT_ENTRYPOINT_FILE };
52647
+ }
52390
52648
  const mcp = cloud.components.filter((c2) => c2.type === "mcp").map((c2) => {
52391
52649
  const payload = (c2.meta ?? {}).mcp ?? {};
52392
52650
  const entry = { name: c2.slug };
@@ -52406,17 +52664,32 @@ function mergeManifest(cwd2, prev, cloud, link2) {
52406
52664
  });
52407
52665
  return {
52408
52666
  schema: 1,
52667
+ id: cloudAgent.id,
52668
+ harness,
52409
52669
  agent: {
52410
- name: link2.name,
52411
- ...link2.tagline ? { tagline: link2.tagline } : {}
52670
+ name: cloudAgent.name,
52671
+ ...cloudAgent.tagline ? { tagline: cloudAgent.tagline } : {}
52412
52672
  },
52413
- ...hasInstructions ? {
52414
- instructions: { file: prev?.instructions?.file ?? DEFAULT_INSTRUCTIONS_FILE }
52415
- } : {},
52673
+ ...instructions ? { instructions } : {},
52674
+ ...entrypoint ? { entrypoint } : {},
52416
52675
  skills,
52417
52676
  mcp
52418
52677
  };
52419
52678
  }
52679
+ function materializeEntrypoint(cwd2, cloudEntrypoint, prev) {
52680
+ if (!cloudEntrypoint.trim())
52681
+ return;
52682
+ if (prev?.entrypoint?.commands)
52683
+ return;
52684
+ if (prev?.entrypoint?.text !== undefined)
52685
+ return;
52686
+ const filename = prev?.entrypoint?.file ?? DEFAULT_ENTRYPOINT_FILE;
52687
+ const target = path48.resolve(cwd2, filename);
52688
+ fs45.writeFileSync(target, cloudEntrypoint, "utf8");
52689
+ try {
52690
+ fs45.chmodSync(target, 493);
52691
+ } catch {}
52692
+ }
52420
52693
  function parseSourceLoose(raw) {
52421
52694
  const m3 = raw.match(/^registry:[a-z0-9_-]+\/([a-z0-9_-]+)/i);
52422
52695
  if (m3)
@@ -52458,7 +52731,7 @@ function buildLockComponents(input) {
52458
52731
  }
52459
52732
  return out;
52460
52733
  }
52461
- function buildLockFromCloud(agent_id, cloud, prev) {
52734
+ function buildLockFromCloud(agent_id, cloud, prev, cloudAgent) {
52462
52735
  return {
52463
52736
  schemaVersion: 1,
52464
52737
  agent_id,
@@ -52470,11 +52743,73 @@ function buildLockFromCloud(agent_id, cloud, prev) {
52470
52743
  hash: c2.hash,
52471
52744
  installedPaths: []
52472
52745
  })),
52473
- agentMeta: prev?.agentMeta
52746
+ agentMeta: cloudAgent ? {
52747
+ name: cloudAgent.name,
52748
+ tagline: cloudAgent.tagline,
52749
+ ...cloudAgent.entrypoint ? { entrypoint: cloudAgent.entrypoint } : {}
52750
+ } : prev?.agentMeta
52751
+ };
52752
+ }
52753
+ function buildLinkFromAgent(agent, harness, prev) {
52754
+ return {
52755
+ schemaVersion: 1,
52756
+ agent_id: agent.id,
52757
+ org_id: agent.org_id ?? prev?.org_id ?? "",
52758
+ team_id: agent.team_id ?? prev?.team_id ?? "",
52759
+ slug: agent.slug,
52760
+ name: agent.name,
52761
+ tagline: agent.tagline,
52762
+ url: agent.url,
52763
+ linked_at: prev?.linked_at ?? new Date().toISOString(),
52764
+ linked_by: prev?.linked_by,
52765
+ harness,
52766
+ tracking: prev?.tracking
52474
52767
  };
52475
52768
  }
52476
- function writeBrainbaseYamlFromCloud(cwd2, link2, cloud) {
52477
- writeManifest(cwd2, mergeManifest(cwd2, null, cloud, link2));
52769
+ async function runEntrypointIfPresent(cwd2, manifest) {
52770
+ if (!manifest.entrypoint)
52771
+ return;
52772
+ const body = resolveEntrypoint(cwd2, manifest);
52773
+ if (body === null || !body.trim())
52774
+ return;
52775
+ const stateDir = path48.join(cwd2, LINK_DIR);
52776
+ ensureDir(stateDir);
52777
+ const scriptPath = path48.join(stateDir, "entrypoint.sh");
52778
+ const logPath = path48.join(stateDir, "entrypoint.log");
52779
+ fs45.writeFileSync(scriptPath, body, "utf8");
52780
+ try {
52781
+ fs45.chmodSync(scriptPath, 493);
52782
+ } catch {}
52783
+ f2.info(`Running entrypoint ${import_picocolors25.default.dim(`(${path48.relative(cwd2, scriptPath)})`)}`);
52784
+ const secrets = readLocalSecrets(cwd2);
52785
+ const env3 = { ...process.env, ...secrets };
52786
+ const logStream = fs45.createWriteStream(logPath, { flags: "w" });
52787
+ const exitCode = await new Promise((resolve) => {
52788
+ const child = spawn2("bash", [scriptPath], {
52789
+ cwd: cwd2,
52790
+ env: env3,
52791
+ stdio: ["ignore", "pipe", "pipe"]
52792
+ });
52793
+ child.stdout?.on("data", (chunk) => {
52794
+ process.stdout.write(chunk);
52795
+ logStream.write(chunk);
52796
+ });
52797
+ child.stderr?.on("data", (chunk) => {
52798
+ process.stderr.write(chunk);
52799
+ logStream.write(chunk);
52800
+ });
52801
+ child.on("error", (err) => {
52802
+ f2.warn(`entrypoint failed to start: ${err.message}`);
52803
+ resolve(null);
52804
+ });
52805
+ child.on("exit", (code) => resolve(code));
52806
+ });
52807
+ await new Promise((resolve) => logStream.end(resolve));
52808
+ if (exitCode === 0) {
52809
+ f2.info("Entrypoint completed.");
52810
+ } else if (exitCode === null) {} else {
52811
+ f2.warn(`Entrypoint exited ${exitCode} — continuing. Log at ${import_picocolors25.default.dim(path48.relative(cwd2, logPath))}.`);
52812
+ }
52478
52813
  }
52479
52814
  async function pullSecrets(cwd2, agentId) {
52480
52815
  let cloudSecrets;
@@ -52508,6 +52843,8 @@ function handleApiError2(err) {
52508
52843
  if (err instanceof ApiError) {
52509
52844
  if (err.status === 401) {
52510
52845
  f2.error("Your session is invalid. Run `brainbase login` and try again.");
52846
+ } else if (err.status === 404) {
52847
+ f2.error(`Agent not found, or you don't have access. Double-check the id.`);
52511
52848
  } else {
52512
52849
  f2.error(err.message);
52513
52850
  }
@@ -52517,18 +52854,96 @@ function handleApiError2(err) {
52517
52854
  }
52518
52855
 
52519
52856
  // src/cli/agent-push.ts
52857
+ var import_picocolors27 = __toESM(require_picocolors(), 1);
52858
+
52859
+ // src/core/agent-outgoing.ts
52520
52860
  var import_picocolors26 = __toESM(require_picocolors(), 1);
52861
+ async function buildOutgoingComponents(cwd2, manifest, cloud) {
52862
+ const out = [];
52863
+ if (manifest.instructions) {
52864
+ if (manifest.instructions.text !== undefined && manifest.instructions.file !== undefined) {
52865
+ f2.error(`instructions block sets both ${import_picocolors26.default.cyan("text")} and ${import_picocolors26.default.cyan("file")} — pick one.`);
52866
+ return null;
52867
+ }
52868
+ const body = readInstructions(cwd2, manifest);
52869
+ if (body === null) {
52870
+ if (manifest.instructions.file) {
52871
+ f2.error(`Instructions file ${import_picocolors26.default.bold(manifest.instructions.file)} not found.`);
52872
+ } else {
52873
+ f2.error("Instructions block is empty.");
52874
+ }
52875
+ return null;
52876
+ }
52877
+ if (body.trim()) {
52878
+ const fileName = manifest.instructions.file ?? "instructions.md";
52879
+ const fileHash2 = hashString(body);
52880
+ const file = {
52881
+ path: fileName,
52882
+ content: body,
52883
+ hash: fileHash2
52884
+ };
52885
+ out.push({
52886
+ type: "instruction",
52887
+ slug: "agent-instructions",
52888
+ description: "Agent instructions",
52889
+ hash: componentHashFromFileHashes([fileHash2]),
52890
+ files: [file],
52891
+ meta: { source: "global_prompt" }
52892
+ });
52893
+ }
52894
+ }
52895
+ for (const entry of manifest.skills) {
52896
+ const parsed = parseSkillSource2(entry.source);
52897
+ if (parsed.kind === "local") {
52898
+ f2.error(`Skill ${import_picocolors26.default.bold(entry.source)} is a local-authored skill. Local skill push isn't supported yet — publish it to the registry first (\`brainbase skill publish\`).`);
52899
+ return null;
52900
+ }
52901
+ const cloudMatch = cloud?.components.find((c2) => c2.type === "skill" && c2.slug === parsed.slug);
52902
+ out.push({
52903
+ type: "skill",
52904
+ slug: parsed.slug,
52905
+ hash: cloudMatch?.hash ?? "",
52906
+ files: [],
52907
+ meta: {
52908
+ name: parsed.creator ? `${parsed.creator}/${parsed.slug}` : parsed.slug,
52909
+ ...parsed.version ? { version: parsed.version } : {}
52910
+ }
52911
+ });
52912
+ }
52913
+ for (const entry of manifest.mcp ?? []) {
52914
+ if (!entry.url && !entry.command) {
52915
+ f2.error(`MCP ${import_picocolors26.default.bold(entry.name)} needs either ${import_picocolors26.default.cyan("url")} or ${import_picocolors26.default.cyan("command")}.`);
52916
+ return null;
52917
+ }
52918
+ const payload = {};
52919
+ if (entry.url !== undefined)
52920
+ payload.url = entry.url;
52921
+ if (entry.command !== undefined)
52922
+ payload.command = entry.command;
52923
+ if (entry.args !== undefined)
52924
+ payload.args = entry.args;
52925
+ if (entry.env !== undefined)
52926
+ payload.env = entry.env;
52927
+ if (entry.headers !== undefined)
52928
+ payload.headers = entry.headers;
52929
+ payload.is_enabled = entry.is_enabled ?? true;
52930
+ out.push({
52931
+ type: "mcp",
52932
+ slug: entry.name,
52933
+ hash: "",
52934
+ files: [],
52935
+ meta: { mcp: payload }
52936
+ });
52937
+ }
52938
+ return out;
52939
+ }
52940
+
52941
+ // src/cli/agent-push.ts
52521
52942
  async function runAgentPush(cwd2, args) {
52522
52943
  banner("agent push — send your local changes to the cloud");
52523
- const link2 = readLink(cwd2);
52524
- if (!link2) {
52525
- f2.warn("This folder is not linked to any agent.");
52526
- f2.info(`Run ${import_picocolors26.default.cyan("brainbase link")} first.`);
52527
- return;
52528
- }
52529
52944
  if (!hasManifest(cwd2)) {
52530
- f2.warn(`No ${import_picocolors26.default.bold(AGENT_MANIFEST_FILE)} here.`);
52531
- f2.info(`Run ${import_picocolors26.default.cyan("brainbase agent pull")} to materialize the manifest before pushing.`);
52945
+ f2.warn(`No ${import_picocolors27.default.bold(AGENT_MANIFEST_FILE)} here.`);
52946
+ f2.info(`Run ${import_picocolors27.default.cyan("brainbase agent create")} to claim a new agent from a manifest, ` + `or ${import_picocolors27.default.cyan("brainbase agent pull <id>")} to pull an existing one.`);
52532
52947
  return;
52533
52948
  }
52534
52949
  let manifest;
@@ -52538,11 +52953,17 @@ async function runAgentPush(cwd2, args) {
52538
52953
  f2.error(err.message);
52539
52954
  return;
52540
52955
  }
52956
+ if (!manifest.id) {
52957
+ f2.warn(`${import_picocolors27.default.bold(AGENT_MANIFEST_FILE)} is unclaimed (no ${import_picocolors27.default.cyan("id")}). Nothing to push to.`);
52958
+ f2.info(`Run ${import_picocolors27.default.cyan("brainbase agent create")} first — that creates the cloud agent and stamps an id here.`);
52959
+ return;
52960
+ }
52961
+ const agentId = manifest.id;
52541
52962
  const sp = de();
52542
- sp.start(`Fetching cloud state for ${link2.name}…`);
52963
+ sp.start(`Fetching cloud state…`);
52543
52964
  let cloud;
52544
52965
  try {
52545
- cloud = await api.getAgentManifest(link2.agent_id);
52966
+ cloud = await api.getAgentManifest(agentId);
52546
52967
  sp.stop(`Cloud revision ${cloud.revision}.`);
52547
52968
  } catch (err) {
52548
52969
  sp.stop("Failed.");
@@ -52555,17 +52976,42 @@ async function runAgentPush(cwd2, args) {
52555
52976
  lock: lock?.components ?? [],
52556
52977
  cloud: cloud.components
52557
52978
  });
52558
- const meta = diffAgentMeta(manifest.agent, lock?.agentMeta, { name: link2.name, tagline: link2.tagline });
52979
+ let cloudMeta = lock?.agentMeta;
52980
+ if (!cloudMeta) {
52981
+ try {
52982
+ const a3 = await api.getAgent(agentId);
52983
+ cloudMeta = { name: a3.name, tagline: a3.tagline, entrypoint: a3.entrypoint };
52984
+ } catch {}
52985
+ }
52986
+ const meta = diffAgentMeta(manifest.agent, lock?.agentMeta, cloudMeta);
52987
+ let resolvedEntrypoint;
52988
+ if (manifest.entrypoint) {
52989
+ const body = resolveEntrypoint(cwd2, manifest);
52990
+ if (body === null) {
52991
+ if (manifest.entrypoint.file) {
52992
+ f2.error(`Entrypoint file ${import_picocolors27.default.bold(manifest.entrypoint.file)} not found.`);
52993
+ } else {
52994
+ f2.error("Entrypoint block is empty.");
52995
+ }
52996
+ return;
52997
+ }
52998
+ resolvedEntrypoint = body;
52999
+ } else {
53000
+ if ((lock?.agentMeta?.entrypoint ?? "") !== "") {
53001
+ resolvedEntrypoint = "";
53002
+ }
53003
+ }
53004
+ const entrypointChanged = resolvedEntrypoint !== undefined && resolvedEntrypoint !== (lock?.agentMeta?.entrypoint ?? "");
52559
53005
  for (const r2 of rows) {
52560
53006
  if (r2.type !== "instruction" && r2.type !== "skill" && r2.type !== "mcp") {
52561
- f2.error(`Component ${fmtType(r2.type)} ${import_picocolors26.default.bold(r2.slug)} can't be pushed yet — the server accepts instructions, skills, and mcps in this version.`);
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.`);
52562
53008
  return;
52563
53009
  }
52564
53010
  }
52565
53011
  for (const entry of manifest.skills) {
52566
53012
  const parsed = parseSkillSource2(entry.source);
52567
53013
  if (parsed.kind === "local") {
52568
- f2.error(`Skill ${import_picocolors26.default.bold(entry.source)} is a local-authored skill. Local skill push isn't supported yet — publish it to the registry first (\`brainbase skill publish\`).`);
53014
+ f2.error(`Skill ${import_picocolors27.default.bold(entry.source)} is a local-authored skill. Local skill push isn't supported yet — publish it to the registry first (\`brainbase skill publish\`).`);
52569
53015
  return;
52570
53016
  }
52571
53017
  }
@@ -52589,22 +53035,22 @@ async function runAgentPush(cwd2, args) {
52589
53035
  break;
52590
53036
  }
52591
53037
  }
52592
- if (!meta.localChanged && toSend.length === 0 && conflicts.length === 0) {
53038
+ if (!meta.localChanged && !entrypointChanged && toSend.length === 0 && conflicts.length === 0) {
52593
53039
  f2.info("Nothing to push — local is in sync with the cloud.");
52594
53040
  return;
52595
53041
  }
52596
53042
  if (conflicts.length > 0) {
52597
53043
  f2.error(`Cannot push: ${conflicts.length} component${conflicts.length === 1 ? "" : "s"} changed both locally and on the cloud:`);
52598
53044
  for (const r2 of conflicts) {
52599
- console.error(` ${import_picocolors26.default.red("!")} ${fmtType(r2.type)} ${import_picocolors26.default.bold(r2.slug)}`);
53045
+ console.error(` ${import_picocolors27.default.red("!")} ${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)}`);
52600
53046
  }
52601
- f2.info(`Run ${import_picocolors26.default.cyan("brainbase agent pull")} first to reconcile, then push again.`);
53047
+ f2.info(`Run ${import_picocolors27.default.cyan("brainbase agent pull")} first to reconcile, then push again.`);
52602
53048
  return;
52603
53049
  }
52604
53050
  if (upstreamOnly.length > 0 && !args.yes) {
52605
53051
  f2.warn(`Cloud has ${upstreamOnly.length} change${upstreamOnly.length === 1 ? "" : "s"} you don't have locally:`);
52606
53052
  for (const r2 of upstreamOnly) {
52607
- console.warn(` ${import_picocolors26.default.cyan("←")} ${fmtType(r2.type)} ${import_picocolors26.default.bold(r2.slug)} ${import_picocolors26.default.dim(`(${r2.status})`)}`);
53053
+ console.warn(` ${import_picocolors27.default.cyan("←")} ${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)} ${import_picocolors27.default.dim(`(${r2.status})`)}`);
52608
53054
  }
52609
53055
  f2.info(`If you push now, your push targets revision ${cloud.revision} and may race. Consider \`brainbase agent pull\` first.`);
52610
53056
  }
@@ -52616,6 +53062,13 @@ async function runAgentPush(cwd2, args) {
52616
53062
  text: "name/tagline"
52617
53063
  });
52618
53064
  }
53065
+ if (entrypointChanged) {
53066
+ resultRows.push({
53067
+ type: "upd",
53068
+ label: "entrypoint",
53069
+ text: resolvedEntrypoint === "" ? "cleared" : "updated"
53070
+ });
53071
+ }
52619
53072
  if (toSend.length) {
52620
53073
  resultRows.push({
52621
53074
  type: "add",
@@ -52626,7 +53079,7 @@ async function runAgentPush(cwd2, args) {
52626
53079
  await showResultCard({
52627
53080
  title: "PUSH",
52628
53081
  tone: "info",
52629
- subtitle: `${link2.name} ← local`,
53082
+ subtitle: `${manifest.agent.name} ← local`,
52630
53083
  rows: resultRows
52631
53084
  });
52632
53085
  if (!args.yes) {
@@ -52636,14 +53089,19 @@ async function runAgentPush(cwd2, args) {
52636
53089
  return;
52637
53090
  }
52638
53091
  }
52639
- if (meta.localChanged) {
53092
+ if (meta.localChanged || entrypointChanged) {
52640
53093
  const metaSpinner = de();
52641
53094
  metaSpinner.start("Updating agent metadata…");
52642
53095
  try {
52643
- await api.updateAgent(link2.agent_id, {
52644
- name: manifest.agent.name,
52645
- tagline: manifest.agent.tagline ?? ""
52646
- });
53096
+ const update = {};
53097
+ if (meta.localChanged) {
53098
+ update.name = manifest.agent.name;
53099
+ update.tagline = manifest.agent.tagline ?? "";
53100
+ }
53101
+ if (entrypointChanged) {
53102
+ update.entrypoint = resolvedEntrypoint;
53103
+ }
53104
+ await api.updateAgent(agentId, update);
52647
53105
  metaSpinner.stop("Metadata updated.");
52648
53106
  } catch (err) {
52649
53107
  metaSpinner.stop("Failed.");
@@ -52657,7 +53115,7 @@ async function runAgentPush(cwd2, args) {
52657
53115
  pushSpinner.start("Pushing…");
52658
53116
  let updatedCloud;
52659
53117
  try {
52660
- updatedCloud = await api.pushAgentManifest(link2.agent_id, {
53118
+ updatedCloud = await api.pushAgentManifest(agentId, {
52661
53119
  components: outgoing,
52662
53120
  base_revision: cloud.revision
52663
53121
  });
@@ -52666,14 +53124,22 @@ async function runAgentPush(cwd2, args) {
52666
53124
  pushSpinner.stop("Failed.");
52667
53125
  if (err instanceof ApiError && err.status === 409) {
52668
53126
  f2.error(err.message);
52669
- f2.info(`Run ${import_picocolors26.default.cyan("brainbase agent pull")} and try again.`);
53127
+ f2.info(`Run ${import_picocolors27.default.cyan("brainbase agent pull")} and try again.`);
52670
53128
  return;
52671
53129
  }
52672
53130
  return handleApiError3(err);
52673
53131
  }
53132
+ const existing = readLink(cwd2);
53133
+ if (existing) {
53134
+ writeLink(cwd2, {
53135
+ ...existing,
53136
+ name: manifest.agent.name,
53137
+ tagline: manifest.agent.tagline
53138
+ });
53139
+ }
52674
53140
  const newLock = {
52675
53141
  schemaVersion: 1,
52676
- agent_id: link2.agent_id,
53142
+ agent_id: agentId,
52677
53143
  revision: updatedCloud.revision,
52678
53144
  synced_at: new Date().toISOString(),
52679
53145
  components: updatedCloud.components.map((c2) => {
@@ -52685,7 +53151,7 @@ async function runAgentPush(cwd2, args) {
52685
53151
  return false;
52686
53152
  }
52687
53153
  })?.source;
52688
- const prior = lock?.components.find((pc25) => pc25.type === c2.type && pc25.slug === c2.slug);
53154
+ const prior = lock?.components.find((pc26) => pc26.type === c2.type && pc26.slug === c2.slug);
52689
53155
  return {
52690
53156
  type: c2.type,
52691
53157
  slug: c2.slug,
@@ -52694,11 +53160,15 @@ async function runAgentPush(cwd2, args) {
52694
53160
  ...decl ? { source: decl } : {}
52695
53161
  };
52696
53162
  }),
52697
- agentMeta: { name: manifest.agent.name, tagline: manifest.agent.tagline }
53163
+ agentMeta: {
53164
+ name: manifest.agent.name,
53165
+ tagline: manifest.agent.tagline,
53166
+ entrypoint: resolvedEntrypoint !== undefined ? resolvedEntrypoint : lock?.agentMeta?.entrypoint
53167
+ }
52698
53168
  };
52699
53169
  writeSyncState(cwd2, newLock);
52700
- await pushSecrets(cwd2, link2.agent_id);
52701
- $e(`Pushed ${link2.name} at revision ${updatedCloud.revision}.`);
53170
+ await pushSecrets(cwd2, agentId);
53171
+ $e(`Pushed ${manifest.agent.name} at revision ${updatedCloud.revision}.`);
52702
53172
  }
52703
53173
  async function pushSecrets(cwd2, agentId) {
52704
53174
  const localSecrets = readLocalSecrets(cwd2);
@@ -52726,80 +53196,12 @@ async function pushSecrets(cwd2, agentId) {
52726
53196
  handleApiError3(err);
52727
53197
  }
52728
53198
  }
52729
- async function buildOutgoingComponents(cwd2, manifest, cloud) {
52730
- const out = [];
52731
- if (manifest.instructions) {
52732
- const body = readInstructions(cwd2, manifest);
52733
- if (body === null) {
52734
- f2.error(`Instructions file ${import_picocolors26.default.bold(manifest.instructions.file)} not found.`);
52735
- return null;
52736
- }
52737
- if (body.trim()) {
52738
- const fileHash2 = hashString(body);
52739
- const file = {
52740
- path: manifest.instructions.file,
52741
- content: body,
52742
- hash: fileHash2
52743
- };
52744
- out.push({
52745
- type: "instruction",
52746
- slug: "agent-instructions",
52747
- description: "Agent instructions",
52748
- hash: componentHashFromFileHashes([fileHash2]),
52749
- files: [file],
52750
- meta: { source: "global_prompt" }
52751
- });
52752
- }
52753
- }
52754
- for (const entry of manifest.skills) {
52755
- const parsed = parseSkillSource2(entry.source);
52756
- if (parsed.kind !== "registry")
52757
- continue;
52758
- const cloudMatch = cloud.components.find((c2) => c2.type === "skill" && c2.slug === parsed.slug);
52759
- out.push({
52760
- type: "skill",
52761
- slug: parsed.slug,
52762
- hash: cloudMatch?.hash ?? "",
52763
- files: [],
52764
- meta: {
52765
- name: parsed.creator ? `${parsed.creator}/${parsed.slug}` : parsed.slug,
52766
- ...parsed.version ? { version: parsed.version } : {}
52767
- }
52768
- });
52769
- }
52770
- for (const entry of manifest.mcp ?? []) {
52771
- if (!entry.url && !entry.command) {
52772
- f2.error(`MCP ${import_picocolors26.default.bold(entry.name)} needs either ${import_picocolors26.default.cyan("url")} or ${import_picocolors26.default.cyan("command")}.`);
52773
- return null;
52774
- }
52775
- const payload = {};
52776
- if (entry.url !== undefined)
52777
- payload.url = entry.url;
52778
- if (entry.command !== undefined)
52779
- payload.command = entry.command;
52780
- if (entry.args !== undefined)
52781
- payload.args = entry.args;
52782
- if (entry.env !== undefined)
52783
- payload.env = entry.env;
52784
- if (entry.headers !== undefined)
52785
- payload.headers = entry.headers;
52786
- payload.is_enabled = entry.is_enabled ?? true;
52787
- out.push({
52788
- type: "mcp",
52789
- slug: entry.name,
52790
- hash: "",
52791
- files: [],
52792
- meta: { mcp: payload }
52793
- });
52794
- }
52795
- return out;
52796
- }
52797
- function handleApiError3(err) {
52798
- if (err instanceof ApiError) {
52799
- if (err.status === 401) {
52800
- f2.error("Your session is invalid. Run `brainbase login` and try again.");
52801
- } else {
52802
- f2.error(err.message);
53199
+ function handleApiError3(err) {
53200
+ if (err instanceof ApiError) {
53201
+ if (err.status === 401) {
53202
+ f2.error("Your session is invalid. Run `brainbase login` and try again.");
53203
+ } else {
53204
+ f2.error(err.message);
52803
53205
  }
52804
53206
  } else {
52805
53207
  f2.error(err.message);
@@ -52807,13 +53209,13 @@ function handleApiError3(err) {
52807
53209
  }
52808
53210
 
52809
53211
  // src/cli/agent-status.ts
52810
- var import_picocolors27 = __toESM(require_picocolors(), 1);
53212
+ var import_picocolors28 = __toESM(require_picocolors(), 1);
52811
53213
  async function runAgentStatus(cwd2) {
52812
53214
  banner("agent status — what changed locally, remotely, both");
52813
53215
  const link2 = readLink(cwd2);
52814
53216
  if (!link2) {
52815
53217
  f2.warn("This folder is not linked to any agent.");
52816
- f2.info(`Run ${import_picocolors27.default.cyan("brainbase link")} first.`);
53218
+ f2.info(`Run ${import_picocolors28.default.cyan("brainbase link")} first.`);
52817
53219
  return;
52818
53220
  }
52819
53221
  const manifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
@@ -52834,8 +53236,8 @@ async function runAgentStatus(cwd2) {
52834
53236
  return;
52835
53237
  }
52836
53238
  if (!manifest) {
52837
- f2.info(`${import_picocolors27.default.dim("No")} ${import_picocolors27.default.bold("brainbase.yaml")} ${import_picocolors27.default.dim("here yet.")} Run ${import_picocolors27.default.cyan("brainbase agent pull")} to populate this folder.`);
52838
- f2.info(`Cloud has ${import_picocolors27.default.bold(String(cloud.components.length))} component${cloud.components.length === 1 ? "" : "s"} at revision ${cloud.revision}.`);
53239
+ f2.info(`${import_picocolors28.default.dim("No")} ${import_picocolors28.default.bold("brainbase.agent.yaml")} ${import_picocolors28.default.dim("here yet.")} Run ${import_picocolors28.default.cyan("brainbase agent pull")} to populate this folder.`);
53240
+ f2.info(`Cloud has ${import_picocolors28.default.bold(String(cloud.components.length))} component${cloud.components.length === 1 ? "" : "s"} at revision ${cloud.revision}.`);
52839
53241
  return;
52840
53242
  }
52841
53243
  const localComponents = readLocalComponents(cwd2, manifest);
@@ -52874,17 +53276,17 @@ async function runAgentStatus(cwd2) {
52874
53276
  }
52875
53277
  const lines = [];
52876
53278
  lines.push("");
52877
- lines.push(` ${import_picocolors27.default.bold(link2.name)} ${import_picocolors27.default.dim(`(${link2.slug})`)}`);
52878
- lines.push(` ${import_picocolors27.default.dim("agent_id")} ${link2.agent_id}`);
52879
- lines.push(` ${import_picocolors27.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
53279
+ lines.push(` ${import_picocolors28.default.bold(link2.name)} ${import_picocolors28.default.dim(`(${link2.slug})`)}`);
53280
+ lines.push(` ${import_picocolors28.default.dim("agent_id")} ${link2.agent_id}`);
53281
+ lines.push(` ${import_picocolors28.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
52880
53282
  lines.push("");
52881
53283
  if (meta.localChanged || meta.cloudChanged) {
52882
- lines.push(` ${import_picocolors27.default.bold("agent metadata")}`);
53284
+ lines.push(` ${import_picocolors28.default.bold("agent metadata")}`);
52883
53285
  if (meta.localChanged) {
52884
- lines.push(` ${import_picocolors27.default.yellow("→ push")} name/tagline edited in brainbase.yaml`);
53286
+ lines.push(` ${import_picocolors28.default.yellow("→ push")} name/tagline edited in brainbase.agent.yaml`);
52885
53287
  }
52886
53288
  if (meta.cloudChanged) {
52887
- lines.push(` ${import_picocolors27.default.cyan("← pull")} name/tagline changed on cloud`);
53289
+ lines.push(` ${import_picocolors28.default.cyan("← pull")} name/tagline changed on cloud`);
52888
53290
  }
52889
53291
  lines.push("");
52890
53292
  }
@@ -52894,65 +53296,65 @@ async function runAgentStatus(cwd2) {
52894
53296
  const cloudSecrets = cloudRes.secrets ?? {};
52895
53297
  const sd = diffSecrets(localSecrets, cloudSecrets);
52896
53298
  if (sd.localOnly.length || sd.cloudOnly.length || sd.changed.length) {
52897
- lines.push(` ${import_picocolors27.default.bold("secrets")}`);
53299
+ lines.push(` ${import_picocolors28.default.bold("secrets")}`);
52898
53300
  if (sd.localOnly.length)
52899
- lines.push(` ${import_picocolors27.default.yellow("→ push")} new locally: ${sd.localOnly.join(", ")}`);
53301
+ lines.push(` ${import_picocolors28.default.yellow("→ push")} new locally: ${sd.localOnly.join(", ")}`);
52900
53302
  if (sd.changed.length)
52901
- lines.push(` ${import_picocolors27.default.yellow("→ push")} values changed: ${sd.changed.join(", ")}`);
53303
+ lines.push(` ${import_picocolors28.default.yellow("→ push")} values changed: ${sd.changed.join(", ")}`);
52902
53304
  if (sd.cloudOnly.length)
52903
- lines.push(` ${import_picocolors27.default.cyan("← pull")} new on cloud: ${sd.cloudOnly.join(", ")}`);
53305
+ lines.push(` ${import_picocolors28.default.cyan("← pull")} new on cloud: ${sd.cloudOnly.join(", ")}`);
52904
53306
  lines.push("");
52905
53307
  }
52906
53308
  } catch {}
52907
53309
  if (conflicts.length === 0 && toPush.length === 0 && toPull.length === 0) {
52908
- lines.push(` ${import_picocolors27.default.green("✓")} everything is in sync`);
53310
+ lines.push(` ${import_picocolors28.default.green("✓")} everything is in sync`);
52909
53311
  lines.push("");
52910
53312
  console.log(lines.join(`
52911
53313
  `));
52912
53314
  return;
52913
53315
  }
52914
53316
  if (toPush.length) {
52915
- lines.push(` ${import_picocolors27.default.bold("changes to push")} ${import_picocolors27.default.dim(`(${toPush.length})`)}`);
53317
+ lines.push(` ${import_picocolors28.default.bold("changes to push")} ${import_picocolors28.default.dim(`(${toPush.length})`)}`);
52916
53318
  for (const r2 of toPush)
52917
- lines.push(` ${import_picocolors27.default.yellow("→")} ${fmtRow(r2)}`);
53319
+ lines.push(` ${import_picocolors28.default.yellow("→")} ${fmtRow(r2)}`);
52918
53320
  lines.push("");
52919
53321
  }
52920
53322
  if (toPull.length) {
52921
- lines.push(` ${import_picocolors27.default.bold("changes to pull")} ${import_picocolors27.default.dim(`(${toPull.length})`)}`);
53323
+ lines.push(` ${import_picocolors28.default.bold("changes to pull")} ${import_picocolors28.default.dim(`(${toPull.length})`)}`);
52922
53324
  for (const r2 of toPull)
52923
- lines.push(` ${import_picocolors27.default.cyan("←")} ${fmtRow(r2)}`);
53325
+ lines.push(` ${import_picocolors28.default.cyan("←")} ${fmtRow(r2)}`);
52924
53326
  lines.push("");
52925
53327
  }
52926
53328
  if (conflicts.length) {
52927
- lines.push(` ${import_picocolors27.default.bold(import_picocolors27.default.red("conflicts"))} ${import_picocolors27.default.dim(`(${conflicts.length})`)}`);
53329
+ lines.push(` ${import_picocolors28.default.bold(import_picocolors28.default.red("conflicts"))} ${import_picocolors28.default.dim(`(${conflicts.length})`)}`);
52928
53330
  for (const r2 of conflicts)
52929
- lines.push(` ${import_picocolors27.default.red("!")} ${fmtRow(r2)}`);
53331
+ lines.push(` ${import_picocolors28.default.red("!")} ${fmtRow(r2)}`);
52930
53332
  lines.push("");
52931
53333
  }
52932
- lines.push(` ${import_picocolors27.default.dim("run")} ${import_picocolors27.default.cyan("brainbase agent pull")} ${import_picocolors27.default.dim("to apply cloud changes,")} ${import_picocolors27.default.cyan("brainbase agent push")} ${import_picocolors27.default.dim("to send yours")}`);
53334
+ lines.push(` ${import_picocolors28.default.dim("run")} ${import_picocolors28.default.cyan("brainbase agent pull")} ${import_picocolors28.default.dim("to apply cloud changes,")} ${import_picocolors28.default.cyan("brainbase agent push")} ${import_picocolors28.default.dim("to send yours")}`);
52933
53335
  lines.push("");
52934
53336
  console.log(lines.join(`
52935
53337
  `));
52936
53338
  }
52937
53339
  function fmtRow(r2) {
52938
- const head = `${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)}`;
53340
+ const head = `${fmtType(r2.type)} ${import_picocolors28.default.bold(r2.slug)}`;
52939
53341
  switch (r2.status) {
52940
53342
  case "added-only-local":
52941
- return `${head} ${import_picocolors27.default.dim("(new — only in brainbase.yaml)")}`;
53343
+ return `${head} ${import_picocolors28.default.dim("(new — only in brainbase.agent.yaml)")}`;
52942
53344
  case "added-cloud":
52943
- return `${head} ${import_picocolors27.default.dim("(new on cloud)")}`;
53345
+ return `${head} ${import_picocolors28.default.dim("(new on cloud)")}`;
52944
53346
  case "added-local":
52945
- return `${head} ${import_picocolors27.default.dim("(present locally and on cloud, never synced here)")}`;
53347
+ return `${head} ${import_picocolors28.default.dim("(present locally and on cloud, never synced here)")}`;
52946
53348
  case "removed-local":
52947
- return `${head} ${import_picocolors27.default.dim("(removed from brainbase.yaml)")}`;
53349
+ return `${head} ${import_picocolors28.default.dim("(removed from brainbase.agent.yaml)")}`;
52948
53350
  case "removed-cloud":
52949
- return `${head} ${import_picocolors27.default.dim("(removed on cloud)")}`;
53351
+ return `${head} ${import_picocolors28.default.dim("(removed on cloud)")}`;
52950
53352
  case "modified-local":
52951
- return `${head} ${import_picocolors27.default.dim("(you edited it)")}`;
53353
+ return `${head} ${import_picocolors28.default.dim("(you edited it)")}`;
52952
53354
  case "modified-cloud":
52953
- return `${head} ${import_picocolors27.default.dim("(cloud was updated)")}`;
53355
+ return `${head} ${import_picocolors28.default.dim("(cloud was updated)")}`;
52954
53356
  case "modified-both":
52955
- return `${head} ${import_picocolors27.default.dim("(both diverged — needs resolution)")}`;
53357
+ return `${head} ${import_picocolors28.default.dim("(both diverged — needs resolution)")}`;
52956
53358
  default:
52957
53359
  return head;
52958
53360
  }
@@ -52989,10 +53391,11 @@ function formatExport(shell, key2, value) {
52989
53391
  }
52990
53392
 
52991
53393
  // src/cli/agent-create.ts
52992
- var import_picocolors29 = __toESM(require_picocolors(), 1);
53394
+ import path49 from "node:path";
53395
+ var import_picocolors30 = __toESM(require_picocolors(), 1);
52993
53396
 
52994
53397
  // src/ui/box.ts
52995
- var import_picocolors28 = __toESM(require_picocolors(), 1);
53398
+ var import_picocolors29 = __toESM(require_picocolors(), 1);
52996
53399
  var H3 = "─";
52997
53400
  var TINT = {
52998
53401
  ok: COLOR.ok,
@@ -53004,20 +53407,28 @@ var TINT = {
53004
53407
  function divider(label, width = 56, indent = 2) {
53005
53408
  const ind = " ".repeat(indent);
53006
53409
  if (!label)
53007
- return `${ind}${import_picocolors28.default.dim(H3.repeat(width))}`;
53410
+ return `${ind}${import_picocolors29.default.dim(H3.repeat(width))}`;
53008
53411
  const labelText = ` ${label} `;
53009
53412
  const labelLen = visibleLength(labelText);
53010
- const left = import_picocolors28.default.dim(H3.repeat(2));
53011
- const right = import_picocolors28.default.dim(H3.repeat(Math.max(0, width - labelLen - 2)));
53012
- return `${ind}${left}${import_picocolors28.default.bold(import_picocolors28.default.dim(labelText))}${right}`;
53413
+ const left = import_picocolors29.default.dim(H3.repeat(2));
53414
+ const right = import_picocolors29.default.dim(H3.repeat(Math.max(0, width - labelLen - 2)));
53415
+ return `${ind}${left}${import_picocolors29.default.bold(import_picocolors29.default.dim(labelText))}${right}`;
53013
53416
  }
53014
53417
  function tip(text, indent = 2) {
53015
- return " ".repeat(indent) + import_picocolors28.default.dim("›") + " " + import_picocolors28.default.dim(text);
53418
+ return " ".repeat(indent) + import_picocolors29.default.dim("›") + " " + import_picocolors29.default.dim(text);
53016
53419
  }
53017
53420
 
53018
53421
  // src/cli/agent-create.ts
53019
53422
  async function runAgentCreate(cwd2, args) {
53020
- banner("agent create — make a new brainbase agent and link this folder");
53423
+ banner("agent create — claim a brainbase.agent.yaml and link this folder");
53424
+ let manifest = await loadOrScaffoldManifest(cwd2, args);
53425
+ if (!manifest)
53426
+ return;
53427
+ if (manifest.id) {
53428
+ f2.warn(`This folder already belongs to an agent — ${import_picocolors30.default.bold(manifest.agent.name)} (${import_picocolors30.default.dim(manifest.id)}).`);
53429
+ f2.info(`If you want to detach it, run ${import_picocolors30.default.cyan("brainbase unlink")} first; or move to a different directory.`);
53430
+ return;
53431
+ }
53021
53432
  const orgsSpinner = de();
53022
53433
  orgsSpinner.start("Loading your organizations…");
53023
53434
  let orgs;
@@ -53044,7 +53455,7 @@ async function runAgentCreate(cwd2, args) {
53044
53455
  org = found;
53045
53456
  } else if (orgs.length === 1) {
53046
53457
  org = orgs[0];
53047
- f2.info(`Using organization ${import_picocolors29.default.bold(org.name)}.`);
53458
+ f2.info(`Using organization ${import_picocolors30.default.bold(org.name)}.`);
53048
53459
  } else {
53049
53460
  const orgChoice = await ie({
53050
53461
  message: "Pick an organization",
@@ -53092,7 +53503,7 @@ async function runAgentCreate(cwd2, args) {
53092
53503
  createSpinner2.start("Creating team…");
53093
53504
  try {
53094
53505
  team = await api.createTeam(org.id, teamName.trim());
53095
- createSpinner2.stop(`Created team ${import_picocolors29.default.bold(team.name)}.`);
53506
+ createSpinner2.stop(`Created team ${import_picocolors30.default.bold(team.name)}.`);
53096
53507
  } catch (err) {
53097
53508
  createSpinner2.stop("Failed.");
53098
53509
  handleApiError4(err);
@@ -53102,8 +53513,8 @@ async function runAgentCreate(cwd2, args) {
53102
53513
  team = teams.find((t) => t.id === picked);
53103
53514
  }
53104
53515
  }
53105
- const harness = normalizeHarnessId(args.harness ?? await pickHarness(cwd2));
53106
- let agentName = args.name?.trim();
53516
+ const harness = normalizeHarnessId(args.harness ?? manifest.harness ?? await pickHarness(cwd2));
53517
+ let agentName = args.name?.trim() || manifest.agent.name.trim();
53107
53518
  if (!agentName) {
53108
53519
  const ans = await te({
53109
53520
  message: "Agent name",
@@ -53112,7 +53523,7 @@ async function runAgentCreate(cwd2, args) {
53112
53523
  });
53113
53524
  agentName = ensureNotCancelled(ans).trim();
53114
53525
  }
53115
- let tagline = args.tagline?.trim() || undefined;
53526
+ let tagline = (args.tagline ?? manifest.agent.tagline)?.trim() || undefined;
53116
53527
  if (tagline === undefined && !args.yes) {
53117
53528
  const ans = await te({
53118
53529
  message: "Tagline",
@@ -53124,11 +53535,11 @@ async function runAgentCreate(cwd2, args) {
53124
53535
  }
53125
53536
  if (!args.yes) {
53126
53537
  le([
53127
- `${import_picocolors29.default.dim("org")} ${import_picocolors29.default.bold(org.name)}`,
53128
- `${import_picocolors29.default.dim("team")} ${import_picocolors29.default.bold(team.name)}`,
53129
- `${import_picocolors29.default.dim("harness")} ${import_picocolors29.default.bold(harness)}`,
53130
- `${import_picocolors29.default.dim("agent")} ${import_picocolors29.default.bold(agentName)}`,
53131
- ...tagline ? [`${import_picocolors29.default.dim("tagline")} ${tagline}`] : []
53538
+ `${import_picocolors30.default.dim("org")} ${import_picocolors30.default.bold(org.name)}`,
53539
+ `${import_picocolors30.default.dim("team")} ${import_picocolors30.default.bold(team.name)}`,
53540
+ `${import_picocolors30.default.dim("harness")} ${import_picocolors30.default.bold(harness)}`,
53541
+ `${import_picocolors30.default.dim("agent")} ${import_picocolors30.default.bold(agentName)}`,
53542
+ ...tagline ? [`${import_picocolors30.default.dim("tagline")} ${tagline}`] : []
53132
53543
  ].join(`
53133
53544
  `), "Will create");
53134
53545
  const confirmed = await se({ message: "Create this agent?", initialValue: true });
@@ -53137,6 +53548,19 @@ async function runAgentCreate(cwd2, args) {
53137
53548
  return;
53138
53549
  }
53139
53550
  }
53551
+ let resolvedEntrypoint;
53552
+ if (manifest.entrypoint) {
53553
+ const body = resolveEntrypoint(cwd2, manifest);
53554
+ if (body === null) {
53555
+ if (manifest.entrypoint.file) {
53556
+ f2.error(`Entrypoint file ${import_picocolors30.default.bold(manifest.entrypoint.file)} not found.`);
53557
+ } else {
53558
+ f2.error("Entrypoint block is empty.");
53559
+ }
53560
+ return;
53561
+ }
53562
+ resolvedEntrypoint = body;
53563
+ }
53140
53564
  const createSpinner = de();
53141
53565
  createSpinner.start("Creating agent…");
53142
53566
  let agent;
@@ -53146,9 +53570,10 @@ async function runAgentCreate(cwd2, args) {
53146
53570
  team_id: team.id,
53147
53571
  name: agentName,
53148
53572
  tagline,
53149
- harness
53573
+ harness,
53574
+ ...resolvedEntrypoint !== undefined ? { entrypoint: resolvedEntrypoint } : {}
53150
53575
  });
53151
- createSpinner.stop(`Created ${import_picocolors29.default.bold(agent.name)}.`);
53576
+ createSpinner.stop(`Created ${import_picocolors30.default.bold(agent.name)}.`);
53152
53577
  } catch (err) {
53153
53578
  createSpinner.stop("Failed.");
53154
53579
  handleApiError4(err);
@@ -53161,7 +53586,7 @@ async function runAgentCreate(cwd2, args) {
53161
53586
  let wantsTracking = true;
53162
53587
  if (!args.yes) {
53163
53588
  const ans = await se({
53164
- message: `Track ${harness} conversations on the brainbase platform? ${import_picocolors29.default.dim("(routes LLM calls through brainbase so they appear under this agent)")}`,
53589
+ message: `Track ${harness} conversations on the brainbase platform? ${import_picocolors30.default.dim("(routes LLM calls through brainbase so they appear under this agent)")}`,
53165
53590
  initialValue: true
53166
53591
  });
53167
53592
  wantsTracking = ensureNotCancelled(ans);
@@ -53200,71 +53625,455 @@ async function runAgentCreate(cwd2, args) {
53200
53625
  }
53201
53626
  }
53202
53627
  }
53203
- const link2 = {
53204
- schemaVersion: 1,
53205
- agent_id: agent.id,
53206
- org_id: agent.org_id,
53207
- team_id: agent.team_id,
53208
- slug: agent.slug,
53209
- name: agent.name,
53210
- tagline: agent.tagline,
53211
- url: agent.url,
53212
- linked_at: new Date().toISOString(),
53213
- linked_by: session?.email ?? session?.user_id,
53214
- harness,
53215
- tracking
53216
- };
53217
- writeLink(cwd2, link2);
53218
- $e(`Created ${import_picocolors29.default.bold(agent.name)} and linked this folder.`);
53628
+ const link2 = {
53629
+ schemaVersion: 1,
53630
+ agent_id: agent.id,
53631
+ org_id: agent.org_id,
53632
+ team_id: agent.team_id,
53633
+ slug: agent.slug,
53634
+ name: agent.name,
53635
+ tagline: agent.tagline,
53636
+ url: agent.url,
53637
+ linked_at: new Date().toISOString(),
53638
+ linked_by: session?.email ?? session?.user_id,
53639
+ harness,
53640
+ tracking
53641
+ };
53642
+ writeLink(cwd2, link2);
53643
+ manifest = readManifest(cwd2);
53644
+ let updatedCloud = null;
53645
+ const hasContent = !!manifest.instructions || manifest.skills.length > 0 || (manifest.mcp ?? []).length > 0;
53646
+ if (hasContent) {
53647
+ const outgoing = await buildOutgoingComponents(cwd2, manifest, null);
53648
+ if (outgoing === null) {
53649
+ f2.warn(`Agent created, but local content wasn't uploaded. Fix the issue above and run ${import_picocolors30.default.cyan("brainbase agent push")}.`);
53650
+ } else if (outgoing.length > 0) {
53651
+ const pushSpinner = de();
53652
+ pushSpinner.start("Pushing local content…");
53653
+ try {
53654
+ updatedCloud = await api.pushAgentManifest(agent.id, {
53655
+ components: outgoing,
53656
+ base_revision: 0
53657
+ });
53658
+ pushSpinner.stop(`Pushed at revision ${updatedCloud.revision}.`);
53659
+ } catch (err) {
53660
+ pushSpinner.stop("Failed.");
53661
+ if (err instanceof ApiError) {
53662
+ f2.warn(`Content upload failed: ${err.message}. Run ${import_picocolors30.default.cyan("brainbase agent push")} to retry.`);
53663
+ } else {
53664
+ f2.warn(`Content upload failed: ${err.message}. Run ${import_picocolors30.default.cyan("brainbase agent push")} to retry.`);
53665
+ }
53666
+ }
53667
+ }
53668
+ }
53669
+ if (updatedCloud) {
53670
+ const syncedComponents = updatedCloud.components.map((c2) => ({
53671
+ type: c2.type,
53672
+ slug: c2.slug,
53673
+ hash: c2.hash,
53674
+ installedPaths: []
53675
+ }));
53676
+ const state = {
53677
+ schemaVersion: 1,
53678
+ agent_id: agent.id,
53679
+ revision: updatedCloud.revision,
53680
+ synced_at: new Date().toISOString(),
53681
+ components: syncedComponents,
53682
+ agentMeta: {
53683
+ name: agent.name,
53684
+ tagline: agent.tagline,
53685
+ ...resolvedEntrypoint ? { entrypoint: resolvedEntrypoint } : {}
53686
+ }
53687
+ };
53688
+ writeSyncState(cwd2, state);
53689
+ }
53690
+ $e(`Created ${import_picocolors30.default.bold(agent.name)} and linked this folder.`);
53691
+ await showResultCard({
53692
+ title: "CREATED",
53693
+ tone: "ok",
53694
+ subtitle: link2.tagline ? `${link2.name} — ${link2.tagline}` : link2.name,
53695
+ meta: [
53696
+ ["slug", link2.slug],
53697
+ ["agent", link2.agent_id],
53698
+ ...link2.url ? [["url", link2.url]] : []
53699
+ ]
53700
+ });
53701
+ console.log();
53702
+ if (tracking && harness === "codex") {
53703
+ console.log(tip(`Run ${import_picocolors30.default.cyan("codex")} once in this folder and approve trust ${import_picocolors30.default.dim("— Codex only loads project-scope config in trusted projects.")}`));
53704
+ }
53705
+ console.log(tip(`brainbase agent unpack ${import_picocolors30.default.dim("— install harness files (skills/mcps) under .claude/, .codex/, …")}`));
53706
+ console.log();
53707
+ }
53708
+ async function loadOrScaffoldManifest(cwd2, args) {
53709
+ if (hasManifest(cwd2)) {
53710
+ try {
53711
+ return readManifest(cwd2);
53712
+ } catch (err) {
53713
+ f2.error(err.message);
53714
+ return null;
53715
+ }
53716
+ }
53717
+ f2.warn(`No ${import_picocolors30.default.bold(AGENT_MANIFEST_FILE)} here.`);
53718
+ if (!args.yes) {
53719
+ const ans = await se({
53720
+ message: `Scaffold a minimal ${import_picocolors30.default.bold(AGENT_MANIFEST_FILE)} and continue?`,
53721
+ initialValue: true
53722
+ });
53723
+ if (!ensureNotCancelled(ans)) {
53724
+ $e("Aborted.");
53725
+ return null;
53726
+ }
53727
+ }
53728
+ const seedName = args.name?.trim() ?? path49.basename(path49.resolve(cwd2)) ?? "My Agent";
53729
+ const seedHarness = args.harness ? normalizeHarnessId(args.harness) : undefined;
53730
+ const scaffold = {
53731
+ schema: 1,
53732
+ ...seedHarness ? { harness: seedHarness } : {},
53733
+ agent: { name: seedName, ...args.tagline ? { tagline: args.tagline } : {} },
53734
+ skills: [],
53735
+ mcp: []
53736
+ };
53737
+ try {
53738
+ writeManifest(cwd2, scaffold);
53739
+ f2.info(`Wrote ${import_picocolors30.default.bold(AGENT_MANIFEST_FILE)}.`);
53740
+ } catch (err) {
53741
+ f2.error(`Failed to write manifest: ${err.message}`);
53742
+ return null;
53743
+ }
53744
+ return scaffold;
53745
+ }
53746
+ async function pickHarness(cwd2) {
53747
+ const detections = await detectHarnesses(cwd2);
53748
+ const detected = detections.filter((d3) => d3.detection.detected);
53749
+ if (detected.length === 1) {
53750
+ f2.info(`Detected harness: ${import_picocolors30.default.bold(detected[0].adapter.displayName)}.`);
53751
+ return detected[0].adapter.id;
53752
+ }
53753
+ const choice = await ie({
53754
+ message: detected.length > 1 ? "Multiple harnesses detected — which one is this agent for?" : "No harness detected here. Which harness is this agent for?",
53755
+ options: detections.map((d3) => ({
53756
+ value: d3.adapter.id,
53757
+ label: d3.adapter.displayName,
53758
+ hint: d3.detection.detected ? "detected" : undefined
53759
+ }))
53760
+ });
53761
+ return ensureNotCancelled(choice);
53762
+ }
53763
+ function handleApiError4(err) {
53764
+ if (err instanceof ApiError) {
53765
+ if (err.status === 401) {
53766
+ f2.error("Your session is invalid. Run `brainbase login` and try again.");
53767
+ } else {
53768
+ f2.error(err.message);
53769
+ }
53770
+ } else {
53771
+ f2.error(err.message);
53772
+ }
53773
+ $e("Aborted.");
53774
+ }
53775
+
53776
+ // src/cli/agent-unpack.ts
53777
+ var import_picocolors31 = __toESM(require_picocolors(), 1);
53778
+
53779
+ // src/core/agent-fresh-install.ts
53780
+ import path50 from "node:path";
53781
+ import fs46 from "node:fs";
53782
+ 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
53954
+ async function runAgentUnpack(cwd2, args) {
53955
+ banner("agent unpack — install this agent into a harness layout");
53956
+ if (!hasManifest(cwd2)) {
53957
+ f2.error(`No ${import_picocolors31.default.bold(AGENT_MANIFEST_FILE)} here.`);
53958
+ f2.info(`Run ${import_picocolors31.default.cyan("brainbase agent pull <id>")} to bring an agent into this folder first.`);
53959
+ return;
53960
+ }
53961
+ let manifest;
53962
+ try {
53963
+ manifest = readManifest(cwd2);
53964
+ } catch (err) {
53965
+ f2.error(err.message);
53966
+ return;
53967
+ }
53968
+ if (!manifest.id) {
53969
+ f2.error(`${import_picocolors31.default.bold(AGENT_MANIFEST_FILE)} is unclaimed (no ${import_picocolors31.default.cyan("id")}).`);
53970
+ f2.info(`Run ${import_picocolors31.default.cyan("brainbase agent create")} to claim it, ` + `or ${import_picocolors31.default.cyan("brainbase agent pull <id>")} to link it to an existing agent.`);
53971
+ return;
53972
+ }
53973
+ let harness;
53974
+ if (args.harness) {
53975
+ harness = normalizeHarnessId(args.harness);
53976
+ } else if (args.yes) {
53977
+ if (!manifest.harness) {
53978
+ f2.error(`--yes mode but no harness — set ${import_picocolors31.default.cyan("harness")} in the manifest or pass ${import_picocolors31.default.cyan("--harness")}.`);
53979
+ return;
53980
+ }
53981
+ harness = normalizeHarnessId(manifest.harness);
53982
+ } else {
53983
+ harness = await pickHarness2(manifest.harness);
53984
+ }
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
+ if (!args.yes) {
53999
+ const ok = await se({
54000
+ message: `Install ${import_picocolors31.default.bold(cloudAgent.name)} as ${import_picocolors31.default.bold(harness)} here?`,
54001
+ initialValue: true
54002
+ });
54003
+ if (!ensureNotCancelled(ok)) {
54004
+ $e("Aborted.");
54005
+ return;
54006
+ }
54007
+ }
54008
+ const prevLink = readLink(cwd2);
54009
+ 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
+ });
54027
+ } catch (err) {
54028
+ f2.error(`Install failed: ${err.message}`);
54029
+ return;
54030
+ }
54031
+ manifest = readManifest(cwd2);
54032
+ if (manifest.harness !== harness) {
54033
+ manifest.harness = harness;
54034
+ writeManifest(cwd2, manifest);
54035
+ }
54036
+ $e(`Unpacked ${import_picocolors31.default.bold(cloudAgent.name)} as ${import_picocolors31.default.bold(harness)}.`);
53219
54037
  await showResultCard({
53220
- title: "CREATED",
54038
+ title: "UNPACKED",
53221
54039
  tone: "ok",
53222
- subtitle: link2.tagline ? `${link2.name} — ${link2.tagline}` : link2.name,
54040
+ subtitle: cloudAgent.name,
53223
54041
  meta: [
53224
- ["slug", link2.slug],
53225
- ["agent", link2.agent_id],
53226
- ...link2.url ? [["url", link2.url]] : []
54042
+ ["harness", harness],
54043
+ ["agent", cloudAgent.id],
54044
+ ...cloudAgent.url ? [["url", cloudAgent.url]] : []
53227
54045
  ]
53228
54046
  });
53229
- console.log();
53230
- if (tracking && harness === "codex") {
53231
- console.log(tip(`Run ${import_picocolors29.default.cyan("codex")} once in this folder and approve trust ${import_picocolors29.default.dim("— Codex only loads project-scope config in trusted projects.")}`));
53232
- }
53233
- console.log(tip(`brainbase agent pull ${import_picocolors29.default.dim("— pull the agent contents into this folder")}`));
53234
- console.log();
53235
54047
  }
53236
- async function pickHarness(cwd2) {
53237
- const detections = await detectHarnesses(cwd2);
53238
- const detected = detections.filter((d3) => d3.detection.detected);
53239
- if (detected.length === 1) {
53240
- f2.info(`Detected harness: ${import_picocolors29.default.bold(detected[0].adapter.displayName)}.`);
53241
- return detected[0].adapter.id;
53242
- }
54048
+ async function pickHarness2(current) {
54049
+ const initial = current ? normalizeHarnessId(current) : undefined;
53243
54050
  const choice = await ie({
53244
- message: detected.length > 1 ? "Multiple harnesses detected — which one is this agent for?" : "No harness detected here. Which harness is this agent for?",
53245
- options: detections.map((d3) => ({
53246
- value: d3.adapter.id,
53247
- label: d3.adapter.displayName,
53248
- hint: d3.detection.detected ? "detected" : undefined
53249
- }))
54051
+ message: "Pick a harness to install as",
54052
+ options: adapters.map((a3) => ({
54053
+ value: a3.id,
54054
+ label: a3.displayName,
54055
+ hint: a3.id === initial ? "current" : undefined
54056
+ })),
54057
+ initialValue: initial ?? adapters[0].id
53250
54058
  });
53251
54059
  return ensureNotCancelled(choice);
53252
54060
  }
53253
- function handleApiError4(err) {
54061
+ function handleApiError5(err) {
53254
54062
  if (err instanceof ApiError) {
53255
54063
  if (err.status === 401) {
53256
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.`);
53257
54067
  } else {
53258
54068
  f2.error(err.message);
53259
54069
  }
53260
54070
  } else {
53261
54071
  f2.error(err.message);
53262
54072
  }
53263
- $e("Aborted.");
53264
54073
  }
53265
54074
 
53266
54075
  // src/cli/agent.ts
53267
- async function runAgent(cwd2, sub, _args, opts) {
54076
+ async function runAgent(cwd2, sub, args, opts) {
53268
54077
  switch (sub) {
53269
54078
  case "create":
53270
54079
  await runAgentCreate(cwd2, {
@@ -53278,10 +54087,22 @@ async function runAgent(cwd2, sub, _args, opts) {
53278
54087
  });
53279
54088
  return;
53280
54089
  case "pull":
53281
- await runAgentPull(cwd2, opts);
54090
+ await runAgentPull(cwd2, {
54091
+ yes: opts.yes,
54092
+ scope: opts.scope,
54093
+ agentIdArg: args[0],
54094
+ force: opts.force
54095
+ });
53282
54096
  return;
53283
54097
  case "push":
53284
- await runAgentPush(cwd2, opts);
54098
+ await runAgentPush(cwd2, { yes: opts.yes });
54099
+ return;
54100
+ case "unpack":
54101
+ await runAgentUnpack(cwd2, {
54102
+ yes: opts.yes,
54103
+ scope: opts.scope,
54104
+ harness: opts.harness
54105
+ });
53285
54106
  return;
53286
54107
  case "status":
53287
54108
  await runAgentStatus(cwd2);
@@ -53305,29 +54126,30 @@ async function runAgent(cwd2, sub, _args, opts) {
53305
54126
  function printHelp() {
53306
54127
  const out = [];
53307
54128
  out.push("");
53308
- out.push(` ${import_picocolors30.default.bold("brainbase agent")} ${import_picocolors30.default.dim("<sub> [options]")}`);
54129
+ out.push(` ${import_picocolors32.default.bold("brainbase agent")} ${import_picocolors32.default.dim("<sub> [options]")}`);
53309
54130
  out.push("");
53310
- out.push(` ${import_picocolors30.default.cyan("create")} ${import_picocolors30.default.dim("make a new agent on the cloud and link this folder to it")}`);
53311
- out.push(` ${import_picocolors30.default.cyan("pull")} ${import_picocolors30.default.dim("apply cloud changes into this folder")}`);
53312
- out.push(` ${import_picocolors30.default.cyan("push")} ${import_picocolors30.default.dim("send local changes to the cloud")}`);
53313
- out.push(` ${import_picocolors30.default.cyan("status")} ${import_picocolors30.default.dim("show what would push and what would pull")}`);
53314
- out.push(` ${import_picocolors30.default.cyan("env")} ${import_picocolors30.default.dim('print export statements use with `eval "$(brainbase agent env)"`')}`);
54131
+ out.push(` ${import_picocolors32.default.cyan("create")} ${import_picocolors32.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
54132
+ out.push(` ${import_picocolors32.default.cyan("pull")} ${import_picocolors32.default.dim("[<id>]")} ${import_picocolors32.default.dim("apply cloud changes into this folder — pass <id> to switch (--force to override)")}`);
54133
+ out.push(` ${import_picocolors32.default.cyan("push")} ${import_picocolors32.default.dim("send local changes to the cloud")}`);
54134
+ out.push(` ${import_picocolors32.default.cyan("unpack")} ${import_picocolors32.default.dim("install the claimed agent into a harness layout (--harness to override)")}`);
54135
+ out.push(` ${import_picocolors32.default.cyan("status")} ${import_picocolors32.default.dim("show what would push and what would pull")}`);
54136
+ out.push(` ${import_picocolors32.default.cyan("env")} ${import_picocolors32.default.dim('print export statements — use with `eval "$(brainbase agent env)"`')}`);
53315
54137
  out.push("");
53316
54138
  console.log(out.join(`
53317
54139
  `));
53318
54140
  }
53319
54141
 
53320
54142
  // src/cli/orchestration.ts
53321
- var import_picocolors35 = __toESM(require_picocolors(), 1);
54143
+ var import_picocolors37 = __toESM(require_picocolors(), 1);
53322
54144
 
53323
54145
  // src/cli/orchestration-pull.ts
53324
- import path52 from "node:path";
54146
+ import path53 from "node:path";
53325
54147
  import fs49 from "node:fs";
53326
- var import_picocolors31 = __toESM(require_picocolors(), 1);
54148
+ var import_picocolors33 = __toESM(require_picocolors(), 1);
53327
54149
 
53328
54150
  // src/core/orchestration-manifest.ts
53329
- import path49 from "node:path";
53330
- import fs46 from "node:fs";
54151
+ import path51 from "node:path";
54152
+ import fs47 from "node:fs";
53331
54153
  var import_yaml3 = __toESM(require_dist(), 1);
53332
54154
  var ORCH_MANIFEST_FILE = "brainbase-orchestration.yaml";
53333
54155
  var ORCH_MEMBERS_DIR = "agents";
@@ -53355,16 +54177,16 @@ var OrchestrationManifestSchema = exports_external.object({
53355
54177
  edges: exports_external.array(EdgeSchema).default([])
53356
54178
  });
53357
54179
  function orchManifestPath(cwd2) {
53358
- return path49.join(cwd2, ORCH_MANIFEST_FILE);
54180
+ return path51.join(cwd2, ORCH_MANIFEST_FILE);
53359
54181
  }
53360
54182
  function hasOrchManifest(cwd2) {
53361
- return fs46.existsSync(orchManifestPath(cwd2));
54183
+ return fs47.existsSync(orchManifestPath(cwd2));
53362
54184
  }
53363
54185
  function readOrchManifest(cwd2) {
53364
54186
  const p2 = orchManifestPath(cwd2);
53365
- if (!fs46.existsSync(p2))
54187
+ if (!fs47.existsSync(p2))
53366
54188
  return null;
53367
- const raw = fs46.readFileSync(p2, "utf8");
54189
+ const raw = fs47.readFileSync(p2, "utf8");
53368
54190
  let parsed;
53369
54191
  try {
53370
54192
  parsed = import_yaml3.default.parse(raw);
@@ -53383,15 +54205,15 @@ function writeOrchManifest(cwd2, manifest) {
53383
54205
  doc.commentBefore = ` brainbase-orchestration.yaml — declarative orchestration manifest.
53384
54206
  ` + ` Committed to source control. Edit by hand, then
53385
54207
  ` + " `brainbase orchestration push`. Member agents live under ./agents/.";
53386
- fs46.writeFileSync(orchManifestPath(cwd2), String(doc), "utf8");
54208
+ fs47.writeFileSync(orchManifestPath(cwd2), String(doc), "utf8");
53387
54209
  }
53388
54210
  function memberDir(cwd2, slug) {
53389
- return path49.join(cwd2, ORCH_MEMBERS_DIR, slug);
54211
+ return path51.join(cwd2, ORCH_MEMBERS_DIR, slug);
53390
54212
  }
53391
54213
 
53392
54214
  // src/core/orchestration-link.ts
53393
- import path50 from "node:path";
53394
- import fs47 from "node:fs";
54215
+ import path52 from "node:path";
54216
+ import fs48 from "node:fs";
53395
54217
  var ORCH_LINK_FILE = "orchestration-link.json";
53396
54218
  var ORCH_SYNC_STATE_FILE = "orchestration-sync-state.json";
53397
54219
  var OrchestrationLinkSchema = exports_external.object({
@@ -53425,10 +54247,10 @@ var OrchestrationSyncStateSchema = exports_external.object({
53425
54247
  edges: exports_external.array(SyncedEdgeSchema)
53426
54248
  });
53427
54249
  function orchLinkPath(cwd2) {
53428
- return path50.join(cwd2, LINK_DIR, ORCH_LINK_FILE);
54250
+ return path52.join(cwd2, LINK_DIR, ORCH_LINK_FILE);
53429
54251
  }
53430
54252
  function orchSyncStatePath(cwd2) {
53431
- return path50.join(cwd2, LINK_DIR, ORCH_SYNC_STATE_FILE);
54253
+ return path52.join(cwd2, LINK_DIR, ORCH_SYNC_STATE_FILE);
53432
54254
  }
53433
54255
  function readOrchLink(cwd2) {
53434
54256
  const p2 = orchLinkPath(cwd2);
@@ -53441,7 +54263,7 @@ function readOrchLink(cwd2) {
53441
54263
  }
53442
54264
  }
53443
54265
  function writeOrchLink(cwd2, link2) {
53444
- ensureDir(path50.join(cwd2, LINK_DIR));
54266
+ ensureDir(path52.join(cwd2, LINK_DIR));
53445
54267
  const clean = {};
53446
54268
  for (const [k3, v3] of Object.entries(link2)) {
53447
54269
  if (v3 !== null && v3 !== undefined)
@@ -53461,200 +54283,28 @@ function readOrchSyncState(cwd2) {
53461
54283
  }
53462
54284
  }
53463
54285
  function writeOrchSyncState(cwd2, state) {
53464
- ensureDir(path50.join(cwd2, LINK_DIR));
54286
+ ensureDir(path52.join(cwd2, LINK_DIR));
53465
54287
  writeJson(orchSyncStatePath(cwd2), state);
53466
54288
  ensureGitignore2(cwd2);
53467
54289
  }
53468
54290
  function ensureGitignore2(cwd2) {
53469
- const ignorePath = path50.join(cwd2, LINK_DIR, ".gitignore");
54291
+ const ignorePath = path52.join(cwd2, LINK_DIR, ".gitignore");
53470
54292
  const desired = `${ORCH_SYNC_STATE_FILE}
53471
54293
  `;
53472
54294
  try {
53473
54295
  if (!exists(ignorePath)) {
53474
- fs47.writeFileSync(ignorePath, desired);
54296
+ fs48.writeFileSync(ignorePath, desired);
53475
54297
  return;
53476
54298
  }
53477
- const current = fs47.readFileSync(ignorePath, "utf8");
54299
+ const current = fs48.readFileSync(ignorePath, "utf8");
53478
54300
  if (!current.split(/\r?\n/).some((l2) => l2.trim() === ORCH_SYNC_STATE_FILE)) {
53479
- fs47.writeFileSync(ignorePath, current.endsWith(`
54301
+ fs48.writeFileSync(ignorePath, current.endsWith(`
53480
54302
  `) ? current + desired : current + `
53481
54303
  ` + desired);
53482
54304
  }
53483
54305
  } catch {}
53484
54306
  }
53485
54307
 
53486
- // src/core/agent-fresh-install.ts
53487
- import path51 from "node:path";
53488
- import fs48 from "node:fs";
53489
- import os13 from "node:os";
53490
- async function installAgentFresh(input) {
53491
- const { cwd: cwd2, agent, cloud, harness } = input;
53492
- const scope = input.scope ?? "project";
53493
- ensureDir(cwd2);
53494
- const stageRoot = stageManifestComponents2(cloud.components);
53495
- const justInstalledPaths = new Map;
53496
- const cloudHasOrchestrationMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === ORCHESTRATION_MCP_SLUG);
53497
- const needOrchestrationMcpInstall = !cloudHasOrchestrationMcp;
53498
- const cloudHasMemoryMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === MEMORY_MCP_SLUG);
53499
- const needMemoryMcpInstall = !cloudHasMemoryMcp;
53500
- try {
53501
- if (cloud.components.length > 0 || needOrchestrationMcpInstall || needMemoryMcpInstall) {
53502
- const toInstall = cloud.components.map((c2) => ({
53503
- type: c2.type,
53504
- slug: c2.slug,
53505
- scope,
53506
- rootDir: path51.join(stageRoot, c2.type, c2.slug),
53507
- description: c2.description,
53508
- meta: c2.meta,
53509
- payload: c2.meta?.mcp,
53510
- checksum: c2.hash
53511
- }));
53512
- if (needOrchestrationMcpInstall) {
53513
- toInstall.push(buildOrchestrationMcpComponent(scope));
53514
- }
53515
- if (needMemoryMcpInstall) {
53516
- toInstall.push(buildMemoryMcpComponent(scope));
53517
- }
53518
- const installOpts = {
53519
- cwd: cwd2,
53520
- scope,
53521
- resolveConflict: async (_c) => "overwrite",
53522
- resolveSecret: async () => null
53523
- };
53524
- const result = await runHarnessInstall3(harness, toInstall, installOpts, agent.name);
53525
- for (const o2 of result.installed) {
53526
- justInstalledPaths.set(`${o2.type}/${o2.slug}`, o2.installedPaths);
53527
- }
53528
- }
53529
- materializeInstructions2(cwd2, cloud);
53530
- const manifest = buildManifestFromCloud(cloud, agent);
53531
- writeManifest(cwd2, manifest);
53532
- writeLink(cwd2, {
53533
- schemaVersion: 1,
53534
- agent_id: agent.id,
53535
- org_id: agent.org_id,
53536
- team_id: agent.team_id,
53537
- slug: agent.slug,
53538
- name: agent.name,
53539
- tagline: agent.tagline,
53540
- url: agent.url,
53541
- linked_at: new Date().toISOString(),
53542
- harness
53543
- });
53544
- const syncedComponents = cloud.components.map((c2) => ({
53545
- type: c2.type,
53546
- slug: c2.slug,
53547
- hash: c2.hash,
53548
- installedPaths: justInstalledPaths.get(`${c2.type}/${c2.slug}`) ?? []
53549
- }));
53550
- writeSyncState(cwd2, {
53551
- schemaVersion: 1,
53552
- agent_id: agent.id,
53553
- revision: cloud.revision,
53554
- synced_at: new Date().toISOString(),
53555
- components: syncedComponents,
53556
- agentMeta: { name: agent.name, tagline: agent.tagline }
53557
- });
53558
- if (input.pullSecrets !== false) {
53559
- await pullAgentSecrets(cwd2, agent.id);
53560
- }
53561
- return {
53562
- installedPaths: justInstalledPaths,
53563
- manifest,
53564
- syncedComponents
53565
- };
53566
- } finally {
53567
- try {
53568
- fs48.rmSync(stageRoot, { recursive: true, force: true });
53569
- } catch {}
53570
- }
53571
- }
53572
- function stageManifestComponents2(components) {
53573
- const root = fs48.mkdtempSync(path51.join(os13.tmpdir(), "brainbase-orch-pull-"));
53574
- for (const c2 of components) {
53575
- const compDir = path51.join(root, c2.type, c2.slug);
53576
- ensureDir(compDir);
53577
- for (const f4 of c2.files) {
53578
- const target = path51.join(compDir, f4.path);
53579
- ensureDir(path51.dirname(target));
53580
- fs48.writeFileSync(target, f4.content);
53581
- }
53582
- }
53583
- return root;
53584
- }
53585
- function runHarnessInstall3(harnessId, components, opts, agentName) {
53586
- if (harnessId === "claude-code")
53587
- return installClaudeCodeWithCtx(components, opts, agentName);
53588
- if (harnessId === "codex")
53589
- return installCodexWithCtx(components, opts, agentName);
53590
- if (harnessId === "kafka")
53591
- return installKafkaWithCtx(components, opts, agentName);
53592
- return getAdapter(harnessId).install(components, opts);
53593
- }
53594
- function materializeInstructions2(cwd2, cloud) {
53595
- for (const c2 of cloud.components) {
53596
- if (c2.type !== "instruction")
53597
- continue;
53598
- const body = c2.files[0]?.content ?? "";
53599
- if (!body.trim())
53600
- continue;
53601
- fs48.writeFileSync(path51.join(cwd2, DEFAULT_INSTRUCTIONS_FILE), body, "utf8");
53602
- return;
53603
- }
53604
- }
53605
- function buildManifestFromCloud(cloud, agent) {
53606
- const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
53607
- const meta = c2.meta ?? {};
53608
- if (meta.name && meta.name.includes("/")) {
53609
- return {
53610
- source: meta.version ? `registry:${meta.name}@${meta.version}` : `registry:${meta.name}`
53611
- };
53612
- }
53613
- return { source: `registry:${c2.slug}` };
53614
- });
53615
- const hasInstructions = cloud.components.some((c2) => c2.type === "instruction" && c2.files[0]?.content?.trim());
53616
- const mcp = cloud.components.filter((c2) => c2.type === "mcp").map((c2) => {
53617
- const payload = (c2.meta ?? {}).mcp ?? {};
53618
- const entry = { name: c2.slug };
53619
- if (typeof payload.url === "string")
53620
- entry.url = payload.url;
53621
- if (typeof payload.command === "string")
53622
- entry.command = payload.command;
53623
- if (Array.isArray(payload.args))
53624
- entry.args = payload.args.map(String);
53625
- if (payload.env && typeof payload.env === "object")
53626
- entry.env = payload.env;
53627
- if (payload.headers && typeof payload.headers === "object")
53628
- entry.headers = payload.headers;
53629
- if (typeof payload.is_enabled === "boolean")
53630
- entry.is_enabled = payload.is_enabled;
53631
- return entry;
53632
- });
53633
- return {
53634
- schema: 1,
53635
- agent: {
53636
- name: agent.name,
53637
- ...agent.tagline ? { tagline: agent.tagline } : {}
53638
- },
53639
- ...hasInstructions ? { instructions: { file: DEFAULT_INSTRUCTIONS_FILE } } : {},
53640
- skills,
53641
- mcp
53642
- };
53643
- }
53644
- async function pullAgentSecrets(cwd2, agentId) {
53645
- try {
53646
- const res = await api.getAgentSecrets(agentId);
53647
- const secrets = res.secrets ?? {};
53648
- if (Object.keys(secrets).length > 0) {
53649
- writeLocalSecrets(cwd2, secrets);
53650
- }
53651
- } catch (err) {
53652
- if (err instanceof ApiError && err.status !== 404) {
53653
- f2.warn(`Skipped secrets for agent ${agentId}: ${err.message}`);
53654
- }
53655
- }
53656
- }
53657
-
53658
54308
  // src/cli/orchestration-pull.ts
53659
54309
  async function runOrchestrationPull(cwd2, args) {
53660
54310
  banner("orchestration pull — fetch orchestration + all member agents");
@@ -53666,8 +54316,8 @@ async function runOrchestrationPull(cwd2, args) {
53666
54316
  orchId = args.orchestrationId;
53667
54317
  } else {
53668
54318
  f2.warn("This folder is not linked to any orchestration.");
53669
- f2.info(`Run ${import_picocolors31.default.cyan("brainbase orchestration pull <id>")} with an orchestration id,
53670
- or ${import_picocolors31.default.cyan("brainbase orchestration list")} to find one.`);
54319
+ f2.info(`Run ${import_picocolors33.default.cyan("brainbase orchestration pull <id>")} with an orchestration id,
54320
+ or ${import_picocolors33.default.cyan("brainbase orchestration list")} to find one.`);
53671
54321
  return;
53672
54322
  }
53673
54323
  const sp = de();
@@ -53678,29 +54328,29 @@ async function runOrchestrationPull(cwd2, args) {
53678
54328
  sp.stop(`Cloud revision ${cloud.revision} — ${cloud.members.length} member${cloud.members.length === 1 ? "" : "s"}, ${cloud.edges.length} edge${cloud.edges.length === 1 ? "" : "s"}.`);
53679
54329
  } catch (err) {
53680
54330
  sp.stop("Failed.");
53681
- handleApiError5(err);
54331
+ handleApiError6(err);
53682
54332
  return;
53683
54333
  }
53684
54334
  const planLines = [];
53685
54335
  planLines.push("");
53686
- planLines.push(` ${import_picocolors31.default.bold(cloud.name)} ${import_picocolors31.default.dim(`(${cloud.id})`)}`);
54336
+ planLines.push(` ${import_picocolors33.default.bold(cloud.name)} ${import_picocolors33.default.dim(`(${cloud.id})`)}`);
53687
54337
  if (cloud.description)
53688
- planLines.push(` ${import_picocolors31.default.dim(cloud.description)}`);
54338
+ planLines.push(` ${import_picocolors33.default.dim(cloud.description)}`);
53689
54339
  planLines.push("");
53690
- planLines.push(` ${import_picocolors31.default.dim("members:")}`);
54340
+ planLines.push(` ${import_picocolors33.default.dim("members:")}`);
53691
54341
  for (const m3 of cloud.members) {
53692
54342
  const skipped = !m3.manifest;
53693
- const tail = skipped ? import_picocolors31.default.red(" (manifest unavailable — skipped)") : "";
53694
- planLines.push(` ${import_picocolors31.default.cyan("•")} ${import_picocolors31.default.bold(m3.slug)} ${import_picocolors31.default.dim(`(${m3.name})`)}${tail}`);
54343
+ const tail = skipped ? import_picocolors33.default.red(" (manifest unavailable — skipped)") : "";
54344
+ planLines.push(` ${import_picocolors33.default.cyan("•")} ${import_picocolors33.default.bold(m3.slug)} ${import_picocolors33.default.dim(`(${m3.name})`)}${tail}`);
53695
54345
  }
53696
54346
  if (cloud.edges.length) {
53697
54347
  planLines.push("");
53698
- planLines.push(` ${import_picocolors31.default.dim("edges:")}`);
54348
+ planLines.push(` ${import_picocolors33.default.dim("edges:")}`);
53699
54349
  for (const e2 of cloud.edges) {
53700
54350
  const from = e2.from_slug ?? e2.from_agent_id;
53701
54351
  const to2 = e2.to_slug ?? e2.to_agent_id;
53702
- const desc = e2.description ? ` ${import_picocolors31.default.dim("— " + e2.description)}` : "";
53703
- planLines.push(` ${import_picocolors31.default.cyan(from)} ${import_picocolors31.default.dim("→")} ${import_picocolors31.default.cyan(to2)}${desc}`);
54352
+ const desc = e2.description ? ` ${import_picocolors33.default.dim("— " + e2.description)}` : "";
54353
+ planLines.push(` ${import_picocolors33.default.cyan(from)} ${import_picocolors33.default.dim("→")} ${import_picocolors33.default.cyan(to2)}${desc}`);
53704
54354
  }
53705
54355
  }
53706
54356
  planLines.push("");
@@ -53709,7 +54359,7 @@ async function runOrchestrationPull(cwd2, args) {
53709
54359
  const isRefresh = !!existingLink;
53710
54360
  if (!args.yes && !isRefresh) {
53711
54361
  const ok = await se({
53712
- message: `Pull into ${import_picocolors31.default.bold(cwd2)}?`,
54362
+ message: `Pull into ${import_picocolors33.default.bold(cwd2)}?`,
53713
54363
  initialValue: true
53714
54364
  });
53715
54365
  if (!ensureNotCancelled(ok)) {
@@ -53750,7 +54400,7 @@ async function runOrchestrationPull(cwd2, args) {
53750
54400
  scope: "project",
53751
54401
  pullSecrets: true
53752
54402
  });
53753
- memberSp.stop(`Installed ${import_picocolors31.default.bold(m3.slug)} ${import_picocolors31.default.dim(`(${m3.manifest.components.length} components)`)}.`);
54403
+ memberSp.stop(`Installed ${import_picocolors33.default.bold(m3.slug)} ${import_picocolors33.default.dim(`(${m3.manifest.components.length} components)`)}.`);
53754
54404
  installedMembers.push({
53755
54405
  agent_id: m3.agent_id,
53756
54406
  slug: m3.slug,
@@ -53805,9 +54455,9 @@ async function runOrchestrationPull(cwd2, args) {
53805
54455
  payload_schema: e2.payload_schema ?? {}
53806
54456
  }))
53807
54457
  });
53808
- $e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path52.basename(cwd2)}/ ${import_picocolors31.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
54458
+ $e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path53.basename(cwd2)}/ ${import_picocolors33.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
53809
54459
  }
53810
- function handleApiError5(err) {
54460
+ function handleApiError6(err) {
53811
54461
  if (err instanceof ApiError) {
53812
54462
  if (err.status === 401) {
53813
54463
  f2.error("Your session is invalid. Run `brainbase login` and try again.");
@@ -53822,18 +54472,18 @@ function handleApiError5(err) {
53822
54472
  }
53823
54473
 
53824
54474
  // src/cli/orchestration-push.ts
53825
- var import_picocolors32 = __toESM(require_picocolors(), 1);
54475
+ var import_picocolors34 = __toESM(require_picocolors(), 1);
53826
54476
  async function runOrchestrationPush(cwd2, args) {
53827
54477
  banner("orchestration push — recursively push each member, then update the graph");
53828
54478
  const link2 = readOrchLink(cwd2);
53829
54479
  if (!link2) {
53830
54480
  f2.warn("This folder is not linked to any orchestration.");
53831
- f2.info(`Run ${import_picocolors32.default.cyan("brainbase orchestration pull <id>")} first.`);
54481
+ f2.info(`Run ${import_picocolors34.default.cyan("brainbase orchestration pull <id>")} first.`);
53832
54482
  return;
53833
54483
  }
53834
54484
  if (!hasOrchManifest(cwd2)) {
53835
- f2.warn(`No ${import_picocolors32.default.bold(ORCH_MANIFEST_FILE)} here.`);
53836
- f2.info(`Run ${import_picocolors32.default.cyan("brainbase orchestration pull")} to materialise the manifest before pushing.`);
54485
+ f2.warn(`No ${import_picocolors34.default.bold(ORCH_MANIFEST_FILE)} here.`);
54486
+ f2.info(`Run ${import_picocolors34.default.cyan("brainbase orchestration pull")} to materialise the manifest before pushing.`);
53837
54487
  return;
53838
54488
  }
53839
54489
  let manifest;
@@ -53846,15 +54496,15 @@ async function runOrchestrationPush(cwd2, args) {
53846
54496
  const memberSlugs = new Set(manifest.members.map((m3) => m3.slug));
53847
54497
  for (const e2 of manifest.edges) {
53848
54498
  if (!memberSlugs.has(e2.from)) {
53849
- f2.error(`Edge from "${import_picocolors32.default.bold(e2.from)}" references a slug that isn't in members.`);
54499
+ f2.error(`Edge from "${import_picocolors34.default.bold(e2.from)}" references a slug that isn't in members.`);
53850
54500
  return;
53851
54501
  }
53852
54502
  if (!memberSlugs.has(e2.to)) {
53853
- f2.error(`Edge to "${import_picocolors32.default.bold(e2.to)}" references a slug that isn't in members.`);
54503
+ f2.error(`Edge to "${import_picocolors34.default.bold(e2.to)}" references a slug that isn't in members.`);
53854
54504
  return;
53855
54505
  }
53856
54506
  if (e2.from === e2.to) {
53857
- f2.error(`Edge ${import_picocolors32.default.bold(e2.from)} → ${import_picocolors32.default.bold(e2.to)}: self-loops are not allowed.`);
54507
+ f2.error(`Edge ${import_picocolors34.default.bold(e2.from)} → ${import_picocolors34.default.bold(e2.to)}: self-loops are not allowed.`);
53858
54508
  return;
53859
54509
  }
53860
54510
  }
@@ -53871,17 +54521,17 @@ async function runOrchestrationPush(cwd2, args) {
53871
54521
  }
53872
54522
  if (missing.length) {
53873
54523
  f2.error(`These members have no local checkout (expected at agents/<slug>/.brainbase/link.json): ${missing.join(", ")}.`);
53874
- f2.info(`Run ${import_picocolors32.default.cyan("brainbase orchestration pull")} to materialise the missing folders.`);
54524
+ f2.info(`Run ${import_picocolors34.default.cyan("brainbase orchestration pull")} to materialise the missing folders.`);
53875
54525
  return;
53876
54526
  }
53877
54527
  const plan = [""];
53878
- plan.push(` ${import_picocolors32.default.bold(link2.name)} ${import_picocolors32.default.dim(`(${link2.orchestration_id})`)}`);
53879
- plan.push(` ${import_picocolors32.default.dim(`${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}`)}`);
54528
+ plan.push(` ${import_picocolors34.default.bold(link2.name)} ${import_picocolors34.default.dim(`(${link2.orchestration_id})`)}`);
54529
+ plan.push(` ${import_picocolors34.default.dim(`${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}`)}`);
53880
54530
  plan.push("");
53881
54531
  if (!args.graphOnly) {
53882
- plan.push(` ${import_picocolors32.default.dim("per-member agent push:")}`);
54532
+ plan.push(` ${import_picocolors34.default.dim("per-member agent push:")}`);
53883
54533
  for (const m3 of manifest.members) {
53884
- plan.push(` ${import_picocolors32.default.cyan("•")} ${import_picocolors32.default.bold(m3.slug)}`);
54534
+ plan.push(` ${import_picocolors34.default.cyan("•")} ${import_picocolors34.default.bold(m3.slug)}`);
53885
54535
  }
53886
54536
  plan.push("");
53887
54537
  }
@@ -53901,7 +54551,7 @@ async function runOrchestrationPush(cwd2, args) {
53901
54551
  for (const m3 of manifest.members) {
53902
54552
  const dir = memberDir(cwd2, m3.slug);
53903
54553
  console.log("");
53904
- console.log(`${import_picocolors32.default.dim("───")} ${import_picocolors32.default.bold(m3.slug)} ${import_picocolors32.default.dim("───")}`);
54554
+ console.log(`${import_picocolors34.default.dim("───")} ${import_picocolors34.default.bold(m3.slug)} ${import_picocolors34.default.dim("───")}`);
53905
54555
  try {
53906
54556
  await runAgentPush(dir, { yes: true });
53907
54557
  } catch (err) {
@@ -53952,10 +54602,10 @@ async function runOrchestrationPush(cwd2, args) {
53952
54602
  $e(`Pushed ${link2.name} at revision ${updated.revision}.`);
53953
54603
  } catch (err) {
53954
54604
  sp.stop("Failed.");
53955
- handleApiError6(err);
54605
+ handleApiError7(err);
53956
54606
  }
53957
54607
  }
53958
- function handleApiError6(err) {
54608
+ function handleApiError7(err) {
53959
54609
  if (err instanceof ApiError) {
53960
54610
  if (err.status === 401) {
53961
54611
  f2.error("Your session is invalid. Run `brainbase login` and try again.");
@@ -53963,7 +54613,7 @@ function handleApiError6(err) {
53963
54613
  f2.error("You do not have access to this orchestration.");
53964
54614
  } else if (err.status === 409) {
53965
54615
  f2.error(err.message);
53966
- f2.info(`Run ${import_picocolors32.default.cyan("brainbase orchestration pull")} to reconcile, then push again.`);
54616
+ f2.info(`Run ${import_picocolors34.default.cyan("brainbase orchestration pull")} to reconcile, then push again.`);
53967
54617
  } else {
53968
54618
  f2.error(err.message);
53969
54619
  }
@@ -53973,13 +54623,13 @@ function handleApiError6(err) {
53973
54623
  }
53974
54624
 
53975
54625
  // src/cli/orchestration-status.ts
53976
- var import_picocolors33 = __toESM(require_picocolors(), 1);
54626
+ var import_picocolors35 = __toESM(require_picocolors(), 1);
53977
54627
  async function runOrchestrationStatus(cwd2) {
53978
54628
  banner("orchestration status — what changed locally, remotely, both");
53979
54629
  const link2 = readOrchLink(cwd2);
53980
54630
  if (!link2) {
53981
54631
  f2.warn("This folder is not linked to any orchestration.");
53982
- f2.info(`Run ${import_picocolors33.default.cyan("brainbase orchestration pull <id>")} first.`);
54632
+ f2.info(`Run ${import_picocolors35.default.cyan("brainbase orchestration pull <id>")} first.`);
53983
54633
  return;
53984
54634
  }
53985
54635
  const localManifest = hasOrchManifest(cwd2) ? readOrchManifest(cwd2) : null;
@@ -54001,20 +54651,20 @@ async function runOrchestrationStatus(cwd2) {
54001
54651
  }
54002
54652
  const lines = [];
54003
54653
  lines.push("");
54004
- lines.push(` ${import_picocolors33.default.bold(link2.name)} ${import_picocolors33.default.dim(`(${link2.orchestration_id})`)}`);
54005
- lines.push(` ${import_picocolors33.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
54654
+ lines.push(` ${import_picocolors35.default.bold(link2.name)} ${import_picocolors35.default.dim(`(${link2.orchestration_id})`)}`);
54655
+ lines.push(` ${import_picocolors35.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
54006
54656
  lines.push("");
54007
54657
  const cloudMemberSet = new Set(cloud.members.map((m3) => m3.slug));
54008
54658
  const localMemberSet = new Set((localManifest?.members ?? []).map((m3) => m3.slug));
54009
54659
  const membersAdded = [...localMemberSet].filter((s3) => !cloudMemberSet.has(s3));
54010
54660
  const membersRemoved = [...cloudMemberSet].filter((s3) => !localMemberSet.has(s3));
54011
54661
  if (membersAdded.length || membersRemoved.length) {
54012
- lines.push(` ${import_picocolors33.default.bold("members")}`);
54662
+ lines.push(` ${import_picocolors35.default.bold("members")}`);
54013
54663
  for (const slug of membersAdded) {
54014
- lines.push(` ${import_picocolors33.default.yellow("→ push")} added in yaml: ${import_picocolors33.default.bold(slug)}`);
54664
+ lines.push(` ${import_picocolors35.default.yellow("→ push")} added in yaml: ${import_picocolors35.default.bold(slug)}`);
54015
54665
  }
54016
54666
  for (const slug of membersRemoved) {
54017
- lines.push(` ${import_picocolors33.default.cyan("← pull")} added on cloud: ${import_picocolors33.default.bold(slug)}`);
54667
+ lines.push(` ${import_picocolors35.default.cyan("← pull")} added on cloud: ${import_picocolors35.default.bold(slug)}`);
54018
54668
  }
54019
54669
  lines.push("");
54020
54670
  }
@@ -54029,11 +54679,11 @@ async function runOrchestrationStatus(cwd2) {
54029
54679
  const edgesAdded = [...localEdges.keys()].filter((k3) => !cloudEdges.has(k3));
54030
54680
  const edgesRemoved = [...cloudEdges.keys()].filter((k3) => !localEdges.has(k3));
54031
54681
  if (edgesAdded.length || edgesRemoved.length) {
54032
- lines.push(` ${import_picocolors33.default.bold("edges")}`);
54682
+ lines.push(` ${import_picocolors35.default.bold("edges")}`);
54033
54683
  for (const k3 of edgesAdded)
54034
- lines.push(` ${import_picocolors33.default.yellow("→ push")} added in yaml: ${k3}`);
54684
+ lines.push(` ${import_picocolors35.default.yellow("→ push")} added in yaml: ${k3}`);
54035
54685
  for (const k3 of edgesRemoved)
54036
- lines.push(` ${import_picocolors33.default.cyan("← pull")} added on cloud: ${k3}`);
54686
+ lines.push(` ${import_picocolors35.default.cyan("← pull")} added on cloud: ${k3}`);
54037
54687
  lines.push("");
54038
54688
  }
54039
54689
  const lockByAgentId = new Map((lock?.members ?? []).map((m3) => [m3.agent_id, m3]));
@@ -54055,28 +54705,28 @@ async function runOrchestrationStatus(cwd2) {
54055
54705
  }
54056
54706
  }
54057
54707
  if (memberDrift.length) {
54058
- lines.push(` ${import_picocolors33.default.bold("member content drift")}`);
54708
+ lines.push(` ${import_picocolors35.default.bold("member content drift")}`);
54059
54709
  for (const d3 of memberDrift) {
54060
- lines.push(` ${import_picocolors33.default.cyan("?")} ${import_picocolors33.default.bold(d3.slug)} ${import_picocolors33.default.dim("— " + d3.reason)}`);
54710
+ lines.push(` ${import_picocolors35.default.cyan("?")} ${import_picocolors35.default.bold(d3.slug)} ${import_picocolors35.default.dim("— " + d3.reason)}`);
54061
54711
  }
54062
- lines.push(` ${import_picocolors33.default.dim("cd into each member folder and run")} ${import_picocolors33.default.cyan("brainbase agent status")}`);
54712
+ lines.push(` ${import_picocolors35.default.dim("cd into each member folder and run")} ${import_picocolors35.default.cyan("brainbase agent status")}`);
54063
54713
  lines.push("");
54064
54714
  }
54065
54715
  if (!membersAdded.length && !membersRemoved.length && !edgesAdded.length && !edgesRemoved.length && !memberDrift.length) {
54066
- lines.push(` ${import_picocolors33.default.green("✓")} everything is in sync`);
54716
+ lines.push(` ${import_picocolors35.default.green("✓")} everything is in sync`);
54067
54717
  lines.push("");
54068
54718
  console.log(lines.join(`
54069
54719
  `));
54070
54720
  return;
54071
54721
  }
54072
- lines.push(` ${import_picocolors33.default.dim("run")} ${import_picocolors33.default.cyan("brainbase orchestration pull")} ${import_picocolors33.default.dim("to apply cloud changes,")} ${import_picocolors33.default.cyan("brainbase orchestration push")} ${import_picocolors33.default.dim("to send yours")}`);
54722
+ lines.push(` ${import_picocolors35.default.dim("run")} ${import_picocolors35.default.cyan("brainbase orchestration pull")} ${import_picocolors35.default.dim("to apply cloud changes,")} ${import_picocolors35.default.cyan("brainbase orchestration push")} ${import_picocolors35.default.dim("to send yours")}`);
54073
54723
  lines.push("");
54074
54724
  console.log(lines.join(`
54075
54725
  `));
54076
54726
  }
54077
54727
 
54078
54728
  // src/cli/orchestration-list.ts
54079
- var import_picocolors34 = __toESM(require_picocolors(), 1);
54729
+ var import_picocolors36 = __toESM(require_picocolors(), 1);
54080
54730
  async function runOrchestrationList(args) {
54081
54731
  banner("orchestration list — orchestrations under a team");
54082
54732
  let orgId = args.orgId;
@@ -54086,7 +54736,7 @@ async function runOrchestrationList(args) {
54086
54736
  try {
54087
54737
  orgs = await api.listOrgs();
54088
54738
  } catch (err) {
54089
- handleApiError7(err);
54739
+ handleApiError8(err);
54090
54740
  return;
54091
54741
  }
54092
54742
  if (orgs.length === 0) {
@@ -54108,7 +54758,7 @@ async function runOrchestrationList(args) {
54108
54758
  try {
54109
54759
  teams = await api.listTeams(orgId);
54110
54760
  } catch (err) {
54111
- handleApiError7(err);
54761
+ handleApiError8(err);
54112
54762
  return;
54113
54763
  }
54114
54764
  if (teams.length === 0) {
@@ -54133,7 +54783,7 @@ async function runOrchestrationList(args) {
54133
54783
  sp.stop(`${items.length} orchestration${items.length === 1 ? "" : "s"}.`);
54134
54784
  } catch (err) {
54135
54785
  sp.stop("Failed.");
54136
- handleApiError7(err);
54786
+ handleApiError8(err);
54137
54787
  return;
54138
54788
  }
54139
54789
  if (items.length === 0) {
@@ -54142,18 +54792,18 @@ async function runOrchestrationList(args) {
54142
54792
  }
54143
54793
  const lines = [""];
54144
54794
  for (const o2 of items) {
54145
- lines.push(` ${import_picocolors34.default.bold(o2.name)} ${import_picocolors34.default.dim(o2.id)}`);
54795
+ lines.push(` ${import_picocolors36.default.bold(o2.name)} ${import_picocolors36.default.dim(o2.id)}`);
54146
54796
  if (o2.description)
54147
- lines.push(` ${import_picocolors34.default.dim(o2.description)}`);
54148
- lines.push(` ${import_picocolors34.default.dim(`${o2.member_count} member${o2.member_count === 1 ? "" : "s"} · ${o2.edge_count} edge${o2.edge_count === 1 ? "" : "s"}`)}`);
54797
+ lines.push(` ${import_picocolors36.default.dim(o2.description)}`);
54798
+ lines.push(` ${import_picocolors36.default.dim(`${o2.member_count} member${o2.member_count === 1 ? "" : "s"} · ${o2.edge_count} edge${o2.edge_count === 1 ? "" : "s"}`)}`);
54149
54799
  lines.push("");
54150
54800
  }
54151
- lines.push(` ${import_picocolors34.default.dim("pull one with")} ${import_picocolors34.default.cyan("brainbase orchestration pull <id>")}`);
54801
+ lines.push(` ${import_picocolors36.default.dim("pull one with")} ${import_picocolors36.default.cyan("brainbase orchestration pull <id>")}`);
54152
54802
  lines.push("");
54153
54803
  console.log(lines.join(`
54154
54804
  `));
54155
54805
  }
54156
- function handleApiError7(err) {
54806
+ function handleApiError8(err) {
54157
54807
  if (err instanceof ApiError) {
54158
54808
  if (err.status === 401) {
54159
54809
  f2.error("Your session is invalid. Run `brainbase login` and try again.");
@@ -54204,26 +54854,26 @@ async function runOrchestration(cwd2, sub, args, opts) {
54204
54854
  function printHelp2() {
54205
54855
  const out = [];
54206
54856
  out.push("");
54207
- out.push(` ${import_picocolors35.default.bold("brainbase orchestration")} ${import_picocolors35.default.dim("<sub> [options]")}`);
54857
+ out.push(` ${import_picocolors37.default.bold("brainbase orchestration")} ${import_picocolors37.default.dim("<sub> [options]")}`);
54208
54858
  out.push("");
54209
- out.push(` ${import_picocolors35.default.cyan("pull")} ${import_picocolors35.default.dim("<id>")} ${import_picocolors35.default.dim("fetch orchestration + every member agent into this folder")}`);
54210
- out.push(` ${import_picocolors35.default.cyan("push")} ${import_picocolors35.default.dim("push each member, then update the orchestration graph")}`);
54211
- out.push(` ${import_picocolors35.default.cyan("status")} ${import_picocolors35.default.dim("show what would push and what would pull")}`);
54212
- out.push(` ${import_picocolors35.default.cyan("list")} ${import_picocolors35.default.dim("list orchestrations under a team")}`);
54859
+ out.push(` ${import_picocolors37.default.cyan("pull")} ${import_picocolors37.default.dim("<id>")} ${import_picocolors37.default.dim("fetch orchestration + every member agent into this folder")}`);
54860
+ out.push(` ${import_picocolors37.default.cyan("push")} ${import_picocolors37.default.dim("push each member, then update the orchestration graph")}`);
54861
+ out.push(` ${import_picocolors37.default.cyan("status")} ${import_picocolors37.default.dim("show what would push and what would pull")}`);
54862
+ out.push(` ${import_picocolors37.default.cyan("list")} ${import_picocolors37.default.dim("list orchestrations under a team")}`);
54213
54863
  out.push("");
54214
- out.push(` ${import_picocolors35.default.bold("Flags")}`);
54215
- out.push(` ${import_picocolors35.default.dim("--yes, -y")} skip confirmations`);
54216
- out.push(` ${import_picocolors35.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
54217
- out.push(` ${import_picocolors35.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`);
54218
- out.push(` ${import_picocolors35.default.dim("--org <id>")} for list: org id (CLI vocab — DB teams.id)`);
54219
- out.push(` ${import_picocolors35.default.dim("--team <id>")} for list: team id (CLI vocab — DB groups.id)`);
54864
+ out.push(` ${import_picocolors37.default.bold("Flags")}`);
54865
+ out.push(` ${import_picocolors37.default.dim("--yes, -y")} skip confirmations`);
54866
+ out.push(` ${import_picocolors37.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
54867
+ out.push(` ${import_picocolors37.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`);
54868
+ out.push(` ${import_picocolors37.default.dim("--org <id>")} for list: org id (CLI vocab — DB teams.id)`);
54869
+ out.push(` ${import_picocolors37.default.dim("--team <id>")} for list: team id (CLI vocab — DB groups.id)`);
54220
54870
  out.push("");
54221
54871
  console.log(out.join(`
54222
54872
  `));
54223
54873
  }
54224
54874
 
54225
54875
  // src/cli/run.ts
54226
- import { spawn as spawn2 } from "node:child_process";
54876
+ import { spawn as spawn3 } from "node:child_process";
54227
54877
  async function runRun(cwd2, args) {
54228
54878
  const cleaned = args[0] === "--" ? args.slice(1) : args;
54229
54879
  if (cleaned.length === 0) {
@@ -54235,7 +54885,7 @@ async function runRun(cwd2, args) {
54235
54885
  const [cmd, ...cmdArgs] = cleaned;
54236
54886
  const secrets = readLocalSecrets(cwd2);
54237
54887
  const env3 = { ...process.env, ...secrets };
54238
- const child = spawn2(cmd, cmdArgs, {
54888
+ const child = spawn3(cmd, cmdArgs, {
54239
54889
  cwd: cwd2,
54240
54890
  env: env3,
54241
54891
  stdio: "inherit",
@@ -54261,16 +54911,16 @@ async function runRun(cwd2, args) {
54261
54911
  }
54262
54912
 
54263
54913
  // src/cli/publish.ts
54264
- var import_picocolors36 = __toESM(require_picocolors(), 1);
54914
+ var import_picocolors38 = __toESM(require_picocolors(), 1);
54265
54915
  async function runPublish(cwd2, _args) {
54266
54916
  banner("publish — send your changes to the team");
54267
54917
  const link2 = readLink(cwd2);
54268
54918
  if (!link2) {
54269
54919
  f2.warn("This folder is not linked to any agent.");
54270
- f2.info(`Run ${import_picocolors36.default.cyan("brainbase link")} first.`);
54920
+ f2.info(`Run ${import_picocolors38.default.cyan("brainbase link")} first.`);
54271
54921
  return;
54272
54922
  }
54273
- f2.info(`${import_picocolors36.default.bold("publish")} is coming soon — for now, edit the agent on the web app and run ${import_picocolors36.default.cyan("brainbase sync")} to bring changes here.`);
54923
+ f2.info(`${import_picocolors38.default.bold("publish")} is coming soon — for now, edit the agent on the web app and run ${import_picocolors38.default.cyan("brainbase sync")} to bring changes here.`);
54274
54924
  }
54275
54925
 
54276
54926
  // src/ui/ink/StatusCard.tsx
@@ -54568,7 +55218,7 @@ async function runStatus(cwd2) {
54568
55218
  }
54569
55219
 
54570
55220
  // src/cli/token.ts
54571
- var import_picocolors37 = __toESM(require_picocolors(), 1);
55221
+ var import_picocolors39 = __toESM(require_picocolors(), 1);
54572
55222
 
54573
55223
  // src/ui/ink/TokenCards.tsx
54574
55224
  var jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
@@ -54862,7 +55512,7 @@ async function runTokenRevoke(args) {
54862
55512
  }
54863
55513
  if (!args.yes) {
54864
55514
  const ok = await se({
54865
- message: `Revoke token ${import_picocolors37.default.bold(args.id)}? CIs and machines using it will stop working.`,
55515
+ message: `Revoke token ${import_picocolors39.default.bold(args.id)}? CIs and machines using it will stop working.`,
54866
55516
  initialValue: false
54867
55517
  });
54868
55518
  if (!ensureNotCancelled(ok))
@@ -54877,7 +55527,7 @@ async function runTokenRevoke(args) {
54877
55527
  }
54878
55528
  async function runTokenClear() {
54879
55529
  if (!readToken()) {
54880
- console.log(import_picocolors37.default.dim("No local token stored."));
55530
+ console.log(import_picocolors39.default.dim("No local token stored."));
54881
55531
  return;
54882
55532
  }
54883
55533
  clearToken();
@@ -54928,17 +55578,17 @@ async function runToken(sub, rest, args) {
54928
55578
  function printTokenHelp() {
54929
55579
  const out = [];
54930
55580
  out.push("");
54931
- out.push(` ${import_picocolors37.default.bold("brainbase token")} ${import_picocolors37.default.dim("<command>")}`);
55581
+ out.push(` ${import_picocolors39.default.bold("brainbase token")} ${import_picocolors39.default.dim("<command>")}`);
54932
55582
  out.push("");
54933
- out.push(` ${import_picocolors37.default.cyan("create")} ${import_picocolors37.default.dim("issue a new long-lived CLI key (PAT)")}`);
54934
- out.push(` ${import_picocolors37.default.cyan("list")} ${import_picocolors37.default.dim("show your active tokens")}`);
54935
- out.push(` ${import_picocolors37.default.cyan("revoke")} ${import_picocolors37.default.dim("<id>")} ${import_picocolors37.default.dim("revoke a token by id")}`);
54936
- out.push(` ${import_picocolors37.default.cyan("clear")} ${import_picocolors37.default.dim("forget the local token (does not revoke)")}`);
55583
+ out.push(` ${import_picocolors39.default.cyan("create")} ${import_picocolors39.default.dim("issue a new long-lived CLI key (PAT)")}`);
55584
+ out.push(` ${import_picocolors39.default.cyan("list")} ${import_picocolors39.default.dim("show your active tokens")}`);
55585
+ out.push(` ${import_picocolors39.default.cyan("revoke")} ${import_picocolors39.default.dim("<id>")} ${import_picocolors39.default.dim("revoke a token by id")}`);
55586
+ out.push(` ${import_picocolors39.default.cyan("clear")} ${import_picocolors39.default.dim("forget the local token (does not revoke)")}`);
54937
55587
  out.push("");
54938
- out.push(` ${import_picocolors37.default.bold("create flags")}`);
54939
- out.push(` ${import_picocolors37.default.cyan("--name, -n")} ${import_picocolors37.default.dim("<label>")} ${import_picocolors37.default.dim("token label (prompted if omitted)")}`);
54940
- out.push(` ${import_picocolors37.default.cyan("--scopes")} ${import_picocolors37.default.dim("<list>")} ${import_picocolors37.default.dim("comma-separated; allowed: read, publish, admin")}`);
54941
- out.push(` ${import_picocolors37.default.dim("default: read,publish")}`);
55588
+ out.push(` ${import_picocolors39.default.bold("create flags")}`);
55589
+ out.push(` ${import_picocolors39.default.cyan("--name, -n")} ${import_picocolors39.default.dim("<label>")} ${import_picocolors39.default.dim("token label (prompted if omitted)")}`);
55590
+ out.push(` ${import_picocolors39.default.cyan("--scopes")} ${import_picocolors39.default.dim("<list>")} ${import_picocolors39.default.dim("comma-separated; allowed: read, publish, admin")}`);
55591
+ out.push(` ${import_picocolors39.default.dim("default: read,publish")}`);
54942
55592
  out.push("");
54943
55593
  console.log(out.join(`
54944
55594
  `));
@@ -54958,89 +55608,90 @@ var PROTECTED = new Set([
54958
55608
  function help() {
54959
55609
  const out = [];
54960
55610
  out.push("");
54961
- out.push(` ${brandTint("◆")} ${import_picocolors38.default.bold("brainbase")} ${import_picocolors38.default.dim("v0.2.0")}`);
54962
- out.push(` ${import_picocolors38.default.dim("connect your local agent to the brainbase platform")}`);
55611
+ out.push(` ${brandTint("◆")} ${import_picocolors40.default.bold("brainbase")} ${import_picocolors40.default.dim("v0.5.0")}`);
55612
+ out.push(` ${import_picocolors40.default.dim("connect your local agent to the brainbase platform")}`);
54963
55613
  out.push("");
54964
55614
  out.push(divider("USAGE"));
54965
55615
  out.push("");
54966
- out.push(` ${import_picocolors38.default.bold("brainbase")} ${import_picocolors38.default.dim("<command> [options]")}`);
55616
+ out.push(` ${import_picocolors40.default.bold("brainbase")} ${import_picocolors40.default.dim("<command> [options]")}`);
54967
55617
  out.push("");
54968
55618
  out.push(divider("AUTH"));
54969
55619
  out.push("");
54970
- out.push(` ${import_picocolors38.default.cyan("login")} ${import_picocolors38.default.dim(" open the web app and connect this device")}`);
54971
- out.push(` ${import_picocolors38.default.cyan("logout")} ${import_picocolors38.default.dim(" clear the local session")}`);
54972
- out.push(` ${import_picocolors38.default.cyan("whoami")} ${import_picocolors38.default.dim(" show the current user")}`);
55620
+ out.push(` ${import_picocolors40.default.cyan("login")} ${import_picocolors40.default.dim(" open the web app and connect this device")}`);
55621
+ out.push(` ${import_picocolors40.default.cyan("logout")} ${import_picocolors40.default.dim(" clear the local session")}`);
55622
+ out.push(` ${import_picocolors40.default.cyan("whoami")} ${import_picocolors40.default.dim(" show the current user")}`);
54973
55623
  out.push("");
54974
55624
  out.push(divider("LINKED AGENT"));
54975
55625
  out.push("");
54976
- out.push(` ${import_picocolors38.default.cyan("agent create")} ${import_picocolors38.default.dim("make a new agent on the cloud and link this folder")}`);
54977
- out.push(` ${import_picocolors38.default.cyan("link")} ${import_picocolors38.default.dim("attach this folder to an existing agent")}`);
54978
- out.push(` ${import_picocolors38.default.cyan("agent pull")} ${import_picocolors38.default.dim("bring cloud changes into this folder")}`);
54979
- out.push(` ${import_picocolors38.default.cyan("agent push")} ${import_picocolors38.default.dim("send local changes to the cloud")}`);
54980
- out.push(` ${import_picocolors38.default.cyan("agent status")} ${import_picocolors38.default.dim("show what would pull and what would push")}`);
54981
- out.push(` ${import_picocolors38.default.cyan("agent env")} ${import_picocolors38.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
54982
- out.push(` ${import_picocolors38.default.cyan("run")} ${import_picocolors38.default.dim("<cmd> [args...]")} ${import_picocolors38.default.dim("run <cmd> with secrets.env loaded into env")}`);
54983
- out.push(` ${import_picocolors38.default.cyan("status")} ${import_picocolors38.default.dim("show what this folder is linked to")}`);
54984
- out.push(` ${import_picocolors38.default.cyan("unlink")} ${import_picocolors38.default.dim("disconnect this folder")}`);
55626
+ out.push(` ${import_picocolors40.default.cyan("agent create")} ${import_picocolors40.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
55627
+ out.push(` ${import_picocolors40.default.cyan("agent pull")} ${import_picocolors40.default.dim("[<id>]")} ${import_picocolors40.default.dim("bring cloud changes into this folder (--force to override)")}`);
55628
+ out.push(` ${import_picocolors40.default.cyan("agent push")} ${import_picocolors40.default.dim("send local changes to the cloud")}`);
55629
+ out.push(` ${import_picocolors40.default.cyan("agent unpack")} ${import_picocolors40.default.dim("install the claimed agent into a harness layout")}`);
55630
+ out.push(` ${import_picocolors40.default.cyan("link")} ${import_picocolors40.default.dim("attach this folder to an existing agent")}`);
55631
+ out.push(` ${import_picocolors40.default.cyan("agent status")} ${import_picocolors40.default.dim("show what would pull and what would push")}`);
55632
+ out.push(` ${import_picocolors40.default.cyan("agent env")} ${import_picocolors40.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
55633
+ out.push(` ${import_picocolors40.default.cyan("run")} ${import_picocolors40.default.dim("<cmd> [args...]")} ${import_picocolors40.default.dim("run <cmd> with secrets.env loaded into env")}`);
55634
+ out.push(` ${import_picocolors40.default.cyan("status")} ${import_picocolors40.default.dim("show what this folder is linked to")}`);
55635
+ out.push(` ${import_picocolors40.default.cyan("unlink")} ${import_picocolors40.default.dim("disconnect this folder")}`);
54985
55636
  out.push("");
54986
55637
  out.push(divider("ORCHESTRATIONS"));
54987
55638
  out.push("");
54988
- out.push(` ${import_picocolors38.default.cyan("orchestration list")} ${import_picocolors38.default.dim("list orchestrations under a team")}`);
54989
- out.push(` ${import_picocolors38.default.cyan("orchestration pull")} ${import_picocolors38.default.dim("<id>")} ${import_picocolors38.default.dim("recursively fetch an orchestration + every member agent")}`);
54990
- out.push(` ${import_picocolors38.default.cyan("orchestration push")} ${import_picocolors38.default.dim("recursively push each member, then update the graph")}`);
54991
- out.push(` ${import_picocolors38.default.cyan("orchestration status")} ${import_picocolors38.default.dim("show what would push and what would pull")}`);
55639
+ out.push(` ${import_picocolors40.default.cyan("orchestration list")} ${import_picocolors40.default.dim("list orchestrations under a team")}`);
55640
+ out.push(` ${import_picocolors40.default.cyan("orchestration pull")} ${import_picocolors40.default.dim("<id>")} ${import_picocolors40.default.dim("recursively fetch an orchestration + every member agent")}`);
55641
+ out.push(` ${import_picocolors40.default.cyan("orchestration push")} ${import_picocolors40.default.dim("recursively push each member, then update the graph")}`);
55642
+ out.push(` ${import_picocolors40.default.cyan("orchestration status")} ${import_picocolors40.default.dim("show what would push and what would pull")}`);
54992
55643
  out.push("");
54993
55644
  out.push(divider("TEMPLATES"));
54994
55645
  out.push("");
54995
- out.push(` ${import_picocolors38.default.cyan("template pack")} ${import_picocolors38.default.dim("bundle the current agent into a template")}`);
54996
- out.push(` ${import_picocolors38.default.cyan("template publish")} ${import_picocolors38.default.dim("upload a template to the registry")}`);
54997
- out.push(` ${import_picocolors38.default.cyan("template search")} ${import_picocolors38.default.dim("[query]")} ${import_picocolors38.default.dim("search the registry")}`);
54998
- out.push(` ${import_picocolors38.default.cyan("template info")} ${import_picocolors38.default.dim("<creator/slug>")} ${import_picocolors38.default.dim("show registry details for a template")}`);
54999
- out.push(` ${import_picocolors38.default.cyan("template onboard")} ${import_picocolors38.default.dim("<creator/slug>")} ${import_picocolors38.default.dim("install (or refresh) a template")}`);
55000
- out.push(` ${import_picocolors38.default.cyan("template list")} ${import_picocolors38.default.dim("show installed templates")}`);
55001
- out.push(` ${import_picocolors38.default.cyan("template remove")} ${import_picocolors38.default.dim("<creator/slug>")} ${import_picocolors38.default.dim("uninstall a template")}`);
55646
+ out.push(` ${import_picocolors40.default.cyan("template pack")} ${import_picocolors40.default.dim("bundle the current agent into a template")}`);
55647
+ out.push(` ${import_picocolors40.default.cyan("template publish")} ${import_picocolors40.default.dim("upload a template to the registry")}`);
55648
+ out.push(` ${import_picocolors40.default.cyan("template search")} ${import_picocolors40.default.dim("[query]")} ${import_picocolors40.default.dim("search the registry")}`);
55649
+ out.push(` ${import_picocolors40.default.cyan("template info")} ${import_picocolors40.default.dim("<creator/slug>")} ${import_picocolors40.default.dim("show registry details for a template")}`);
55650
+ out.push(` ${import_picocolors40.default.cyan("template onboard")} ${import_picocolors40.default.dim("<creator/slug>")} ${import_picocolors40.default.dim("install (or refresh) a template")}`);
55651
+ out.push(` ${import_picocolors40.default.cyan("template list")} ${import_picocolors40.default.dim("show installed templates")}`);
55652
+ out.push(` ${import_picocolors40.default.cyan("template remove")} ${import_picocolors40.default.dim("<creator/slug>")} ${import_picocolors40.default.dim("uninstall a template")}`);
55002
55653
  out.push("");
55003
55654
  out.push(divider("SKILLS"));
55004
55655
  out.push("");
55005
- out.push(` ${import_picocolors38.default.cyan("skill add")} ${import_picocolors38.default.dim("<source>")} ${import_picocolors38.default.dim("install a skill (github / git / brainbase)")}`);
55006
- out.push(` ${import_picocolors38.default.cyan("skill list")} ${import_picocolors38.default.dim("show locally installed skills + their source")}`);
55007
- out.push(` ${import_picocolors38.default.cyan("skill update")} ${import_picocolors38.default.dim("<slug>")} ${import_picocolors38.default.dim("re-fetch a skill from its recorded source")}`);
55008
- out.push(` ${import_picocolors38.default.cyan("skill remove")} ${import_picocolors38.default.dim("<slug>")} ${import_picocolors38.default.dim("uninstall a skill")}`);
55009
- out.push(` ${import_picocolors38.default.cyan("skill search")} ${import_picocolors38.default.dim("[query]")} ${import_picocolors38.default.dim("search the brainbase skill registry")}`);
55010
- out.push(` ${import_picocolors38.default.cyan("skill info")} ${import_picocolors38.default.dim("<creator/slug>")} ${import_picocolors38.default.dim("show registry details for a skill")}`);
55011
- out.push(` ${import_picocolors38.default.cyan("skill publish")} ${import_picocolors38.default.dim("[dir]")} ${import_picocolors38.default.dim("publish a SKILL.md folder (defaults to .)")}`);
55656
+ out.push(` ${import_picocolors40.default.cyan("skill add")} ${import_picocolors40.default.dim("<source>")} ${import_picocolors40.default.dim("install a skill (github / git / brainbase)")}`);
55657
+ out.push(` ${import_picocolors40.default.cyan("skill list")} ${import_picocolors40.default.dim("show locally installed skills + their source")}`);
55658
+ out.push(` ${import_picocolors40.default.cyan("skill update")} ${import_picocolors40.default.dim("<slug>")} ${import_picocolors40.default.dim("re-fetch a skill from its recorded source")}`);
55659
+ out.push(` ${import_picocolors40.default.cyan("skill remove")} ${import_picocolors40.default.dim("<slug>")} ${import_picocolors40.default.dim("uninstall a skill")}`);
55660
+ out.push(` ${import_picocolors40.default.cyan("skill search")} ${import_picocolors40.default.dim("[query]")} ${import_picocolors40.default.dim("search the brainbase skill registry")}`);
55661
+ out.push(` ${import_picocolors40.default.cyan("skill info")} ${import_picocolors40.default.dim("<creator/slug>")} ${import_picocolors40.default.dim("show registry details for a skill")}`);
55662
+ out.push(` ${import_picocolors40.default.cyan("skill publish")} ${import_picocolors40.default.dim("[dir]")} ${import_picocolors40.default.dim("publish a SKILL.md folder (defaults to .)")}`);
55012
55663
  out.push("");
55013
55664
  out.push(divider("CLI TOKENS"));
55014
55665
  out.push("");
55015
- out.push(` ${import_picocolors38.default.cyan("token create")} ${import_picocolors38.default.dim("issue a long-lived CLI key for CI / scripts")}`);
55016
- out.push(` ${import_picocolors38.default.cyan("token list")} ${import_picocolors38.default.dim("show your active tokens")}`);
55017
- out.push(` ${import_picocolors38.default.cyan("token revoke")} ${import_picocolors38.default.dim("<id>")} ${import_picocolors38.default.dim("revoke a token")}`);
55666
+ out.push(` ${import_picocolors40.default.cyan("token create")} ${import_picocolors40.default.dim("issue a long-lived CLI key for CI / scripts")}`);
55667
+ out.push(` ${import_picocolors40.default.cyan("token list")} ${import_picocolors40.default.dim("show your active tokens")}`);
55668
+ out.push(` ${import_picocolors40.default.cyan("token revoke")} ${import_picocolors40.default.dim("<id>")} ${import_picocolors40.default.dim("revoke a token")}`);
55018
55669
  out.push("");
55019
55670
  out.push(divider("FLAGS"));
55020
55671
  out.push("");
55021
- out.push(` ${import_picocolors38.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
55022
- out.push(` ${import_picocolors38.default.dim("--scope <s>")} force scope: global | project`);
55023
- out.push(` ${import_picocolors38.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
55024
- out.push(` ${import_picocolors38.default.dim("--agent <id>")} for link: attach this folder to an existing agent non-interactively`);
55025
- out.push(` ${import_picocolors38.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
55026
- out.push(` ${import_picocolors38.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
55027
- out.push(` ${import_picocolors38.default.dim("--all")} for template list: include installs from other folders`);
55028
- out.push(` ${import_picocolors38.default.dim("--web <url>")} for login: web app URL (default https://new.usekafka.com)`);
55672
+ out.push(` ${import_picocolors40.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
55673
+ out.push(` ${import_picocolors40.default.dim("--scope <s>")} force scope: global | project`);
55674
+ out.push(` ${import_picocolors40.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
55675
+ out.push(` ${import_picocolors40.default.dim("--agent <id>")} for link: attach this folder to an existing agent non-interactively`);
55676
+ out.push(` ${import_picocolors40.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
55677
+ out.push(` ${import_picocolors40.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
55678
+ out.push(` ${import_picocolors40.default.dim("--all")} for template list: include installs from other folders`);
55679
+ out.push(` ${import_picocolors40.default.dim("--web <url>")} for login: web app URL (default https://new.usekafka.com)`);
55029
55680
  out.push("");
55030
55681
  out.push(divider("ENV"));
55031
55682
  out.push("");
55032
- out.push(` ${import_picocolors38.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
55033
- out.push(` ${import_picocolors38.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
55034
- out.push(` ${import_picocolors38.default.dim("BRAINBASE_API_URL")} override the API URL used by link / sync`);
55035
- out.push(` ${import_picocolors38.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL`);
55036
- out.push(` ${import_picocolors38.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
55037
- out.push(` ${import_picocolors38.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
55683
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
55684
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
55685
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_API_URL")} override the API URL used by link / sync`);
55686
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL`);
55687
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
55688
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
55038
55689
  out.push("");
55039
55690
  out.push(divider("HARNESSES"));
55040
55691
  out.push("");
55041
- out.push(` ${import_picocolors38.default.dim("•")} ${import_picocolors38.default.bold("claude-code")} ${import_picocolors38.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
55042
- out.push(` ${import_picocolors38.default.dim("•")} ${import_picocolors38.default.bold("codex")} ${import_picocolors38.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
55043
- out.push(` ${import_picocolors38.default.dim("•")} ${import_picocolors38.default.bold("kafka")} ${import_picocolors38.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
55692
+ out.push(` ${import_picocolors40.default.dim("•")} ${import_picocolors40.default.bold("claude-code")} ${import_picocolors40.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
55693
+ out.push(` ${import_picocolors40.default.dim("•")} ${import_picocolors40.default.bold("codex")} ${import_picocolors40.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
55694
+ out.push(` ${import_picocolors40.default.dim("•")} ${import_picocolors40.default.bold("kafka")} ${import_picocolors40.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
55044
55695
  out.push("");
55045
55696
  console.log(out.join(`
55046
55697
  `));
@@ -55084,13 +55735,13 @@ async function requireAuth(cmd) {
55084
55735
  if (status.ok)
55085
55736
  return;
55086
55737
  console.error("");
55087
- console.error(` ${brandTint("◆")} ${import_picocolors38.default.bold("brainbase")}`);
55738
+ console.error(` ${brandTint("◆")} ${import_picocolors40.default.bold("brainbase")}`);
55088
55739
  console.error("");
55089
- console.error(` ${import_picocolors38.default.red("✗")} You need to sign in to use ${import_picocolors38.default.bold("brainbase " + cmd)}.`);
55740
+ console.error(` ${import_picocolors40.default.red("✗")} You need to sign in to use ${import_picocolors40.default.bold("brainbase " + cmd)}.`);
55090
55741
  if (status.reason)
55091
- console.error(` ${import_picocolors38.default.dim(status.reason)}`);
55742
+ console.error(` ${import_picocolors40.default.dim(status.reason)}`);
55092
55743
  console.error("");
55093
- console.error(` Run ${import_picocolors38.default.cyan("brainbase login")} to connect this device.`);
55744
+ console.error(` Run ${import_picocolors40.default.cyan("brainbase login")} to connect this device.`);
55094
55745
  console.error("");
55095
55746
  process13.exit(1);
55096
55747
  }
@@ -55127,6 +55778,7 @@ async function main() {
55127
55778
  const agentFlag = getFlag(argv, "--agent");
55128
55779
  const shellFlag = getFlag(argv, "--shell");
55129
55780
  const noTracking = hasFlag2(argv, "--no-tracking");
55781
+ const forceFlag = hasFlag2(argv, "--force");
55130
55782
  const graphOnlyFlag = hasFlag2(argv, "--graph-only");
55131
55783
  const nameFlag = getFlag(argv, "--name");
55132
55784
  const skillVersionFlag = getFlag(argv, "--skill-version");
@@ -55211,7 +55863,8 @@ async function main() {
55211
55863
  tagline: taglineFlag,
55212
55864
  orgId: orgIdFlag,
55213
55865
  teamId: teamIdFlag,
55214
- noTracking
55866
+ noTracking,
55867
+ force: forceFlag
55215
55868
  });
55216
55869
  break;
55217
55870
  }
@@ -55242,7 +55895,7 @@ async function main() {
55242
55895
  process13.exit(1);
55243
55896
  }
55244
55897
  } catch (err) {
55245
- console.error(import_picocolors38.default.red(`
55898
+ console.error(import_picocolors40.default.red(`
55246
55899
  ${err.message}`));
55247
55900
  if (process13.env.BRAINBASE_DEBUG)
55248
55901
  console.error(err.stack);