@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.
Files changed (2) hide show
  1. package/dist/index.js +2372 -593
  2. 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 import_picocolors81 = __toESM(require_picocolors(), 1);
35185
+ var import_picocolors84 = __toESM(require_picocolors(), 1);
35186
35186
  import process14 from "node:process";
35187
- import fs94 from "node:fs";
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.54.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 import_picocolors59 = __toESM(require_picocolors(), 1);
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 !== "schedule", {
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([ScheduleTriggerSchema, ReadOnlyTriggerSchema]);
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 preserved
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 config2 = schedule ? scheduleTriggerConfigForManifest(trigger.config) : trigger.config;
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
- if (blockedTriggers || metaConflicts.length > 0) {
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"}, ${graph.triggers.length} trigger${graph.triggers.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: triggerDeletes.length ? `Push, deleting ${triggerDeletes.length} schedule trigger${triggerDeletes.length === 1 ? "" : "s"}?` : args.graphOnly ? "Push graph (members, edges + triggers) only?" : "Push each member, then update the graph?",
83880
- initialValue: triggerDeletes.length === 0
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 ${import_picocolors54.default.cyan("brainbase orchestration pull <id>")} first.`);
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(` ${import_picocolors54.default.bold(link2.name)} ${import_picocolors54.default.dim(`(${link2.orchestration_id})`)}`);
84007
- lines.push(` ${import_picocolors54.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
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(` ${import_picocolors54.default.bold("members")}`);
84636
+ lines.push(` ${import_picocolors55.default.bold("members")}`);
84022
84637
  for (const slug of membersAdded) {
84023
- lines.push(` ${import_picocolors54.default.yellow("→ push")} added in yaml: ${import_picocolors54.default.bold(slug)}`);
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(` ${import_picocolors54.default.cyan("← pull")} added on cloud: ${import_picocolors54.default.bold(slug)}`);
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(` ${import_picocolors54.default.bold("edges")}`);
84656
+ lines.push(` ${import_picocolors55.default.bold("edges")}`);
84042
84657
  for (const k3 of edgesAdded)
84043
- lines.push(` ${import_picocolors54.default.yellow("→ push")} added in yaml: ${k3}`);
84658
+ lines.push(` ${import_picocolors55.default.yellow("→ push")} added in yaml: ${k3}`);
84044
84659
  for (const k3 of edgesRemoved)
84045
- lines.push(` ${import_picocolors54.default.cyan("← pull")} added on cloud: ${k3}`);
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(` ${import_picocolors54.default.bold("orchestration metadata")}`);
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(` ${import_picocolors54.default.yellow("→ push")} ${import_picocolors54.default.bold(m3.field)}: cloud ${import_picocolors54.default.dim(`"${m3.cloud}"`)} → local ${import_picocolors54.default.dim(`"${m3.local}"`)}`);
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(` ${import_picocolors54.default.cyan("← pull")} ${import_picocolors54.default.bold(m3.field)}: changed in the cloud to ${import_picocolors54.default.dim(`"${m3.cloud}"`)}; push leaves it alone ${import_picocolors54.default.dim(`(yaml still has "${m3.local}")`)}`);
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(` ${import_picocolors54.default.red("! conflict")} ${import_picocolors54.default.bold(m3.field)}: local ${import_picocolors54.default.dim(`"${m3.local}"`)} vs cloud ${import_picocolors54.default.dim(`"${m3.cloud}"`)} — push refuses until you pull or ${import_picocolors54.default.cyan("--force")}`);
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(` ${import_picocolors54.default.dim("fields the manifest omits, and fields only the cloud changed, are left alone")}`);
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(` ${import_picocolors54.default.bold("schedule triggers")}`);
84705
+ lines.push(` ${import_picocolors55.default.bold("schedule triggers")}`);
84091
84706
  for (const t of triggersToPush) {
84092
- lines.push(` ${import_picocolors54.default.yellow("→ push")} added/changed in yaml: ${scheduleTriggerLabel(t)}`);
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 ? ` ${import_picocolors54.default.red("⨯ push deletes")} ${scheduleTriggerLabel(t)}` : ` ${import_picocolors54.default.cyan("← pull")} only on cloud: ${scheduleTriggerLabel(t)}`);
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(` ${import_picocolors54.default.bold(import_picocolors54.default.red("schedule triggers: push blocked"))}`);
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(` ${import_picocolors54.default.red("!")} ${triggerLabel(nodeId)} ${import_picocolors54.default.dim("— only in the cloud; pushing would delete it")}`);
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(` ${import_picocolors54.default.red("!")} ${triggerLabel(nodeId)} ${import_picocolors54.default.dim("— edited in the cloud; pushing would overwrite that edit")}`);
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(` ${import_picocolors54.default.red("!")} ${triggerLabel(nodeId)} ${import_picocolors54.default.dim("— deleted here, edited in the cloud since; pushing would delete that edit")}`);
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(` ${import_picocolors54.default.dim("run")} ${import_picocolors54.default.cyan("brainbase orchestration pull")} ${import_picocolors54.default.dim("first")}`);
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(` ${import_picocolors54.default.dim(`${left.length} cloud schedule trigger${left.length === 1 ? "" : "s"} not managed by this manifest — push leaves ${left.length === 1 ? "it" : "them"} untouched`)}`);
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(` ${import_picocolors54.default.bold("member content drift")}`);
84860
+ lines.push(` ${import_picocolors55.default.bold("member content drift")}`);
84139
84861
  for (const d3 of memberDrift) {
84140
- lines.push(` ${import_picocolors54.default.cyan("?")} ${import_picocolors54.default.bold(d3.slug)} ${import_picocolors54.default.dim("— " + d3.reason)}`);
84862
+ lines.push(` ${import_picocolors55.default.cyan("?")} ${import_picocolors55.default.bold(d3.slug)} ${import_picocolors55.default.dim("— " + d3.reason)}`);
84141
84863
  }
84142
- lines.push(` ${import_picocolors54.default.dim("cd into each member folder and run")} ${import_picocolors54.default.cyan("brainbase agent status")}`);
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(` ${import_picocolors54.default.bold("cloud revision")}`);
84148
- lines.push(` ${import_picocolors54.default.cyan("← pull")} cloud changed since last pull: ${import_picocolors54.default.dim(`lock ${lock.revision} → cloud ${cloud.revision}`)}`);
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
- if (!membersAdded.length && !membersRemoved.length && !edgesAdded.length && !edgesRemoved.length && !triggersToPush.length && !triggersToPull.length && !metaDecisions.length && !memberDrift.length && !revisionDrift) {
84152
- lines.push(` ${import_picocolors54.default.green("✓")} everything is in sync`);
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(` ${import_picocolors54.default.dim("run")} ${import_picocolors54.default.cyan("brainbase orchestration pull")} ${import_picocolors54.default.dim("to apply cloud changes,")} ${import_picocolors54.default.cyan("brainbase orchestration push")} ${import_picocolors54.default.dim("to send yours")}`);
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 import_picocolors55 = __toESM(require_picocolors(), 1);
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(` ${import_picocolors55.default.bold(o2.name)} ${import_picocolors55.default.dim(o2.id)}`);
84934
+ lines.push(` ${import_picocolors56.default.bold(o2.name)} ${import_picocolors56.default.dim(o2.id)}`);
84205
84935
  if (o2.description)
84206
- lines.push(` ${import_picocolors55.default.dim(o2.description)}`);
84207
- lines.push(` ${import_picocolors55.default.dim(`${o2.member_count} member${o2.member_count === 1 ? "" : "s"} · ${o2.edge_count} edge${o2.edge_count === 1 ? "" : "s"}`)}`);
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(` ${import_picocolors55.default.dim("pull one with")} ${import_picocolors55.default.cyan("brainbase orchestration pull <id>")}`);
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 import_picocolors56 = __toESM(require_picocolors(), 1);
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 ${import_picocolors56.default.cyan("brainbase orchestration pull <id>")} first.`);
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 ${import_picocolors56.default.bold(slug)} is taken — using ${import_picocolors56.default.bold(candidate)}.`);
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 ${import_picocolors56.default.bold(link2.group_id)}. ` + `Pass ${import_picocolors56.default.cyan("--org <id>")} explicitly.`);
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 ${import_picocolors56.default.bold(slug)} FROM which member(s)? — edges INTO ${slug} (space to select, enter to skip)`,
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 ${import_picocolors56.default.bold(slug)} TO which member(s)? — edges OUT of ${slug} (space to select, enter to skip)`,
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 ${import_picocolors56.default.cyan("brainbase orchestration push")} to apply.`);
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 import_picocolors57 = __toESM(require_picocolors(), 1);
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 ${import_picocolors57.default.cyan("brainbase orchestration push")} to update it.`);
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 ${import_picocolors57.default.bold(ORCH_MANIFEST_FILE)} here.`);
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
- ` ${import_picocolors57.default.bold(manifest.orchestration.name)}`,
84446
- ` ${import_picocolors57.default.dim("org")} ${import_picocolors57.default.bold(target.org.name)}`,
84447
- ` ${import_picocolors57.default.dim("team")} ${import_picocolors57.default.bold(target.team.name)}`,
84448
- ` ${import_picocolors57.default.dim("graph")} ${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}, ${graph.triggers.length} trigger${graph.triggers.length === 1 ? "" : "s"}`,
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 ${import_picocolors57.default.bold(created.name)}.`);
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 import_picocolors58 = __toESM(require_picocolors(), 1);
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 ${import_picocolors58.default.cyan("--minimal")} or ${import_picocolors58.default.cyan("--full")}, not both.`
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 ${import_picocolors58.default.bold(ORCH_MANIFEST_FILE)} and run ${import_picocolors58.default.cyan("brainbase orchestration push")}, or init in a new folder.`
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: `${import_picocolors58.default.bold(ORCH_MANIFEST_FILE)} already exists here. Edit it, or pass ${import_picocolors58.default.cyan("--force")} to overwrite it.`
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(import_picocolors58.default.red(`Failed to write ${ORCH_MANIFEST_FILE}: ${err.message}`));
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 ${import_picocolors58.default.bold(ORCH_MANIFEST_FILE)}${existed ? " (overwritten)" : ""}.`);
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 ${import_picocolors58.default.cyan("brainbase orchestration create")} ${import_picocolors58.default.dim("— creates the orchestration and links this folder.")}`));
84685
- console.log(tip(`Then ${import_picocolors58.default.cyan("brainbase orchestration add-agent <name>")} ${import_picocolors58.default.dim("— creates a member agent and wires it into the graph.")}`));
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
- ${import_picocolors58.default.red(message)}
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(` ${import_picocolors59.default.bold("brainbase orchestration")} ${import_picocolors59.default.dim("<sub> [options]")}`);
85746
+ out.push(` ${import_picocolors62.default.bold("brainbase orchestration")} ${import_picocolors62.default.dim("<sub> [options]")}`);
84781
85747
  out.push("");
84782
- out.push(` ${import_picocolors59.default.cyan("init")} ${import_picocolors59.default.dim("write a starter brainbase-orchestration.yaml here — offline, no login (--full for a commented template, --force to overwrite)")}`);
84783
- out.push(` ${import_picocolors59.default.cyan("create")} ${import_picocolors59.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
84784
- out.push(` ${import_picocolors59.default.cyan("pull")} ${import_picocolors59.default.dim("<id>")} ${import_picocolors59.default.dim("fetch orchestration + every member agent into this folder")}`);
84785
- out.push(` ${import_picocolors59.default.cyan("push")} ${import_picocolors59.default.dim("push each member, then update the orchestration graph")}`);
84786
- out.push(` ${import_picocolors59.default.cyan("add-agent")} ${import_picocolors59.default.dim("<name>")} ${import_picocolors59.default.dim("create a member agent, wire edges (--from/--to), and push")}`);
84787
- out.push(` ${import_picocolors59.default.cyan("status")} ${import_picocolors59.default.dim("show what would push and what would pull")}`);
84788
- out.push(` ${import_picocolors59.default.cyan("list")} ${import_picocolors59.default.dim("list orchestrations under a team")}`);
84789
- out.push(` ${import_picocolors59.default.cyan("delete")} ${import_picocolors59.default.dim("<id>")} ${import_picocolors59.default.dim("permanently delete an orchestration graph — member agents are kept")}`);
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(` ${import_picocolors59.default.bold("Flags")}`);
84792
- out.push(` ${import_picocolors59.default.dim("--yes, -y")} skip confirmations (required for delete without a terminal)`);
84793
- out.push(` ${import_picocolors59.default.dim("--json")} for init, list and delete: machine-readable result`);
84794
- out.push(` ${import_picocolors59.default.dim("--name <name>")} for init: orchestration name (default: this folder's name)`);
84795
- out.push(` ${import_picocolors59.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
84796
- out.push(` ${import_picocolors59.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`, ` ${import_picocolors59.default.dim("--force")} for push: settle every conflict in your file's favour — deletes cloud schedule`, ` triggers this folder has never seen, and overwrites cloud-side edits to`, ` name, description, icon, icon_color and credit_limit`);
84797
- out.push(` ${import_picocolors59.default.dim("--org <id>")} for create/list: org id or slug (CLI vocab — DB teams.id)`);
84798
- out.push(` ${import_picocolors59.default.dim("--team <id>")} for create/list: team id (CLI vocab — DB groups.id)`);
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 import_picocolors60 = __toESM(require_picocolors(), 1);
85812
+ var import_picocolors63 = __toESM(require_picocolors(), 1);
84844
85813
  function runPublish() {
84845
85814
  banner("publish — moved");
84846
- f2.error(`${import_picocolors60.default.bold("brainbase publish")} does not exist.`);
84847
- f2.info(`Use ${import_picocolors60.default.cyan("brainbase agent push")} to send your local changes to the cloud.`);
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 import_picocolors61 = __toESM(require_picocolors(), 1);
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 MAX_NAME_LENGTH = 128;
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 > MAX_NAME_LENGTH) {
85530
- return `Too long — keep the label to ${MAX_NAME_LENGTH} characters or fewer.`;
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} ${import_picocolors61.default.bold(target.name.trim())} already has that label; nothing to do.`);
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 ${import_picocolors61.default.dim(target.name)} → ${import_picocolors61.default.bold(name)}`);
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, `${import_picocolors61.default.bold(target.name)} is already revoked.`);
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 ${import_picocolors61.default.bold(target.name)} (${args.id})? This is the token this CLI is using, so it will stop working here too.` : `Revoke ${import_picocolors61.default.bold(target.name)} (${args.id})? CIs and machines using it will stop working.`,
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, `${import_picocolors61.default.bold(target.name)} had already expired.`);
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 ${import_picocolors61.default.bold(target.name)}.`);
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(import_picocolors61.default.dim("No local token stored."));
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(` ${import_picocolors61.default.bold("brainbase token")} ${import_picocolors61.default.dim("<command>")}`);
86712
+ out.push(` ${import_picocolors64.default.bold("brainbase token")} ${import_picocolors64.default.dim("<command>")}`);
85744
86713
  out.push("");
85745
- out.push(` ${import_picocolors61.default.cyan("create")} ${import_picocolors61.default.dim("issue a new long-lived CLI key (PAT)")}`);
85746
- out.push(` ${import_picocolors61.default.cyan("list")} ${import_picocolors61.default.dim("show your tokens")}`);
85747
- out.push(` ${import_picocolors61.default.cyan("rename")} ${import_picocolors61.default.dim("<id>")} ${import_picocolors61.default.dim("relabel a token by id")}`);
85748
- out.push(` ${import_picocolors61.default.cyan("revoke")} ${import_picocolors61.default.dim("<id>")} ${import_picocolors61.default.dim("revoke a token by id")}`);
85749
- out.push(` ${import_picocolors61.default.cyan("clear")} ${import_picocolors61.default.dim("forget the local token (does not revoke)")}`);
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(` ${import_picocolors61.default.bold("create flags")}`);
85752
- out.push(` ${import_picocolors61.default.cyan("--name, -n")} ${import_picocolors61.default.dim("<label>")} ${import_picocolors61.default.dim("token label (prompted if omitted)")}`);
85753
- out.push(` ${import_picocolors61.default.cyan("--scopes")} ${import_picocolors61.default.dim("<list>")} ${import_picocolors61.default.dim("comma-separated; allowed: read, publish, admin")}`);
85754
- out.push(` ${import_picocolors61.default.dim("default: read,publish")}`);
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(` ${import_picocolors61.default.bold("rename flags")}`);
85757
- out.push(` ${import_picocolors61.default.cyan("--name, -n")} ${import_picocolors61.default.dim("<label>")} ${import_picocolors61.default.dim("new label (prompted if omitted)")}`);
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 import_picocolors63 = __toESM(require_picocolors(), 1);
86733
+ var import_picocolors66 = __toESM(require_picocolors(), 1);
85765
86734
 
85766
86735
  // src/cli/integration-context.ts
85767
- var import_picocolors62 = __toESM(require_picocolors(), 1);
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: fail3 } = options;
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 fail3(`${problem} ${CONTEXT_USAGE.split(`
86894
+ return fail4(`${problem} ${CONTEXT_USAGE.split(`
85926
86895
  `)[0]}`);
85927
86896
  }
