@brainbase-labs/cli 0.13.0 → 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.
- package/dist/index.js +109 -51
- 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.
|
|
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: {
|
|
@@ -51314,6 +51314,45 @@ function assignPlaybookSlugs(titles) {
|
|
|
51314
51314
|
return slug;
|
|
51315
51315
|
});
|
|
51316
51316
|
}
|
|
51317
|
+
function backfillPlaybookIds(playbooks, cloudComponents) {
|
|
51318
|
+
const idBySlug = new Map;
|
|
51319
|
+
for (const c2 of cloudComponents) {
|
|
51320
|
+
if (c2.type !== "playbook")
|
|
51321
|
+
continue;
|
|
51322
|
+
const id = c2.meta?.playbook_id;
|
|
51323
|
+
if (typeof id === "string" && id)
|
|
51324
|
+
idBySlug.set(c2.slug, id);
|
|
51325
|
+
}
|
|
51326
|
+
const slugs = assignPlaybookSlugs(playbooks.map((e2) => e2.title));
|
|
51327
|
+
let changed = false;
|
|
51328
|
+
const next = playbooks.map((entry, i) => {
|
|
51329
|
+
if (entry.id)
|
|
51330
|
+
return entry;
|
|
51331
|
+
const id = idBySlug.get(slugs[i]);
|
|
51332
|
+
if (!id)
|
|
51333
|
+
return entry;
|
|
51334
|
+
changed = true;
|
|
51335
|
+
return { id, ...entry };
|
|
51336
|
+
});
|
|
51337
|
+
return { playbooks: changed ? next : playbooks, changed };
|
|
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
|
+
}
|
|
51317
51356
|
|
|
51318
51357
|
// src/core/link.ts
|
|
51319
51358
|
var LINK_DIR = ".brainbase";
|
|
@@ -52527,7 +52566,6 @@ import path48 from "node:path";
|
|
|
52527
52566
|
import fs45 from "node:fs";
|
|
52528
52567
|
import os12 from "node:os";
|
|
52529
52568
|
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
52530
|
-
var import_yaml3 = __toESM(require_dist(), 1);
|
|
52531
52569
|
|
|
52532
52570
|
// src/core/agent-diff.ts
|
|
52533
52571
|
import path46 from "node:path";
|
|
@@ -52539,6 +52577,9 @@ function compKey(type, slug) {
|
|
|
52539
52577
|
function hashString(s3) {
|
|
52540
52578
|
return crypto4.createHash("sha256").update(s3).digest("hex");
|
|
52541
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
|
+
}
|
|
52542
52583
|
function canonicalJson(value) {
|
|
52543
52584
|
if (value === null)
|
|
52544
52585
|
return "null";
|
|
@@ -52550,14 +52591,14 @@ function canonicalJson(value) {
|
|
|
52550
52591
|
return String(value);
|
|
52551
52592
|
}
|
|
52552
52593
|
if (typeof value === "string")
|
|
52553
|
-
return
|
|
52594
|
+
return jsonStringAsciiSafe(value);
|
|
52554
52595
|
if (Array.isArray(value)) {
|
|
52555
52596
|
return "[" + value.map(canonicalJson).join(",") + "]";
|
|
52556
52597
|
}
|
|
52557
52598
|
if (typeof value === "object") {
|
|
52558
52599
|
const obj = value;
|
|
52559
52600
|
const keys2 = Object.keys(obj).sort();
|
|
52560
|
-
return "{" + keys2.map((k3) => `${
|
|
52601
|
+
return "{" + keys2.map((k3) => `${jsonStringAsciiSafe(k3)}:${canonicalJson(obj[k3])}`).join(",") + "}";
|
|
52561
52602
|
}
|
|
52562
52603
|
throw new Error(`Unsupported value in canonicalJson: ${typeof value}`);
|
|
52563
52604
|
}
|
|
@@ -52627,7 +52668,7 @@ function readLocalComponents(cwd2, manifest) {
|
|
|
52627
52668
|
out.push({
|
|
52628
52669
|
type: "instruction",
|
|
52629
52670
|
slug: "agent-instructions",
|
|
52630
|
-
hash: componentHashFromFileHashes([hashString(instr)])
|
|
52671
|
+
hash: componentHashFromFileHashes([hashString(normalizeInstructionBody(instr))])
|
|
52631
52672
|
});
|
|
52632
52673
|
}
|
|
52633
52674
|
for (const entry of manifest.skills) {
|
|
@@ -52765,6 +52806,38 @@ function threeWayDiff(input) {
|
|
|
52765
52806
|
}
|
|
52766
52807
|
return rows;
|
|
52767
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
|
+
}
|
|
52768
52841
|
function diffAgentMeta(manifestMeta, lockMeta, cloudMeta) {
|
|
52769
52842
|
const eq = (a3, b4) => {
|
|
52770
52843
|
if (!a3 && !b4)
|
|
@@ -53199,7 +53272,7 @@ function materializeInstructions(cwd2, cloud, toInstall, keepLocal, existingMani
|
|
|
53199
53272
|
const targetRel = existingManifest?.instructions?.file ?? DEFAULT_INSTRUCTIONS_FILE;
|
|
53200
53273
|
const target = path48.resolve(cwd2, targetRel);
|
|
53201
53274
|
ensureDir(path48.dirname(target));
|
|
53202
|
-
fs45.writeFileSync(target, body, "utf8");
|
|
53275
|
+
fs45.writeFileSync(target, normalizeInstructionBody(body), "utf8");
|
|
53203
53276
|
}
|
|
53204
53277
|
}
|
|
53205
53278
|
function materializePlaybooks(cwd2, cloud, toInstall, keepLocal, existingManifest) {
|
|
@@ -53214,7 +53287,7 @@ function materializePlaybooks(cwd2, cloud, toInstall, keepLocal, existingManifes
|
|
|
53214
53287
|
const raw = c2.files[0]?.content ?? "";
|
|
53215
53288
|
if (!raw.trim())
|
|
53216
53289
|
continue;
|
|
53217
|
-
const { body } =
|
|
53290
|
+
const { body } = stripPlaybookFrontmatter(raw);
|
|
53218
53291
|
const existing = existingManifest?.playbooks?.find((p2) => slugifyPlaybookTitle(p2.title) === c2.slug);
|
|
53219
53292
|
if (existing?.content?.text !== undefined)
|
|
53220
53293
|
continue;
|
|
@@ -53224,20 +53297,6 @@ function materializePlaybooks(cwd2, cloud, toInstall, keepLocal, existingManifes
|
|
|
53224
53297
|
fs45.writeFileSync(target, body, "utf8");
|
|
53225
53298
|
}
|
|
53226
53299
|
}
|
|
53227
|
-
function stripFrontmatter(raw) {
|
|
53228
|
-
const m3 = /^---\s*\n([\s\S]*?)\n---\s*\n?/.exec(raw);
|
|
53229
|
-
if (!m3)
|
|
53230
|
-
return { frontmatter: {}, body: raw };
|
|
53231
|
-
let fm = {};
|
|
53232
|
-
try {
|
|
53233
|
-
const parsed = import_yaml3.default.parse(m3[1] ?? "");
|
|
53234
|
-
if (parsed && typeof parsed === "object")
|
|
53235
|
-
fm = parsed;
|
|
53236
|
-
} catch {
|
|
53237
|
-
return { frontmatter: {}, body: raw };
|
|
53238
|
-
}
|
|
53239
|
-
return { frontmatter: fm, body: raw.slice(m3[0].length) };
|
|
53240
|
-
}
|
|
53241
53300
|
function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
|
|
53242
53301
|
const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
|
|
53243
53302
|
const localDecl = prev?.skills.find((s3) => {
|
|
@@ -53275,7 +53334,7 @@ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
|
|
|
53275
53334
|
}
|
|
53276
53335
|
const playbooks = cloud.components.filter((c2) => c2.type === "playbook").map((c2) => {
|
|
53277
53336
|
const raw = c2.files[0]?.content ?? "";
|
|
53278
|
-
const { frontmatter } =
|
|
53337
|
+
const { frontmatter } = stripPlaybookFrontmatter(raw);
|
|
53279
53338
|
const local = prev?.playbooks?.find((pb) => slugifyPlaybookTitle(pb.title) === c2.slug);
|
|
53280
53339
|
const title = local?.title ?? (typeof frontmatter.title === "string" && frontmatter.title || c2.slug);
|
|
53281
53340
|
const description = local?.description ?? (typeof frontmatter.description === "string" ? frontmatter.description : undefined);
|
|
@@ -53540,10 +53599,11 @@ async function buildOutgoingComponents(cwd2, manifest, cloud, resolvedVersions)
|
|
|
53540
53599
|
}
|
|
53541
53600
|
if (body.trim()) {
|
|
53542
53601
|
const fileName = manifest.instructions.file ?? "instructions.md";
|
|
53543
|
-
const
|
|
53602
|
+
const wireBody = normalizeInstructionBody(body);
|
|
53603
|
+
const fileHash2 = hashString(wireBody);
|
|
53544
53604
|
const file = {
|
|
53545
53605
|
path: fileName,
|
|
53546
|
-
content:
|
|
53606
|
+
content: wireBody,
|
|
53547
53607
|
hash: fileHash2
|
|
53548
53608
|
};
|
|
53549
53609
|
out.push({
|
|
@@ -53856,26 +53916,8 @@ async function runAgentPush(cwd2, args) {
|
|
|
53856
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.`);
|
|
53857
53917
|
return;
|
|
53858
53918
|
}
|
|
53859
|
-
const toSend =
|
|
53860
|
-
const
|
|
53861
|
-
const upstreamOnly = [];
|
|
53862
|
-
for (const r2 of rows) {
|
|
53863
|
-
switch (r2.status) {
|
|
53864
|
-
case "modified-local":
|
|
53865
|
-
case "added-only-local":
|
|
53866
|
-
case "removed-local":
|
|
53867
|
-
toSend.push(r2);
|
|
53868
|
-
break;
|
|
53869
|
-
case "modified-both":
|
|
53870
|
-
conflicts.push(r2);
|
|
53871
|
-
break;
|
|
53872
|
-
case "modified-cloud":
|
|
53873
|
-
case "added-cloud":
|
|
53874
|
-
case "removed-cloud":
|
|
53875
|
-
upstreamOnly.push(r2);
|
|
53876
|
-
break;
|
|
53877
|
-
}
|
|
53878
|
-
}
|
|
53919
|
+
const { toSend, conflicts, upstreamOnly } = partitionPushRows(rows, !!args.force);
|
|
53920
|
+
const forcedOverrides = args.force ? rows.filter((r2) => r2.status === "modified-both") : [];
|
|
53879
53921
|
if (!meta.localChanged && !entrypointChanged && toSend.length === 0 && conflicts.length === 0) {
|
|
53880
53922
|
f2.info("Nothing to push — local is in sync with the cloud.");
|
|
53881
53923
|
return;
|
|
@@ -53885,9 +53927,15 @@ async function runAgentPush(cwd2, args) {
|
|
|
53885
53927
|
for (const r2 of conflicts) {
|
|
53886
53928
|
console.error(` ${import_picocolors27.default.red("!")} ${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)}`);
|
|
53887
53929
|
}
|
|
53888
|
-
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.`);
|
|
53889
53931
|
return;
|
|
53890
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
|
+
}
|
|
53891
53939
|
if (upstreamOnly.length > 0 && !args.yes) {
|
|
53892
53940
|
f2.warn(`Cloud has ${upstreamOnly.length} change${upstreamOnly.length === 1 ? "" : "s"} you don't have locally:`);
|
|
53893
53941
|
for (const r2 of upstreamOnly) {
|
|
@@ -53981,6 +54029,11 @@ async function runAgentPush(cwd2, args) {
|
|
|
53981
54029
|
}
|
|
53982
54030
|
return handleApiError3(err);
|
|
53983
54031
|
}
|
|
54032
|
+
const backfill = backfillPlaybookIds(manifest.playbooks ?? [], updatedCloud.components);
|
|
54033
|
+
if (backfill.changed) {
|
|
54034
|
+
manifest.playbooks = backfill.playbooks;
|
|
54035
|
+
writeManifest(cwd2, manifest);
|
|
54036
|
+
}
|
|
53984
54037
|
const existing = readLink(cwd2);
|
|
53985
54038
|
if (existing) {
|
|
53986
54039
|
writeLink(cwd2, {
|
|
@@ -54542,6 +54595,11 @@ async function runAgentCreate(cwd2, args) {
|
|
|
54542
54595
|
}
|
|
54543
54596
|
}
|
|
54544
54597
|
if (updatedCloud) {
|
|
54598
|
+
const backfill = backfillPlaybookIds(manifest.playbooks ?? [], updatedCloud.components);
|
|
54599
|
+
if (backfill.changed) {
|
|
54600
|
+
manifest.playbooks = backfill.playbooks;
|
|
54601
|
+
writeManifest(cwd2, manifest);
|
|
54602
|
+
}
|
|
54545
54603
|
const localHashByKey = new Map;
|
|
54546
54604
|
for (const lc of readLocalComponents(cwd2, manifest)) {
|
|
54547
54605
|
if (lc.hash)
|
|
@@ -54947,7 +55005,7 @@ async function runAgent(cwd2, sub, args, opts) {
|
|
|
54947
55005
|
});
|
|
54948
55006
|
return;
|
|
54949
55007
|
case "push":
|
|
54950
|
-
await runAgentPush(cwd2, { yes: opts.yes });
|
|
55008
|
+
await runAgentPush(cwd2, { yes: opts.yes, force: opts.force });
|
|
54951
55009
|
return;
|
|
54952
55010
|
case "unpack":
|
|
54953
55011
|
await runAgentUnpack(cwd2, {
|
|
@@ -54982,7 +55040,7 @@ function printHelp() {
|
|
|
54982
55040
|
out.push("");
|
|
54983
55041
|
out.push(` ${import_picocolors32.default.cyan("create")} ${import_picocolors32.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
|
|
54984
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")}`);
|
|
54985
|
-
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)")}`);
|
|
54986
55044
|
out.push(` ${import_picocolors32.default.cyan("unpack")} ${import_picocolors32.default.dim("install the claimed agent into a harness layout (--harness to override)")}`);
|
|
54987
55045
|
out.push(` ${import_picocolors32.default.cyan("status")} ${import_picocolors32.default.dim("show what would push and what would pull")}`);
|
|
54988
55046
|
out.push(` ${import_picocolors32.default.cyan("env")} ${import_picocolors32.default.dim('print export statements — use with `eval "$(brainbase agent env)"`')}`);
|
|
@@ -55002,7 +55060,7 @@ var import_picocolors33 = __toESM(require_picocolors(), 1);
|
|
|
55002
55060
|
// src/core/orchestration-manifest.ts
|
|
55003
55061
|
import path51 from "node:path";
|
|
55004
55062
|
import fs47 from "node:fs";
|
|
55005
|
-
var
|
|
55063
|
+
var import_yaml3 = __toESM(require_dist(), 1);
|
|
55006
55064
|
var ORCH_MANIFEST_FILE = "brainbase-orchestration.yaml";
|
|
55007
55065
|
var ORCH_MEMBERS_DIR = "agents";
|
|
55008
55066
|
var OrchMetaSchema = exports_external.object({
|
|
@@ -55054,7 +55112,7 @@ function readOrchManifest(cwd2) {
|
|
|
55054
55112
|
const raw = fs47.readFileSync(p2, "utf8");
|
|
55055
55113
|
let parsed;
|
|
55056
55114
|
try {
|
|
55057
|
-
parsed =
|
|
55115
|
+
parsed = import_yaml3.default.parse(raw);
|
|
55058
55116
|
} catch (err) {
|
|
55059
55117
|
throw new Error(`${ORCH_MANIFEST_FILE} is not valid YAML: ${err.message}`);
|
|
55060
55118
|
}
|
|
@@ -55065,7 +55123,7 @@ function readOrchManifest(cwd2) {
|
|
|
55065
55123
|
return result2.data;
|
|
55066
55124
|
}
|
|
55067
55125
|
function writeOrchManifest(cwd2, manifest) {
|
|
55068
|
-
const doc = new
|
|
55126
|
+
const doc = new import_yaml3.default.Document;
|
|
55069
55127
|
doc.contents = manifest;
|
|
55070
55128
|
doc.commentBefore = ` brainbase-orchestration.yaml — declarative orchestration manifest.
|
|
55071
55129
|
` + ` Committed to source control. Edit by hand, then
|
|
@@ -56920,7 +56978,7 @@ function help() {
|
|
|
56920
56978
|
out.push("");
|
|
56921
56979
|
out.push(` ${import_picocolors41.default.cyan("agent create")} ${import_picocolors41.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
|
|
56922
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)")}`);
|
|
56923
|
-
out.push(` ${import_picocolors41.default.cyan("agent push")} ${import_picocolors41.default.dim("send local changes to the cloud
|
|
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)")}`);
|
|
56924
56982
|
out.push(` ${import_picocolors41.default.cyan("agent unpack")} ${import_picocolors41.default.dim("install the claimed agent into a harness layout")}`);
|
|
56925
56983
|
out.push(` ${import_picocolors41.default.cyan("link")} ${import_picocolors41.default.dim("attach this folder to an existing agent")}`);
|
|
56926
56984
|
out.push(` ${import_picocolors41.default.cyan("agent status")} ${import_picocolors41.default.dim("show what would pull and what would push")}`);
|