@brainbase-labs/cli 0.32.0 → 0.33.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 +608 -501
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -36018,7 +36018,7 @@ function padStart(s, n) {
|
|
|
36018
36018
|
// package.json
|
|
36019
36019
|
var package_default = {
|
|
36020
36020
|
name: "@brainbase-labs/cli",
|
|
36021
|
-
version: "0.
|
|
36021
|
+
version: "0.33.0",
|
|
36022
36022
|
description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
|
|
36023
36023
|
type: "module",
|
|
36024
36024
|
bin: {
|
|
@@ -41663,6 +41663,12 @@ ${block}
|
|
|
41663
41663
|
var DEFAULT_MCP_PROXY_BASE = "https://brainbase-mcp-proxy.onrender.com";
|
|
41664
41664
|
var THREAD_ID_TEMPLATE = "${BRAINBASE_THREAD_ID}";
|
|
41665
41665
|
var PROXY_AUTH_HEADER = "Bearer ${BRAINBASE_TOKEN}";
|
|
41666
|
+
function isRuntimeMcpAuth(value) {
|
|
41667
|
+
if (!value || typeof value !== "object")
|
|
41668
|
+
return false;
|
|
41669
|
+
const auth = value;
|
|
41670
|
+
return auth.version === 1 && auth.requires_oauth === true && (auth.kind === "agent" || auth.kind === "orchestration") && typeof auth.server_id === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(auth.server_id);
|
|
41671
|
+
}
|
|
41666
41672
|
function mcpProxyBaseUrl(env = process.env) {
|
|
41667
41673
|
const envOverride = env.BRAINBASE_MCP_PROXY_URL;
|
|
41668
41674
|
if (envOverride) {
|
|
@@ -41675,19 +41681,31 @@ function mcpProxyBaseUrl(env = process.env) {
|
|
|
41675
41681
|
function isBrainbaseTaskRuntime(env = process.env) {
|
|
41676
41682
|
return typeof env.BRAINBASE_THREAD_ID === "string" && env.BRAINBASE_THREAD_ID.trim().length > 0 && typeof env.BRAINBASE_TOKEN === "string" && env.BRAINBASE_TOKEN.trim().length > 0;
|
|
41677
41683
|
}
|
|
41678
|
-
function proxifyMcpPayload(payload, env = process.env) {
|
|
41684
|
+
function proxifyMcpPayload(payload, env = process.env, identity) {
|
|
41679
41685
|
if (!payload)
|
|
41680
41686
|
return payload;
|
|
41681
41687
|
if (!isBrainbaseTaskRuntime(env))
|
|
41682
41688
|
return payload;
|
|
41683
|
-
if (!
|
|
41689
|
+
if (typeof payload.url !== "string" || !payload.url || payload.command)
|
|
41690
|
+
return payload;
|
|
41691
|
+
let route = "";
|
|
41692
|
+
let keepInstalledUrl = false;
|
|
41693
|
+
let upstreamUrl = payload.url;
|
|
41694
|
+
if (identity !== undefined) {
|
|
41695
|
+
if (!isRuntimeMcpAuth(identity))
|
|
41696
|
+
throw new Error("mcp_server_identity_required: incompatible runtime_mcp_auth");
|
|
41697
|
+
route = `s/${identity.kind}/${identity.server_id}/`;
|
|
41698
|
+
const installed = parseMcpProxyUrl(payload.url, env.BRAINBASE_THREAD_ID?.trim() ?? "", mcpProxyBaseUrl(env));
|
|
41699
|
+
keepInstalledUrl = installed?.kind === identity.kind && installed.serverId === identity.server_id;
|
|
41700
|
+
if (installed)
|
|
41701
|
+
upstreamUrl = installed.upstreamUrl;
|
|
41702
|
+
} else if (!shouldProxy(payload, env))
|
|
41684
41703
|
return payload;
|
|
41685
41704
|
const base = mcpProxyBaseUrl(env);
|
|
41686
|
-
const
|
|
41687
|
-
const existingHeaders = payload.headers ?? {};
|
|
41705
|
+
const existingHeaders = Object.fromEntries(Object.entries(payload.headers ?? {}).filter(([key]) => key.toLowerCase() !== "authorization"));
|
|
41688
41706
|
return {
|
|
41689
41707
|
...payload,
|
|
41690
|
-
url: `${base}/t/${THREAD_ID_TEMPLATE}/${upstreamUrl}`,
|
|
41708
|
+
url: keepInstalledUrl ? payload.url : `${base}/t/${THREAD_ID_TEMPLATE}/${route}${upstreamUrl}`,
|
|
41691
41709
|
headers: { ...existingHeaders, Authorization: PROXY_AUTH_HEADER }
|
|
41692
41710
|
};
|
|
41693
41711
|
}
|
|
@@ -41701,46 +41719,57 @@ function shouldProxy(payload, env) {
|
|
|
41701
41719
|
if (headers && typeof headers === "object" && Object.keys(headers).length > 0) {
|
|
41702
41720
|
return false;
|
|
41703
41721
|
}
|
|
41704
|
-
if (
|
|
41722
|
+
if (parseMcpProxyUrl(url, env.BRAINBASE_THREAD_ID?.trim() ?? "", mcpProxyBaseUrl(env))) {
|
|
41705
41723
|
return false;
|
|
41706
41724
|
}
|
|
41707
41725
|
return true;
|
|
41708
41726
|
}
|
|
41709
|
-
function
|
|
41727
|
+
function parseMcpProxyUrl(value, threadId, proxyBase) {
|
|
41710
41728
|
let outer;
|
|
41711
41729
|
try {
|
|
41712
41730
|
outer = new URL(value);
|
|
41713
41731
|
} catch {
|
|
41714
|
-
return
|
|
41732
|
+
return;
|
|
41715
41733
|
}
|
|
41716
41734
|
if (outer.protocol !== "http:" && outer.protocol !== "https:")
|
|
41717
|
-
return
|
|
41718
|
-
const candidatePaths = [
|
|
41719
|
-
|
|
41720
|
-
|
|
41721
|
-
|
|
41722
|
-
|
|
41723
|
-
|
|
41724
|
-
|
|
41725
|
-
|
|
41726
|
-
|
|
41735
|
+
return;
|
|
41736
|
+
const candidatePaths = [];
|
|
41737
|
+
for (const trusted of [proxyBase, DEFAULT_MCP_PROXY_BASE]) {
|
|
41738
|
+
try {
|
|
41739
|
+
const base = new URL(trusted);
|
|
41740
|
+
if (outer.origin !== base.origin || outer.username || outer.password)
|
|
41741
|
+
continue;
|
|
41742
|
+
const basePath = base.pathname.replace(/\/+$/, "");
|
|
41743
|
+
if (outer.pathname.startsWith(`${basePath}/`)) {
|
|
41744
|
+
candidatePaths.push(outer.pathname.slice(basePath.length));
|
|
41745
|
+
}
|
|
41746
|
+
} catch {}
|
|
41747
|
+
}
|
|
41748
|
+
const match = candidatePaths.map((path13) => /^\/t\/([^/]+)\/(?:s\/(agent|orchestration)\/([0-9a-f-]+)\/)?(https?:\/\/.+)$/i.exec(path13)).find((candidate) => candidate !== null);
|
|
41727
41749
|
if (!match)
|
|
41728
|
-
return
|
|
41750
|
+
return;
|
|
41729
41751
|
let pathThreadId = match[1];
|
|
41730
41752
|
try {
|
|
41731
41753
|
pathThreadId = decodeURIComponent(pathThreadId);
|
|
41732
41754
|
} catch {
|
|
41733
|
-
return
|
|
41755
|
+
return;
|
|
41734
41756
|
}
|
|
41735
41757
|
if (pathThreadId !== threadId && pathThreadId !== THREAD_ID_TEMPLATE)
|
|
41736
|
-
return
|
|
41758
|
+
return;
|
|
41737
41759
|
try {
|
|
41738
|
-
const
|
|
41739
|
-
|
|
41760
|
+
const upstreamUrl = match[4] + outer.search + outer.hash;
|
|
41761
|
+
const upstream = new URL(upstreamUrl);
|
|
41762
|
+
if (upstream.protocol !== "http:" && upstream.protocol !== "https:" || !upstream.hostname)
|
|
41763
|
+
return;
|
|
41764
|
+
return { upstreamUrl, kind: match[2], serverId: match[3] };
|
|
41740
41765
|
} catch {
|
|
41741
|
-
return
|
|
41766
|
+
return;
|
|
41742
41767
|
}
|
|
41743
41768
|
}
|
|
41769
|
+
function mcpUpstreamUrl(value, env = process.env) {
|
|
41770
|
+
const resolved = resolveMcpEnvTemplates({ url: value }, env)?.url;
|
|
41771
|
+
return parseMcpProxyUrl(resolved, env.BRAINBASE_THREAD_ID?.trim() ?? "", mcpProxyBaseUrl(env))?.upstreamUrl ?? resolved;
|
|
41772
|
+
}
|
|
41744
41773
|
function resolveMcpEnvTemplates(payload, env = process.env) {
|
|
41745
41774
|
if (!payload)
|
|
41746
41775
|
return payload;
|
|
@@ -53941,6 +53970,7 @@ var InstalledComponentSchema = exports_external.object({
|
|
|
53941
53970
|
slug: exports_external.string(),
|
|
53942
53971
|
installedPaths: exports_external.array(exports_external.string()),
|
|
53943
53972
|
sourceChecksum: exports_external.string(),
|
|
53973
|
+
runtime_mcp_auth: exports_external.unknown().optional(),
|
|
53944
53974
|
scope: ScopeSchema.optional(),
|
|
53945
53975
|
embeddedKey: exports_external.string().optional(),
|
|
53946
53976
|
settingsFile: exports_external.string().optional()
|
|
@@ -59276,7 +59306,7 @@ function buildTemplateComponents(manifest, rootDir) {
|
|
|
59276
59306
|
rootDir: path63.join(rootDir, c2.path),
|
|
59277
59307
|
description: c2.description,
|
|
59278
59308
|
target: c2.target,
|
|
59279
|
-
payload: proxifyMcpPayload(c2.meta?.mcp),
|
|
59309
|
+
payload: proxifyMcpPayload(c2.meta?.mcp, undefined, c2.meta?.runtime_mcp_auth),
|
|
59280
59310
|
meta: c2.meta,
|
|
59281
59311
|
checksum: c2.checksum,
|
|
59282
59312
|
source: c2.source
|
|
@@ -59446,6 +59476,7 @@ async function runOnboard(cwd2, args) {
|
|
|
59446
59476
|
slug: o2.slug,
|
|
59447
59477
|
installedPaths: o2.installedPaths,
|
|
59448
59478
|
sourceChecksum: o2.sourceChecksum,
|
|
59479
|
+
...o2.type === "mcp" ? { runtime_mcp_auth: components.find((c2) => c2.type === o2.type && c2.slug === o2.slug)?.meta?.runtime_mcp_auth } : {},
|
|
59449
59480
|
scope: o2.scope,
|
|
59450
59481
|
embeddedKey: o2.embeddedKey,
|
|
59451
59482
|
settingsFile: o2.settingsFile
|
|
@@ -63542,10 +63573,462 @@ async function runUnlink(cwd2, args) {
|
|
|
63542
63573
|
}
|
|
63543
63574
|
|
|
63544
63575
|
// src/cli/sync.ts
|
|
63576
|
+
import { isDeepStrictEqual } from "node:util";
|
|
63577
|
+
|
|
63578
|
+
// src/core/agent-diff.ts
|
|
63545
63579
|
import path77 from "node:path";
|
|
63546
63580
|
import fs69 from "node:fs";
|
|
63547
|
-
import os12 from "node:os";
|
|
63548
63581
|
import crypto3 from "node:crypto";
|
|
63582
|
+
function compKey(type, slug) {
|
|
63583
|
+
return `${type}/${slug}`;
|
|
63584
|
+
}
|
|
63585
|
+
function hashString(s3) {
|
|
63586
|
+
return crypto3.createHash("sha256").update(s3).digest("hex");
|
|
63587
|
+
}
|
|
63588
|
+
function jsonStringAsciiSafe(s3) {
|
|
63589
|
+
return JSON.stringify(s3).replace(/[\u007f-\uffff]/g, (c2) => "\\u" + c2.charCodeAt(0).toString(16).padStart(4, "0"));
|
|
63590
|
+
}
|
|
63591
|
+
function canonicalJson2(value) {
|
|
63592
|
+
if (value === null)
|
|
63593
|
+
return "null";
|
|
63594
|
+
if (typeof value === "boolean")
|
|
63595
|
+
return value ? "true" : "false";
|
|
63596
|
+
if (typeof value === "number") {
|
|
63597
|
+
if (!Number.isFinite(value))
|
|
63598
|
+
throw new Error("Non-finite numbers are not JSON");
|
|
63599
|
+
return String(value);
|
|
63600
|
+
}
|
|
63601
|
+
if (typeof value === "string")
|
|
63602
|
+
return jsonStringAsciiSafe(value);
|
|
63603
|
+
if (Array.isArray(value)) {
|
|
63604
|
+
return "[" + value.map(canonicalJson2).join(",") + "]";
|
|
63605
|
+
}
|
|
63606
|
+
if (typeof value === "object") {
|
|
63607
|
+
const obj = value;
|
|
63608
|
+
const keys2 = Object.keys(obj).sort();
|
|
63609
|
+
return "{" + keys2.map((k3) => `${jsonStringAsciiSafe(k3)}:${canonicalJson2(obj[k3])}`).join(",") + "}";
|
|
63610
|
+
}
|
|
63611
|
+
throw new Error(`Unsupported value in canonicalJson: ${typeof value}`);
|
|
63612
|
+
}
|
|
63613
|
+
function hashMcpEntry(entry) {
|
|
63614
|
+
const payload = {
|
|
63615
|
+
args: entry.args ?? [],
|
|
63616
|
+
env: entry.env ?? {},
|
|
63617
|
+
headers: entry.headers ?? {}
|
|
63618
|
+
};
|
|
63619
|
+
if (entry.url !== undefined)
|
|
63620
|
+
payload.url = entry.url;
|
|
63621
|
+
if (entry.command !== undefined)
|
|
63622
|
+
payload.command = entry.command;
|
|
63623
|
+
payload.is_enabled = entry.is_enabled ?? true;
|
|
63624
|
+
return crypto3.createHash("sha256").update(canonicalJson2(payload)).digest("hex");
|
|
63625
|
+
}
|
|
63626
|
+
function evalWirePayload(entry) {
|
|
63627
|
+
return {
|
|
63628
|
+
criteria: entry.criteria,
|
|
63629
|
+
enabled: entry.enabled,
|
|
63630
|
+
icon: entry.icon || null,
|
|
63631
|
+
judge_agent: entry.judge_agent ?? null,
|
|
63632
|
+
judge_model: entry.judge_model,
|
|
63633
|
+
judge_type: entry.judge_type,
|
|
63634
|
+
output_shape: entry.output_shape,
|
|
63635
|
+
classification_values: entry.classification_values && entry.classification_values.length > 0 ? entry.classification_values : null
|
|
63636
|
+
};
|
|
63637
|
+
}
|
|
63638
|
+
function hashEvalEntry(entry) {
|
|
63639
|
+
return crypto3.createHash("sha256").update(canonicalJson2(evalWirePayload(entry))).digest("hex");
|
|
63640
|
+
}
|
|
63641
|
+
function fileHash(p2) {
|
|
63642
|
+
if (!exists(p2))
|
|
63643
|
+
return null;
|
|
63644
|
+
try {
|
|
63645
|
+
const buf = fs69.readFileSync(p2);
|
|
63646
|
+
return crypto3.createHash("sha256").update(buf).digest("hex");
|
|
63647
|
+
} catch {
|
|
63648
|
+
return null;
|
|
63649
|
+
}
|
|
63650
|
+
}
|
|
63651
|
+
function componentHashFromFileHashes(fileHashes) {
|
|
63652
|
+
const h2 = crypto3.createHash("sha256");
|
|
63653
|
+
for (const fh of [...fileHashes].sort()) {
|
|
63654
|
+
h2.update(fh);
|
|
63655
|
+
h2.update(`
|
|
63656
|
+
`);
|
|
63657
|
+
}
|
|
63658
|
+
return h2.digest("hex");
|
|
63659
|
+
}
|
|
63660
|
+
function hashDirectoryAsComponent(dir) {
|
|
63661
|
+
if (!exists(dir))
|
|
63662
|
+
return null;
|
|
63663
|
+
const fileHashes = [];
|
|
63664
|
+
const walk = (sub) => {
|
|
63665
|
+
let entries;
|
|
63666
|
+
try {
|
|
63667
|
+
entries = fs69.readdirSync(sub, { withFileTypes: true });
|
|
63668
|
+
} catch {
|
|
63669
|
+
return;
|
|
63670
|
+
}
|
|
63671
|
+
for (const e2 of entries) {
|
|
63672
|
+
const full = path77.join(sub, e2.name);
|
|
63673
|
+
if (e2.isFile()) {
|
|
63674
|
+
const fh = fileHash(full);
|
|
63675
|
+
if (fh)
|
|
63676
|
+
fileHashes.push(fh);
|
|
63677
|
+
} else if (e2.isDirectory()) {
|
|
63678
|
+
walk(full);
|
|
63679
|
+
}
|
|
63680
|
+
}
|
|
63681
|
+
};
|
|
63682
|
+
walk(dir);
|
|
63683
|
+
return componentHashFromFileHashes(fileHashes);
|
|
63684
|
+
}
|
|
63685
|
+
function readLocalComponents(cwd2, manifest) {
|
|
63686
|
+
const out = [];
|
|
63687
|
+
const instr = readInstructions(cwd2, manifest);
|
|
63688
|
+
if (instr !== null && instr.trim().length > 0) {
|
|
63689
|
+
out.push({
|
|
63690
|
+
type: "instruction",
|
|
63691
|
+
slug: "agent-instructions",
|
|
63692
|
+
hash: componentHashFromFileHashes([hashString(normalizeInstructionBody(instr))])
|
|
63693
|
+
});
|
|
63694
|
+
}
|
|
63695
|
+
for (const entry of manifest.skills) {
|
|
63696
|
+
let parsed;
|
|
63697
|
+
try {
|
|
63698
|
+
parsed = parseSkillSource2(entry.source);
|
|
63699
|
+
} catch {
|
|
63700
|
+
try {
|
|
63701
|
+
const core = parseSkillSource(entry.source);
|
|
63702
|
+
if (core.type !== "inline" && core.type !== "local") {
|
|
63703
|
+
out.push({
|
|
63704
|
+
type: "skill",
|
|
63705
|
+
slug: defaultSkillSlug(core),
|
|
63706
|
+
hash: null,
|
|
63707
|
+
declaredSource: entry.source
|
|
63708
|
+
});
|
|
63709
|
+
}
|
|
63710
|
+
} catch {}
|
|
63711
|
+
continue;
|
|
63712
|
+
}
|
|
63713
|
+
if (parsed.kind === "registry") {
|
|
63714
|
+
out.push({
|
|
63715
|
+
type: "skill",
|
|
63716
|
+
slug: registrySkillComponentSlug(parsed),
|
|
63717
|
+
hash: null,
|
|
63718
|
+
declaredSource: entry.source
|
|
63719
|
+
});
|
|
63720
|
+
} else {
|
|
63721
|
+
const abs = path77.resolve(cwd2, parsed.path);
|
|
63722
|
+
const slug = path77.basename(abs);
|
|
63723
|
+
out.push({
|
|
63724
|
+
type: "skill",
|
|
63725
|
+
slug,
|
|
63726
|
+
hash: hashDirectoryAsComponent(abs),
|
|
63727
|
+
declaredSource: entry.source,
|
|
63728
|
+
localPath: abs
|
|
63729
|
+
});
|
|
63730
|
+
}
|
|
63731
|
+
}
|
|
63732
|
+
for (const entry of manifest.mcp ?? []) {
|
|
63733
|
+
out.push({
|
|
63734
|
+
type: "mcp",
|
|
63735
|
+
slug: entry.name,
|
|
63736
|
+
hash: hashMcpEntry(entry)
|
|
63737
|
+
});
|
|
63738
|
+
}
|
|
63739
|
+
const pbEntries = manifest.playbooks ?? [];
|
|
63740
|
+
const pbSlugs = assignPlaybookSlugs(pbEntries.map((e2) => e2.title));
|
|
63741
|
+
for (let i = 0;i < pbEntries.length; i++) {
|
|
63742
|
+
const entry = pbEntries[i];
|
|
63743
|
+
const slug = pbSlugs[i];
|
|
63744
|
+
const body = resolvePlaybookContent(cwd2, entry);
|
|
63745
|
+
if (body === null) {
|
|
63746
|
+
out.push({ type: "playbook", slug, hash: null });
|
|
63747
|
+
continue;
|
|
63748
|
+
}
|
|
63749
|
+
const wireBody = assemblePlaybookWireBody(entry, body);
|
|
63750
|
+
out.push({
|
|
63751
|
+
type: "playbook",
|
|
63752
|
+
slug,
|
|
63753
|
+
hash: componentHashFromFileHashes([hashString(wireBody)])
|
|
63754
|
+
});
|
|
63755
|
+
}
|
|
63756
|
+
for (const entry of manifest.evals ?? []) {
|
|
63757
|
+
out.push({
|
|
63758
|
+
type: "eval",
|
|
63759
|
+
slug: entry.slug,
|
|
63760
|
+
hash: hashEvalEntry(entry)
|
|
63761
|
+
});
|
|
63762
|
+
}
|
|
63763
|
+
return out;
|
|
63764
|
+
}
|
|
63765
|
+
function threeWayDiff(input) {
|
|
63766
|
+
const lockMap = new Map;
|
|
63767
|
+
for (const c2 of input.lock)
|
|
63768
|
+
lockMap.set(compKey(c2.type, c2.slug), c2);
|
|
63769
|
+
const cloudMap = new Map;
|
|
63770
|
+
for (const c2 of input.cloud)
|
|
63771
|
+
cloudMap.set(compKey(c2.type, c2.slug), c2);
|
|
63772
|
+
const localMap = new Map;
|
|
63773
|
+
for (const c2 of input.local)
|
|
63774
|
+
localMap.set(compKey(c2.type, c2.slug), c2);
|
|
63775
|
+
const keys2 = new Set;
|
|
63776
|
+
for (const k3 of lockMap.keys())
|
|
63777
|
+
keys2.add(k3);
|
|
63778
|
+
for (const k3 of cloudMap.keys())
|
|
63779
|
+
keys2.add(k3);
|
|
63780
|
+
for (const k3 of localMap.keys())
|
|
63781
|
+
keys2.add(k3);
|
|
63782
|
+
const rows = [];
|
|
63783
|
+
for (const key2 of [...keys2].sort()) {
|
|
63784
|
+
const lock = lockMap.get(key2);
|
|
63785
|
+
const cloud = cloudMap.get(key2);
|
|
63786
|
+
const local = localMap.get(key2);
|
|
63787
|
+
const [type, slug] = key2.split("/", 2);
|
|
63788
|
+
let localHash = local?.hash ?? null;
|
|
63789
|
+
if (local && local.hash === null && local.declaredSource && lock?.source === local.declaredSource && cloud) {
|
|
63790
|
+
localHash = cloud.hash;
|
|
63791
|
+
}
|
|
63792
|
+
const cloudHash = cloud?.hash;
|
|
63793
|
+
const lockHash = lock?.hash;
|
|
63794
|
+
const declaredSource = local?.declaredSource;
|
|
63795
|
+
const present = {
|
|
63796
|
+
local: !!local,
|
|
63797
|
+
lock: !!lock,
|
|
63798
|
+
cloud: !!cloud
|
|
63799
|
+
};
|
|
63800
|
+
let status;
|
|
63801
|
+
if (present.local && present.cloud && !present.lock) {
|
|
63802
|
+
status = "added-local";
|
|
63803
|
+
} else if (!present.local && present.cloud && !present.lock) {
|
|
63804
|
+
status = "added-cloud";
|
|
63805
|
+
} else if (present.local && !present.cloud && !present.lock) {
|
|
63806
|
+
status = "added-only-local";
|
|
63807
|
+
} else if (!present.local && present.lock) {
|
|
63808
|
+
status = "removed-local";
|
|
63809
|
+
} else if (present.local && !present.cloud && present.lock) {
|
|
63810
|
+
status = "removed-cloud";
|
|
63811
|
+
} else {
|
|
63812
|
+
const sourceChanged = !!local && local.hash === null && !!local.declaredSource && lock?.source !== undefined && lock.source !== local.declaredSource;
|
|
63813
|
+
const localChanged = sourceChanged || localHash !== null && lockHash !== undefined && localHash !== lockHash;
|
|
63814
|
+
const cloudChanged = cloudHash !== undefined && lockHash !== undefined && cloudHash !== lockHash;
|
|
63815
|
+
const converged = !sourceChanged && localHash !== null && cloudHash !== undefined && localHash === cloudHash;
|
|
63816
|
+
if (converged)
|
|
63817
|
+
status = "in-sync";
|
|
63818
|
+
else if (localChanged && cloudChanged)
|
|
63819
|
+
status = "modified-both";
|
|
63820
|
+
else if (localChanged)
|
|
63821
|
+
status = "modified-local";
|
|
63822
|
+
else if (cloudChanged)
|
|
63823
|
+
status = "modified-cloud";
|
|
63824
|
+
else
|
|
63825
|
+
status = "in-sync";
|
|
63826
|
+
}
|
|
63827
|
+
rows.push({
|
|
63828
|
+
key: key2,
|
|
63829
|
+
type,
|
|
63830
|
+
slug,
|
|
63831
|
+
status,
|
|
63832
|
+
localHash: localHash ?? undefined,
|
|
63833
|
+
lockHash,
|
|
63834
|
+
cloudHash,
|
|
63835
|
+
declaredSource
|
|
63836
|
+
});
|
|
63837
|
+
}
|
|
63838
|
+
return rows;
|
|
63839
|
+
}
|
|
63840
|
+
function partitionPushRows(rows, force) {
|
|
63841
|
+
const toSend = [];
|
|
63842
|
+
const conflicts = [];
|
|
63843
|
+
const upstreamOnly = [];
|
|
63844
|
+
for (const r2 of rows) {
|
|
63845
|
+
switch (r2.status) {
|
|
63846
|
+
case "modified-local":
|
|
63847
|
+
case "added-only-local":
|
|
63848
|
+
case "added-local":
|
|
63849
|
+
case "removed-local":
|
|
63850
|
+
toSend.push(r2);
|
|
63851
|
+
break;
|
|
63852
|
+
case "modified-both":
|
|
63853
|
+
if (force)
|
|
63854
|
+
toSend.push(r2);
|
|
63855
|
+
else
|
|
63856
|
+
conflicts.push(r2);
|
|
63857
|
+
break;
|
|
63858
|
+
case "modified-cloud":
|
|
63859
|
+
case "added-cloud":
|
|
63860
|
+
case "removed-cloud":
|
|
63861
|
+
upstreamOnly.push(r2);
|
|
63862
|
+
break;
|
|
63863
|
+
case "in-sync":
|
|
63864
|
+
break;
|
|
63865
|
+
default: {
|
|
63866
|
+
const _exhaustive = r2.status;
|
|
63867
|
+
}
|
|
63868
|
+
}
|
|
63869
|
+
}
|
|
63870
|
+
return { toSend, conflicts, upstreamOnly };
|
|
63871
|
+
}
|
|
63872
|
+
function diffAgentMeta(manifestMeta, lockMeta, cloudMeta) {
|
|
63873
|
+
const eq = (a3, b4) => {
|
|
63874
|
+
if (!a3 && !b4)
|
|
63875
|
+
return true;
|
|
63876
|
+
if (!a3 || !b4)
|
|
63877
|
+
return false;
|
|
63878
|
+
return a3.name === b4.name && (a3.tagline ?? "") === (b4.tagline ?? "");
|
|
63879
|
+
};
|
|
63880
|
+
return {
|
|
63881
|
+
localChanged: !!manifestMeta && !!lockMeta && !eq(manifestMeta, lockMeta),
|
|
63882
|
+
cloudChanged: !!cloudMeta && !!lockMeta && !eq(cloudMeta, lockMeta)
|
|
63883
|
+
};
|
|
63884
|
+
}
|
|
63885
|
+
var WRITABLE_CAPABILITIES = ["memory", "browser"];
|
|
63886
|
+
var MIRRORED_CAPABILITIES = ["slack", "meeting", "github", "linear"];
|
|
63887
|
+
function manifestConfigState(manifest) {
|
|
63888
|
+
return {
|
|
63889
|
+
...manifest.machine_kind !== undefined ? { machine_kind: manifest.machine_kind } : {},
|
|
63890
|
+
...hasOwn(manifest, "default_model") ? { default_model: manifest.default_model ?? null } : {},
|
|
63891
|
+
...manifest.capabilities?.memory !== undefined ? { memory: manifest.capabilities.memory } : {},
|
|
63892
|
+
...manifest.capabilities?.browser !== undefined ? { browser: manifest.capabilities.browser } : {}
|
|
63893
|
+
};
|
|
63894
|
+
}
|
|
63895
|
+
function cloudConfigState(agent) {
|
|
63896
|
+
return {
|
|
63897
|
+
...agent.machine_kind !== undefined ? { machine_kind: agent.machine_kind } : {},
|
|
63898
|
+
...hasOwn(agent, "default_model") ? { default_model: agent.default_model ?? null } : {},
|
|
63899
|
+
...agent.memory_enabled !== undefined ? { memory: agent.memory_enabled } : {},
|
|
63900
|
+
...agent.browser_enabled !== undefined ? { browser: agent.browser_enabled } : {}
|
|
63901
|
+
};
|
|
63902
|
+
}
|
|
63903
|
+
function hasOwn(value, key2) {
|
|
63904
|
+
return !!value && Object.prototype.hasOwnProperty.call(value, key2);
|
|
63905
|
+
}
|
|
63906
|
+
function staleConnectionMirrors(manifest, cloud) {
|
|
63907
|
+
const actualByName = {
|
|
63908
|
+
slack: cloud.slack_connected,
|
|
63909
|
+
meeting: cloud.meeting_connected,
|
|
63910
|
+
github: cloud.github_connected,
|
|
63911
|
+
linear: cloud.linear_connected
|
|
63912
|
+
};
|
|
63913
|
+
const stale = [];
|
|
63914
|
+
for (const name of MIRRORED_CAPABILITIES) {
|
|
63915
|
+
const authored = manifest.capabilities?.[name];
|
|
63916
|
+
const actual = actualByName[name];
|
|
63917
|
+
if (authored === undefined || actual === undefined)
|
|
63918
|
+
continue;
|
|
63919
|
+
if (authored !== actual)
|
|
63920
|
+
stale.push({ name, authored, actual });
|
|
63921
|
+
}
|
|
63922
|
+
return stale;
|
|
63923
|
+
}
|
|
63924
|
+
function diffAgentConfig(manifest, lock, cloud) {
|
|
63925
|
+
const unsupported = [];
|
|
63926
|
+
const machineSupported = cloud.machine_kind !== undefined;
|
|
63927
|
+
const defaultModelSupported = hasOwn(cloud, "default_model");
|
|
63928
|
+
if (manifest.machine_kind !== undefined && !machineSupported) {
|
|
63929
|
+
unsupported.push("machine_kind");
|
|
63930
|
+
}
|
|
63931
|
+
if (manifest.default_model !== undefined && !defaultModelSupported) {
|
|
63932
|
+
unsupported.push("default_model");
|
|
63933
|
+
}
|
|
63934
|
+
const machineMismatch = manifest.machine_kind !== undefined && machineSupported && manifest.machine_kind !== cloud.machine_kind;
|
|
63935
|
+
const machineLocalChanged = manifest.machine_kind !== undefined && machineSupported && (lock?.machine_kind !== undefined ? manifest.machine_kind !== lock.machine_kind && manifest.machine_kind !== cloud.machine_kind : manifest.machine_kind !== cloud.machine_kind);
|
|
63936
|
+
const machineCloudChanged = lock?.machine_kind !== undefined && machineSupported && lock.machine_kind !== cloud.machine_kind && manifest.machine_kind !== cloud.machine_kind;
|
|
63937
|
+
const machineConverged = manifest.machine_kind !== undefined && machineSupported && manifest.machine_kind === cloud.machine_kind && (lock?.machine_kind === undefined || lock.machine_kind !== cloud.machine_kind);
|
|
63938
|
+
const defaultModel = threeWayField(defaultModelSupported, manifest.default_model, cloud.default_model, lock, "default_model");
|
|
63939
|
+
const memory = threeWayField(hasOwn(cloud, "memory"), manifest.memory, cloud.memory, lock, "memory");
|
|
63940
|
+
const browser = threeWayField(hasOwn(cloud, "browser"), manifest.browser, cloud.browser, lock, "browser");
|
|
63941
|
+
if (manifest.memory !== undefined && !hasOwn(cloud, "memory")) {
|
|
63942
|
+
unsupported.push("memory");
|
|
63943
|
+
}
|
|
63944
|
+
if (manifest.browser !== undefined && !hasOwn(cloud, "browser")) {
|
|
63945
|
+
unsupported.push("browser");
|
|
63946
|
+
}
|
|
63947
|
+
return {
|
|
63948
|
+
unsupported,
|
|
63949
|
+
machineMismatch,
|
|
63950
|
+
machineLocalChanged,
|
|
63951
|
+
machineCloudChanged,
|
|
63952
|
+
defaultModelLocalChanged: defaultModel.localChanged,
|
|
63953
|
+
defaultModelCloudChanged: defaultModel.cloudChanged,
|
|
63954
|
+
defaultModelConflict: defaultModel.conflict,
|
|
63955
|
+
memory,
|
|
63956
|
+
browser,
|
|
63957
|
+
baselineConverged: machineConverged || defaultModel.converged || memory.converged || browser.converged
|
|
63958
|
+
};
|
|
63959
|
+
}
|
|
63960
|
+
function threeWayField(supported, authored, cloudRaw, lock, key2) {
|
|
63961
|
+
const result2 = {
|
|
63962
|
+
localChanged: false,
|
|
63963
|
+
cloudChanged: false,
|
|
63964
|
+
conflict: false,
|
|
63965
|
+
converged: false
|
|
63966
|
+
};
|
|
63967
|
+
if (!supported)
|
|
63968
|
+
return result2;
|
|
63969
|
+
const cloudValue = cloudRaw ?? null;
|
|
63970
|
+
const lockSupported = hasOwn(lock, key2);
|
|
63971
|
+
const lockValue = lock?.[key2] ?? null;
|
|
63972
|
+
if (authored === undefined) {
|
|
63973
|
+
if (lockSupported)
|
|
63974
|
+
result2.cloudChanged = cloudValue !== lockValue;
|
|
63975
|
+
return result2;
|
|
63976
|
+
}
|
|
63977
|
+
const localValue = authored ?? null;
|
|
63978
|
+
if (!lockSupported) {
|
|
63979
|
+
result2.localChanged = localValue !== cloudValue;
|
|
63980
|
+
result2.converged = localValue === cloudValue;
|
|
63981
|
+
return result2;
|
|
63982
|
+
}
|
|
63983
|
+
const localMoved = localValue !== lockValue;
|
|
63984
|
+
const cloudMoved = cloudValue !== lockValue;
|
|
63985
|
+
result2.conflict = localMoved && cloudMoved && localValue !== cloudValue;
|
|
63986
|
+
result2.localChanged = localMoved && localValue !== cloudValue;
|
|
63987
|
+
result2.cloudChanged = cloudMoved && localValue !== cloudValue;
|
|
63988
|
+
result2.converged = localMoved && cloudMoved && localValue === cloudValue;
|
|
63989
|
+
return result2;
|
|
63990
|
+
}
|
|
63991
|
+
|
|
63992
|
+
// src/core/mcp-merge.ts
|
|
63993
|
+
var RUNTIME_META_PREFIX = "runtime_";
|
|
63994
|
+
function runtimeMetaFromComponent(component) {
|
|
63995
|
+
const meta = component.meta ?? {};
|
|
63996
|
+
const carried = {};
|
|
63997
|
+
for (const [key2, value] of Object.entries(meta)) {
|
|
63998
|
+
if (key2.startsWith(RUNTIME_META_PREFIX) && value !== undefined) {
|
|
63999
|
+
carried[key2] = value;
|
|
64000
|
+
}
|
|
64001
|
+
}
|
|
64002
|
+
return Object.keys(carried).length > 0 ? carried : undefined;
|
|
64003
|
+
}
|
|
64004
|
+
function mcpEntriesFromCloudComponents(components) {
|
|
64005
|
+
return components.filter((c2) => c2.type === "mcp").map((c2) => {
|
|
64006
|
+
const payload = (c2.meta ?? {}).mcp ?? {};
|
|
64007
|
+
const entry = { name: c2.slug };
|
|
64008
|
+
if (typeof payload.url === "string")
|
|
64009
|
+
entry.url = payload.url;
|
|
64010
|
+
if (typeof payload.command === "string")
|
|
64011
|
+
entry.command = payload.command;
|
|
64012
|
+
if (Array.isArray(payload.args))
|
|
64013
|
+
entry.args = payload.args.map(String);
|
|
64014
|
+
if (payload.env && typeof payload.env === "object")
|
|
64015
|
+
entry.env = payload.env;
|
|
64016
|
+
if (payload.headers && typeof payload.headers === "object")
|
|
64017
|
+
entry.headers = payload.headers;
|
|
64018
|
+
if (typeof payload.is_enabled === "boolean")
|
|
64019
|
+
entry.is_enabled = payload.is_enabled;
|
|
64020
|
+
const runtimeMeta = runtimeMetaFromComponent(c2);
|
|
64021
|
+
if (runtimeMeta)
|
|
64022
|
+
entry.runtime_meta = runtimeMeta;
|
|
64023
|
+
return entry;
|
|
64024
|
+
});
|
|
64025
|
+
}
|
|
64026
|
+
|
|
64027
|
+
// src/cli/sync.ts
|
|
64028
|
+
import path78 from "node:path";
|
|
64029
|
+
import fs70 from "node:fs";
|
|
64030
|
+
import os12 from "node:os";
|
|
64031
|
+
import crypto4 from "node:crypto";
|
|
63549
64032
|
var import_picocolors24 = __toESM(require_picocolors(), 1);
|
|
63550
64033
|
|
|
63551
64034
|
// src/core/memory-mcp.ts
|
|
@@ -63866,6 +64349,21 @@ async function runSync(cwd2, args) {
|
|
|
63866
64349
|
declaredSlugs: declaredMcpSlugs,
|
|
63867
64350
|
scope
|
|
63868
64351
|
});
|
|
64352
|
+
const localManifest = readManifest(cwd2);
|
|
64353
|
+
for (const component of manifest.components) {
|
|
64354
|
+
if (component.type !== "mcp")
|
|
64355
|
+
continue;
|
|
64356
|
+
const prior = prevState?.components.find((c2) => c2.type === "mcp" && c2.slug === component.slug);
|
|
64357
|
+
const entry = localManifest?.mcp.find((c2) => c2.name === component.slug);
|
|
64358
|
+
if (!prior || prior.hash !== component.hash || isDeepStrictEqual(component.meta?.runtime_mcp_auth, entry?.runtime_meta?.runtime_mcp_auth))
|
|
64359
|
+
continue;
|
|
64360
|
+
const harness = args.harness ?? link2.harness ?? link2.tracking?.harness;
|
|
64361
|
+
const locallyReplaced = harness && readHarnessMcpEntry(harness, cwd2, scope, component.slug) !== undefined && !lockEntryOwnsMcpInStore(prior, { harness, cwd: cwd2, scope });
|
|
64362
|
+
if (entry && hashMcpEntry(entry) !== prior.hash || locallyReplaced)
|
|
64363
|
+
diff2.localModified.push(component);
|
|
64364
|
+
else
|
|
64365
|
+
diff2.upstreamUpdated.push(component);
|
|
64366
|
+
}
|
|
63869
64367
|
if (diff2.added.length === 0 && diff2.upstreamUpdated.length === 0 && diff2.localModified.length === 0 && diff2.deletedUpstream.length === 0 && builtinInstall.length === 0 && builtinRemoveSlugs.length === 0) {
|
|
63870
64368
|
f2.info(`${sym.same} You're up to date.`);
|
|
63871
64369
|
writeSyncState(cwd2, {
|
|
@@ -63962,10 +64460,10 @@ async function runSync(cwd2, args) {
|
|
|
63962
64460
|
type: c2.type,
|
|
63963
64461
|
slug: c2.slug,
|
|
63964
64462
|
scope,
|
|
63965
|
-
rootDir:
|
|
64463
|
+
rootDir: path78.join(stageRoot, c2.type, c2.slug),
|
|
63966
64464
|
description: c2.description,
|
|
63967
64465
|
meta: c2.meta,
|
|
63968
|
-
payload: proxifyMcpPayload(c2.meta?.mcp),
|
|
64466
|
+
payload: proxifyMcpPayload(c2.meta?.mcp, undefined, c2.meta?.runtime_mcp_auth),
|
|
63969
64467
|
checksum: c2.hash
|
|
63970
64468
|
}));
|
|
63971
64469
|
toInstall.push(...builtinInstall);
|
|
@@ -64032,11 +64530,11 @@ async function runSync(cwd2, args) {
|
|
|
64032
64530
|
if (!exists(filePath))
|
|
64033
64531
|
continue;
|
|
64034
64532
|
try {
|
|
64035
|
-
const stat =
|
|
64533
|
+
const stat = fs70.statSync(filePath);
|
|
64036
64534
|
if (stat.isDirectory())
|
|
64037
|
-
|
|
64535
|
+
fs70.rmSync(filePath, { recursive: true, force: true });
|
|
64038
64536
|
else
|
|
64039
|
-
|
|
64537
|
+
fs70.rmSync(filePath);
|
|
64040
64538
|
} catch (err) {
|
|
64041
64539
|
f2.warn(`Failed to remove ${filePath}: ${err.message}`);
|
|
64042
64540
|
}
|
|
@@ -64077,10 +64575,23 @@ async function runSync(cwd2, args) {
|
|
|
64077
64575
|
agentMeta: prevState?.agentMeta
|
|
64078
64576
|
};
|
|
64079
64577
|
writeSyncState(cwd2, newState);
|
|
64578
|
+
if (localManifest) {
|
|
64579
|
+
for (const component of manifest.components) {
|
|
64580
|
+
if (component.type !== "mcp" || !justInstalledPaths.has(`mcp/${component.slug}`))
|
|
64581
|
+
continue;
|
|
64582
|
+
const index = localManifest.mcp.findIndex((entry2) => entry2.name === component.slug);
|
|
64583
|
+
const entry = mcpEntriesFromCloudComponents([component])[0];
|
|
64584
|
+
if (index >= 0)
|
|
64585
|
+
localManifest.mcp[index] = entry;
|
|
64586
|
+
else
|
|
64587
|
+
localManifest.mcp.push(entry);
|
|
64588
|
+
}
|
|
64589
|
+
writeManifest(cwd2, localManifest);
|
|
64590
|
+
}
|
|
64080
64591
|
$e(`Synced ${link2.name} to revision ${manifest.revision}.`);
|
|
64081
64592
|
} finally {
|
|
64082
64593
|
try {
|
|
64083
|
-
|
|
64594
|
+
fs70.rmSync(stageRoot, { recursive: true, force: true });
|
|
64084
64595
|
} catch {}
|
|
64085
64596
|
}
|
|
64086
64597
|
}
|
|
@@ -64123,19 +64634,19 @@ function computeDiff(upstream, prev) {
|
|
|
64123
64634
|
function computeLocalHash(paths) {
|
|
64124
64635
|
if (paths.length === 0)
|
|
64125
64636
|
return null;
|
|
64126
|
-
const h2 =
|
|
64637
|
+
const h2 = crypto4.createHash("sha256");
|
|
64127
64638
|
for (const filePath of paths) {
|
|
64128
64639
|
if (!exists(filePath))
|
|
64129
64640
|
return null;
|
|
64130
64641
|
try {
|
|
64131
|
-
const stat =
|
|
64642
|
+
const stat = fs70.statSync(filePath);
|
|
64132
64643
|
if (stat.isFile()) {
|
|
64133
64644
|
h2.update("F " + filePath + " ");
|
|
64134
|
-
h2.update(
|
|
64645
|
+
h2.update(fs70.readFileSync(filePath));
|
|
64135
64646
|
h2.update(`
|
|
64136
64647
|
`);
|
|
64137
64648
|
} else if (stat.isDirectory()) {
|
|
64138
|
-
for (const name of
|
|
64649
|
+
for (const name of fs70.readdirSync(filePath).sort()) {
|
|
64139
64650
|
h2.update("E " + name + `
|
|
64140
64651
|
`);
|
|
64141
64652
|
}
|
|
@@ -64147,14 +64658,14 @@ function computeLocalHash(paths) {
|
|
|
64147
64658
|
return h2.digest("hex");
|
|
64148
64659
|
}
|
|
64149
64660
|
function stageManifest(components) {
|
|
64150
|
-
const root =
|
|
64661
|
+
const root = fs70.mkdtempSync(path78.join(os12.tmpdir(), "brainbase-sync-"));
|
|
64151
64662
|
for (const c2 of components) {
|
|
64152
|
-
const compDir =
|
|
64663
|
+
const compDir = path78.join(root, c2.type, c2.slug);
|
|
64153
64664
|
ensureDir(compDir);
|
|
64154
64665
|
for (const f4 of c2.files) {
|
|
64155
|
-
const target =
|
|
64156
|
-
ensureDir(
|
|
64157
|
-
|
|
64666
|
+
const target = path78.join(compDir, f4.path);
|
|
64667
|
+
ensureDir(path78.dirname(target));
|
|
64668
|
+
fs70.writeFileSync(target, f4.content);
|
|
64158
64669
|
}
|
|
64159
64670
|
}
|
|
64160
64671
|
return root;
|
|
@@ -64171,6 +64682,7 @@ function runHarnessInstall(harnessId, components, opts, agentName) {
|
|
|
64171
64682
|
var import_picocolors39 = __toESM(require_picocolors(), 1);
|
|
64172
64683
|
|
|
64173
64684
|
// src/cli/agent-pull.ts
|
|
64685
|
+
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
64174
64686
|
import { spawn as spawn2 } from "node:child_process";
|
|
64175
64687
|
import path81 from "node:path";
|
|
64176
64688
|
import fs74 from "node:fs";
|
|
@@ -64178,7 +64690,7 @@ import os14 from "node:os";
|
|
|
64178
64690
|
var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
64179
64691
|
|
|
64180
64692
|
// src/core/manifest-unsynced.ts
|
|
64181
|
-
import
|
|
64693
|
+
import fs71 from "node:fs";
|
|
64182
64694
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
64183
64695
|
function findUnsyncedBlocks(manifest) {
|
|
64184
64696
|
const found = [];
|
|
@@ -64256,7 +64768,7 @@ function readLocalOnlyContent(cwd2) {
|
|
|
64256
64768
|
let raw = null;
|
|
64257
64769
|
if (file) {
|
|
64258
64770
|
try {
|
|
64259
|
-
raw = import_yaml3.default.parse(
|
|
64771
|
+
raw = import_yaml3.default.parse(fs71.readFileSync(file, "utf8"));
|
|
64260
64772
|
} catch {
|
|
64261
64773
|
raw = null;
|
|
64262
64774
|
}
|
|
@@ -64278,7 +64790,7 @@ function readManifestAgentId(cwd2) {
|
|
|
64278
64790
|
if (!file)
|
|
64279
64791
|
return;
|
|
64280
64792
|
try {
|
|
64281
|
-
const raw = import_yaml3.default.parse(
|
|
64793
|
+
const raw = import_yaml3.default.parse(fs71.readFileSync(file, "utf8"));
|
|
64282
64794
|
if (!raw || typeof raw !== "object")
|
|
64283
64795
|
return;
|
|
64284
64796
|
return clean(raw.id);
|
|
@@ -64296,420 +64808,6 @@ function readLocalOnlyContentReporting(cwd2) {
|
|
|
64296
64808
|
return content;
|
|
64297
64809
|
}
|
|
64298
64810
|
|
|
64299
|
-
// src/core/agent-diff.ts
|
|
64300
|
-
import path78 from "node:path";
|
|
64301
|
-
import fs71 from "node:fs";
|
|
64302
|
-
import crypto4 from "node:crypto";
|
|
64303
|
-
function compKey(type, slug) {
|
|
64304
|
-
return `${type}/${slug}`;
|
|
64305
|
-
}
|
|
64306
|
-
function hashString(s3) {
|
|
64307
|
-
return crypto4.createHash("sha256").update(s3).digest("hex");
|
|
64308
|
-
}
|
|
64309
|
-
function jsonStringAsciiSafe(s3) {
|
|
64310
|
-
return JSON.stringify(s3).replace(/[\u007f-\uffff]/g, (c2) => "\\u" + c2.charCodeAt(0).toString(16).padStart(4, "0"));
|
|
64311
|
-
}
|
|
64312
|
-
function canonicalJson2(value) {
|
|
64313
|
-
if (value === null)
|
|
64314
|
-
return "null";
|
|
64315
|
-
if (typeof value === "boolean")
|
|
64316
|
-
return value ? "true" : "false";
|
|
64317
|
-
if (typeof value === "number") {
|
|
64318
|
-
if (!Number.isFinite(value))
|
|
64319
|
-
throw new Error("Non-finite numbers are not JSON");
|
|
64320
|
-
return String(value);
|
|
64321
|
-
}
|
|
64322
|
-
if (typeof value === "string")
|
|
64323
|
-
return jsonStringAsciiSafe(value);
|
|
64324
|
-
if (Array.isArray(value)) {
|
|
64325
|
-
return "[" + value.map(canonicalJson2).join(",") + "]";
|
|
64326
|
-
}
|
|
64327
|
-
if (typeof value === "object") {
|
|
64328
|
-
const obj = value;
|
|
64329
|
-
const keys2 = Object.keys(obj).sort();
|
|
64330
|
-
return "{" + keys2.map((k3) => `${jsonStringAsciiSafe(k3)}:${canonicalJson2(obj[k3])}`).join(",") + "}";
|
|
64331
|
-
}
|
|
64332
|
-
throw new Error(`Unsupported value in canonicalJson: ${typeof value}`);
|
|
64333
|
-
}
|
|
64334
|
-
function hashMcpEntry(entry) {
|
|
64335
|
-
const payload = {
|
|
64336
|
-
args: entry.args ?? [],
|
|
64337
|
-
env: entry.env ?? {},
|
|
64338
|
-
headers: entry.headers ?? {}
|
|
64339
|
-
};
|
|
64340
|
-
if (entry.url !== undefined)
|
|
64341
|
-
payload.url = entry.url;
|
|
64342
|
-
if (entry.command !== undefined)
|
|
64343
|
-
payload.command = entry.command;
|
|
64344
|
-
payload.is_enabled = entry.is_enabled ?? true;
|
|
64345
|
-
return crypto4.createHash("sha256").update(canonicalJson2(payload)).digest("hex");
|
|
64346
|
-
}
|
|
64347
|
-
function evalWirePayload(entry) {
|
|
64348
|
-
return {
|
|
64349
|
-
criteria: entry.criteria,
|
|
64350
|
-
enabled: entry.enabled,
|
|
64351
|
-
icon: entry.icon || null,
|
|
64352
|
-
judge_agent: entry.judge_agent ?? null,
|
|
64353
|
-
judge_model: entry.judge_model,
|
|
64354
|
-
judge_type: entry.judge_type,
|
|
64355
|
-
output_shape: entry.output_shape,
|
|
64356
|
-
classification_values: entry.classification_values && entry.classification_values.length > 0 ? entry.classification_values : null
|
|
64357
|
-
};
|
|
64358
|
-
}
|
|
64359
|
-
function hashEvalEntry(entry) {
|
|
64360
|
-
return crypto4.createHash("sha256").update(canonicalJson2(evalWirePayload(entry))).digest("hex");
|
|
64361
|
-
}
|
|
64362
|
-
function fileHash(p2) {
|
|
64363
|
-
if (!exists(p2))
|
|
64364
|
-
return null;
|
|
64365
|
-
try {
|
|
64366
|
-
const buf = fs71.readFileSync(p2);
|
|
64367
|
-
return crypto4.createHash("sha256").update(buf).digest("hex");
|
|
64368
|
-
} catch {
|
|
64369
|
-
return null;
|
|
64370
|
-
}
|
|
64371
|
-
}
|
|
64372
|
-
function componentHashFromFileHashes(fileHashes) {
|
|
64373
|
-
const h2 = crypto4.createHash("sha256");
|
|
64374
|
-
for (const fh of [...fileHashes].sort()) {
|
|
64375
|
-
h2.update(fh);
|
|
64376
|
-
h2.update(`
|
|
64377
|
-
`);
|
|
64378
|
-
}
|
|
64379
|
-
return h2.digest("hex");
|
|
64380
|
-
}
|
|
64381
|
-
function hashDirectoryAsComponent(dir) {
|
|
64382
|
-
if (!exists(dir))
|
|
64383
|
-
return null;
|
|
64384
|
-
const fileHashes = [];
|
|
64385
|
-
const walk = (sub) => {
|
|
64386
|
-
let entries;
|
|
64387
|
-
try {
|
|
64388
|
-
entries = fs71.readdirSync(sub, { withFileTypes: true });
|
|
64389
|
-
} catch {
|
|
64390
|
-
return;
|
|
64391
|
-
}
|
|
64392
|
-
for (const e2 of entries) {
|
|
64393
|
-
const full = path78.join(sub, e2.name);
|
|
64394
|
-
if (e2.isFile()) {
|
|
64395
|
-
const fh = fileHash(full);
|
|
64396
|
-
if (fh)
|
|
64397
|
-
fileHashes.push(fh);
|
|
64398
|
-
} else if (e2.isDirectory()) {
|
|
64399
|
-
walk(full);
|
|
64400
|
-
}
|
|
64401
|
-
}
|
|
64402
|
-
};
|
|
64403
|
-
walk(dir);
|
|
64404
|
-
return componentHashFromFileHashes(fileHashes);
|
|
64405
|
-
}
|
|
64406
|
-
function readLocalComponents(cwd2, manifest) {
|
|
64407
|
-
const out = [];
|
|
64408
|
-
const instr = readInstructions(cwd2, manifest);
|
|
64409
|
-
if (instr !== null && instr.trim().length > 0) {
|
|
64410
|
-
out.push({
|
|
64411
|
-
type: "instruction",
|
|
64412
|
-
slug: "agent-instructions",
|
|
64413
|
-
hash: componentHashFromFileHashes([hashString(normalizeInstructionBody(instr))])
|
|
64414
|
-
});
|
|
64415
|
-
}
|
|
64416
|
-
for (const entry of manifest.skills) {
|
|
64417
|
-
let parsed;
|
|
64418
|
-
try {
|
|
64419
|
-
parsed = parseSkillSource2(entry.source);
|
|
64420
|
-
} catch {
|
|
64421
|
-
try {
|
|
64422
|
-
const core = parseSkillSource(entry.source);
|
|
64423
|
-
if (core.type !== "inline" && core.type !== "local") {
|
|
64424
|
-
out.push({
|
|
64425
|
-
type: "skill",
|
|
64426
|
-
slug: defaultSkillSlug(core),
|
|
64427
|
-
hash: null,
|
|
64428
|
-
declaredSource: entry.source
|
|
64429
|
-
});
|
|
64430
|
-
}
|
|
64431
|
-
} catch {}
|
|
64432
|
-
continue;
|
|
64433
|
-
}
|
|
64434
|
-
if (parsed.kind === "registry") {
|
|
64435
|
-
out.push({
|
|
64436
|
-
type: "skill",
|
|
64437
|
-
slug: registrySkillComponentSlug(parsed),
|
|
64438
|
-
hash: null,
|
|
64439
|
-
declaredSource: entry.source
|
|
64440
|
-
});
|
|
64441
|
-
} else {
|
|
64442
|
-
const abs = path78.resolve(cwd2, parsed.path);
|
|
64443
|
-
const slug = path78.basename(abs);
|
|
64444
|
-
out.push({
|
|
64445
|
-
type: "skill",
|
|
64446
|
-
slug,
|
|
64447
|
-
hash: hashDirectoryAsComponent(abs),
|
|
64448
|
-
declaredSource: entry.source,
|
|
64449
|
-
localPath: abs
|
|
64450
|
-
});
|
|
64451
|
-
}
|
|
64452
|
-
}
|
|
64453
|
-
for (const entry of manifest.mcp ?? []) {
|
|
64454
|
-
out.push({
|
|
64455
|
-
type: "mcp",
|
|
64456
|
-
slug: entry.name,
|
|
64457
|
-
hash: hashMcpEntry(entry)
|
|
64458
|
-
});
|
|
64459
|
-
}
|
|
64460
|
-
const pbEntries = manifest.playbooks ?? [];
|
|
64461
|
-
const pbSlugs = assignPlaybookSlugs(pbEntries.map((e2) => e2.title));
|
|
64462
|
-
for (let i = 0;i < pbEntries.length; i++) {
|
|
64463
|
-
const entry = pbEntries[i];
|
|
64464
|
-
const slug = pbSlugs[i];
|
|
64465
|
-
const body = resolvePlaybookContent(cwd2, entry);
|
|
64466
|
-
if (body === null) {
|
|
64467
|
-
out.push({ type: "playbook", slug, hash: null });
|
|
64468
|
-
continue;
|
|
64469
|
-
}
|
|
64470
|
-
const wireBody = assemblePlaybookWireBody(entry, body);
|
|
64471
|
-
out.push({
|
|
64472
|
-
type: "playbook",
|
|
64473
|
-
slug,
|
|
64474
|
-
hash: componentHashFromFileHashes([hashString(wireBody)])
|
|
64475
|
-
});
|
|
64476
|
-
}
|
|
64477
|
-
for (const entry of manifest.evals ?? []) {
|
|
64478
|
-
out.push({
|
|
64479
|
-
type: "eval",
|
|
64480
|
-
slug: entry.slug,
|
|
64481
|
-
hash: hashEvalEntry(entry)
|
|
64482
|
-
});
|
|
64483
|
-
}
|
|
64484
|
-
return out;
|
|
64485
|
-
}
|
|
64486
|
-
function threeWayDiff(input) {
|
|
64487
|
-
const lockMap = new Map;
|
|
64488
|
-
for (const c2 of input.lock)
|
|
64489
|
-
lockMap.set(compKey(c2.type, c2.slug), c2);
|
|
64490
|
-
const cloudMap = new Map;
|
|
64491
|
-
for (const c2 of input.cloud)
|
|
64492
|
-
cloudMap.set(compKey(c2.type, c2.slug), c2);
|
|
64493
|
-
const localMap = new Map;
|
|
64494
|
-
for (const c2 of input.local)
|
|
64495
|
-
localMap.set(compKey(c2.type, c2.slug), c2);
|
|
64496
|
-
const keys2 = new Set;
|
|
64497
|
-
for (const k3 of lockMap.keys())
|
|
64498
|
-
keys2.add(k3);
|
|
64499
|
-
for (const k3 of cloudMap.keys())
|
|
64500
|
-
keys2.add(k3);
|
|
64501
|
-
for (const k3 of localMap.keys())
|
|
64502
|
-
keys2.add(k3);
|
|
64503
|
-
const rows = [];
|
|
64504
|
-
for (const key2 of [...keys2].sort()) {
|
|
64505
|
-
const lock = lockMap.get(key2);
|
|
64506
|
-
const cloud = cloudMap.get(key2);
|
|
64507
|
-
const local = localMap.get(key2);
|
|
64508
|
-
const [type, slug] = key2.split("/", 2);
|
|
64509
|
-
let localHash = local?.hash ?? null;
|
|
64510
|
-
if (local && local.hash === null && local.declaredSource && lock?.source === local.declaredSource && cloud) {
|
|
64511
|
-
localHash = cloud.hash;
|
|
64512
|
-
}
|
|
64513
|
-
const cloudHash = cloud?.hash;
|
|
64514
|
-
const lockHash = lock?.hash;
|
|
64515
|
-
const declaredSource = local?.declaredSource;
|
|
64516
|
-
const present = {
|
|
64517
|
-
local: !!local,
|
|
64518
|
-
lock: !!lock,
|
|
64519
|
-
cloud: !!cloud
|
|
64520
|
-
};
|
|
64521
|
-
let status;
|
|
64522
|
-
if (present.local && present.cloud && !present.lock) {
|
|
64523
|
-
status = "added-local";
|
|
64524
|
-
} else if (!present.local && present.cloud && !present.lock) {
|
|
64525
|
-
status = "added-cloud";
|
|
64526
|
-
} else if (present.local && !present.cloud && !present.lock) {
|
|
64527
|
-
status = "added-only-local";
|
|
64528
|
-
} else if (!present.local && present.lock) {
|
|
64529
|
-
status = "removed-local";
|
|
64530
|
-
} else if (present.local && !present.cloud && present.lock) {
|
|
64531
|
-
status = "removed-cloud";
|
|
64532
|
-
} else {
|
|
64533
|
-
const sourceChanged = !!local && local.hash === null && !!local.declaredSource && lock?.source !== undefined && lock.source !== local.declaredSource;
|
|
64534
|
-
const localChanged = sourceChanged || localHash !== null && lockHash !== undefined && localHash !== lockHash;
|
|
64535
|
-
const cloudChanged = cloudHash !== undefined && lockHash !== undefined && cloudHash !== lockHash;
|
|
64536
|
-
const converged = !sourceChanged && localHash !== null && cloudHash !== undefined && localHash === cloudHash;
|
|
64537
|
-
if (converged)
|
|
64538
|
-
status = "in-sync";
|
|
64539
|
-
else if (localChanged && cloudChanged)
|
|
64540
|
-
status = "modified-both";
|
|
64541
|
-
else if (localChanged)
|
|
64542
|
-
status = "modified-local";
|
|
64543
|
-
else if (cloudChanged)
|
|
64544
|
-
status = "modified-cloud";
|
|
64545
|
-
else
|
|
64546
|
-
status = "in-sync";
|
|
64547
|
-
}
|
|
64548
|
-
rows.push({
|
|
64549
|
-
key: key2,
|
|
64550
|
-
type,
|
|
64551
|
-
slug,
|
|
64552
|
-
status,
|
|
64553
|
-
localHash: localHash ?? undefined,
|
|
64554
|
-
lockHash,
|
|
64555
|
-
cloudHash,
|
|
64556
|
-
declaredSource
|
|
64557
|
-
});
|
|
64558
|
-
}
|
|
64559
|
-
return rows;
|
|
64560
|
-
}
|
|
64561
|
-
function partitionPushRows(rows, force) {
|
|
64562
|
-
const toSend = [];
|
|
64563
|
-
const conflicts = [];
|
|
64564
|
-
const upstreamOnly = [];
|
|
64565
|
-
for (const r2 of rows) {
|
|
64566
|
-
switch (r2.status) {
|
|
64567
|
-
case "modified-local":
|
|
64568
|
-
case "added-only-local":
|
|
64569
|
-
case "added-local":
|
|
64570
|
-
case "removed-local":
|
|
64571
|
-
toSend.push(r2);
|
|
64572
|
-
break;
|
|
64573
|
-
case "modified-both":
|
|
64574
|
-
if (force)
|
|
64575
|
-
toSend.push(r2);
|
|
64576
|
-
else
|
|
64577
|
-
conflicts.push(r2);
|
|
64578
|
-
break;
|
|
64579
|
-
case "modified-cloud":
|
|
64580
|
-
case "added-cloud":
|
|
64581
|
-
case "removed-cloud":
|
|
64582
|
-
upstreamOnly.push(r2);
|
|
64583
|
-
break;
|
|
64584
|
-
case "in-sync":
|
|
64585
|
-
break;
|
|
64586
|
-
default: {
|
|
64587
|
-
const _exhaustive = r2.status;
|
|
64588
|
-
}
|
|
64589
|
-
}
|
|
64590
|
-
}
|
|
64591
|
-
return { toSend, conflicts, upstreamOnly };
|
|
64592
|
-
}
|
|
64593
|
-
function diffAgentMeta(manifestMeta, lockMeta, cloudMeta) {
|
|
64594
|
-
const eq = (a3, b4) => {
|
|
64595
|
-
if (!a3 && !b4)
|
|
64596
|
-
return true;
|
|
64597
|
-
if (!a3 || !b4)
|
|
64598
|
-
return false;
|
|
64599
|
-
return a3.name === b4.name && (a3.tagline ?? "") === (b4.tagline ?? "");
|
|
64600
|
-
};
|
|
64601
|
-
return {
|
|
64602
|
-
localChanged: !!manifestMeta && !!lockMeta && !eq(manifestMeta, lockMeta),
|
|
64603
|
-
cloudChanged: !!cloudMeta && !!lockMeta && !eq(cloudMeta, lockMeta)
|
|
64604
|
-
};
|
|
64605
|
-
}
|
|
64606
|
-
var WRITABLE_CAPABILITIES = ["memory", "browser"];
|
|
64607
|
-
var MIRRORED_CAPABILITIES = ["slack", "meeting", "github", "linear"];
|
|
64608
|
-
function manifestConfigState(manifest) {
|
|
64609
|
-
return {
|
|
64610
|
-
...manifest.machine_kind !== undefined ? { machine_kind: manifest.machine_kind } : {},
|
|
64611
|
-
...hasOwn(manifest, "default_model") ? { default_model: manifest.default_model ?? null } : {},
|
|
64612
|
-
...manifest.capabilities?.memory !== undefined ? { memory: manifest.capabilities.memory } : {},
|
|
64613
|
-
...manifest.capabilities?.browser !== undefined ? { browser: manifest.capabilities.browser } : {}
|
|
64614
|
-
};
|
|
64615
|
-
}
|
|
64616
|
-
function cloudConfigState(agent) {
|
|
64617
|
-
return {
|
|
64618
|
-
...agent.machine_kind !== undefined ? { machine_kind: agent.machine_kind } : {},
|
|
64619
|
-
...hasOwn(agent, "default_model") ? { default_model: agent.default_model ?? null } : {},
|
|
64620
|
-
...agent.memory_enabled !== undefined ? { memory: agent.memory_enabled } : {},
|
|
64621
|
-
...agent.browser_enabled !== undefined ? { browser: agent.browser_enabled } : {}
|
|
64622
|
-
};
|
|
64623
|
-
}
|
|
64624
|
-
function hasOwn(value, key2) {
|
|
64625
|
-
return !!value && Object.prototype.hasOwnProperty.call(value, key2);
|
|
64626
|
-
}
|
|
64627
|
-
function staleConnectionMirrors(manifest, cloud) {
|
|
64628
|
-
const actualByName = {
|
|
64629
|
-
slack: cloud.slack_connected,
|
|
64630
|
-
meeting: cloud.meeting_connected,
|
|
64631
|
-
github: cloud.github_connected,
|
|
64632
|
-
linear: cloud.linear_connected
|
|
64633
|
-
};
|
|
64634
|
-
const stale = [];
|
|
64635
|
-
for (const name of MIRRORED_CAPABILITIES) {
|
|
64636
|
-
const authored = manifest.capabilities?.[name];
|
|
64637
|
-
const actual = actualByName[name];
|
|
64638
|
-
if (authored === undefined || actual === undefined)
|
|
64639
|
-
continue;
|
|
64640
|
-
if (authored !== actual)
|
|
64641
|
-
stale.push({ name, authored, actual });
|
|
64642
|
-
}
|
|
64643
|
-
return stale;
|
|
64644
|
-
}
|
|
64645
|
-
function diffAgentConfig(manifest, lock, cloud) {
|
|
64646
|
-
const unsupported = [];
|
|
64647
|
-
const machineSupported = cloud.machine_kind !== undefined;
|
|
64648
|
-
const defaultModelSupported = hasOwn(cloud, "default_model");
|
|
64649
|
-
if (manifest.machine_kind !== undefined && !machineSupported) {
|
|
64650
|
-
unsupported.push("machine_kind");
|
|
64651
|
-
}
|
|
64652
|
-
if (manifest.default_model !== undefined && !defaultModelSupported) {
|
|
64653
|
-
unsupported.push("default_model");
|
|
64654
|
-
}
|
|
64655
|
-
const machineMismatch = manifest.machine_kind !== undefined && machineSupported && manifest.machine_kind !== cloud.machine_kind;
|
|
64656
|
-
const machineLocalChanged = manifest.machine_kind !== undefined && machineSupported && (lock?.machine_kind !== undefined ? manifest.machine_kind !== lock.machine_kind && manifest.machine_kind !== cloud.machine_kind : manifest.machine_kind !== cloud.machine_kind);
|
|
64657
|
-
const machineCloudChanged = lock?.machine_kind !== undefined && machineSupported && lock.machine_kind !== cloud.machine_kind && manifest.machine_kind !== cloud.machine_kind;
|
|
64658
|
-
const machineConverged = manifest.machine_kind !== undefined && machineSupported && manifest.machine_kind === cloud.machine_kind && (lock?.machine_kind === undefined || lock.machine_kind !== cloud.machine_kind);
|
|
64659
|
-
const defaultModel = threeWayField(defaultModelSupported, manifest.default_model, cloud.default_model, lock, "default_model");
|
|
64660
|
-
const memory = threeWayField(hasOwn(cloud, "memory"), manifest.memory, cloud.memory, lock, "memory");
|
|
64661
|
-
const browser = threeWayField(hasOwn(cloud, "browser"), manifest.browser, cloud.browser, lock, "browser");
|
|
64662
|
-
if (manifest.memory !== undefined && !hasOwn(cloud, "memory")) {
|
|
64663
|
-
unsupported.push("memory");
|
|
64664
|
-
}
|
|
64665
|
-
if (manifest.browser !== undefined && !hasOwn(cloud, "browser")) {
|
|
64666
|
-
unsupported.push("browser");
|
|
64667
|
-
}
|
|
64668
|
-
return {
|
|
64669
|
-
unsupported,
|
|
64670
|
-
machineMismatch,
|
|
64671
|
-
machineLocalChanged,
|
|
64672
|
-
machineCloudChanged,
|
|
64673
|
-
defaultModelLocalChanged: defaultModel.localChanged,
|
|
64674
|
-
defaultModelCloudChanged: defaultModel.cloudChanged,
|
|
64675
|
-
defaultModelConflict: defaultModel.conflict,
|
|
64676
|
-
memory,
|
|
64677
|
-
browser,
|
|
64678
|
-
baselineConverged: machineConverged || defaultModel.converged || memory.converged || browser.converged
|
|
64679
|
-
};
|
|
64680
|
-
}
|
|
64681
|
-
function threeWayField(supported, authored, cloudRaw, lock, key2) {
|
|
64682
|
-
const result2 = {
|
|
64683
|
-
localChanged: false,
|
|
64684
|
-
cloudChanged: false,
|
|
64685
|
-
conflict: false,
|
|
64686
|
-
converged: false
|
|
64687
|
-
};
|
|
64688
|
-
if (!supported)
|
|
64689
|
-
return result2;
|
|
64690
|
-
const cloudValue = cloudRaw ?? null;
|
|
64691
|
-
const lockSupported = hasOwn(lock, key2);
|
|
64692
|
-
const lockValue = lock?.[key2] ?? null;
|
|
64693
|
-
if (authored === undefined) {
|
|
64694
|
-
if (lockSupported)
|
|
64695
|
-
result2.cloudChanged = cloudValue !== lockValue;
|
|
64696
|
-
return result2;
|
|
64697
|
-
}
|
|
64698
|
-
const localValue = authored ?? null;
|
|
64699
|
-
if (!lockSupported) {
|
|
64700
|
-
result2.localChanged = localValue !== cloudValue;
|
|
64701
|
-
result2.converged = localValue === cloudValue;
|
|
64702
|
-
return result2;
|
|
64703
|
-
}
|
|
64704
|
-
const localMoved = localValue !== lockValue;
|
|
64705
|
-
const cloudMoved = cloudValue !== lockValue;
|
|
64706
|
-
result2.conflict = localMoved && cloudMoved && localValue !== cloudValue;
|
|
64707
|
-
result2.localChanged = localMoved && localValue !== cloudValue;
|
|
64708
|
-
result2.cloudChanged = cloudMoved && localValue !== cloudValue;
|
|
64709
|
-
result2.converged = localMoved && cloudMoved && localValue === cloudValue;
|
|
64710
|
-
return result2;
|
|
64711
|
-
}
|
|
64712
|
-
|
|
64713
64811
|
// src/core/eval-merge.ts
|
|
64714
64812
|
function evalsFromCloudComponents(components) {
|
|
64715
64813
|
return components.filter((c2) => c2.type === "eval").map((c2) => {
|
|
@@ -64792,41 +64890,6 @@ function capabilityBaselineAfterPush(cloudAgent, previous, diff2) {
|
|
|
64792
64890
|
return out;
|
|
64793
64891
|
}
|
|
64794
64892
|
|
|
64795
|
-
// src/core/mcp-merge.ts
|
|
64796
|
-
var RUNTIME_META_PREFIX = "runtime_";
|
|
64797
|
-
function runtimeMetaFromComponent(component) {
|
|
64798
|
-
const meta = component.meta ?? {};
|
|
64799
|
-
const carried = {};
|
|
64800
|
-
for (const [key2, value] of Object.entries(meta)) {
|
|
64801
|
-
if (key2.startsWith(RUNTIME_META_PREFIX) && value !== undefined) {
|
|
64802
|
-
carried[key2] = value;
|
|
64803
|
-
}
|
|
64804
|
-
}
|
|
64805
|
-
return Object.keys(carried).length > 0 ? carried : undefined;
|
|
64806
|
-
}
|
|
64807
|
-
function mcpEntriesFromCloudComponents(components) {
|
|
64808
|
-
return components.filter((c2) => c2.type === "mcp").map((c2) => {
|
|
64809
|
-
const payload = (c2.meta ?? {}).mcp ?? {};
|
|
64810
|
-
const entry = { name: c2.slug };
|
|
64811
|
-
if (typeof payload.url === "string")
|
|
64812
|
-
entry.url = payload.url;
|
|
64813
|
-
if (typeof payload.command === "string")
|
|
64814
|
-
entry.command = payload.command;
|
|
64815
|
-
if (Array.isArray(payload.args))
|
|
64816
|
-
entry.args = payload.args.map(String);
|
|
64817
|
-
if (payload.env && typeof payload.env === "object")
|
|
64818
|
-
entry.env = payload.env;
|
|
64819
|
-
if (payload.headers && typeof payload.headers === "object")
|
|
64820
|
-
entry.headers = payload.headers;
|
|
64821
|
-
if (typeof payload.is_enabled === "boolean")
|
|
64822
|
-
entry.is_enabled = payload.is_enabled;
|
|
64823
|
-
const runtimeMeta = runtimeMetaFromComponent(c2);
|
|
64824
|
-
if (runtimeMeta)
|
|
64825
|
-
entry.runtime_meta = runtimeMeta;
|
|
64826
|
-
return entry;
|
|
64827
|
-
});
|
|
64828
|
-
}
|
|
64829
|
-
|
|
64830
64893
|
// src/core/secrets-env.ts
|
|
64831
64894
|
import path79 from "node:path";
|
|
64832
64895
|
import fs72 from "node:fs";
|
|
@@ -65035,7 +65098,8 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
65035
65098
|
slug: entry.name,
|
|
65036
65099
|
scope,
|
|
65037
65100
|
rootDir: compDir,
|
|
65038
|
-
payload: proxifyMcpPayload(payload),
|
|
65101
|
+
payload: proxifyMcpPayload(payload, undefined, entry.runtime_meta?.runtime_mcp_auth),
|
|
65102
|
+
meta: entry.runtime_meta,
|
|
65039
65103
|
checksum: ""
|
|
65040
65104
|
});
|
|
65041
65105
|
}
|
|
@@ -65426,13 +65490,28 @@ async function runAgentPull(cwd2, args) {
|
|
|
65426
65490
|
break;
|
|
65427
65491
|
}
|
|
65428
65492
|
}
|
|
65493
|
+
for (const r2 of rows) {
|
|
65494
|
+
if (r2.type !== "mcp" || !["in-sync", "added-local"].includes(r2.status))
|
|
65495
|
+
continue;
|
|
65496
|
+
const remote = cloud.components.find((c2) => c2.type === "mcp" && c2.slug === r2.slug);
|
|
65497
|
+
const local = existingManifest?.mcp.find((entry) => entry.name === r2.slug);
|
|
65498
|
+
if (!remote || isDeepStrictEqual2(remote.meta?.runtime_mcp_auth, local?.runtime_meta?.runtime_mcp_auth))
|
|
65499
|
+
continue;
|
|
65500
|
+
const prior = lock?.components.find((c2) => c2.type === "mcp" && c2.slug === r2.slug);
|
|
65501
|
+
const target = { harness, cwd: cwd2, scope: args.scope ?? "project" };
|
|
65502
|
+
const locallyReplaced = prior && readHarnessMcpEntry(harness, cwd2, target.scope, r2.slug) !== undefined && !lockEntryOwnsMcpInStore(prior, target);
|
|
65503
|
+
if (locallyReplaced && !override)
|
|
65504
|
+
conflicts.push(r2);
|
|
65505
|
+
else
|
|
65506
|
+
toInstallKeys.add(r2.key);
|
|
65507
|
+
}
|
|
65429
65508
|
const keepLocalKeys = new Set;
|
|
65430
65509
|
if (conflicts.length > 0) {
|
|
65431
65510
|
requireInteractive(`${conflicts.length} file(s) changed both locally and in the cloud — resolve them in an interactive terminal, or pass --force to take the cloud copy.`);
|
|
65432
65511
|
}
|
|
65433
65512
|
for (const r2 of conflicts) {
|
|
65434
65513
|
const choice = await ie({
|
|
65435
|
-
message: r2.status === "modified-both" ? `${fmtType(r2.type)} ${import_picocolors26.default.bold(r2.slug)} — both you and the cloud edited it` : `${fmtType(r2.type)} ${import_picocolors26.default.bold(r2.slug)} — you have local edits not yet pushed`,
|
|
65514
|
+
message: r2.status === "in-sync" || r2.status === "added-local" ? `${fmtType(r2.type)} ${import_picocolors26.default.bold(r2.slug)} — your installed server was replaced and its cloud authentication changed` : r2.status === "modified-both" ? `${fmtType(r2.type)} ${import_picocolors26.default.bold(r2.slug)} — both you and the cloud edited it` : `${fmtType(r2.type)} ${import_picocolors26.default.bold(r2.slug)} — you have local edits not yet pushed`,
|
|
65436
65515
|
options: [
|
|
65437
65516
|
{ value: "cloud", label: "Use the cloud's version (discard local edits)" },
|
|
65438
65517
|
{ value: "keep", label: "Keep your local edits (skip this one)" }
|
|
@@ -65512,6 +65591,7 @@ async function runAgentPull(cwd2, args) {
|
|
|
65512
65591
|
const installComponents = cloud.components.filter((c2) => toInstallKeys.has(`${c2.type}/${c2.slug}`));
|
|
65513
65592
|
const stageRoot = stageManifestComponents(installComponents);
|
|
65514
65593
|
const justInstalledPaths = new Map;
|
|
65594
|
+
const skippedMcpSlugs = new Set;
|
|
65515
65595
|
const justInstalledFingerprints = new Map;
|
|
65516
65596
|
try {
|
|
65517
65597
|
const availableSecrets = await pullSecrets(cwd2, agentId);
|
|
@@ -65525,7 +65605,7 @@ async function runAgentPull(cwd2, args) {
|
|
|
65525
65605
|
rootDir: path81.join(stageRoot, c2.type, c2.slug),
|
|
65526
65606
|
description: c2.description,
|
|
65527
65607
|
meta: c2.meta,
|
|
65528
|
-
payload: proxifyMcpPayload(structuredClone(c2.meta?.mcp)),
|
|
65608
|
+
payload: proxifyMcpPayload(structuredClone(c2.meta?.mcp), undefined, c2.meta?.runtime_mcp_auth),
|
|
65529
65609
|
checksum: c2.hash,
|
|
65530
65610
|
source: skillSourceFromMeta(c2)
|
|
65531
65611
|
}));
|
|
@@ -65550,6 +65630,8 @@ async function runAgentPull(cwd2, args) {
|
|
|
65550
65630
|
}
|
|
65551
65631
|
}
|
|
65552
65632
|
for (const s3 of result2.skipped) {
|
|
65633
|
+
if (s3.type === "mcp")
|
|
65634
|
+
skippedMcpSlugs.add(s3.slug);
|
|
65553
65635
|
if (s3.reason !== KEPT_UNOWNED_MCP_SKIP)
|
|
65554
65636
|
continue;
|
|
65555
65637
|
f2.warn(`Kept local MCP server ${import_picocolors26.default.bold(s3.slug)}: not installed by this agent; the cloud has it disabled. Remove it from your harness config to let the cloud's setting apply.`);
|
|
@@ -65597,6 +65679,24 @@ async function runAgentPull(cwd2, args) {
|
|
|
65597
65679
|
materializeEntrypoint(cwd2, cloudAgent.entrypoint ?? "", existingManifest);
|
|
65598
65680
|
materializePlaybooks(cwd2, cloud, toInstallKeys, keepLocalKeys, existingManifest);
|
|
65599
65681
|
const yaml = mergeManifest(cwd2, existingManifest, cloud, cloudAgent, harness, override ? {} : readLocalOnlyContentReporting(cwd2), new Map((lock?.components ?? []).filter((c2) => c2.type === "eval").map((c2) => [c2.slug, c2.hash])), new Set([...keepLocalKeys].filter((key2) => key2.startsWith("eval/")).map((key2) => key2.slice("eval/".length))));
|
|
65682
|
+
for (const entry of existingManifest?.mcp ?? []) {
|
|
65683
|
+
if (!keepLocalKeys.has(`mcp/${entry.name}`))
|
|
65684
|
+
continue;
|
|
65685
|
+
const index = yaml.mcp.findIndex((c2) => c2.name === entry.name);
|
|
65686
|
+
if (index >= 0)
|
|
65687
|
+
yaml.mcp[index] = entry;
|
|
65688
|
+
}
|
|
65689
|
+
for (const entry of yaml.mcp) {
|
|
65690
|
+
if (!skippedMcpSlugs.has(entry.name))
|
|
65691
|
+
continue;
|
|
65692
|
+
const priorAuth = existingManifest?.mcp.find((c2) => c2.name === entry.name)?.runtime_meta?.runtime_mcp_auth;
|
|
65693
|
+
const runtimeMeta = { ...entry.runtime_meta };
|
|
65694
|
+
if (priorAuth === undefined)
|
|
65695
|
+
delete runtimeMeta.runtime_mcp_auth;
|
|
65696
|
+
else
|
|
65697
|
+
runtimeMeta.runtime_mcp_auth = priorAuth;
|
|
65698
|
+
entry.runtime_meta = Object.keys(runtimeMeta).length > 0 ? runtimeMeta : undefined;
|
|
65699
|
+
}
|
|
65600
65700
|
writeManifest(cwd2, yaml);
|
|
65601
65701
|
writeLink(cwd2, buildLinkFromAgent(cloudAgent, harness, readLink(cwd2)));
|
|
65602
65702
|
const lockComponents = buildLockComponents({
|
|
@@ -69285,7 +69385,7 @@ async function installAgentFresh(input) {
|
|
|
69285
69385
|
rootDir: path87.join(stageRoot, c2.type, c2.slug),
|
|
69286
69386
|
description: c2.description,
|
|
69287
69387
|
meta: c2.meta,
|
|
69288
|
-
payload: proxifyMcpPayload(structuredClone(c2.meta?.mcp)),
|
|
69388
|
+
payload: proxifyMcpPayload(structuredClone(c2.meta?.mcp), undefined, c2.meta?.runtime_mcp_auth),
|
|
69289
69389
|
checksum: c2.hash
|
|
69290
69390
|
}));
|
|
69291
69391
|
toInstall.push(...builtinInstall);
|
|
@@ -71867,14 +71967,21 @@ import fs81 from "node:fs";
|
|
|
71867
71967
|
function collectServers(cwd2, env3 = process.env) {
|
|
71868
71968
|
const out = [];
|
|
71869
71969
|
const seen = new Set;
|
|
71970
|
+
let manifestEntries = [];
|
|
71971
|
+
try {
|
|
71972
|
+
manifestEntries = readManifest(cwd2)?.mcp ?? [];
|
|
71973
|
+
} catch {}
|
|
71974
|
+
const identities = new Map(manifestEntries.map((entry) => [entry.name, entry]));
|
|
71870
71975
|
for (const source of [readClaudeCode, readCodex, readKafka, readResolvedMcps]) {
|
|
71871
71976
|
for (const [name, entry] of source(cwd2)) {
|
|
71872
|
-
|
|
71977
|
+
const authored = identities.get(name);
|
|
71978
|
+
const identity2 = typeof entry.url === "string" && typeof authored?.url === "string" && mcpUpstreamUrl(entry.url, env3) === mcpUpstreamUrl(authored.url, env3) ? authored.runtime_meta?.runtime_mcp_auth : undefined;
|
|
71979
|
+
pushResolved(out, seen, name, entry, env3, identity2);
|
|
71873
71980
|
}
|
|
71874
71981
|
}
|
|
71875
71982
|
return out;
|
|
71876
71983
|
}
|
|
71877
|
-
function pushResolved(out, seen, name, entry, env3) {
|
|
71984
|
+
function pushResolved(out, seen, name, entry, env3, identity2) {
|
|
71878
71985
|
if (seen.has(name))
|
|
71879
71986
|
return;
|
|
71880
71987
|
if (entry.is_enabled === false) {
|
|
@@ -71897,7 +72004,7 @@ function pushResolved(out, seen, name, entry, env3) {
|
|
|
71897
72004
|
};
|
|
71898
72005
|
}
|
|
71899
72006
|
delete normalized.http_headers;
|
|
71900
|
-
const proxied = proxifyMcpPayload(normalized, env3) ?? normalized;
|
|
72007
|
+
const proxied = proxifyMcpPayload(normalized, env3, identity2) ?? normalized;
|
|
71901
72008
|
const resolved = resolveMcpEnvTemplates(proxied, env3) ?? proxied;
|
|
71902
72009
|
const finalUrl = resolved.url;
|
|
71903
72010
|
if (typeof finalUrl !== "string" || finalUrl.length === 0)
|