85928
86897
  if ("error" in parsed)
85929
- return fail3(parsed.error);
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 fail3(`Unexpected argument: ${sanitizeLabel(positionals[0])}. ${CREATE_USAGE}`);
86902
+ return fail4(`Unexpected argument: ${sanitizeLabel(positionals[0])}. ${CREATE_USAGE}`);
85934
86903
  if (values2.has("--reason"))
85935
- return fail3(`--reason is for \`context end\`. ${CREATE_USAGE}`);
86904
+ return fail4(`--reason is for \`context end\`. ${CREATE_USAGE}`);
85936
86905
  const target = cloudTargetAgent(cwd2, options);
85937
86906
  if (!target)
85938
- return fail3(NO_AGENT_MESSAGE);
86907
+ return fail4(NO_AGENT_MESSAGE);
85939
86908
  if ("error" in target)
85940
- return fail3(target.error);
86909
+ return fail4(target.error);
85941
86910
  if (!UUID_PATTERN.test(target.agentId)) {
85942
- return fail3(`${sanitizeLabel(target.agentId)} is not an agent id. --agent takes the agent's UUID, as \`brainbase agent list\` shows it.`);
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 fail3(`--application is required. ${CREATE_USAGE}`);
86916
+ return fail4(`--application is required. ${CREATE_USAGE}`);
85948
86917
  if (!APPLICATION_PATTERN.test(application)) {
85949
- return fail3(`--application must be 1-120 characters of lowercase letters, digits and . _ : / -, starting with a letter or digit (e.g. billing-sync); got "${sanitizeLabel(application)}".`);
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 fail3(lifetime.error);
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 fail3(`brainbase integrations context create failed: ${message(err)}`);
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 fail3(`--application and --max-lifetime are for \`context create\`. ${END_USAGE}`);
86943
+ return fail4(`--application and --max-lifetime are for \`context create\`. ${END_USAGE}`);
85975
86944
  }
85976
86945
  if (positionals.length !== 1)
85977
- return fail3(END_USAGE);
86946
+ return fail4(END_USAGE);
85978
86947
  const contextId = positionals[0];
85979
86948
  if (!UUID_PATTERN.test(contextId)) {
85980
- return fail3(`${sanitizeLabel(contextId)} is not a context id. Pass the context_id \`context create\` printed.`);
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 fail3(`--reason must be 1-${MAX_REASON_LENGTH2} characters; got ${reasonLength}.`);
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 fail3(`brainbase integrations context end failed: ${message(err)}`);
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" ? `${import_picocolors62.default.green("✓")} Ended integration context ${id}. Its renewal handle and access grants no longer work.
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
- `${import_picocolors62.default.green("✓")} Created integration context ${id}`,
86060
- ` ${import_picocolors62.default.dim(`agent ${agentId} · application ${application}`)}`,
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
- import_picocolors62.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."),
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")} ${import_picocolors62.default.dim("(its maximum lifetime)")}`,
87038
+ ` Context ends ${sanitizeLabel(created.max_expires_at ?? "unknown")} ${import_picocolors65.default.dim("(its maximum lifetime)")}`,
86070
87039
  "",
86071
- import_picocolors62.default.dim(` End it sooner with \`brainbase integrations context end ${id}\`.`),
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 fail3 = (message2) => {
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: fail3
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 fail3(`${problem} ${USAGE.split(`
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 fail3(`Usage: brainbase integrations ${sub} <${sub === "search" ? "query" : isEffect ? "app>[.<action>" : "app"}>`);
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 fail3(`brainbase integrations search failed: ${message2(err)}`);
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 fail3(NO_AGENT_MESSAGE);
87130
+ return fail4(NO_AGENT_MESSAGE);
86162
87131
  if ("error" in target)
86163
- return fail3(target.error);
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 fail3(`brainbase integrations ${sub} failed: ${message2(err)}`);
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 }, `${import_picocolors63.default.green("✓")} Added ${import_picocolors63.default.bold(label2(added.name))}. It needs no account; your agent can use it on its next turn.
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 fail3(`${name} needs no account. Run brainbase integrations add ${label2(slug)} instead.`);
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 fail3("The server returned an unusable connect link.");
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 ${import_picocolors63.default.bold(name)}:
87225
+ write3(`Open this link to connect ${import_picocolors66.default.bold(name)}:
86257
87226
 
86258
- ${import_picocolors63.default.cyan(url2)}
87227
+ ${import_picocolors66.default.cyan(url2)}
86259
87228
 
86260
87229
  `);
86261
- write3(import_picocolors63.default.dim(`Anyone with this link can connect an account to this agent until it expires, so do not share it.
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(import_picocolors63.default.dim(`Opening your browser…
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(import_picocolors63.default.dim("Not waiting. Run `brainbase integrations list` to see when it is connected.\n"));
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(`${import_picocolors63.default.green("✔")} ${text3}
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 fail3(`No connected ${label2(slug)} account on this agent.`);
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 fail3(`${label2(options.account)} is not a ${label2(slug)} account on this agent. Its accounts: ${describeAccounts(accounts)}.`);
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 fail3(`This agent has ${accounts.length} ${label2(slug)} accounts. Pick one with --account <id>: ${describeAccounts(accounts)}.`);
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 fail3("`brainbase integrations disconnect --json` never prompts. Pass --yes to disconnect without one.");
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" }, ` ${import_picocolors63.default.dim("Left alone.")}
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 }, `${import_picocolors63.default.green("✓")} Disconnected ${import_picocolors63.default.bold(label2(slug))} account ${accountLabel}.
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 fail3(`${label2(slug)} is connected with an account. Run brainbase integrations disconnect ${label2(slug)} instead.`);
87323
+ return fail4(`${label2(slug)} is connected with an account. Run brainbase integrations disconnect ${label2(slug)} instead.`);
86355
87324
  }
86356
- return fail3(`${label2(slug)} is not installed on this agent.`);
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 }, `${import_picocolors63.default.green("✓")} Removed ${import_picocolors63.default.bold(label2(slug))}.
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 fail3(`Usage: brainbase integrations ${effect} <app>[.<action>]`);
87334
+ return fail4(`Usage: brainbase integrations ${effect} <app>[.<action>]`);
86366
87335
  if (!permissionToken(app) || action !== undefined && !permissionToken(action)) {
86367
- return fail3(`${label2(raw)} is not an app or action name. Use the key \`brainbase integrations actions <app>\` shows.`);
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 }, `${import_picocolors63.default.green("✓")} ${capability} → ${import_picocolors63.default.bold(effect)} ${import_picocolors63.default.dim(`(${scope})`)}
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: import_picocolors63.default.green,
86426
- ask: import_picocolors63.default.yellow,
86427
- deny: import_picocolors63.default.red
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] ?? import_picocolors63.default.dim)(sanitizeLabel(effect).padEnd(width));
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(import_picocolors63.default.yellow(" Integrations only work on Kafka agents for now; this agent cannot use them."), "");
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(import_picocolors63.default.dim(" No integrations on this agent."));
86439
- lines.push(import_picocolors63.default.dim(" Find one with `brainbase integrations search <query>`, then `brainbase integrations add <app>`."), "");
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 ? import_picocolors63.default.green("✓") : import_picocolors63.default.yellow("!");
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} ${import_picocolors63.default.bold(sanitizeLabel(row.app))} ${import_picocolors63.default.dim(bits.join(" · "))} ${effectLabel(effect)}${row.effect ? "" : import_picocolors63.default.dim(" (default)")}`);
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("", import_picocolors63.default.dim(" Run `brainbase integrations actions <app>` to see and set per-action permissions."), "");
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 import_picocolors63.default.dim("No apps match.") + `
87430
+ return import_picocolors66.default.dim("No apps match.") + `
86462
87431
  `;
86463
87432
  const lines = [""];
86464
87433
  for (const app of apps) {
86465
- const hint = needsAccount(app) ? "" : import_picocolors63.default.dim(" no account needed");
86466
- lines.push(` ${import_picocolors63.default.bold(sanitizeLabel(app.nameSlug))} ${sanitizeLabel(app.name)}${hint}`);
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("", import_picocolors63.default.dim(" Add one with `brainbase integrations add <app>`."), "");
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 import_picocolors63.default.dim(`No actions found for ${sanitizeLabel(slug)}.`) + `
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 = import_picocolors63.default.dim((row.source === "action" ? "" : `(${row.source})`).padEnd(9));
86479
- lines.push(` ${effectLabel(row.effect, 5)} ${source} ${import_picocolors63.default.bold(sanitizeLabel(row.key))} ${import_picocolors63.default.dim(sanitizeLabel(row.name))}`);
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("", import_picocolors63.default.dim(` Change one with \`brainbase integrations allow|ask|deny ${sanitizeLabel(slug)}.<action>\`, or the whole app with \`… ${sanitizeLabel(slug)}\`.`), "");
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 import_picocolors69 = __toESM(require_picocolors(), 1);
87514
+ var import_picocolors72 = __toESM(require_picocolors(), 1);
86546
87515
 
86547
87516
  // src/cli/task-create.ts
86548
- var import_picocolors65 = __toESM(require_picocolors(), 1);
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 import_picocolors64 = __toESM(require_picocolors(), 1);
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) : import_picocolors64.default.dim("(untitled)");
86692
- lines.push(` ${import_picocolors64.default.green("updated")} ${import_picocolors64.default.bold(title)}`);
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(` ${import_picocolors64.default.dim("task")} ${sanitizeLabel(task.id)}`);
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) : import_picocolors64.default.dim("agent default");
86697
- lines.push(` ${import_picocolors64.default.dim("model")} ${model}`);
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(` ${import_picocolors64.default.bold(import_picocolors64.default.dim("METADATA"))}`);
87670
+ lines.push(` ${import_picocolors67.default.bold(import_picocolors67.default.dim("METADATA"))}`);
86702
87671
  if (metadata.length === 0) {
86703
- lines.push(` ${import_picocolors64.default.dim("none")}`);
87672
+ lines.push(` ${import_picocolors67.default.dim("none")}`);
86704
87673
  }
86705
87674
  for (const [key2, value2] of metadata) {
86706
- lines.push(` ${import_picocolors64.default.dim(sanitizeLabel(key2))} ${sanitizeLabel(value2)}`);
87675
+ lines.push(` ${import_picocolors67.default.dim(sanitizeLabel(key2))} ${sanitizeLabel(value2)}`);
86707
87676
  }
86708
87677
  lines.push("");
86709
- lines.push(` ${import_picocolors64.default.dim("read it with")} ${import_picocolors64.default.cyan(`brainbase task get ${sanitizeLabel(task.id)}`)}`, "");
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(import_picocolors65.default.yellow(`Timed out after ${options.timeoutSeconds}s with the task still ${status}.`));
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(import_picocolors65.default.yellow("Interrupted. The task is still running."));
87820
+ console.log(import_picocolors68.default.yellow("Interrupted. The task is still running."));
86852
87821
  return;
86853
87822
  }
