@brainbase-labs/cli 0.5.0 → 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.
- package/dist/index.js +556 -248
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28566,7 +28566,7 @@ var require_jsx_dev_runtime = __commonJS((exports, module) => {
|
|
|
28566
28566
|
// src/index.ts
|
|
28567
28567
|
var import_picocolors40 = __toESM(require_picocolors(), 1);
|
|
28568
28568
|
import process13 from "node:process";
|
|
28569
|
-
import
|
|
28569
|
+
import fs51 from "node:fs";
|
|
28570
28570
|
|
|
28571
28571
|
// src/cli/template.ts
|
|
28572
28572
|
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
@@ -50768,8 +50768,9 @@ import fs39 from "node:fs";
|
|
|
50768
50768
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
50769
50769
|
var AGENT_MANIFEST_FILE = "brainbase.agent.yaml";
|
|
50770
50770
|
var LEGACY_AGENT_MANIFEST_FILE = "brainbase.yaml";
|
|
50771
|
-
var DEFAULT_INSTRUCTIONS_FILE = "instructions.md";
|
|
50772
|
-
var DEFAULT_ENTRYPOINT_FILE = "entrypoint.sh";
|
|
50771
|
+
var DEFAULT_INSTRUCTIONS_FILE = ".brainbase/instructions.md";
|
|
50772
|
+
var DEFAULT_ENTRYPOINT_FILE = ".brainbase/entrypoint.sh";
|
|
50773
|
+
var DEFAULT_PLAYBOOKS_DIR = ".brainbase/playbooks";
|
|
50773
50774
|
var REGISTRY_SOURCE_RE = /^registry:(?:([a-z0-9_-]+)\/)?([a-z0-9_-]+)(?:@(.+))?$/i;
|
|
50774
50775
|
function parseSkillSource2(raw) {
|
|
50775
50776
|
if (!raw || typeof raw !== "string") {
|
|
@@ -50809,6 +50810,17 @@ var EntrypointSchema = exports_external.object({
|
|
|
50809
50810
|
}, {
|
|
50810
50811
|
message: "entrypoint must set exactly one of `file`, `commands`, or `text`"
|
|
50811
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
|
+
});
|
|
50812
50824
|
var SkillEntrySchema = exports_external.object({
|
|
50813
50825
|
source: exports_external.string().min(1)
|
|
50814
50826
|
});
|
|
@@ -50828,6 +50840,7 @@ var AgentManifestSchema = exports_external.object({
|
|
|
50828
50840
|
agent: AgentMetaSchema,
|
|
50829
50841
|
instructions: InstructionsSchema.optional(),
|
|
50830
50842
|
entrypoint: EntrypointSchema.optional(),
|
|
50843
|
+
playbooks: exports_external.array(PlaybookSchema).default([]),
|
|
50831
50844
|
skills: exports_external.array(SkillEntrySchema).default([]),
|
|
50832
50845
|
mcp: exports_external.array(McpEntrySchema).default([]),
|
|
50833
50846
|
commands: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
|
|
@@ -50911,6 +50924,21 @@ function resolveEntrypoint(cwd2, manifest) {
|
|
|
50911
50924
|
}
|
|
50912
50925
|
return null;
|
|
50913
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
|
+
}
|
|
50914
50942
|
|
|
50915
50943
|
// src/core/link.ts
|
|
50916
50944
|
var LINK_DIR = ".brainbase";
|
|
@@ -51064,6 +51092,7 @@ function writeLink(cwd2, link2) {
|
|
|
51064
51092
|
manifest = readManifest(cwd2) ?? {
|
|
51065
51093
|
schema: 1,
|
|
51066
51094
|
agent: { name: link2.name },
|
|
51095
|
+
playbooks: [],
|
|
51067
51096
|
skills: [],
|
|
51068
51097
|
mcp: []
|
|
51069
51098
|
};
|
|
@@ -51071,6 +51100,7 @@ function writeLink(cwd2, link2) {
|
|
|
51071
51100
|
manifest = {
|
|
51072
51101
|
schema: 1,
|
|
51073
51102
|
agent: { name: link2.name },
|
|
51103
|
+
playbooks: [],
|
|
51074
51104
|
skills: [],
|
|
51075
51105
|
mcp: []
|
|
51076
51106
|
};
|
|
@@ -51973,6 +52003,7 @@ import path48 from "node:path";
|
|
|
51973
52003
|
import fs45 from "node:fs";
|
|
51974
52004
|
import os12 from "node:os";
|
|
51975
52005
|
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
52006
|
+
var import_yaml3 = __toESM(require_dist(), 1);
|
|
51976
52007
|
|
|
51977
52008
|
// src/core/agent-diff.ts
|
|
51978
52009
|
import path46 from "node:path";
|
|
@@ -52119,8 +52150,34 @@ function readLocalComponents(cwd2, manifest) {
|
|
|
52119
52150
|
hash: hashMcpEntry(entry)
|
|
52120
52151
|
});
|
|
52121
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
|
+
}
|
|
52122
52174
|
return out;
|
|
52123
52175
|
}
|
|
52176
|
+
function jsonOrPlain(s3) {
|
|
52177
|
+
if (!/[\n":#&*!|>'%@`{}[\]]/.test(s3) && s3.trim() === s3 && s3 !== "")
|
|
52178
|
+
return s3;
|
|
52179
|
+
return JSON.stringify(s3);
|
|
52180
|
+
}
|
|
52124
52181
|
function threeWayDiff(input) {
|
|
52125
52182
|
const lockMap = new Map;
|
|
52126
52183
|
for (const c2 of input.lock)
|
|
@@ -52489,8 +52546,9 @@ async function runAgentPull(cwd2, args) {
|
|
|
52489
52546
|
}
|
|
52490
52547
|
}
|
|
52491
52548
|
}
|
|
52492
|
-
materializeInstructions(cwd2, cloud, toInstallKeys, keepLocalKeys);
|
|
52549
|
+
materializeInstructions(cwd2, cloud, toInstallKeys, keepLocalKeys, existingManifest);
|
|
52493
52550
|
materializeEntrypoint(cwd2, cloudAgent.entrypoint ?? "", existingManifest);
|
|
52551
|
+
materializePlaybooks(cwd2, cloud, toInstallKeys, keepLocalKeys, existingManifest);
|
|
52494
52552
|
const yaml = mergeManifest(cwd2, existingManifest, cloud, cloudAgent, harness);
|
|
52495
52553
|
writeManifest(cwd2, yaml);
|
|
52496
52554
|
writeLink(cwd2, buildLinkFromAgent(cloudAgent, harness, readLink(cwd2)));
|
|
@@ -52595,7 +52653,7 @@ function runHarnessInstall2(harnessId, components, opts, agentName) {
|
|
|
52595
52653
|
return installKafkaWithCtx(components, opts, agentName);
|
|
52596
52654
|
return getAdapter(harnessId).install(components, opts);
|
|
52597
52655
|
}
|
|
52598
|
-
function materializeInstructions(cwd2, cloud, toInstall, keepLocal) {
|
|
52656
|
+
function materializeInstructions(cwd2, cloud, toInstall, keepLocal, existingManifest) {
|
|
52599
52657
|
for (const c2 of cloud.components) {
|
|
52600
52658
|
if (c2.type !== "instruction")
|
|
52601
52659
|
continue;
|
|
@@ -52607,8 +52665,52 @@ function materializeInstructions(cwd2, cloud, toInstall, keepLocal) {
|
|
|
52607
52665
|
const body = c2.files[0]?.content ?? "";
|
|
52608
52666
|
if (!body.trim())
|
|
52609
52667
|
continue;
|
|
52610
|
-
|
|
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 };
|
|
52611
52712
|
}
|
|
52713
|
+
return { frontmatter: fm, body: raw.slice(m3[0].length) };
|
|
52612
52714
|
}
|
|
52613
52715
|
function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
|
|
52614
52716
|
const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
|
|
@@ -52645,6 +52747,21 @@ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
|
|
|
52645
52747
|
else
|
|
52646
52748
|
entrypoint = { file: prev?.entrypoint?.file ?? DEFAULT_ENTRYPOINT_FILE };
|
|
52647
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
|
+
});
|
|
52648
52765
|
const mcp = cloud.components.filter((c2) => c2.type === "mcp").map((c2) => {
|
|
52649
52766
|
const payload = (c2.meta ?? {}).mcp ?? {};
|
|
52650
52767
|
const entry = { name: c2.slug };
|
|
@@ -52672,6 +52789,7 @@ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
|
|
|
52672
52789
|
},
|
|
52673
52790
|
...instructions ? { instructions } : {},
|
|
52674
52791
|
...entrypoint ? { entrypoint } : {},
|
|
52792
|
+
playbooks,
|
|
52675
52793
|
skills,
|
|
52676
52794
|
mcp
|
|
52677
52795
|
};
|
|
@@ -52910,6 +53028,42 @@ async function buildOutgoingComponents(cwd2, manifest, cloud) {
|
|
|
52910
53028
|
}
|
|
52911
53029
|
});
|
|
52912
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
|
+
}
|
|
52913
53067
|
for (const entry of manifest.mcp ?? []) {
|
|
52914
53068
|
if (!entry.url && !entry.command) {
|
|
52915
53069
|
f2.error(`MCP ${import_picocolors26.default.bold(entry.name)} needs either ${import_picocolors26.default.cyan("url")} or ${import_picocolors26.default.cyan("command")}.`);
|
|
@@ -52937,6 +53091,23 @@ async function buildOutgoingComponents(cwd2, manifest, cloud) {
|
|
|
52937
53091
|
}
|
|
52938
53092
|
return out;
|
|
52939
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
|
+
}
|
|
52940
53111
|
|
|
52941
53112
|
// src/cli/agent-push.ts
|
|
52942
53113
|
async function runAgentPush(cwd2, args) {
|
|
@@ -53003,8 +53174,8 @@ async function runAgentPush(cwd2, args) {
|
|
|
53003
53174
|
}
|
|
53004
53175
|
const entrypointChanged = resolvedEntrypoint !== undefined && resolvedEntrypoint !== (lock?.agentMeta?.entrypoint ?? "");
|
|
53005
53176
|
for (const r2 of rows) {
|
|
53006
|
-
if (r2.type !== "instruction" && r2.type !== "skill" && r2.type !== "mcp") {
|
|
53007
|
-
f2.error(`Component ${fmtType(r2.type)} ${import_picocolors27.default.bold(r2.slug)} can't be pushed yet — the server accepts instructions, skills, and
|
|
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.`);
|
|
53008
53179
|
return;
|
|
53009
53180
|
}
|
|
53010
53181
|
}
|
|
@@ -53731,6 +53902,7 @@ async function loadOrScaffoldManifest(cwd2, args) {
|
|
|
53731
53902
|
schema: 1,
|
|
53732
53903
|
...seedHarness ? { harness: seedHarness } : {},
|
|
53733
53904
|
agent: { name: seedName, ...args.tagline ? { tagline: args.tagline } : {} },
|
|
53905
|
+
playbooks: [],
|
|
53734
53906
|
skills: [],
|
|
53735
53907
|
mcp: []
|
|
53736
53908
|
};
|
|
@@ -53774,183 +53946,10 @@ function handleApiError4(err) {
|
|
|
53774
53946
|
}
|
|
53775
53947
|
|
|
53776
53948
|
// src/cli/agent-unpack.ts
|
|
53777
|
-
var import_picocolors31 = __toESM(require_picocolors(), 1);
|
|
53778
|
-
|
|
53779
|
-
// src/core/agent-fresh-install.ts
|
|
53780
53949
|
import path50 from "node:path";
|
|
53781
53950
|
import fs46 from "node:fs";
|
|
53782
53951
|
import os13 from "node:os";
|
|
53783
|
-
|
|
53784
|
-
const { cwd: cwd2, agent, cloud, harness } = input;
|
|
53785
|
-
const scope = input.scope ?? "project";
|
|
53786
|
-
ensureDir(cwd2);
|
|
53787
|
-
const stageRoot = stageManifestComponents2(cloud.components);
|
|
53788
|
-
const justInstalledPaths = new Map;
|
|
53789
|
-
const cloudHasOrchestrationMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === ORCHESTRATION_MCP_SLUG);
|
|
53790
|
-
const needOrchestrationMcpInstall = !cloudHasOrchestrationMcp;
|
|
53791
|
-
const cloudHasMemoryMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === MEMORY_MCP_SLUG);
|
|
53792
|
-
const needMemoryMcpInstall = !cloudHasMemoryMcp;
|
|
53793
|
-
try {
|
|
53794
|
-
if (cloud.components.length > 0 || needOrchestrationMcpInstall || needMemoryMcpInstall) {
|
|
53795
|
-
const toInstall = cloud.components.map((c2) => ({
|
|
53796
|
-
type: c2.type,
|
|
53797
|
-
slug: c2.slug,
|
|
53798
|
-
scope,
|
|
53799
|
-
rootDir: path50.join(stageRoot, c2.type, c2.slug),
|
|
53800
|
-
description: c2.description,
|
|
53801
|
-
meta: c2.meta,
|
|
53802
|
-
payload: c2.meta?.mcp,
|
|
53803
|
-
checksum: c2.hash
|
|
53804
|
-
}));
|
|
53805
|
-
if (needOrchestrationMcpInstall) {
|
|
53806
|
-
toInstall.push(buildOrchestrationMcpComponent(scope));
|
|
53807
|
-
}
|
|
53808
|
-
if (needMemoryMcpInstall) {
|
|
53809
|
-
toInstall.push(buildMemoryMcpComponent(scope));
|
|
53810
|
-
}
|
|
53811
|
-
const installOpts = {
|
|
53812
|
-
cwd: cwd2,
|
|
53813
|
-
scope,
|
|
53814
|
-
resolveConflict: async (_c) => "overwrite",
|
|
53815
|
-
resolveSecret: async () => null
|
|
53816
|
-
};
|
|
53817
|
-
const result = await runHarnessInstall3(harness, toInstall, installOpts, agent.name);
|
|
53818
|
-
for (const o2 of result.installed) {
|
|
53819
|
-
justInstalledPaths.set(`${o2.type}/${o2.slug}`, o2.installedPaths);
|
|
53820
|
-
}
|
|
53821
|
-
}
|
|
53822
|
-
materializeInstructions2(cwd2, cloud);
|
|
53823
|
-
const manifest = input.preserveManifest ? null : buildManifestFromCloud(cloud, agent);
|
|
53824
|
-
if (manifest)
|
|
53825
|
-
writeManifest(cwd2, manifest);
|
|
53826
|
-
writeLink(cwd2, {
|
|
53827
|
-
schemaVersion: 1,
|
|
53828
|
-
agent_id: agent.id,
|
|
53829
|
-
org_id: agent.org_id,
|
|
53830
|
-
team_id: agent.team_id,
|
|
53831
|
-
slug: agent.slug,
|
|
53832
|
-
name: agent.name,
|
|
53833
|
-
tagline: agent.tagline,
|
|
53834
|
-
url: agent.url,
|
|
53835
|
-
linked_at: new Date().toISOString(),
|
|
53836
|
-
harness
|
|
53837
|
-
});
|
|
53838
|
-
const syncedComponents = cloud.components.map((c2) => ({
|
|
53839
|
-
type: c2.type,
|
|
53840
|
-
slug: c2.slug,
|
|
53841
|
-
hash: c2.hash,
|
|
53842
|
-
installedPaths: justInstalledPaths.get(`${c2.type}/${c2.slug}`) ?? []
|
|
53843
|
-
}));
|
|
53844
|
-
writeSyncState(cwd2, {
|
|
53845
|
-
schemaVersion: 1,
|
|
53846
|
-
agent_id: agent.id,
|
|
53847
|
-
revision: cloud.revision,
|
|
53848
|
-
synced_at: new Date().toISOString(),
|
|
53849
|
-
components: syncedComponents,
|
|
53850
|
-
agentMeta: { name: agent.name, tagline: agent.tagline }
|
|
53851
|
-
});
|
|
53852
|
-
if (input.pullSecrets !== false) {
|
|
53853
|
-
await pullAgentSecrets(cwd2, agent.id);
|
|
53854
|
-
}
|
|
53855
|
-
const returnedManifest = manifest ?? buildManifestFromCloud(cloud, agent);
|
|
53856
|
-
return {
|
|
53857
|
-
installedPaths: justInstalledPaths,
|
|
53858
|
-
manifest: returnedManifest,
|
|
53859
|
-
syncedComponents
|
|
53860
|
-
};
|
|
53861
|
-
} finally {
|
|
53862
|
-
try {
|
|
53863
|
-
fs46.rmSync(stageRoot, { recursive: true, force: true });
|
|
53864
|
-
} catch {}
|
|
53865
|
-
}
|
|
53866
|
-
}
|
|
53867
|
-
function stageManifestComponents2(components) {
|
|
53868
|
-
const root = fs46.mkdtempSync(path50.join(os13.tmpdir(), "brainbase-orch-pull-"));
|
|
53869
|
-
for (const c2 of components) {
|
|
53870
|
-
const compDir = path50.join(root, c2.type, c2.slug);
|
|
53871
|
-
ensureDir(compDir);
|
|
53872
|
-
for (const f4 of c2.files) {
|
|
53873
|
-
const target = path50.join(compDir, f4.path);
|
|
53874
|
-
ensureDir(path50.dirname(target));
|
|
53875
|
-
fs46.writeFileSync(target, f4.content);
|
|
53876
|
-
}
|
|
53877
|
-
}
|
|
53878
|
-
return root;
|
|
53879
|
-
}
|
|
53880
|
-
function runHarnessInstall3(harnessId, components, opts, agentName) {
|
|
53881
|
-
if (harnessId === "claude-code")
|
|
53882
|
-
return installClaudeCodeWithCtx(components, opts, agentName);
|
|
53883
|
-
if (harnessId === "codex")
|
|
53884
|
-
return installCodexWithCtx(components, opts, agentName);
|
|
53885
|
-
if (harnessId === "kafka")
|
|
53886
|
-
return installKafkaWithCtx(components, opts, agentName);
|
|
53887
|
-
return getAdapter(harnessId).install(components, opts);
|
|
53888
|
-
}
|
|
53889
|
-
function materializeInstructions2(cwd2, cloud) {
|
|
53890
|
-
for (const c2 of cloud.components) {
|
|
53891
|
-
if (c2.type !== "instruction")
|
|
53892
|
-
continue;
|
|
53893
|
-
const body = c2.files[0]?.content ?? "";
|
|
53894
|
-
if (!body.trim())
|
|
53895
|
-
continue;
|
|
53896
|
-
fs46.writeFileSync(path50.join(cwd2, DEFAULT_INSTRUCTIONS_FILE), body, "utf8");
|
|
53897
|
-
return;
|
|
53898
|
-
}
|
|
53899
|
-
}
|
|
53900
|
-
function buildManifestFromCloud(cloud, agent) {
|
|
53901
|
-
const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
|
|
53902
|
-
const meta = c2.meta ?? {};
|
|
53903
|
-
if (meta.name && meta.name.includes("/")) {
|
|
53904
|
-
return {
|
|
53905
|
-
source: meta.version ? `registry:${meta.name}@${meta.version}` : `registry:${meta.name}`
|
|
53906
|
-
};
|
|
53907
|
-
}
|
|
53908
|
-
return { source: `registry:${c2.slug}` };
|
|
53909
|
-
});
|
|
53910
|
-
const hasInstructions = cloud.components.some((c2) => c2.type === "instruction" && c2.files[0]?.content?.trim());
|
|
53911
|
-
const mcp = cloud.components.filter((c2) => c2.type === "mcp").map((c2) => {
|
|
53912
|
-
const payload = (c2.meta ?? {}).mcp ?? {};
|
|
53913
|
-
const entry = { name: c2.slug };
|
|
53914
|
-
if (typeof payload.url === "string")
|
|
53915
|
-
entry.url = payload.url;
|
|
53916
|
-
if (typeof payload.command === "string")
|
|
53917
|
-
entry.command = payload.command;
|
|
53918
|
-
if (Array.isArray(payload.args))
|
|
53919
|
-
entry.args = payload.args.map(String);
|
|
53920
|
-
if (payload.env && typeof payload.env === "object")
|
|
53921
|
-
entry.env = payload.env;
|
|
53922
|
-
if (payload.headers && typeof payload.headers === "object")
|
|
53923
|
-
entry.headers = payload.headers;
|
|
53924
|
-
if (typeof payload.is_enabled === "boolean")
|
|
53925
|
-
entry.is_enabled = payload.is_enabled;
|
|
53926
|
-
return entry;
|
|
53927
|
-
});
|
|
53928
|
-
return {
|
|
53929
|
-
schema: 1,
|
|
53930
|
-
agent: {
|
|
53931
|
-
name: agent.name,
|
|
53932
|
-
...agent.tagline ? { tagline: agent.tagline } : {}
|
|
53933
|
-
},
|
|
53934
|
-
...hasInstructions ? { instructions: { file: DEFAULT_INSTRUCTIONS_FILE } } : {},
|
|
53935
|
-
skills,
|
|
53936
|
-
mcp
|
|
53937
|
-
};
|
|
53938
|
-
}
|
|
53939
|
-
async function pullAgentSecrets(cwd2, agentId) {
|
|
53940
|
-
try {
|
|
53941
|
-
const res = await api.getAgentSecrets(agentId);
|
|
53942
|
-
const secrets = res.secrets ?? {};
|
|
53943
|
-
if (Object.keys(secrets).length > 0) {
|
|
53944
|
-
writeLocalSecrets(cwd2, secrets);
|
|
53945
|
-
}
|
|
53946
|
-
} catch (err) {
|
|
53947
|
-
if (err instanceof ApiError && err.status !== 404) {
|
|
53948
|
-
f2.warn(`Skipped secrets for agent ${agentId}: ${err.message}`);
|
|
53949
|
-
}
|
|
53950
|
-
}
|
|
53951
|
-
}
|
|
53952
|
-
|
|
53953
|
-
// src/cli/agent-unpack.ts
|
|
53952
|
+
var import_picocolors31 = __toESM(require_picocolors(), 1);
|
|
53954
53953
|
async function runAgentUnpack(cwd2, args) {
|
|
53955
53954
|
banner("agent unpack — install this agent into a harness layout");
|
|
53956
53955
|
if (!hasManifest(cwd2)) {
|
|
@@ -53982,22 +53981,9 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
53982
53981
|
} else {
|
|
53983
53982
|
harness = await pickHarness2(manifest.harness);
|
|
53984
53983
|
}
|
|
53985
|
-
const sp = de();
|
|
53986
|
-
sp.start("Fetching agent…");
|
|
53987
|
-
let cloudAgent;
|
|
53988
|
-
let cloud;
|
|
53989
|
-
try {
|
|
53990
|
-
cloudAgent = await api.getAgent(manifest.id);
|
|
53991
|
-
cloud = await api.getAgentManifest(manifest.id);
|
|
53992
|
-
sp.stop(`Cloud revision ${cloud.revision}.`);
|
|
53993
|
-
} catch (err) {
|
|
53994
|
-
sp.stop("Failed.");
|
|
53995
|
-
handleApiError5(err);
|
|
53996
|
-
return;
|
|
53997
|
-
}
|
|
53998
53984
|
if (!args.yes) {
|
|
53999
53985
|
const ok = await se({
|
|
54000
|
-
message: `Install ${import_picocolors31.default.bold(
|
|
53986
|
+
message: `Install ${import_picocolors31.default.bold(manifest.agent.name)} as ${import_picocolors31.default.bold(harness)} here?`,
|
|
54001
53987
|
initialValue: true
|
|
54002
53988
|
});
|
|
54003
53989
|
if (!ensureNotCancelled(ok)) {
|
|
@@ -54005,46 +53991,206 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
54005
53991
|
return;
|
|
54006
53992
|
}
|
|
54007
53993
|
}
|
|
54008
|
-
const
|
|
53994
|
+
const scope = args.scope ?? "project";
|
|
53995
|
+
const stageRoot = fs46.mkdtempSync(path50.join(os13.tmpdir(), "brainbase-unpack-"));
|
|
54009
53996
|
try {
|
|
54010
|
-
|
|
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 = {
|
|
54011
54055
|
cwd: cwd2,
|
|
54012
|
-
|
|
54013
|
-
|
|
54014
|
-
|
|
54015
|
-
|
|
54016
|
-
|
|
54017
|
-
|
|
54018
|
-
|
|
54019
|
-
|
|
54020
|
-
|
|
54021
|
-
},
|
|
54022
|
-
|
|
54023
|
-
harness,
|
|
54024
|
-
scope: args.scope ?? "project",
|
|
54025
|
-
preserveManifest: true
|
|
54026
|
-
});
|
|
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
|
+
}
|
|
54027
54067
|
} catch (err) {
|
|
54028
54068
|
f2.error(`Install failed: ${err.message}`);
|
|
54029
54069
|
return;
|
|
54070
|
+
} finally {
|
|
54071
|
+
try {
|
|
54072
|
+
fs46.rmSync(stageRoot, { recursive: true, force: true });
|
|
54073
|
+
} catch {}
|
|
54030
54074
|
}
|
|
54031
|
-
manifest = readManifest(cwd2);
|
|
54032
54075
|
if (manifest.harness !== harness) {
|
|
54033
54076
|
manifest.harness = harness;
|
|
54034
54077
|
writeManifest(cwd2, manifest);
|
|
54035
54078
|
}
|
|
54036
|
-
$e(`Unpacked ${import_picocolors31.default.bold(
|
|
54079
|
+
$e(`Unpacked ${import_picocolors31.default.bold(manifest.agent.name)} as ${import_picocolors31.default.bold(harness)}.`);
|
|
54037
54080
|
await showResultCard({
|
|
54038
54081
|
title: "UNPACKED",
|
|
54039
54082
|
tone: "ok",
|
|
54040
|
-
subtitle:
|
|
54083
|
+
subtitle: manifest.agent.name,
|
|
54041
54084
|
meta: [
|
|
54042
54085
|
["harness", harness],
|
|
54043
|
-
["agent",
|
|
54044
|
-
...cloudAgent.url ? [["url", cloudAgent.url]] : []
|
|
54086
|
+
["agent", manifest.id]
|
|
54045
54087
|
]
|
|
54046
54088
|
});
|
|
54047
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
|
+
}
|
|
54048
54194
|
async function pickHarness2(current) {
|
|
54049
54195
|
const initial = current ? normalizeHarnessId(current) : undefined;
|
|
54050
54196
|
const choice = await ie({
|
|
@@ -54058,19 +54204,6 @@ async function pickHarness2(current) {
|
|
|
54058
54204
|
});
|
|
54059
54205
|
return ensureNotCancelled(choice);
|
|
54060
54206
|
}
|
|
54061
|
-
function handleApiError5(err) {
|
|
54062
|
-
if (err instanceof ApiError) {
|
|
54063
|
-
if (err.status === 401) {
|
|
54064
|
-
f2.error("Your session is invalid. Run `brainbase login` and try again.");
|
|
54065
|
-
} else if (err.status === 404) {
|
|
54066
|
-
f2.error(`Agent not found, or you don't have access. The id in ${import_picocolors31.default.bold(AGENT_MANIFEST_FILE)} may be stale.`);
|
|
54067
|
-
} else {
|
|
54068
|
-
f2.error(err.message);
|
|
54069
|
-
}
|
|
54070
|
-
} else {
|
|
54071
|
-
f2.error(err.message);
|
|
54072
|
-
}
|
|
54073
|
-
}
|
|
54074
54207
|
|
|
54075
54208
|
// src/cli/agent.ts
|
|
54076
54209
|
async function runAgent(cwd2, sub, args, opts) {
|
|
@@ -54143,14 +54276,14 @@ function printHelp() {
|
|
|
54143
54276
|
var import_picocolors37 = __toESM(require_picocolors(), 1);
|
|
54144
54277
|
|
|
54145
54278
|
// src/cli/orchestration-pull.ts
|
|
54146
|
-
import
|
|
54147
|
-
import
|
|
54279
|
+
import path54 from "node:path";
|
|
54280
|
+
import fs50 from "node:fs";
|
|
54148
54281
|
var import_picocolors33 = __toESM(require_picocolors(), 1);
|
|
54149
54282
|
|
|
54150
54283
|
// src/core/orchestration-manifest.ts
|
|
54151
54284
|
import path51 from "node:path";
|
|
54152
54285
|
import fs47 from "node:fs";
|
|
54153
|
-
var
|
|
54286
|
+
var import_yaml4 = __toESM(require_dist(), 1);
|
|
54154
54287
|
var ORCH_MANIFEST_FILE = "brainbase-orchestration.yaml";
|
|
54155
54288
|
var ORCH_MEMBERS_DIR = "agents";
|
|
54156
54289
|
var OrchMetaSchema = exports_external.object({
|
|
@@ -54189,7 +54322,7 @@ function readOrchManifest(cwd2) {
|
|
|
54189
54322
|
const raw = fs47.readFileSync(p2, "utf8");
|
|
54190
54323
|
let parsed;
|
|
54191
54324
|
try {
|
|
54192
|
-
parsed =
|
|
54325
|
+
parsed = import_yaml4.default.parse(raw);
|
|
54193
54326
|
} catch (err) {
|
|
54194
54327
|
throw new Error(`${ORCH_MANIFEST_FILE} is not valid YAML: ${err.message}`);
|
|
54195
54328
|
}
|
|
@@ -54200,7 +54333,7 @@ function readOrchManifest(cwd2) {
|
|
|
54200
54333
|
return result.data;
|
|
54201
54334
|
}
|
|
54202
54335
|
function writeOrchManifest(cwd2, manifest) {
|
|
54203
|
-
const doc = new
|
|
54336
|
+
const doc = new import_yaml4.default.Document;
|
|
54204
54337
|
doc.contents = manifest;
|
|
54205
54338
|
doc.commentBefore = ` brainbase-orchestration.yaml — declarative orchestration manifest.
|
|
54206
54339
|
` + ` Committed to source control. Edit by hand, then
|
|
@@ -54305,6 +54438,181 @@ function ensureGitignore2(cwd2) {
|
|
|
54305
54438
|
} catch {}
|
|
54306
54439
|
}
|
|
54307
54440
|
|
|
54441
|
+
// src/core/agent-fresh-install.ts
|
|
54442
|
+
import path53 from "node:path";
|
|
54443
|
+
import fs49 from "node:fs";
|
|
54444
|
+
import os14 from "node:os";
|
|
54445
|
+
async function installAgentFresh(input) {
|
|
54446
|
+
const { cwd: cwd2, agent, cloud, harness } = input;
|
|
54447
|
+
const scope = input.scope ?? "project";
|
|
54448
|
+
ensureDir(cwd2);
|
|
54449
|
+
const stageRoot = stageManifestComponents2(cloud.components);
|
|
54450
|
+
const justInstalledPaths = new Map;
|
|
54451
|
+
const cloudHasOrchestrationMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === ORCHESTRATION_MCP_SLUG);
|
|
54452
|
+
const needOrchestrationMcpInstall = !cloudHasOrchestrationMcp;
|
|
54453
|
+
const cloudHasMemoryMcp = cloud.components.some((c2) => c2.type === "mcp" && c2.slug === MEMORY_MCP_SLUG);
|
|
54454
|
+
const needMemoryMcpInstall = !cloudHasMemoryMcp;
|
|
54455
|
+
try {
|
|
54456
|
+
if (cloud.components.length > 0 || needOrchestrationMcpInstall || needMemoryMcpInstall) {
|
|
54457
|
+
const toInstall = cloud.components.map((c2) => ({
|
|
54458
|
+
type: c2.type,
|
|
54459
|
+
slug: c2.slug,
|
|
54460
|
+
scope,
|
|
54461
|
+
rootDir: path53.join(stageRoot, c2.type, c2.slug),
|
|
54462
|
+
description: c2.description,
|
|
54463
|
+
meta: c2.meta,
|
|
54464
|
+
payload: c2.meta?.mcp,
|
|
54465
|
+
checksum: c2.hash
|
|
54466
|
+
}));
|
|
54467
|
+
if (needOrchestrationMcpInstall) {
|
|
54468
|
+
toInstall.push(buildOrchestrationMcpComponent(scope));
|
|
54469
|
+
}
|
|
54470
|
+
if (needMemoryMcpInstall) {
|
|
54471
|
+
toInstall.push(buildMemoryMcpComponent(scope));
|
|
54472
|
+
}
|
|
54473
|
+
const installOpts = {
|
|
54474
|
+
cwd: cwd2,
|
|
54475
|
+
scope,
|
|
54476
|
+
resolveConflict: async (_c) => "overwrite",
|
|
54477
|
+
resolveSecret: async () => null
|
|
54478
|
+
};
|
|
54479
|
+
const result = await runHarnessInstall4(harness, toInstall, installOpts, agent.name);
|
|
54480
|
+
for (const o2 of result.installed) {
|
|
54481
|
+
justInstalledPaths.set(`${o2.type}/${o2.slug}`, o2.installedPaths);
|
|
54482
|
+
}
|
|
54483
|
+
}
|
|
54484
|
+
materializeInstructions2(cwd2, cloud);
|
|
54485
|
+
const manifest = input.preserveManifest ? null : buildManifestFromCloud(cloud, agent);
|
|
54486
|
+
if (manifest)
|
|
54487
|
+
writeManifest(cwd2, manifest);
|
|
54488
|
+
writeLink(cwd2, {
|
|
54489
|
+
schemaVersion: 1,
|
|
54490
|
+
agent_id: agent.id,
|
|
54491
|
+
org_id: agent.org_id,
|
|
54492
|
+
team_id: agent.team_id,
|
|
54493
|
+
slug: agent.slug,
|
|
54494
|
+
name: agent.name,
|
|
54495
|
+
tagline: agent.tagline,
|
|
54496
|
+
url: agent.url,
|
|
54497
|
+
linked_at: new Date().toISOString(),
|
|
54498
|
+
harness
|
|
54499
|
+
});
|
|
54500
|
+
const syncedComponents = cloud.components.map((c2) => ({
|
|
54501
|
+
type: c2.type,
|
|
54502
|
+
slug: c2.slug,
|
|
54503
|
+
hash: c2.hash,
|
|
54504
|
+
installedPaths: justInstalledPaths.get(`${c2.type}/${c2.slug}`) ?? []
|
|
54505
|
+
}));
|
|
54506
|
+
writeSyncState(cwd2, {
|
|
54507
|
+
schemaVersion: 1,
|
|
54508
|
+
agent_id: agent.id,
|
|
54509
|
+
revision: cloud.revision,
|
|
54510
|
+
synced_at: new Date().toISOString(),
|
|
54511
|
+
components: syncedComponents,
|
|
54512
|
+
agentMeta: { name: agent.name, tagline: agent.tagline }
|
|
54513
|
+
});
|
|
54514
|
+
if (input.pullSecrets !== false) {
|
|
54515
|
+
await pullAgentSecrets(cwd2, agent.id);
|
|
54516
|
+
}
|
|
54517
|
+
const returnedManifest = manifest ?? buildManifestFromCloud(cloud, agent);
|
|
54518
|
+
return {
|
|
54519
|
+
installedPaths: justInstalledPaths,
|
|
54520
|
+
manifest: returnedManifest,
|
|
54521
|
+
syncedComponents
|
|
54522
|
+
};
|
|
54523
|
+
} finally {
|
|
54524
|
+
try {
|
|
54525
|
+
fs49.rmSync(stageRoot, { recursive: true, force: true });
|
|
54526
|
+
} catch {}
|
|
54527
|
+
}
|
|
54528
|
+
}
|
|
54529
|
+
function stageManifestComponents2(components) {
|
|
54530
|
+
const root = fs49.mkdtempSync(path53.join(os14.tmpdir(), "brainbase-orch-pull-"));
|
|
54531
|
+
for (const c2 of components) {
|
|
54532
|
+
const compDir = path53.join(root, c2.type, c2.slug);
|
|
54533
|
+
ensureDir(compDir);
|
|
54534
|
+
for (const f4 of c2.files) {
|
|
54535
|
+
const target = path53.join(compDir, f4.path);
|
|
54536
|
+
ensureDir(path53.dirname(target));
|
|
54537
|
+
fs49.writeFileSync(target, f4.content);
|
|
54538
|
+
}
|
|
54539
|
+
}
|
|
54540
|
+
return root;
|
|
54541
|
+
}
|
|
54542
|
+
function runHarnessInstall4(harnessId, components, opts, agentName) {
|
|
54543
|
+
if (harnessId === "claude-code")
|
|
54544
|
+
return installClaudeCodeWithCtx(components, opts, agentName);
|
|
54545
|
+
if (harnessId === "codex")
|
|
54546
|
+
return installCodexWithCtx(components, opts, agentName);
|
|
54547
|
+
if (harnessId === "kafka")
|
|
54548
|
+
return installKafkaWithCtx(components, opts, agentName);
|
|
54549
|
+
return getAdapter(harnessId).install(components, opts);
|
|
54550
|
+
}
|
|
54551
|
+
function materializeInstructions2(cwd2, cloud) {
|
|
54552
|
+
for (const c2 of cloud.components) {
|
|
54553
|
+
if (c2.type !== "instruction")
|
|
54554
|
+
continue;
|
|
54555
|
+
const body = c2.files[0]?.content ?? "";
|
|
54556
|
+
if (!body.trim())
|
|
54557
|
+
continue;
|
|
54558
|
+
fs49.writeFileSync(path53.join(cwd2, DEFAULT_INSTRUCTIONS_FILE), body, "utf8");
|
|
54559
|
+
return;
|
|
54560
|
+
}
|
|
54561
|
+
}
|
|
54562
|
+
function buildManifestFromCloud(cloud, agent) {
|
|
54563
|
+
const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
|
|
54564
|
+
const meta = c2.meta ?? {};
|
|
54565
|
+
if (meta.name && meta.name.includes("/")) {
|
|
54566
|
+
return {
|
|
54567
|
+
source: meta.version ? `registry:${meta.name}@${meta.version}` : `registry:${meta.name}`
|
|
54568
|
+
};
|
|
54569
|
+
}
|
|
54570
|
+
return { source: `registry:${c2.slug}` };
|
|
54571
|
+
});
|
|
54572
|
+
const hasInstructions = cloud.components.some((c2) => c2.type === "instruction" && c2.files[0]?.content?.trim());
|
|
54573
|
+
const mcp = cloud.components.filter((c2) => c2.type === "mcp").map((c2) => {
|
|
54574
|
+
const payload = (c2.meta ?? {}).mcp ?? {};
|
|
54575
|
+
const entry = { name: c2.slug };
|
|
54576
|
+
if (typeof payload.url === "string")
|
|
54577
|
+
entry.url = payload.url;
|
|
54578
|
+
if (typeof payload.command === "string")
|
|
54579
|
+
entry.command = payload.command;
|
|
54580
|
+
if (Array.isArray(payload.args))
|
|
54581
|
+
entry.args = payload.args.map(String);
|
|
54582
|
+
if (payload.env && typeof payload.env === "object")
|
|
54583
|
+
entry.env = payload.env;
|
|
54584
|
+
if (payload.headers && typeof payload.headers === "object")
|
|
54585
|
+
entry.headers = payload.headers;
|
|
54586
|
+
if (typeof payload.is_enabled === "boolean")
|
|
54587
|
+
entry.is_enabled = payload.is_enabled;
|
|
54588
|
+
return entry;
|
|
54589
|
+
});
|
|
54590
|
+
return {
|
|
54591
|
+
schema: 1,
|
|
54592
|
+
agent: {
|
|
54593
|
+
name: agent.name,
|
|
54594
|
+
...agent.tagline ? { tagline: agent.tagline } : {}
|
|
54595
|
+
},
|
|
54596
|
+
...hasInstructions ? { instructions: { file: DEFAULT_INSTRUCTIONS_FILE } } : {},
|
|
54597
|
+
playbooks: [],
|
|
54598
|
+
skills,
|
|
54599
|
+
mcp
|
|
54600
|
+
};
|
|
54601
|
+
}
|
|
54602
|
+
async function pullAgentSecrets(cwd2, agentId) {
|
|
54603
|
+
try {
|
|
54604
|
+
const res = await api.getAgentSecrets(agentId);
|
|
54605
|
+
const secrets = res.secrets ?? {};
|
|
54606
|
+
if (Object.keys(secrets).length > 0) {
|
|
54607
|
+
writeLocalSecrets(cwd2, secrets);
|
|
54608
|
+
}
|
|
54609
|
+
} catch (err) {
|
|
54610
|
+
if (err instanceof ApiError && err.status !== 404) {
|
|
54611
|
+
f2.warn(`Skipped secrets for agent ${agentId}: ${err.message}`);
|
|
54612
|
+
}
|
|
54613
|
+
}
|
|
54614
|
+
}
|
|
54615
|
+
|
|
54308
54616
|
// src/cli/orchestration-pull.ts
|
|
54309
54617
|
async function runOrchestrationPull(cwd2, args) {
|
|
54310
54618
|
banner("orchestration pull — fetch orchestration + all member agents");
|
|
@@ -54328,7 +54636,7 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
54328
54636
|
sp.stop(`Cloud revision ${cloud.revision} — ${cloud.members.length} member${cloud.members.length === 1 ? "" : "s"}, ${cloud.edges.length} edge${cloud.edges.length === 1 ? "" : "s"}.`);
|
|
54329
54637
|
} catch (err) {
|
|
54330
54638
|
sp.stop("Failed.");
|
|
54331
|
-
|
|
54639
|
+
handleApiError5(err);
|
|
54332
54640
|
return;
|
|
54333
54641
|
}
|
|
54334
54642
|
const planLines = [];
|
|
@@ -54368,7 +54676,7 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
54368
54676
|
}
|
|
54369
54677
|
}
|
|
54370
54678
|
const fallbackHarness = args.harness ?? "claude-code";
|
|
54371
|
-
|
|
54679
|
+
fs50.mkdirSync(cwd2, { recursive: true });
|
|
54372
54680
|
if (hasOrchManifest(cwd2) && existingLink && existingLink.orchestration_id !== orchId) {
|
|
54373
54681
|
f2.error(`This folder is linked to orchestration ${existingLink.orchestration_id}, not ${orchId}. Move to a fresh directory or unlink first.`);
|
|
54374
54682
|
return;
|
|
@@ -54455,9 +54763,9 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
54455
54763
|
payload_schema: e2.payload_schema ?? {}
|
|
54456
54764
|
}))
|
|
54457
54765
|
});
|
|
54458
|
-
$e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${
|
|
54766
|
+
$e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path54.basename(cwd2)}/ ${import_picocolors33.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
|
|
54459
54767
|
}
|
|
54460
|
-
function
|
|
54768
|
+
function handleApiError5(err) {
|
|
54461
54769
|
if (err instanceof ApiError) {
|
|
54462
54770
|
if (err.status === 401) {
|
|
54463
54771
|
f2.error("Your session is invalid. Run `brainbase login` and try again.");
|
|
@@ -54602,10 +54910,10 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
54602
54910
|
$e(`Pushed ${link2.name} at revision ${updated.revision}.`);
|
|
54603
54911
|
} catch (err) {
|
|
54604
54912
|
sp.stop("Failed.");
|
|
54605
|
-
|
|
54913
|
+
handleApiError6(err);
|
|
54606
54914
|
}
|
|
54607
54915
|
}
|
|
54608
|
-
function
|
|
54916
|
+
function handleApiError6(err) {
|
|
54609
54917
|
if (err instanceof ApiError) {
|
|
54610
54918
|
if (err.status === 401) {
|
|
54611
54919
|
f2.error("Your session is invalid. Run `brainbase login` and try again.");
|
|
@@ -54736,7 +55044,7 @@ async function runOrchestrationList(args) {
|
|
|
54736
55044
|
try {
|
|
54737
55045
|
orgs = await api.listOrgs();
|
|
54738
55046
|
} catch (err) {
|
|
54739
|
-
|
|
55047
|
+
handleApiError7(err);
|
|
54740
55048
|
return;
|
|
54741
55049
|
}
|
|
54742
55050
|
if (orgs.length === 0) {
|
|
@@ -54758,7 +55066,7 @@ async function runOrchestrationList(args) {
|
|
|
54758
55066
|
try {
|
|
54759
55067
|
teams = await api.listTeams(orgId);
|
|
54760
55068
|
} catch (err) {
|
|
54761
|
-
|
|
55069
|
+
handleApiError7(err);
|
|
54762
55070
|
return;
|
|
54763
55071
|
}
|
|
54764
55072
|
if (teams.length === 0) {
|
|
@@ -54783,7 +55091,7 @@ async function runOrchestrationList(args) {
|
|
|
54783
55091
|
sp.stop(`${items.length} orchestration${items.length === 1 ? "" : "s"}.`);
|
|
54784
55092
|
} catch (err) {
|
|
54785
55093
|
sp.stop("Failed.");
|
|
54786
|
-
|
|
55094
|
+
handleApiError7(err);
|
|
54787
55095
|
return;
|
|
54788
55096
|
}
|
|
54789
55097
|
if (items.length === 0) {
|
|
@@ -54803,7 +55111,7 @@ async function runOrchestrationList(args) {
|
|
|
54803
55111
|
console.log(lines.join(`
|
|
54804
55112
|
`));
|
|
54805
55113
|
}
|
|
54806
|
-
function
|
|
55114
|
+
function handleApiError7(err) {
|
|
54807
55115
|
if (err instanceof ApiError) {
|
|
54808
55116
|
if (err.status === 401) {
|
|
54809
55117
|
f2.error("Your session is invalid. Run `brainbase login` and try again.");
|
|
@@ -55608,7 +55916,7 @@ var PROTECTED = new Set([
|
|
|
55608
55916
|
function help() {
|
|
55609
55917
|
const out = [];
|
|
55610
55918
|
out.push("");
|
|
55611
|
-
out.push(` ${brandTint("◆")} ${import_picocolors40.default.bold("brainbase")} ${import_picocolors40.default.dim("v0.
|
|
55919
|
+
out.push(` ${brandTint("◆")} ${import_picocolors40.default.bold("brainbase")} ${import_picocolors40.default.dim("v0.6.0")}`);
|
|
55612
55920
|
out.push(` ${import_picocolors40.default.dim("connect your local agent to the brainbase platform")}`);
|
|
55613
55921
|
out.push("");
|
|
55614
55922
|
out.push(divider("USAGE"));
|
|
@@ -55751,7 +56059,7 @@ async function main() {
|
|
|
55751
56059
|
const rawCwd = process13.cwd();
|
|
55752
56060
|
const cwd2 = (() => {
|
|
55753
56061
|
try {
|
|
55754
|
-
return
|
|
56062
|
+
return fs51.realpathSync(rawCwd);
|
|
55755
56063
|
} catch {
|
|
55756
56064
|
return rawCwd;
|
|
55757
56065
|
}
|