@brainbase-labs/cli 0.7.0 → 0.8.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 +497 -361
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1056,14 +1056,14 @@ var require_foldFlowLines = __commonJS((exports) => {
1056
1056
  var FOLD_FLOW = "flow";
1057
1057
  var FOLD_BLOCK = "block";
1058
1058
  var FOLD_QUOTED = "quoted";
1059
- function foldFlowLines(text, indent, mode = "flow", { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) {
1059
+ function foldFlowLines(text2, indent, mode = "flow", { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) {
1060
1060
  if (!lineWidth || lineWidth < 0)
1061
- return text;
1061
+ return text2;
1062
1062
  if (lineWidth < minContentWidth)
1063
1063
  minContentWidth = 0;
1064
1064
  const endStep = Math.max(1 + minContentWidth, 1 + lineWidth - indent.length);
1065
- if (text.length <= endStep)
1066
- return text;
1065
+ if (text2.length <= endStep)
1066
+ return text2;
1067
1067
  const folds = [];
1068
1068
  const escapedFolds = {};
1069
1069
  let end = lineWidth - indent.length;
@@ -1080,14 +1080,14 @@ var require_foldFlowLines = __commonJS((exports) => {
1080
1080
  let escStart = -1;
1081
1081
  let escEnd = -1;
1082
1082
  if (mode === FOLD_BLOCK) {
1083
- i = consumeMoreIndentedLines(text, i, indent.length);
1083
+ i = consumeMoreIndentedLines(text2, i, indent.length);
1084
1084
  if (i !== -1)
1085
1085
  end = i + endStep;
1086
1086
  }
1087
- for (let ch;ch = text[i += 1]; ) {
1087
+ for (let ch;ch = text2[i += 1]; ) {
1088
1088
  if (mode === FOLD_QUOTED && ch === "\\") {
1089
1089
  escStart = i;
1090
- switch (text[i + 1]) {
1090
+ switch (text2[i + 1]) {
1091
1091
  case "x":
1092
1092
  i += 3;
1093
1093
  break;
@@ -1105,13 +1105,13 @@ var require_foldFlowLines = __commonJS((exports) => {
1105
1105
  if (ch === `
1106
1106
  `) {
1107
1107
  if (mode === FOLD_BLOCK)
1108
- i = consumeMoreIndentedLines(text, i, indent.length);
1108
+ i = consumeMoreIndentedLines(text2, i, indent.length);
1109
1109
  end = i + indent.length + endStep;
1110
1110
  split = undefined;
1111
1111
  } else {
1112
1112
  if (ch === " " && prev && prev !== " " && prev !== `
1113
1113
  ` && prev !== "\t") {
1114
- const next = text[i + 1];
1114
+ const next = text2[i + 1];
1115
1115
  if (next && next !== " " && next !== `
1116
1116
  ` && next !== "\t")
1117
1117
  split = i;
@@ -1124,12 +1124,12 @@ var require_foldFlowLines = __commonJS((exports) => {
1124
1124
  } else if (mode === FOLD_QUOTED) {
1125
1125
  while (prev === " " || prev === "\t") {
1126
1126
  prev = ch;
1127
- ch = text[i += 1];
1127
+ ch = text2[i += 1];
1128
1128
  overflow = true;
1129
1129
  }
1130
1130
  const j2 = i > escEnd + 1 ? i - 2 : escStart - 1;
1131
1131
  if (escapedFolds[j2])
1132
- return text;
1132
+ return text2;
1133
1133
  folds.push(j2);
1134
1134
  escapedFolds[j2] = true;
1135
1135
  end = j2 + endStep;
@@ -1144,40 +1144,40 @@ var require_foldFlowLines = __commonJS((exports) => {
1144
1144
  if (overflow && onOverflow)
1145
1145
  onOverflow();
1146
1146
  if (folds.length === 0)
1147
- return text;
1147
+ return text2;
1148
1148
  if (onFold)
1149
1149
  onFold();
1150
- let res = text.slice(0, folds[0]);
1150
+ let res = text2.slice(0, folds[0]);
1151
1151
  for (let i2 = 0;i2 < folds.length; ++i2) {
1152
1152
  const fold = folds[i2];
1153
- const end2 = folds[i2 + 1] || text.length;
1153
+ const end2 = folds[i2 + 1] || text2.length;
1154
1154
  if (fold === 0)
1155
1155
  res = `
1156
- ${indent}${text.slice(0, end2)}`;
1156
+ ${indent}${text2.slice(0, end2)}`;
1157
1157
  else {
1158
1158
  if (mode === FOLD_QUOTED && escapedFolds[fold])
1159
- res += `${text[fold]}\\`;
1159
+ res += `${text2[fold]}\\`;
1160
1160
  res += `
1161
- ${indent}${text.slice(fold + 1, end2)}`;
1161
+ ${indent}${text2.slice(fold + 1, end2)}`;
1162
1162
  }
1163
1163
  }
1164
1164
  return res;
1165
1165
  }
1166
- function consumeMoreIndentedLines(text, i, indent) {
1166
+ function consumeMoreIndentedLines(text2, i, indent) {
1167
1167
  let end = i;
1168
1168
  let start = i + 1;
1169
- let ch = text[start];
1169
+ let ch = text2[start];
1170
1170
  while (ch === " " || ch === "\t") {
1171
1171
  if (i < start + indent) {
1172
- ch = text[++i];
1172
+ ch = text2[++i];
1173
1173
  } else {
1174
1174
  do {
1175
- ch = text[++i];
1175
+ ch = text2[++i];
1176
1176
  } while (ch && ch !== `
1177
1177
  `);
1178
1178
  end = i;
1179
1179
  start = i + 1;
1180
- ch = text[start];
1180
+ ch = text2[start];
1181
1181
  }
1182
1182
  }
1183
1183
  return end;
@@ -7701,8 +7701,8 @@ var require_react_development = __commonJS((exports, module) => {
7701
7701
  }
7702
7702
  var didWarnAboutMaps = false;
7703
7703
  var userProvidedKeyEscapeRegex = /\/+/g;
7704
- function escapeUserProvidedKey(text) {
7705
- return text.replace(userProvidedKeyEscapeRegex, "$&/");
7704
+ function escapeUserProvidedKey(text2) {
7705
+ return text2.replace(userProvidedKeyEscapeRegex, "$&/");
7706
7706
  }
7707
7707
  function getElementKey(element, index) {
7708
7708
  if (typeof element === "object" && element !== null && element.key != null) {
@@ -8975,26 +8975,26 @@ var require_signals = __commonJS((exports, module) => {
8975
8975
 
8976
8976
  // node_modules/signal-exit/index.js
8977
8977
  var require_signal_exit = __commonJS((exports, module) => {
8978
- var process3 = global.process;
8979
- var processOk = function(process4) {
8980
- return process4 && typeof process4 === "object" && typeof process4.removeListener === "function" && typeof process4.emit === "function" && typeof process4.reallyExit === "function" && typeof process4.listeners === "function" && typeof process4.kill === "function" && typeof process4.pid === "number" && typeof process4.on === "function";
8978
+ var process4 = global.process;
8979
+ var processOk = function(process5) {
8980
+ return process5 && typeof process5 === "object" && typeof process5.removeListener === "function" && typeof process5.emit === "function" && typeof process5.reallyExit === "function" && typeof process5.listeners === "function" && typeof process5.kill === "function" && typeof process5.pid === "number" && typeof process5.on === "function";
8981
8981
  };
8982
- if (!processOk(process3)) {
8982
+ if (!processOk(process4)) {
8983
8983
  module.exports = function() {
8984
8984
  return function() {};
8985
8985
  };
8986
8986
  } else {
8987
8987
  assert = __require("assert");
8988
8988
  signals = require_signals();
8989
- isWin = /^win/i.test(process3.platform);
8989
+ isWin = /^win/i.test(process4.platform);
8990
8990
  EE = __require("events");
8991
8991
  if (typeof EE !== "function") {
8992
8992
  EE = EE.EventEmitter;
8993
8993
  }
8994
- if (process3.__signal_exit_emitter__) {
8995
- emitter = process3.__signal_exit_emitter__;
8994
+ if (process4.__signal_exit_emitter__) {
8995
+ emitter = process4.__signal_exit_emitter__;
8996
8996
  } else {
8997
- emitter = process3.__signal_exit_emitter__ = new EE;
8997
+ emitter = process4.__signal_exit_emitter__ = new EE;
8998
8998
  emitter.count = 0;
8999
8999
  emitter.emitted = {};
9000
9000
  }
@@ -9030,11 +9030,11 @@ var require_signal_exit = __commonJS((exports, module) => {
9030
9030
  loaded = false;
9031
9031
  signals.forEach(function(sig) {
9032
9032
  try {
9033
- process3.removeListener(sig, sigListeners[sig]);
9033
+ process4.removeListener(sig, sigListeners[sig]);
9034
9034
  } catch (er) {}
9035
9035
  });
9036
- process3.emit = originalProcessEmit;
9037
- process3.reallyExit = originalProcessReallyExit;
9036
+ process4.emit = originalProcessEmit;
9037
+ process4.reallyExit = originalProcessReallyExit;
9038
9038
  emitter.count -= 1;
9039
9039
  };
9040
9040
  module.exports.unload = unload;
@@ -9051,7 +9051,7 @@ var require_signal_exit = __commonJS((exports, module) => {
9051
9051
  if (!processOk(global.process)) {
9052
9052
  return;
9053
9053
  }
9054
- var listeners = process3.listeners(sig);
9054
+ var listeners = process4.listeners(sig);
9055
9055
  if (listeners.length === emitter.count) {
9056
9056
  unload();
9057
9057
  emit("exit", null, sig);
@@ -9059,7 +9059,7 @@ var require_signal_exit = __commonJS((exports, module) => {
9059
9059
  if (isWin && sig === "SIGHUP") {
9060
9060
  sig = "SIGINT";
9061
9061
  }
9062
- process3.kill(process3.pid, sig);
9062
+ process4.kill(process4.pid, sig);
9063
9063
  }
9064
9064
  };
9065
9065
  });
@@ -9075,35 +9075,35 @@ var require_signal_exit = __commonJS((exports, module) => {
9075
9075
  emitter.count += 1;
9076
9076
  signals = signals.filter(function(sig) {
9077
9077
  try {
9078
- process3.on(sig, sigListeners[sig]);
9078
+ process4.on(sig, sigListeners[sig]);
9079
9079
  return true;
9080
9080
  } catch (er) {
9081
9081
  return false;
9082
9082
  }
9083
9083
  });
9084
- process3.emit = processEmit;
9085
- process3.reallyExit = processReallyExit;
9084
+ process4.emit = processEmit;
9085
+ process4.reallyExit = processReallyExit;
9086
9086
  };
9087
9087
  module.exports.load = load;
9088
- originalProcessReallyExit = process3.reallyExit;
9088
+ originalProcessReallyExit = process4.reallyExit;
9089
9089
  processReallyExit = function processReallyExit2(code) {
9090
9090
  if (!processOk(global.process)) {
9091
9091
  return;
9092
9092
  }
9093
- process3.exitCode = code || 0;
9094
- emit("exit", process3.exitCode, null);
9095
- emit("afterexit", process3.exitCode, null);
9096
- originalProcessReallyExit.call(process3, process3.exitCode);
9093
+ process4.exitCode = code || 0;
9094
+ emit("exit", process4.exitCode, null);
9095
+ emit("afterexit", process4.exitCode, null);
9096
+ originalProcessReallyExit.call(process4, process4.exitCode);
9097
9097
  };
9098
- originalProcessEmit = process3.emit;
9098
+ originalProcessEmit = process4.emit;
9099
9099
  processEmit = function processEmit2(ev, arg) {
9100
9100
  if (ev === "exit" && processOk(global.process)) {
9101
9101
  if (arg !== undefined) {
9102
- process3.exitCode = arg;
9102
+ process4.exitCode = arg;
9103
9103
  }
9104
9104
  var ret = originalProcessEmit.apply(this, arguments);
9105
- emit("exit", process3.exitCode, null);
9106
- emit("afterexit", process3.exitCode, null);
9105
+ emit("exit", process4.exitCode, null);
9106
+ emit("afterexit", process4.exitCode, null);
9107
9107
  return ret;
9108
9108
  } else {
9109
9109
  return originalProcessEmit.apply(this, arguments);
@@ -11818,8 +11818,8 @@ var require_react_reconciler_development = __commonJS((exports, module) => {
11818
11818
  didNotFindHydratableInstanceWithinContainer(parentContainer, type, props);
11819
11819
  break;
11820
11820
  case HostText:
11821
- var text = fiber.pendingProps;
11822
- didNotFindHydratableTextInstanceWithinContainer(parentContainer, text);
11821
+ var text2 = fiber.pendingProps;
11822
+ didNotFindHydratableTextInstanceWithinContainer(parentContainer, text2);
11823
11823
  break;
11824
11824
  case SuspenseComponent:
11825
11825
  didNotFindHydratableSuspenseInstanceWithinContainer(parentContainer);
@@ -11896,8 +11896,8 @@ var require_react_reconciler_development = __commonJS((exports, module) => {
11896
11896
  return false;
11897
11897
  }
11898
11898
  case HostText: {
11899
- var text = fiber.pendingProps;
11900
- var textInstance = canHydrateTextInstance(nextInstance, text);
11899
+ var text2 = fiber.pendingProps;
11900
+ var textInstance = canHydrateTextInstance(nextInstance, text2);
11901
11901
  if (textInstance !== null) {
11902
11902
  fiber.stateNode = textInstance;
11903
11903
  hydrationParentFiber = fiber;
@@ -18602,8 +18602,8 @@ Check the render method of \`` + ownerName + "`.";
18602
18602
  } else if (node.tag === HostText) {
18603
18603
  var _instance = node.stateNode;
18604
18604
  if (needsVisibilityToggle && isHidden) {
18605
- var text = node.memoizedProps;
18606
- _instance = cloneHiddenTextInstance(_instance, text, node);
18605
+ var text2 = node.memoizedProps;
18606
+ _instance = cloneHiddenTextInstance(_instance, text2, node);
18607
18607
  }
18608
18608
  appendInitialChild(parent, _instance);
18609
18609
  } else if (node.tag === HostPortal)
@@ -18647,8 +18647,8 @@ Check the render method of \`` + ownerName + "`.";
18647
18647
  } else if (node.tag === HostText) {
18648
18648
  var _instance2 = node.stateNode;
18649
18649
  if (needsVisibilityToggle && isHidden) {
18650
- var text = node.memoizedProps;
18651
- _instance2 = cloneHiddenTextInstance(_instance2, text, node);
18650
+ var text2 = node.memoizedProps;
18651
+ _instance2 = cloneHiddenTextInstance(_instance2, text2, node);
18652
18652
  }
18653
18653
  appendChildToContainerChildSet(containerChildSet, _instance2);
18654
18654
  } else if (node.tag === HostPortal)
@@ -21223,10 +21223,10 @@ It looks like you wrote ` + hookName + "(async () => ...) or returned a Promise.
21223
21223
  value: role
21224
21224
  };
21225
21225
  }
21226
- function createTextSelector(text) {
21226
+ function createTextSelector(text2) {
21227
21227
  return {
21228
21228
  $$typeof: TEXT_TYPE,
21229
- value: text
21229
+ value: text2
21230
21230
  };
21231
21231
  }
21232
21232
  function createTestNameSelector(id) {
@@ -28583,7 +28583,7 @@ var require_jsx_dev_runtime = __commonJS((exports, module) => {
28583
28583
 
28584
28584
  // src/index.ts
28585
28585
  var import_picocolors40 = __toESM(require_picocolors(), 1);
28586
- import process13 from "node:process";
28586
+ import process14 from "node:process";
28587
28587
  import fs51 from "node:fs";
28588
28588
 
28589
28589
  // src/cli/template.ts
@@ -29449,7 +29449,7 @@ function padStart(s, n) {
29449
29449
  // package.json
29450
29450
  var package_default = {
29451
29451
  name: "@brainbase-labs/cli",
29452
- version: "0.7.0",
29452
+ version: "0.8.0",
29453
29453
  description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
29454
29454
  type: "module",
29455
29455
  bin: {
@@ -29539,6 +29539,62 @@ function ensureNotCancelled(value) {
29539
29539
  return value;
29540
29540
  }
29541
29541
 
29542
+ // src/core/tty.ts
29543
+ import process2 from "node:process";
29544
+ function isInteractive() {
29545
+ if (process2.env.BRAINBASE_NON_INTERACTIVE === "1")
29546
+ return false;
29547
+ if (process2.env.CI)
29548
+ return false;
29549
+ return Boolean(process2.stdin.isTTY);
29550
+ }
29551
+
29552
+ // src/ui/prompt.ts
29553
+ class NonInteractiveError extends Error {
29554
+ constructor(message) {
29555
+ super(message);
29556
+ this.name = "NonInteractiveError";
29557
+ }
29558
+ }
29559
+ async function select(opts) {
29560
+ if (!isInteractive()) {
29561
+ if (opts.fallback !== undefined)
29562
+ return opts.fallback;
29563
+ const autoPick = opts.autoPick !== false;
29564
+ if (autoPick && opts.options.length === 1)
29565
+ return opts.options[0].value;
29566
+ throw new NonInteractiveError(`${opts.message} needs an interactive terminal. ${opts.flagHint}`);
29567
+ }
29568
+ const choice = await ie({
29569
+ message: opts.message,
29570
+ options: opts.options,
29571
+ ...opts.initialValue !== undefined ? { initialValue: opts.initialValue } : {}
29572
+ });
29573
+ return ensureNotCancelled(choice);
29574
+ }
29575
+ async function text(opts) {
29576
+ if (!isInteractive()) {
29577
+ if (opts.fallback !== undefined)
29578
+ return opts.fallback;
29579
+ throw new NonInteractiveError(`${opts.message} needs an interactive terminal. ${opts.flagHint}`);
29580
+ }
29581
+ const ans = await te({
29582
+ message: opts.message,
29583
+ placeholder: opts.placeholder,
29584
+ defaultValue: opts.defaultValue,
29585
+ validate: opts.validate
29586
+ });
29587
+ return ensureNotCancelled(ans);
29588
+ }
29589
+ function requireInteractive(flagHint) {
29590
+ if (!isInteractive()) {
29591
+ throw new NonInteractiveError(`This step needs an interactive terminal. ${flagHint}`);
29592
+ }
29593
+ }
29594
+ function autoProceed(yes) {
29595
+ return Boolean(yes) || !isInteractive();
29596
+ }
29597
+
29542
29598
  // src/ui/symbols.ts
29543
29599
  var import_picocolors5 = __toESM(require_picocolors(), 1);
29544
29600
  var sym = {
@@ -29631,6 +29687,7 @@ function pruneRedundant(set) {
29631
29687
  }
29632
29688
  }
29633
29689
  async function pickPaths(rootDir) {
29690
+ requireInteractive("Selecting files is interactive — run this in a real terminal.");
29634
29691
  const root = path.resolve(rootDir);
29635
29692
  const selected = new Set;
29636
29693
  let current = root;
@@ -37701,11 +37758,11 @@ class LocalRegistry {
37701
37758
 
37702
37759
  // node_modules/ink/build/render.js
37703
37760
  import { Stream } from "node:stream";
37704
- import process12 from "node:process";
37761
+ import process13 from "node:process";
37705
37762
 
37706
37763
  // node_modules/ink/build/ink.js
37707
37764
  var import_react10 = __toESM(require_react(), 1);
37708
- import process11 from "node:process";
37765
+ import process12 from "node:process";
37709
37766
  // node_modules/es-toolkit/dist/function/debounce.mjs
37710
37767
  function debounce(func, debounceMs, { signal, edges } = {}) {
37711
37768
  let pendingThis = undefined;
@@ -37862,7 +37919,7 @@ __export(exports_base, {
37862
37919
  beep: () => beep,
37863
37920
  ConEmu: () => ConEmu
37864
37921
  });
37865
- import process2 from "node:process";
37922
+ import process3 from "node:process";
37866
37923
  import os2 from "node:os";
37867
37924
 
37868
37925
  // node_modules/environment/index.js
@@ -37888,12 +37945,12 @@ var ESC = "\x1B[";
37888
37945
  var OSC = "\x1B]";
37889
37946
  var BEL = "\x07";
37890
37947
  var SEP = ";";
37891
- var isTerminalApp = !isBrowser && process2.env.TERM_PROGRAM === "Apple_Terminal";
37892
- var isWindows2 = !isBrowser && process2.platform === "win32";
37893
- var isTmux = !isBrowser && (process2.env.TERM?.startsWith("screen") || process2.env.TERM?.startsWith("tmux") || process2.env.TMUX !== undefined);
37948
+ var isTerminalApp = !isBrowser && process3.env.TERM_PROGRAM === "Apple_Terminal";
37949
+ var isWindows2 = !isBrowser && process3.platform === "win32";
37950
+ var isTmux = !isBrowser && (process3.env.TERM?.startsWith("screen") || process3.env.TERM?.startsWith("tmux") || process3.env.TMUX !== undefined);
37894
37951
  var cwdFunction = isBrowser ? () => {
37895
37952
  throw new Error("`process.cwd()` only works in Node.js, not the browser.");
37896
- } : process2.cwd;
37953
+ } : process3.cwd;
37897
37954
  var wrapOsc = (sequence) => {
37898
37955
  if (isTmux) {
37899
37956
  return "\x1BPtmux;" + sequence.replaceAll("\x1B", "\x1B\x1B") + "\x1B\\";
@@ -37978,12 +38035,12 @@ var enterAlternativeScreen = ESC + "?1049h";
37978
38035
  var exitAlternativeScreen = ESC + "?1049l";
37979
38036
  var beginSynchronizedOutput = ESC + "?2026h";
37980
38037
  var endSynchronizedOutput = ESC + "?2026l";
37981
- var synchronizedOutput = (text) => beginSynchronizedOutput + text + endSynchronizedOutput;
38038
+ var synchronizedOutput = (text2) => beginSynchronizedOutput + text2 + endSynchronizedOutput;
37982
38039
  var beep = BEL;
37983
- var link = (text, url) => {
38040
+ var link = (text2, url) => {
37984
38041
  const openLink = wrapOsc(`${OSC}8${SEP}${SEP}${url}${BEL}`);
37985
38042
  const closeLink = wrapOsc(`${OSC}8${SEP}${SEP}${BEL}`);
37986
- return openLink + text + closeLink;
38043
+ return openLink + text2 + closeLink;
37987
38044
  };
37988
38045
  var image = (data, options = {}) => {
37989
38046
  let returnValue = `${OSC}1337;File=inline=1`;
@@ -39726,7 +39783,7 @@ var src_default = Yoga;
39726
39783
  // node_modules/ink/build/reconciler.js
39727
39784
  var import_react_reconciler = __toESM(require_react_reconciler(), 1);
39728
39785
  var import_constants = __toESM(require_constants(), 1);
39729
- import process3 from "node:process";
39786
+ import process4 from "node:process";
39730
39787
 
39731
39788
  // node_modules/ansi-regex/index.js
39732
39789
  function ansiRegex({ onlyFirst = false } = {}) {
@@ -39900,21 +39957,21 @@ function widestLine(string) {
39900
39957
 
39901
39958
  // node_modules/ink/build/measure-text.js
39902
39959
  var cache = {};
39903
- var measureText = (text) => {
39904
- if (text.length === 0) {
39960
+ var measureText = (text2) => {
39961
+ if (text2.length === 0) {
39905
39962
  return {
39906
39963
  width: 0,
39907
39964
  height: 0
39908
39965
  };
39909
39966
  }
39910
- const cachedDimensions = cache[text];
39967
+ const cachedDimensions = cache[text2];
39911
39968
  if (cachedDimensions) {
39912
39969
  return cachedDimensions;
39913
39970
  }
39914
- const width = widestLine(text);
39915
- const height = text.split(`
39971
+ const width = widestLine(text2);
39972
+ const height = text2.split(`
39916
39973
  `).length;
39917
- cache[text] = { width, height };
39974
+ cache[text2] = { width, height };
39918
39975
  return { width, height };
39919
39976
  };
39920
39977
  var measure_text_default = measureText;
@@ -40363,15 +40420,15 @@ function getIndexOfNearestSpace(string, wantedIndex, shouldSearchRight) {
40363
40420
  }
40364
40421
  return wantedIndex;
40365
40422
  }
40366
- function cliTruncate(text, columns, options = {}) {
40423
+ function cliTruncate(text2, columns, options = {}) {
40367
40424
  const {
40368
40425
  position = "end",
40369
40426
  space = false,
40370
40427
  preferTruncationOnSpace = false
40371
40428
  } = options;
40372
40429
  let { truncationCharacter = "…" } = options;
40373
- if (typeof text !== "string") {
40374
- throw new TypeError(`Expected \`input\` to be a string, got ${typeof text}`);
40430
+ if (typeof text2 !== "string") {
40431
+ throw new TypeError(`Expected \`input\` to be a string, got ${typeof text2}`);
40375
40432
  }
40376
40433
  if (typeof columns !== "number") {
40377
40434
  throw new TypeError(`Expected \`columns\` to be a number, got ${typeof columns}`);
@@ -40382,19 +40439,19 @@ function cliTruncate(text, columns, options = {}) {
40382
40439
  if (columns === 1) {
40383
40440
  return truncationCharacter;
40384
40441
  }
40385
- const length = stringWidth(text);
40442
+ const length = stringWidth(text2);
40386
40443
  if (length <= columns) {
40387
- return text;
40444
+ return text2;
40388
40445
  }
40389
40446
  if (position === "start") {
40390
40447
  if (preferTruncationOnSpace) {
40391
- const nearestSpace = getIndexOfNearestSpace(text, length - columns + 1, true);
40392
- return truncationCharacter + sliceAnsi(text, nearestSpace, length).trim();
40448
+ const nearestSpace = getIndexOfNearestSpace(text2, length - columns + 1, true);
40449
+ return truncationCharacter + sliceAnsi(text2, nearestSpace, length).trim();
40393
40450
  }
40394
40451
  if (space === true) {
40395
40452
  truncationCharacter += " ";
40396
40453
  }
40397
- return truncationCharacter + sliceAnsi(text, length - columns + stringWidth(truncationCharacter), length);
40454
+ return truncationCharacter + sliceAnsi(text2, length - columns + stringWidth(truncationCharacter), length);
40398
40455
  }
40399
40456
  if (position === "middle") {
40400
40457
  if (space === true) {
@@ -40402,36 +40459,36 @@ function cliTruncate(text, columns, options = {}) {
40402
40459
  }
40403
40460
  const half = Math.floor(columns / 2);
40404
40461
  if (preferTruncationOnSpace) {
40405
- const spaceNearFirstBreakPoint = getIndexOfNearestSpace(text, half);
40406
- const spaceNearSecondBreakPoint = getIndexOfNearestSpace(text, length - (columns - half) + 1, true);
40407
- return sliceAnsi(text, 0, spaceNearFirstBreakPoint) + truncationCharacter + sliceAnsi(text, spaceNearSecondBreakPoint, length).trim();
40462
+ const spaceNearFirstBreakPoint = getIndexOfNearestSpace(text2, half);
40463
+ const spaceNearSecondBreakPoint = getIndexOfNearestSpace(text2, length - (columns - half) + 1, true);
40464
+ return sliceAnsi(text2, 0, spaceNearFirstBreakPoint) + truncationCharacter + sliceAnsi(text2, spaceNearSecondBreakPoint, length).trim();
40408
40465
  }
40409
- return sliceAnsi(text, 0, half) + truncationCharacter + sliceAnsi(text, length - (columns - half) + stringWidth(truncationCharacter), length);
40466
+ return sliceAnsi(text2, 0, half) + truncationCharacter + sliceAnsi(text2, length - (columns - half) + stringWidth(truncationCharacter), length);
40410
40467
  }
40411
40468
  if (position === "end") {
40412
40469
  if (preferTruncationOnSpace) {
40413
- const nearestSpace = getIndexOfNearestSpace(text, columns - 1);
40414
- return sliceAnsi(text, 0, nearestSpace) + truncationCharacter;
40470
+ const nearestSpace = getIndexOfNearestSpace(text2, columns - 1);
40471
+ return sliceAnsi(text2, 0, nearestSpace) + truncationCharacter;
40415
40472
  }
40416
40473
  if (space === true) {
40417
40474
  truncationCharacter = ` ${truncationCharacter}`;
40418
40475
  }
40419
- return sliceAnsi(text, 0, columns - stringWidth(truncationCharacter)) + truncationCharacter;
40476
+ return sliceAnsi(text2, 0, columns - stringWidth(truncationCharacter)) + truncationCharacter;
40420
40477
  }
40421
40478
  throw new Error(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${position}`);
40422
40479
  }
40423
40480
 
40424
40481
  // node_modules/ink/build/wrap-text.js
40425
40482
  var cache2 = {};
40426
- var wrapText = (text, maxWidth, wrapType) => {
40427
- const cacheKey = text + String(maxWidth) + String(wrapType);
40483
+ var wrapText = (text2, maxWidth, wrapType) => {
40484
+ const cacheKey = text2 + String(maxWidth) + String(wrapType);
40428
40485
  const cachedText = cache2[cacheKey];
40429
40486
  if (cachedText) {
40430
40487
  return cachedText;
40431
40488
  }
40432
- let wrappedText = text;
40489
+ let wrappedText = text2;
40433
40490
  if (wrapType === "wrap") {
40434
- wrappedText = wrapAnsi(text, maxWidth, {
40491
+ wrappedText = wrapAnsi(text2, maxWidth, {
40435
40492
  trim: false,
40436
40493
  hard: true
40437
40494
  });
@@ -40444,7 +40501,7 @@ var wrapText = (text, maxWidth, wrapType) => {
40444
40501
  if (wrapType === "truncate-start") {
40445
40502
  position = "start";
40446
40503
  }
40447
- wrappedText = cliTruncate(text, maxWidth, { position });
40504
+ wrappedText = cliTruncate(text2, maxWidth, { position });
40448
40505
  }
40449
40506
  cache2[cacheKey] = wrappedText;
40450
40507
  return wrappedText;
@@ -40453,7 +40510,7 @@ var wrap_text_default = wrapText;
40453
40510
 
40454
40511
  // node_modules/ink/build/squash-text-nodes.js
40455
40512
  var squashTextNodes = (node) => {
40456
- let text = "";
40513
+ let text2 = "";
40457
40514
  for (let index = 0;index < node.childNodes.length; index++) {
40458
40515
  const childNode = node.childNodes[index];
40459
40516
  if (childNode === undefined) {
@@ -40470,9 +40527,9 @@ var squashTextNodes = (node) => {
40470
40527
  nodeText = childNode.internal_transform(nodeText, index);
40471
40528
  }
40472
40529
  }
40473
- text += nodeText;
40530
+ text2 += nodeText;
40474
40531
  }
40475
- return text;
40532
+ return text2;
40476
40533
  };
40477
40534
  var squash_text_nodes_default = squashTextNodes;
40478
40535
 
@@ -40544,20 +40601,20 @@ var setAttribute = (node, key, value) => {
40544
40601
  var setStyle = (node, style) => {
40545
40602
  node.style = style;
40546
40603
  };
40547
- var createTextNode = (text) => {
40604
+ var createTextNode = (text2) => {
40548
40605
  const node = {
40549
40606
  nodeName: "#text",
40550
- nodeValue: text,
40607
+ nodeValue: text2,
40551
40608
  yogaNode: undefined,
40552
40609
  parentNode: undefined,
40553
40610
  style: {}
40554
40611
  };
40555
- setTextNodeValue(node, text);
40612
+ setTextNodeValue(node, text2);
40556
40613
  return node;
40557
40614
  };
40558
40615
  var measureTextNode = function(node, width) {
40559
- const text = node.nodeName === "#text" ? node.nodeValue : squash_text_nodes_default(node);
40560
- const dimensions = measure_text_default(text);
40616
+ const text2 = node.nodeName === "#text" ? node.nodeValue : squash_text_nodes_default(node);
40617
+ const dimensions = measure_text_default(text2);
40561
40618
  if (dimensions.width <= width) {
40562
40619
  return dimensions;
40563
40620
  }
@@ -40565,7 +40622,7 @@ var measureTextNode = function(node, width) {
40565
40622
  return dimensions;
40566
40623
  }
40567
40624
  const textWrap = node.style?.textWrap ?? "wrap";
40568
- const wrappedText = wrap_text_default(text, width, textWrap);
40625
+ const wrappedText = wrap_text_default(text2, width, textWrap);
40569
40626
  return measure_text_default(wrappedText);
40570
40627
  };
40571
40628
  var findClosestYogaNode = (node) => {
@@ -40578,11 +40635,11 @@ var markNodeAsDirty = (node) => {
40578
40635
  const yogaNode = findClosestYogaNode(node);
40579
40636
  yogaNode?.markDirty();
40580
40637
  };
40581
- var setTextNodeValue = (node, text) => {
40582
- if (typeof text !== "string") {
40583
- text = String(text);
40638
+ var setTextNodeValue = (node, text2) => {
40639
+ if (typeof text2 !== "string") {
40640
+ text2 = String(text2);
40584
40641
  }
40585
- node.nodeValue = text;
40642
+ node.nodeValue = text2;
40586
40643
  markNodeAsDirty(node);
40587
40644
  };
40588
40645
 
@@ -40808,7 +40865,7 @@ var styles2 = (node, style = {}) => {
40808
40865
  var styles_default = styles2;
40809
40866
 
40810
40867
  // node_modules/ink/build/reconciler.js
40811
- if (process3.env["DEV"] === "true") {
40868
+ if (process4.env["DEV"] === "true") {
40812
40869
  try {
40813
40870
  await Promise.resolve().then(() => (init_devtools(), exports_devtools));
40814
40871
  } catch (error) {
@@ -40917,18 +40974,18 @@ var reconciler_default = import_react_reconciler.default({
40917
40974
  }
40918
40975
  return node;
40919
40976
  },
40920
- createTextInstance(text, _root, hostContext) {
40977
+ createTextInstance(text2, _root, hostContext) {
40921
40978
  if (!hostContext.isInsideText) {
40922
- throw new Error(`Text string "${text}" must be rendered inside <Text> component`);
40979
+ throw new Error(`Text string "${text2}" must be rendered inside <Text> component`);
40923
40980
  }
40924
- return createTextNode(text);
40981
+ return createTextNode(text2);
40925
40982
  },
40926
40983
  resetTextContent() {},
40927
40984
  hideTextInstance(node) {
40928
40985
  setTextNodeValue(node, "");
40929
40986
  },
40930
- unhideTextInstance(node, text) {
40931
- setTextNodeValue(node, text);
40987
+ unhideTextInstance(node, text2) {
40988
+ setTextNodeValue(node, text2);
40932
40989
  },
40933
40990
  getPublicInstance: (instance) => instance,
40934
40991
  hideInstance(node) {
@@ -41221,16 +41278,16 @@ var ansiStyles2 = assembleStyles2();
41221
41278
  var ansi_styles_default2 = ansiStyles2;
41222
41279
 
41223
41280
  // node_modules/chalk/source/vendor/supports-color/index.js
41224
- import process4 from "node:process";
41281
+ import process5 from "node:process";
41225
41282
  import os3 from "node:os";
41226
41283
  import tty from "node:tty";
41227
- function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process4.argv) {
41284
+ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process5.argv) {
41228
41285
  const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
41229
41286
  const position = argv.indexOf(prefix + flag);
41230
41287
  const terminatorPosition = argv.indexOf("--");
41231
41288
  return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
41232
41289
  }
41233
- var { env: env2 } = process4;
41290
+ var { env: env2 } = process5;
41234
41291
  var flagForceColor;
41235
41292
  if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
41236
41293
  flagForceColor = 0;
@@ -41286,7 +41343,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
41286
41343
  if (env2.TERM === "dumb") {
41287
41344
  return min2;
41288
41345
  }
41289
- if (process4.platform === "win32") {
41346
+ if (process5.platform === "win32") {
41290
41347
  const osRelease = os3.release().split(".");
41291
41348
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
41292
41349
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
@@ -41638,15 +41695,15 @@ var renderBorder = (x3, y3, node, output) => {
41638
41695
  var render_border_default = renderBorder;
41639
41696
 
41640
41697
  // node_modules/ink/build/render-node-to-output.js
41641
- var applyPaddingToText = (node, text) => {
41698
+ var applyPaddingToText = (node, text2) => {
41642
41699
  const yogaNode = node.childNodes[0]?.yogaNode;
41643
41700
  if (yogaNode) {
41644
41701
  const offsetX = yogaNode.getComputedLeft();
41645
41702
  const offsetY = yogaNode.getComputedTop();
41646
- text = `
41647
- `.repeat(offsetY) + indentString(text, offsetX);
41703
+ text2 = `
41704
+ `.repeat(offsetY) + indentString(text2, offsetX);
41648
41705
  }
41649
- return text;
41706
+ return text2;
41650
41707
  };
41651
41708
  var renderNodeToOutput = (node, output, options) => {
41652
41709
  const { offsetX = 0, offsetY = 0, transformers = [], skipStaticElements } = options;
@@ -41665,16 +41722,16 @@ var renderNodeToOutput = (node, output, options) => {
41665
41722
  newTransformers = [node.internal_transform, ...transformers];
41666
41723
  }
41667
41724
  if (node.nodeName === "ink-text") {
41668
- let text = squash_text_nodes_default(node);
41669
- if (text.length > 0) {
41670
- const currentWidth = widestLine(text);
41725
+ let text2 = squash_text_nodes_default(node);
41726
+ if (text2.length > 0) {
41727
+ const currentWidth = widestLine(text2);
41671
41728
  const maxWidth = get_max_width_default(yogaNode);
41672
41729
  if (currentWidth > maxWidth) {
41673
41730
  const textWrap = node.style.textWrap ?? "wrap";
41674
- text = wrap_text_default(text, maxWidth, textWrap);
41731
+ text2 = wrap_text_default(text2, maxWidth, textWrap);
41675
41732
  }
41676
- text = applyPaddingToText(node, text);
41677
- output.write(x3, y3, text, { transformers: newTransformers });
41733
+ text2 = applyPaddingToText(node, text2);
41734
+ output.write(x3, y3, text2, { transformers: newTransformers });
41678
41735
  }
41679
41736
  return;
41680
41737
  }
@@ -42026,16 +42083,16 @@ class Output {
42026
42083
  this.width = width;
42027
42084
  this.height = height;
42028
42085
  }
42029
- write(x3, y3, text, options) {
42086
+ write(x3, y3, text2, options) {
42030
42087
  const { transformers } = options;
42031
- if (!text) {
42088
+ if (!text2) {
42032
42089
  return;
42033
42090
  }
42034
42091
  this.operations.push({
42035
42092
  type: "write",
42036
42093
  x: x3,
42037
42094
  y: y3,
42038
- text,
42095
+ text: text2,
42039
42096
  transformers
42040
42097
  });
42041
42098
  }
@@ -42073,16 +42130,16 @@ class Output {
42073
42130
  clips.pop();
42074
42131
  }
42075
42132
  if (operation.type === "write") {
42076
- const { text, transformers } = operation;
42133
+ const { text: text2, transformers } = operation;
42077
42134
  let { x: x3, y: y3 } = operation;
42078
- let lines = text.split(`
42135
+ let lines = text2.split(`
42079
42136
  `);
42080
42137
  const clip = clips.at(-1);
42081
42138
  if (clip) {
42082
42139
  const clipHorizontally = typeof clip?.x1 === "number" && typeof clip?.x2 === "number";
42083
42140
  const clipVertically = typeof clip?.y1 === "number" && typeof clip?.y2 === "number";
42084
42141
  if (clipHorizontally) {
42085
- const width = widestLine(text);
42142
+ const width = widestLine(text2);
42086
42143
  if (x3 + width < clip.x1 || x3 > clip.x2) {
42087
42144
  continue;
42088
42145
  }
@@ -42189,15 +42246,15 @@ var renderer = (node) => {
42189
42246
  var renderer_default = renderer;
42190
42247
 
42191
42248
  // node_modules/cli-cursor/index.js
42192
- import process6 from "node:process";
42249
+ import process7 from "node:process";
42193
42250
 
42194
42251
  // node_modules/restore-cursor/index.js
42195
42252
  var import_onetime = __toESM(require_onetime(), 1);
42196
42253
  var import_signal_exit = __toESM(require_signal_exit(), 1);
42197
- import process5 from "node:process";
42254
+ import process6 from "node:process";
42198
42255
  var restoreCursor = import_onetime.default(() => {
42199
42256
  import_signal_exit.default(() => {
42200
- process5.stderr.write("\x1B[?25h");
42257
+ process6.stderr.write("\x1B[?25h");
42201
42258
  }, { alwaysLast: true });
42202
42259
  });
42203
42260
  var restore_cursor_default = restoreCursor;
@@ -42205,14 +42262,14 @@ var restore_cursor_default = restoreCursor;
42205
42262
  // node_modules/cli-cursor/index.js
42206
42263
  var isHidden = false;
42207
42264
  var cliCursor = {};
42208
- cliCursor.show = (writableStream = process6.stderr) => {
42265
+ cliCursor.show = (writableStream = process7.stderr) => {
42209
42266
  if (!writableStream.isTTY) {
42210
42267
  return;
42211
42268
  }
42212
42269
  isHidden = false;
42213
42270
  writableStream.write("\x1B[?25h");
42214
42271
  };
42215
- cliCursor.hide = (writableStream = process6.stderr) => {
42272
+ cliCursor.hide = (writableStream = process7.stderr) => {
42216
42273
  if (!writableStream.isTTY) {
42217
42274
  return;
42218
42275
  }
@@ -42277,7 +42334,7 @@ var instances_default = instances;
42277
42334
  // node_modules/ink/build/components/App.js
42278
42335
  var import_react9 = __toESM(require_react(), 1);
42279
42336
  import { EventEmitter as EventEmitter2 } from "node:events";
42280
- import process10 from "node:process";
42337
+ import process11 from "node:process";
42281
42338
 
42282
42339
  // node_modules/ink/build/components/AppContext.js
42283
42340
  var import_react = __toESM(require_react(), 1);
@@ -42290,9 +42347,9 @@ var AppContext_default = AppContext;
42290
42347
  // node_modules/ink/build/components/StdinContext.js
42291
42348
  var import_react2 = __toESM(require_react(), 1);
42292
42349
  import { EventEmitter } from "node:events";
42293
- import process7 from "node:process";
42350
+ import process8 from "node:process";
42294
42351
  var StdinContext = import_react2.createContext({
42295
- stdin: process7.stdin,
42352
+ stdin: process8.stdin,
42296
42353
  internal_eventEmitter: new EventEmitter,
42297
42354
  setRawMode() {},
42298
42355
  isRawModeSupported: false,
@@ -42303,9 +42360,9 @@ var StdinContext_default = StdinContext;
42303
42360
 
42304
42361
  // node_modules/ink/build/components/StdoutContext.js
42305
42362
  var import_react3 = __toESM(require_react(), 1);
42306
- import process8 from "node:process";
42363
+ import process9 from "node:process";
42307
42364
  var StdoutContext = import_react3.createContext({
42308
- stdout: process8.stdout,
42365
+ stdout: process9.stdout,
42309
42366
  write() {}
42310
42367
  });
42311
42368
  StdoutContext.displayName = "InternalStdoutContext";
@@ -42313,9 +42370,9 @@ var StdoutContext_default = StdoutContext;
42313
42370
 
42314
42371
  // node_modules/ink/build/components/StderrContext.js
42315
42372
  var import_react4 = __toESM(require_react(), 1);
42316
- import process9 from "node:process";
42373
+ import process10 from "node:process";
42317
42374
  var StderrContext = import_react4.createContext({
42318
- stderr: process9.stderr,
42375
+ stderr: process10.stderr,
42319
42376
  write() {}
42320
42377
  });
42321
42378
  StderrContext.displayName = "InternalStderrContext";
@@ -42538,7 +42595,7 @@ class App extends import_react9.PureComponent {
42538
42595
  handleSetRawMode = (isEnabled) => {
42539
42596
  const { stdin } = this.props;
42540
42597
  if (!this.isRawModeSupported()) {
42541
- if (stdin === process10.stdin) {
42598
+ if (stdin === process11.stdin) {
42542
42599
  throw new Error(`Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default.
42543
42600
  Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`);
42544
42601
  } else {
@@ -42744,7 +42801,7 @@ class Ink {
42744
42801
  this.fullStaticOutput = "";
42745
42802
  this.container = reconciler_default.createContainer(this.rootNode, 0, null, false, null, "id", () => {}, null);
42746
42803
  this.unsubscribeExit = import_signal_exit2.default(this.unmount, { alwaysLast: false });
42747
- if (process11.env["DEV"] === "true") {
42804
+ if (process12.env["DEV"] === "true") {
42748
42805
  reconciler_default.injectIntoDevTools({
42749
42806
  bundleType: 0,
42750
42807
  version: "16.13.1",
@@ -42910,9 +42967,9 @@ class Ink {
42910
42967
  // node_modules/ink/build/render.js
42911
42968
  var render = (node, options) => {
42912
42969
  const inkOptions = {
42913
- stdout: process12.stdout,
42914
- stdin: process12.stdin,
42915
- stderr: process12.stderr,
42970
+ stdout: process13.stdout,
42971
+ stdin: process13.stdin,
42972
+ stderr: process13.stderr,
42916
42973
  debug: false,
42917
42974
  exitOnCtrlC: true,
42918
42975
  patchConsole: true,
@@ -42935,7 +42992,7 @@ var getOptions = (stdout = {}) => {
42935
42992
  if (stdout instanceof Stream) {
42936
42993
  return {
42937
42994
  stdout,
42938
- stdin: process12.stdin
42995
+ stdin: process13.stdin
42939
42996
  };
42940
42997
  }
42941
42998
  return stdout;
@@ -43224,6 +43281,7 @@ function formatItemLabel(item) {
43224
43281
  return `${fmtType(item.type)} ${import_picocolors7.default.bold(item.slug)} ${fmtScope(item.scope)}${desc}${size2}`;
43225
43282
  }
43226
43283
  async function runPack(cwd2) {
43284
+ requireInteractive("`brainbase template pack` is interactive — it asks which components, name, version and description to include. Run it in a real terminal.");
43227
43285
  banner("pack — bundle your agent into a template");
43228
43286
  const detections = await detectHarnesses(cwd2);
43229
43287
  const detected = detections.filter((d3) => d3.detection.detected);
@@ -43610,10 +43668,10 @@ async function request(pathname, init = {}) {
43610
43668
  } catch (err) {
43611
43669
  throw new ApiError(`Network error: ${err.message}`);
43612
43670
  }
43613
- const text = await res.text();
43614
- let body = text;
43671
+ const text2 = await res.text();
43672
+ let body = text2;
43615
43673
  try {
43616
- body = text ? JSON.parse(text) : null;
43674
+ body = text2 ? JSON.parse(text2) : null;
43617
43675
  } catch {}
43618
43676
  if (!res.ok) {
43619
43677
  const msg = (body && typeof body === "object" && "error" in body ? String(body.error) : null) ?? (body && typeof body === "object" && "message" in body ? String(body.message) : null) ?? `HTTP ${res.status}`;
@@ -43833,10 +43891,10 @@ async function jsonRequest(pathname, init = {}) {
43833
43891
  } catch (err) {
43834
43892
  throw new ApiError(`Network error: ${err.message}`);
43835
43893
  }
43836
- const text = await res.text();
43837
- let body = text;
43894
+ const text2 = await res.text();
43895
+ let body = text2;
43838
43896
  try {
43839
- body = text ? JSON.parse(text) : null;
43897
+ body = text2 ? JSON.parse(text2) : null;
43840
43898
  } catch {}
43841
43899
  if (!res.ok) {
43842
43900
  let code = null;
@@ -43947,10 +44005,10 @@ var registryApi = {
43947
44005
  } catch (err) {
43948
44006
  throw new ApiError(`Network error: ${err.message}`);
43949
44007
  }
43950
- const text = await res.text();
43951
- let body = text;
44008
+ const text2 = await res.text();
44009
+ let body = text2;
43952
44010
  try {
43953
- body = text ? JSON.parse(text) : null;
44011
+ body = text2 ? JSON.parse(text2) : null;
43954
44012
  } catch {}
43955
44013
  if (!res.ok) {
43956
44014
  throw new ApiError(`Publish failed: HTTP ${res.status}`, res.status, body);
@@ -47215,24 +47273,24 @@ var INJECTION_PHRASES = [
47215
47273
  /<\|im_start\|>/i,
47216
47274
  /\bact as (?:a |the )?(?:different|new) (?:assistant|model|system)/i
47217
47275
  ];
47218
- function stripFences(text) {
47219
- return text.replace(/```[\s\S]*?```/g, "").replace(/~~~[\s\S]*?~~~/g, "");
47276
+ function stripFences(text2) {
47277
+ return text2.replace(/```[\s\S]*?```/g, "").replace(/~~~[\s\S]*?~~~/g, "");
47220
47278
  }
47221
- function lineOf(text, index) {
47279
+ function lineOf(text2, index) {
47222
47280
  let line = 1;
47223
- for (let i = 0;i < index && i < text.length; i++) {
47224
- if (text.charCodeAt(i) === 10)
47281
+ for (let i = 0;i < index && i < text2.length; i++) {
47282
+ if (text2.charCodeAt(i) === 10)
47225
47283
  line++;
47226
47284
  }
47227
47285
  return line;
47228
47286
  }
47229
- function scanText(text, opts = {
47287
+ function scanText(text2, opts = {
47230
47288
  kind: "other"
47231
47289
  }) {
47232
47290
  const findings = [];
47233
47291
  const file = opts.relPath;
47234
47292
  const sizeCap = opts.kind === "markdown" ? MAX_MARKDOWN_BYTES : opts.kind === "readme" ? MAX_README_BYTES : Infinity;
47235
- const bytes = Buffer.byteLength(text, "utf8");
47293
+ const bytes = Buffer.byteLength(text2, "utf8");
47236
47294
  if (bytes > sizeCap) {
47237
47295
  findings.push({
47238
47296
  severity: "block",
@@ -47241,8 +47299,8 @@ function scanText(text, opts = {
47241
47299
  file
47242
47300
  });
47243
47301
  }
47244
- for (let i = 0;i < text.length; i++) {
47245
- const cp = text.codePointAt(i);
47302
+ for (let i = 0;i < text2.length; i++) {
47303
+ const cp = text2.codePointAt(i);
47246
47304
  if (cp === undefined)
47247
47305
  continue;
47248
47306
  if (isInvisibleCodepoint(cp)) {
@@ -47251,7 +47309,7 @@ function scanText(text, opts = {
47251
47309
  code: "invisible.codepoint",
47252
47310
  message: `invisible/bidi codepoint U+${cp.toString(16).toUpperCase().padStart(4, "0")} at offset ${i}`,
47253
47311
  file,
47254
- line: lineOf(text, i),
47312
+ line: lineOf(text2, i),
47255
47313
  detail: "Strip zero-width or bidi-control characters before publishing. They are usually a prompt-injection attempt."
47256
47314
  });
47257
47315
  break;
@@ -47262,7 +47320,7 @@ function scanText(text, opts = {
47262
47320
  if (opts.kind !== "markdown" && opts.kind !== "readme") {
47263
47321
  return findings;
47264
47322
  }
47265
- const stripped = stripFences(text);
47323
+ const stripped = stripFences(text2);
47266
47324
  HTML_COMMENT_RE.lastIndex = 0;
47267
47325
  let m3;
47268
47326
  while (m3 = HTML_COMMENT_RE.exec(stripped)) {
@@ -47272,7 +47330,7 @@ function scanText(text, opts = {
47272
47330
  code: "html.comment",
47273
47331
  message: `HTML comment in markdown (${m3[0].length} chars) — readers may not see this content but the model will`,
47274
47332
  file,
47275
- line: lineOf(text, text.indexOf(m3[0]))
47333
+ line: lineOf(text2, text2.indexOf(m3[0]))
47276
47334
  });
47277
47335
  break;
47278
47336
  }
@@ -47284,7 +47342,7 @@ function scanText(text, opts = {
47284
47342
  code: "base64.long",
47285
47343
  message: `long base64-like blob in instructions (${b64[0].length} chars)`,
47286
47344
  file,
47287
- line: lineOf(text, text.indexOf(b64[0])),
47345
+ line: lineOf(text2, text2.indexOf(b64[0])),
47288
47346
  detail: "If this is real content, fence it as a code block so it stops being treated as instruction text."
47289
47347
  });
47290
47348
  }
@@ -47297,7 +47355,7 @@ function scanText(text, opts = {
47297
47355
  code: "injection.phrase",
47298
47356
  message: `instruction-override phrase: "${hit[0].slice(0, 80)}"`,
47299
47357
  file,
47300
- line: lineOf(text, text.indexOf(hit[0])),
47358
+ line: lineOf(text2, text2.indexOf(hit[0])),
47301
47359
  detail: "This phrase is commonly used in prompt-injection attacks. If it is intentional, ignore this warning."
47302
47360
  });
47303
47361
  break;
@@ -47367,9 +47425,9 @@ function scanBundleDir(input) {
47367
47425
  const isText = isMarkdown || lower.endsWith(".txt") || lower.endsWith(".json") || lower.endsWith(".toml") || lower.endsWith(".yaml") || lower.endsWith(".yml");
47368
47426
  if (!isText)
47369
47427
  continue;
47370
- let text;
47428
+ let text2;
47371
47429
  try {
47372
- text = fs24.readFileSync(full, "utf8");
47430
+ text2 = fs24.readFileSync(full, "utf8");
47373
47431
  } catch {
47374
47432
  findings.push({
47375
47433
  severity: "warn",
@@ -47380,7 +47438,7 @@ function scanBundleDir(input) {
47380
47438
  continue;
47381
47439
  }
47382
47440
  const kind = isReadme ? "readme" : isMarkdown ? "markdown" : "other";
47383
- const fileFindings = scanText(text, {
47441
+ const fileFindings = scanText(text2, {
47384
47442
  kind,
47385
47443
  relPath: path28.relative(input.rootDir, full)
47386
47444
  });
@@ -47562,11 +47620,11 @@ function readFileSafe(p2, byteCap = MAX_INSTRUCTION_BYTES) {
47562
47620
  return null;
47563
47621
  }
47564
47622
  }
47565
- function truncateLines(text, max2) {
47566
- const lines = text.split(`
47623
+ function truncateLines(text2, max2) {
47624
+ const lines = text2.split(`
47567
47625
  `);
47568
47626
  if (lines.length <= max2)
47569
- return text;
47627
+ return text2;
47570
47628
  const dropped = lines.length - max2;
47571
47629
  return lines.slice(0, max2).join(`
47572
47630
  `) + `
@@ -47613,13 +47671,13 @@ function buildInstallPreview(input) {
47613
47671
  const p2 = path30.join(input.templateRoot, fname);
47614
47672
  if (!fs26.existsSync(p2))
47615
47673
  continue;
47616
- const text = readFileSafe(p2);
47617
- if (!text || text.trim().length === 0)
47674
+ const text2 = readFileSafe(p2);
47675
+ if (!text2 || text2.trim().length === 0)
47618
47676
  break;
47619
47677
  blocks.push({
47620
47678
  severity: "info",
47621
47679
  title: `${fname} — merged into harness instructions`,
47622
- lines: [truncateLines(text, MAX_INSTRUCTION_LINES)]
47680
+ lines: [truncateLines(text2, MAX_INSTRUCTION_LINES)]
47623
47681
  });
47624
47682
  break;
47625
47683
  }
@@ -47629,13 +47687,13 @@ function buildInstallPreview(input) {
47629
47687
  const file = pickInstructionFile(c2.rootDir);
47630
47688
  if (!file)
47631
47689
  continue;
47632
- const text = readFileSafe(file);
47633
- if (!text || text.trim().length === 0)
47690
+ const text2 = readFileSafe(file);
47691
+ if (!text2 || text2.trim().length === 0)
47634
47692
  continue;
47635
47693
  blocks.push({
47636
47694
  severity: "info",
47637
47695
  title: `instruction ${import_picocolors8.default.bold(c2.slug)} — merged into harness instructions`,
47638
- lines: [truncateLines(text, MAX_INSTRUCTION_LINES)]
47696
+ lines: [truncateLines(text2, MAX_INSTRUCTION_LINES)]
47639
47697
  });
47640
47698
  }
47641
47699
  for (const c2 of input.components) {
@@ -48007,6 +48065,8 @@ function buildTemplateComponents(manifest, rootDir) {
48007
48065
  }
48008
48066
  async function runOnboard(cwd2, args) {
48009
48067
  banner(`onboard — install ${import_picocolors9.default.bold(args.ref)}`);
48068
+ const interactive = isInteractive();
48069
+ const autoYes = args.yes || !interactive;
48010
48070
  const { name, version } = parseTemplateRef(args.ref);
48011
48071
  const registry = new LocalRegistry;
48012
48072
  let templateRef;
@@ -48025,7 +48085,7 @@ async function runOnboard(cwd2, args) {
48025
48085
  const cmp = compareSemver(templateRef.version, prior.version);
48026
48086
  if (cmp === 0) {
48027
48087
  f2.info(`Already installed at ${import_picocolors9.default.bold("@" + prior.version)} (latest version).`);
48028
- if (!args.yes) {
48088
+ if (!autoYes) {
48029
48089
  const again = await se({
48030
48090
  message: "Re-onboard anyway?",
48031
48091
  initialValue: false
@@ -48037,7 +48097,7 @@ async function runOnboard(cwd2, args) {
48037
48097
  }
48038
48098
  } else if (cmp > 0) {
48039
48099
  f2.info(`You have ${import_picocolors9.default.bold("@" + prior.version)}, latest is ${import_picocolors9.default.bold("@" + templateRef.version)}.`);
48040
- if (!args.yes) {
48100
+ if (!autoYes) {
48041
48101
  const upgrade = await se({
48042
48102
  message: "Re-onboard to update?",
48043
48103
  initialValue: true
@@ -48049,7 +48109,7 @@ async function runOnboard(cwd2, args) {
48049
48109
  }
48050
48110
  } else {
48051
48111
  f2.warn(`You have ${import_picocolors9.default.bold("@" + prior.version)}, which is newer than ${import_picocolors9.default.bold("@" + templateRef.version)}.`);
48052
- if (!args.yes) {
48112
+ if (!autoYes) {
48053
48113
  const downgrade = await se({
48054
48114
  message: "Re-onboard with the older version?",
48055
48115
  initialValue: false
@@ -48065,16 +48125,16 @@ async function runOnboard(cwd2, args) {
48065
48125
  const detected = detections.filter((d3) => d3.detection.detected);
48066
48126
  let adapterId = args.harness ?? detected[0]?.adapter.id ?? templateRef.manifest.sourceHarness;
48067
48127
  if (!args.harness && detected.length !== 1) {
48068
- const choice = await ie({
48128
+ adapterId = await select({
48069
48129
  message: "Install into which harness?",
48070
48130
  options: detections.map((d3) => ({
48071
48131
  value: d3.adapter.id,
48072
48132
  label: d3.adapter.displayName,
48073
48133
  hint: d3.detection.detected ? "detected" : "will scaffold"
48074
48134
  })),
48075
- initialValue: adapterId
48135
+ initialValue: adapterId,
48136
+ flagHint: "Pass --harness <id>."
48076
48137
  });
48077
- adapterId = ensureNotCancelled(choice);
48078
48138
  }
48079
48139
  const adapter = getAdapter(adapterId);
48080
48140
  const caps = adapter.capabilities;
@@ -48093,15 +48153,19 @@ async function runOnboard(cwd2, args) {
48093
48153
  }
48094
48154
  let scope = args.scope;
48095
48155
  if (!scope) {
48096
- const choice = await ie({
48097
- message: "Where do you want to install?",
48098
- options: [
48099
- { value: "project", label: `Project (${path31.basename(cwd2)}/.claude)` },
48100
- { value: "global", label: "Global (~/.claude)" }
48101
- ],
48102
- initialValue: "project"
48103
- });
48104
- scope = ensureNotCancelled(choice);
48156
+ if (!interactive) {
48157
+ scope = "project";
48158
+ } else {
48159
+ scope = await select({
48160
+ message: "Where do you want to install?",
48161
+ options: [
48162
+ { value: "project", label: `Project (${path31.basename(cwd2)}/.claude)` },
48163
+ { value: "global", label: "Global (~/.claude)" }
48164
+ ],
48165
+ initialValue: "project",
48166
+ flagHint: "Pass --scope project|global."
48167
+ });
48168
+ }
48105
48169
  }
48106
48170
  const allComponents = buildTemplateComponents(templateRef.manifest, templateRef.rootDir);
48107
48171
  const components = allComponents.map((c2) => ({ ...c2, scope }));
@@ -48130,7 +48194,7 @@ async function runOnboard(cwd2, args) {
48130
48194
  `)).filter((l2) => l2.length > 0)
48131
48195
  }))
48132
48196
  });
48133
- if (!args.yes) {
48197
+ if (!autoYes) {
48134
48198
  const danger = previewHasDanger(previewBlocks);
48135
48199
  const confirmed = await se({
48136
48200
  message: danger ? import_picocolors9.default.red("Dangerous components detected. Proceed?") : "Proceed?",
@@ -48144,8 +48208,8 @@ async function runOnboard(cwd2, args) {
48144
48208
  const opts = {
48145
48209
  cwd: cwd2,
48146
48210
  scope,
48147
- resolveConflict: makeConflictResolver(args.yes),
48148
- resolveSecret: makeSecretResolver(templateRef.manifest, args.yes)
48211
+ resolveConflict: makeConflictResolver(args.yes, interactive),
48212
+ resolveSecret: makeSecretResolver(templateRef.manifest, args.yes, interactive)
48149
48213
  };
48150
48214
  const installSpinner = de();
48151
48215
  installSpinner.start("Installing…");
@@ -48196,10 +48260,15 @@ async function runOnboard(cwd2, args) {
48196
48260
  hint: "brainbase template list"
48197
48261
  });
48198
48262
  }
48199
- function makeConflictResolver(autoYes) {
48200
- if (autoYes) {
48263
+ function makeConflictResolver(yes, interactive = true) {
48264
+ if (yes) {
48201
48265
  return async () => "overwrite";
48202
48266
  }
48267
+ if (!interactive) {
48268
+ return async (item) => {
48269
+ throw new NonInteractiveError(`Conflict for ${item.type} "${item.slug}": a local copy differs from the template. Re-run with --yes to overwrite, or run interactively to choose.`);
48270
+ };
48271
+ }
48203
48272
  return async (item) => {
48204
48273
  const choice = await ie({
48205
48274
  message: `Conflict for ${item.type} "${item.slug}". What do you want to do?`,
@@ -48259,13 +48328,16 @@ async function resolveWithRemoteFallback(registry, name, version) {
48259
48328
  throw err;
48260
48329
  }
48261
48330
  }
48262
- function makeSecretResolver(manifest, autoYes) {
48331
+ function makeSecretResolver(manifest, yes, interactive = true) {
48263
48332
  return async (name, description) => {
48264
48333
  const fromEnv = process.env[name];
48265
48334
  if (fromEnv)
48266
48335
  return fromEnv;
48267
- if (autoYes)
48336
+ if (yes)
48268
48337
  return null;
48338
+ if (!interactive) {
48339
+ throw new NonInteractiveError(`Secret "${name}" is needed — set the ${name} environment variable, re-run with --yes to skip it, or run interactively.`);
48340
+ }
48269
48341
  const declared = manifest.secrets?.find((s3) => s3.name === name);
48270
48342
  const ans = await re({
48271
48343
  message: `Secret needed: ${import_picocolors9.default.bold(name)}${declared?.description ? ` ${import_picocolors9.default.dim("— " + declared.description)}` : description ? ` ${import_picocolors9.default.dim("— " + description)}` : ""}`
@@ -48462,7 +48534,7 @@ async function runRemove(cwd2, args) {
48462
48534
  text: c2.slug
48463
48535
  }))
48464
48536
  });
48465
- if (!args.yes) {
48537
+ if (!autoProceed(args.yes)) {
48466
48538
  const ans = await se({ message: "Proceed?", initialValue: true });
48467
48539
  if (!ensureNotCancelled(ans))
48468
48540
  continue;
@@ -48586,10 +48658,10 @@ var skillsApi = {
48586
48658
  } catch (err) {
48587
48659
  throw new ApiError(`Network error: ${err.message}`);
48588
48660
  }
48589
- const text = await res.text();
48590
- let body = text;
48661
+ const text2 = await res.text();
48662
+ let body = text2;
48591
48663
  try {
48592
- body = text ? JSON.parse(text) : null;
48664
+ body = text2 ? JSON.parse(text2) : null;
48593
48665
  } catch {}
48594
48666
  if (!res.ok) {
48595
48667
  throw new ApiError(`Skill publish failed: HTTP ${res.status}`, res.status, body);
@@ -48894,23 +48966,20 @@ function parseRef(input) {
48894
48966
  }
48895
48967
  async function publishSkillForTemplate(opts) {
48896
48968
  const { entry, bundleRoot, ownerForFallback } = opts;
48897
- const nameAns = await te({
48969
+ const nameAns = await text({
48898
48970
  message: `Publish ${import_picocolors11.default.bold(entry.slug)} as (creator/slug)`,
48899
48971
  placeholder: `gokhan/${entry.slug}`,
48900
- initialValue: `gokhan/${entry.slug}`,
48901
- validate: (v3) => /^[a-z0-9_-]+\/[a-z0-9_-]+$/i.test(v3 ?? "") ? undefined : "Use creator/slug"
48972
+ defaultValue: `gokhan/${entry.slug}`,
48973
+ validate: (v3) => /^[a-z0-9_-]+\/[a-z0-9_-]+$/i.test(v3 ?? "") ? undefined : "Use creator/slug",
48974
+ flagHint: "Run `brainbase skill publish <creator/slug>` interactively, or keep skills inline."
48902
48975
  });
48903
- if (lD(nameAns))
48904
- return false;
48905
48976
  const [creator, pkgSlug] = nameAns.toLowerCase().split("/");
48906
- const verAns = await te({
48977
+ const version = await text({
48907
48978
  message: `Skill version`,
48908
- initialValue: "0.1.0",
48909
- validate: (v3) => /^\d+\.\d+\.\d+$/.test(v3 ?? "") ? undefined : "MAJOR.MINOR.PATCH"
48979
+ defaultValue: "0.1.0",
48980
+ validate: (v3) => /^\d+\.\d+\.\d+$/.test(v3 ?? "") ? undefined : "MAJOR.MINOR.PATCH",
48981
+ flagHint: "Run `brainbase skill publish` interactively to set a version."
48910
48982
  });
48911
- if (lD(verAns))
48912
- return false;
48913
- const version = verAns;
48914
48983
  let probe;
48915
48984
  try {
48916
48985
  probe = await skillsApi.canPublish(creator, pkgSlug);
@@ -49010,14 +49079,14 @@ async function runTemplatePublish(_cwd, args) {
49010
49079
  if (!cur || cur < ref2.version)
49011
49080
  byName.set(ref2.name, ref2.version);
49012
49081
  }
49013
- const choice = await ie({
49082
+ const picked = await select({
49014
49083
  message: "Which template do you want to publish?",
49015
49084
  options: [...byName.entries()].map(([n, v3]) => ({
49016
49085
  value: `${n}@${v3}`,
49017
49086
  label: `${import_picocolors11.default.bold(n)} ${import_picocolors11.default.dim("@" + v3)}`
49018
- }))
49087
+ })),
49088
+ flagHint: "Pass <creator/slug>[@version]."
49019
49089
  });
49020
- const picked = ensureNotCancelled(choice);
49021
49090
  const parsed = parseRef(picked);
49022
49091
  name = parsed.name;
49023
49092
  version = parsed.version;
@@ -49041,7 +49110,7 @@ async function runTemplatePublish(_cwd, args) {
49041
49110
  f2.error("Blocking issues found. Fix them and re-pack before publishing.");
49042
49111
  return;
49043
49112
  }
49044
- if (report.findings.some((f4) => f4.severity === "warn") && !args.yes) {
49113
+ if (report.findings.some((f4) => f4.severity === "warn") && !autoProceed(args.yes)) {
49045
49114
  const proceed = await se({
49046
49115
  message: "Warnings present. Publish anyway?",
49047
49116
  initialValue: false
@@ -49075,24 +49144,25 @@ async function runTemplatePublish(_cwd, args) {
49075
49144
  label: `Team — ${o2.name}`
49076
49145
  }))
49077
49146
  ];
49078
- const ownerChoice = await ie({
49147
+ const ownerChoice = await select({
49079
49148
  message: "Publish under which identity?",
49080
49149
  options: ownerOptions.map((o2, i) => ({ value: String(i), label: o2.label })),
49081
- initialValue: "0"
49150
+ initialValue: "0",
49151
+ flagHint: "Publishing picks an owner — run interactively to choose a team."
49082
49152
  });
49083
- const owner = ownerOptions[Number(ensureNotCancelled(ownerChoice))];
49153
+ const owner = ownerOptions[Number(ownerChoice)];
49084
49154
  let visibility = args.visibility;
49085
49155
  if (!visibility) {
49086
- const vc = await ie({
49156
+ visibility = await select({
49087
49157
  message: "Visibility",
49088
49158
  options: [
49089
49159
  { value: "private", label: "Private — only you / your team can install" },
49090
49160
  { value: "unlisted", label: "Unlisted — anyone with the link can install" },
49091
49161
  { value: "public", label: "Public — listed and searchable (will quarantine for review)" }
49092
49162
  ],
49093
- initialValue: "private"
49163
+ initialValue: "private",
49164
+ flagHint: "Pass --visibility public|unlisted|private."
49094
49165
  });
49095
- visibility = ensureNotCancelled(vc);
49096
49166
  }
49097
49167
  const skillEntries = ref.manifest.components.filter((c2) => c2.type === "skill");
49098
49168
  let manifestMutated = false;
@@ -49102,7 +49172,7 @@ async function runTemplatePublish(_cwd, args) {
49102
49172
  f2.info(`${import_picocolors11.default.dim("skill")} ${import_picocolors11.default.bold(entry.slug)} → ${describeSource(src)} ${import_picocolors11.default.dim("(reference)")}`);
49103
49173
  continue;
49104
49174
  }
49105
- if (args.yes)
49175
+ if (autoProceed(args.yes))
49106
49176
  continue;
49107
49177
  const mode = await ie({
49108
49178
  message: `${import_picocolors11.default.bold(entry.slug)} is locally authored. How should the template reference it?`,
@@ -49153,7 +49223,7 @@ async function runTemplatePublish(_cwd, args) {
49153
49223
  target: registryHost2(),
49154
49224
  scanWarnings: report.findings.filter((f4) => f4.severity === "warn").length
49155
49225
  });
49156
- if (!args.yes) {
49226
+ if (!autoProceed(args.yes)) {
49157
49227
  const ok = await se({ message: "Proceed?", initialValue: true });
49158
49228
  if (!ensureNotCancelled(ok)) {
49159
49229
  $e("Aborted.");
@@ -49683,13 +49753,13 @@ function declaredSkillName(dir) {
49683
49753
  const md = skillMdPath(dir);
49684
49754
  if (!md)
49685
49755
  return null;
49686
- let text;
49756
+ let text2;
49687
49757
  try {
49688
- text = fs32.readFileSync(md, "utf8");
49758
+ text2 = fs32.readFileSync(md, "utf8");
49689
49759
  } catch {
49690
49760
  return null;
49691
49761
  }
49692
- const fm = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text);
49762
+ const fm = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text2);
49693
49763
  if (!fm)
49694
49764
  return null;
49695
49765
  const m3 = /^name:[ \t]*(.+?)[ \t]*$/m.exec(fm[1]);
@@ -49869,34 +49939,32 @@ async function runSkillAdd(cwd2, args) {
49869
49939
  if (detected.length === 1) {
49870
49940
  adapterId = detected[0].adapter.id;
49871
49941
  } else {
49872
- const choice = await ie({
49942
+ adapterId = await select({
49873
49943
  message: "Install into which harness?",
49874
49944
  options: detections.map((d3) => ({
49875
49945
  value: d3.adapter.id,
49876
49946
  label: d3.adapter.displayName,
49877
49947
  hint: d3.detection.detected ? "detected" : "will scaffold"
49878
- }))
49948
+ })),
49949
+ flagHint: "Pass --harness <id> to choose non-interactively."
49879
49950
  });
49880
- adapterId = ensureNotCancelled(choice);
49881
49951
  }
49882
49952
  }
49883
49953
  getAdapter(adapterId);
49884
- let scope = args.scope;
49885
- if (!scope) {
49886
- const choice = await ie({
49887
- message: "Where do you want to install?",
49888
- options: [
49889
- { value: "project", label: `Project (${path37.basename(cwd2)})` },
49890
- { value: "global", label: "Global (~)" }
49891
- ],
49892
- initialValue: "project"
49893
- });
49894
- scope = ensureNotCancelled(choice);
49895
- }
49954
+ const scope = args.scope ?? await select({
49955
+ message: "Where do you want to install?",
49956
+ options: [
49957
+ { value: "project", label: `Project (${path37.basename(cwd2)})` },
49958
+ { value: "global", label: "Global (~)" }
49959
+ ],
49960
+ initialValue: "project",
49961
+ fallback: "project",
49962
+ flagHint: "Pass --scope project|global."
49963
+ });
49896
49964
  const skillsRoot = skillsRootFor(adapterId, cwd2, scope);
49897
49965
  const dest = path37.join(skillsRoot, slug);
49898
49966
  if (exists(dest)) {
49899
- if (!args.yes) {
49967
+ if (!autoProceed(args.yes)) {
49900
49968
  const confirm = await se({
49901
49969
  message: `${import_picocolors13.default.bold(slug)} already exists at ${dest}. Overwrite?`,
49902
49970
  initialValue: false
@@ -50001,16 +50069,17 @@ async function runSkillRemove(cwd2, args) {
50001
50069
  }
50002
50070
  let target = candidates[0];
50003
50071
  if (candidates.length > 1) {
50004
- const choice = await ie({
50072
+ const choice = await select({
50005
50073
  message: "Which one?",
50006
50074
  options: candidates.map((c2, i) => ({
50007
50075
  value: String(i),
50008
50076
  label: `${c2.harness}/${c2.scope} — ${c2.dir}`
50009
- }))
50077
+ })),
50078
+ flagHint: "Pass --harness <id> and/or --scope <s> to disambiguate."
50010
50079
  });
50011
- target = candidates[Number(ensureNotCancelled(choice))];
50080
+ target = candidates[Number(choice)];
50012
50081
  }
50013
- if (!args.yes) {
50082
+ if (!autoProceed(args.yes)) {
50014
50083
  const ok = await se({
50015
50084
  message: `Delete ${import_picocolors15.default.bold(target.dir)}?`,
50016
50085
  initialValue: false
@@ -50065,13 +50134,14 @@ async function runSkillPublish(cwd2, args) {
50065
50134
  f2.error("Non-interactive publish (--yes) requires --name <creator/slug>.");
50066
50135
  return;
50067
50136
  }
50068
- const ans = await te({
50137
+ const ans = await text({
50069
50138
  message: "Publish as (creator/slug)",
50070
50139
  placeholder: `gokhan/${folderSlug}`,
50071
- initialValue: `gokhan/${folderSlug}`,
50072
- validate: (v3) => parseName(v3 ?? "") ? undefined : "Use creator/slug"
50140
+ defaultValue: `gokhan/${folderSlug}`,
50141
+ validate: (v3) => parseName(v3 ?? "") ? undefined : "Use creator/slug",
50142
+ flagHint: "Pass --name creator/slug."
50073
50143
  });
50074
- name = ensureNotCancelled(ans).toLowerCase();
50144
+ name = ans.toLowerCase();
50075
50145
  }
50076
50146
  const { creator, slug: pkgSlug } = parseName(name);
50077
50147
  let version = args.version;
@@ -50084,12 +50154,13 @@ async function runSkillPublish(cwd2, args) {
50084
50154
  f2.error("Non-interactive publish (--yes) requires --skill-version <MAJOR.MINOR.PATCH>.");
50085
50155
  return;
50086
50156
  }
50087
- const ans = await te({
50157
+ const ans = await text({
50088
50158
  message: "Version",
50089
- initialValue: "0.1.0",
50090
- validate: (v3) => /^\d+\.\d+\.\d+$/.test(v3 ?? "") ? undefined : "Must be MAJOR.MINOR.PATCH"
50159
+ defaultValue: "0.1.0",
50160
+ validate: (v3) => /^\d+\.\d+\.\d+$/.test(v3 ?? "") ? undefined : "Must be MAJOR.MINOR.PATCH",
50161
+ flagHint: "Pass --skill-version <x.y.z>."
50091
50162
  });
50092
- version = ensureNotCancelled(ans);
50163
+ version = ans;
50093
50164
  }
50094
50165
  let probe;
50095
50166
  try {
@@ -50122,7 +50193,7 @@ async function runSkillPublish(cwd2, args) {
50122
50193
  return;
50123
50194
  let visibility = args.visibility;
50124
50195
  if (!visibility) {
50125
- if (args.yes) {
50196
+ if (args.yes || !isInteractive()) {
50126
50197
  visibility = "private";
50127
50198
  } else {
50128
50199
  const v3 = await ie({
@@ -50171,7 +50242,7 @@ async function runSkillPublish(cwd2, args) {
50171
50242
  const sha = await sha256OfFile(tar);
50172
50243
  const size2 = fs37.statSync(tar).size;
50173
50244
  buildSp.stop(`Bundle ready (${(size2 / 1024).toFixed(1)} KB).`);
50174
- if (!args.yes) {
50245
+ if (!autoProceed(args.yes)) {
50175
50246
  const ok = await se({
50176
50247
  message: `Publish ${import_picocolors16.default.bold(skillDir)} as ${import_picocolors16.default.bold(creator + "/" + pkgSlug)}@${version}?`,
50177
50248
  initialValue: true
@@ -50260,13 +50331,12 @@ async function pickOwner(userId, email) {
50260
50331
  label: `Team — ${o2.name}`
50261
50332
  }))
50262
50333
  ];
50263
- const choice = await ie({
50334
+ const choice = await select({
50264
50335
  message: "Owner",
50265
50336
  options: opts.map((o2, i) => ({ value: String(i), label: o2.label })),
50266
- initialValue: "0"
50337
+ initialValue: "0",
50338
+ flagHint: "Publishing a NEW package picks an owner — pass --yes to use your personal namespace, or run interactively."
50267
50339
  });
50268
- if (lD(choice))
50269
- return null;
50270
50340
  return opts[Number(choice)] ?? null;
50271
50341
  }
50272
50342
 
@@ -50299,14 +50369,15 @@ async function runSkillUpdate(cwd2, args) {
50299
50369
  }
50300
50370
  let target = candidates[0];
50301
50371
  if (candidates.length > 1) {
50302
- const choice = await ie({
50372
+ const choice = await select({
50303
50373
  message: "Which one?",
50304
50374
  options: candidates.map((c2, i) => ({
50305
50375
  value: String(i),
50306
50376
  label: `${c2.harness}/${c2.scope} — ${c2.dir}`
50307
- }))
50377
+ })),
50378
+ flagHint: "Pass --harness <id> and/or --scope <s> to disambiguate."
50308
50379
  });
50309
- target = candidates[Number(ensureNotCancelled(choice))];
50380
+ target = candidates[Number(choice)];
50310
50381
  }
50311
50382
  const marker = readSkillMarker(target.dir);
50312
50383
  if (!marker) {
@@ -50322,7 +50393,7 @@ async function runSkillUpdate(cwd2, args) {
50322
50393
  f2.error(`No resolver for ${marker.source.type}.`);
50323
50394
  return;
50324
50395
  }
50325
- if (!args.yes) {
50396
+ if (!autoProceed(args.yes)) {
50326
50397
  const ok = await se({
50327
50398
  message: `Re-fetch ${import_picocolors17.default.bold(args.slug)} from ${describeSource(marker.source)}?`,
50328
50399
  initialValue: true
@@ -51462,18 +51533,19 @@ async function runLink(cwd2, args) {
51462
51533
  await handleAlreadyLinked(cwd2, existing, args);
51463
51534
  return;
51464
51535
  }
51465
- const ans = await te({
51536
+ const ans = await text({
51466
51537
  message: "Agent id (UUID)",
51467
51538
  placeholder: "paste from the web app URL",
51468
- validate: (v3) => !v3?.trim() ? "Required" : undefined
51539
+ validate: (v3) => !v3?.trim() ? "Required" : undefined,
51540
+ flagHint: "Pass --agent <id>."
51469
51541
  });
51470
- agentId = ensureNotCancelled(ans).trim();
51542
+ agentId = ans.trim();
51471
51543
  }
51472
51544
  await attachToExistingAgent(cwd2, agentId, args, existing);
51473
51545
  }
51474
51546
  async function handleAlreadyLinked(cwd2, link2, args) {
51475
51547
  f2.info(`This folder is already linked to ${import_picocolors22.default.bold(link2.name)} ${import_picocolors22.default.dim(`(${link2.slug})`)}.`);
51476
- const action = await ie({
51548
+ const next = await select({
51477
51549
  message: "What do you want to do?",
51478
51550
  options: [
51479
51551
  { value: "show", label: "Show details" },
@@ -51481,9 +51553,9 @@ async function handleAlreadyLinked(cwd2, link2, args) {
51481
51553
  { value: "unlink", label: "Unlink this folder" },
51482
51554
  { value: "cancel", label: "Cancel" }
51483
51555
  ],
51484
- initialValue: "show"
51556
+ initialValue: "show",
51557
+ flagHint: "Pass --agent <id> to link non-interactively."
51485
51558
  });
51486
- const next = ensureNotCancelled(action);
51487
51559
  if (next === "cancel") {
51488
51560
  $e("Cancelled.");
51489
51561
  return;
@@ -51493,7 +51565,7 @@ async function handleAlreadyLinked(cwd2, link2, args) {
51493
51565
  return;
51494
51566
  }
51495
51567
  if (next === "unlink") {
51496
- if (!args.yes) {
51568
+ if (!autoProceed(args.yes)) {
51497
51569
  const confirmed = await se({
51498
51570
  message: "Remove the link from this folder? (the cloud agent will stay)",
51499
51571
  initialValue: true
@@ -51508,13 +51580,14 @@ async function handleAlreadyLinked(cwd2, link2, args) {
51508
51580
  $e("Unlinked.");
51509
51581
  return;
51510
51582
  }
51511
- const ans = await te({
51583
+ const ans = await text({
51512
51584
  message: "New agent id (UUID)",
51513
51585
  placeholder: "paste from the web app URL",
51514
- validate: (v3) => !v3?.trim() ? "Required" : undefined
51586
+ validate: (v3) => !v3?.trim() ? "Required" : undefined,
51587
+ flagHint: "Pass --agent <id>."
51515
51588
  });
51516
- const newId = ensureNotCancelled(ans).trim();
51517
- if (!args.yes) {
51589
+ const newId = ans.trim();
51590
+ if (!autoProceed(args.yes)) {
51518
51591
  const confirmed = await se({
51519
51592
  message: "This will replace the current link. Continue?",
51520
51593
  initialValue: false
@@ -51685,7 +51758,7 @@ async function runUnlink(cwd2, args) {
51685
51758
  return;
51686
51759
  }
51687
51760
  f2.info(`Currently linked to ${import_picocolors23.default.bold(link2.name)} ${import_picocolors23.default.dim(`(${link2.slug})`)}.`);
51688
- if (!args.yes) {
51761
+ if (!autoProceed(args.yes)) {
51689
51762
  const ok = await se({
51690
51763
  message: "Remove the link from this folder? (the cloud agent will stay)",
51691
51764
  initialValue: true
@@ -51871,7 +51944,7 @@ async function runSync(cwd2, args) {
51871
51944
  subtitle: `updates for ${link2.name}`,
51872
51945
  rows: resultRows
51873
51946
  });
51874
- if (!args.yes) {
51947
+ if (!autoProceed(args.yes)) {
51875
51948
  const ok = await se({ message: "Apply these changes?", initialValue: true });
51876
51949
  if (!ensureNotCancelled(ok)) {
51877
51950
  $e("Aborted.");
@@ -51882,19 +51955,22 @@ async function runSync(cwd2, args) {
51882
51955
  const detected = detections.filter((d3) => d3.detection.detected);
51883
51956
  let adapterId = args.harness ?? link2.harness ?? link2.tracking?.harness ?? detected[0]?.adapter.id;
51884
51957
  if (!adapterId) {
51885
- const choice = await ie({
51958
+ adapterId = await select({
51886
51959
  message: "Install into which harness?",
51887
51960
  options: detections.map((d3) => ({
51888
51961
  value: d3.adapter.id,
51889
51962
  label: d3.adapter.displayName,
51890
51963
  hint: d3.detection.detected ? "detected" : "will scaffold"
51891
- }))
51964
+ })),
51965
+ flagHint: "Pass --harness <id> to choose non-interactively."
51892
51966
  });
51893
- adapterId = ensureNotCancelled(choice);
51894
51967
  }
51895
51968
  const adapter = getAdapter(adapterId);
51896
51969
  const scope = args.scope ?? "project";
51897
51970
  const keepLocal = new Set;
51971
+ if (diff2.localModified.length > 0) {
51972
+ requireInteractive(`${diff2.localModified.length} component(s) changed both locally and in the cloud — run \`brainbase sync\` in an interactive terminal to resolve them (or revert your local changes).`);
51973
+ }
51898
51974
  for (const c2 of diff2.localModified) {
51899
51975
  const choice = await ie({
51900
51976
  message: `${fmtType(c2.type)} ${import_picocolors24.default.bold(c2.slug)} — your version is different from your team's`,
@@ -51957,7 +52033,7 @@ async function runSync(cwd2, args) {
51957
52033
  }
51958
52034
  if (diff2.deletedUpstream.length > 0) {
51959
52035
  for (const removed of diff2.deletedUpstream) {
51960
- let goAhead = args.yes ?? false;
52036
+ let goAhead = autoProceed(args.yes);
51961
52037
  if (!goAhead) {
51962
52038
  const ans = await se({
51963
52039
  message: `${fmtType(removed.type)} ${import_picocolors24.default.bold(removed.slug)} was removed by your team — remove locally?`,
@@ -52377,9 +52453,9 @@ function secretsPath(cwd2) {
52377
52453
  return path47.join(cwd2, LINK_DIR, SECRETS_FILE);
52378
52454
  }
52379
52455
  var VALID_KEY = /^[A-Z][A-Z0-9_]*$/;
52380
- function parseSecretsEnv(text) {
52456
+ function parseSecretsEnv(text2) {
52381
52457
  const out = {};
52382
- const lines = text.split(/\r?\n/);
52458
+ const lines = text2.split(/\r?\n/);
52383
52459
  for (const raw of lines) {
52384
52460
  const line = raw.replace(/^\s+/, "");
52385
52461
  if (!line || line.startsWith("#"))
@@ -52526,6 +52602,9 @@ async function runAgentPull(cwd2, args) {
52526
52602
  }
52527
52603
  }
52528
52604
  const keepLocalKeys = new Set;
52605
+ if (conflicts.length > 0) {
52606
+ requireInteractive(`${conflicts.length} file(s) changed both locally and in the cloud — resolve them in an interactive terminal, or pass --force to take the cloud copy.`);
52607
+ }
52529
52608
  for (const r2 of conflicts) {
52530
52609
  const choice = await ie({
52531
52610
  message: r2.status === "modified-both" ? `${fmtType(r2.type)} ${import_picocolors25.default.bold(r2.slug)} — both you and the cloud edited it` : `${fmtType(r2.type)} ${import_picocolors25.default.bold(r2.slug)} — you have local edits not yet pushed`,
@@ -52585,7 +52664,7 @@ async function runAgentPull(cwd2, args) {
52585
52664
  subtitle: `updates for ${cloudAgent.name}`,
52586
52665
  rows: resultRows
52587
52666
  });
52588
- if (!args.yes) {
52667
+ if (!autoProceed(args.yes)) {
52589
52668
  const msg = override ? "Apply these changes? Local edits to overlapping components will be discarded." : "Apply these changes?";
52590
52669
  const ok = await se({ message: msg, initialValue: true });
52591
52670
  if (!ensureNotCancelled(ok)) {
@@ -53377,7 +53456,7 @@ async function runAgentPush(cwd2, args) {
53377
53456
  subtitle: `${manifest.agent.name} ← local`,
53378
53457
  rows: resultRows
53379
53458
  });
53380
- if (!args.yes) {
53459
+ if (!autoProceed(args.yes)) {
53381
53460
  const ok = await se({ message: "Send these changes?", initialValue: true });
53382
53461
  if (!ensureNotCancelled(ok)) {
53383
53462
  $e("Aborted.");
@@ -53715,8 +53794,8 @@ function divider(label, width = 56, indent = 2) {
53715
53794
  const right = import_picocolors29.default.dim(H3.repeat(Math.max(0, width - labelLen - 2)));
53716
53795
  return `${ind}${left}${import_picocolors29.default.bold(import_picocolors29.default.dim(labelText))}${right}`;
53717
53796
  }
53718
- function tip(text, indent = 2) {
53719
- return " ".repeat(indent) + import_picocolors29.default.dim("›") + " " + import_picocolors29.default.dim(text);
53797
+ function tip(text2, indent = 2) {
53798
+ return " ".repeat(indent) + import_picocolors29.default.dim("›") + " " + import_picocolors29.default.dim(text2);
53720
53799
  }
53721
53800
 
53722
53801
  // src/cli/agent-create.ts
@@ -53758,11 +53837,11 @@ async function runAgentCreate(cwd2, args) {
53758
53837
  org = orgs[0];
53759
53838
  f2.info(`Using organization ${import_picocolors30.default.bold(org.name)}.`);
53760
53839
  } else {
53761
- const orgChoice = await ie({
53840
+ const orgId = await select({
53762
53841
  message: "Pick an organization",
53763
- options: orgs.map((o2) => ({ value: o2.id, label: o2.name, hint: o2.role }))
53842
+ options: orgs.map((o2) => ({ value: o2.id, label: o2.name, hint: o2.role })),
53843
+ flagHint: "Pass --org <id> to choose non-interactively."
53764
53844
  });
53765
- const orgId = ensureNotCancelled(orgChoice);
53766
53845
  org = orgs.find((o2) => o2.id === orgId);
53767
53846
  }
53768
53847
  const teamsSpinner = de();
@@ -53784,6 +53863,15 @@ async function runAgentCreate(cwd2, args) {
53784
53863
  return;
53785
53864
  }
53786
53865
  team = found;
53866
+ } else if (!isInteractive()) {
53867
+ if (teams.length === 1) {
53868
+ team = teams[0];
53869
+ f2.info(`Using team ${import_picocolors30.default.bold(team.name)}.`);
53870
+ } else if (teams.length === 0) {
53871
+ throw new NonInteractiveError(`No teams in ${org.name} yet — create one in the web app, then re-run.`);
53872
+ } else {
53873
+ throw new NonInteractiveError(`Multiple teams in ${org.name}. Pass --team <id> to choose non-interactively.`);
53874
+ }
53787
53875
  } else {
53788
53876
  const teamOptions = [
53789
53877
  ...teams.map((t) => ({ value: t.id, label: t.name, hint: t.role })),
@@ -53817,15 +53905,15 @@ async function runAgentCreate(cwd2, args) {
53817
53905
  const harness = normalizeHarnessId(args.harness ?? manifest.harness ?? await pickHarness(cwd2));
53818
53906
  let agentName = args.name?.trim() || manifest.agent.name.trim();
53819
53907
  if (!agentName) {
53820
- const ans = await te({
53908
+ agentName = (await text({
53821
53909
  message: "Agent name",
53822
53910
  placeholder: "e.g. Customer Support Bot",
53823
- validate: (v3) => !v3?.trim() ? "Required" : undefined
53824
- });
53825
- agentName = ensureNotCancelled(ans).trim();
53911
+ validate: (v3) => !v3?.trim() ? "Required" : undefined,
53912
+ flagHint: "Pass --name <name>."
53913
+ })).trim();
53826
53914
  }
53827
53915
  let tagline = (args.tagline ?? manifest.agent.tagline)?.trim() || undefined;
53828
- if (tagline === undefined && !args.yes) {
53916
+ if (tagline === undefined && !autoProceed(args.yes)) {
53829
53917
  const ans = await te({
53830
53918
  message: "Tagline",
53831
53919
  placeholder: "optional one-line description"
@@ -53834,7 +53922,7 @@ async function runAgentCreate(cwd2, args) {
53834
53922
  if (typeof raw === "string" && raw.trim())
53835
53923
  tagline = raw.trim();
53836
53924
  }
53837
- if (!args.yes) {
53925
+ if (!autoProceed(args.yes)) {
53838
53926
  le([
53839
53927
  `${import_picocolors30.default.dim("org")} ${import_picocolors30.default.bold(org.name)}`,
53840
53928
  `${import_picocolors30.default.dim("team")} ${import_picocolors30.default.bold(team.name)}`,
@@ -53884,8 +53972,15 @@ async function runAgentCreate(cwd2, args) {
53884
53972
  let tracking;
53885
53973
  const adapter = getRouteAdapter(harness);
53886
53974
  if (adapter && !args.noTracking) {
53887
- let wantsTracking = true;
53888
- if (!args.yes) {
53975
+ let wantsTracking;
53976
+ if (args.track) {
53977
+ wantsTracking = true;
53978
+ } else if (!isInteractive()) {
53979
+ wantsTracking = false;
53980
+ f2.info(`Tracking left off (non-interactive). Re-run with ${import_picocolors30.default.cyan("--track")} to route ${harness} LLM traffic through brainbase.`);
53981
+ } else if (args.yes) {
53982
+ wantsTracking = true;
53983
+ } else {
53889
53984
  const ans = await se({
53890
53985
  message: `Track ${harness} conversations on the brainbase platform? ${import_picocolors30.default.dim("(routes LLM calls through brainbase so they appear under this agent)")}`,
53891
53986
  initialValue: true
@@ -54022,6 +54117,9 @@ async function loadOrScaffoldManifest(cwd2, args) {
54022
54117
  }
54023
54118
  f2.warn(`No ${import_picocolors30.default.bold(AGENT_MANIFEST_FILE)} here.`);
54024
54119
  if (!args.yes) {
54120
+ if (!isInteractive()) {
54121
+ throw new NonInteractiveError(`No ${AGENT_MANIFEST_FILE} here. Create one first, or re-run with --yes to scaffold a minimal one.`);
54122
+ }
54025
54123
  const ans = await se({
54026
54124
  message: `Scaffold a minimal ${import_picocolors30.default.bold(AGENT_MANIFEST_FILE)} and continue?`,
54027
54125
  initialValue: true
@@ -54057,15 +54155,15 @@ async function pickHarness(cwd2) {
54057
54155
  f2.info(`Detected harness: ${import_picocolors30.default.bold(detected[0].adapter.displayName)}.`);
54058
54156
  return detected[0].adapter.id;
54059
54157
  }
54060
- const choice = await ie({
54158
+ return await select({
54061
54159
  message: detected.length > 1 ? "Multiple harnesses detected — which one is this agent for?" : "No harness detected here. Which harness is this agent for?",
54062
54160
  options: detections.map((d3) => ({
54063
54161
  value: d3.adapter.id,
54064
54162
  label: d3.adapter.displayName,
54065
54163
  hint: d3.detection.detected ? "detected" : undefined
54066
- }))
54164
+ })),
54165
+ flagHint: "Pass --harness <claude-code|codex|kafka>."
54067
54166
  });
54068
- return ensureNotCancelled(choice);
54069
54167
  }
54070
54168
  function handleApiError4(err) {
54071
54169
  if (err instanceof ApiError) {
@@ -54116,7 +54214,7 @@ async function runAgentUnpack(cwd2, args) {
54116
54214
  } else {
54117
54215
  harness = await pickHarness2(manifest.harness);
54118
54216
  }
54119
- if (!args.yes) {
54217
+ if (!autoProceed(args.yes)) {
54120
54218
  const ok = await se({
54121
54219
  message: `Install ${import_picocolors31.default.bold(manifest.agent.name)} as ${import_picocolors31.default.bold(harness)} here?`,
54122
54220
  initialValue: true
@@ -54328,16 +54426,16 @@ function runHarnessInstall3(harnessId, components, opts, agentName) {
54328
54426
  }
54329
54427
  async function pickHarness2(current) {
54330
54428
  const initial2 = current ? normalizeHarnessId(current) : undefined;
54331
- const choice = await ie({
54429
+ return select({
54332
54430
  message: "Pick a harness to install as",
54333
54431
  options: adapters.map((a3) => ({
54334
54432
  value: a3.id,
54335
54433
  label: a3.displayName,
54336
54434
  hint: a3.id === initial2 ? "current" : undefined
54337
54435
  })),
54338
- initialValue: initial2 ?? adapters[0].id
54436
+ initialValue: initial2 ?? adapters[0].id,
54437
+ flagHint: "Pass --harness <id> to choose non-interactively."
54339
54438
  });
54340
- return ensureNotCancelled(choice);
54341
54439
  }
54342
54440
 
54343
54441
  // src/cli/agent.ts
@@ -54351,7 +54449,8 @@ async function runAgent(cwd2, sub, args, opts) {
54351
54449
  tagline: opts.tagline,
54352
54450
  orgId: opts.orgId,
54353
54451
  teamId: opts.teamId,
54354
- noTracking: opts.noTracking
54452
+ noTracking: opts.noTracking,
54453
+ track: opts.track
54355
54454
  });
54356
54455
  return;
54357
54456
  case "pull":
@@ -54478,6 +54577,33 @@ function writeOrchManifest(cwd2, manifest) {
54478
54577
  function memberDir(cwd2, slug) {
54479
54578
  return path51.join(cwd2, ORCH_MEMBERS_DIR, slug);
54480
54579
  }
54580
+ var MEMBER_SLUG_MAX = 50;
54581
+ function slugifyRaw(raw) {
54582
+ return (raw || "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
54583
+ }
54584
+ function resolveMemberSlugs(members) {
54585
+ const SAFE = /^[a-z0-9][a-z0-9-]*$/;
54586
+ const used = new Set;
54587
+ const byAgent = new Map;
54588
+ for (const m3 of members) {
54589
+ const raw = (m3.slug ?? "").trim();
54590
+ let base2 = raw && SAFE.test(raw) ? raw : slugifyRaw(raw) || slugifyRaw(m3.name ?? "") || "agent";
54591
+ if (base2.length > MEMBER_SLUG_MAX) {
54592
+ base2 = base2.slice(0, MEMBER_SLUG_MAX).replace(/-+$/, "") || base2.slice(0, MEMBER_SLUG_MAX);
54593
+ }
54594
+ let slug = base2;
54595
+ if (used.has(slug)) {
54596
+ const suffix = (m3.agent_id || "").split("-")[0] || "x";
54597
+ slug = `${base2}-${suffix}`;
54598
+ let n = 2;
54599
+ while (used.has(slug))
54600
+ slug = `${base2}-${suffix}-${n++}`;
54601
+ }
54602
+ used.add(slug);
54603
+ byAgent.set(m3.agent_id, slug);
54604
+ }
54605
+ return byAgent;
54606
+ }
54481
54607
 
54482
54608
  // src/core/orchestration-link.ts
54483
54609
  import path52 from "node:path";
@@ -54774,6 +54900,8 @@ async function runOrchestrationPull(cwd2, args) {
54774
54900
  handleApiError5(err);
54775
54901
  return;
54776
54902
  }
54903
+ const slugByAgent = resolveMemberSlugs(cloud.members);
54904
+ const slugFor = (agentId) => slugByAgent.get(agentId) ?? agentId;
54777
54905
  const planLines = [];
54778
54906
  planLines.push("");
54779
54907
  planLines.push(` ${import_picocolors33.default.bold(cloud.name)} ${import_picocolors33.default.dim(`(${cloud.id})`)}`);
@@ -54784,14 +54912,14 @@ async function runOrchestrationPull(cwd2, args) {
54784
54912
  for (const m3 of cloud.members) {
54785
54913
  const skipped = !m3.manifest;
54786
54914
  const tail2 = skipped ? import_picocolors33.default.red(" (manifest unavailable — skipped)") : "";
54787
- planLines.push(` ${import_picocolors33.default.cyan("•")} ${import_picocolors33.default.bold(m3.slug)} ${import_picocolors33.default.dim(`(${m3.name})`)}${tail2}`);
54915
+ planLines.push(` ${import_picocolors33.default.cyan("•")} ${import_picocolors33.default.bold(slugFor(m3.agent_id))} ${import_picocolors33.default.dim(`(${m3.name})`)}${tail2}`);
54788
54916
  }
54789
54917
  if (cloud.edges.length) {
54790
54918
  planLines.push("");
54791
54919
  planLines.push(` ${import_picocolors33.default.dim("edges:")}`);
54792
54920
  for (const e2 of cloud.edges) {
54793
- const from = e2.from_slug ?? e2.from_agent_id;
54794
- const to2 = e2.to_slug ?? e2.to_agent_id;
54921
+ const from = slugFor(e2.from_agent_id);
54922
+ const to2 = slugFor(e2.to_agent_id);
54795
54923
  const desc = e2.description ? ` ${import_picocolors33.default.dim("— " + e2.description)}` : "";
54796
54924
  planLines.push(` ${import_picocolors33.default.cyan(from)} ${import_picocolors33.default.dim("→")} ${import_picocolors33.default.cyan(to2)}${desc}`);
54797
54925
  }
@@ -54800,7 +54928,7 @@ async function runOrchestrationPull(cwd2, args) {
54800
54928
  console.log(planLines.join(`
54801
54929
  `));
54802
54930
  const isRefresh = !!existingLink;
54803
- if (!args.yes && !isRefresh) {
54931
+ if (!autoProceed(args.yes) && !isRefresh) {
54804
54932
  const ok = await se({
54805
54933
  message: `Pull into ${import_picocolors33.default.bold(cwd2)}?`,
54806
54934
  initialValue: true
@@ -54822,16 +54950,17 @@ async function runOrchestrationPull(cwd2, args) {
54822
54950
  f2.warn(`Skipping member ${m3.slug}: server did not return a manifest.`);
54823
54951
  continue;
54824
54952
  }
54825
- const dest = memberDir(cwd2, m3.slug);
54953
+ const slug = slugFor(m3.agent_id);
54954
+ const dest = memberDir(cwd2, slug);
54826
54955
  const memberSp = de();
54827
- memberSp.start(`Installing ${m3.slug}…`);
54956
+ memberSp.start(`Installing ${slug}…`);
54828
54957
  try {
54829
54958
  await installAgentFresh({
54830
54959
  cwd: dest,
54831
54960
  agent: {
54832
54961
  id: m3.agent_id,
54833
- name: m3.name || m3.slug,
54834
- slug: m3.slug,
54962
+ name: m3.name || slug,
54963
+ slug,
54835
54964
  tagline: undefined,
54836
54965
  org_id: cloud.group_id,
54837
54966
  team_id: cloud.group_id,
@@ -54843,14 +54972,14 @@ async function runOrchestrationPull(cwd2, args) {
54843
54972
  scope: "project",
54844
54973
  pullSecrets: true
54845
54974
  });
54846
- memberSp.stop(`Installed ${import_picocolors33.default.bold(m3.slug)} ${import_picocolors33.default.dim(`(${m3.manifest.components.length} components)`)}.`);
54975
+ memberSp.stop(`Installed ${import_picocolors33.default.bold(slug)} ${import_picocolors33.default.dim(`(${m3.manifest.components.length} components)`)}.`);
54847
54976
  installedMembers.push({
54848
54977
  agent_id: m3.agent_id,
54849
- slug: m3.slug,
54978
+ slug,
54850
54979
  revision: m3.manifest.revision
54851
54980
  });
54852
54981
  } catch (err) {
54853
- memberSp.stop(`Failed to install ${m3.slug}.`);
54982
+ memberSp.stop(`Failed to install ${slug}.`);
54854
54983
  f2.error(err.message);
54855
54984
  }
54856
54985
  }
@@ -54863,13 +54992,16 @@ async function runOrchestrationPull(cwd2, args) {
54863
54992
  ...cloud.icon_color ? { icon_color: cloud.icon_color } : {},
54864
54993
  ...cloud.credit_limit != null ? { credit_limit: cloud.credit_limit } : {}
54865
54994
  },
54866
- members: cloud.members.map((m3) => ({
54867
- slug: m3.slug,
54868
- ...m3.name && m3.name !== m3.slug ? { name: m3.name } : {}
54869
- })),
54995
+ members: cloud.members.map((m3) => {
54996
+ const slug = slugFor(m3.agent_id);
54997
+ return {
54998
+ slug,
54999
+ ...m3.name && m3.name !== slug ? { name: m3.name } : {}
55000
+ };
55001
+ }),
54870
55002
  edges: cloud.edges.map((e2) => ({
54871
- from: e2.from_slug ?? e2.from_agent_id,
54872
- to: e2.to_slug ?? e2.to_agent_id,
55003
+ from: slugFor(e2.from_agent_id),
55004
+ to: slugFor(e2.to_agent_id),
54873
55005
  ...e2.description ? { description: e2.description } : {},
54874
55006
  ...e2.payload_schema && Object.keys(e2.payload_schema).length ? { payload_schema: e2.payload_schema } : {}
54875
55007
  }))
@@ -54892,8 +55024,8 @@ async function runOrchestrationPull(cwd2, args) {
54892
55024
  synced_at: new Date().toISOString(),
54893
55025
  members: installedMembers,
54894
55026
  edges: cloud.edges.map((e2) => ({
54895
- from_slug: e2.from_slug ?? e2.from_agent_id,
54896
- to_slug: e2.to_slug ?? e2.to_agent_id,
55027
+ from_slug: slugFor(e2.from_agent_id),
55028
+ to_slug: slugFor(e2.to_agent_id),
54897
55029
  description: e2.description ?? "",
54898
55030
  payload_schema: e2.payload_schema ?? {}
54899
55031
  }))
@@ -54963,7 +55095,7 @@ async function runOrchestrationPush(cwd2, args) {
54963
55095
  slugToAgentId.set(m3.slug, memberLink.agent_id);
54964
55096
  }
54965
55097
  if (missing.length) {
54966
- f2.error(`These members have no local checkout (expected at agents/<slug>/.brainbase/link.json): ${missing.join(", ")}.`);
55098
+ f2.error(`These members have no local checkout (expected at agents/<slug>/brainbase.agent.yaml): ${missing.join(", ")}.`);
54967
55099
  f2.info(`Run ${import_picocolors34.default.cyan("brainbase orchestration pull")} to materialise the missing folders.`);
54968
55100
  return;
54969
55101
  }
@@ -54980,7 +55112,7 @@ async function runOrchestrationPush(cwd2, args) {
54980
55112
  }
54981
55113
  console.log(plan.join(`
54982
55114
  `));
54983
- if (!args.yes) {
55115
+ if (!autoProceed(args.yes)) {
54984
55116
  const ok = await se({
54985
55117
  message: args.graphOnly ? "Push graph (members + edges) only?" : "Push each member, then update the graph?",
54986
55118
  initialValue: true
@@ -55189,11 +55321,11 @@ async function runOrchestrationList(args) {
55189
55321
  if (orgs.length === 1) {
55190
55322
  orgId = orgs[0].id;
55191
55323
  } else {
55192
- const choice = await ie({
55324
+ orgId = await select({
55193
55325
  message: "Which organization?",
55194
- options: orgs.map((o2) => ({ value: o2.id, label: o2.name }))
55326
+ options: orgs.map((o2) => ({ value: o2.id, label: o2.name })),
55327
+ flagHint: "Pass --org <id>."
55195
55328
  });
55196
- orgId = ensureNotCancelled(choice);
55197
55329
  }
55198
55330
  }
55199
55331
  if (!teamId) {
@@ -55211,11 +55343,11 @@ async function runOrchestrationList(args) {
55211
55343
  if (teams.length === 1) {
55212
55344
  teamId = teams[0].id;
55213
55345
  } else {
55214
- const choice = await ie({
55346
+ teamId = await select({
55215
55347
  message: "Which team?",
55216
- options: teams.map((t) => ({ value: t.id, label: t.name }))
55348
+ options: teams.map((t) => ({ value: t.id, label: t.name })),
55349
+ flagHint: "Pass --team <id>."
55217
55350
  });
55218
- teamId = ensureNotCancelled(choice);
55219
55351
  }
55220
55352
  }
55221
55353
  let items;
@@ -55906,12 +56038,12 @@ async function runTokenCreate(args) {
55906
56038
  banner("token create — make a long-lived CLI key");
55907
56039
  let name = args.name;
55908
56040
  if (!name) {
55909
- const ans = await te({
56041
+ name = await text({
55910
56042
  message: "Token label",
55911
56043
  placeholder: "my-laptop or ci-runner",
55912
- validate: (v3) => v3.length === 0 ? "Required." : undefined
56044
+ validate: (v3) => v3.length === 0 ? "Required." : undefined,
56045
+ flagHint: "Pass --name <label>."
55913
56046
  });
55914
- name = ensureNotCancelled(ans);
55915
56047
  }
55916
56048
  const scopes = args.scopes && args.scopes.length > 0 ? args.scopes : DEFAULT_SCOPES;
55917
56049
  const spinner = de();
@@ -55953,7 +56085,7 @@ async function runTokenRevoke(args) {
55953
56085
  console.error("Usage: brainbase token revoke <id>");
55954
56086
  process.exit(1);
55955
56087
  }
55956
- if (!args.yes) {
56088
+ if (!autoProceed(args.yes)) {
55957
56089
  const ok = await se({
55958
56090
  message: `Revoke token ${import_picocolors39.default.bold(args.id)}? CIs and machines using it will stop working.`,
55959
56091
  initialValue: false
@@ -56117,6 +56249,7 @@ function help() {
56117
56249
  out.push(` ${import_picocolors40.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
56118
56250
  out.push(` ${import_picocolors40.default.dim("--agent <id>")} for link: attach this folder to an existing agent non-interactively`);
56119
56251
  out.push(` ${import_picocolors40.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
56252
+ out.push(` ${import_picocolors40.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
56120
56253
  out.push(` ${import_picocolors40.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
56121
56254
  out.push(` ${import_picocolors40.default.dim("--all")} for template list: include installs from other folders`);
56122
56255
  out.push(` ${import_picocolors40.default.dim("--web <url>")} for login: web app URL (default https://new.usekafka.com)`);
@@ -56129,6 +56262,7 @@ function help() {
56129
56262
  out.push(` ${import_picocolors40.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL`);
56130
56263
  out.push(` ${import_picocolors40.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
56131
56264
  out.push(` ${import_picocolors40.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
56265
+ out.push(` ${import_picocolors40.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
56132
56266
  out.push("");
56133
56267
  out.push(divider("HARNESSES"));
56134
56268
  out.push("");
@@ -56163,9 +56297,9 @@ function hasFlag2(args, ...names) {
56163
56297
  async function requireAuth(cmd) {
56164
56298
  if (!PROTECTED.has(cmd))
56165
56299
  return;
56166
- if (process13.env.BRAINBASE_SKIP_AUTH === "1")
56300
+ if (process14.env.BRAINBASE_SKIP_AUTH === "1")
56167
56301
  return;
56168
- const envToken = process13.env.BRAINBASE_TOKEN;
56302
+ const envToken = process14.env.BRAINBASE_TOKEN;
56169
56303
  if (envToken && envToken.trim())
56170
56304
  return;
56171
56305
  let status = authStatus();
@@ -56186,12 +56320,12 @@ async function requireAuth(cmd) {
56186
56320
  console.error("");
56187
56321
  console.error(` Run ${import_picocolors40.default.cyan("brainbase login")} to connect this device.`);
56188
56322
  console.error("");
56189
- process13.exit(1);
56323
+ process14.exit(1);
56190
56324
  }
56191
56325
  async function main() {
56192
- const argv = process13.argv.slice(2);
56326
+ const argv = process14.argv.slice(2);
56193
56327
  const cmd = argv.shift();
56194
- const rawCwd = process13.cwd();
56328
+ const rawCwd = process14.cwd();
56195
56329
  const cwd2 = (() => {
56196
56330
  try {
56197
56331
  return fs51.realpathSync(rawCwd);
@@ -56221,6 +56355,7 @@ async function main() {
56221
56355
  const agentFlag = getFlag(argv, "--agent");
56222
56356
  const shellFlag = getFlag(argv, "--shell");
56223
56357
  const noTracking = hasFlag2(argv, "--no-tracking");
56358
+ const track = hasFlag2(argv, "--track");
56224
56359
  const forceFlag = hasFlag2(argv, "--force");
56225
56360
  const graphOnlyFlag = hasFlag2(argv, "--graph-only");
56226
56361
  const nameFlag = getFlag(argv, "--name");
@@ -56307,6 +56442,7 @@ async function main() {
56307
56442
  orgId: orgIdFlag,
56308
56443
  teamId: teamIdFlag,
56309
56444
  noTracking,
56445
+ track,
56310
56446
  force: forceFlag
56311
56447
  });
56312
56448
  break;
@@ -56335,14 +56471,14 @@ async function main() {
56335
56471
  console.error(`Unknown command: ${cmd}
56336
56472
  `);
56337
56473
  help();
56338
- process13.exit(1);
56474
+ process14.exit(1);
56339
56475
  }
56340
56476
  } catch (err) {
56341
56477
  console.error(import_picocolors40.default.red(`
56342
56478
  ${err.message}`));
56343
- if (process13.env.BRAINBASE_DEBUG)
56479
+ if (process14.env.BRAINBASE_DEBUG)
56344
56480
  console.error(err.stack);
56345
- process13.exit(1);
56481
+ process14.exit(1);
56346
56482
  }
56347
56483
  }
56348
56484
  main();