86854
- console.log(code === 0 ? import_picocolors65.default.green("Task completed.") : import_picocolors65.default.red(`Task finished as ${status}.`));
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 import_picocolors67 = __toESM(require_picocolors(), 1);
87830
+ var import_picocolors70 = __toESM(require_picocolors(), 1);
86862
87831
 
86863
87832
  // src/cli/task-list.ts
86864
- var import_picocolors66 = __toESM(require_picocolors(), 1);
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(` ${import_picocolors66.default.dim("No tasks carry every label given with --metadata.")}`, "");
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(` ${import_picocolors66.default.dim(`No build conversations for interface ${id}.`)}`, "", ` ${import_picocolors66.default.dim("start one with")} ${import_picocolors66.default.cyan(`brainbase interface build ${id} "..."`)}`, "");
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(` ${import_picocolors66.default.dim(agentId ? `No tasks for agent ${agentId}.` : "No tasks yet.")}`, "", ` ${import_picocolors66.default.dim("start one with")} ${import_picocolors66.default.cyan('brainbase task create --message "..."')}`, "");
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() || import_picocolors66.default.dim("(untitled)");
86946
- lines.push(` ${statusLabel(task.status)} ${import_picocolors66.default.bold(title)}`);
86947
- lines.push(` ${import_picocolors66.default.dim(sanitizeLabel(task.id))}`);
86948
- lines.push(` ${import_picocolors66.default.dim(`agent ${agentLabel(task.agent_id, names)} · created ${sanitizeLabel(task.created_at)}`)}`);
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(` ${import_picocolors66.default.dim("inspect one with")} ${import_picocolors66.default.cyan("brainbase task get <id>")}`, "");
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 import_picocolors66.default.green(padded);
87928
+ return import_picocolors69.default.green(padded);
86960
87929
  case "fail":
86961
- return import_picocolors66.default.red(padded);
87930
+ return import_picocolors69.default.red(padded);
86962
87931
  case "need_more_info":
86963
- return import_picocolors66.default.yellow(padded);
87932
+ return import_picocolors69.default.yellow(padded);
86964
87933
  case "running":
86965
87934
  case "initializing":
86966
- return import_picocolors66.default.cyan(padded);
87935
+ return import_picocolors69.default.cyan(padded);
86967
87936
  default:
86968
- return import_picocolors66.default.dim(padded);
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() || import_picocolors67.default.dim("(untitled)");
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)} ${import_picocolors67.default.bold(title)}`);
87973
+ lines.push(` ${statusLabel(task.status)} ${import_picocolors70.default.bold(title)}`);
87005
87974
  lines.push("");
87006
- lines.push(` ${import_picocolors67.default.dim("task")} ${id}`);
87007
- lines.push(` ${import_picocolors67.default.dim("agent")} ${agentLabel(task.agent_id, names)}`);
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) : import_picocolors67.default.dim("agent default");
87010
- lines.push(` ${import_picocolors67.default.dim("model")} ${model}`);
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(` ${import_picocolors67.default.dim("created")} ${sanitizeLabel(task.created_at)}`);
87981
+ lines.push(` ${import_picocolors70.default.dim("created")} ${sanitizeLabel(task.created_at)}`);
87013
87982
  if (task.parent_task_id) {
87014
- lines.push(` ${import_picocolors67.default.dim("parent")} ${sanitizeLabel(task.parent_task_id)}`);
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(` ${import_picocolors67.default.dim("machine")} ${sanitizeLabel(task.machine_id)}${size2}`);
87987
+ lines.push(` ${import_picocolors70.default.dim("machine")} ${sanitizeLabel(task.machine_id)}${size2}`);
87019
87988
  }
87020
87989
  if (task.sandbox_id)
87021
- lines.push(` ${import_picocolors67.default.dim("sandbox")} ${sanitizeLabel(task.sandbox_id)}`);
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(` ${import_picocolors67.default.red("failure")} ${failure}`);
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(` ${import_picocolors67.default.bold(import_picocolors67.default.dim("METADATA"))}`);
88002
+ lines.push(` ${import_picocolors70.default.bold(import_picocolors70.default.dim("METADATA"))}`);
87034
88003
  for (const [key2, value2] of metadata) {
87035
- lines.push(` ${import_picocolors67.default.dim(sanitizeLabel(key2))} ${sanitizeLabel(String(value2))}`);
88004
+ lines.push(` ${import_picocolors70.default.dim(sanitizeLabel(key2))} ${sanitizeLabel(String(value2))}`);
87036
88005
  }
87037
88006
  }
87038
88007
  lines.push("");
87039
- lines.push(` ${import_picocolors67.default.bold(import_picocolors67.default.dim("EVAL VERDICTS"))}`);
88008
+ lines.push(` ${import_picocolors70.default.bold(import_picocolors70.default.dim("EVAL VERDICTS"))}`);
87040
88009
  if (evals.unavailable) {
87041
- lines.push(` ${import_picocolors67.default.dim(sanitizeLabel(evals.unavailable))}`);
88010
+ lines.push(` ${import_picocolors70.default.dim(sanitizeLabel(evals.unavailable))}`);
87042
88011
  } else if (evals.runs.length === 0) {
87043
- lines.push(` ${import_picocolors67.default.dim("none")}`);
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 ? import_picocolors67.default.green("pass") : run.passed === false ? import_picocolors67.default.red("fail") : import_picocolors67.default.dim(sanitizeLabel(run.status));
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(` ${import_picocolors67.default.dim(line2)}`);
88019
+ lines.push(` ${import_picocolors70.default.dim(line2)}`);
87051
88020
  }
87052
88021
  }
87053
88022
  }
87054
88023
  lines.push("");
87055
- lines.push(` ${import_picocolors67.default.dim("read its transcript with")} ${import_picocolors67.default.cyan(`brainbase task logs ${id}`)}`, "");
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 import_picocolors68 = __toESM(require_picocolors(), 1);
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(import_picocolors68.default.dim("No events for this task yet."));
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(import_picocolors68.default.dim(`Following task ${taskId} — Ctrl-C to stop.`));
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(import_picocolors68.default.dim(frame.type));
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(import_picocolors68.default.dim(`reconnecting — ${reason}`));
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(` ${import_picocolors69.default.bold("brainbase task")} ${import_picocolors69.default.dim("<sub> [options]")}`);
89057
+ out.push(` ${import_picocolors72.default.bold("brainbase task")} ${import_picocolors72.default.dim("<sub> [options]")}`);
88089
89058
  out.push("");
88090
- out.push(` ${import_picocolors69.default.cyan("create")} ${import_picocolors69.default.dim("--message <text>")} ${import_picocolors69.default.dim("create a task and start its first run")}`);
88091
- out.push(` ${import_picocolors69.default.cyan("list | ls")} ${import_picocolors69.default.dim("recent tasks you can reach (--json for scripts)")}`);
88092
- out.push(` ${import_picocolors69.default.cyan("get")} ${import_picocolors69.default.dim("<task-id>")} ${import_picocolors69.default.dim("one task: status, agent, machine, eval verdicts")}`);
88093
- out.push(` ${import_picocolors69.default.cyan("logs")} ${import_picocolors69.default.dim("<task-id> [--follow]")} ${import_picocolors69.default.dim("one line per event in the task's transcript, or tail it live")}`);
88094
- out.push(` ${import_picocolors69.default.cyan("send")} ${import_picocolors69.default.dim("<task-id> <message>")} ${import_picocolors69.default.dim("send a follow-up, including while the agent is running")}`);
88095
- out.push(` ${import_picocolors69.default.cyan("stop")} ${import_picocolors69.default.dim("<task-id>")} ${import_picocolors69.default.dim("stop execution and cancel pending follow-ups, retaining their text")}`);
88096
- out.push(` ${import_picocolors69.default.cyan("update")} ${import_picocolors69.default.dim("<task-id>")} ${import_picocolors69.default.dim("rename a task, change its metadata labels, switch its model or reset it to the agent default, including while it runs")}`);
88097
- out.push(` ${import_picocolors69.default.cyan("delete")} ${import_picocolors69.default.dim("<task-id>")} ${import_picocolors69.default.dim("permanently delete a stopped task and tear down its sandbox (--yes to skip the prompt)")}`);
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(` ${import_picocolors69.default.bold("create flags")}`);
88100
- out.push(` ${import_picocolors69.default.dim("--message <text>")} required first user message`);
88101
- out.push(` ${import_picocolors69.default.dim("--agent <id>")} override the claimed agent in brainbase.agent.yaml`);
88102
- out.push(` ${import_picocolors69.default.dim("--interface <id>")} open it as a build conversation for this interface (agent defaults to the interface's)`);
88103
- out.push(` ${import_picocolors69.default.dim("--title <text>")} optional task title`);
88104
- out.push(` ${import_picocolors69.default.dim("--model <id>")} optional model override`);
88105
- out.push(` ${import_picocolors69.default.dim("--version <v>")} run a saved version of the agent: 12, v12 or a version id (\`agent versions list\`)`);
88106
- out.push(` ${import_picocolors69.default.dim("--metadata key=value")} label the task (repeatable)`);
88107
- out.push(` ${import_picocolors69.default.dim("--wait")} block until the task finishes; exit 1 unless it succeeded`);
88108
- out.push(` ${import_picocolors69.default.dim("--timeout <secs>")} give up waiting after <secs> and exit 1 (needs --wait)`);
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(` ${import_picocolors69.default.bold("list flags")}`);
88111
- out.push(` ${import_picocolors69.default.dim("--agent <id>")} only this agent's tasks`);
88112
- out.push(` ${import_picocolors69.default.dim("--interface <id>")} only this interface's build conversations (hidden from a plain list)`);
88113
- out.push(` ${import_picocolors69.default.dim("--metadata key=value")} only tasks carrying this label (repeatable; all must match)`);
88114
- out.push(` ${import_picocolors69.default.dim("--limit <n>")} cap the page (1-200, server default 50)`);
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(` ${import_picocolors69.default.bold("logs flags")}`);
88117
- out.push(` ${import_picocolors69.default.dim("--limit <n>")} stop after <n> events instead of the whole transcript; with --follow, the first page size`);
88118
- out.push(` ${import_picocolors69.default.dim("--follow, -f")} stay attached and print events as they land, until the task finishes and any queued follow-ups have run`);
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(` ${import_picocolors69.default.bold("update flags")}`);
88121
- out.push(` ${import_picocolors69.default.dim("--title <text>")} new title`);
88122
- out.push(` ${import_picocolors69.default.dim("--clear-title")} remove the title; automatic titling may name the task again on a later turn`);
88123
- out.push(` ${import_picocolors69.default.dim("--metadata key=value")} set one label, keeping the others (repeatable)`);
88124
- out.push(` ${import_picocolors69.default.dim("--unset-metadata <key>")} remove one label (repeatable)`);
88125
- out.push(` ${import_picocolors69.default.dim(" the server applies label edits in one step, so concurrent edits from other clients are kept")}`);
88126
- out.push(` ${import_picocolors69.default.dim("--clear-metadata")} remove every label; with --metadata, the labels become exactly those given`);
88127
- out.push(` ${import_picocolors69.default.dim("--model <id>")} switch the model the task's next turn runs on (the running turn keeps its model)`);
88128
- out.push(` ${import_picocolors69.default.dim("--clear-model")} go back to the agent's default model from the next turn`);
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(` ${import_picocolors69.default.bold("send flags")}`);
88131
- out.push(` ${import_picocolors69.default.dim("--input-id <uuid>")} recover the same request using its original ID and identical message`);
88132
- out.push(` ${import_picocolors69.default.dim(" omit it to send a new follow-up; an unconfirmed receipt is never automatically replayed")}`);
88133
- out.push(` ${import_picocolors69.default.dim(" admission disabled/recovery unavailable means no input was admitted; retry the same ID after recovery")}`);
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(` ${import_picocolors69.default.bold("send and stop flags")}`);
88136
- out.push(` ${import_picocolors69.default.dim("--generation <n>")} retain the printed generation when retrying; defaults to a fresh snapshot for a new operation`);
88137
- out.push(` ${import_picocolors69.default.dim(" Stop errors may follow queued-input cancellation; retry the printed command to avoid stopping newer work")}`);
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(` ${import_picocolors69.default.bold("every subcommand")}`);
88140
- out.push(` ${import_picocolors69.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`);
88141
- out.push(` ${import_picocolors69.default.dim(" send and stop include expected_generation for safe retries; send also reports idempotency_replayed when present")}`);
88142
- out.push(` ${import_picocolors69.default.dim(" logs --follow --json prints one record per line, since a live stream has no end to close on")}`);
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(` ${import_picocolors69.default.dim("Exit codes with --wait:")} ${import_picocolors69.default.dim("0 succeeded · 1 failed, needs input, or timed out · 130 interrupted")}`);
88145
- out.push(` ${import_picocolors69.default.dim("Exit codes with --follow:")} ${import_picocolors69.default.dim("0 task reached a terminal state · 1 stream refused, or unreachable for 60s · 130 interrupted (Ctrl-C) · 143 terminated")}`);
88146
- out.push(` ${import_picocolors69.default.dim("Exit codes with send:")} ${import_picocolors69.default.dim("0 queued, dispatching, submitted or completed · 1 unconfirmed, cancelled, failed or request error")}`);
88147
- out.push(` ${import_picocolors69.default.dim("Ctrl-C while waiting or following logs detaches; use task stop to cancel remote work.")}`);
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(` ${import_picocolors69.default.dim("Flag-like values:")} use ${import_picocolors69.default.cyan("--flag=value")} or ${import_picocolors69.default.cyan("--flag -- <value>")}`);
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 import_picocolors72 = __toESM(require_picocolors(), 1);
89125
+ var import_picocolors75 = __toESM(require_picocolors(), 1);
88157
89126
 
88158
89127
  // src/cli/machine-list.ts
88159
- var import_picocolors70 = __toESM(require_picocolors(), 1);
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(` ${import_picocolors70.default.dim(includedDead ? "No machines." : "No live machines. Pass --all to include torn-down ones.")}`, "");
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(` ${import_picocolors70.default.dim([
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
- import_picocolors70.default.dim(row.age)
89182
+ import_picocolors73.default.dim(row.age)
88214
89183
  ].join(" ");
88215
- lines.push(` ${row.dead ? import_picocolors70.default.dim(cells) : cells}`);
89184
+ lines.push(` ${row.dead ? import_picocolors73.default.dim(cells) : cells}`);
88216
89185
  }
88217
- lines.push("", ` ${import_picocolors70.default.dim("tear one down with")} ${import_picocolors70.default.cyan("brainbase machine rm <id>")}`, "");
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 import_picocolors70.default.green(padded);
89193
+ return import_picocolors73.default.green(padded);
88225
89194
  case "stopped":
88226
89195
  case "starting":
88227
- return import_picocolors70.default.yellow(padded);
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 import_picocolors71 = __toESM(require_picocolors(), 1);
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(` ${import_picocolors71.default.dim("Left alone.")}`);
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
- ${import_picocolors71.default.red("This destroys the sandbox.")} ${import_picocolors71.default.dim("Anything not committed out of it is lost. The machine row is kept for cost history.")}
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(` ${import_picocolors71.default.green("✓")} ${machine.kind} sandbox ${machine.id} is torn down.`, ` ${import_picocolors71.default.dim(`destroyed_at ${machine.destroyed_at}`)}`);
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(` ${import_picocolors71.default.yellow("!")} ${machine.id} came back without a teardown timestamp (status ${machine.status}).`, ` ${import_picocolors71.default.dim("Re-check with `brainbase machine ls --all` before assuming it stopped billing.")}`);
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(` ${import_picocolors72.default.bold("brainbase machine")} ${import_picocolors72.default.dim("<sub> [options]")}`);
89306
+ out.push(` ${import_picocolors75.default.bold("brainbase machine")} ${import_picocolors75.default.dim("<sub> [options]")}`);
88338
89307
  out.push("");
88339
- out.push(` ${import_picocolors72.default.cyan("ls")} ${import_picocolors72.default.dim("list your sandboxes — live ones only unless --all")}`);
88340
- out.push(` ${import_picocolors72.default.cyan("rm")} ${import_picocolors72.default.dim("<id>")} ${import_picocolors72.default.dim("tear a sandbox down (terminal; the row is kept for cost history)")}`);
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(` ${import_picocolors72.default.dim("--all")} ${import_picocolors72.default.dim("for ls: include machines already torn down")}`);
88343
- out.push(` ${import_picocolors72.default.dim("--limit <n>")} ${import_picocolors72.default.dim("for ls: how many to fetch (1-200, default 50)")}`);
88344
- out.push(` ${import_picocolors72.default.dim("--yes, -y")} ${import_picocolors72.default.dim("for rm: skip the confirmation")}`);
88345
- out.push(` ${import_picocolors72.default.dim("--json")} ${import_picocolors72.default.dim("machine-readable output")}`);
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 import_picocolors78 = __toESM(require_picocolors(), 1);
89321
+ var import_picocolors81 = __toESM(require_picocolors(), 1);
88353
89322
 
88354
89323
  // src/cli/interface-build.ts
88355
- var import_picocolors73 = __toESM(require_picocolors(), 1);
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(` ${import_picocolors73.default.dim("build")} ${safe(outcome.build.id)} ${import_picocolors73.default.green("succeeded")}`);
89423
+ say(` ${import_picocolors76.default.dim("build")} ${safe(outcome.build.id)} ${import_picocolors76.default.green("succeeded")}`);
88455
89424
  say("");
88456
- say(` ${import_picocolors73.default.dim("Next:")} ${import_picocolors73.default.cyan(`brainbase interface publish ${safe(interfaceId)}`)}`);
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(` ${import_picocolors73.default.dim("build")} ${outcome.build ? safe(outcome.build.id) : import_picocolors73.default.dim("none")} ${import_picocolors73.default.red("failed")}`);
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(` ${import_picocolors73.default.dim("Try again with")} ${import_picocolors73.default.cyan(`brainbase interface rebuild ${safe(interfaceId)}`)}`);
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(` ${import_picocolors73.default.yellow(safe(outcome.message))}`);
89438
+ say(` ${import_picocolors76.default.yellow(safe(outcome.message))}`);
88470
89439
  return;
88471
89440
  case "timeout":
88472
- say(` ${import_picocolors73.default.yellow(`Still building after ${timeoutSeconds}s.`)} ${import_picocolors73.default.dim(`It keeps going; check \`brainbase interface builds ${safe(interfaceId)}\`.`)}`);
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(` ${import_picocolors73.default.yellow("Stopped waiting.")} ${import_picocolors73.default.dim(`The build keeps going; check \`brainbase interface builds ${safe(interfaceId)}\`.`)}`);
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(` ${import_picocolors73.default.dim("Build conversation")} ${import_picocolors73.default.bold(safe(taskId))} ${import_picocolors73.default.dim(`on ${safe(before2.name)}`)}`);
88523
- say(` ${import_picocolors73.default.dim(`If this stops early, reattach with \`${reattach}\`.`)}`);
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(` ${import_picocolors73.default.red(`Lost the conversation's event stream: ${safe(error2.message)}`)}`);
88541
- say(` ${import_picocolors73.default.dim(`Conversation ${safe(taskId)} may still be running. Reattach with`)} ${import_picocolors73.default.cyan(reattach)}`);
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(` ${import_picocolors73.default.yellow("Stopped following.")} ${import_picocolors73.default.dim(`The conversation keeps running. Reattach with \`${reattach}\`.`)}`);
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(` ${import_picocolors73.default.yellow(interrupted ? "Stopped." : `The conversation is still ${safe(status2 ?? "running")}.`)} ${import_picocolors73.default.dim(`Check it with \`brainbase task get ${safe(taskId)}\`.`)}`);
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(` ${import_picocolors73.default.dim("conversation")} ${safe(taskId)} ${import_picocolors73.default.dim("ended")} ${safe(task.status)}`);
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(` ${import_picocolors73.default.red(`This conversation's build work failed${why ? ` (${why})` : ""}.`)}`);
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(` ${import_picocolors73.default.red(`The conversation finished as ${safe(task.status)}.`)} ${import_picocolors73.default.dim(`See \`brainbase task logs ${safe(taskId)}\`.`)}`);
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(` ${import_picocolors73.default.bold("The agent asks:")}`);
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(` ${import_picocolors73.default.bold("The agent needs more from you before it can go on.")}`);
89567
+ say(` ${import_picocolors76.default.bold("The agent needs more from you before it can go on.")}`);
88599
89568
  }
88600
89569
  say("");
88601
- say(` ${import_picocolors73.default.dim("Reply with")} ${import_picocolors73.default.cyan(`brainbase task send ${safe(taskId)} "<reply>"`)}`);
88602
- say(` ${import_picocolors73.default.dim("then follow it with")} ${import_picocolors73.default.cyan(reattach)}`);
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(` ${import_picocolors73.default.dim("version")} ${safe(versionId)}`);
89577
+ say(` ${import_picocolors76.default.dim("version")} ${safe(versionId)}`);
88609
89578
  if (!json3)
88610
- say(` ${import_picocolors73.default.dim("Waiting for its build...")}`);
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(` ${import_picocolors73.default.yellow("The build looks stalled; still waiting in case another worker picks it up.")}`)
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(` ${import_picocolors73.default.red("The conversation finished without committing a version, so there is nothing to build.")}`);
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(` ${import_picocolors73.default.dim("This conversation produced no version, so there is nothing to build.")}`);
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 import_picocolors75 = __toESM(require_picocolors(), 1);
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 import_picocolors74 = __toESM(require_picocolors(), 1);
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 import_picocolors74.default.green;
89698
+ return import_picocolors77.default.green;
88730
89699
  case "building":
88731
- return import_picocolors74.default.yellow;
89700
+ return import_picocolors77.default.yellow;
88732
89701
  case "archived":
88733
- return import_picocolors74.default.dim;
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
- ${import_picocolors74.default.dim(empty)}
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, import_picocolors74.default.bold, null, null, null, import_picocolors74.default.dim]), ""].join(`
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)} ${import_picocolors74.default.dim("(nothing live yet)")}`));
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)} ${import_picocolors74.default.dim(`published ${ago(row.live_release.published_at)}`)}` : import_picocolors74.default.dim("none")));
88817
- out.push(field("draft", row.draft_version_id ? safe(row.draft_version_id) : import_picocolors74.default.dim("none yet")));
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 ?? "")} ${import_picocolors74.default.dim(`(follow it with \`brainbase task logs ${safe(row.running_generation.thread_id ?? "")} --follow\`)`)}`));
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(import_picocolors74.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."));
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
- ${import_picocolors74.default.dim(`No ${name} yet.`)}
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) : import_picocolors75.default.dim("nobody named");
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
- ` ${import_picocolors75.default.green("Created")} ${import_picocolors75.default.bold(safe(created.name))}`,
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)} ${import_picocolors75.default.dim("(nothing live yet)")}`),
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(` ${import_picocolors75.default.dim(`To show viewers only their own conversations: \`brainbase interface threads ${id} --private\`.`)}`);
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("", ` ${import_picocolors75.default.dim(`Next: \`brainbase interface build ${id} "<what to build>"\``)}`, "");
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 ? "" : ` ${import_picocolors75.default.dim("(already set; nothing changed)")}`;
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 ${import_picocolors75.default.bold(safe(updated.name))}.
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 ${import_picocolors75.default.bold(where)}.
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 import_picocolors76 = __toESM(require_picocolors(), 1);
90351
+ var import_picocolors79 = __toESM(require_picocolors(), 1);
89383
90352
  function warn(line2) {
89384
- console.error(import_picocolors76.default.yellow(line2));
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(import_picocolors76.default.dim(` Previewing ${why}, ${safe(taskId)}.`));
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(import_picocolors76.default.dim(" Starting the dev server in the sandbox…"));
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" ? import_picocolors76.default.green("Preview ready") : import_picocolors76.default.yellow("Preview starting")} ${import_picocolors76.default.bold(safe(started.name))}`,
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) : import_picocolors76.default.dim(missingAddress(started))),
90458
+ field("address", address2 ? safe(address2) : import_picocolors79.default.dim(missingAddress(started))),
89490
90459
  field("showing", showing(started, taskId)),
