@brainbase-labs/cli 0.11.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +81 -67
  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.11.0",
29452
+ version: "0.11.1",
29453
29453
  description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
29454
29454
  type: "module",
29455
29455
  bin: {
@@ -43741,6 +43741,33 @@ function removeInstalledRecord(name, scope, cwd2) {
43741
43741
  // src/core/registry-remote.ts
43742
43742
  import fs22 from "node:fs";
43743
43743
 
43744
+ // src/core/api-error-message.ts
43745
+ function apiErrorMessage(body, status) {
43746
+ if (body && typeof body === "object") {
43747
+ const obj = body;
43748
+ for (const key2 of ["error", "message", "detail"]) {
43749
+ const v2 = obj[key2];
43750
+ if (typeof v2 === "string" && v2.trim())
43751
+ return v2.trim();
43752
+ if (Array.isArray(v2)) {
43753
+ const msgs = v2.map((item) => {
43754
+ if (typeof item === "string" && item.trim())
43755
+ return item.trim();
43756
+ if (item && typeof item === "object" && typeof item.msg === "string") {
43757
+ return item.msg;
43758
+ }
43759
+ return null;
43760
+ }).filter((m2) => !!m2);
43761
+ if (msgs.length)
43762
+ return msgs.join("; ");
43763
+ }
43764
+ }
43765
+ } else if (typeof body === "string" && body.trim()) {
43766
+ return body.trim();
43767
+ }
43768
+ return `HTTP ${status}`;
43769
+ }
43770
+
43744
43771
  // src/core/api.ts
43745
43772
  var DEFAULT_API_BASE = "https://kafka-llm-service.onrender.com";
43746
43773
 
@@ -43800,8 +43827,7 @@ async function request(pathname, init = {}) {
43800
43827
  body = text2 ? JSON.parse(text2) : null;
43801
43828
  } catch {}
43802
43829
  if (!res.ok) {
43803
- const msg = (body && typeof body === "object" && "error" in body ? String(body.error) : null) ?? (body && typeof body === "object" && "message" in body ? String(body.message) : null) ?? `HTTP ${res.status}`;
43804
- throw new ApiError(msg, res.status, body);
43830
+ throw new ApiError(apiErrorMessage(body, res.status), res.status, body);
43805
43831
  }
43806
43832
  return body;
43807
43833
  }
@@ -53489,42 +53515,6 @@ async function buildOutgoingComponents(cwd2, manifest, cloud, resolvedVersions)
53489
53515
  }
53490
53516
  });
53491
53517
  }
53492
- const seenPlaybookSlugs = new Set;
53493
- for (const entry of manifest.playbooks ?? []) {
53494
- if (entry.content.text !== undefined && entry.content.file !== undefined) {
53495
- f2.error(`Playbook ${import_picocolors26.default.bold(entry.title)} sets both ${import_picocolors26.default.cyan("text")} and ${import_picocolors26.default.cyan("file")} — pick one.`);
53496
- return null;
53497
- }
53498
- const body = resolvePlaybookContent(cwd2, entry);
53499
- if (body === null) {
53500
- if (entry.content.file) {
53501
- f2.error(`Playbook ${import_picocolors26.default.bold(entry.title)} content file ${import_picocolors26.default.bold(entry.content.file)} not found.`);
53502
- } else {
53503
- f2.error(`Playbook ${import_picocolors26.default.bold(entry.title)} content is empty.`);
53504
- }
53505
- return null;
53506
- }
53507
- const slug = slugifyPlaybookTitle(entry.title);
53508
- if (seenPlaybookSlugs.has(slug)) {
53509
- 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.`);
53510
- return null;
53511
- }
53512
- seenPlaybookSlugs.add(slug);
53513
- const wireBody = assemblePlaybookBody(entry, body);
53514
- const fileName = `${slug}.md`;
53515
- const fileHash2 = hashString(wireBody);
53516
- out.push({
53517
- type: "playbook",
53518
- slug,
53519
- description: entry.description,
53520
- hash: componentHashFromFileHashes([fileHash2]),
53521
- files: [{ path: fileName, content: wireBody, hash: fileHash2 }],
53522
- meta: {
53523
- title: entry.title,
53524
- ...entry.description ? { description: entry.description } : {}
53525
- }
53526
- });
53527
- }
53528
53518
  for (const entry of manifest.mcp ?? []) {
53529
53519
  if (!entry.url && !entry.command) {
53530
53520
  f2.error(`MCP ${import_picocolors26.default.bold(entry.name)} needs either ${import_picocolors26.default.cyan("url")} or ${import_picocolors26.default.cyan("command")}.`);
@@ -53552,23 +53542,6 @@ async function buildOutgoingComponents(cwd2, manifest, cloud, resolvedVersions)
53552
53542
  }
53553
53543
  return out;
53554
53544
  }
53555
- function assemblePlaybookBody(entry, body) {
53556
- if (/^---\s*\n/.test(body))
53557
- return body;
53558
- const lines = ["---", `title: ${yamlScalar(entry.title)}`];
53559
- if (entry.description) {
53560
- lines.push(`description: ${yamlScalar(entry.description)}`);
53561
- }
53562
- lines.push("---", "");
53563
- return lines.join(`
53564
- `) + body.replace(/^\n+/, "");
53565
- }
53566
- function yamlScalar(s3) {
53567
- if (!/[\n":#&*!|>'%@`{}[\]]/.test(s3) && s3.trim() === s3 && s3 !== "") {
53568
- return s3;
53569
- }
53570
- return JSON.stringify(s3);
53571
- }
53572
53545
 
