@brainbase-labs/cli 0.4.2 → 0.6.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 +1532 -581
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -28564,9 +28564,9 @@ 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
- import fs50 from "node:fs";
28569
+ import fs51 from "node:fs";
28570
28570
 
28571
28571
  // src/cli/template.ts
28572
28572
  var import_picocolors12 = __toESM(require_picocolors(), 1);
@@ -50759,11 +50759,192 @@ async function runWhoami() {
50759
50759
  var import_picocolors22 = __toESM(require_picocolors(), 1);
50760
50760
 
50761
50761
  // src/core/link.ts
50762
+ import path43 from "node:path";
50763
+ import fs40 from "node:fs";
50764
+
50765
+ // src/core/agent-manifest.ts
50762
50766
  import path42 from "node:path";
50763
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 = ".brainbase/instructions.md";
50772
+ var DEFAULT_ENTRYPOINT_FILE = ".brainbase/entrypoint.sh";
50773
+ var DEFAULT_PLAYBOOKS_DIR = ".brainbase/playbooks";
50774
+ var REGISTRY_SOURCE_RE = /^registry:(?:([a-z0-9_-]+)\/)?([a-z0-9_-]+)(?:@(.+))?$/i;
50775
+ function parseSkillSource2(raw) {
50776
+ if (!raw || typeof raw !== "string") {
50777
+ throw new Error("Skill source must be a non-empty string");
50778
+ }
50779
+ const m3 = raw.match(REGISTRY_SOURCE_RE);
50780
+ if (m3) {
50781
+ return {
50782
+ kind: "registry",
50783
+ ...m3[1] ? { creator: m3[1] } : {},
50784
+ slug: m3[2],
50785
+ version: m3[3]
50786
+ };
50787
+ }
50788
+ if (raw.startsWith("./") || raw.startsWith("../") || raw.startsWith("/")) {
50789
+ return { kind: "local", path: raw };
50790
+ }
50791
+ throw new Error(`Unrecognized skill source "${raw}". Expected "registry:creator/slug[@version]", "registry:slug", or a relative path starting with "./".`);
50792
+ }
50793
+ var AgentMetaSchema = exports_external.object({
50794
+ name: exports_external.string().min(1),
50795
+ tagline: exports_external.string().optional()
50796
+ });
50797
+ var InstructionsSchema = exports_external.object({
50798
+ file: exports_external.string().min(1).optional(),
50799
+ text: exports_external.string().optional()
50800
+ }).refine((v3) => v3.file !== undefined || v3.text !== undefined, {
50801
+ message: "instructions must set either `file` or `text`"
50802
+ });
50803
+ var EntrypointSchema = exports_external.object({
50804
+ file: exports_external.string().min(1).optional(),
50805
+ commands: exports_external.array(exports_external.string().min(1)).optional(),
50806
+ text: exports_external.string().optional()
50807
+ }).refine((v3) => {
50808
+ const set = [v3.file, v3.commands, v3.text].filter((x3) => x3 !== undefined);
50809
+ return set.length === 1;
50810
+ }, {
50811
+ message: "entrypoint must set exactly one of `file`, `commands`, or `text`"
50812
+ });
50813
+ var PlaybookContentSchema = exports_external.object({
50814
+ file: exports_external.string().min(1).optional(),
50815
+ text: exports_external.string().optional()
50816
+ }).refine((v3) => v3.file !== undefined || v3.text !== undefined, {
50817
+ message: "playbook content must set either `file` or `text`"
50818
+ });
50819
+ var PlaybookSchema = exports_external.object({
50820
+ title: exports_external.string().min(1),
50821
+ description: exports_external.string().optional(),
50822
+ content: PlaybookContentSchema
50823
+ });
50824
+ var SkillEntrySchema = exports_external.object({
50825
+ source: exports_external.string().min(1)
50826
+ });
50827
+ var McpEntrySchema = exports_external.object({
50828
+ name: exports_external.string().min(1),
50829
+ url: exports_external.string().optional(),
50830
+ command: exports_external.string().optional(),
50831
+ args: exports_external.array(exports_external.string()).optional(),
50832
+ env: exports_external.record(exports_external.string()).optional(),
50833
+ headers: exports_external.record(exports_external.string()).optional(),
50834
+ is_enabled: exports_external.boolean().optional()
50835
+ });
50836
+ var AgentManifestSchema = exports_external.object({
50837
+ schema: exports_external.literal(1),
50838
+ id: exports_external.string().min(1).optional(),
50839
+ harness: exports_external.string().min(1).optional(),
50840
+ agent: AgentMetaSchema,
50841
+ instructions: InstructionsSchema.optional(),
50842
+ entrypoint: EntrypointSchema.optional(),
50843
+ playbooks: exports_external.array(PlaybookSchema).default([]),
50844
+ skills: exports_external.array(SkillEntrySchema).default([]),
50845
+ mcp: exports_external.array(McpEntrySchema).default([]),
50846
+ commands: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
50847
+ hooks: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
50848
+ files: exports_external.array(exports_external.record(exports_external.unknown())).optional()
50849
+ });
50850
+ function manifestPath(cwd2) {
50851
+ return path42.join(cwd2, AGENT_MANIFEST_FILE);
50852
+ }
50853
+ function existingManifestPath(cwd2) {
50854
+ const newPath = path42.join(cwd2, AGENT_MANIFEST_FILE);
50855
+ if (fs39.existsSync(newPath))
50856
+ return newPath;
50857
+ const legacy = path42.join(cwd2, LEGACY_AGENT_MANIFEST_FILE);
50858
+ if (fs39.existsSync(legacy))
50859
+ return legacy;
50860
+ return null;
50861
+ }
50862
+ function hasManifest(cwd2) {
50863
+ return existingManifestPath(cwd2) !== null;
50864
+ }
50865
+ function readManifest(cwd2) {
50866
+ const p2 = existingManifestPath(cwd2);
50867
+ if (!p2)
50868
+ return null;
50869
+ const raw = fs39.readFileSync(p2, "utf8");
50870
+ let parsed;
50871
+ try {
50872
+ parsed = import_yaml2.default.parse(raw);
50873
+ } catch (err) {
50874
+ throw new Error(`${path42.basename(p2)} is not valid YAML: ${err.message}`);
50875
+ }
50876
+ const result = AgentManifestSchema.safeParse(parsed);
50877
+ if (!result.success) {
50878
+ throw new Error(`${path42.basename(p2)} is invalid: ${result.error.issues.map((i) => `${i.path.join(".") || "(root)"} — ${i.message}`).join("; ")}`);
50879
+ }
50880
+ return result.data;
50881
+ }
50882
+ function writeManifest(cwd2, manifest) {
50883
+ const doc = new import_yaml2.default.Document;
50884
+ doc.contents = manifest;
50885
+ doc.commentBefore = ` brainbase.agent.yaml — declarative agent manifest.
50886
+ ` + " Committed to source control. Edit by hand, then `brainbase agent push`.";
50887
+ const out = String(doc);
50888
+ fs39.writeFileSync(manifestPath(cwd2), out, "utf8");
50889
+ }
50890
+ function resolveInstructionsPath(cwd2, manifest) {
50891
+ if (!manifest.instructions?.file)
50892
+ return null;
50893
+ return path42.resolve(cwd2, manifest.instructions.file);
50894
+ }
50895
+ function readInstructions(cwd2, manifest) {
50896
+ if (!manifest.instructions)
50897
+ return null;
50898
+ if (typeof manifest.instructions.text === "string") {
50899
+ return manifest.instructions.text;
50900
+ }
50901
+ const p2 = resolveInstructionsPath(cwd2, manifest);
50902
+ if (!p2 || !fs39.existsSync(p2))
50903
+ return null;
50904
+ return fs39.readFileSync(p2, "utf8");
50905
+ }
50906
+ function resolveEntrypoint(cwd2, manifest) {
50907
+ const ep = manifest.entrypoint;
50908
+ if (!ep)
50909
+ return null;
50910
+ if (typeof ep.text === "string")
50911
+ return ep.text;
50912
+ if (Array.isArray(ep.commands)) {
50913
+ if (ep.commands.length === 0)
50914
+ return null;
50915
+ return ["set -euo pipefail", ...ep.commands].join(`
50916
+ `) + `
50917
+ `;
50918
+ }
50919
+ if (typeof ep.file === "string") {
50920
+ const p2 = path42.resolve(cwd2, ep.file);
50921
+ if (!fs39.existsSync(p2))
50922
+ return null;
50923
+ return fs39.readFileSync(p2, "utf8");
50924
+ }
50925
+ return null;
50926
+ }
50927
+ function resolvePlaybookContent(cwd2, entry) {
50928
+ const c2 = entry.content;
50929
+ if (typeof c2.text === "string")
50930
+ return c2.text;
50931
+ if (typeof c2.file === "string") {
50932
+ const p2 = path42.resolve(cwd2, c2.file);
50933
+ if (!fs39.existsSync(p2))
50934
+ return null;
50935
+ return fs39.readFileSync(p2, "utf8");
50936
+ }
50937
+ return null;
50938
+ }
50939
+ function slugifyPlaybookTitle(title) {
50940
+ return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "playbook";
50941
+ }
50942
+
50943
+ // src/core/link.ts
50764
50944
  var LINK_DIR = ".brainbase";
50765
- var LINK_FILE = "link.json";
50945
+ var STATE_FILE = "state.json";
50766
50946
  var SYNC_STATE_FILE = "sync-state.json";
50947
+ var LEGACY_LINK_FILE = "link.json";
50767
50948
  var TrackingSchema = exports_external.object({
50768
50949
  harness: exports_external.string(),
50769
50950
  key_id: exports_external.string(),
@@ -50786,6 +50967,16 @@ var LinkSchema = exports_external.object({
50786
50967
  harness: exports_external.string().nullish().transform((v3) => v3 ?? undefined),
50787
50968
  tracking: TrackingSchema.nullish().transform((v3) => v3 ?? undefined)
50788
50969
  });
50970
+ var LinkStateSchema = exports_external.object({
50971
+ schemaVersion: exports_external.literal(1),
50972
+ org_id: exports_external.string().default(""),
50973
+ team_id: exports_external.string().default(""),
50974
+ slug: exports_external.string().default(""),
50975
+ url: exports_external.string().nullish().transform((v3) => v3 ?? undefined),
50976
+ linked_at: exports_external.string(),
50977
+ linked_by: exports_external.string().nullish().transform((v3) => v3 ?? undefined),
50978
+ tracking: TrackingSchema.nullish().transform((v3) => v3 ?? undefined)
50979
+ });
50789
50980
  var SyncedComponentSchema = exports_external.object({
50790
50981
  type: exports_external.string(),
50791
50982
  slug: exports_external.string(),
@@ -50795,7 +50986,8 @@ var SyncedComponentSchema = exports_external.object({
50795
50986
  });
50796
50987
  var AgentMetaSnapshotSchema = exports_external.object({
50797
50988
  name: exports_external.string(),
50798
- tagline: exports_external.string().optional()
50989
+ tagline: exports_external.string().optional(),
50990
+ entrypoint: exports_external.string().optional()
50799
50991
  });
50800
50992
  var SyncStateSchema = exports_external.object({
50801
50993
  schemaVersion: exports_external.literal(1),
@@ -50805,39 +50997,159 @@ var SyncStateSchema = exports_external.object({
50805
50997
  components: exports_external.array(SyncedComponentSchema),
50806
50998
  agentMeta: AgentMetaSnapshotSchema.optional()
50807
50999
  });
50808
- function linkPath(cwd2) {
50809
- return path42.join(cwd2, LINK_DIR, LINK_FILE);
51000
+ function statePath(cwd2) {
51001
+ return path43.join(cwd2, LINK_DIR, STATE_FILE);
50810
51002
  }
50811
51003
  function syncStatePath(cwd2) {
50812
- return path42.join(cwd2, LINK_DIR, SYNC_STATE_FILE);
51004
+ return path43.join(cwd2, LINK_DIR, SYNC_STATE_FILE);
51005
+ }
51006
+ function legacyLinkPath(cwd2) {
51007
+ return path43.join(cwd2, LINK_DIR, LEGACY_LINK_FILE);
51008
+ }
51009
+ function readState(cwd2) {
51010
+ const p2 = statePath(cwd2);
51011
+ if (exists(p2)) {
51012
+ try {
51013
+ return LinkStateSchema.parse(readJson(p2));
51014
+ } catch {
51015
+ return null;
51016
+ }
51017
+ }
51018
+ const legacy = legacyLinkPath(cwd2);
51019
+ if (exists(legacy)) {
51020
+ try {
51021
+ const raw = readJson(legacy);
51022
+ const lifted = {
51023
+ schemaVersion: 1,
51024
+ org_id: String(raw.org_id ?? ""),
51025
+ team_id: String(raw.team_id ?? ""),
51026
+ slug: String(raw.slug ?? ""),
51027
+ url: typeof raw.url === "string" ? raw.url : undefined,
51028
+ linked_at: typeof raw.linked_at === "string" ? raw.linked_at : new Date().toISOString(),
51029
+ linked_by: typeof raw.linked_by === "string" ? raw.linked_by : undefined,
51030
+ tracking: (() => {
51031
+ try {
51032
+ return TrackingSchema.parse(raw.tracking);
51033
+ } catch {
51034
+ return;
51035
+ }
51036
+ })()
51037
+ };
51038
+ try {
51039
+ ensureDir(path43.join(cwd2, LINK_DIR));
51040
+ writeJson(statePath(cwd2), lifted);
51041
+ ensureGitignore(cwd2);
51042
+ } catch {}
51043
+ return lifted;
51044
+ } catch {
51045
+ return null;
51046
+ }
51047
+ }
51048
+ return null;
51049
+ }
51050
+ function writeState(cwd2, state) {
51051
+ ensureDir(path43.join(cwd2, LINK_DIR));
51052
+ writeJson(statePath(cwd2), state);
51053
+ ensureGitignore(cwd2);
50813
51054
  }
50814
51055
  function readLink(cwd2) {
50815
- const p2 = linkPath(cwd2);
50816
- if (!exists(p2))
50817
- return null;
51056
+ let manifest = null;
50818
51057
  try {
50819
- return LinkSchema.parse(readJson(p2));
51058
+ manifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
50820
51059
  } catch {
50821
- return null;
51060
+ manifest = null;
51061
+ }
51062
+ const state = readState(cwd2);
51063
+ if (manifest?.id) {
51064
+ return {
51065
+ schemaVersion: 1,
51066
+ agent_id: manifest.id,
51067
+ org_id: state?.org_id ?? "",
51068
+ team_id: state?.team_id ?? "",
51069
+ slug: state?.slug ?? "",
51070
+ name: manifest.agent.name,
51071
+ tagline: manifest.agent.tagline,
51072
+ url: state?.url,
51073
+ linked_at: state?.linked_at ?? new Date().toISOString(),
51074
+ linked_by: state?.linked_by,
51075
+ harness: manifest.harness,
51076
+ tracking: state?.tracking
51077
+ };
51078
+ }
51079
+ const legacy = legacyLinkPath(cwd2);
51080
+ if (exists(legacy)) {
51081
+ try {
51082
+ return LinkSchema.parse(readJson(legacy));
51083
+ } catch {
51084
+ return null;
51085
+ }
50822
51086
  }
51087
+ return null;
50823
51088
  }
50824
51089
  function writeLink(cwd2, link2) {
50825
- ensureDir(path42.join(cwd2, LINK_DIR));
50826
- const clean = {};
50827
- for (const [k3, v3] of Object.entries(link2)) {
50828
- if (v3 !== null && v3 !== undefined)
50829
- clean[k3] = v3;
51090
+ let manifest;
51091
+ try {
51092
+ manifest = readManifest(cwd2) ?? {
51093
+ schema: 1,
51094
+ agent: { name: link2.name },
51095
+ playbooks: [],
51096
+ skills: [],
51097
+ mcp: []
51098
+ };
51099
+ } catch {
51100
+ manifest = {
51101
+ schema: 1,
51102
+ agent: { name: link2.name },
51103
+ playbooks: [],
51104
+ skills: [],
51105
+ mcp: []
51106
+ };
51107
+ }
51108
+ manifest.id = link2.agent_id;
51109
+ if (link2.harness)
51110
+ manifest.harness = link2.harness;
51111
+ manifest.agent.name = link2.name;
51112
+ if (link2.tagline)
51113
+ manifest.agent.tagline = link2.tagline;
51114
+ else
51115
+ delete manifest.agent.tagline;
51116
+ writeManifest(cwd2, manifest);
51117
+ const state = {
51118
+ schemaVersion: 1,
51119
+ org_id: link2.org_id,
51120
+ team_id: link2.team_id,
51121
+ slug: link2.slug,
51122
+ url: link2.url,
51123
+ linked_at: link2.linked_at,
51124
+ linked_by: link2.linked_by,
51125
+ tracking: link2.tracking
51126
+ };
51127
+ writeState(cwd2, state);
51128
+ const legacy = legacyLinkPath(cwd2);
51129
+ if (exists(legacy)) {
51130
+ try {
51131
+ fs40.rmSync(legacy);
51132
+ } catch {}
50830
51133
  }
50831
- writeJson(linkPath(cwd2), clean);
50832
- ensureGitignore(cwd2);
50833
51134
  }
50834
51135
  function clearLink(cwd2) {
50835
- const p2 = linkPath(cwd2);
51136
+ try {
51137
+ const m3 = hasManifest(cwd2) ? readManifest(cwd2) : null;
51138
+ if (m3) {
51139
+ delete m3.id;
51140
+ delete m3.harness;
51141
+ writeManifest(cwd2, m3);
51142
+ }
51143
+ } catch {}
51144
+ const p2 = statePath(cwd2);
50836
51145
  if (exists(p2))
50837
- fs39.rmSync(p2);
51146
+ fs40.rmSync(p2);
50838
51147
  const sp = syncStatePath(cwd2);
50839
51148
  if (exists(sp))
50840
- fs39.rmSync(sp);
51149
+ fs40.rmSync(sp);
51150
+ const legacy = legacyLinkPath(cwd2);
51151
+ if (exists(legacy))
51152
+ fs40.rmSync(legacy);
50841
51153
  }
50842
51154
  function readSyncState(cwd2) {
50843
51155
  const p2 = syncStatePath(cwd2);
@@ -50850,22 +51162,22 @@ function readSyncState(cwd2) {
50850
51162
  }
50851
51163
  }
50852
51164
  function writeSyncState(cwd2, state) {
50853
- ensureDir(path42.join(cwd2, LINK_DIR));
51165
+ ensureDir(path43.join(cwd2, LINK_DIR));
50854
51166
  writeJson(syncStatePath(cwd2), state);
50855
51167
  ensureGitignore(cwd2);
50856
51168
  }
50857
51169
  function ensureGitignore(cwd2) {
50858
- const ignorePath = path42.join(cwd2, LINK_DIR, ".gitignore");
50859
- const desired = `${SYNC_STATE_FILE}
50860
- `;
51170
+ const ignorePath = path43.join(cwd2, LINK_DIR, ".gitignore");
51171
+ const desired = ["*", `!.gitignore`, ""].join(`
51172
+ `);
50861
51173
  try {
50862
51174
  if (!exists(ignorePath)) {
50863
- fs39.writeFileSync(ignorePath, desired);
51175
+ fs40.writeFileSync(ignorePath, desired);
50864
51176
  return;
50865
51177
  }
50866
- const current = fs39.readFileSync(ignorePath, "utf8");
50867
- if (!current.split(/\r?\n/).some((l2) => l2.trim() === SYNC_STATE_FILE)) {
50868
- fs39.writeFileSync(ignorePath, current.endsWith(`
51178
+ const current = fs40.readFileSync(ignorePath, "utf8");
51179
+ if (!current.split(/\r?\n/).some((l2) => l2.trim() === "*")) {
51180
+ fs40.writeFileSync(ignorePath, current.endsWith(`
50869
51181
  `) ? current + desired : current + `
50870
51182
  ` + desired);
50871
51183
  }
@@ -50873,15 +51185,15 @@ function ensureGitignore(cwd2) {
50873
51185
  }
50874
51186
 
50875
51187
  // src/core/route-adapters.ts
50876
- import path43 from "node:path";
51188
+ import path44 from "node:path";
50877
51189
  import os10 from "node:os";
50878
- import fs40 from "node:fs";
51190
+ import fs41 from "node:fs";
50879
51191
  var CLAUDE_ENV_KEYS = ["ANTHROPIC_BASE_URL", "ANTHROPIC_AUTH_TOKEN"];
50880
51192
  function claudeSettingsPath(cwd2) {
50881
- return path43.join(cwd2, ".claude", "settings.json");
51193
+ return path44.join(cwd2, ".claude", "settings.json");
50882
51194
  }
50883
51195
  function claudeUserConfigPath() {
50884
- return path43.join(os10.homedir(), ".claude.json");
51196
+ return path44.join(os10.homedir(), ".claude.json");
50885
51197
  }
50886
51198
  function ensureClaudeOnboarded() {
50887
51199
  const file = claudeUserConfigPath();
@@ -50905,7 +51217,7 @@ var claudeRouteAdapter = {
50905
51217
  settings.env = { ...settings.env ?? {} };
50906
51218
  settings.env.ANTHROPIC_BASE_URL = target.apiBase;
50907
51219
  settings.env.ANTHROPIC_AUTH_TOKEN = target.apiKey;
50908
- ensureDir(path43.dirname(file));
51220
+ ensureDir(path44.dirname(file));
50909
51221
  writeJson(file, settings);
50910
51222
  const notes = [];
50911
51223
  if (ensureClaudeOnboarded()) {
@@ -50932,11 +51244,11 @@ var claudeRouteAdapter = {
50932
51244
  delete settings.env;
50933
51245
  }
50934
51246
  if (snap && !snap.fileExisted && Object.keys(settings).length === 0) {
50935
- fs40.rmSync(file);
50936
- const dir = path43.dirname(file);
51247
+ fs41.rmSync(file);
51248
+ const dir = path44.dirname(file);
50937
51249
  try {
50938
- if (fs40.readdirSync(dir).length === 0)
50939
- fs40.rmdirSync(dir);
51250
+ if (fs41.readdirSync(dir).length === 0)
51251
+ fs41.rmdirSync(dir);
50940
51252
  } catch {}
50941
51253
  return;
50942
51254
  }
@@ -50946,20 +51258,20 @@ var claudeRouteAdapter = {
50946
51258
  var CODEX_PROVIDER_KEY = "brainbase";
50947
51259
  var CODEX_AUTH_HEADER = "Authorization";
50948
51260
  function codexConfigPath(cwd2) {
50949
- return path43.join(cwd2, ".codex", "config.toml");
51261
+ return path44.join(cwd2, ".codex", "config.toml");
50950
51262
  }
50951
51263
  function readCodexConfig2(file) {
50952
51264
  if (!exists(file))
50953
51265
  return {};
50954
51266
  try {
50955
- return parse(fs40.readFileSync(file, "utf8"));
51267
+ return parse(fs41.readFileSync(file, "utf8"));
50956
51268
  } catch {
50957
51269
  return {};
50958
51270
  }
50959
51271
  }
50960
51272
  function writeCodexConfig2(file, value) {
50961
- ensureDir(path43.dirname(file));
50962
- fs40.writeFileSync(file, stringify(value) + `
51273
+ ensureDir(path44.dirname(file));
51274
+ fs41.writeFileSync(file, stringify(value) + `
50963
51275
  `);
50964
51276
  }
50965
51277
  function ensureV1(base2) {
@@ -51015,11 +51327,11 @@ var codexRouteAdapter = {
51015
51327
  }
51016
51328
  }
51017
51329
  if (snap && !snap.fileExisted && Object.keys(cfg).length === 0) {
51018
- fs40.rmSync(file);
51019
- const dir = path43.dirname(file);
51330
+ fs41.rmSync(file);
51331
+ const dir = path44.dirname(file);
51020
51332
  try {
51021
- if (fs40.readdirSync(dir).length === 0)
51022
- fs40.rmdirSync(dir);
51333
+ if (fs41.readdirSync(dir).length === 0)
51334
+ fs41.rmdirSync(dir);
51023
51335
  } catch {}
51024
51336
  return;
51025
51337
  }
@@ -51309,8 +51621,8 @@ async function runUnlink(cwd2, args) {
51309
51621
  }
51310
51622
 
51311
51623
  // src/cli/sync.ts
51312
- import path44 from "node:path";
51313
- import fs41 from "node:fs";
51624
+ import path45 from "node:path";
51625
+ import fs42 from "node:fs";
51314
51626
  import os11 from "node:os";
51315
51627
  import crypto3 from "node:crypto";
51316
51628
  var import_picocolors24 = __toESM(require_picocolors(), 1);
@@ -51504,7 +51816,7 @@ async function runSync(cwd2, args) {
51504
51816
  type: c2.type,
51505
51817
  slug: c2.slug,
51506
51818
  scope,
51507
- rootDir: path44.join(stageRoot, c2.type, c2.slug),
51819
+ rootDir: path45.join(stageRoot, c2.type, c2.slug),
51508
51820
  description: c2.description,
51509
51821
  meta: c2.meta,
51510
51822
  payload: c2.meta?.mcp,
@@ -51553,11 +51865,11 @@ async function runSync(cwd2, args) {
51553
51865
  if (!exists(filePath))
51554
51866
  continue;
51555
51867
  try {
51556
- const stat = fs41.statSync(filePath);
51868
+ const stat = fs42.statSync(filePath);
51557
51869
  if (stat.isDirectory())
51558
- fs41.rmSync(filePath, { recursive: true, force: true });
51870
+ fs42.rmSync(filePath, { recursive: true, force: true });
51559
51871
  else
51560
- fs41.rmSync(filePath);
51872
+ fs42.rmSync(filePath);
51561
51873
  } catch (err) {
51562
51874
  f2.warn(`Failed to remove ${filePath}: ${err.message}`);
51563
51875
  }
@@ -51595,7 +51907,7 @@ async function runSync(cwd2, args) {
51595
51907
  $e(`Synced ${link2.name} to revision ${manifest.revision}.`);
51596
51908
  } finally {
51597
51909
  try {
51598
- fs41.rmSync(stageRoot, { recursive: true, force: true });
51910
+ fs42.rmSync(stageRoot, { recursive: true, force: true });
51599
51911
  } catch {}
51600
51912
  }
51601
51913
  }
@@ -51643,14 +51955,14 @@ function computeLocalHash(paths) {
51643
51955
  if (!exists(filePath))
51644
51956
  return null;
51645
51957
  try {
51646
- const stat = fs41.statSync(filePath);
51958
+ const stat = fs42.statSync(filePath);
51647
51959
  if (stat.isFile()) {
51648
51960
  h2.update("F " + filePath + " ");
51649
- h2.update(fs41.readFileSync(filePath));
51961
+ h2.update(fs42.readFileSync(filePath));
51650
51962
  h2.update(`
51651
51963
  `);
51652
51964
  } else if (stat.isDirectory()) {
51653
- for (const name of fs41.readdirSync(filePath).sort()) {
51965
+ for (const name of fs42.readdirSync(filePath).sort()) {
51654
51966
  h2.update("E " + name + `
51655
51967
  `);
51656
51968
  }
@@ -51662,14 +51974,14 @@ function computeLocalHash(paths) {
51662
51974
  return h2.digest("hex");
51663
51975
  }
51664
51976
  function stageManifest(components) {
51665
- const root = fs41.mkdtempSync(path44.join(os11.tmpdir(), "brainbase-sync-"));
51977
+ const root = fs42.mkdtempSync(path45.join(os11.tmpdir(), "brainbase-sync-"));
51666
51978
  for (const c2 of components) {
51667
- const compDir = path44.join(root, c2.type, c2.slug);
51979
+ const compDir = path45.join(root, c2.type, c2.slug);
51668
51980
  ensureDir(compDir);
51669
51981
  for (const f4 of c2.files) {
51670
- const target = path44.join(compDir, f4.path);
51671
- ensureDir(path44.dirname(target));
51672
- fs41.writeFileSync(target, f4.content);
51982
+ const target = path45.join(compDir, f4.path);
51983
+ ensureDir(path45.dirname(target));
51984
+ fs42.writeFileSync(target, f4.content);
51673
51985
  }
51674
51986
  }
51675
51987
  return root;
@@ -51683,142 +51995,47 @@ function runHarnessInstall(harnessId, components, opts, agentName) {
51683
51995
  }
51684
51996
 
51685
51997
  // src/cli/agent.ts
51686
- var import_picocolors30 = __toESM(require_picocolors(), 1);
51998
+ var import_picocolors32 = __toESM(require_picocolors(), 1);
51687
51999
 
51688
52000
  // src/cli/agent-pull.ts
52001
+ import { spawn as spawn2 } from "node:child_process";
51689
52002
  import path48 from "node:path";
51690
52003
  import fs45 from "node:fs";
51691
52004
  import os12 from "node:os";
51692
52005
  var import_picocolors25 = __toESM(require_picocolors(), 1);
52006
+ var import_yaml3 = __toESM(require_dist(), 1);
51693
52007
 
51694
- // src/core/agent-manifest.ts
51695
- import path45 from "node:path";
51696
- import fs42 from "node:fs";
51697
- var import_yaml2 = __toESM(require_dist(), 1);
51698
- var AGENT_MANIFEST_FILE = "brainbase.yaml";
51699
- var DEFAULT_INSTRUCTIONS_FILE = "instructions.md";
51700
- var REGISTRY_SOURCE_RE = /^registry:(?:([a-z0-9_-]+)\/)?([a-z0-9_-]+)(?:@(.+))?$/i;
51701
- function parseSkillSource2(raw) {
51702
- if (!raw || typeof raw !== "string") {
51703
- throw new Error("Skill source must be a non-empty string");
52008
+ // src/core/agent-diff.ts
52009
+ import path46 from "node:path";
52010
+ import fs43 from "node:fs";
52011
+ import crypto4 from "node:crypto";
52012
+ function compKey(type, slug) {
52013
+ return `${type}/${slug}`;
52014
+ }
52015
+ function hashString(s3) {
52016
+ return crypto4.createHash("sha256").update(s3).digest("hex");
52017
+ }
52018
+ function canonicalJson(value) {
52019
+ if (value === null)
52020
+ return "null";
52021
+ if (typeof value === "boolean")
52022
+ return value ? "true" : "false";
52023
+ if (typeof value === "number") {
52024
+ if (!Number.isFinite(value))
52025
+ throw new Error("Non-finite numbers are not JSON");
52026
+ return String(value);
51704
52027
  }
51705
- const m3 = raw.match(REGISTRY_SOURCE_RE);
51706
- if (m3) {
51707
- return {
51708
- kind: "registry",
51709
- ...m3[1] ? { creator: m3[1] } : {},
51710
- slug: m3[2],
51711
- version: m3[3]
51712
- };
52028
+ if (typeof value === "string")
52029
+ return JSON.stringify(value);
52030
+ if (Array.isArray(value)) {
52031
+ return "[" + value.map(canonicalJson).join(",") + "]";
51713
52032
  }
51714
- if (raw.startsWith("./") || raw.startsWith("../") || raw.startsWith("/")) {
51715
- return { kind: "local", path: raw };
52033
+ if (typeof value === "object") {
52034
+ const obj = value;
52035
+ const keys = Object.keys(obj).sort();
52036
+ return "{" + keys.map((k3) => `${JSON.stringify(k3)}:${canonicalJson(obj[k3])}`).join(",") + "}";
51716
52037
  }
51717
- throw new Error(`Unrecognized skill source "${raw}". Expected "registry:creator/slug[@version]", "registry:slug", or a relative path starting with "./".`);
51718
- }
51719
- var AgentMetaSchema = exports_external.object({
51720
- name: exports_external.string().min(1),
51721
- tagline: exports_external.string().optional()
51722
- });
51723
- var InstructionsSchema = exports_external.object({
51724
- file: exports_external.string().min(1)
51725
- });
51726
- var SkillEntrySchema = exports_external.object({
51727
- source: exports_external.string().min(1)
51728
- });
51729
- var McpEntrySchema = exports_external.object({
51730
- name: exports_external.string().min(1),
51731
- url: exports_external.string().optional(),
51732
- command: exports_external.string().optional(),
51733
- args: exports_external.array(exports_external.string()).optional(),
51734
- env: exports_external.record(exports_external.string()).optional(),
51735
- headers: exports_external.record(exports_external.string()).optional(),
51736
- is_enabled: exports_external.boolean().optional()
51737
- });
51738
- var AgentManifestSchema = exports_external.object({
51739
- schema: exports_external.literal(1),
51740
- agent: AgentMetaSchema,
51741
- instructions: InstructionsSchema.optional(),
51742
- skills: exports_external.array(SkillEntrySchema).default([]),
51743
- mcp: exports_external.array(McpEntrySchema).default([]),
51744
- commands: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
51745
- hooks: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
51746
- files: exports_external.array(exports_external.record(exports_external.unknown())).optional()
51747
- });
51748
- function manifestPath(cwd2) {
51749
- return path45.join(cwd2, AGENT_MANIFEST_FILE);
51750
- }
51751
- function hasManifest(cwd2) {
51752
- return fs42.existsSync(manifestPath(cwd2));
51753
- }
51754
- function readManifest(cwd2) {
51755
- const p2 = manifestPath(cwd2);
51756
- if (!fs42.existsSync(p2))
51757
- return null;
51758
- const raw = fs42.readFileSync(p2, "utf8");
51759
- let parsed;
51760
- try {
51761
- parsed = import_yaml2.default.parse(raw);
51762
- } catch (err) {
51763
- throw new Error(`${AGENT_MANIFEST_FILE} is not valid YAML: ${err.message}`);
51764
- }
51765
- const result = AgentManifestSchema.safeParse(parsed);
51766
- if (!result.success) {
51767
- throw new Error(`${AGENT_MANIFEST_FILE} is invalid: ${result.error.issues.map((i) => `${i.path.join(".") || "(root)"} — ${i.message}`).join("; ")}`);
51768
- }
51769
- return result.data;
51770
- }
51771
- function writeManifest(cwd2, manifest) {
51772
- const doc = new import_yaml2.default.Document;
51773
- doc.contents = manifest;
51774
- doc.commentBefore = ` brainbase.yaml — declarative agent manifest.
51775
- ` + " Committed to source control. Edit by hand, then `brainbase agent push`.";
51776
- const out = String(doc);
51777
- fs42.writeFileSync(manifestPath(cwd2), out, "utf8");
51778
- }
51779
- function resolveInstructionsPath(cwd2, manifest) {
51780
- if (!manifest.instructions)
51781
- return null;
51782
- return path45.resolve(cwd2, manifest.instructions.file);
51783
- }
51784
- function readInstructions(cwd2, manifest) {
51785
- const p2 = resolveInstructionsPath(cwd2, manifest);
51786
- if (!p2 || !fs42.existsSync(p2))
51787
- return null;
51788
- return fs42.readFileSync(p2, "utf8");
51789
- }
51790
-
51791
- // src/core/agent-diff.ts
51792
- import path46 from "node:path";
51793
- import fs43 from "node:fs";
51794
- import crypto4 from "node:crypto";
51795
- function compKey(type, slug) {
51796
- return `${type}/${slug}`;
51797
- }
51798
- function hashString(s3) {
51799
- return crypto4.createHash("sha256").update(s3).digest("hex");
51800
- }
51801
- function canonicalJson(value) {
51802
- if (value === null)
51803
- return "null";
51804
- if (typeof value === "boolean")
51805
- return value ? "true" : "false";
51806
- if (typeof value === "number") {
51807
- if (!Number.isFinite(value))
51808
- throw new Error("Non-finite numbers are not JSON");
51809
- return String(value);
51810
- }
51811
- if (typeof value === "string")
51812
- return JSON.stringify(value);
51813
- if (Array.isArray(value)) {
51814
- return "[" + value.map(canonicalJson).join(",") + "]";
51815
- }
51816
- if (typeof value === "object") {
51817
- const obj = value;
51818
- const keys = Object.keys(obj).sort();
51819
- return "{" + keys.map((k3) => `${JSON.stringify(k3)}:${canonicalJson(obj[k3])}`).join(",") + "}";
51820
- }
51821
- throw new Error(`Unsupported value in canonicalJson: ${typeof value}`);
52038
+ throw new Error(`Unsupported value in canonicalJson: ${typeof value}`);
51822
52039
  }
51823
52040
  function hashMcpEntry(entry) {
51824
52041
  const payload = {};
@@ -51933,8 +52150,34 @@ function readLocalComponents(cwd2, manifest) {
51933
52150
  hash: hashMcpEntry(entry)
51934
52151
  });
51935
52152
  }
52153
+ for (const entry of manifest.playbooks ?? []) {
52154
+ const body = resolvePlaybookContent(cwd2, entry);
52155
+ if (body === null) {
52156
+ out.push({
52157
+ type: "playbook",
52158
+ slug: slugifyPlaybookTitle(entry.title),
52159
+ hash: null
52160
+ });
52161
+ continue;
52162
+ }
52163
+ const wireBody = /^---\s*\n/.test(body) ? body : `---
52164
+ title: ${jsonOrPlain(entry.title)}` + (entry.description ? `
52165
+ description: ${jsonOrPlain(entry.description)}` : "") + `
52166
+ ---
52167
+ ${body.replace(/^\n+/, "")}`;
52168
+ out.push({
52169
+ type: "playbook",
52170
+ slug: slugifyPlaybookTitle(entry.title),
52171
+ hash: componentHashFromFileHashes([hashString(wireBody)])
52172
+ });
52173
+ }
51936
52174
  return out;
51937
52175
  }
52176
+ function jsonOrPlain(s3) {
52177
+ if (!/[\n":#&*!|>'%@`{}[\]]/.test(s3) && s3.trim() === s3 && s3 !== "")
52178
+ return s3;
52179
+ return JSON.stringify(s3);
52180
+ }
51938
52181
  function threeWayDiff(input) {
51939
52182
  const lockMap = new Map;
51940
52183
  for (const c2 of input.lock)
@@ -52123,26 +52366,27 @@ function diffSecrets(local, cloud) {
52123
52366
  // src/cli/agent-pull.ts
52124
52367
  async function runAgentPull(cwd2, args) {
52125
52368
  banner("agent pull — bring cloud changes into this folder");
52126
- const link2 = readLink(cwd2);
52127
- if (!link2) {
52128
- f2.warn("This folder is not linked to any agent.");
52129
- f2.info(`Run ${import_picocolors25.default.cyan("brainbase link")} first.`);
52369
+ const resolution = resolveTargetAgentId(cwd2, args);
52370
+ if (!resolution)
52130
52371
  return;
52131
- }
52372
+ const { agentId, override } = resolution;
52132
52373
  const sp = de();
52133
- sp.start(`Fetching ${link2.name}…`);
52374
+ sp.start("Fetching agent…");
52375
+ let cloudAgent;
52134
52376
  let cloud;
52135
52377
  try {
52136
- cloud = await api.getAgentManifest(link2.agent_id);
52378
+ cloudAgent = await api.getAgent(agentId);
52379
+ cloud = await api.getAgentManifest(agentId);
52137
52380
  sp.stop(`Cloud revision ${cloud.revision}.`);
52138
52381
  } catch (err) {
52139
52382
  sp.stop("Failed.");
52140
52383
  handleApiError2(err);
52141
52384
  return;
52142
52385
  }
52143
- const lock = readSyncState(cwd2);
52144
- const localManifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
52145
- const localComponents = localManifest ? readLocalComponents(cwd2, localManifest) : [];
52386
+ const harness = normalizeHarnessId(cloudAgent.harness ?? "claude-code");
52387
+ const existingManifest = !override && hasManifest(cwd2) ? safeReadManifest(cwd2) : null;
52388
+ const lock = override ? null : readSyncState(cwd2);
52389
+ const localComponents = existingManifest ? readLocalComponents(cwd2, existingManifest) : [];
52146
52390
  const rows = threeWayDiff({
52147
52391
  local: localComponents,
52148
52392
  lock: lock?.components ?? [],
@@ -52167,7 +52411,11 @@ async function runAgentPull(cwd2, args) {
52167
52411
  break;
52168
52412
  case "modified-both":
52169
52413
  case "modified-local":
52170
- conflicts.push(r2);
52414
+ if (override) {
52415
+ toInstallKeys.add(r2.key);
52416
+ } else {
52417
+ conflicts.push(r2);
52418
+ }
52171
52419
  break;
52172
52420
  }
52173
52421
  }
@@ -52191,11 +52439,12 @@ async function runAgentPull(cwd2, args) {
52191
52439
  const needOrchestrationMcpInstall = !cloudHasOrchestrationMcp;
52192
52440
  const cloudHasMemoryMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === MEMORY_MCP_SLUG);
52193
52441
  const needMemoryMcpInstall = !cloudHasMemoryMcp;
52194
- if (toInstallKeys.size === 0 && toRemoveKeys.size === 0 && !needOrchestrationMcpInstall && !needMemoryMcpInstall) {
52442
+ if (toInstallKeys.size === 0 && toRemoveKeys.size === 0 && !needOrchestrationMcpInstall && !needMemoryMcpInstall && !override) {
52195
52443
  f2.info(`You're up to date.`);
52196
- writeSyncState(cwd2, buildLockFromCloud(link2.agent_id, cloud, lock));
52197
- if (!localManifest) {
52198
- writeBrainbaseYamlFromCloud(cwd2, link2, cloud);
52444
+ writeLink(cwd2, buildLinkFromAgent(cloudAgent, harness, readLink(cwd2)));
52445
+ writeSyncState(cwd2, buildLockFromCloud(agentId, cloud, lock, cloudAgent));
52446
+ if (!existingManifest) {
52447
+ writeManifest(cwd2, mergeManifest(cwd2, null, cloud, cloudAgent, harness));
52199
52448
  f2.info(`Wrote ${import_picocolors25.default.bold(AGENT_MANIFEST_FILE)}.`);
52200
52449
  }
52201
52450
  return;
@@ -52225,20 +52474,20 @@ async function runAgentPull(cwd2, args) {
52225
52474
  });
52226
52475
  }
52227
52476
  await showResultCard({
52228
- title: "PULL",
52229
- tone: "info",
52230
- subtitle: `updates for ${link2.name}`,
52477
+ title: override ? "PULL (FORCE)" : "PULL",
52478
+ tone: override ? "warn" : "info",
52479
+ subtitle: `updates for ${cloudAgent.name}`,
52231
52480
  rows: resultRows
52232
52481
  });
52233
52482
  if (!args.yes) {
52234
- const ok = await se({ message: "Apply these changes?", initialValue: true });
52483
+ const msg = override ? "Apply these changes? Local edits to overlapping components will be discarded." : "Apply these changes?";
52484
+ const ok = await se({ message: msg, initialValue: true });
52235
52485
  if (!ensureNotCancelled(ok)) {
52236
52486
  $e("Aborted.");
52237
52487
  return;
52238
52488
  }
52239
52489
  }
52240
- const adapterId = link2.harness ?? link2.tracking?.harness ?? "claude-code";
52241
- const adapter = getAdapter(adapterId);
52490
+ const adapter = getAdapter(harness);
52242
52491
  const scope = args.scope ?? "project";
52243
52492
  const installComponents = cloud.components.filter((c2) => toInstallKeys.has(`${c2.type}/${c2.slug}`));
52244
52493
  const stageRoot = stageManifestComponents(installComponents);
@@ -52270,7 +52519,7 @@ async function runAgentPull(cwd2, args) {
52270
52519
  resolveConflict: async (_c) => "overwrite",
52271
52520
  resolveSecret: async () => null
52272
52521
  };
52273
- const result = await runHarnessInstall2(adapter.id, toInstall, opts, link2.name);
52522
+ const result = await runHarnessInstall2(adapter.id, toInstall, opts, cloudAgent.name);
52274
52523
  installSpinner.stop("Applied.");
52275
52524
  for (const o2 of result.installed) {
52276
52525
  justInstalledPaths.set(`${o2.type}/${o2.slug}`, o2.installedPaths);
@@ -52297,9 +52546,12 @@ async function runAgentPull(cwd2, args) {
52297
52546
  }
52298
52547
  }
52299
52548
  }
52300
- materializeInstructions(cwd2, cloud, toInstallKeys, keepLocalKeys);
52301
- const yaml = mergeManifest(cwd2, localManifest, cloud, link2);
52549
+ materializeInstructions(cwd2, cloud, toInstallKeys, keepLocalKeys, existingManifest);
52550
+ materializeEntrypoint(cwd2, cloudAgent.entrypoint ?? "", existingManifest);
52551
+ materializePlaybooks(cwd2, cloud, toInstallKeys, keepLocalKeys, existingManifest);
52552
+ const yaml = mergeManifest(cwd2, existingManifest, cloud, cloudAgent, harness);
52302
52553
  writeManifest(cwd2, yaml);
52554
+ writeLink(cwd2, buildLinkFromAgent(cloudAgent, harness, readLink(cwd2)));
52303
52555
  const lockComponents = buildLockComponents({
52304
52556
  cloud,
52305
52557
  prevLock: lock,
@@ -52309,21 +52561,64 @@ async function runAgentPull(cwd2, args) {
52309
52561
  });
52310
52562
  const newState = {
52311
52563
  schemaVersion: 1,
52312
- agent_id: link2.agent_id,
52564
+ agent_id: agentId,
52313
52565
  revision: cloud.revision,
52314
52566
  synced_at: new Date().toISOString(),
52315
52567
  components: lockComponents,
52316
- agentMeta: { name: link2.name, tagline: link2.tagline }
52568
+ agentMeta: {
52569
+ name: cloudAgent.name,
52570
+ tagline: cloudAgent.tagline,
52571
+ ...cloudAgent.entrypoint ? { entrypoint: cloudAgent.entrypoint } : {}
52572
+ }
52317
52573
  };
52318
52574
  writeSyncState(cwd2, newState);
52319
- await pullSecrets(cwd2, link2.agent_id);
52320
- $e(`Pulled ${link2.name} at revision ${cloud.revision}.`);
52575
+ await pullSecrets(cwd2, agentId);
52576
+ await runEntrypointIfPresent(cwd2, yaml);
52577
+ $e(`Pulled ${cloudAgent.name} at revision ${cloud.revision}.`);
52321
52578
  } finally {
52322
52579
  try {
52323
52580
  fs45.rmSync(stageRoot, { recursive: true, force: true });
52324
52581
  } catch {}
52325
52582
  }
52326
52583
  }
52584
+ function resolveTargetAgentId(cwd2, args) {
52585
+ const arg = args.agentIdArg?.trim() || undefined;
52586
+ let manifest = null;
52587
+ try {
52588
+ manifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
52589
+ } catch (err) {
52590
+ f2.error(err.message);
52591
+ return null;
52592
+ }
52593
+ const manifestId = manifest?.id;
52594
+ if (arg && manifestId && arg !== manifestId) {
52595
+ if (!args.force) {
52596
+ f2.error(`This folder is already linked to a different agent (${import_picocolors25.default.dim(manifestId)}).`);
52597
+ 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."));
52598
+ return null;
52599
+ }
52600
+ return { agentId: arg, override: true };
52601
+ }
52602
+ if (arg)
52603
+ return { agentId: arg, override: false };
52604
+ if (manifestId)
52605
+ return { agentId: manifestId, override: false };
52606
+ if (manifest) {
52607
+ f2.error(`${import_picocolors25.default.bold(AGENT_MANIFEST_FILE)} is unclaimed (no ${import_picocolors25.default.cyan("id")}).`);
52608
+ 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.`);
52609
+ } else {
52610
+ f2.error(`No ${import_picocolors25.default.bold(AGENT_MANIFEST_FILE)} here and no ${import_picocolors25.default.cyan("<id>")} given.`);
52611
+ f2.info(`Run ${import_picocolors25.default.cyan("brainbase agent pull <id>")} to pull an existing agent into this folder.`);
52612
+ }
52613
+ return null;
52614
+ }
52615
+ function safeReadManifest(cwd2) {
52616
+ try {
52617
+ return readManifest(cwd2);
52618
+ } catch {
52619
+ return null;
52620
+ }
52621
+ }
52327
52622
  function skillSourceFromMeta(c2) {
52328
52623
  if (c2.type !== "skill")
52329
52624
  return;
@@ -52358,7 +52653,7 @@ function runHarnessInstall2(harnessId, components, opts, agentName) {
52358
52653
  return installKafkaWithCtx(components, opts, agentName);
52359
52654
  return getAdapter(harnessId).install(components, opts);
52360
52655
  }
52361
- function materializeInstructions(cwd2, cloud, toInstall, keepLocal) {
52656
+ function materializeInstructions(cwd2, cloud, toInstall, keepLocal, existingManifest) {
52362
52657
  for (const c2 of cloud.components) {
52363
52658
  if (c2.type !== "instruction")
52364
52659
  continue;
@@ -52370,10 +52665,54 @@ function materializeInstructions(cwd2, cloud, toInstall, keepLocal) {
52370
52665
  const body = c2.files[0]?.content ?? "";
52371
52666
  if (!body.trim())
52372
52667
  continue;
52373
- fs45.writeFileSync(path48.join(cwd2, DEFAULT_INSTRUCTIONS_FILE), body, "utf8");
52668
+ if (existingManifest?.instructions?.text !== undefined)
52669
+ continue;
52670
+ const targetRel = existingManifest?.instructions?.file ?? DEFAULT_INSTRUCTIONS_FILE;
52671
+ const target = path48.resolve(cwd2, targetRel);
52672
+ ensureDir(path48.dirname(target));
52673
+ fs45.writeFileSync(target, body, "utf8");
52674
+ }
52675
+ }
52676
+ function materializePlaybooks(cwd2, cloud, toInstall, keepLocal, existingManifest) {
52677
+ for (const c2 of cloud.components) {
52678
+ if (c2.type !== "playbook")
52679
+ continue;
52680
+ const key2 = `${c2.type}/${c2.slug}`;
52681
+ if (keepLocal.has(key2))
52682
+ continue;
52683
+ if (!toInstall.has(key2))
52684
+ continue;
52685
+ const raw = c2.files[0]?.content ?? "";
52686
+ if (!raw.trim())
52687
+ continue;
52688
+ const { body } = stripFrontmatter(raw);
52689
+ const existing = existingManifest?.playbooks?.find((p2) => slugifyForCompare(p2.title) === c2.slug);
52690
+ if (existing?.content?.text !== undefined)
52691
+ continue;
52692
+ const targetRel = existing?.content?.file ?? path48.join(DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`);
52693
+ const target = path48.resolve(cwd2, targetRel);
52694
+ ensureDir(path48.dirname(target));
52695
+ fs45.writeFileSync(target, body, "utf8");
52696
+ }
52697
+ }
52698
+ function slugifyForCompare(s3) {
52699
+ return s3.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "playbook";
52700
+ }
52701
+ function stripFrontmatter(raw) {
52702
+ const m3 = /^---\s*\n([\s\S]*?)\n---\s*\n?/.exec(raw);
52703
+ if (!m3)
52704
+ return { frontmatter: {}, body: raw };
52705
+ let fm = {};
52706
+ try {
52707
+ const parsed = import_yaml3.default.parse(m3[1] ?? "");
52708
+ if (parsed && typeof parsed === "object")
52709
+ fm = parsed;
52710
+ } catch {
52711
+ return { frontmatter: {}, body: raw };
52374
52712
  }
52713
+ return { frontmatter: fm, body: raw.slice(m3[0].length) };
52375
52714
  }
52376
- function mergeManifest(cwd2, prev, cloud, link2) {
52715
+ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
52377
52716
  const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
52378
52717
  const localDecl = prev?.skills.find((s3) => {
52379
52718
  try {
@@ -52396,7 +52735,33 @@ function mergeManifest(cwd2, prev, cloud, link2) {
52396
52735
  }
52397
52736
  return { source: `registry:${c2.slug}` };
52398
52737
  });
52399
- const hasInstructions = cloud.components.some((c2) => c2.type === "instruction" && c2.files[0]?.content?.trim());
52738
+ const cloudInstrComp = cloud.components.find((c2) => c2.type === "instruction" && c2.files[0]?.content?.trim());
52739
+ const instructions = cloudInstrComp ? prev?.instructions?.text !== undefined ? { text: cloudInstrComp.files[0].content } : { file: prev?.instructions?.file ?? DEFAULT_INSTRUCTIONS_FILE } : undefined;
52740
+ const cloudEntrypoint = (cloudAgent.entrypoint ?? "").trim();
52741
+ let entrypoint;
52742
+ if (cloudEntrypoint.length > 0) {
52743
+ if (prev?.entrypoint?.commands)
52744
+ entrypoint = { commands: prev.entrypoint.commands };
52745
+ else if (prev?.entrypoint?.text !== undefined)
52746
+ entrypoint = { text: cloudAgent.entrypoint };
52747
+ else
52748
+ entrypoint = { file: prev?.entrypoint?.file ?? DEFAULT_ENTRYPOINT_FILE };
52749
+ }
52750
+ const playbooks = cloud.components.filter((c2) => c2.type === "playbook").map((c2) => {
52751
+ const raw = c2.files[0]?.content ?? "";
52752
+ const { frontmatter } = stripFrontmatter(raw);
52753
+ const local = prev?.playbooks?.find((pb) => slugifyForCompare(pb.title) === c2.slug);
52754
+ const title = local?.title ?? (typeof frontmatter.title === "string" && frontmatter.title || c2.slug);
52755
+ const description = local?.description ?? (typeof frontmatter.description === "string" ? frontmatter.description : undefined);
52756
+ const content = local?.content?.text !== undefined ? { text: local.content.text } : {
52757
+ file: local?.content?.file ?? path48.join(DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`)
52758
+ };
52759
+ return {
52760
+ title,
52761
+ ...description ? { description } : {},
52762
+ content
52763
+ };
52764
+ });
52400
52765
  const mcp = cloud.components.filter((c2) => c2.type === "mcp").map((c2) => {
52401
52766
  const payload = (c2.meta ?? {}).mcp ?? {};
52402
52767
  const entry = { name: c2.slug };
@@ -52416,17 +52781,33 @@ function mergeManifest(cwd2, prev, cloud, link2) {
52416
52781
  });
52417
52782
  return {
52418
52783
  schema: 1,
52784
+ id: cloudAgent.id,
52785
+ harness,
52419
52786
  agent: {
52420
- name: link2.name,
52421
- ...link2.tagline ? { tagline: link2.tagline } : {}
52787
+ name: cloudAgent.name,
52788
+ ...cloudAgent.tagline ? { tagline: cloudAgent.tagline } : {}
52422
52789
  },
52423
- ...hasInstructions ? {
52424
- instructions: { file: prev?.instructions?.file ?? DEFAULT_INSTRUCTIONS_FILE }
52425
- } : {},
52790
+ ...instructions ? { instructions } : {},
52791
+ ...entrypoint ? { entrypoint } : {},
52792
+ playbooks,
52426
52793
  skills,
52427
52794
  mcp
52428
52795
  };
52429
52796
  }
52797
+ function materializeEntrypoint(cwd2, cloudEntrypoint, prev) {
52798
+ if (!cloudEntrypoint.trim())
52799
+ return;
52800
+ if (prev?.entrypoint?.commands)
52801
+ return;
52802
+ if (prev?.entrypoint?.text !== undefined)
52803
+ return;
52804
+ const filename = prev?.entrypoint?.file ?? DEFAULT_ENTRYPOINT_FILE;
52805
+ const target = path48.resolve(cwd2, filename);
52806
+ fs45.writeFileSync(target, cloudEntrypoint, "utf8");
52807
+ try {
52808
+ fs45.chmodSync(target, 493);
52809
+ } catch {}
52810
+ }
52430
52811
  function parseSourceLoose(raw) {
52431
52812
  const m3 = raw.match(/^registry:[a-z0-9_-]+\/([a-z0-9_-]+)/i);
52432
52813
  if (m3)
@@ -52468,7 +52849,7 @@ function buildLockComponents(input) {
52468
52849
  }
52469
52850
  return out;
52470
52851
  }
52471
- function buildLockFromCloud(agent_id, cloud, prev) {
52852
+ function buildLockFromCloud(agent_id, cloud, prev, cloudAgent) {
52472
52853
  return {
52473
52854
  schemaVersion: 1,
52474
52855
  agent_id,
@@ -52480,11 +52861,73 @@ function buildLockFromCloud(agent_id, cloud, prev) {
52480
52861
  hash: c2.hash,
52481
52862
  installedPaths: []
52482
52863
  })),
52483
- agentMeta: prev?.agentMeta
52864
+ agentMeta: cloudAgent ? {
52865
+ name: cloudAgent.name,
52866
+ tagline: cloudAgent.tagline,
52867
+ ...cloudAgent.entrypoint ? { entrypoint: cloudAgent.entrypoint } : {}
52868
+ } : prev?.agentMeta
52484
52869
  };
52485
52870
  }
52486
- function writeBrainbaseYamlFromCloud(cwd2, link2, cloud) {
52487
- writeManifest(cwd2, mergeManifest(cwd2, null, cloud, link2));
52871
+ function buildLinkFromAgent(agent, harness, prev) {
52872
+ return {
52873
+ schemaVersion: 1,
52874
+ agent_id: agent.id,
52875
+ org_id: agent.org_id ?? prev?.org_id ?? "",
52876
+ team_id: agent.team_id ?? prev?.team_id ?? "",
52877
+ slug: agent.slug,
52878
+ name: agent.name,
52879
+ tagline: agent.tagline,
52880
+ url: agent.url,
52881
+ linked_at: prev?.linked_at ?? new Date().toISOString(),
52882
+ linked_by: prev?.linked_by,
52883
+ harness,
52884
+ tracking: prev?.tracking
52885
+ };
52886
+ }
52887
+ async function runEntrypointIfPresent(cwd2, manifest) {
52888
+ if (!manifest.entrypoint)
52889
+ return;
52890
+ const body = resolveEntrypoint(cwd2, manifest);
52891
+ if (body === null || !body.trim())
52892
+ return;
52893
+ const stateDir = path48.join(cwd2, LINK_DIR);
52894
+ ensureDir(stateDir);
52895
+ const scriptPath = path48.join(stateDir, "entrypoint.sh");
52896
+ const logPath = path48.join(stateDir, "entrypoint.log");
52897
+ fs45.writeFileSync(scriptPath, body, "utf8");
52898
+ try {
52899
+ fs45.chmodSync(scriptPath, 493);
52900
+ } catch {}
52901
+ f2.info(`Running entrypoint ${import_picocolors25.default.dim(`(${path48.relative(cwd2, scriptPath)})`)}`);
52902
+ const secrets = readLocalSecrets(cwd2);
52903
+ const env3 = { ...process.env, ...secrets };
52904
+ const logStream = fs45.createWriteStream(logPath, { flags: "w" });
52905
+ const exitCode = await new Promise((resolve) => {
52906
+ const child = spawn2("bash", [scriptPath], {
52907
+ cwd: cwd2,
52908
+ env: env3,
52909
+ stdio: ["ignore", "pipe", "pipe"]
52910
+ });
52911
+ child.stdout?.on("data", (chunk) => {
52912
+ process.stdout.write(chunk);
52913
+ logStream.write(chunk);
52914
+ });
52915
+ child.stderr?.on("data", (chunk) => {
52916
+ process.stderr.write(chunk);
52917
+ logStream.write(chunk);
52918
+ });
52919
+ child.on("error", (err) => {
52920
+ f2.warn(`entrypoint failed to start: ${err.message}`);
52921
+ resolve(null);
52922
+ });
52923
+ child.on("exit", (code) => resolve(code));
52924
+ });
52925
+ await new Promise((resolve) => logStream.end(resolve));
52926
+ if (exitCode === 0) {
52927
+ f2.info("Entrypoint completed.");
52928
+ } else if (exitCode === null) {} else {
52929
+ f2.warn(`Entrypoint exited ${exitCode} — continuing. Log at ${import_picocolors25.default.dim(path48.relative(cwd2, logPath))}.`);
52930
+ }
52488
52931
  }
52489
52932
  async function pullSecrets(cwd2, agentId) {
52490
52933
  let cloudSecrets;
@@ -52518,6 +52961,8 @@ function handleApiError2(err) {
52518
52961
  if (err instanceof ApiError) {
52519
52962
  if (err.status === 401) {
52520
52963
  f2.error("Your session is invalid. Run `brainbase login` and try again.");
52964
+ } else if (err.status === 404) {
52965
+ f2.error(`Agent not found, or you don't have access. Double-check the id.`);
52521
52966
  } else {
52522
52967
  f2.error(err.message);
52523
52968
  }
@@ -52527,18 +52972,149 @@ function handleApiError2(err) {
52527
52972
  }
52528
52973
 
52529
52974
  // src/cli/agent-push.ts
52975
+ var import_picocolors27 = __toESM(require_picocolors(), 1);
52976
+
52977
+ // src/core/agent-outgoing.ts
52530
52978
  var import_picocolors26 = __toESM(require_picocolors(), 1);
52979
+ async function buildOutgoingComponents(cwd2, manifest, cloud) {
52980
+ const out = [];
52981
+ if (manifest.instructions) {
52982
+ if (manifest.instructions.text !== undefined && manifest.instructions.file !== undefined) {
52983
+ f2.error(`instructions block sets both ${import_picocolors26.default.cyan("text")} and ${import_picocolors26.default.cyan("file")} — pick one.`);
52984
+ return null;
52985
+ }
52986
+ const body = readInstructions(cwd2, manifest);
52987
+ if (body === null) {
52988
+ if (manifest.instructions.file) {
52989
+ f2.error(`Instructions file ${import_picocolors26.default.bold(manifest.instructions.file)} not found.`);
52990
+ } else {
52991
+ f2.error("Instructions block is empty.");
52992
+ }
52993
+ return null;
52994
+ }
52995
+ if (body.trim()) {
52996
+ const fileName = manifest.instructions.file ?? "instructions.md";
52997
+ const fileHash2 = hashString(body);
52998
+ const file = {
52999
+ path: fileName,
53000
+ content: body,
53001
+ hash: fileHash2
53002
+ };
53003
+ out.push({
53004
+ type: "instruction",
53005
+ slug: "agent-instructions",
53006
+ description: "Agent instructions",
53007
+ hash: componentHashFromFileHashes([fileHash2]),
53008
+ files: [file],
53009
+ meta: { source: "global_prompt" }
53010
+ });
53011
+ }
53012
+ }
53013
+ for (const entry of manifest.skills) {
53014
+ const parsed = parseSkillSource2(entry.source);
53015
+ if (parsed.kind === "local") {
53016
+ 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\`).`);
53017
+ return null;
53018
+ }
53019
+ const cloudMatch = cloud?.components.find((c2) => c2.type === "skill" && c2.slug === parsed.slug);
53020
+ out.push({
53021
+ type: "skill",
53022
+ slug: parsed.slug,
53023
+ hash: cloudMatch?.hash ?? "",
53024
+ files: [],
53025
+ meta: {
53026
+ name: parsed.creator ? `${parsed.creator}/${parsed.slug}` : parsed.slug,
53027
+ ...parsed.version ? { version: parsed.version } : {}
53028
+ }
53029
+ });
53030
+ }
53031
+ const seenPlaybookSlugs = new Set;
53032
+ for (const entry of manifest.playbooks ?? []) {
53033
+ if (entry.content.text !== undefined && entry.content.file !== undefined) {
53034
+ f2.error(`Playbook ${import_picocolors26.default.bold(entry.title)} sets both ${import_picocolors26.default.cyan("text")} and ${import_picocolors26.default.cyan("file")} — pick one.`);
53035
+ return null;
53036
+ }
53037
+ const body = resolvePlaybookContent(cwd2, entry);
53038
+ if (body === null) {
53039
+ if (entry.content.file) {
53040
+ f2.error(`Playbook ${import_picocolors26.default.bold(entry.title)} content file ${import_picocolors26.default.bold(entry.content.file)} not found.`);
53041
+ } else {
53042
+ f2.error(`Playbook ${import_picocolors26.default.bold(entry.title)} content is empty.`);
53043
+ }
53044
+ return null;
53045
+ }
53046
+ const slug = slugifyPlaybookTitle(entry.title);
53047
+ if (seenPlaybookSlugs.has(slug)) {
53048
+ f2.error(`Two playbooks resolve to the same slug ${import_picocolors26.default.bold(slug)} (from title ${import_picocolors26.default.bold(entry.title)}). Pick distinct titles.`);
53049
+ return null;
53050
+ }
53051
+ seenPlaybookSlugs.add(slug);
53052
+ const wireBody = assemblePlaybookBody(entry, body);
53053
+ const fileName = `${slug}.md`;
53054
+ const fileHash2 = hashString(wireBody);
53055
+ out.push({
53056
+ type: "playbook",
53057
+ slug,
53058
+ description: entry.description,
53059
+ hash: componentHashFromFileHashes([fileHash2]),
53060
+ files: [{ path: fileName, content: wireBody, hash: fileHash2 }],
53061
+ meta: {
53062
+ title: entry.title,
53063
+ ...entry.description ? { description: entry.description } : {}
53064
+ }
53065
+ });
53066
+ }
53067
+ for (const entry of manifest.mcp ?? []) {
53068
+ if (!entry.url && !entry.command) {
53069
+ f2.error(`MCP ${import_picocolors26.default.bold(entry.name)} needs either ${import_picocolors26.default.cyan("url")} or ${import_picocolors26.default.cyan("command")}.`);
53070
+ return null;
53071
+ }
53072
+ const payload = {};
53073
+ if (entry.url !== undefined)
53074
+ payload.url = entry.url;
53075
+ if (entry.command !== undefined)
53076
+ payload.command = entry.command;
53077
+ if (entry.args !== undefined)
53078
+ payload.args = entry.args;
53079
+ if (entry.env !== undefined)
53080
+ payload.env = entry.env;
53081
+ if (entry.headers !== undefined)
53082
+ payload.headers = entry.headers;
53083
+ payload.is_enabled = entry.is_enabled ?? true;
53084
+ out.push({
53085
+ type: "mcp",
53086
+ slug: entry.name,
53087
+ hash: "",
53088
+ files: [],
53089
+ meta: { mcp: payload }
53090
+ });
53091
+ }
53092
+ return out;
53093
+ }
53094
+ function assemblePlaybookBody(entry, body) {
53095
+ if (/^---\s*\n/.test(body))
53096
+ return body;
53097
+ const lines = ["---", `title: ${yamlScalar(entry.title)}`];
53098
+ if (entry.description) {
53099
+ lines.push(`description: ${yamlScalar(entry.description)}`);
53100
+ }
53101
+ lines.push("---", "");
53102
+ return lines.join(`
53103
+ `) + body.replace(/^\n+/, "");
53104
+ }
53105
+ function yamlScalar(s3) {
53106
+ if (!/[\n":#&*!|>'%@`{}[\]]/.test(s3) && s3.trim() === s3 && s3 !== "") {
53107
+ return s3;
53108
+ }
53109
+ return JSON.stringify(s3);
53110
+ }
53111
+
53112
+ // src/cli/agent-push.ts
52531
53113
  async function runAgentPush(cwd2, args) {
52532
53114
  banner("agent push — send your local changes to the cloud");
52533
- const link2 = readLink(cwd2);
52534
- if (!link2) {
52535
- f2.warn("This folder is not linked to any agent.");
52536
- f2.info(`Run ${import_picocolors26.default.cyan("brainbase link")} first.`);
52537
- return;
52538
- }
52539
53115
  if (!hasManifest(cwd2)) {
52540
- f2.warn(`No ${import_picocolors26.default.bold(AGENT_MANIFEST_FILE)} here.`);
52541
- f2.info(`Run ${import_picocolors26.default.cyan("brainbase agent pull")} to materialize the manifest before pushing.`);
53116
+ f2.warn(`No ${import_picocolors27.default.bold(AGENT_MANIFEST_FILE)} here.`);
53117
+ 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.`);
52542
53118
  return;
52543
53119
  }
52544
53120
  let manifest;
@@ -52548,11 +53124,17 @@ async function runAgentPush(cwd2, args) {
52548
53124
  f2.error(err.message);
52549
53125
  return;
52550
53126
  }
53127
+ if (!manifest.id) {
53128
+ f2.warn(`${import_picocolors27.default.bold(AGENT_MANIFEST_FILE)} is unclaimed (no ${import_picocolors27.default.cyan("id")}). Nothing to push to.`);
53129
+ f2.info(`Run ${import_picocolors27.default.cyan("brainbase agent create")} first — that creates the cloud agent and stamps an id here.`);
53130
+ return;
53131
+ }
53132
+ const agentId = manifest.id;
52551
53133
  const sp = de();
52552
- sp.start(`Fetching cloud state for ${link2.name}…`);
53134
+ sp.start(`Fetching cloud state…`);
52553
53135
  let cloud;
52554
53136
  try {
52555
- cloud = await api.getAgentManifest(link2.agent_id);
53137
+ cloud = await api.getAgentManifest(agentId);
52556
53138
  sp.stop(`Cloud revision ${cloud.revision}.`);
52557
53139
  } catch (err) {
52558
53140
  sp.stop("Failed.");
@@ -52565,17 +53147,42 @@ async function runAgentPush(cwd2, args) {
52565
53147
  lock: lock?.components ?? [],
52566
53148
  cloud: cloud.components
52567
53149
  });
52568
- const meta = diffAgentMeta(manifest.agent, lock?.agentMeta, { name: link2.name, tagline: link2.tagline });
53150
+ let cloudMeta = lock?.agentMeta;
53151
+ if (!cloudMeta) {
53152
+ try {
53153
+ const a3 = await api.getAgent(agentId);
53154
+ cloudMeta = { name: a3.name, tagline: a3.tagline, entrypoint: a3.entrypoint };
53155
+ } catch {}
53156
+ }
53157
+ const meta = diffAgentMeta(manifest.agent, lock?.agentMeta, cloudMeta);
53158
+ let resolvedEntrypoint;
53159
+ if (manifest.entrypoint) {
53160
+ const body = resolveEntrypoint(cwd2, manifest);
53161
+ if (body === null) {
53162
+ if (manifest.entrypoint.file) {
53163
+ f2.error(`Entrypoint file ${import_picocolors27.default.bold(manifest.entrypoint.file)} not found.`);
53164
+ } else {
53165
+ f2.error("Entrypoint block is empty.");
53166
+ }
53167
+ return;
53168
+ }
53169
+ resolvedEntrypoint = body;
53170
+ } else {
53171
+ if ((lock?.agentMeta?.entrypoint ?? "") !== "") {
53172
+ resolvedEntrypoint = "";
53173
+ }
53174
+ }
53175
+ const entrypointChanged = resolvedEntrypoint !== undefined && resolvedEntrypoint !== (lock?.agentMeta?.entrypoint ?? "");
52569
53176
  for (const r2 of rows) {
52570
- if (r2.type !== "instruction" && r2.type !== "skill" && r2.type !== "mcp") {
52571
- 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.`);
53177
+ if (r2.type !== "instruction" && r2.type !== "skill" && r2.type !== "mcp" && r2.type !== "playbook") {
53178
+ f2.error(`Component ${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)} can't be pushed yet — the server accepts instructions, skills, mcps, and playbooks in this version.`);
52572
53179
  return;
52573
53180
  }
52574
53181
  }
52575
53182
  for (const entry of manifest.skills) {
52576
53183
  const parsed = parseSkillSource2(entry.source);
52577
53184
  if (parsed.kind === "local") {
52578
- 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\`).`);
53185
+ 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\`).`);
52579
53186
  return;
52580
53187
  }
52581
53188
  }
@@ -52599,22 +53206,22 @@ async function runAgentPush(cwd2, args) {
52599
53206
  break;
52600
53207
  }
52601
53208
  }
52602
- if (!meta.localChanged && toSend.length === 0 && conflicts.length === 0) {
53209
+ if (!meta.localChanged && !entrypointChanged && toSend.length === 0 && conflicts.length === 0) {
52603
53210
  f2.info("Nothing to push — local is in sync with the cloud.");
52604
53211
  return;
52605
53212
  }
52606
53213
  if (conflicts.length > 0) {
52607
53214
  f2.error(`Cannot push: ${conflicts.length} component${conflicts.length === 1 ? "" : "s"} changed both locally and on the cloud:`);
52608
53215
  for (const r2 of conflicts) {
52609
- console.error(` ${import_picocolors26.default.red("!")} ${fmtType(r2.type)} ${import_picocolors26.default.bold(r2.slug)}`);
53216
+ console.error(` ${import_picocolors27.default.red("!")} ${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)}`);
52610
53217
  }
52611
- f2.info(`Run ${import_picocolors26.default.cyan("brainbase agent pull")} first to reconcile, then push again.`);
53218
+ f2.info(`Run ${import_picocolors27.default.cyan("brainbase agent pull")} first to reconcile, then push again.`);
52612
53219
  return;
52613
53220
  }
52614
53221
  if (upstreamOnly.length > 0 && !args.yes) {
52615
53222
  f2.warn(`Cloud has ${upstreamOnly.length} change${upstreamOnly.length === 1 ? "" : "s"} you don't have locally:`);
52616
53223
  for (const r2 of upstreamOnly) {
52617
- console.warn(` ${import_picocolors26.default.cyan("←")} ${fmtType(r2.type)} ${import_picocolors26.default.bold(r2.slug)} ${import_picocolors26.default.dim(`(${r2.status})`)}`);
53224
+ console.warn(` ${import_picocolors27.default.cyan("←")} ${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)} ${import_picocolors27.default.dim(`(${r2.status})`)}`);
52618
53225
  }
52619
53226
  f2.info(`If you push now, your push targets revision ${cloud.revision} and may race. Consider \`brainbase agent pull\` first.`);
52620
53227
  }
@@ -52626,6 +53233,13 @@ async function runAgentPush(cwd2, args) {
52626
53233
  text: "name/tagline"
52627
53234
  });
52628
53235
  }
53236
+ if (entrypointChanged) {
53237
+ resultRows.push({
53238
+ type: "upd",
53239
+ label: "entrypoint",
53240
+ text: resolvedEntrypoint === "" ? "cleared" : "updated"
53241
+ });
53242
+ }
52629
53243
  if (toSend.length) {
52630
53244
  resultRows.push({
52631
53245
  type: "add",
@@ -52636,7 +53250,7 @@ async function runAgentPush(cwd2, args) {
52636
53250
  await showResultCard({
52637
53251
  title: "PUSH",
52638
53252
  tone: "info",
52639
- subtitle: `${link2.name} ← local`,
53253
+ subtitle: `${manifest.agent.name} ← local`,
52640
53254
  rows: resultRows
52641
53255
  });
52642
53256
  if (!args.yes) {
@@ -52646,14 +53260,19 @@ async function runAgentPush(cwd2, args) {
52646
53260
  return;
52647
53261
  }
52648
53262
  }
52649
- if (meta.localChanged) {
53263
+ if (meta.localChanged || entrypointChanged) {
52650
53264
  const metaSpinner = de();
52651
53265
  metaSpinner.start("Updating agent metadata…");
52652
53266
  try {
52653
- await api.updateAgent(link2.agent_id, {
52654
- name: manifest.agent.name,
52655
- tagline: manifest.agent.tagline ?? ""
52656
- });
53267
+ const update = {};
53268
+ if (meta.localChanged) {
53269
+ update.name = manifest.agent.name;
53270
+ update.tagline = manifest.agent.tagline ?? "";
53271
+ }
53272
+ if (entrypointChanged) {
53273
+ update.entrypoint = resolvedEntrypoint;
53274
+ }
53275
+ await api.updateAgent(agentId, update);
52657
53276
  metaSpinner.stop("Metadata updated.");
52658
53277
  } catch (err) {
52659
53278
  metaSpinner.stop("Failed.");
@@ -52667,7 +53286,7 @@ async function runAgentPush(cwd2, args) {
52667
53286
  pushSpinner.start("Pushing…");
52668
53287
  let updatedCloud;
52669
53288
  try {
52670
- updatedCloud = await api.pushAgentManifest(link2.agent_id, {
53289
+ updatedCloud = await api.pushAgentManifest(agentId, {
52671
53290
  components: outgoing,
52672
53291
  base_revision: cloud.revision
52673
53292
  });
@@ -52676,14 +53295,22 @@ async function runAgentPush(cwd2, args) {
52676
53295
  pushSpinner.stop("Failed.");
52677
53296
  if (err instanceof ApiError && err.status === 409) {
52678
53297
  f2.error(err.message);
52679
- f2.info(`Run ${import_picocolors26.default.cyan("brainbase agent pull")} and try again.`);
53298
+ f2.info(`Run ${import_picocolors27.default.cyan("brainbase agent pull")} and try again.`);
52680
53299
  return;
52681
53300
  }
52682
53301
  return handleApiError3(err);
52683
53302
  }
53303
+ const existing = readLink(cwd2);
53304
+ if (existing) {
53305
+ writeLink(cwd2, {
53306
+ ...existing,
53307
+ name: manifest.agent.name,
53308
+ tagline: manifest.agent.tagline
53309
+ });
53310
+ }
52684
53311
  const newLock = {
52685
53312
  schemaVersion: 1,
52686
- agent_id: link2.agent_id,
53313
+ agent_id: agentId,
52687
53314
  revision: updatedCloud.revision,
52688
53315
  synced_at: new Date().toISOString(),
52689
53316
  components: updatedCloud.components.map((c2) => {
@@ -52695,7 +53322,7 @@ async function runAgentPush(cwd2, args) {
52695
53322
  return false;
52696
53323
  }
52697
53324
  })?.source;
52698
- const prior = lock?.components.find((pc25) => pc25.type === c2.type && pc25.slug === c2.slug);
53325
+ const prior = lock?.components.find((pc26) => pc26.type === c2.type && pc26.slug === c2.slug);
52699
53326
  return {
52700
53327
  type: c2.type,
52701
53328
  slug: c2.slug,
@@ -52704,11 +53331,15 @@ async function runAgentPush(cwd2, args) {
52704
53331
  ...decl ? { source: decl } : {}
52705
53332
  };
52706
53333
  }),
52707
- agentMeta: { name: manifest.agent.name, tagline: manifest.agent.tagline }
53334
+ agentMeta: {
53335
+ name: manifest.agent.name,
53336
+ tagline: manifest.agent.tagline,
53337
+ entrypoint: resolvedEntrypoint !== undefined ? resolvedEntrypoint : lock?.agentMeta?.entrypoint
53338
+ }
52708
53339
  };
52709
53340
  writeSyncState(cwd2, newLock);
52710
- await pushSecrets(cwd2, link2.agent_id);
52711
- $e(`Pushed ${link2.name} at revision ${updatedCloud.revision}.`);
53341
+ await pushSecrets(cwd2, agentId);
53342
+ $e(`Pushed ${manifest.agent.name} at revision ${updatedCloud.revision}.`);
52712
53343
  }
52713
53344
  async function pushSecrets(cwd2, agentId) {
52714
53345
  const localSecrets = readLocalSecrets(cwd2);
@@ -52722,87 +53353,19 @@ async function pushSecrets(cwd2, agentId) {
52722
53353
  f2.warn(`Couldn't read cloud secrets to diff: ${err.message}. Skipping secret push.`);
52723
53354
  return;
52724
53355
  }
52725
- const diff2 = diffSecrets(localSecrets, cloudSecrets);
52726
- if (diff2.localOnly.length === 0 && diff2.changed.length === 0 && diff2.cloudOnly.length === 0) {
52727
- return;
52728
- }
52729
- const sp = de();
52730
- sp.start("Pushing secrets…");
52731
- try {
52732
- await api.putAgentSecrets(agentId, localSecrets);
52733
- sp.stop(`Secrets pushed (${diff2.localOnly.length} added, ${diff2.changed.length} updated, ${diff2.cloudOnly.length} removed).`);
52734
- } catch (err) {
52735
- sp.stop("Failed.");
52736
- handleApiError3(err);
52737
- }
52738
- }
52739
- async function buildOutgoingComponents(cwd2, manifest, cloud) {
52740
- const out = [];
52741
- if (manifest.instructions) {
52742
- const body = readInstructions(cwd2, manifest);
52743
- if (body === null) {
52744
- f2.error(`Instructions file ${import_picocolors26.default.bold(manifest.instructions.file)} not found.`);
52745
- return null;
52746
- }
52747
- if (body.trim()) {
52748
- const fileHash2 = hashString(body);
52749
- const file = {
52750
- path: manifest.instructions.file,
52751
- content: body,
52752
- hash: fileHash2
52753
- };
52754
- out.push({
52755
- type: "instruction",
52756
- slug: "agent-instructions",
52757
- description: "Agent instructions",
52758
- hash: componentHashFromFileHashes([fileHash2]),
52759
- files: [file],
52760
- meta: { source: "global_prompt" }
52761
- });
52762
- }
52763
- }
52764
- for (const entry of manifest.skills) {
52765
- const parsed = parseSkillSource2(entry.source);
52766
- if (parsed.kind !== "registry")
52767
- continue;
52768
- const cloudMatch = cloud.components.find((c2) => c2.type === "skill" && c2.slug === parsed.slug);
52769
- out.push({
52770
- type: "skill",
52771
- slug: parsed.slug,
52772
- hash: cloudMatch?.hash ?? "",
52773
- files: [],
52774
- meta: {
52775
- name: parsed.creator ? `${parsed.creator}/${parsed.slug}` : parsed.slug,
52776
- ...parsed.version ? { version: parsed.version } : {}
52777
- }
52778
- });
53356
+ const diff2 = diffSecrets(localSecrets, cloudSecrets);
53357
+ if (diff2.localOnly.length === 0 && diff2.changed.length === 0 && diff2.cloudOnly.length === 0) {
53358
+ return;
52779
53359
  }
52780
- for (const entry of manifest.mcp ?? []) {
52781
- if (!entry.url && !entry.command) {
52782
- f2.error(`MCP ${import_picocolors26.default.bold(entry.name)} needs either ${import_picocolors26.default.cyan("url")} or ${import_picocolors26.default.cyan("command")}.`);
52783
- return null;
52784
- }
52785
- const payload = {};
52786
- if (entry.url !== undefined)
52787
- payload.url = entry.url;
52788
- if (entry.command !== undefined)
52789
- payload.command = entry.command;
52790
- if (entry.args !== undefined)
52791
- payload.args = entry.args;
52792
- if (entry.env !== undefined)
52793
- payload.env = entry.env;
52794
- if (entry.headers !== undefined)
52795
- payload.headers = entry.headers;
52796
- payload.is_enabled = entry.is_enabled ?? true;
52797
- out.push({
52798
- type: "mcp",
52799
- slug: entry.name,
52800
- hash: "",
52801
- files: [],
52802
- meta: { mcp: payload }
52803
- });
53360
+ const sp = de();
53361
+ sp.start("Pushing secrets…");
53362
+ try {
53363
+ await api.putAgentSecrets(agentId, localSecrets);
53364
+ sp.stop(`Secrets pushed (${diff2.localOnly.length} added, ${diff2.changed.length} updated, ${diff2.cloudOnly.length} removed).`);
53365
+ } catch (err) {
53366
+ sp.stop("Failed.");
53367
+ handleApiError3(err);
52804
53368
  }
52805
- return out;
52806
53369
  }
52807
53370
  function handleApiError3(err) {
52808
53371
  if (err instanceof ApiError) {
@@ -52817,13 +53380,13 @@ function handleApiError3(err) {
52817
53380
  }
52818
53381
 
52819
53382
  // src/cli/agent-status.ts
52820
- var import_picocolors27 = __toESM(require_picocolors(), 1);
53383
+ var import_picocolors28 = __toESM(require_picocolors(), 1);
52821
53384
  async function runAgentStatus(cwd2) {
52822
53385
  banner("agent status — what changed locally, remotely, both");
52823
53386
  const link2 = readLink(cwd2);
52824
53387
  if (!link2) {
52825
53388
  f2.warn("This folder is not linked to any agent.");
52826
- f2.info(`Run ${import_picocolors27.default.cyan("brainbase link")} first.`);
53389
+ f2.info(`Run ${import_picocolors28.default.cyan("brainbase link")} first.`);
52827
53390
  return;
52828
53391
  }
52829
53392
  const manifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
@@ -52844,8 +53407,8 @@ async function runAgentStatus(cwd2) {
52844
53407
  return;
52845
53408
  }
52846
53409
  if (!manifest) {
52847
- 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.`);
52848
- f2.info(`Cloud has ${import_picocolors27.default.bold(String(cloud.components.length))} component${cloud.components.length === 1 ? "" : "s"} at revision ${cloud.revision}.`);
53410
+ 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.`);
53411
+ f2.info(`Cloud has ${import_picocolors28.default.bold(String(cloud.components.length))} component${cloud.components.length === 1 ? "" : "s"} at revision ${cloud.revision}.`);
52849
53412
  return;
52850
53413
  }
52851
53414
  const localComponents = readLocalComponents(cwd2, manifest);
@@ -52884,17 +53447,17 @@ async function runAgentStatus(cwd2) {
52884
53447
  }
52885
53448
  const lines = [];
52886
53449
  lines.push("");
52887
- lines.push(` ${import_picocolors27.default.bold(link2.name)} ${import_picocolors27.default.dim(`(${link2.slug})`)}`);
52888
- lines.push(` ${import_picocolors27.default.dim("agent_id")} ${link2.agent_id}`);
52889
- lines.push(` ${import_picocolors27.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
53450
+ lines.push(` ${import_picocolors28.default.bold(link2.name)} ${import_picocolors28.default.dim(`(${link2.slug})`)}`);
53451
+ lines.push(` ${import_picocolors28.default.dim("agent_id")} ${link2.agent_id}`);
53452
+ lines.push(` ${import_picocolors28.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
52890
53453
  lines.push("");
52891
53454
  if (meta.localChanged || meta.cloudChanged) {
52892
- lines.push(` ${import_picocolors27.default.bold("agent metadata")}`);
53455
+ lines.push(` ${import_picocolors28.default.bold("agent metadata")}`);
52893
53456
  if (meta.localChanged) {
52894
- lines.push(` ${import_picocolors27.default.yellow("→ push")} name/tagline edited in brainbase.yaml`);
53457
+ lines.push(` ${import_picocolors28.default.yellow("→ push")} name/tagline edited in brainbase.agent.yaml`);
52895
53458
  }
52896
53459
  if (meta.cloudChanged) {
52897
- lines.push(` ${import_picocolors27.default.cyan("← pull")} name/tagline changed on cloud`);
53460
+ lines.push(` ${import_picocolors28.default.cyan("← pull")} name/tagline changed on cloud`);
52898
53461
  }
52899
53462
  lines.push("");
52900
53463
  }
@@ -52904,65 +53467,65 @@ async function runAgentStatus(cwd2) {
52904
53467
  const cloudSecrets = cloudRes.secrets ?? {};
52905
53468
  const sd = diffSecrets(localSecrets, cloudSecrets);
52906
53469
  if (sd.localOnly.length || sd.cloudOnly.length || sd.changed.length) {
52907
- lines.push(` ${import_picocolors27.default.bold("secrets")}`);
53470
+ lines.push(` ${import_picocolors28.default.bold("secrets")}`);
52908
53471
  if (sd.localOnly.length)
52909
- lines.push(` ${import_picocolors27.default.yellow("→ push")} new locally: ${sd.localOnly.join(", ")}`);
53472
+ lines.push(` ${import_picocolors28.default.yellow("→ push")} new locally: ${sd.localOnly.join(", ")}`);
52910
53473
  if (sd.changed.length)
52911
- lines.push(` ${import_picocolors27.default.yellow("→ push")} values changed: ${sd.changed.join(", ")}`);
53474
+ lines.push(` ${import_picocolors28.default.yellow("→ push")} values changed: ${sd.changed.join(", ")}`);
52912
53475
  if (sd.cloudOnly.length)
52913
- lines.push(` ${import_picocolors27.default.cyan("← pull")} new on cloud: ${sd.cloudOnly.join(", ")}`);
53476
+ lines.push(` ${import_picocolors28.default.cyan("← pull")} new on cloud: ${sd.cloudOnly.join(", ")}`);
52914
53477
  lines.push("");
52915
53478
  }
52916
53479
  } catch {}
52917
53480
  if (conflicts.length === 0 && toPush.length === 0 && toPull.length === 0) {
52918
- lines.push(` ${import_picocolors27.default.green("✓")} everything is in sync`);
53481
+ lines.push(` ${import_picocolors28.default.green("✓")} everything is in sync`);
52919
53482
  lines.push("");
52920
53483
  console.log(lines.join(`
52921
53484
  `));
52922
53485
  return;
52923
53486
  }
52924
53487
  if (toPush.length) {
52925
- lines.push(` ${import_picocolors27.default.bold("changes to push")} ${import_picocolors27.default.dim(`(${toPush.length})`)}`);
53488
+ lines.push(` ${import_picocolors28.default.bold("changes to push")} ${import_picocolors28.default.dim(`(${toPush.length})`)}`);
52926
53489
  for (const r2 of toPush)
52927
- lines.push(` ${import_picocolors27.default.yellow("→")} ${fmtRow(r2)}`);
53490
+ lines.push(` ${import_picocolors28.default.yellow("→")} ${fmtRow(r2)}`);
52928
53491
  lines.push("");
52929
53492
  }
52930
53493
  if (toPull.length) {
52931
- lines.push(` ${import_picocolors27.default.bold("changes to pull")} ${import_picocolors27.default.dim(`(${toPull.length})`)}`);
53494
+ lines.push(` ${import_picocolors28.default.bold("changes to pull")} ${import_picocolors28.default.dim(`(${toPull.length})`)}`);
52932
53495
  for (const r2 of toPull)
52933
- lines.push(` ${import_picocolors27.default.cyan("←")} ${fmtRow(r2)}`);
53496
+ lines.push(` ${import_picocolors28.default.cyan("←")} ${fmtRow(r2)}`);
52934
53497
  lines.push("");
52935
53498
  }
52936
53499
  if (conflicts.length) {
52937
- lines.push(` ${import_picocolors27.default.bold(import_picocolors27.default.red("conflicts"))} ${import_picocolors27.default.dim(`(${conflicts.length})`)}`);
53500
+ lines.push(` ${import_picocolors28.default.bold(import_picocolors28.default.red("conflicts"))} ${import_picocolors28.default.dim(`(${conflicts.length})`)}`);
52938
53501
  for (const r2 of conflicts)
52939
- lines.push(` ${import_picocolors27.default.red("!")} ${fmtRow(r2)}`);
53502
+ lines.push(` ${import_picocolors28.default.red("!")} ${fmtRow(r2)}`);
52940
53503
  lines.push("");
52941
53504
  }
52942
- 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")}`);
53505
+ 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")}`);
52943
53506
  lines.push("");
52944
53507
  console.log(lines.join(`
52945
53508
  `));
52946
53509
  }
52947
53510
  function fmtRow(r2) {
52948
- const head = `${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)}`;
53511
+ const head = `${fmtType(r2.type)} ${import_picocolors28.default.bold(r2.slug)}`;
52949
53512
  switch (r2.status) {
52950
53513
  case "added-only-local":
52951
- return `${head} ${import_picocolors27.default.dim("(new — only in brainbase.yaml)")}`;
53514
+ return `${head} ${import_picocolors28.default.dim("(new — only in brainbase.agent.yaml)")}`;
52952
53515
  case "added-cloud":
52953
- return `${head} ${import_picocolors27.default.dim("(new on cloud)")}`;
53516
+ return `${head} ${import_picocolors28.default.dim("(new on cloud)")}`;
52954
53517
  case "added-local":
52955
- return `${head} ${import_picocolors27.default.dim("(present locally and on cloud, never synced here)")}`;
53518
+ return `${head} ${import_picocolors28.default.dim("(present locally and on cloud, never synced here)")}`;
52956
53519
  case "removed-local":
52957
- return `${head} ${import_picocolors27.default.dim("(removed from brainbase.yaml)")}`;
53520
+ return `${head} ${import_picocolors28.default.dim("(removed from brainbase.agent.yaml)")}`;
52958
53521
  case "removed-cloud":
52959
- return `${head} ${import_picocolors27.default.dim("(removed on cloud)")}`;
53522
+ return `${head} ${import_picocolors28.default.dim("(removed on cloud)")}`;
52960
53523
  case "modified-local":
52961
- return `${head} ${import_picocolors27.default.dim("(you edited it)")}`;
53524
+ return `${head} ${import_picocolors28.default.dim("(you edited it)")}`;
52962
53525
  case "modified-cloud":
52963
- return `${head} ${import_picocolors27.default.dim("(cloud was updated)")}`;
53526
+ return `${head} ${import_picocolors28.default.dim("(cloud was updated)")}`;
52964
53527
  case "modified-both":
52965
- return `${head} ${import_picocolors27.default.dim("(both diverged — needs resolution)")}`;
53528
+ return `${head} ${import_picocolors28.default.dim("(both diverged — needs resolution)")}`;
52966
53529
  default:
52967
53530
  return head;
52968
53531
  }
@@ -52999,10 +53562,11 @@ function formatExport(shell, key2, value) {
52999
53562
  }
53000
53563
 
53001
53564
  // src/cli/agent-create.ts
53002
- var import_picocolors29 = __toESM(require_picocolors(), 1);
53565
+ import path49 from "node:path";
53566
+ var import_picocolors30 = __toESM(require_picocolors(), 1);
53003
53567
 
53004
53568
  // src/ui/box.ts
53005
- var import_picocolors28 = __toESM(require_picocolors(), 1);
53569
+ var import_picocolors29 = __toESM(require_picocolors(), 1);
53006
53570
  var H3 = "─";
53007
53571
  var TINT = {
53008
53572
  ok: COLOR.ok,
@@ -53014,20 +53578,28 @@ var TINT = {
53014
53578
  function divider(label, width = 56, indent = 2) {
53015
53579
  const ind = " ".repeat(indent);
53016
53580
  if (!label)
53017
- return `${ind}${import_picocolors28.default.dim(H3.repeat(width))}`;
53581
+ return `${ind}${import_picocolors29.default.dim(H3.repeat(width))}`;
53018
53582
  const labelText = ` ${label} `;
53019
53583
  const labelLen = visibleLength(labelText);
53020
- const left = import_picocolors28.default.dim(H3.repeat(2));
53021
- const right = import_picocolors28.default.dim(H3.repeat(Math.max(0, width - labelLen - 2)));
53022
- return `${ind}${left}${import_picocolors28.default.bold(import_picocolors28.default.dim(labelText))}${right}`;
53584
+ const left = import_picocolors29.default.dim(H3.repeat(2));
53585
+ const right = import_picocolors29.default.dim(H3.repeat(Math.max(0, width - labelLen - 2)));
53586
+ return `${ind}${left}${import_picocolors29.default.bold(import_picocolors29.default.dim(labelText))}${right}`;
53023
53587
  }
53024
53588
  function tip(text, indent = 2) {
53025
- return " ".repeat(indent) + import_picocolors28.default.dim("›") + " " + import_picocolors28.default.dim(text);
53589
+ return " ".repeat(indent) + import_picocolors29.default.dim("›") + " " + import_picocolors29.default.dim(text);
53026
53590
  }
53027
53591
 
53028
53592
  // src/cli/agent-create.ts
53029
53593
  async function runAgentCreate(cwd2, args) {
53030
- banner("agent create — make a new brainbase agent and link this folder");
53594
+ banner("agent create — claim a brainbase.agent.yaml and link this folder");
53595
+ let manifest = await loadOrScaffoldManifest(cwd2, args);
53596
+ if (!manifest)
53597
+ return;
53598
+ if (manifest.id) {
53599
+ f2.warn(`This folder already belongs to an agent — ${import_picocolors30.default.bold(manifest.agent.name)} (${import_picocolors30.default.dim(manifest.id)}).`);
53600
+ f2.info(`If you want to detach it, run ${import_picocolors30.default.cyan("brainbase unlink")} first; or move to a different directory.`);
53601
+ return;
53602
+ }
53031
53603
  const orgsSpinner = de();
53032
53604
  orgsSpinner.start("Loading your organizations…");
53033
53605
  let orgs;
@@ -53054,7 +53626,7 @@ async function runAgentCreate(cwd2, args) {
53054
53626
  org = found;
53055
53627
  } else if (orgs.length === 1) {
53056
53628
  org = orgs[0];
53057
- f2.info(`Using organization ${import_picocolors29.default.bold(org.name)}.`);
53629
+ f2.info(`Using organization ${import_picocolors30.default.bold(org.name)}.`);
53058
53630
  } else {
53059
53631
  const orgChoice = await ie({
53060
53632
  message: "Pick an organization",
@@ -53102,7 +53674,7 @@ async function runAgentCreate(cwd2, args) {
53102
53674
  createSpinner2.start("Creating team…");
53103
53675
  try {
53104
53676
  team = await api.createTeam(org.id, teamName.trim());
53105
- createSpinner2.stop(`Created team ${import_picocolors29.default.bold(team.name)}.`);
53677
+ createSpinner2.stop(`Created team ${import_picocolors30.default.bold(team.name)}.`);
53106
53678
  } catch (err) {
53107
53679
  createSpinner2.stop("Failed.");
53108
53680
  handleApiError4(err);
@@ -53112,8 +53684,8 @@ async function runAgentCreate(cwd2, args) {
53112
53684
  team = teams.find((t) => t.id === picked);
53113
53685
  }
53114
53686
  }
53115
- const harness = normalizeHarnessId(args.harness ?? await pickHarness(cwd2));
53116
- let agentName = args.name?.trim();
53687
+ const harness = normalizeHarnessId(args.harness ?? manifest.harness ?? await pickHarness(cwd2));
53688
+ let agentName = args.name?.trim() || manifest.agent.name.trim();
53117
53689
  if (!agentName) {
53118
53690
  const ans = await te({
53119
53691
  message: "Agent name",
@@ -53122,7 +53694,7 @@ async function runAgentCreate(cwd2, args) {
53122
53694
  });
53123
53695
  agentName = ensureNotCancelled(ans).trim();
53124
53696
  }
53125
- let tagline = args.tagline?.trim() || undefined;
53697
+ let tagline = (args.tagline ?? manifest.agent.tagline)?.trim() || undefined;
53126
53698
  if (tagline === undefined && !args.yes) {
53127
53699
  const ans = await te({
53128
53700
  message: "Tagline",
@@ -53134,11 +53706,11 @@ async function runAgentCreate(cwd2, args) {
53134
53706
  }
53135
53707
  if (!args.yes) {
53136
53708
  le([
53137
- `${import_picocolors29.default.dim("org")} ${import_picocolors29.default.bold(org.name)}`,
53138
- `${import_picocolors29.default.dim("team")} ${import_picocolors29.default.bold(team.name)}`,
53139
- `${import_picocolors29.default.dim("harness")} ${import_picocolors29.default.bold(harness)}`,
53140
- `${import_picocolors29.default.dim("agent")} ${import_picocolors29.default.bold(agentName)}`,
53141
- ...tagline ? [`${import_picocolors29.default.dim("tagline")} ${tagline}`] : []
53709
+ `${import_picocolors30.default.dim("org")} ${import_picocolors30.default.bold(org.name)}`,
53710
+ `${import_picocolors30.default.dim("team")} ${import_picocolors30.default.bold(team.name)}`,
53711
+ `${import_picocolors30.default.dim("harness")} ${import_picocolors30.default.bold(harness)}`,
53712
+ `${import_picocolors30.default.dim("agent")} ${import_picocolors30.default.bold(agentName)}`,
53713
+ ...tagline ? [`${import_picocolors30.default.dim("tagline")} ${tagline}`] : []
53142
53714
  ].join(`
53143
53715
  `), "Will create");
53144
53716
  const confirmed = await se({ message: "Create this agent?", initialValue: true });
@@ -53147,6 +53719,19 @@ async function runAgentCreate(cwd2, args) {
53147
53719
  return;
53148
53720
  }
53149
53721
  }
53722
+ let resolvedEntrypoint;
53723
+ if (manifest.entrypoint) {
53724
+ const body = resolveEntrypoint(cwd2, manifest);
53725
+ if (body === null) {
53726
+ if (manifest.entrypoint.file) {
53727
+ f2.error(`Entrypoint file ${import_picocolors30.default.bold(manifest.entrypoint.file)} not found.`);
53728
+ } else {
53729
+ f2.error("Entrypoint block is empty.");
53730
+ }
53731
+ return;
53732
+ }
53733
+ resolvedEntrypoint = body;
53734
+ }
53150
53735
  const createSpinner = de();
53151
53736
  createSpinner.start("Creating agent…");
53152
53737
  let agent;
@@ -53156,9 +53741,10 @@ async function runAgentCreate(cwd2, args) {
53156
53741
  team_id: team.id,
53157
53742
  name: agentName,
53158
53743
  tagline,
53159
- harness
53744
+ harness,
53745
+ ...resolvedEntrypoint !== undefined ? { entrypoint: resolvedEntrypoint } : {}
53160
53746
  });
53161
- createSpinner.stop(`Created ${import_picocolors29.default.bold(agent.name)}.`);
53747
+ createSpinner.stop(`Created ${import_picocolors30.default.bold(agent.name)}.`);
53162
53748
  } catch (err) {
53163
53749
  createSpinner.stop("Failed.");
53164
53750
  handleApiError4(err);
@@ -53171,7 +53757,7 @@ async function runAgentCreate(cwd2, args) {
53171
53757
  let wantsTracking = true;
53172
53758
  if (!args.yes) {
53173
53759
  const ans = await se({
53174
- message: `Track ${harness} conversations on the brainbase platform? ${import_picocolors29.default.dim("(routes LLM calls through brainbase so they appear under this agent)")}`,
53760
+ message: `Track ${harness} conversations on the brainbase platform? ${import_picocolors30.default.dim("(routes LLM calls through brainbase so they appear under this agent)")}`,
53175
53761
  initialValue: true
53176
53762
  });
53177
53763
  wantsTracking = ensureNotCancelled(ans);
@@ -53225,7 +53811,54 @@ async function runAgentCreate(cwd2, args) {
53225
53811
  tracking
53226
53812
  };
53227
53813
  writeLink(cwd2, link2);
53228
- $e(`Created ${import_picocolors29.default.bold(agent.name)} and linked this folder.`);
53814
+ manifest = readManifest(cwd2);
53815
+ let updatedCloud = null;
53816
+ const hasContent = !!manifest.instructions || manifest.skills.length > 0 || (manifest.mcp ?? []).length > 0;
53817
+ if (hasContent) {
53818
+ const outgoing = await buildOutgoingComponents(cwd2, manifest, null);
53819
+ if (outgoing === null) {
53820
+ f2.warn(`Agent created, but local content wasn't uploaded. Fix the issue above and run ${import_picocolors30.default.cyan("brainbase agent push")}.`);
53821
+ } else if (outgoing.length > 0) {
53822
+ const pushSpinner = de();
53823
+ pushSpinner.start("Pushing local content…");
53824
+ try {
53825
+ updatedCloud = await api.pushAgentManifest(agent.id, {
53826
+ components: outgoing,
53827
+ base_revision: 0
53828
+ });
53829
+ pushSpinner.stop(`Pushed at revision ${updatedCloud.revision}.`);
53830
+ } catch (err) {
53831
+ pushSpinner.stop("Failed.");
53832
+ if (err instanceof ApiError) {
53833
+ f2.warn(`Content upload failed: ${err.message}. Run ${import_picocolors30.default.cyan("brainbase agent push")} to retry.`);
53834
+ } else {
53835
+ f2.warn(`Content upload failed: ${err.message}. Run ${import_picocolors30.default.cyan("brainbase agent push")} to retry.`);
53836
+ }
53837
+ }
53838
+ }
53839
+ }
53840
+ if (updatedCloud) {
53841
+ const syncedComponents = updatedCloud.components.map((c2) => ({
53842
+ type: c2.type,
53843
+ slug: c2.slug,
53844
+ hash: c2.hash,
53845
+ installedPaths: []
53846
+ }));
53847
+ const state = {
53848
+ schemaVersion: 1,
53849
+ agent_id: agent.id,
53850
+ revision: updatedCloud.revision,
53851
+ synced_at: new Date().toISOString(),
53852
+ components: syncedComponents,
53853
+ agentMeta: {
53854
+ name: agent.name,
53855
+ tagline: agent.tagline,
53856
+ ...resolvedEntrypoint ? { entrypoint: resolvedEntrypoint } : {}
53857
+ }
53858
+ };
53859
+ writeSyncState(cwd2, state);
53860
+ }
53861
+ $e(`Created ${import_picocolors30.default.bold(agent.name)} and linked this folder.`);
53229
53862
  await showResultCard({
53230
53863
  title: "CREATED",
53231
53864
  tone: "ok",
@@ -53238,16 +53871,55 @@ async function runAgentCreate(cwd2, args) {
53238
53871
  });
53239
53872
  console.log();
53240
53873
  if (tracking && harness === "codex") {
53241
- 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.")}`));
53874
+ 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.")}`));
53242
53875
  }
53243
- console.log(tip(`brainbase agent pull ${import_picocolors29.default.dim("— pull the agent contents into this folder")}`));
53876
+ console.log(tip(`brainbase agent unpack ${import_picocolors30.default.dim("— install harness files (skills/mcps) under .claude/, .codex/, …")}`));
53244
53877
  console.log();
53245
53878
  }
53879
+ async function loadOrScaffoldManifest(cwd2, args) {
53880
+ if (hasManifest(cwd2)) {
53881
+ try {
53882
+ return readManifest(cwd2);
53883
+ } catch (err) {
53884
+ f2.error(err.message);
53885
+ return null;
53886
+ }
53887
+ }
53888
+ f2.warn(`No ${import_picocolors30.default.bold(AGENT_MANIFEST_FILE)} here.`);
53889
+ if (!args.yes) {
53890
+ const ans = await se({
53891
+ message: `Scaffold a minimal ${import_picocolors30.default.bold(AGENT_MANIFEST_FILE)} and continue?`,
53892
+ initialValue: true
53893
+ });
53894
+ if (!ensureNotCancelled(ans)) {
53895
+ $e("Aborted.");
53896
+ return null;
53897
+ }
53898
+ }
53899
+ const seedName = args.name?.trim() ?? path49.basename(path49.resolve(cwd2)) ?? "My Agent";
53900
+ const seedHarness = args.harness ? normalizeHarnessId(args.harness) : undefined;
53901
+ const scaffold = {
53902
+ schema: 1,
53903
+ ...seedHarness ? { harness: seedHarness } : {},
53904
+ agent: { name: seedName, ...args.tagline ? { tagline: args.tagline } : {} },
53905
+ playbooks: [],
53906
+ skills: [],
53907
+ mcp: []
53908
+ };
53909
+ try {
53910
+ writeManifest(cwd2, scaffold);
53911
+ f2.info(`Wrote ${import_picocolors30.default.bold(AGENT_MANIFEST_FILE)}.`);
53912
+ } catch (err) {
53913
+ f2.error(`Failed to write manifest: ${err.message}`);
53914
+ return null;
53915
+ }
53916
+ return scaffold;
53917
+ }
53246
53918
  async function pickHarness(cwd2) {
53247
53919
  const detections = await detectHarnesses(cwd2);
53248
53920
  const detected = detections.filter((d3) => d3.detection.detected);
53249
53921
  if (detected.length === 1) {
53250
- f2.info(`Detected harness: ${import_picocolors29.default.bold(detected[0].adapter.displayName)}.`);
53922
+ f2.info(`Detected harness: ${import_picocolors30.default.bold(detected[0].adapter.displayName)}.`);
53251
53923
  return detected[0].adapter.id;
53252
53924
  }
53253
53925
  const choice = await ie({
@@ -53273,8 +53945,268 @@ function handleApiError4(err) {
53273
53945
  $e("Aborted.");
53274
53946
  }
53275
53947
 
53948
+ // src/cli/agent-unpack.ts
53949
+ import path50 from "node:path";
53950
+ import fs46 from "node:fs";
53951
+ import os13 from "node:os";
53952
+ var import_picocolors31 = __toESM(require_picocolors(), 1);
53953
+ async function runAgentUnpack(cwd2, args) {
53954
+ banner("agent unpack — install this agent into a harness layout");
53955
+ if (!hasManifest(cwd2)) {
53956
+ f2.error(`No ${import_picocolors31.default.bold(AGENT_MANIFEST_FILE)} here.`);
53957
+ f2.info(`Run ${import_picocolors31.default.cyan("brainbase agent pull <id>")} to bring an agent into this folder first.`);
53958
+ return;
53959
+ }
53960
+ let manifest;
53961
+ try {
53962
+ manifest = readManifest(cwd2);
53963
+ } catch (err) {
53964
+ f2.error(err.message);
53965
+ return;
53966
+ }
53967
+ if (!manifest.id) {
53968
+ f2.error(`${import_picocolors31.default.bold(AGENT_MANIFEST_FILE)} is unclaimed (no ${import_picocolors31.default.cyan("id")}).`);
53969
+ 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.`);
53970
+ return;
53971
+ }
53972
+ let harness;
53973
+ if (args.harness) {
53974
+ harness = normalizeHarnessId(args.harness);
53975
+ } else if (args.yes) {
53976
+ if (!manifest.harness) {
53977
+ f2.error(`--yes mode but no harness — set ${import_picocolors31.default.cyan("harness")} in the manifest or pass ${import_picocolors31.default.cyan("--harness")}.`);
53978
+ return;
53979
+ }
53980
+ harness = normalizeHarnessId(manifest.harness);
53981
+ } else {
53982
+ harness = await pickHarness2(manifest.harness);
53983
+ }
53984
+ if (!args.yes) {
53985
+ const ok = await se({
53986
+ message: `Install ${import_picocolors31.default.bold(manifest.agent.name)} as ${import_picocolors31.default.bold(harness)} here?`,
53987
+ initialValue: true
53988
+ });
53989
+ if (!ensureNotCancelled(ok)) {
53990
+ $e("Aborted.");
53991
+ return;
53992
+ }
53993
+ }
53994
+ const scope = args.scope ?? "project";
53995
+ const stageRoot = fs46.mkdtempSync(path50.join(os13.tmpdir(), "brainbase-unpack-"));
53996
+ try {
53997
+ const toInstall = [];
53998
+ const instructionsBody = readInstructions(cwd2, manifest);
53999
+ if (instructionsBody && instructionsBody.trim()) {
54000
+ const compDir = path50.join(stageRoot, "instruction", "agent-instructions");
54001
+ ensureDir(compDir);
54002
+ fs46.writeFileSync(path50.join(compDir, "instructions.md"), instructionsBody, "utf8");
54003
+ toInstall.push({
54004
+ type: "instruction",
54005
+ slug: "agent-instructions",
54006
+ scope,
54007
+ rootDir: compDir,
54008
+ description: "Agent instructions",
54009
+ checksum: ""
54010
+ });
54011
+ }
54012
+ for (const entry of manifest.playbooks ?? []) {
54013
+ const issue = stageLocalPlaybook(entry, cwd2, stageRoot, scope, toInstall);
54014
+ if (issue) {
54015
+ f2.warn(issue);
54016
+ }
54017
+ }
54018
+ for (const entry of manifest.skills ?? []) {
54019
+ const issue = stageLocalSkill(entry.source, cwd2, stageRoot, scope, toInstall);
54020
+ if (issue) {
54021
+ f2.warn(issue);
54022
+ }
54023
+ }
54024
+ for (const entry of manifest.mcp ?? []) {
54025
+ const compDir = path50.join(stageRoot, "mcp", entry.name);
54026
+ ensureDir(compDir);
54027
+ const payload = {};
54028
+ if (entry.url !== undefined)
54029
+ payload.url = entry.url;
54030
+ if (entry.command !== undefined)
54031
+ payload.command = entry.command;
54032
+ if (entry.args !== undefined)
54033
+ payload.args = entry.args;
54034
+ if (entry.env !== undefined)
54035
+ payload.env = entry.env;
54036
+ if (entry.headers !== undefined)
54037
+ payload.headers = entry.headers;
54038
+ payload.is_enabled = entry.is_enabled ?? true;
54039
+ toInstall.push({
54040
+ type: "mcp",
54041
+ slug: entry.name,
54042
+ scope,
54043
+ rootDir: compDir,
54044
+ payload,
54045
+ checksum: ""
54046
+ });
54047
+ }
54048
+ const haveOrchMcp = (manifest.mcp ?? []).some((m3) => m3.name === ORCHESTRATION_MCP_SLUG);
54049
+ const haveMemoryMcp = (manifest.mcp ?? []).some((m3) => m3.name === MEMORY_MCP_SLUG);
54050
+ if (!haveOrchMcp)
54051
+ toInstall.push(buildOrchestrationMcpComponent(scope));
54052
+ if (!haveMemoryMcp)
54053
+ toInstall.push(buildMemoryMcpComponent(scope));
54054
+ const opts = {
54055
+ cwd: cwd2,
54056
+ scope,
54057
+ resolveConflict: async (_c) => "overwrite",
54058
+ resolveSecret: async () => null
54059
+ };
54060
+ const sp = de();
54061
+ sp.start("Installing harness layout…");
54062
+ const result = await runHarnessInstall3(harness, toInstall, opts, manifest.agent.name);
54063
+ sp.stop("Installed.");
54064
+ if (result.skipped.length) {
54065
+ f2.warn(`Skipped: ${result.skipped.map((s3) => `${s3.type}/${s3.slug} (${s3.reason})`).join(", ")}`);
54066
+ }
54067
+ } catch (err) {
54068
+ f2.error(`Install failed: ${err.message}`);
54069
+ return;
54070
+ } finally {
54071
+ try {
54072
+ fs46.rmSync(stageRoot, { recursive: true, force: true });
54073
+ } catch {}
54074
+ }
54075
+ if (manifest.harness !== harness) {
54076
+ manifest.harness = harness;
54077
+ writeManifest(cwd2, manifest);
54078
+ }
54079
+ $e(`Unpacked ${import_picocolors31.default.bold(manifest.agent.name)} as ${import_picocolors31.default.bold(harness)}.`);
54080
+ await showResultCard({
54081
+ title: "UNPACKED",
54082
+ tone: "ok",
54083
+ subtitle: manifest.agent.name,
54084
+ meta: [
54085
+ ["harness", harness],
54086
+ ["agent", manifest.id]
54087
+ ]
54088
+ });
54089
+ }
54090
+ function stageLocalPlaybook(entry, cwd2, stageRoot, scope, toInstall) {
54091
+ if (entry.content.text !== undefined && entry.content.file !== undefined) {
54092
+ return `Playbook ${entry.title}: both text and file set — skipped.`;
54093
+ }
54094
+ const body = resolvePlaybookContent(cwd2, entry);
54095
+ if (body === null) {
54096
+ return entry.content.file ? `Playbook ${entry.title}: file ${entry.content.file} not found — skipped.` : `Playbook ${entry.title}: content empty — skipped.`;
54097
+ }
54098
+ const slug = slugifyPlaybookTitle(entry.title);
54099
+ const compDir = path50.join(stageRoot, "playbook", slug);
54100
+ ensureDir(compDir);
54101
+ const wireBody = /^---\s*\n/.test(body) ? body : assembleFrontmatter(entry.title, entry.description) + body.replace(/^\n+/, "");
54102
+ fs46.writeFileSync(path50.join(compDir, `${slug}.md`), wireBody, "utf8");
54103
+ toInstall.push({
54104
+ type: "playbook",
54105
+ slug,
54106
+ scope,
54107
+ rootDir: compDir,
54108
+ description: entry.description,
54109
+ checksum: ""
54110
+ });
54111
+ return null;
54112
+ }
54113
+ function stageLocalSkill(source, cwd2, stageRoot, scope, toInstall) {
54114
+ if (source.startsWith("./") || source.startsWith("../") || source.startsWith("/")) {
54115
+ const abs = path50.resolve(cwd2, source);
54116
+ if (!fs46.existsSync(abs)) {
54117
+ return `Skill ${source}: not found on disk — skipped.`;
54118
+ }
54119
+ const slug = path50.basename(abs);
54120
+ const compDir = path50.join(stageRoot, "skill", slug);
54121
+ ensureDir(compDir);
54122
+ copyDirRecursive(abs, compDir);
54123
+ toInstall.push({
54124
+ type: "skill",
54125
+ slug,
54126
+ scope,
54127
+ rootDir: compDir,
54128
+ checksum: ""
54129
+ });
54130
+ return null;
54131
+ }
54132
+ try {
54133
+ const parsed = parseSkillSource(source);
54134
+ if (parsed.type === "local" || parsed.type === "inline")
54135
+ return null;
54136
+ const slug = defaultSlugForSource(source);
54137
+ const compDir = path50.join(stageRoot, "skill", slug);
54138
+ ensureDir(compDir);
54139
+ toInstall.push({
54140
+ type: "skill",
54141
+ slug,
54142
+ scope,
54143
+ rootDir: compDir,
54144
+ source: parsed,
54145
+ checksum: ""
54146
+ });
54147
+ return null;
54148
+ } catch (err) {
54149
+ return `Skill ${source}: ${err.message} — skipped.`;
54150
+ }
54151
+ }
54152
+ function defaultSlugForSource(source) {
54153
+ const reg = /^registry:(?:[a-z0-9_-]+\/)?([a-z0-9_-]+)/i.exec(source);
54154
+ if (reg)
54155
+ return reg[1].toLowerCase();
54156
+ const gh = /^(?:github|git):[^/]*\/?([a-z0-9_-]+)/i.exec(source);
54157
+ if (gh)
54158
+ return gh[1].toLowerCase();
54159
+ return source.replace(/[^a-z0-9_-]/gi, "-").slice(0, 60) || "skill";
54160
+ }
54161
+ function copyDirRecursive(src, dest) {
54162
+ ensureDir(dest);
54163
+ for (const entry of fs46.readdirSync(src, { withFileTypes: true })) {
54164
+ const s3 = path50.join(src, entry.name);
54165
+ const d3 = path50.join(dest, entry.name);
54166
+ if (entry.isDirectory())
54167
+ copyDirRecursive(s3, d3);
54168
+ else if (entry.isFile())
54169
+ fs46.copyFileSync(s3, d3);
54170
+ }
54171
+ }
54172
+ function assembleFrontmatter(title, description) {
54173
+ const lines = ["---", `title: ${yamlScalar2(title)}`];
54174
+ if (description)
54175
+ lines.push(`description: ${yamlScalar2(description)}`);
54176
+ lines.push("---", "");
54177
+ return lines.join(`
54178
+ `);
54179
+ }
54180
+ function yamlScalar2(s3) {
54181
+ if (!/[\n":#&*!|>'%@`{}[\]]/.test(s3) && s3.trim() === s3 && s3 !== "")
54182
+ return s3;
54183
+ return JSON.stringify(s3);
54184
+ }
54185
+ function runHarnessInstall3(harnessId, components, opts, agentName) {
54186
+ if (harnessId === "claude-code")
54187
+ return installClaudeCodeWithCtx(components, opts, agentName);
54188
+ if (harnessId === "codex")
54189
+ return installCodexWithCtx(components, opts, agentName);
54190
+ if (harnessId === "kafka")
54191
+ return installKafkaWithCtx(components, opts, agentName);
54192
+ return getAdapter(harnessId).install(components, opts);
54193
+ }
54194
+ async function pickHarness2(current) {
54195
+ const initial = current ? normalizeHarnessId(current) : undefined;
54196
+ const choice = await ie({
54197
+ message: "Pick a harness to install as",
54198
+ options: adapters.map((a3) => ({
54199
+ value: a3.id,
54200
+ label: a3.displayName,
54201
+ hint: a3.id === initial ? "current" : undefined
54202
+ })),
54203
+ initialValue: initial ?? adapters[0].id
54204
+ });
54205
+ return ensureNotCancelled(choice);
54206
+ }
54207
+
53276
54208
  // src/cli/agent.ts
53277
- async function runAgent(cwd2, sub, _args, opts) {
54209
+ async function runAgent(cwd2, sub, args, opts) {
53278
54210
  switch (sub) {
53279
54211
  case "create":
53280
54212
  await runAgentCreate(cwd2, {
@@ -53288,10 +54220,22 @@ async function runAgent(cwd2, sub, _args, opts) {
53288
54220
  });
53289
54221
  return;
53290
54222
  case "pull":
53291
- await runAgentPull(cwd2, opts);
54223
+ await runAgentPull(cwd2, {
54224
+ yes: opts.yes,
54225
+ scope: opts.scope,
54226
+ agentIdArg: args[0],
54227
+ force: opts.force
54228
+ });
53292
54229
  return;
53293
54230
  case "push":
53294
- await runAgentPush(cwd2, opts);
54231
+ await runAgentPush(cwd2, { yes: opts.yes });
54232
+ return;
54233
+ case "unpack":
54234
+ await runAgentUnpack(cwd2, {
54235
+ yes: opts.yes,
54236
+ scope: opts.scope,
54237
+ harness: opts.harness
54238
+ });
53295
54239
  return;
53296
54240
  case "status":
53297
54241
  await runAgentStatus(cwd2);
@@ -53315,30 +54259,31 @@ async function runAgent(cwd2, sub, _args, opts) {
53315
54259
  function printHelp() {
53316
54260
  const out = [];
53317
54261
  out.push("");
53318
- out.push(` ${import_picocolors30.default.bold("brainbase agent")} ${import_picocolors30.default.dim("<sub> [options]")}`);
54262
+ out.push(` ${import_picocolors32.default.bold("brainbase agent")} ${import_picocolors32.default.dim("<sub> [options]")}`);
53319
54263
  out.push("");
53320
- out.push(` ${import_picocolors30.default.cyan("create")} ${import_picocolors30.default.dim("make a new agent on the cloud and link this folder to it")}`);
53321
- out.push(` ${import_picocolors30.default.cyan("pull")} ${import_picocolors30.default.dim("apply cloud changes into this folder")}`);
53322
- out.push(` ${import_picocolors30.default.cyan("push")} ${import_picocolors30.default.dim("send local changes to the cloud")}`);
53323
- out.push(` ${import_picocolors30.default.cyan("status")} ${import_picocolors30.default.dim("show what would push and what would pull")}`);
53324
- out.push(` ${import_picocolors30.default.cyan("env")} ${import_picocolors30.default.dim('print export statements use with `eval "$(brainbase agent env)"`')}`);
54264
+ out.push(` ${import_picocolors32.default.cyan("create")} ${import_picocolors32.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
54265
+ 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)")}`);
54266
+ out.push(` ${import_picocolors32.default.cyan("push")} ${import_picocolors32.default.dim("send local changes to the cloud")}`);
54267
+ out.push(` ${import_picocolors32.default.cyan("unpack")} ${import_picocolors32.default.dim("install the claimed agent into a harness layout (--harness to override)")}`);
54268
+ out.push(` ${import_picocolors32.default.cyan("status")} ${import_picocolors32.default.dim("show what would push and what would pull")}`);
54269
+ out.push(` ${import_picocolors32.default.cyan("env")} ${import_picocolors32.default.dim('print export statements — use with `eval "$(brainbase agent env)"`')}`);
53325
54270
  out.push("");
53326
54271
  console.log(out.join(`
53327
54272
  `));
53328
54273
  }
53329
54274
 
53330
54275
  // src/cli/orchestration.ts
53331
- var import_picocolors35 = __toESM(require_picocolors(), 1);
54276
+ var import_picocolors37 = __toESM(require_picocolors(), 1);
53332
54277
 
53333
54278
  // src/cli/orchestration-pull.ts
53334
- import path52 from "node:path";
53335
- import fs49 from "node:fs";
53336
- var import_picocolors31 = __toESM(require_picocolors(), 1);
54279
+ import path54 from "node:path";
54280
+ import fs50 from "node:fs";
54281
+ var import_picocolors33 = __toESM(require_picocolors(), 1);
53337
54282
 
53338
54283
  // src/core/orchestration-manifest.ts
53339
- import path49 from "node:path";
53340
- import fs46 from "node:fs";
53341
- var import_yaml3 = __toESM(require_dist(), 1);
54284
+ import path51 from "node:path";
54285
+ import fs47 from "node:fs";
54286
+ var import_yaml4 = __toESM(require_dist(), 1);
53342
54287
  var ORCH_MANIFEST_FILE = "brainbase-orchestration.yaml";
53343
54288
  var ORCH_MEMBERS_DIR = "agents";
53344
54289
  var OrchMetaSchema = exports_external.object({
@@ -53365,19 +54310,19 @@ var OrchestrationManifestSchema = exports_external.object({
53365
54310
  edges: exports_external.array(EdgeSchema).default([])
53366
54311
  });
53367
54312
  function orchManifestPath(cwd2) {
53368
- return path49.join(cwd2, ORCH_MANIFEST_FILE);
54313
+ return path51.join(cwd2, ORCH_MANIFEST_FILE);
53369
54314
  }
53370
54315
  function hasOrchManifest(cwd2) {
53371
- return fs46.existsSync(orchManifestPath(cwd2));
54316
+ return fs47.existsSync(orchManifestPath(cwd2));
53372
54317
  }
53373
54318
  function readOrchManifest(cwd2) {
53374
54319
  const p2 = orchManifestPath(cwd2);
53375
- if (!fs46.existsSync(p2))
54320
+ if (!fs47.existsSync(p2))
53376
54321
  return null;
53377
- const raw = fs46.readFileSync(p2, "utf8");
54322
+ const raw = fs47.readFileSync(p2, "utf8");
53378
54323
  let parsed;
53379
54324
  try {
53380
- parsed = import_yaml3.default.parse(raw);
54325
+ parsed = import_yaml4.default.parse(raw);
53381
54326
  } catch (err) {
53382
54327
  throw new Error(`${ORCH_MANIFEST_FILE} is not valid YAML: ${err.message}`);
53383
54328
  }
@@ -53388,20 +54333,20 @@ function readOrchManifest(cwd2) {
53388
54333
  return result.data;
53389
54334
  }
53390
54335
  function writeOrchManifest(cwd2, manifest) {
53391
- const doc = new import_yaml3.default.Document;
54336
+ const doc = new import_yaml4.default.Document;
53392
54337
  doc.contents = manifest;
53393
54338
  doc.commentBefore = ` brainbase-orchestration.yaml — declarative orchestration manifest.
53394
54339
  ` + ` Committed to source control. Edit by hand, then
53395
54340
  ` + " `brainbase orchestration push`. Member agents live under ./agents/.";
53396
- fs46.writeFileSync(orchManifestPath(cwd2), String(doc), "utf8");
54341
+ fs47.writeFileSync(orchManifestPath(cwd2), String(doc), "utf8");
53397
54342
  }
53398
54343
  function memberDir(cwd2, slug) {
53399
- return path49.join(cwd2, ORCH_MEMBERS_DIR, slug);
54344
+ return path51.join(cwd2, ORCH_MEMBERS_DIR, slug);
53400
54345
  }
53401
54346
 
53402
54347
  // src/core/orchestration-link.ts
53403
- import path50 from "node:path";
53404
- import fs47 from "node:fs";
54348
+ import path52 from "node:path";
54349
+ import fs48 from "node:fs";
53405
54350
  var ORCH_LINK_FILE = "orchestration-link.json";
53406
54351
  var ORCH_SYNC_STATE_FILE = "orchestration-sync-state.json";
53407
54352
  var OrchestrationLinkSchema = exports_external.object({
@@ -53435,10 +54380,10 @@ var OrchestrationSyncStateSchema = exports_external.object({
53435
54380
  edges: exports_external.array(SyncedEdgeSchema)
53436
54381
  });
53437
54382
  function orchLinkPath(cwd2) {
53438
- return path50.join(cwd2, LINK_DIR, ORCH_LINK_FILE);
54383
+ return path52.join(cwd2, LINK_DIR, ORCH_LINK_FILE);
53439
54384
  }
53440
54385
  function orchSyncStatePath(cwd2) {
53441
- return path50.join(cwd2, LINK_DIR, ORCH_SYNC_STATE_FILE);
54386
+ return path52.join(cwd2, LINK_DIR, ORCH_SYNC_STATE_FILE);
53442
54387
  }
53443
54388
  function readOrchLink(cwd2) {
53444
54389
  const p2 = orchLinkPath(cwd2);
@@ -53451,7 +54396,7 @@ function readOrchLink(cwd2) {
53451
54396
  }
53452
54397
  }
53453
54398
  function writeOrchLink(cwd2, link2) {
53454
- ensureDir(path50.join(cwd2, LINK_DIR));
54399
+ ensureDir(path52.join(cwd2, LINK_DIR));
53455
54400
  const clean = {};
53456
54401
  for (const [k3, v3] of Object.entries(link2)) {
53457
54402
  if (v3 !== null && v3 !== undefined)
@@ -53471,22 +54416,22 @@ function readOrchSyncState(cwd2) {
53471
54416
  }
53472
54417
  }
53473
54418
  function writeOrchSyncState(cwd2, state) {
53474
- ensureDir(path50.join(cwd2, LINK_DIR));
54419
+ ensureDir(path52.join(cwd2, LINK_DIR));
53475
54420
  writeJson(orchSyncStatePath(cwd2), state);
53476
54421
  ensureGitignore2(cwd2);
53477
54422
  }
53478
54423
  function ensureGitignore2(cwd2) {
53479
- const ignorePath = path50.join(cwd2, LINK_DIR, ".gitignore");
54424
+ const ignorePath = path52.join(cwd2, LINK_DIR, ".gitignore");
53480
54425
  const desired = `${ORCH_SYNC_STATE_FILE}
53481
54426
  `;
53482
54427
  try {
53483
54428
  if (!exists(ignorePath)) {
53484
- fs47.writeFileSync(ignorePath, desired);
54429
+ fs48.writeFileSync(ignorePath, desired);
53485
54430
  return;
53486
54431
  }
53487
- const current = fs47.readFileSync(ignorePath, "utf8");
54432
+ const current = fs48.readFileSync(ignorePath, "utf8");
53488
54433
  if (!current.split(/\r?\n/).some((l2) => l2.trim() === ORCH_SYNC_STATE_FILE)) {
53489
- fs47.writeFileSync(ignorePath, current.endsWith(`
54434
+ fs48.writeFileSync(ignorePath, current.endsWith(`
53490
54435
  `) ? current + desired : current + `
53491
54436
  ` + desired);
53492
54437
  }
@@ -53494,9 +54439,9 @@ function ensureGitignore2(cwd2) {
53494
54439
  }
53495
54440
 
53496
54441
  // src/core/agent-fresh-install.ts
53497
- import path51 from "node:path";
53498
- import fs48 from "node:fs";
53499
- import os13 from "node:os";
54442
+ import path53 from "node:path";
54443
+ import fs49 from "node:fs";
54444
+ import os14 from "node:os";
53500
54445
  async function installAgentFresh(input) {
53501
54446
  const { cwd: cwd2, agent, cloud, harness } = input;
53502
54447
  const scope = input.scope ?? "project";
@@ -53513,7 +54458,7 @@ async function installAgentFresh(input) {
53513
54458
  type: c2.type,
53514
54459
  slug: c2.slug,
53515
54460
  scope,
53516
- rootDir: path51.join(stageRoot, c2.type, c2.slug),
54461
+ rootDir: path53.join(stageRoot, c2.type, c2.slug),
53517
54462
  description: c2.description,
53518
54463
  meta: c2.meta,
53519
54464
  payload: c2.meta?.mcp,
@@ -53531,14 +54476,15 @@ async function installAgentFresh(input) {
53531
54476
  resolveConflict: async (_c) => "overwrite",
53532
54477
  resolveSecret: async () => null
53533
54478
  };
53534
- const result = await runHarnessInstall3(harness, toInstall, installOpts, agent.name);
54479
+ const result = await runHarnessInstall4(harness, toInstall, installOpts, agent.name);
53535
54480
  for (const o2 of result.installed) {
53536
54481
  justInstalledPaths.set(`${o2.type}/${o2.slug}`, o2.installedPaths);
53537
54482
  }
53538
54483
  }
53539
54484
  materializeInstructions2(cwd2, cloud);
53540
- const manifest = buildManifestFromCloud(cloud, agent);
53541
- writeManifest(cwd2, manifest);
54485
+ const manifest = input.preserveManifest ? null : buildManifestFromCloud(cloud, agent);
54486
+ if (manifest)
54487
+ writeManifest(cwd2, manifest);
53542
54488
  writeLink(cwd2, {
53543
54489
  schemaVersion: 1,
53544
54490
  agent_id: agent.id,
@@ -53568,31 +54514,32 @@ async function installAgentFresh(input) {
53568
54514
  if (input.pullSecrets !== false) {
53569
54515
  await pullAgentSecrets(cwd2, agent.id);
53570
54516
  }
54517
+ const returnedManifest = manifest ?? buildManifestFromCloud(cloud, agent);
53571
54518
  return {
53572
54519
  installedPaths: justInstalledPaths,
53573
- manifest,
54520
+ manifest: returnedManifest,
53574
54521
  syncedComponents
53575
54522
  };
53576
54523
  } finally {
53577
54524
  try {
53578
- fs48.rmSync(stageRoot, { recursive: true, force: true });
54525
+ fs49.rmSync(stageRoot, { recursive: true, force: true });
53579
54526
  } catch {}
53580
54527
  }
53581
54528
  }
53582
54529
  function stageManifestComponents2(components) {
53583
- const root = fs48.mkdtempSync(path51.join(os13.tmpdir(), "brainbase-orch-pull-"));
54530
+ const root = fs49.mkdtempSync(path53.join(os14.tmpdir(), "brainbase-orch-pull-"));
53584
54531
  for (const c2 of components) {
53585
- const compDir = path51.join(root, c2.type, c2.slug);
54532
+ const compDir = path53.join(root, c2.type, c2.slug);
53586
54533
  ensureDir(compDir);
53587
54534
  for (const f4 of c2.files) {
53588
- const target = path51.join(compDir, f4.path);
53589
- ensureDir(path51.dirname(target));
53590
- fs48.writeFileSync(target, f4.content);
54535
+ const target = path53.join(compDir, f4.path);
54536
+ ensureDir(path53.dirname(target));
54537
+ fs49.writeFileSync(target, f4.content);
53591
54538
  }
53592
54539
  }
53593
54540
  return root;
53594
54541
  }
53595
- function runHarnessInstall3(harnessId, components, opts, agentName) {
54542
+ function runHarnessInstall4(harnessId, components, opts, agentName) {
53596
54543
  if (harnessId === "claude-code")
53597
54544
  return installClaudeCodeWithCtx(components, opts, agentName);
53598
54545
  if (harnessId === "codex")
@@ -53608,7 +54555,7 @@ function materializeInstructions2(cwd2, cloud) {
53608
54555
  const body = c2.files[0]?.content ?? "";
53609
54556
  if (!body.trim())
53610
54557
  continue;
53611
- fs48.writeFileSync(path51.join(cwd2, DEFAULT_INSTRUCTIONS_FILE), body, "utf8");
54558
+ fs49.writeFileSync(path53.join(cwd2, DEFAULT_INSTRUCTIONS_FILE), body, "utf8");
53612
54559
  return;
53613
54560
  }
53614
54561
  }
@@ -53647,6 +54594,7 @@ function buildManifestFromCloud(cloud, agent) {
53647
54594
  ...agent.tagline ? { tagline: agent.tagline } : {}
53648
54595
  },
53649
54596
  ...hasInstructions ? { instructions: { file: DEFAULT_INSTRUCTIONS_FILE } } : {},
54597
+ playbooks: [],
53650
54598
  skills,
53651
54599
  mcp
53652
54600
  };
@@ -53676,8 +54624,8 @@ async function runOrchestrationPull(cwd2, args) {
53676
54624
  orchId = args.orchestrationId;
53677
54625
  } else {
53678
54626
  f2.warn("This folder is not linked to any orchestration.");
53679
- f2.info(`Run ${import_picocolors31.default.cyan("brainbase orchestration pull <id>")} with an orchestration id,
53680
- or ${import_picocolors31.default.cyan("brainbase orchestration list")} to find one.`);
54627
+ f2.info(`Run ${import_picocolors33.default.cyan("brainbase orchestration pull <id>")} with an orchestration id,
54628
+ or ${import_picocolors33.default.cyan("brainbase orchestration list")} to find one.`);
53681
54629
  return;
53682
54630
  }
53683
54631
  const sp = de();
@@ -53693,24 +54641,24 @@ async function runOrchestrationPull(cwd2, args) {
53693
54641
  }
53694
54642
  const planLines = [];
53695
54643
  planLines.push("");
53696
- planLines.push(` ${import_picocolors31.default.bold(cloud.name)} ${import_picocolors31.default.dim(`(${cloud.id})`)}`);
54644
+ planLines.push(` ${import_picocolors33.default.bold(cloud.name)} ${import_picocolors33.default.dim(`(${cloud.id})`)}`);
53697
54645
  if (cloud.description)
53698
- planLines.push(` ${import_picocolors31.default.dim(cloud.description)}`);
54646
+ planLines.push(` ${import_picocolors33.default.dim(cloud.description)}`);
53699
54647
  planLines.push("");
53700
- planLines.push(` ${import_picocolors31.default.dim("members:")}`);
54648
+ planLines.push(` ${import_picocolors33.default.dim("members:")}`);
53701
54649
  for (const m3 of cloud.members) {
53702
54650
  const skipped = !m3.manifest;
53703
- const tail = skipped ? import_picocolors31.default.red(" (manifest unavailable — skipped)") : "";
53704
- planLines.push(` ${import_picocolors31.default.cyan("•")} ${import_picocolors31.default.bold(m3.slug)} ${import_picocolors31.default.dim(`(${m3.name})`)}${tail}`);
54651
+ const tail = skipped ? import_picocolors33.default.red(" (manifest unavailable — skipped)") : "";
54652
+ planLines.push(` ${import_picocolors33.default.cyan("•")} ${import_picocolors33.default.bold(m3.slug)} ${import_picocolors33.default.dim(`(${m3.name})`)}${tail}`);
53705
54653
  }
53706
54654
  if (cloud.edges.length) {
53707
54655
  planLines.push("");
53708
- planLines.push(` ${import_picocolors31.default.dim("edges:")}`);
54656
+ planLines.push(` ${import_picocolors33.default.dim("edges:")}`);
53709
54657
  for (const e2 of cloud.edges) {
53710
54658
  const from = e2.from_slug ?? e2.from_agent_id;
53711
54659
  const to2 = e2.to_slug ?? e2.to_agent_id;
53712
- const desc = e2.description ? ` ${import_picocolors31.default.dim("— " + e2.description)}` : "";
53713
- planLines.push(` ${import_picocolors31.default.cyan(from)} ${import_picocolors31.default.dim("→")} ${import_picocolors31.default.cyan(to2)}${desc}`);
54660
+ const desc = e2.description ? ` ${import_picocolors33.default.dim("— " + e2.description)}` : "";
54661
+ planLines.push(` ${import_picocolors33.default.cyan(from)} ${import_picocolors33.default.dim("→")} ${import_picocolors33.default.cyan(to2)}${desc}`);
53714
54662
  }
53715
54663
  }
53716
54664
  planLines.push("");
@@ -53719,7 +54667,7 @@ async function runOrchestrationPull(cwd2, args) {
53719
54667
  const isRefresh = !!existingLink;
53720
54668
  if (!args.yes && !isRefresh) {
53721
54669
  const ok = await se({
53722
- message: `Pull into ${import_picocolors31.default.bold(cwd2)}?`,
54670
+ message: `Pull into ${import_picocolors33.default.bold(cwd2)}?`,
53723
54671
  initialValue: true
53724
54672
  });
53725
54673
  if (!ensureNotCancelled(ok)) {
@@ -53728,7 +54676,7 @@ async function runOrchestrationPull(cwd2, args) {
53728
54676
  }
53729
54677
  }
53730
54678
  const fallbackHarness = args.harness ?? "claude-code";
53731
- fs49.mkdirSync(cwd2, { recursive: true });
54679
+ fs50.mkdirSync(cwd2, { recursive: true });
53732
54680
  if (hasOrchManifest(cwd2) && existingLink && existingLink.orchestration_id !== orchId) {
53733
54681
  f2.error(`This folder is linked to orchestration ${existingLink.orchestration_id}, not ${orchId}. Move to a fresh directory or unlink first.`);
53734
54682
  return;
@@ -53760,7 +54708,7 @@ async function runOrchestrationPull(cwd2, args) {
53760
54708
  scope: "project",
53761
54709
  pullSecrets: true
53762
54710
  });
53763
- memberSp.stop(`Installed ${import_picocolors31.default.bold(m3.slug)} ${import_picocolors31.default.dim(`(${m3.manifest.components.length} components)`)}.`);
54711
+ memberSp.stop(`Installed ${import_picocolors33.default.bold(m3.slug)} ${import_picocolors33.default.dim(`(${m3.manifest.components.length} components)`)}.`);
53764
54712
  installedMembers.push({
53765
54713
  agent_id: m3.agent_id,
53766
54714
  slug: m3.slug,
@@ -53815,7 +54763,7 @@ async function runOrchestrationPull(cwd2, args) {
53815
54763
  payload_schema: e2.payload_schema ?? {}
53816
54764
  }))
53817
54765
  });
53818
- $e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path52.basename(cwd2)}/ ${import_picocolors31.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
54766
+ $e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path54.basename(cwd2)}/ ${import_picocolors33.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
53819
54767
  }
53820
54768
  function handleApiError5(err) {
53821
54769
  if (err instanceof ApiError) {
@@ -53832,18 +54780,18 @@ function handleApiError5(err) {
53832
54780
  }
53833
54781
 
53834
54782
  // src/cli/orchestration-push.ts
53835
- var import_picocolors32 = __toESM(require_picocolors(), 1);
54783
+ var import_picocolors34 = __toESM(require_picocolors(), 1);
53836
54784
  async function runOrchestrationPush(cwd2, args) {
53837
54785
  banner("orchestration push — recursively push each member, then update the graph");
53838
54786
  const link2 = readOrchLink(cwd2);
53839
54787
  if (!link2) {
53840
54788
  f2.warn("This folder is not linked to any orchestration.");
53841
- f2.info(`Run ${import_picocolors32.default.cyan("brainbase orchestration pull <id>")} first.`);
54789
+ f2.info(`Run ${import_picocolors34.default.cyan("brainbase orchestration pull <id>")} first.`);
53842
54790
  return;
53843
54791
  }
53844
54792
  if (!hasOrchManifest(cwd2)) {
53845
- f2.warn(`No ${import_picocolors32.default.bold(ORCH_MANIFEST_FILE)} here.`);
53846
- f2.info(`Run ${import_picocolors32.default.cyan("brainbase orchestration pull")} to materialise the manifest before pushing.`);
54793
+ f2.warn(`No ${import_picocolors34.default.bold(ORCH_MANIFEST_FILE)} here.`);
54794
+ f2.info(`Run ${import_picocolors34.default.cyan("brainbase orchestration pull")} to materialise the manifest before pushing.`);
53847
54795
  return;
53848
54796
  }
53849
54797
  let manifest;
@@ -53856,15 +54804,15 @@ async function runOrchestrationPush(cwd2, args) {
53856
54804
  const memberSlugs = new Set(manifest.members.map((m3) => m3.slug));
53857
54805
  for (const e2 of manifest.edges) {
53858
54806
  if (!memberSlugs.has(e2.from)) {
53859
- f2.error(`Edge from "${import_picocolors32.default.bold(e2.from)}" references a slug that isn't in members.`);
54807
+ f2.error(`Edge from "${import_picocolors34.default.bold(e2.from)}" references a slug that isn't in members.`);
53860
54808
  return;
53861
54809
  }
53862
54810
  if (!memberSlugs.has(e2.to)) {
53863
- f2.error(`Edge to "${import_picocolors32.default.bold(e2.to)}" references a slug that isn't in members.`);
54811
+ f2.error(`Edge to "${import_picocolors34.default.bold(e2.to)}" references a slug that isn't in members.`);
53864
54812
  return;
53865
54813
  }
53866
54814
  if (e2.from === e2.to) {
53867
- f2.error(`Edge ${import_picocolors32.default.bold(e2.from)} → ${import_picocolors32.default.bold(e2.to)}: self-loops are not allowed.`);
54815
+ f2.error(`Edge ${import_picocolors34.default.bold(e2.from)} → ${import_picocolors34.default.bold(e2.to)}: self-loops are not allowed.`);
53868
54816
  return;
53869
54817
  }
53870
54818
  }
@@ -53881,17 +54829,17 @@ async function runOrchestrationPush(cwd2, args) {
53881
54829
  }
53882
54830
  if (missing.length) {
53883
54831
  f2.error(`These members have no local checkout (expected at agents/<slug>/.brainbase/link.json): ${missing.join(", ")}.`);
53884
- f2.info(`Run ${import_picocolors32.default.cyan("brainbase orchestration pull")} to materialise the missing folders.`);
54832
+ f2.info(`Run ${import_picocolors34.default.cyan("brainbase orchestration pull")} to materialise the missing folders.`);
53885
54833
  return;
53886
54834
  }
53887
54835
  const plan = [""];
53888
- plan.push(` ${import_picocolors32.default.bold(link2.name)} ${import_picocolors32.default.dim(`(${link2.orchestration_id})`)}`);
53889
- plan.push(` ${import_picocolors32.default.dim(`${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}`)}`);
54836
+ plan.push(` ${import_picocolors34.default.bold(link2.name)} ${import_picocolors34.default.dim(`(${link2.orchestration_id})`)}`);
54837
+ plan.push(` ${import_picocolors34.default.dim(`${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}`)}`);
53890
54838
  plan.push("");
53891
54839
  if (!args.graphOnly) {
53892
- plan.push(` ${import_picocolors32.default.dim("per-member agent push:")}`);
54840
+ plan.push(` ${import_picocolors34.default.dim("per-member agent push:")}`);
53893
54841
  for (const m3 of manifest.members) {
53894
- plan.push(` ${import_picocolors32.default.cyan("•")} ${import_picocolors32.default.bold(m3.slug)}`);
54842
+ plan.push(` ${import_picocolors34.default.cyan("•")} ${import_picocolors34.default.bold(m3.slug)}`);
53895
54843
  }
53896
54844
  plan.push("");
53897
54845
  }
@@ -53911,7 +54859,7 @@ async function runOrchestrationPush(cwd2, args) {
53911
54859
  for (const m3 of manifest.members) {
53912
54860
  const dir = memberDir(cwd2, m3.slug);
53913
54861
  console.log("");
53914
- console.log(`${import_picocolors32.default.dim("───")} ${import_picocolors32.default.bold(m3.slug)} ${import_picocolors32.default.dim("───")}`);
54862
+ console.log(`${import_picocolors34.default.dim("───")} ${import_picocolors34.default.bold(m3.slug)} ${import_picocolors34.default.dim("───")}`);
53915
54863
  try {
53916
54864
  await runAgentPush(dir, { yes: true });
53917
54865
  } catch (err) {
@@ -53973,7 +54921,7 @@ function handleApiError6(err) {
53973
54921
  f2.error("You do not have access to this orchestration.");
53974
54922
  } else if (err.status === 409) {
53975
54923
  f2.error(err.message);
53976
- f2.info(`Run ${import_picocolors32.default.cyan("brainbase orchestration pull")} to reconcile, then push again.`);
54924
+ f2.info(`Run ${import_picocolors34.default.cyan("brainbase orchestration pull")} to reconcile, then push again.`);
53977
54925
  } else {
53978
54926
  f2.error(err.message);
53979
54927
  }
@@ -53983,13 +54931,13 @@ function handleApiError6(err) {
53983
54931
  }
53984
54932
 
53985
54933
  // src/cli/orchestration-status.ts
53986
- var import_picocolors33 = __toESM(require_picocolors(), 1);
54934
+ var import_picocolors35 = __toESM(require_picocolors(), 1);
53987
54935
  async function runOrchestrationStatus(cwd2) {
53988
54936
  banner("orchestration status — what changed locally, remotely, both");
53989
54937
  const link2 = readOrchLink(cwd2);
53990
54938
  if (!link2) {
53991
54939
  f2.warn("This folder is not linked to any orchestration.");
53992
- f2.info(`Run ${import_picocolors33.default.cyan("brainbase orchestration pull <id>")} first.`);
54940
+ f2.info(`Run ${import_picocolors35.default.cyan("brainbase orchestration pull <id>")} first.`);
53993
54941
  return;
53994
54942
  }
53995
54943
  const localManifest = hasOrchManifest(cwd2) ? readOrchManifest(cwd2) : null;
@@ -54011,20 +54959,20 @@ async function runOrchestrationStatus(cwd2) {
54011
54959
  }
54012
54960
  const lines = [];
54013
54961
  lines.push("");
54014
- lines.push(` ${import_picocolors33.default.bold(link2.name)} ${import_picocolors33.default.dim(`(${link2.orchestration_id})`)}`);
54015
- lines.push(` ${import_picocolors33.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
54962
+ lines.push(` ${import_picocolors35.default.bold(link2.name)} ${import_picocolors35.default.dim(`(${link2.orchestration_id})`)}`);
54963
+ lines.push(` ${import_picocolors35.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
54016
54964
  lines.push("");
54017
54965
  const cloudMemberSet = new Set(cloud.members.map((m3) => m3.slug));
54018
54966
  const localMemberSet = new Set((localManifest?.members ?? []).map((m3) => m3.slug));
54019
54967
  const membersAdded = [...localMemberSet].filter((s3) => !cloudMemberSet.has(s3));
54020
54968
  const membersRemoved = [...cloudMemberSet].filter((s3) => !localMemberSet.has(s3));
54021
54969
  if (membersAdded.length || membersRemoved.length) {
54022
- lines.push(` ${import_picocolors33.default.bold("members")}`);
54970
+ lines.push(` ${import_picocolors35.default.bold("members")}`);
54023
54971
  for (const slug of membersAdded) {
54024
- lines.push(` ${import_picocolors33.default.yellow("→ push")} added in yaml: ${import_picocolors33.default.bold(slug)}`);
54972
+ lines.push(` ${import_picocolors35.default.yellow("→ push")} added in yaml: ${import_picocolors35.default.bold(slug)}`);
54025
54973
  }
54026
54974
  for (const slug of membersRemoved) {
54027
- lines.push(` ${import_picocolors33.default.cyan("← pull")} added on cloud: ${import_picocolors33.default.bold(slug)}`);
54975
+ lines.push(` ${import_picocolors35.default.cyan("← pull")} added on cloud: ${import_picocolors35.default.bold(slug)}`);
54028
54976
  }
54029
54977
  lines.push("");
54030
54978
  }
@@ -54039,11 +54987,11 @@ async function runOrchestrationStatus(cwd2) {
54039
54987
  const edgesAdded = [...localEdges.keys()].filter((k3) => !cloudEdges.has(k3));
54040
54988
  const edgesRemoved = [...cloudEdges.keys()].filter((k3) => !localEdges.has(k3));
54041
54989
  if (edgesAdded.length || edgesRemoved.length) {
54042
- lines.push(` ${import_picocolors33.default.bold("edges")}`);
54990
+ lines.push(` ${import_picocolors35.default.bold("edges")}`);
54043
54991
  for (const k3 of edgesAdded)
54044
- lines.push(` ${import_picocolors33.default.yellow("→ push")} added in yaml: ${k3}`);
54992
+ lines.push(` ${import_picocolors35.default.yellow("→ push")} added in yaml: ${k3}`);
54045
54993
  for (const k3 of edgesRemoved)
54046
- lines.push(` ${import_picocolors33.default.cyan("← pull")} added on cloud: ${k3}`);
54994
+ lines.push(` ${import_picocolors35.default.cyan("← pull")} added on cloud: ${k3}`);
54047
54995
  lines.push("");
54048
54996
  }
54049
54997
  const lockByAgentId = new Map((lock?.members ?? []).map((m3) => [m3.agent_id, m3]));
@@ -54065,28 +55013,28 @@ async function runOrchestrationStatus(cwd2) {
54065
55013
  }
54066
55014
  }
54067
55015
  if (memberDrift.length) {
54068
- lines.push(` ${import_picocolors33.default.bold("member content drift")}`);
55016
+ lines.push(` ${import_picocolors35.default.bold("member content drift")}`);
54069
55017
  for (const d3 of memberDrift) {
54070
- lines.push(` ${import_picocolors33.default.cyan("?")} ${import_picocolors33.default.bold(d3.slug)} ${import_picocolors33.default.dim("— " + d3.reason)}`);
55018
+ lines.push(` ${import_picocolors35.default.cyan("?")} ${import_picocolors35.default.bold(d3.slug)} ${import_picocolors35.default.dim("— " + d3.reason)}`);
54071
55019
  }
54072
- lines.push(` ${import_picocolors33.default.dim("cd into each member folder and run")} ${import_picocolors33.default.cyan("brainbase agent status")}`);
55020
+ lines.push(` ${import_picocolors35.default.dim("cd into each member folder and run")} ${import_picocolors35.default.cyan("brainbase agent status")}`);
54073
55021
  lines.push("");
54074
55022
  }
54075
55023
  if (!membersAdded.length && !membersRemoved.length && !edgesAdded.length && !edgesRemoved.length && !memberDrift.length) {
54076
- lines.push(` ${import_picocolors33.default.green("✓")} everything is in sync`);
55024
+ lines.push(` ${import_picocolors35.default.green("✓")} everything is in sync`);
54077
55025
  lines.push("");
54078
55026
  console.log(lines.join(`
54079
55027
  `));
54080
55028
  return;
54081
55029
  }
54082
- 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")}`);
55030
+ 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")}`);
54083
55031
  lines.push("");
54084
55032
  console.log(lines.join(`
54085
55033
  `));
54086
55034
  }
54087
55035
 
54088
55036
  // src/cli/orchestration-list.ts
54089
- var import_picocolors34 = __toESM(require_picocolors(), 1);
55037
+ var import_picocolors36 = __toESM(require_picocolors(), 1);
54090
55038
  async function runOrchestrationList(args) {
54091
55039
  banner("orchestration list — orchestrations under a team");
54092
55040
  let orgId = args.orgId;
@@ -54152,13 +55100,13 @@ async function runOrchestrationList(args) {
54152
55100
  }
54153
55101
  const lines = [""];
54154
55102
  for (const o2 of items) {
54155
- lines.push(` ${import_picocolors34.default.bold(o2.name)} ${import_picocolors34.default.dim(o2.id)}`);
55103
+ lines.push(` ${import_picocolors36.default.bold(o2.name)} ${import_picocolors36.default.dim(o2.id)}`);
54156
55104
  if (o2.description)
54157
- lines.push(` ${import_picocolors34.default.dim(o2.description)}`);
54158
- lines.push(` ${import_picocolors34.default.dim(`${o2.member_count} member${o2.member_count === 1 ? "" : "s"} · ${o2.edge_count} edge${o2.edge_count === 1 ? "" : "s"}`)}`);
55105
+ lines.push(` ${import_picocolors36.default.dim(o2.description)}`);
55106
+ lines.push(` ${import_picocolors36.default.dim(`${o2.member_count} member${o2.member_count === 1 ? "" : "s"} · ${o2.edge_count} edge${o2.edge_count === 1 ? "" : "s"}`)}`);
54159
55107
  lines.push("");
54160
55108
  }
54161
- lines.push(` ${import_picocolors34.default.dim("pull one with")} ${import_picocolors34.default.cyan("brainbase orchestration pull <id>")}`);
55109
+ lines.push(` ${import_picocolors36.default.dim("pull one with")} ${import_picocolors36.default.cyan("brainbase orchestration pull <id>")}`);
54162
55110
  lines.push("");
54163
55111
  console.log(lines.join(`
54164
55112
  `));
@@ -54214,26 +55162,26 @@ async function runOrchestration(cwd2, sub, args, opts) {
54214
55162
  function printHelp2() {
54215
55163
  const out = [];
54216
55164
  out.push("");
54217
- out.push(` ${import_picocolors35.default.bold("brainbase orchestration")} ${import_picocolors35.default.dim("<sub> [options]")}`);
55165
+ out.push(` ${import_picocolors37.default.bold("brainbase orchestration")} ${import_picocolors37.default.dim("<sub> [options]")}`);
54218
55166
  out.push("");
54219
- out.push(` ${import_picocolors35.default.cyan("pull")} ${import_picocolors35.default.dim("<id>")} ${import_picocolors35.default.dim("fetch orchestration + every member agent into this folder")}`);
54220
- out.push(` ${import_picocolors35.default.cyan("push")} ${import_picocolors35.default.dim("push each member, then update the orchestration graph")}`);
54221
- out.push(` ${import_picocolors35.default.cyan("status")} ${import_picocolors35.default.dim("show what would push and what would pull")}`);
54222
- out.push(` ${import_picocolors35.default.cyan("list")} ${import_picocolors35.default.dim("list orchestrations under a team")}`);
55167
+ out.push(` ${import_picocolors37.default.cyan("pull")} ${import_picocolors37.default.dim("<id>")} ${import_picocolors37.default.dim("fetch orchestration + every member agent into this folder")}`);
55168
+ out.push(` ${import_picocolors37.default.cyan("push")} ${import_picocolors37.default.dim("push each member, then update the orchestration graph")}`);
55169
+ out.push(` ${import_picocolors37.default.cyan("status")} ${import_picocolors37.default.dim("show what would push and what would pull")}`);
55170
+ out.push(` ${import_picocolors37.default.cyan("list")} ${import_picocolors37.default.dim("list orchestrations under a team")}`);
54223
55171
  out.push("");
54224
- out.push(` ${import_picocolors35.default.bold("Flags")}`);
54225
- out.push(` ${import_picocolors35.default.dim("--yes, -y")} skip confirmations`);
54226
- out.push(` ${import_picocolors35.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
54227
- out.push(` ${import_picocolors35.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`);
54228
- out.push(` ${import_picocolors35.default.dim("--org <id>")} for list: org id (CLI vocab — DB teams.id)`);
54229
- out.push(` ${import_picocolors35.default.dim("--team <id>")} for list: team id (CLI vocab — DB groups.id)`);
55172
+ out.push(` ${import_picocolors37.default.bold("Flags")}`);
55173
+ out.push(` ${import_picocolors37.default.dim("--yes, -y")} skip confirmations`);
55174
+ out.push(` ${import_picocolors37.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
55175
+ out.push(` ${import_picocolors37.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`);
55176
+ out.push(` ${import_picocolors37.default.dim("--org <id>")} for list: org id (CLI vocab — DB teams.id)`);
55177
+ out.push(` ${import_picocolors37.default.dim("--team <id>")} for list: team id (CLI vocab — DB groups.id)`);
54230
55178
  out.push("");
54231
55179
  console.log(out.join(`
54232
55180
  `));
54233
55181
  }
54234
55182
 
54235
55183
  // src/cli/run.ts
54236
- import { spawn as spawn2 } from "node:child_process";
55184
+ import { spawn as spawn3 } from "node:child_process";
54237
55185
  async function runRun(cwd2, args) {
54238
55186
  const cleaned = args[0] === "--" ? args.slice(1) : args;
54239
55187
  if (cleaned.length === 0) {
@@ -54245,7 +55193,7 @@ async function runRun(cwd2, args) {
54245
55193
  const [cmd, ...cmdArgs] = cleaned;
54246
55194
  const secrets = readLocalSecrets(cwd2);
54247
55195
  const env3 = { ...process.env, ...secrets };
54248
- const child = spawn2(cmd, cmdArgs, {
55196
+ const child = spawn3(cmd, cmdArgs, {
54249
55197
  cwd: cwd2,
54250
55198
  env: env3,
54251
55199
  stdio: "inherit",
@@ -54271,16 +55219,16 @@ async function runRun(cwd2, args) {
54271
55219
  }
54272
55220
 
54273
55221
  // src/cli/publish.ts
54274
- var import_picocolors36 = __toESM(require_picocolors(), 1);
55222
+ var import_picocolors38 = __toESM(require_picocolors(), 1);
54275
55223
  async function runPublish(cwd2, _args) {
54276
55224
  banner("publish — send your changes to the team");
54277
55225
  const link2 = readLink(cwd2);
54278
55226
  if (!link2) {
54279
55227
  f2.warn("This folder is not linked to any agent.");
54280
- f2.info(`Run ${import_picocolors36.default.cyan("brainbase link")} first.`);
55228
+ f2.info(`Run ${import_picocolors38.default.cyan("brainbase link")} first.`);
54281
55229
  return;
54282
55230
  }
54283
- 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.`);
55231
+ 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.`);
54284
55232
  }
54285
55233
 
54286
55234
  // src/ui/ink/StatusCard.tsx
@@ -54578,7 +55526,7 @@ async function runStatus(cwd2) {
54578
55526
  }
54579
55527
 
54580
55528
  // src/cli/token.ts
54581
- var import_picocolors37 = __toESM(require_picocolors(), 1);
55529
+ var import_picocolors39 = __toESM(require_picocolors(), 1);
54582
55530
 
54583
55531
  // src/ui/ink/TokenCards.tsx
54584
55532
  var jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
@@ -54872,7 +55820,7 @@ async function runTokenRevoke(args) {
54872
55820
  }
54873
55821
  if (!args.yes) {
54874
55822
  const ok = await se({
54875
- message: `Revoke token ${import_picocolors37.default.bold(args.id)}? CIs and machines using it will stop working.`,
55823
+ message: `Revoke token ${import_picocolors39.default.bold(args.id)}? CIs and machines using it will stop working.`,
54876
55824
  initialValue: false
54877
55825
  });
54878
55826
  if (!ensureNotCancelled(ok))
@@ -54887,7 +55835,7 @@ async function runTokenRevoke(args) {
54887
55835
  }
54888
55836
  async function runTokenClear() {
54889
55837
  if (!readToken()) {
54890
- console.log(import_picocolors37.default.dim("No local token stored."));
55838
+ console.log(import_picocolors39.default.dim("No local token stored."));
54891
55839
  return;
54892
55840
  }
54893
55841
  clearToken();
@@ -54938,17 +55886,17 @@ async function runToken(sub, rest, args) {
54938
55886
  function printTokenHelp() {
54939
55887
  const out = [];
54940
55888
  out.push("");
54941
- out.push(` ${import_picocolors37.default.bold("brainbase token")} ${import_picocolors37.default.dim("<command>")}`);
55889
+ out.push(` ${import_picocolors39.default.bold("brainbase token")} ${import_picocolors39.default.dim("<command>")}`);
54942
55890
  out.push("");
54943
- out.push(` ${import_picocolors37.default.cyan("create")} ${import_picocolors37.default.dim("issue a new long-lived CLI key (PAT)")}`);
54944
- out.push(` ${import_picocolors37.default.cyan("list")} ${import_picocolors37.default.dim("show your active tokens")}`);
54945
- out.push(` ${import_picocolors37.default.cyan("revoke")} ${import_picocolors37.default.dim("<id>")} ${import_picocolors37.default.dim("revoke a token by id")}`);
54946
- out.push(` ${import_picocolors37.default.cyan("clear")} ${import_picocolors37.default.dim("forget the local token (does not revoke)")}`);
55891
+ out.push(` ${import_picocolors39.default.cyan("create")} ${import_picocolors39.default.dim("issue a new long-lived CLI key (PAT)")}`);
55892
+ out.push(` ${import_picocolors39.default.cyan("list")} ${import_picocolors39.default.dim("show your active tokens")}`);
55893
+ out.push(` ${import_picocolors39.default.cyan("revoke")} ${import_picocolors39.default.dim("<id>")} ${import_picocolors39.default.dim("revoke a token by id")}`);
55894
+ out.push(` ${import_picocolors39.default.cyan("clear")} ${import_picocolors39.default.dim("forget the local token (does not revoke)")}`);
54947
55895
  out.push("");
54948
- out.push(` ${import_picocolors37.default.bold("create flags")}`);
54949
- out.push(` ${import_picocolors37.default.cyan("--name, -n")} ${import_picocolors37.default.dim("<label>")} ${import_picocolors37.default.dim("token label (prompted if omitted)")}`);
54950
- out.push(` ${import_picocolors37.default.cyan("--scopes")} ${import_picocolors37.default.dim("<list>")} ${import_picocolors37.default.dim("comma-separated; allowed: read, publish, admin")}`);
54951
- out.push(` ${import_picocolors37.default.dim("default: read,publish")}`);
55896
+ out.push(` ${import_picocolors39.default.bold("create flags")}`);
55897
+ out.push(` ${import_picocolors39.default.cyan("--name, -n")} ${import_picocolors39.default.dim("<label>")} ${import_picocolors39.default.dim("token label (prompted if omitted)")}`);
55898
+ out.push(` ${import_picocolors39.default.cyan("--scopes")} ${import_picocolors39.default.dim("<list>")} ${import_picocolors39.default.dim("comma-separated; allowed: read, publish, admin")}`);
55899
+ out.push(` ${import_picocolors39.default.dim("default: read,publish")}`);
54952
55900
  out.push("");
54953
55901
  console.log(out.join(`
54954
55902
  `));
@@ -54968,89 +55916,90 @@ var PROTECTED = new Set([
54968
55916
  function help() {
54969
55917
  const out = [];
54970
55918
  out.push("");
54971
- out.push(` ${brandTint("◆")} ${import_picocolors38.default.bold("brainbase")} ${import_picocolors38.default.dim("v0.2.0")}`);
54972
- out.push(` ${import_picocolors38.default.dim("connect your local agent to the brainbase platform")}`);
55919
+ out.push(` ${brandTint("◆")} ${import_picocolors40.default.bold("brainbase")} ${import_picocolors40.default.dim("v0.6.0")}`);
55920
+ out.push(` ${import_picocolors40.default.dim("connect your local agent to the brainbase platform")}`);
54973
55921
  out.push("");
54974
55922
  out.push(divider("USAGE"));
54975
55923
  out.push("");
54976
- out.push(` ${import_picocolors38.default.bold("brainbase")} ${import_picocolors38.default.dim("<command> [options]")}`);
55924
+ out.push(` ${import_picocolors40.default.bold("brainbase")} ${import_picocolors40.default.dim("<command> [options]")}`);
54977
55925
  out.push("");
54978
55926
  out.push(divider("AUTH"));
54979
55927
  out.push("");
54980
- out.push(` ${import_picocolors38.default.cyan("login")} ${import_picocolors38.default.dim(" open the web app and connect this device")}`);
54981
- out.push(` ${import_picocolors38.default.cyan("logout")} ${import_picocolors38.default.dim(" clear the local session")}`);
54982
- out.push(` ${import_picocolors38.default.cyan("whoami")} ${import_picocolors38.default.dim(" show the current user")}`);
55928
+ out.push(` ${import_picocolors40.default.cyan("login")} ${import_picocolors40.default.dim(" open the web app and connect this device")}`);
55929
+ out.push(` ${import_picocolors40.default.cyan("logout")} ${import_picocolors40.default.dim(" clear the local session")}`);
55930
+ out.push(` ${import_picocolors40.default.cyan("whoami")} ${import_picocolors40.default.dim(" show the current user")}`);
54983
55931
  out.push("");
54984
55932
  out.push(divider("LINKED AGENT"));
54985
55933
  out.push("");
54986
- out.push(` ${import_picocolors38.default.cyan("agent create")} ${import_picocolors38.default.dim("make a new agent on the cloud and link this folder")}`);
54987
- out.push(` ${import_picocolors38.default.cyan("link")} ${import_picocolors38.default.dim("attach this folder to an existing agent")}`);
54988
- out.push(` ${import_picocolors38.default.cyan("agent pull")} ${import_picocolors38.default.dim("bring cloud changes into this folder")}`);
54989
- out.push(` ${import_picocolors38.default.cyan("agent push")} ${import_picocolors38.default.dim("send local changes to the cloud")}`);
54990
- out.push(` ${import_picocolors38.default.cyan("agent status")} ${import_picocolors38.default.dim("show what would pull and what would push")}`);
54991
- out.push(` ${import_picocolors38.default.cyan("agent env")} ${import_picocolors38.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
54992
- 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")}`);
54993
- out.push(` ${import_picocolors38.default.cyan("status")} ${import_picocolors38.default.dim("show what this folder is linked to")}`);
54994
- out.push(` ${import_picocolors38.default.cyan("unlink")} ${import_picocolors38.default.dim("disconnect this folder")}`);
55934
+ out.push(` ${import_picocolors40.default.cyan("agent create")} ${import_picocolors40.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
55935
+ 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)")}`);
55936
+ out.push(` ${import_picocolors40.default.cyan("agent push")} ${import_picocolors40.default.dim("send local changes to the cloud")}`);
55937
+ out.push(` ${import_picocolors40.default.cyan("agent unpack")} ${import_picocolors40.default.dim("install the claimed agent into a harness layout")}`);
55938
+ out.push(` ${import_picocolors40.default.cyan("link")} ${import_picocolors40.default.dim("attach this folder to an existing agent")}`);
55939
+ out.push(` ${import_picocolors40.default.cyan("agent status")} ${import_picocolors40.default.dim("show what would pull and what would push")}`);
55940
+ out.push(` ${import_picocolors40.default.cyan("agent env")} ${import_picocolors40.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
55941
+ 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")}`);
55942
+ out.push(` ${import_picocolors40.default.cyan("status")} ${import_picocolors40.default.dim("show what this folder is linked to")}`);
55943
+ out.push(` ${import_picocolors40.default.cyan("unlink")} ${import_picocolors40.default.dim("disconnect this folder")}`);
54995
55944
  out.push("");
54996
55945
  out.push(divider("ORCHESTRATIONS"));
54997
55946
  out.push("");
54998
- out.push(` ${import_picocolors38.default.cyan("orchestration list")} ${import_picocolors38.default.dim("list orchestrations under a team")}`);
54999
- out.push(` ${import_picocolors38.default.cyan("orchestration pull")} ${import_picocolors38.default.dim("<id>")} ${import_picocolors38.default.dim("recursively fetch an orchestration + every member agent")}`);
55000
- out.push(` ${import_picocolors38.default.cyan("orchestration push")} ${import_picocolors38.default.dim("recursively push each member, then update the graph")}`);
55001
- out.push(` ${import_picocolors38.default.cyan("orchestration status")} ${import_picocolors38.default.dim("show what would push and what would pull")}`);
55947
+ out.push(` ${import_picocolors40.default.cyan("orchestration list")} ${import_picocolors40.default.dim("list orchestrations under a team")}`);
55948
+ out.push(` ${import_picocolors40.default.cyan("orchestration pull")} ${import_picocolors40.default.dim("<id>")} ${import_picocolors40.default.dim("recursively fetch an orchestration + every member agent")}`);
55949
+ out.push(` ${import_picocolors40.default.cyan("orchestration push")} ${import_picocolors40.default.dim("recursively push each member, then update the graph")}`);
55950
+ out.push(` ${import_picocolors40.default.cyan("orchestration status")} ${import_picocolors40.default.dim("show what would push and what would pull")}`);
55002
55951
  out.push("");
55003
55952
  out.push(divider("TEMPLATES"));
55004
55953
  out.push("");
55005
- out.push(` ${import_picocolors38.default.cyan("template pack")} ${import_picocolors38.default.dim("bundle the current agent into a template")}`);
55006
- out.push(` ${import_picocolors38.default.cyan("template publish")} ${import_picocolors38.default.dim("upload a template to the registry")}`);
55007
- out.push(` ${import_picocolors38.default.cyan("template search")} ${import_picocolors38.default.dim("[query]")} ${import_picocolors38.default.dim("search the registry")}`);
55008
- out.push(` ${import_picocolors38.default.cyan("template info")} ${import_picocolors38.default.dim("<creator/slug>")} ${import_picocolors38.default.dim("show registry details for a template")}`);
55009
- out.push(` ${import_picocolors38.default.cyan("template onboard")} ${import_picocolors38.default.dim("<creator/slug>")} ${import_picocolors38.default.dim("install (or refresh) a template")}`);
55010
- out.push(` ${import_picocolors38.default.cyan("template list")} ${import_picocolors38.default.dim("show installed templates")}`);
55011
- out.push(` ${import_picocolors38.default.cyan("template remove")} ${import_picocolors38.default.dim("<creator/slug>")} ${import_picocolors38.default.dim("uninstall a template")}`);
55954
+ out.push(` ${import_picocolors40.default.cyan("template pack")} ${import_picocolors40.default.dim("bundle the current agent into a template")}`);
55955
+ out.push(` ${import_picocolors40.default.cyan("template publish")} ${import_picocolors40.default.dim("upload a template to the registry")}`);
55956
+ out.push(` ${import_picocolors40.default.cyan("template search")} ${import_picocolors40.default.dim("[query]")} ${import_picocolors40.default.dim("search the registry")}`);
55957
+ out.push(` ${import_picocolors40.default.cyan("template info")} ${import_picocolors40.default.dim("<creator/slug>")} ${import_picocolors40.default.dim("show registry details for a template")}`);
55958
+ out.push(` ${import_picocolors40.default.cyan("template onboard")} ${import_picocolors40.default.dim("<creator/slug>")} ${import_picocolors40.default.dim("install (or refresh) a template")}`);
55959
+ out.push(` ${import_picocolors40.default.cyan("template list")} ${import_picocolors40.default.dim("show installed templates")}`);
55960
+ out.push(` ${import_picocolors40.default.cyan("template remove")} ${import_picocolors40.default.dim("<creator/slug>")} ${import_picocolors40.default.dim("uninstall a template")}`);
55012
55961
  out.push("");
55013
55962
  out.push(divider("SKILLS"));
55014
55963
  out.push("");
55015
- out.push(` ${import_picocolors38.default.cyan("skill add")} ${import_picocolors38.default.dim("<source>")} ${import_picocolors38.default.dim("install a skill (github / git / brainbase)")}`);
55016
- out.push(` ${import_picocolors38.default.cyan("skill list")} ${import_picocolors38.default.dim("show locally installed skills + their source")}`);
55017
- 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")}`);
55018
- out.push(` ${import_picocolors38.default.cyan("skill remove")} ${import_picocolors38.default.dim("<slug>")} ${import_picocolors38.default.dim("uninstall a skill")}`);
55019
- out.push(` ${import_picocolors38.default.cyan("skill search")} ${import_picocolors38.default.dim("[query]")} ${import_picocolors38.default.dim("search the brainbase skill registry")}`);
55020
- out.push(` ${import_picocolors38.default.cyan("skill info")} ${import_picocolors38.default.dim("<creator/slug>")} ${import_picocolors38.default.dim("show registry details for a skill")}`);
55021
- out.push(` ${import_picocolors38.default.cyan("skill publish")} ${import_picocolors38.default.dim("[dir]")} ${import_picocolors38.default.dim("publish a SKILL.md folder (defaults to .)")}`);
55964
+ out.push(` ${import_picocolors40.default.cyan("skill add")} ${import_picocolors40.default.dim("<source>")} ${import_picocolors40.default.dim("install a skill (github / git / brainbase)")}`);
55965
+ out.push(` ${import_picocolors40.default.cyan("skill list")} ${import_picocolors40.default.dim("show locally installed skills + their source")}`);
55966
+ 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")}`);
55967
+ out.push(` ${import_picocolors40.default.cyan("skill remove")} ${import_picocolors40.default.dim("<slug>")} ${import_picocolors40.default.dim("uninstall a skill")}`);
55968
+ out.push(` ${import_picocolors40.default.cyan("skill search")} ${import_picocolors40.default.dim("[query]")} ${import_picocolors40.default.dim("search the brainbase skill registry")}`);
55969
+ out.push(` ${import_picocolors40.default.cyan("skill info")} ${import_picocolors40.default.dim("<creator/slug>")} ${import_picocolors40.default.dim("show registry details for a skill")}`);
55970
+ out.push(` ${import_picocolors40.default.cyan("skill publish")} ${import_picocolors40.default.dim("[dir]")} ${import_picocolors40.default.dim("publish a SKILL.md folder (defaults to .)")}`);
55022
55971
  out.push("");
55023
55972
  out.push(divider("CLI TOKENS"));
55024
55973
  out.push("");
55025
- out.push(` ${import_picocolors38.default.cyan("token create")} ${import_picocolors38.default.dim("issue a long-lived CLI key for CI / scripts")}`);
55026
- out.push(` ${import_picocolors38.default.cyan("token list")} ${import_picocolors38.default.dim("show your active tokens")}`);
55027
- out.push(` ${import_picocolors38.default.cyan("token revoke")} ${import_picocolors38.default.dim("<id>")} ${import_picocolors38.default.dim("revoke a token")}`);
55974
+ out.push(` ${import_picocolors40.default.cyan("token create")} ${import_picocolors40.default.dim("issue a long-lived CLI key for CI / scripts")}`);
55975
+ out.push(` ${import_picocolors40.default.cyan("token list")} ${import_picocolors40.default.dim("show your active tokens")}`);
55976
+ out.push(` ${import_picocolors40.default.cyan("token revoke")} ${import_picocolors40.default.dim("<id>")} ${import_picocolors40.default.dim("revoke a token")}`);
55028
55977
  out.push("");
55029
55978
  out.push(divider("FLAGS"));
55030
55979
  out.push("");
55031
- out.push(` ${import_picocolors38.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
55032
- out.push(` ${import_picocolors38.default.dim("--scope <s>")} force scope: global | project`);
55033
- out.push(` ${import_picocolors38.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
55034
- out.push(` ${import_picocolors38.default.dim("--agent <id>")} for link: attach this folder to an existing agent non-interactively`);
55035
- out.push(` ${import_picocolors38.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
55036
- out.push(` ${import_picocolors38.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
55037
- out.push(` ${import_picocolors38.default.dim("--all")} for template list: include installs from other folders`);
55038
- out.push(` ${import_picocolors38.default.dim("--web <url>")} for login: web app URL (default https://new.usekafka.com)`);
55980
+ out.push(` ${import_picocolors40.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
55981
+ out.push(` ${import_picocolors40.default.dim("--scope <s>")} force scope: global | project`);
55982
+ out.push(` ${import_picocolors40.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
55983
+ out.push(` ${import_picocolors40.default.dim("--agent <id>")} for link: attach this folder to an existing agent non-interactively`);
55984
+ out.push(` ${import_picocolors40.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
55985
+ out.push(` ${import_picocolors40.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
55986
+ out.push(` ${import_picocolors40.default.dim("--all")} for template list: include installs from other folders`);
55987
+ out.push(` ${import_picocolors40.default.dim("--web <url>")} for login: web app URL (default https://new.usekafka.com)`);
55039
55988
  out.push("");
55040
55989
  out.push(divider("ENV"));
55041
55990
  out.push("");
55042
- out.push(` ${import_picocolors38.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
55043
- out.push(` ${import_picocolors38.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
55044
- out.push(` ${import_picocolors38.default.dim("BRAINBASE_API_URL")} override the API URL used by link / sync`);
55045
- out.push(` ${import_picocolors38.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL`);
55046
- out.push(` ${import_picocolors38.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
55047
- out.push(` ${import_picocolors38.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
55991
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
55992
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
55993
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_API_URL")} override the API URL used by link / sync`);
55994
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL`);
55995
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
55996
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
55048
55997
  out.push("");
55049
55998
  out.push(divider("HARNESSES"));
55050
55999
  out.push("");
55051
- out.push(` ${import_picocolors38.default.dim("•")} ${import_picocolors38.default.bold("claude-code")} ${import_picocolors38.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
55052
- out.push(` ${import_picocolors38.default.dim("•")} ${import_picocolors38.default.bold("codex")} ${import_picocolors38.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
55053
- out.push(` ${import_picocolors38.default.dim("•")} ${import_picocolors38.default.bold("kafka")} ${import_picocolors38.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
56000
+ out.push(` ${import_picocolors40.default.dim("•")} ${import_picocolors40.default.bold("claude-code")} ${import_picocolors40.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
56001
+ out.push(` ${import_picocolors40.default.dim("•")} ${import_picocolors40.default.bold("codex")} ${import_picocolors40.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
56002
+ out.push(` ${import_picocolors40.default.dim("•")} ${import_picocolors40.default.bold("kafka")} ${import_picocolors40.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
55054
56003
  out.push("");
55055
56004
  console.log(out.join(`
55056
56005
  `));
@@ -55094,13 +56043,13 @@ async function requireAuth(cmd) {
55094
56043
  if (status.ok)
55095
56044
  return;
55096
56045
  console.error("");
55097
- console.error(` ${brandTint("◆")} ${import_picocolors38.default.bold("brainbase")}`);
56046
+ console.error(` ${brandTint("◆")} ${import_picocolors40.default.bold("brainbase")}`);
55098
56047
  console.error("");
55099
- console.error(` ${import_picocolors38.default.red("✗")} You need to sign in to use ${import_picocolors38.default.bold("brainbase " + cmd)}.`);
56048
+ console.error(` ${import_picocolors40.default.red("✗")} You need to sign in to use ${import_picocolors40.default.bold("brainbase " + cmd)}.`);
55100
56049
  if (status.reason)
55101
- console.error(` ${import_picocolors38.default.dim(status.reason)}`);
56050
+ console.error(` ${import_picocolors40.default.dim(status.reason)}`);
55102
56051
  console.error("");
55103
- console.error(` Run ${import_picocolors38.default.cyan("brainbase login")} to connect this device.`);
56052
+ console.error(` Run ${import_picocolors40.default.cyan("brainbase login")} to connect this device.`);
55104
56053
  console.error("");
55105
56054
  process13.exit(1);
55106
56055
  }
@@ -55110,7 +56059,7 @@ async function main() {
55110
56059
  const rawCwd = process13.cwd();
55111
56060
  const cwd2 = (() => {
55112
56061
  try {
55113
- return fs50.realpathSync(rawCwd);
56062
+ return fs51.realpathSync(rawCwd);
55114
56063
  } catch {
55115
56064
  return rawCwd;
55116
56065
  }
@@ -55137,6 +56086,7 @@ async function main() {
55137
56086
  const agentFlag = getFlag(argv, "--agent");
55138
56087
  const shellFlag = getFlag(argv, "--shell");
55139
56088
  const noTracking = hasFlag2(argv, "--no-tracking");
56089
+ const forceFlag = hasFlag2(argv, "--force");
55140
56090
  const graphOnlyFlag = hasFlag2(argv, "--graph-only");
55141
56091
  const nameFlag = getFlag(argv, "--name");
55142
56092
  const skillVersionFlag = getFlag(argv, "--skill-version");
@@ -55221,7 +56171,8 @@ async function main() {
55221
56171
  tagline: taglineFlag,
55222
56172
  orgId: orgIdFlag,
55223
56173
  teamId: teamIdFlag,
55224
- noTracking
56174
+ noTracking,
56175
+ force: forceFlag
55225
56176
  });
55226
56177
  break;
55227
56178
  }
@@ -55252,7 +56203,7 @@ async function main() {
55252
56203
  process13.exit(1);
55253
56204
  }
55254
56205
  } catch (err) {
55255
- console.error(import_picocolors38.default.red(`
56206
+ console.error(import_picocolors40.default.red(`
55256
56207
  ${err.message}`));
55257
56208
  if (process13.env.BRAINBASE_DEBUG)
55258
56209
  console.error(err.stack);