@brainbase-labs/cli 0.13.1 → 0.13.2

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 +77 -51
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -29449,7 +29449,7 @@ function padStart(s, n) {
29449
29449
  // package.json
29450
29450
  var package_default = {
29451
29451
  name: "@brainbase-labs/cli",
29452
- version: "0.13.1",
29452
+ version: "0.13.2",
29453
29453
  description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
29454
29454
  type: "module",
29455
29455
  bin: {
@@ -51336,6 +51336,23 @@ function backfillPlaybookIds(playbooks, cloudComponents) {
51336
51336
  });
51337
51337
  return { playbooks: changed ? next : playbooks, changed };
51338
51338
  }
51339
+ function stripPlaybookFrontmatter(raw) {
51340
+ const m3 = /^---\s*\n([\s\S]*?)\n---[ \t]*(?:\n|$)/.exec(raw);
51341
+ if (!m3)
51342
+ return { frontmatter: {}, body: raw };
51343
+ let fm = {};
51344
+ try {
51345
+ const parsed = import_yaml2.default.parse(m3[1] ?? "");
51346
+ if (parsed && typeof parsed === "object")
51347
+ fm = parsed;
51348
+ } catch {
51349
+ return { frontmatter: {}, body: raw };
51350
+ }
51351
+ return { frontmatter: fm, body: raw.slice(m3[0].length).replace(/^\n+/, "") };
51352
+ }
51353
+ function normalizeInstructionBody(body) {
51354
+ return body.trim();
51355
+ }
51339
51356
 
51340
51357
  // src/core/link.ts
51341
51358
  var LINK_DIR = ".brainbase";
@@ -52549,7 +52566,6 @@ import path48 from "node:path";
52549
52566
  import fs45 from "node:fs";
52550
52567
  import os12 from "node:os";
52551
52568
  var import_picocolors25 = __toESM(require_picocolors(), 1);
52552
- var import_yaml3 = __toESM(require_dist(), 1);
52553
52569
 
52554
52570
  // src/core/agent-diff.ts
52555
52571
  import path46 from "node:path";
@@ -52561,6 +52577,9 @@ function compKey(type, slug) {
52561
52577
  function hashString(s3) {
52562
52578
  return crypto4.createHash("sha256").update(s3).digest("hex");
52563
52579
  }
52580
+ function jsonStringAsciiSafe(s3) {
52581
+ return JSON.stringify(s3).replace(/[\u007f-\uffff]/g, (c2) => "\\u" + c2.charCodeAt(0).toString(16).padStart(4, "0"));
52582
+ }
52564
52583
  function canonicalJson(value) {
52565
52584
  if (value === null)
52566
52585
  return "null";
@@ -52572,14 +52591,14 @@ function canonicalJson(value) {
52572
52591
  return String(value);
52573
52592
  }
52574
52593
  if (typeof value === "string")
52575
- return JSON.stringify(value);
52594
+ return jsonStringAsciiSafe(value);
52576
52595
  if (Array.isArray(value)) {
52577
52596
  return "[" + value.map(canonicalJson).join(",") + "]";
52578
52597
  }
52579
52598
  if (typeof value === "object") {
52580
52599
  const obj = value;
52581
52600
  const keys2 = Object.keys(obj).sort();
52582
- return "{" + keys2.map((k3) => `${JSON.stringify(k3)}:${canonicalJson(obj[k3])}`).join(",") + "}";
52601
+ return "{" + keys2.map((k3) => `${jsonStringAsciiSafe(k3)}:${canonicalJson(obj[k3])}`).join(",") + "}";
52583
52602
  }
52584
52603
  throw new Error(`Unsupported value in canonicalJson: ${typeof value}`);
52585
52604
  }
@@ -52649,7 +52668,7 @@ function readLocalComponents(cwd2, manifest) {
52649
52668
  out.push({
52650
52669
  type: "instruction",
52651
52670
  slug: "agent-instructions",
52652
- hash: componentHashFromFileHashes([hashString(instr)])
52671
+ hash: componentHashFromFileHashes([hashString(normalizeInstructionBody(instr))])
52653
52672
  });
52654
52673
  }
52655
52674
  for (const entry of manifest.skills) {
@@ -52787,6 +52806,38 @@ function threeWayDiff(input) {
52787
52806
  }
52788
52807
  return rows;
52789
52808
  }
52809
+ function partitionPushRows(rows, force) {
52810
+ const toSend = [];
52811
+ const conflicts = [];
52812
+ const upstreamOnly = [];
52813
+ for (const r2 of rows) {
52814
+ switch (r2.status) {
52815
+ case "modified-local":
52816
+ case "added-only-local":
52817
+ case "added-local":
52818
+ case "removed-local":
52819
+ toSend.push(r2);
52820
+ break;
52821
+ case "modified-both":
52822
+ if (force)
52823
+ toSend.push(r2);
52824
+ else
52825
+ conflicts.push(r2);
52826
+ break;
52827
+ case "modified-cloud":
52828
+ case "added-cloud":
52829
+ case "removed-cloud":
52830
+ upstreamOnly.push(r2);
52831
+ break;
52832
+ case "in-sync":
52833
+ break;
52834
+ default: {
52835
+ const _exhaustive = r2.status;
52836
+ }
52837
+ }
52838
+ }
52839
+ return { toSend, conflicts, upstreamOnly };
52840
+ }
52790
52841
  function diffAgentMeta(manifestMeta, lockMeta, cloudMeta) {
52791
52842
  const eq = (a3, b4) => {
52792
52843
  if (!a3 && !b4)
@@ -53221,7 +53272,7 @@ function materializeInstructions(cwd2, cloud, toInstall, keepLocal, existingMani
53221
53272
  const targetRel = existingManifest?.instructions?.file ?? DEFAULT_INSTRUCTIONS_FILE;
53222
53273
  const target = path48.resolve(cwd2, targetRel);
53223
53274
  ensureDir(path48.dirname(target));
53224
- fs45.writeFileSync(target, body, "utf8");
53275
+ fs45.writeFileSync(target, normalizeInstructionBody(body), "utf8");
53225
53276
  }
53226
53277
  }
53227
53278
  function materializePlaybooks(cwd2, cloud, toInstall, keepLocal, existingManifest) {
@@ -53236,7 +53287,7 @@ function materializePlaybooks(cwd2, cloud, toInstall, keepLocal, existingManifes
53236
53287
  const raw = c2.files[0]?.content ?? "";
53237
53288
  if (!raw.trim())
53238
53289
  continue;
53239
- const { body } = stripFrontmatter(raw);
53290
+ const { body } = stripPlaybookFrontmatter(raw);
53240
53291
  const existing = existingManifest?.playbooks?.find((p2) => slugifyPlaybookTitle(p2.title) === c2.slug);
53241
53292
  if (existing?.content?.text !== undefined)
53242
53293
  continue;
@@ -53246,20 +53297,6 @@ function materializePlaybooks(cwd2, cloud, toInstall, keepLocal, existingManifes
53246
53297
  fs45.writeFileSync(target, body, "utf8");
53247
53298
  }
53248
53299
  }
53249
- function stripFrontmatter(raw) {
53250
- const m3 = /^---\s*\n([\s\S]*?)\n---\s*\n?/.exec(raw);
53251
- if (!m3)
53252
- return { frontmatter: {}, body: raw };
53253
- let fm = {};
53254
- try {
53255
- const parsed = import_yaml3.default.parse(m3[1] ?? "");
53256
- if (parsed && typeof parsed === "object")
53257
- fm = parsed;
53258
- } catch {
53259
- return { frontmatter: {}, body: raw };
53260
- }
53261
- return { frontmatter: fm, body: raw.slice(m3[0].length) };
53262
- }
53263
53300
  function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
53264
53301
  const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
53265
53302
  const localDecl = prev?.skills.find((s3) => {
@@ -53297,7 +53334,7 @@ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
53297
53334
  }
53298
53335
  const playbooks = cloud.components.filter((c2) => c2.type === "playbook").map((c2) => {
53299
53336
  const raw = c2.files[0]?.content ?? "";
53300
- const { frontmatter } = stripFrontmatter(raw);
53337
+ const { frontmatter } = stripPlaybookFrontmatter(raw);
53301
53338
  const local = prev?.playbooks?.find((pb) => slugifyPlaybookTitle(pb.title) === c2.slug);
53302
53339
  const title = local?.title ?? (typeof frontmatter.title === "string" && frontmatter.title || c2.slug);
53303
53340
  const description = local?.description ?? (typeof frontmatter.description === "string" ? frontmatter.description : undefined);
@@ -53562,10 +53599,11 @@ async function buildOutgoingComponents(cwd2, manifest, cloud, resolvedVersions)
53562
53599
  }
53563
53600
  if (body.trim()) {
53564
53601
  const fileName = manifest.instructions.file ?? "instructions.md";
53565
- const fileHash2 = hashString(body);
53602
+ const wireBody = normalizeInstructionBody(body);
53603
+ const fileHash2 = hashString(wireBody);
53566
53604
  const file = {
53567
53605
  path: fileName,
53568
- content: body,
53606
+ content: wireBody,
53569
53607
  hash: fileHash2
53570
53608
  };
53571
53609
  out.push({
@@ -53878,26 +53916,8 @@ async function runAgentPush(cwd2, args) {
53878
53916
  f2.error(`Playbook ${preIdSchemaSlugs.length === 1 ? "entry" : "entries"} ${preIdSchemaSlugs.map((s3) => import_picocolors27.default.bold(s3)).join(", ")} in ${import_picocolors27.default.bold("brainbase.agent.yaml")} ${preIdSchemaSlugs.length === 1 ? "is" : "are"} missing ${import_picocolors27.default.cyan("id:")}. Run ${import_picocolors27.default.bold("brainbase agent pull")} first to sync playbook ids, then push.`);
53879
53917
  return;
53880
53918
  }
53881
- const toSend = [];
53882
- const conflicts = [];
53883
- const upstreamOnly = [];
53884
- for (const r2 of rows) {
53885
- switch (r2.status) {
53886
- case "modified-local":
53887
- case "added-only-local":
53888
- case "removed-local":
53889
- toSend.push(r2);
53890
- break;
53891
- case "modified-both":
53892
- conflicts.push(r2);
53893
- break;
53894
- case "modified-cloud":
53895
- case "added-cloud":
53896
- case "removed-cloud":
53897
- upstreamOnly.push(r2);
53898
- break;
53899
- }
53900
- }
53919
+ const { toSend, conflicts, upstreamOnly } = partitionPushRows(rows, !!args.force);
53920
+ const forcedOverrides = args.force ? rows.filter((r2) => r2.status === "modified-both") : [];
53901
53921
  if (!meta.localChanged && !entrypointChanged && toSend.length === 0 && conflicts.length === 0) {
53902
53922
  f2.info("Nothing to push — local is in sync with the cloud.");
53903
53923
  return;
@@ -53907,9 +53927,15 @@ async function runAgentPush(cwd2, args) {
53907
53927
  for (const r2 of conflicts) {
53908
53928
  console.error(` ${import_picocolors27.default.red("!")} ${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)}`);
53909
53929
  }
53910
- f2.info(`Run ${import_picocolors27.default.cyan("brainbase agent pull")} first to reconcile, then push again.`);
53930
+ f2.info(`Run ${import_picocolors27.default.cyan("brainbase agent pull")} first to reconcile, then push again — or ${import_picocolors27.default.cyan("brainbase agent push --force")} to overwrite the cloud with your local version.`);
53911
53931
  return;
53912
53932
  }
53933
+ if (forcedOverrides.length > 0) {
53934
+ f2.warn(`${import_picocolors27.default.yellow("--force")}: overwriting ${forcedOverrides.length} cloud change${forcedOverrides.length === 1 ? "" : "s"} with your local version (cloud edits discarded):`);
53935
+ for (const r2 of forcedOverrides) {
53936
+ console.warn(` ${import_picocolors27.default.yellow("⤒")} ${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)}`);
53937
+ }
53938
+ }
53913
53939
  if (upstreamOnly.length > 0 && !args.yes) {
53914
53940
  f2.warn(`Cloud has ${upstreamOnly.length} change${upstreamOnly.length === 1 ? "" : "s"} you don't have locally:`);
53915
53941
  for (const r2 of upstreamOnly) {
@@ -54979,7 +55005,7 @@ async function runAgent(cwd2, sub, args, opts) {
54979
55005
  });
54980
55006
  return;
54981
55007
  case "push":
54982
- await runAgentPush(cwd2, { yes: opts.yes });
55008
+ await runAgentPush(cwd2, { yes: opts.yes, force: opts.force });
54983
55009
  return;
54984
55010
  case "unpack":
54985
55011
  await runAgentUnpack(cwd2, {
@@ -55014,7 +55040,7 @@ function printHelp() {
55014
55040
  out.push("");
55015
55041
  out.push(` ${import_picocolors32.default.cyan("create")} ${import_picocolors32.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
55016
55042
  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); --run-entrypoint to also execute the agent entrypoint")}`);
55017
- out.push(` ${import_picocolors32.default.cyan("push")} ${import_picocolors32.default.dim("send local changes to the cloud — instructions, playbooks, skills, MCPs, entrypoint")}`);
55043
+ out.push(` ${import_picocolors32.default.cyan("push")} ${import_picocolors32.default.dim("send local changes to the cloud — instructions, playbooks, skills, MCPs, entrypoint (--force to overwrite cloud-side conflicts with local)")}`);
55018
55044
  out.push(` ${import_picocolors32.default.cyan("unpack")} ${import_picocolors32.default.dim("install the claimed agent into a harness layout (--harness to override)")}`);
55019
55045
  out.push(` ${import_picocolors32.default.cyan("status")} ${import_picocolors32.default.dim("show what would push and what would pull")}`);
55020
55046
  out.push(` ${import_picocolors32.default.cyan("env")} ${import_picocolors32.default.dim('print export statements — use with `eval "$(brainbase agent env)"`')}`);
@@ -55034,7 +55060,7 @@ var import_picocolors33 = __toESM(require_picocolors(), 1);
55034
55060
  // src/core/orchestration-manifest.ts
55035
55061
  import path51 from "node:path";
55036
55062
  import fs47 from "node:fs";
55037
- var import_yaml4 = __toESM(require_dist(), 1);
55063
+ var import_yaml3 = __toESM(require_dist(), 1);
55038
55064
  var ORCH_MANIFEST_FILE = "brainbase-orchestration.yaml";
55039
55065
  var ORCH_MEMBERS_DIR = "agents";
55040
55066
  var OrchMetaSchema = exports_external.object({
@@ -55086,7 +55112,7 @@ function readOrchManifest(cwd2) {
55086
55112
  const raw = fs47.readFileSync(p2, "utf8");
55087
55113
  let parsed;
55088
55114
  try {
55089
- parsed = import_yaml4.default.parse(raw);
55115
+ parsed = import_yaml3.default.parse(raw);
55090
55116
  } catch (err) {
55091
55117
  throw new Error(`${ORCH_MANIFEST_FILE} is not valid YAML: ${err.message}`);
55092
55118
  }
@@ -55097,7 +55123,7 @@ function readOrchManifest(cwd2) {
55097
55123
  return result2.data;
55098
55124
  }
55099
55125
  function writeOrchManifest(cwd2, manifest) {
55100
- const doc = new import_yaml4.default.Document;
55126
+ const doc = new import_yaml3.default.Document;
55101
55127
  doc.contents = manifest;
55102
55128
  doc.commentBefore = ` brainbase-orchestration.yaml — declarative orchestration manifest.
55103
55129
  ` + ` Committed to source control. Edit by hand, then
@@ -56952,7 +56978,7 @@ function help() {
56952
56978
  out.push("");
56953
56979
  out.push(` ${import_picocolors41.default.cyan("agent create")} ${import_picocolors41.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
56954
56980
  out.push(` ${import_picocolors41.default.cyan("agent pull")} ${import_picocolors41.default.dim("[<id>]")} ${import_picocolors41.default.dim("bring cloud changes into this folder (--force to override; --run-entrypoint to also execute the agent entrypoint)")}`);
56955
- out.push(` ${import_picocolors41.default.cyan("agent push")} ${import_picocolors41.default.dim("send local changes to the cloud instructions, playbooks, skills, MCPs, entrypoint")}`);
56981
+ out.push(` ${import_picocolors41.default.cyan("agent push")} ${import_picocolors41.default.dim("send local changes to the cloud (--force to overwrite cloud-side conflicts with local)")}`);
56956
56982
  out.push(` ${import_picocolors41.default.cyan("agent unpack")} ${import_picocolors41.default.dim("install the claimed agent into a harness layout")}`);
56957
56983
  out.push(` ${import_picocolors41.default.cyan("link")} ${import_picocolors41.default.dim("attach this folder to an existing agent")}`);
56958
56984
  out.push(` ${import_picocolors41.default.cyan("agent status")} ${import_picocolors41.default.dim("show what would pull and what would push")}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainbase-labs/cli",
3
- "version": "0.13.1",
3
+ "version": "0.13.2",
4
4
  "description": "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
5
5
  "type": "module",
6
6
  "bin": {