53573
53546
  // src/core/registry-skill-updates.ts
53574
53547
  function parseSemver2(v3) {
@@ -53664,29 +53637,56 @@ async function runAgentPush(cwd2, args) {
53664
53637
  lock: lock?.components ?? [],
53665
53638
  cloud: cloud.components
53666
53639
  });
53667
- const unpinned = new Map;
53640
+ const registryRefs = new Map;
53668
53641
  for (const entry of manifest.skills) {
53669
53642
  try {
53670
53643
  const parsed = parseSkillSource2(entry.source);
53671
- if (parsed.kind === "registry" && !parsed.version && parsed.creator) {
53672
- unpinned.set(`${parsed.creator}/${parsed.slug}`, {
53644
+ if (parsed.kind === "registry" && parsed.creator) {
53645
+ registryRefs.set(`${parsed.creator}/${parsed.slug}`, {
53673
53646
  creator: parsed.creator,
53674
- slug: parsed.slug
53647
+ slug: parsed.slug,
53648
+ version: parsed.version
53675
53649
  });
53676
53650
  }
53677
53651
  } catch {}
53678
53652
  }
53679
53653
  const latestByName = new Map;
53680
- if (unpinned.size > 0) {
53681
- await Promise.all([...unpinned.entries()].map(async ([name, ref]) => {
53654
+ const notInRegistry = new Set;
53655
+ if (registryRefs.size > 0) {
53656
+ await Promise.all([...registryRefs.entries()].map(async ([name, ref]) => {
53682
53657
  try {
53683
53658
  const pkg = await skillsApi.getPackage(ref.creator, ref.slug);
53684
53659
  if (pkg.latest_version?.version) {
53685
53660
  latestByName.set(name, pkg.latest_version.version);
53686
53661
  }
53687
- } catch {}
53662
+ } catch (err) {
53663
+ if (err instanceof ApiError && err.status === 404) {
53664
+ notInRegistry.add(name);
53665
+ }
53666
+ }
53688
53667
  }));
53689
53668
  }
53669
+ const unresolvable = [...notInRegistry].filter((name) => {
53670
+ const ref = registryRefs.get(name);
53671
+ const componentSlug = registrySkillComponentSlug({
53672
+ kind: "registry",
53673
+ creator: ref.creator,
53674
+ slug: ref.slug
53675
+ });
53676
+ return !cloud.components.some((c2) => c2.type === "skill" && c2.slug === componentSlug);
53677
+ });
53678
+ if (unresolvable.length > 0) {
53679
+ for (const name of unresolvable) {
53680
+ f2.error(`Skill ${import_picocolors27.default.bold(name)} isn't in the registry (not published, or private to another owner).`);
53681
+ }
53682
+ const noun = unresolvable.length === 1 ? "it" : "each one";
53683
+ f2.info(`Publish ${noun} first, then push again:`);
53684
+ for (const name of unresolvable) {
53685
+ const version = registryRefs.get(name)?.version ?? "0.1.0";
53686
+ f2.info(` ${import_picocolors27.default.cyan(`brainbase skill publish ./path/to/skill --name ${name} --skill-version ${version} --yes`)}`);
53687
+ }
53688
+ return;
53689
+ }
53690
53690
  const skillUpdates = planRegistrySkillUpdates(manifest.skills, cloud.components, latestByName);
53691
53691
  const resolvedVersions = new Map(skillUpdates.map((u2) => [u2.componentSlug, u2.latest]));
53692
53692
  for (const u2 of skillUpdates) {
@@ -53723,7 +53723,7 @@ async function runAgentPush(cwd2, args) {
53723
53723
  const entrypointChanged = resolvedEntrypoint !== undefined && (resolvedEntrypoint ?? "").trim() !== (lock?.agentMeta?.entrypoint ?? "").trim();
53724
53724
  for (const r2 of rows) {
53725
53725
  if (r2.type !== "instruction" && r2.type !== "skill" && r2.type !== "mcp" && r2.type !== "playbook") {
53726
- 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.`);
53726
+ f2.error(`Component ${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)} can't be pushed yet — the server accepts instructions, skills, and mcps in this version.`);
53727
53727
  return;
53728
53728
  }
53729
53729
  }
@@ -53742,7 +53742,13 @@ async function runAgentPush(cwd2, args) {
53742
53742
  const toSend = [];
53743
53743
  const conflicts = [];
53744
53744
  const upstreamOnly = [];
53745
+ const unpushablePlaybooks = [];
53745
53746
  for (const r2 of rows) {
53747
+ const localish = r2.status === "modified-local" || r2.status === "added-only-local" || r2.status === "removed-local" || r2.status === "modified-both";
53748
+ if (r2.type === "playbook" && localish) {
53749
+ unpushablePlaybooks.push(r2);
53750
+ continue;
53751
+ }
53746
53752
  switch (r2.status) {
53747
53753
  case "modified-local":
53748
53754
  case "added-only-local":
@@ -53759,6 +53765,9 @@ async function runAgentPush(cwd2, args) {
53759
53765
  break;
53760
53766
  }
53761
53767
  }
53768
+ if (unpushablePlaybooks.length > 0) {
53769
+ f2.warn(`Local playbook change${unpushablePlaybooks.length === 1 ? "" : "s"} can't be pushed yet (the server doesn't accept playbooks) — edit playbooks in the UI instead: ${unpushablePlaybooks.map((r2) => import_picocolors27.default.bold(r2.slug)).join(", ")}`);
53770
+ }
53762
53771
  if (!meta.localChanged && !entrypointChanged && toSend.length === 0 && conflicts.length === 0) {
53763
53772
  f2.info("Nothing to push — local is in sync with the cloud.");
53764
53773
  return;
@@ -53873,6 +53882,8 @@ async function runAgentPush(cwd2, args) {
53873
53882
  }
53874
53883
  const localHashByKey = new Map;
53875
53884
  for (const lc of localComponents) {
53885
+ if (lc.type === "playbook")
53886
+ continue;
53876
53887
  if (lc.hash)
53877
53888
  localHashByKey.set(`${lc.type}/${lc.slug}`, lc.hash);
53878
53889
  }
@@ -54398,6 +54409,9 @@ async function runAgentCreate(cwd2, args) {
54398
54409
  writeLink(cwd2, link2);
54399
54410
  manifest = readManifest(cwd2);
54400
54411
  let updatedCloud = null;
54412
+ if ((manifest.playbooks ?? []).length > 0) {
54413
+ f2.info(`Playbooks aren't pushable yet — skipping ${manifest.playbooks.length}. Create playbooks in the UI instead.`);
54414
+ }
54401
54415
  const hasContent = !!manifest.instructions || manifest.skills.length > 0 || (manifest.mcp ?? []).length > 0;
54402
54416
  if (hasContent) {
54403
54417
  const outgoing = await buildOutgoingComponents(cwd2, manifest, null);
@@ -54768,14 +54782,14 @@ function copyDirRecursive(src, dest) {
54768
54782
  }
54769
54783
  }
54770
54784
  function assembleFrontmatter(title, description) {
54771
- const lines = ["---", `title: ${yamlScalar2(title)}`];
54785
+ const lines = ["---", `title: ${yamlScalar(title)}`];
54772
54786
  if (description)
54773
- lines.push(`description: ${yamlScalar2(description)}`);
54787
+ lines.push(`description: ${yamlScalar(description)}`);
54774
54788
  lines.push("---", "");
54775
54789
  return lines.join(`
54776
54790
  `);
54777
54791
  }
54778
- function yamlScalar2(s3) {
54792
+ function yamlScalar(s3) {
54779
54793
  if (!/[\n":#&*!|>'%@`{}[\]]/.test(s3) && s3.trim() === s3 && s3 !== "")
54780
54794
  return s3;
54781
54795
  return JSON.stringify(s3);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainbase-labs/cli",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
5
5
  "type": "module",
6
6
  "bin": {