@brainbase-labs/cli 0.54.0 → 0.57.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 +2372 -593
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -35182,9 +35182,9 @@ var require_dist2 = __commonJS((exports, module) => {
|
|
|
35182
35182
|
});
|
|
35183
35183
|
|
|
35184
35184
|
// src/index.ts
|
|
35185
|
-
var
|
|
35185
|
+
var import_picocolors84 = __toESM(require_picocolors(), 1);
|
|
35186
35186
|
import process14 from "node:process";
|
|
35187
|
-
import
|
|
35187
|
+
import fs96 from "node:fs";
|
|
35188
35188
|
|
|
35189
35189
|
// src/cli/template.ts
|
|
35190
35190
|
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
@@ -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.57.0",
|
|
36095
36095
|
description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
|
|
36096
36096
|
type: "module",
|
|
36097
36097
|
bin: {
|
|
@@ -55200,6 +55200,9 @@ function masControlPlaneBaseUrl(session) {
|
|
|
55200
55200
|
const controlPlane = process.env.BRAINBASE_CONTROL_PLANE_URL?.trim();
|
|
55201
55201
|
return normalizeControlPlaneUrl(controlPlane || session?.control_plane_url);
|
|
55202
55202
|
}
|
|
55203
|
+
function masEndpointUrl(pathname, session) {
|
|
55204
|
+
return `${masControlPlaneBaseUrl(session)}${pathname}`;
|
|
55205
|
+
}
|
|
55203
55206
|
function apiBase(session) {
|
|
55204
55207
|
const suffix = usesLegacyControlPlane() ? "/api/cli" : "/v2/cli";
|
|
55205
55208
|
return `${controlPlaneBaseUrl(session)}${suffix}`;
|
|
@@ -55737,6 +55740,23 @@ var masApi = {
|
|
|
55737
55740
|
createDesign(agentId, input) {
|
|
55738
55741
|
return masResourceRequest(`/agents/${encodeURIComponent(agentId)}/designs`, { method: "POST", body: JSON.stringify(input) });
|
|
55739
55742
|
},
|
|
55743
|
+
createOrchestrationFromAgent(input) {
|
|
55744
|
+
return masResourceRequest("/orchestrations", {
|
|
55745
|
+
method: "POST",
|
|
55746
|
+
body: JSON.stringify({
|
|
55747
|
+
group_id: input.group_id,
|
|
55748
|
+
name: input.name,
|
|
55749
|
+
description: input.description,
|
|
55750
|
+
members: [input.agent_id]
|
|
55751
|
+
})
|
|
55752
|
+
});
|
|
55753
|
+
},
|
|
55754
|
+
async getAgentSummary(agentId) {
|
|
55755
|
+
const body = await masReadRequest(`/agents/${encodeURIComponent(agentId)}`);
|
|
55756
|
+
const { name } = masNamedRecord(body, "agent", "title");
|
|
55757
|
+
const description = body.description;
|
|
55758
|
+
return { name, description: typeof description === "string" ? description : "" };
|
|
55759
|
+
},
|
|
55740
55760
|
async deleteDesign(agentId, designId) {
|
|
55741
55761
|
await masResourceRequest(`/agents/${encodeURIComponent(agentId)}/designs/${encodeURIComponent(designId)}`, { method: "DELETE" });
|
|
55742
55762
|
},
|
|
@@ -55972,6 +55992,13 @@ var api = {
|
|
|
55972
55992
|
getOrchestration(orchId) {
|
|
55973
55993
|
return request(`/orchestrations/${encodeURIComponent(orchId)}`);
|
|
55974
55994
|
},
|
|
55995
|
+
fireOrchestrationTrigger(orchId, triggerId, payload, idempotencyKey) {
|
|
55996
|
+
return masResourceRequest(`/orchestrations/${encodeURIComponent(orchId)}/triggers/${encodeURIComponent(triggerId)}/fire`, {
|
|
55997
|
+
method: "POST",
|
|
55998
|
+
headers: idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {},
|
|
55999
|
+
body: JSON.stringify(payload)
|
|
56000
|
+
});
|
|
56001
|
+
},
|
|
55975
56002
|
getOrchestrationManifest(orchId) {
|
|
55976
56003
|
return request(`/orchestrations/${encodeURIComponent(orchId)}/manifest`);
|
|
55977
56004
|
},
|
|
@@ -82445,6 +82472,10 @@ var SyncedScheduleTriggerSchema = exports_external.object({
|
|
|
82445
82472
|
node_id: exports_external.string(),
|
|
82446
82473
|
hash: exports_external.string()
|
|
82447
82474
|
});
|
|
82475
|
+
var SyncedDecisionSchema = exports_external.object({
|
|
82476
|
+
id: exports_external.string(),
|
|
82477
|
+
hash: exports_external.string()
|
|
82478
|
+
});
|
|
82448
82479
|
var SyncedOrchestrationMetaSchema = exports_external.object({
|
|
82449
82480
|
name: exports_external.string().optional(),
|
|
82450
82481
|
description: exports_external.string().optional(),
|
|
@@ -82460,6 +82491,8 @@ var OrchestrationSyncStateSchema = exports_external.object({
|
|
|
82460
82491
|
members: exports_external.array(SyncedMemberSchema),
|
|
82461
82492
|
edges: exports_external.array(SyncedEdgeSchema),
|
|
82462
82493
|
triggers: exports_external.array(SyncedScheduleTriggerSchema).optional(),
|
|
82494
|
+
webhook_triggers: exports_external.array(SyncedScheduleTriggerSchema).optional(),
|
|
82495
|
+
decisions: exports_external.array(SyncedDecisionSchema).optional(),
|
|
82463
82496
|
meta: SyncedOrchestrationMetaSchema.optional()
|
|
82464
82497
|
});
|
|
82465
82498
|
function orchLinkPath(cwd2) {
|
|
@@ -82844,7 +82877,7 @@ function printHelp3() {
|
|
|
82844
82877
|
}
|
|
82845
82878
|
|
|
82846
82879
|
// src/cli/orchestration.ts
|
|
82847
|
-
var
|
|
82880
|
+
var import_picocolors62 = __toESM(require_picocolors(), 1);
|
|
82848
82881
|
|
|
82849
82882
|
// src/cli/orchestration-pull.ts
|
|
82850
82883
|
import path98 from "node:path";
|
|
@@ -82881,6 +82914,9 @@ var TriggerEdgeSchema = exports_external.object({
|
|
|
82881
82914
|
payload_schema: exports_external.record(exports_external.unknown()).optional()
|
|
82882
82915
|
});
|
|
82883
82916
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
82917
|
+
function canonicalUuid2(value2) {
|
|
82918
|
+
return UUID_RE.test(value2) ? value2.toLowerCase() : value2;
|
|
82919
|
+
}
|
|
82884
82920
|
var ScheduleTriggerSchema = exports_external.object({
|
|
82885
82921
|
type: exports_external.literal("schedule"),
|
|
82886
82922
|
node_id: exports_external.string().regex(UUID_RE, "must be a UUID"),
|
|
@@ -82888,22 +82924,75 @@ var ScheduleTriggerSchema = exports_external.object({
|
|
|
82888
82924
|
config: exports_external.record(exports_external.unknown()).optional(),
|
|
82889
82925
|
to: exports_external.array(TriggerEdgeSchema).default([])
|
|
82890
82926
|
});
|
|
82927
|
+
var WebhookTriggerSchema = exports_external.object({
|
|
82928
|
+
type: exports_external.literal("webhook"),
|
|
82929
|
+
node_id: exports_external.string().regex(UUID_RE, "must be a UUID"),
|
|
82930
|
+
is_active: exports_external.boolean().optional(),
|
|
82931
|
+
public: exports_external.boolean().optional(),
|
|
82932
|
+
config: exports_external.record(exports_external.unknown()).optional(),
|
|
82933
|
+
to: exports_external.array(TriggerEdgeSchema).default([])
|
|
82934
|
+
});
|
|
82935
|
+
var WRITABLE_TRIGGER_TYPES = new Set(["schedule", "webhook"]);
|
|
82891
82936
|
var ReadOnlyTriggerSchema = exports_external.object({
|
|
82892
|
-
type: exports_external.string().refine((value2) => value2
|
|
82893
|
-
message: "schedule triggers must use a UUID node_id"
|
|
82937
|
+
type: exports_external.string().refine((value2) => !WRITABLE_TRIGGER_TYPES.has(value2), {
|
|
82938
|
+
message: "schedule and webhook triggers must use a UUID node_id"
|
|
82894
82939
|
}),
|
|
82895
82940
|
node_id: exports_external.string().min(1),
|
|
82896
82941
|
is_active: exports_external.boolean().optional(),
|
|
82897
82942
|
config: exports_external.record(exports_external.unknown()).optional(),
|
|
82898
82943
|
to: exports_external.array(TriggerEdgeSchema).default([])
|
|
82899
82944
|
});
|
|
82900
|
-
var TriggerSchema = exports_external.union([
|
|
82945
|
+
var TriggerSchema = exports_external.union([
|
|
82946
|
+
ScheduleTriggerSchema,
|
|
82947
|
+
WebhookTriggerSchema,
|
|
82948
|
+
ReadOnlyTriggerSchema
|
|
82949
|
+
]);
|
|
82950
|
+
var DECISION_MODELS = [
|
|
82951
|
+
"jev",
|
|
82952
|
+
"kev-4b",
|
|
82953
|
+
"clef",
|
|
82954
|
+
"clef-flash",
|
|
82955
|
+
"gpt-6-luna"
|
|
82956
|
+
];
|
|
82957
|
+
var DEFAULT_DECISION_MODEL = "clef-flash";
|
|
82958
|
+
var DECISION_LIMITS = {
|
|
82959
|
+
name: 200,
|
|
82960
|
+
model: 100,
|
|
82961
|
+
instructions: 4000,
|
|
82962
|
+
answersMin: 2,
|
|
82963
|
+
answersMax: 20,
|
|
82964
|
+
answer: 200,
|
|
82965
|
+
criterion: 1000
|
|
82966
|
+
};
|
|
82967
|
+
var DecisionTargetSchema = exports_external.object({
|
|
82968
|
+
agent: exports_external.string().min(1).optional(),
|
|
82969
|
+
decision: exports_external.string().regex(UUID_RE, "must be a UUID").optional(),
|
|
82970
|
+
description: exports_external.string().optional()
|
|
82971
|
+
}).refine((t) => t.agent === undefined !== (t.decision === undefined), {
|
|
82972
|
+
message: "set exactly one of agent or decision"
|
|
82973
|
+
});
|
|
82974
|
+
var DecisionAnswerSchema = exports_external.object({
|
|
82975
|
+
answer: exports_external.string(),
|
|
82976
|
+
criterion: exports_external.string().optional(),
|
|
82977
|
+
to: exports_external.array(DecisionTargetSchema).default([])
|
|
82978
|
+
});
|
|
82979
|
+
var DecisionSchema = exports_external.object({
|
|
82980
|
+
id: exports_external.string().regex(UUID_RE, "must be a UUID"),
|
|
82981
|
+
name: exports_external.string(),
|
|
82982
|
+
model: exports_external.string().optional(),
|
|
82983
|
+
instructions: exports_external.string().optional(),
|
|
82984
|
+
confidence_threshold: exports_external.number().min(0).max(1).nullable().optional(),
|
|
82985
|
+
from: exports_external.array(exports_external.object({ trigger: exports_external.string().regex(UUID_RE, "must be a UUID") })).default([]),
|
|
82986
|
+
answers: exports_external.array(DecisionAnswerSchema),
|
|
82987
|
+
fallback: exports_external.array(DecisionTargetSchema).default([])
|
|
82988
|
+
});
|
|
82901
82989
|
var OrchestrationManifestSchema = exports_external.object({
|
|
82902
82990
|
schema: exports_external.literal(1),
|
|
82903
82991
|
orchestration: OrchMetaSchema,
|
|
82904
82992
|
members: exports_external.array(MemberSchema).default([]),
|
|
82905
82993
|
edges: exports_external.array(EdgeSchema).default([]),
|
|
82906
|
-
triggers: exports_external.array(TriggerSchema).optional()
|
|
82994
|
+
triggers: exports_external.array(TriggerSchema).optional(),
|
|
82995
|
+
decisions: exports_external.array(DecisionSchema).optional()
|
|
82907
82996
|
});
|
|
82908
82997
|
function orchManifestPath(cwd2) {
|
|
82909
82998
|
return path96.join(cwd2, ORCH_MANIFEST_FILE);
|
|
@@ -82934,8 +83023,8 @@ function writeOrchManifest(cwd2, manifest) {
|
|
|
82934
83023
|
doc2.commentBefore = ` brainbase-orchestration.yaml — declarative orchestration manifest.
|
|
82935
83024
|
` + ` Committed to source control. Edit by hand, then
|
|
82936
83025
|
` + " `brainbase orchestration push`. Member agents live under ./agents/." + `
|
|
82937
|
-
Schedule triggers are writable. App/Pipedream triggers are
|
|
82938
|
-
` + " as read-only context and ignored by `orchestration push`.";
|
|
83026
|
+
Schedule and webhook triggers are writable. App/Pipedream triggers are
|
|
83027
|
+
` + " preserved as read-only context and ignored by `orchestration push`.";
|
|
82939
83028
|
fs83.writeFileSync(orchManifestPath(cwd2), String(doc2), "utf8");
|
|
82940
83029
|
}
|
|
82941
83030
|
function memberDir(cwd2, slug) {
|
|
@@ -83328,6 +83417,214 @@ function syncedScheduleTriggers(triggers) {
|
|
|
83328
83417
|
hash: scheduleTriggerHash(t)
|
|
83329
83418
|
}));
|
|
83330
83419
|
}
|
|
83420
|
+
var WEBHOOK_TRIGGER = "webhook-trigger";
|
|
83421
|
+
function webhookPublicFromConfig(config2) {
|
|
83422
|
+
const value2 = config2?.public_url;
|
|
83423
|
+
return value2 === undefined || value2 === true;
|
|
83424
|
+
}
|
|
83425
|
+
function webhookTriggerHash(t) {
|
|
83426
|
+
const canonical = {
|
|
83427
|
+
is_active: t.is_active,
|
|
83428
|
+
public: t.public,
|
|
83429
|
+
targets: t.targets.map((e2) => ({
|
|
83430
|
+
agent: e2.agent,
|
|
83431
|
+
description: e2.description,
|
|
83432
|
+
payload_schema: e2.payload_schema
|
|
83433
|
+
})).sort((a3, b4) => stableJson(a3) < stableJson(b4) ? -1 : 1)
|
|
83434
|
+
};
|
|
83435
|
+
return crypto6.createHash("sha256").update(stableJson(canonical)).digest("hex");
|
|
83436
|
+
}
|
|
83437
|
+
function webhookTriggerLabel(t) {
|
|
83438
|
+
const access = t.public ? "public URL" : "members only";
|
|
83439
|
+
const state = t.is_active ? "active" : "inactive";
|
|
83440
|
+
const targets = t.targets.length ? ` -> ${t.targets.map((e2) => e2.agent).join(", ")}` : "";
|
|
83441
|
+
return `webhook ${t.node_id} (${access}, ${state})${targets}`;
|
|
83442
|
+
}
|
|
83443
|
+
function cloudWebhookTriggers(cloud, slugForAgent) {
|
|
83444
|
+
return (cloud.triggers ?? []).filter((t) => t.trigger_type === "webhook").map((t) => ({
|
|
83445
|
+
node_id: canonicalUuid2(t.node_id),
|
|
83446
|
+
is_active: t.is_active ?? false,
|
|
83447
|
+
public: typeof t.public === "boolean" ? t.public : webhookPublicFromConfig(t.config),
|
|
83448
|
+
targets: t.edges.map((e2) => ({
|
|
83449
|
+
agent: slugForAgent(e2.to_agent_id, e2.to_slug ?? e2.to_agent_id),
|
|
83450
|
+
description: e2.description ?? "",
|
|
83451
|
+
payload_schema: e2.payload_schema ?? {}
|
|
83452
|
+
})),
|
|
83453
|
+
...t.id ? { id: t.id } : {},
|
|
83454
|
+
...t.fire_path ? { fire_path: t.fire_path } : {}
|
|
83455
|
+
}));
|
|
83456
|
+
}
|
|
83457
|
+
function manifestWebhookTriggers(manifest) {
|
|
83458
|
+
return (manifest?.triggers ?? []).filter((t) => t.type === "webhook").map((t) => ({
|
|
83459
|
+
node_id: canonicalUuid2(t.node_id),
|
|
83460
|
+
is_active: t.is_active ?? false,
|
|
83461
|
+
public: "public" in t && typeof t.public === "boolean" ? t.public : t.config ? webhookPublicFromConfig(t.config) : false,
|
|
83462
|
+
targets: t.to.map((e2) => ({
|
|
83463
|
+
agent: e2.agent,
|
|
83464
|
+
description: e2.description ?? "",
|
|
83465
|
+
payload_schema: e2.payload_schema ?? {}
|
|
83466
|
+
}))
|
|
83467
|
+
}));
|
|
83468
|
+
}
|
|
83469
|
+
function decideWebhookTriggerReconcile(input) {
|
|
83470
|
+
const rows = threeWayDiff({
|
|
83471
|
+
local: input.local.map((t) => ({
|
|
83472
|
+
type: WEBHOOK_TRIGGER,
|
|
83473
|
+
slug: t.node_id,
|
|
83474
|
+
hash: webhookTriggerHash(t)
|
|
83475
|
+
})),
|
|
83476
|
+
lock: (input.baseline ?? []).map((t) => ({
|
|
83477
|
+
type: WEBHOOK_TRIGGER,
|
|
83478
|
+
slug: canonicalUuid2(t.node_id),
|
|
83479
|
+
hash: t.hash,
|
|
83480
|
+
installedPaths: []
|
|
83481
|
+
})),
|
|
83482
|
+
cloud: input.cloud.map((t) => ({
|
|
83483
|
+
type: WEBHOOK_TRIGGER,
|
|
83484
|
+
slug: t.node_id,
|
|
83485
|
+
hash: webhookTriggerHash(t),
|
|
83486
|
+
files: []
|
|
83487
|
+
}))
|
|
83488
|
+
});
|
|
83489
|
+
return decideCollectionReconcile({
|
|
83490
|
+
rows,
|
|
83491
|
+
type: WEBHOOK_TRIGGER,
|
|
83492
|
+
claims: input.local.length > 0,
|
|
83493
|
+
force: input.force
|
|
83494
|
+
});
|
|
83495
|
+
}
|
|
83496
|
+
function syncedWebhookTriggers(triggers) {
|
|
83497
|
+
return triggers.map((t) => ({
|
|
83498
|
+
node_id: t.node_id,
|
|
83499
|
+
hash: webhookTriggerHash(t)
|
|
83500
|
+
}));
|
|
83501
|
+
}
|
|
83502
|
+
var DECISION = "decision";
|
|
83503
|
+
function manifestDecisions(manifest, slugToAgentId) {
|
|
83504
|
+
const target = (t) => {
|
|
83505
|
+
const agentId = t.agent !== undefined ? slugToAgentId?.get(t.agent) : undefined;
|
|
83506
|
+
return {
|
|
83507
|
+
...t.agent !== undefined ? { agent: t.agent, ...agentId ? { agent_id: agentId } : {} } : { decision: canonicalUuid2(t.decision) },
|
|
83508
|
+
description: t.description ?? ""
|
|
83509
|
+
};
|
|
83510
|
+
};
|
|
83511
|
+
return (manifest?.decisions ?? []).map((d3) => ({
|
|
83512
|
+
id: canonicalUuid2(d3.id),
|
|
83513
|
+
name: d3.name.trim(),
|
|
83514
|
+
model: (d3.model ?? DEFAULT_DECISION_MODEL).trim(),
|
|
83515
|
+
instructions: d3.instructions ?? "",
|
|
83516
|
+
confidence_threshold: d3.confidence_threshold ?? null,
|
|
83517
|
+
triggers: d3.from.map((f4) => canonicalUuid2(f4.trigger)),
|
|
83518
|
+
answers: d3.answers.map((a3) => ({
|
|
83519
|
+
answer: a3.answer.trim(),
|
|
83520
|
+
criterion: (a3.criterion ?? "").trim(),
|
|
83521
|
+
to: a3.to.map(target)
|
|
83522
|
+
})),
|
|
83523
|
+
fallback: d3.fallback.map(target)
|
|
83524
|
+
}));
|
|
83525
|
+
}
|
|
83526
|
+
function liveDecisionLinks(cloud) {
|
|
83527
|
+
const agents = new Set(cloud.members.map((m3) => m3.agent_id));
|
|
83528
|
+
const decisions = new Set((cloud.decisions ?? []).map((d3) => canonicalUuid2(d3.id)));
|
|
83529
|
+
const triggers = new Set((cloud.triggers ?? []).map((t) => canonicalUuid2(t.node_id)));
|
|
83530
|
+
return (d3) => {
|
|
83531
|
+
const answers = new Set(d3.answers.map((a3) => a3.answer));
|
|
83532
|
+
return {
|
|
83533
|
+
routes: d3.routes.filter((r2) => (r2.is_fallback || r2.answer != null && answers.has(r2.answer)) && (r2.to_agent_id ? agents.has(r2.to_agent_id) : r2.to_decision_id != null && decisions.has(canonicalUuid2(r2.to_decision_id)))),
|
|
83534
|
+
inputs: d3.inputs.filter((i) => triggers.has(canonicalUuid2(i.from_trigger_node_id)))
|
|
83535
|
+
};
|
|
83536
|
+
};
|
|
83537
|
+
}
|
|
83538
|
+
function cloudDecisions(cloud, slugForAgent) {
|
|
83539
|
+
if (cloud.decisions == null)
|
|
83540
|
+
return null;
|
|
83541
|
+
const live = liveDecisionLinks(cloud);
|
|
83542
|
+
return cloud.decisions.map((d3) => {
|
|
83543
|
+
const { routes, inputs } = live(d3);
|
|
83544
|
+
const target = (r2) => ({
|
|
83545
|
+
...r2.to_agent_id ? {
|
|
83546
|
+
agent: slugForAgent(r2.to_agent_id, r2.to_slug ?? r2.to_agent_id),
|
|
83547
|
+
agent_id: r2.to_agent_id
|
|
83548
|
+
} : { decision: canonicalUuid2(r2.to_decision_id) },
|
|
83549
|
+
description: r2.description ?? ""
|
|
83550
|
+
});
|
|
83551
|
+
return {
|
|
83552
|
+
id: canonicalUuid2(d3.id),
|
|
83553
|
+
name: d3.name.trim(),
|
|
83554
|
+
model: d3.model.trim(),
|
|
83555
|
+
instructions: d3.instructions ?? "",
|
|
83556
|
+
confidence_threshold: d3.confidence_threshold ?? null,
|
|
83557
|
+
triggers: inputs.map((i) => canonicalUuid2(i.from_trigger_node_id)),
|
|
83558
|
+
answers: d3.answers.map((a3) => ({
|
|
83559
|
+
answer: a3.answer.trim(),
|
|
83560
|
+
criterion: (a3.criterion ?? "").trim(),
|
|
83561
|
+
to: routes.filter((r2) => !r2.is_fallback && r2.answer === a3.answer).map(target)
|
|
83562
|
+
})),
|
|
83563
|
+
fallback: routes.filter((r2) => r2.is_fallback).map(target)
|
|
83564
|
+
};
|
|
83565
|
+
});
|
|
83566
|
+
}
|
|
83567
|
+
function deadDecisionLinks(cloud) {
|
|
83568
|
+
const live = liveDecisionLinks(cloud);
|
|
83569
|
+
const out = new Map;
|
|
83570
|
+
for (const d3 of cloud.decisions ?? []) {
|
|
83571
|
+
const { routes, inputs } = live(d3);
|
|
83572
|
+
const dead = d3.routes.length - routes.length + d3.inputs.length - inputs.length;
|
|
83573
|
+
if (dead > 0)
|
|
83574
|
+
out.set(d3.id, dead);
|
|
83575
|
+
}
|
|
83576
|
+
return out;
|
|
83577
|
+
}
|
|
83578
|
+
function decisionHash(d3) {
|
|
83579
|
+
const targets = (ts2) => ts2.map(({ agent, agent_id, ...rest2 }) => stableJson(agent_id !== undefined ? { agent_id, ...rest2 } : { agent, ...rest2 })).sort();
|
|
83580
|
+
const canonical = {
|
|
83581
|
+
name: d3.name,
|
|
83582
|
+
model: d3.model,
|
|
83583
|
+
instructions: d3.instructions,
|
|
83584
|
+
confidence_threshold: d3.confidence_threshold,
|
|
83585
|
+
triggers: [...d3.triggers].sort(),
|
|
83586
|
+
answers: d3.answers.map((a3) => ({
|
|
83587
|
+
answer: a3.answer,
|
|
83588
|
+
criterion: a3.criterion,
|
|
83589
|
+
to: targets(a3.to)
|
|
83590
|
+
})),
|
|
83591
|
+
fallback: targets(d3.fallback)
|
|
83592
|
+
};
|
|
83593
|
+
return crypto6.createHash("sha256").update(stableJson(canonical)).digest("hex");
|
|
83594
|
+
}
|
|
83595
|
+
function decisionLabel(d3) {
|
|
83596
|
+
return `decision "${d3.name}" (${d3.id})`;
|
|
83597
|
+
}
|
|
83598
|
+
function decideDecisionReconcile(input) {
|
|
83599
|
+
const rows = threeWayDiff({
|
|
83600
|
+
local: input.local.map((d3) => ({
|
|
83601
|
+
type: DECISION,
|
|
83602
|
+
slug: d3.id,
|
|
83603
|
+
hash: decisionHash(d3)
|
|
83604
|
+
})),
|
|
83605
|
+
lock: (input.baseline ?? []).map((d3) => ({
|
|
83606
|
+
type: DECISION,
|
|
83607
|
+
slug: d3.id,
|
|
83608
|
+
hash: d3.hash,
|
|
83609
|
+
installedPaths: []
|
|
83610
|
+
})),
|
|
83611
|
+
cloud: input.cloud.map((d3) => ({
|
|
83612
|
+
type: DECISION,
|
|
83613
|
+
slug: d3.id,
|
|
83614
|
+
hash: decisionHash(d3),
|
|
83615
|
+
files: []
|
|
83616
|
+
}))
|
|
83617
|
+
});
|
|
83618
|
+
return decideCollectionReconcile({
|
|
83619
|
+
rows,
|
|
83620
|
+
type: DECISION,
|
|
83621
|
+
claims: input.local.length > 0,
|
|
83622
|
+
force: input.force
|
|
83623
|
+
});
|
|
83624
|
+
}
|
|
83625
|
+
function syncedDecisions(decisions) {
|
|
83626
|
+
return decisions.map((d3) => ({ id: d3.id, hash: decisionHash(d3) }));
|
|
83627
|
+
}
|
|
83331
83628
|
var ORCH_META_FIELDS = [
|
|
83332
83629
|
"name",
|
|
83333
83630
|
"description",
|
|
@@ -83396,11 +83693,15 @@ function syncedOrchestrationMeta(cloud) {
|
|
|
83396
83693
|
function triggersForManifest(triggers, slugFor) {
|
|
83397
83694
|
return triggers.map((trigger) => {
|
|
83398
83695
|
const schedule = trigger.trigger_type === "schedule";
|
|
83399
|
-
const
|
|
83696
|
+
const webhook = trigger.trigger_type === "webhook";
|
|
83697
|
+
const config2 = schedule ? scheduleTriggerConfigForManifest(trigger.config) : webhook ? undefined : trigger.config;
|
|
83400
83698
|
return {
|
|
83401
83699
|
type: trigger.trigger_type,
|
|
83402
83700
|
node_id: trigger.node_id,
|
|
83403
83701
|
is_active: trigger.is_active,
|
|
83702
|
+
...webhook ? {
|
|
83703
|
+
public: typeof trigger.public === "boolean" ? trigger.public : webhookPublicFromConfig(trigger.config)
|
|
83704
|
+
} : {},
|
|
83404
83705
|
...config2 && Object.keys(config2).length ? { config: config2 } : {},
|
|
83405
83706
|
to: trigger.edges.map((edge) => ({
|
|
83406
83707
|
agent: slugFor(edge.to_agent_id),
|
|
@@ -83410,6 +83711,26 @@ function triggersForManifest(triggers, slugFor) {
|
|
|
83410
83711
|
};
|
|
83411
83712
|
});
|
|
83412
83713
|
}
|
|
83714
|
+
function decisionsForManifest(decisions) {
|
|
83715
|
+
const target = (t) => ({
|
|
83716
|
+
...t.agent !== undefined ? { agent: t.agent } : { decision: t.decision },
|
|
83717
|
+
...t.description ? { description: t.description } : {}
|
|
83718
|
+
});
|
|
83719
|
+
return decisions.map((d3) => ({
|
|
83720
|
+
id: d3.id,
|
|
83721
|
+
name: d3.name,
|
|
83722
|
+
model: d3.model,
|
|
83723
|
+
...d3.instructions ? { instructions: d3.instructions } : {},
|
|
83724
|
+
...d3.confidence_threshold != null ? { confidence_threshold: d3.confidence_threshold } : {},
|
|
83725
|
+
...d3.triggers.length ? { from: d3.triggers.map((trigger) => ({ trigger })) } : {},
|
|
83726
|
+
answers: d3.answers.map((a3) => ({
|
|
83727
|
+
answer: a3.answer,
|
|
83728
|
+
...a3.criterion ? { criterion: a3.criterion } : {},
|
|
83729
|
+
...a3.to.length ? { to: a3.to.map(target) } : {}
|
|
83730
|
+
})),
|
|
83731
|
+
...d3.fallback.length ? { fallback: d3.fallback.map(target) } : {}
|
|
83732
|
+
}));
|
|
83733
|
+
}
|
|
83413
83734
|
async function runOrchestrationPull(cwd2, args) {
|
|
83414
83735
|
banner("orchestration pull — fetch orchestration + all member agents");
|
|
83415
83736
|
let orchId = null;
|
|
@@ -83460,6 +83781,14 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
83460
83781
|
planLines.push(` ${import_picocolors52.default.cyan(from)} ${import_picocolors52.default.dim("→")} ${import_picocolors52.default.cyan(to2)}${desc}`);
|
|
83461
83782
|
}
|
|
83462
83783
|
}
|
|
83784
|
+
const pulledDecisions = cloudDecisions(cloud, (agentId, fallback) => slugByAgent.get(agentId) ?? fallback);
|
|
83785
|
+
if (pulledDecisions?.length) {
|
|
83786
|
+
planLines.push("");
|
|
83787
|
+
planLines.push(` ${import_picocolors52.default.dim("decisions:")}`);
|
|
83788
|
+
for (const d3 of pulledDecisions) {
|
|
83789
|
+
planLines.push(` ${import_picocolors52.default.cyan("◆")} ${import_picocolors52.default.bold(d3.name)} ${import_picocolors52.default.dim(`(${d3.model}, ${d3.answers.length} answers)`)}`);
|
|
83790
|
+
}
|
|
83791
|
+
}
|
|
83463
83792
|
planLines.push("");
|
|
83464
83793
|
console.log(planLines.join(`
|
|
83465
83794
|
`));
|
|
@@ -83525,6 +83854,19 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
83525
83854
|
}
|
|
83526
83855
|
}
|
|
83527
83856
|
const manifestTriggers = triggersForManifest(cloud.triggers ?? [], slugFor);
|
|
83857
|
+
let manifestDecisions2 = pulledDecisions ? decisionsForManifest(pulledDecisions) : undefined;
|
|
83858
|
+
let decisionBaseline = pulledDecisions ? syncedDecisions(pulledDecisions) : undefined;
|
|
83859
|
+
if (!pulledDecisions) {
|
|
83860
|
+
try {
|
|
83861
|
+
manifestDecisions2 = readOrchManifest(cwd2)?.decisions;
|
|
83862
|
+
} catch {}
|
|
83863
|
+
const lock = readOrchSyncState(cwd2);
|
|
83864
|
+
decisionBaseline = lock?.orchestration_id === cloud.id ? lock.decisions : undefined;
|
|
83865
|
+
}
|
|
83866
|
+
for (const [decisionId, count] of deadDecisionLinks(cloud)) {
|
|
83867
|
+
const name = pulledDecisions?.find((d3) => d3.id === decisionId)?.name;
|
|
83868
|
+
f2.warn(`Decision ${import_picocolors52.default.bold(name ?? decisionId)} has ${count} route${count === 1 ? "" : "s"} or input${count === 1 ? "" : "s"} that lead${count === 1 ? "s" : ""} nowhere: on an answer it no longer has, or to an agent, decision or trigger no longer in this orchestration. They never run and are not in ${import_picocolors52.default.bold("brainbase-orchestration.yaml")}; the next push of decisions removes them.`);
|
|
83869
|
+
}
|
|
83528
83870
|
const manifest = {
|
|
83529
83871
|
schema: 1,
|
|
83530
83872
|
orchestration: {
|
|
@@ -83548,7 +83890,8 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
83548
83890
|
...e2.payload_schema && Object.keys(e2.payload_schema).length ? { payload_schema: e2.payload_schema } : {},
|
|
83549
83891
|
...e2.settings && Object.keys(e2.settings).length ? { settings: e2.settings } : {}
|
|
83550
83892
|
})),
|
|
83551
|
-
...manifestTriggers.length ? { triggers: manifestTriggers } : {}
|
|
83893
|
+
...manifestTriggers.length ? { triggers: manifestTriggers } : {},
|
|
83894
|
+
...manifestDecisions2?.length ? { decisions: manifestDecisions2 } : {}
|
|
83552
83895
|
};
|
|
83553
83896
|
writeOrchManifest(cwd2, manifest);
|
|
83554
83897
|
writeOrchLink(cwd2, {
|
|
@@ -83574,6 +83917,8 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
83574
83917
|
payload_schema: e2.payload_schema ?? {}
|
|
83575
83918
|
})),
|
|
83576
83919
|
triggers: syncedScheduleTriggers(cloudScheduleTriggers(cloud, (agentId, fallback) => slugFor(agentId) || fallback)),
|
|
83920
|
+
webhook_triggers: syncedWebhookTriggers(cloudWebhookTriggers(cloud, (agentId, fallback) => slugFor(agentId) || fallback)),
|
|
83921
|
+
...decisionBaseline ? { decisions: decisionBaseline } : {},
|
|
83577
83922
|
meta: syncedOrchestrationMeta(cloud)
|
|
83578
83923
|
});
|
|
83579
83924
|
if (missingMembers.length > 0) {
|
|
@@ -83601,6 +83946,83 @@ function handleApiError5(err) {
|
|
|
83601
83946
|
var import_picocolors53 = __toESM(require_picocolors(), 1);
|
|
83602
83947
|
|
|
83603
83948
|
// src/core/orchestration-outgoing.ts
|
|
83949
|
+
function charLength(value2) {
|
|
83950
|
+
return Array.from(value2).length;
|
|
83951
|
+
}
|
|
83952
|
+
function validateDecisions(decisions, memberSlugs, triggerNodeIds) {
|
|
83953
|
+
const ids = new Set;
|
|
83954
|
+
for (const d3 of decisions) {
|
|
83955
|
+
if (ids.has(d3.id))
|
|
83956
|
+
throw new Error(`Decision ${d3.id} is duplicated.`);
|
|
83957
|
+
ids.add(d3.id);
|
|
83958
|
+
}
|
|
83959
|
+
for (const d3 of decisions) {
|
|
83960
|
+
const label2 = `Decision "${d3.name || d3.id}"`;
|
|
83961
|
+
const fail3 = (message) => {
|
|
83962
|
+
throw new Error(`${label2}: ${message}`);
|
|
83963
|
+
};
|
|
83964
|
+
if (!d3.name || charLength(d3.name) > DECISION_LIMITS.name) {
|
|
83965
|
+
fail3(`name must be 1 to ${DECISION_LIMITS.name} characters.`);
|
|
83966
|
+
}
|
|
83967
|
+
if (!d3.model || charLength(d3.model) > DECISION_LIMITS.model) {
|
|
83968
|
+
fail3(`model must be 1 to ${DECISION_LIMITS.model} characters.`);
|
|
83969
|
+
}
|
|
83970
|
+
if (charLength(d3.instructions) > DECISION_LIMITS.instructions) {
|
|
83971
|
+
fail3(`instructions must be ${DECISION_LIMITS.instructions} characters or fewer.`);
|
|
83972
|
+
}
|
|
83973
|
+
const count = d3.answers.length;
|
|
83974
|
+
if (count < DECISION_LIMITS.answersMin || count > DECISION_LIMITS.answersMax) {
|
|
83975
|
+
fail3(`needs ${DECISION_LIMITS.answersMin} to ${DECISION_LIMITS.answersMax} answers (has ${count}).`);
|
|
83976
|
+
}
|
|
83977
|
+
const answers = new Set;
|
|
83978
|
+
for (const a3 of d3.answers) {
|
|
83979
|
+
if (!a3.answer || charLength(a3.answer) > DECISION_LIMITS.answer) {
|
|
83980
|
+
fail3(`each answer must be 1 to ${DECISION_LIMITS.answer} characters.`);
|
|
83981
|
+
}
|
|
83982
|
+
if (answers.has(a3.answer))
|
|
83983
|
+
fail3(`answer "${a3.answer}" appears twice.`);
|
|
83984
|
+
answers.add(a3.answer);
|
|
83985
|
+
if (charLength(a3.criterion) > DECISION_LIMITS.criterion) {
|
|
83986
|
+
fail3(`the criterion for "${a3.answer}" must be ${DECISION_LIMITS.criterion} characters or fewer.`);
|
|
83987
|
+
}
|
|
83988
|
+
}
|
|
83989
|
+
const fed = new Set;
|
|
83990
|
+
for (const nodeId of d3.triggers) {
|
|
83991
|
+
if (!triggerNodeIds.has(nodeId)) {
|
|
83992
|
+
fail3(`from trigger ${nodeId}, which isn't in triggers.`);
|
|
83993
|
+
}
|
|
83994
|
+
if (fed.has(nodeId))
|
|
83995
|
+
fail3(`trigger ${nodeId} is listed twice in from.`);
|
|
83996
|
+
fed.add(nodeId);
|
|
83997
|
+
}
|
|
83998
|
+
const checkTargets = (targets, branch) => {
|
|
83999
|
+
const seen = new Set;
|
|
84000
|
+
for (const t of targets) {
|
|
84001
|
+
if (t.agent !== undefined && !memberSlugs.has(t.agent)) {
|
|
84002
|
+
fail3(`${branch} routes to "${t.agent}", which isn't in members.`);
|
|
84003
|
+
}
|
|
84004
|
+
if (t.decision !== undefined) {
|
|
84005
|
+
if (t.decision === d3.id)
|
|
84006
|
+
fail3(`${branch} routes to the decision itself.`);
|
|
84007
|
+
if (!ids.has(t.decision)) {
|
|
84008
|
+
fail3(`${branch} routes to decision ${t.decision}, which isn't in decisions.`);
|
|
84009
|
+
}
|
|
84010
|
+
}
|
|
84011
|
+
const key2 = t.agent !== undefined ? `agent:${t.agent}` : `decision:${t.decision}`;
|
|
84012
|
+
if (seen.has(key2))
|
|
84013
|
+
fail3(`${branch} routes to ${key2.replace(":", " ")} twice.`);
|
|
84014
|
+
seen.add(key2);
|
|
84015
|
+
}
|
|
84016
|
+
};
|
|
84017
|
+
for (const a3 of d3.answers)
|
|
84018
|
+
checkTargets(a3.to, `answer "${a3.answer}"`);
|
|
84019
|
+
checkTargets(d3.fallback, "fallback");
|
|
84020
|
+
}
|
|
84021
|
+
}
|
|
84022
|
+
function unknownDecisionModels(manifest) {
|
|
84023
|
+
const known = new Set(DECISION_MODELS);
|
|
84024
|
+
return manifestDecisions(manifest).filter((d3) => !known.has(d3.model)).map((d3) => ({ name: d3.name, model: d3.model }));
|
|
84025
|
+
}
|
|
83604
84026
|
function buildOrchestrationGraphPayload(manifest, slugToAgentId) {
|
|
83605
84027
|
const memberSlugs = new Set(manifest.members.map((m3) => m3.slug));
|
|
83606
84028
|
for (const e2 of manifest.edges) {
|
|
@@ -83615,12 +84037,25 @@ function buildOrchestrationGraphPayload(manifest, slugToAgentId) {
|
|
|
83615
84037
|
}
|
|
83616
84038
|
}
|
|
83617
84039
|
const scheduleTriggers = (manifest.triggers ?? []).filter((t) => t.type === "schedule");
|
|
84040
|
+
const webhookTriggers = manifestWebhookTriggers(manifest);
|
|
83618
84041
|
const seenTriggerNodeIds = new Set;
|
|
84042
|
+
for (const t of webhookTriggers) {
|
|
84043
|
+
const nodeId = canonicalUuid2(t.node_id);
|
|
84044
|
+
if (seenTriggerNodeIds.has(nodeId)) {
|
|
84045
|
+
throw new Error(`Webhook trigger ${t.node_id} is duplicated.`);
|
|
84046
|
+
}
|
|
84047
|
+
seenTriggerNodeIds.add(nodeId);
|
|
84048
|
+
for (const e2 of t.targets) {
|
|
84049
|
+
if (!memberSlugs.has(e2.agent)) {
|
|
84050
|
+
throw new Error(`Trigger ${t.node_id} points to "${e2.agent}", which isn't in members.`);
|
|
84051
|
+
}
|
|
84052
|
+
}
|
|
84053
|
+
}
|
|
83619
84054
|
for (const t of scheduleTriggers) {
|
|
83620
|
-
if (seenTriggerNodeIds.has(t.node_id)) {
|
|
84055
|
+
if (seenTriggerNodeIds.has(canonicalUuid2(t.node_id))) {
|
|
83621
84056
|
throw new Error(`Schedule trigger ${t.node_id} is duplicated.`);
|
|
83622
84057
|
}
|
|
83623
|
-
seenTriggerNodeIds.add(t.node_id);
|
|
84058
|
+
seenTriggerNodeIds.add(canonicalUuid2(t.node_id));
|
|
83624
84059
|
const config2 = normalizeScheduleTriggerConfig(t.config);
|
|
83625
84060
|
const cron = config2.cron_expression;
|
|
83626
84061
|
if (typeof cron !== "string" || !cron.trim()) {
|
|
@@ -83658,9 +84093,46 @@ function buildOrchestrationGraphPayload(manifest, slugToAgentId) {
|
|
|
83658
84093
|
description: e2.description ?? "",
|
|
83659
84094
|
payload_schema: e2.payload_schema ?? {}
|
|
83660
84095
|
}))
|
|
84096
|
+
})),
|
|
84097
|
+
webhookTriggers: webhookTriggers.map((t) => ({
|
|
84098
|
+
node_id: t.node_id,
|
|
84099
|
+
type: "webhook",
|
|
84100
|
+
is_active: t.is_active,
|
|
84101
|
+
public: t.public,
|
|
84102
|
+
edges: t.targets.map((e2) => ({
|
|
84103
|
+
to_agent_id: slugToAgentId.get(e2.agent),
|
|
84104
|
+
description: e2.description,
|
|
84105
|
+
payload_schema: e2.payload_schema
|
|
84106
|
+
}))
|
|
83661
84107
|
}))
|
|
83662
84108
|
};
|
|
83663
84109
|
}
|
|
84110
|
+
function buildDecisionsPayload(manifest, slugToAgentId) {
|
|
84111
|
+
const decisions = manifestDecisions(manifest, slugToAgentId);
|
|
84112
|
+
validateDecisions(decisions, new Set(manifest.members.map((m3) => m3.slug)), new Set((manifest.triggers ?? []).map((t) => canonicalUuid2(t.node_id))));
|
|
84113
|
+
return decisions.map((d3) => decisionPayload(d3, slugToAgentId));
|
|
84114
|
+
}
|
|
84115
|
+
function decisionPayload(d3, slugToAgentId) {
|
|
84116
|
+
const route = (answer, t) => ({
|
|
84117
|
+
answer,
|
|
84118
|
+
is_fallback: answer === null,
|
|
84119
|
+
...t.agent !== undefined ? { to_agent_id: slugToAgentId.get(t.agent) } : { to_decision_id: t.decision },
|
|
84120
|
+
description: t.description
|
|
84121
|
+
});
|
|
84122
|
+
return {
|
|
84123
|
+
id: d3.id,
|
|
84124
|
+
name: d3.name,
|
|
84125
|
+
model: d3.model,
|
|
84126
|
+
instructions: d3.instructions,
|
|
84127
|
+
answers: d3.answers.map((a3) => ({ answer: a3.answer, criterion: a3.criterion })),
|
|
84128
|
+
confidence_threshold: d3.confidence_threshold,
|
|
84129
|
+
inputs: d3.triggers.map((nodeId) => ({ from_trigger_node_id: nodeId })),
|
|
84130
|
+
routes: [
|
|
84131
|
+
...d3.answers.flatMap((a3) => a3.to.map((t) => route(a3.answer, t))),
|
|
84132
|
+
...d3.fallback.map((t) => route(null, t))
|
|
84133
|
+
]
|
|
84134
|
+
};
|
|
84135
|
+
}
|
|
83664
84136
|
|
|
83665
84137
|
// src/cli/orchestration-push.ts
|
|
83666
84138
|
function joinList(items) {
|
|
@@ -83778,6 +84250,20 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
83778
84250
|
const t = triggerByNode.get(nodeId);
|
|
83779
84251
|
return t ? scheduleTriggerLabel(t) : nodeId;
|
|
83780
84252
|
};
|
|
84253
|
+
const localWebhooks = manifestWebhookTriggers(manifest);
|
|
84254
|
+
const cloudWebhooks = cloudWebhookTriggers(cloud, slugForAgent);
|
|
84255
|
+
const webhookDecision = decideWebhookTriggerReconcile({
|
|
84256
|
+
local: localWebhooks,
|
|
84257
|
+
cloud: cloudWebhooks,
|
|
84258
|
+
baseline: lock?.webhook_triggers,
|
|
84259
|
+
force: !!args.force
|
|
84260
|
+
});
|
|
84261
|
+
const webhookByNode = new Map([...cloudWebhooks, ...localWebhooks].map((t) => [t.node_id, t]));
|
|
84262
|
+
const webhookLabelFor = (nodeId) => {
|
|
84263
|
+
const t = webhookByNode.get(nodeId);
|
|
84264
|
+
return t ? webhookTriggerLabel(t) : nodeId;
|
|
84265
|
+
};
|
|
84266
|
+
const blockedWebhooks = webhookDecision.kind === "blocked" ? webhookDecision : null;
|
|
83781
84267
|
const metaDecisions = decideOrchestrationMeta({
|
|
83782
84268
|
manifest,
|
|
83783
84269
|
cloud,
|
|
@@ -83788,7 +84274,21 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
83788
84274
|
const metaOverwrites = metaDecisions.filter((d3) => d3.kind === "push");
|
|
83789
84275
|
const metaKept = metaDecisions.filter((d3) => d3.kind === "keep");
|
|
83790
84276
|
const blockedTriggers = triggerDecision.kind === "blocked" ? triggerDecision : null;
|
|
83791
|
-
|
|
84277
|
+
const localDecisions = manifestDecisions(manifest, slugToAgentId);
|
|
84278
|
+
const cloudDecisionList = cloudDecisions(cloud, slugForAgent);
|
|
84279
|
+
const decisionPlan = cloudDecisionList ? decideDecisionReconcile({
|
|
84280
|
+
local: localDecisions,
|
|
84281
|
+
cloud: cloudDecisionList,
|
|
84282
|
+
baseline: lock?.decisions,
|
|
84283
|
+
force: !!args.force
|
|
84284
|
+
}) : null;
|
|
84285
|
+
const decisionById = new Map([...cloudDecisionList ?? [], ...localDecisions].map((d3) => [d3.id, d3]));
|
|
84286
|
+
const decisionLabelFor = (id) => {
|
|
84287
|
+
const d3 = decisionById.get(id);
|
|
84288
|
+
return d3 ? decisionLabel(d3) : id;
|
|
84289
|
+
};
|
|
84290
|
+
const blockedDecisions = decisionPlan?.kind === "blocked" ? decisionPlan : null;
|
|
84291
|
+
if (blockedTriggers || blockedWebhooks || blockedDecisions || metaConflicts.length > 0) {
|
|
83792
84292
|
const pullTargets = [];
|
|
83793
84293
|
const forceEffects = [];
|
|
83794
84294
|
if (blockedTriggers) {
|
|
@@ -83807,6 +84307,38 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
83807
84307
|
pullTargets.push(`${total} schedule trigger${total === 1 ? "" : "s"}`);
|
|
83808
84308
|
forceEffects.push("make your local schedule triggers authoritative (deleting the cloud ones above)");
|
|
83809
84309
|
}
|
|
84310
|
+
if (blockedWebhooks) {
|
|
84311
|
+
const { unseen, cloudModified, staleArchives } = blockedWebhooks;
|
|
84312
|
+
f2.error(unseen.length > 0 ? "Cannot push: the cloud has webhook triggers this folder has never seen." : "Cannot push: webhook triggers changed both locally and in the cloud.");
|
|
84313
|
+
for (const nodeId of unseen) {
|
|
84314
|
+
console.error(` ${import_picocolors53.default.red("!")} ${import_picocolors53.default.bold(webhookLabelFor(nodeId))} ${import_picocolors53.default.dim("(only in the cloud — pushing would delete it and its URL)")}`);
|
|
84315
|
+
}
|
|
84316
|
+
for (const nodeId of cloudModified) {
|
|
84317
|
+
console.error(` ${import_picocolors53.default.red("!")} ${import_picocolors53.default.bold(webhookLabelFor(nodeId))} ${import_picocolors53.default.dim("(edited in the cloud — pushing would overwrite that edit)")}`);
|
|
84318
|
+
}
|
|
84319
|
+
for (const nodeId of staleArchives) {
|
|
84320
|
+
console.error(` ${import_picocolors53.default.red("!")} ${import_picocolors53.default.bold(webhookLabelFor(nodeId))} ${import_picocolors53.default.dim("(deleted here, edited in the cloud since — pushing would delete that edit)")}`);
|
|
84321
|
+
}
|
|
84322
|
+
const total = unseen.length + cloudModified.length + staleArchives.length;
|
|
84323
|
+
pullTargets.push(`${total} webhook trigger${total === 1 ? "" : "s"}`);
|
|
84324
|
+
forceEffects.push("make your local webhook triggers authoritative (deleting or overwriting the cloud ones above)");
|
|
84325
|
+
}
|
|
84326
|
+
if (blockedDecisions) {
|
|
84327
|
+
const { unseen, cloudModified, staleArchives } = blockedDecisions;
|
|
84328
|
+
f2.error(unseen.length > 0 ? "Cannot push: the cloud has decisions this folder has never seen." : "Cannot push: decisions changed both locally and in the cloud.");
|
|
84329
|
+
for (const id of unseen) {
|
|
84330
|
+
console.error(` ${import_picocolors53.default.red("!")} ${import_picocolors53.default.bold(decisionLabelFor(id))} ${import_picocolors53.default.dim("(only in the cloud — pushing would delete it)")}`);
|
|
84331
|
+
}
|
|
84332
|
+
for (const id of cloudModified) {
|
|
84333
|
+
console.error(` ${import_picocolors53.default.red("!")} ${import_picocolors53.default.bold(decisionLabelFor(id))} ${import_picocolors53.default.dim("(edited in the cloud — pushing would overwrite that edit)")}`);
|
|
84334
|
+
}
|
|
84335
|
+
for (const id of staleArchives) {
|
|
84336
|
+
console.error(` ${import_picocolors53.default.red("!")} ${import_picocolors53.default.bold(decisionLabelFor(id))} ${import_picocolors53.default.dim("(deleted here, edited in the cloud since — pushing would delete that edit)")}`);
|
|
84337
|
+
}
|
|
84338
|
+
const total = unseen.length + cloudModified.length + staleArchives.length;
|
|
84339
|
+
pullTargets.push(`${total} decision${total === 1 ? "" : "s"}`);
|
|
84340
|
+
forceEffects.push("make your local decisions authoritative (deleting or overwriting the cloud ones above)");
|
|
84341
|
+
}
|
|
83810
84342
|
if (metaConflicts.length > 0) {
|
|
83811
84343
|
f2.error("Cannot push: orchestration metadata changed both locally and in the cloud.");
|
|
83812
84344
|
for (const d3 of metaConflicts) {
|
|
@@ -83839,9 +84371,37 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
83839
84371
|
f2.warn(`${cloudTriggers.length} cloud schedule trigger${cloudTriggers.length === 1 ? "" : "s"} ${cloudTriggers.length === 1 ? "is" : "are"} not in ${import_picocolors53.default.bold(ORCH_MANIFEST_FILE)} and will be left untouched. Run ${import_picocolors53.default.cyan("brainbase orchestration pull")} to manage ${cloudTriggers.length === 1 ? "it" : "them"} from here.`);
|
|
83840
84372
|
}
|
|
83841
84373
|
const triggerDeletes = triggerDecision.kind === "reconcile" ? triggerDecision.archives : [];
|
|
84374
|
+
const webhookDeletes = webhookDecision.kind === "reconcile" ? webhookDecision.archives : [];
|
|
84375
|
+
const sendWebhooks = webhookDecision.kind === "reconcile" && (localWebhooks.length > 0 || webhookDeletes.length > 0);
|
|
84376
|
+
if (webhookDecision.kind === "skip") {
|
|
84377
|
+
const left = webhookDecision.unseen.length + webhookDecision.cloudModified.length;
|
|
84378
|
+
f2.warn(`${left} cloud webhook trigger${left === 1 ? "" : "s"} ${left === 1 ? "is" : "are"} not in ${import_picocolors53.default.bold(ORCH_MANIFEST_FILE)} and will be left untouched. Run ${import_picocolors53.default.cyan("brainbase orchestration pull")} to manage ${left === 1 ? "it" : "them"} from here.`);
|
|
84379
|
+
}
|
|
84380
|
+
const triggerCount = graph.triggers.length + (sendWebhooks ? graph.webhookTriggers.length : 0);
|
|
84381
|
+
const decisionDeletes = decisionPlan?.kind === "reconcile" ? decisionPlan.archives : [];
|
|
84382
|
+
const sendDecisions = decisionPlan?.kind === "reconcile" && (localDecisions.length > 0 || decisionDeletes.length > 0);
|
|
84383
|
+
if (!cloudDecisionList && localDecisions.length > 0) {
|
|
84384
|
+
f2.warn(`The cloud did not return decision nodes for this account, so the ${localDecisions.length} decision${localDecisions.length === 1 ? "" : "s"} in ${import_picocolors53.default.bold(ORCH_MANIFEST_FILE)} ${localDecisions.length === 1 ? "is" : "are"} left out of this push and the cloud's are left alone.`);
|
|
84385
|
+
} else if (decisionPlan?.kind === "skip") {
|
|
84386
|
+
const left = decisionPlan.unseen.length + decisionPlan.cloudModified.length;
|
|
84387
|
+
f2.warn(`${left} cloud decision${left === 1 ? "" : "s"} ${left === 1 ? "is" : "are"} not in ${import_picocolors53.default.bold(ORCH_MANIFEST_FILE)} and will be left untouched. Run ${import_picocolors53.default.cyan("brainbase orchestration pull")} to manage ${left === 1 ? "it" : "them"} from here.`);
|
|
84388
|
+
}
|
|
84389
|
+
let decisionsPayload = [];
|
|
84390
|
+
if (sendDecisions) {
|
|
84391
|
+
try {
|
|
84392
|
+
decisionsPayload = buildDecisionsPayload(manifest, slugToAgentId);
|
|
84393
|
+
} catch (err) {
|
|
84394
|
+
f2.error(err.message);
|
|
84395
|
+
process.exitCode = 1;
|
|
84396
|
+
return;
|
|
84397
|
+
}
|
|
84398
|
+
for (const { name, model } of unknownDecisionModels(manifest)) {
|
|
84399
|
+
f2.warn(`Decision ${import_picocolors53.default.bold(name)} uses model ${import_picocolors53.default.bold(model)}, which is not one the canvas offers. It is pushed as written; if the gateway does not know it, the decision fails when its trigger fires.`);
|
|
84400
|
+
}
|
|
84401
|
+
}
|
|
83842
84402
|
const plan = [""];
|
|
83843
84403
|
plan.push(` ${import_picocolors53.default.bold(link2.name)} ${import_picocolors53.default.dim(`(${link2.orchestration_id})`)}`);
|
|
83844
|
-
plan.push(` ${import_picocolors53.default.dim(`${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}, ${
|
|
84404
|
+
plan.push(` ${import_picocolors53.default.dim(`${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}, ${triggerCount} trigger${triggerCount === 1 ? "" : "s"}${sendDecisions ? `, ${decisionsPayload.length} decision${decisionsPayload.length === 1 ? "" : "s"}` : ""}`)}`);
|
|
83845
84405
|
plan.push("");
|
|
83846
84406
|
if (!args.graphOnly) {
|
|
83847
84407
|
plan.push(` ${import_picocolors53.default.dim("per-member agent push:")}`);
|
|
@@ -83857,6 +84417,20 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
83857
84417
|
}
|
|
83858
84418
|
plan.push("");
|
|
83859
84419
|
}
|
|
84420
|
+
if (webhookDeletes.length) {
|
|
84421
|
+
plan.push(` ${import_picocolors53.default.bold("webhook triggers this push will delete")} ${import_picocolors53.default.dim(`(${webhookDeletes.length})`)}`);
|
|
84422
|
+
for (const nodeId of webhookDeletes) {
|
|
84423
|
+
plan.push(` ${import_picocolors53.default.yellow("⨯")} ${webhookLabelFor(nodeId)}`);
|
|
84424
|
+
}
|
|
84425
|
+
plan.push("");
|
|
84426
|
+
}
|
|
84427
|
+
if (decisionDeletes.length) {
|
|
84428
|
+
plan.push(` ${import_picocolors53.default.bold("decisions this push will delete")} ${import_picocolors53.default.dim(`(${decisionDeletes.length})`)}`);
|
|
84429
|
+
for (const id of decisionDeletes) {
|
|
84430
|
+
plan.push(` ${import_picocolors53.default.yellow("⨯")} ${decisionLabelFor(id)}`);
|
|
84431
|
+
}
|
|
84432
|
+
plan.push("");
|
|
84433
|
+
}
|
|
83860
84434
|
if (metaOverwrites.length) {
|
|
83861
84435
|
plan.push(` ${import_picocolors53.default.bold("orchestration metadata this push will overwrite")}`);
|
|
83862
84436
|
for (const m3 of metaOverwrites) {
|
|
@@ -83875,9 +84449,14 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
83875
84449
|
console.log(plan.join(`
|
|
83876
84450
|
`));
|
|
83877
84451
|
if (!autoProceed(args.yes)) {
|
|
84452
|
+
const deletions = [
|
|
84453
|
+
...triggerDeletes.length ? [`${triggerDeletes.length} schedule trigger${triggerDeletes.length === 1 ? "" : "s"}`] : [],
|
|
84454
|
+
...webhookDeletes.length ? [`${webhookDeletes.length} webhook trigger${webhookDeletes.length === 1 ? "" : "s"}`] : [],
|
|
84455
|
+
...decisionDeletes.length ? [`${decisionDeletes.length} decision${decisionDeletes.length === 1 ? "" : "s"}`] : []
|
|
84456
|
+
];
|
|
83878
84457
|
const ok = await se({
|
|
83879
|
-
message:
|
|
83880
|
-
initialValue:
|
|
84458
|
+
message: deletions.length ? `Push, deleting ${joinList(deletions)}?` : args.graphOnly ? "Push graph (members, edges + triggers) only?" : "Push each member, then update the graph?",
|
|
84459
|
+
initialValue: deletions.length === 0
|
|
83881
84460
|
});
|
|
83882
84461
|
if (!ensureNotCancelled(ok)) {
|
|
83883
84462
|
$e("Aborted.");
|
|
@@ -83922,10 +84501,13 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
83922
84501
|
...metaField("credit_limit"),
|
|
83923
84502
|
members: graph.memberIds,
|
|
83924
84503
|
edges: graph.edges,
|
|
83925
|
-
triggers: graph.triggers,
|
|
84504
|
+
triggers: sendWebhooks ? [...graph.triggers, ...graph.webhookTriggers] : graph.triggers,
|
|
84505
|
+
...sendWebhooks ? { replace_webhook_triggers: true } : {},
|
|
84506
|
+
...sendDecisions ? { decisions: decisionsPayload } : {},
|
|
83926
84507
|
...lock?.revision != null ? { base_revision: lock.revision } : {}
|
|
83927
84508
|
});
|
|
83928
84509
|
sp.stop(`Graph updated. New cloud revision ${updated.revision}.`);
|
|
84510
|
+
const settledDecisions = sendDecisions ? cloudDecisions(updated, slugForAgent) : decisionPlan?.kind === "reconcile" ? cloudDecisionList : null;
|
|
83929
84511
|
writeOrchSyncState(cwd2, {
|
|
83930
84512
|
schemaVersion: 1,
|
|
83931
84513
|
orchestration_id: updated.id,
|
|
@@ -83943,6 +84525,8 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
83943
84525
|
payload_schema: e2.payload_schema ?? {}
|
|
83944
84526
|
})),
|
|
83945
84527
|
triggers: triggerDecision.kind === "skip" ? lock?.triggers ?? [] : syncedScheduleTriggers(cloudScheduleTriggers(updated, slugForAgent)),
|
|
84528
|
+
webhook_triggers: webhookDecision.kind === "skip" ? lock?.webhook_triggers ?? [] : syncedWebhookTriggers(cloudWebhookTriggers(updated, slugForAgent)),
|
|
84529
|
+
...settledDecisions ? { decisions: syncedDecisions(settledDecisions) } : lock?.decisions ? { decisions: lock.decisions } : {},
|
|
83946
84530
|
meta: nextOrchestrationMeta({
|
|
83947
84531
|
applied: updated,
|
|
83948
84532
|
decisions: metaDecisions,
|
|
@@ -83974,13 +84558,44 @@ function handleApiError6(err) {
|
|
|
83974
84558
|
}
|
|
83975
84559
|
|
|
83976
84560
|
// src/cli/orchestration-status.ts
|
|
84561
|
+
var import_picocolors55 = __toESM(require_picocolors(), 1);
|
|
84562
|
+
|
|
84563
|
+
// src/core/orchestration-webhooks.ts
|
|
83977
84564
|
var import_picocolors54 = __toESM(require_picocolors(), 1);
|
|
84565
|
+
function webhookEndpointUrl(firePath) {
|
|
84566
|
+
return masEndpointUrl(firePath, readAuth());
|
|
84567
|
+
}
|
|
84568
|
+
function webhookEndpointLines(triggers, indent = " ") {
|
|
84569
|
+
return triggers.flatMap((t) => [
|
|
84570
|
+
`${indent}${webhookTriggerLabel(t)}`,
|
|
84571
|
+
t.fire_path ? `${indent} ${import_picocolors54.default.dim("POST")} ${webhookEndpointUrl(t.fire_path)}` : `${indent} ${import_picocolors54.default.dim("member endpoint shows once the control plane is updated")}`
|
|
84572
|
+
]);
|
|
84573
|
+
}
|
|
84574
|
+
function resolveWebhookTrigger(cloud, ref) {
|
|
84575
|
+
const want = canonicalUuid2(ref.trim());
|
|
84576
|
+
const webhooks = cloudWebhookTriggers(cloud, (_id, fallback) => fallback);
|
|
84577
|
+
const match = webhooks.find((t) => canonicalUuid2(t.node_id) === want || t.id && canonicalUuid2(t.id) === want);
|
|
84578
|
+
if (!match) {
|
|
84579
|
+
const other = (cloud.triggers ?? []).find((t) => canonicalUuid2(t.node_id) === want || t.id && canonicalUuid2(t.id) === want);
|
|
84580
|
+
if (other) {
|
|
84581
|
+
throw new Error(`Trigger ${ref} is a ${other.trigger_type} trigger; only webhook triggers fire this way.`);
|
|
84582
|
+
}
|
|
84583
|
+
const known = webhooks.map((t) => t.node_id);
|
|
84584
|
+
throw new Error(known.length ? `No webhook trigger ${ref} in this orchestration. Its webhook triggers: ${known.join(", ")}.` : `No webhook trigger ${ref}: this orchestration has none.`);
|
|
84585
|
+
}
|
|
84586
|
+
if (!match.id) {
|
|
84587
|
+
throw new Error("This control plane does not return trigger ids yet, so the CLI cannot fire a trigger. Update the server, or use the web app.");
|
|
84588
|
+
}
|
|
84589
|
+
return match;
|
|
84590
|
+
}
|
|
84591
|
+
|
|
84592
|
+
// src/cli/orchestration-status.ts
|
|
83978
84593
|
async function runOrchestrationStatus(cwd2) {
|
|
83979
84594
|
banner("orchestration status — what changed locally, remotely, both");
|
|
83980
84595
|
const link2 = readOrchLink(cwd2);
|
|
83981
84596
|
if (!link2) {
|
|
83982
84597
|
failWarn("This folder is not linked to any orchestration.");
|
|
83983
|
-
f2.info(`Run ${
|
|
84598
|
+
f2.info(`Run ${import_picocolors55.default.cyan("brainbase orchestration pull <id>")} first.`);
|
|
83984
84599
|
return;
|
|
83985
84600
|
}
|
|
83986
84601
|
const localManifest = hasOrchManifest(cwd2) ? readOrchManifest(cwd2) : null;
|
|
@@ -84003,8 +84618,8 @@ async function runOrchestrationStatus(cwd2) {
|
|
|
84003
84618
|
}
|
|
84004
84619
|
const lines = [];
|
|
84005
84620
|
lines.push("");
|
|
84006
|
-
lines.push(` ${
|
|
84007
|
-
lines.push(` ${
|
|
84621
|
+
lines.push(` ${import_picocolors55.default.bold(link2.name)} ${import_picocolors55.default.dim(`(${link2.orchestration_id})`)}`);
|
|
84622
|
+
lines.push(` ${import_picocolors55.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
|
|
84008
84623
|
lines.push("");
|
|
84009
84624
|
const localSlugByAgentId = new Map;
|
|
84010
84625
|
for (const m3 of localManifest?.members ?? []) {
|
|
@@ -84018,12 +84633,12 @@ async function runOrchestrationStatus(cwd2) {
|
|
|
84018
84633
|
const membersAdded = [...localMemberSet].filter((s3) => !cloudMemberSet.has(s3));
|
|
84019
84634
|
const membersRemoved = [...cloudMemberSet].filter((s3) => !localMemberSet.has(s3));
|
|
84020
84635
|
if (membersAdded.length || membersRemoved.length) {
|
|
84021
|
-
lines.push(` ${
|
|
84636
|
+
lines.push(` ${import_picocolors55.default.bold("members")}`);
|
|
84022
84637
|
for (const slug of membersAdded) {
|
|
84023
|
-
lines.push(` ${
|
|
84638
|
+
lines.push(` ${import_picocolors55.default.yellow("→ push")} added in yaml: ${import_picocolors55.default.bold(slug)}`);
|
|
84024
84639
|
}
|
|
84025
84640
|
for (const slug of membersRemoved) {
|
|
84026
|
-
lines.push(` ${
|
|
84641
|
+
lines.push(` ${import_picocolors55.default.cyan("← pull")} added on cloud: ${import_picocolors55.default.bold(slug)}`);
|
|
84027
84642
|
}
|
|
84028
84643
|
lines.push("");
|
|
84029
84644
|
}
|
|
@@ -84038,11 +84653,11 @@ async function runOrchestrationStatus(cwd2) {
|
|
|
84038
84653
|
const edgesAdded = [...localEdges.keys()].filter((k3) => !cloudEdges.has(k3));
|
|
84039
84654
|
const edgesRemoved = [...cloudEdges.keys()].filter((k3) => !localEdges.has(k3));
|
|
84040
84655
|
if (edgesAdded.length || edgesRemoved.length) {
|
|
84041
|
-
lines.push(` ${
|
|
84656
|
+
lines.push(` ${import_picocolors55.default.bold("edges")}`);
|
|
84042
84657
|
for (const k3 of edgesAdded)
|
|
84043
|
-
lines.push(` ${
|
|
84658
|
+
lines.push(` ${import_picocolors55.default.yellow("→ push")} added in yaml: ${k3}`);
|
|
84044
84659
|
for (const k3 of edgesRemoved)
|
|
84045
|
-
lines.push(` ${
|
|
84660
|
+
lines.push(` ${import_picocolors55.default.cyan("← pull")} added on cloud: ${k3}`);
|
|
84046
84661
|
lines.push("");
|
|
84047
84662
|
}
|
|
84048
84663
|
const metaDecisions = decideOrchestrationMeta({
|
|
@@ -84052,17 +84667,17 @@ async function runOrchestrationStatus(cwd2) {
|
|
|
84052
84667
|
force: false
|
|
84053
84668
|
});
|
|
84054
84669
|
if (metaDecisions.length) {
|
|
84055
|
-
lines.push(` ${
|
|
84670
|
+
lines.push(` ${import_picocolors55.default.bold("orchestration metadata")}`);
|
|
84056
84671
|
for (const m3 of metaDecisions) {
|
|
84057
84672
|
if (m3.kind === "push") {
|
|
84058
|
-
lines.push(` ${
|
|
84673
|
+
lines.push(` ${import_picocolors55.default.yellow("→ push")} ${import_picocolors55.default.bold(m3.field)}: cloud ${import_picocolors55.default.dim(`"${m3.cloud}"`)} → local ${import_picocolors55.default.dim(`"${m3.local}"`)}`);
|
|
84059
84674
|
} else if (m3.kind === "keep") {
|
|
84060
|
-
lines.push(` ${
|
|
84675
|
+
lines.push(` ${import_picocolors55.default.cyan("← pull")} ${import_picocolors55.default.bold(m3.field)}: changed in the cloud to ${import_picocolors55.default.dim(`"${m3.cloud}"`)}; push leaves it alone ${import_picocolors55.default.dim(`(yaml still has "${m3.local}")`)}`);
|
|
84061
84676
|
} else {
|
|
84062
|
-
lines.push(` ${
|
|
84677
|
+
lines.push(` ${import_picocolors55.default.red("! conflict")} ${import_picocolors55.default.bold(m3.field)}: local ${import_picocolors55.default.dim(`"${m3.local}"`)} vs cloud ${import_picocolors55.default.dim(`"${m3.cloud}"`)} — push refuses until you pull or ${import_picocolors55.default.cyan("--force")}`);
|
|
84063
84678
|
}
|
|
84064
84679
|
}
|
|
84065
|
-
lines.push(` ${
|
|
84680
|
+
lines.push(` ${import_picocolors55.default.dim("fields the manifest omits, and fields only the cloud changed, are left alone")}`);
|
|
84066
84681
|
lines.push("");
|
|
84067
84682
|
}
|
|
84068
84683
|
const cloudTriggers = cloudScheduleTriggers(cloud, slugForAgent);
|
|
@@ -84087,34 +84702,141 @@ async function runOrchestrationStatus(cwd2) {
|
|
|
84087
84702
|
const triggersToPull = cloudTriggers.filter((t) => !localNodes.has(t.node_id));
|
|
84088
84703
|
const triggerDeletes = triggerPlan.kind === "reconcile" ? triggerPlan.archives : [];
|
|
84089
84704
|
if (triggersToPush.length || triggersToPull.length) {
|
|
84090
|
-
lines.push(` ${
|
|
84705
|
+
lines.push(` ${import_picocolors55.default.bold("schedule triggers")}`);
|
|
84091
84706
|
for (const t of triggersToPush) {
|
|
84092
|
-
lines.push(` ${
|
|
84707
|
+
lines.push(` ${import_picocolors55.default.yellow("→ push")} added/changed in yaml: ${scheduleTriggerLabel(t)}`);
|
|
84093
84708
|
}
|
|
84094
84709
|
for (const t of triggersToPull) {
|
|
84095
84710
|
const doomed = triggerDeletes.includes(t.node_id);
|
|
84096
|
-
lines.push(doomed ? ` ${
|
|
84711
|
+
lines.push(doomed ? ` ${import_picocolors55.default.red("⨯ push deletes")} ${scheduleTriggerLabel(t)}` : ` ${import_picocolors55.default.cyan("← pull")} only on cloud: ${scheduleTriggerLabel(t)}`);
|
|
84097
84712
|
}
|
|
84098
84713
|
lines.push("");
|
|
84099
84714
|
}
|
|
84100
84715
|
if (triggerPlan.kind === "blocked") {
|
|
84101
|
-
lines.push(` ${
|
|
84716
|
+
lines.push(` ${import_picocolors55.default.bold(import_picocolors55.default.red("schedule triggers: push blocked"))}`);
|
|
84102
84717
|
for (const nodeId of triggerPlan.unseen) {
|
|
84103
|
-
lines.push(` ${
|
|
84718
|
+
lines.push(` ${import_picocolors55.default.red("!")} ${triggerLabel(nodeId)} ${import_picocolors55.default.dim("— only in the cloud; pushing would delete it")}`);
|
|
84104
84719
|
}
|
|
84105
84720
|
for (const nodeId of triggerPlan.cloudModified) {
|
|
84106
|
-
lines.push(` ${
|
|
84721
|
+
lines.push(` ${import_picocolors55.default.red("!")} ${triggerLabel(nodeId)} ${import_picocolors55.default.dim("— edited in the cloud; pushing would overwrite that edit")}`);
|
|
84107
84722
|
}
|
|
84108
84723
|
for (const nodeId of triggerPlan.staleArchives) {
|
|
84109
|
-
lines.push(` ${
|
|
84724
|
+
lines.push(` ${import_picocolors55.default.red("!")} ${triggerLabel(nodeId)} ${import_picocolors55.default.dim("— deleted here, edited in the cloud since; pushing would delete that edit")}`);
|
|
84110
84725
|
}
|
|
84111
|
-
lines.push(` ${
|
|
84726
|
+
lines.push(` ${import_picocolors55.default.dim("run")} ${import_picocolors55.default.cyan("brainbase orchestration pull")} ${import_picocolors55.default.dim("first")}`);
|
|
84112
84727
|
lines.push("");
|
|
84113
84728
|
} else if (triggerPlan.kind === "skip") {
|
|
84114
84729
|
const left = untouchedRows(triggerPlan);
|
|
84115
|
-
lines.push(` ${
|
|
84730
|
+
lines.push(` ${import_picocolors55.default.dim(`${left.length} cloud schedule trigger${left.length === 1 ? "" : "s"} not managed by this manifest — push leaves ${left.length === 1 ? "it" : "them"} untouched`)}`);
|
|
84731
|
+
lines.push("");
|
|
84732
|
+
}
|
|
84733
|
+
const cloudWebhooks = cloudWebhookTriggers(cloud, slugForAgent);
|
|
84734
|
+
const localWebhooks = manifestWebhookTriggers(localManifest);
|
|
84735
|
+
const webhookPlan = decideWebhookTriggerReconcile({
|
|
84736
|
+
local: localWebhooks,
|
|
84737
|
+
cloud: cloudWebhooks,
|
|
84738
|
+
baseline: lock?.webhook_triggers,
|
|
84739
|
+
force: false
|
|
84740
|
+
});
|
|
84741
|
+
const webhookByNode = new Map([...cloudWebhooks, ...localWebhooks].map((t) => [t.node_id, t]));
|
|
84742
|
+
const webhookLabel = (nodeId) => {
|
|
84743
|
+
const t = webhookByNode.get(nodeId);
|
|
84744
|
+
return t ? webhookTriggerLabel(t) : nodeId;
|
|
84745
|
+
};
|
|
84746
|
+
const localWebhookNodes = new Set(localWebhooks.map((t) => t.node_id));
|
|
84747
|
+
const cloudWebhookByNode = new Map(cloudWebhooks.map((t) => [t.node_id, t]));
|
|
84748
|
+
const webhooksToPush = localWebhooks.filter((t) => {
|
|
84749
|
+
const remote = cloudWebhookByNode.get(t.node_id);
|
|
84750
|
+
return !remote || webhookTriggerHash(remote) !== webhookTriggerHash(t);
|
|
84751
|
+
});
|
|
84752
|
+
const webhooksToPull = cloudWebhooks.filter((t) => !localWebhookNodes.has(t.node_id));
|
|
84753
|
+
const webhookDeletes = webhookPlan.kind === "reconcile" ? webhookPlan.archives : [];
|
|
84754
|
+
if (webhooksToPush.length || webhooksToPull.length) {
|
|
84755
|
+
lines.push(` ${import_picocolors55.default.bold("webhook triggers")}`);
|
|
84756
|
+
for (const t of webhooksToPush) {
|
|
84757
|
+
lines.push(` ${import_picocolors55.default.yellow("→ push")} added/changed in yaml: ${webhookTriggerLabel(t)}`);
|
|
84758
|
+
}
|
|
84759
|
+
for (const t of webhooksToPull) {
|
|
84760
|
+
lines.push(webhookDeletes.includes(t.node_id) ? ` ${import_picocolors55.default.red("⨯ push deletes")} ${webhookTriggerLabel(t)}` : ` ${import_picocolors55.default.cyan("← pull")} only on cloud: ${webhookTriggerLabel(t)}`);
|
|
84761
|
+
}
|
|
84762
|
+
lines.push("");
|
|
84763
|
+
}
|
|
84764
|
+
if (webhookPlan.kind === "blocked") {
|
|
84765
|
+
lines.push(` ${import_picocolors55.default.bold(import_picocolors55.default.red("webhook triggers: push blocked"))}`);
|
|
84766
|
+
for (const nodeId of webhookPlan.unseen) {
|
|
84767
|
+
lines.push(` ${import_picocolors55.default.red("!")} ${webhookLabel(nodeId)} ${import_picocolors55.default.dim("— only in the cloud; pushing would delete it")}`);
|
|
84768
|
+
}
|
|
84769
|
+
for (const nodeId of webhookPlan.cloudModified) {
|
|
84770
|
+
lines.push(` ${import_picocolors55.default.red("!")} ${webhookLabel(nodeId)} ${import_picocolors55.default.dim("— edited in the cloud; pushing would overwrite that edit")}`);
|
|
84771
|
+
}
|
|
84772
|
+
for (const nodeId of webhookPlan.staleArchives) {
|
|
84773
|
+
lines.push(` ${import_picocolors55.default.red("!")} ${webhookLabel(nodeId)} ${import_picocolors55.default.dim("— deleted here, edited in the cloud since; pushing would delete that edit")}`);
|
|
84774
|
+
}
|
|
84775
|
+
lines.push(` ${import_picocolors55.default.dim("run")} ${import_picocolors55.default.cyan("brainbase orchestration pull")} ${import_picocolors55.default.dim("first")}`);
|
|
84776
|
+
lines.push("");
|
|
84777
|
+
} else if (webhookPlan.kind === "skip") {
|
|
84778
|
+
const left = untouchedRows(webhookPlan);
|
|
84779
|
+
lines.push(` ${import_picocolors55.default.dim(`${left.length} cloud webhook trigger${left.length === 1 ? "" : "s"} not managed by this manifest — push leaves ${left.length === 1 ? "it" : "them"} untouched`)}`);
|
|
84116
84780
|
lines.push("");
|
|
84117
84781
|
}
|
|
84782
|
+
const localDecisions = manifestDecisions(localManifest, new Map([...localSlugByAgentId].map(([agentId, slug]) => [slug, agentId])));
|
|
84783
|
+
const cloudDecisionList = cloudDecisions(cloud, slugForAgent);
|
|
84784
|
+
let decisionsToPush = [];
|
|
84785
|
+
let decisionsToPull = [];
|
|
84786
|
+
if (!cloudDecisionList) {
|
|
84787
|
+
if (localDecisions.length) {
|
|
84788
|
+
lines.push(` ${import_picocolors55.default.dim(`${localDecisions.length} decision${localDecisions.length === 1 ? "" : "s"} in yaml, but the cloud does not show decision nodes to this account — push leaves ${localDecisions.length === 1 ? "it" : "them"} alone`)}`);
|
|
84789
|
+
lines.push("");
|
|
84790
|
+
}
|
|
84791
|
+
} else {
|
|
84792
|
+
const decisionPlan = decideDecisionReconcile({
|
|
84793
|
+
local: localDecisions,
|
|
84794
|
+
cloud: cloudDecisionList,
|
|
84795
|
+
baseline: lock?.decisions,
|
|
84796
|
+
force: false
|
|
84797
|
+
});
|
|
84798
|
+
const byId = new Map([...cloudDecisionList, ...localDecisions].map((d3) => [d3.id, d3]));
|
|
84799
|
+
const label2 = (id) => {
|
|
84800
|
+
const d3 = byId.get(id);
|
|
84801
|
+
return d3 ? decisionLabel(d3) : id;
|
|
84802
|
+
};
|
|
84803
|
+
const localIds = new Set(localDecisions.map((d3) => d3.id));
|
|
84804
|
+
const cloudById = new Map(cloudDecisionList.map((d3) => [d3.id, d3]));
|
|
84805
|
+
decisionsToPush = localDecisions.filter((d3) => {
|
|
84806
|
+
const remote = cloudById.get(d3.id);
|
|
84807
|
+
return !remote || decisionHash(remote) !== decisionHash(d3);
|
|
84808
|
+
});
|
|
84809
|
+
decisionsToPull = cloudDecisionList.filter((d3) => !localIds.has(d3.id));
|
|
84810
|
+
const decisionDeletes = decisionPlan.kind === "reconcile" ? decisionPlan.archives : [];
|
|
84811
|
+
if (decisionsToPush.length || decisionsToPull.length) {
|
|
84812
|
+
lines.push(` ${import_picocolors55.default.bold("decisions")}`);
|
|
84813
|
+
for (const d3 of decisionsToPush) {
|
|
84814
|
+
lines.push(` ${import_picocolors55.default.yellow("→ push")} added/changed in yaml: ${decisionLabel(d3)}`);
|
|
84815
|
+
}
|
|
84816
|
+
for (const d3 of decisionsToPull) {
|
|
84817
|
+
lines.push(decisionDeletes.includes(d3.id) ? ` ${import_picocolors55.default.red("⨯ push deletes")} ${decisionLabel(d3)}` : ` ${import_picocolors55.default.cyan("← pull")} only on cloud: ${decisionLabel(d3)}`);
|
|
84818
|
+
}
|
|
84819
|
+
lines.push("");
|
|
84820
|
+
}
|
|
84821
|
+
if (decisionPlan.kind === "blocked") {
|
|
84822
|
+
lines.push(` ${import_picocolors55.default.bold(import_picocolors55.default.red("decisions: push blocked"))}`);
|
|
84823
|
+
for (const id of decisionPlan.unseen) {
|
|
84824
|
+
lines.push(` ${import_picocolors55.default.red("!")} ${label2(id)} ${import_picocolors55.default.dim("— only in the cloud; pushing would delete it")}`);
|
|
84825
|
+
}
|
|
84826
|
+
for (const id of decisionPlan.cloudModified) {
|
|
84827
|
+
lines.push(` ${import_picocolors55.default.red("!")} ${label2(id)} ${import_picocolors55.default.dim("— edited in the cloud; pushing would overwrite that edit")}`);
|
|
84828
|
+
}
|
|
84829
|
+
for (const id of decisionPlan.staleArchives) {
|
|
84830
|
+
lines.push(` ${import_picocolors55.default.red("!")} ${label2(id)} ${import_picocolors55.default.dim("— deleted here, edited in the cloud since; pushing would delete that edit")}`);
|
|
84831
|
+
}
|
|
84832
|
+
lines.push(` ${import_picocolors55.default.dim("run")} ${import_picocolors55.default.cyan("brainbase orchestration pull")} ${import_picocolors55.default.dim("first")}`);
|
|
84833
|
+
lines.push("");
|
|
84834
|
+
} else if (decisionPlan.kind === "skip") {
|
|
84835
|
+
const left = untouchedRows(decisionPlan);
|
|
84836
|
+
lines.push(` ${import_picocolors55.default.dim(`${left.length} cloud decision${left.length === 1 ? "" : "s"} not managed by this manifest — push leaves ${left.length === 1 ? "it" : "them"} untouched`)}`);
|
|
84837
|
+
lines.push("");
|
|
84838
|
+
}
|
|
84839
|
+
}
|
|
84118
84840
|
const lockByAgentId = new Map((lock?.members ?? []).map((m3) => [m3.agent_id, m3]));
|
|
84119
84841
|
const memberDrift = [];
|
|
84120
84842
|
for (const m3 of cloud.members) {
|
|
@@ -84135,27 +84857,35 @@ async function runOrchestrationStatus(cwd2) {
|
|
|
84135
84857
|
}
|
|
84136
84858
|
}
|
|
84137
84859
|
if (memberDrift.length) {
|
|
84138
|
-
lines.push(` ${
|
|
84860
|
+
lines.push(` ${import_picocolors55.default.bold("member content drift")}`);
|
|
84139
84861
|
for (const d3 of memberDrift) {
|
|
84140
|
-
lines.push(` ${
|
|
84862
|
+
lines.push(` ${import_picocolors55.default.cyan("?")} ${import_picocolors55.default.bold(d3.slug)} ${import_picocolors55.default.dim("— " + d3.reason)}`);
|
|
84141
84863
|
}
|
|
84142
|
-
lines.push(` ${
|
|
84864
|
+
lines.push(` ${import_picocolors55.default.dim("cd into each member folder and run")} ${import_picocolors55.default.cyan("brainbase agent status")}`);
|
|
84143
84865
|
lines.push("");
|
|
84144
84866
|
}
|
|
84145
84867
|
const revisionDrift = lock?.revision != null && cloud.revision !== lock.revision;
|
|
84146
84868
|
if (revisionDrift) {
|
|
84147
|
-
lines.push(` ${
|
|
84148
|
-
lines.push(` ${
|
|
84869
|
+
lines.push(` ${import_picocolors55.default.bold("cloud revision")}`);
|
|
84870
|
+
lines.push(` ${import_picocolors55.default.cyan("← pull")} cloud changed since last pull: ${import_picocolors55.default.dim(`lock ${lock.revision} → cloud ${cloud.revision}`)}`);
|
|
84149
84871
|
lines.push("");
|
|
84150
84872
|
}
|
|
84151
|
-
|
|
84152
|
-
|
|
84873
|
+
const endpointLines = [];
|
|
84874
|
+
if (cloudWebhooks.length) {
|
|
84875
|
+
endpointLines.push(` ${import_picocolors55.default.bold("webhook endpoints")} ${import_picocolors55.default.dim("— fire with your credentials, or")} ${import_picocolors55.default.cyan("brainbase orchestration trigger fire <node_id>")}`);
|
|
84876
|
+
endpointLines.push(...webhookEndpointLines(cloudWebhooks, " "));
|
|
84877
|
+
endpointLines.push("");
|
|
84878
|
+
}
|
|
84879
|
+
if (!membersAdded.length && !membersRemoved.length && !edgesAdded.length && !edgesRemoved.length && !triggersToPush.length && !triggersToPull.length && !webhooksToPush.length && !webhooksToPull.length && !decisionsToPush.length && !decisionsToPull.length && !metaDecisions.length && !memberDrift.length && !revisionDrift) {
|
|
84880
|
+
lines.push(` ${import_picocolors55.default.green("✓")} everything is in sync`);
|
|
84153
84881
|
lines.push("");
|
|
84882
|
+
lines.push(...endpointLines);
|
|
84154
84883
|
console.log(lines.join(`
|
|
84155
84884
|
`));
|
|
84156
84885
|
return;
|
|
84157
84886
|
}
|
|
84158
|
-
lines.push(
|
|
84887
|
+
lines.push(...endpointLines);
|
|
84888
|
+
lines.push(` ${import_picocolors55.default.dim("run")} ${import_picocolors55.default.cyan("brainbase orchestration pull")} ${import_picocolors55.default.dim("to apply cloud changes,")} ${import_picocolors55.default.cyan("brainbase orchestration push")} ${import_picocolors55.default.dim("to send yours")}`);
|
|
84159
84889
|
lines.push("");
|
|
84160
84890
|
console.log(lines.join(`
|
|
84161
84891
|
`));
|
|
@@ -84170,7 +84900,7 @@ function stableJson2(value2) {
|
|
|
84170
84900
|
}
|
|
84171
84901
|
|
|
84172
84902
|
// src/cli/orchestration-list.ts
|
|
84173
|
-
var
|
|
84903
|
+
var import_picocolors56 = __toESM(require_picocolors(), 1);
|
|
84174
84904
|
async function runOrchestrationList(args) {
|
|
84175
84905
|
const json3 = args.json === true;
|
|
84176
84906
|
if (!json3)
|
|
@@ -84201,13 +84931,13 @@ async function runOrchestrationList(args) {
|
|
|
84201
84931
|
}
|
|
84202
84932
|
const lines = [""];
|
|
84203
84933
|
for (const o2 of items) {
|
|
84204
|
-
lines.push(` ${
|
|
84934
|
+
lines.push(` ${import_picocolors56.default.bold(o2.name)} ${import_picocolors56.default.dim(o2.id)}`);
|
|
84205
84935
|
if (o2.description)
|
|
84206
|
-
lines.push(` ${
|
|
84207
|
-
lines.push(` ${
|
|
84936
|
+
lines.push(` ${import_picocolors56.default.dim(o2.description)}`);
|
|
84937
|
+
lines.push(` ${import_picocolors56.default.dim(`${o2.member_count} member${o2.member_count === 1 ? "" : "s"} · ${o2.edge_count} edge${o2.edge_count === 1 ? "" : "s"}`)}`);
|
|
84208
84938
|
lines.push("");
|
|
84209
84939
|
}
|
|
84210
|
-
lines.push(` ${
|
|
84940
|
+
lines.push(` ${import_picocolors56.default.dim("pull one with")} ${import_picocolors56.default.cyan("brainbase orchestration pull <id>")}`);
|
|
84211
84941
|
lines.push("");
|
|
84212
84942
|
console.log(lines.join(`
|
|
84213
84943
|
`));
|
|
@@ -84215,7 +84945,7 @@ async function runOrchestrationList(args) {
|
|
|
84215
84945
|
|
|
84216
84946
|
// src/cli/orchestration-add-agent.ts
|
|
84217
84947
|
import fs86 from "node:fs";
|
|
84218
|
-
var
|
|
84948
|
+
var import_picocolors57 = __toESM(require_picocolors(), 1);
|
|
84219
84949
|
|
|
84220
84950
|
// src/core/orchestration-add.ts
|
|
84221
84951
|
function resolveOrgIdForGroup(groupId, orgsWithTeams) {
|
|
@@ -84280,7 +85010,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
84280
85010
|
const link2 = readOrchLink(cwd2);
|
|
84281
85011
|
if (!link2 || !hasOrchManifest(cwd2)) {
|
|
84282
85012
|
failWarn("This folder is not a linked orchestration.");
|
|
84283
|
-
f2.info(`Run ${
|
|
85013
|
+
f2.info(`Run ${import_picocolors57.default.cyan("brainbase orchestration pull <id>")} first.`);
|
|
84284
85014
|
return;
|
|
84285
85015
|
}
|
|
84286
85016
|
let manifest;
|
|
@@ -84306,7 +85036,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
84306
85036
|
while (manifest.members.some((m3) => m3.slug === candidate) || fs86.existsSync(memberDir(cwd2, candidate))) {
|
|
84307
85037
|
candidate = `${slug}-${++n}`;
|
|
84308
85038
|
}
|
|
84309
|
-
f2.info(`Slug ${
|
|
85039
|
+
f2.info(`Slug ${import_picocolors57.default.bold(slug)} is taken — using ${import_picocolors57.default.bold(candidate)}.`);
|
|
84310
85040
|
slug = candidate;
|
|
84311
85041
|
}
|
|
84312
85042
|
let payloadSchema;
|
|
@@ -84330,7 +85060,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
84330
85060
|
const resolved = resolveOrgIdForGroup(link2.group_id, orgsWithTeams);
|
|
84331
85061
|
if (!resolved) {
|
|
84332
85062
|
sp.stop("Failed.");
|
|
84333
|
-
fail(`Could not find an org that owns group ${
|
|
85063
|
+
fail(`Could not find an org that owns group ${import_picocolors57.default.bold(link2.group_id)}. ` + `Pass ${import_picocolors57.default.cyan("--org <id>")} explicitly.`);
|
|
84334
85064
|
return;
|
|
84335
85065
|
}
|
|
84336
85066
|
orgId = resolved;
|
|
@@ -84347,14 +85077,14 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
84347
85077
|
if (from.length === 0 && to2.length === 0 && isInteractive() && manifest.members.length > 0) {
|
|
84348
85078
|
const memberOptions = manifest.members.map((m3) => ({ value: m3.slug, label: m3.slug }));
|
|
84349
85079
|
const pickedFrom = await ae({
|
|
84350
|
-
message: `Connect ${
|
|
85080
|
+
message: `Connect ${import_picocolors57.default.bold(slug)} FROM which member(s)? — edges INTO ${slug} (space to select, enter to skip)`,
|
|
84351
85081
|
options: memberOptions,
|
|
84352
85082
|
required: false
|
|
84353
85083
|
});
|
|
84354
85084
|
if (Array.isArray(pickedFrom))
|
|
84355
85085
|
from = pickedFrom;
|
|
84356
85086
|
const pickedTo = await ae({
|
|
84357
|
-
message: `Connect ${
|
|
85087
|
+
message: `Connect ${import_picocolors57.default.bold(slug)} TO which member(s)? — edges OUT of ${slug} (space to select, enter to skip)`,
|
|
84358
85088
|
options: memberOptions,
|
|
84359
85089
|
required: false
|
|
84360
85090
|
});
|
|
@@ -84393,23 +85123,23 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
84393
85123
|
}
|
|
84394
85124
|
writeOrchManifest(cwd2, updated);
|
|
84395
85125
|
if (args.noPush) {
|
|
84396
|
-
f2.info(`Manifest updated. Run ${
|
|
85126
|
+
f2.info(`Manifest updated. Run ${import_picocolors57.default.cyan("brainbase orchestration push")} to apply.`);
|
|
84397
85127
|
return;
|
|
84398
85128
|
}
|
|
84399
85129
|
await runOrchestrationPush(cwd2, { yes: true, graphOnly: true });
|
|
84400
85130
|
}
|
|
84401
85131
|
|
|
84402
85132
|
// src/cli/orchestration-create.ts
|
|
84403
|
-
var
|
|
85133
|
+
var import_picocolors58 = __toESM(require_picocolors(), 1);
|
|
84404
85134
|
async function runOrchestrationCreate(cwd2, args) {
|
|
84405
85135
|
banner("orchestration create — claim a brainbase-orchestration.yaml");
|
|
84406
85136
|
if (readOrchLink(cwd2)) {
|
|
84407
85137
|
failWarn("This folder is already linked to an orchestration.");
|
|
84408
|
-
f2.info(`Run ${
|
|
85138
|
+
f2.info(`Run ${import_picocolors58.default.cyan("brainbase orchestration push")} to update it.`);
|
|
84409
85139
|
return;
|
|
84410
85140
|
}
|
|
84411
85141
|
if (!hasOrchManifest(cwd2)) {
|
|
84412
|
-
failWarn(`No ${
|
|
85142
|
+
failWarn(`No ${import_picocolors58.default.bold(ORCH_MANIFEST_FILE)} here.`);
|
|
84413
85143
|
f2.info(`Create one, or pull an existing orchestration first.`);
|
|
84414
85144
|
return;
|
|
84415
85145
|
}
|
|
@@ -84442,10 +85172,10 @@ async function runOrchestrationCreate(cwd2, args) {
|
|
|
84442
85172
|
});
|
|
84443
85173
|
const plan = [
|
|
84444
85174
|
"",
|
|
84445
|
-
` ${
|
|
84446
|
-
` ${
|
|
84447
|
-
` ${
|
|
84448
|
-
` ${
|
|
85175
|
+
` ${import_picocolors58.default.bold(manifest.orchestration.name)}`,
|
|
85176
|
+
` ${import_picocolors58.default.dim("org")} ${import_picocolors58.default.bold(target.org.name)}`,
|
|
85177
|
+
` ${import_picocolors58.default.dim("team")} ${import_picocolors58.default.bold(target.team.name)}`,
|
|
85178
|
+
` ${import_picocolors58.default.dim("graph")} ${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}, ${graph.triggers.length + graph.webhookTriggers.length} trigger${graph.triggers.length + graph.webhookTriggers.length === 1 ? "" : "s"}`,
|
|
84449
85179
|
""
|
|
84450
85180
|
];
|
|
84451
85181
|
console.log(plan.join(`
|
|
@@ -84473,9 +85203,11 @@ async function runOrchestrationCreate(cwd2, args) {
|
|
|
84473
85203
|
credit_limit: manifest.orchestration.credit_limit,
|
|
84474
85204
|
members: graph.memberIds,
|
|
84475
85205
|
edges: graph.edges,
|
|
84476
|
-
triggers: graph.triggers
|
|
85206
|
+
triggers: [...graph.triggers, ...graph.webhookTriggers]
|
|
84477
85207
|
});
|
|
84478
|
-
sp.stop(`Created ${
|
|
85208
|
+
sp.stop(`Created ${import_picocolors58.default.bold(created.name)}.`);
|
|
85209
|
+
const slugForAgent = (agentId, fallback) => manifest.members.find((m3) => slugToAgentId.get(m3.slug) === agentId)?.slug ?? fallback;
|
|
85210
|
+
const webhooks = cloudWebhookTriggers(created, slugForAgent);
|
|
84479
85211
|
writeOrchLink(cwd2, {
|
|
84480
85212
|
schemaVersion: 1,
|
|
84481
85213
|
orchestration_id: created.id,
|
|
@@ -84501,8 +85233,13 @@ async function runOrchestrationCreate(cwd2, args) {
|
|
|
84501
85233
|
to_slug: e2.to_slug ?? e2.to_agent_id,
|
|
84502
85234
|
description: e2.description ?? "",
|
|
84503
85235
|
payload_schema: e2.payload_schema ?? {}
|
|
84504
|
-
}))
|
|
85236
|
+
})),
|
|
85237
|
+
webhook_triggers: syncedWebhookTriggers(webhooks)
|
|
84505
85238
|
});
|
|
85239
|
+
const decisionCount = manifest.decisions?.length ?? 0;
|
|
85240
|
+
if (decisionCount) {
|
|
85241
|
+
f2.info(`Run ${import_picocolors58.default.cyan("brainbase orchestration push")} to add the ${decisionCount} decision${decisionCount === 1 ? "" : "s"} in this manifest.`);
|
|
85242
|
+
}
|
|
84506
85243
|
$e(`Created ${created.name} at revision ${created.revision}.`);
|
|
84507
85244
|
} catch (err) {
|
|
84508
85245
|
sp.stop("Failed.");
|
|
@@ -84524,8 +85261,98 @@ function handleApiError7(err) {
|
|
|
84524
85261
|
}
|
|
84525
85262
|
}
|
|
84526
85263
|
|
|
85264
|
+
// src/cli/orchestration-from-agent.ts
|
|
85265
|
+
var import_picocolors59 = __toESM(require_picocolors(), 1);
|
|
85266
|
+
var MEMBERSHIP_CONFLICT_CODE = "orchestration_membership_conflict";
|
|
85267
|
+
var MAX_NAME_LENGTH = 200;
|
|
85268
|
+
async function runOrchestrationFromAgent(cwd2, args) {
|
|
85269
|
+
const json3 = args.json === true;
|
|
85270
|
+
if (args.agentId !== undefined && !args.agentId.trim()) {
|
|
85271
|
+
fail3(json3, "The agent id is empty.", `Pass an agent id, or omit it to use the agent linked here.`);
|
|
85272
|
+
return;
|
|
85273
|
+
}
|
|
85274
|
+
const link2 = readLink(cwd2);
|
|
85275
|
+
const agentId = args.agentId?.trim() || link2?.agent_id;
|
|
85276
|
+
if (!agentId) {
|
|
85277
|
+
fail3(json3, "No agent given and this folder is not linked to one.", `Pass an agent id: ${import_picocolors59.default.cyan("brainbase orchestration from-agent <agent-id>")}`);
|
|
85278
|
+
return;
|
|
85279
|
+
}
|
|
85280
|
+
const fromLink = args.agentId === undefined && link2 !== null;
|
|
85281
|
+
if (!json3)
|
|
85282
|
+
banner("orchestration from-agent — turn an agent into an orchestration");
|
|
85283
|
+
let created;
|
|
85284
|
+
try {
|
|
85285
|
+
const teamId = args.teamId ?? (fromLink ? link2.team_id : (await resolveOrgAndTeam({
|
|
85286
|
+
orgId: args.orgId,
|
|
85287
|
+
allowPrompt: !json3,
|
|
85288
|
+
announce: !json3
|
|
85289
|
+
})).team.id);
|
|
85290
|
+
const agent = await masApi.getAgentSummary(agentId);
|
|
85291
|
+
const sp = json3 ? null : spinner();
|
|
85292
|
+
sp?.start("Creating orchestration…");
|
|
85293
|
+
try {
|
|
85294
|
+
created = await masApi.createOrchestrationFromAgent({
|
|
85295
|
+
agent_id: agentId,
|
|
85296
|
+
group_id: teamId,
|
|
85297
|
+
name: args.name ?? (agent.name.trim().slice(0, MAX_NAME_LENGTH) || "Orchestration"),
|
|
85298
|
+
description: args.description ?? agent.description
|
|
85299
|
+
});
|
|
85300
|
+
} catch (err) {
|
|
85301
|
+
sp?.stop("Failed.");
|
|
85302
|
+
throw err;
|
|
85303
|
+
}
|
|
85304
|
+
sp?.stop(`Created ${import_picocolors59.default.bold(sanitizeLabel(created.name))}.`);
|
|
85305
|
+
} catch (err) {
|
|
85306
|
+
if (err instanceof ApiError) {
|
|
85307
|
+
fail3(json3, err.message, hint(err), { status: err.status ?? null });
|
|
85308
|
+
return;
|
|
85309
|
+
}
|
|
85310
|
+
if (json3 && err instanceof Error) {
|
|
85311
|
+
fail3(json3, err.message, undefined, { status: null });
|
|
85312
|
+
return;
|
|
85313
|
+
}
|
|
85314
|
+
throw err;
|
|
85315
|
+
}
|
|
85316
|
+
if (json3) {
|
|
85317
|
+
console.log(JSON.stringify(created, null, 2));
|
|
85318
|
+
return;
|
|
85319
|
+
}
|
|
85320
|
+
console.log([
|
|
85321
|
+
"",
|
|
85322
|
+
` ${import_picocolors59.default.green("✓")} ${import_picocolors59.default.bold(sanitizeLabel(created.name))} ${import_picocolors59.default.dim(sanitizeLabel(created.id))}`,
|
|
85323
|
+
` ${import_picocolors59.default.dim("only member:")} ${sanitizeLabel(agentId)}`,
|
|
85324
|
+
"",
|
|
85325
|
+
` ${import_picocolors59.default.dim("work on its graph with")} ${import_picocolors59.default.cyan(`brainbase orchestration pull ${sanitizeLabel(created.id)}`)}`,
|
|
85326
|
+
""
|
|
85327
|
+
].join(`
|
|
85328
|
+
`));
|
|
85329
|
+
}
|
|
85330
|
+
function hint(err) {
|
|
85331
|
+
if (err.status === 409) {
|
|
85332
|
+
const code = err.body?.detail?.code;
|
|
85333
|
+
if (code === MEMBERSHIP_CONFLICT_CODE) {
|
|
85334
|
+
return "An agent belongs to one orchestration at a time. Remove it from that one first.";
|
|
85335
|
+
}
|
|
85336
|
+
return `Pick another name with ${import_picocolors59.default.cyan("--name <name>")}.`;
|
|
85337
|
+
}
|
|
85338
|
+
if (err.status === 400 || err.status === 403) {
|
|
85339
|
+
return `The agent must be in the team you create it in. Pick one with ${import_picocolors59.default.cyan("--team <id>")}.`;
|
|
85340
|
+
}
|
|
85341
|
+
return;
|
|
85342
|
+
}
|
|
85343
|
+
function fail3(json3, message, help, extra = {}) {
|
|
85344
|
+
if (json3)
|
|
85345
|
+
console.log(JSON.stringify({ error: message, ...extra }, null, 2));
|
|
85346
|
+
else {
|
|
85347
|
+
f2.error(sanitizeLabel(message));
|
|
85348
|
+
if (help)
|
|
85349
|
+
f2.info(help);
|
|
85350
|
+
}
|
|
85351
|
+
process.exitCode = 1;
|
|
85352
|
+
}
|
|
85353
|
+
|
|
84527
85354
|
// src/cli/orchestration-init.ts
|
|
84528
|
-
var
|
|
85355
|
+
var import_picocolors60 = __toESM(require_picocolors(), 1);
|
|
84529
85356
|
|
|
84530
85357
|
// src/core/orchestration-scaffold.ts
|
|
84531
85358
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
@@ -84560,6 +85387,13 @@ var FULL_TEMPLATE_EXAMPLES = {
|
|
|
84560
85387
|
is_active: false,
|
|
84561
85388
|
config: { cron_expression: "0 9 * * 1" },
|
|
84562
85389
|
to: [{ agent: "triage" }]
|
|
85390
|
+
},
|
|
85391
|
+
{
|
|
85392
|
+
type: "webhook",
|
|
85393
|
+
node_id: "00000000-0000-4000-8000-000000000001",
|
|
85394
|
+
is_active: false,
|
|
85395
|
+
public: false,
|
|
85396
|
+
to: [{ agent: "triage" }]
|
|
84563
85397
|
}
|
|
84564
85398
|
]
|
|
84565
85399
|
};
|
|
@@ -84614,6 +85448,10 @@ edges: []
|
|
|
84614
85448
|
${commented({ edges: ex.edges })}
|
|
84615
85449
|
|
|
84616
85450
|
# Schedule triggers start members on a cron (standard 5-field syntax).
|
|
85451
|
+
# Webhook triggers start them when something outside Brainbase POSTs to them.
|
|
85452
|
+
# A webhook's \`public\` switches its secret URL: off (the default), only
|
|
85453
|
+
# members fire it, with \`brainbase orchestration trigger fire <node_id>\`;
|
|
85454
|
+
# on, anyone holding the URL (shown in the web app) can.
|
|
84617
85455
|
# \`node_id\` is a UUID you generate once and keep, so pushes update the
|
|
84618
85456
|
# same trigger instead of creating another.
|
|
84619
85457
|
${commented({ triggers: ex.triggers })}
|
|
@@ -84644,7 +85482,7 @@ async function runOrchestrationInit(cwd2, args = {}) {
|
|
|
84644
85482
|
path: target,
|
|
84645
85483
|
created: false,
|
|
84646
85484
|
reason: "conflicting-flags",
|
|
84647
|
-
message: `Pass either ${
|
|
85485
|
+
message: `Pass either ${import_picocolors60.default.cyan("--minimal")} or ${import_picocolors60.default.cyan("--full")}, not both.`
|
|
84648
85486
|
});
|
|
84649
85487
|
}
|
|
84650
85488
|
if (readOrchLink(cwd2)) {
|
|
@@ -84652,7 +85490,7 @@ async function runOrchestrationInit(cwd2, args = {}) {
|
|
|
84652
85490
|
path: target,
|
|
84653
85491
|
created: false,
|
|
84654
85492
|
reason: "linked",
|
|
84655
|
-
message: `This folder is linked to an orchestration. Edit ${
|
|
85493
|
+
message: `This folder is linked to an orchestration. Edit ${import_picocolors60.default.bold(ORCH_MANIFEST_FILE)} and run ${import_picocolors60.default.cyan("brainbase orchestration push")}, or init in a new folder.`
|
|
84656
85494
|
});
|
|
84657
85495
|
}
|
|
84658
85496
|
const existed = hasOrchManifest(cwd2);
|
|
@@ -84661,7 +85499,7 @@ async function runOrchestrationInit(cwd2, args = {}) {
|
|
|
84661
85499
|
path: target,
|
|
84662
85500
|
created: false,
|
|
84663
85501
|
reason: "manifest-exists",
|
|
84664
|
-
message: `${
|
|
85502
|
+
message: `${import_picocolors60.default.bold(ORCH_MANIFEST_FILE)} already exists here. Edit it, or pass ${import_picocolors60.default.cyan("--force")} to overwrite it.`
|
|
84665
85503
|
});
|
|
84666
85504
|
}
|
|
84667
85505
|
const name = resolveScaffoldName(cwd2, args.name, FALLBACK_NAME2);
|
|
@@ -84671,7 +85509,7 @@ async function runOrchestrationInit(cwd2, args = {}) {
|
|
|
84671
85509
|
try {
|
|
84672
85510
|
writeOrchestrationScaffold(cwd2, { name }, { full: args.full });
|
|
84673
85511
|
} catch (err) {
|
|
84674
|
-
console.error(
|
|
85512
|
+
console.error(import_picocolors60.default.red(`Failed to write ${ORCH_MANIFEST_FILE}: ${err.message}`));
|
|
84675
85513
|
process.exitCode = 1;
|
|
84676
85514
|
return;
|
|
84677
85515
|
}
|
|
@@ -84679,10 +85517,10 @@ async function runOrchestrationInit(cwd2, args = {}) {
|
|
|
84679
85517
|
emit2({ path: target, created: true, name, template: template2 });
|
|
84680
85518
|
return;
|
|
84681
85519
|
}
|
|
84682
|
-
f2.success(`Wrote ${
|
|
85520
|
+
f2.success(`Wrote ${import_picocolors60.default.bold(ORCH_MANIFEST_FILE)}${existed ? " (overwritten)" : ""}.`);
|
|
84683
85521
|
console.log();
|
|
84684
|
-
console.log(tip(`Edit it, then run ${
|
|
84685
|
-
console.log(tip(`Then ${
|
|
85522
|
+
console.log(tip(`Edit it, then run ${import_picocolors60.default.cyan("brainbase orchestration create")} ${import_picocolors60.default.dim("— creates the orchestration and links this folder.")}`));
|
|
85523
|
+
console.log(tip(`Then ${import_picocolors60.default.cyan("brainbase orchestration add-agent <name>")} ${import_picocolors60.default.dim("— creates a member agent and wires it into the graph.")}`));
|
|
84686
85524
|
console.log();
|
|
84687
85525
|
}
|
|
84688
85526
|
function emit2(result2) {
|
|
@@ -84696,13 +85534,127 @@ function refuse2(json3, outcome) {
|
|
|
84696
85534
|
return;
|
|
84697
85535
|
}
|
|
84698
85536
|
console.error(`
|
|
84699
|
-
${
|
|
85537
|
+
${import_picocolors60.default.red(message)}
|
|
84700
85538
|
`);
|
|
84701
85539
|
}
|
|
84702
85540
|
|
|
85541
|
+
// src/cli/orchestration-trigger.ts
|
|
85542
|
+
var import_picocolors61 = __toESM(require_picocolors(), 1);
|
|
85543
|
+
var OPTIONS = [
|
|
85544
|
+
{ key: "data", names: ["--data", "-d"], kind: "value" },
|
|
85545
|
+
{ key: "idempotencyKey", names: ["--idempotency-key"], kind: "value" },
|
|
85546
|
+
{ key: "orchestration", names: ["--orchestration"], kind: "value" }
|
|
85547
|
+
];
|
|
85548
|
+
async function runOrchestrationTrigger(cwd2, args, opts) {
|
|
85549
|
+
const [sub, ...rest2] = args;
|
|
85550
|
+
if (sub !== "fire") {
|
|
85551
|
+
if (sub !== undefined && sub !== "help") {
|
|
85552
|
+
console.error(`Unknown orchestration trigger subcommand: ${sub}`);
|
|
85553
|
+
process.exitCode = 1;
|
|
85554
|
+
}
|
|
85555
|
+
printTriggerHelp();
|
|
85556
|
+
return;
|
|
85557
|
+
}
|
|
85558
|
+
let parsed;
|
|
85559
|
+
try {
|
|
85560
|
+
parsed = parseArgv(rest2, OPTIONS);
|
|
85561
|
+
} catch (err) {
|
|
85562
|
+
if (!(err instanceof ArgvParseError))
|
|
85563
|
+
throw err;
|
|
85564
|
+
return refuse3(err.message, opts);
|
|
85565
|
+
}
|
|
85566
|
+
const [ref, ...extra] = parsed.positionals;
|
|
85567
|
+
if (!ref || extra.length > 0) {
|
|
85568
|
+
return refuse3("Usage: brainbase orchestration trigger fire <trigger> [--data JSON] [--idempotency-key K]", opts);
|
|
85569
|
+
}
|
|
85570
|
+
let payload = {};
|
|
85571
|
+
const data = stringOption(parsed, "data");
|
|
85572
|
+
if (data !== undefined) {
|
|
85573
|
+
try {
|
|
85574
|
+
payload = JSON.parse(data);
|
|
85575
|
+
} catch (err) {
|
|
85576
|
+
return refuse3(`--data is not valid JSON: ${err.message}`, opts);
|
|
85577
|
+
}
|
|
85578
|
+
}
|
|
85579
|
+
const idempotencyKey = stringOption(parsed, "idempotencyKey");
|
|
85580
|
+
if (idempotencyKey !== undefined && !idempotencyKey.trim()) {
|
|
85581
|
+
return refuse3("--idempotency-key cannot be empty.", opts);
|
|
85582
|
+
}
|
|
85583
|
+
const orchestrationId = stringOption(parsed, "orchestration") ?? readOrchLink(cwd2)?.orchestration_id;
|
|
85584
|
+
if (!orchestrationId) {
|
|
85585
|
+
return refuse3(`This folder is not linked to an orchestration. Run it where ${ORCH_MANIFEST_FILE} lives, or pass --orchestration <id>.`, opts);
|
|
85586
|
+
}
|
|
85587
|
+
try {
|
|
85588
|
+
const trigger = resolveWebhookTrigger(await api.getOrchestration(orchestrationId), ref);
|
|
85589
|
+
const fire = await api.fireOrchestrationTrigger(orchestrationId, trigger.id, payload, idempotencyKey);
|
|
85590
|
+
reportFire(fire, webhookTriggerLabel(trigger), opts);
|
|
85591
|
+
} catch (err) {
|
|
85592
|
+
return refuse3(errorMessage2(err), opts);
|
|
85593
|
+
}
|
|
85594
|
+
}
|
|
85595
|
+
function reportFire(fire, label2, opts) {
|
|
85596
|
+
const failed = !fire.duplicate && !!fire.dispatch_error;
|
|
85597
|
+
if (failed)
|
|
85598
|
+
process.exitCode = 1;
|
|
85599
|
+
if (opts.json) {
|
|
85600
|
+
console.log(JSON.stringify(fire, null, 2));
|
|
85601
|
+
return;
|
|
85602
|
+
}
|
|
85603
|
+
const started = fire.dispatched_agent_ids?.length ?? 0;
|
|
85604
|
+
const tasks = `${started} task${started === 1 ? "" : "s"}`;
|
|
85605
|
+
if (fire.duplicate) {
|
|
85606
|
+
f2.info(`Already fired with this idempotency key (fire ${fire.fire_id}); nothing new started.`);
|
|
85607
|
+
} else if (failed) {
|
|
85608
|
+
fail(started > 0 ? `Fired ${label2} — started ${tasks}, then failed: ${fire.dispatch_error} (fire ${fire.fire_id})` : `Fired ${label2}, but nothing started: ${fire.dispatch_error} (fire ${fire.fire_id})`);
|
|
85609
|
+
} else {
|
|
85610
|
+
f2.success(`Fired ${label2} — started ${tasks} (fire ${fire.fire_id}).`);
|
|
85611
|
+
}
|
|
85612
|
+
}
|
|
85613
|
+
function refuse3(message, opts) {
|
|
85614
|
+
process.exitCode = 1;
|
|
85615
|
+
if (opts.json) {
|
|
85616
|
+
console.log(JSON.stringify({ error: message }, null, 2));
|
|
85617
|
+
} else {
|
|
85618
|
+
f2.error(message);
|
|
85619
|
+
}
|
|
85620
|
+
}
|
|
85621
|
+
function errorMessage2(err) {
|
|
85622
|
+
if (!(err instanceof ApiError))
|
|
85623
|
+
return err.message;
|
|
85624
|
+
if (err.status === 401)
|
|
85625
|
+
return "Your session is invalid. Run `brainbase login` and try again.";
|
|
85626
|
+
if (err.status === 403) {
|
|
85627
|
+
return `${err.message} Firing a trigger needs a login or an API key with publish scope.`;
|
|
85628
|
+
}
|
|
85629
|
+
if (err.status === 404)
|
|
85630
|
+
return `${err.message} (or you do not have access to this orchestration).`;
|
|
85631
|
+
return err.message;
|
|
85632
|
+
}
|
|
85633
|
+
function printTriggerHelp() {
|
|
85634
|
+
console.log([
|
|
85635
|
+
"",
|
|
85636
|
+
` ${import_picocolors61.default.bold("brainbase orchestration trigger fire")} ${import_picocolors61.default.dim("<trigger> [options]")}`,
|
|
85637
|
+
"",
|
|
85638
|
+
` ${import_picocolors61.default.dim("Fire a webhook trigger with your credentials, whether or not its URL is public. Starts real, billable runs.")}`,
|
|
85639
|
+
` ${import_picocolors61.default.dim("<trigger> is its node_id from")} ${ORCH_MANIFEST_FILE}${import_picocolors61.default.dim(", or its trigger id.")}`,
|
|
85640
|
+
"",
|
|
85641
|
+
` ${import_picocolors61.default.bold("Flags")}`,
|
|
85642
|
+
` ${import_picocolors61.default.dim("--data <json>")} the payload (default {})`,
|
|
85643
|
+
` ${import_picocolors61.default.dim("--idempotency-key <k>")} a retry with the same key fires once`,
|
|
85644
|
+
` ${import_picocolors61.default.dim("--orchestration <id>")} the orchestration, when this folder is not linked to one`,
|
|
85645
|
+
` ${import_picocolors61.default.dim("--json")} print the fire as JSON`,
|
|
85646
|
+
""
|
|
85647
|
+
].join(`
|
|
85648
|
+
`));
|
|
85649
|
+
}
|
|
85650
|
+
|
|
84703
85651
|
// src/cli/orchestration.ts
|
|
84704
85652
|
async function runOrchestration(cwd2, sub, args, opts) {
|
|
84705
85653
|
if (args.some((arg) => arg === "--help" || arg === "-h")) {
|
|
85654
|
+
if (sub === "trigger" || sub === "triggers") {
|
|
85655
|
+
await runOrchestrationTrigger(cwd2, ["help"], { json: opts.json });
|
|
85656
|
+
return;
|
|
85657
|
+
}
|
|
84706
85658
|
printHelp4();
|
|
84707
85659
|
return;
|
|
84708
85660
|
}
|
|
@@ -84723,6 +85675,16 @@ async function runOrchestration(cwd2, sub, args, opts) {
|
|
|
84723
85675
|
teamId: opts.teamId
|
|
84724
85676
|
});
|
|
84725
85677
|
return;
|
|
85678
|
+
case "from-agent":
|
|
85679
|
+
await runOrchestrationFromAgent(cwd2, {
|
|
85680
|
+
agentId: args[0],
|
|
85681
|
+
orgId: opts.orgId,
|
|
85682
|
+
teamId: opts.teamId,
|
|
85683
|
+
name: opts.name,
|
|
85684
|
+
description: opts.description,
|
|
85685
|
+
json: opts.json
|
|
85686
|
+
});
|
|
85687
|
+
return;
|
|
84726
85688
|
case "pull":
|
|
84727
85689
|
await runOrchestrationPull(cwd2, {
|
|
84728
85690
|
orchestrationId: args[0],
|
|
@@ -84740,6 +85702,10 @@ async function runOrchestration(cwd2, sub, args, opts) {
|
|
|
84740
85702
|
case "status":
|
|
84741
85703
|
await runOrchestrationStatus(cwd2);
|
|
84742
85704
|
return;
|
|
85705
|
+
case "trigger":
|
|
85706
|
+
case "triggers":
|
|
85707
|
+
await runOrchestrationTrigger(cwd2, args, { json: opts.json });
|
|
85708
|
+
return;
|
|
84743
85709
|
case "list":
|
|
84744
85710
|
case "ls":
|
|
84745
85711
|
await runOrchestrationList({ orgId: opts.orgId, teamId: opts.teamId, json: opts.json });
|
|
@@ -84769,7 +85735,7 @@ async function runOrchestration(cwd2, sub, args, opts) {
|
|
|
84769
85735
|
return;
|
|
84770
85736
|
default:
|
|
84771
85737
|
console.error(`Unknown orchestration subcommand: ${sub}
|
|
84772
|
-
${didYouMean(sub, ["create", "pull", "push", "status", "list", "delete", "add-agent"], "brainbase orchestration")}`);
|
|
85738
|
+
${didYouMean(sub, ["create", "from-agent", "pull", "push", "status", "list", "delete", "add-agent", "trigger"], "brainbase orchestration")}`);
|
|
84773
85739
|
printHelp4();
|
|
84774
85740
|
process.exit(1);
|
|
84775
85741
|
}
|
|
@@ -84777,25 +85743,28 @@ ${didYouMean(sub, ["create", "pull", "push", "status", "list", "delete", "add-ag
|
|
|
84777
85743
|
function printHelp4() {
|
|
84778
85744
|
const out = [];
|
|
84779
85745
|
out.push("");
|
|
84780
|
-
out.push(` ${
|
|
85746
|
+
out.push(` ${import_picocolors62.default.bold("brainbase orchestration")} ${import_picocolors62.default.dim("<sub> [options]")}`);
|
|
84781
85747
|
out.push("");
|
|
84782
|
-
out.push(` ${
|
|
84783
|
-
out.push(` ${
|
|
84784
|
-
out.push(` ${
|
|
84785
|
-
out.push(` ${
|
|
84786
|
-
out.push(` ${
|
|
84787
|
-
out.push(` ${
|
|
84788
|
-
out.push(` ${
|
|
84789
|
-
out.push(` ${
|
|
85748
|
+
out.push(` ${import_picocolors62.default.cyan("init")} ${import_picocolors62.default.dim("write a starter brainbase-orchestration.yaml here — offline, no login (--full for a commented template, --force to overwrite)")}`);
|
|
85749
|
+
out.push(` ${import_picocolors62.default.cyan("create")} ${import_picocolors62.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
|
|
85750
|
+
out.push(` ${import_picocolors62.default.cyan("from-agent")} ${import_picocolors62.default.dim("[agent-id]")} ${import_picocolors62.default.dim("turn an existing agent (default: this folder's) into an orchestration")}`);
|
|
85751
|
+
out.push(` ${import_picocolors62.default.cyan("pull")} ${import_picocolors62.default.dim("<id>")} ${import_picocolors62.default.dim("fetch orchestration + every member agent into this folder")}`);
|
|
85752
|
+
out.push(` ${import_picocolors62.default.cyan("push")} ${import_picocolors62.default.dim("push each member, then update the orchestration graph")}`);
|
|
85753
|
+
out.push(` ${import_picocolors62.default.cyan("add-agent")} ${import_picocolors62.default.dim("<name>")} ${import_picocolors62.default.dim("create a member agent, wire edges (--from/--to), and push")}`);
|
|
85754
|
+
out.push(` ${import_picocolors62.default.cyan("status")} ${import_picocolors62.default.dim("show what would push and what would pull")}`);
|
|
85755
|
+
out.push(` ${import_picocolors62.default.cyan("trigger fire")} ${import_picocolors62.default.dim("<t>")} ${import_picocolors62.default.dim("fire a webhook trigger with your credentials (--data JSON, --idempotency-key K)")}`);
|
|
85756
|
+
out.push(` ${import_picocolors62.default.cyan("list")} ${import_picocolors62.default.dim("list orchestrations under a team")}`);
|
|
85757
|
+
out.push(` ${import_picocolors62.default.cyan("delete")} ${import_picocolors62.default.dim("<id>")} ${import_picocolors62.default.dim("permanently delete an orchestration graph — member agents are kept")}`);
|
|
84790
85758
|
out.push("");
|
|
84791
|
-
out.push(` ${
|
|
84792
|
-
out.push(` ${
|
|
84793
|
-
out.push(` ${
|
|
84794
|
-
out.push(` ${
|
|
84795
|
-
out.push(` ${
|
|
84796
|
-
out.push(` ${
|
|
84797
|
-
out.push(` ${
|
|
84798
|
-
out.push(` ${
|
|
85759
|
+
out.push(` ${import_picocolors62.default.bold("Flags")}`);
|
|
85760
|
+
out.push(` ${import_picocolors62.default.dim("--yes, -y")} skip confirmations (required for delete without a terminal)`);
|
|
85761
|
+
out.push(` ${import_picocolors62.default.dim("--json")} for init, from-agent, list and delete: machine-readable result`);
|
|
85762
|
+
out.push(` ${import_picocolors62.default.dim("--name <name>")} for init: orchestration name (default: this folder's name); for from-agent: default the agent's`);
|
|
85763
|
+
out.push(` ${import_picocolors62.default.dim("--description <text>")} for from-agent: orchestration description (default: the agent's)`);
|
|
85764
|
+
out.push(` ${import_picocolors62.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
|
|
85765
|
+
out.push(` ${import_picocolors62.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`, ` ${import_picocolors62.default.dim("--force")} for push: settle every conflict in your file's favour — deletes cloud schedule`, ` and webhook triggers this folder has never seen, and overwrites cloud-side edits to`, ` name, description, icon, icon_color and credit_limit`);
|
|
85766
|
+
out.push(` ${import_picocolors62.default.dim("--org <id>")} for create/list/from-agent: org id or slug (CLI vocab — DB teams.id)`);
|
|
85767
|
+
out.push(` ${import_picocolors62.default.dim("--team <id>")} for create/list/from-agent: team id (CLI vocab — DB groups.id)`);
|
|
84799
85768
|
out.push("");
|
|
84800
85769
|
console.log(out.join(`
|
|
84801
85770
|
`));
|
|
@@ -84840,11 +85809,11 @@ async function runRun(cwd2, args) {
|
|
|
84840
85809
|
}
|
|
84841
85810
|
|
|
84842
85811
|
// src/cli/publish.ts
|
|
84843
|
-
var
|
|
85812
|
+
var import_picocolors63 = __toESM(require_picocolors(), 1);
|
|
84844
85813
|
function runPublish() {
|
|
84845
85814
|
banner("publish — moved");
|
|
84846
|
-
f2.error(`${
|
|
84847
|
-
f2.info(`Use ${
|
|
85815
|
+
f2.error(`${import_picocolors63.default.bold("brainbase publish")} does not exist.`);
|
|
85816
|
+
f2.info(`Use ${import_picocolors63.default.cyan("brainbase agent push")} to send your local changes to the cloud.`);
|
|
84848
85817
|
process.exit(1);
|
|
84849
85818
|
}
|
|
84850
85819
|
|
|
@@ -85135,7 +86104,7 @@ async function runStatus(cwd2) {
|
|
|
85135
86104
|
}
|
|
85136
86105
|
|
|
85137
86106
|
// src/cli/token.ts
|
|
85138
|
-
var
|
|
86107
|
+
var import_picocolors64 = __toESM(require_picocolors(), 1);
|
|
85139
86108
|
|
|
85140
86109
|
// src/ui/ink/TokenCards.tsx
|
|
85141
86110
|
var jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
|
|
@@ -85383,7 +86352,7 @@ async function showTokenListCard(props) {
|
|
|
85383
86352
|
|
|
85384
86353
|
// src/cli/token.ts
|
|
85385
86354
|
var DEFAULT_SCOPES = ["read", "publish"];
|
|
85386
|
-
var
|
|
86355
|
+
var MAX_NAME_LENGTH2 = 128;
|
|
85387
86356
|
var ALLOWED_SCOPES = ["read", "publish", "admin"];
|
|
85388
86357
|
function isAllowedScope(value2) {
|
|
85389
86358
|
return ALLOWED_SCOPES.includes(value2);
|
|
@@ -85526,8 +86495,8 @@ async function runTokenRename(args) {
|
|
|
85526
86495
|
const candidate = value2.trim();
|
|
85527
86496
|
if (!candidate)
|
|
85528
86497
|
return "Required.";
|
|
85529
|
-
if (candidate.length >
|
|
85530
|
-
return `Too long — keep the label to ${
|
|
86498
|
+
if (candidate.length > MAX_NAME_LENGTH2) {
|
|
86499
|
+
return `Too long — keep the label to ${MAX_NAME_LENGTH2} characters or fewer.`;
|
|
85531
86500
|
}
|
|
85532
86501
|
const clash = takenBy.get(candidate.toLowerCase());
|
|
85533
86502
|
if (clash) {
|
|
@@ -85552,7 +86521,7 @@ async function runTokenRename(args) {
|
|
|
85552
86521
|
}
|
|
85553
86522
|
}
|
|
85554
86523
|
if (name === target.name.trim()) {
|
|
85555
|
-
console.log(`${sym.ok} ${
|
|
86524
|
+
console.log(`${sym.ok} ${import_picocolors64.default.bold(target.name.trim())} already has that label; nothing to do.`);
|
|
85556
86525
|
return;
|
|
85557
86526
|
}
|
|
85558
86527
|
try {
|
|
@@ -85560,7 +86529,7 @@ async function runTokenRename(args) {
|
|
|
85560
86529
|
} catch (error2) {
|
|
85561
86530
|
throw withLoginHint(error2);
|
|
85562
86531
|
}
|
|
85563
|
-
console.log(`${sym.ok} Renamed ${
|
|
86532
|
+
console.log(`${sym.ok} Renamed ${import_picocolors64.default.dim(target.name)} → ${import_picocolors64.default.bold(name)}`);
|
|
85564
86533
|
}
|
|
85565
86534
|
async function runTokenRevoke(args) {
|
|
85566
86535
|
if (!args.id) {
|
|
@@ -85578,7 +86547,7 @@ async function runTokenRevoke(args) {
|
|
|
85578
86547
|
throw new Error(`No token with id ${args.id}. Run \`brainbase token list\` to see yours.`);
|
|
85579
86548
|
}
|
|
85580
86549
|
if (target.revoked_at) {
|
|
85581
|
-
reconcileDeadToken(target, `${
|
|
86550
|
+
reconcileDeadToken(target, `${import_picocolors64.default.bold(target.name)} is already revoked.`);
|
|
85582
86551
|
return;
|
|
85583
86552
|
}
|
|
85584
86553
|
const stored = readToken();
|
|
@@ -85588,7 +86557,7 @@ async function runTokenRevoke(args) {
|
|
|
85588
86557
|
flagHint: "Pass --yes to revoke it without a prompt."
|
|
85589
86558
|
})) {
|
|
85590
86559
|
const ok = await se({
|
|
85591
|
-
message: isLocalToken ? `Revoke ${
|
|
86560
|
+
message: isLocalToken ? `Revoke ${import_picocolors64.default.bold(target.name)} (${args.id})? This is the token this CLI is using, so it will stop working here too.` : `Revoke ${import_picocolors64.default.bold(target.name)} (${args.id})? CIs and machines using it will stop working.`,
|
|
85592
86561
|
initialValue: false
|
|
85593
86562
|
});
|
|
85594
86563
|
if (!ensureNotCancelled(ok))
|
|
@@ -85599,14 +86568,14 @@ async function runTokenRevoke(args) {
|
|
|
85599
86568
|
} catch (error2) {
|
|
85600
86569
|
if (error2 instanceof ApiError && error2.status === 404) {
|
|
85601
86570
|
if (isExpired2(target)) {
|
|
85602
|
-
reconcileDeadToken(target, `${
|
|
86571
|
+
reconcileDeadToken(target, `${import_picocolors64.default.bold(target.name)} had already expired.`);
|
|
85603
86572
|
return;
|
|
85604
86573
|
}
|
|
85605
86574
|
throw new Error(`The server reported no active token with id ${args.id}, but it listed one a moment ago. ` + "The local token has been left alone, since that key may still work. " + "If this server predates `DELETE /v1/registry/cli-tokens/{id}`, revoke from the web app instead.");
|
|
85606
86575
|
}
|
|
85607
86576
|
throw withLoginHint(error2);
|
|
85608
86577
|
}
|
|
85609
|
-
reconcileDeadToken(target, `Revoked ${
|
|
86578
|
+
reconcileDeadToken(target, `Revoked ${import_picocolors64.default.bold(target.name)}.`);
|
|
85610
86579
|
}
|
|
85611
86580
|
function reconcileDeadToken(target, headline) {
|
|
85612
86581
|
let outcome;
|
|
@@ -85640,7 +86609,7 @@ function reportLocalToken(headline, outcome) {
|
|
|
85640
86609
|
}
|
|
85641
86610
|
async function runTokenClear() {
|
|
85642
86611
|
if (!readToken()) {
|
|
85643
|
-
console.log(
|
|
86612
|
+
console.log(import_picocolors64.default.dim("No local token stored."));
|
|
85644
86613
|
return;
|
|
85645
86614
|
}
|
|
85646
86615
|
clearToken();
|
|
@@ -85740,31 +86709,31 @@ async function runToken(sub, rest2, args) {
|
|
|
85740
86709
|
function printTokenHelp() {
|
|
85741
86710
|
const out = [];
|
|
85742
86711
|
out.push("");
|
|
85743
|
-
out.push(` ${
|
|
86712
|
+
out.push(` ${import_picocolors64.default.bold("brainbase token")} ${import_picocolors64.default.dim("<command>")}`);
|
|
85744
86713
|
out.push("");
|
|
85745
|
-
out.push(` ${
|
|
85746
|
-
out.push(` ${
|
|
85747
|
-
out.push(` ${
|
|
85748
|
-
out.push(` ${
|
|
85749
|
-
out.push(` ${
|
|
86714
|
+
out.push(` ${import_picocolors64.default.cyan("create")} ${import_picocolors64.default.dim("issue a new long-lived CLI key (PAT)")}`);
|
|
86715
|
+
out.push(` ${import_picocolors64.default.cyan("list")} ${import_picocolors64.default.dim("show your tokens")}`);
|
|
86716
|
+
out.push(` ${import_picocolors64.default.cyan("rename")} ${import_picocolors64.default.dim("<id>")} ${import_picocolors64.default.dim("relabel a token by id")}`);
|
|
86717
|
+
out.push(` ${import_picocolors64.default.cyan("revoke")} ${import_picocolors64.default.dim("<id>")} ${import_picocolors64.default.dim("revoke a token by id")}`);
|
|
86718
|
+
out.push(` ${import_picocolors64.default.cyan("clear")} ${import_picocolors64.default.dim("forget the local token (does not revoke)")}`);
|
|
85750
86719
|
out.push("");
|
|
85751
|
-
out.push(` ${
|
|
85752
|
-
out.push(` ${
|
|
85753
|
-
out.push(` ${
|
|
85754
|
-
out.push(` ${
|
|
86720
|
+
out.push(` ${import_picocolors64.default.bold("create flags")}`);
|
|
86721
|
+
out.push(` ${import_picocolors64.default.cyan("--name, -n")} ${import_picocolors64.default.dim("<label>")} ${import_picocolors64.default.dim("token label (prompted if omitted)")}`);
|
|
86722
|
+
out.push(` ${import_picocolors64.default.cyan("--scopes")} ${import_picocolors64.default.dim("<list>")} ${import_picocolors64.default.dim("comma-separated; allowed: read, publish, admin")}`);
|
|
86723
|
+
out.push(` ${import_picocolors64.default.dim("default: read,publish")}`);
|
|
85755
86724
|
out.push("");
|
|
85756
|
-
out.push(` ${
|
|
85757
|
-
out.push(` ${
|
|
86725
|
+
out.push(` ${import_picocolors64.default.bold("rename flags")}`);
|
|
86726
|
+
out.push(` ${import_picocolors64.default.cyan("--name, -n")} ${import_picocolors64.default.dim("<label>")} ${import_picocolors64.default.dim("new label (prompted if omitted)")}`);
|
|
85758
86727
|
out.push("");
|
|
85759
86728
|
console.log(out.join(`
|
|
85760
86729
|
`));
|
|
85761
86730
|
}
|
|
85762
86731
|
|
|
85763
86732
|
// src/cli/integrations.ts
|
|
85764
|
-
var
|
|
86733
|
+
var import_picocolors66 = __toESM(require_picocolors(), 1);
|
|
85765
86734
|
|
|
85766
86735
|
// src/cli/integration-context.ts
|
|
85767
|
-
var
|
|
86736
|
+
var import_picocolors65 = __toESM(require_picocolors(), 1);
|
|
85768
86737
|
|
|
85769
86738
|
// src/core/integration-contexts-api.ts
|
|
85770
86739
|
var REQUEST_TIMEOUT_MS2 = 30000;
|
|
@@ -85913,7 +86882,7 @@ Both need your own \`brainbase login\` session and management rights on the
|
|
|
85913
86882
|
agent. BRAINBASE_TOKEN and the PAT saved by \`brainbase token create\` are refused.
|
|
85914
86883
|
`;
|
|
85915
86884
|
async function runIntegrationContext(cwd2, argv, options) {
|
|
85916
|
-
const { write: write3, fail:
|
|
86885
|
+
const { write: write3, fail: fail4 } = options;
|
|
85917
86886
|
const [action, ...rest2] = argv;
|
|
85918
86887
|
const parsed = parseContextArgs(rest2, "--application", "--max-lifetime", "--reason");
|
|
85919
86888
|
if (action === "help" || action === "--help" || action === "-h" || "help" in parsed) {
|
|
@@ -85922,36 +86891,36 @@ async function runIntegrationContext(cwd2, argv, options) {
|
|
|
85922
86891
|
}
|
|
85923
86892
|
if (action !== "create" && action !== "end") {
|
|
85924
86893
|
const problem = action ? `Unknown integrations context subcommand: ${sanitizeLabel(action)}.` : "Missing integrations context subcommand.";
|
|
85925
|
-
return
|
|
86894
|
+
return fail4(`${problem} ${CONTEXT_USAGE.split(`
|
|
85926
86895
|
`)[0]}`);
|
|
85927
86896
|
}
|
|
85928
86897
|
if ("error" in parsed)
|
|
85929
|
-
return
|
|
86898
|
+
return fail4(parsed.error);
|
|
85930
86899
|
const { values: values2, positionals } = parsed;
|
|
85931
86900
|
if (action === "create") {
|
|
85932
86901
|
if (positionals.length > 0)
|
|
85933
|
-
return
|
|
86902
|
+
return fail4(`Unexpected argument: ${sanitizeLabel(positionals[0])}. ${CREATE_USAGE}`);
|
|
85934
86903
|
if (values2.has("--reason"))
|
|
85935
|
-
return
|
|
86904
|
+
return fail4(`--reason is for \`context end\`. ${CREATE_USAGE}`);
|
|
85936
86905
|
const target = cloudTargetAgent(cwd2, options);
|
|
85937
86906
|
if (!target)
|
|
85938
|
-
return
|
|
86907
|
+
return fail4(NO_AGENT_MESSAGE);
|
|
85939
86908
|
if ("error" in target)
|
|
85940
|
-
return
|
|
86909
|
+
return fail4(target.error);
|
|
85941
86910
|
if (!UUID_PATTERN.test(target.agentId)) {
|
|
85942
|
-
return
|
|
86911
|
+
return fail4(`${sanitizeLabel(target.agentId)} is not an agent id. --agent takes the agent's UUID, as \`brainbase agent list\` shows it.`);
|
|
85943
86912
|
}
|
|
85944
86913
|
const agentId = target.agentId.toLowerCase();
|
|
85945
86914
|
const application = values2.get("--application");
|
|
85946
86915
|
if (application === undefined)
|
|
85947
|
-
return
|
|
86916
|
+
return fail4(`--application is required. ${CREATE_USAGE}`);
|
|
85948
86917
|
if (!APPLICATION_PATTERN.test(application)) {
|
|
85949
|
-
return
|
|
86918
|
+
return fail4(`--application must be 1-120 characters of lowercase letters, digits and . _ : / -, starting with a letter or digit (e.g. billing-sync); got "${sanitizeLabel(application)}".`);
|
|
85950
86919
|
}
|
|
85951
86920
|
const rawLifetime = values2.get("--max-lifetime");
|
|
85952
86921
|
const lifetime = rawLifetime === undefined ? DEFAULT_LIFETIME_S : parseMaxLifetime(rawLifetime);
|
|
85953
86922
|
if (typeof lifetime !== "number")
|
|
85954
|
-
return
|
|
86923
|
+
return fail4(lifetime.error);
|
|
85955
86924
|
let created;
|
|
85956
86925
|
try {
|
|
85957
86926
|
created = await integrationContextsApi.create({
|
|
@@ -85960,7 +86929,7 @@ async function runIntegrationContext(cwd2, argv, options) {
|
|
|
85960
86929
|
max_lifetime_s: lifetime
|
|
85961
86930
|
});
|
|
85962
86931
|
} catch (err) {
|
|
85963
|
-
return
|
|
86932
|
+
return fail4(`brainbase integrations context create failed: ${message(err)}`);
|
|
85964
86933
|
}
|
|
85965
86934
|
if (options.json) {
|
|
85966
86935
|
write3(JSON.stringify(created) + `
|
|
@@ -85971,24 +86940,24 @@ async function runIntegrationContext(cwd2, argv, options) {
|
|
|
85971
86940
|
return 0;
|
|
85972
86941
|
}
|
|
85973
86942
|
if (values2.has("--application") || values2.has("--max-lifetime")) {
|
|
85974
|
-
return
|
|
86943
|
+
return fail4(`--application and --max-lifetime are for \`context create\`. ${END_USAGE}`);
|
|
85975
86944
|
}
|
|
85976
86945
|
if (positionals.length !== 1)
|
|
85977
|
-
return
|
|
86946
|
+
return fail4(END_USAGE);
|
|
85978
86947
|
const contextId = positionals[0];
|
|
85979
86948
|
if (!UUID_PATTERN.test(contextId)) {
|
|
85980
|
-
return
|
|
86949
|
+
return fail4(`${sanitizeLabel(contextId)} is not a context id. Pass the context_id \`context create\` printed.`);
|
|
85981
86950
|
}
|
|
85982
86951
|
const reason = (values2.get("--reason") ?? DEFAULT_END_REASON).trim();
|
|
85983
86952
|
const reasonLength = [...reason].length;
|
|
85984
86953
|
if (reasonLength < 1 || reasonLength > MAX_REASON_LENGTH2) {
|
|
85985
|
-
return
|
|
86954
|
+
return fail4(`--reason must be 1-${MAX_REASON_LENGTH2} characters; got ${reasonLength}.`);
|
|
85986
86955
|
}
|
|
85987
86956
|
let ended;
|
|
85988
86957
|
try {
|
|
85989
86958
|
ended = await integrationContextsApi.end(contextId.toLowerCase(), reason);
|
|
85990
86959
|
} catch (err) {
|
|
85991
|
-
return
|
|
86960
|
+
return fail4(`brainbase integrations context end failed: ${message(err)}`);
|
|
85992
86961
|
}
|
|
85993
86962
|
const id = contextId.toLowerCase();
|
|
85994
86963
|
if (options.json) {
|
|
@@ -85997,7 +86966,7 @@ async function runIntegrationContext(cwd2, argv, options) {
|
|
|
85997
86966
|
return 0;
|
|
85998
86967
|
}
|
|
85999
86968
|
const state = sanitizeLabel(ended.state);
|
|
86000
|
-
write3(state === "ended" ? `${
|
|
86969
|
+
write3(state === "ended" ? `${import_picocolors65.default.green("✓")} Ended integration context ${id}. Its renewal handle and access grants no longer work.
|
|
86001
86970
|
` : `Integration context ${id} is ${state}. Its renewal handle and access grants no longer work.
|
|
86002
86971
|
`);
|
|
86003
86972
|
return 0;
|
|
@@ -86056,19 +87025,19 @@ function parseMaxLifetime(raw) {
|
|
|
86056
87025
|
function renderCreated(created, agentId, application) {
|
|
86057
87026
|
const id = sanitizeLabel(created.context_id);
|
|
86058
87027
|
const lines = [
|
|
86059
|
-
`${
|
|
86060
|
-
` ${
|
|
87028
|
+
`${import_picocolors65.default.green("✓")} Created integration context ${id}`,
|
|
87029
|
+
` ${import_picocolors65.default.dim(`agent ${agentId} · application ${application}`)}`,
|
|
86061
87030
|
"",
|
|
86062
87031
|
" Renewal handle:",
|
|
86063
87032
|
"",
|
|
86064
87033
|
` ${sanitizeLabel(created.renewal_handle)}`,
|
|
86065
87034
|
"",
|
|
86066
|
-
|
|
87035
|
+
import_picocolors65.default.yellow(" Store it now in the SDK program's secret store: it is shown only this once, and it rotates on every renewal, so the program must save the newest handle each time."),
|
|
86067
87036
|
"",
|
|
86068
87037
|
` Handle expires ${sanitizeLabel(created.renewal_expires_at ?? "unknown")}`,
|
|
86069
|
-
` Context ends ${sanitizeLabel(created.max_expires_at ?? "unknown")} ${
|
|
87038
|
+
` Context ends ${sanitizeLabel(created.max_expires_at ?? "unknown")} ${import_picocolors65.default.dim("(its maximum lifetime)")}`,
|
|
86070
87039
|
"",
|
|
86071
|
-
|
|
87040
|
+
import_picocolors65.default.dim(` End it sooner with \`brainbase integrations context end ${id}\`.`),
|
|
86072
87041
|
""
|
|
86073
87042
|
];
|
|
86074
87043
|
return lines.join(`
|
|
@@ -86105,7 +87074,7 @@ async function runIntegrations(cwd2, sub, argv, options) {
|
|
|
86105
87074
|
const write3 = options.write ?? ((s3) => process.stdout.write(s3));
|
|
86106
87075
|
const writeErr = options.writeErr ?? ((s3) => process.stderr.write(s3));
|
|
86107
87076
|
const api4 = { ...integrationsApi, ...options.api };
|
|
86108
|
-
const
|
|
87077
|
+
const fail4 = (message2) => {
|
|
86109
87078
|
if (options.json)
|
|
86110
87079
|
write3(JSON.stringify({ error: message2 }) + `
|
|
86111
87080
|
`);
|
|
@@ -86125,7 +87094,7 @@ async function runIntegrations(cwd2, sub, argv, options) {
|
|
|
86125
87094
|
agentId: options.agentId,
|
|
86126
87095
|
resolveAgentId: options.resolveAgentId,
|
|
86127
87096
|
write: write3,
|
|
86128
|
-
fail:
|
|
87097
|
+
fail: fail4
|
|
86129
87098
|
});
|
|
86130
87099
|
}
|
|
86131
87100
|
const isHelpFlag = (s3) => s3 === "--help" || s3 === "-h";
|
|
@@ -86138,7 +87107,7 @@ async function runIntegrations(cwd2, sub, argv, options) {
|
|
|
86138
87107
|
if (!sub || !known.includes(sub) && !isEffect) {
|
|
86139
87108
|
const problem = sub ? `Unknown integrations subcommand: ${sanitizeLabel(sub)}` : "Missing integrations subcommand.";
|
|
86140
87109
|
if (options.json)
|
|
86141
|
-
return
|
|
87110
|
+
return fail4(`${problem} ${USAGE.split(`
|
|
86142
87111
|
`)[0]}`);
|
|
86143
87112
|
writeErr(`${problem}
|
|
86144
87113
|
${USAGE}`);
|
|
@@ -86146,21 +87115,21 @@ ${USAGE}`);
|
|
|
86146
87115
|
}
|
|
86147
87116
|
const arg = sub === "search" ? argv.join(" ").trim() : argv[0];
|
|
86148
87117
|
if (sub !== "list" && (!arg || arg.startsWith("-") || sub !== "search" && argv.length > 1)) {
|
|
86149
|
-
return
|
|
87118
|
+
return fail4(`Usage: brainbase integrations ${sub} <${sub === "search" ? "query" : isEffect ? "app>[.<action>" : "app"}>`);
|
|
86150
87119
|
}
|
|
86151
87120
|
if (sub === "search") {
|
|
86152
87121
|
try {
|
|
86153
87122
|
const apps = await api4.searchApps(arg);
|
|
86154
87123
|
return out({ apps }, renderSearch(apps));
|
|
86155
87124
|
} catch (err) {
|
|
86156
|
-
return
|
|
87125
|
+
return fail4(`brainbase integrations search failed: ${message2(err)}`);
|
|
86157
87126
|
}
|
|
86158
87127
|
}
|
|
86159
87128
|
const target = cloudTargetAgent(cwd2, options);
|
|
86160
87129
|
if (!target)
|
|
86161
|
-
return
|
|
87130
|
+
return fail4(NO_AGENT_MESSAGE);
|
|
86162
87131
|
if ("error" in target)
|
|
86163
|
-
return
|
|
87132
|
+
return fail4(target.error);
|
|
86164
87133
|
const { agentId } = target;
|
|
86165
87134
|
try {
|
|
86166
87135
|
switch (sub) {
|
|
@@ -86180,7 +87149,7 @@ ${USAGE}`);
|
|
|
86180
87149
|
return await setEffect(agentId, sub, arg);
|
|
86181
87150
|
}
|
|
86182
87151
|
} catch (err) {
|
|
86183
|
-
return
|
|
87152
|
+
return fail4(`brainbase integrations ${sub} failed: ${message2(err)}`);
|
|
86184
87153
|
}
|
|
86185
87154
|
async function list3(agentId2) {
|
|
86186
87155
|
const [accounts, noAuthApps, permissions] = await Promise.all([
|
|
@@ -86233,40 +87202,40 @@ ${USAGE}`);
|
|
|
86233
87202
|
if (needsAccount(app))
|
|
86234
87203
|
return await connect2(agentId2, slug, app);
|
|
86235
87204
|
const added = await api4.addNoAuthApp(agentId2, slug);
|
|
86236
|
-
return out({ app: added.appSlug, name: added.name, needs_account: false, added: true }, `${
|
|
87205
|
+
return out({ app: added.appSlug, name: added.name, needs_account: false, added: true }, `${import_picocolors66.default.green("✓")} Added ${import_picocolors66.default.bold(label2(added.name))}. It needs no account; your agent can use it on its next turn.
|
|
86237
87206
|
`);
|
|
86238
87207
|
}
|
|
86239
87208
|
async function connect2(agentId2, slug, known2) {
|
|
86240
87209
|
const app = known2 ?? await api4.getApp(slug);
|
|
86241
87210
|
const name = label2(app.name || slug);
|
|
86242
87211
|
if (!needsAccount(app)) {
|
|
86243
|
-
return
|
|
87212
|
+
return fail4(`${name} needs no account. Run brainbase integrations add ${label2(slug)} instead.`);
|
|
86244
87213
|
}
|
|
86245
87214
|
const before2 = new Set((await api4.listAccounts(agentId2)).map((a3) => a3.id));
|
|
86246
87215
|
const token = await api4.createConnectToken(agentId2);
|
|
86247
87216
|
const url2 = connectUrl(token.connect_link_url, slug);
|
|
86248
87217
|
if (!url2)
|
|
86249
|
-
return
|
|
87218
|
+
return fail4("The server returned an unusable connect link.");
|
|
86250
87219
|
if (options.json) {
|
|
86251
87220
|
write3(JSON.stringify({ app: slug, url: url2, expires_at: token.expires_at ?? null }) + `
|
|
86252
87221
|
`);
|
|
86253
87222
|
return 0;
|
|
86254
87223
|
}
|
|
86255
87224
|
const interactive = options.interactive ?? isInteractive();
|
|
86256
|
-
write3(`Open this link to connect ${
|
|
87225
|
+
write3(`Open this link to connect ${import_picocolors66.default.bold(name)}:
|
|
86257
87226
|
|
|
86258
|
-
${
|
|
87227
|
+
${import_picocolors66.default.cyan(url2)}
|
|
86259
87228
|
|
|
86260
87229
|
`);
|
|
86261
|
-
write3(
|
|
87230
|
+
write3(import_picocolors66.default.dim(`Anyone with this link can connect an account to this agent until it expires, so do not share it.
|
|
86262
87231
|
`));
|
|
86263
87232
|
if (!options.noOpen && interactive) {
|
|
86264
|
-
write3(
|
|
87233
|
+
write3(import_picocolors66.default.dim(`Opening your browser…
|
|
86265
87234
|
`));
|
|
86266
87235
|
(options.openUrl ?? openInBrowser)(url2);
|
|
86267
87236
|
}
|
|
86268
87237
|
if (options.noWait) {
|
|
86269
|
-
write3(
|
|
87238
|
+
write3(import_picocolors66.default.dim("Not waiting. Run `brainbase integrations list` to see when it is connected.\n"));
|
|
86270
87239
|
return 0;
|
|
86271
87240
|
}
|
|
86272
87241
|
const controller = new AbortController;
|
|
@@ -86299,7 +87268,7 @@ ${USAGE}`);
|
|
|
86299
87268
|
if (spinner2)
|
|
86300
87269
|
spinner2.stop(text3, ok ? 0 : 2);
|
|
86301
87270
|
else if (ok)
|
|
86302
|
-
write3(`${
|
|
87271
|
+
write3(`${import_picocolors66.default.green("✔")} ${text3}
|
|
86303
87272
|
`);
|
|
86304
87273
|
else
|
|
86305
87274
|
writeErr(`${text3}
|
|
@@ -86323,27 +87292,27 @@ ${USAGE}`);
|
|
|
86323
87292
|
async function disconnect2(agentId2, slug) {
|
|
86324
87293
|
const accounts = (await api4.listAccounts(agentId2)).filter((a3) => isCredentialed(a3) && a3.app?.nameSlug === slug);
|
|
86325
87294
|
if (accounts.length === 0)
|
|
86326
|
-
return
|
|
87295
|
+
return fail4(`No connected ${label2(slug)} account on this agent.`);
|
|
86327
87296
|
let account = accounts[0];
|
|
86328
87297
|
if (options.account !== undefined) {
|
|
86329
87298
|
const chosen = accounts.find((a3) => a3.id === options.account);
|
|
86330
87299
|
if (!chosen)
|
|
86331
|
-
return
|
|
87300
|
+
return fail4(`${label2(options.account)} is not a ${label2(slug)} account on this agent. Its accounts: ${describeAccounts(accounts)}.`);
|
|
86332
87301
|
account = chosen;
|
|
86333
87302
|
} else if (accounts.length > 1) {
|
|
86334
|
-
return
|
|
87303
|
+
return fail4(`This agent has ${accounts.length} ${label2(slug)} accounts. Pick one with --account <id>: ${describeAccounts(accounts)}.`);
|
|
86335
87304
|
}
|
|
86336
87305
|
if (options.json && !options.yes) {
|
|
86337
|
-
return
|
|
87306
|
+
return fail4("`brainbase integrations disconnect --json` never prompts. Pass --yes to disconnect without one.");
|
|
86338
87307
|
}
|
|
86339
87308
|
const confirm = options.confirmDisconnect ?? promptForDisconnect;
|
|
86340
87309
|
const accountLabel = account.name ? `${label2(account.name)} (${account.id})` : account.id;
|
|
86341
87310
|
if (!await confirm(`Disconnect ${label2(slug)} account ${accountLabel}? Everyone using this agent loses it.`, options.yes)) {
|
|
86342
|
-
return out({ app: slug, account_id: account.id, disconnected: false, outcome: "declined" }, ` ${
|
|
87311
|
+
return out({ app: slug, account_id: account.id, disconnected: false, outcome: "declined" }, ` ${import_picocolors66.default.dim("Left alone.")}
|
|
86343
87312
|
`);
|
|
86344
87313
|
}
|
|
86345
87314
|
await api4.deleteAccount(agentId2, account.id);
|
|
86346
|
-
return out({ app: slug, account_id: account.id, disconnected: true }, `${
|
|
87315
|
+
return out({ app: slug, account_id: account.id, disconnected: true }, `${import_picocolors66.default.green("✓")} Disconnected ${import_picocolors66.default.bold(label2(slug))} account ${accountLabel}.
|
|
86347
87316
|
`);
|
|
86348
87317
|
}
|
|
86349
87318
|
async function remove2(agentId2, slug) {
|
|
@@ -86351,25 +87320,25 @@ ${USAGE}`);
|
|
|
86351
87320
|
if (!installed.some((a3) => a3.appSlug === slug)) {
|
|
86352
87321
|
const accounts = await api4.listAccounts(agentId2);
|
|
86353
87322
|
if (accounts.some((a3) => isCredentialed(a3) && a3.app?.nameSlug === slug)) {
|
|
86354
|
-
return
|
|
87323
|
+
return fail4(`${label2(slug)} is connected with an account. Run brainbase integrations disconnect ${label2(slug)} instead.`);
|
|
86355
87324
|
}
|
|
86356
|
-
return
|
|
87325
|
+
return fail4(`${label2(slug)} is not installed on this agent.`);
|
|
86357
87326
|
}
|
|
86358
87327
|
await api4.removeNoAuthApp(agentId2, slug);
|
|
86359
|
-
return out({ app: slug, removed: true }, `${
|
|
87328
|
+
return out({ app: slug, removed: true }, `${import_picocolors66.default.green("✓")} Removed ${import_picocolors66.default.bold(label2(slug))}.
|
|
86360
87329
|
`);
|
|
86361
87330
|
}
|
|
86362
87331
|
async function setEffect(agentId2, effect, raw) {
|
|
86363
87332
|
const [app, action] = raw.split(/\.(.*)/s, 2);
|
|
86364
87333
|
if (!app || action === "")
|
|
86365
|
-
return
|
|
87334
|
+
return fail4(`Usage: brainbase integrations ${effect} <app>[.<action>]`);
|
|
86366
87335
|
if (!permissionToken(app) || action !== undefined && !permissionToken(action)) {
|
|
86367
|
-
return
|
|
87336
|
+
return fail4(`${label2(raw)} is not an app or action name. Use the key \`brainbase integrations actions <app>\` shows.`);
|
|
86368
87337
|
}
|
|
86369
87338
|
const capability = pattern(appSlug(app), action);
|
|
86370
87339
|
await api4.setPermission(agentId2, capability, effect);
|
|
86371
87340
|
const scope = action ? `${label2(action)} on ${label2(app)}` : `every ${label2(app)} action without its own rule`;
|
|
86372
|
-
return out({ capability_pattern: capability, effect }, `${
|
|
87341
|
+
return out({ capability_pattern: capability, effect }, `${import_picocolors66.default.green("✓")} ${capability} → ${import_picocolors66.default.bold(effect)} ${import_picocolors66.default.dim(`(${scope})`)}
|
|
86373
87342
|
`);
|
|
86374
87343
|
}
|
|
86375
87344
|
}
|
|
@@ -86422,27 +87391,27 @@ async function promptForDisconnect(question, yes) {
|
|
|
86422
87391
|
return ensureNotCancelled(answer);
|
|
86423
87392
|
}
|
|
86424
87393
|
var EFFECT_COLOR = {
|
|
86425
|
-
allow:
|
|
86426
|
-
ask:
|
|
86427
|
-
deny:
|
|
87394
|
+
allow: import_picocolors66.default.green,
|
|
87395
|
+
ask: import_picocolors66.default.yellow,
|
|
87396
|
+
deny: import_picocolors66.default.red
|
|
86428
87397
|
};
|
|
86429
87398
|
function effectLabel(effect, width = 0) {
|
|
86430
|
-
return (EFFECT_COLOR[effect] ??
|
|
87399
|
+
return (EFFECT_COLOR[effect] ?? import_picocolors66.default.dim)(sanitizeLabel(effect).padEnd(width));
|
|
86431
87400
|
}
|
|
86432
87401
|
function renderList(rows, permissions) {
|
|
86433
87402
|
const lines = [""];
|
|
86434
87403
|
if (!permissions.permissionsAvailable) {
|
|
86435
|
-
lines.push(
|
|
87404
|
+
lines.push(import_picocolors66.default.yellow(" Integrations only work on Kafka agents for now; this agent cannot use them."), "");
|
|
86436
87405
|
}
|
|
86437
87406
|
if (rows.length === 0) {
|
|
86438
|
-
lines.push(
|
|
86439
|
-
lines.push(
|
|
87407
|
+
lines.push(import_picocolors66.default.dim(" No integrations on this agent."));
|
|
87408
|
+
lines.push(import_picocolors66.default.dim(" Find one with `brainbase integrations search <query>`, then `brainbase integrations add <app>`."), "");
|
|
86440
87409
|
return lines.join(`
|
|
86441
87410
|
`);
|
|
86442
87411
|
}
|
|
86443
87412
|
for (const row of rows) {
|
|
86444
87413
|
const healthy = row.accounts.every((a3) => a3.healthy);
|
|
86445
|
-
const mark = healthy ?
|
|
87414
|
+
const mark = healthy ? import_picocolors66.default.green("✓") : import_picocolors66.default.yellow("!");
|
|
86446
87415
|
const bits = [sanitizeLabel(row.name)];
|
|
86447
87416
|
if (!row.needs_account)
|
|
86448
87417
|
bits.push("no account needed");
|
|
@@ -86450,35 +87419,35 @@ function renderList(rows, permissions) {
|
|
|
86450
87419
|
bits.push(`account ${account.name ? sanitizeLabel(account.name) : account.id}${account.healthy ? "" : " (needs reconnecting)"}`);
|
|
86451
87420
|
}
|
|
86452
87421
|
const effect = row.effect ?? permissions.defaultEffect;
|
|
86453
|
-
lines.push(` ${mark} ${
|
|
87422
|
+
lines.push(` ${mark} ${import_picocolors66.default.bold(sanitizeLabel(row.app))} ${import_picocolors66.default.dim(bits.join(" · "))} ${effectLabel(effect)}${row.effect ? "" : import_picocolors66.default.dim(" (default)")}`);
|
|
86454
87423
|
}
|
|
86455
|
-
lines.push("",
|
|
87424
|
+
lines.push("", import_picocolors66.default.dim(" Run `brainbase integrations actions <app>` to see and set per-action permissions."), "");
|
|
86456
87425
|
return lines.join(`
|
|
86457
87426
|
`);
|
|
86458
87427
|
}
|
|
86459
87428
|
function renderSearch(apps) {
|
|
86460
87429
|
if (apps.length === 0)
|
|
86461
|
-
return
|
|
87430
|
+
return import_picocolors66.default.dim("No apps match.") + `
|
|
86462
87431
|
`;
|
|
86463
87432
|
const lines = [""];
|
|
86464
87433
|
for (const app of apps) {
|
|
86465
|
-
const
|
|
86466
|
-
lines.push(` ${
|
|
87434
|
+
const hint2 = needsAccount(app) ? "" : import_picocolors66.default.dim(" no account needed");
|
|
87435
|
+
lines.push(` ${import_picocolors66.default.bold(sanitizeLabel(app.nameSlug))} ${sanitizeLabel(app.name)}${hint2}`);
|
|
86467
87436
|
}
|
|
86468
|
-
lines.push("",
|
|
87437
|
+
lines.push("", import_picocolors66.default.dim(" Add one with `brainbase integrations add <app>`."), "");
|
|
86469
87438
|
return lines.join(`
|
|
86470
87439
|
`);
|
|
86471
87440
|
}
|
|
86472
87441
|
function renderActions(slug, rows) {
|
|
86473
87442
|
if (rows.length === 0)
|
|
86474
|
-
return
|
|
87443
|
+
return import_picocolors66.default.dim(`No actions found for ${sanitizeLabel(slug)}.`) + `
|
|
86475
87444
|
`;
|
|
86476
87445
|
const lines = [""];
|
|
86477
87446
|
for (const row of rows) {
|
|
86478
|
-
const source =
|
|
86479
|
-
lines.push(` ${effectLabel(row.effect, 5)} ${source} ${
|
|
87447
|
+
const source = import_picocolors66.default.dim((row.source === "action" ? "" : `(${row.source})`).padEnd(9));
|
|
87448
|
+
lines.push(` ${effectLabel(row.effect, 5)} ${source} ${import_picocolors66.default.bold(sanitizeLabel(row.key))} ${import_picocolors66.default.dim(sanitizeLabel(row.name))}`);
|
|
86480
87449
|
}
|
|
86481
|
-
lines.push("",
|
|
87450
|
+
lines.push("", import_picocolors66.default.dim(` Change one with \`brainbase integrations allow|ask|deny ${sanitizeLabel(slug)}.<action>\`, or the whole app with \`… ${sanitizeLabel(slug)}\`.`), "");
|
|
86482
87451
|
return lines.join(`
|
|
86483
87452
|
`);
|
|
86484
87453
|
}
|
|
@@ -86542,14 +87511,14 @@ async function waitForAccount(agentId, slug, before2, options) {
|
|
|
86542
87511
|
}
|
|
86543
87512
|
|
|
86544
87513
|
// src/cli/task.ts
|
|
86545
|
-
var
|
|
87514
|
+
var import_picocolors72 = __toESM(require_picocolors(), 1);
|
|
86546
87515
|
|
|
86547
87516
|
// src/cli/task-create.ts
|
|
86548
|
-
var
|
|
87517
|
+
var import_picocolors68 = __toESM(require_picocolors(), 1);
|
|
86549
87518
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
86550
87519
|
|
|
86551
87520
|
// src/cli/task-update.ts
|
|
86552
|
-
var
|
|
87521
|
+
var import_picocolors67 = __toESM(require_picocolors(), 1);
|
|
86553
87522
|
var TASK_UPDATE_USAGE = "brainbase task update <task-id> [--title <text> | --clear-title] [--metadata key=value]... [--unset-metadata <key>]... [--clear-metadata] [--model <id> | --clear-model] [--json]";
|
|
86554
87523
|
var TITLE_MAX = 200;
|
|
86555
87524
|
var MODEL_UNSUPPORTED = "This control plane does not support changing a task's model yet.";
|
|
@@ -86688,25 +87657,25 @@ function applyLabelEdit(current, edit) {
|
|
|
86688
87657
|
}
|
|
86689
87658
|
function format(task) {
|
|
86690
87659
|
const lines = [""];
|
|
86691
|
-
const title = task.title?.trim() ? sanitizeLabel(task.title) :
|
|
86692
|
-
lines.push(` ${
|
|
87660
|
+
const title = task.title?.trim() ? sanitizeLabel(task.title) : import_picocolors67.default.dim("(untitled)");
|
|
87661
|
+
lines.push(` ${import_picocolors67.default.green("updated")} ${import_picocolors67.default.bold(title)}`);
|
|
86693
87662
|
lines.push("");
|
|
86694
|
-
lines.push(` ${
|
|
87663
|
+
lines.push(` ${import_picocolors67.default.dim("task")} ${sanitizeLabel(task.id)}`);
|
|
86695
87664
|
if (task.model !== undefined) {
|
|
86696
|
-
const model = task.model?.trim() ? sanitizeLabel(task.model) :
|
|
86697
|
-
lines.push(` ${
|
|
87665
|
+
const model = task.model?.trim() ? sanitizeLabel(task.model) : import_picocolors67.default.dim("agent default");
|
|
87666
|
+
lines.push(` ${import_picocolors67.default.dim("model")} ${model}`);
|
|
86698
87667
|
}
|
|
86699
87668
|
const metadata = Object.entries(task.metadata ?? {});
|
|
86700
87669
|
lines.push("");
|
|
86701
|
-
lines.push(` ${
|
|
87670
|
+
lines.push(` ${import_picocolors67.default.bold(import_picocolors67.default.dim("METADATA"))}`);
|
|
86702
87671
|
if (metadata.length === 0) {
|
|
86703
|
-
lines.push(` ${
|
|
87672
|
+
lines.push(` ${import_picocolors67.default.dim("none")}`);
|
|
86704
87673
|
}
|
|
86705
87674
|
for (const [key2, value2] of metadata) {
|
|
86706
|
-
lines.push(` ${
|
|
87675
|
+
lines.push(` ${import_picocolors67.default.dim(sanitizeLabel(key2))} ${sanitizeLabel(value2)}`);
|
|
86707
87676
|
}
|
|
86708
87677
|
lines.push("");
|
|
86709
|
-
lines.push(` ${
|
|
87678
|
+
lines.push(` ${import_picocolors67.default.dim("read it with")} ${import_picocolors67.default.cyan(`brainbase task get ${sanitizeLabel(task.id)}`)}`, "");
|
|
86710
87679
|
return lines.join(`
|
|
86711
87680
|
`);
|
|
86712
87681
|
}
|
|
@@ -86844,24 +87813,24 @@ async function waitForCreatedTask(created, options, dependencies, version2) {
|
|
|
86844
87813
|
return;
|
|
86845
87814
|
}
|
|
86846
87815
|
if (outcome.kind === "timeout") {
|
|
86847
|
-
console.log(
|
|
87816
|
+
console.log(import_picocolors68.default.yellow(`Timed out after ${options.timeoutSeconds}s with the task still ${status}.`));
|
|
86848
87817
|
return;
|
|
86849
87818
|
}
|
|
86850
87819
|
if (outcome.kind === "interrupted") {
|
|
86851
|
-
console.log(
|
|
87820
|
+
console.log(import_picocolors68.default.yellow("Interrupted. The task is still running."));
|
|
86852
87821
|
return;
|
|
86853
87822
|
}
|
|
86854
|
-
console.log(code === 0 ?
|
|
87823
|
+
console.log(code === 0 ? import_picocolors68.default.green("Task completed.") : import_picocolors68.default.red(`Task finished as ${status}.`));
|
|
86855
87824
|
} finally {
|
|
86856
87825
|
process.removeListener("SIGINT", onSigint);
|
|
86857
87826
|
}
|
|
86858
87827
|
}
|
|
86859
87828
|
|
|
86860
87829
|
// src/cli/task-get.ts
|
|
86861
|
-
var
|
|
87830
|
+
var import_picocolors70 = __toESM(require_picocolors(), 1);
|
|
86862
87831
|
|
|
86863
87832
|
// src/cli/task-list.ts
|
|
86864
|
-
var
|
|
87833
|
+
var import_picocolors69 = __toESM(require_picocolors(), 1);
|
|
86865
87834
|
|
|
86866
87835
|
// src/core/agent-names.ts
|
|
86867
87836
|
async function agentNames(ids) {
|
|
@@ -86926,29 +87895,29 @@ function labelFilter(options) {
|
|
|
86926
87895
|
function formatTaskList(tasks, names, agentId, interfaceId, labelFiltered = false) {
|
|
86927
87896
|
const lines = [""];
|
|
86928
87897
|
if (tasks.length === 0 && labelFiltered) {
|
|
86929
|
-
lines.push(` ${
|
|
87898
|
+
lines.push(` ${import_picocolors69.default.dim("No tasks carry every label given with --metadata.")}`, "");
|
|
86930
87899
|
return lines.join(`
|
|
86931
87900
|
`);
|
|
86932
87901
|
}
|
|
86933
87902
|
if (tasks.length === 0 && interfaceId) {
|
|
86934
87903
|
const id = sanitizeLabel(interfaceId);
|
|
86935
|
-
lines.push(` ${
|
|
87904
|
+
lines.push(` ${import_picocolors69.default.dim(`No build conversations for interface ${id}.`)}`, "", ` ${import_picocolors69.default.dim("start one with")} ${import_picocolors69.default.cyan(`brainbase interface build ${id} "..."`)}`, "");
|
|
86936
87905
|
return lines.join(`
|
|
86937
87906
|
`);
|
|
86938
87907
|
}
|
|
86939
87908
|
if (tasks.length === 0) {
|
|
86940
|
-
lines.push(` ${
|
|
87909
|
+
lines.push(` ${import_picocolors69.default.dim(agentId ? `No tasks for agent ${agentId}.` : "No tasks yet.")}`, "", ` ${import_picocolors69.default.dim("start one with")} ${import_picocolors69.default.cyan('brainbase task create --message "..."')}`, "");
|
|
86941
87910
|
return lines.join(`
|
|
86942
87911
|
`);
|
|
86943
87912
|
}
|
|
86944
87913
|
for (const task of tasks) {
|
|
86945
|
-
const title = sanitizeLabel(task.title ?? "").trim() ||
|
|
86946
|
-
lines.push(` ${statusLabel(task.status)} ${
|
|
86947
|
-
lines.push(` ${
|
|
86948
|
-
lines.push(` ${
|
|
87914
|
+
const title = sanitizeLabel(task.title ?? "").trim() || import_picocolors69.default.dim("(untitled)");
|
|
87915
|
+
lines.push(` ${statusLabel(task.status)} ${import_picocolors69.default.bold(title)}`);
|
|
87916
|
+
lines.push(` ${import_picocolors69.default.dim(sanitizeLabel(task.id))}`);
|
|
87917
|
+
lines.push(` ${import_picocolors69.default.dim(`agent ${agentLabel(task.agent_id, names)} · created ${sanitizeLabel(task.created_at)}`)}`);
|
|
86949
87918
|
lines.push("");
|
|
86950
87919
|
}
|
|
86951
|
-
lines.push(` ${
|
|
87920
|
+
lines.push(` ${import_picocolors69.default.dim("inspect one with")} ${import_picocolors69.default.cyan("brainbase task get <id>")}`, "");
|
|
86952
87921
|
return lines.join(`
|
|
86953
87922
|
`);
|
|
86954
87923
|
}
|
|
@@ -86956,16 +87925,16 @@ function statusLabel(status) {
|
|
|
86956
87925
|
const padded = sanitizeLabel(status).padEnd(14);
|
|
86957
87926
|
switch (status) {
|
|
86958
87927
|
case "success":
|
|
86959
|
-
return
|
|
87928
|
+
return import_picocolors69.default.green(padded);
|
|
86960
87929
|
case "fail":
|
|
86961
|
-
return
|
|
87930
|
+
return import_picocolors69.default.red(padded);
|
|
86962
87931
|
case "need_more_info":
|
|
86963
|
-
return
|
|
87932
|
+
return import_picocolors69.default.yellow(padded);
|
|
86964
87933
|
case "running":
|
|
86965
87934
|
case "initializing":
|
|
86966
|
-
return
|
|
87935
|
+
return import_picocolors69.default.cyan(padded);
|
|
86967
87936
|
default:
|
|
86968
|
-
return
|
|
87937
|
+
return import_picocolors69.default.dim(padded);
|
|
86969
87938
|
}
|
|
86970
87939
|
}
|
|
86971
87940
|
|
|
@@ -86999,60 +87968,60 @@ async function readEvalRuns(task) {
|
|
|
86999
87968
|
}
|
|
87000
87969
|
function format2(task, evals, names) {
|
|
87001
87970
|
const lines = [""];
|
|
87002
|
-
const title = sanitizeLabel(task.title ?? "").trim() ||
|
|
87971
|
+
const title = sanitizeLabel(task.title ?? "").trim() || import_picocolors70.default.dim("(untitled)");
|
|
87003
87972
|
const id = sanitizeLabel(task.id);
|
|
87004
|
-
lines.push(` ${statusLabel(task.status)} ${
|
|
87973
|
+
lines.push(` ${statusLabel(task.status)} ${import_picocolors70.default.bold(title)}`);
|
|
87005
87974
|
lines.push("");
|
|
87006
|
-
lines.push(` ${
|
|
87007
|
-
lines.push(` ${
|
|
87975
|
+
lines.push(` ${import_picocolors70.default.dim("task")} ${id}`);
|
|
87976
|
+
lines.push(` ${import_picocolors70.default.dim("agent")} ${agentLabel(task.agent_id, names)}`);
|
|
87008
87977
|
if (task.model !== undefined) {
|
|
87009
|
-
const model = task.model?.trim() ? sanitizeLabel(task.model) :
|
|
87010
|
-
lines.push(` ${
|
|
87978
|
+
const model = task.model?.trim() ? sanitizeLabel(task.model) : import_picocolors70.default.dim("agent default");
|
|
87979
|
+
lines.push(` ${import_picocolors70.default.dim("model")} ${model}`);
|
|
87011
87980
|
}
|
|
87012
|
-
lines.push(` ${
|
|
87981
|
+
lines.push(` ${import_picocolors70.default.dim("created")} ${sanitizeLabel(task.created_at)}`);
|
|
87013
87982
|
if (task.parent_task_id) {
|
|
87014
|
-
lines.push(` ${
|
|
87983
|
+
lines.push(` ${import_picocolors70.default.dim("parent")} ${sanitizeLabel(task.parent_task_id)}`);
|
|
87015
87984
|
}
|
|
87016
87985
|
if (task.machine_id) {
|
|
87017
87986
|
const size2 = task.machine_size ? ` (size ${sanitizeLabel(task.machine_size)})` : "";
|
|
87018
|
-
lines.push(` ${
|
|
87987
|
+
lines.push(` ${import_picocolors70.default.dim("machine")} ${sanitizeLabel(task.machine_id)}${size2}`);
|
|
87019
87988
|
}
|
|
87020
87989
|
if (task.sandbox_id)
|
|
87021
|
-
lines.push(` ${
|
|
87990
|
+
lines.push(` ${import_picocolors70.default.dim("sandbox")} ${sanitizeLabel(task.sandbox_id)}`);
|
|
87022
87991
|
const [failure, ...failureRest] = sanitizeLines(failureSummary(task) ?? "").filter((line2) => line2.trim());
|
|
87023
87992
|
if (failure) {
|
|
87024
87993
|
const label3 = " failure ";
|
|
87025
87994
|
lines.push("");
|
|
87026
|
-
lines.push(` ${
|
|
87995
|
+
lines.push(` ${import_picocolors70.default.red("failure")} ${failure}`);
|
|
87027
87996
|
for (const line2 of failureRest)
|
|
87028
87997
|
lines.push(`${" ".repeat(label3.length)}${line2}`);
|
|
87029
87998
|
}
|
|
87030
87999
|
const metadata = Object.entries(task.metadata ?? {});
|
|
87031
88000
|
if (metadata.length > 0) {
|
|
87032
88001
|
lines.push("");
|
|
87033
|
-
lines.push(` ${
|
|
88002
|
+
lines.push(` ${import_picocolors70.default.bold(import_picocolors70.default.dim("METADATA"))}`);
|
|
87034
88003
|
for (const [key2, value2] of metadata) {
|
|
87035
|
-
lines.push(` ${
|
|
88004
|
+
lines.push(` ${import_picocolors70.default.dim(sanitizeLabel(key2))} ${sanitizeLabel(String(value2))}`);
|
|
87036
88005
|
}
|
|
87037
88006
|
}
|
|
87038
88007
|
lines.push("");
|
|
87039
|
-
lines.push(` ${
|
|
88008
|
+
lines.push(` ${import_picocolors70.default.bold(import_picocolors70.default.dim("EVAL VERDICTS"))}`);
|
|
87040
88009
|
if (evals.unavailable) {
|
|
87041
|
-
lines.push(` ${
|
|
88010
|
+
lines.push(` ${import_picocolors70.default.dim(sanitizeLabel(evals.unavailable))}`);
|
|
87042
88011
|
} else if (evals.runs.length === 0) {
|
|
87043
|
-
lines.push(` ${
|
|
88012
|
+
lines.push(` ${import_picocolors70.default.dim("none")}`);
|
|
87044
88013
|
} else {
|
|
87045
88014
|
for (const run of evals.runs) {
|
|
87046
|
-
const verdict = run.passed === true ?
|
|
88015
|
+
const verdict = run.passed === true ? import_picocolors70.default.green("pass") : run.passed === false ? import_picocolors70.default.red("fail") : import_picocolors70.default.dim(sanitizeLabel(run.status));
|
|
87047
88016
|
lines.push(` ${verdict} ${sanitizeLabel(run.eval_slug ?? run.eval_id)}`);
|
|
87048
88017
|
for (const line2 of sanitizeLines(run.reasoning ?? "")) {
|
|
87049
88018
|
if (line2.trim())
|
|
87050
|
-
lines.push(` ${
|
|
88019
|
+
lines.push(` ${import_picocolors70.default.dim(line2)}`);
|
|
87051
88020
|
}
|
|
87052
88021
|
}
|
|
87053
88022
|
}
|
|
87054
88023
|
lines.push("");
|
|
87055
|
-
lines.push(` ${
|
|
88024
|
+
lines.push(` ${import_picocolors70.default.dim("read its transcript with")} ${import_picocolors70.default.cyan(`brainbase task logs ${id}`)}`, "");
|
|
87056
88025
|
return lines.join(`
|
|
87057
88026
|
`);
|
|
87058
88027
|
}
|
|
@@ -87069,7 +88038,7 @@ function failureSummary(task) {
|
|
|
87069
88038
|
}
|
|
87070
88039
|
|
|
87071
88040
|
// src/cli/task-logs.ts
|
|
87072
|
-
var
|
|
88041
|
+
var import_picocolors71 = __toESM(require_picocolors(), 1);
|
|
87073
88042
|
|
|
87074
88043
|
// src/core/task-events.ts
|
|
87075
88044
|
var DEFAULT_RETRY_BUDGET_MS = 60000;
|
|
@@ -87352,14 +88321,14 @@ async function runTaskLogs(taskId, options = {}, dependencies = {}) {
|
|
|
87352
88321
|
console.log(renderEvent(event, messages));
|
|
87353
88322
|
}
|
|
87354
88323
|
if (ordered.length === 0) {
|
|
87355
|
-
console.log(
|
|
88324
|
+
console.log(import_picocolors71.default.dim("No events for this task yet."));
|
|
87356
88325
|
}
|
|
87357
88326
|
}
|
|
87358
88327
|
async function followTranscript(taskId, options, dependencies) {
|
|
87359
88328
|
const backfill = options.limit === undefined ? "" : `?backfill=${options.limit}`;
|
|
87360
88329
|
const { url: url2, resolveBearer } = await masStreamTarget(`/tasks/${encodeURIComponent(taskId)}/events/stream${backfill}`);
|
|
87361
88330
|
if (!options.json) {
|
|
87362
|
-
console.log(
|
|
88331
|
+
console.log(import_picocolors71.default.dim(`Following task ${taskId} — Ctrl-C to stop.`));
|
|
87363
88332
|
}
|
|
87364
88333
|
const setExitCode = dependencies.setExitCode ?? ((code) => process.exitCode = code);
|
|
87365
88334
|
const controller = new AbortController;
|
|
@@ -87401,13 +88370,13 @@ async function followTranscript(taskId, options, dependencies) {
|
|
|
87401
88370
|
} else if (options.json) {
|
|
87402
88371
|
console.log(JSON.stringify(frame));
|
|
87403
88372
|
} else {
|
|
87404
|
-
console.log(
|
|
88373
|
+
console.log(import_picocolors71.default.dim(frame.type));
|
|
87405
88374
|
}
|
|
87406
88375
|
},
|
|
87407
88376
|
onOpen: () => settle.noteFrame(),
|
|
87408
88377
|
onReconnect: (reason) => {
|
|
87409
88378
|
settle.noteDisconnected();
|
|
87410
|
-
console.error(
|
|
88379
|
+
console.error(import_picocolors71.default.dim(`reconnecting — ${reason}`));
|
|
87411
88380
|
}
|
|
87412
88381
|
});
|
|
87413
88382
|
if (interruptCode !== undefined)
|
|
@@ -88085,78 +89054,78 @@ ${didYouMean(sub, ["create", "list", "get", "logs", "send", "stop", "update", "d
|
|
|
88085
89054
|
function printHelp5() {
|
|
88086
89055
|
const out = [];
|
|
88087
89056
|
out.push("");
|
|
88088
|
-
out.push(` ${
|
|
89057
|
+
out.push(` ${import_picocolors72.default.bold("brainbase task")} ${import_picocolors72.default.dim("<sub> [options]")}`);
|
|
88089
89058
|
out.push("");
|
|
88090
|
-
out.push(` ${
|
|
88091
|
-
out.push(` ${
|
|
88092
|
-
out.push(` ${
|
|
88093
|
-
out.push(` ${
|
|
88094
|
-
out.push(` ${
|
|
88095
|
-
out.push(` ${
|
|
88096
|
-
out.push(` ${
|
|
88097
|
-
out.push(` ${
|
|
89059
|
+
out.push(` ${import_picocolors72.default.cyan("create")} ${import_picocolors72.default.dim("--message <text>")} ${import_picocolors72.default.dim("create a task and start its first run")}`);
|
|
89060
|
+
out.push(` ${import_picocolors72.default.cyan("list | ls")} ${import_picocolors72.default.dim("recent tasks you can reach (--json for scripts)")}`);
|
|
89061
|
+
out.push(` ${import_picocolors72.default.cyan("get")} ${import_picocolors72.default.dim("<task-id>")} ${import_picocolors72.default.dim("one task: status, agent, machine, eval verdicts")}`);
|
|
89062
|
+
out.push(` ${import_picocolors72.default.cyan("logs")} ${import_picocolors72.default.dim("<task-id> [--follow]")} ${import_picocolors72.default.dim("one line per event in the task's transcript, or tail it live")}`);
|
|
89063
|
+
out.push(` ${import_picocolors72.default.cyan("send")} ${import_picocolors72.default.dim("<task-id> <message>")} ${import_picocolors72.default.dim("send a follow-up, including while the agent is running")}`);
|
|
89064
|
+
out.push(` ${import_picocolors72.default.cyan("stop")} ${import_picocolors72.default.dim("<task-id>")} ${import_picocolors72.default.dim("stop execution and cancel pending follow-ups, retaining their text")}`);
|
|
89065
|
+
out.push(` ${import_picocolors72.default.cyan("update")} ${import_picocolors72.default.dim("<task-id>")} ${import_picocolors72.default.dim("rename a task, change its metadata labels, switch its model or reset it to the agent default, including while it runs")}`);
|
|
89066
|
+
out.push(` ${import_picocolors72.default.cyan("delete")} ${import_picocolors72.default.dim("<task-id>")} ${import_picocolors72.default.dim("permanently delete a stopped task and tear down its sandbox (--yes to skip the prompt)")}`);
|
|
88098
89067
|
out.push("");
|
|
88099
|
-
out.push(` ${
|
|
88100
|
-
out.push(` ${
|
|
88101
|
-
out.push(` ${
|
|
88102
|
-
out.push(` ${
|
|
88103
|
-
out.push(` ${
|
|
88104
|
-
out.push(` ${
|
|
88105
|
-
out.push(` ${
|
|
88106
|
-
out.push(` ${
|
|
88107
|
-
out.push(` ${
|
|
88108
|
-
out.push(` ${
|
|
89068
|
+
out.push(` ${import_picocolors72.default.bold("create flags")}`);
|
|
89069
|
+
out.push(` ${import_picocolors72.default.dim("--message <text>")} required first user message`);
|
|
89070
|
+
out.push(` ${import_picocolors72.default.dim("--agent <id>")} override the claimed agent in brainbase.agent.yaml`);
|
|
89071
|
+
out.push(` ${import_picocolors72.default.dim("--interface <id>")} open it as a build conversation for this interface (agent defaults to the interface's)`);
|
|
89072
|
+
out.push(` ${import_picocolors72.default.dim("--title <text>")} optional task title`);
|
|
89073
|
+
out.push(` ${import_picocolors72.default.dim("--model <id>")} optional model override`);
|
|
89074
|
+
out.push(` ${import_picocolors72.default.dim("--version <v>")} run a saved version of the agent: 12, v12 or a version id (\`agent versions list\`)`);
|
|
89075
|
+
out.push(` ${import_picocolors72.default.dim("--metadata key=value")} label the task (repeatable)`);
|
|
89076
|
+
out.push(` ${import_picocolors72.default.dim("--wait")} block until the task finishes; exit 1 unless it succeeded`);
|
|
89077
|
+
out.push(` ${import_picocolors72.default.dim("--timeout <secs>")} give up waiting after <secs> and exit 1 (needs --wait)`);
|
|
88109
89078
|
out.push("");
|
|
88110
|
-
out.push(` ${
|
|
88111
|
-
out.push(` ${
|
|
88112
|
-
out.push(` ${
|
|
88113
|
-
out.push(` ${
|
|
88114
|
-
out.push(` ${
|
|
89079
|
+
out.push(` ${import_picocolors72.default.bold("list flags")}`);
|
|
89080
|
+
out.push(` ${import_picocolors72.default.dim("--agent <id>")} only this agent's tasks`);
|
|
89081
|
+
out.push(` ${import_picocolors72.default.dim("--interface <id>")} only this interface's build conversations (hidden from a plain list)`);
|
|
89082
|
+
out.push(` ${import_picocolors72.default.dim("--metadata key=value")} only tasks carrying this label (repeatable; all must match)`);
|
|
89083
|
+
out.push(` ${import_picocolors72.default.dim("--limit <n>")} cap the page (1-200, server default 50)`);
|
|
88115
89084
|
out.push("");
|
|
88116
|
-
out.push(` ${
|
|
88117
|
-
out.push(` ${
|
|
88118
|
-
out.push(` ${
|
|
89085
|
+
out.push(` ${import_picocolors72.default.bold("logs flags")}`);
|
|
89086
|
+
out.push(` ${import_picocolors72.default.dim("--limit <n>")} stop after <n> events instead of the whole transcript; with --follow, the first page size`);
|
|
89087
|
+
out.push(` ${import_picocolors72.default.dim("--follow, -f")} stay attached and print events as they land, until the task finishes and any queued follow-ups have run`);
|
|
88119
89088
|
out.push("");
|
|
88120
|
-
out.push(` ${
|
|
88121
|
-
out.push(` ${
|
|
88122
|
-
out.push(` ${
|
|
88123
|
-
out.push(` ${
|
|
88124
|
-
out.push(` ${
|
|
88125
|
-
out.push(` ${
|
|
88126
|
-
out.push(` ${
|
|
88127
|
-
out.push(` ${
|
|
88128
|
-
out.push(` ${
|
|
89089
|
+
out.push(` ${import_picocolors72.default.bold("update flags")}`);
|
|
89090
|
+
out.push(` ${import_picocolors72.default.dim("--title <text>")} new title`);
|
|
89091
|
+
out.push(` ${import_picocolors72.default.dim("--clear-title")} remove the title; automatic titling may name the task again on a later turn`);
|
|
89092
|
+
out.push(` ${import_picocolors72.default.dim("--metadata key=value")} set one label, keeping the others (repeatable)`);
|
|
89093
|
+
out.push(` ${import_picocolors72.default.dim("--unset-metadata <key>")} remove one label (repeatable)`);
|
|
89094
|
+
out.push(` ${import_picocolors72.default.dim(" the server applies label edits in one step, so concurrent edits from other clients are kept")}`);
|
|
89095
|
+
out.push(` ${import_picocolors72.default.dim("--clear-metadata")} remove every label; with --metadata, the labels become exactly those given`);
|
|
89096
|
+
out.push(` ${import_picocolors72.default.dim("--model <id>")} switch the model the task's next turn runs on (the running turn keeps its model)`);
|
|
89097
|
+
out.push(` ${import_picocolors72.default.dim("--clear-model")} go back to the agent's default model from the next turn`);
|
|
88129
89098
|
out.push("");
|
|
88130
|
-
out.push(` ${
|
|
88131
|
-
out.push(` ${
|
|
88132
|
-
out.push(` ${
|
|
88133
|
-
out.push(` ${
|
|
89099
|
+
out.push(` ${import_picocolors72.default.bold("send flags")}`);
|
|
89100
|
+
out.push(` ${import_picocolors72.default.dim("--input-id <uuid>")} recover the same request using its original ID and identical message`);
|
|
89101
|
+
out.push(` ${import_picocolors72.default.dim(" omit it to send a new follow-up; an unconfirmed receipt is never automatically replayed")}`);
|
|
89102
|
+
out.push(` ${import_picocolors72.default.dim(" admission disabled/recovery unavailable means no input was admitted; retry the same ID after recovery")}`);
|
|
88134
89103
|
out.push("");
|
|
88135
|
-
out.push(` ${
|
|
88136
|
-
out.push(` ${
|
|
88137
|
-
out.push(` ${
|
|
89104
|
+
out.push(` ${import_picocolors72.default.bold("send and stop flags")}`);
|
|
89105
|
+
out.push(` ${import_picocolors72.default.dim("--generation <n>")} retain the printed generation when retrying; defaults to a fresh snapshot for a new operation`);
|
|
89106
|
+
out.push(` ${import_picocolors72.default.dim(" Stop errors may follow queued-input cancellation; retry the printed command to avoid stopping newer work")}`);
|
|
88138
89107
|
out.push("");
|
|
88139
|
-
out.push(` ${
|
|
88140
|
-
out.push(` ${
|
|
88141
|
-
out.push(` ${
|
|
88142
|
-
out.push(` ${
|
|
89108
|
+
out.push(` ${import_picocolors72.default.bold("every subcommand")}`);
|
|
89109
|
+
out.push(` ${import_picocolors72.default.dim("--json")} machine-readable output — create prints task_id, agent_id and status (with --version, also agent_version_id and version_number); list, get, logs, send, stop and update print the raw records; delete prints id and deleted`);
|
|
89110
|
+
out.push(` ${import_picocolors72.default.dim(" send and stop include expected_generation for safe retries; send also reports idempotency_replayed when present")}`);
|
|
89111
|
+
out.push(` ${import_picocolors72.default.dim(" logs --follow --json prints one record per line, since a live stream has no end to close on")}`);
|
|
88143
89112
|
out.push("");
|
|
88144
|
-
out.push(` ${
|
|
88145
|
-
out.push(` ${
|
|
88146
|
-
out.push(` ${
|
|
88147
|
-
out.push(` ${
|
|
89113
|
+
out.push(` ${import_picocolors72.default.dim("Exit codes with --wait:")} ${import_picocolors72.default.dim("0 succeeded · 1 failed, needs input, or timed out · 130 interrupted")}`);
|
|
89114
|
+
out.push(` ${import_picocolors72.default.dim("Exit codes with --follow:")} ${import_picocolors72.default.dim("0 task reached a terminal state · 1 stream refused, or unreachable for 60s · 130 interrupted (Ctrl-C) · 143 terminated")}`);
|
|
89115
|
+
out.push(` ${import_picocolors72.default.dim("Exit codes with send:")} ${import_picocolors72.default.dim("0 queued, dispatching, submitted or completed · 1 unconfirmed, cancelled, failed or request error")}`);
|
|
89116
|
+
out.push(` ${import_picocolors72.default.dim("Ctrl-C while waiting or following logs detaches; use task stop to cancel remote work.")}`);
|
|
88148
89117
|
out.push("");
|
|
88149
|
-
out.push(` ${
|
|
89118
|
+
out.push(` ${import_picocolors72.default.dim("Flag-like values:")} use ${import_picocolors72.default.cyan("--flag=value")} or ${import_picocolors72.default.cyan("--flag -- <value>")}`);
|
|
88150
89119
|
out.push("");
|
|
88151
89120
|
console.log(out.join(`
|
|
88152
89121
|
`));
|
|
88153
89122
|
}
|
|
88154
89123
|
|
|
88155
89124
|
// src/cli/machine.ts
|
|
88156
|
-
var
|
|
89125
|
+
var import_picocolors75 = __toESM(require_picocolors(), 1);
|
|
88157
89126
|
|
|
88158
89127
|
// src/cli/machine-list.ts
|
|
88159
|
-
var
|
|
89128
|
+
var import_picocolors73 = __toESM(require_picocolors(), 1);
|
|
88160
89129
|
async function runMachineList(args = {}) {
|
|
88161
89130
|
if (!args.json)
|
|
88162
89131
|
banner("machine list — sandboxes you can reach");
|
|
@@ -88174,7 +89143,7 @@ async function runMachineList(args = {}) {
|
|
|
88174
89143
|
function formatMachineList(machines, includedDead, names = new Map) {
|
|
88175
89144
|
const lines = [""];
|
|
88176
89145
|
if (machines.length === 0) {
|
|
88177
|
-
lines.push(` ${
|
|
89146
|
+
lines.push(` ${import_picocolors73.default.dim(includedDead ? "No machines." : "No live machines. Pass --all to include torn-down ones.")}`, "");
|
|
88178
89147
|
return lines.join(`
|
|
88179
89148
|
`);
|
|
88180
89149
|
}
|
|
@@ -88194,7 +89163,7 @@ function formatMachineList(machines, includedDead, names = new Map) {
|
|
|
88194
89163
|
const statusWidth = width((row) => row.status);
|
|
88195
89164
|
const sizeWidth = width((row) => row.size);
|
|
88196
89165
|
const agentWidth = width((row) => row.agent);
|
|
88197
|
-
lines.push(` ${
|
|
89166
|
+
lines.push(` ${import_picocolors73.default.dim([
|
|
88198
89167
|
header.id.padEnd(idWidth),
|
|
88199
89168
|
header.kind.padEnd(kindWidth),
|
|
88200
89169
|
header.status.padEnd(statusWidth),
|
|
@@ -88210,21 +89179,21 @@ function formatMachineList(machines, includedDead, names = new Map) {
|
|
|
88210
89179
|
row.dead ? status : statusTint(row.status, status),
|
|
88211
89180
|
row.size.padEnd(sizeWidth),
|
|
88212
89181
|
row.agent.padEnd(agentWidth),
|
|
88213
|
-
|
|
89182
|
+
import_picocolors73.default.dim(row.age)
|
|
88214
89183
|
].join(" ");
|
|
88215
|
-
lines.push(` ${row.dead ?
|
|
89184
|
+
lines.push(` ${row.dead ? import_picocolors73.default.dim(cells) : cells}`);
|
|
88216
89185
|
}
|
|
88217
|
-
lines.push("", ` ${
|
|
89186
|
+
lines.push("", ` ${import_picocolors73.default.dim("tear one down with")} ${import_picocolors73.default.cyan("brainbase machine rm <id>")}`, "");
|
|
88218
89187
|
return lines.join(`
|
|
88219
89188
|
`);
|
|
88220
89189
|
}
|
|
88221
89190
|
function statusTint(status, padded) {
|
|
88222
89191
|
switch (status) {
|
|
88223
89192
|
case "running":
|
|
88224
|
-
return
|
|
89193
|
+
return import_picocolors73.default.green(padded);
|
|
88225
89194
|
case "stopped":
|
|
88226
89195
|
case "starting":
|
|
88227
|
-
return
|
|
89196
|
+
return import_picocolors73.default.yellow(padded);
|
|
88228
89197
|
default:
|
|
88229
89198
|
return padded;
|
|
88230
89199
|
}
|
|
@@ -88247,7 +89216,7 @@ function age(createdAt) {
|
|
|
88247
89216
|
}
|
|
88248
89217
|
|
|
88249
89218
|
// src/cli/machine-rm.ts
|
|
88250
|
-
var
|
|
89219
|
+
var import_picocolors74 = __toESM(require_picocolors(), 1);
|
|
88251
89220
|
async function runMachineRm(args, dependencies = {}) {
|
|
88252
89221
|
const setExitCode = dependencies.setExitCode ?? ((code) => process.exitCode = code);
|
|
88253
89222
|
const machineId = args.machineId?.trim();
|
|
@@ -88261,7 +89230,7 @@ async function runMachineRm(args, dependencies = {}) {
|
|
|
88261
89230
|
if (args.json) {
|
|
88262
89231
|
console.log(JSON.stringify({ id: machineId, torn_down: false, outcome: "declined" }, null, 2));
|
|
88263
89232
|
} else {
|
|
88264
|
-
console.log(` ${
|
|
89233
|
+
console.log(` ${import_picocolors74.default.dim("Left alone.")}`);
|
|
88265
89234
|
}
|
|
88266
89235
|
return;
|
|
88267
89236
|
}
|
|
@@ -88279,7 +89248,7 @@ async function promptForTeardown(args) {
|
|
|
88279
89248
|
return true;
|
|
88280
89249
|
if (!args.json) {
|
|
88281
89250
|
console.log(`
|
|
88282
|
-
${
|
|
89251
|
+
${import_picocolors74.default.red("This destroys the sandbox.")} ${import_picocolors74.default.dim("Anything not committed out of it is lost. The machine row is kept for cost history.")}
|
|
88283
89252
|
`);
|
|
88284
89253
|
}
|
|
88285
89254
|
const answer = await se({
|
|
@@ -88291,9 +89260,9 @@ async function promptForTeardown(args) {
|
|
|
88291
89260
|
function formatMachineRm(machine) {
|
|
88292
89261
|
const lines = [""];
|
|
88293
89262
|
if (machine.destroyed_at) {
|
|
88294
|
-
lines.push(` ${
|
|
89263
|
+
lines.push(` ${import_picocolors74.default.green("✓")} ${machine.kind} sandbox ${machine.id} is torn down.`, ` ${import_picocolors74.default.dim(`destroyed_at ${machine.destroyed_at}`)}`);
|
|
88295
89264
|
} else {
|
|
88296
|
-
lines.push(` ${
|
|
89265
|
+
lines.push(` ${import_picocolors74.default.yellow("!")} ${machine.id} came back without a teardown timestamp (status ${machine.status}).`, ` ${import_picocolors74.default.dim("Re-check with `brainbase machine ls --all` before assuming it stopped billing.")}`);
|
|
88297
89266
|
}
|
|
88298
89267
|
lines.push("");
|
|
88299
89268
|
return lines.join(`
|
|
@@ -88334,25 +89303,25 @@ ${didYouMean(sub, ["ls", "rm"], "brainbase machine")}`);
|
|
|
88334
89303
|
function printHelp6() {
|
|
88335
89304
|
const out = [];
|
|
88336
89305
|
out.push("");
|
|
88337
|
-
out.push(` ${
|
|
89306
|
+
out.push(` ${import_picocolors75.default.bold("brainbase machine")} ${import_picocolors75.default.dim("<sub> [options]")}`);
|
|
88338
89307
|
out.push("");
|
|
88339
|
-
out.push(` ${
|
|
88340
|
-
out.push(` ${
|
|
89308
|
+
out.push(` ${import_picocolors75.default.cyan("ls")} ${import_picocolors75.default.dim("list your sandboxes — live ones only unless --all")}`);
|
|
89309
|
+
out.push(` ${import_picocolors75.default.cyan("rm")} ${import_picocolors75.default.dim("<id>")} ${import_picocolors75.default.dim("tear a sandbox down (terminal; the row is kept for cost history)")}`);
|
|
88341
89310
|
out.push("");
|
|
88342
|
-
out.push(` ${
|
|
88343
|
-
out.push(` ${
|
|
88344
|
-
out.push(` ${
|
|
88345
|
-
out.push(` ${
|
|
89311
|
+
out.push(` ${import_picocolors75.default.dim("--all")} ${import_picocolors75.default.dim("for ls: include machines already torn down")}`);
|
|
89312
|
+
out.push(` ${import_picocolors75.default.dim("--limit <n>")} ${import_picocolors75.default.dim("for ls: how many to fetch (1-200, default 50)")}`);
|
|
89313
|
+
out.push(` ${import_picocolors75.default.dim("--yes, -y")} ${import_picocolors75.default.dim("for rm: skip the confirmation")}`);
|
|
89314
|
+
out.push(` ${import_picocolors75.default.dim("--json")} ${import_picocolors75.default.dim("machine-readable output")}`);
|
|
88346
89315
|
out.push("");
|
|
88347
89316
|
console.log(out.join(`
|
|
88348
89317
|
`));
|
|
88349
89318
|
}
|
|
88350
89319
|
|
|
88351
89320
|
// src/cli/interface.ts
|
|
88352
|
-
var
|
|
89321
|
+
var import_picocolors81 = __toESM(require_picocolors(), 1);
|
|
88353
89322
|
|
|
88354
89323
|
// src/cli/interface-build.ts
|
|
88355
|
-
var
|
|
89324
|
+
var import_picocolors76 = __toESM(require_picocolors(), 1);
|
|
88356
89325
|
var USAGE2 = 'brainbase interface build <id> "<request>" [--timeout <seconds>] [--idempotency-key <key>] [--json]';
|
|
88357
89326
|
var SETTLE_TIMEOUT_MS = 120000;
|
|
88358
89327
|
async function reportingErrors(json3, work) {
|
|
@@ -88451,28 +89420,28 @@ function buildExitCode(outcome) {
|
|
|
88451
89420
|
function reportBuild(say, interfaceId, outcome, timeoutSeconds) {
|
|
88452
89421
|
switch (outcome.kind) {
|
|
88453
89422
|
case "built":
|
|
88454
|
-
say(` ${
|
|
89423
|
+
say(` ${import_picocolors76.default.dim("build")} ${safe(outcome.build.id)} ${import_picocolors76.default.green("succeeded")}`);
|
|
88455
89424
|
say("");
|
|
88456
|
-
say(` ${
|
|
89425
|
+
say(` ${import_picocolors76.default.dim("Next:")} ${import_picocolors76.default.cyan(`brainbase interface publish ${safe(interfaceId)}`)}`);
|
|
88457
89426
|
return;
|
|
88458
89427
|
case "failed": {
|
|
88459
89428
|
const reason = outcome.build?.error_summary ?? outcome.operation?.error ?? outcome.operation?.reason ?? null;
|
|
88460
|
-
say(` ${
|
|
89429
|
+
say(` ${import_picocolors76.default.dim("build")} ${outcome.build ? safe(outcome.build.id) : import_picocolors76.default.dim("none")} ${import_picocolors76.default.red("failed")}`);
|
|
88461
89430
|
if (reason)
|
|
88462
89431
|
say(` ${safeBlock(reason).split(`
|
|
88463
89432
|
`).join(`
|
|
88464
89433
|
`)}`);
|
|
88465
|
-
say(` ${
|
|
89434
|
+
say(` ${import_picocolors76.default.dim("Try again with")} ${import_picocolors76.default.cyan(`brainbase interface rebuild ${safe(interfaceId)}`)}`);
|
|
88466
89435
|
return;
|
|
88467
89436
|
}
|
|
88468
89437
|
case "busy":
|
|
88469
|
-
say(` ${
|
|
89438
|
+
say(` ${import_picocolors76.default.yellow(safe(outcome.message))}`);
|
|
88470
89439
|
return;
|
|
88471
89440
|
case "timeout":
|
|
88472
|
-
say(` ${
|
|
89441
|
+
say(` ${import_picocolors76.default.yellow(`Still building after ${timeoutSeconds}s.`)} ${import_picocolors76.default.dim(`It keeps going; check \`brainbase interface builds ${safe(interfaceId)}\`.`)}`);
|
|
88473
89442
|
return;
|
|
88474
89443
|
case "interrupted":
|
|
88475
|
-
say(` ${
|
|
89444
|
+
say(` ${import_picocolors76.default.yellow("Stopped waiting.")} ${import_picocolors76.default.dim(`The build keeps going; check \`brainbase interface builds ${safe(interfaceId)}\`.`)}`);
|
|
88476
89445
|
return;
|
|
88477
89446
|
default: {
|
|
88478
89447
|
const unreachable = outcome;
|
|
@@ -88519,8 +89488,8 @@ async function build(ctx) {
|
|
|
88519
89488
|
throw held;
|
|
88520
89489
|
}
|
|
88521
89490
|
const reattach = `brainbase task logs ${safe(taskId)} --follow`;
|
|
88522
|
-
say(` ${
|
|
88523
|
-
say(` ${
|
|
89491
|
+
say(` ${import_picocolors76.default.dim("Build conversation")} ${import_picocolors76.default.bold(safe(taskId))} ${import_picocolors76.default.dim(`on ${safe(before2.name)}`)}`);
|
|
89492
|
+
say(` ${import_picocolors76.default.dim(`If this stops early, reattach with \`${reattach}\`.`)}`);
|
|
88524
89493
|
const finish = (result2, exitCode) => {
|
|
88525
89494
|
if (json3)
|
|
88526
89495
|
console.log(JSON.stringify({ type: "result", task_id: taskId, ...result2 }));
|
|
@@ -88537,13 +89506,13 @@ async function build(ctx) {
|
|
|
88537
89506
|
});
|
|
88538
89507
|
} catch (error2) {
|
|
88539
89508
|
say("");
|
|
88540
|
-
say(` ${
|
|
88541
|
-
say(` ${
|
|
89509
|
+
say(` ${import_picocolors76.default.red(`Lost the conversation's event stream: ${safe(error2.message)}`)}`);
|
|
89510
|
+
say(` ${import_picocolors76.default.dim(`Conversation ${safe(taskId)} may still be running. Reattach with`)} ${import_picocolors76.default.cyan(reattach)}`);
|
|
88542
89511
|
finish({ version_id: null, build_id: null, status: "stream_lost", task_status: null }, 1);
|
|
88543
89512
|
return;
|
|
88544
89513
|
}
|
|
88545
89514
|
if (followExit !== undefined) {
|
|
88546
|
-
say(` ${
|
|
89515
|
+
say(` ${import_picocolors76.default.yellow("Stopped following.")} ${import_picocolors76.default.dim(`The conversation keeps running. Reattach with \`${reattach}\`.`)}`);
|
|
88547
89516
|
finish({ version_id: null, build_id: null, status: "interrupted", task_status: null }, followExit);
|
|
88548
89517
|
return;
|
|
88549
89518
|
}
|
|
@@ -88558,7 +89527,7 @@ async function build(ctx) {
|
|
|
88558
89527
|
if (settled.kind !== "terminal") {
|
|
88559
89528
|
const interrupted = settled.kind === "interrupted";
|
|
88560
89529
|
const status2 = settled.task?.status ?? null;
|
|
88561
|
-
say(` ${
|
|
89530
|
+
say(` ${import_picocolors76.default.yellow(interrupted ? "Stopped." : `The conversation is still ${safe(status2 ?? "running")}.`)} ${import_picocolors76.default.dim(`Check it with \`brainbase task get ${safe(taskId)}\`.`)}`);
|
|
88562
89531
|
finish({ version_id: null, build_id: null, status: interrupted ? "interrupted" : "task_unsettled", task_status: status2 }, interrupted ? SIGINT_EXIT_CODE : 1);
|
|
88563
89532
|
return;
|
|
88564
89533
|
}
|
|
@@ -88578,36 +89547,36 @@ async function build(ctx) {
|
|
|
88578
89547
|
}
|
|
88579
89548
|
const codes = [exitCodeForTaskStatus(task.status)];
|
|
88580
89549
|
say("");
|
|
88581
|
-
say(` ${
|
|
89550
|
+
say(` ${import_picocolors76.default.dim("conversation")} ${safe(taskId)} ${import_picocolors76.default.dim("ended")} ${safe(task.status)}`);
|
|
88582
89551
|
if (mine?.status === "failed") {
|
|
88583
89552
|
codes.push(1);
|
|
88584
89553
|
const why = [mine.reason, mine.error].filter(Boolean).map((part) => safe(part)).join(": ");
|
|
88585
|
-
say(` ${
|
|
89554
|
+
say(` ${import_picocolors76.default.red(`This conversation's build work failed${why ? ` (${why})` : ""}.`)}`);
|
|
88586
89555
|
} else if (task.status !== "success" && task.status !== "need_more_info") {
|
|
88587
|
-
say(` ${
|
|
89556
|
+
say(` ${import_picocolors76.default.red(`The conversation finished as ${safe(task.status)}.`)} ${import_picocolors76.default.dim(`See \`brainbase task logs ${safe(taskId)}\`.`)}`);
|
|
88588
89557
|
}
|
|
88589
89558
|
if (task.status === "need_more_info") {
|
|
88590
89559
|
const question = await lastAgentMessage(taskId);
|
|
88591
89560
|
say("");
|
|
88592
89561
|
if (question) {
|
|
88593
|
-
say(` ${
|
|
89562
|
+
say(` ${import_picocolors76.default.bold("The agent asks:")}`);
|
|
88594
89563
|
say(` ${safeBlock(question).split(`
|
|
88595
89564
|
`).join(`
|
|
88596
89565
|
`)}`);
|
|
88597
89566
|
} else {
|
|
88598
|
-
say(` ${
|
|
89567
|
+
say(` ${import_picocolors76.default.bold("The agent needs more from you before it can go on.")}`);
|
|
88599
89568
|
}
|
|
88600
89569
|
say("");
|
|
88601
|
-
say(` ${
|
|
88602
|
-
say(` ${
|
|
89570
|
+
say(` ${import_picocolors76.default.dim("Reply with")} ${import_picocolors76.default.cyan(`brainbase task send ${safe(taskId)} "<reply>"`)}`);
|
|
89571
|
+
say(` ${import_picocolors76.default.dim("then follow it with")} ${import_picocolors76.default.cyan(reattach)}`);
|
|
88603
89572
|
}
|
|
88604
89573
|
let status;
|
|
88605
89574
|
let buildId = null;
|
|
88606
89575
|
if (versionId) {
|
|
88607
89576
|
say("");
|
|
88608
|
-
say(` ${
|
|
89577
|
+
say(` ${import_picocolors76.default.dim("version")} ${safe(versionId)}`);
|
|
88609
89578
|
if (!json3)
|
|
88610
|
-
say(` ${
|
|
89579
|
+
say(` ${import_picocolors76.default.dim("Waiting for its build...")}`);
|
|
88611
89580
|
const buildKey = `${key2}-build`;
|
|
88612
89581
|
let outcome;
|
|
88613
89582
|
try {
|
|
@@ -88617,7 +89586,7 @@ async function build(ctx) {
|
|
|
88617
89586
|
signal: stop.signal,
|
|
88618
89587
|
now: deps.now,
|
|
88619
89588
|
idempotencyKey: buildKey,
|
|
88620
|
-
onStall: () => say(` ${
|
|
89589
|
+
onStall: () => say(` ${import_picocolors76.default.yellow("The build looks stalled; still waiting in case another worker picks it up.")}`)
|
|
88621
89590
|
});
|
|
88622
89591
|
} catch (error2) {
|
|
88623
89592
|
if (error2 instanceof LostResponseError) {
|
|
@@ -88633,9 +89602,9 @@ async function build(ctx) {
|
|
|
88633
89602
|
status = noVersionStatus(mine?.status === "failed", task.status);
|
|
88634
89603
|
if (status === "no_version") {
|
|
88635
89604
|
codes.push(1);
|
|
88636
|
-
say(` ${
|
|
89605
|
+
say(` ${import_picocolors76.default.red("The conversation finished without committing a version, so there is nothing to build.")}`);
|
|
88637
89606
|
} else if (task.status !== "need_more_info") {
|
|
88638
|
-
say(` ${
|
|
89607
|
+
say(` ${import_picocolors76.default.dim("This conversation produced no version, so there is nothing to build.")}`);
|
|
88639
89608
|
}
|
|
88640
89609
|
}
|
|
88641
89610
|
if (!json3)
|
|
@@ -88650,7 +89619,7 @@ async function build(ctx) {
|
|
|
88650
89619
|
var buildCommands = { build };
|
|
88651
89620
|
|
|
88652
89621
|
// src/cli/interface-lifecycle.ts
|
|
88653
|
-
var
|
|
89622
|
+
var import_picocolors78 = __toESM(require_picocolors(), 1);
|
|
88654
89623
|
|
|
88655
89624
|
// src/core/org-members.ts
|
|
88656
89625
|
async function listAllOrgMembers(orgId) {
|
|
@@ -88704,7 +89673,7 @@ function membersById(members) {
|
|
|
88704
89673
|
}
|
|
88705
89674
|
|
|
88706
89675
|
// src/cli/interface-read.ts
|
|
88707
|
-
var
|
|
89676
|
+
var import_picocolors77 = __toESM(require_picocolors(), 1);
|
|
88708
89677
|
function interfaceState(row) {
|
|
88709
89678
|
if (row.archived_at)
|
|
88710
89679
|
return "archived";
|
|
@@ -88726,11 +89695,11 @@ function threadsLabel(shared) {
|
|
|
88726
89695
|
function stateTint(state) {
|
|
88727
89696
|
switch (state) {
|
|
88728
89697
|
case "live":
|
|
88729
|
-
return
|
|
89698
|
+
return import_picocolors77.default.green;
|
|
88730
89699
|
case "building":
|
|
88731
|
-
return
|
|
89700
|
+
return import_picocolors77.default.yellow;
|
|
88732
89701
|
case "archived":
|
|
88733
|
-
return
|
|
89702
|
+
return import_picocolors77.default.dim;
|
|
88734
89703
|
case "draft":
|
|
88735
89704
|
return (cell) => cell;
|
|
88736
89705
|
default: {
|
|
@@ -88763,7 +89732,7 @@ async function list3(ctx) {
|
|
|
88763
89732
|
if (shown.length === 0) {
|
|
88764
89733
|
const empty = onlyArchived ? "No archived interfaces." : includeArchived ? "No interfaces. Create one with `brainbase interface create`." : await emptyWithoutArchived(agentId);
|
|
88765
89734
|
console.log(`
|
|
88766
|
-
${
|
|
89735
|
+
${import_picocolors77.default.dim(empty)}
|
|
88767
89736
|
`);
|
|
88768
89737
|
return;
|
|
88769
89738
|
}
|
|
@@ -88776,7 +89745,7 @@ async function list3(ctx) {
|
|
|
88776
89745
|
audienceWord(row),
|
|
88777
89746
|
ago(row.last_edited_at ?? row.created_at, now2)
|
|
88778
89747
|
]);
|
|
88779
|
-
console.log(["", ...table(cells, [null,
|
|
89748
|
+
console.log(["", ...table(cells, [null, import_picocolors77.default.bold, null, null, null, import_picocolors77.default.dim]), ""].join(`
|
|
88780
89749
|
`));
|
|
88781
89750
|
});
|
|
88782
89751
|
}
|
|
@@ -88810,13 +89779,13 @@ async function get2(ctx) {
|
|
|
88810
89779
|
out.push(field("id", safe(row.id)));
|
|
88811
89780
|
out.push(field("agent", agentLabel(safe(row.agent_id), await agentNames([row.agent_id]))));
|
|
88812
89781
|
out.push(field("state", stateTint(state)(state)));
|
|
88813
|
-
out.push(field("address", row.live_release ? safe(row.live_release.url) : `${safe(row.slug)} ${
|
|
89782
|
+
out.push(field("address", row.live_release ? safe(row.live_release.url) : `${safe(row.slug)} ${import_picocolors77.default.dim("(nothing live yet)")}`));
|
|
88814
89783
|
out.push(field("audience", audienceLabel(row)));
|
|
88815
89784
|
out.push(field("threads", threadsLabel(row.share_agent_threads)));
|
|
88816
|
-
out.push(field("live", row.live_release ? `${safe(row.live_release.id)} ${
|
|
88817
|
-
out.push(field("draft", row.draft_version_id ? safe(row.draft_version_id) :
|
|
89785
|
+
out.push(field("live", row.live_release ? `${safe(row.live_release.id)} ${import_picocolors77.default.dim(`published ${ago(row.live_release.published_at)}`)}` : import_picocolors77.default.dim("none")));
|
|
89786
|
+
out.push(field("draft", row.draft_version_id ? safe(row.draft_version_id) : import_picocolors77.default.dim("none yet")));
|
|
88818
89787
|
if (row.running_generation) {
|
|
88819
|
-
out.push(field("building", `conversation ${safe(row.running_generation.thread_id ?? "")} ${
|
|
89788
|
+
out.push(field("building", `conversation ${safe(row.running_generation.thread_id ?? "")} ${import_picocolors77.default.dim(`(follow it with \`brainbase task logs ${safe(row.running_generation.thread_id ?? "")} --follow\`)`)}`));
|
|
88820
89789
|
}
|
|
88821
89790
|
if (row.archived_at)
|
|
88822
89791
|
out.push(field("archived", ago(row.archived_at)));
|
|
@@ -88845,7 +89814,7 @@ async function open(ctx) {
|
|
|
88845
89814
|
}
|
|
88846
89815
|
console.log(safe(url2));
|
|
88847
89816
|
if (new URL(url2).hostname.endsWith("vercel.app")) {
|
|
88848
|
-
console.error(
|
|
89817
|
+
console.error(import_picocolors77.default.yellow("This is the raw Vercel deployment address, which sits behind Vercel protection and will not open for viewers. The control plane has no public interfaces domain configured."));
|
|
88849
89818
|
}
|
|
88850
89819
|
});
|
|
88851
89820
|
}
|
|
@@ -88883,7 +89852,7 @@ async function history(ctx, name) {
|
|
|
88883
89852
|
banner(`interface ${name} — ${safe(id)}`);
|
|
88884
89853
|
if (rows.length === 0) {
|
|
88885
89854
|
console.log(`
|
|
88886
|
-
${
|
|
89855
|
+
${import_picocolors77.default.dim(`No ${name} yet.`)}
|
|
88887
89856
|
`);
|
|
88888
89857
|
return;
|
|
88889
89858
|
}
|
|
@@ -88960,7 +89929,7 @@ function exactlyOne(parsed, flags) {
|
|
|
88960
89929
|
}
|
|
88961
89930
|
function peopleLine(access, members) {
|
|
88962
89931
|
const ids = grantIds(access);
|
|
88963
|
-
return ids.length ? namesOf(ids, members) :
|
|
89932
|
+
return ids.length ? namesOf(ids, members) : import_picocolors78.default.dim("nobody named");
|
|
88964
89933
|
}
|
|
88965
89934
|
function printAccess(row, access, members) {
|
|
88966
89935
|
console.log([
|
|
@@ -89056,11 +90025,11 @@ async function create3(ctx) {
|
|
|
89056
90025
|
const id = safe(created.id);
|
|
89057
90026
|
const out = [
|
|
89058
90027
|
"",
|
|
89059
|
-
` ${
|
|
90028
|
+
` ${import_picocolors78.default.green("Created")} ${import_picocolors78.default.bold(safe(created.name))}`,
|
|
89060
90029
|
"",
|
|
89061
90030
|
field("id", id),
|
|
89062
90031
|
field("agent", safe(created.agent_id)),
|
|
89063
|
-
field("address", `${safe(created.slug)} ${
|
|
90032
|
+
field("address", `${safe(created.slug)} ${import_picocolors78.default.dim("(nothing live yet)")}`),
|
|
89064
90033
|
field("threads", threadsLabel(created.share_agent_threads))
|
|
89065
90034
|
];
|
|
89066
90035
|
if (access) {
|
|
@@ -89072,11 +90041,11 @@ async function create3(ctx) {
|
|
|
89072
90041
|
out.push("", ` Nobody can open it until you choose who can: \`brainbase interface access ${id} --everyone\` or \`--people <emails>\`.`);
|
|
89073
90042
|
}
|
|
89074
90043
|
if (created.share_agent_threads) {
|
|
89075
|
-
out.push(` ${
|
|
90044
|
+
out.push(` ${import_picocolors78.default.dim(`To show viewers only their own conversations: \`brainbase interface threads ${id} --private\`.`)}`);
|
|
89076
90045
|
}
|
|
89077
90046
|
if (note)
|
|
89078
90047
|
out.push("", ` ${safe(note)}`);
|
|
89079
|
-
out.push("", ` ${
|
|
90048
|
+
out.push("", ` ${import_picocolors78.default.dim(`Next: \`brainbase interface build ${id} "<what to build>"\``)}`, "");
|
|
89080
90049
|
console.log(out.join(`
|
|
89081
90050
|
`));
|
|
89082
90051
|
if (readFailed) {
|
|
@@ -89212,7 +90181,7 @@ async function threads(ctx) {
|
|
|
89212
90181
|
printJson({ id: row.id, share_agent_threads: row.share_agent_threads });
|
|
89213
90182
|
return;
|
|
89214
90183
|
}
|
|
89215
|
-
const already = wanted === null ? "" : ` ${
|
|
90184
|
+
const already = wanted === null ? "" : ` ${import_picocolors78.default.dim("(already set; nothing changed)")}`;
|
|
89216
90185
|
console.log(`
|
|
89217
90186
|
${field("threads", `${threadsLabel(row.share_agent_threads)}${already}`)}
|
|
89218
90187
|
`);
|
|
@@ -89251,7 +90220,7 @@ async function rename(ctx) {
|
|
|
89251
90220
|
return;
|
|
89252
90221
|
}
|
|
89253
90222
|
console.log(`
|
|
89254
|
-
Renamed ${safe(updated.id)} to ${
|
|
90223
|
+
Renamed ${safe(updated.id)} to ${import_picocolors78.default.bold(safe(updated.name))}.
|
|
89255
90224
|
`);
|
|
89256
90225
|
});
|
|
89257
90226
|
}
|
|
@@ -89287,7 +90256,7 @@ async function address(ctx) {
|
|
|
89287
90256
|
}
|
|
89288
90257
|
const where = updated.live_release ? safe(updated.live_release.url) : safe(updated.slug);
|
|
89289
90258
|
console.log(`
|
|
89290
|
-
${safe(updated.name)} is now at ${
|
|
90259
|
+
${safe(updated.name)} is now at ${import_picocolors78.default.bold(where)}.
|
|
89291
90260
|
`);
|
|
89292
90261
|
});
|
|
89293
90262
|
}
|
|
@@ -89379,9 +90348,9 @@ var lifecycleCommands = {
|
|
|
89379
90348
|
};
|
|
89380
90349
|
|
|
89381
90350
|
// src/cli/interface-preview.ts
|
|
89382
|
-
var
|
|
90351
|
+
var import_picocolors79 = __toESM(require_picocolors(), 1);
|
|
89383
90352
|
function warn(line2) {
|
|
89384
|
-
console.error(
|
|
90353
|
+
console.error(import_picocolors79.default.yellow(line2));
|
|
89385
90354
|
}
|
|
89386
90355
|
var PREVIEW_TIMEOUT_SECONDS = 300;
|
|
89387
90356
|
var PROBE_INTERVAL_MS = 2000;
|
|
@@ -89471,12 +90440,12 @@ async function preview(ctx) {
|
|
|
89471
90440
|
const say = progress(json3);
|
|
89472
90441
|
const row = await interfacesApi.get(id);
|
|
89473
90442
|
const { taskId, why } = await pickConversation(row, stringOption(parsed, "task")?.trim() || undefined);
|
|
89474
|
-
say(
|
|
90443
|
+
say(import_picocolors79.default.dim(` Previewing ${why}, ${safe(taskId)}.`));
|
|
89475
90444
|
const started = await interfacesApi.startPreview(taskId, row.id);
|
|
89476
90445
|
const address2 = previewAddress(started, row);
|
|
89477
90446
|
let outcome = started.state === "serving" ? "serving" : "not_waited";
|
|
89478
90447
|
if (outcome !== "serving" && !noWait) {
|
|
89479
|
-
say(
|
|
90448
|
+
say(import_picocolors79.default.dim(" Starting the dev server in the sandbox…"));
|
|
89480
90449
|
outcome = await waitUntilServing(started, { timeoutMs: waitMs, deps: ctx.deps });
|
|
89481
90450
|
}
|
|
89482
90451
|
if (json3) {
|
|
@@ -89484,12 +90453,12 @@ async function preview(ctx) {
|
|
|
89484
90453
|
} else {
|
|
89485
90454
|
const out = [
|
|
89486
90455
|
"",
|
|
89487
|
-
` ${outcome === "serving" ?
|
|
90456
|
+
` ${outcome === "serving" ? import_picocolors79.default.green("Preview ready") : import_picocolors79.default.yellow("Preview starting")} ${import_picocolors79.default.bold(safe(started.name))}`,
|
|
89488
90457
|
"",
|
|
89489
|
-
field("address", address2 ? safe(address2) :
|
|
90458
|
+
field("address", address2 ? safe(address2) : import_picocolors79.default.dim(missingAddress(started))),
|
|
89490
90459
|
field("showing", showing(started, taskId)),
|
|
89491
90460
|
"",
|
|
89492
|
-
` ${
|
|
90461
|
+
` ${import_picocolors79.default.dim("Opens for people who can edit the agent, after signing in. Nothing is published.")}`,
|
|
89493
90462
|
""
|
|
89494
90463
|
];
|
|
89495
90464
|
console.log(out.join(`
|
|
@@ -89510,13 +90479,13 @@ async function preview(ctx) {
|
|
|
89510
90479
|
var previewCommands = { preview };
|
|
89511
90480
|
|
|
89512
90481
|
// src/cli/interface-release.ts
|
|
89513
|
-
var
|
|
90482
|
+
var import_picocolors80 = __toESM(require_picocolors(), 1);
|
|
89514
90483
|
var PUBLISH_TIMEOUT_SECONDS = 300;
|
|
89515
90484
|
var REBUILD_USAGE = "brainbase interface rebuild <id> [--version <version id>] [--yes]";
|
|
89516
90485
|
var PUBLISH_USAGE = "brainbase interface publish <id> [--build <build id>]";
|
|
89517
90486
|
var ROLLBACK_USAGE = "brainbase interface rollback <id> --release <release id>";
|
|
89518
90487
|
function warn2(line2) {
|
|
89519
|
-
console.error(
|
|
90488
|
+
console.error(import_picocolors80.default.yellow(line2));
|
|
89520
90489
|
}
|
|
89521
90490
|
function text3(value2) {
|
|
89522
90491
|
return typeof value2 === "string" && value2.trim() ? value2 : null;
|
|
@@ -89533,7 +90502,7 @@ async function follow(operationId, what, options) {
|
|
|
89533
90502
|
intervalMs: options.deps.pollIntervalMs,
|
|
89534
90503
|
signal: stop.signal,
|
|
89535
90504
|
now: options.deps.now,
|
|
89536
|
-
onStatus: (operation) => say(
|
|
90505
|
+
onStatus: (operation) => say(import_picocolors80.default.dim(` ${what} ${operation.status}`)),
|
|
89537
90506
|
onStall: () => warn2(`The ${what} looks stalled: its worker stopped checking in. Still waiting, in case another worker picks it up.`)
|
|
89538
90507
|
});
|
|
89539
90508
|
if (outcome.kind === "settled") {
|
|
@@ -89552,7 +90521,7 @@ function reportUnsuccessful(result2, what, options) {
|
|
|
89552
90521
|
if (options.json) {
|
|
89553
90522
|
printJson({ outcome: result2.outcome, operation_id: result2.operationId, operation: result2.operation });
|
|
89554
90523
|
} else if (result2.outcome === "failed") {
|
|
89555
|
-
console.error(
|
|
90524
|
+
console.error(import_picocolors80.default.red(`The ${what} failed (operation ${id}):`));
|
|
89556
90525
|
console.error(safeBlock(result2.operation?.error ?? "Brainbase gave no reason."));
|
|
89557
90526
|
} else if (result2.outcome === "timeout") {
|
|
89558
90527
|
warn2(`Stopped waiting after ${Math.round(options.timeoutMs / 1000)}s. The ${what} keeps running on the server (operation ${id}).`);
|
|
@@ -89612,7 +90581,7 @@ async function rebuild(ctx) {
|
|
|
89612
90581
|
if (json3)
|
|
89613
90582
|
printJson({ outcome: "started", operation_id: operationId, operation });
|
|
89614
90583
|
else
|
|
89615
|
-
console.log(
|
|
90584
|
+
console.log(import_picocolors80.default.dim(` Follow it with \`brainbase interface builds ${safe(id)}\`.`));
|
|
89616
90585
|
return;
|
|
89617
90586
|
}
|
|
89618
90587
|
const result2 = await follow(operationId, "build", { json: json3, timeoutMs: waitMs, deps: ctx.deps });
|
|
@@ -89624,8 +90593,8 @@ async function rebuild(ctx) {
|
|
|
89624
90593
|
}
|
|
89625
90594
|
const buildId = safe(result2.operation?.build_id ?? "");
|
|
89626
90595
|
const version2 = safe(result2.operation?.source_version_id ?? "");
|
|
89627
|
-
console.log(
|
|
89628
|
-
console.log(
|
|
90596
|
+
console.log(import_picocolors80.default.green(`✓ Build ${buildId} succeeded${version2 ? ` (version ${version2})` : ""}.`));
|
|
90597
|
+
console.log(import_picocolors80.default.dim(` Publish it with \`brainbase interface publish ${safe(id)} --build ${buildId}\`.`));
|
|
89629
90598
|
});
|
|
89630
90599
|
}
|
|
89631
90600
|
function liveBuildOf(row, releases) {
|
|
@@ -89683,7 +90652,7 @@ function describeBuild(buildId, builds) {
|
|
|
89683
90652
|
const build2 = builds.find((candidate) => candidate.id === buildId);
|
|
89684
90653
|
if (!build2)
|
|
89685
90654
|
return `build ${safe(buildId)}`;
|
|
89686
|
-
return `build ${safe(build2.id)} ${
|
|
90655
|
+
return `build ${safe(build2.id)} ${import_picocolors80.default.dim(`(version ${safe(build2.source_version_id)}, built ${ago(build2.created_at)})`)}`;
|
|
89687
90656
|
}
|
|
89688
90657
|
function reportAlreadyLive(json3, buildId, releaseId, url2) {
|
|
89689
90658
|
if (json3) {
|
|
@@ -89737,8 +90706,8 @@ async function publish(ctx) {
|
|
|
89737
90706
|
}
|
|
89738
90707
|
if (!json3) {
|
|
89739
90708
|
console.log("");
|
|
89740
|
-
console.log(` ${
|
|
89741
|
-
console.log(` ${
|
|
90709
|
+
console.log(` ${import_picocolors80.default.dim("Live now".padEnd(14))}${liveBuildId ? `${describeBuild(liveBuildId, builds)} at ${safe(row.live_release?.url)}` : row.live_release ? `release ${safe(row.live_release.id)} at ${safe(row.live_release.url)}` : import_picocolors80.default.dim("nothing")}`);
|
|
90710
|
+
console.log(` ${import_picocolors80.default.dim("Will publish".padEnd(14))}${describeBuild(buildId, builds)}`);
|
|
89742
90711
|
console.log("");
|
|
89743
90712
|
}
|
|
89744
90713
|
const proceed = await confirmChange({
|
|
@@ -89781,7 +90750,7 @@ async function publish(ctx) {
|
|
|
89781
90750
|
if (json3)
|
|
89782
90751
|
printJson({ outcome: "started", operation_id: operationId, operation });
|
|
89783
90752
|
else
|
|
89784
|
-
console.log(
|
|
90753
|
+
console.log(import_picocolors80.default.dim(` Check it with \`brainbase interface get ${safe(id)}\`.`));
|
|
89785
90754
|
return;
|
|
89786
90755
|
}
|
|
89787
90756
|
const result2 = await follow(operationId, "publish", { json: json3, timeoutMs: waitMs, deps: ctx.deps });
|
|
@@ -89798,11 +90767,11 @@ async function publish(ctx) {
|
|
|
89798
90767
|
printJson({ outcome: "succeeded", operation_id: operationId, operation: result2.operation, url: url2 });
|
|
89799
90768
|
return;
|
|
89800
90769
|
}
|
|
89801
|
-
console.log(
|
|
90770
|
+
console.log(import_picocolors80.default.green(`✓ Build ${safe(buildId)} is live.`));
|
|
89802
90771
|
if (url2)
|
|
89803
90772
|
console.log(` ${safe(url2)}`);
|
|
89804
90773
|
if (urlUnread) {
|
|
89805
|
-
console.log(
|
|
90774
|
+
console.log(import_picocolors80.default.dim(` Its address could not be read just now; see it with \`brainbase interface open ${safe(id)}\`.`));
|
|
89806
90775
|
}
|
|
89807
90776
|
});
|
|
89808
90777
|
}
|
|
@@ -89838,8 +90807,8 @@ async function rollback(ctx) {
|
|
|
89838
90807
|
}
|
|
89839
90808
|
if (!json3) {
|
|
89840
90809
|
console.log("");
|
|
89841
|
-
console.log(` ${
|
|
89842
|
-
console.log(` ${
|
|
90810
|
+
console.log(` ${import_picocolors80.default.dim("Live now".padEnd(16))}release ${safe(row.live_release.id)} at ${safe(row.live_release.url)}`);
|
|
90811
|
+
console.log(` ${import_picocolors80.default.dim("Will republish".padEnd(16))}release ${safe(releaseId)} ${import_picocolors80.default.dim("as a new release, with a new id")}`);
|
|
89843
90812
|
console.log("");
|
|
89844
90813
|
}
|
|
89845
90814
|
const proceed = await confirmChange({
|
|
@@ -89872,7 +90841,7 @@ async function rollback(ctx) {
|
|
|
89872
90841
|
printJson(release);
|
|
89873
90842
|
return;
|
|
89874
90843
|
}
|
|
89875
|
-
console.log(
|
|
90844
|
+
console.log(import_picocolors80.default.green(release.id === releaseId ? `✓ Release ${safe(releaseId)} is live (build ${safe(release.build_id)}).` : `✓ Republished release ${safe(releaseId)} as new release ${safe(release.id)} (build ${safe(release.build_id)}). It is live.`));
|
|
89876
90845
|
console.log(` ${safe(release.url)}`);
|
|
89877
90846
|
});
|
|
89878
90847
|
}
|
|
@@ -89907,14 +90876,14 @@ ${didYouMean(sub, Object.keys(COMMANDS2), "brainbase interface")}`);
|
|
|
89907
90876
|
await command({ cwd: cwd2, args, deps });
|
|
89908
90877
|
}
|
|
89909
90878
|
function line2(command, args, description) {
|
|
89910
|
-
return ` ${
|
|
89911
|
-
${
|
|
90879
|
+
return ` ${import_picocolors81.default.cyan(command)}${args ? ` ${import_picocolors81.default.dim(args)}` : ""}
|
|
90880
|
+
${import_picocolors81.default.dim(description)}`;
|
|
89912
90881
|
}
|
|
89913
90882
|
function printHelp7() {
|
|
89914
90883
|
const out = [];
|
|
89915
90884
|
out.push("");
|
|
89916
|
-
out.push(` ${
|
|
89917
|
-
out.push(` ${
|
|
90885
|
+
out.push(` ${import_picocolors81.default.bold("brainbase interface")} ${import_picocolors81.default.dim("<sub> [options]")}`);
|
|
90886
|
+
out.push(` ${import_picocolors81.default.dim("Dashboards for an agent: build them in a conversation, publish them, choose who can open them.")}`);
|
|
89918
90887
|
out.push("");
|
|
89919
90888
|
out.push(line2("ls", "[--agent <id>] [--archived | --only-archived]", "list interfaces you can see"));
|
|
89920
90889
|
out.push(line2("get", "<id>", "one interface: address, audience, live release, draft, running build conversation"));
|
|
@@ -89934,22 +90903,22 @@ function printHelp7() {
|
|
|
89934
90903
|
out.push(line2("rollback", "<id> --release <id>", "republish an earlier release; it goes live under a new release id"));
|
|
89935
90904
|
out.push(line2("preview", "<id> [--task <id>] [--no-wait]", "serve the unpublished draft from its build conversation and print the preview address"));
|
|
89936
90905
|
out.push("");
|
|
89937
|
-
out.push(` ${
|
|
89938
|
-
out.push(` ${
|
|
89939
|
-
out.push(` ${
|
|
89940
|
-
out.push(` ${
|
|
89941
|
-
out.push(` ${
|
|
90906
|
+
out.push(` ${import_picocolors81.default.dim("--json")} machine-readable output; never prompts`);
|
|
90907
|
+
out.push(` ${import_picocolors81.default.dim("--yes, -y")} skip confirmation (required without a terminal)`);
|
|
90908
|
+
out.push(` ${import_picocolors81.default.dim("--no-wait")} for rebuild and publish: return the operation at once; for preview: do not wait for the dev server`);
|
|
90909
|
+
out.push(` ${import_picocolors81.default.dim("--timeout <seconds>")} for build, rebuild, publish and preview: how long to wait (builds 900, publish and preview 300)`);
|
|
90910
|
+
out.push(` ${import_picocolors81.default.dim("--idempotency-key <key>")} replay a create, build, rebuild, publish or rollback whose answer was lost`);
|
|
89942
90911
|
out.push("");
|
|
89943
|
-
out.push(` ${
|
|
89944
|
-
out.push(` ${
|
|
89945
|
-
out.push(` ${
|
|
90912
|
+
out.push(` ${import_picocolors81.default.dim("People are emails (see `brainbase member ls`), user ids, or `me`. Audience members also need access to the agent.")}`);
|
|
90913
|
+
out.push(` ${import_picocolors81.default.dim("Audience: everyone (--everyone, `org` under --json) or chosen people (--people, `users` under --json).")}`);
|
|
90914
|
+
out.push(` ${import_picocolors81.default.dim("Exit codes: 0 done, 1 refused or failed, 130 interrupted (the server keeps working).")}`);
|
|
89946
90915
|
out.push("");
|
|
89947
90916
|
console.log(out.join(`
|
|
89948
90917
|
`));
|
|
89949
90918
|
}
|
|
89950
90919
|
|
|
89951
90920
|
// src/cli/member.ts
|
|
89952
|
-
var
|
|
90921
|
+
var import_picocolors82 = __toESM(require_picocolors(), 1);
|
|
89953
90922
|
async function runMember(sub, args, opts) {
|
|
89954
90923
|
if (args.some((arg) => arg === "--help" || arg === "-h")) {
|
|
89955
90924
|
printHelp8();
|
|
@@ -89992,7 +90961,7 @@ async function runMemberList(opts) {
|
|
|
89992
90961
|
function formatMemberList(members) {
|
|
89993
90962
|
if (members.length === 0)
|
|
89994
90963
|
return `
|
|
89995
|
-
${
|
|
90964
|
+
${import_picocolors82.default.dim("Nobody here you can see.")}
|
|
89996
90965
|
`;
|
|
89997
90966
|
const sorted = [...members].sort((a3, b4) => (a3.email ?? a3.id).localeCompare(b4.email ?? b4.id));
|
|
89998
90967
|
const rows = sorted.map((member) => ({
|
|
@@ -90006,24 +90975,24 @@ function formatMemberList(members) {
|
|
|
90006
90975
|
const roleWidth = Math.max(...rows.map((row) => row.role.length));
|
|
90007
90976
|
const lines = [""];
|
|
90008
90977
|
for (const row of rows) {
|
|
90009
|
-
lines.push(` ${row.email.padEnd(emailWidth)} ${row.name.padEnd(nameWidth)} ${
|
|
90978
|
+
lines.push(` ${row.email.padEnd(emailWidth)} ${row.name.padEnd(nameWidth)} ${import_picocolors82.default.dim(row.role.padEnd(roleWidth))} ${import_picocolors82.default.dim(row.teams)}`.trimEnd());
|
|
90010
90979
|
}
|
|
90011
|
-
lines.push("", ` ${
|
|
90980
|
+
lines.push("", ` ${import_picocolors82.default.dim("share a dashboard with one of them:")} ${import_picocolors82.default.cyan("brainbase interface access <id> --add <email>")}`, "");
|
|
90012
90981
|
return lines.join(`
|
|
90013
90982
|
`);
|
|
90014
90983
|
}
|
|
90015
90984
|
function printHelp8() {
|
|
90016
90985
|
const out = [];
|
|
90017
90986
|
out.push("");
|
|
90018
|
-
out.push(` ${
|
|
90987
|
+
out.push(` ${import_picocolors82.default.bold("brainbase member")} ${import_picocolors82.default.dim("<sub> [options]")}`);
|
|
90019
90988
|
out.push("");
|
|
90020
|
-
out.push(` ${
|
|
90989
|
+
out.push(` ${import_picocolors82.default.cyan("ls")} ${import_picocolors82.default.dim("the people in an organization you can see, with their emails, roles and teams")}`);
|
|
90021
90990
|
out.push("");
|
|
90022
|
-
out.push(` ${
|
|
90023
|
-
out.push(` ${
|
|
90991
|
+
out.push(` ${import_picocolors82.default.dim("--org <id-or-slug>")} ${import_picocolors82.default.dim("which organization (picked automatically when you are in one)")}`);
|
|
90992
|
+
out.push(` ${import_picocolors82.default.dim("--json")} ${import_picocolors82.default.dim("machine-readable output")}`);
|
|
90024
90993
|
out.push("");
|
|
90025
|
-
out.push(` ${
|
|
90026
|
-
out.push(` ${
|
|
90994
|
+
out.push(` ${import_picocolors82.default.dim("Owners and admins see everyone. Anyone else sees the owners, the admins, themselves")}`);
|
|
90995
|
+
out.push(` ${import_picocolors82.default.dim("and the people who share a team with them, as in the web app.")}`);
|
|
90027
90996
|
out.push("");
|
|
90028
90997
|
console.log(out.join(`
|
|
90029
90998
|
`));
|
|
@@ -91734,7 +92703,7 @@ async function runCommand(command, root, spec, context, options = {}) {
|
|
|
91734
92703
|
return error2;
|
|
91735
92704
|
return new BenchmarkCommandExecutionError(error2.code, error2.message, sanitizedOutput(stdout), sanitizedOutput(stderr), error2.durationMs);
|
|
91736
92705
|
};
|
|
91737
|
-
const
|
|
92706
|
+
const fail4 = (error2) => {
|
|
91738
92707
|
if (settled)
|
|
91739
92708
|
return;
|
|
91740
92709
|
settled = true;
|
|
@@ -91753,7 +92722,7 @@ async function runCommand(command, root, spec, context, options = {}) {
|
|
|
91753
92722
|
captured += chunk2.length;
|
|
91754
92723
|
context.remainingOutputBytes -= chunk2.length;
|
|
91755
92724
|
if (captured > spec.budget.max_output_bytes || context.remainingOutputBytes < 0) {
|
|
91756
|
-
|
|
92725
|
+
fail4(new BenchmarkPhaseError("output_limit_exceeded", `command output exceeded budget: ${command.id}`));
|
|
91757
92726
|
return;
|
|
91758
92727
|
}
|
|
91759
92728
|
target.push(chunk2);
|
|
@@ -91776,14 +92745,14 @@ async function runCommand(command, root, spec, context, options = {}) {
|
|
|
91776
92745
|
child.stdout?.on("data", (chunk2) => capture(stdout, chunk2));
|
|
91777
92746
|
child.stderr?.on("data", (chunk2) => capture(stderr, chunk2));
|
|
91778
92747
|
child.on("error", (error2) => {
|
|
91779
|
-
|
|
92748
|
+
fail4(new BenchmarkCommandExecutionError("command_start_failed", `failed to start ${command.id}: ${error2.message}`, Buffer.concat(stdout), Buffer.concat(stderr), Date.now() - started));
|
|
91780
92749
|
});
|
|
91781
92750
|
timer = setTimeout(() => {
|
|
91782
92751
|
if (reachesPhaseDeadline) {
|
|
91783
|
-
|
|
92752
|
+
fail4(new BenchmarkPhaseError("phase_timeout", "phase budget expired"));
|
|
91784
92753
|
return;
|
|
91785
92754
|
}
|
|
91786
|
-
|
|
92755
|
+
fail4(new BenchmarkCommandExecutionError("command_timeout", `command timed out: ${command.id}`, Buffer.concat(stdout), Buffer.concat(stderr), Date.now() - started));
|
|
91787
92756
|
}, timeoutMs3);
|
|
91788
92757
|
child.on("exit", (code, signal) => {
|
|
91789
92758
|
if (settled)
|
|
@@ -93116,7 +94085,7 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
|
|
|
93116
94085
|
}
|
|
93117
94086
|
|
|
93118
94087
|
// src/cli/benchmark-control.ts
|
|
93119
|
-
var
|
|
94088
|
+
var import_picocolors83 = __toESM(require_picocolors(), 1);
|
|
93120
94089
|
import fs92 from "node:fs";
|
|
93121
94090
|
import path103 from "node:path";
|
|
93122
94091
|
|
|
@@ -96130,20 +97099,20 @@ async function emitCursorPages(output, fetchPage, options) {
|
|
|
96130
97099
|
function commandHelp() {
|
|
96131
97100
|
return [
|
|
96132
97101
|
"",
|
|
96133
|
-
` ${
|
|
97102
|
+
` ${import_picocolors83.default.bold("brainbase benchmark")} ${import_picocolors83.default.dim("<command> [options]")}`,
|
|
96134
97103
|
"",
|
|
96135
|
-
` ${
|
|
96136
|
-
` ${
|
|
96137
|
-
` ${
|
|
96138
|
-
` ${
|
|
96139
|
-
` ${
|
|
97104
|
+
` ${import_picocolors83.default.cyan("init | list | show | create | validate | pull | push")}`,
|
|
97105
|
+
` ${import_picocolors83.default.cyan("publish | revisions | import | export | archive | restore")}`,
|
|
97106
|
+
` ${import_picocolors83.default.cyan("run plan|start|watch|list|show|cancel|resume")}`,
|
|
97107
|
+
` ${import_picocolors83.default.cyan("results | diagnoses | attempt | artifacts | export-results")}`,
|
|
97108
|
+
` ${import_picocolors83.default.cyan("history | baseline show|set|clear")}`,
|
|
96140
97109
|
"",
|
|
96141
|
-
` ${
|
|
97110
|
+
` ${import_picocolors83.default.dim("Use --agent to override brainbase.agent.yaml, and --json or --jsonl for automation.")}`,
|
|
96142
97111
|
"",
|
|
96143
|
-
` ${
|
|
96144
|
-
` ${
|
|
96145
|
-
` ${
|
|
96146
|
-
` ${
|
|
97112
|
+
` ${import_picocolors83.default.bold("benchmark runtime (machine-only)")}`,
|
|
97113
|
+
` ${import_picocolors83.default.cyan("hydrate")} ${import_picocolors83.default.dim("--spec <path> --result <path> --json")}`,
|
|
97114
|
+
` ${import_picocolors83.default.cyan("evaluate")} ${import_picocolors83.default.dim("--spec <path> --result <path> --json")}`,
|
|
97115
|
+
` ${import_picocolors83.default.cyan("capabilities")} ${import_picocolors83.default.dim("--json")}`,
|
|
96147
97116
|
""
|
|
96148
97117
|
].join(`
|
|
96149
97118
|
`);
|
|
@@ -97544,6 +98513,806 @@ async function runBenchmark(sub, args, write3 = (value2) => process.stdout.write
|
|
|
97544
98513
|
}
|
|
97545
98514
|
}
|
|
97546
98515
|
|
|
98516
|
+
// src/cli/decide.ts
|
|
98517
|
+
import fs95 from "node:fs";
|
|
98518
|
+
import path107 from "node:path";
|
|
98519
|
+
|
|
98520
|
+
// src/core/decide-api.ts
|
|
98521
|
+
import path105 from "node:path";
|
|
98522
|
+
function decideKeysFile() {
|
|
98523
|
+
return path105.join(process.env.BRAINBASE_HOME ?? BRAINBASE_HOME, "decide-keys.json");
|
|
98524
|
+
}
|
|
98525
|
+
var ATTEMPTS = 3;
|
|
98526
|
+
var RETRY_STATUSES = new Set([429, 502, 503, 504]);
|
|
98527
|
+
var MAX_RETRY_DELAY_MS = 30000;
|
|
98528
|
+
var REQUEST_TIMEOUT_MS3 = 5 * 60000;
|
|
98529
|
+
|
|
98530
|
+
class DecideHttpError extends Error {
|
|
98531
|
+
status;
|
|
98532
|
+
constructor(message3, status) {
|
|
98533
|
+
super(message3);
|
|
98534
|
+
this.status = status;
|
|
98535
|
+
this.name = "DecideHttpError";
|
|
98536
|
+
}
|
|
98537
|
+
}
|
|
98538
|
+
function cacheKey(base2, agentId) {
|
|
98539
|
+
return `${base2}|${agentId}`;
|
|
98540
|
+
}
|
|
98541
|
+
async function resolveDecideCredential(cwd2, agentFlag) {
|
|
98542
|
+
const base2 = proxyBaseUrl(authStatus().session ?? null);
|
|
98543
|
+
const taskKey = process.env.BB_TASK_KEY?.trim();
|
|
98544
|
+
if (taskKey)
|
|
98545
|
+
return { key: taskKey, base: base2, source: "task_key" };
|
|
98546
|
+
const agentId = agentFlag?.trim() || readLink(cwd2)?.agent_id;
|
|
98547
|
+
if (!agentId) {
|
|
98548
|
+
throw new DecideHttpError("No agent to bill. Run inside a linked folder, or pass --agent <id> (see `brainbase agent list`).", null);
|
|
98549
|
+
}
|
|
98550
|
+
const cached2 = readJsonOr(decideKeysFile(), {})[cacheKey(base2, agentId)];
|
|
98551
|
+
if (cached2?.key)
|
|
98552
|
+
return { key: cached2.key, base: base2, source: "agent_key", agentId };
|
|
98553
|
+
return mintAgentKey(base2, agentId);
|
|
98554
|
+
}
|
|
98555
|
+
async function mintAgentKey(base2, agentId) {
|
|
98556
|
+
const created = await api.createCliKey(agentId, { name: "brainbase decide" });
|
|
98557
|
+
const cache3 = readJsonOr(decideKeysFile(), {});
|
|
98558
|
+
cache3[cacheKey(base2, agentId)] = { key: created.key, key_id: created.id };
|
|
98559
|
+
writeJsonAtomic(decideKeysFile(), cache3);
|
|
98560
|
+
return { key: created.key, base: base2, source: "agent_key", agentId };
|
|
98561
|
+
}
|
|
98562
|
+
async function replaceAgentKey(credential) {
|
|
98563
|
+
if (credential.source !== "agent_key" || !credential.agentId)
|
|
98564
|
+
return credential;
|
|
98565
|
+
const cache3 = readJsonOr(decideKeysFile(), {});
|
|
98566
|
+
delete cache3[cacheKey(credential.base, credential.agentId)];
|
|
98567
|
+
writeJsonAtomic(decideKeysFile(), cache3);
|
|
98568
|
+
return mintAgentKey(credential.base, credential.agentId);
|
|
98569
|
+
}
|
|
98570
|
+
function retryDelayMs(attempt2, retryAfter) {
|
|
98571
|
+
const seconds = retryAfter === null ? Number.NaN : Number(retryAfter);
|
|
98572
|
+
const base2 = Number.isFinite(seconds) ? seconds * 1000 : 1000 * 2 ** attempt2;
|
|
98573
|
+
return Math.min(Math.max(base2, 0), MAX_RETRY_DELAY_MS) + Math.random() * 500;
|
|
98574
|
+
}
|
|
98575
|
+
function errorMessage3(status, text4) {
|
|
98576
|
+
try {
|
|
98577
|
+
const body = JSON.parse(text4);
|
|
98578
|
+
const message3 = body.error?.message ?? body.detail;
|
|
98579
|
+
if (typeof message3 === "string" && message3)
|
|
98580
|
+
return message3;
|
|
98581
|
+
} catch {}
|
|
98582
|
+
return `HTTP ${status}`;
|
|
98583
|
+
}
|
|
98584
|
+
async function postDecide(credential, body, options = {}) {
|
|
98585
|
+
const sleep3 = options.sleep ?? ((ms2) => new Promise((resolve) => setTimeout(resolve, ms2)));
|
|
98586
|
+
const payload = JSON.stringify(body);
|
|
98587
|
+
let failure = new DecideHttpError("The decide request failed", null);
|
|
98588
|
+
for (let attempt2 = 0;attempt2 < ATTEMPTS; attempt2 += 1) {
|
|
98589
|
+
let retryAfter = null;
|
|
98590
|
+
try {
|
|
98591
|
+
const response = await fetch(`${credential.base}/v1/decide`, {
|
|
98592
|
+
method: "POST",
|
|
98593
|
+
headers: {
|
|
98594
|
+
Authorization: `Bearer ${credential.key}`,
|
|
98595
|
+
"Content-Type": "application/json"
|
|
98596
|
+
},
|
|
98597
|
+
body: payload,
|
|
98598
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
|
|
98599
|
+
});
|
|
98600
|
+
const text4 = await response.text();
|
|
98601
|
+
if (response.ok) {
|
|
98602
|
+
try {
|
|
98603
|
+
return JSON.parse(text4);
|
|
98604
|
+
} catch {
|
|
98605
|
+
throw new DecideHttpError("The server sent an unreadable response", response.status);
|
|
98606
|
+
}
|
|
98607
|
+
}
|
|
98608
|
+
failure = new DecideHttpError(errorMessage3(response.status, text4), response.status);
|
|
98609
|
+
if (!RETRY_STATUSES.has(response.status))
|
|
98610
|
+
throw failure;
|
|
98611
|
+
retryAfter = response.headers.get("retry-after");
|
|
98612
|
+
} catch (error2) {
|
|
98613
|
+
if (error2 instanceof DecideHttpError)
|
|
98614
|
+
throw error2;
|
|
98615
|
+
failure = new DecideHttpError(`Network error: ${error2.message}`, null);
|
|
98616
|
+
}
|
|
98617
|
+
if (attempt2 + 1 < ATTEMPTS)
|
|
98618
|
+
await sleep3(retryDelayMs(attempt2, retryAfter));
|
|
98619
|
+
}
|
|
98620
|
+
throw failure;
|
|
98621
|
+
}
|
|
98622
|
+
|
|
98623
|
+
// src/core/decide-items.ts
|
|
98624
|
+
import fs94 from "node:fs";
|
|
98625
|
+
import path106 from "node:path";
|
|
98626
|
+
|
|
98627
|
+
class DecideInputError extends Error {
|
|
98628
|
+
constructor(message3) {
|
|
98629
|
+
super(message3);
|
|
98630
|
+
this.name = "DecideInputError";
|
|
98631
|
+
}
|
|
98632
|
+
}
|
|
98633
|
+
var GLOB_CHARS = /[*?[{]/;
|
|
98634
|
+
function fileId(cwd2, file) {
|
|
98635
|
+
return path106.relative(cwd2, file).split(path106.sep).join("/") || path106.basename(file);
|
|
98636
|
+
}
|
|
98637
|
+
function isHidden2(name) {
|
|
98638
|
+
return name.startsWith(".") || name === "node_modules";
|
|
98639
|
+
}
|
|
98640
|
+
function appendAll(into, from) {
|
|
98641
|
+
for (const value2 of from)
|
|
98642
|
+
into.push(value2);
|
|
98643
|
+
}
|
|
98644
|
+
function walk(dir, out = []) {
|
|
98645
|
+
for (const entry of fs94.readdirSync(dir, { withFileTypes: true })) {
|
|
98646
|
+
if (isHidden2(entry.name))
|
|
98647
|
+
continue;
|
|
98648
|
+
const full = path106.join(dir, entry.name);
|
|
98649
|
+
if (entry.isDirectory())
|
|
98650
|
+
walk(full, out);
|
|
98651
|
+
else if (entry.isFile())
|
|
98652
|
+
out.push(full);
|
|
98653
|
+
else if (entry.isSymbolicLink()) {
|
|
98654
|
+
try {
|
|
98655
|
+
if (fs94.statSync(full).isFile())
|
|
98656
|
+
out.push(full);
|
|
98657
|
+
} catch {}
|
|
98658
|
+
}
|
|
98659
|
+
}
|
|
98660
|
+
return out;
|
|
98661
|
+
}
|
|
98662
|
+
function walkSorted(dir) {
|
|
98663
|
+
return walk(dir).sort();
|
|
98664
|
+
}
|
|
98665
|
+
function globToRegExp(pattern2) {
|
|
98666
|
+
let source = "";
|
|
98667
|
+
for (let i = 0;i < pattern2.length; i += 1) {
|
|
98668
|
+
const char = pattern2[i];
|
|
98669
|
+
if (char === "*") {
|
|
98670
|
+
if (pattern2[i + 1] === "*") {
|
|
98671
|
+
const slashFollows = pattern2[i + 2] === "/";
|
|
98672
|
+
source += slashFollows ? "(?:.*/)?" : ".*";
|
|
98673
|
+
i += slashFollows ? 2 : 1;
|
|
98674
|
+
} else {
|
|
98675
|
+
source += "[^/]*";
|
|
98676
|
+
}
|
|
98677
|
+
} else if (char === "?") {
|
|
98678
|
+
source += "[^/]";
|
|
98679
|
+
} else if (char === "{") {
|
|
98680
|
+
const close = pattern2.indexOf("}", i);
|
|
98681
|
+
if (close === -1) {
|
|
98682
|
+
source += "\\{";
|
|
98683
|
+
continue;
|
|
98684
|
+
}
|
|
98685
|
+
const choices = pattern2.slice(i + 1, close).split(",");
|
|
98686
|
+
source += `(?:${choices.map((choice) => globToRegExp(choice).source.slice(1, -1)).join("|")})`;
|
|
98687
|
+
i = close;
|
|
98688
|
+
} else if (char === "[") {
|
|
98689
|
+
const close = pattern2.indexOf("]", i + 1);
|
|
98690
|
+
if (close === -1) {
|
|
98691
|
+
source += "\\[";
|
|
98692
|
+
continue;
|
|
98693
|
+
}
|
|
98694
|
+
let body = pattern2.slice(i + 1, close);
|
|
98695
|
+
if (body.startsWith("!"))
|
|
98696
|
+
body = `^${body.slice(1)}`;
|
|
98697
|
+
source += `[${body.replace(/\\/g, "\\\\")}]`;
|
|
98698
|
+
i = close;
|
|
98699
|
+
} else {
|
|
98700
|
+
source += char.replace(/[.+^$()|\\/]/g, "\\$&");
|
|
98701
|
+
}
|
|
98702
|
+
}
|
|
98703
|
+
return new RegExp(`^${source}$`);
|
|
98704
|
+
}
|
|
98705
|
+
function expandGlob(cwd2, pattern2) {
|
|
98706
|
+
const absolute = path106.isAbsolute(pattern2);
|
|
98707
|
+
const segments = pattern2.split("/");
|
|
98708
|
+
const fixed = [];
|
|
98709
|
+
for (const segment of segments) {
|
|
98710
|
+
if (GLOB_CHARS.test(segment))
|
|
98711
|
+
break;
|
|
98712
|
+
fixed.push(segment);
|
|
98713
|
+
}
|
|
98714
|
+
if (fixed.length === segments.length) {
|
|
98715
|
+
return [path106.resolve(cwd2, pattern2)];
|
|
98716
|
+
}
|
|
98717
|
+
const root = path106.resolve(cwd2, fixed.join("/") || ".");
|
|
98718
|
+
if (!fs94.existsSync(root) || !fs94.statSync(root).isDirectory())
|
|
98719
|
+
return [];
|
|
98720
|
+
const matcher = globToRegExp(absolute ? pattern2 : path106.posix.normalize(segments.join("/")));
|
|
98721
|
+
return walkSorted(root).filter((file) => {
|
|
98722
|
+
const candidate = absolute ? file.split(path106.sep).join("/") : fileId(cwd2, file);
|
|
98723
|
+
return matcher.test(candidate);
|
|
98724
|
+
});
|
|
98725
|
+
}
|
|
98726
|
+
function readFileItem(cwd2, file) {
|
|
98727
|
+
const id = fileId(cwd2, file);
|
|
98728
|
+
let bytes;
|
|
98729
|
+
try {
|
|
98730
|
+
bytes = fs94.readFileSync(file);
|
|
98731
|
+
} catch (error2) {
|
|
98732
|
+
return { id, error: `Could not read the file: ${error2.message}` };
|
|
98733
|
+
}
|
|
98734
|
+
if (bytes.includes(0))
|
|
98735
|
+
return { id, error: "Not a text file" };
|
|
98736
|
+
let text4;
|
|
98737
|
+
try {
|
|
98738
|
+
text4 = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
98739
|
+
} catch {
|
|
98740
|
+
return { id, error: "Not UTF-8 text" };
|
|
98741
|
+
}
|
|
98742
|
+
if (!text4.trim())
|
|
98743
|
+
return { id, error: "Empty file" };
|
|
98744
|
+
return { id, text: text4 };
|
|
98745
|
+
}
|
|
98746
|
+
function fileItems(cwd2, paths, globs) {
|
|
98747
|
+
const files = [];
|
|
98748
|
+
for (const entry of paths) {
|
|
98749
|
+
const full = path106.resolve(cwd2, entry);
|
|
98750
|
+
let stat;
|
|
98751
|
+
try {
|
|
98752
|
+
stat = fs94.statSync(full);
|
|
98753
|
+
} catch {
|
|
98754
|
+
throw new DecideInputError(`No such file or directory: ${entry}`);
|
|
98755
|
+
}
|
|
98756
|
+
if (stat.isDirectory())
|
|
98757
|
+
appendAll(files, walkSorted(full));
|
|
98758
|
+
else
|
|
98759
|
+
files.push(full);
|
|
98760
|
+
}
|
|
98761
|
+
for (const pattern2 of globs) {
|
|
98762
|
+
const matched = expandGlob(cwd2, pattern2);
|
|
98763
|
+
if (matched.length === 0 || !matched.some((file) => fs94.existsSync(file))) {
|
|
98764
|
+
throw new DecideInputError(`No files match ${pattern2}`);
|
|
98765
|
+
}
|
|
98766
|
+
appendAll(files, matched);
|
|
98767
|
+
}
|
|
98768
|
+
return [...new Set(files)];
|
|
98769
|
+
}
|
|
98770
|
+
function readFileItems(cwd2, files) {
|
|
98771
|
+
const set3 = { items: [], failures: [] };
|
|
98772
|
+
for (const file of files) {
|
|
98773
|
+
const item = readFileItem(cwd2, file);
|
|
98774
|
+
if ("error" in item)
|
|
98775
|
+
set3.failures.push(item);
|
|
98776
|
+
else
|
|
98777
|
+
set3.items.push(item);
|
|
98778
|
+
}
|
|
98779
|
+
return set3;
|
|
98780
|
+
}
|
|
98781
|
+
function isRecord2(value2) {
|
|
98782
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
98783
|
+
}
|
|
98784
|
+
function rowItem(row, options, fallbackId) {
|
|
98785
|
+
const idField = options.idField ?? "id";
|
|
98786
|
+
const rawId = isRecord2(row) ? row[idField] : undefined;
|
|
98787
|
+
let id = fallbackId;
|
|
98788
|
+
if (rawId !== undefined && rawId !== null && rawId !== "")
|
|
98789
|
+
id = String(rawId);
|
|
98790
|
+
else if (options.idField)
|
|
98791
|
+
return { id: fallbackId, error: `Missing ${options.idField}` };
|
|
98792
|
+
if (options.textFields.length === 0)
|
|
98793
|
+
return { id, json: row };
|
|
98794
|
+
if (!isRecord2(row))
|
|
98795
|
+
return { id, error: "Not an object, so --text-field has nothing to select" };
|
|
98796
|
+
if (options.textFields.length === 1) {
|
|
98797
|
+
const field2 = options.textFields[0];
|
|
98798
|
+
const value2 = row[field2];
|
|
98799
|
+
if (value2 === undefined || value2 === null || value2 === "")
|
|
98800
|
+
return { id, error: `Empty ${field2}` };
|
|
98801
|
+
return { id, text: typeof value2 === "string" ? value2 : JSON.stringify(value2) };
|
|
98802
|
+
}
|
|
98803
|
+
const missing = options.textFields.filter((field2) => row[field2] === undefined);
|
|
98804
|
+
if (missing.length)
|
|
98805
|
+
return { id, error: `Missing ${missing.join(", ")}` };
|
|
98806
|
+
const picked = {};
|
|
98807
|
+
for (const field2 of options.textFields)
|
|
98808
|
+
picked[field2] = row[field2];
|
|
98809
|
+
return { id, json: picked };
|
|
98810
|
+
}
|
|
98811
|
+
function sourceLabel(cwd2, file) {
|
|
98812
|
+
return fileId(cwd2, path106.resolve(cwd2, file));
|
|
98813
|
+
}
|
|
98814
|
+
function readSource(cwd2, file) {
|
|
98815
|
+
try {
|
|
98816
|
+
return fs94.readFileSync(path106.resolve(cwd2, file), "utf8");
|
|
98817
|
+
} catch (error2) {
|
|
98818
|
+
throw new DecideInputError(`Could not read ${file}: ${error2.message}`);
|
|
98819
|
+
}
|
|
98820
|
+
}
|
|
98821
|
+
function jsonlItems(cwd2, file, options) {
|
|
98822
|
+
const set3 = { items: [], failures: [] };
|
|
98823
|
+
const label3 = sourceLabel(cwd2, file);
|
|
98824
|
+
readSource(cwd2, file).split(`
|
|
98825
|
+
`).forEach((line3, index) => {
|
|
98826
|
+
if (!line3.trim())
|
|
98827
|
+
return;
|
|
98828
|
+
const fallbackId = `${label3}:${index + 1}`;
|
|
98829
|
+
let row;
|
|
98830
|
+
try {
|
|
98831
|
+
row = JSON.parse(line3);
|
|
98832
|
+
} catch {
|
|
98833
|
+
set3.failures.push({ id: fallbackId, error: "Not valid JSON" });
|
|
98834
|
+
return;
|
|
98835
|
+
}
|
|
98836
|
+
const item = rowItem(row, options, fallbackId);
|
|
98837
|
+
if ("error" in item)
|
|
98838
|
+
set3.failures.push(item);
|
|
98839
|
+
else
|
|
98840
|
+
set3.items.push(item);
|
|
98841
|
+
});
|
|
98842
|
+
return set3;
|
|
98843
|
+
}
|
|
98844
|
+
function parseCsv(text4) {
|
|
98845
|
+
const rows = [];
|
|
98846
|
+
let row = [];
|
|
98847
|
+
let field2 = "";
|
|
98848
|
+
let quoted = false;
|
|
98849
|
+
for (let i = 0;i < text4.length; i += 1) {
|
|
98850
|
+
const char = text4[i];
|
|
98851
|
+
if (quoted) {
|
|
98852
|
+
if (char === '"' && text4[i + 1] === '"') {
|
|
98853
|
+
field2 += '"';
|
|
98854
|
+
i += 1;
|
|
98855
|
+
} else if (char === '"') {
|
|
98856
|
+
quoted = false;
|
|
98857
|
+
} else {
|
|
98858
|
+
field2 += char;
|
|
98859
|
+
}
|
|
98860
|
+
} else if (char === '"' && field2 === "") {
|
|
98861
|
+
quoted = true;
|
|
98862
|
+
} else if (char === ",") {
|
|
98863
|
+
row.push(field2);
|
|
98864
|
+
field2 = "";
|
|
98865
|
+
} else if (char === `
|
|
98866
|
+
` || char === "\r") {
|
|
98867
|
+
if (char === "\r" && text4[i + 1] === `
|
|
98868
|
+
`)
|
|
98869
|
+
i += 1;
|
|
98870
|
+
row.push(field2);
|
|
98871
|
+
rows.push(row);
|
|
98872
|
+
row = [];
|
|
98873
|
+
field2 = "";
|
|
98874
|
+
} else {
|
|
98875
|
+
field2 += char;
|
|
98876
|
+
}
|
|
98877
|
+
}
|
|
98878
|
+
if (field2 !== "" || row.length > 0) {
|
|
98879
|
+
row.push(field2);
|
|
98880
|
+
rows.push(row);
|
|
98881
|
+
}
|
|
98882
|
+
return rows.filter((cells) => cells.some((cell) => cell !== ""));
|
|
98883
|
+
}
|
|
98884
|
+
function csvItems(cwd2, file, options) {
|
|
98885
|
+
const set3 = { items: [], failures: [] };
|
|
98886
|
+
const label3 = sourceLabel(cwd2, file);
|
|
98887
|
+
const [header, ...rows] = parseCsv(readSource(cwd2, file).replace(/^/, ""));
|
|
98888
|
+
if (!header)
|
|
98889
|
+
return set3;
|
|
98890
|
+
rows.forEach((cells, index) => {
|
|
98891
|
+
const row = {};
|
|
98892
|
+
header.forEach((name, column) => {
|
|
98893
|
+
row[name] = cells[column] ?? "";
|
|
98894
|
+
});
|
|
98895
|
+
const item = rowItem(row, options, `${label3}:${index + 2}`);
|
|
98896
|
+
if ("error" in item)
|
|
98897
|
+
set3.failures.push(item);
|
|
98898
|
+
else
|
|
98899
|
+
set3.items.push(item);
|
|
98900
|
+
});
|
|
98901
|
+
return set3;
|
|
98902
|
+
}
|
|
98903
|
+
function readResults(file) {
|
|
98904
|
+
const rows = new Map;
|
|
98905
|
+
if (!fs94.existsSync(file))
|
|
98906
|
+
return rows;
|
|
98907
|
+
for (const line3 of fs94.readFileSync(file, "utf8").split(`
|
|
98908
|
+
`)) {
|
|
98909
|
+
if (!line3.trim())
|
|
98910
|
+
continue;
|
|
98911
|
+
try {
|
|
98912
|
+
const row = JSON.parse(line3);
|
|
98913
|
+
if (row && typeof row.id === "string")
|
|
98914
|
+
rows.set(row.id, row);
|
|
98915
|
+
} catch {}
|
|
98916
|
+
}
|
|
98917
|
+
return rows;
|
|
98918
|
+
}
|
|
98919
|
+
function repairResultsTail(file) {
|
|
98920
|
+
if (!fs94.existsSync(file))
|
|
98921
|
+
return;
|
|
98922
|
+
const text4 = fs94.readFileSync(file, "utf8");
|
|
98923
|
+
if (!text4 || text4.endsWith(`
|
|
98924
|
+
`))
|
|
98925
|
+
return;
|
|
98926
|
+
const cut = text4.lastIndexOf(`
|
|
98927
|
+
`) + 1;
|
|
98928
|
+
const tail2 = text4.slice(cut);
|
|
98929
|
+
let complete = false;
|
|
98930
|
+
try {
|
|
98931
|
+
const row = JSON.parse(tail2);
|
|
98932
|
+
complete = Boolean(row) && typeof row.id === "string";
|
|
98933
|
+
} catch {
|
|
98934
|
+
complete = false;
|
|
98935
|
+
}
|
|
98936
|
+
if (complete)
|
|
98937
|
+
fs94.appendFileSync(file, `
|
|
98938
|
+
`);
|
|
98939
|
+
else
|
|
98940
|
+
fs94.truncateSync(file, Buffer.byteLength(text4.slice(0, cut)));
|
|
98941
|
+
}
|
|
98942
|
+
function parseWhere(value2) {
|
|
98943
|
+
if (value2 === "failed")
|
|
98944
|
+
return { kind: "failed" };
|
|
98945
|
+
if (value2 === "uncertain")
|
|
98946
|
+
return { kind: "uncertain" };
|
|
98947
|
+
const split2 = value2.indexOf("=");
|
|
98948
|
+
if (split2 > 0 && split2 < value2.length - 1) {
|
|
98949
|
+
return { kind: "answer", question: value2.slice(0, split2), answer: value2.slice(split2 + 1) };
|
|
98950
|
+
}
|
|
98951
|
+
throw new DecideInputError(`--where takes failed, uncertain or <question>=<answer>, not ${value2}`);
|
|
98952
|
+
}
|
|
98953
|
+
function rowMatches(row, where) {
|
|
98954
|
+
switch (where.kind) {
|
|
98955
|
+
case "failed":
|
|
98956
|
+
return row.error !== undefined;
|
|
98957
|
+
case "uncertain":
|
|
98958
|
+
return row.error === undefined && row.uncertain === true;
|
|
98959
|
+
case "answer":
|
|
98960
|
+
return row.error === undefined && row.answers?.[where.question]?.choice === where.answer;
|
|
98961
|
+
}
|
|
98962
|
+
}
|
|
98963
|
+
|
|
98964
|
+
// src/cli/decide.ts
|
|
98965
|
+
var DEFAULT_OUT = "decide-results.jsonl";
|
|
98966
|
+
var MAX_ITEMS_PER_REQUEST = 200;
|
|
98967
|
+
var MAX_REQUEST_BYTES = 6 * 1024 * 1024;
|
|
98968
|
+
var DEFAULT_CONCURRENCY = 4;
|
|
98969
|
+
var MAX_CONCURRENCY = 16;
|
|
98970
|
+
var SUMMARY_UNCERTAIN_IDS = 20;
|
|
98971
|
+
var SUMMARY_FAILED = 10;
|
|
98972
|
+
var STOP_STATUSES = new Set([401, 402, 403, 404]);
|
|
98973
|
+
var OPTIONS2 = [
|
|
98974
|
+
{ key: "questions", names: ["--questions", "-q"], kind: "value" },
|
|
98975
|
+
{ key: "items", names: ["--items"], kind: "value", multiple: true },
|
|
98976
|
+
{ key: "jsonl", names: ["--jsonl"], kind: "value", multiple: true },
|
|
98977
|
+
{ key: "csv", names: ["--csv"], kind: "value", multiple: true },
|
|
98978
|
+
{ key: "idField", names: ["--id-field"], kind: "value" },
|
|
98979
|
+
{ key: "textField", names: ["--text-field"], kind: "value", multiple: true },
|
|
98980
|
+
{ key: "model", names: ["--model"], kind: "value" },
|
|
98981
|
+
{ key: "minConfidence", names: ["--min-confidence"], kind: "value" },
|
|
98982
|
+
{ key: "out", names: ["--out", "-o"], kind: "value" },
|
|
98983
|
+
{ key: "resume", names: ["--resume"], kind: "boolean" },
|
|
98984
|
+
{ key: "overwrite", names: ["--overwrite"], kind: "boolean" },
|
|
98985
|
+
{ key: "selectFrom", names: ["--select-from"], kind: "value" },
|
|
98986
|
+
{ key: "where", names: ["--where"], kind: "value" },
|
|
98987
|
+
{ key: "agent", names: ["--agent"], kind: "value" },
|
|
98988
|
+
{ key: "concurrency", names: ["--concurrency"], kind: "value" },
|
|
98989
|
+
{ key: "help", names: ["--help", "-h"], kind: "boolean" }
|
|
98990
|
+
];
|
|
98991
|
+
var DECIDE_USAGE = `Usage: brainbase decide --questions <file.json> <sources...> [options]
|
|
98992
|
+
|
|
98993
|
+
Answer the same decision-model questions over many items. Items are read on
|
|
98994
|
+
this machine and never pass through your agent's context.
|
|
98995
|
+
|
|
98996
|
+
Sources (at least one):
|
|
98997
|
+
<path>... files, or directories (every file under them)
|
|
98998
|
+
--items <glob> files matching a glob; quote it ('docs/**/*.md')
|
|
98999
|
+
--jsonl <file> one item per line
|
|
99000
|
+
--csv <file> one item per row; the first row names the fields
|
|
99001
|
+
--id-field <name> JSONL/CSV field holding each item's id
|
|
99002
|
+
(default: id when present, else file:line)
|
|
99003
|
+
--text-field <name> field to judge; repeat for several (a row
|
|
99004
|
+
missing any of them fails without being sent)
|
|
99005
|
+
(default: the whole row)
|
|
99006
|
+
|
|
99007
|
+
Questions:
|
|
99008
|
+
--questions, -q <file> JSON object of System One questions, e.g.
|
|
99009
|
+
{"team": {"type": "choice", "instructions": "Which team?",
|
|
99010
|
+
"criteria": {"billing": "...", "infra": "..."}}}
|
|
99011
|
+
--model <slug> jev, kev-4b, clef, clef-flash or gpt-6-luna
|
|
99012
|
+
(default: the server's default)
|
|
99013
|
+
--min-confidence <0-1> mark answers below this confidence as uncertain
|
|
99014
|
+
|
|
99015
|
+
Results:
|
|
99016
|
+
--out, -o <file> one JSON line per item (default: ${DEFAULT_OUT})
|
|
99017
|
+
--resume skip ids already answered in --out; append the rest
|
|
99018
|
+
--overwrite replace an existing --out
|
|
99019
|
+
--select-from <file> only items whose row in this earlier results file
|
|
99020
|
+
--where <filter> matches: failed, uncertain or <question>=<answer>
|
|
99021
|
+
|
|
99022
|
+
Other:
|
|
99023
|
+
--agent <id> agent to bill outside a Brainbase task
|
|
99024
|
+
(default: this folder's linked agent)
|
|
99025
|
+
--concurrency <n> requests in flight, 1-${MAX_CONCURRENCY} (default: ${DEFAULT_CONCURRENCY})
|
|
99026
|
+
|
|
99027
|
+
Prints one JSON summary on stdout. Exits 0 when every item was sent (check
|
|
99028
|
+
counts.failed), 1 when the run stopped early (rerun with --resume), 2 for a
|
|
99029
|
+
usage error.
|
|
99030
|
+
`;
|
|
99031
|
+
function usageError2(stderr, message3) {
|
|
99032
|
+
stderr(`brainbase decide: ${message3}
|
|
99033
|
+
Run \`brainbase decide --help\` for usage.
|
|
99034
|
+
`);
|
|
99035
|
+
return 2;
|
|
99036
|
+
}
|
|
99037
|
+
function readQuestions(cwd2, file) {
|
|
99038
|
+
let parsed;
|
|
99039
|
+
try {
|
|
99040
|
+
parsed = JSON.parse(fs95.readFileSync(path107.resolve(cwd2, file), "utf8"));
|
|
99041
|
+
} catch (error2) {
|
|
99042
|
+
throw new DecideInputError(`Could not read questions from ${file}: ${error2.message}`);
|
|
99043
|
+
}
|
|
99044
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || !Object.keys(parsed).length) {
|
|
99045
|
+
throw new DecideInputError(`${file} must hold a JSON object of questions`);
|
|
99046
|
+
}
|
|
99047
|
+
return parsed;
|
|
99048
|
+
}
|
|
99049
|
+
function mergeSets(sets) {
|
|
99050
|
+
const merged = { items: [], failures: [] };
|
|
99051
|
+
for (const set3 of sets) {
|
|
99052
|
+
appendAll(merged.items, set3.items);
|
|
99053
|
+
appendAll(merged.failures, set3.failures);
|
|
99054
|
+
}
|
|
99055
|
+
const seen = new Set;
|
|
99056
|
+
for (const { id } of [...merged.items, ...merged.failures]) {
|
|
99057
|
+
if (seen.has(id)) {
|
|
99058
|
+
throw new DecideInputError(`Two items share the id ${JSON.stringify(id)}; pass --id-field naming a unique field`);
|
|
99059
|
+
}
|
|
99060
|
+
seen.add(id);
|
|
99061
|
+
}
|
|
99062
|
+
return merged;
|
|
99063
|
+
}
|
|
99064
|
+
function chunk2(items, failures) {
|
|
99065
|
+
const chunks = [];
|
|
99066
|
+
let current = [];
|
|
99067
|
+
let bytes = 0;
|
|
99068
|
+
for (const item of items) {
|
|
99069
|
+
const size2 = Buffer.byteLength(JSON.stringify(item));
|
|
99070
|
+
if (size2 > MAX_REQUEST_BYTES) {
|
|
99071
|
+
failures.push({ id: item.id, error: "Larger than one request can carry (6 MB)" });
|
|
99072
|
+
continue;
|
|
99073
|
+
}
|
|
99074
|
+
if (current.length === MAX_ITEMS_PER_REQUEST || bytes + size2 > MAX_REQUEST_BYTES) {
|
|
99075
|
+
chunks.push(current);
|
|
99076
|
+
current = [];
|
|
99077
|
+
bytes = 0;
|
|
99078
|
+
}
|
|
99079
|
+
current.push(item);
|
|
99080
|
+
bytes += size2;
|
|
99081
|
+
}
|
|
99082
|
+
if (current.length)
|
|
99083
|
+
chunks.push(current);
|
|
99084
|
+
return chunks;
|
|
99085
|
+
}
|
|
99086
|
+
|
|
99087
|
+
class Tally {
|
|
99088
|
+
done = 0;
|
|
99089
|
+
uncertainIds = [];
|
|
99090
|
+
failed = [];
|
|
99091
|
+
answers = {};
|
|
99092
|
+
credits = 0;
|
|
99093
|
+
model = null;
|
|
99094
|
+
addRow(row) {
|
|
99095
|
+
if (row.error !== undefined) {
|
|
99096
|
+
this.failed.push({ id: row.id, reason: row.error });
|
|
99097
|
+
return;
|
|
99098
|
+
}
|
|
99099
|
+
this.done += 1;
|
|
99100
|
+
if (row.uncertain)
|
|
99101
|
+
this.uncertainIds.push(row.id);
|
|
99102
|
+
}
|
|
99103
|
+
addResponse(response) {
|
|
99104
|
+
this.model ??= response.model;
|
|
99105
|
+
this.credits += response.credits;
|
|
99106
|
+
for (const [question, counts] of Object.entries(response.answers)) {
|
|
99107
|
+
const into = this.answers[question] ??= {};
|
|
99108
|
+
for (const [answer, count] of Object.entries(counts)) {
|
|
99109
|
+
into[answer] = (into[answer] ?? 0) + count;
|
|
99110
|
+
}
|
|
99111
|
+
}
|
|
99112
|
+
}
|
|
99113
|
+
}
|
|
99114
|
+
async function runDecide(cwd2, argv, deps = {}) {
|
|
99115
|
+
const stdout = deps.stdout ?? ((text4) => void process.stdout.write(text4));
|
|
99116
|
+
const stderr = deps.stderr ?? ((text4) => void process.stderr.write(text4));
|
|
99117
|
+
const started = Date.now();
|
|
99118
|
+
let parsed;
|
|
99119
|
+
try {
|
|
99120
|
+
parsed = parseArgv(argv, OPTIONS2);
|
|
99121
|
+
} catch (error2) {
|
|
99122
|
+
if (error2 instanceof ArgvParseError)
|
|
99123
|
+
return usageError2(stderr, error2.message);
|
|
99124
|
+
throw error2;
|
|
99125
|
+
}
|
|
99126
|
+
if (booleanOption(parsed, "help")) {
|
|
99127
|
+
stdout(DECIDE_USAGE);
|
|
99128
|
+
return 0;
|
|
99129
|
+
}
|
|
99130
|
+
const questionsFile = stringOption(parsed, "questions");
|
|
99131
|
+
if (!questionsFile)
|
|
99132
|
+
return usageError2(stderr, "--questions <file.json> is required");
|
|
99133
|
+
const paths = parsed.positionals;
|
|
99134
|
+
const globs = stringOptions(parsed, "items");
|
|
99135
|
+
const jsonlFiles = stringOptions(parsed, "jsonl");
|
|
99136
|
+
const csvFiles = stringOptions(parsed, "csv");
|
|
99137
|
+
if (!paths.length && !globs.length && !jsonlFiles.length && !csvFiles.length) {
|
|
99138
|
+
return usageError2(stderr, "name at least one source: paths, --items, --jsonl or --csv");
|
|
99139
|
+
}
|
|
99140
|
+
const minConfidenceRaw = stringOption(parsed, "minConfidence");
|
|
99141
|
+
const minConfidence = minConfidenceRaw === undefined ? undefined : Number(minConfidenceRaw);
|
|
99142
|
+
if (minConfidence !== undefined && !(minConfidence >= 0 && minConfidence <= 1)) {
|
|
99143
|
+
return usageError2(stderr, "--min-confidence takes a number from 0 to 1");
|
|
99144
|
+
}
|
|
99145
|
+
const concurrencyRaw = stringOption(parsed, "concurrency");
|
|
99146
|
+
const concurrency = concurrencyRaw === undefined ? DEFAULT_CONCURRENCY : Number(concurrencyRaw);
|
|
99147
|
+
if (!Number.isInteger(concurrency) || concurrency < 1 || concurrency > MAX_CONCURRENCY) {
|
|
99148
|
+
return usageError2(stderr, `--concurrency takes a whole number from 1 to ${MAX_CONCURRENCY}`);
|
|
99149
|
+
}
|
|
99150
|
+
const selectFrom = stringOption(parsed, "selectFrom");
|
|
99151
|
+
const whereRaw = stringOption(parsed, "where");
|
|
99152
|
+
if (Boolean(selectFrom) !== Boolean(whereRaw)) {
|
|
99153
|
+
return usageError2(stderr, "--select-from and --where go together");
|
|
99154
|
+
}
|
|
99155
|
+
const resume = booleanOption(parsed, "resume");
|
|
99156
|
+
const overwrite = booleanOption(parsed, "overwrite");
|
|
99157
|
+
if (resume && overwrite)
|
|
99158
|
+
return usageError2(stderr, "--resume and --overwrite cannot be combined");
|
|
99159
|
+
const outArg = stringOption(parsed, "out") ?? DEFAULT_OUT;
|
|
99160
|
+
const outPath = path107.resolve(cwd2, outArg);
|
|
99161
|
+
let questions;
|
|
99162
|
+
let set3;
|
|
99163
|
+
let skipped = 0;
|
|
99164
|
+
try {
|
|
99165
|
+
questions = readQuestions(cwd2, questionsFile);
|
|
99166
|
+
const rowOptions = {
|
|
99167
|
+
idField: stringOption(parsed, "idField"),
|
|
99168
|
+
textFields: stringOptions(parsed, "textField")
|
|
99169
|
+
};
|
|
99170
|
+
set3 = mergeSets([
|
|
99171
|
+
readFileItems(cwd2, fileItems(cwd2, paths, globs)),
|
|
99172
|
+
...jsonlFiles.map((file) => jsonlItems(cwd2, file, rowOptions)),
|
|
99173
|
+
...csvFiles.map((file) => csvItems(cwd2, file, rowOptions))
|
|
99174
|
+
]);
|
|
99175
|
+
if (selectFrom && whereRaw) {
|
|
99176
|
+
const where = parseWhere(whereRaw);
|
|
99177
|
+
const earlier = path107.resolve(cwd2, selectFrom);
|
|
99178
|
+
if (!fs95.existsSync(earlier))
|
|
99179
|
+
throw new DecideInputError(`No such results file: ${selectFrom}`);
|
|
99180
|
+
const rows = readResults(earlier);
|
|
99181
|
+
const keep = (id) => {
|
|
99182
|
+
const row = rows.get(id);
|
|
99183
|
+
return row !== undefined && rowMatches(row, where);
|
|
99184
|
+
};
|
|
99185
|
+
set3 = { items: set3.items.filter((item) => keep(item.id)), failures: set3.failures.filter((f4) => keep(f4.id)) };
|
|
99186
|
+
}
|
|
99187
|
+
const outHasRows = fs95.existsSync(outPath) && fs95.statSync(outPath).size > 0;
|
|
99188
|
+
if (outHasRows && !resume && !overwrite) {
|
|
99189
|
+
throw new DecideInputError(`${outArg} already has results; pass --resume to continue it or --overwrite to replace it`);
|
|
99190
|
+
}
|
|
99191
|
+
if (resume) {
|
|
99192
|
+
const answered = new Set([...readResults(outPath).values()].filter((row) => row.error === undefined).map((row) => row.id));
|
|
99193
|
+
const before2 = set3.items.length + set3.failures.length;
|
|
99194
|
+
set3 = {
|
|
99195
|
+
items: set3.items.filter((item) => !answered.has(item.id)),
|
|
99196
|
+
failures: set3.failures.filter((failure) => !answered.has(failure.id))
|
|
99197
|
+
};
|
|
99198
|
+
skipped = before2 - set3.items.length - set3.failures.length;
|
|
99199
|
+
}
|
|
99200
|
+
} catch (error2) {
|
|
99201
|
+
if (error2 instanceof DecideInputError)
|
|
99202
|
+
return usageError2(stderr, error2.message);
|
|
99203
|
+
throw error2;
|
|
99204
|
+
}
|
|
99205
|
+
fs95.mkdirSync(path107.dirname(outPath), { recursive: true });
|
|
99206
|
+
if (resume)
|
|
99207
|
+
repairResultsTail(outPath);
|
|
99208
|
+
else
|
|
99209
|
+
fs95.writeFileSync(outPath, "");
|
|
99210
|
+
const append = (rows) => {
|
|
99211
|
+
if (rows.length)
|
|
99212
|
+
fs95.appendFileSync(outPath, rows.map((row) => JSON.stringify(row)).join(`
|
|
99213
|
+
`) + `
|
|
99214
|
+
`);
|
|
99215
|
+
};
|
|
99216
|
+
const tally = new Tally;
|
|
99217
|
+
const localFailures = [...set3.failures];
|
|
99218
|
+
const chunks = chunk2(set3.items, localFailures);
|
|
99219
|
+
const localRows = localFailures.map((failure) => ({ id: failure.id, error: failure.error }));
|
|
99220
|
+
append(localRows);
|
|
99221
|
+
localRows.forEach((row) => tally.addRow(row));
|
|
99222
|
+
const total = set3.items.length + set3.failures.length;
|
|
99223
|
+
let stopError;
|
|
99224
|
+
let unsent = 0;
|
|
99225
|
+
let next = 0;
|
|
99226
|
+
if (chunks.length) {
|
|
99227
|
+
let credential;
|
|
99228
|
+
try {
|
|
99229
|
+
credential = await resolveDecideCredential(cwd2, stringOption(parsed, "agent"));
|
|
99230
|
+
} catch (error2) {
|
|
99231
|
+
stopError = error2.message;
|
|
99232
|
+
}
|
|
99233
|
+
if (credential) {
|
|
99234
|
+
const modelFlag = stringOption(parsed, "model");
|
|
99235
|
+
const body = (items) => ({
|
|
99236
|
+
questions,
|
|
99237
|
+
items,
|
|
99238
|
+
...modelFlag ? { model: modelFlag } : {},
|
|
99239
|
+
...minConfidence !== undefined ? { min_confidence: minConfidence } : {},
|
|
99240
|
+
output: "full"
|
|
99241
|
+
});
|
|
99242
|
+
const progress2 = process.stderr.isTTY && !deps.stderr;
|
|
99243
|
+
let answeredSoFar = localRows.length;
|
|
99244
|
+
let replacement;
|
|
99245
|
+
const send = async (items) => {
|
|
99246
|
+
const used = credential;
|
|
99247
|
+
try {
|
|
99248
|
+
return await postDecide(used, body(items), deps);
|
|
99249
|
+
} catch (error2) {
|
|
99250
|
+
if (!(error2 instanceof DecideHttpError && error2.status === 401 && used.source === "agent_key")) {
|
|
99251
|
+
throw error2;
|
|
99252
|
+
}
|
|
99253
|
+
replacement ??= replaceAgentKey(used).then((fresh2) => credential = fresh2);
|
|
99254
|
+
const fresh = await replacement;
|
|
99255
|
+
if (fresh.key === used.key)
|
|
99256
|
+
throw error2;
|
|
99257
|
+
return postDecide(fresh, body(items), deps);
|
|
99258
|
+
}
|
|
99259
|
+
};
|
|
99260
|
+
const worker = async () => {
|
|
99261
|
+
while (next < chunks.length && stopError === undefined) {
|
|
99262
|
+
const items = chunks[next++];
|
|
99263
|
+
let rows;
|
|
99264
|
+
try {
|
|
99265
|
+
const response = await send(items);
|
|
99266
|
+
tally.addResponse(response);
|
|
99267
|
+
rows = response.rows;
|
|
99268
|
+
} catch (error2) {
|
|
99269
|
+
const message3 = error2.message;
|
|
99270
|
+
const refusal = error2 instanceof DecideHttpError;
|
|
99271
|
+
if (!refusal || error2.status !== null && STOP_STATUSES.has(error2.status)) {
|
|
99272
|
+
stopError ??= refusal && error2.status === 404 ? `/v1/decide is not available on ${credential.base} (${message3})` : message3;
|
|
99273
|
+
unsent += items.length;
|
|
99274
|
+
continue;
|
|
99275
|
+
}
|
|
99276
|
+
rows = items.map((item) => ({ id: item.id, error: `Request failed: ${message3}` }));
|
|
99277
|
+
}
|
|
99278
|
+
append(rows);
|
|
99279
|
+
rows.forEach((row) => tally.addRow(row));
|
|
99280
|
+
answeredSoFar += rows.length;
|
|
99281
|
+
if (progress2)
|
|
99282
|
+
process.stderr.write(`\rdecided ${answeredSoFar}/${total}`);
|
|
99283
|
+
}
|
|
99284
|
+
};
|
|
99285
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, chunks.length) }, worker));
|
|
99286
|
+
if (progress2)
|
|
99287
|
+
process.stderr.write(`
|
|
99288
|
+
`);
|
|
99289
|
+
}
|
|
99290
|
+
unsent += chunks.slice(next).reduce((count, items) => count + items.length, 0);
|
|
99291
|
+
}
|
|
99292
|
+
const summary = {
|
|
99293
|
+
status: stopError === undefined ? "done" : "stopped",
|
|
99294
|
+
model: tally.model ?? stringOption(parsed, "model") ?? null,
|
|
99295
|
+
counts: {
|
|
99296
|
+
total,
|
|
99297
|
+
done: tally.done,
|
|
99298
|
+
uncertain: tally.uncertainIds.length,
|
|
99299
|
+
failed: tally.failed.length,
|
|
99300
|
+
skipped,
|
|
99301
|
+
unsent
|
|
99302
|
+
},
|
|
99303
|
+
answers: tally.answers,
|
|
99304
|
+
uncertain_ids: tally.uncertainIds.slice(0, SUMMARY_UNCERTAIN_IDS),
|
|
99305
|
+
failed: tally.failed.slice(0, SUMMARY_FAILED),
|
|
99306
|
+
credits: tally.credits,
|
|
99307
|
+
elapsed_ms: Date.now() - started,
|
|
99308
|
+
out: path107.relative(cwd2, outPath) || outArg,
|
|
99309
|
+
...stopError !== undefined ? { error: `${stopError}. Answers so far are in ${outArg}; rerun with --resume to continue.` } : {}
|
|
99310
|
+
};
|
|
99311
|
+
stdout(JSON.stringify(summary, null, 2) + `
|
|
99312
|
+
`);
|
|
99313
|
+
return stopError === undefined ? 0 : 1;
|
|
99314
|
+
}
|
|
99315
|
+
|
|
97547
99316
|
// src/ui/console-streams.ts
|
|
97548
99317
|
import { format as format3 } from "node:util";
|
|
97549
99318
|
function routeConsoleThroughStreams() {
|
|
@@ -97601,6 +99370,7 @@ var COMMANDS3 = [
|
|
|
97601
99370
|
"status",
|
|
97602
99371
|
"mcp",
|
|
97603
99372
|
"integrations",
|
|
99373
|
+
"decide",
|
|
97604
99374
|
"run",
|
|
97605
99375
|
"help",
|
|
97606
99376
|
"version"
|
|
@@ -97611,213 +99381,218 @@ var SUBCOMMAND_OWNED_FLAGS = {
|
|
|
97611
99381
|
function help() {
|
|
97612
99382
|
const out = [];
|
|
97613
99383
|
out.push("");
|
|
97614
|
-
out.push(` ${brandTint("◆")} ${
|
|
97615
|
-
out.push(` ${
|
|
99384
|
+
out.push(` ${brandTint("◆")} ${import_picocolors84.default.bold("brainbase")} ${import_picocolors84.default.dim(`v${VERSION}`)}`);
|
|
99385
|
+
out.push(` ${import_picocolors84.default.dim("connect your local agent to the brainbase platform")}`);
|
|
97616
99386
|
out.push("");
|
|
97617
99387
|
out.push(divider("USAGE"));
|
|
97618
99388
|
out.push("");
|
|
97619
|
-
out.push(` ${
|
|
99389
|
+
out.push(` ${import_picocolors84.default.bold("brainbase")} ${import_picocolors84.default.dim("<command> [options]")}`);
|
|
97620
99390
|
out.push("");
|
|
97621
99391
|
out.push(divider("AUTH"));
|
|
97622
99392
|
out.push("");
|
|
97623
|
-
out.push(` ${
|
|
97624
|
-
out.push(` ${
|
|
97625
|
-
out.push(` ${
|
|
99393
|
+
out.push(` ${import_picocolors84.default.cyan("login")} ${import_picocolors84.default.dim(" open the web app and connect this device")}`);
|
|
99394
|
+
out.push(` ${import_picocolors84.default.cyan("logout")} ${import_picocolors84.default.dim(" clear the local session")}`);
|
|
99395
|
+
out.push(` ${import_picocolors84.default.cyan("whoami")} ${import_picocolors84.default.dim("[--json]")} ${import_picocolors84.default.dim(" show which credential is in use and what it covers")}`);
|
|
97626
99396
|
out.push("");
|
|
97627
99397
|
out.push(divider("DISCOVERY"));
|
|
97628
99398
|
out.push("");
|
|
97629
|
-
out.push(` ${
|
|
97630
|
-
out.push(` ${
|
|
97631
|
-
out.push(` ${
|
|
99399
|
+
out.push(` ${import_picocolors84.default.cyan("team list")} ${import_picocolors84.default.dim("show the teams you can create agents in")}`);
|
|
99400
|
+
out.push(` ${import_picocolors84.default.cyan("member ls")} ${import_picocolors84.default.dim("show the people in an organization, with the emails interface access takes")}`);
|
|
99401
|
+
out.push(` ${import_picocolors84.default.cyan("agent list")} ${import_picocolors84.default.dim("show a team's agents and their ids")}`);
|
|
97632
99402
|
out.push("");
|
|
97633
99403
|
out.push(divider("LINKED AGENT"));
|
|
97634
99404
|
out.push("");
|
|
97635
|
-
out.push(` ${
|
|
97636
|
-
out.push(` ${
|
|
97637
|
-
out.push(` ${
|
|
97638
|
-
out.push(` ${
|
|
97639
|
-
out.push(` ${
|
|
97640
|
-
out.push(` ${
|
|
97641
|
-
out.push(` ${
|
|
97642
|
-
out.push(` ${
|
|
97643
|
-
out.push(` ${
|
|
97644
|
-
out.push(` ${
|
|
97645
|
-
out.push(` ${
|
|
97646
|
-
out.push(` ${
|
|
97647
|
-
out.push(` ${
|
|
97648
|
-
out.push(` ${
|
|
97649
|
-
out.push(` ${
|
|
97650
|
-
out.push(` ${
|
|
97651
|
-
out.push(` ${
|
|
97652
|
-
out.push(` ${
|
|
99405
|
+
out.push(` ${import_picocolors84.default.cyan("agent init")} ${import_picocolors84.default.dim("write a starter brainbase.agent.yaml here — offline, no login needed")}`);
|
|
99406
|
+
out.push(` ${import_picocolors84.default.cyan("agent create")} ${import_picocolors84.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
|
|
99407
|
+
out.push(` ${import_picocolors84.default.cyan("agent pull")} ${import_picocolors84.default.dim("[<id>]")} ${import_picocolors84.default.dim("bring cloud changes into this folder (--force to override; --run-entrypoint to also execute the agent entrypoint; --link to link first)")}`);
|
|
99408
|
+
out.push(` ${import_picocolors84.default.cyan("agent push")} ${import_picocolors84.default.dim("send local changes to the cloud (--force to overwrite cloud-side conflicts with local)")}`);
|
|
99409
|
+
out.push(` ${import_picocolors84.default.cyan("agent delete")} ${import_picocolors84.default.dim("<id>")} ${import_picocolors84.default.dim("permanently delete a cloud agent and every task it has run")}`);
|
|
99410
|
+
out.push(` ${import_picocolors84.default.cyan("agent unpack")} ${import_picocolors84.default.dim("install the claimed agent into a harness layout")}`);
|
|
99411
|
+
out.push(` ${import_picocolors84.default.cyan("link")} ${import_picocolors84.default.dim("attach this folder to an existing agent")}`);
|
|
99412
|
+
out.push(` ${import_picocolors84.default.cyan("agent status")} ${import_picocolors84.default.dim("show what would pull and what would push")}`);
|
|
99413
|
+
out.push(` ${import_picocolors84.default.cyan("agent connections")} ${import_picocolors84.default.dim("show which integrations this agent is wired to (--json for CI)")}`);
|
|
99414
|
+
out.push(` ${import_picocolors84.default.cyan("agent connect")} ${import_picocolors84.default.dim("<name>")} ${import_picocolors84.default.dim("connect chat, slack, meeting, github, linear or phone")}`);
|
|
99415
|
+
out.push(` ${import_picocolors84.default.cyan("agent disconnect")} ${import_picocolors84.default.dim("<name>")} ${import_picocolors84.default.dim("disable or disconnect an agent surface")}`);
|
|
99416
|
+
out.push(` ${import_picocolors84.default.cyan("agent surface")} ${import_picocolors84.default.dim("<name>")} ${import_picocolors84.default.dim("status, settings and setup for all six surfaces (--help)")}`);
|
|
99417
|
+
out.push(` ${import_picocolors84.default.cyan("agent versions")} ${import_picocolors84.default.dim("saved versions: list, show, diff, label, restore, pin and unpin (`agent versions --help`)")}`);
|
|
99418
|
+
out.push(` ${import_picocolors84.default.cyan("agent eval")} ${import_picocolors84.default.dim("<list|runs>")} ${import_picocolors84.default.dim("read eval definitions and judge verdicts (`agent eval --help`)")}`);
|
|
99419
|
+
out.push(` ${import_picocolors84.default.cyan("agent env")} ${import_picocolors84.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
|
|
99420
|
+
out.push(` ${import_picocolors84.default.cyan("run")} ${import_picocolors84.default.dim("<cmd> [args...]")} ${import_picocolors84.default.dim("run <cmd> with secrets.env loaded into env")}`);
|
|
99421
|
+
out.push(` ${import_picocolors84.default.cyan("status")} ${import_picocolors84.default.dim("show what this folder is linked to")}`);
|
|
99422
|
+
out.push(` ${import_picocolors84.default.cyan("unlink")} ${import_picocolors84.default.dim("disconnect this folder")}`);
|
|
97653
99423
|
out.push("");
|
|
97654
99424
|
out.push(divider("TASKS"));
|
|
97655
99425
|
out.push("");
|
|
97656
|
-
out.push(` ${
|
|
97657
|
-
out.push(` ${
|
|
97658
|
-
out.push(` ${
|
|
97659
|
-
out.push(` ${
|
|
97660
|
-
out.push(` ${
|
|
97661
|
-
out.push(` ${
|
|
97662
|
-
out.push(` ${
|
|
97663
|
-
out.push(` ${
|
|
99426
|
+
out.push(` ${import_picocolors84.default.cyan("task create")} ${import_picocolors84.default.dim("--message <text>")} ${import_picocolors84.default.dim("create a managed task and start its first run (--wait to block on it; --interface <id> for a build conversation)")}`);
|
|
99427
|
+
out.push(` ${import_picocolors84.default.cyan("task list")} ${import_picocolors84.default.dim("recent tasks you can reach (--metadata k=v to filter by label; --interface <id> for its build conversations)")}`);
|
|
99428
|
+
out.push(` ${import_picocolors84.default.cyan("task get")} ${import_picocolors84.default.dim("<task-id>")} ${import_picocolors84.default.dim("one task: status, agent, machine, eval verdicts")}`);
|
|
99429
|
+
out.push(` ${import_picocolors84.default.cyan("task logs")} ${import_picocolors84.default.dim("<task-id> [--follow]")} ${import_picocolors84.default.dim("one line per event in the task's transcript, or tail it live")}`);
|
|
99430
|
+
out.push(` ${import_picocolors84.default.cyan("task send")} ${import_picocolors84.default.dim("<task-id> <message>")} ${import_picocolors84.default.dim("send a follow-up during execution, or queue it for the next turn")}`);
|
|
99431
|
+
out.push(` ${import_picocolors84.default.cyan("task stop")} ${import_picocolors84.default.dim("<task-id>")} ${import_picocolors84.default.dim("stop execution and cancel pending follow-ups, retaining their text")}`);
|
|
99432
|
+
out.push(` ${import_picocolors84.default.cyan("task update")} ${import_picocolors84.default.dim("<task-id>")} ${import_picocolors84.default.dim("rename a task, change its metadata labels, switch its model or reset it to the agent default, including while it runs")}`);
|
|
99433
|
+
out.push(` ${import_picocolors84.default.cyan("task delete")} ${import_picocolors84.default.dim("<task-id>")} ${import_picocolors84.default.dim("permanently delete a stopped task and tear down its sandbox")}`);
|
|
97664
99434
|
out.push("");
|
|
97665
99435
|
out.push(divider("INTERFACES"));
|
|
97666
99436
|
out.push("");
|
|
97667
|
-
out.push(` ${
|
|
97668
|
-
out.push(` ${
|
|
97669
|
-
out.push(` ${
|
|
97670
|
-
out.push(` ${
|
|
97671
|
-
out.push(` ${
|
|
97672
|
-
out.push(` ${
|
|
97673
|
-
out.push(` ${
|
|
99437
|
+
out.push(` ${import_picocolors84.default.cyan("interface ls")} ${import_picocolors84.default.dim("dashboards you can see (--agent to narrow)")}`);
|
|
99438
|
+
out.push(` ${import_picocolors84.default.cyan("interface create")} ${import_picocolors84.default.dim("--name <n>")} ${import_picocolors84.default.dim("create one on an agent, with who can open it")}`);
|
|
99439
|
+
out.push(` ${import_picocolors84.default.cyan("interface build")} ${import_picocolors84.default.dim('<id> "<ask>"')} ${import_picocolors84.default.dim("describe a change; the agent builds it while you watch")}`);
|
|
99440
|
+
out.push(` ${import_picocolors84.default.cyan("interface publish")} ${import_picocolors84.default.dim("<id>")} ${import_picocolors84.default.dim("make the newest succeeded build live")}`);
|
|
99441
|
+
out.push(` ${import_picocolors84.default.cyan("interface rollback")} ${import_picocolors84.default.dim("<id>")} ${import_picocolors84.default.dim("republish an earlier release under a new id (--release <id>)")}`);
|
|
99442
|
+
out.push(` ${import_picocolors84.default.cyan("interface access")} ${import_picocolors84.default.dim("<id>")} ${import_picocolors84.default.dim("show or set who can open it")}`);
|
|
99443
|
+
out.push(` ${import_picocolors84.default.cyan("interface --help")} ${import_picocolors84.default.dim("every interface subcommand")}`);
|
|
97674
99444
|
out.push("");
|
|
97675
99445
|
out.push(divider("SANDBOXES"));
|
|
97676
99446
|
out.push("");
|
|
97677
|
-
out.push(` ${
|
|
97678
|
-
out.push(` ${
|
|
99447
|
+
out.push(` ${import_picocolors84.default.cyan("machine ls")} ${import_picocolors84.default.dim("[--all]")} ${import_picocolors84.default.dim("list your sandboxes — live ones only unless --all")}`);
|
|
99448
|
+
out.push(` ${import_picocolors84.default.cyan("machine rm")} ${import_picocolors84.default.dim("<id>")} ${import_picocolors84.default.dim("tear a sandbox down (it bills until you do)")}`);
|
|
97679
99449
|
out.push("");
|
|
97680
99450
|
out.push(divider("BENCHMARKS"));
|
|
97681
99451
|
out.push("");
|
|
97682
|
-
out.push(` ${
|
|
97683
|
-
out.push(` ${
|
|
97684
|
-
out.push(` ${
|
|
97685
|
-
out.push(` ${
|
|
97686
|
-
out.push(` ${
|
|
99452
|
+
out.push(` ${import_picocolors84.default.cyan("benchmark list")} ${import_picocolors84.default.dim("list benchmarks for the linked agent")}`);
|
|
99453
|
+
out.push(` ${import_picocolors84.default.cyan("benchmark init")} ${import_picocolors84.default.dim("[directory]")} ${import_picocolors84.default.dim("scaffold a local benchmark")}`);
|
|
99454
|
+
out.push(` ${import_picocolors84.default.cyan("benchmark create")} ${import_picocolors84.default.dim("[path|-]")} ${import_picocolors84.default.dim("create a benchmark draft")}`);
|
|
99455
|
+
out.push(` ${import_picocolors84.default.cyan("benchmark run")} ${import_picocolors84.default.dim("<benchmark> --yes")} ${import_picocolors84.default.dim("plan and start a benchmark run")}`);
|
|
99456
|
+
out.push(` ${import_picocolors84.default.cyan("benchmark results")} ${import_picocolors84.default.dim("<run>")} ${import_picocolors84.default.dim("inspect normalized benchmark results")}`);
|
|
97687
99457
|
out.push("");
|
|
97688
99458
|
out.push(divider("BENCHMARK RUNTIME"));
|
|
97689
99459
|
out.push("");
|
|
97690
|
-
out.push(` ${
|
|
97691
|
-
out.push(` ${
|
|
97692
|
-
out.push(` ${
|
|
99460
|
+
out.push(` ${import_picocolors84.default.cyan("benchmark hydrate")} ${import_picocolors84.default.dim("--spec <path> --result <path> --json")}`);
|
|
99461
|
+
out.push(` ${import_picocolors84.default.cyan("benchmark evaluate")} ${import_picocolors84.default.dim("--spec <path> --result <path> --json")}`);
|
|
99462
|
+
out.push(` ${import_picocolors84.default.cyan("benchmark capabilities")} ${import_picocolors84.default.dim("--json")}`);
|
|
97693
99463
|
out.push("");
|
|
97694
99464
|
out.push(divider("ORCHESTRATIONS"));
|
|
97695
99465
|
out.push("");
|
|
97696
|
-
out.push(` ${
|
|
97697
|
-
out.push(` ${
|
|
97698
|
-
out.push(` ${
|
|
97699
|
-
out.push(` ${
|
|
97700
|
-
out.push(` ${
|
|
97701
|
-
out.push(` ${
|
|
97702
|
-
out.push(` ${
|
|
99466
|
+
out.push(` ${import_picocolors84.default.cyan("orchestration init")} ${import_picocolors84.default.dim("write a starter brainbase-orchestration.yaml here (offline, no login)")}`);
|
|
99467
|
+
out.push(` ${import_picocolors84.default.cyan("orchestration create")} ${import_picocolors84.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
|
|
99468
|
+
out.push(` ${import_picocolors84.default.cyan("orchestration from-agent")} ${import_picocolors84.default.dim("turn an existing agent into an orchestration")}`);
|
|
99469
|
+
out.push(` ${import_picocolors84.default.cyan("orchestration list")} ${import_picocolors84.default.dim("list orchestrations under a team")}`);
|
|
99470
|
+
out.push(` ${import_picocolors84.default.cyan("orchestration pull")} ${import_picocolors84.default.dim("<id>")} ${import_picocolors84.default.dim("recursively fetch an orchestration + every member agent")}`);
|
|
99471
|
+
out.push(` ${import_picocolors84.default.cyan("orchestration push")} ${import_picocolors84.default.dim("recursively push each member, then update the graph")}`);
|
|
99472
|
+
out.push(` ${import_picocolors84.default.cyan("orchestration status")} ${import_picocolors84.default.dim("show what would push and what would pull")}`);
|
|
99473
|
+
out.push(` ${import_picocolors84.default.cyan("orchestration delete")} ${import_picocolors84.default.dim("<id>")} ${import_picocolors84.default.dim("permanently delete an orchestration graph (member agents are kept)")}`);
|
|
97703
99474
|
out.push("");
|
|
97704
99475
|
out.push(divider("TEMPLATES"));
|
|
97705
99476
|
out.push("");
|
|
97706
|
-
out.push(` ${
|
|
97707
|
-
out.push(` ${
|
|
97708
|
-
out.push(` ${
|
|
97709
|
-
out.push(` ${
|
|
97710
|
-
out.push(` ${
|
|
97711
|
-
out.push(` ${
|
|
97712
|
-
out.push(` ${
|
|
99477
|
+
out.push(` ${import_picocolors84.default.cyan("template pack")} ${import_picocolors84.default.dim("bundle the current agent into a template")}`);
|
|
99478
|
+
out.push(` ${import_picocolors84.default.cyan("template publish")} ${import_picocolors84.default.dim("upload a template to the registry")}`);
|
|
99479
|
+
out.push(` ${import_picocolors84.default.cyan("template search")} ${import_picocolors84.default.dim("[query]")} ${import_picocolors84.default.dim("search the registry")}`);
|
|
99480
|
+
out.push(` ${import_picocolors84.default.cyan("template info")} ${import_picocolors84.default.dim("<creator/slug>")} ${import_picocolors84.default.dim("show registry details for a template")}`);
|
|
99481
|
+
out.push(` ${import_picocolors84.default.cyan("template onboard")} ${import_picocolors84.default.dim("<creator/slug>")} ${import_picocolors84.default.dim("install (or refresh) a template")}`);
|
|
99482
|
+
out.push(` ${import_picocolors84.default.cyan("template list")} ${import_picocolors84.default.dim("show installed templates")}`);
|
|
99483
|
+
out.push(` ${import_picocolors84.default.cyan("template remove")} ${import_picocolors84.default.dim("<creator/slug>")} ${import_picocolors84.default.dim("uninstall a template")}`);
|
|
97713
99484
|
out.push("");
|
|
97714
99485
|
out.push(divider("SKILLS"));
|
|
97715
99486
|
out.push("");
|
|
97716
|
-
out.push(` ${
|
|
97717
|
-
out.push(` ${
|
|
97718
|
-
out.push(` ${
|
|
97719
|
-
out.push(` ${
|
|
97720
|
-
out.push(` ${
|
|
97721
|
-
out.push(` ${
|
|
97722
|
-
out.push(` ${
|
|
99487
|
+
out.push(` ${import_picocolors84.default.cyan("skill add")} ${import_picocolors84.default.dim("<source>")} ${import_picocolors84.default.dim("install a skill (github / git / brainbase)")}`);
|
|
99488
|
+
out.push(` ${import_picocolors84.default.cyan("skill list")} ${import_picocolors84.default.dim("show locally installed skills + their source")}`);
|
|
99489
|
+
out.push(` ${import_picocolors84.default.cyan("skill update")} ${import_picocolors84.default.dim("<slug>")} ${import_picocolors84.default.dim("re-fetch a skill from its recorded source")}`);
|
|
99490
|
+
out.push(` ${import_picocolors84.default.cyan("skill remove")} ${import_picocolors84.default.dim("<slug>")} ${import_picocolors84.default.dim("uninstall a skill")}`);
|
|
99491
|
+
out.push(` ${import_picocolors84.default.cyan("skill search")} ${import_picocolors84.default.dim("[query]")} ${import_picocolors84.default.dim("search the brainbase skill registry")}`);
|
|
99492
|
+
out.push(` ${import_picocolors84.default.cyan("skill info")} ${import_picocolors84.default.dim("<creator/slug>")} ${import_picocolors84.default.dim("show registry details for a skill")}`);
|
|
99493
|
+
out.push(` ${import_picocolors84.default.cyan("skill publish")} ${import_picocolors84.default.dim("[dir]")} ${import_picocolors84.default.dim("publish a SKILL.md folder (defaults to .)")}`);
|
|
97723
99494
|
out.push("");
|
|
97724
99495
|
out.push(divider("CLI TOKENS"));
|
|
97725
99496
|
out.push("");
|
|
97726
|
-
out.push(` ${
|
|
97727
|
-
out.push(` ${
|
|
97728
|
-
out.push(` ${
|
|
97729
|
-
out.push(` ${
|
|
99497
|
+
out.push(` ${import_picocolors84.default.cyan("token create")} ${import_picocolors84.default.dim("issue a long-lived CLI key for CI / scripts")}`);
|
|
99498
|
+
out.push(` ${import_picocolors84.default.cyan("token list")} ${import_picocolors84.default.dim("show your tokens")}`);
|
|
99499
|
+
out.push(` ${import_picocolors84.default.cyan("token rename")} ${import_picocolors84.default.dim("<id>")} ${import_picocolors84.default.dim("relabel a token")}`);
|
|
99500
|
+
out.push(` ${import_picocolors84.default.cyan("token revoke")} ${import_picocolors84.default.dim("<id>")} ${import_picocolors84.default.dim("revoke a token")}`);
|
|
99501
|
+
out.push("");
|
|
99502
|
+
out.push(divider("DECISIONS"));
|
|
99503
|
+
out.push("");
|
|
99504
|
+
out.push(` ${import_picocolors84.default.cyan("decide")} ${import_picocolors84.default.dim("-q <questions.json> <sources...>")} ${import_picocolors84.default.dim("answer decision-model questions over many files or rows in a few requests (`decide --help`)")}`);
|
|
97730
99505
|
out.push("");
|
|
97731
99506
|
out.push(divider("MCP"));
|
|
97732
99507
|
out.push("");
|
|
97733
|
-
out.push(` ${
|
|
97734
|
-
out.push(` ${
|
|
97735
|
-
out.push(` ${
|
|
99508
|
+
out.push(` ${import_picocolors84.default.cyan("mcp check")} ${import_picocolors84.default.dim("[--json]")} ${import_picocolors84.default.dim("verify MCP server connectivity through the brainbase proxy (runs at sandbox bootstrap)")}`);
|
|
99509
|
+
out.push(` ${import_picocolors84.default.cyan("mcp list")} ${import_picocolors84.default.dim("[--json]")} ${import_picocolors84.default.dim("show configured servers with OAuth state and expiry")}`);
|
|
99510
|
+
out.push(` ${import_picocolors84.default.cyan("mcp connect")} ${import_picocolors84.default.dim("<name>")} ${import_picocolors84.default.dim("authorize an OAuth-backed server: prints a single-use link, opens it, waits for approval")}`);
|
|
97736
99511
|
out.push("");
|
|
97737
99512
|
out.push(divider("INTEGRATIONS"));
|
|
97738
99513
|
out.push("");
|
|
97739
|
-
out.push(` ${
|
|
97740
|
-
out.push(` ${
|
|
97741
|
-
out.push(` ${
|
|
97742
|
-
out.push(` ${
|
|
97743
|
-
out.push(` ${
|
|
97744
|
-
out.push(` ${
|
|
97745
|
-
out.push(` ${
|
|
97746
|
-
out.push(` ${
|
|
97747
|
-
out.push(` ${
|
|
97748
|
-
out.push(` ${
|
|
99514
|
+
out.push(` ${import_picocolors84.default.cyan("integrations list")} ${import_picocolors84.default.dim("show the agent's Pipedream apps, accounts and app-level permission")}`);
|
|
99515
|
+
out.push(` ${import_picocolors84.default.cyan("integrations search")} ${import_picocolors84.default.dim("<query>")} ${import_picocolors84.default.dim("find apps in the Pipedream catalog")}`);
|
|
99516
|
+
out.push(` ${import_picocolors84.default.cyan("integrations actions")} ${import_picocolors84.default.dim("<app>")} ${import_picocolors84.default.dim("list an app's actions and whether each is allowed")}`);
|
|
99517
|
+
out.push(` ${import_picocolors84.default.cyan("integrations add")} ${import_picocolors84.default.dim("<app>")} ${import_picocolors84.default.dim("install an app; one that needs an account runs connect")}`);
|
|
99518
|
+
out.push(` ${import_picocolors84.default.cyan("integrations connect")} ${import_picocolors84.default.dim("<app>")} ${import_picocolors84.default.dim("open Pipedream's connect page for the app and wait for the account")}`);
|
|
99519
|
+
out.push(` ${import_picocolors84.default.cyan("integrations disconnect")} ${import_picocolors84.default.dim("<app>")} ${import_picocolors84.default.dim("delete the app's connected account")}`);
|
|
99520
|
+
out.push(` ${import_picocolors84.default.cyan("integrations remove")} ${import_picocolors84.default.dim("<app>")} ${import_picocolors84.default.dim("uninstall an app that needs no account")}`);
|
|
99521
|
+
out.push(` ${import_picocolors84.default.cyan("integrations allow|ask|deny")} ${import_picocolors84.default.dim("<app>[.<action>]")} ${import_picocolors84.default.dim("set the permission for an app or one of its actions")}`);
|
|
99522
|
+
out.push(` ${import_picocolors84.default.cyan("integrations context create")} ${import_picocolors84.default.dim("--application <name>")} ${import_picocolors84.default.dim("let a program outside Brainbase (the SDK) use the agent's integrations; prints a renewal handle once")}`);
|
|
99523
|
+
out.push(` ${import_picocolors84.default.cyan("integrations context end")} ${import_picocolors84.default.dim("<context-id>")} ${import_picocolors84.default.dim("end a standalone integration context now")}`);
|
|
97749
99524
|
out.push("");
|
|
97750
99525
|
out.push(divider("FLAGS"));
|
|
97751
99526
|
out.push("");
|
|
97752
|
-
out.push(` ${
|
|
97753
|
-
out.push(` ${
|
|
97754
|
-
out.push(` ${
|
|
99527
|
+
out.push(` ${import_picocolors84.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
|
|
99528
|
+
out.push(` ${import_picocolors84.default.dim("--scope <s>")} force scope: global | project`);
|
|
99529
|
+
out.push(` ${import_picocolors84.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
|
|
97755
99530
|
out.push(` ${" ".repeat("--yes, -y".length)} required for destructive commands with no terminal (pipes, CI)`);
|
|
97756
|
-
out.push(` ${
|
|
97757
|
-
out.push(` ${
|
|
97758
|
-
out.push(` ${
|
|
97759
|
-
out.push(` ${
|
|
97760
|
-
out.push(` ${
|
|
97761
|
-
out.push(` ${
|
|
97762
|
-
out.push(` ${
|
|
97763
|
-
out.push(` ${
|
|
97764
|
-
out.push(` ${
|
|
97765
|
-
out.push(` ${
|
|
97766
|
-
out.push(` ${
|
|
97767
|
-
out.push(` ${
|
|
97768
|
-
out.push(` ${
|
|
97769
|
-
out.push(` ${
|
|
97770
|
-
out.push(` ${
|
|
97771
|
-
out.push(` ${
|
|
97772
|
-
out.push(` ${
|
|
97773
|
-
out.push(` ${
|
|
97774
|
-
out.push(` ${
|
|
97775
|
-
out.push(` ${
|
|
97776
|
-
out.push(` ${
|
|
97777
|
-
out.push(` ${
|
|
97778
|
-
out.push(` ${
|
|
97779
|
-
out.push(` ${
|
|
97780
|
-
out.push(` ${
|
|
97781
|
-
out.push(` ${
|
|
97782
|
-
out.push(` ${
|
|
97783
|
-
out.push(` ${
|
|
97784
|
-
out.push(` ${
|
|
97785
|
-
out.push(` ${
|
|
97786
|
-
out.push(` ${
|
|
97787
|
-
out.push(` ${
|
|
97788
|
-
out.push(` ${
|
|
97789
|
-
out.push(` ${
|
|
97790
|
-
out.push(` ${
|
|
97791
|
-
out.push(` ${
|
|
97792
|
-
out.push(` ${
|
|
99531
|
+
out.push(` ${import_picocolors84.default.dim("--agent <id>")} for link/task create/mcp list/mcp connect/integrations: use this agent id explicitly instead of the linked folder's (task list: filter to it)`);
|
|
99532
|
+
out.push(` ${import_picocolors84.default.dim("--message <text>")} for task create: required first user message`);
|
|
99533
|
+
out.push(` ${import_picocolors84.default.dim("--title <text>")} for task create: optional task title; for task update: the new title`);
|
|
99534
|
+
out.push(` ${import_picocolors84.default.dim("--clear-title")} for task update: remove the title (automatic titling may name it again later)`);
|
|
99535
|
+
out.push(` ${import_picocolors84.default.dim("--metadata k=v")} for task create: label the task; for task list: only tasks with this label; for task update: set one label, keeping the others (all repeatable)`);
|
|
99536
|
+
out.push(` ${import_picocolors84.default.dim("--unset-metadata <k>")} for task update: remove one label (repeatable)`);
|
|
99537
|
+
out.push(` ${import_picocolors84.default.dim("--clear-metadata")} for task update: remove every label; with --metadata, keep only those given`);
|
|
99538
|
+
out.push(` ${import_picocolors84.default.dim("--model <id>")} for task create: optional model override; for task update: switch the model the task's next turn runs on (the running turn keeps its model)`);
|
|
99539
|
+
out.push(` ${import_picocolors84.default.dim("--clear-model")} for task update: go back to the agent's default model from the next turn`);
|
|
99540
|
+
out.push(` ${import_picocolors84.default.dim("--version <v>")} for task create: run a saved version of the agent (12, v12 or a version id)`);
|
|
99541
|
+
out.push(` ${import_picocolors84.default.dim("--wait")} for task create: block until the task finishes; exit 1 unless it succeeded`);
|
|
99542
|
+
out.push(` ${import_picocolors84.default.dim("--timeout <secs>")} for task create --wait: give up after <secs> and exit 1`);
|
|
99543
|
+
out.push(` ${import_picocolors84.default.dim("--limit <n>")} for task list (1-200), task logs (events to print; with --follow, the first page size) and machine ls`);
|
|
99544
|
+
out.push(` ${import_picocolors84.default.dim("--follow, -f")} for task logs: stay attached and print events as they land`);
|
|
99545
|
+
out.push(` ${import_picocolors84.default.dim("--org <id-or-slug>")} pick the organization (team/agent list, agent create, orchestration create/list)`);
|
|
99546
|
+
out.push(` ${import_picocolors84.default.dim("--team <id>")} pick the team, same commands (works without --org)`);
|
|
99547
|
+
out.push(` ${import_picocolors84.default.dim("--all-teams")} for agent list: every team in the org (the default with no terminal)`);
|
|
99548
|
+
out.push(` ${import_picocolors84.default.dim("--json")} machine-readable output for supported commands`);
|
|
99549
|
+
out.push(` ${import_picocolors84.default.dim("--no-tracking")} for link / agent pull --link: skip routing LLM traffic through brainbase`);
|
|
99550
|
+
out.push(` ${import_picocolors84.default.dim("--link")} for agent pull: link this folder to the agent first, as \`brainbase link --agent <id> --yes\` would, in one process`);
|
|
99551
|
+
out.push(` ${import_picocolors84.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
|
|
99552
|
+
out.push(` ${import_picocolors84.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
|
|
99553
|
+
out.push(` ${import_picocolors84.default.dim("--bot-token <t>")} for agent connect slack (or BRAINBASE_SLACK_BOT_TOKEN, or stdin)`);
|
|
99554
|
+
out.push(` ${import_picocolors84.default.dim("--signing-secret <s>")} for agent connect slack (or BRAINBASE_SLACK_SIGNING_SECRET, or stdin)`);
|
|
99555
|
+
out.push(` ${import_picocolors84.default.dim("--bot-name <name>")} for agent connect meeting: the bot's display name`);
|
|
99556
|
+
out.push(` ${import_picocolors84.default.dim("--app-id <id> / --app-name <name>")} optional Slack app identity`);
|
|
99557
|
+
out.push(` ${import_picocolors84.default.dim("--bot-image-url <url>")} optional meeting bot image`);
|
|
99558
|
+
out.push(` ${import_picocolors84.default.dim("--full")} for agent/orchestration init: write a commented template covering every block`);
|
|
99559
|
+
out.push(` ${import_picocolors84.default.dim("--minimal")} for agent init: write the starter manifest (the default)`);
|
|
99560
|
+
out.push(` ${import_picocolors84.default.dim("--all")} for template list: include installs from other folders; for machine ls: include torn-down machines`);
|
|
99561
|
+
out.push(` ${import_picocolors84.default.dim("--web <url>")} for login: web app URL (default https://app.brainbaselabs.com)`);
|
|
99562
|
+
out.push(` ${import_picocolors84.default.dim("--no-open")} for mcp/integrations connect: print the link without opening a browser (implied with no terminal)`);
|
|
99563
|
+
out.push(` ${import_picocolors84.default.dim("--no-wait")} for mcp/integrations connect: print the link and exit instead of waiting`);
|
|
99564
|
+
out.push(` ${import_picocolors84.default.dim("--account <id>")} for integrations disconnect: which account, when the app has more than one`);
|
|
99565
|
+
out.push(` ${import_picocolors84.default.dim("--application <name>")} for integrations context create: names the program the context is for`);
|
|
99566
|
+
out.push(` ${import_picocolors84.default.dim("--max-lifetime <dur>")} for integrations context create: when the context ends at the latest, 60s-30d (default 7d)`);
|
|
99567
|
+
out.push(` ${import_picocolors84.default.dim("--reason <text>")} for integrations context end: recorded with the context`);
|
|
97793
99568
|
out.push("");
|
|
97794
99569
|
out.push(divider("ENV"));
|
|
97795
99570
|
out.push("");
|
|
97796
|
-
out.push(` ${
|
|
97797
|
-
out.push(` ${
|
|
97798
|
-
out.push(` ${
|
|
97799
|
-
out.push(` ${
|
|
97800
|
-
out.push(` ${
|
|
97801
|
-
out.push(` ${
|
|
97802
|
-
out.push(` ${
|
|
97803
|
-
out.push(` ${
|
|
97804
|
-
out.push(` ${
|
|
97805
|
-
out.push(` ${
|
|
97806
|
-
out.push(` ${
|
|
99571
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
|
|
99572
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_DEBUG")} print full stack traces on error (any value; unset to disable)`);
|
|
99573
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login, console links and integrations`);
|
|
99574
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_CONTROL_PLANE_URL")} override the MAS host (/v2/cli; task and interface commands use /v2/tasks and /v2/interfaces)`);
|
|
99575
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_API_URL")} legacy KLS host override (uses /api/cli; proxy/registry fallback)`);
|
|
99576
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_PROXY_URL")} override the model-proxy URL used by harness traffic (default https://api.v1.brainbaselabs.com)`);
|
|
99577
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL (default https://api.v1.brainbaselabs.com)`);
|
|
99578
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT; outranks the login session and the PAT saved in token.json`);
|
|
99579
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
|
|
99580
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
|
|
99581
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 → agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
|
|
97807
99582
|
out.push("");
|
|
97808
|
-
out.push(` ${
|
|
97809
|
-
out.push(` ${
|
|
97810
|
-
out.push(` ${
|
|
97811
|
-
out.push(` ${
|
|
97812
|
-
out.push(` ${
|
|
97813
|
-
out.push(` ${
|
|
97814
|
-
out.push(` ${
|
|
99583
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_MEMORY_MCP_URL")} override the built-in memory MCP host`);
|
|
99584
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_BROWSER_MCP_URL")} override the built-in browser MCP host`);
|
|
99585
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_SLACK_MCP_URL")} override the built-in Slack MCP host`);
|
|
99586
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_MEETING_MCP_URL")} override the built-in meeting MCP host`);
|
|
99587
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_GITHUB_MCP_URL")} override the built-in GitHub MCP host`);
|
|
99588
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_LINEAR_MCP_URL")} override the built-in Linear MCP host`);
|
|
99589
|
+
out.push(` ${import_picocolors84.default.dim("BRAINBASE_ORCHESTRATION_MCP_URL")} override the built-in orchestration MCP host`);
|
|
97815
99590
|
out.push("");
|
|
97816
99591
|
out.push(divider("HARNESSES"));
|
|
97817
99592
|
out.push("");
|
|
97818
|
-
out.push(` ${
|
|
97819
|
-
out.push(` ${
|
|
97820
|
-
out.push(` ${
|
|
99593
|
+
out.push(` ${import_picocolors84.default.dim("•")} ${import_picocolors84.default.bold("claude-code")} ${import_picocolors84.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
|
|
99594
|
+
out.push(` ${import_picocolors84.default.dim("•")} ${import_picocolors84.default.bold("codex")} ${import_picocolors84.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
|
|
99595
|
+
out.push(` ${import_picocolors84.default.dim("•")} ${import_picocolors84.default.bold("kafka")} ${import_picocolors84.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
|
|
97821
99596
|
out.push("");
|
|
97822
99597
|
console.log(out.join(`
|
|
97823
99598
|
`));
|
|
@@ -97886,7 +99661,7 @@ function takeFlagOnce(args, names) {
|
|
|
97886
99661
|
return best.joinedValue;
|
|
97887
99662
|
}
|
|
97888
99663
|
const v3 = args[best.index + 1];
|
|
97889
|
-
if (v3 && !v3.startsWith("-")) {
|
|
99664
|
+
if (v3 !== undefined && !v3.startsWith("-")) {
|
|
97890
99665
|
args.splice(best.index, 2);
|
|
97891
99666
|
return v3;
|
|
97892
99667
|
}
|
|
@@ -97975,10 +99750,10 @@ async function requireAuth(cmd) {
|
|
|
97975
99750
|
if (storedPatFor(status.session))
|
|
97976
99751
|
return;
|
|
97977
99752
|
console.error("");
|
|
97978
|
-
console.error(` ${brandTint("◆")} ${
|
|
99753
|
+
console.error(` ${brandTint("◆")} ${import_picocolors84.default.bold("brainbase")}`);
|
|
97979
99754
|
console.error("");
|
|
97980
|
-
console.error(` ${
|
|
97981
|
-
console.error(` ${
|
|
99755
|
+
console.error(` ${import_picocolors84.default.red("✗")} You need to sign in to use ${import_picocolors84.default.bold("brainbase " + cmd)}.`);
|
|
99756
|
+
console.error(` ${import_picocolors84.default.dim(noUsableCredentialMessage())}`);
|
|
97982
99757
|
console.error("");
|
|
97983
99758
|
process14.exit(1);
|
|
97984
99759
|
}
|
|
@@ -97988,7 +99763,7 @@ async function main() {
|
|
|
97988
99763
|
const rawCwd = process14.cwd();
|
|
97989
99764
|
const cwd2 = (() => {
|
|
97990
99765
|
try {
|
|
97991
|
-
return
|
|
99766
|
+
return fs96.realpathSync(rawCwd);
|
|
97992
99767
|
} catch {
|
|
97993
99768
|
return rawCwd;
|
|
97994
99769
|
}
|
|
@@ -98005,7 +99780,7 @@ async function main() {
|
|
|
98005
99780
|
await runRun(cwd2, argv);
|
|
98006
99781
|
return;
|
|
98007
99782
|
}
|
|
98008
|
-
const ownsArgs = new Set(["task", "benchmark", "interface", "interfaces"]);
|
|
99783
|
+
const ownsArgs = new Set(["task", "benchmark", "interface", "interfaces", "decide"]);
|
|
98009
99784
|
if (cmd === "agent")
|
|
98010
99785
|
argv.splice(0, argv.length, ...routeAgentSurfaceArgs(argv));
|
|
98011
99786
|
const sharedArgs = ownsArgs.has(cmd) || cmd === "agent" && ["versions", "surface", "connect", "disconnect", "connections"].includes(argv[0] ?? "") ? [] : argv;
|
|
@@ -98242,6 +100017,10 @@ async function main() {
|
|
|
98242
100017
|
process14.exitCode = code;
|
|
98243
100018
|
break;
|
|
98244
100019
|
}
|
|
100020
|
+
case "decide": {
|
|
100021
|
+
process14.exitCode = await runDecide(cwd2, argv);
|
|
100022
|
+
break;
|
|
100023
|
+
}
|
|
98245
100024
|
case "integration":
|
|
98246
100025
|
case "integrations": {
|
|
98247
100026
|
const sub = argv.shift();
|
|
@@ -98264,10 +100043,10 @@ ${didYouMean(cmd, COMMANDS3, "brainbase")}`);
|
|
|
98264
100043
|
} catch (err) {
|
|
98265
100044
|
const message3 = sanitizeLines(err.message).join(`
|
|
98266
100045
|
`);
|
|
98267
|
-
console.error(
|
|
100046
|
+
console.error(import_picocolors84.default.red(`
|
|
98268
100047
|
${message3}`));
|
|
98269
100048
|
if (err instanceof ApiError && err.status === 401 && !err.message.includes("brainbase login")) {
|
|
98270
|
-
console.error(` Run ${
|
|
100049
|
+
console.error(` Run ${import_picocolors84.default.cyan("brainbase login")} to connect this device.`);
|
|
98271
100050
|
}
|
|
98272
100051
|
if (process14.env.BRAINBASE_DEBUG)
|
|
98273
100052
|
console.error(err.stack);
|