@kimbho/kimbho-cli 0.1.32 → 0.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1147,9 +1147,9 @@ var require_command = __commonJS({
1147
1147
  "../../node_modules/commander/lib/command.js"(exports2) {
1148
1148
  var EventEmitter = require("node:events").EventEmitter;
1149
1149
  var childProcess = require("node:child_process");
1150
- var path34 = require("node:path");
1150
+ var path35 = require("node:path");
1151
1151
  var fs = require("node:fs");
1152
- var process37 = require("node:process");
1152
+ var process38 = require("node:process");
1153
1153
  var { Argument: Argument2, humanReadableArgName } = require_argument();
1154
1154
  var { CommanderError: CommanderError2 } = require_error();
1155
1155
  var { Help: Help2, stripColor } = require_help();
@@ -1196,13 +1196,13 @@ var require_command = __commonJS({
1196
1196
  this._showSuggestionAfterError = true;
1197
1197
  this._savedState = null;
1198
1198
  this._outputConfiguration = {
1199
- writeOut: (str) => process37.stdout.write(str),
1200
- writeErr: (str) => process37.stderr.write(str),
1199
+ writeOut: (str) => process38.stdout.write(str),
1200
+ writeErr: (str) => process38.stderr.write(str),
1201
1201
  outputError: (str, write) => write(str),
1202
- getOutHelpWidth: () => process37.stdout.isTTY ? process37.stdout.columns : void 0,
1203
- getErrHelpWidth: () => process37.stderr.isTTY ? process37.stderr.columns : void 0,
1204
- getOutHasColors: () => useColor() ?? (process37.stdout.isTTY && process37.stdout.hasColors?.()),
1205
- getErrHasColors: () => useColor() ?? (process37.stderr.isTTY && process37.stderr.hasColors?.()),
1202
+ getOutHelpWidth: () => process38.stdout.isTTY ? process38.stdout.columns : void 0,
1203
+ getErrHelpWidth: () => process38.stderr.isTTY ? process38.stderr.columns : void 0,
1204
+ getOutHasColors: () => useColor() ?? (process38.stdout.isTTY && process38.stdout.hasColors?.()),
1205
+ getErrHasColors: () => useColor() ?? (process38.stderr.isTTY && process38.stderr.hasColors?.()),
1206
1206
  stripColor: (str) => stripColor(str)
1207
1207
  };
1208
1208
  this._hidden = false;
@@ -1585,7 +1585,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1585
1585
  if (this._exitCallback) {
1586
1586
  this._exitCallback(new CommanderError2(exitCode, code, message));
1587
1587
  }
1588
- process37.exit(exitCode);
1588
+ process38.exit(exitCode);
1589
1589
  }
1590
1590
  /**
1591
1591
  * Register callback `fn` for the command.
@@ -1983,16 +1983,16 @@ Expecting one of '${allowedValues.join("', '")}'`);
1983
1983
  }
1984
1984
  parseOptions = parseOptions || {};
1985
1985
  if (argv === void 0 && parseOptions.from === void 0) {
1986
- if (process37.versions?.electron) {
1986
+ if (process38.versions?.electron) {
1987
1987
  parseOptions.from = "electron";
1988
1988
  }
1989
- const execArgv = process37.execArgv ?? [];
1989
+ const execArgv = process38.execArgv ?? [];
1990
1990
  if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
1991
1991
  parseOptions.from = "eval";
1992
1992
  }
1993
1993
  }
1994
1994
  if (argv === void 0) {
1995
- argv = process37.argv;
1995
+ argv = process38.argv;
1996
1996
  }
1997
1997
  this.rawArgs = argv.slice();
1998
1998
  let userArgs;
@@ -2003,7 +2003,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2003
2003
  userArgs = argv.slice(2);
2004
2004
  break;
2005
2005
  case "electron":
2006
- if (process37.defaultApp) {
2006
+ if (process38.defaultApp) {
2007
2007
  this._scriptPath = argv[1];
2008
2008
  userArgs = argv.slice(2);
2009
2009
  } else {
@@ -2147,9 +2147,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2147
2147
  let launchWithNode = false;
2148
2148
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
2149
2149
  function findFile(baseDir, baseName) {
2150
- const localBin = path34.resolve(baseDir, baseName);
2150
+ const localBin = path35.resolve(baseDir, baseName);
2151
2151
  if (fs.existsSync(localBin)) return localBin;
2152
- if (sourceExt.includes(path34.extname(baseName))) return void 0;
2152
+ if (sourceExt.includes(path35.extname(baseName))) return void 0;
2153
2153
  const foundExt = sourceExt.find(
2154
2154
  (ext) => fs.existsSync(`${localBin}${ext}`)
2155
2155
  );
@@ -2167,17 +2167,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
2167
2167
  } catch {
2168
2168
  resolvedScriptPath = this._scriptPath;
2169
2169
  }
2170
- executableDir = path34.resolve(
2171
- path34.dirname(resolvedScriptPath),
2170
+ executableDir = path35.resolve(
2171
+ path35.dirname(resolvedScriptPath),
2172
2172
  executableDir
2173
2173
  );
2174
2174
  }
2175
2175
  if (executableDir) {
2176
2176
  let localFile = findFile(executableDir, executableFile);
2177
2177
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
2178
- const legacyName = path34.basename(
2178
+ const legacyName = path35.basename(
2179
2179
  this._scriptPath,
2180
- path34.extname(this._scriptPath)
2180
+ path35.extname(this._scriptPath)
2181
2181
  );
2182
2182
  if (legacyName !== this._name) {
2183
2183
  localFile = findFile(
@@ -2188,13 +2188,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
2188
2188
  }
2189
2189
  executableFile = localFile || executableFile;
2190
2190
  }
2191
- launchWithNode = sourceExt.includes(path34.extname(executableFile));
2191
+ launchWithNode = sourceExt.includes(path35.extname(executableFile));
2192
2192
  let proc;
2193
- if (process37.platform !== "win32") {
2193
+ if (process38.platform !== "win32") {
2194
2194
  if (launchWithNode) {
2195
2195
  args.unshift(executableFile);
2196
- args = incrementNodeInspectorPort(process37.execArgv).concat(args);
2197
- proc = childProcess.spawn(process37.argv[0], args, { stdio: "inherit" });
2196
+ args = incrementNodeInspectorPort(process38.execArgv).concat(args);
2197
+ proc = childProcess.spawn(process38.argv[0], args, { stdio: "inherit" });
2198
2198
  } else {
2199
2199
  proc = childProcess.spawn(executableFile, args, { stdio: "inherit" });
2200
2200
  }
@@ -2205,13 +2205,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
2205
2205
  subcommand._name
2206
2206
  );
2207
2207
  args.unshift(executableFile);
2208
- args = incrementNodeInspectorPort(process37.execArgv).concat(args);
2209
- proc = childProcess.spawn(process37.execPath, args, { stdio: "inherit" });
2208
+ args = incrementNodeInspectorPort(process38.execArgv).concat(args);
2209
+ proc = childProcess.spawn(process38.execPath, args, { stdio: "inherit" });
2210
2210
  }
2211
2211
  if (!proc.killed) {
2212
2212
  const signals = ["SIGUSR1", "SIGUSR2", "SIGTERM", "SIGINT", "SIGHUP"];
2213
2213
  signals.forEach((signal) => {
2214
- process37.on(signal, () => {
2214
+ process38.on(signal, () => {
2215
2215
  if (proc.killed === false && proc.exitCode === null) {
2216
2216
  proc.kill(signal);
2217
2217
  }
@@ -2222,7 +2222,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2222
2222
  proc.on("close", (code) => {
2223
2223
  code = code ?? 1;
2224
2224
  if (!exitCallback) {
2225
- process37.exit(code);
2225
+ process38.exit(code);
2226
2226
  } else {
2227
2227
  exitCallback(
2228
2228
  new CommanderError2(
@@ -2244,7 +2244,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2244
2244
  throw new Error(`'${executableFile}' not executable`);
2245
2245
  }
2246
2246
  if (!exitCallback) {
2247
- process37.exit(1);
2247
+ process38.exit(1);
2248
2248
  } else {
2249
2249
  const wrappedError = new CommanderError2(
2250
2250
  1,
@@ -2739,13 +2739,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
2739
2739
  */
2740
2740
  _parseOptionsEnv() {
2741
2741
  this.options.forEach((option) => {
2742
- if (option.envVar && option.envVar in process37.env) {
2742
+ if (option.envVar && option.envVar in process38.env) {
2743
2743
  const optionKey = option.attributeName();
2744
2744
  if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
2745
2745
  this.getOptionValueSource(optionKey)
2746
2746
  )) {
2747
2747
  if (option.required || option.optional) {
2748
- this.emit(`optionEnv:${option.name()}`, process37.env[option.envVar]);
2748
+ this.emit(`optionEnv:${option.name()}`, process38.env[option.envVar]);
2749
2749
  } else {
2750
2750
  this.emit(`optionEnv:${option.name()}`);
2751
2751
  }
@@ -3035,7 +3035,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3035
3035
  * @return {Command}
3036
3036
  */
3037
3037
  nameFromFilename(filename) {
3038
- this._name = path34.basename(filename, path34.extname(filename));
3038
+ this._name = path35.basename(filename, path35.extname(filename));
3039
3039
  return this;
3040
3040
  }
3041
3041
  /**
@@ -3049,9 +3049,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3049
3049
  * @param {string} [path]
3050
3050
  * @return {(string|null|Command)}
3051
3051
  */
3052
- executableDir(path35) {
3053
- if (path35 === void 0) return this._executableDir;
3054
- this._executableDir = path35;
3052
+ executableDir(path36) {
3053
+ if (path36 === void 0) return this._executableDir;
3054
+ this._executableDir = path36;
3055
3055
  return this;
3056
3056
  }
3057
3057
  /**
@@ -3200,7 +3200,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3200
3200
  */
3201
3201
  help(contextOptions) {
3202
3202
  this.outputHelp(contextOptions);
3203
- let exitCode = Number(process37.exitCode ?? 0);
3203
+ let exitCode = Number(process38.exitCode ?? 0);
3204
3204
  if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
3205
3205
  exitCode = 1;
3206
3206
  }
@@ -3290,9 +3290,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3290
3290
  });
3291
3291
  }
3292
3292
  function useColor() {
3293
- if (process37.env.NO_COLOR || process37.env.FORCE_COLOR === "0" || process37.env.FORCE_COLOR === "false")
3293
+ if (process38.env.NO_COLOR || process38.env.FORCE_COLOR === "0" || process38.env.FORCE_COLOR === "false")
3294
3294
  return false;
3295
- if (process37.env.FORCE_COLOR || process37.env.CLICOLOR_FORCE !== void 0)
3295
+ if (process38.env.FORCE_COLOR || process38.env.CLICOLOR_FORCE !== void 0)
3296
3296
  return true;
3297
3297
  return void 0;
3298
3298
  }
@@ -8511,8 +8511,8 @@ var require_utils = __commonJS({
8511
8511
  }
8512
8512
  return ind;
8513
8513
  }
8514
- function removeDotSegments(path34) {
8515
- let input = path34;
8514
+ function removeDotSegments(path35) {
8515
+ let input = path35;
8516
8516
  const output = [];
8517
8517
  let nextSlash = -1;
8518
8518
  let len = 0;
@@ -8711,8 +8711,8 @@ var require_schemes = __commonJS({
8711
8711
  wsComponent.secure = void 0;
8712
8712
  }
8713
8713
  if (wsComponent.resourceName) {
8714
- const [path34, query] = wsComponent.resourceName.split("?");
8715
- wsComponent.path = path34 && path34 !== "/" ? path34 : void 0;
8714
+ const [path35, query] = wsComponent.resourceName.split("?");
8715
+ wsComponent.path = path35 && path35 !== "/" ? path35 : void 0;
8716
8716
  wsComponent.query = query;
8717
8717
  wsComponent.resourceName = void 0;
8718
8718
  }
@@ -12093,7 +12093,7 @@ var require_windows = __commonJS({
12093
12093
  module2.exports = isexe;
12094
12094
  isexe.sync = sync;
12095
12095
  var fs = require("fs");
12096
- function checkPathExt(path34, options) {
12096
+ function checkPathExt(path35, options) {
12097
12097
  var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
12098
12098
  if (!pathext) {
12099
12099
  return true;
@@ -12104,25 +12104,25 @@ var require_windows = __commonJS({
12104
12104
  }
12105
12105
  for (var i = 0; i < pathext.length; i++) {
12106
12106
  var p = pathext[i].toLowerCase();
12107
- if (p && path34.substr(-p.length).toLowerCase() === p) {
12107
+ if (p && path35.substr(-p.length).toLowerCase() === p) {
12108
12108
  return true;
12109
12109
  }
12110
12110
  }
12111
12111
  return false;
12112
12112
  }
12113
- function checkStat(stat2, path34, options) {
12113
+ function checkStat(stat2, path35, options) {
12114
12114
  if (!stat2.isSymbolicLink() && !stat2.isFile()) {
12115
12115
  return false;
12116
12116
  }
12117
- return checkPathExt(path34, options);
12117
+ return checkPathExt(path35, options);
12118
12118
  }
12119
- function isexe(path34, options, cb) {
12120
- fs.stat(path34, function(er, stat2) {
12121
- cb(er, er ? false : checkStat(stat2, path34, options));
12119
+ function isexe(path35, options, cb) {
12120
+ fs.stat(path35, function(er, stat2) {
12121
+ cb(er, er ? false : checkStat(stat2, path35, options));
12122
12122
  });
12123
12123
  }
12124
- function sync(path34, options) {
12125
- return checkStat(fs.statSync(path34), path34, options);
12124
+ function sync(path35, options) {
12125
+ return checkStat(fs.statSync(path35), path35, options);
12126
12126
  }
12127
12127
  }
12128
12128
  });
@@ -12133,13 +12133,13 @@ var require_mode = __commonJS({
12133
12133
  module2.exports = isexe;
12134
12134
  isexe.sync = sync;
12135
12135
  var fs = require("fs");
12136
- function isexe(path34, options, cb) {
12137
- fs.stat(path34, function(er, stat2) {
12136
+ function isexe(path35, options, cb) {
12137
+ fs.stat(path35, function(er, stat2) {
12138
12138
  cb(er, er ? false : checkStat(stat2, options));
12139
12139
  });
12140
12140
  }
12141
- function sync(path34, options) {
12142
- return checkStat(fs.statSync(path34), options);
12141
+ function sync(path35, options) {
12142
+ return checkStat(fs.statSync(path35), options);
12143
12143
  }
12144
12144
  function checkStat(stat2, options) {
12145
12145
  return stat2.isFile() && checkMode(stat2, options);
@@ -12172,7 +12172,7 @@ var require_isexe = __commonJS({
12172
12172
  }
12173
12173
  module2.exports = isexe;
12174
12174
  isexe.sync = sync;
12175
- function isexe(path34, options, cb) {
12175
+ function isexe(path35, options, cb) {
12176
12176
  if (typeof options === "function") {
12177
12177
  cb = options;
12178
12178
  options = {};
@@ -12182,7 +12182,7 @@ var require_isexe = __commonJS({
12182
12182
  throw new TypeError("callback not provided");
12183
12183
  }
12184
12184
  return new Promise(function(resolve, reject) {
12185
- isexe(path34, options || {}, function(er, is) {
12185
+ isexe(path35, options || {}, function(er, is) {
12186
12186
  if (er) {
12187
12187
  reject(er);
12188
12188
  } else {
@@ -12191,7 +12191,7 @@ var require_isexe = __commonJS({
12191
12191
  });
12192
12192
  });
12193
12193
  }
12194
- core(path34, options || {}, function(er, is) {
12194
+ core(path35, options || {}, function(er, is) {
12195
12195
  if (er) {
12196
12196
  if (er.code === "EACCES" || options && options.ignoreErrors) {
12197
12197
  er = null;
@@ -12201,9 +12201,9 @@ var require_isexe = __commonJS({
12201
12201
  cb(er, is);
12202
12202
  });
12203
12203
  }
12204
- function sync(path34, options) {
12204
+ function sync(path35, options) {
12205
12205
  try {
12206
- return core.sync(path34, options || {});
12206
+ return core.sync(path35, options || {});
12207
12207
  } catch (er) {
12208
12208
  if (options && options.ignoreErrors || er.code === "EACCES") {
12209
12209
  return false;
@@ -12219,7 +12219,7 @@ var require_isexe = __commonJS({
12219
12219
  var require_which = __commonJS({
12220
12220
  "../../node_modules/which/which.js"(exports2, module2) {
12221
12221
  var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
12222
- var path34 = require("path");
12222
+ var path35 = require("path");
12223
12223
  var COLON = isWindows ? ";" : ":";
12224
12224
  var isexe = require_isexe();
12225
12225
  var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
@@ -12257,7 +12257,7 @@ var require_which = __commonJS({
12257
12257
  return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
12258
12258
  const ppRaw = pathEnv[i];
12259
12259
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
12260
- const pCmd = path34.join(pathPart, cmd);
12260
+ const pCmd = path35.join(pathPart, cmd);
12261
12261
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
12262
12262
  resolve(subStep(p, i, 0));
12263
12263
  });
@@ -12284,7 +12284,7 @@ var require_which = __commonJS({
12284
12284
  for (let i = 0; i < pathEnv.length; i++) {
12285
12285
  const ppRaw = pathEnv[i];
12286
12286
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
12287
- const pCmd = path34.join(pathPart, cmd);
12287
+ const pCmd = path35.join(pathPart, cmd);
12288
12288
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
12289
12289
  for (let j = 0; j < pathExt.length; j++) {
12290
12290
  const cur = p + pathExt[j];
@@ -12332,7 +12332,7 @@ var require_path_key = __commonJS({
12332
12332
  var require_resolveCommand = __commonJS({
12333
12333
  "../../node_modules/cross-spawn/lib/util/resolveCommand.js"(exports2, module2) {
12334
12334
  "use strict";
12335
- var path34 = require("path");
12335
+ var path35 = require("path");
12336
12336
  var which = require_which();
12337
12337
  var getPathKey = require_path_key();
12338
12338
  function resolveCommandAttempt(parsed, withoutPathExt) {
@@ -12350,7 +12350,7 @@ var require_resolveCommand = __commonJS({
12350
12350
  try {
12351
12351
  resolved = which.sync(parsed.command, {
12352
12352
  path: env[getPathKey({ env })],
12353
- pathExt: withoutPathExt ? path34.delimiter : void 0
12353
+ pathExt: withoutPathExt ? path35.delimiter : void 0
12354
12354
  });
12355
12355
  } catch (e) {
12356
12356
  } finally {
@@ -12359,7 +12359,7 @@ var require_resolveCommand = __commonJS({
12359
12359
  }
12360
12360
  }
12361
12361
  if (resolved) {
12362
- resolved = path34.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
12362
+ resolved = path35.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
12363
12363
  }
12364
12364
  return resolved;
12365
12365
  }
@@ -12413,8 +12413,8 @@ var require_shebang_command = __commonJS({
12413
12413
  if (!match) {
12414
12414
  return null;
12415
12415
  }
12416
- const [path34, argument] = match[0].replace(/#! ?/, "").split(" ");
12417
- const binary = path34.split("/").pop();
12416
+ const [path35, argument] = match[0].replace(/#! ?/, "").split(" ");
12417
+ const binary = path35.split("/").pop();
12418
12418
  if (binary === "env") {
12419
12419
  return argument;
12420
12420
  }
@@ -12449,7 +12449,7 @@ var require_readShebang = __commonJS({
12449
12449
  var require_parse2 = __commonJS({
12450
12450
  "../../node_modules/cross-spawn/lib/parse.js"(exports2, module2) {
12451
12451
  "use strict";
12452
- var path34 = require("path");
12452
+ var path35 = require("path");
12453
12453
  var resolveCommand = require_resolveCommand();
12454
12454
  var escape2 = require_escape();
12455
12455
  var readShebang = require_readShebang();
@@ -12474,7 +12474,7 @@ var require_parse2 = __commonJS({
12474
12474
  const needsShell = !isExecutableRegExp.test(commandFile);
12475
12475
  if (parsed.options.forceShell || needsShell) {
12476
12476
  const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
12477
- parsed.command = path34.normalize(parsed.command);
12477
+ parsed.command = path35.normalize(parsed.command);
12478
12478
  parsed.command = escape2.command(parsed.command);
12479
12479
  parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
12480
12480
  const shellCommand = [parsed.command].concat(parsed.args).join(" ");
@@ -12718,7 +12718,7 @@ function createCompletionRuntimeCommand(program2) {
12718
12718
  // package.json
12719
12719
  var package_default = {
12720
12720
  name: "@kimbho/kimbho-cli",
12721
- version: "0.1.32",
12721
+ version: "0.1.36",
12722
12722
  description: "Kimbho CLI is a terminal-native coding agent for planning, execution, and verification.",
12723
12723
  type: "module",
12724
12724
  engines: {
@@ -13771,8 +13771,8 @@ function getErrorMap() {
13771
13771
 
13772
13772
  // ../../node_modules/zod/v3/helpers/parseUtil.js
13773
13773
  var makeIssue = (params) => {
13774
- const { data, path: path34, errorMaps, issueData } = params;
13775
- const fullPath = [...path34, ...issueData.path || []];
13774
+ const { data, path: path35, errorMaps, issueData } = params;
13775
+ const fullPath = [...path35, ...issueData.path || []];
13776
13776
  const fullIssue = {
13777
13777
  ...issueData,
13778
13778
  path: fullPath
@@ -13888,11 +13888,11 @@ var errorUtil;
13888
13888
 
13889
13889
  // ../../node_modules/zod/v3/types.js
13890
13890
  var ParseInputLazyPath = class {
13891
- constructor(parent, value, path34, key) {
13891
+ constructor(parent, value, path35, key) {
13892
13892
  this._cachedPath = [];
13893
13893
  this.parent = parent;
13894
13894
  this.data = value;
13895
- this._path = path34;
13895
+ this._path = path35;
13896
13896
  this._key = key;
13897
13897
  }
13898
13898
  get path() {
@@ -26304,10 +26304,10 @@ function assignProp(target, prop, value) {
26304
26304
  configurable: true
26305
26305
  });
26306
26306
  }
26307
- function getElementAtPath(obj, path34) {
26308
- if (!path34)
26307
+ function getElementAtPath(obj, path35) {
26308
+ if (!path35)
26309
26309
  return obj;
26310
- return path34.reduce((acc, key) => acc?.[key], obj);
26310
+ return path35.reduce((acc, key) => acc?.[key], obj);
26311
26311
  }
26312
26312
  function promiseAllObject(promisesObj) {
26313
26313
  const keys = Object.keys(promisesObj);
@@ -26627,11 +26627,11 @@ function aborted(x, startIndex = 0) {
26627
26627
  }
26628
26628
  return false;
26629
26629
  }
26630
- function prefixIssues(path34, issues) {
26630
+ function prefixIssues(path35, issues) {
26631
26631
  return issues.map((iss) => {
26632
26632
  var _a;
26633
26633
  (_a = iss).path ?? (_a.path = []);
26634
- iss.path.unshift(path34);
26634
+ iss.path.unshift(path35);
26635
26635
  return iss;
26636
26636
  });
26637
26637
  }
@@ -41714,7 +41714,7 @@ function formatCliHookIssues(issues) {
41714
41714
 
41715
41715
  // src/commands/exec.ts
41716
41716
  var import_promises22 = require("node:fs/promises");
41717
- var import_node_path22 = __toESM(require("node:path"), 1);
41717
+ var import_node_path23 = __toESM(require("node:path"), 1);
41718
41718
  var import_node_process8 = __toESM(require("node:process"), 1);
41719
41719
  var import_ajv2 = __toESM(require_ajv(), 1);
41720
41720
 
@@ -42420,6 +42420,9 @@ async function resolveAgentSelection(cwd, options) {
42420
42420
  }
42421
42421
 
42422
42422
  // src/prompt-intent.ts
42423
+ var WORKSPACE_NOUN_PATTERN = /\b(project|repo|repository|codebase|workspace|app|directory|folder|dir)\b/;
42424
+ var WORKSPACE_CONTENT_PATTERN = /\b(files?|contents?|structure|layout|tree|code)\b/;
42425
+ var WORKSPACE_REFERENCE_PATTERN = /\b(current|this|the|local|working)\s+(project|repo|repository|codebase|workspace|app|directory|folder|dir)\b/;
42423
42426
  var EXECUTION_PREFIXES = [
42424
42427
  "build ",
42425
42428
  "create ",
@@ -42478,13 +42481,26 @@ function looksLikeInformationalRequest(input) {
42478
42481
  if (/\b(tell me|describe|walk me through|help me understand)\b/.test(input)) {
42479
42482
  return true;
42480
42483
  }
42481
- if (/\b(details?|overview|summary|walkthrough|explanation)\b/.test(input) && /\b(project|repo|repository|codebase|workspace|app)\b/.test(input)) {
42484
+ if (/\b(details?|overview|summary|walkthrough|explanation|structure|layout|contents?)\b/.test(input) && (WORKSPACE_NOUN_PATTERN.test(input) || WORKSPACE_CONTENT_PATTERN.test(input))) {
42482
42485
  return true;
42483
42486
  }
42484
- return /\b(current|this|the)\s+(project|repo|repository|codebase|workspace|app)\b/.test(input) && /\b(details?|overview|summary|about)\b/.test(input);
42487
+ return WORKSPACE_REFERENCE_PATTERN.test(input) && /\b(details?|overview|summary|about|inside|in|contents?|structure|layout)\b/.test(input);
42485
42488
  }
42486
42489
  function looksLikeWorkspaceInfoPrompt(input) {
42487
- return looksLikeInformationalRequest(input.toLowerCase()) && /\b(project|repo|repository|codebase|workspace|app)\b/.test(input.toLowerCase());
42490
+ const normalized = input.toLowerCase();
42491
+ if (looksLikeInformationalRequest(normalized) && (WORKSPACE_NOUN_PATTERN.test(normalized) || WORKSPACE_CONTENT_PATTERN.test(normalized))) {
42492
+ return true;
42493
+ }
42494
+ if (/\b(analy[sz]e|summari[sz]e|explain|describe|show|list|walk me through|tell me about)\b/.test(normalized) && (WORKSPACE_NOUN_PATTERN.test(normalized) || WORKSPACE_CONTENT_PATTERN.test(normalized))) {
42495
+ return true;
42496
+ }
42497
+ if (/\b(what('?s| is)?\s+in|show me|list)\b/.test(normalized) && /\b(this|the current|current)\s+(directory|folder|workspace|repo|repository|project|dir)\b/.test(normalized)) {
42498
+ return true;
42499
+ }
42500
+ if (/\bfiles?\s+in\s+(this|the current|current)\s+(directory|folder|workspace|repo|repository|project|dir)\b/.test(normalized)) {
42501
+ return true;
42502
+ }
42503
+ return false;
42488
42504
  }
42489
42505
  function stripConversationalLead(input) {
42490
42506
  let normalized = input.trim().toLowerCase();
@@ -42804,10 +42820,265 @@ async function resolveExecutionWorkspace(cwd, goal) {
42804
42820
  };
42805
42821
  }
42806
42822
 
42823
+ // src/workspace-analysis.ts
42824
+ var import_node_path22 = __toESM(require("node:path"), 1);
42825
+ function buildWorkspaceAnalysisPlan(request, prompt) {
42826
+ const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
42827
+ return {
42828
+ goal: request.goal,
42829
+ generatedAt,
42830
+ summary: "Read-only multi-agent analysis of the current repository to answer the operator's question with concrete workspace evidence.",
42831
+ repoStrategy: {
42832
+ mode: "existing-repo",
42833
+ reasoning: "This is an analysis-only request about the current workspace, so the agent team should inspect the repo and synthesize findings without editing source files."
42834
+ },
42835
+ assumptions: [
42836
+ "The user wants a grounded explanation of the current repository, not code changes.",
42837
+ "The analysis should stay read-only and avoid modifying product files."
42838
+ ],
42839
+ openQuestions: [],
42840
+ milestones: [
42841
+ {
42842
+ id: "m1-repo-survey",
42843
+ title: "Repository Survey",
42844
+ objective: "Inspect the current workspace structure, entrypoints, tooling, and conventions.",
42845
+ tasks: [
42846
+ {
42847
+ id: "t1-repo-analysis",
42848
+ title: "Analyze the current workspace and conventions",
42849
+ description: "Map the repository shape, commands, entrypoints, and constraints before answering the user's question.",
42850
+ type: "analysis",
42851
+ status: "pending",
42852
+ agentRole: "repo-analyst",
42853
+ dependsOn: [],
42854
+ acceptanceCriteria: [
42855
+ "Repository shape and commands are captured.",
42856
+ "Likely entrypoints and major packages are identified."
42857
+ ],
42858
+ outputs: [
42859
+ "Repo analysis summary"
42860
+ ],
42861
+ filesLikelyTouched: [
42862
+ ".",
42863
+ ".kimbho/"
42864
+ ],
42865
+ riskLevel: "low",
42866
+ sandboxModeOverride: "read-only"
42867
+ },
42868
+ {
42869
+ id: "t2-architecture",
42870
+ title: "Synthesize the architecture and package boundaries",
42871
+ description: "Turn the repository findings into a clear explanation of the system structure and responsibilities.",
42872
+ type: "documentation",
42873
+ status: "pending",
42874
+ agentRole: "planner",
42875
+ dependsOn: [
42876
+ "t1-repo-analysis"
42877
+ ],
42878
+ acceptanceCriteria: [
42879
+ "Architecture summary is grounded in repo analysis findings.",
42880
+ "The main packages and responsibilities are explicit."
42881
+ ],
42882
+ outputs: [
42883
+ "Architecture brief"
42884
+ ],
42885
+ filesLikelyTouched: [
42886
+ ".kimbho/"
42887
+ ],
42888
+ riskLevel: "low",
42889
+ sandboxModeOverride: "read-only"
42890
+ }
42891
+ ]
42892
+ },
42893
+ {
42894
+ id: "m2-answer",
42895
+ title: "Answer",
42896
+ objective: "Review the gathered analysis artifacts and produce the final project explanation.",
42897
+ tasks: [
42898
+ {
42899
+ id: "t3-project-brief",
42900
+ title: "Review the analysis artifacts and prepare the project explanation",
42901
+ description: "Inspect the repo-analysis and architecture artifacts, then summarize the current project in terms that answer the user's question.",
42902
+ type: "documentation",
42903
+ status: "pending",
42904
+ agentRole: "reviewer",
42905
+ dependsOn: [
42906
+ "t1-repo-analysis",
42907
+ "t2-architecture"
42908
+ ],
42909
+ acceptanceCriteria: [
42910
+ "The answer addresses the user's question directly.",
42911
+ "The summary is grounded in repository evidence instead of generic assistant chatter."
42912
+ ],
42913
+ outputs: [
42914
+ "Project explanation summary"
42915
+ ],
42916
+ filesLikelyTouched: [
42917
+ ".kimbho/logs/",
42918
+ "kimbho_init.md"
42919
+ ],
42920
+ riskLevel: "low",
42921
+ sandboxModeOverride: "read-only",
42922
+ allowedTools: [
42923
+ "file.read",
42924
+ "file.search",
42925
+ "file.list",
42926
+ "repo.index",
42927
+ "repo.query",
42928
+ "git.diff"
42929
+ ],
42930
+ deniedTools: [
42931
+ "file.write",
42932
+ "file.patch",
42933
+ "shell.exec"
42934
+ ],
42935
+ agentPromptPreamble: [
42936
+ "This is a read-only repository explanation task.",
42937
+ "Do not modify product files, install packages, or run development servers.",
42938
+ `Answer the operator's question: ${prompt}`,
42939
+ "Use the repo-analysis and architecture artifacts plus direct file inspection if needed.",
42940
+ "Finish with a concise but concrete summary of the project, stack, entrypoints, commands, and notable risks or gaps."
42941
+ ].join("\n")
42942
+ }
42943
+ ]
42944
+ }
42945
+ ],
42946
+ verificationChecklist: [
42947
+ "Repo analysis artifacts were captured.",
42948
+ "The architecture summary is grounded in the workspace.",
42949
+ "The final explanation answers the user's question without changing source files."
42950
+ ],
42951
+ executionNotes: [
42952
+ "Read-only analysis run triggered directly from a workspace question.",
42953
+ "Prefer repo/file tools and existing memory artifacts over generic assistant responses."
42954
+ ]
42955
+ };
42956
+ }
42957
+ async function synthesizeWorkspaceAnalysisAnswer(cwd, prompt, role, snapshot) {
42958
+ const config2 = await loadConfig(cwd);
42959
+ const projectInit = await readMarkdownIfExists(import_node_path22.default.join(cwd, "kimbho_init.md"));
42960
+ const artifactPaths = Array.from(new Set(
42961
+ snapshot.events.flatMap((event) => [
42962
+ ...event.artifacts,
42963
+ ...event.toolResults.flatMap((toolResult) => toolResult.artifacts)
42964
+ ])
42965
+ ));
42966
+ const prioritizedArtifacts = artifactPaths.filter((artifactPath) => /repo-analysis|architecture-brief|project-brief|transcript/i.test(import_node_path22.default.basename(artifactPath))).slice(0, 4);
42967
+ const artifactSections = (await Promise.all(
42968
+ prioritizedArtifacts.map(async (artifactPath) => {
42969
+ const content = await readMarkdownIfExists(artifactPath);
42970
+ if (!content) {
42971
+ return null;
42972
+ }
42973
+ return `Artifact: ${artifactPath}
42974
+ ${content.slice(0, 4e3)}`;
42975
+ })
42976
+ )).filter((section) => Boolean(section));
42977
+ if (!config2) {
42978
+ return [
42979
+ "Repository analysis completed.",
42980
+ projectInit ? `Current workspace summary:
42981
+ ${projectInit.slice(0, 4e3)}` : "Project summary is available in the session artifacts, but no configured model was available to synthesize a narrative answer."
42982
+ ].join("\n\n");
42983
+ }
42984
+ const resolver = new BrainResolver(config2, createDefaultBrainProviderRegistry(cwd));
42985
+ const brain = await resolver.resolve(role);
42986
+ const result = await brain.client.generateText({
42987
+ model: brain.model,
42988
+ systemPrompt: [
42989
+ brain.settings.promptPreamble,
42990
+ "You are summarizing the current repository after a read-only multi-agent analysis session.",
42991
+ "Answer the user's question directly and concretely from the provided workspace evidence.",
42992
+ "Do not greet, do not speak generically about your own capabilities, and do not invent repository details.",
42993
+ "Prefer a crisp project overview with stack, structure, key entrypoints, commands, and notable risks or gaps."
42994
+ ].filter(Boolean).join("\n\n"),
42995
+ userPrompt: [
42996
+ `User question: ${prompt}`,
42997
+ projectInit ? `Workspace overview:
42998
+ ${projectInit.slice(0, 6e3)}` : null,
42999
+ artifactSections.length > 0 ? artifactSections.join("\n\n") : "No detailed analysis artifacts were available; answer from the workspace overview only."
43000
+ ].filter((value) => Boolean(value)).join("\n\n"),
43001
+ ...typeof brain.settings.temperature === "number" ? {
43002
+ temperature: brain.settings.temperature
43003
+ } : {},
43004
+ ...typeof brain.settings.maxTokens === "number" ? {
43005
+ maxTokens: brain.settings.maxTokens
43006
+ } : {}
43007
+ });
43008
+ return result.text;
43009
+ }
43010
+ async function executeWorkspaceAnalysis(cwd, prompt, options) {
43011
+ const prepared = await preparePlanningRequest({
43012
+ goal: `Analyze the current repository and answer the user's question: ${prompt}`,
43013
+ mode: "run",
43014
+ cwd,
43015
+ workspaceState: "existing",
43016
+ constraints: [
43017
+ "Read-only repository analysis only.",
43018
+ "Do not modify source files, install packages, or start development servers.",
43019
+ "Use multiple agents to inspect the workspace and synthesize the answer when helpful."
43020
+ ],
43021
+ ...options.agentSelection ? {
43022
+ agentSelection: options.agentSelection
43023
+ } : {}
43024
+ });
43025
+ const request = prepared.request;
43026
+ const plan = buildWorkspaceAnalysisPlan(request, prompt);
43027
+ const planPath = options.ephemeral ? null : await savePlan(plan, request.cwd);
43028
+ const orchestrator = new ExecutionOrchestrator();
43029
+ const envelope = orchestrator.buildEnvelope(request, plan, options.sessionId);
43030
+ const initialSnapshot = orchestrator.createSessionSnapshot(envelope);
43031
+ const progressEvents = [];
43032
+ const snapshot = await orchestrator.continueSession(initialSnapshot, {
43033
+ maxAutoTasks: options.maxAutoTasks,
43034
+ maxAgentSteps: options.maxAgentSteps,
43035
+ maxRepairAttempts: options.maxRepairAttempts,
43036
+ ...typeof options.maxToolCalls === "number" ? {
43037
+ maxToolCalls: options.maxToolCalls
43038
+ } : {},
43039
+ ...typeof options.maxModelCalls === "number" ? {
43040
+ maxModelCalls: options.maxModelCalls
43041
+ } : {},
43042
+ ...typeof options.maxInputTokens === "number" ? {
43043
+ maxInputTokens: options.maxInputTokens
43044
+ } : {},
43045
+ ...typeof options.maxOutputTokens === "number" ? {
43046
+ maxOutputTokens: options.maxOutputTokens
43047
+ } : {},
43048
+ onProgress: async (event) => {
43049
+ progressEvents.push(event);
43050
+ await options.onProgress?.(event);
43051
+ }
43052
+ });
43053
+ const sessionPath = options.ephemeral ? null : await saveSession(snapshot, request.cwd);
43054
+ const answer = await synthesizeWorkspaceAnalysisAnswer(
43055
+ request.cwd,
43056
+ prompt,
43057
+ options.answerRole ?? "coder",
43058
+ snapshot
43059
+ );
43060
+ return {
43061
+ answer,
43062
+ plan,
43063
+ planPath,
43064
+ preparedNotes: prepared.notes,
43065
+ progressEvents,
43066
+ request,
43067
+ sessionPath,
43068
+ snapshot
43069
+ };
43070
+ }
43071
+
42807
43072
  // src/commands/exec.ts
42808
43073
  function resolveSkillPromptSource(input) {
42809
43074
  return input.prompt || input.messages.at(-1)?.content || "";
42810
43075
  }
43076
+ function shouldRouteToWorkspaceAnalysis(input, explicitIntent) {
43077
+ if (explicitIntent) {
43078
+ return false;
43079
+ }
43080
+ return looksLikeWorkspaceInfoPrompt(resolveSkillPromptSource(input));
43081
+ }
42811
43082
  var IMAGE_EXTENSIONS = /* @__PURE__ */ new Map([
42812
43083
  [".png", "image/png"],
42813
43084
  [".jpg", "image/jpeg"],
@@ -42902,14 +43173,14 @@ async function pathExists4(filePath) {
42902
43173
  }
42903
43174
  }
42904
43175
  function inferMimeType(name, fallback = "application/octet-stream") {
42905
- const extension = import_node_path22.default.extname(name).toLowerCase();
43176
+ const extension = import_node_path23.default.extname(name).toLowerCase();
42906
43177
  return IMAGE_EXTENSIONS.get(extension) ?? TEXT_EXTENSIONS.get(extension) ?? fallback;
42907
43178
  }
42908
43179
  function isLikelyText(name, mimeType, buffer) {
42909
43180
  if (mimeType.startsWith("text/") || mimeType === "application/json" || mimeType === "application/toml" || mimeType === "application/yaml" || mimeType === "application/xml") {
42910
43181
  return true;
42911
43182
  }
42912
- if (TEXT_EXTENSIONS.has(import_node_path22.default.extname(name).toLowerCase())) {
43183
+ if (TEXT_EXTENSIONS.has(import_node_path23.default.extname(name).toLowerCase())) {
42913
43184
  return true;
42914
43185
  }
42915
43186
  return !buffer.includes(0);
@@ -42932,7 +43203,7 @@ async function fetchAttachment(value) {
42932
43203
  throw new Error(`Failed to download attachment "${value}": ${response.status} ${response.statusText}`);
42933
43204
  }
42934
43205
  const url = new URL(value);
42935
- const name2 = import_node_path22.default.basename(url.pathname) || "attachment";
43206
+ const name2 = import_node_path23.default.basename(url.pathname) || "attachment";
42936
43207
  const mimeType = response.headers.get("content-type")?.split(";")[0]?.trim() ?? inferMimeType(name2);
42937
43208
  const buffer2 = Buffer.from(await response.arrayBuffer());
42938
43209
  return {
@@ -42941,9 +43212,9 @@ async function fetchAttachment(value) {
42941
43212
  buffer: buffer2
42942
43213
  };
42943
43214
  }
42944
- const filePath = import_node_path22.default.resolve(import_node_process8.default.cwd(), value);
43215
+ const filePath = import_node_path23.default.resolve(import_node_process8.default.cwd(), value);
42945
43216
  const buffer = await (0, import_promises22.readFile)(filePath);
42946
- const name = import_node_path22.default.basename(filePath);
43217
+ const name = import_node_path23.default.basename(filePath);
42947
43218
  return {
42948
43219
  name,
42949
43220
  mimeType: inferMimeType(name),
@@ -43140,7 +43411,7 @@ async function resolveJsonSchemaInput(cwd, schemaInput) {
43140
43411
  if (!schemaInput) {
43141
43412
  return null;
43142
43413
  }
43143
- const candidatePath = import_node_path22.default.resolve(cwd, schemaInput);
43414
+ const candidatePath = import_node_path23.default.resolve(cwd, schemaInput);
43144
43415
  if (await pathExists4(candidatePath)) {
43145
43416
  const raw = await (0, import_promises22.readFile)(candidatePath, "utf8");
43146
43417
  return JSON.parse(raw);
@@ -43169,7 +43440,7 @@ async function maybeWriteOutputFile(outputFile, format, payload, textOutput) {
43169
43440
  if (!outputFile) {
43170
43441
  return;
43171
43442
  }
43172
- const filePath = import_node_path22.default.resolve(import_node_process8.default.cwd(), outputFile);
43443
+ const filePath = import_node_path23.default.resolve(import_node_process8.default.cwd(), outputFile);
43173
43444
  const serialized = format === "text" ? textOutput : `${renderJson(payload)}
43174
43445
  `;
43175
43446
  await (0, import_promises22.writeFile)(filePath, serialized, "utf8");
@@ -43397,8 +43668,104 @@ async function executeRunPrompt(cwd, input, format, options) {
43397
43668
  textOutput
43398
43669
  };
43399
43670
  }
43671
+ async function executeWorkspaceAnalysisPrompt(cwd, input, format, options) {
43672
+ const question = enrichPromptWithAttachments(resolveSkillPromptSource(input), input.attachments);
43673
+ const result = await executeWorkspaceAnalysis(cwd, question, {
43674
+ answerRole: "coder",
43675
+ ephemeral: options.ephemeral,
43676
+ maxAutoTasks: options.maxAutoTasks,
43677
+ maxAgentSteps: options.maxAgentSteps,
43678
+ maxRepairAttempts: options.maxRepairAttempts,
43679
+ ...typeof options.maxToolCalls === "number" ? {
43680
+ maxToolCalls: options.maxToolCalls
43681
+ } : {},
43682
+ ...typeof options.maxModelCalls === "number" ? {
43683
+ maxModelCalls: options.maxModelCalls
43684
+ } : {},
43685
+ ...typeof options.maxInputTokens === "number" ? {
43686
+ maxInputTokens: options.maxInputTokens
43687
+ } : {},
43688
+ ...typeof options.maxOutputTokens === "number" ? {
43689
+ maxOutputTokens: options.maxOutputTokens
43690
+ } : {},
43691
+ ...options.sessionId ? {
43692
+ sessionId: options.sessionId
43693
+ } : {},
43694
+ ...options.agentSelection ? {
43695
+ agentSelection: options.agentSelection
43696
+ } : {},
43697
+ ...format === "stream-json" ? {
43698
+ onProgress: async (event) => {
43699
+ printStreamEvent({
43700
+ type: "progress",
43701
+ event
43702
+ });
43703
+ }
43704
+ } : {}
43705
+ });
43706
+ const textOutput = [
43707
+ ...result.preparedNotes,
43708
+ ...result.preparedNotes.length > 0 ? [""] : [],
43709
+ renderPlan(result.plan),
43710
+ "",
43711
+ renderSession(result.snapshot),
43712
+ ...result.planPath ? ["", `Saved plan: ${result.planPath}`] : [],
43713
+ ...result.sessionPath ? [`Saved session: ${result.sessionPath}`] : [],
43714
+ ...result.request.cwd !== cwd ? [`Continue in: cd ${result.request.cwd}`] : [],
43715
+ "",
43716
+ "[analysis answer]",
43717
+ result.answer
43718
+ ].join("\n");
43719
+ const payload = {
43720
+ mode: "workspace-analysis",
43721
+ prompt: question,
43722
+ answer: result.answer,
43723
+ plan: result.plan,
43724
+ session: result.snapshot,
43725
+ planningNotes: result.preparedNotes,
43726
+ attachments: input.attachments.map((attachment) => ({
43727
+ kind: attachment.kind,
43728
+ name: attachment.name,
43729
+ mimeType: attachment.mimeType
43730
+ })),
43731
+ planPath: result.planPath,
43732
+ sessionPath: result.sessionPath,
43733
+ progressEvents: result.progressEvents
43734
+ };
43735
+ return {
43736
+ payload,
43737
+ lastMessage: result.answer,
43738
+ textOutput
43739
+ };
43740
+ }
43400
43741
  async function executePromptByIntent(cwd, input, options = {}) {
43401
- const intent = options.intent ?? inferPromptIntent(input.prompt || input.messages.at(-1)?.content || "");
43742
+ if (shouldRouteToWorkspaceAnalysis(input, options.intent)) {
43743
+ return executeWorkspaceAnalysisPrompt(cwd, input, options.outputFormat ?? "json", {
43744
+ ephemeral: options.ephemeral ?? false,
43745
+ maxAutoTasks: options.maxAutoTasks ?? 4,
43746
+ maxAgentSteps: options.maxAgentSteps ?? 8,
43747
+ maxRepairAttempts: options.maxRepairAttempts ?? 2,
43748
+ ...typeof options.maxToolCalls === "number" ? {
43749
+ maxToolCalls: options.maxToolCalls
43750
+ } : {},
43751
+ ...typeof options.maxModelCalls === "number" ? {
43752
+ maxModelCalls: options.maxModelCalls
43753
+ } : {},
43754
+ ...typeof options.maxInputTokens === "number" ? {
43755
+ maxInputTokens: options.maxInputTokens
43756
+ } : {},
43757
+ ...typeof options.maxOutputTokens === "number" ? {
43758
+ maxOutputTokens: options.maxOutputTokens
43759
+ } : {},
43760
+ ...options.sessionId ? {
43761
+ sessionId: options.sessionId
43762
+ } : {},
43763
+ ...options.agentSelection ? {
43764
+ agentSelection: options.agentSelection
43765
+ } : {}
43766
+ });
43767
+ }
43768
+ const intent = options.intent ?? inferPromptIntent(resolveSkillPromptSource(input));
43402
43769
  if (intent === "chat") {
43403
43770
  return executeChatPrompt(cwd, input);
43404
43771
  }
@@ -43456,12 +43823,9 @@ function createExecCommand() {
43456
43823
  file: options.file,
43457
43824
  image: options.image
43458
43825
  });
43459
- const intent = inferPromptIntent(input.prompt || input.messages.at(-1)?.content || "");
43460
43826
  const schema = await resolveJsonSchemaInput(cwd, options.jsonSchema);
43461
- const result = intent === "chat" ? await executeChatPrompt(cwd, input) : intent === "plan" ? await executePlanPrompt(cwd, input, {
43462
- ephemeral: options.ephemeral,
43463
- agentSelection
43464
- }) : await executeRunPrompt(cwd, input, format, {
43827
+ const result = await executePromptByIntent(cwd, input, {
43828
+ outputFormat: format,
43465
43829
  sessionId: options.sessionId,
43466
43830
  ephemeral: options.ephemeral,
43467
43831
  maxAutoTasks: options.maxAutoTasks,
@@ -43502,7 +43866,7 @@ function createExecCommand() {
43502
43866
 
43503
43867
  // src/review-service.ts
43504
43868
  var import_promises23 = require("node:fs/promises");
43505
- var import_node_path23 = __toESM(require("node:path"), 1);
43869
+ var import_node_path24 = __toESM(require("node:path"), 1);
43506
43870
  function summarizeChangedFiles2(diff) {
43507
43871
  const files = /* @__PURE__ */ new Set();
43508
43872
  for (const line of diff.split("\n")) {
@@ -43571,20 +43935,20 @@ async function reviewWorkspace(cwd, options = {}) {
43571
43935
  toolId: "file.read",
43572
43936
  success: true,
43573
43937
  summary: `Loaded review patch ${options.patchPath}.`,
43574
- stdout: `patch:${import_node_path23.default.resolve(cwd, options.patchPath)}`,
43938
+ stdout: `patch:${import_node_path24.default.resolve(cwd, options.patchPath)}`,
43575
43939
  stderr: "",
43576
43940
  artifacts: [
43577
- import_node_path23.default.resolve(cwd, options.patchPath)
43941
+ import_node_path24.default.resolve(cwd, options.patchPath)
43578
43942
  ]
43579
43943
  } : await runtime.run("git.status", {}, { cwd });
43580
43944
  const diff = options.patchPath ? {
43581
43945
  toolId: "file.read",
43582
43946
  success: true,
43583
43947
  summary: `Loaded review patch ${options.patchPath}.`,
43584
- stdout: await (0, import_promises23.readFile)(import_node_path23.default.resolve(cwd, options.patchPath), "utf8"),
43948
+ stdout: await (0, import_promises23.readFile)(import_node_path24.default.resolve(cwd, options.patchPath), "utf8"),
43585
43949
  stderr: "",
43586
43950
  artifacts: [
43587
- import_node_path23.default.resolve(cwd, options.patchPath)
43951
+ import_node_path24.default.resolve(cwd, options.patchPath)
43588
43952
  ]
43589
43953
  } : await runtime.run("git.diff", {}, { cwd });
43590
43954
  const repoIndex = await runtime.run("repo.index", {}, { cwd }).catch(() => null);
@@ -43651,7 +44015,7 @@ ${diff.stdout}`
43651
44015
  }
43652
44016
  }
43653
44017
  await ensureKimbhoDir(cwd);
43654
- const artifactPath = import_node_path23.default.join(resolveKimbhoDir(cwd), "logs", `review-${Date.now()}.md`);
44018
+ const artifactPath = import_node_path24.default.join(resolveKimbhoDir(cwd), "logs", `review-${Date.now()}.md`);
43655
44019
  await (0, import_promises23.writeFile)(artifactPath, [
43656
44020
  `# Review`,
43657
44021
  ``,
@@ -45245,7 +45609,7 @@ function createChromeCommand() {
45245
45609
 
45246
45610
  // src/commands/cloud.ts
45247
45611
  var import_promises24 = require("node:fs/promises");
45248
- var import_node_path24 = __toESM(require("node:path"), 1);
45612
+ var import_node_path25 = __toESM(require("node:path"), 1);
45249
45613
  var import_node_process12 = __toESM(require("node:process"), 1);
45250
45614
  var import_node_child_process8 = require("node:child_process");
45251
45615
  function parseCount2(value) {
@@ -45317,15 +45681,15 @@ async function resolveSession(sessionId, last = false) {
45317
45681
  return loadSessionById(sessionId, import_node_process12.default.cwd());
45318
45682
  }
45319
45683
  async function ensureCloudPatchDir(cwd) {
45320
- const outputDir = import_node_path24.default.join(resolveKimbhoDir(cwd), "cloud");
45684
+ const outputDir = import_node_path25.default.join(resolveKimbhoDir(cwd), "cloud");
45321
45685
  await (0, import_promises24.mkdir)(outputDir, {
45322
45686
  recursive: true
45323
45687
  });
45324
45688
  return outputDir;
45325
45689
  }
45326
45690
  async function writePatchArtifact(cwd, taskId, patchArtifact, output) {
45327
- const outputPath = output ? import_node_path24.default.resolve(cwd, output) : import_node_path24.default.join(await ensureCloudPatchDir(cwd), patchArtifact.fileName ?? `${taskId}.patch`);
45328
- await (0, import_promises24.mkdir)(import_node_path24.default.dirname(outputPath), {
45691
+ const outputPath = output ? import_node_path25.default.resolve(cwd, output) : import_node_path25.default.join(await ensureCloudPatchDir(cwd), patchArtifact.fileName ?? `${taskId}.patch`);
45692
+ await (0, import_promises24.mkdir)(import_node_path25.default.dirname(outputPath), {
45329
45693
  recursive: true
45330
45694
  });
45331
45695
  await (0, import_promises24.writeFile)(outputPath, patchArtifact.content, "utf8");
@@ -45474,7 +45838,7 @@ function createCloudCommand() {
45474
45838
  }
45475
45839
 
45476
45840
  // src/commands/compat.ts
45477
- var import_node_path25 = __toESM(require("node:path"), 1);
45841
+ var import_node_path26 = __toESM(require("node:path"), 1);
45478
45842
  var import_node_process13 = __toESM(require("node:process"), 1);
45479
45843
 
45480
45844
  // src/plugin-commands.ts
@@ -45837,7 +46201,7 @@ function createPluginCommand() {
45837
46201
  const cwd = import_node_process13.default.cwd();
45838
46202
  const { direct, resolved } = await loadScopedConfig(scope, cwd);
45839
46203
  const current = baseConfig(direct, resolved);
45840
- const normalized = import_node_path25.default.resolve(cwd, directory);
46204
+ const normalized = import_node_path26.default.resolve(cwd, directory);
45841
46205
  const outputPath = await saveScopedConfig(scope, cwd, {
45842
46206
  ...current,
45843
46207
  pluginDirectories: Array.from(/* @__PURE__ */ new Set([
@@ -45852,7 +46216,7 @@ function createPluginCommand() {
45852
46216
  const cwd = import_node_process13.default.cwd();
45853
46217
  const { direct, resolved } = await loadScopedConfig(scope, cwd);
45854
46218
  const current = baseConfig(direct, resolved);
45855
- const normalized = import_node_path25.default.resolve(cwd, directory);
46219
+ const normalized = import_node_path26.default.resolve(cwd, directory);
45856
46220
  const outputPath = await saveScopedConfig(scope, cwd, {
45857
46221
  ...current,
45858
46222
  pluginDirectories: current.pluginDirectories.filter((entry) => entry !== directory && entry !== normalized)
@@ -46029,11 +46393,11 @@ function createSandboxCommand() {
46029
46393
  var import_node_process14 = __toESM(require("node:process"), 1);
46030
46394
 
46031
46395
  // src/memory.ts
46032
- var import_node_path27 = __toESM(require("node:path"), 1);
46396
+ var import_node_path28 = __toESM(require("node:path"), 1);
46033
46397
 
46034
46398
  // src/project-init.ts
46035
46399
  var import_promises25 = require("node:fs/promises");
46036
- var import_node_path26 = __toESM(require("node:path"), 1);
46400
+ var import_node_path27 = __toESM(require("node:path"), 1);
46037
46401
  var import_node_child_process9 = require("node:child_process");
46038
46402
  var import_node_util = require("node:util");
46039
46403
  var execFileAsync = (0, import_node_util.promisify)(import_node_child_process9.execFile);
@@ -46046,16 +46410,16 @@ async function pathExists5(filePath) {
46046
46410
  }
46047
46411
  }
46048
46412
  async function detectPackageManager(cwd) {
46049
- if (await pathExists5(import_node_path26.default.join(cwd, "pnpm-lock.yaml"))) {
46413
+ if (await pathExists5(import_node_path27.default.join(cwd, "pnpm-lock.yaml"))) {
46050
46414
  return "pnpm";
46051
46415
  }
46052
- if (await pathExists5(import_node_path26.default.join(cwd, "yarn.lock"))) {
46416
+ if (await pathExists5(import_node_path27.default.join(cwd, "yarn.lock"))) {
46053
46417
  return "yarn";
46054
46418
  }
46055
- if (await pathExists5(import_node_path26.default.join(cwd, "bun.lockb")) || await pathExists5(import_node_path26.default.join(cwd, "bun.lock"))) {
46419
+ if (await pathExists5(import_node_path27.default.join(cwd, "bun.lockb")) || await pathExists5(import_node_path27.default.join(cwd, "bun.lock"))) {
46056
46420
  return "bun";
46057
46421
  }
46058
- if (await pathExists5(import_node_path26.default.join(cwd, "package-lock.json"))) {
46422
+ if (await pathExists5(import_node_path27.default.join(cwd, "package-lock.json"))) {
46059
46423
  return "npm";
46060
46424
  }
46061
46425
  return "npm";
@@ -46199,8 +46563,8 @@ async function generateProjectInitFile(cwd, outputFileName = "kimbho_init.md") {
46199
46563
  const entrypoints = inferPrimaryEntrypoints(index);
46200
46564
  const verificationCommands = inferVerificationCommands(rootPackage, packageManager);
46201
46565
  const git = await captureGitSnapshot(cwd);
46202
- const packageJson = await readJsonFile2(import_node_path26.default.join(cwd, "package.json"));
46203
- const outputPath = import_node_path26.default.join(cwd, outputFileName);
46566
+ const packageJson = await readJsonFile2(import_node_path27.default.join(cwd, "package.json"));
46567
+ const outputPath = import_node_path27.default.join(cwd, outputFileName);
46204
46568
  const summaryLines = [
46205
46569
  `- workspace: \`${cwd}\``,
46206
46570
  `- generated: ${(/* @__PURE__ */ new Date()).toISOString()}`,
@@ -46261,14 +46625,14 @@ async function generateProjectInitFile(cwd, outputFileName = "kimbho_init.md") {
46261
46625
  renderSection("Schemas", schemaLines),
46262
46626
  renderSection("Key Symbols", symbolLines),
46263
46627
  renderSection("Agent Guidance", guidanceLines),
46264
- `Repo index artifact: \`${import_node_path26.default.relative(cwd, artifactPath) || artifactPath}\``,
46628
+ `Repo index artifact: \`${import_node_path27.default.relative(cwd, artifactPath) || artifactPath}\``,
46265
46629
  ""
46266
46630
  ].join("\n");
46267
46631
  await (0, import_promises25.writeFile)(outputPath, content, "utf8");
46268
46632
  return {
46269
46633
  outputPath,
46270
46634
  indexArtifactPath: artifactPath,
46271
- summary: `Generated ${outputFileName} with indexed project context for ${import_node_path26.default.basename(cwd)}.`,
46635
+ summary: `Generated ${outputFileName} with indexed project context for ${import_node_path27.default.basename(cwd)}.`,
46272
46636
  purpose,
46273
46637
  frameworks,
46274
46638
  entrypoints,
@@ -46289,7 +46653,7 @@ function renderProjectMemory(initFilePath) {
46289
46653
  "",
46290
46654
  "## Canonical References",
46291
46655
  "",
46292
- `- bootstrap: \`${import_node_path27.default.basename(initFilePath)}\``,
46656
+ `- bootstrap: \`${import_node_path28.default.basename(initFilePath)}\``,
46293
46657
  "- read the bootstrap file before large changes",
46294
46658
  "- record important repo-specific rules here so future runs do not need to rediscover them",
46295
46659
  "",
@@ -46333,7 +46697,7 @@ async function refreshMemoryFiles(cwd) {
46333
46697
  initFilePath: init.outputPath,
46334
46698
  projectMemoryPath,
46335
46699
  userMemoryPath,
46336
- summary: `Refreshed project bootstrap and memory files for ${import_node_path27.default.basename(cwd)}.`,
46700
+ summary: `Refreshed project bootstrap and memory files for ${import_node_path28.default.basename(cwd)}.`,
46337
46701
  purpose: init.purpose,
46338
46702
  frameworks: init.frameworks,
46339
46703
  entrypoints: init.entrypoints,
@@ -46354,7 +46718,7 @@ async function appendMemoryNote(cwd, scope, text, agentId) {
46354
46718
  throw new Error("Agent memory updates require an agent id.");
46355
46719
  }
46356
46720
  return appendMarkdownSection(
46357
- import_node_path27.default.join(resolveAgentMemoryDir(cwd), `${agentId}.md`),
46721
+ import_node_path28.default.join(resolveAgentMemoryDir(cwd), `${agentId}.md`),
46358
46722
  "Note",
46359
46723
  text
46360
46724
  );
@@ -46364,7 +46728,7 @@ async function appendMemoryNote(cwd, scope, text, agentId) {
46364
46728
  async function listMemoryPaths(cwd) {
46365
46729
  await ensureMemoryDirs(cwd);
46366
46730
  return {
46367
- initFilePath: import_node_path27.default.join(cwd, "kimbho_init.md"),
46731
+ initFilePath: import_node_path28.default.join(cwd, "kimbho_init.md"),
46368
46732
  projectMemoryPath: resolveProjectMemoryPath(cwd),
46369
46733
  userMemoryPath: resolveUserMemoryPath(),
46370
46734
  adaptiveProjectMemoryPath: resolveAdaptiveProjectMemoryPath(cwd),
@@ -46726,7 +47090,7 @@ function createDoctorCommand() {
46726
47090
  });
46727
47091
  }
46728
47092
 
46729
- // src/commands/fork.ts
47093
+ // src/commands/fix.ts
46730
47094
  var import_node_process17 = __toESM(require("node:process"), 1);
46731
47095
  function parseCount3(value) {
46732
47096
  const parsed = Number(value);
@@ -46735,6 +47099,111 @@ function parseCount3(value) {
46735
47099
  }
46736
47100
  return parsed;
46737
47101
  }
47102
+ function buildFixPrompt(issue2, review) {
47103
+ const lines = [
47104
+ issue2?.trim() ? `Fix request: ${issue2.trim()}` : "Fix the current repository issue.",
47105
+ "Diagnose the failing behavior first, identify the root cause, implement the minimum safe fix, and verify the result before finishing."
47106
+ ];
47107
+ if (!review) {
47108
+ return lines.join("\n\n");
47109
+ }
47110
+ lines.push(
47111
+ "Use the current repository state and review context below as additional evidence.",
47112
+ [
47113
+ "Review context:",
47114
+ `- source: ${review.source}`,
47115
+ `- risk: ${review.riskLevel}`,
47116
+ `- changed files: ${review.changedFiles.length > 0 ? review.changedFiles.join(", ") : "none recorded"}`,
47117
+ `- summary: ${review.summary}`,
47118
+ ...review.findings.length > 0 ? review.findings.slice(0, 5).map((finding) => `- finding: [${finding.severity}] ${finding.title}${finding.file ? ` (${finding.file})` : ""} :: ${finding.detail}`) : [
47119
+ "- findings: none recorded"
47120
+ ],
47121
+ ...review.missingVerification.length > 0 ? review.missingVerification.map((item) => `- missing verification: ${item}`) : [
47122
+ "- missing verification: none recorded"
47123
+ ],
47124
+ `- review artifact: ${review.artifactPath}`
47125
+ ].join("\n")
47126
+ );
47127
+ return lines.join("\n\n");
47128
+ }
47129
+ function renderFixTextOutput(input, result, review) {
47130
+ const lines = [
47131
+ `Goal: ${input.prompt}`
47132
+ ];
47133
+ if (review) {
47134
+ lines.push(`Diagnostic review: ${review.artifactPath}`);
47135
+ lines.push(`Risk: ${review.riskLevel}`);
47136
+ lines.push("");
47137
+ }
47138
+ lines.push(result.textOutput);
47139
+ return lines.join("\n");
47140
+ }
47141
+ function createFixCommand() {
47142
+ return new Command("fix").description("Diagnose the current repository issue, implement the minimum safe fix, and verify the result.").argument("[issue]", "Optional issue description or failure symptom").option("--json", "Print the fix payload as JSON", false).option("--patch <path>", "Use a patch file as additional diagnostic context").option("--agent <id>", "Prefer one custom or plugin agent id for this invocation").option("--agents <jsonOrPath>", "Inline agent definitions as JSON or a path to a JSON file").option("--session-id <id>", "Use an explicit session id for the repair run").option("--ephemeral", "Do not persist plans or sessions for this invocation", false).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount3, 4).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount3, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount3, 2).option("--max-tool-calls <count>", "Maximum tool calls per autonomous task", parseCount3).option("--max-model-calls <count>", "Maximum model calls per autonomous task", parseCount3).option("--max-input-tokens <count>", "Maximum input tokens per autonomous task", parseCount3).option("--max-output-tokens <count>", "Maximum output tokens per autonomous task", parseCount3).action(async (issue2, options) => {
47143
+ const cwd = import_node_process17.default.cwd();
47144
+ const agentSelection = await resolveAgentSelection(cwd, {
47145
+ agent: options.agent,
47146
+ agents: options.agents
47147
+ });
47148
+ const review = await reviewWorkspace(cwd, {
47149
+ patchPath: options.patch
47150
+ }).catch(() => null);
47151
+ const input = {
47152
+ prompt: buildFixPrompt(issue2, review),
47153
+ messages: [],
47154
+ attachments: []
47155
+ };
47156
+ const result = await executePromptByIntent(cwd, input, {
47157
+ intent: "run",
47158
+ outputFormat: options.json ? "json" : "text",
47159
+ sessionId: options.sessionId,
47160
+ ephemeral: options.ephemeral,
47161
+ maxAutoTasks: options.maxAutoTasks,
47162
+ maxAgentSteps: options.maxAgentSteps,
47163
+ maxRepairAttempts: options.maxRepairAttempts,
47164
+ ...typeof options.maxToolCalls === "number" ? {
47165
+ maxToolCalls: options.maxToolCalls
47166
+ } : {},
47167
+ ...typeof options.maxModelCalls === "number" ? {
47168
+ maxModelCalls: options.maxModelCalls
47169
+ } : {},
47170
+ ...typeof options.maxInputTokens === "number" ? {
47171
+ maxInputTokens: options.maxInputTokens
47172
+ } : {},
47173
+ ...typeof options.maxOutputTokens === "number" ? {
47174
+ maxOutputTokens: options.maxOutputTokens
47175
+ } : {},
47176
+ ...agentSelection ? {
47177
+ agentSelection
47178
+ } : {}
47179
+ });
47180
+ if (options.json) {
47181
+ console.log(renderJson({
47182
+ mode: "fix",
47183
+ goal: input.prompt,
47184
+ review: review ? {
47185
+ source: review.source,
47186
+ riskLevel: review.riskLevel,
47187
+ changedFiles: review.changedFiles,
47188
+ artifactPath: review.artifactPath
47189
+ } : null,
47190
+ result: result.payload
47191
+ }));
47192
+ return;
47193
+ }
47194
+ console.log(renderFixTextOutput(input, result, review));
47195
+ });
47196
+ }
47197
+
47198
+ // src/commands/fork.ts
47199
+ var import_node_process18 = __toESM(require("node:process"), 1);
47200
+ function parseCount4(value) {
47201
+ const parsed = Number(value);
47202
+ if (!Number.isInteger(parsed) || parsed <= 0) {
47203
+ throw new Error(`Expected a positive integer, received "${value}".`);
47204
+ }
47205
+ return parsed;
47206
+ }
46738
47207
  function printSessionList(rows) {
46739
47208
  if (rows.length === 0) {
46740
47209
  console.log("No saved sessions found.");
@@ -46759,8 +47228,8 @@ async function resolveSourceSession(cwd, sessionId, last = false, search) {
46759
47228
  return loadSessionById(sessionId, cwd);
46760
47229
  }
46761
47230
  function createForkCommand() {
46762
- return new Command("fork").description("Fork a saved session into a new session snapshot.").argument("[sessionId]", "Optional session id; defaults to the latest session").option("--last", "Fork the most recent session", false).option("--list", "List recent sessions and exit", false).option("--search <query>", "Filter sessions by id, goal, cwd, or labels").option("--json", "Print the forked snapshot as JSON", false).option("--execute", "Continue auto-executing the forked session", false).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount3, 4).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount3, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount3, 2).option("--max-tool-calls <count>", "Maximum tool calls per autonomous task", parseCount3).option("--max-model-calls <count>", "Maximum model calls per autonomous task", parseCount3).option("--max-input-tokens <count>", "Maximum input tokens per autonomous task", parseCount3).option("--max-output-tokens <count>", "Maximum output tokens per autonomous task", parseCount3).action(async (sessionId, options) => {
46763
- const cwd = import_node_process17.default.cwd();
47231
+ return new Command("fork").description("Fork a saved session into a new session snapshot.").argument("[sessionId]", "Optional session id; defaults to the latest session").option("--last", "Fork the most recent session", false).option("--list", "List recent sessions and exit", false).option("--search <query>", "Filter sessions by id, goal, cwd, or labels").option("--json", "Print the forked snapshot as JSON", false).option("--execute", "Continue auto-executing the forked session", false).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount4, 4).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount4, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount4, 2).option("--max-tool-calls <count>", "Maximum tool calls per autonomous task", parseCount4).option("--max-model-calls <count>", "Maximum model calls per autonomous task", parseCount4).option("--max-input-tokens <count>", "Maximum input tokens per autonomous task", parseCount4).option("--max-output-tokens <count>", "Maximum output tokens per autonomous task", parseCount4).action(async (sessionId, options) => {
47232
+ const cwd = import_node_process18.default.cwd();
46764
47233
  if (options.list) {
46765
47234
  const sessions = options.search ? await searchSessions(options.search, cwd) : await listSessions(cwd);
46766
47235
  if (options.json) {
@@ -46773,7 +47242,7 @@ function createForkCommand() {
46773
47242
  const source = await resolveSourceSession(cwd, sessionId, options.last, options.search);
46774
47243
  if (!source) {
46775
47244
  console.error("No saved session found.");
46776
- import_node_process17.default.exitCode = 1;
47245
+ import_node_process18.default.exitCode = 1;
46777
47246
  return;
46778
47247
  }
46779
47248
  const forked = forkSessionSnapshot(source);
@@ -46811,7 +47280,7 @@ function createForkCommand() {
46811
47280
  }
46812
47281
 
46813
47282
  // src/commands/init.ts
46814
- var import_node_process18 = __toESM(require("node:process"), 1);
47283
+ var import_node_process19 = __toESM(require("node:process"), 1);
46815
47284
  function printProjectUnderstanding(result) {
46816
47285
  console.log(result.summary);
46817
47286
  console.log("Now I have a durable understanding of the current project structure.");
@@ -46830,7 +47299,7 @@ function printProjectUnderstanding(result) {
46830
47299
  }
46831
47300
  function createInitCommand() {
46832
47301
  return new Command("init").description("Create or refresh local Kimbho config and project bootstrap memory.").option("--template <template>", "Provider template to use for the initial provider").option("--provider-id <id>", "Identifier for the initial provider").option("--driver <driver>", "Provider driver to use when no template is supplied").option("--label <label>", "Human-readable provider label").option("--model <model>", "Default model to use for planner/coder/reviewer brains").option("--fast-model <model>", "Model to use for the fast utility brain").option("--api-key-env <env>", "Environment variable that stores the provider API key").option("--base-url <url>", "Base URL or endpoint for the provider driver").option("--module-path <path>", "Module path for a custom provider driver").option("--config-only", "Only write .kimbho/config.toml and skip project memory generation", false).option("--memory-only", "Only generate kimbho_init.md and keep the existing config untouched", false).option("--memory-file <file>", "Project memory file to write", "kimbho_init.md").option("--force", "Overwrite an existing config file", false).action(async (options) => {
46833
- const existing = await loadConfig(import_node_process18.default.cwd());
47302
+ const existing = await loadConfig(import_node_process19.default.cwd());
46834
47303
  const configMutationRequested = [
46835
47304
  options.template,
46836
47305
  options.providerId,
@@ -46844,12 +47313,12 @@ function createInitCommand() {
46844
47313
  ].some((value) => typeof value === "string" && value.trim().length > 0);
46845
47314
  if (options.configOnly && options.memoryOnly) {
46846
47315
  console.error("Choose either --config-only or --memory-only, not both.");
46847
- import_node_process18.default.exitCode = 1;
47316
+ import_node_process19.default.exitCode = 1;
46848
47317
  return;
46849
47318
  }
46850
47319
  if (existing && !options.force && configMutationRequested && !options.memoryOnly) {
46851
47320
  console.error("Config already exists. Re-run with --force to overwrite it.");
46852
- import_node_process18.default.exitCode = 1;
47321
+ import_node_process19.default.exitCode = 1;
46853
47322
  return;
46854
47323
  }
46855
47324
  if (!options.memoryOnly) {
@@ -46887,20 +47356,20 @@ function createInitCommand() {
46887
47356
  defaultModel: options.model ?? provider.defaultModel,
46888
47357
  fastModel: options.fastModel ?? options.model ?? provider.defaultModel
46889
47358
  });
46890
- const outputPath = await saveConfig(nextConfig, import_node_process18.default.cwd());
47359
+ const outputPath = await saveConfig(nextConfig, import_node_process19.default.cwd());
46891
47360
  console.log(`Created ${outputPath}`);
46892
47361
  }
46893
47362
  }
46894
47363
  if (!options.configOnly) {
46895
- const result = await refreshMemoryFiles(import_node_process18.default.cwd());
47364
+ const result = await refreshMemoryFiles(import_node_process19.default.cwd());
46896
47365
  printProjectUnderstanding(result);
46897
47366
  }
46898
47367
  });
46899
47368
  }
46900
47369
 
46901
47370
  // src/commands/ide.ts
46902
- var import_node_path28 = __toESM(require("node:path"), 1);
46903
- var import_node_process19 = __toESM(require("node:process"), 1);
47371
+ var import_node_path29 = __toESM(require("node:path"), 1);
47372
+ var import_node_process20 = __toESM(require("node:process"), 1);
46904
47373
  function renderIdeState(state) {
46905
47374
  if (!state) {
46906
47375
  return "No IDE companion is linked.";
@@ -46918,27 +47387,27 @@ function renderIdeState(state) {
46918
47387
  function createIdeCommand() {
46919
47388
  const command = new Command("ide").description("Discover, link, and open the active workspace in a local IDE companion.");
46920
47389
  command.command("status").description("Show the linked or detected IDE companion.").option("--json", "Print the IDE companion payload as JSON", false).action(async (options) => {
46921
- const state = await detectIdeBridge(import_node_process19.default.cwd());
47390
+ const state = await detectIdeBridge(import_node_process20.default.cwd());
46922
47391
  if (options.json) {
46923
47392
  console.log(JSON.stringify(state, null, 2));
46924
47393
  return;
46925
47394
  }
46926
47395
  console.log(renderIdeState(state));
46927
47396
  });
46928
- command.command("link").description("Persist a local IDE companion link for this workspace.").option("--editor <id>", "Editor id", "manual").option("--label <label>", "Human-readable label").option("--command <binary>", "Launcher command").option("--workspace <path>", "Workspace path", import_node_process19.default.cwd()).option("--json", "Print the IDE companion payload as JSON", false).action(async (options) => {
46929
- const detected = !options.command ? await detectIdeBridge(import_node_process19.default.cwd()) : null;
47397
+ command.command("link").description("Persist a local IDE companion link for this workspace.").option("--editor <id>", "Editor id", "manual").option("--label <label>", "Human-readable label").option("--command <binary>", "Launcher command").option("--workspace <path>", "Workspace path", import_node_process20.default.cwd()).option("--json", "Print the IDE companion payload as JSON", false).action(async (options) => {
47398
+ const detected = !options.command ? await detectIdeBridge(import_node_process20.default.cwd()) : null;
46930
47399
  const state = {
46931
47400
  editorId: options.command ? options.editor : detected?.editorId ?? options.editor,
46932
47401
  label: options.label ?? detected?.label ?? options.editor,
46933
47402
  command: options.command ?? detected?.command ?? options.editor,
46934
- workspace: import_node_path28.default.resolve(import_node_process19.default.cwd(), options.workspace),
47403
+ workspace: import_node_path29.default.resolve(import_node_process20.default.cwd(), options.workspace),
46935
47404
  source: options.command ? "manual" : detected?.source ?? "detected",
46936
47405
  linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
46937
47406
  ...detected?.lastOpenedPath ? {
46938
47407
  lastOpenedPath: detected.lastOpenedPath
46939
47408
  } : {}
46940
47409
  };
46941
- const outputPath = await saveIdeBridgeState(import_node_process19.default.cwd(), state);
47410
+ const outputPath = await saveIdeBridgeState(import_node_process20.default.cwd(), state);
46942
47411
  if (options.json) {
46943
47412
  console.log(JSON.stringify({
46944
47413
  state,
@@ -46950,13 +47419,13 @@ function createIdeCommand() {
46950
47419
  console.log(`Saved: ${outputPath}`);
46951
47420
  });
46952
47421
  command.command("open").description("Open one file or the current workspace in the linked IDE.").argument("[target]", "Optional file path; defaults to the current workspace", ".").option("--line <line>", "Open at a specific line", (value) => Number.parseInt(value, 10)).option("--column <column>", "Open at a specific column", (value) => Number.parseInt(value, 10)).option("--json", "Print the IDE companion payload as JSON", false).action(async (target, options) => {
46953
- const state = await openInIde(import_node_process19.default.cwd(), target, {
47422
+ const state = await openInIde(import_node_process20.default.cwd(), target, {
46954
47423
  line: Number.isInteger(options.line) && options.line > 0 ? options.line : void 0,
46955
47424
  column: Number.isInteger(options.column) && options.column > 0 ? options.column : void 0
46956
47425
  });
46957
47426
  const payload = {
46958
47427
  state,
46959
- target: import_node_path28.default.resolve(import_node_process19.default.cwd(), target)
47428
+ target: import_node_path29.default.resolve(import_node_process20.default.cwd(), target)
46960
47429
  };
46961
47430
  if (options.json) {
46962
47431
  console.log(JSON.stringify(payload, null, 2));
@@ -46968,7 +47437,7 @@ function createIdeCommand() {
46968
47437
  }
46969
47438
 
46970
47439
  // src/commands/update.ts
46971
- var import_node_process20 = __toESM(require("node:process"), 1);
47440
+ var import_node_process21 = __toESM(require("node:process"), 1);
46972
47441
  function renderUpdatePayload(payload) {
46973
47442
  return [
46974
47443
  `current: ${payload.currentVersion}`,
@@ -46997,7 +47466,7 @@ function createInstallCommand() {
46997
47466
  console.log(result.detail);
46998
47467
  }
46999
47468
  if (!result.ok) {
47000
- import_node_process20.default.exitCode = 1;
47469
+ import_node_process21.default.exitCode = 1;
47001
47470
  }
47002
47471
  return;
47003
47472
  }
@@ -47010,7 +47479,7 @@ function createInstallCommand() {
47010
47479
  }
47011
47480
  function createUpdateCommand(commandName = "update") {
47012
47481
  return new Command(commandName).description(commandName === "upgrade" ? "Check for and optionally install a newer Kimbho CLI build." : "Check for and optionally install a newer Kimbho CLI build.").option("--apply", "Run the global npm install command immediately when an update exists", false).option("--json", "Print the update payload as JSON", false).action(async (options) => {
47013
- const payload = await resolveUpdateManifest(import_node_process20.default.cwd());
47482
+ const payload = await resolveUpdateManifest(import_node_process21.default.cwd());
47014
47483
  const updateAvailable = isUpgradeAvailable(payload);
47015
47484
  if (options.apply && updateAvailable) {
47016
47485
  const result = runGlobalNpmInstall(payload.latestVersion);
@@ -47024,7 +47493,7 @@ function createUpdateCommand(commandName = "update") {
47024
47493
  console.log(result.detail);
47025
47494
  }
47026
47495
  if (!result.ok) {
47027
- import_node_process20.default.exitCode = 1;
47496
+ import_node_process21.default.exitCode = 1;
47028
47497
  }
47029
47498
  return;
47030
47499
  }
@@ -47041,7 +47510,7 @@ function createUpdateCommand(commandName = "update") {
47041
47510
  }
47042
47511
 
47043
47512
  // src/commands/mcp.ts
47044
- var import_node_process21 = __toESM(require("node:process"), 1);
47513
+ var import_node_process22 = __toESM(require("node:process"), 1);
47045
47514
 
47046
47515
  // src/mcp.ts
47047
47516
  async function renderMcpServerList(cwd) {
@@ -47205,7 +47674,7 @@ function collectValues(value, previous = []) {
47205
47674
  function createMcpCommand() {
47206
47675
  const command = new Command("mcp").description("Manage project-local MCP servers in .mcp.json.");
47207
47676
  command.command("list").description("List configured MCP servers.").action(async () => {
47208
- for (const line of await renderMcpServerList(import_node_process21.default.cwd())) {
47677
+ for (const line of await renderMcpServerList(import_node_process22.default.cwd())) {
47209
47678
  console.log(line);
47210
47679
  }
47211
47680
  });
@@ -47213,7 +47682,7 @@ function createMcpCommand() {
47213
47682
  const env = Object.fromEntries(
47214
47683
  options.env.map((pair) => pair.split("=", 2)).filter((entry) => entry.length === 2 && entry[0].length > 0)
47215
47684
  );
47216
- const outputPath = await addMcpServer(import_node_process21.default.cwd(), name, {
47685
+ const outputPath = await addMcpServer(import_node_process22.default.cwd(), name, {
47217
47686
  command: options.command,
47218
47687
  args: options.arg,
47219
47688
  env,
@@ -47227,34 +47696,34 @@ function createMcpCommand() {
47227
47696
  console.log(`Updated ${outputPath}`);
47228
47697
  });
47229
47698
  command.command("remove").description("Remove an MCP server.").argument("<name>", "Server name").action(async (name) => {
47230
- const outputPath = await removeMcpServerByName(import_node_process21.default.cwd(), name);
47699
+ const outputPath = await removeMcpServerByName(import_node_process22.default.cwd(), name);
47231
47700
  console.log(`Updated ${outputPath}`);
47232
47701
  });
47233
47702
  command.command("enable").description("Enable an MCP server.").argument("<name>", "Server name").action(async (name) => {
47234
- const outputPath = await toggleMcpServer(import_node_process21.default.cwd(), name, true);
47703
+ const outputPath = await toggleMcpServer(import_node_process22.default.cwd(), name, true);
47235
47704
  console.log(`Updated ${outputPath}`);
47236
47705
  });
47237
47706
  command.command("disable").description("Disable an MCP server.").argument("<name>", "Server name").action(async (name) => {
47238
- const outputPath = await toggleMcpServer(import_node_process21.default.cwd(), name, false);
47707
+ const outputPath = await toggleMcpServer(import_node_process22.default.cwd(), name, false);
47239
47708
  console.log(`Updated ${outputPath}`);
47240
47709
  });
47241
47710
  command.command("tools").description("Inspect MCP tool, prompt, and resource inventory.").argument("[name]", "Optional server name").action(async (name) => {
47242
- for (const line of await renderMcpInventory(import_node_process21.default.cwd(), name)) {
47711
+ for (const line of await renderMcpInventory(import_node_process22.default.cwd(), name)) {
47243
47712
  console.log(line);
47244
47713
  }
47245
47714
  });
47246
47715
  command.command("discover").description("Show MCP tools, prompts-as-commands, and resource attachment syntax.").argument("[name]", "Optional server name").action(async (name) => {
47247
- for (const line of await renderMcpInventory(import_node_process21.default.cwd(), name)) {
47716
+ for (const line of await renderMcpInventory(import_node_process22.default.cwd(), name)) {
47248
47717
  console.log(line);
47249
47718
  }
47250
47719
  });
47251
47720
  command.command("prompts").description("List MCP prompts.").argument("[name]", "Optional server name").action(async (name) => {
47252
- for (const line of await renderMcpPromptList(import_node_process21.default.cwd(), name)) {
47721
+ for (const line of await renderMcpPromptList(import_node_process22.default.cwd(), name)) {
47253
47722
  console.log(line);
47254
47723
  }
47255
47724
  });
47256
47725
  command.command("resources").description("List MCP resources and resource templates.").argument("[name]", "Optional server name").action(async (name) => {
47257
- for (const line of await renderMcpResourceList(import_node_process21.default.cwd(), name)) {
47726
+ for (const line of await renderMcpResourceList(import_node_process22.default.cwd(), name)) {
47258
47727
  console.log(line);
47259
47728
  }
47260
47729
  });
@@ -47262,12 +47731,12 @@ function createMcpCommand() {
47262
47731
  const args = Object.fromEntries(
47263
47732
  rawArgs.map((entry) => entry.split("=", 2)).filter((parts) => parts.length === 2 && parts[0].length > 0)
47264
47733
  );
47265
- for (const line of await renderMcpPromptInvocation(import_node_process21.default.cwd(), server, prompt, args)) {
47734
+ for (const line of await renderMcpPromptInvocation(import_node_process22.default.cwd(), server, prompt, args)) {
47266
47735
  console.log(line);
47267
47736
  }
47268
47737
  });
47269
47738
  command.command("read").description("Read one MCP resource by URI.").argument("<server>", "Server name").argument("<uri>", "Resource URI").action(async (server, uri) => {
47270
- for (const line of await renderMcpResourceRead(import_node_process21.default.cwd(), server, uri)) {
47739
+ for (const line of await renderMcpResourceRead(import_node_process22.default.cwd(), server, uri)) {
47271
47740
  console.log(line);
47272
47741
  }
47273
47742
  });
@@ -47275,20 +47744,20 @@ function createMcpCommand() {
47275
47744
  }
47276
47745
 
47277
47746
  // src/commands/mcp-server.ts
47278
- var import_node_process22 = __toESM(require("node:process"), 1);
47747
+ var import_node_process23 = __toESM(require("node:process"), 1);
47279
47748
  function createMcpServerCommand() {
47280
47749
  return new Command("mcp-server").description("Run Kimbho as an MCP server over stdio.").action(async () => {
47281
- await runMcpServer(import_node_process22.default.cwd());
47750
+ await runMcpServer(import_node_process23.default.cwd());
47282
47751
  });
47283
47752
  }
47284
47753
 
47285
47754
  // src/commands/memory.ts
47286
- var import_node_path29 = __toESM(require("node:path"), 1);
47287
- var import_node_process23 = __toESM(require("node:process"), 1);
47755
+ var import_node_path30 = __toESM(require("node:path"), 1);
47756
+ var import_node_process24 = __toESM(require("node:process"), 1);
47288
47757
  function createMemoryCommand() {
47289
47758
  const command = new Command("memory").description("Manage markdown-backed Kimbho memory files.");
47290
47759
  command.command("status").description("Show the memory file locations.").action(async () => {
47291
- const paths = await listMemoryPaths(import_node_process23.default.cwd());
47760
+ const paths = await listMemoryPaths(import_node_process24.default.cwd());
47292
47761
  console.log(`init: ${paths.initFilePath}`);
47293
47762
  console.log(`project: ${paths.projectMemoryPath}`);
47294
47763
  console.log(`user: ${paths.userMemoryPath}`);
@@ -47298,7 +47767,7 @@ function createMemoryCommand() {
47298
47767
  console.log(`agents: ${paths.agentMemoryDir}`);
47299
47768
  });
47300
47769
  command.command("refresh").description("Refresh kimbho_init.md and project memory.").action(async () => {
47301
- const result = await refreshMemoryFiles(import_node_process23.default.cwd());
47770
+ const result = await refreshMemoryFiles(import_node_process24.default.cwd());
47302
47771
  console.log(result.summary);
47303
47772
  console.log(`Wrote ${result.initFilePath}`);
47304
47773
  console.log(`Wrote ${result.projectMemoryPath}`);
@@ -47307,16 +47776,16 @@ function createMemoryCommand() {
47307
47776
  command.command("show").description("Print one memory file.").argument("<scope>", "init, project, user, or agent").argument("[agentId]", "Agent id when scope is agent").action(async (scope, agentId) => {
47308
47777
  let filePath;
47309
47778
  if (scope === "init") {
47310
- filePath = import_node_path29.default.join(import_node_process23.default.cwd(), "kimbho_init.md");
47779
+ filePath = import_node_path30.default.join(import_node_process24.default.cwd(), "kimbho_init.md");
47311
47780
  } else if (scope === "project") {
47312
- filePath = resolveProjectMemoryPath(import_node_process23.default.cwd());
47781
+ filePath = resolveProjectMemoryPath(import_node_process24.default.cwd());
47313
47782
  } else if (scope === "user") {
47314
47783
  filePath = resolveUserMemoryPath();
47315
47784
  } else if (scope === "agent") {
47316
47785
  if (!agentId) {
47317
47786
  throw new Error("Pass an agent id when using scope=agent.");
47318
47787
  }
47319
- filePath = import_node_path29.default.join(resolveAgentMemoryDir(import_node_process23.default.cwd()), `${agentId}.md`);
47788
+ filePath = import_node_path30.default.join(resolveAgentMemoryDir(import_node_process24.default.cwd()), `${agentId}.md`);
47320
47789
  } else {
47321
47790
  throw new Error("Scope must be one of: init, project, user, agent.");
47322
47791
  }
@@ -47329,7 +47798,7 @@ function createMemoryCommand() {
47329
47798
  });
47330
47799
  command.command("add").description("Append a memory note.").argument("<scope>", "project, user, or agent").argument("<first>", "Text or agent id when scope=agent").argument("[rest...]", "Remaining note text").action(async (scope, first, rest = []) => {
47331
47800
  if (scope === "project" || scope === "user") {
47332
- const outputPath = await appendMemoryNote(import_node_process23.default.cwd(), scope, [
47801
+ const outputPath = await appendMemoryNote(import_node_process24.default.cwd(), scope, [
47333
47802
  first,
47334
47803
  ...rest
47335
47804
  ].join(" "));
@@ -47337,7 +47806,7 @@ function createMemoryCommand() {
47337
47806
  return;
47338
47807
  }
47339
47808
  if (scope === "agent") {
47340
- const outputPath = await appendMemoryNote(import_node_process23.default.cwd(), "agent", rest.join(" "), first);
47809
+ const outputPath = await appendMemoryNote(import_node_process24.default.cwd(), "agent", rest.join(" "), first);
47341
47810
  console.log(`Updated ${outputPath}`);
47342
47811
  return;
47343
47812
  }
@@ -47347,7 +47816,7 @@ function createMemoryCommand() {
47347
47816
  }
47348
47817
 
47349
47818
  // src/commands/model.ts
47350
- var import_node_process24 = __toESM(require("node:process"), 1);
47819
+ var import_node_process25 = __toESM(require("node:process"), 1);
47351
47820
  function requireConfig() {
47352
47821
  throw new Error("No config found. Run `kimbho init` first.");
47353
47822
  }
@@ -47370,7 +47839,7 @@ async function fetchModels(provider, options) {
47370
47839
  models: cachedModels
47371
47840
  };
47372
47841
  }
47373
- const registry2 = createDefaultBrainProviderRegistry(import_node_process24.default.cwd());
47842
+ const registry2 = createDefaultBrainProviderRegistry(import_node_process25.default.cwd());
47374
47843
  try {
47375
47844
  const models = await registry2.listModels(provider, {
47376
47845
  ...options.search ? {
@@ -47412,14 +47881,14 @@ function printAssignments(config2) {
47412
47881
  function createModelCommand() {
47413
47882
  const command = new Command("model").description("Use one MECE surface for providers, models, and role assignments.");
47414
47883
  command.command("show").description("Show current provider/model assignments.").action(async () => {
47415
- const config2 = await loadConfig(import_node_process24.default.cwd());
47884
+ const config2 = await loadConfig(import_node_process25.default.cwd());
47416
47885
  if (!config2) {
47417
47886
  requireConfig();
47418
47887
  }
47419
47888
  printAssignments(config2);
47420
47889
  });
47421
47890
  command.command("providers").description("List configured providers.").action(async () => {
47422
- const config2 = await loadConfig(import_node_process24.default.cwd());
47891
+ const config2 = await loadConfig(import_node_process25.default.cwd());
47423
47892
  if (!config2) {
47424
47893
  requireConfig();
47425
47894
  }
@@ -47442,7 +47911,7 @@ function createModelCommand() {
47442
47911
  }
47443
47912
  });
47444
47913
  command.command("add").description("Add a provider from a template.").argument("<template>", "Template id").argument("[providerId]", "Optional provider id").option("--label <label>", "Provider label").option("--base-url <url>", "Base URL override").option("--api-key-env <env>", "API key environment variable").option("--model <id>", "Default model").action(async (templateId, providerId, options) => {
47445
- const config2 = await loadConfig(import_node_process24.default.cwd());
47914
+ const config2 = await loadConfig(import_node_process25.default.cwd());
47446
47915
  if (!config2) {
47447
47916
  requireConfig();
47448
47917
  }
@@ -47453,12 +47922,12 @@ function createModelCommand() {
47453
47922
  apiKeyEnv: options.apiKeyEnv,
47454
47923
  model: options.model
47455
47924
  });
47456
- const outputPath = await saveConfig(upsertProvider(config2, provider), import_node_process24.default.cwd());
47925
+ const outputPath = await saveConfig(upsertProvider(config2, provider), import_node_process25.default.cwd());
47457
47926
  console.log(`Updated ${outputPath}`);
47458
47927
  console.log(`Added ${provider.id} via ${templateId}`);
47459
47928
  });
47460
47929
  command.command("find").description("Find models on a provider.").argument("[search]", "Optional search text").option("--provider <id>", "Provider id; defaults to coder provider").option("--limit <count>", "Max number of models", parseInteger, 20).option("--cached", "Use cached provider models", false).action(async (search, options) => {
47461
- const config2 = await loadConfig(import_node_process24.default.cwd());
47930
+ const config2 = await loadConfig(import_node_process25.default.cwd());
47462
47931
  if (!config2) {
47463
47932
  requireConfig();
47464
47933
  }
@@ -47483,7 +47952,7 @@ function createModelCommand() {
47483
47952
  }
47484
47953
  });
47485
47954
  command.command("use").description("Assign one provider/model globally or to one role.").argument("<provider>", "Provider id").argument("[model]", "Optional model id").option("--role <role>", "Optional role override").action(async (providerId, modelId, options) => {
47486
- let config2 = await loadConfig(import_node_process24.default.cwd());
47955
+ let config2 = await loadConfig(import_node_process25.default.cwd());
47487
47956
  if (!config2) {
47488
47957
  requireConfig();
47489
47958
  }
@@ -47500,7 +47969,7 @@ function createModelCommand() {
47500
47969
  } else {
47501
47970
  config2 = assignProviderToAllBrains(config2, providerId);
47502
47971
  }
47503
- const outputPath2 = await saveConfig(config2, import_node_process24.default.cwd());
47972
+ const outputPath2 = await saveConfig(config2, import_node_process25.default.cwd());
47504
47973
  console.log(`Updated ${outputPath2}`);
47505
47974
  console.log(options.role ? `Assigned ${providerId} to ${options.role}` : `Assigned ${providerId} to all roles`);
47506
47975
  return;
@@ -47538,16 +48007,16 @@ function createModelCommand() {
47538
48007
  model: modelId
47539
48008
  });
47540
48009
  }
47541
- const outputPath = await saveConfig(config2, import_node_process24.default.cwd());
48010
+ const outputPath = await saveConfig(config2, import_node_process25.default.cwd());
47542
48011
  console.log(`Updated ${outputPath}`);
47543
48012
  console.log(options.role ? `Assigned ${providerId}/${modelId} to ${options.role}` : `Assigned ${providerId}/${modelId} to all roles`);
47544
48013
  });
47545
48014
  command.command("check").description("Run health checks for configured providers.").action(async () => {
47546
- const config2 = await loadConfig(import_node_process24.default.cwd());
48015
+ const config2 = await loadConfig(import_node_process25.default.cwd());
47547
48016
  if (!config2) {
47548
48017
  requireConfig();
47549
48018
  }
47550
- const registry2 = createDefaultBrainProviderRegistry(import_node_process24.default.cwd());
48019
+ const registry2 = createDefaultBrainProviderRegistry(import_node_process25.default.cwd());
47551
48020
  for (const provider of config2.providers) {
47552
48021
  try {
47553
48022
  const result = await registry2.healthCheck(provider);
@@ -47559,7 +48028,7 @@ function createModelCommand() {
47559
48028
  }
47560
48029
  });
47561
48030
  command.action(async () => {
47562
- const config2 = await loadConfig(import_node_process24.default.cwd());
48031
+ const config2 = await loadConfig(import_node_process25.default.cwd());
47563
48032
  if (!config2) {
47564
48033
  requireConfig();
47565
48034
  }
@@ -47569,7 +48038,7 @@ function createModelCommand() {
47569
48038
  }
47570
48039
 
47571
48040
  // src/commands/models.ts
47572
- var import_node_process25 = __toESM(require("node:process"), 1);
48041
+ var import_node_process26 = __toESM(require("node:process"), 1);
47573
48042
  function parseInteger2(value) {
47574
48043
  const parsed = Number.parseInt(value, 10);
47575
48044
  if (!Number.isFinite(parsed)) {
@@ -47628,7 +48097,7 @@ async function fetchProviderModels(provider, options) {
47628
48097
  models: cachedModels
47629
48098
  };
47630
48099
  }
47631
- const registry2 = createDefaultBrainProviderRegistry(import_node_process25.default.cwd());
48100
+ const registry2 = createDefaultBrainProviderRegistry(import_node_process26.default.cwd());
47632
48101
  try {
47633
48102
  const models = await registry2.listModels(provider, {
47634
48103
  ...options.search ? {
@@ -47655,7 +48124,7 @@ async function fetchProviderModels(provider, options) {
47655
48124
  function createModelsCommand() {
47656
48125
  const command = new Command("models").description("[legacy] Discover and select models from configured providers.");
47657
48126
  command.command("list").description("List models for one provider or all configured providers.").argument("[provider]", "Optional provider id to inspect").option("--search <term>", "Filter the returned models by search text").option("--limit <count>", "Maximum number of models to print", parseInteger2, 25).option("--cached", "Use cached models from config instead of remote discovery", false).option("--sync", "Persist discovered model ids back into config", false).option("--json", "Print models as JSON", false).action(async (providerId, options) => {
47658
- let config2 = await loadConfig(import_node_process25.default.cwd());
48127
+ let config2 = await loadConfig(import_node_process26.default.cwd());
47659
48128
  if (!config2) {
47660
48129
  requireConfigMessage2();
47661
48130
  }
@@ -47684,7 +48153,7 @@ function createModelsCommand() {
47684
48153
  }
47685
48154
  }
47686
48155
  if (mutated) {
47687
- await saveConfig(config2, import_node_process25.default.cwd());
48156
+ await saveConfig(config2, import_node_process26.default.cwd());
47688
48157
  }
47689
48158
  if (options.json) {
47690
48159
  console.log(renderJson(groups));
@@ -47701,7 +48170,7 @@ function createModelsCommand() {
47701
48170
  }
47702
48171
  });
47703
48172
  command.command("sync").description("Fetch remote models for one provider and cache the ids in config.").argument("<provider>", "Provider id to sync").option("--search <term>", "Optional search filter to limit what gets cached").option("--limit <count>", "Maximum number of models to cache", parseInteger2, 200).action(async (providerId, options) => {
47704
- const config2 = await loadConfig(import_node_process25.default.cwd());
48173
+ const config2 = await loadConfig(import_node_process26.default.cwd());
47705
48174
  if (!config2) {
47706
48175
  requireConfigMessage2();
47707
48176
  }
@@ -47709,7 +48178,7 @@ function createModelsCommand() {
47709
48178
  if (!provider) {
47710
48179
  throw new Error(`Unknown provider "${providerId}".`);
47711
48180
  }
47712
- const registry2 = createDefaultBrainProviderRegistry(import_node_process25.default.cwd());
48181
+ const registry2 = createDefaultBrainProviderRegistry(import_node_process26.default.cwd());
47713
48182
  const models = await registry2.listModels(provider, {
47714
48183
  ...options.search ? {
47715
48184
  search: options.search
@@ -47720,12 +48189,12 @@ function createModelsCommand() {
47720
48189
  ...provider,
47721
48190
  models: Array.from(new Set(models.map((model) => model.id)))
47722
48191
  });
47723
- const outputPath = await saveConfig(nextConfig, import_node_process25.default.cwd());
48192
+ const outputPath = await saveConfig(nextConfig, import_node_process26.default.cwd());
47724
48193
  console.log(`Updated ${outputPath}`);
47725
48194
  console.log(`Synced ${models.length} models for ${provider.id}`);
47726
48195
  });
47727
48196
  command.command("use").description("Select a model for a provider and assign it globally unless a specific role is requested.").argument("<model>", "Model id to select").requiredOption("--provider <provider>", "Provider id to use").option("--role <role>", "Brain role to assign: planner, coder, reviewer, or fast").option("--set-default", "Also set this model as the provider default", false).option("--force", "Skip remote model validation", false).option("--temperature <value>", "Temperature override for the role", parseNumber2).option("--max-tokens <value>", "Max token override for the role", parseInteger2).action(async (model, options) => {
47728
- let config2 = await loadConfig(import_node_process25.default.cwd());
48197
+ let config2 = await loadConfig(import_node_process26.default.cwd());
47729
48198
  if (!config2) {
47730
48199
  requireConfigMessage2();
47731
48200
  }
@@ -47735,7 +48204,7 @@ function createModelsCommand() {
47735
48204
  }
47736
48205
  if (!options.force) {
47737
48206
  try {
47738
- const registry2 = createDefaultBrainProviderRegistry(import_node_process25.default.cwd());
48207
+ const registry2 = createDefaultBrainProviderRegistry(import_node_process26.default.cwd());
47739
48208
  const models = await registry2.listModels(provider, {
47740
48209
  search: model,
47741
48210
  limit: 500
@@ -47777,7 +48246,7 @@ function createModelsCommand() {
47777
48246
  } else {
47778
48247
  config2 = assignProviderToAllBrains(config2, provider.id, model);
47779
48248
  }
47780
- const outputPath = await saveConfig(config2, import_node_process25.default.cwd());
48249
+ const outputPath = await saveConfig(config2, import_node_process26.default.cwd());
47781
48250
  console.log(`Updated ${outputPath}`);
47782
48251
  console.log(`Selected ${provider.id}/${model}`);
47783
48252
  if (options.role) {
@@ -47793,7 +48262,7 @@ function createModelsCommand() {
47793
48262
  }
47794
48263
 
47795
48264
  // src/commands/plan.ts
47796
- var import_node_process26 = __toESM(require("node:process"), 1);
48265
+ var import_node_process27 = __toESM(require("node:process"), 1);
47797
48266
  function createPlanCommand() {
47798
48267
  return new Command("plan").description("Generate a structured Kimbho execution plan for the provided goal.").argument("<goal>", "High-level product or engineering goal").option("--stack <stack>", "Preferred stack or preset").option(
47799
48268
  "--constraint <constraint>",
@@ -47801,7 +48270,7 @@ function createPlanCommand() {
47801
48270
  (value, previous = []) => [...previous, value],
47802
48271
  []
47803
48272
  ).option("--json", "Print the plan as JSON", false).action(async (goal, options) => {
47804
- const cwd = import_node_process26.default.cwd();
48273
+ const cwd = import_node_process27.default.cwd();
47805
48274
  const request = {
47806
48275
  goal,
47807
48276
  mode: "plan",
@@ -47858,8 +48327,8 @@ function createPlanCommand() {
47858
48327
  }
47859
48328
 
47860
48329
  // src/commands/permissions.ts
47861
- var import_node_process27 = __toESM(require("node:process"), 1);
47862
- var import_node_path30 = __toESM(require("node:path"), 1);
48330
+ var import_node_process28 = __toESM(require("node:process"), 1);
48331
+ var import_node_path31 = __toESM(require("node:path"), 1);
47863
48332
  function getScope2(options) {
47864
48333
  return options.scope === "user" ? "user" : "project";
47865
48334
  }
@@ -47878,7 +48347,7 @@ function createPermissionsCommand() {
47878
48347
  const command = new Command("permissions").description("Manage approval mode, sandbox mode, and trusted directories.");
47879
48348
  command.command("status").description("Show permission settings.").option("--scope <scope>", "project or user", "project").action(async (options) => {
47880
48349
  const scope = getScope2(options);
47881
- const { direct, resolved } = await loadScopedConfig2(scope, import_node_process27.default.cwd());
48350
+ const { direct, resolved } = await loadScopedConfig2(scope, import_node_process28.default.cwd());
47882
48351
  console.log(`scope: ${scope}`);
47883
48352
  console.log(`direct config: ${direct ? "present" : "missing"}`);
47884
48353
  if (!resolved) {
@@ -47900,7 +48369,7 @@ function createPermissionsCommand() {
47900
48369
  });
47901
48370
  command.command("set").description("Set approval mode or sandbox mode.").option("--scope <scope>", "project or user", "project").option("--approval <mode>", "manual, on-request, plan, auto, dontAsk, acceptEdits, or bypassPermissions").option("--sandbox <mode>", "read-only, workspace-write, or full").action(async (options) => {
47902
48371
  const scope = getScope2(options);
47903
- const cwd = import_node_process27.default.cwd();
48372
+ const cwd = import_node_process28.default.cwd();
47904
48373
  const { direct, resolved } = await loadScopedConfig2(scope, cwd);
47905
48374
  if (!resolved && !direct) {
47906
48375
  throw new Error("No config found. Run `kimbho init` first.");
@@ -47920,13 +48389,13 @@ function createPermissionsCommand() {
47920
48389
  });
47921
48390
  command.command("trust").description("Add a trusted directory.").argument("<path>", "Directory to trust").option("--scope <scope>", "project or user", "project").action(async (trustedPath, options) => {
47922
48391
  const scope = getScope2(options);
47923
- const cwd = import_node_process27.default.cwd();
48392
+ const cwd = import_node_process28.default.cwd();
47924
48393
  const { direct, resolved } = await loadScopedConfig2(scope, cwd);
47925
48394
  if (!resolved && !direct) {
47926
48395
  throw new Error("No config found. Run `kimbho init` first.");
47927
48396
  }
47928
48397
  const base = direct ?? resolved ?? createDefaultConfig();
47929
- const normalizedPath = import_node_path30.default.resolve(cwd, trustedPath);
48398
+ const normalizedPath = import_node_path31.default.resolve(cwd, trustedPath);
47930
48399
  const outputPath = await saveScopedConfig2(scope, cwd, {
47931
48400
  ...base,
47932
48401
  trustedDirectories: Array.from(/* @__PURE__ */ new Set([
@@ -47938,13 +48407,13 @@ function createPermissionsCommand() {
47938
48407
  });
47939
48408
  command.command("untrust").description("Remove a trusted directory.").argument("<path>", "Directory to remove").option("--scope <scope>", "project or user", "project").action(async (trustedPath, options) => {
47940
48409
  const scope = getScope2(options);
47941
- const cwd = import_node_process27.default.cwd();
48410
+ const cwd = import_node_process28.default.cwd();
47942
48411
  const { direct, resolved } = await loadScopedConfig2(scope, cwd);
47943
48412
  if (!resolved && !direct) {
47944
48413
  throw new Error("No config found. Run `kimbho init` first.");
47945
48414
  }
47946
48415
  const base = direct ?? resolved ?? createDefaultConfig();
47947
- const normalizedPath = import_node_path30.default.resolve(cwd, trustedPath);
48416
+ const normalizedPath = import_node_path31.default.resolve(cwd, trustedPath);
47948
48417
  const outputPath = await saveScopedConfig2(scope, cwd, {
47949
48418
  ...base,
47950
48419
  trustedDirectories: base.trustedDirectories.filter((directory) => directory !== trustedPath && directory !== normalizedPath)
@@ -47955,14 +48424,14 @@ function createPermissionsCommand() {
47955
48424
  }
47956
48425
 
47957
48426
  // src/commands/providers.ts
47958
- var import_node_process28 = __toESM(require("node:process"), 1);
48427
+ var import_node_process29 = __toESM(require("node:process"), 1);
47959
48428
  function requireConfigMessage3() {
47960
48429
  throw new Error("No config found. Run `kimbho init` first.");
47961
48430
  }
47962
48431
  function createProvidersCommand() {
47963
48432
  const command = new Command("providers").description("[legacy] Manage configured model providers and built-in templates.");
47964
48433
  command.command("list").description("List configured providers.").option("--json", "Print providers as JSON", false).action(async (options) => {
47965
- const config2 = await loadConfig(import_node_process28.default.cwd());
48434
+ const config2 = await loadConfig(import_node_process29.default.cwd());
47966
48435
  if (!config2) {
47967
48436
  requireConfigMessage3();
47968
48437
  }
@@ -48003,7 +48472,7 @@ function createProvidersCommand() {
48003
48472
  (value, previous = []) => [...previous, value],
48004
48473
  []
48005
48474
  ).option("--module-path <path>", "Module path for a custom provider driver").action(async (options) => {
48006
- const config2 = await loadConfig(import_node_process28.default.cwd());
48475
+ const config2 = await loadConfig(import_node_process29.default.cwd());
48007
48476
  if (!config2) {
48008
48477
  requireConfigMessage3();
48009
48478
  }
@@ -48037,16 +48506,16 @@ function createProvidersCommand() {
48037
48506
  } : {}
48038
48507
  });
48039
48508
  const nextConfig = upsertProvider(config2, provider);
48040
- const outputPath = await saveConfig(nextConfig, import_node_process28.default.cwd());
48509
+ const outputPath = await saveConfig(nextConfig, import_node_process29.default.cwd());
48041
48510
  console.log(`Updated ${outputPath}`);
48042
48511
  console.log(`Provider ${provider.id} -> ${provider.driver}`);
48043
48512
  });
48044
48513
  command.command("check").description("Run health checks for the configured providers.").action(async () => {
48045
- const config2 = await loadConfig(import_node_process28.default.cwd());
48514
+ const config2 = await loadConfig(import_node_process29.default.cwd());
48046
48515
  if (!config2) {
48047
48516
  requireConfigMessage3();
48048
48517
  }
48049
- const registry2 = createDefaultBrainProviderRegistry(import_node_process28.default.cwd());
48518
+ const registry2 = createDefaultBrainProviderRegistry(import_node_process29.default.cwd());
48050
48519
  for (const provider of config2.providers) {
48051
48520
  try {
48052
48521
  const result = await registry2.healthCheck(provider);
@@ -48061,10 +48530,10 @@ function createProvidersCommand() {
48061
48530
  }
48062
48531
 
48063
48532
  // src/commands/review.ts
48064
- var import_node_process29 = __toESM(require("node:process"), 1);
48533
+ var import_node_process30 = __toESM(require("node:process"), 1);
48065
48534
  function createReviewCommand() {
48066
48535
  return new Command("review").description("Review the current diff, summarize changed files, and surface risks.").option("--json", "Print the review payload as JSON", false).option("--patch <path>", "Review a patch file instead of the current git diff").action(async (options) => {
48067
- const cwd = import_node_process29.default.cwd();
48536
+ const cwd = import_node_process30.default.cwd();
48068
48537
  const payload = await reviewWorkspace(cwd, {
48069
48538
  patchPath: options.patch
48070
48539
  });
@@ -48097,8 +48566,8 @@ function createReviewCommand() {
48097
48566
  }
48098
48567
 
48099
48568
  // src/commands/resume.ts
48100
- var import_node_process30 = __toESM(require("node:process"), 1);
48101
- function parseCount4(value) {
48569
+ var import_node_process31 = __toESM(require("node:process"), 1);
48570
+ function parseCount5(value) {
48102
48571
  const parsed = Number(value);
48103
48572
  if (!Number.isInteger(parsed) || parsed <= 0) {
48104
48573
  throw new Error(`Expected a positive integer, received "${value}".`);
@@ -48106,8 +48575,8 @@ function parseCount4(value) {
48106
48575
  return parsed;
48107
48576
  }
48108
48577
  function createResumeCommand() {
48109
- return new Command("resume").alias("continue").description("Resume the latest saved Kimbho session snapshot.").argument("[sessionId]", "Optional session id; defaults to the latest session").option("--json", "Print the latest session as JSON", false).option("--last", "Resume the most recent session", false).option("--list", "List recent sessions and exit", false).option("--search <query>", "Filter sessions by id, goal, cwd, or labels").option("--pr <query>", "Filter sessions by linked PR url, repo, or number").option("--execute", "Continue auto-executing the ready-task frontier", false).option("--approve <approvalId>", "Approve a pending action before continuing").option("--deny <approvalId>", "Deny a pending action before continuing").option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount4, 4).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount4, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount4, 2).option("--max-tool-calls <count>", "Maximum tool calls per autonomous task", parseCount4).option("--max-model-calls <count>", "Maximum model calls per autonomous task", parseCount4).option("--max-input-tokens <count>", "Maximum input tokens per autonomous task", parseCount4).option("--max-output-tokens <count>", "Maximum output tokens per autonomous task", parseCount4).action(async (sessionId, options) => {
48110
- const cwd = import_node_process30.default.cwd();
48578
+ return new Command("resume").alias("continue").description("Resume the latest saved Kimbho session snapshot.").argument("[sessionId]", "Optional session id; defaults to the latest session").option("--json", "Print the latest session as JSON", false).option("--last", "Resume the most recent session", false).option("--list", "List recent sessions and exit", false).option("--search <query>", "Filter sessions by id, goal, cwd, or labels").option("--pr <query>", "Filter sessions by linked PR url, repo, or number").option("--execute", "Continue auto-executing the ready-task frontier", false).option("--approve <approvalId>", "Approve a pending action before continuing").option("--deny <approvalId>", "Deny a pending action before continuing").option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount5, 4).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount5, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount5, 2).option("--max-tool-calls <count>", "Maximum tool calls per autonomous task", parseCount5).option("--max-model-calls <count>", "Maximum model calls per autonomous task", parseCount5).option("--max-input-tokens <count>", "Maximum input tokens per autonomous task", parseCount5).option("--max-output-tokens <count>", "Maximum output tokens per autonomous task", parseCount5).action(async (sessionId, options) => {
48579
+ const cwd = import_node_process31.default.cwd();
48111
48580
  const effectiveSearch = options.pr?.trim() || options.search?.trim();
48112
48581
  const firstSearchMatch = effectiveSearch ? (await searchSessions(effectiveSearch, cwd, 1)).at(0) ?? null : null;
48113
48582
  if (options.list) {
@@ -48132,12 +48601,12 @@ function createResumeCommand() {
48132
48601
  const session = effectiveSearch && !sessionId && !options.last ? firstSearchMatch ? await loadSessionById(firstSearchMatch.id, cwd) : null : options.last || !sessionId ? await loadLatestSession(cwd) : await loadSessionById(sessionId, cwd);
48133
48602
  if (!session) {
48134
48603
  console.error("No saved session found. Run `kimbho run` first.");
48135
- import_node_process30.default.exitCode = 1;
48604
+ import_node_process31.default.exitCode = 1;
48136
48605
  return;
48137
48606
  }
48138
48607
  if (options.approve && options.deny) {
48139
48608
  console.error("Pass only one of --approve or --deny.");
48140
- import_node_process30.default.exitCode = 1;
48609
+ import_node_process31.default.exitCode = 1;
48141
48610
  return;
48142
48611
  }
48143
48612
  const snapshot = options.execute ? await new ExecutionOrchestrator().continueSession(session, {
@@ -48184,7 +48653,7 @@ function createResumeCommand() {
48184
48653
  }
48185
48654
 
48186
48655
  // src/commands/run.ts
48187
- var import_node_process31 = __toESM(require("node:process"), 1);
48656
+ var import_node_process32 = __toESM(require("node:process"), 1);
48188
48657
 
48189
48658
  // src/pr-link.ts
48190
48659
  function inferProvider(hostname2) {
@@ -48227,7 +48696,7 @@ function parsePrLinkFromUrl(value, overrides = {}) {
48227
48696
  }
48228
48697
 
48229
48698
  // src/commands/run.ts
48230
- function parseCount5(value) {
48699
+ function parseCount6(value) {
48231
48700
  const parsed = Number(value);
48232
48701
  if (!Number.isInteger(parsed) || parsed <= 0) {
48233
48702
  throw new Error(`Expected a positive integer, received "${value}".`);
@@ -48240,8 +48709,8 @@ function createRunCommand() {
48240
48709
  "Explicit execution constraint; can be provided multiple times",
48241
48710
  (value, previous = []) => [...previous, value],
48242
48711
  []
48243
- ).option("--json", "Print the session snapshot as JSON", false).option("--snapshot-only", "Create the session without auto-executing ready tasks", false).option("--agent <id>", "Prefer one custom or plugin agent id for this session").option("--agents <jsonOrPath>", "Inline agent definitions as JSON or a path to a JSON file").option("--session-id <id>", "Use an explicit session id").option("--pr-url <url>", "Link this session to a pull request URL").option("--ephemeral", "Do not persist plans or sessions for this invocation", false).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount5, 4).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount5, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount5, 2).option("--max-tool-calls <count>", "Maximum tool calls per autonomous task", parseCount5).option("--max-model-calls <count>", "Maximum model calls per autonomous task", parseCount5).option("--max-input-tokens <count>", "Maximum input tokens per autonomous task", parseCount5).option("--max-output-tokens <count>", "Maximum output tokens per autonomous task", parseCount5).action(async (goal, options) => {
48244
- const cwd = import_node_process31.default.cwd();
48712
+ ).option("--json", "Print the session snapshot as JSON", false).option("--snapshot-only", "Create the session without auto-executing ready tasks", false).option("--agent <id>", "Prefer one custom or plugin agent id for this session").option("--agents <jsonOrPath>", "Inline agent definitions as JSON or a path to a JSON file").option("--session-id <id>", "Use an explicit session id").option("--pr-url <url>", "Link this session to a pull request URL").option("--ephemeral", "Do not persist plans or sessions for this invocation", false).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount6, 4).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount6, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount6, 2).option("--max-tool-calls <count>", "Maximum tool calls per autonomous task", parseCount6).option("--max-model-calls <count>", "Maximum model calls per autonomous task", parseCount6).option("--max-input-tokens <count>", "Maximum input tokens per autonomous task", parseCount6).option("--max-output-tokens <count>", "Maximum output tokens per autonomous task", parseCount6).action(async (goal, options) => {
48713
+ const cwd = import_node_process32.default.cwd();
48245
48714
  const orchestrator = new ExecutionOrchestrator();
48246
48715
  const agentSelection = await resolveAgentSelection(cwd, {
48247
48716
  agent: options.agent,
@@ -48253,7 +48722,7 @@ function createRunCommand() {
48253
48722
  let planResult = null;
48254
48723
  if (!plan && !goal) {
48255
48724
  console.error("No saved plan found. Pass a goal or run `kimbho plan` first.");
48256
- import_node_process31.default.exitCode = 1;
48725
+ import_node_process32.default.exitCode = 1;
48257
48726
  return;
48258
48727
  }
48259
48728
  if (goal) {
@@ -48358,7 +48827,7 @@ function createRunCommand() {
48358
48827
  }
48359
48828
 
48360
48829
  // src/commands/skills.ts
48361
- var import_node_process32 = __toESM(require("node:process"), 1);
48830
+ var import_node_process33 = __toESM(require("node:process"), 1);
48362
48831
  function renderMetadataBlock(metadata) {
48363
48832
  return [
48364
48833
  ` userInvocable: ${String(metadata.userInvocable)}`,
@@ -48376,7 +48845,7 @@ function renderOriginLabel(definition) {
48376
48845
  function createSkillsCommand() {
48377
48846
  const command = new Command("skills").description("Inspect Kimbho-native skill packs and command packs, with .claude fallback compatibility.");
48378
48847
  command.action(async () => {
48379
- const skills = await listClaudeSkills(import_node_process32.default.cwd());
48848
+ const skills = await listClaudeSkills(import_node_process33.default.cwd());
48380
48849
  if (skills.length === 0) {
48381
48850
  console.log("No skill packs discovered.");
48382
48851
  return;
@@ -48387,7 +48856,7 @@ function createSkillsCommand() {
48387
48856
  }
48388
48857
  });
48389
48858
  command.command("list").description("List discovered skill packs from .kimbho/skills and .claude/skills.").action(async () => {
48390
- const skills = await listClaudeSkills(import_node_process32.default.cwd());
48859
+ const skills = await listClaudeSkills(import_node_process33.default.cwd());
48391
48860
  if (skills.length === 0) {
48392
48861
  console.log("No skill packs discovered.");
48393
48862
  return;
@@ -48398,7 +48867,7 @@ function createSkillsCommand() {
48398
48867
  }
48399
48868
  });
48400
48869
  command.command("commands").description("List discovered command packs from .kimbho/commands and .claude/commands.").option("--all", "Include commands marked user-invocable=false", false).action(async (options) => {
48401
- const commands = await listClaudeCommands(import_node_process32.default.cwd(), {
48870
+ const commands = await listClaudeCommands(import_node_process33.default.cwd(), {
48402
48871
  includeHidden: Boolean(options.all)
48403
48872
  });
48404
48873
  if (commands.length === 0) {
@@ -48411,7 +48880,7 @@ function createSkillsCommand() {
48411
48880
  }
48412
48881
  });
48413
48882
  command.command("inspect").description("Inspect one skill pack entry.").argument("<id>", "Skill id").action(async (id) => {
48414
- const skill = await loadClaudeSkillById(import_node_process32.default.cwd(), id);
48883
+ const skill = await loadClaudeSkillById(import_node_process33.default.cwd(), id);
48415
48884
  if (!skill) {
48416
48885
  throw new Error(`Unknown skill "${id}".`);
48417
48886
  }
@@ -48424,7 +48893,7 @@ function createSkillsCommand() {
48424
48893
  }
48425
48894
  });
48426
48895
  command.command("inspect-command").description("Inspect one command pack entry.").argument("<name>", "Command name").action(async (name) => {
48427
- const definition = await loadClaudeCommandByName(import_node_process32.default.cwd(), name, {
48896
+ const definition = await loadClaudeCommandByName(import_node_process33.default.cwd(), name, {
48428
48897
  includeHidden: true
48429
48898
  });
48430
48899
  if (!definition) {
@@ -48439,7 +48908,7 @@ function createSkillsCommand() {
48439
48908
  }
48440
48909
  });
48441
48910
  command.command("render-command").description("Render one command pack entry with arguments, without executing it.").argument("<name>", "Command name").argument("[args...]", "Arguments to substitute into the command body").action(async (name, args = []) => {
48442
- const invocation = await resolveClaudeCommandInvocation(import_node_process32.default.cwd(), [
48911
+ const invocation = await resolveClaudeCommandInvocation(import_node_process33.default.cwd(), [
48443
48912
  name,
48444
48913
  ...args
48445
48914
  ]);
@@ -48453,8 +48922,8 @@ function createSkillsCommand() {
48453
48922
 
48454
48923
  // src/commands/worktree.ts
48455
48924
  var import_promises26 = require("node:fs/promises");
48456
- var import_node_path31 = __toESM(require("node:path"), 1);
48457
- var import_node_process33 = __toESM(require("node:process"), 1);
48925
+ var import_node_path32 = __toESM(require("node:path"), 1);
48926
+ var import_node_process34 = __toESM(require("node:process"), 1);
48458
48927
  var import_node_child_process12 = require("node:child_process");
48459
48928
  function sanitizeName3(value) {
48460
48929
  return value.replace(/[^a-zA-Z0-9._-]+/g, "-").slice(0, 80);
@@ -48463,10 +48932,10 @@ function storedWorktreeName(name) {
48463
48932
  return sanitizeName3(`manual-${name}`);
48464
48933
  }
48465
48934
  function resolveStoredWorktreePath(cwd, name) {
48466
- return import_node_path31.default.join(resolveKimbhoDir(cwd), "worktrees", storedWorktreeName(name));
48935
+ return import_node_path32.default.join(resolveKimbhoDir(cwd), "worktrees", storedWorktreeName(name));
48467
48936
  }
48468
48937
  function resolveStoredPatchPath(cwd, name) {
48469
- return import_node_path31.default.join(resolveKimbhoDir(cwd), "logs", `${storedWorktreeName(name)}.patch`);
48938
+ return import_node_path32.default.join(resolveKimbhoDir(cwd), "logs", `${storedWorktreeName(name)}.patch`);
48470
48939
  }
48471
48940
  async function resolveStoredWorktree(cwd, name) {
48472
48941
  const worktreePath = resolveStoredWorktreePath(cwd, name);
@@ -48492,14 +48961,14 @@ function gitRun(cwd, args) {
48492
48961
  function createWorktreeCommand() {
48493
48962
  const command = new Command("worktree").description("Manage user-visible isolated worktrees and apply their diffs back.");
48494
48963
  command.command("list").description("List Kimbho-managed worktrees.").option("--json", "Print the worktree payload as JSON", false).action(async (options) => {
48495
- const dir = import_node_path31.default.join(resolveKimbhoDir(import_node_process33.default.cwd()), "worktrees");
48964
+ const dir = import_node_path32.default.join(resolveKimbhoDir(import_node_process34.default.cwd()), "worktrees");
48496
48965
  const entries = await (0, import_promises26.readdir)(dir, {
48497
48966
  withFileTypes: true
48498
48967
  }).catch(() => []);
48499
48968
  const worktrees = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
48500
48969
  id: entry.name.replace(/^manual-/, ""),
48501
- worktreePath: import_node_path31.default.join(dir, entry.name),
48502
- patchPath: import_node_path31.default.join(resolveKimbhoDir(import_node_process33.default.cwd()), "logs", `${entry.name}.patch`)
48970
+ worktreePath: import_node_path32.default.join(dir, entry.name),
48971
+ patchPath: import_node_path32.default.join(resolveKimbhoDir(import_node_process34.default.cwd()), "logs", `${entry.name}.patch`)
48503
48972
  }));
48504
48973
  if (options.json) {
48505
48974
  console.log(JSON.stringify(worktrees, null, 2));
@@ -48516,7 +48985,7 @@ function createWorktreeCommand() {
48516
48985
  }
48517
48986
  });
48518
48987
  command.command("create").description("Create one user-visible isolated worktree.").argument("<name>", "Worktree name").option("--json", "Print the worktree payload as JSON", false).action(async (name, options) => {
48519
- const worktree = await createIsolatedWorktree(import_node_process33.default.cwd(), "manual", name);
48988
+ const worktree = await createIsolatedWorktree(import_node_process34.default.cwd(), "manual", name);
48520
48989
  if (!worktree) {
48521
48990
  throw new Error("This workspace is not a git repo with a valid HEAD. Worktrees require git history.");
48522
48991
  }
@@ -48528,19 +48997,19 @@ function createWorktreeCommand() {
48528
48997
  console.log(`Patch artifact: ${worktree.patchArtifactPath}`);
48529
48998
  });
48530
48999
  command.command("diff").description("Inspect the current diff inside one managed worktree.").argument("<name>", "Worktree name").option("--stat", "Show only diff stats", false).action(async (name, options) => {
48531
- const worktree = await resolveStoredWorktree(import_node_process33.default.cwd(), name);
49000
+ const worktree = await resolveStoredWorktree(import_node_process34.default.cwd(), name);
48532
49001
  const args = options.stat ? ["diff", "--stat", "HEAD"] : ["diff", "--binary", "--full-index", "--no-ext-diff", "--stat", "--patch", "HEAD"];
48533
49002
  const result = gitRun(worktree.worktreePath, args);
48534
49003
  if (!result.ok) {
48535
49004
  console.error(result.detail);
48536
- import_node_process33.default.exitCode = 1;
49005
+ import_node_process34.default.exitCode = 1;
48537
49006
  return;
48538
49007
  }
48539
49008
  console.log(result.stdout.trim() || "No diff.");
48540
49009
  });
48541
49010
  command.command("apply").description("Apply one managed worktree back into the main workspace and clean it up.").argument("<name>", "Worktree name").option("--json", "Print the integration payload as JSON", false).action(async (name, options) => {
48542
- const worktree = await resolveStoredWorktree(import_node_process33.default.cwd(), name);
48543
- const result = await integrateIsolatedWorktree(import_node_process33.default.cwd(), worktree, [], []);
49011
+ const worktree = await resolveStoredWorktree(import_node_process34.default.cwd(), name);
49012
+ const result = await integrateIsolatedWorktree(import_node_process34.default.cwd(), worktree, [], []);
48544
49013
  if (options.json) {
48545
49014
  console.log(JSON.stringify(result, null, 2));
48546
49015
  return;
@@ -48552,11 +49021,11 @@ function createWorktreeCommand() {
48552
49021
  console.log(`artifact: ${artifact}`);
48553
49022
  }
48554
49023
  if (result.integrationFailed) {
48555
- import_node_process33.default.exitCode = 1;
49024
+ import_node_process34.default.exitCode = 1;
48556
49025
  }
48557
49026
  });
48558
49027
  command.command("remove").description("Delete one managed worktree without applying it back.").argument("<name>", "Worktree name").option("--json", "Print the removal payload as JSON", false).action(async (name, options) => {
48559
- const cwd = import_node_process33.default.cwd();
49028
+ const cwd = import_node_process34.default.cwd();
48560
49029
  const worktreePath = resolveStoredWorktreePath(cwd, name);
48561
49030
  const removal = gitRun(cwd, [
48562
49031
  "worktree",
@@ -48586,20 +49055,6 @@ function createWorktreeCommand() {
48586
49055
  return command;
48587
49056
  }
48588
49057
 
48589
- // src/commands/placeholders.ts
48590
- function createPlaceholder(name, description, milestone) {
48591
- return new Command(name).description(description).action(() => {
48592
- console.log(`${name} is planned for ${milestone}.`);
48593
- });
48594
- }
48595
- function createFixCommand() {
48596
- return createPlaceholder(
48597
- "fix",
48598
- "Diagnose and repair a failing repository state.",
48599
- "Milestone 4: Executor Loop"
48600
- );
48601
- }
48602
-
48603
49058
  // src/program.ts
48604
49059
  var MODELS_SUBCOMMANDS = /* @__PURE__ */ new Set([
48605
49060
  "help",
@@ -48726,10 +49181,10 @@ function createProgram(onOpenShell) {
48726
49181
  }
48727
49182
 
48728
49183
  // src/runtime-flags.ts
48729
- var import_node_path32 = __toESM(require("node:path"), 1);
48730
- var import_node_process34 = __toESM(require("node:process"), 1);
49184
+ var import_node_path33 = __toESM(require("node:path"), 1);
49185
+ var import_node_process35 = __toESM(require("node:process"), 1);
48731
49186
  function parseJsonEnv2(name, fallback) {
48732
- const raw = import_node_process34.default.env[name];
49187
+ const raw = import_node_process35.default.env[name];
48733
49188
  if (!raw || raw.trim().length === 0) {
48734
49189
  return fallback;
48735
49190
  }
@@ -48813,7 +49268,7 @@ function readOptionValue(tokens, index, label) {
48813
49268
  return value;
48814
49269
  }
48815
49270
  function applyRuntimeFlags(tokens) {
48816
- const initialCwd = import_node_process34.default.cwd();
49271
+ const initialCwd = import_node_process35.default.cwd();
48817
49272
  const remaining = [];
48818
49273
  const overrides = parseJsonEnv2(
48819
49274
  KIMBHO_RUNTIME_OVERRIDES_ENV,
@@ -48824,7 +49279,7 @@ function applyRuntimeFlags(tokens) {
48824
49279
  []
48825
49280
  );
48826
49281
  let nextCwd = null;
48827
- let selectedProfile = import_node_process34.default.env[KIMBHO_RUNTIME_PROFILE_ENV] ?? null;
49282
+ let selectedProfile = import_node_process35.default.env[KIMBHO_RUNTIME_PROFILE_ENV] ?? null;
48828
49283
  let forceExec = false;
48829
49284
  let index = 0;
48830
49285
  while (index < tokens.length) {
@@ -48922,14 +49377,14 @@ function applyRuntimeFlags(tokens) {
48922
49377
  break;
48923
49378
  }
48924
49379
  if (nextCwd) {
48925
- import_node_process34.default.chdir(import_node_path32.default.resolve(initialCwd, nextCwd));
49380
+ import_node_process35.default.chdir(import_node_path33.default.resolve(initialCwd, nextCwd));
48926
49381
  }
48927
49382
  if (selectedProfile) {
48928
- import_node_process34.default.env[KIMBHO_RUNTIME_PROFILE_ENV] = selectedProfile;
49383
+ import_node_process35.default.env[KIMBHO_RUNTIME_PROFILE_ENV] = selectedProfile;
48929
49384
  }
48930
- import_node_process34.default.env[KIMBHO_RUNTIME_OVERRIDES_ENV] = JSON.stringify(overrides);
48931
- import_node_process34.default.env[KIMBHO_RUNTIME_ADDITIONAL_DIRS_ENV] = JSON.stringify(
48932
- additionalDirectories.map((directory) => import_node_path32.default.resolve(import_node_process34.default.cwd(), directory))
49385
+ import_node_process35.default.env[KIMBHO_RUNTIME_OVERRIDES_ENV] = JSON.stringify(overrides);
49386
+ import_node_process35.default.env[KIMBHO_RUNTIME_ADDITIONAL_DIRS_ENV] = JSON.stringify(
49387
+ additionalDirectories.map((directory) => import_node_path33.default.resolve(import_node_process35.default.cwd(), directory))
48933
49388
  );
48934
49389
  return {
48935
49390
  tokens: remaining,
@@ -48941,8 +49396,8 @@ function applyRuntimeFlags(tokens) {
48941
49396
  var import_node_child_process13 = require("node:child_process");
48942
49397
  var import_node_readline2 = require("node:readline");
48943
49398
  var import_promises27 = require("node:readline/promises");
48944
- var import_node_path33 = __toESM(require("node:path"), 1);
48945
- var import_node_process35 = __toESM(require("node:process"), 1);
49399
+ var import_node_path34 = __toESM(require("node:path"), 1);
49400
+ var import_node_process36 = __toESM(require("node:process"), 1);
48946
49401
 
48947
49402
  // src/agent-management.ts
48948
49403
  async function renderCustomAgents(cwd) {
@@ -49116,7 +49571,7 @@ function renderShimmeringLabel(label, frameIndex) {
49116
49571
  }).join("");
49117
49572
  }
49118
49573
  function readRuntimeOverrideEntries() {
49119
- const raw = import_node_process35.default.env[KIMBHO_RUNTIME_OVERRIDES_ENV];
49574
+ const raw = import_node_process36.default.env[KIMBHO_RUNTIME_OVERRIDES_ENV];
49120
49575
  if (!raw || raw.trim().length === 0) {
49121
49576
  return [];
49122
49577
  }
@@ -49134,7 +49589,7 @@ function readRuntimeOverrideEntries() {
49134
49589
  }
49135
49590
  }
49136
49591
  function readAdditionalDirectories2() {
49137
- const raw = import_node_process35.default.env[KIMBHO_RUNTIME_ADDITIONAL_DIRS_ENV];
49592
+ const raw = import_node_process36.default.env[KIMBHO_RUNTIME_ADDITIONAL_DIRS_ENV];
49138
49593
  if (!raw || raw.trim().length === 0) {
49139
49594
  return [];
49140
49595
  }
@@ -49170,17 +49625,17 @@ function syncShellRuntimeOverrides(runtime) {
49170
49625
  ] : []
49171
49626
  ];
49172
49627
  if (merged.length === 0) {
49173
- delete import_node_process35.default.env[KIMBHO_RUNTIME_OVERRIDES_ENV];
49628
+ delete import_node_process36.default.env[KIMBHO_RUNTIME_OVERRIDES_ENV];
49174
49629
  return;
49175
49630
  }
49176
- import_node_process35.default.env[KIMBHO_RUNTIME_OVERRIDES_ENV] = JSON.stringify(merged);
49631
+ import_node_process36.default.env[KIMBHO_RUNTIME_OVERRIDES_ENV] = JSON.stringify(merged);
49177
49632
  }
49178
49633
  function syncShellAdditionalDirectories(runtime) {
49179
49634
  if (runtime.additionalDirectories.length === 0) {
49180
- delete import_node_process35.default.env[KIMBHO_RUNTIME_ADDITIONAL_DIRS_ENV];
49635
+ delete import_node_process36.default.env[KIMBHO_RUNTIME_ADDITIONAL_DIRS_ENV];
49181
49636
  return;
49182
49637
  }
49183
- import_node_process35.default.env[KIMBHO_RUNTIME_ADDITIONAL_DIRS_ENV] = JSON.stringify(runtime.additionalDirectories);
49638
+ import_node_process36.default.env[KIMBHO_RUNTIME_ADDITIONAL_DIRS_ENV] = JSON.stringify(runtime.additionalDirectories);
49184
49639
  }
49185
49640
  function resolveRuntimeOverrideApprovalMode(runtime) {
49186
49641
  if (runtime.sessionApprovalModeOverride) {
@@ -49362,7 +49817,7 @@ var ShellActivityIndicator = class {
49362
49817
  this.label = label;
49363
49818
  }
49364
49819
  start() {
49365
- if (!import_node_process35.default.stdout.isTTY || this.interval) {
49820
+ if (!import_node_process36.default.stdout.isTTY || this.interval) {
49366
49821
  return;
49367
49822
  }
49368
49823
  this.activeLine = true;
@@ -49383,13 +49838,13 @@ var ShellActivityIndicator = class {
49383
49838
  }
49384
49839
  }
49385
49840
  suspend() {
49386
- if (!import_node_process35.default.stdout.isTTY) {
49841
+ if (!import_node_process36.default.stdout.isTTY) {
49387
49842
  return;
49388
49843
  }
49389
49844
  this.clear();
49390
49845
  }
49391
49846
  resume() {
49392
- if (!import_node_process35.default.stdout.isTTY || !this.interval) {
49847
+ if (!import_node_process36.default.stdout.isTTY || !this.interval) {
49393
49848
  return;
49394
49849
  }
49395
49850
  this.render();
@@ -49403,7 +49858,7 @@ var ShellActivityIndicator = class {
49403
49858
  this.activeLine = false;
49404
49859
  }
49405
49860
  render() {
49406
- if (!import_node_process35.default.stdout.isTTY) {
49861
+ if (!import_node_process36.default.stdout.isTTY) {
49407
49862
  return;
49408
49863
  }
49409
49864
  const frame = color(AMBER, SPINNER_FRAMES[this.animationTick % SPINNER_FRAMES.length]);
@@ -49411,15 +49866,15 @@ var ShellActivityIndicator = class {
49411
49866
  const dots = color(DIM, ELLIPSIS_FRAMES[this.animationTick % ELLIPSIS_FRAMES.length]);
49412
49867
  const raw = `${frame} ${status}${dots}`;
49413
49868
  this.clear();
49414
- (0, import_node_readline2.cursorTo)(import_node_process35.default.stdout, 0);
49415
- import_node_process35.default.stdout.write(raw);
49869
+ (0, import_node_readline2.cursorTo)(import_node_process36.default.stdout, 0);
49870
+ import_node_process36.default.stdout.write(raw);
49416
49871
  }
49417
49872
  clear() {
49418
- if (!import_node_process35.default.stdout.isTTY || !this.activeLine) {
49873
+ if (!import_node_process36.default.stdout.isTTY || !this.activeLine) {
49419
49874
  return;
49420
49875
  }
49421
- (0, import_node_readline2.cursorTo)(import_node_process35.default.stdout, 0);
49422
- (0, import_node_readline2.clearLine)(import_node_process35.default.stdout, 0);
49876
+ (0, import_node_readline2.cursorTo)(import_node_process36.default.stdout, 0);
49877
+ (0, import_node_readline2.clearLine)(import_node_process36.default.stdout, 0);
49423
49878
  }
49424
49879
  };
49425
49880
  var ShellExecutionTui = class {
@@ -49438,12 +49893,12 @@ var ShellExecutionTui = class {
49438
49893
  this.render();
49439
49894
  };
49440
49895
  start() {
49441
- if (!import_node_process35.default.stdout.isTTY) {
49896
+ if (!import_node_process36.default.stdout.isTTY) {
49442
49897
  return;
49443
49898
  }
49444
49899
  if (this.ownsScreen) {
49445
- import_node_process35.default.stdout.write(`${ALT_SCREEN_ENTER}${HIDE_CURSOR}${CLEAR_SCREEN}${HOME_CURSOR}`);
49446
- import_node_process35.default.stdout.on("resize", this.handleResize);
49900
+ import_node_process36.default.stdout.write(`${ALT_SCREEN_ENTER}${HIDE_CURSOR}${CLEAR_SCREEN}${HOME_CURSOR}`);
49901
+ import_node_process36.default.stdout.on("resize", this.handleResize);
49447
49902
  }
49448
49903
  this.render();
49449
49904
  this.interval = setInterval(() => {
@@ -49457,12 +49912,12 @@ var ShellExecutionTui = class {
49457
49912
  clearInterval(this.interval);
49458
49913
  this.interval = null;
49459
49914
  }
49460
- if (!import_node_process35.default.stdout.isTTY) {
49915
+ if (!import_node_process36.default.stdout.isTTY) {
49461
49916
  return;
49462
49917
  }
49463
49918
  if (this.ownsScreen) {
49464
- import_node_process35.default.stdout.off("resize", this.handleResize);
49465
- import_node_process35.default.stdout.write(`${SHOW_CURSOR}${ALT_SCREEN_EXIT}`);
49919
+ import_node_process36.default.stdout.off("resize", this.handleResize);
49920
+ import_node_process36.default.stdout.write(`${SHOW_CURSOR}${ALT_SCREEN_EXIT}`);
49466
49921
  }
49467
49922
  }
49468
49923
  updateActivity(label) {
@@ -49483,11 +49938,11 @@ var ShellExecutionTui = class {
49483
49938
  this.render();
49484
49939
  }
49485
49940
  render() {
49486
- if (!import_node_process35.default.stdout.isTTY) {
49941
+ if (!import_node_process36.default.stdout.isTTY) {
49487
49942
  return;
49488
49943
  }
49489
- const columns = Math.max(import_node_process35.default.stdout.columns ?? 100, 72);
49490
- const rows = Math.max(import_node_process35.default.stdout.rows ?? 36, 24);
49944
+ const columns = Math.max(import_node_process36.default.stdout.columns ?? 100, 72);
49945
+ const rows = Math.max(import_node_process36.default.stdout.rows ?? 36, 24);
49491
49946
  const headerLines = [
49492
49947
  color(BOLD, "Kimbho Execution"),
49493
49948
  color(DIM, `session ${shortenMiddle(this.board.sessionId, Math.max(20, columns - 12))}`),
@@ -49498,6 +49953,10 @@ var ShellExecutionTui = class {
49498
49953
  const footerLines = [
49499
49954
  "",
49500
49955
  `${color(AMBER, SPINNER_FRAMES[this.animationTick % SPINNER_FRAMES.length])} ${renderShimmeringLabel(this.activityLabel, this.animationTick)}${color(DIM, ELLIPSIS_FRAMES[this.animationTick % ELLIPSIS_FRAMES.length])} `,
49956
+ ...this.board.approvals > 0 ? [
49957
+ color(DIM, renderApprovalCommandHint()),
49958
+ color(DIM, renderApprovalShortcutHint(this.board.approvals))
49959
+ ] : [],
49501
49960
  color(DIM, "Ctrl+C pauses the run and returns to the shell. A concise summary prints after the run exits.")
49502
49961
  ];
49503
49962
  const chromeLines = headerLines.length + boardLines.length + footerLines.length + 1;
@@ -49515,7 +49974,7 @@ var ShellExecutionTui = class {
49515
49974
  while (paddedLines.length < rows) {
49516
49975
  paddedLines.push("");
49517
49976
  }
49518
- import_node_process35.default.stdout.write(`${CLEAR_SCREEN}${HOME_CURSOR}${paddedLines.join("\n")}`);
49977
+ import_node_process36.default.stdout.write(`${CLEAR_SCREEN}${HOME_CURSOR}${paddedLines.join("\n")}`);
49519
49978
  }
49520
49979
  };
49521
49980
  function renderExecutionTelemetry(telemetry, startedAt) {
@@ -49652,6 +50111,8 @@ function renderBanner() {
49652
50111
  }
49653
50112
  async function getShellSessionState(cwd, focusRole, runtime) {
49654
50113
  const config2 = await loadConfig(cwd);
50114
+ const latestSession = await loadLatestSession(cwd).catch(() => null);
50115
+ const pendingApprovals = latestSession?.pendingApprovals ?? [];
49655
50116
  if (!config2) {
49656
50117
  return {
49657
50118
  focusRole,
@@ -49663,7 +50124,8 @@ async function getShellSessionState(cwd, focusRole, runtime) {
49663
50124
  approvalMode: "manual",
49664
50125
  sandboxMode: "workspace-write",
49665
50126
  stackPreset: "next-prisma-postgres",
49666
- configured: false
50127
+ configured: false,
50128
+ pendingApprovals
49667
50129
  };
49668
50130
  }
49669
50131
  const focusSettings = config2.brains[focusRole];
@@ -49678,7 +50140,8 @@ async function getShellSessionState(cwd, focusRole, runtime) {
49678
50140
  approvalMode: runtime?.sessionApprovalModeOverride ? `${runtime.sessionApprovalModeOverride} (session override)` : config2.approvalMode,
49679
50141
  sandboxMode: runtime?.sessionSandboxModeOverride ? `${runtime.sessionSandboxModeOverride} (session override)` : config2.sandboxMode,
49680
50142
  stackPreset: config2.stackPresets[0] ?? "none",
49681
- configured: true
50143
+ configured: true,
50144
+ pendingApprovals
49682
50145
  };
49683
50146
  }
49684
50147
  function renderCardLine(label, value) {
@@ -49767,8 +50230,8 @@ function renderHelp() {
49767
50230
  "/permissions sandbox <mode> Set read-only, workspace-write, or full.",
49768
50231
  "/permissions trust <path> Add a trusted directory.",
49769
50232
  "/permissions untrust <path> Remove a trusted directory.",
49770
- "/approve [id] Approve a pending risky action and continue.",
49771
- "/approve-all [full-auto|full] Approve pending actions and optionally stop future prompts in this shell.",
50233
+ "/approve [id] Approve a pending risky action and continue once.",
50234
+ "/approve-all [auto|full-auto|full|once] Approve pending actions. Default: auto for the rest of this shell.",
49772
50235
  "/deny [id] Deny a pending risky action.",
49773
50236
  "",
49774
50237
  `${color(BOLD, "Memory")}`,
@@ -49830,6 +50293,10 @@ function renderStartupCard(cwd, state) {
49830
50293
  renderCardLine("approval", state.approvalMode),
49831
50294
  renderCardLine("sandbox", state.sandboxMode),
49832
50295
  renderCardLine("preset", state.stackPreset),
50296
+ ...state.pendingApprovals.length > 0 ? [
50297
+ renderCardLine("pending approvals", String(state.pendingApprovals.length)),
50298
+ renderCardLine("next", "select 1 approve once | 2 approve all | 3 deny")
50299
+ ] : [],
49833
50300
  renderCardLine("shortcuts", "/ask /run /model /permissions /memory /mcp /quit")
49834
50301
  ];
49835
50302
  if (!state.configured) {
@@ -49871,9 +50338,83 @@ function renderShellRuntimeOverview(runtime) {
49871
50338
  return lines;
49872
50339
  }
49873
50340
  function formatPrompt(state) {
50341
+ if (state.pendingApprovals.length > 0) {
50342
+ return state.pendingApprovals.length > 1 ? `${color(AMBER, "select approvals")} ${color(DIM, "[1 current | 2 current+future | 3 deny]")} > ` : `${color(AMBER, "select approval")} ${color(DIM, "[1 approve | 2 all | 3 deny]")} > `;
50343
+ }
49874
50344
  const model = state.focusModel === "not set" ? "unconfigured" : shortenMiddle(state.focusModel, 18);
49875
50345
  return `${color(AMBER, "kimbho")} ${color(DIM, `[${state.focusRole}:${model}]`)} > `;
49876
50346
  }
50347
+ async function readSelectionPrompt(prompt) {
50348
+ if (!import_node_process36.default.stdin.isTTY || !import_node_process36.default.stdout.isTTY) {
50349
+ return "";
50350
+ }
50351
+ return new Promise((resolve) => {
50352
+ const stdin = import_node_process36.default.stdin;
50353
+ const stdout = import_node_process36.default.stdout;
50354
+ const previousRawMode = stdin.isRaw;
50355
+ let buffer = "";
50356
+ const redraw = () => {
50357
+ (0, import_node_readline2.cursorTo)(stdout, 0);
50358
+ (0, import_node_readline2.clearLine)(stdout, 0);
50359
+ stdout.write(`${prompt}${buffer}`);
50360
+ };
50361
+ const cleanup = () => {
50362
+ stdin.off("keypress", onKeypress);
50363
+ stdin.setRawMode?.(Boolean(previousRawMode));
50364
+ };
50365
+ const finish = (value, options = {}) => {
50366
+ cleanup();
50367
+ if (options.printNewline ?? true) {
50368
+ stdout.write("\n");
50369
+ }
50370
+ resolve(value);
50371
+ };
50372
+ const onKeypress = (character, key) => {
50373
+ if (key.ctrl && key.name === "c") {
50374
+ finish("__kimbho_sigint__");
50375
+ return;
50376
+ }
50377
+ if (buffer.length === 0 && (character === "1" || character === "2" || character === "3")) {
50378
+ stdout.write(`${character}
50379
+ `);
50380
+ finish(character, {
50381
+ printNewline: false
50382
+ });
50383
+ return;
50384
+ }
50385
+ if (key.name === "return" || key.name === "enter") {
50386
+ finish(buffer.trim());
50387
+ return;
50388
+ }
50389
+ if (key.name === "backspace") {
50390
+ buffer = buffer.slice(0, -1);
50391
+ redraw();
50392
+ return;
50393
+ }
50394
+ if (key.name === "escape") {
50395
+ buffer = "";
50396
+ redraw();
50397
+ return;
50398
+ }
50399
+ if (key.ctrl || key.meta || !character || key.name === "tab") {
50400
+ return;
50401
+ }
50402
+ buffer += character;
50403
+ redraw();
50404
+ };
50405
+ (0, import_node_readline2.emitKeypressEvents)(stdin);
50406
+ stdin.setRawMode?.(true);
50407
+ stdout.write(prompt);
50408
+ stdin.on("keypress", onKeypress);
50409
+ });
50410
+ }
50411
+ async function readShellInput(readline, state) {
50412
+ const prompt = formatPrompt(state);
50413
+ if (state.pendingApprovals.length > 0) {
50414
+ return readSelectionPrompt(prompt);
50415
+ }
50416
+ return readline.question(prompt);
50417
+ }
49877
50418
  function printHeader(cwd, state) {
49878
50419
  console.log(renderBanner());
49879
50420
  console.log(color(DIM, "Terminal-native coding agent"));
@@ -49897,8 +50438,8 @@ function appendShellLog(runtime, value) {
49897
50438
  }
49898
50439
  }
49899
50440
  function renderShellDashboard(cwd, state, runtime) {
49900
- const columns = Math.max(import_node_process35.default.stdout.columns ?? 100, 76);
49901
- const rows = Math.max(import_node_process35.default.stdout.rows ?? 30, 20);
50441
+ const columns = Math.max(import_node_process36.default.stdout.columns ?? 100, 76);
50442
+ const rows = Math.max(import_node_process36.default.stdout.rows ?? 30, 20);
49902
50443
  const lines = [
49903
50444
  `${color(BOLD, "Kimbho CLI")} ${color(DIM, `(v${KIMBHO_VERSION})`)}`,
49904
50445
  color(DIM, `focus ${state.focusRole} | model ${shortenMiddle(state.focusModel, 28)} | provider ${state.providerId}`),
@@ -49921,6 +50462,16 @@ function renderShellDashboard(cwd, state, runtime) {
49921
50462
  lines.push(`\u2022 ${shortenMiddle(runtime.pendingHookElicitation.question, Math.max(24, columns - 10))}`);
49922
50463
  lines.push(color(DIM, "next: /answer <text> or /skip"));
49923
50464
  }
50465
+ if (state.pendingApprovals.length > 0) {
50466
+ lines.push("");
50467
+ lines.push(color(BOLD, state.pendingApprovals.length === 1 ? "Pending Approval" : "Pending Approvals"));
50468
+ lines.push(...renderPendingApprovalLines(
50469
+ state.pendingApprovals.slice(0, 3),
50470
+ Math.max(32, columns - 18)
50471
+ ));
50472
+ lines.push(color(DIM, renderApprovalCommandHint()));
50473
+ lines.push(color(DIM, renderApprovalShortcutHint(state.pendingApprovals.length)));
50474
+ }
49924
50475
  if (runtime.activeExecution) {
49925
50476
  lines.push("");
49926
50477
  lines.push(color(BOLD, "Active Execution"));
@@ -49942,9 +50493,10 @@ function renderShellDashboard(cwd, state, runtime) {
49942
50493
  }
49943
50494
  lines.push("");
49944
50495
  lines.push(color(BOLD, "Recent Output"));
50496
+ const footerActionLabel = runtime.pendingRunProposal ? "Direct request to act | /ask chat | /run approve | /run revise | /status | /quit" : "Direct request to act | /ask chat | /run <goal> | /queue list | /status | /quit";
49945
50497
  const footerLines = [
49946
50498
  "",
49947
- color(DIM, "Direct request to act | /ask chat | /run approve | /queue list | /status | /quit")
50499
+ color(DIM, footerActionLabel)
49948
50500
  ];
49949
50501
  const activityBudget = Math.max(6, rows - lines.length - footerLines.length - 2);
49950
50502
  const activity = runtime.shellLog.slice(-activityBudget);
@@ -49963,23 +50515,54 @@ function renderShellDashboard(cwd, state, runtime) {
49963
50515
  return `${CLEAR_SCREEN}${HOME_CURSOR}${frame.join("\n")}
49964
50516
  `;
49965
50517
  }
50518
+ function renderApprovalCommandHint() {
50519
+ return "next: /approve once, /approve-all to stop future prompts in this shell, /deny to stop";
50520
+ }
50521
+ function renderApprovalShortcutHint(pendingCount = 1) {
50522
+ return pendingCount > 1 ? "choices: 1 approve current set | 2 approve current + future for this shell | 3 deny current set" : "choices: 1 approve once | 2 approve all for this shell | 3 deny";
50523
+ }
50524
+ function summarizeApprovalInput(input) {
50525
+ if (typeof input.command === "string" && input.command.trim().length > 0) {
50526
+ return shortenMiddle(input.command.trim(), 90);
50527
+ }
50528
+ if (typeof input.path === "string" && input.path.trim().length > 0) {
50529
+ return shortenMiddle(input.path.trim(), 90);
50530
+ }
50531
+ if (typeof input.url === "string" && input.url.trim().length > 0) {
50532
+ return shortenMiddle(input.url.trim(), 90);
50533
+ }
50534
+ const serialized = Object.entries(input).slice(0, 3).map(([key, value]) => `${key}=${String(value)}`).join(" ");
50535
+ return serialized.length > 0 ? shortenMiddle(serialized, 90) : null;
50536
+ }
50537
+ function renderPendingApprovalLines(approvals, maxReasonWidth = 110) {
50538
+ const lines = [];
50539
+ for (const approval of approvals) {
50540
+ lines.push(`\u2022 ${approval.toolId} for ${approval.taskId} (${approval.permission})`);
50541
+ lines.push(` reason: ${shortenMiddle(approval.reason, maxReasonWidth)}`);
50542
+ const request = summarizeApprovalInput(approval.input);
50543
+ if (request) {
50544
+ lines.push(` request: ${request}`);
50545
+ }
50546
+ }
50547
+ return lines;
50548
+ }
49966
50549
  var ShellDashboardTui = class {
49967
50550
  constructor(runtime) {
49968
50551
  this.runtime = runtime;
49969
50552
  }
49970
- cwd = import_node_process35.default.cwd();
50553
+ cwd = import_node_process36.default.cwd();
49971
50554
  state = null;
49972
50555
  handleResize = () => {
49973
50556
  this.render();
49974
50557
  };
49975
50558
  start(cwd, state) {
49976
- if (!import_node_process35.default.stdout.isTTY) {
50559
+ if (!import_node_process36.default.stdout.isTTY) {
49977
50560
  return;
49978
50561
  }
49979
50562
  this.cwd = cwd;
49980
50563
  this.state = state;
49981
- import_node_process35.default.stdout.write(`${ALT_SCREEN_ENTER}${HIDE_CURSOR}`);
49982
- import_node_process35.default.stdout.on("resize", this.handleResize);
50564
+ import_node_process36.default.stdout.write(`${ALT_SCREEN_ENTER}${HIDE_CURSOR}`);
50565
+ import_node_process36.default.stdout.on("resize", this.handleResize);
49983
50566
  this.render();
49984
50567
  }
49985
50568
  update(cwd, state) {
@@ -49988,17 +50571,17 @@ var ShellDashboardTui = class {
49988
50571
  this.render();
49989
50572
  }
49990
50573
  render() {
49991
- if (!import_node_process35.default.stdout.isTTY || !this.state || this.runtime.activeExecution) {
50574
+ if (!import_node_process36.default.stdout.isTTY || !this.state || this.runtime.activeExecution) {
49992
50575
  return;
49993
50576
  }
49994
- import_node_process35.default.stdout.write(renderShellDashboard(this.cwd, this.state, this.runtime));
50577
+ import_node_process36.default.stdout.write(renderShellDashboard(this.cwd, this.state, this.runtime));
49995
50578
  }
49996
50579
  stop() {
49997
- if (!import_node_process35.default.stdout.isTTY) {
50580
+ if (!import_node_process36.default.stdout.isTTY) {
49998
50581
  return;
49999
50582
  }
50000
- import_node_process35.default.stdout.off("resize", this.handleResize);
50001
- import_node_process35.default.stdout.write(`${SHOW_CURSOR}${ALT_SCREEN_EXIT}`);
50583
+ import_node_process36.default.stdout.off("resize", this.handleResize);
50584
+ import_node_process36.default.stdout.write(`${SHOW_CURSOR}${ALT_SCREEN_EXIT}`);
50002
50585
  }
50003
50586
  };
50004
50587
  function renderInlineMarkdown(value) {
@@ -50311,138 +50894,6 @@ function renderPendingRunProposal(proposal, options = {}) {
50311
50894
  }
50312
50895
  return lines;
50313
50896
  }
50314
- function buildWorkspaceAnalysisPlan(request, prompt) {
50315
- const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
50316
- return {
50317
- goal: request.goal,
50318
- generatedAt,
50319
- summary: "Read-only multi-agent analysis of the current repository to answer the operator's question with concrete workspace evidence.",
50320
- repoStrategy: {
50321
- mode: "existing-repo",
50322
- reasoning: "This is an analysis-only request about the current workspace, so the agent team should inspect the repo and synthesize findings without editing source files."
50323
- },
50324
- assumptions: [
50325
- "The user wants a grounded explanation of the current repository, not code changes.",
50326
- "The analysis should stay read-only and avoid modifying product files."
50327
- ],
50328
- openQuestions: [],
50329
- milestones: [
50330
- {
50331
- id: "m1-repo-survey",
50332
- title: "Repository Survey",
50333
- objective: "Inspect the current workspace structure, entrypoints, tooling, and conventions.",
50334
- tasks: [
50335
- {
50336
- id: "t1-repo-analysis",
50337
- title: "Analyze the current workspace and conventions",
50338
- description: "Map the repository shape, commands, entrypoints, and constraints before answering the user's question.",
50339
- type: "analysis",
50340
- status: "pending",
50341
- agentRole: "repo-analyst",
50342
- dependsOn: [],
50343
- acceptanceCriteria: [
50344
- "Repository shape and commands are captured.",
50345
- "Likely entrypoints and major packages are identified."
50346
- ],
50347
- outputs: [
50348
- "Repo analysis summary"
50349
- ],
50350
- filesLikelyTouched: [
50351
- ".",
50352
- ".kimbho/"
50353
- ],
50354
- riskLevel: "low",
50355
- sandboxModeOverride: "read-only"
50356
- },
50357
- {
50358
- id: "t2-architecture",
50359
- title: "Synthesize the architecture and package boundaries",
50360
- description: "Turn the repository findings into a clear explanation of the system structure and responsibilities.",
50361
- type: "documentation",
50362
- status: "pending",
50363
- agentRole: "planner",
50364
- dependsOn: [
50365
- "t1-repo-analysis"
50366
- ],
50367
- acceptanceCriteria: [
50368
- "Architecture summary is grounded in repo analysis findings.",
50369
- "The main packages and responsibilities are explicit."
50370
- ],
50371
- outputs: [
50372
- "Architecture brief"
50373
- ],
50374
- filesLikelyTouched: [
50375
- ".kimbho/"
50376
- ],
50377
- riskLevel: "low",
50378
- sandboxModeOverride: "read-only"
50379
- }
50380
- ]
50381
- },
50382
- {
50383
- id: "m2-answer",
50384
- title: "Answer",
50385
- objective: "Review the gathered analysis artifacts and produce the final project explanation.",
50386
- tasks: [
50387
- {
50388
- id: "t3-project-brief",
50389
- title: "Review the analysis artifacts and prepare the project explanation",
50390
- description: "Inspect the repo-analysis and architecture artifacts, then summarize the current project in terms that answer the user's question.",
50391
- type: "documentation",
50392
- status: "pending",
50393
- agentRole: "reviewer",
50394
- dependsOn: [
50395
- "t1-repo-analysis",
50396
- "t2-architecture"
50397
- ],
50398
- acceptanceCriteria: [
50399
- "The answer addresses the user's question directly.",
50400
- "The summary is grounded in repository evidence instead of generic assistant chatter."
50401
- ],
50402
- outputs: [
50403
- "Project explanation summary"
50404
- ],
50405
- filesLikelyTouched: [
50406
- ".kimbho/logs/",
50407
- "kimbho_init.md"
50408
- ],
50409
- riskLevel: "low",
50410
- sandboxModeOverride: "read-only",
50411
- allowedTools: [
50412
- "file.read",
50413
- "file.search",
50414
- "file.list",
50415
- "repo.index",
50416
- "repo.query",
50417
- "git.diff"
50418
- ],
50419
- deniedTools: [
50420
- "file.write",
50421
- "file.patch",
50422
- "shell.exec"
50423
- ],
50424
- agentPromptPreamble: [
50425
- "This is a read-only repository explanation task.",
50426
- "Do not modify product files, install packages, or run development servers.",
50427
- `Answer the operator's question: ${prompt}`,
50428
- "Use the repo-analysis and architecture artifacts plus direct file inspection if needed.",
50429
- "Finish with a concise but concrete summary of the project, stack, entrypoints, commands, and notable risks or gaps."
50430
- ].join("\n")
50431
- }
50432
- ]
50433
- }
50434
- ],
50435
- verificationChecklist: [
50436
- "Repo analysis artifacts were captured.",
50437
- "The architecture summary is grounded in the workspace.",
50438
- "The final explanation answers the user's question without changing source files."
50439
- ],
50440
- executionNotes: [
50441
- "Read-only analysis run triggered directly from a workspace question.",
50442
- "Prefer repo/file tools and existing memory artifacts over generic assistant responses."
50443
- ]
50444
- };
50445
- }
50446
50897
  function hasRenderableDiff(toolId, output) {
50447
50898
  if (!output || output.trim().length === 0) {
50448
50899
  return false;
@@ -50567,7 +51018,7 @@ function renderShellSessionSummary(snapshot, planPath, sessionPath) {
50567
51018
  snapshot.events.flatMap((event) => [
50568
51019
  ...event.artifacts,
50569
51020
  ...event.toolResults.flatMap((toolResult) => toolResult.artifacts)
50570
- ]).filter((artifact) => !artifact.includes(`${import_node_path33.default.sep}.kimbho${import_node_path33.default.sep}`))
51021
+ ]).filter((artifact) => !artifact.includes(`${import_node_path34.default.sep}.kimbho${import_node_path34.default.sep}`))
50571
51022
  ));
50572
51023
  const visibleNotes = snapshot.notes.filter(
50573
51024
  (note) => /limit reached|approval|blocked|failed|error|conflict|denied/i.test(note)
@@ -50594,9 +51045,7 @@ function renderShellSessionSummary(snapshot, planPath, sessionPath) {
50594
51045
  if (snapshot.pendingApprovals.length > 0) {
50595
51046
  lines.push("");
50596
51047
  lines.push(color(BOLD, "Waiting For Approval"));
50597
- for (const approval of snapshot.pendingApprovals) {
50598
- lines.push(`\u2022 ${approval.reason}`);
50599
- }
51048
+ lines.push(...renderPendingApprovalLines(snapshot.pendingApprovals.slice(0, 4)));
50600
51049
  }
50601
51050
  if (visibleNotes.length > 0) {
50602
51051
  lines.push("");
@@ -50611,7 +51060,8 @@ function renderShellSessionSummary(snapshot, planPath, sessionPath) {
50611
51060
  }
50612
51061
  lines.push(color(DIM, `saved session: ${sessionPath}`));
50613
51062
  if (snapshot.pendingApprovals.length > 0) {
50614
- lines.push("next: /approve to continue, /deny to stop");
51063
+ lines.push(renderApprovalCommandHint());
51064
+ lines.push(color(DIM, renderApprovalShortcutHint(snapshot.pendingApprovals.length)));
50615
51065
  } else if (snapshot.status === "paused" || snapshot.status === "running" || snapshot.status === "ready") {
50616
51066
  lines.push("next: /resume to continue a paused run or start another request");
50617
51067
  } else if (snapshot.status === "blocked") {
@@ -50723,7 +51173,8 @@ function renderLiveExecutionEvent(event, board, startedAt, options = {}) {
50723
51173
  case "approval-requested":
50724
51174
  return [
50725
51175
  `${color(AMBER, "Approval Needed")} ${event.approval.reason}`,
50726
- color(DIM, "next: /approve to continue, /deny to stop, /approve-all full-auto to stop future prompts"),
51176
+ color(DIM, renderApprovalCommandHint()),
51177
+ color(DIM, renderApprovalShortcutHint(board.approvals)),
50727
51178
  ...progressLines
50728
51179
  ];
50729
51180
  case "approval-resolved":
@@ -50910,12 +51361,12 @@ function rewindConversation(runtime, role, turns) {
50910
51361
  return removed;
50911
51362
  }
50912
51363
  async function writeTextToClipboard(value) {
50913
- const candidates = import_node_process35.default.platform === "darwin" ? [
51364
+ const candidates = import_node_process36.default.platform === "darwin" ? [
50914
51365
  {
50915
51366
  command: "pbcopy",
50916
51367
  args: []
50917
51368
  }
50918
- ] : import_node_process35.default.platform === "win32" ? [
51369
+ ] : import_node_process36.default.platform === "win32" ? [
50919
51370
  {
50920
51371
  command: "clip",
50921
51372
  args: []
@@ -50963,7 +51414,7 @@ async function writeTextToClipboard(value) {
50963
51414
  }
50964
51415
  function createShellExportPath(cwd, role, kind) {
50965
51416
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
50966
- return import_node_path33.default.join(cwd, ".kimbho", "exports", `${kind}-${role}-${stamp}.md`);
51417
+ return import_node_path34.default.join(cwd, ".kimbho", "exports", `${kind}-${role}-${stamp}.md`);
50967
51418
  }
50968
51419
  function clearConversation(runtime, role) {
50969
51420
  runtime.conversations[role] = [];
@@ -51069,7 +51520,7 @@ async function handleChatPrompt(cwd, prompt, runtime) {
51069
51520
  const workspaceInfoPrompt = looksLikeWorkspaceInfoPrompt(hydrated.prompt);
51070
51521
  let workspaceOverview = null;
51071
51522
  if (workspaceInfoPrompt) {
51072
- const existingOverview = await readMarkdownIfExists(import_node_path33.default.join(cwd, "kimbho_init.md"));
51523
+ const existingOverview = await readMarkdownIfExists(import_node_path34.default.join(cwd, "kimbho_init.md"));
51073
51524
  if (existingOverview) {
51074
51525
  workspaceOverview = existingOverview.slice(0, 6e3);
51075
51526
  } else {
@@ -51255,7 +51706,7 @@ async function executePendingRunProposal(runtime) {
51255
51706
  resolveShellMaxAgentSteps(runtime),
51256
51707
  DEFAULT_MAX_REPAIR_ATTEMPTS2
51257
51708
  );
51258
- const tui = import_node_process35.default.stdout.isTTY ? new ShellExecutionTui(liveBoard, telemetry, startedAt, "starting", !runtime.dashboard) : null;
51709
+ const tui = import_node_process36.default.stdout.isTTY ? new ShellExecutionTui(liveBoard, telemetry, startedAt, "starting", !runtime.dashboard) : null;
51259
51710
  const activity = tui ? null : new ShellActivityIndicator("starting");
51260
51711
  if (tui) {
51261
51712
  tui.start();
@@ -51323,59 +51774,6 @@ async function executePendingRunProposal(runtime) {
51323
51774
  void drainQueuedWork(runtime);
51324
51775
  return request.cwd;
51325
51776
  }
51326
- async function synthesizeWorkspaceAnalysisAnswer(cwd, prompt, runtime, snapshot) {
51327
- const config2 = await loadConfig(cwd);
51328
- const projectInit = await readMarkdownIfExists(import_node_path33.default.join(cwd, "kimbho_init.md"));
51329
- const artifactPaths = Array.from(new Set(
51330
- snapshot.events.flatMap((event) => [
51331
- ...event.artifacts,
51332
- ...event.toolResults.flatMap((toolResult) => toolResult.artifacts)
51333
- ])
51334
- ));
51335
- const prioritizedArtifacts = artifactPaths.filter((artifactPath) => /repo-analysis|architecture-brief|project-brief|transcript/i.test(import_node_path33.default.basename(artifactPath))).slice(0, 4);
51336
- const artifactSections = (await Promise.all(
51337
- prioritizedArtifacts.map(async (artifactPath) => {
51338
- const content = await readMarkdownIfExists(artifactPath);
51339
- if (!content) {
51340
- return null;
51341
- }
51342
- return `Artifact: ${artifactPath}
51343
- ${content.slice(0, 4e3)}`;
51344
- })
51345
- )).filter((section) => Boolean(section));
51346
- if (!config2) {
51347
- return [
51348
- "Repository analysis completed.",
51349
- projectInit ? `Current workspace summary:
51350
- ${projectInit.slice(0, 4e3)}` : "Project summary is available in the session artifacts, but no configured model was available to synthesize a narrative answer."
51351
- ].join("\n\n");
51352
- }
51353
- const resolver = new BrainResolver(config2, createDefaultBrainProviderRegistry(cwd));
51354
- const brain = await resolver.resolve(runtime.focusRole);
51355
- const result = await brain.client.generateText({
51356
- model: brain.model,
51357
- systemPrompt: [
51358
- brain.settings.promptPreamble,
51359
- "You are summarizing the current repository after a read-only multi-agent analysis session.",
51360
- "Answer the user's question directly and concretely from the provided workspace evidence.",
51361
- "Do not greet, do not speak generically about your own capabilities, and do not invent repository details.",
51362
- "Prefer a crisp project overview with stack, structure, key entrypoints, commands, and notable risks or gaps."
51363
- ].filter(Boolean).join("\n\n"),
51364
- userPrompt: [
51365
- `User question: ${prompt}`,
51366
- projectInit ? `Workspace overview:
51367
- ${projectInit.slice(0, 6e3)}` : null,
51368
- artifactSections.length > 0 ? artifactSections.join("\n\n") : "No detailed analysis artifacts were available; answer from the workspace overview only."
51369
- ].filter((value) => Boolean(value)).join("\n\n"),
51370
- ...typeof brain.settings.temperature === "number" ? {
51371
- temperature: brain.settings.temperature
51372
- } : {},
51373
- ...typeof brain.settings.maxTokens === "number" ? {
51374
- maxTokens: brain.settings.maxTokens
51375
- } : {}
51376
- });
51377
- return result.text;
51378
- }
51379
51777
  async function handleWorkspaceAnalysisPrompt(cwd, prompt, runtime) {
51380
51778
  const hydrated = await hydratePromptWithMcpResources(cwd, prompt);
51381
51779
  await recordAdaptiveTextObservation(cwd, hydrated.prompt, "chat");
@@ -51413,7 +51811,7 @@ async function handleWorkspaceAnalysisPrompt(cwd, prompt, runtime) {
51413
51811
  resolveShellMaxAgentSteps(runtime),
51414
51812
  DEFAULT_MAX_REPAIR_ATTEMPTS2
51415
51813
  );
51416
- const tui = import_node_process35.default.stdout.isTTY ? new ShellExecutionTui(liveBoard, telemetry, startedAt, "analyzing", !runtime.dashboard) : null;
51814
+ const tui = import_node_process36.default.stdout.isTTY ? new ShellExecutionTui(liveBoard, telemetry, startedAt, "analyzing", !runtime.dashboard) : null;
51417
51815
  const activity = tui ? null : new ShellActivityIndicator("analyzing");
51418
51816
  if (tui) {
51419
51817
  tui.start();
@@ -51469,7 +51867,12 @@ async function handleWorkspaceAnalysisPrompt(cwd, prompt, runtime) {
51469
51867
  const sessionPath = await saveSession(snapshot, request.cwd);
51470
51868
  await recordAdaptiveSessionOutcome(request.cwd, snapshot);
51471
51869
  runtime.currentCwd = request.cwd;
51472
- const answer = await synthesizeWorkspaceAnalysisAnswer(request.cwd, hydrated.prompt, runtime, snapshot);
51870
+ const answer = await synthesizeWorkspaceAnalysisAnswer(
51871
+ request.cwd,
51872
+ hydrated.prompt,
51873
+ runtime.focusRole,
51874
+ snapshot
51875
+ );
51473
51876
  const conversation = trimConversation([
51474
51877
  ...getConversation(runtime, runtime.focusRole),
51475
51878
  {
@@ -51513,7 +51916,7 @@ async function resumeGoalExecution(cwd, runtime) {
51513
51916
  controller,
51514
51917
  label: session.id
51515
51918
  };
51516
- const tui = import_node_process35.default.stdout.isTTY ? new ShellExecutionTui(liveBoard, telemetry, startedAt, "resuming", !runtime.dashboard) : null;
51919
+ const tui = import_node_process36.default.stdout.isTTY ? new ShellExecutionTui(liveBoard, telemetry, startedAt, "resuming", !runtime.dashboard) : null;
51517
51920
  const activity = tui ? null : new ShellActivityIndicator("resuming");
51518
51921
  if (tui) {
51519
51922
  tui.start();
@@ -51629,7 +52032,7 @@ async function resolvePendingApproval(cwd, runtime, decision, approvalId, option
51629
52032
  controller,
51630
52033
  label: approvals.length === 1 ? `${session.id}:${approvals[0].id}` : `${session.id}:batch-approval`
51631
52034
  };
51632
- const tui = import_node_process35.default.stdout.isTTY ? new ShellExecutionTui(liveBoard, telemetry, startedAt, decision === "approve" ? "approving" : "denying", !runtime.dashboard) : null;
52035
+ const tui = import_node_process36.default.stdout.isTTY ? new ShellExecutionTui(liveBoard, telemetry, startedAt, decision === "approve" ? "approving" : "denying", !runtime.dashboard) : null;
51633
52036
  const activity = tui ? null : new ShellActivityIndicator(decision === "approve" ? "approving" : "denying");
51634
52037
  if (tui) {
51635
52038
  tui.start();
@@ -51693,16 +52096,74 @@ async function resolvePendingApproval(cwd, runtime, decision, approvalId, option
51693
52096
  void drainQueuedWork(runtime);
51694
52097
  }
51695
52098
  async function applyApproveAllPreset(cwd, runtime, rawPreset) {
51696
- if (!rawPreset) {
51697
- return false;
52099
+ const normalized = rawPreset?.trim().toLowerCase();
52100
+ if (!normalized) {
52101
+ runtime.sessionApprovalModeOverride = "auto";
52102
+ syncShellRuntimeOverrides(runtime);
52103
+ console.log("Shell permission override: auto approvals for the rest of this shell.");
52104
+ await recordAdaptiveTextObservation(cwd, "User approval preference: auto approvals for the rest of this shell.", "approval");
52105
+ const session2 = await loadLatestSession(cwd);
52106
+ return Boolean(session2 && session2.pendingApprovals.length > 0);
52107
+ }
52108
+ if (normalized === "once" || normalized === "current") {
52109
+ const session2 = await loadLatestSession(cwd);
52110
+ if (!session2 || session2.pendingApprovals.length === 0) {
52111
+ return false;
52112
+ }
52113
+ console.log("Approving all currently pending actions once. Future actions will keep the current approval mode.");
52114
+ return true;
51698
52115
  }
51699
- const preset = resolvePermissionPreset(rawPreset);
52116
+ const preset = resolvePermissionPreset(rawPreset ?? "auto");
51700
52117
  setShellSessionPermissions(runtime, preset);
51701
52118
  console.log(`Shell permission override: ${preset.label}`);
51702
52119
  await recordAdaptiveTextObservation(cwd, `User approval preference: ${preset.label}`, "approval");
51703
52120
  const session = await loadLatestSession(cwd);
51704
52121
  return Boolean(session && session.pendingApprovals.length > 0);
51705
52122
  }
52123
+ async function tryResolveApprovalShortcut(cwd, runtime, input) {
52124
+ if (input !== "1" && input !== "2" && input !== "3") {
52125
+ return false;
52126
+ }
52127
+ const session = await loadLatestSession(cwd);
52128
+ if (!session || session.pendingApprovals.length === 0) {
52129
+ return false;
52130
+ }
52131
+ if (input === "1") {
52132
+ await resolvePendingApproval(
52133
+ cwd,
52134
+ runtime,
52135
+ "approve",
52136
+ session.pendingApprovals.length > 1 ? "all" : void 0,
52137
+ {
52138
+ allowAll: session.pendingApprovals.length > 1
52139
+ }
52140
+ );
52141
+ return true;
52142
+ }
52143
+ if (input === "2") {
52144
+ await applyApproveAllPreset(cwd, runtime);
52145
+ await resolvePendingApproval(
52146
+ cwd,
52147
+ runtime,
52148
+ "approve",
52149
+ "all",
52150
+ {
52151
+ allowAll: true
52152
+ }
52153
+ );
52154
+ return true;
52155
+ }
52156
+ await resolvePendingApproval(
52157
+ cwd,
52158
+ runtime,
52159
+ "deny",
52160
+ session.pendingApprovals.length > 1 ? "all" : void 0,
52161
+ {
52162
+ allowAll: session.pendingApprovals.length > 1
52163
+ }
52164
+ );
52165
+ return true;
52166
+ }
51706
52167
  async function printLatestPlanSummary(cwd) {
51707
52168
  const plan = await loadLatestPlan(cwd);
51708
52169
  if (!plan) {
@@ -51849,7 +52310,7 @@ async function handlePermissionsCommand(cwd, tokens, runtime) {
51849
52310
  if (!target) {
51850
52311
  throw new Error(`Usage: /permissions ${subcommand} <path>`);
51851
52312
  }
51852
- const normalizedTarget = import_node_path33.default.resolve(cwd, target);
52313
+ const normalizedTarget = import_node_path34.default.resolve(cwd, target);
51853
52314
  const trustedDirectories = subcommand === "trust" ? Array.from(/* @__PURE__ */ new Set([
51854
52315
  ...effective.trustedDirectories,
51855
52316
  normalizedTarget
@@ -51965,7 +52426,7 @@ async function handleExportCommand(cwd, tokens, runtime) {
51965
52426
  );
51966
52427
  const destinationToken = knownKind ? tokens[2] : tokens[1];
51967
52428
  const outputPath = await writeMarkdownFile(
51968
- destinationToken ? import_node_path33.default.resolve(cwd, destinationToken) : createShellExportPath(cwd, runtime.focusRole, knownKind ? kindToken : "context"),
52429
+ destinationToken ? import_node_path34.default.resolve(cwd, destinationToken) : createShellExportPath(cwd, runtime.focusRole, knownKind ? kindToken : "context"),
51969
52430
  payload.content
51970
52431
  );
51971
52432
  console.log(`Exported ${payload.label} -> ${outputPath}`);
@@ -51975,7 +52436,7 @@ async function handleAddDirCommand(cwd, tokens, runtime) {
51975
52436
  if (!target) {
51976
52437
  throw new Error("Usage: /add-dir <path>");
51977
52438
  }
51978
- const resolved = import_node_path33.default.resolve(cwd, target);
52439
+ const resolved = import_node_path34.default.resolve(cwd, target);
51979
52440
  if (!runtime.additionalDirectories.includes(resolved)) {
51980
52441
  runtime.additionalDirectories.push(resolved);
51981
52442
  runtime.additionalDirectories.sort((left, right) => left.localeCompare(right));
@@ -52052,7 +52513,7 @@ async function handleHooksCommand(cwd, tokens) {
52052
52513
  console.log(lines.join("\n"));
52053
52514
  }
52054
52515
  function shellHookSessionId(runtime, cwd) {
52055
- return runtime.pendingRunProposal?.snapshot.id ?? `shell-${import_node_process35.default.pid}-${import_node_path33.default.basename(cwd) || "workspace"}`;
52516
+ return runtime.pendingRunProposal?.snapshot.id ?? `shell-${import_node_process36.default.pid}-${import_node_path34.default.basename(cwd) || "workspace"}`;
52056
52517
  }
52057
52518
  async function createShellHookRunner(cwd, config2) {
52058
52519
  const resolvedConfig = config2 ?? await loadConfig(cwd).catch(() => null);
@@ -52236,7 +52697,7 @@ async function handleMemoryCommand(cwd, tokens) {
52236
52697
  }
52237
52698
  let filePath;
52238
52699
  if (scope === "init") {
52239
- filePath = import_node_path33.default.join(cwd, "kimbho_init.md");
52700
+ filePath = import_node_path34.default.join(cwd, "kimbho_init.md");
52240
52701
  } else if (scope === "project") {
52241
52702
  filePath = resolveProjectMemoryPath(cwd);
52242
52703
  } else if (scope === "user") {
@@ -52246,7 +52707,7 @@ async function handleMemoryCommand(cwd, tokens) {
52246
52707
  if (!agentId) {
52247
52708
  throw new Error("Usage: /memory show agent <agent-id>");
52248
52709
  }
52249
- filePath = import_node_path33.default.join(resolveAgentMemoryDir(cwd), `${agentId}.md`);
52710
+ filePath = import_node_path34.default.join(resolveAgentMemoryDir(cwd), `${agentId}.md`);
52250
52711
  } else {
52251
52712
  throw new Error("Usage: /memory show <init|project|user|agent> [id]");
52252
52713
  }
@@ -52855,7 +53316,7 @@ async function printProviderList(cwd, focusRole) {
52855
53316
  const activeProviderId = config2.brains[focusRole].providerId;
52856
53317
  for (const provider of config2.providers) {
52857
53318
  const marker = provider.id === activeProviderId ? "*" : " ";
52858
- const envState = provider.apiKeyEnv ? import_node_process35.default.env[provider.apiKeyEnv] ? "present" : `missing ${provider.apiKeyEnv}` : "no key required";
53319
+ const envState = provider.apiKeyEnv ? import_node_process36.default.env[provider.apiKeyEnv] ? "present" : `missing ${provider.apiKeyEnv}` : "no key required";
52859
53320
  console.log(`${marker} ${provider.id}`);
52860
53321
  console.log(` label: ${provider.label ?? "-"}`);
52861
53322
  console.log(` driver: ${provider.driver}`);
@@ -53310,6 +53771,9 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
53310
53771
  await resolvePendingHookElicitation(cwd, runtime, "answer", trimmed);
53311
53772
  return cwd;
53312
53773
  }
53774
+ if (!isSlashCommand && !runtime.pendingRunProposal && await tryResolveApprovalShortcut(cwd, runtime, trimmed)) {
53775
+ return cwd;
53776
+ }
53313
53777
  if (head.startsWith("mcp__")) {
53314
53778
  const parts = head.split("__").filter((part) => part.length > 0);
53315
53779
  if (parts.length < 3) {
@@ -53613,7 +54077,7 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
53613
54077
  await createPlanOnly(cwd, goal);
53614
54078
  return cwd;
53615
54079
  }
53616
- if (head === "resume") {
54080
+ if (head === "resume" || head === "continue") {
53617
54081
  queueResumeRequest(cwd, runtime);
53618
54082
  return cwd;
53619
54083
  }
@@ -53626,16 +54090,16 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
53626
54090
  }
53627
54091
  if (head === "approve-all") {
53628
54092
  const shouldResolvePending = await applyApproveAllPreset(cwd, runtime, tokens[1]?.trim());
53629
- if (tokens[1] && !shouldResolvePending) {
54093
+ if (!shouldResolvePending) {
53630
54094
  if (runtime.pendingRunProposal) {
53631
54095
  void startPendingRunExecution(cwd, runtime);
53632
54096
  return cwd;
53633
54097
  }
53634
- console.log("No pending approvals right now. Future actions in this shell will use the new permission mode.");
53635
- return cwd;
53636
- }
53637
- if (!shouldResolvePending && runtime.pendingRunProposal) {
53638
- void startPendingRunExecution(cwd, runtime);
54098
+ if (tokens[1]?.trim()) {
54099
+ console.log("No pending approvals right now. Future actions in this shell will use the new permission mode.");
54100
+ } else {
54101
+ console.log("No pending approvals right now. Future actions in this shell will use auto approvals.");
54102
+ }
53639
54103
  return cwd;
53640
54104
  }
53641
54105
  await resolvePendingApproval(
@@ -53651,6 +54115,27 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
53651
54115
  }
53652
54116
  if (head === "approve" || head === "deny") {
53653
54117
  const approvalId = tokens[1]?.trim();
54118
+ if (head === "approve" && approvalId === "all") {
54119
+ const shouldResolvePending = await applyApproveAllPreset(cwd, runtime);
54120
+ if (!shouldResolvePending) {
54121
+ if (runtime.pendingRunProposal) {
54122
+ void startPendingRunExecution(cwd, runtime);
54123
+ return cwd;
54124
+ }
54125
+ console.log("No pending approvals right now. Future actions in this shell will use auto approvals.");
54126
+ return cwd;
54127
+ }
54128
+ await resolvePendingApproval(
54129
+ cwd,
54130
+ runtime,
54131
+ "approve",
54132
+ "all",
54133
+ {
54134
+ allowAll: true
54135
+ }
54136
+ );
54137
+ return cwd;
54138
+ }
53654
54139
  if (!approvalId && runtime.pendingRunProposal) {
53655
54140
  if (head === "approve") {
53656
54141
  void startPendingRunExecution(cwd, runtime);
@@ -53681,9 +54166,9 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
53681
54166
  }
53682
54167
  async function runInteractiveShell(options) {
53683
54168
  const readline = (0, import_promises27.createInterface)({
53684
- input: import_node_process35.default.stdin,
53685
- output: import_node_process35.default.stdout,
53686
- terminal: Boolean(import_node_process35.default.stdin.isTTY && import_node_process35.default.stdout.isTTY)
54169
+ input: import_node_process36.default.stdin,
54170
+ output: import_node_process36.default.stdout,
54171
+ terminal: Boolean(import_node_process36.default.stdin.isTTY && import_node_process36.default.stdout.isTTY)
53687
54172
  });
53688
54173
  const runtime = {
53689
54174
  focusRole: "coder",
@@ -53715,7 +54200,7 @@ async function runInteractiveShell(options) {
53715
54200
  };
53716
54201
  let currentCwd = options.cwd;
53717
54202
  let closed = false;
53718
- const useDashboard = Boolean(import_node_process35.default.stdin.isTTY && import_node_process35.default.stdout.isTTY);
54203
+ const useDashboard = Boolean(import_node_process36.default.stdin.isTTY && import_node_process36.default.stdout.isTTY);
53719
54204
  const originalLog = console.log;
53720
54205
  const originalError = console.error;
53721
54206
  if (useDashboard) {
@@ -53731,7 +54216,7 @@ async function runInteractiveShell(options) {
53731
54216
  readline.on("SIGINT", () => {
53732
54217
  if (runtime.activeExecution) {
53733
54218
  runtime.activeExecution.controller.abort();
53734
- import_node_process35.default.stdout.write("\n");
54219
+ import_node_process36.default.stdout.write("\n");
53735
54220
  console.log(color(DIM, `Interrupt requested. Pausing ${runtime.activeExecution.label} after the current step...`));
53736
54221
  return;
53737
54222
  }
@@ -53752,10 +54237,14 @@ async function runInteractiveShell(options) {
53752
54237
  try {
53753
54238
  state = await getShellSessionState(currentCwd, runtime.focusRole, runtime);
53754
54239
  runtime.dashboard?.update(currentCwd, state);
53755
- line = await readline.question(formatPrompt(state));
54240
+ line = await readShellInput(readline, state);
53756
54241
  } catch {
53757
54242
  break;
53758
54243
  }
54244
+ if (line === "__kimbho_sigint__") {
54245
+ closed = true;
54246
+ break;
54247
+ }
53759
54248
  try {
53760
54249
  currentCwd = await handleShellCommand(currentCwd, line, state, runtime, options.execute);
53761
54250
  runtime.currentCwd = currentCwd;
@@ -53767,7 +54256,7 @@ async function runInteractiveShell(options) {
53767
54256
  }
53768
54257
  console.error(message);
53769
54258
  } finally {
53770
- import_node_process35.default.exitCode = 0;
54259
+ import_node_process36.default.exitCode = 0;
53771
54260
  }
53772
54261
  if (!closed && !useDashboard) {
53773
54262
  console.log("");
@@ -53778,7 +54267,7 @@ async function runInteractiveShell(options) {
53778
54267
  if (runtime.activeExecution) {
53779
54268
  runtime.activeExecution.controller.abort();
53780
54269
  }
53781
- import_node_process35.default.exitCode = 0;
54270
+ import_node_process36.default.exitCode = 0;
53782
54271
  if (useDashboard) {
53783
54272
  runtime.dashboard?.stop();
53784
54273
  console.log = originalLog;