89491
90460
  "",
89492
- ` ${import_picocolors76.default.dim("Opens for people who can edit the agent, after signing in. Nothing is published.")}`,
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 import_picocolors77 = __toESM(require_picocolors(), 1);
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(import_picocolors77.default.yellow(line2));
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(import_picocolors77.default.dim(` ${what} ${operation.status}`)),
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(import_picocolors77.default.red(`The ${what} failed (operation ${id}):`));
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(import_picocolors77.default.dim(` Follow it with \`brainbase interface builds ${safe(id)}\`.`));
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(import_picocolors77.default.green(`✓ Build ${buildId} succeeded${version2 ? ` (version ${version2})` : ""}.`));
89628
- console.log(import_picocolors77.default.dim(` Publish it with \`brainbase interface publish ${safe(id)} --build ${buildId}\`.`));
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)} ${import_picocolors77.default.dim(`(version ${safe(build2.source_version_id)}, built ${ago(build2.created_at)})`)}`;
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(` ${import_picocolors77.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_picocolors77.default.dim("nothing")}`);
89741
- console.log(` ${import_picocolors77.default.dim("Will publish".padEnd(14))}${describeBuild(buildId, builds)}`);
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(import_picocolors77.default.dim(` Check it with \`brainbase interface get ${safe(id)}\`.`));
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(import_picocolors77.default.green(`✓ Build ${safe(buildId)} is live.`));
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(import_picocolors77.default.dim(` Its address could not be read just now; see it with \`brainbase interface open ${safe(id)}\`.`));
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(` ${import_picocolors77.default.dim("Live now".padEnd(16))}release ${safe(row.live_release.id)} at ${safe(row.live_release.url)}`);
89842
- console.log(` ${import_picocolors77.default.dim("Will republish".padEnd(16))}release ${safe(releaseId)} ${import_picocolors77.default.dim("as a new release, with a new id")}`);
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(import_picocolors77.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.`));
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 ` ${import_picocolors78.default.cyan(command)}${args ? ` ${import_picocolors78.default.dim(args)}` : ""}
89911
- ${import_picocolors78.default.dim(description)}`;
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(` ${import_picocolors78.default.bold("brainbase interface")} ${import_picocolors78.default.dim("<sub> [options]")}`);
89917
- out.push(` ${import_picocolors78.default.dim("Dashboards for an agent: build them in a conversation, publish them, choose who can open them.")}`);
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(` ${import_picocolors78.default.dim("--json")} machine-readable output; never prompts`);
89938
- out.push(` ${import_picocolors78.default.dim("--yes, -y")} skip confirmation (required without a terminal)`);
89939
- out.push(` ${import_picocolors78.default.dim("--no-wait")} for rebuild and publish: return the operation at once; for preview: do not wait for the dev server`);
89940
- out.push(` ${import_picocolors78.default.dim("--timeout <seconds>")} for build, rebuild, publish and preview: how long to wait (builds 900, publish and preview 300)`);
89941
- out.push(` ${import_picocolors78.default.dim("--idempotency-key <key>")} replay a create, build, rebuild, publish or rollback whose answer was lost`);
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(` ${import_picocolors78.default.dim("People are emails (see `brainbase member ls`), user ids, or `me`. Audience members also need access to the agent.")}`);
89944
- out.push(` ${import_picocolors78.default.dim("Audience: everyone (--everyone, `org` under --json) or chosen people (--people, `users` under --json).")}`);
89945
- out.push(` ${import_picocolors78.default.dim("Exit codes: 0 done, 1 refused or failed, 130 interrupted (the server keeps working).")}`);
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 import_picocolors79 = __toESM(require_picocolors(), 1);
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
- ${import_picocolors79.default.dim("Nobody here you can see.")}
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)} ${import_picocolors79.default.dim(row.role.padEnd(roleWidth))} ${import_picocolors79.default.dim(row.teams)}`.trimEnd());
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("", ` ${import_picocolors79.default.dim("share a dashboard with one of them:")} ${import_picocolors79.default.cyan("brainbase interface access <id> --add <email>")}`, "");
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(` ${import_picocolors79.default.bold("brainbase member")} ${import_picocolors79.default.dim("<sub> [options]")}`);
90987
+ out.push(` ${import_picocolors82.default.bold("brainbase member")} ${import_picocolors82.default.dim("<sub> [options]")}`);
90019
90988
  out.push("");
