@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.
- package/dist/index.js +81 -67
- 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.
|
|
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
|
-
|
|
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
|
|
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" &&
|
|
53672
|
-
|
|
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
|
-
|
|
53681
|
-
|
|
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,
|
|
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: ${
|
|
54785
|
+
const lines = ["---", `title: ${yamlScalar(title)}`];
|
|
54772
54786
|
if (description)
|
|
54773
|
-
lines.push(`description: ${
|
|
54787
|
+
lines.push(`description: ${yamlScalar(description)}`);
|
|
54774
54788
|
lines.push("---", "");
|
|
54775
54789
|
return lines.join(`
|
|
54776
54790
|
`);
|
|
54777
54791
|
}
|
|
54778
|
-
function
|
|
54792
|
+
function yamlScalar(s3) {
|
|
54779
54793
|
if (!/[\n":#&*!|>'%@`{}[\]]/.test(s3) && s3.trim() === s3 && s3 !== "")
|
|
54780
54794
|
return s3;
|
|
54781
54795
|
return JSON.stringify(s3);
|