@brainbase-labs/cli 0.16.5 → 0.17.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 (3) hide show
  1. package/README.md +9 -5
  2. package/dist/index.js +606 -156
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -18,6 +18,8 @@ brainbase template pack # bundle the current agent into a template
18
18
  brainbase template publish # upload to the registry
19
19
  brainbase template search # find templates published by your team
20
20
  brainbase template onboard <creator/slug> # install or refresh a template
21
+ brainbase agent create # claim a local brainbase.agent.yaml
22
+ brainbase task create --message "Review this project and propose next steps"
21
23
  ```
22
24
 
23
25
  Run `brainbase help` to see every command.
@@ -74,7 +76,7 @@ Playbook files carry a small YAML frontmatter (`title`, `description`) — the C
74
76
 
75
77
  | Variable | Purpose |
76
78
  |-|-|
77
- | `BRAINBASE_CONTROL_PLANE_URL` | Override the MAS control-plane host. Requests use `/v2/cli`; the default is `https://api.brainbaselabs.com`. |
79
+ | `BRAINBASE_CONTROL_PLANE_URL` | Override the MAS host. Agent/orchestration requests use `/v2/cli`; `task create` uses `/v2/tasks`. The default is `https://api.brainbaselabs.com`. |
78
80
  | `BRAINBASE_API_URL` | Legacy KLS host override. Control requests use `/api/cli`; it is also the fallback for model-proxy and registry traffic. |
79
81
  | `BRAINBASE_PROXY_URL` | Override the model-proxy host used when enabling harness tracking. |
80
82
  | `BRAINBASE_REGISTRY_URL` | Override the registry API host. |
@@ -86,12 +88,14 @@ the server captured at login, and finally `https://api.v1.brainbaselabs.com`.
86
88
 
87
89
  ## Auth
88
90
 
89
- Two ways to authenticate, in priority order:
91
+ Managed task creation uses this authentication precedence:
90
92
 
91
- 1. `brainbase login` — interactive Supabase OAuth, stored in `~/.brainbase/auth.json`. Carries full scopes.
92
- 2. `brainbase token create --scope publish` — long-lived PAT (`bbpat_…`) for CI / unattended use.
93
+ 1. `BRAINBASE_TOKEN` — an explicit PAT from the environment.
94
+ 2. `brainbase login` — a Supabase session stored in `~/.brainbase/auth.json`.
95
+ 3. `brainbase token create --scopes read,publish` — a PAT stored in `~/.brainbase/token.json` when no login session is configured.
93
96
 
94
- `BRAINBASE_TOKEN` env var overrides both.
97
+ An explicit PAT does not inherit routing from a stored login. Set
98
+ `BRAINBASE_CONTROL_PLANE_URL` when using a PAT against a non-default MAS host.
95
99
 
96
100
  ## License
97
101
 
package/dist/index.js CHANGED
@@ -35141,7 +35141,7 @@ var require_dist2 = __commonJS((exports, module) => {
35141
35141
  });
35142
35142
 
35143
35143
  // src/index.ts
35144
- var import_picocolors43 = __toESM(require_picocolors(), 1);
35144
+ var import_picocolors44 = __toESM(require_picocolors(), 1);
35145
35145
  import process14 from "node:process";
35146
35146
  import fs79 from "node:fs";
35147
35147
 