90020
- out.push(` ${import_picocolors79.default.cyan("ls")} ${import_picocolors79.default.dim("the people in an organization you can see, with their emails, roles and teams")}`);
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(` ${import_picocolors79.default.dim("--org <id-or-slug>")} ${import_picocolors79.default.dim("which organization (picked automatically when you are in one)")}`);
90023
- out.push(` ${import_picocolors79.default.dim("--json")} ${import_picocolors79.default.dim("machine-readable output")}`);
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(` ${import_picocolors79.default.dim("Owners and admins see everyone. Anyone else sees the owners, the admins, themselves")}`);
90026
- out.push(` ${import_picocolors79.default.dim("and the people who share a team with them, as in the web app.")}`);
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 fail3 = (error2) => {
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
- fail3(new BenchmarkPhaseError("output_limit_exceeded", `command output exceeded budget: ${command.id}`));
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
- fail3(new BenchmarkCommandExecutionError("command_start_failed", `failed to start ${command.id}: ${error2.message}`, Buffer.concat(stdout), Buffer.concat(stderr), Date.now() - started));
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
- fail3(new BenchmarkPhaseError("phase_timeout", "phase budget expired"));
92752
+ fail4(new BenchmarkPhaseError("phase_timeout", "phase budget expired"));
91784
92753
  return;
91785
92754
  }
91786
- fail3(new BenchmarkCommandExecutionError("command_timeout", `command timed out: ${command.id}`, Buffer.concat(stdout), Buffer.concat(stderr), Date.now() - started));
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 import_picocolors80 = __toESM(require_picocolors(), 1);
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
- ` ${import_picocolors80.default.bold("brainbase benchmark")} ${import_picocolors80.default.dim("<command> [options]")}`,
97102
+ ` ${import_picocolors83.default.bold("brainbase benchmark")} ${import_picocolors83.default.dim("<command> [options]")}`,
96134
97103
  "",
96135
- ` ${import_picocolors80.default.cyan("init | list | show | create | validate | pull | push")}`,
96136
- ` ${import_picocolors80.default.cyan("publish | revisions | import | export | archive | restore")}`,
96137
- ` ${import_picocolors80.default.cyan("run plan|start|watch|list|show|cancel|resume")}`,
96138
- ` ${import_picocolors80.default.cyan("results | diagnoses | attempt | artifacts | export-results")}`,
96139
- ` ${import_picocolors80.default.cyan("history | baseline show|set|clear")}`,
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
- ` ${import_picocolors80.default.dim("Use --agent to override brainbase.agent.yaml, and --json or --jsonl for automation.")}`,
97110
+ ` ${import_picocolors83.default.dim("Use --agent to override brainbase.agent.yaml, and --json or --jsonl for automation.")}`,
96142
97111
  "",
