@brainbase-labs/cli 0.52.0 → 0.53.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 +58 -17
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -36091,7 +36091,7 @@ function padStart(s, n) {
|
|
|
36091
36091
|
// package.json
|
|
36092
36092
|
var package_default = {
|
|
36093
36093
|
name: "@brainbase-labs/cli",
|
|
36094
|
-
version: "0.
|
|
36094
|
+
version: "0.53.0",
|
|
36095
36095
|
description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
|
|
36096
36096
|
type: "module",
|
|
36097
36097
|
bin: {
|
|
@@ -67885,9 +67885,6 @@ function automationErrorEnvelope(command, error) {
|
|
|
67885
67885
|
};
|
|
67886
67886
|
}
|
|
67887
67887
|
|
|
67888
|
-
// src/core/interfaces-api.ts
|
|
67889
|
-
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
67890
|
-
|
|
67891
67888
|
// src/core/fastapi-detail.ts
|
|
67892
67889
|
function record(value) {
|
|
67893
67890
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -67900,6 +67897,9 @@ function rejectsBodyField(body, field) {
|
|
|
67900
67897
|
return fastApiDetails(body).some((entry) => entry.type === "extra_forbidden" && Array.isArray(entry.loc) && entry.loc[0] === "body" && entry.loc[1] === field);
|
|
67901
67898
|
}
|
|
67902
67899
|
|
|
67900
|
+
// src/core/interfaces-api.ts
|
|
67901
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
67902
|
+
|
|
67903
67903
|
// src/ui/terminal-safe.ts
|
|
67904
67904
|
function sanitizeLabel(s3) {
|
|
67905
67905
|
return s3.replace(/\u001b\][\s\S]*?(?:\u0007|\u001b\\|$)/g, "").replace(/\u001b\[[\u0030-\u003f]*[\u0020-\u002f]*[\u0040-\u007e]?/g, "").replace(/\u001b[\s\S]?/g, "").replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/g, "");
|
|
@@ -68450,6 +68450,7 @@ var REASONS = {
|
|
|
68450
68450
|
"versioning is paused": "versioning_paused",
|
|
68451
68451
|
"restore already in progress": "restore_in_progress"
|
|
68452
68452
|
};
|
|
68453
|
+
var PIN_CONFLICTS = new Set(["pin_changed", "not_pinned"]);
|
|
68453
68454
|
function sentence(value) {
|
|
68454
68455
|
const trimmed = value.trim();
|
|
68455
68456
|
const capital = trimmed.charAt(0).toUpperCase() + trimmed.slice(1);
|
|
@@ -68474,7 +68475,9 @@ function toVersionsError(error, agentId) {
|
|
|
68474
68475
|
const detail = record2(body?.detail);
|
|
68475
68476
|
const serverText = text2(body?.detail) ?? text2(detail?.message) ?? text2(body?.error);
|
|
68476
68477
|
const said = clean(serverText ?? error.message);
|
|
68477
|
-
const
|
|
68478
|
+
const detailCode = text2(detail?.code);
|
|
68479
|
+
const pinReason = status === 409 && detailCode && PIN_CONFLICTS.has(detailCode) ? detailCode : null;
|
|
68480
|
+
const reason = pinReason ?? (serverText ? REASONS[serverText.toLowerCase()] ?? null : null);
|
|
68478
68481
|
const details = {
|
|
68479
68482
|
status,
|
|
68480
68483
|
retry_after: retrySeconds(error.retryAfter),
|
|
@@ -68510,7 +68513,7 @@ function toVersionsError(error, agentId) {
|
|
|
68510
68513
|
break;
|
|
68511
68514
|
case 409:
|
|
68512
68515
|
code = "conflict";
|
|
68513
|
-
message = reason === "versioning_paused" ? "Versioning is paused on Brainbase, so nothing was changed. Try again later." : reason === "restore_in_progress" ? "A restore of this agent is already running. Wait for it to finish, then check `brainbase agent versions list`." : sentence(said);
|
|
68516
|
+
message = reason === "versioning_paused" ? "Versioning is paused on Brainbase, so nothing was changed. Try again later." : reason === "restore_in_progress" ? "A restore of this agent is already running. Wait for it to finish, then check `brainbase agent versions list`." : reason === "pin_changed" ? `Someone changed this agent's pin after it was read, so nothing was changed. Run \`brainbase agent versions list --agent ${sanitizeLabel(agentId)}\` to see the pin now, then try again.` : reason === "not_pinned" ? "The agent is not pinned, so there was nothing to unpin." : sentence(said);
|
|
68514
68517
|
break;
|
|
68515
68518
|
case 502:
|
|
68516
68519
|
if (details.sections?.some((section) => section.error !== null)) {
|
|
@@ -68638,11 +68641,21 @@ var agentVersionsApi = {
|
|
|
68638
68641
|
throw new AgentVersionsError("No answer came back from the restore in time, so whether it happened is unknown. " + `Run \`brainbase agent versions list --agent ${sanitizeLabel(agentId)}\` and look for a new rollback version before trying again.`, "outcome_unknown", null, NO_DETAILS);
|
|
68639
68642
|
}
|
|
68640
68643
|
},
|
|
68641
|
-
pin(agentId, versionId) {
|
|
68642
|
-
|
|
68644
|
+
async pin(agentId, versionId, currentPinId) {
|
|
68645
|
+
try {
|
|
68646
|
+
return await write2(agentId, pinPath(agentId), "PUT", {
|
|
68647
|
+
version_id: versionId,
|
|
68648
|
+
expected_version_id: currentPinId
|
|
68649
|
+
});
|
|
68650
|
+
} catch (error) {
|
|
68651
|
+
if (!(error instanceof ApiError && error.status === 422 && rejectsBodyField(error.body, "expected_version_id"))) {
|
|
68652
|
+
throw error;
|
|
68653
|
+
}
|
|
68654
|
+
return write2(agentId, pinPath(agentId), "PUT", { version_id: versionId });
|
|
68655
|
+
}
|
|
68643
68656
|
},
|
|
68644
|
-
unpin(agentId) {
|
|
68645
|
-
return write2(agentId, pinPath(agentId)
|
|
68657
|
+
unpin(agentId, pinnedVersionId) {
|
|
68658
|
+
return write2(agentId, `${pinPath(agentId)}${masListQuery({ expected_version_id: pinnedVersionId })}`, "DELETE");
|
|
68646
68659
|
}
|
|
68647
68660
|
};
|
|
68648
68661
|
|
|
@@ -81814,6 +81827,7 @@ function renderLines(lines, indent) {
|
|
|
81814
81827
|
var import_picocolors46 = __toESM(require_picocolors(), 1);
|
|
81815
81828
|
var PIN_NOTE = "New tasks will run this version's instructions, entrypoint, installed skills, tools, playbooks, harness and default model. " + "Secrets, credentials, machine settings, permission rules, connections and skill contents always stay current. " + "Tasks already running keep the version they started with.";
|
|
81816
81829
|
var UNPIN_NOTE = "New tasks will run the agent's current configuration again. Tasks already running keep the version they started with.";
|
|
81830
|
+
var NOT_PINNED_NOTE = "This agent is not pinned, so nothing changed.";
|
|
81817
81831
|
var PULL_NOTE = "This folder is now behind the cloud. Run `brainbase agent pull` to bring it up to date.";
|
|
81818
81832
|
function pinnedNote(pin) {
|
|
81819
81833
|
return `This agent is pinned to ${pinName(pin)}, so new tasks keep running that version, not the restored configuration, until you run \`brainbase agent versions unpin\`.`;
|
|
@@ -81995,18 +82009,18 @@ async function pin(ctx) {
|
|
|
81995
82009
|
const agentId = resolveAgentId(ctx.cwd, parsed);
|
|
81996
82010
|
const action = `Pinning agent ${sanitizeLabel(agentId)} to ${sanitizeLabel(ref)}`;
|
|
81997
82011
|
requireConsentPossible(yes, json3, action, ctx.deps);
|
|
81998
|
-
const { version: version2, capturePending } = await agentVersionsApi.resolve(agentId, ref);
|
|
82012
|
+
const { version: version2, pin: current, capturePending } = await agentVersionsApi.resolve(agentId, ref);
|
|
81999
82013
|
const accepted = await confirmChange({
|
|
82000
82014
|
yes,
|
|
82001
82015
|
json: json3,
|
|
82002
82016
|
action,
|
|
82003
|
-
consequence: PIN_NOTE,
|
|
82017
|
+
consequence: current ? `${PIN_NOTE} It is pinned to ${pinName(current)} now.` : PIN_NOTE,
|
|
82004
82018
|
question: `Pin the agent to ${versionName(version2)}?`,
|
|
82005
82019
|
deps: ctx.deps
|
|
82006
82020
|
});
|
|
82007
82021
|
if (!accepted)
|
|
82008
82022
|
return;
|
|
82009
|
-
const result2 = await agentVersionsApi.pin(agentId, version2.id);
|
|
82023
|
+
const result2 = await agentVersionsApi.pin(agentId, version2.id, current?.version_id ?? null);
|
|
82010
82024
|
const notes = [...pendingNotes(capturePending), PIN_NOTE];
|
|
82011
82025
|
if (json3) {
|
|
82012
82026
|
printJson({ ...result2, notes });
|
|
@@ -82018,6 +82032,24 @@ async function pin(ctx) {
|
|
|
82018
82032
|
printNotes(notes);
|
|
82019
82033
|
});
|
|
82020
82034
|
}
|
|
82035
|
+
function printNotPinned(json3) {
|
|
82036
|
+
if (json3) {
|
|
82037
|
+
printJson({ pinned_version_id: null, pinned_at: null, pinned_by: null, changed: false, notes: [NOT_PINNED_NOTE] });
|
|
82038
|
+
return;
|
|
82039
|
+
}
|
|
82040
|
+
console.log(`
|
|
82041
|
+
${NOT_PINNED_NOTE}
|
|
82042
|
+
`);
|
|
82043
|
+
}
|
|
82044
|
+
async function unpinIfStill(agentId, versionId) {
|
|
82045
|
+
try {
|
|
82046
|
+
return await agentVersionsApi.unpin(agentId, versionId);
|
|
82047
|
+
} catch (error2) {
|
|
82048
|
+
if (error2 instanceof AgentVersionsError && error2.reason === "not_pinned")
|
|
82049
|
+
return null;
|
|
82050
|
+
throw error2;
|
|
82051
|
+
}
|
|
82052
|
+
}
|
|
82021
82053
|
async function unpin(ctx) {
|
|
82022
82054
|
let json3 = wantsJson(ctx.args);
|
|
82023
82055
|
await runReportingErrors(() => json3, async () => {
|
|
@@ -82028,24 +82060,33 @@ async function unpin(ctx) {
|
|
|
82028
82060
|
const agentId = resolveAgentId(ctx.cwd, parsed);
|
|
82029
82061
|
const action = `Unpinning agent ${sanitizeLabel(agentId)}`;
|
|
82030
82062
|
requireConsentPossible(yes, json3, action, ctx.deps);
|
|
82063
|
+
const { pin: current } = await agentVersionsApi.latest(agentId);
|
|
82064
|
+
if (!current) {
|
|
82065
|
+
printNotPinned(json3);
|
|
82066
|
+
return;
|
|
82067
|
+
}
|
|
82031
82068
|
const accepted = await confirmChange({
|
|
82032
82069
|
yes,
|
|
82033
82070
|
json: json3,
|
|
82034
82071
|
action,
|
|
82035
82072
|
consequence: UNPIN_NOTE,
|
|
82036
|
-
question:
|
|
82073
|
+
question: `Unpin the agent from ${pinName(current)}?`,
|
|
82037
82074
|
deps: ctx.deps
|
|
82038
82075
|
});
|
|
82039
82076
|
if (!accepted)
|
|
82040
82077
|
return;
|
|
82041
|
-
const result2 = await
|
|
82078
|
+
const result2 = await unpinIfStill(agentId, current.version_id);
|
|
82079
|
+
if (!result2) {
|
|
82080
|
+
printNotPinned(json3);
|
|
82081
|
+
return;
|
|
82082
|
+
}
|
|
82042
82083
|
const notes = [UNPIN_NOTE];
|
|
82043
82084
|
if (json3) {
|
|
82044
|
-
printJson({ ...result2, notes });
|
|
82085
|
+
printJson({ ...result2, changed: true, notes });
|
|
82045
82086
|
return;
|
|
82046
82087
|
}
|
|
82047
82088
|
console.log(`
|
|
82048
|
-
${import_picocolors46.default.green("✓")} Unpinned
|
|
82089
|
+
${import_picocolors46.default.green("✓")} Unpinned from ${pinName(current)}
|
|
82049
82090
|
`);
|
|
82050
82091
|
printNotes(notes);
|
|
82051
82092
|
});
|