@@ -36008,7 +36008,7 @@ function padStart(s, n) {
36008
36008
  // package.json
36009
36009
  var package_default = {
36010
36010
  name: "@brainbase-labs/cli",
36011
- version: "0.16.5",
36011
+ version: "0.17.0",
36012
36012
  description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
36013
36013
  type: "module",
36014
36014
  bin: {
@@ -53841,9 +53841,80 @@ function apiErrorMessage(body, status) {
53841
53841
  return `HTTP ${status}`;
53842
53842
  }
53843
53843
 
53844
+ // src/core/token.ts
53845
+ import path57 from "node:path";
53846
+ import fs47 from "node:fs";
53847
+ var TOKEN_FILE = path57.join(BRAINBASE_HOME, "token.json");
53848
+ var TOKEN_PREFIX = "bbpat_";
53849
+ var TOKEN_PREFIX_LEN = 14;
53850
+ function tokenPrefix(token) {
53851
+ if (!token.startsWith(TOKEN_PREFIX)) {
53852
+ throw new Error(`not a brainbase PAT: missing ${TOKEN_PREFIX} prefix`);
53853
+ }
53854
+ return token.slice(0, TOKEN_PREFIX_LEN);
53855
+ }
53856
+ function isValidTokenFormat(token) {
53857
+ if (typeof token !== "string")
53858
+ return false;
53859
+ if (!token.startsWith(TOKEN_PREFIX))
53860
+ return false;
53861
+ return /^bbpat_[A-Za-z0-9]{20,}$/.test(token);
53862
+ }
53863
+ var StoredTokenSchema = exports_external.object({
53864
+ schemaVersion: exports_external.literal(1),
53865
+ token: exports_external.string(),
53866
+ prefix: exports_external.string(),
53867
+ name: exports_external.string().optional(),
53868
+ createdAt: exports_external.string()
53869
+ });
53870
+ function readToken() {
53871
+ if (!exists(TOKEN_FILE))
53872
+ return null;
53873
+ try {
53874
+ return StoredTokenSchema.parse(readJson(TOKEN_FILE));
53875
+ } catch {
53876
+ return null;
53877
+ }
53878
+ }
53879
+ function writeToken(token, name) {
53880
+ if (!isValidTokenFormat(token)) {
53881
+ throw new Error("refusing to store token: invalid format");
53882
+ }
53883
+ ensureDir(BRAINBASE_HOME);
53884
+ const stored = {
53885
+ schemaVersion: 1,
53886
+ token,
53887
+ prefix: tokenPrefix(token),
53888
+ name,
53889
+ createdAt: new Date().toISOString()
53890
+ };
53891
+ writeJson(TOKEN_FILE, stored);
53892
+ try {
53893
+ fs47.chmodSync(TOKEN_FILE, 384);
53894
+ } catch {}
53895
+ return stored;
53896
+ }
53897
+ function clearToken() {
53898
+ if (exists(TOKEN_FILE))
53899
+ fs47.rmSync(TOKEN_FILE);
53900
+ }
53901
+
53844
53902
  // src/core/api.ts
53845
53903
  var DEFAULT_CONTROL_PLANE_BASE = "https://api.brainbaselabs.com";
53846
53904
  var DEFAULT_PROXY_BASE = "https://api.v1.brainbaselabs.com";
53905
+ var MAS_IN_PROGRESS_MAX_WAIT_MS = 15000;
53906
+ var MAS_REQUEST_TIMEOUT_MS = 30000;
53907
+ var MAS_MIN_RETRY_DELAY_MS = 100;
53908
+ var MAS_MAX_RETRY_DELAY_MS = 2000;
53909
+ var DEFINITELY_UNSENT_NETWORK_CODES = new Set([
53910
+ "ConnectionRefused",
53911
+ "ECONNREFUSED",
53912
+ "ENOTFOUND",
53913
+ "EAI_AGAIN",
53914
+ "ERR_INVALID_URL",
53915
+ "FailedToOpenSocket",
53916
+ "UND_ERR_CONNECT_TIMEOUT"
53917
+ ]);
53847
53918
 
53848
53919
  class ApiError extends Error {
53849
53920
  status;
@@ -53855,6 +53926,17 @@ class ApiError extends Error {
53855
53926
  this.name = "ApiError";
53856
53927
  }
53857
53928
  }
53929
+
53930
+ class NetworkApiError extends ApiError {
53931
+ definitelyUnsent;
53932
+ constructor(message, definitelyUnsent) {
53933
+ super(message);
53934
+ this.definitelyUnsent = definitelyUnsent;
53935
+ }
53936
+ }
53937
+
53938
+ class TaskRecoveryDeadlineError extends ApiError {
53939
+ }
53858
53940
  function normalizeControlPlaneUrl(url) {
53859
53941
  const normalized = url?.trim().replace(/\/+$/, "");
53860
53942
  return normalized || DEFAULT_CONTROL_PLANE_BASE;
@@ -53870,10 +53952,17 @@ function controlPlaneBaseUrl(session) {
53870
53952
  }
53871
53953
  return normalizeControlPlaneUrl(session?.control_plane_url);
53872
53954
  }
53955
+ function masControlPlaneBaseUrl(session) {
53956
+ const controlPlane = process.env.BRAINBASE_CONTROL_PLANE_URL?.trim();
53957
+ return normalizeControlPlaneUrl(controlPlane || session?.control_plane_url);
53958
+ }
53873
53959
  function apiBase(session) {
53874
53960
  const suffix = usesLegacyControlPlane() ? "/api/cli" : "/v2/cli";
53875
53961
  return `${controlPlaneBaseUrl(session)}${suffix}`;
53876
53962
  }
53963
+ function masApiBase(session) {
53964
+ return `${masControlPlaneBaseUrl(session)}/v2`;
53965
+ }
53877
53966
  function usesLegacyControlPlane() {
53878
53967
  return !process.env.BRAINBASE_CONTROL_PLANE_URL?.trim() && !!process.env.BRAINBASE_API_URL?.trim();
53879
53968
  }
@@ -53903,6 +53992,53 @@ async function resolveCredential() {
53903
53992
  const status = authStatus();
53904
53993
  throw new ApiError(status.ok ? "CLI authentication changed while this command was starting; retry it" : status.reason ?? "not logged in", 401);
53905
53994
  }
53995
+ async function resolveMasCredential() {
53996
+ const configuredSession = readAuth();
53997
+ try {
53998
+ return await resolveCredential();
53999
+ } catch (error) {
54000
+ if (!(error instanceof ApiError && error.status === 401)) {
54001
+ throw error;
54002
+ }
54003
+ if (configuredSession || readAuth()) {
54004
+ if (readToken()) {
54005
+ throw new ApiError(`${error.message}. A stored PAT is available but will not be used while a login session is configured. Run \`brainbase logout\` to use the stored PAT, or \`brainbase login\` to refresh the session.`, 401);
54006
+ }
54007
+ throw error;
54008
+ }
54009
+ }
54010
+ const storedToken = readToken();
54011
+ if (storedToken) {
54012
+ return {
54013
+ bearer: storedToken.token,
54014
+ session: null,
54015
+ source: "stored_pat"
54016
+ };
54017
+ }
54018
+ const status = authStatus();
54019
+ throw new ApiError(status.ok ? "CLI authentication changed while this command was starting; retry it" : status.reason ?? "not logged in", 401);
54020
+ }
54021
+ function networkErrorCode(error) {
54022
+ if (!error || typeof error !== "object")
54023
+ return;
54024
+ const code = error.code;
54025
+ if (typeof code === "string")
54026
+ return code;
54027
+ const cause = error.cause;
54028
+ if (!cause || typeof cause !== "object")
54029
+ return;
54030
+ const causeCode = cause.code;
54031
+ return typeof causeCode === "string" ? causeCode : undefined;
54032
+ }
54033
+ function isDefinitelyUnsentNetworkError(error) {
54034
+ const code = networkErrorCode(error);
54035
+ if (DEFINITELY_UNSENT_NETWORK_CODES.has(code ?? ""))
54036
+ return true;
54037
+ if (!error || typeof error !== "object")
54038
+ return false;
54039
+ const cause = error.cause;
54040
+ return !!cause && typeof cause === "object" && cause.message === "bad port";
54041
+ }
53906
54042
  async function sendRequest(url, init, bearer) {
53907
54043
  const headers = new Headers(init.headers);
53908
54044
  if (!headers.has("Authorization")) {
@@ -53916,7 +54052,7 @@ async function sendRequest(url, init, bearer) {
53916
54052
  try {
53917
54053
  return await fetch(url, { ...init, headers });
53918
54054
  } catch (err) {
53919
- throw new ApiError(`Network error: ${err.message}`);
54055
+ throw new NetworkApiError(`Network error: ${err.message}`, isDefinitelyUnsentNetworkError(err));
53920
54056
  }
53921
54057
  }
53922
54058
  async function sendWithAuthRetry(session, send) {
@@ -53945,6 +54081,160 @@ async function request(pathname, init = {}) {
53945
54081
  }
53946
54082
  return body;
53947
54083
  }
54084
+ function masApiErrorMessage(body, status) {
54085
+ if (body && typeof body === "object") {
54086
+ const obj = body;
54087
+ if (typeof obj.error === "string" && obj.error.trim() && typeof obj.message === "string" && obj.message.trim()) {
54088
+ const error = obj.error.trim();
54089
+ const message = obj.message.trim();
54090
+ return error === message ? message : `${error}: ${message}`;
54091
+ }
54092
+ for (const key2 of ["detail", "error", "message"]) {
54093
+ const value = obj[key2];
54094
+ if (!value || typeof value !== "object" || Array.isArray(value))
54095
+ continue;
54096
+ const nested = value;
54097
+ for (const nestedKey of ["message", "detail", "error"]) {
54098
+ const message = nested[nestedKey];
54099
+ if (typeof message === "string" && message.trim()) {
54100
+ return message.trim();
54101
+ }
54102
+ }
54103
+ }
54104
+ }
54105
+ return apiErrorMessage(body, status);
54106
+ }
54107
+ function masRetryDelayMs(retryAfterHeader, fallbackMs) {
54108
+ const normalized = retryAfterHeader?.trim();
54109
+ if (!normalized)
54110
+ return fallbackMs;
54111
+ const retryAfterSeconds = Number(normalized);
54112
+ if (!Number.isFinite(retryAfterSeconds) || retryAfterSeconds < 0) {
54113
+ return fallbackMs;
54114
+ }
54115
+ return Math.min(MAS_MAX_RETRY_DELAY_MS, Math.max(MAS_MIN_RETRY_DELAY_MS, retryAfterSeconds * 1000));
54116
+ }
54117
+ function parseMasTaskCreateResponse(body) {
54118
+ if (!body || typeof body !== "object") {
54119
+ throw new ApiError("Task creation may have succeeded, but MAS returned an invalid response. Check your tasks before running this command again.", undefined, body);
54120
+ }
54121
+ const task = body;
54122
+ if (typeof task.id !== "string" || !task.id.trim() || typeof task.agent_id !== "string" || !task.agent_id.trim() || typeof task.status !== "string" || !task.status.trim()) {
54123
+ throw new ApiError("Task creation may have succeeded, but MAS returned an invalid response. Check your tasks before running this command again.", undefined, body);
54124
+ }
54125
+ return {
54126
+ id: task.id,
54127
+ agent_id: task.agent_id,
54128
+ status: task.status
54129
+ };
54130
+ }
54131
+ async function masRequest(pathname, init) {
54132
+ const credential = await resolveMasCredential();
54133
+ let currentSession = credential.session;
54134
+ let ambiguousNetworkRetriesRemaining = 1;
54135
+ let requestMayHaveSucceeded = false;
54136
+ let transientHttpRetriesRemaining = 1;
54137
+ let recoveryDeadline = null;
54138
+ let recoveryTaskId = null;
54139
+ const recoveryRequestTimeoutMs = () => {
54140
+ if (recoveryDeadline === null)
54141
+ return MAS_REQUEST_TIMEOUT_MS;
54142
+ const remainingMs = recoveryDeadline - Date.now();
54143
+ if (remainingMs <= 0) {
54144
+ throw new TaskRecoveryDeadlineError(recoveryTaskId ? `Task ${recoveryTaskId} is still being processed. Check its status before starting another task.` : "Task creation may still be processing. Check your tasks before running this command again.");
54145
+ }
54146
+ return Math.min(MAS_REQUEST_TIMEOUT_MS, remainingMs);
54147
+ };
54148
+ while (true) {
54149
+ const retrySession = credential.source === "session" ? currentSession : null;
54150
+ let res;
54151
+ try {
54152
+ res = await sendWithAuthRetry(retrySession, async (refreshed) => {
54153
+ if (refreshed)
54154
+ currentSession = refreshed;
54155
+ while (true) {
54156
+ const signal = AbortSignal.timeout(recoveryRequestTimeoutMs());
54157
+ try {
54158
+ return await sendRequest(`${masApiBase(currentSession)}${pathname}`, {
54159
+ ...init,
54160
+ signal
54161
+ }, currentSession?.access_token ?? credential.bearer);
54162
+ } catch (error) {
54163
+ if (error instanceof NetworkApiError && error.definitelyUnsent) {
54164
+ throw error;
54165
+ }
54166
+ if (ambiguousNetworkRetriesRemaining === 0)
54167
+ throw error;
54168
+ requestMayHaveSucceeded = true;
54169
+ ambiguousNetworkRetriesRemaining -= 1;
54170
+ }
54171
+ }
54172
+ });
54173
+ } catch (error) {
54174
+ if (error instanceof TaskRecoveryDeadlineError)
54175
+ throw error;
54176
+ if (recoveryTaskId || recoveryDeadline !== null || requestMayHaveSucceeded) {
54177
+ throw new ApiError(recoveryTaskId ? `Task ${recoveryTaskId} may still be processing. Check its status before starting another task. ${error.message}` : `Task creation may still be processing. Check your tasks before running this command again. ${error.message}`);
54178
+ }
54179
+ throw error;
54180
+ }
54181
+ let text2;
54182
+ try {
54183
+ text2 = await res.text();
54184
+ } catch (error) {
54185
+ if (ambiguousNetworkRetriesRemaining > 0) {
54186
+ requestMayHaveSucceeded = true;
54187
+ ambiguousNetworkRetriesRemaining -= 1;
54188
+ continue;
54189
+ }
54190
+ throw new ApiError(recoveryTaskId ? `Task ${recoveryTaskId} may still be processing. Check its status before starting another task. ${error.message}` : recoveryDeadline !== null || requestMayHaveSucceeded ? `Task creation may still be processing. Check your tasks before running this command again. ${error.message}` : `Network error while reading response: ${error.message}`);
54191
+ }
54192
+ let body = text2;
54193
+ try {
54194
+ body = text2 ? JSON.parse(text2) : null;
54195
+ } catch {}
54196
+ const detail = body && typeof body === "object" ? body.detail : null;
54197
+ const detailObject = detail && typeof detail === "object" ? detail : null;
54198
+ const code = detailObject?.code;
54199
+ if (res.status === 409 && code === "idempotency_request_in_progress") {
54200
+ if (typeof detailObject?.task_id === "string") {
54201
+ recoveryTaskId = detailObject.task_id;
54202
+ }
54203
+ recoveryDeadline ??= Date.now() + MAS_IN_PROGRESS_MAX_WAIT_MS;
54204
+ const delayMs = masRetryDelayMs(res.headers.get("Retry-After"), 1000);
54205
+ if (Date.now() + delayMs >= recoveryDeadline) {
54206
+ throw new ApiError(recoveryTaskId ? `Task ${recoveryTaskId} is still being processed. Check its status before starting another task.` : masApiErrorMessage(body, res.status), res.status, body);
54207
+ }
54208
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
54209
+ continue;
54210
+ }
54211
+ if (res.status >= 500 && transientHttpRetriesRemaining > 0) {
54212
+ transientHttpRetriesRemaining -= 1;
54213
+ requestMayHaveSucceeded = true;
54214
+ const delayMs = masRetryDelayMs(res.headers.get("Retry-After"), 250);
54215
+ if (recoveryDeadline !== null && Date.now() + delayMs >= recoveryDeadline) {
54216
+ throw new TaskRecoveryDeadlineError(recoveryTaskId ? `Task ${recoveryTaskId} is still being processed. Check its status before starting another task.` : "Task creation may still be processing. Check your tasks before running this command again.");
54217
+ }
54218
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
54219
+ continue;
54220
+ }
54221
+ if (!res.ok) {
54222
+ const message = masApiErrorMessage(body, res.status);
54223
+ throw new ApiError(res.status >= 500 ? `${message} Task creation may still be processing; check your tasks before running this command again.` : message, res.status, body);
54224
+ }
54225
+ return body;
54226
+ }
54227
+ }
54228
+ var masApi = {
54229
+ async createTask(input, options) {
54230
+ const body = await masRequest("/tasks", {
54231
+ method: "POST",
54232
+ headers: { "Idempotency-Key": options.idempotencyKey },
54233
+ body: JSON.stringify(input)
54234
+ });
54235
+ return parseMasTaskCreateResponse(body);
54236
+ }
54237
+ };
53948
54238
  var api = {
53949
54239
  listOrgs() {
53950
54240
  return request("/orgs");
@@ -54059,64 +54349,6 @@ function proxyBaseUrl(session) {
54059
54349
  return DEFAULT_PROXY_BASE.replace(/\/+$/, "");
54060
54350
  }
54061
54351
 
54062
- // src/core/token.ts
54063
- import path57 from "node:path";
54064
- import fs47 from "node:fs";
54065
- var TOKEN_FILE = path57.join(BRAINBASE_HOME, "token.json");
54066
- var TOKEN_PREFIX = "bbpat_";
54067
- var TOKEN_PREFIX_LEN = 14;
54068
- function tokenPrefix(token) {
54069
- if (!token.startsWith(TOKEN_PREFIX)) {
54070
- throw new Error(`not a brainbase PAT: missing ${TOKEN_PREFIX} prefix`);
54071
- }
54072
- return token.slice(0, TOKEN_PREFIX_LEN);
54073
- }
54074
- function isValidTokenFormat(token) {
54075
- if (typeof token !== "string")
54076
- return false;
54077
- if (!token.startsWith(TOKEN_PREFIX))
54078
- return false;
54079
- return /^bbpat_[A-Za-z0-9]{20,}$/.test(token);
54080
- }
54081
- var StoredTokenSchema = exports_external.object({
54082
- schemaVersion: exports_external.literal(1),
54083
- token: exports_external.string(),
54084
- prefix: exports_external.string(),
54085
- name: exports_external.string().optional(),
54086
- createdAt: exports_external.string()
54087
- });
54088
- function readToken() {
54089
- if (!exists(TOKEN_FILE))
54090
- return null;
54091
- try {
54092
- return StoredTokenSchema.parse(readJson(TOKEN_FILE));
54093
- } catch {
54094
- return null;
54095
- }
54096
- }
54097
- function writeToken(token, name) {
54098
- if (!isValidTokenFormat(token)) {
54099
- throw new Error("refusing to store token: invalid format");
54100
- }
54101
- ensureDir(BRAINBASE_HOME);
54102
- const stored = {
54103
- schemaVersion: 1,
54104
- token,
54105
- prefix: tokenPrefix(token),
54106
- name,
54107
- createdAt: new Date().toISOString()
54108
- };
54109
- writeJson(TOKEN_FILE, stored);
54110
- try {
54111
- fs47.chmodSync(TOKEN_FILE, 384);
54112
- } catch {}
54113
- return stored;
54114
- }
54115
- function clearToken() {
54116
- if (exists(TOKEN_FILE))
54117
- fs47.rmSync(TOKEN_FILE);
54118
- }
54119
-
54120
54352
  // src/core/registry-client.ts
54121
54353
  var DEFAULT_BASE = "https://api.v1.brainbaselabs.com";
54122
54354
  function baseUrl(session) {
@@ -76345,6 +76577,210 @@ async function runMcp(cwd2, sub, _argv, options) {
76345
76577
  }
76346
76578
  }
76347
76579
 
76580
+ // src/cli/task.ts
76581
+ var import_picocolors43 = __toESM(require_picocolors(), 1);
76582
+
76583
+ // src/cli/task-create.ts
76584
+ import { randomUUID as randomUUID2 } from "node:crypto";
76585
+ async function createTask(input, options) {
76586
+ return await masApi.createTask(input, options);
76587
+ }
76588
+ function requiredValue(value, flag) {
76589
+ const normalized = value?.trim();
76590
+ if (!normalized) {
76591
+ throw new Error(`${flag} is required and must not be blank.`);
76592
+ }
76593
+ return normalized;
76594
+ }
76595
+ function optionalValue(value, flag) {
76596
+ if (value === undefined)
76597
+ return;
76598
+ const normalized = value.trim();
76599
+ if (!normalized) {
76600
+ throw new Error(`${flag} must not be blank when provided.`);
76601
+ }
76602
+ return normalized;
76603
+ }
76604
+ function resolveAgentId(cwd2, agentId, readLocalManifest) {
76605
+ if (agentId !== undefined) {
76606
+ return requiredValue(agentId, "--agent");
76607
+ }
76608
+ const manifest = readLocalManifest(cwd2);
76609
+ if (!manifest?.id) {
76610
+ throw new Error("No claimed agent found in brainbase.agent.yaml. Run `brainbase agent create` first, or pass --agent <id>.");
76611
+ }
76612
+ return manifest.id;
76613
+ }
76614
+ function isPublishScopeError(error2) {
76615
+ const message = error2 instanceof Error ? error2.message : String(error2);
76616
+ const body = error2 && typeof error2 === "object" && "body" in error2 ? JSON.stringify(error2.body) : "";
76617
+ return /PAT lacks required scope:\s*publish/i.test(`${message} ${body}`);
76618
+ }
76619
+ async function runTaskCreate(cwd2, options, dependencies = {}) {
76620
+ const idempotencyKey = (dependencies.randomUUID ?? randomUUID2)();
76621
+ const message = requiredValue(options.message, "--message");
76622
+ const agentId = resolveAgentId(cwd2, options.agentId, dependencies.readManifest ?? readManifest);
76623
+ const title = optionalValue(options.title, "--title");
76624
+ const model = optionalValue(options.model, "--model");
76625
+ const input = {
76626
+ agent_id: agentId,
76627
+ initial_messages: [{ role: "user", content: message }],
76628
+ auto_run: true,
76629
+ ...title ? { title } : {},
76630
+ ...model ? { default_model: model } : {}
76631
+ };
76632
+ let created;
76633
+ try {
76634
+ created = await (dependencies.createTask ?? createTask)(input, {
76635
+ idempotencyKey
76636
+ });
76637
+ } catch (error2) {
76638
+ if (isPublishScopeError(error2)) {
76639
+ throw new Error("PAT lacks required scope: publish. Mint a replacement with `brainbase token create --scopes read,publish` and try again.");
76640
+ }
76641
+ throw error2;
76642
+ }
76643
+ if (options.json) {
76644
+ console.log(JSON.stringify({
76645
+ task_id: created.id,
76646
+ agent_id: created.agent_id,
76647
+ status: created.status
76648
+ }));
76649
+ return;
76650
+ }
76651
+ console.log([
76652
+ `Task ID: ${created.id}`,
76653
+ `Agent ID: ${created.agent_id}`,
76654
+ `Status: ${created.status}`,
76655
+ "First run accepted."
76656
+ ].join(`
76657
+ `));
76658
+ }
76659
+
76660
+ // src/cli/task.ts
76661
+ var VALUE_FLAGS = [
76662
+ ["--agent", "agentId"],
76663
+ ["--message", "message"],
76664
+ ["--title", "title"],
76665
+ ["--model", "model"]
76666
+ ];
76667
+ var TASK_OPTION_NAMES = new Set([
76668
+ ...VALUE_FLAGS.map(([flag]) => flag),
76669
+ "--json"
76670
+ ]);
76671
+ var HELP_FLAGS = new Set(["--help", "-h"]);
76672
+ function missingValueError(flag) {
76673
+ if (flag === "--message" || flag === "--agent") {
76674
+ return new Error(`${flag} is required and must not be blank.`);
76675
+ }
76676
+ return new Error(`${flag} must not be blank when provided.`);
76677
+ }
76678
+ function flagLikeValueError(flag, value) {
76679
+ return new Error(`${flag} requires a value. If you meant the literal "${value}", use ${flag}=${value} or ${flag} -- ${value}.`);
76680
+ }
76681
+ function parseCreateArgs(args) {
76682
+ const options = {};
76683
+ const seen = new Set;
76684
+ for (let index = 0;index < args.length; index += 1) {
76685
+ const arg = args[index];
76686
+ if (HELP_FLAGS.has(arg)) {
76687
+ return { help: true, options };
76688
+ }
76689
+ if (arg === "--json") {
76690
+ if (seen.has(arg)) {
76691
+ throw new Error(`Duplicate task create option: ${arg}`);
76692
+ }
76693
+ seen.add(arg);
76694
+ options.json = true;
76695
+ continue;
76696
+ }
76697
+ let matched = false;
76698
+ for (const [flag, option] of VALUE_FLAGS) {
76699
+ if (arg === flag) {
76700
+ if (seen.has(flag)) {
76701
+ throw new Error(`Duplicate task create option: ${flag}`);
76702
+ }
76703
+ seen.add(flag);
76704
+ let value = args[index + 1];
76705
+ if (value === undefined) {
76706
+ throw missingValueError(flag);
76707
+ }
76708
+ if (value === "--") {
76709
+ value = args[index + 2];
76710
+ if (value === undefined)
76711
+ throw missingValueError(flag);
76712
+ index += 1;
76713
+ } else if (HELP_FLAGS.has(value) && (option === "agentId" || option === "model")) {
76714
+ return { help: true, options };
76715
+ } else if (TASK_OPTION_NAMES.has(value)) {
76716
+ throw flagLikeValueError(flag, value);
76717
+ }
76718
+ options[option] = value;
76719
+ index += 1;
76720
+ matched = true;
76721
+ break;
76722
+ }
76723
+ const prefix = `${flag}=`;
76724
+ if (arg.startsWith(prefix)) {
76725
+ if (seen.has(flag)) {
76726
+ throw new Error(`Duplicate task create option: ${flag}`);
76727
+ }
76728
+ seen.add(flag);
76729
+ options[option] = arg.slice(prefix.length);
76730
+ matched = true;
76731
+ break;
76732
+ }
76733
+ }
76734
+ if (!matched) {
76735
+ throw new Error(`Unknown task create argument: ${arg}`);
76736
+ }
76737
+ }
76738
+ return { help: false, options };
76739
+ }
76740
+ async function runTask(cwd2, sub, args) {
76741
+ switch (sub) {
76742
+ case "create": {
76743
+ const parsed = parseCreateArgs(args);
76744
+ if (parsed.help) {
76745
+ printHelp3();
76746
+ return;
76747
+ }
76748
+ await runTaskCreate(cwd2, parsed.options);
76749
+ return;
76750
+ }
76751
+ case undefined:
76752
+ case "help":
76753
+ case "-h":
76754
+ case "--help":
76755
+ printHelp3();
76756
+ return;
76757
+ default:
76758
+ console.error(`Unknown task subcommand: ${sub}
76759
+ `);
76760
+ printHelp3();
76761
+ process.exit(1);
76762
+ }
76763
+ }
76764
+ function printHelp3() {
76765
+ const out = [];
76766
+ out.push("");
76767
+ out.push(` ${import_picocolors43.default.bold("brainbase task")} ${import_picocolors43.default.dim("<sub> [options]")}`);
76768
+ out.push("");
76769
+ out.push(` ${import_picocolors43.default.cyan("create")} ${import_picocolors43.default.dim("--message <text>")} ${import_picocolors43.default.dim("create a task and start its first run")}`);
76770
+ out.push("");
76771
+ out.push(` ${import_picocolors43.default.bold("create flags")}`);
76772
+ out.push(` ${import_picocolors43.default.dim("--message <text>")} required first user message`);
76773
+ out.push(` ${import_picocolors43.default.dim("--agent <id>")} override the claimed agent in brainbase.agent.yaml`);
76774
+ out.push(` ${import_picocolors43.default.dim("--title <text>")} optional task title`);
76775
+ out.push(` ${import_picocolors43.default.dim("--model <id>")} optional model override`);
76776
+ out.push(` ${import_picocolors43.default.dim("--json")} print task_id, agent_id, and status as JSON`);
76777
+ out.push("");
76778
+ out.push(` ${import_picocolors43.default.dim("Flag-like values:")} use ${import_picocolors43.default.cyan("--flag=value")} or ${import_picocolors43.default.cyan("--flag -- <value>")}`);
76779
+ out.push("");
76780
+ console.log(out.join(`
76781
+ `));
76782
+ }
76783
+
76348
76784
  // src/index.ts
76349
76785
  var PROTECTED = new Set([
76350
76786
  "template",
@@ -76365,100 +76801,108 @@ var STORED_PAT_COMMANDS = new Set([
76365
76801
  function help() {
76366
76802
  const out = [];
76367
76803
  out.push("");
76368
- out.push(` ${brandTint("◆")} ${import_picocolors43.default.bold("brainbase")} ${import_picocolors43.default.dim(`v${VERSION}`)}`);
76369
- out.push(` ${import_picocolors43.default.dim("connect your local agent to the brainbase platform")}`);
76804
+ out.push(` ${brandTint("◆")} ${import_picocolors44.default.bold("brainbase")} ${import_picocolors44.default.dim(`v${VERSION}`)}`);
76805
+ out.push(` ${import_picocolors44.default.dim("connect your local agent to the brainbase platform")}`);
76370
76806
  out.push("");
76371
76807
  out.push(divider("USAGE"));
76372
76808
  out.push("");
76373
- out.push(` ${import_picocolors43.default.bold("brainbase")} ${import_picocolors43.default.dim("<command> [options]")}`);
76809
+ out.push(` ${import_picocolors44.default.bold("brainbase")} ${import_picocolors44.default.dim("<command> [options]")}`);
76374
76810
  out.push("");
76375
76811
  out.push(divider("AUTH"));
76376
76812
  out.push("");
76377
- out.push(` ${import_picocolors43.default.cyan("login")} ${import_picocolors43.default.dim(" open the web app and connect this device")}`);
76378
- out.push(` ${import_picocolors43.default.cyan("logout")} ${import_picocolors43.default.dim(" clear the local session")}`);
76379
- out.push(` ${import_picocolors43.default.cyan("whoami")} ${import_picocolors43.default.dim(" show the current user")}`);
76813
+ out.push(` ${import_picocolors44.default.cyan("login")} ${import_picocolors44.default.dim(" open the web app and connect this device")}`);
76814
+ out.push(` ${import_picocolors44.default.cyan("logout")} ${import_picocolors44.default.dim(" clear the local session")}`);
76815
+ out.push(` ${import_picocolors44.default.cyan("whoami")} ${import_picocolors44.default.dim(" show the current user")}`);
76380
76816
  out.push("");
76381
76817
  out.push(divider("LINKED AGENT"));
76382
76818
  out.push("");
76383
- out.push(` ${import_picocolors43.default.cyan("agent create")} ${import_picocolors43.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
76384
- out.push(` ${import_picocolors43.default.cyan("agent pull")} ${import_picocolors43.default.dim("[<id>]")} ${import_picocolors43.default.dim("bring cloud changes into this folder (--force to override; --run-entrypoint to also execute the agent entrypoint)")}`);
76385
- out.push(` ${import_picocolors43.default.cyan("agent push")} ${import_picocolors43.default.dim("send local changes to the cloud (--force to overwrite cloud-side conflicts with local)")}`);
76386
- out.push(` ${import_picocolors43.default.cyan("agent unpack")} ${import_picocolors43.default.dim("install the claimed agent into a harness layout")}`);
76387
- out.push(` ${import_picocolors43.default.cyan("link")} ${import_picocolors43.default.dim("attach this folder to an existing agent")}`);
76388
- out.push(` ${import_picocolors43.default.cyan("agent status")} ${import_picocolors43.default.dim("show what would pull and what would push")}`);
76389
- out.push(` ${import_picocolors43.default.cyan("agent env")} ${import_picocolors43.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
76390
- out.push(` ${import_picocolors43.default.cyan("run")} ${import_picocolors43.default.dim("<cmd> [args...]")} ${import_picocolors43.default.dim("run <cmd> with secrets.env loaded into env")}`);
76391
- out.push(` ${import_picocolors43.default.cyan("status")} ${import_picocolors43.default.dim("show what this folder is linked to")}`);
76392
- out.push(` ${import_picocolors43.default.cyan("unlink")} ${import_picocolors43.default.dim("disconnect this folder")}`);
76819
+ out.push(` ${import_picocolors44.default.cyan("agent create")} ${import_picocolors44.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
76820
+ out.push(` ${import_picocolors44.default.cyan("agent pull")} ${import_picocolors44.default.dim("[<id>]")} ${import_picocolors44.default.dim("bring cloud changes into this folder (--force to override; --run-entrypoint to also execute the agent entrypoint)")}`);
76821
+ out.push(` ${import_picocolors44.default.cyan("agent push")} ${import_picocolors44.default.dim("send local changes to the cloud (--force to overwrite cloud-side conflicts with local)")}`);
76822
+ out.push(` ${import_picocolors44.default.cyan("agent unpack")} ${import_picocolors44.default.dim("install the claimed agent into a harness layout")}`);
76823
+ out.push(` ${import_picocolors44.default.cyan("link")} ${import_picocolors44.default.dim("attach this folder to an existing agent")}`);
76824
+ out.push(` ${import_picocolors44.default.cyan("agent status")} ${import_picocolors44.default.dim("show what would pull and what would push")}`);
76825
+ out.push(` ${import_picocolors44.default.cyan("agent env")} ${import_picocolors44.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
76826
+ out.push(` ${import_picocolors44.default.cyan("run")} ${import_picocolors44.default.dim("<cmd> [args...]")} ${import_picocolors44.default.dim("run <cmd> with secrets.env loaded into env")}`);
76827
+ out.push(` ${import_picocolors44.default.cyan("status")} ${import_picocolors44.default.dim("show what this folder is linked to")}`);
76828
+ out.push(` ${import_picocolors44.default.cyan("unlink")} ${import_picocolors44.default.dim("disconnect this folder")}`);
76829
+ out.push("");
76830
+ out.push(divider("TASKS"));
76831
+ out.push("");
76832
+ out.push(` ${import_picocolors44.default.cyan("task create")} ${import_picocolors44.default.dim("--message <text>")} ${import_picocolors44.default.dim("create a managed task and start its first run")}`);
76393
76833
  out.push("");
76394
76834
  out.push(divider("ORCHESTRATIONS"));
76395
76835
  out.push("");
76396
- out.push(` ${import_picocolors43.default.cyan("orchestration create")} ${import_picocolors43.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
76397
- out.push(` ${import_picocolors43.default.cyan("orchestration list")} ${import_picocolors43.default.dim("list orchestrations under a team")}`);
76398
- out.push(` ${import_picocolors43.default.cyan("orchestration pull")} ${import_picocolors43.default.dim("<id>")} ${import_picocolors43.default.dim("recursively fetch an orchestration + every member agent")}`);
76399
- out.push(` ${import_picocolors43.default.cyan("orchestration push")} ${import_picocolors43.default.dim("recursively push each member, then update the graph")}`);
76400
- out.push(` ${import_picocolors43.default.cyan("orchestration status")} ${import_picocolors43.default.dim("show what would push and what would pull")}`);
76836
+ out.push(` ${import_picocolors44.default.cyan("orchestration create")} ${import_picocolors44.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
76837
+ out.push(` ${import_picocolors44.default.cyan("orchestration list")} ${import_picocolors44.default.dim("list orchestrations under a team")}`);
76838
+ out.push(` ${import_picocolors44.default.cyan("orchestration pull")} ${import_picocolors44.default.dim("<id>")} ${import_picocolors44.default.dim("recursively fetch an orchestration + every member agent")}`);
76839
+ out.push(` ${import_picocolors44.default.cyan("orchestration push")} ${import_picocolors44.default.dim("recursively push each member, then update the graph")}`);
76840
+ out.push(` ${import_picocolors44.default.cyan("orchestration status")} ${import_picocolors44.default.dim("show what would push and what would pull")}`);
76401
76841
  out.push("");
76402
76842
  out.push(divider("TEMPLATES"));
76403
76843
  out.push("");
76404
- out.push(` ${import_picocolors43.default.cyan("template pack")} ${import_picocolors43.default.dim("bundle the current agent into a template")}`);
76405
- out.push(` ${import_picocolors43.default.cyan("template publish")} ${import_picocolors43.default.dim("upload a template to the registry")}`);
76406
- out.push(` ${import_picocolors43.default.cyan("template search")} ${import_picocolors43.default.dim("[query]")} ${import_picocolors43.default.dim("search the registry")}`);
76407
- out.push(` ${import_picocolors43.default.cyan("template info")} ${import_picocolors43.default.dim("<creator/slug>")} ${import_picocolors43.default.dim("show registry details for a template")}`);
76408
- out.push(` ${import_picocolors43.default.cyan("template onboard")} ${import_picocolors43.default.dim("<creator/slug>")} ${import_picocolors43.default.dim("install (or refresh) a template")}`);
76409
- out.push(` ${import_picocolors43.default.cyan("template list")} ${import_picocolors43.default.dim("show installed templates")}`);
76410
- out.push(` ${import_picocolors43.default.cyan("template remove")} ${import_picocolors43.default.dim("<creator/slug>")} ${import_picocolors43.default.dim("uninstall a template")}`);
76844
+ out.push(` ${import_picocolors44.default.cyan("template pack")} ${import_picocolors44.default.dim("bundle the current agent into a template")}`);
76845
+ out.push(` ${import_picocolors44.default.cyan("template publish")} ${import_picocolors44.default.dim("upload a template to the registry")}`);
76846
+ out.push(` ${import_picocolors44.default.cyan("template search")} ${import_picocolors44.default.dim("[query]")} ${import_picocolors44.default.dim("search the registry")}`);
76847
+ out.push(` ${import_picocolors44.default.cyan("template info")} ${import_picocolors44.default.dim("<creator/slug>")} ${import_picocolors44.default.dim("show registry details for a template")}`);
76848
+ out.push(` ${import_picocolors44.default.cyan("template onboard")} ${import_picocolors44.default.dim("<creator/slug>")} ${import_picocolors44.default.dim("install (or refresh) a template")}`);
76849
+ out.push(` ${import_picocolors44.default.cyan("template list")} ${import_picocolors44.default.dim("show installed templates")}`);
76850
+ out.push(` ${import_picocolors44.default.cyan("template remove")} ${import_picocolors44.default.dim("<creator/slug>")} ${import_picocolors44.default.dim("uninstall a template")}`);
76411
76851
  out.push("");
76412
76852
  out.push(divider("SKILLS"));
76413
76853
  out.push("");
76414
- out.push(` ${import_picocolors43.default.cyan("skill add")} ${import_picocolors43.default.dim("<source>")} ${import_picocolors43.default.dim("install a skill (github / git / brainbase)")}`);
76415
- out.push(` ${import_picocolors43.default.cyan("skill list")} ${import_picocolors43.default.dim("show locally installed skills + their source")}`);
76416
- out.push(` ${import_picocolors43.default.cyan("skill update")} ${import_picocolors43.default.dim("<slug>")} ${import_picocolors43.default.dim("re-fetch a skill from its recorded source")}`);
76417
- out.push(` ${import_picocolors43.default.cyan("skill remove")} ${import_picocolors43.default.dim("<slug>")} ${import_picocolors43.default.dim("uninstall a skill")}`);
76418
- out.push(` ${import_picocolors43.default.cyan("skill search")} ${import_picocolors43.default.dim("[query]")} ${import_picocolors43.default.dim("search the brainbase skill registry")}`);
76419
- out.push(` ${import_picocolors43.default.cyan("skill info")} ${import_picocolors43.default.dim("<creator/slug>")} ${import_picocolors43.default.dim("show registry details for a skill")}`);
76420
- out.push(` ${import_picocolors43.default.cyan("skill publish")} ${import_picocolors43.default.dim("[dir]")} ${import_picocolors43.default.dim("publish a SKILL.md folder (defaults to .)")}`);
76854
+ out.push(` ${import_picocolors44.default.cyan("skill add")} ${import_picocolors44.default.dim("<source>")} ${import_picocolors44.default.dim("install a skill (github / git / brainbase)")}`);
76855
+ out.push(` ${import_picocolors44.default.cyan("skill list")} ${import_picocolors44.default.dim("show locally installed skills + their source")}`);
76856
+ out.push(` ${import_picocolors44.default.cyan("skill update")} ${import_picocolors44.default.dim("<slug>")} ${import_picocolors44.default.dim("re-fetch a skill from its recorded source")}`);
76857
+ out.push(` ${import_picocolors44.default.cyan("skill remove")} ${import_picocolors44.default.dim("<slug>")} ${import_picocolors44.default.dim("uninstall a skill")}`);
76858
+ out.push(` ${import_picocolors44.default.cyan("skill search")} ${import_picocolors44.default.dim("[query]")} ${import_picocolors44.default.dim("search the brainbase skill registry")}`);
76859
+ out.push(` ${import_picocolors44.default.cyan("skill info")} ${import_picocolors44.default.dim("<creator/slug>")} ${import_picocolors44.default.dim("show registry details for a skill")}`);
76860
+ out.push(` ${import_picocolors44.default.cyan("skill publish")} ${import_picocolors44.default.dim("[dir]")} ${import_picocolors44.default.dim("publish a SKILL.md folder (defaults to .)")}`);
76421
76861
  out.push("");
76422
76862
  out.push(divider("CLI TOKENS"));
76423
76863
  out.push("");
76424
- out.push(` ${import_picocolors43.default.cyan("token create")} ${import_picocolors43.default.dim("issue a long-lived CLI key for CI / scripts")}`);
76425
- out.push(` ${import_picocolors43.default.cyan("token list")} ${import_picocolors43.default.dim("show your active tokens")}`);
76426
- out.push(` ${import_picocolors43.default.cyan("token revoke")} ${import_picocolors43.default.dim("<id>")} ${import_picocolors43.default.dim("revoke a token")}`);
76864
+ out.push(` ${import_picocolors44.default.cyan("token create")} ${import_picocolors44.default.dim("issue a long-lived CLI key for CI / scripts")}`);
76865
+ out.push(` ${import_picocolors44.default.cyan("token list")} ${import_picocolors44.default.dim("show your active tokens")}`);
76866
+ out.push(` ${import_picocolors44.default.cyan("token revoke")} ${import_picocolors44.default.dim("<id>")} ${import_picocolors44.default.dim("revoke a token")}`);
76427
76867
  out.push("");
76428
76868
  out.push(divider("MCP"));
76429
76869
  out.push("");
76430
- out.push(` ${import_picocolors43.default.cyan("mcp check")} ${import_picocolors43.default.dim("[--json]")} ${import_picocolors43.default.dim("verify MCP server connectivity through the brainbase proxy (runs at sandbox bootstrap)")}`);
76870
+ out.push(` ${import_picocolors44.default.cyan("mcp check")} ${import_picocolors44.default.dim("[--json]")} ${import_picocolors44.default.dim("verify MCP server connectivity through the brainbase proxy (runs at sandbox bootstrap)")}`);
76431
76871
  out.push("");
76432
76872
  out.push(divider("FLAGS"));
76433
76873
  out.push("");
76434
- out.push(` ${import_picocolors43.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
76435
- out.push(` ${import_picocolors43.default.dim("--scope <s>")} force scope: global | project`);
76436
- out.push(` ${import_picocolors43.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
76437
- out.push(` ${import_picocolors43.default.dim("--agent <id>")} for link: attach this folder to an existing agent non-interactively`);
76438
- out.push(` ${import_picocolors43.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
76439
- out.push(` ${import_picocolors43.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
76440
- out.push(` ${import_picocolors43.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
76441
- out.push(` ${import_picocolors43.default.dim("--all")} for template list: include installs from other folders`);
76442
- out.push(` ${import_picocolors43.default.dim("--web <url>")} for login: web app URL (default https://app.brainbaselabs.com)`);
76874
+ out.push(` ${import_picocolors44.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
76875
+ out.push(` ${import_picocolors44.default.dim("--scope <s>")} force scope: global | project`);
76876
+ out.push(` ${import_picocolors44.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
76877
+ out.push(` ${import_picocolors44.default.dim("--agent <id>")} for link/task create: use this agent id explicitly`);
76878
+ out.push(` ${import_picocolors44.default.dim("--message <text>")} for task create: required first user message`);
76879
+ out.push(` ${import_picocolors44.default.dim("--title <text>")} for task create: optional task title`);
76880
+ out.push(` ${import_picocolors44.default.dim("--model <id>")} for task create: optional model override`);
76881
+ out.push(` ${import_picocolors44.default.dim("--json")} for task create/mcp check: machine-readable output`);
76882
+ out.push(` ${import_picocolors44.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
76883
+ out.push(` ${import_picocolors44.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
76884
+ out.push(` ${import_picocolors44.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
76885
+ out.push(` ${import_picocolors44.default.dim("--all")} for template list: include installs from other folders`);
76886
+ out.push(` ${import_picocolors44.default.dim("--web <url>")} for login: web app URL (default https://app.brainbaselabs.com)`);
76443
76887
  out.push("");
76444
76888
  out.push(divider("ENV"));
76445
76889
  out.push("");
76446
- out.push(` ${import_picocolors43.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
76447
- out.push(` ${import_picocolors43.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
76448
- out.push(` ${import_picocolors43.default.dim("BRAINBASE_CONTROL_PLANE_URL")} override the MAS control-plane host (uses /v2/cli)`);
76449
- out.push(` ${import_picocolors43.default.dim("BRAINBASE_API_URL")} legacy KLS host override (uses /api/cli; proxy/registry fallback)`);
76450
- out.push(` ${import_picocolors43.default.dim("BRAINBASE_PROXY_URL")} override the model-proxy URL used by harness traffic (default https://api.v1.brainbaselabs.com)`);
76451
- out.push(` ${import_picocolors43.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL (default https://api.v1.brainbaselabs.com)`);
76452
- out.push(` ${import_picocolors43.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
76453
- out.push(` ${import_picocolors43.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
76454
- out.push(` ${import_picocolors43.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
76455
- out.push(` ${import_picocolors43.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 → agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
76890
+ out.push(` ${import_picocolors44.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
76891
+ out.push(` ${import_picocolors44.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
76892
+ out.push(` ${import_picocolors44.default.dim("BRAINBASE_CONTROL_PLANE_URL")} override the MAS host (/v2/cli; task create uses /v2/tasks)`);
76893
+ out.push(` ${import_picocolors44.default.dim("BRAINBASE_API_URL")} legacy KLS host override (uses /api/cli; proxy/registry fallback)`);
76894
+ out.push(` ${import_picocolors44.default.dim("BRAINBASE_PROXY_URL")} override the model-proxy URL used by harness traffic (default https://api.v1.brainbaselabs.com)`);
76895
+ out.push(` ${import_picocolors44.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL (default https://api.v1.brainbaselabs.com)`);
76896
+ out.push(` ${import_picocolors44.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
76897
+ out.push(` ${import_picocolors44.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
76898
+ out.push(` ${import_picocolors44.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
76899
+ out.push(` ${import_picocolors44.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 → agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
76456
76900
  out.push("");
76457
76901
  out.push(divider("HARNESSES"));
76458
76902
  out.push("");
76459
- out.push(` ${import_picocolors43.default.dim("•")} ${import_picocolors43.default.bold("claude-code")} ${import_picocolors43.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
76460
- out.push(` ${import_picocolors43.default.dim("•")} ${import_picocolors43.default.bold("codex")} ${import_picocolors43.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
76461
- out.push(` ${import_picocolors43.default.dim("•")} ${import_picocolors43.default.bold("kafka")} ${import_picocolors43.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
76903
+ out.push(` ${import_picocolors44.default.dim("•")} ${import_picocolors44.default.bold("claude-code")} ${import_picocolors44.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
76904
+ out.push(` ${import_picocolors44.default.dim("•")} ${import_picocolors44.default.bold("codex")} ${import_picocolors44.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
76905
+ out.push(` ${import_picocolors44.default.dim("•")} ${import_picocolors44.default.bold("kafka")} ${import_picocolors44.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
76462
76906
  out.push("");
76463
76907
  console.log(out.join(`
76464
76908
  `));
@@ -76522,13 +76966,13 @@ async function requireAuth(cmd) {
76522
76966
  if (STORED_PAT_COMMANDS.has(cmd) && readToken())
76523
76967
  return;
76524
76968
  console.error("");
76525
- console.error(` ${brandTint("◆")} ${import_picocolors43.default.bold("brainbase")}`);
76969
+ console.error(` ${brandTint("◆")} ${import_picocolors44.default.bold("brainbase")}`);
76526
76970
  console.error("");
76527
- console.error(` ${import_picocolors43.default.red("✗")} You need to sign in to use ${import_picocolors43.default.bold("brainbase " + cmd)}.`);
76971
+ console.error(` ${import_picocolors44.default.red("✗")} You need to sign in to use ${import_picocolors44.default.bold("brainbase " + cmd)}.`);
76528
76972
  if (status.reason)
76529
- console.error(` ${import_picocolors43.default.dim(status.reason)}`);
76973
+ console.error(` ${import_picocolors44.default.dim(status.reason)}`);
76530
76974
  console.error("");
76531
- console.error(` Run ${import_picocolors43.default.cyan("brainbase login")} to connect this device.`);
76975
+ console.error(` Run ${import_picocolors44.default.cyan("brainbase login")} to connect this device.`);
76532
76976
  console.error("");
76533
76977
  process14.exit(1);
76534
76978
  }
@@ -76551,36 +76995,37 @@ async function main() {
76551
76995
  await runRun(cwd2, argv);
76552
76996
  return;
76553
76997
  }
76554
- const yes = hasFlag2(argv, "--yes", "-y");
76555
- const all = hasFlag2(argv, "--all");
76556
- const harness = getFlag(argv, "--harness");
76557
- const scopeFlag = getFlag(argv, "--scope");
76558
- const web = getFlag(argv, "--web");
76559
- const visibility = getFlag(argv, "--visibility");
76560
- const category = getFlag(argv, "--category");
76561
- const target = getFlag(argv, "--target");
76562
- const pageRaw = getFlag(argv, "--page");
76998
+ const sharedArgs = cmd === "task" ? [] : argv;
76999
+ const yes = hasFlag2(sharedArgs, "--yes", "-y");
77000
+ const all = hasFlag2(sharedArgs, "--all");
77001
+ const harness = getFlag(sharedArgs, "--harness");
77002
+ const scopeFlag = getFlag(sharedArgs, "--scope");
77003
+ const web = getFlag(sharedArgs, "--web");
77004
+ const visibility = getFlag(sharedArgs, "--visibility");
77005
+ const category = getFlag(sharedArgs, "--category");
77006
+ const target = getFlag(sharedArgs, "--target");
77007
+ const pageRaw = getFlag(sharedArgs, "--page");
76563
77008
  const page = pageRaw && /^\d+$/.test(pageRaw) ? Number(pageRaw) : undefined;
76564
- const asSlug = getFlag(argv, "--as");
76565
- const agentFlag = getFlag(argv, "--agent");
76566
- const shellFlag = getFlag(argv, "--shell");
76567
- const noTracking = hasFlag2(argv, "--no-tracking");
76568
- const track = hasFlag2(argv, "--track");
76569
- const forceFlag = hasFlag2(argv, "--force");
76570
- const runEntrypointFlag = hasFlag2(argv, "--run-entrypoint");
76571
- const graphOnlyFlag = hasFlag2(argv, "--graph-only");
76572
- const nameFlag = getFlag(argv, "--name");
76573
- const skillVersionFlag = getFlag(argv, "--skill-version");
76574
- const taglineFlag = getFlag(argv, "--tagline");
76575
- const orgIdFlag = getFlag(argv, "--org");
76576
- const teamIdFlag = getFlag(argv, "--team");
76577
- const fromFlags = getFlagAll(argv, "--from");
76578
- const toFlags = getFlagAll(argv, "--to");
76579
- const descriptionFlag = getFlag(argv, "--description");
76580
- const schemaFlag = getFlag(argv, "--schema");
76581
- const noPushFlag = hasFlag2(argv, "--no-push");
76582
- const jsonFlag = hasFlag2(argv, "--json");
76583
- const acpFlag = hasFlag2(argv, "--acp");
77009
+ const asSlug = getFlag(sharedArgs, "--as");
77010
+ const agentFlag = getFlag(sharedArgs, "--agent");
77011
+ const shellFlag = getFlag(sharedArgs, "--shell");
77012
+ const noTracking = hasFlag2(sharedArgs, "--no-tracking");
77013
+ const track = hasFlag2(sharedArgs, "--track");
77014
+ const forceFlag = hasFlag2(sharedArgs, "--force");
77015
+ const runEntrypointFlag = hasFlag2(sharedArgs, "--run-entrypoint");
77016
+ const graphOnlyFlag = hasFlag2(sharedArgs, "--graph-only");
77017
+ const nameFlag = getFlag(sharedArgs, "--name");
77018
+ const skillVersionFlag = getFlag(sharedArgs, "--skill-version");
77019
+ const taglineFlag = getFlag(sharedArgs, "--tagline");
77020
+ const orgIdFlag = getFlag(sharedArgs, "--org");
77021
+ const teamIdFlag = getFlag(sharedArgs, "--team");
77022
+ const fromFlags = getFlagAll(sharedArgs, "--from");
77023
+ const toFlags = getFlagAll(sharedArgs, "--to");
77024
+ const descriptionFlag = getFlag(sharedArgs, "--description");
77025
+ const schemaFlag = getFlag(sharedArgs, "--schema");
77026
+ const noPushFlag = hasFlag2(sharedArgs, "--no-push");
77027
+ const jsonFlag = hasFlag2(sharedArgs, "--json");
77028
+ const acpFlag = hasFlag2(sharedArgs, "--acp");
76584
77029
  ensureSkillResolversRegistered();
76585
77030
  await requireAuth(cmd);
76586
77031
  try {
@@ -76667,6 +77112,11 @@ async function main() {
76667
77112
  });
76668
77113
  break;
76669
77114
  }
77115
+ case "task": {
77116
+ const sub = argv.shift();
77117
+ await runTask(cwd2, sub, argv);
77118
+ break;
77119
+ }
76670
77120
  case "orchestration":
76671
77121
  case "orch": {
76672
77122
  const sub = argv.shift();
@@ -76706,7 +77156,7 @@ async function main() {
76706
77156
  process14.exit(1);
76707
77157
  }
76708
77158
  } catch (err) {
76709
- console.error(import_picocolors43.default.red(`
77159
+ console.error(import_picocolors44.default.red(`
76710
77160
  ${err.message}`));
76711
77161
  if (process14.env.BRAINBASE_DEBUG)
76712
77162
  console.error(err.stack);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainbase-labs/cli",
3
- "version": "0.16.5",
3
+ "version": "0.17.0",
4
4
  "description": "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
5
5
  "type": "module",
6
6
  "bin": {