96143
- ` ${import_picocolors80.default.bold("benchmark runtime (machine-only)")}`,
96144
- ` ${import_picocolors80.default.cyan("hydrate")} ${import_picocolors80.default.dim("--spec <path> --result <path> --json")}`,
96145
- ` ${import_picocolors80.default.cyan("evaluate")} ${import_picocolors80.default.dim("--spec <path> --result <path> --json")}`,
96146
- ` ${import_picocolors80.default.cyan("capabilities")} ${import_picocolors80.default.dim("--json")}`,
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("◆")} ${import_picocolors81.default.bold("brainbase")} ${import_picocolors81.default.dim(`v${VERSION}`)}`);
97615
- out.push(` ${import_picocolors81.default.dim("connect your local agent to the brainbase platform")}`);
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(` ${import_picocolors81.default.bold("brainbase")} ${import_picocolors81.default.dim("<command> [options]")}`);
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(` ${import_picocolors81.default.cyan("login")} ${import_picocolors81.default.dim(" open the web app and connect this device")}`);
97624
- out.push(` ${import_picocolors81.default.cyan("logout")} ${import_picocolors81.default.dim(" clear the local session")}`);
97625
- out.push(` ${import_picocolors81.default.cyan("whoami")} ${import_picocolors81.default.dim("[--json]")} ${import_picocolors81.default.dim(" show which credential is in use and what it covers")}`);
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(` ${import_picocolors81.default.cyan("team list")} ${import_picocolors81.default.dim("show the teams you can create agents in")}`);
97630
- out.push(` ${import_picocolors81.default.cyan("member ls")} ${import_picocolors81.default.dim("show the people in an organization, with the emails interface access takes")}`);
97631
- out.push(` ${import_picocolors81.default.cyan("agent list")} ${import_picocolors81.default.dim("show a team's agents and their ids")}`);
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(` ${import_picocolors81.default.cyan("agent init")} ${import_picocolors81.default.dim("write a starter brainbase.agent.yaml here — offline, no login needed")}`);
97636
- out.push(` ${import_picocolors81.default.cyan("agent create")} ${import_picocolors81.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
97637
- out.push(` ${import_picocolors81.default.cyan("agent pull")} ${import_picocolors81.default.dim("[<id>]")} ${import_picocolors81.default.dim("bring cloud changes into this folder (--force to override; --run-entrypoint to also execute the agent entrypoint; --link to link first)")}`);
97638
- out.push(` ${import_picocolors81.default.cyan("agent push")} ${import_picocolors81.default.dim("send local changes to the cloud (--force to overwrite cloud-side conflicts with local)")}`);
97639
- out.push(` ${import_picocolors81.default.cyan("agent delete")} ${import_picocolors81.default.dim("<id>")} ${import_picocolors81.default.dim("permanently delete a cloud agent and every task it has run")}`);
97640
- out.push(` ${import_picocolors81.default.cyan("agent unpack")} ${import_picocolors81.default.dim("install the claimed agent into a harness layout")}`);
97641
- out.push(` ${import_picocolors81.default.cyan("link")} ${import_picocolors81.default.dim("attach this folder to an existing agent")}`);
97642
- out.push(` ${import_picocolors81.default.cyan("agent status")} ${import_picocolors81.default.dim("show what would pull and what would push")}`);
97643
- out.push(` ${import_picocolors81.default.cyan("agent connections")} ${import_picocolors81.default.dim("show which integrations this agent is wired to (--json for CI)")}`);
97644
- out.push(` ${import_picocolors81.default.cyan("agent connect")} ${import_picocolors81.default.dim("<name>")} ${import_picocolors81.default.dim("connect chat, slack, meeting, github, linear or phone")}`);
97645
- out.push(` ${import_picocolors81.default.cyan("agent disconnect")} ${import_picocolors81.default.dim("<name>")} ${import_picocolors81.default.dim("disable or disconnect an agent surface")}`);
97646
- out.push(` ${import_picocolors81.default.cyan("agent surface")} ${import_picocolors81.default.dim("<name>")} ${import_picocolors81.default.dim("status, settings and setup for all six surfaces (--help)")}`);
97647
- out.push(` ${import_picocolors81.default.cyan("agent versions")} ${import_picocolors81.default.dim("saved versions: list, show, diff, label, restore, pin and unpin (`agent versions --help`)")}`);
97648
- out.push(` ${import_picocolors81.default.cyan("agent eval")} ${import_picocolors81.default.dim("<list|runs>")} ${import_picocolors81.default.dim("read eval definitions and judge verdicts (`agent eval --help`)")}`);
97649
- out.push(` ${import_picocolors81.default.cyan("agent env")} ${import_picocolors81.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
97650
- out.push(` ${import_picocolors81.default.cyan("run")} ${import_picocolors81.default.dim("<cmd> [args...]")} ${import_picocolors81.default.dim("run <cmd> with secrets.env loaded into env")}`);
97651
- out.push(` ${import_picocolors81.default.cyan("status")} ${import_picocolors81.default.dim("show what this folder is linked to")}`);
97652
- out.push(` ${import_picocolors81.default.cyan("unlink")} ${import_picocolors81.default.dim("disconnect this folder")}`);
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(` ${import_picocolors81.default.cyan("task create")} ${import_picocolors81.default.dim("--message <text>")} ${import_picocolors81.default.dim("create a managed task and start its first run (--wait to block on it; --interface <id> for a build conversation)")}`);
97657
- out.push(` ${import_picocolors81.default.cyan("task list")} ${import_picocolors81.default.dim("recent tasks you can reach (--metadata k=v to filter by label; --interface <id> for its build conversations)")}`);
97658
- out.push(` ${import_picocolors81.default.cyan("task get")} ${import_picocolors81.default.dim("<task-id>")} ${import_picocolors81.default.dim("one task: status, agent, machine, eval verdicts")}`);
97659
- out.push(` ${import_picocolors81.default.cyan("task logs")} ${import_picocolors81.default.dim("<task-id> [--follow]")} ${import_picocolors81.default.dim("one line per event in the task's transcript, or tail it live")}`);
97660
- out.push(` ${import_picocolors81.default.cyan("task send")} ${import_picocolors81.default.dim("<task-id> <message>")} ${import_picocolors81.default.dim("send a follow-up during execution, or queue it for the next turn")}`);
97661
- out.push(` ${import_picocolors81.default.cyan("task stop")} ${import_picocolors81.default.dim("<task-id>")} ${import_picocolors81.default.dim("stop execution and cancel pending follow-ups, retaining their text")}`);
97662
- out.push(` ${import_picocolors81.default.cyan("task update")} ${import_picocolors81.default.dim("<task-id>")} ${import_picocolors81.default.dim("rename a task, change its metadata labels, switch its model or reset it to the agent default, including while it runs")}`);
97663
- out.push(` ${import_picocolors81.default.cyan("task delete")} ${import_picocolors81.default.dim("<task-id>")} ${import_picocolors81.default.dim("permanently delete a stopped task and tear down its sandbox")}`);
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(` ${import_picocolors81.default.cyan("interface ls")} ${import_picocolors81.default.dim("dashboards you can see (--agent to narrow)")}`);
97668
- out.push(` ${import_picocolors81.default.cyan("interface create")} ${import_picocolors81.default.dim("--name <n>")} ${import_picocolors81.default.dim("create one on an agent, with who can open it")}`);
97669
- out.push(` ${import_picocolors81.default.cyan("interface build")} ${import_picocolors81.default.dim('<id> "<ask>"')} ${import_picocolors81.default.dim("describe a change; the agent builds it while you watch")}`);
97670
- out.push(` ${import_picocolors81.default.cyan("interface publish")} ${import_picocolors81.default.dim("<id>")} ${import_picocolors81.default.dim("make the newest succeeded build live")}`);
97671
- out.push(` ${import_picocolors81.default.cyan("interface rollback")} ${import_picocolors81.default.dim("<id>")} ${import_picocolors81.default.dim("republish an earlier release under a new id (--release <id>)")}`);
97672
- out.push(` ${import_picocolors81.default.cyan("interface access")} ${import_picocolors81.default.dim("<id>")} ${import_picocolors81.default.dim("show or set who can open it")}`);
97673
- out.push(` ${import_picocolors81.default.cyan("interface --help")} ${import_picocolors81.default.dim("every interface subcommand")}`);
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(` ${import_picocolors81.default.cyan("machine ls")} ${import_picocolors81.default.dim("[--all]")} ${import_picocolors81.default.dim("list your sandboxes — live ones only unless --all")}`);
97678
- out.push(` ${import_picocolors81.default.cyan("machine rm")} ${import_picocolors81.default.dim("<id>")} ${import_picocolors81.default.dim("tear a sandbox down (it bills until you do)")}`);
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(` ${import_picocolors81.default.cyan("benchmark list")} ${import_picocolors81.default.dim("list benchmarks for the linked agent")}`);
97683
- out.push(` ${import_picocolors81.default.cyan("benchmark init")} ${import_picocolors81.default.dim("[directory]")} ${import_picocolors81.default.dim("scaffold a local benchmark")}`);
97684
- out.push(` ${import_picocolors81.default.cyan("benchmark create")} ${import_picocolors81.default.dim("[path|-]")} ${import_picocolors81.default.dim("create a benchmark draft")}`);
97685
- out.push(` ${import_picocolors81.default.cyan("benchmark run")} ${import_picocolors81.default.dim("<benchmark> --yes")} ${import_picocolors81.default.dim("plan and start a benchmark run")}`);
97686
- out.push(` ${import_picocolors81.default.cyan("benchmark results")} ${import_picocolors81.default.dim("<run>")} ${import_picocolors81.default.dim("inspect normalized benchmark results")}`);
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(` ${import_picocolors81.default.cyan("benchmark hydrate")} ${import_picocolors81.default.dim("--spec <path> --result <path> --json")}`);
97691
- out.push(` ${import_picocolors81.default.cyan("benchmark evaluate")} ${import_picocolors81.default.dim("--spec <path> --result <path> --json")}`);
97692
- out.push(` ${import_picocolors81.default.cyan("benchmark capabilities")} ${import_picocolors81.default.dim("--json")}`);
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(` ${import_picocolors81.default.cyan("orchestration init")} ${import_picocolors81.default.dim("write a starter brainbase-orchestration.yaml here (offline, no login)")}`);
97697
- out.push(` ${import_picocolors81.default.cyan("orchestration create")} ${import_picocolors81.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
97698
- out.push(` ${import_picocolors81.default.cyan("orchestration list")} ${import_picocolors81.default.dim("list orchestrations under a team")}`);
97699
- out.push(` ${import_picocolors81.default.cyan("orchestration pull")} ${import_picocolors81.default.dim("<id>")} ${import_picocolors81.default.dim("recursively fetch an orchestration + every member agent")}`);
97700
- out.push(` ${import_picocolors81.default.cyan("orchestration push")} ${import_picocolors81.default.dim("recursively push each member, then update the graph")}`);
97701
- out.push(` ${import_picocolors81.default.cyan("orchestration status")} ${import_picocolors81.default.dim("show what would push and what would pull")}`);
97702
- out.push(` ${import_picocolors81.default.cyan("orchestration delete")} ${import_picocolors81.default.dim("<id>")} ${import_picocolors81.default.dim("permanently delete an orchestration graph (member agents are kept)")}`);
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(` ${import_picocolors81.default.cyan("template pack")} ${import_picocolors81.default.dim("bundle the current agent into a template")}`);
97707
- out.push(` ${import_picocolors81.default.cyan("template publish")} ${import_picocolors81.default.dim("upload a template to the registry")}`);
97708
- out.push(` ${import_picocolors81.default.cyan("template search")} ${import_picocolors81.default.dim("[query]")} ${import_picocolors81.default.dim("search the registry")}`);
97709
- out.push(` ${import_picocolors81.default.cyan("template info")} ${import_picocolors81.default.dim("<creator/slug>")} ${import_picocolors81.default.dim("show registry details for a template")}`);
97710
- out.push(` ${import_picocolors81.default.cyan("template onboard")} ${import_picocolors81.default.dim("<creator/slug>")} ${import_picocolors81.default.dim("install (or refresh) a template")}`);
97711
- out.push(` ${import_picocolors81.default.cyan("template list")} ${import_picocolors81.default.dim("show installed templates")}`);
97712
- out.push(` ${import_picocolors81.default.cyan("template remove")} ${import_picocolors81.default.dim("<creator/slug>")} ${import_picocolors81.default.dim("uninstall a template")}`);
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(` ${import_picocolors81.default.cyan("skill add")} ${import_picocolors81.default.dim("<source>")} ${import_picocolors81.default.dim("install a skill (github / git / brainbase)")}`);
97717
- out.push(` ${import_picocolors81.default.cyan("skill list")} ${import_picocolors81.default.dim("show locally installed skills + their source")}`);
97718
- out.push(` ${import_picocolors81.default.cyan("skill update")} ${import_picocolors81.default.dim("<slug>")} ${import_picocolors81.default.dim("re-fetch a skill from its recorded source")}`);
97719
- out.push(` ${import_picocolors81.default.cyan("skill remove")} ${import_picocolors81.default.dim("<slug>")} ${import_picocolors81.default.dim("uninstall a skill")}`);
97720
- out.push(` ${import_picocolors81.default.cyan("skill search")} ${import_picocolors81.default.dim("[query]")} ${import_picocolors81.default.dim("search the brainbase skill registry")}`);
97721
- out.push(` ${import_picocolors81.default.cyan("skill info")} ${import_picocolors81.default.dim("<creator/slug>")} ${import_picocolors81.default.dim("show registry details for a skill")}`);
97722
- out.push(` ${import_picocolors81.default.cyan("skill publish")} ${import_picocolors81.default.dim("[dir]")} ${import_picocolors81.default.dim("publish a SKILL.md folder (defaults to .)")}`);
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(` ${import_picocolors81.default.cyan("token create")} ${import_picocolors81.default.dim("issue a long-lived CLI key for CI / scripts")}`);
97727
- out.push(` ${import_picocolors81.default.cyan("token list")} ${import_picocolors81.default.dim("show your tokens")}`);
97728
- out.push(` ${import_picocolors81.default.cyan("token rename")} ${import_picocolors81.default.dim("<id>")} ${import_picocolors81.default.dim("relabel a token")}`);
97729
- out.push(` ${import_picocolors81.default.cyan("token revoke")} ${import_picocolors81.default.dim("<id>")} ${import_picocolors81.default.dim("revoke a token")}`);
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(` ${import_picocolors81.default.cyan("mcp check")} ${import_picocolors81.default.dim("[--json]")} ${import_picocolors81.default.dim("verify MCP server connectivity through the brainbase proxy (runs at sandbox bootstrap)")}`);
97734
- out.push(` ${import_picocolors81.default.cyan("mcp list")} ${import_picocolors81.default.dim("[--json]")} ${import_picocolors81.default.dim("show configured servers with OAuth state and expiry")}`);
97735
- out.push(` ${import_picocolors81.default.cyan("mcp connect")} ${import_picocolors81.default.dim("<name>")} ${import_picocolors81.default.dim("authorize an OAuth-backed server: prints a single-use link, opens it, waits for approval")}`);
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(` ${import_picocolors81.default.cyan("integrations list")} ${import_picocolors81.default.dim("show the agent's Pipedream apps, accounts and app-level permission")}`);
97740
- out.push(` ${import_picocolors81.default.cyan("integrations search")} ${import_picocolors81.default.dim("<query>")} ${import_picocolors81.default.dim("find apps in the Pipedream catalog")}`);
97741
- out.push(` ${import_picocolors81.default.cyan("integrations actions")} ${import_picocolors81.default.dim("<app>")} ${import_picocolors81.default.dim("list an app's actions and whether each is allowed")}`);
97742
- out.push(` ${import_picocolors81.default.cyan("integrations add")} ${import_picocolors81.default.dim("<app>")} ${import_picocolors81.default.dim("install an app; one that needs an account runs connect")}`);
97743
- out.push(` ${import_picocolors81.default.cyan("integrations connect")} ${import_picocolors81.default.dim("<app>")} ${import_picocolors81.default.dim("open Pipedream's connect page for the app and wait for the account")}`);
97744
- out.push(` ${import_picocolors81.default.cyan("integrations disconnect")} ${import_picocolors81.default.dim("<app>")} ${import_picocolors81.default.dim("delete the app's connected account")}`);
97745
- out.push(` ${import_picocolors81.default.cyan("integrations remove")} ${import_picocolors81.default.dim("<app>")} ${import_picocolors81.default.dim("uninstall an app that needs no account")}`);
97746
- out.push(` ${import_picocolors81.default.cyan("integrations allow|ask|deny")} ${import_picocolors81.default.dim("<app>[.<action>]")} ${import_picocolors81.default.dim("set the permission for an app or one of its actions")}`);
97747
- out.push(` ${import_picocolors81.default.cyan("integrations context create")} ${import_picocolors81.default.dim("--application <name>")} ${import_picocolors81.default.dim("let a program outside Brainbase (the SDK) use the agent's integrations; prints a renewal handle once")}`);
97748
- out.push(` ${import_picocolors81.default.cyan("integrations context end")} ${import_picocolors81.default.dim("<context-id>")} ${import_picocolors81.default.dim("end a standalone integration context now")}`);
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(` ${import_picocolors81.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
97753
- out.push(` ${import_picocolors81.default.dim("--scope <s>")} force scope: global | project`);
97754
- out.push(` ${import_picocolors81.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
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(` ${import_picocolors81.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)`);
97757
- out.push(` ${import_picocolors81.default.dim("--message <text>")} for task create: required first user message`);
97758
- out.push(` ${import_picocolors81.default.dim("--title <text>")} for task create: optional task title; for task update: the new title`);
97759
- out.push(` ${import_picocolors81.default.dim("--clear-title")} for task update: remove the title (automatic titling may name it again later)`);
97760
- out.push(` ${import_picocolors81.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)`);
97761
- out.push(` ${import_picocolors81.default.dim("--unset-metadata <k>")} for task update: remove one label (repeatable)`);
97762
- out.push(` ${import_picocolors81.default.dim("--clear-metadata")} for task update: remove every label; with --metadata, keep only those given`);
97763
- out.push(` ${import_picocolors81.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)`);
97764
- out.push(` ${import_picocolors81.default.dim("--clear-model")} for task update: go back to the agent's default model from the next turn`);
97765
- out.push(` ${import_picocolors81.default.dim("--version <v>")} for task create: run a saved version of the agent (12, v12 or a version id)`);
97766
- out.push(` ${import_picocolors81.default.dim("--wait")} for task create: block until the task finishes; exit 1 unless it succeeded`);
97767
- out.push(` ${import_picocolors81.default.dim("--timeout <secs>")} for task create --wait: give up after <secs> and exit 1`);
97768
- out.push(` ${import_picocolors81.default.dim("--limit <n>")} for task list (1-200), task logs (events to print; with --follow, the first page size) and machine ls`);
97769
- out.push(` ${import_picocolors81.default.dim("--follow, -f")} for task logs: stay attached and print events as they land`);
97770
- out.push(` ${import_picocolors81.default.dim("--org <id-or-slug>")} pick the organization (team/agent list, agent create, orchestration create/list)`);
97771
- out.push(` ${import_picocolors81.default.dim("--team <id>")} pick the team, same commands (works without --org)`);
97772
- out.push(` ${import_picocolors81.default.dim("--all-teams")} for agent list: every team in the org (the default with no terminal)`);
97773
- out.push(` ${import_picocolors81.default.dim("--json")} machine-readable output for supported commands`);
97774
- out.push(` ${import_picocolors81.default.dim("--no-tracking")} for link / agent pull --link: skip routing LLM traffic through brainbase`);
97775
- out.push(` ${import_picocolors81.default.dim("--link")} for agent pull: link this folder to the agent first, as \`brainbase link --agent <id> --yes\` would, in one process`);
97776
- out.push(` ${import_picocolors81.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
97777
- out.push(` ${import_picocolors81.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
97778
- out.push(` ${import_picocolors81.default.dim("--bot-token <t>")} for agent connect slack (or BRAINBASE_SLACK_BOT_TOKEN, or stdin)`);
97779
- out.push(` ${import_picocolors81.default.dim("--signing-secret <s>")} for agent connect slack (or BRAINBASE_SLACK_SIGNING_SECRET, or stdin)`);
97780
- out.push(` ${import_picocolors81.default.dim("--bot-name <name>")} for agent connect meeting: the bot's display name`);
97781
- out.push(` ${import_picocolors81.default.dim("--app-id <id> / --app-name <name>")} optional Slack app identity`);
97782
- out.push(` ${import_picocolors81.default.dim("--bot-image-url <url>")} optional meeting bot image`);
97783
- out.push(` ${import_picocolors81.default.dim("--full")} for agent/orchestration init: write a commented template covering every block`);
97784
- out.push(` ${import_picocolors81.default.dim("--minimal")} for agent init: write the starter manifest (the default)`);
97785
- out.push(` ${import_picocolors81.default.dim("--all")} for template list: include installs from other folders; for machine ls: include torn-down machines`);
97786
- out.push(` ${import_picocolors81.default.dim("--web <url>")} for login: web app URL (default https://app.brainbaselabs.com)`);
97787
- out.push(` ${import_picocolors81.default.dim("--no-open")} for mcp/integrations connect: print the link without opening a browser (implied with no terminal)`);
97788
- out.push(` ${import_picocolors81.default.dim("--no-wait")} for mcp/integrations connect: print the link and exit instead of waiting`);
97789
- out.push(` ${import_picocolors81.default.dim("--account <id>")} for integrations disconnect: which account, when the app has more than one`);
97790
- out.push(` ${import_picocolors81.default.dim("--application <name>")} for integrations context create: names the program the context is for`);
97791
- out.push(` ${import_picocolors81.default.dim("--max-lifetime <dur>")} for integrations context create: when the context ends at the latest, 60s-30d (default 7d)`);
97792
- out.push(` ${import_picocolors81.default.dim("--reason <text>")} for integrations context end: recorded with the context`);
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(` ${import_picocolors81.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
97797
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_DEBUG")} print full stack traces on error (any value; unset to disable)`);
97798
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login, console links and integrations`);
97799
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_CONTROL_PLANE_URL")} override the MAS host (/v2/cli; task and interface commands use /v2/tasks and /v2/interfaces)`);
97800
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_API_URL")} legacy KLS host override (uses /api/cli; proxy/registry fallback)`);
97801
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_PROXY_URL")} override the model-proxy URL used by harness traffic (default https://api.v1.brainbaselabs.com)`);
97802
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL (default https://api.v1.brainbaselabs.com)`);
97803
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT; outranks the login session and the PAT saved in token.json`);
97804
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
97805
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
97806
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 → agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
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(` ${import_picocolors81.default.dim("BRAINBASE_MEMORY_MCP_URL")} override the built-in memory MCP host`);
97809
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_BROWSER_MCP_URL")} override the built-in browser MCP host`);
97810
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_SLACK_MCP_URL")} override the built-in Slack MCP host`);
97811
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_MEETING_MCP_URL")} override the built-in meeting MCP host`);
97812
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_GITHUB_MCP_URL")} override the built-in GitHub MCP host`);
97813
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_LINEAR_MCP_URL")} override the built-in Linear MCP host`);
97814
- out.push(` ${import_picocolors81.default.dim("BRAINBASE_ORCHESTRATION_MCP_URL")} override the built-in orchestration MCP host`);
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(` ${import_picocolors81.default.dim("•")} ${import_picocolors81.default.bold("claude-code")} ${import_picocolors81.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
97819
- out.push(` ${import_picocolors81.default.dim("•")} ${import_picocolors81.default.bold("codex")} ${import_picocolors81.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
97820
- out.push(` ${import_picocolors81.default.dim("•")} ${import_picocolors81.default.bold("kafka")} ${import_picocolors81.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
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("◆")} ${import_picocolors81.default.bold("brainbase")}`);
99753
+ console.error(` ${brandTint("◆")} ${import_picocolors84.default.bold("brainbase")}`);
97979
99754
  console.error("");
97980
- console.error(` ${import_picocolors81.default.red("✗")} You need to sign in to use ${import_picocolors81.default.bold("brainbase " + cmd)}.`);
97981
- console.error(` ${import_picocolors81.default.dim(noUsableCredentialMessage())}`);
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 fs94.realpathSync(rawCwd);
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(import_picocolors81.default.red(`
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 ${import_picocolors81.default.cyan("brainbase login")} to connect this device.`);
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);