@kimbho/kimbho-cli 0.1.14 → 0.1.16
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 +1013 -214
- package/dist/index.cjs.map +3 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1147,7 +1147,7 @@ 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
|
|
1150
|
+
var path22 = require("node:path");
|
|
1151
1151
|
var fs = require("node:fs");
|
|
1152
1152
|
var process20 = require("node:process");
|
|
1153
1153
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
@@ -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 =
|
|
2150
|
+
const localBin = path22.resolve(baseDir, baseName);
|
|
2151
2151
|
if (fs.existsSync(localBin)) return localBin;
|
|
2152
|
-
if (sourceExt.includes(
|
|
2152
|
+
if (sourceExt.includes(path22.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 =
|
|
2171
|
-
|
|
2170
|
+
executableDir = path22.resolve(
|
|
2171
|
+
path22.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 =
|
|
2178
|
+
const legacyName = path22.basename(
|
|
2179
2179
|
this._scriptPath,
|
|
2180
|
-
|
|
2180
|
+
path22.extname(this._scriptPath)
|
|
2181
2181
|
);
|
|
2182
2182
|
if (legacyName !== this._name) {
|
|
2183
2183
|
localFile = findFile(
|
|
@@ -2188,7 +2188,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2188
2188
|
}
|
|
2189
2189
|
executableFile = localFile || executableFile;
|
|
2190
2190
|
}
|
|
2191
|
-
launchWithNode = sourceExt.includes(
|
|
2191
|
+
launchWithNode = sourceExt.includes(path22.extname(executableFile));
|
|
2192
2192
|
let proc;
|
|
2193
2193
|
if (process20.platform !== "win32") {
|
|
2194
2194
|
if (launchWithNode) {
|
|
@@ -3035,7 +3035,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3035
3035
|
* @return {Command}
|
|
3036
3036
|
*/
|
|
3037
3037
|
nameFromFilename(filename) {
|
|
3038
|
-
this._name =
|
|
3038
|
+
this._name = path22.basename(filename, path22.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(
|
|
3053
|
-
if (
|
|
3054
|
-
this._executableDir =
|
|
3052
|
+
executableDir(path23) {
|
|
3053
|
+
if (path23 === void 0) return this._executableDir;
|
|
3054
|
+
this._executableDir = path23;
|
|
3055
3055
|
return this;
|
|
3056
3056
|
}
|
|
3057
3057
|
/**
|
|
@@ -6516,8 +6516,8 @@ var require_utils = __commonJS({
|
|
|
6516
6516
|
}
|
|
6517
6517
|
return ind;
|
|
6518
6518
|
}
|
|
6519
|
-
function removeDotSegments(
|
|
6520
|
-
let input =
|
|
6519
|
+
function removeDotSegments(path22) {
|
|
6520
|
+
let input = path22;
|
|
6521
6521
|
const output = [];
|
|
6522
6522
|
let nextSlash = -1;
|
|
6523
6523
|
let len = 0;
|
|
@@ -6716,8 +6716,8 @@ var require_schemes = __commonJS({
|
|
|
6716
6716
|
wsComponent.secure = void 0;
|
|
6717
6717
|
}
|
|
6718
6718
|
if (wsComponent.resourceName) {
|
|
6719
|
-
const [
|
|
6720
|
-
wsComponent.path =
|
|
6719
|
+
const [path22, query] = wsComponent.resourceName.split("?");
|
|
6720
|
+
wsComponent.path = path22 && path22 !== "/" ? path22 : void 0;
|
|
6721
6721
|
wsComponent.query = query;
|
|
6722
6722
|
wsComponent.resourceName = void 0;
|
|
6723
6723
|
}
|
|
@@ -10098,7 +10098,7 @@ var require_windows = __commonJS({
|
|
|
10098
10098
|
module2.exports = isexe;
|
|
10099
10099
|
isexe.sync = sync;
|
|
10100
10100
|
var fs = require("fs");
|
|
10101
|
-
function checkPathExt(
|
|
10101
|
+
function checkPathExt(path22, options) {
|
|
10102
10102
|
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
10103
10103
|
if (!pathext) {
|
|
10104
10104
|
return true;
|
|
@@ -10109,25 +10109,25 @@ var require_windows = __commonJS({
|
|
|
10109
10109
|
}
|
|
10110
10110
|
for (var i = 0; i < pathext.length; i++) {
|
|
10111
10111
|
var p = pathext[i].toLowerCase();
|
|
10112
|
-
if (p &&
|
|
10112
|
+
if (p && path22.substr(-p.length).toLowerCase() === p) {
|
|
10113
10113
|
return true;
|
|
10114
10114
|
}
|
|
10115
10115
|
}
|
|
10116
10116
|
return false;
|
|
10117
10117
|
}
|
|
10118
|
-
function checkStat(stat2,
|
|
10118
|
+
function checkStat(stat2, path22, options) {
|
|
10119
10119
|
if (!stat2.isSymbolicLink() && !stat2.isFile()) {
|
|
10120
10120
|
return false;
|
|
10121
10121
|
}
|
|
10122
|
-
return checkPathExt(
|
|
10122
|
+
return checkPathExt(path22, options);
|
|
10123
10123
|
}
|
|
10124
|
-
function isexe(
|
|
10125
|
-
fs.stat(
|
|
10126
|
-
cb(er, er ? false : checkStat(stat2,
|
|
10124
|
+
function isexe(path22, options, cb) {
|
|
10125
|
+
fs.stat(path22, function(er, stat2) {
|
|
10126
|
+
cb(er, er ? false : checkStat(stat2, path22, options));
|
|
10127
10127
|
});
|
|
10128
10128
|
}
|
|
10129
|
-
function sync(
|
|
10130
|
-
return checkStat(fs.statSync(
|
|
10129
|
+
function sync(path22, options) {
|
|
10130
|
+
return checkStat(fs.statSync(path22), path22, options);
|
|
10131
10131
|
}
|
|
10132
10132
|
}
|
|
10133
10133
|
});
|
|
@@ -10138,13 +10138,13 @@ var require_mode = __commonJS({
|
|
|
10138
10138
|
module2.exports = isexe;
|
|
10139
10139
|
isexe.sync = sync;
|
|
10140
10140
|
var fs = require("fs");
|
|
10141
|
-
function isexe(
|
|
10142
|
-
fs.stat(
|
|
10141
|
+
function isexe(path22, options, cb) {
|
|
10142
|
+
fs.stat(path22, function(er, stat2) {
|
|
10143
10143
|
cb(er, er ? false : checkStat(stat2, options));
|
|
10144
10144
|
});
|
|
10145
10145
|
}
|
|
10146
|
-
function sync(
|
|
10147
|
-
return checkStat(fs.statSync(
|
|
10146
|
+
function sync(path22, options) {
|
|
10147
|
+
return checkStat(fs.statSync(path22), options);
|
|
10148
10148
|
}
|
|
10149
10149
|
function checkStat(stat2, options) {
|
|
10150
10150
|
return stat2.isFile() && checkMode(stat2, options);
|
|
@@ -10177,7 +10177,7 @@ var require_isexe = __commonJS({
|
|
|
10177
10177
|
}
|
|
10178
10178
|
module2.exports = isexe;
|
|
10179
10179
|
isexe.sync = sync;
|
|
10180
|
-
function isexe(
|
|
10180
|
+
function isexe(path22, options, cb) {
|
|
10181
10181
|
if (typeof options === "function") {
|
|
10182
10182
|
cb = options;
|
|
10183
10183
|
options = {};
|
|
@@ -10187,7 +10187,7 @@ var require_isexe = __commonJS({
|
|
|
10187
10187
|
throw new TypeError("callback not provided");
|
|
10188
10188
|
}
|
|
10189
10189
|
return new Promise(function(resolve, reject) {
|
|
10190
|
-
isexe(
|
|
10190
|
+
isexe(path22, options || {}, function(er, is) {
|
|
10191
10191
|
if (er) {
|
|
10192
10192
|
reject(er);
|
|
10193
10193
|
} else {
|
|
@@ -10196,7 +10196,7 @@ var require_isexe = __commonJS({
|
|
|
10196
10196
|
});
|
|
10197
10197
|
});
|
|
10198
10198
|
}
|
|
10199
|
-
core(
|
|
10199
|
+
core(path22, options || {}, function(er, is) {
|
|
10200
10200
|
if (er) {
|
|
10201
10201
|
if (er.code === "EACCES" || options && options.ignoreErrors) {
|
|
10202
10202
|
er = null;
|
|
@@ -10206,9 +10206,9 @@ var require_isexe = __commonJS({
|
|
|
10206
10206
|
cb(er, is);
|
|
10207
10207
|
});
|
|
10208
10208
|
}
|
|
10209
|
-
function sync(
|
|
10209
|
+
function sync(path22, options) {
|
|
10210
10210
|
try {
|
|
10211
|
-
return core.sync(
|
|
10211
|
+
return core.sync(path22, options || {});
|
|
10212
10212
|
} catch (er) {
|
|
10213
10213
|
if (options && options.ignoreErrors || er.code === "EACCES") {
|
|
10214
10214
|
return false;
|
|
@@ -10224,7 +10224,7 @@ var require_isexe = __commonJS({
|
|
|
10224
10224
|
var require_which = __commonJS({
|
|
10225
10225
|
"../../node_modules/which/which.js"(exports2, module2) {
|
|
10226
10226
|
var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
|
|
10227
|
-
var
|
|
10227
|
+
var path22 = require("path");
|
|
10228
10228
|
var COLON = isWindows ? ";" : ":";
|
|
10229
10229
|
var isexe = require_isexe();
|
|
10230
10230
|
var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
|
|
@@ -10262,7 +10262,7 @@ var require_which = __commonJS({
|
|
|
10262
10262
|
return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
|
|
10263
10263
|
const ppRaw = pathEnv[i];
|
|
10264
10264
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
10265
|
-
const pCmd =
|
|
10265
|
+
const pCmd = path22.join(pathPart, cmd);
|
|
10266
10266
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
10267
10267
|
resolve(subStep(p, i, 0));
|
|
10268
10268
|
});
|
|
@@ -10289,7 +10289,7 @@ var require_which = __commonJS({
|
|
|
10289
10289
|
for (let i = 0; i < pathEnv.length; i++) {
|
|
10290
10290
|
const ppRaw = pathEnv[i];
|
|
10291
10291
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
10292
|
-
const pCmd =
|
|
10292
|
+
const pCmd = path22.join(pathPart, cmd);
|
|
10293
10293
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
10294
10294
|
for (let j = 0; j < pathExt.length; j++) {
|
|
10295
10295
|
const cur = p + pathExt[j];
|
|
@@ -10337,7 +10337,7 @@ var require_path_key = __commonJS({
|
|
|
10337
10337
|
var require_resolveCommand = __commonJS({
|
|
10338
10338
|
"../../node_modules/cross-spawn/lib/util/resolveCommand.js"(exports2, module2) {
|
|
10339
10339
|
"use strict";
|
|
10340
|
-
var
|
|
10340
|
+
var path22 = require("path");
|
|
10341
10341
|
var which = require_which();
|
|
10342
10342
|
var getPathKey = require_path_key();
|
|
10343
10343
|
function resolveCommandAttempt(parsed, withoutPathExt) {
|
|
@@ -10355,7 +10355,7 @@ var require_resolveCommand = __commonJS({
|
|
|
10355
10355
|
try {
|
|
10356
10356
|
resolved = which.sync(parsed.command, {
|
|
10357
10357
|
path: env[getPathKey({ env })],
|
|
10358
|
-
pathExt: withoutPathExt ?
|
|
10358
|
+
pathExt: withoutPathExt ? path22.delimiter : void 0
|
|
10359
10359
|
});
|
|
10360
10360
|
} catch (e) {
|
|
10361
10361
|
} finally {
|
|
@@ -10364,7 +10364,7 @@ var require_resolveCommand = __commonJS({
|
|
|
10364
10364
|
}
|
|
10365
10365
|
}
|
|
10366
10366
|
if (resolved) {
|
|
10367
|
-
resolved =
|
|
10367
|
+
resolved = path22.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
|
|
10368
10368
|
}
|
|
10369
10369
|
return resolved;
|
|
10370
10370
|
}
|
|
@@ -10418,8 +10418,8 @@ var require_shebang_command = __commonJS({
|
|
|
10418
10418
|
if (!match) {
|
|
10419
10419
|
return null;
|
|
10420
10420
|
}
|
|
10421
|
-
const [
|
|
10422
|
-
const binary =
|
|
10421
|
+
const [path22, argument] = match[0].replace(/#! ?/, "").split(" ");
|
|
10422
|
+
const binary = path22.split("/").pop();
|
|
10423
10423
|
if (binary === "env") {
|
|
10424
10424
|
return argument;
|
|
10425
10425
|
}
|
|
@@ -10454,7 +10454,7 @@ var require_readShebang = __commonJS({
|
|
|
10454
10454
|
var require_parse = __commonJS({
|
|
10455
10455
|
"../../node_modules/cross-spawn/lib/parse.js"(exports2, module2) {
|
|
10456
10456
|
"use strict";
|
|
10457
|
-
var
|
|
10457
|
+
var path22 = require("path");
|
|
10458
10458
|
var resolveCommand = require_resolveCommand();
|
|
10459
10459
|
var escape2 = require_escape();
|
|
10460
10460
|
var readShebang = require_readShebang();
|
|
@@ -10479,7 +10479,7 @@ var require_parse = __commonJS({
|
|
|
10479
10479
|
const needsShell = !isExecutableRegExp.test(commandFile);
|
|
10480
10480
|
if (parsed.options.forceShell || needsShell) {
|
|
10481
10481
|
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
|
|
10482
|
-
parsed.command =
|
|
10482
|
+
parsed.command = path22.normalize(parsed.command);
|
|
10483
10483
|
parsed.command = escape2.command(parsed.command);
|
|
10484
10484
|
parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
|
|
10485
10485
|
const shellCommand = [parsed.command].concat(parsed.args).join(" ");
|
|
@@ -10612,7 +10612,7 @@ var {
|
|
|
10612
10612
|
// package.json
|
|
10613
10613
|
var package_default = {
|
|
10614
10614
|
name: "@kimbho/kimbho-cli",
|
|
10615
|
-
version: "0.1.
|
|
10615
|
+
version: "0.1.16",
|
|
10616
10616
|
description: "Kimbho CLI is a terminal-native coding agent for planning, execution, and verification.",
|
|
10617
10617
|
type: "module",
|
|
10618
10618
|
engines: {
|
|
@@ -11406,8 +11406,8 @@ function getErrorMap() {
|
|
|
11406
11406
|
|
|
11407
11407
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
11408
11408
|
var makeIssue = (params) => {
|
|
11409
|
-
const { data, path:
|
|
11410
|
-
const fullPath = [...
|
|
11409
|
+
const { data, path: path22, errorMaps, issueData } = params;
|
|
11410
|
+
const fullPath = [...path22, ...issueData.path || []];
|
|
11411
11411
|
const fullIssue = {
|
|
11412
11412
|
...issueData,
|
|
11413
11413
|
path: fullPath
|
|
@@ -11523,11 +11523,11 @@ var errorUtil;
|
|
|
11523
11523
|
|
|
11524
11524
|
// ../../node_modules/zod/v3/types.js
|
|
11525
11525
|
var ParseInputLazyPath = class {
|
|
11526
|
-
constructor(parent, value,
|
|
11526
|
+
constructor(parent, value, path22, key) {
|
|
11527
11527
|
this._cachedPath = [];
|
|
11528
11528
|
this.parent = parent;
|
|
11529
11529
|
this.data = value;
|
|
11530
|
-
this._path =
|
|
11530
|
+
this._path = path22;
|
|
11531
11531
|
this._key = key;
|
|
11532
11532
|
}
|
|
11533
11533
|
get path() {
|
|
@@ -15026,7 +15026,10 @@ var PlanTaskSchema = external_exports.object({
|
|
|
15026
15026
|
filesLikelyTouched: external_exports.array(external_exports.string()).default([]),
|
|
15027
15027
|
riskLevel: RiskLevelSchema.default("medium"),
|
|
15028
15028
|
originTaskId: external_exports.string().min(1).optional(),
|
|
15029
|
-
swarmDepth: external_exports.number().int().nonnegative().optional()
|
|
15029
|
+
swarmDepth: external_exports.number().int().nonnegative().optional(),
|
|
15030
|
+
customAgentId: external_exports.string().min(1).optional(),
|
|
15031
|
+
teamId: external_exports.string().min(1).optional(),
|
|
15032
|
+
teamMemberIds: external_exports.array(external_exports.string()).optional()
|
|
15030
15033
|
});
|
|
15031
15034
|
var PlanMilestoneSchema = external_exports.object({
|
|
15032
15035
|
id: external_exports.string().min(1),
|
|
@@ -15437,6 +15440,7 @@ function summarizeStructuredOutputError(context, error2) {
|
|
|
15437
15440
|
|
|
15438
15441
|
// ../core/dist/config/config.js
|
|
15439
15442
|
var import_promises = require("node:fs/promises");
|
|
15443
|
+
var import_node_os = __toESM(require("node:os"), 1);
|
|
15440
15444
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
15441
15445
|
var KIMBHO_DIR_NAME = ".kimbho";
|
|
15442
15446
|
function resolveKimbhoDir(cwd = process.cwd()) {
|
|
@@ -15445,6 +15449,9 @@ function resolveKimbhoDir(cwd = process.cwd()) {
|
|
|
15445
15449
|
function resolveConfigPath(cwd = process.cwd()) {
|
|
15446
15450
|
return import_node_path.default.join(resolveKimbhoDir(cwd), "config.json");
|
|
15447
15451
|
}
|
|
15452
|
+
function resolveGlobalConfigPath() {
|
|
15453
|
+
return import_node_path.default.join(import_node_os.default.homedir(), ".kimbho", "config.json");
|
|
15454
|
+
}
|
|
15448
15455
|
var LegacyProviderNameSchema = external_exports.enum([
|
|
15449
15456
|
"openai",
|
|
15450
15457
|
"anthropic",
|
|
@@ -15599,8 +15606,7 @@ async function ensureKimbhoDir(cwd = process.cwd()) {
|
|
|
15599
15606
|
await (0, import_promises.mkdir)(import_node_path.default.join(root, "teams"), { recursive: true });
|
|
15600
15607
|
return root;
|
|
15601
15608
|
}
|
|
15602
|
-
async function
|
|
15603
|
-
const configPath = resolveConfigPath(cwd);
|
|
15609
|
+
async function loadConfigFile(configPath) {
|
|
15604
15610
|
try {
|
|
15605
15611
|
const raw = await (0, import_promises.readFile)(configPath, "utf8");
|
|
15606
15612
|
return KimbhoConfigSchema.parse(normalizeConfigInput(JSON.parse(raw)));
|
|
@@ -15612,6 +15618,77 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
15612
15618
|
throw error2;
|
|
15613
15619
|
}
|
|
15614
15620
|
}
|
|
15621
|
+
async function loadProjectConfig(cwd = process.cwd()) {
|
|
15622
|
+
return loadConfigFile(resolveConfigPath(cwd));
|
|
15623
|
+
}
|
|
15624
|
+
async function loadUserConfig() {
|
|
15625
|
+
return loadConfigFile(resolveGlobalConfigPath());
|
|
15626
|
+
}
|
|
15627
|
+
function mergeConfigCatalog(lower, upper) {
|
|
15628
|
+
const merged = /* @__PURE__ */ new Map();
|
|
15629
|
+
for (const provider of lower) {
|
|
15630
|
+
merged.set(provider.id, provider);
|
|
15631
|
+
}
|
|
15632
|
+
for (const provider of upper) {
|
|
15633
|
+
merged.set(provider.id, provider);
|
|
15634
|
+
}
|
|
15635
|
+
return Array.from(merged.values());
|
|
15636
|
+
}
|
|
15637
|
+
function mergeConfigLayers(base, override) {
|
|
15638
|
+
return KimbhoConfigSchema.parse({
|
|
15639
|
+
providers: mergeConfigCatalog(base.providers, override.providers),
|
|
15640
|
+
brains: {
|
|
15641
|
+
planner: {
|
|
15642
|
+
...base.brains.planner,
|
|
15643
|
+
...override.brains.planner
|
|
15644
|
+
},
|
|
15645
|
+
coder: {
|
|
15646
|
+
...base.brains.coder,
|
|
15647
|
+
...override.brains.coder
|
|
15648
|
+
},
|
|
15649
|
+
reviewer: {
|
|
15650
|
+
...base.brains.reviewer,
|
|
15651
|
+
...override.brains.reviewer
|
|
15652
|
+
},
|
|
15653
|
+
fast: {
|
|
15654
|
+
...base.brains.fast,
|
|
15655
|
+
...override.brains.fast
|
|
15656
|
+
}
|
|
15657
|
+
},
|
|
15658
|
+
approvalMode: override.approvalMode ?? base.approvalMode,
|
|
15659
|
+
sandboxMode: override.sandboxMode ?? base.sandboxMode,
|
|
15660
|
+
stackPresets: Array.from(/* @__PURE__ */ new Set([
|
|
15661
|
+
...base.stackPresets,
|
|
15662
|
+
...override.stackPresets
|
|
15663
|
+
])),
|
|
15664
|
+
trustedDirectories: Array.from(/* @__PURE__ */ new Set([
|
|
15665
|
+
...base.trustedDirectories,
|
|
15666
|
+
...override.trustedDirectories
|
|
15667
|
+
]))
|
|
15668
|
+
});
|
|
15669
|
+
}
|
|
15670
|
+
async function loadConfigLayers(cwd = process.cwd()) {
|
|
15671
|
+
const [user, project] = await Promise.all([
|
|
15672
|
+
loadUserConfig(),
|
|
15673
|
+
loadProjectConfig(cwd)
|
|
15674
|
+
]);
|
|
15675
|
+
if (!user && !project) {
|
|
15676
|
+
return {
|
|
15677
|
+
user: null,
|
|
15678
|
+
project: null,
|
|
15679
|
+
resolved: null
|
|
15680
|
+
};
|
|
15681
|
+
}
|
|
15682
|
+
return {
|
|
15683
|
+
user,
|
|
15684
|
+
project,
|
|
15685
|
+
resolved: user && project ? mergeConfigLayers(user, project) : project ?? user
|
|
15686
|
+
};
|
|
15687
|
+
}
|
|
15688
|
+
async function loadConfig(cwd = process.cwd()) {
|
|
15689
|
+
const layers = await loadConfigLayers(cwd);
|
|
15690
|
+
return layers.resolved;
|
|
15691
|
+
}
|
|
15615
15692
|
async function saveConfig(config2, cwd = process.cwd()) {
|
|
15616
15693
|
await ensureKimbhoDir(cwd);
|
|
15617
15694
|
const configPath = resolveConfigPath(cwd);
|
|
@@ -15622,6 +15699,16 @@ async function saveConfig(config2, cwd = process.cwd()) {
|
|
|
15622
15699
|
await (0, import_promises.rename)(tempPath, configPath);
|
|
15623
15700
|
return configPath;
|
|
15624
15701
|
}
|
|
15702
|
+
async function saveUserConfig(config2) {
|
|
15703
|
+
const configPath = resolveGlobalConfigPath();
|
|
15704
|
+
await (0, import_promises.mkdir)(import_node_path.default.dirname(configPath), { recursive: true });
|
|
15705
|
+
const normalized = KimbhoConfigSchema.parse(config2);
|
|
15706
|
+
const tempPath = `${configPath}.tmp-${process.pid}-${Date.now()}`;
|
|
15707
|
+
await (0, import_promises.writeFile)(tempPath, `${JSON.stringify(normalized, null, 2)}
|
|
15708
|
+
`, "utf8");
|
|
15709
|
+
await (0, import_promises.rename)(tempPath, configPath);
|
|
15710
|
+
return configPath;
|
|
15711
|
+
}
|
|
15625
15712
|
function findProviderById(config2, providerId) {
|
|
15626
15713
|
return config2.providers.find((provider) => provider.id === providerId);
|
|
15627
15714
|
}
|
|
@@ -15740,10 +15827,10 @@ async function loadLatestSession(cwd = process.cwd()) {
|
|
|
15740
15827
|
|
|
15741
15828
|
// ../core/dist/memory.js
|
|
15742
15829
|
var import_promises3 = require("node:fs/promises");
|
|
15743
|
-
var
|
|
15830
|
+
var import_node_os2 = __toESM(require("node:os"), 1);
|
|
15744
15831
|
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
15745
15832
|
function resolveGlobalKimbhoHome() {
|
|
15746
|
-
return import_node_path3.default.join(
|
|
15833
|
+
return import_node_path3.default.join(import_node_os2.default.homedir(), ".kimbho");
|
|
15747
15834
|
}
|
|
15748
15835
|
function resolveUserMemoryPath() {
|
|
15749
15836
|
return import_node_path3.default.join(resolveGlobalKimbhoHome(), "memory.md");
|
|
@@ -15807,6 +15894,54 @@ ${block}` : `# ${import_node_path3.default.basename(filePath, import_node_path3.
|
|
|
15807
15894
|
|
|
15808
15895
|
${block}`);
|
|
15809
15896
|
}
|
|
15897
|
+
function uniqueOrdered(values) {
|
|
15898
|
+
return Array.from(new Set(values));
|
|
15899
|
+
}
|
|
15900
|
+
function candidateMemoryFilesForDirectory(directory) {
|
|
15901
|
+
return [
|
|
15902
|
+
import_node_path3.default.join(directory, "KIMBHO.md"),
|
|
15903
|
+
import_node_path3.default.join(directory, "KIMBHO.local.md"),
|
|
15904
|
+
import_node_path3.default.join(directory, "CLAUDE.md"),
|
|
15905
|
+
import_node_path3.default.join(directory, "CLAUDE.local.md")
|
|
15906
|
+
];
|
|
15907
|
+
}
|
|
15908
|
+
function discoverMarkdownMemoryPaths(cwd = process.cwd()) {
|
|
15909
|
+
const discovered = [];
|
|
15910
|
+
let current = import_node_path3.default.resolve(cwd);
|
|
15911
|
+
const root = import_node_path3.default.parse(current).root;
|
|
15912
|
+
while (true) {
|
|
15913
|
+
discovered.push(...candidateMemoryFilesForDirectory(current));
|
|
15914
|
+
if (current === root) {
|
|
15915
|
+
break;
|
|
15916
|
+
}
|
|
15917
|
+
current = import_node_path3.default.dirname(current);
|
|
15918
|
+
}
|
|
15919
|
+
discovered.push(import_node_path3.default.join(cwd, "kimbho_init.md"));
|
|
15920
|
+
discovered.push(resolveProjectMemoryPath(cwd));
|
|
15921
|
+
discovered.push(resolveUserMemoryPath());
|
|
15922
|
+
return uniqueOrdered(discovered);
|
|
15923
|
+
}
|
|
15924
|
+
async function loadMarkdownMemoryContext(cwd = process.cwd(), options = {}) {
|
|
15925
|
+
const candidates = discoverMarkdownMemoryPaths(cwd);
|
|
15926
|
+
const records = [];
|
|
15927
|
+
const maxFiles = options.maxFiles ?? 12;
|
|
15928
|
+
const maxCharsPerFile = options.maxCharsPerFile ?? 6e3;
|
|
15929
|
+
for (const filePath of candidates) {
|
|
15930
|
+
if (records.length >= maxFiles) {
|
|
15931
|
+
break;
|
|
15932
|
+
}
|
|
15933
|
+
const content = await readMarkdownIfExists(filePath);
|
|
15934
|
+
if (!content || content.trim().length === 0) {
|
|
15935
|
+
continue;
|
|
15936
|
+
}
|
|
15937
|
+
records.push({
|
|
15938
|
+
filePath,
|
|
15939
|
+
content: content.length > maxCharsPerFile ? `${content.slice(0, maxCharsPerFile)}
|
|
15940
|
+
... [truncated]` : content
|
|
15941
|
+
});
|
|
15942
|
+
}
|
|
15943
|
+
return records;
|
|
15944
|
+
}
|
|
15810
15945
|
|
|
15811
15946
|
// ../core/dist/mcp.js
|
|
15812
15947
|
var import_promises4 = require("node:fs/promises");
|
|
@@ -15996,6 +16131,8 @@ async function loadAgentTeams(cwd) {
|
|
|
15996
16131
|
id,
|
|
15997
16132
|
label: typeof attributes.label === "string" ? attributes.label : id,
|
|
15998
16133
|
agents: asStringArray(attributes.agents),
|
|
16134
|
+
match: asStringArray(attributes.match),
|
|
16135
|
+
strategy: typeof attributes.strategy === "string" && attributes.strategy === "parallel" ? "parallel" : "sequential",
|
|
15999
16136
|
filePath,
|
|
16000
16137
|
...body.trim() ? {
|
|
16001
16138
|
description: body.trim()
|
|
@@ -16044,8 +16181,11 @@ async function createAgentTeamFile(cwd, id, agentIds, label) {
|
|
|
16044
16181
|
"---",
|
|
16045
16182
|
`id: ${id}`,
|
|
16046
16183
|
`label: ${label ?? id}`,
|
|
16184
|
+
"match:",
|
|
16185
|
+
" - feature",
|
|
16047
16186
|
"agents:",
|
|
16048
16187
|
...agentIds.map((agentId) => ` - ${agentId}`),
|
|
16188
|
+
"strategy: sequential",
|
|
16049
16189
|
"---",
|
|
16050
16190
|
"",
|
|
16051
16191
|
`# ${label ?? id}`,
|
|
@@ -16072,11 +16212,46 @@ function scoreCustomAgentMatch(definition, task, request) {
|
|
|
16072
16212
|
}
|
|
16073
16213
|
return definition.match.reduce((score, keyword) => haystack.includes(keyword.toLowerCase()) ? score + 1 : score, 0);
|
|
16074
16214
|
}
|
|
16215
|
+
function scoreAgentTeamMatch(definition, task, request) {
|
|
16216
|
+
const haystack = [
|
|
16217
|
+
request.goal,
|
|
16218
|
+
task.title,
|
|
16219
|
+
task.description,
|
|
16220
|
+
...task.acceptanceCriteria
|
|
16221
|
+
].join(" ").toLowerCase();
|
|
16222
|
+
if (definition.match.length === 0) {
|
|
16223
|
+
return definition.agents.length > 0 ? 1 : -1;
|
|
16224
|
+
}
|
|
16225
|
+
return definition.match.reduce((score, keyword) => haystack.includes(keyword.toLowerCase()) ? score + 1 : score, 0);
|
|
16226
|
+
}
|
|
16227
|
+
async function selectAgentTeam(cwd, task, request) {
|
|
16228
|
+
const [teams, agents] = await Promise.all([
|
|
16229
|
+
loadAgentTeams(cwd),
|
|
16230
|
+
loadCustomAgents(cwd)
|
|
16231
|
+
]);
|
|
16232
|
+
const selected = teams.map((team) => ({
|
|
16233
|
+
team,
|
|
16234
|
+
score: scoreAgentTeamMatch(team, task, request)
|
|
16235
|
+
})).filter((candidate) => candidate.score > 0).sort((left, right) => right.score - left.score || left.team.id.localeCompare(right.team.id))[0]?.team;
|
|
16236
|
+
if (!selected) {
|
|
16237
|
+
return null;
|
|
16238
|
+
}
|
|
16239
|
+
const members = selected.agents.map((agentId) => agents.find((candidate) => candidate.id === agentId)).filter((candidate) => Boolean(candidate));
|
|
16240
|
+
return {
|
|
16241
|
+
team: selected,
|
|
16242
|
+
members
|
|
16243
|
+
};
|
|
16244
|
+
}
|
|
16075
16245
|
async function selectCustomAgentOverlay(cwd, task, request, builtInTools) {
|
|
16076
|
-
const
|
|
16246
|
+
const selectedTeam = task.teamId ? await selectAgentTeam(cwd, task, request) : await selectAgentTeam(cwd, task, request);
|
|
16247
|
+
const allDefinitions = await loadCustomAgents(cwd);
|
|
16248
|
+
const preferredDefinition = task.customAgentId ? allDefinitions.find((definition) => definition.id === task.customAgentId) : null;
|
|
16249
|
+
const definitions = preferredDefinition ? [
|
|
16250
|
+
preferredDefinition
|
|
16251
|
+
] : selectedTeam?.members.length ? selectedTeam.members : allDefinitions;
|
|
16077
16252
|
const ranked = definitions.map((definition) => ({
|
|
16078
16253
|
definition,
|
|
16079
|
-
score: scoreCustomAgentMatch(definition, task, request)
|
|
16254
|
+
score: preferredDefinition && definition.id === preferredDefinition.id ? Number.MAX_SAFE_INTEGER : scoreCustomAgentMatch(definition, task, request)
|
|
16080
16255
|
})).filter((candidate) => candidate.score > 0).sort((left, right) => right.score - left.score || left.definition.id.localeCompare(right.definition.id));
|
|
16081
16256
|
const selected = ranked[0]?.definition;
|
|
16082
16257
|
if (!selected) {
|
|
@@ -16090,6 +16265,12 @@ async function selectCustomAgentOverlay(cwd, task, request, builtInTools) {
|
|
|
16090
16265
|
purpose: selected.purpose ?? baseProfile.purpose,
|
|
16091
16266
|
brainRole: selected.brainRole ?? baseProfile.brainRole,
|
|
16092
16267
|
promptPreamble: [
|
|
16268
|
+
...selectedTeam ? [
|
|
16269
|
+
`Agent team active: ${selectedTeam.team.label} (${selectedTeam.team.id}).`,
|
|
16270
|
+
`Team strategy: ${selectedTeam.team.strategy}.`,
|
|
16271
|
+
`Team roster: ${selectedTeam.members.map((member) => member.id).join(", ") || "(none)"}.`,
|
|
16272
|
+
selectedTeam.team.description?.trim() ?? ""
|
|
16273
|
+
].filter((line) => line.length > 0) : [],
|
|
16093
16274
|
`Custom agent overlay: ${selected.label} (${selected.id}).`,
|
|
16094
16275
|
`Base role: ${selected.baseRole}.`,
|
|
16095
16276
|
selected.instructions.trim()
|
|
@@ -17311,7 +17492,7 @@ var import_promises11 = require("node:fs/promises");
|
|
|
17311
17492
|
var import_node_path11 = __toESM(require("node:path"), 1);
|
|
17312
17493
|
var import_node_process2 = __toESM(require("node:process"), 1);
|
|
17313
17494
|
var import_node_child_process2 = require("node:child_process");
|
|
17314
|
-
var
|
|
17495
|
+
var import_node_os3 = require("node:os");
|
|
17315
17496
|
|
|
17316
17497
|
// ../tools/dist/browser-manager.js
|
|
17317
17498
|
var import_node_crypto2 = require("node:crypto");
|
|
@@ -18109,6 +18290,47 @@ var KNOWN_SCAFFOLD_PRESETS = [
|
|
|
18109
18290
|
];
|
|
18110
18291
|
function looksLikeStaticLandingGoal(value) {
|
|
18111
18292
|
const normalized = value.toLowerCase();
|
|
18293
|
+
const backendSignals = [
|
|
18294
|
+
"api",
|
|
18295
|
+
"database",
|
|
18296
|
+
"backend",
|
|
18297
|
+
"server",
|
|
18298
|
+
"migration",
|
|
18299
|
+
"schema",
|
|
18300
|
+
"prisma",
|
|
18301
|
+
"postgres",
|
|
18302
|
+
"sqlite",
|
|
18303
|
+
"auth",
|
|
18304
|
+
"billing",
|
|
18305
|
+
"webhook"
|
|
18306
|
+
];
|
|
18307
|
+
const pageSignals = [
|
|
18308
|
+
"page",
|
|
18309
|
+
"landing",
|
|
18310
|
+
"lnding",
|
|
18311
|
+
"homepage",
|
|
18312
|
+
"home page",
|
|
18313
|
+
"site",
|
|
18314
|
+
"website",
|
|
18315
|
+
"ui",
|
|
18316
|
+
"hero",
|
|
18317
|
+
"layout",
|
|
18318
|
+
"screen"
|
|
18319
|
+
];
|
|
18320
|
+
const polishSignals = [
|
|
18321
|
+
"animate",
|
|
18322
|
+
"animated",
|
|
18323
|
+
"animation",
|
|
18324
|
+
"motion",
|
|
18325
|
+
"rich",
|
|
18326
|
+
"richer",
|
|
18327
|
+
"polish",
|
|
18328
|
+
"styled",
|
|
18329
|
+
"styling",
|
|
18330
|
+
"visual",
|
|
18331
|
+
"redesign",
|
|
18332
|
+
"revamp"
|
|
18333
|
+
];
|
|
18112
18334
|
if (normalized.includes("landing page") || normalized.includes("landing") || normalized.includes("lnding") || normalized.includes("homepage") || normalized.includes("home page") || normalized.includes("marketing page") || normalized.includes("storefront") || normalized.includes("static")) {
|
|
18113
18335
|
return true;
|
|
18114
18336
|
}
|
|
@@ -18118,6 +18340,12 @@ function looksLikeStaticLandingGoal(value) {
|
|
|
18118
18340
|
if (normalized.includes("restaurant") && (normalized.includes("page") || normalized.includes("site") || normalized.includes("website") || normalized.includes("landing") || normalized.includes("lnding"))) {
|
|
18119
18341
|
return true;
|
|
18120
18342
|
}
|
|
18343
|
+
if (pageSignals.some((signal) => normalized.includes(signal)) && polishSignals.some((signal) => normalized.includes(signal)) && !backendSignals.some((signal) => normalized.includes(signal))) {
|
|
18344
|
+
return true;
|
|
18345
|
+
}
|
|
18346
|
+
if (normalized.includes("blog") && (normalized.includes("make") || normalized.includes("improve") || normalized.includes("enhance") || normalized.includes("redesign")) && !backendSignals.some((signal) => normalized.includes(signal))) {
|
|
18347
|
+
return true;
|
|
18348
|
+
}
|
|
18121
18349
|
return false;
|
|
18122
18350
|
}
|
|
18123
18351
|
function sanitizeName(value) {
|
|
@@ -19019,7 +19247,7 @@ async function createUnifiedDiffPreview(cwd, targetPath, beforeContent, afterCon
|
|
|
19019
19247
|
if (beforeContent === afterContent) {
|
|
19020
19248
|
return void 0;
|
|
19021
19249
|
}
|
|
19022
|
-
const tempDir = await (0, import_promises11.mkdtemp)(import_node_path11.default.join((0,
|
|
19250
|
+
const tempDir = await (0, import_promises11.mkdtemp)(import_node_path11.default.join((0, import_node_os3.tmpdir)(), "kimbho-diff-"));
|
|
19023
19251
|
const beforePath = import_node_path11.default.join(tempDir, "before");
|
|
19024
19252
|
const afterPath = import_node_path11.default.join(tempDir, "after");
|
|
19025
19253
|
const relativeTarget = import_node_path11.default.relative(cwd, targetPath) || import_node_path11.default.basename(targetPath);
|
|
@@ -19051,10 +19279,17 @@ async function createUnifiedDiffPreview(cwd, targetPath, beforeContent, afterCon
|
|
|
19051
19279
|
await (0, import_promises11.rm)(tempDir, { recursive: true, force: true });
|
|
19052
19280
|
}
|
|
19053
19281
|
}
|
|
19054
|
-
function
|
|
19282
|
+
function isTrustedWorkspacePath(resolved, trustedDirectories = []) {
|
|
19283
|
+
return trustedDirectories.some((trustedDirectory) => {
|
|
19284
|
+
const trustedRoot = import_node_path11.default.resolve(trustedDirectory);
|
|
19285
|
+
const relative = import_node_path11.default.relative(trustedRoot, resolved);
|
|
19286
|
+
return relative === "" || !relative.startsWith("..") && !import_node_path11.default.isAbsolute(relative);
|
|
19287
|
+
});
|
|
19288
|
+
}
|
|
19289
|
+
function resolveWorkspacePath(cwd, filePath, trustedDirectories = []) {
|
|
19055
19290
|
const resolved = import_node_path11.default.resolve(cwd, filePath);
|
|
19056
19291
|
const relative = import_node_path11.default.relative(cwd, resolved);
|
|
19057
|
-
if (relative.startsWith("..") || import_node_path11.default.isAbsolute(relative)) {
|
|
19292
|
+
if ((relative.startsWith("..") || import_node_path11.default.isAbsolute(relative)) && !isTrustedWorkspacePath(resolved, trustedDirectories)) {
|
|
19058
19293
|
throw new Error(`Path "${filePath}" escapes the workspace.`);
|
|
19059
19294
|
}
|
|
19060
19295
|
return resolved;
|
|
@@ -19137,10 +19372,10 @@ function normalizeArtifactRelativePath(cwd, absolutePath) {
|
|
|
19137
19372
|
function isProtectedWritePath(relativePath) {
|
|
19138
19373
|
return PROTECTED_WRITE_PREFIXES.some((prefix) => relativePath === prefix || relativePath.startsWith(`${prefix}/`));
|
|
19139
19374
|
}
|
|
19140
|
-
function extractProspectiveWriteTargets(toolId, input, cwd) {
|
|
19375
|
+
function extractProspectiveWriteTargets(toolId, input, cwd, trustedDirectories = []) {
|
|
19141
19376
|
if (toolId === "file.write" && typeof input.path === "string") {
|
|
19142
19377
|
return [
|
|
19143
|
-
normalizeArtifactRelativePath(cwd, resolveWorkspacePath(cwd, input.path))
|
|
19378
|
+
normalizeArtifactRelativePath(cwd, resolveWorkspacePath(cwd, input.path, trustedDirectories))
|
|
19144
19379
|
];
|
|
19145
19380
|
}
|
|
19146
19381
|
if (toolId === "file.patch" && typeof input.patch === "string") {
|
|
@@ -19212,7 +19447,7 @@ function enforceToolPolicy(toolId, input, descriptor, context) {
|
|
|
19212
19447
|
return null;
|
|
19213
19448
|
}
|
|
19214
19449
|
if ((toolId === "file.write" || toolId === "file.patch") && sandboxMode === "workspace-write") {
|
|
19215
|
-
const targets = extractProspectiveWriteTargets(toolId, input, context.cwd);
|
|
19450
|
+
const targets = extractProspectiveWriteTargets(toolId, input, context.cwd, context.trustedDirectories);
|
|
19216
19451
|
const protectedTargets = targets.filter((target) => isProtectedWritePath(target));
|
|
19217
19452
|
if (protectedTargets.length > 0) {
|
|
19218
19453
|
return createPolicyFailure(toolId, `Blocked write to protected workspace paths: ${protectedTargets.join(", ")}`);
|
|
@@ -19319,7 +19554,7 @@ async function executeFileRead(input, context) {
|
|
|
19319
19554
|
if (!rawPath) {
|
|
19320
19555
|
throw new Error("file.read requires a string path.");
|
|
19321
19556
|
}
|
|
19322
|
-
const targetPath = resolveWorkspacePath(context.cwd, rawPath);
|
|
19557
|
+
const targetPath = resolveWorkspacePath(context.cwd, rawPath, context.trustedDirectories);
|
|
19323
19558
|
const contents = await (0, import_promises11.readFile)(targetPath, "utf8");
|
|
19324
19559
|
return ToolResultSchema.parse({
|
|
19325
19560
|
toolId: "file.read",
|
|
@@ -19340,7 +19575,7 @@ async function executeFileList(input, context, timeoutMs) {
|
|
|
19340
19575
|
const root = typeof input.path === "string" && input.path.trim().length > 0 ? input.path : ".";
|
|
19341
19576
|
const pattern = typeof input.pattern === "string" && input.pattern.trim().length > 0 ? input.pattern : null;
|
|
19342
19577
|
const limit = parseLimitValue(input.limit, 200);
|
|
19343
|
-
const searchRoot = resolveWorkspacePath(context.cwd, root);
|
|
19578
|
+
const searchRoot = resolveWorkspacePath(context.cwd, root, context.trustedDirectories);
|
|
19344
19579
|
const relativeRoot = import_node_path11.default.relative(context.cwd, searchRoot) || ".";
|
|
19345
19580
|
const rootArg = relativeRoot === "." ? "." : relativeRoot;
|
|
19346
19581
|
let result;
|
|
@@ -19388,7 +19623,7 @@ async function executeFileSearch(input, context, timeoutMs) {
|
|
|
19388
19623
|
if (!pattern) {
|
|
19389
19624
|
throw new Error("file.search requires a non-empty pattern.");
|
|
19390
19625
|
}
|
|
19391
|
-
const searchRoot = resolveWorkspacePath(context.cwd, root);
|
|
19626
|
+
const searchRoot = resolveWorkspacePath(context.cwd, root, context.trustedDirectories);
|
|
19392
19627
|
const relativeRoot = import_node_path11.default.relative(context.cwd, searchRoot) || ".";
|
|
19393
19628
|
const rootArg = relativeRoot === "." ? "." : relativeRoot;
|
|
19394
19629
|
let result;
|
|
@@ -19444,7 +19679,7 @@ async function executeFileWrite(input, context) {
|
|
|
19444
19679
|
if (content === null) {
|
|
19445
19680
|
throw new Error("file.write requires a string content field.");
|
|
19446
19681
|
}
|
|
19447
|
-
const targetPath = resolveWorkspacePath(context.cwd, rawPath);
|
|
19682
|
+
const targetPath = resolveWorkspacePath(context.cwd, rawPath, context.trustedDirectories);
|
|
19448
19683
|
let existed = true;
|
|
19449
19684
|
let previousContent = "";
|
|
19450
19685
|
try {
|
|
@@ -19522,7 +19757,7 @@ async function executeGitDiff(input, context, timeoutMs) {
|
|
|
19522
19757
|
"--unified=3"
|
|
19523
19758
|
];
|
|
19524
19759
|
if (rawPath) {
|
|
19525
|
-
const targetPath = resolveWorkspacePath(context.cwd, rawPath);
|
|
19760
|
+
const targetPath = resolveWorkspacePath(context.cwd, rawPath, context.trustedDirectories);
|
|
19526
19761
|
const relativeTarget = import_node_path11.default.relative(context.cwd, targetPath) || ".";
|
|
19527
19762
|
args.push("--", relativeTarget);
|
|
19528
19763
|
}
|
|
@@ -19859,7 +20094,7 @@ async function executeProcessStart(input, context) {
|
|
|
19859
20094
|
if (!command) {
|
|
19860
20095
|
throw new Error("process.start requires a command string.");
|
|
19861
20096
|
}
|
|
19862
|
-
const processCwd = rawPath ? resolveWorkspacePath(context.cwd, rawPath) : context.cwd;
|
|
20097
|
+
const processCwd = rawPath ? resolveWorkspacePath(context.cwd, rawPath, context.trustedDirectories) : context.cwd;
|
|
19863
20098
|
const record2 = await startManagedProcess(processCwd, command, name, context.signal);
|
|
19864
20099
|
return ToolResultSchema.parse({
|
|
19865
20100
|
toolId: "process.start",
|
|
@@ -19957,7 +20192,7 @@ async function executeFilePatch(input, context, timeoutMs) {
|
|
|
19957
20192
|
if (!patch) {
|
|
19958
20193
|
throw new Error("file.patch requires a unified diff in the patch field.");
|
|
19959
20194
|
}
|
|
19960
|
-
const tempDir = await (0, import_promises11.mkdtemp)(import_node_path11.default.join((0,
|
|
20195
|
+
const tempDir = await (0, import_promises11.mkdtemp)(import_node_path11.default.join((0, import_node_os3.tmpdir)(), "kimbho-patch-"));
|
|
19961
20196
|
const patchPath = import_node_path11.default.join(tempDir, "change.patch");
|
|
19962
20197
|
try {
|
|
19963
20198
|
await (0, import_promises11.writeFile)(patchPath, patch, "utf8");
|
|
@@ -20310,10 +20545,10 @@ function assignProp(target, prop, value) {
|
|
|
20310
20545
|
configurable: true
|
|
20311
20546
|
});
|
|
20312
20547
|
}
|
|
20313
|
-
function getElementAtPath(obj,
|
|
20314
|
-
if (!
|
|
20548
|
+
function getElementAtPath(obj, path22) {
|
|
20549
|
+
if (!path22)
|
|
20315
20550
|
return obj;
|
|
20316
|
-
return
|
|
20551
|
+
return path22.reduce((acc, key) => acc?.[key], obj);
|
|
20317
20552
|
}
|
|
20318
20553
|
function promiseAllObject(promisesObj) {
|
|
20319
20554
|
const keys = Object.keys(promisesObj);
|
|
@@ -20633,11 +20868,11 @@ function aborted(x, startIndex = 0) {
|
|
|
20633
20868
|
}
|
|
20634
20869
|
return false;
|
|
20635
20870
|
}
|
|
20636
|
-
function prefixIssues(
|
|
20871
|
+
function prefixIssues(path22, issues) {
|
|
20637
20872
|
return issues.map((iss) => {
|
|
20638
20873
|
var _a;
|
|
20639
20874
|
(_a = iss).path ?? (_a.path = []);
|
|
20640
|
-
iss.path.unshift(
|
|
20875
|
+
iss.path.unshift(path22);
|
|
20641
20876
|
return iss;
|
|
20642
20877
|
});
|
|
20643
20878
|
}
|
|
@@ -27385,6 +27620,7 @@ var MCP_ALLOWED_ROLES = [
|
|
|
27385
27620
|
"reviewer",
|
|
27386
27621
|
"integrator"
|
|
27387
27622
|
];
|
|
27623
|
+
var MCP_INVENTORY_TIMEOUT_MS = 8e3;
|
|
27388
27624
|
function toMcpToolId(serverName, toolName) {
|
|
27389
27625
|
return `mcp.${serverName}.${toolName}`;
|
|
27390
27626
|
}
|
|
@@ -27427,7 +27663,7 @@ function renderMcpContent(result) {
|
|
|
27427
27663
|
}
|
|
27428
27664
|
return sections.length > 0 ? sections.join("\n\n") : void 0;
|
|
27429
27665
|
}
|
|
27430
|
-
async function withMcpClient(cwd, name, server, handler) {
|
|
27666
|
+
async function withMcpClient(cwd, name, server, handler, options = {}) {
|
|
27431
27667
|
const transport = new StdioClientTransport({
|
|
27432
27668
|
command: server.command,
|
|
27433
27669
|
args: server.args,
|
|
@@ -27446,10 +27682,31 @@ async function withMcpClient(cwd, name, server, handler) {
|
|
|
27446
27682
|
name: "kimbho",
|
|
27447
27683
|
version: "0.1.13"
|
|
27448
27684
|
});
|
|
27449
|
-
|
|
27685
|
+
const run = async () => {
|
|
27686
|
+
await client.connect(transport);
|
|
27687
|
+
return handler(client);
|
|
27688
|
+
};
|
|
27450
27689
|
try {
|
|
27451
|
-
|
|
27690
|
+
if (typeof options.timeoutMs === "number" && options.timeoutMs > 0) {
|
|
27691
|
+
let timer;
|
|
27692
|
+
try {
|
|
27693
|
+
return await Promise.race([
|
|
27694
|
+
run(),
|
|
27695
|
+
new Promise((_, reject) => {
|
|
27696
|
+
timer = setTimeout(() => {
|
|
27697
|
+
reject(new Error(`${options.timeoutLabel ?? `MCP call for ${name}`} timed out after ${options.timeoutMs}ms.`));
|
|
27698
|
+
}, options.timeoutMs);
|
|
27699
|
+
})
|
|
27700
|
+
]);
|
|
27701
|
+
} finally {
|
|
27702
|
+
if (timer) {
|
|
27703
|
+
clearTimeout(timer);
|
|
27704
|
+
}
|
|
27705
|
+
}
|
|
27706
|
+
}
|
|
27707
|
+
return await run();
|
|
27452
27708
|
} finally {
|
|
27709
|
+
await client.close().catch(() => void 0);
|
|
27453
27710
|
await transport.close().catch(() => void 0);
|
|
27454
27711
|
}
|
|
27455
27712
|
}
|
|
@@ -27458,31 +27715,65 @@ async function loadMcpServerInventory(cwd) {
|
|
|
27458
27715
|
const servers = Object.entries(config2.mcpServers).filter(([, server]) => server.enabled !== false).sort(([left], [right]) => left.localeCompare(right));
|
|
27459
27716
|
const inventory = [];
|
|
27460
27717
|
for (const [name, server] of servers) {
|
|
27461
|
-
|
|
27462
|
-
const
|
|
27463
|
-
|
|
27464
|
-
|
|
27465
|
-
|
|
27466
|
-
|
|
27467
|
-
|
|
27468
|
-
|
|
27718
|
+
try {
|
|
27719
|
+
const record2 = await withMcpClient(cwd, name, server, async (client) => {
|
|
27720
|
+
const [toolsResponse, promptsResponse, resourcesResponse, resourceTemplatesResponse] = await Promise.all([
|
|
27721
|
+
client.listTools().catch(() => ({ tools: [] })),
|
|
27722
|
+
client.listPrompts().catch(() => ({ prompts: [] })),
|
|
27723
|
+
client.listResources().catch(() => ({ resources: [] })),
|
|
27724
|
+
client.listResourceTemplates().catch(() => ({ resourceTemplates: [] }))
|
|
27725
|
+
]);
|
|
27726
|
+
const instructions = client.getInstructions();
|
|
27727
|
+
return {
|
|
27728
|
+
name,
|
|
27729
|
+
config: server,
|
|
27730
|
+
tools: (toolsResponse.tools ?? []).map((tool) => ({
|
|
27731
|
+
serverName: name,
|
|
27732
|
+
toolName: tool.name,
|
|
27733
|
+
toolId: toMcpToolId(name, tool.name),
|
|
27734
|
+
description: tool.description ?? `MCP tool ${tool.name} from ${name}.`,
|
|
27735
|
+
permission: permissionFromAnnotations(tool.annotations)
|
|
27736
|
+
})),
|
|
27737
|
+
prompts: (promptsResponse.prompts ?? []).map((prompt) => ({
|
|
27738
|
+
serverName: name,
|
|
27739
|
+
name: prompt.name,
|
|
27740
|
+
description: prompt.description ?? `MCP prompt ${prompt.name} from ${name}.`,
|
|
27741
|
+
arguments: prompt.arguments ?? []
|
|
27742
|
+
})),
|
|
27743
|
+
resources: (resourcesResponse.resources ?? []).map((resource) => ({
|
|
27744
|
+
serverName: name,
|
|
27745
|
+
uri: resource.uri,
|
|
27746
|
+
name: resource.name,
|
|
27747
|
+
description: resource.description,
|
|
27748
|
+
mimeType: resource.mimeType
|
|
27749
|
+
})),
|
|
27750
|
+
resourceTemplates: (resourceTemplatesResponse.resourceTemplates ?? []).map((resourceTemplate) => ({
|
|
27751
|
+
serverName: name,
|
|
27752
|
+
uriTemplate: resourceTemplate.uriTemplate,
|
|
27753
|
+
name: resourceTemplate.name,
|
|
27754
|
+
description: resourceTemplate.description,
|
|
27755
|
+
mimeType: resourceTemplate.mimeType
|
|
27756
|
+
})),
|
|
27757
|
+
...instructions ? {
|
|
27758
|
+
instructions
|
|
27759
|
+
} : {}
|
|
27760
|
+
};
|
|
27761
|
+
}, {
|
|
27762
|
+
timeoutMs: MCP_INVENTORY_TIMEOUT_MS,
|
|
27763
|
+
timeoutLabel: `MCP inventory for ${name}`
|
|
27764
|
+
});
|
|
27765
|
+
inventory.push(record2);
|
|
27766
|
+
} catch (error2) {
|
|
27767
|
+
inventory.push({
|
|
27469
27768
|
name,
|
|
27470
27769
|
config: server,
|
|
27471
|
-
tools:
|
|
27472
|
-
|
|
27473
|
-
|
|
27474
|
-
|
|
27475
|
-
|
|
27476
|
-
|
|
27477
|
-
|
|
27478
|
-
prompts: (promptsResponse.prompts ?? []).map((prompt) => prompt.name),
|
|
27479
|
-
resources: (resourcesResponse.resources ?? []).map((resource) => resource.name ?? resource.uri),
|
|
27480
|
-
...instructions ? {
|
|
27481
|
-
instructions
|
|
27482
|
-
} : {}
|
|
27483
|
-
};
|
|
27484
|
-
});
|
|
27485
|
-
inventory.push(record2);
|
|
27770
|
+
tools: [],
|
|
27771
|
+
prompts: [],
|
|
27772
|
+
resources: [],
|
|
27773
|
+
resourceTemplates: [],
|
|
27774
|
+
warning: error2 instanceof Error ? error2.message : String(error2)
|
|
27775
|
+
});
|
|
27776
|
+
}
|
|
27486
27777
|
}
|
|
27487
27778
|
return inventory;
|
|
27488
27779
|
}
|
|
@@ -27513,6 +27804,59 @@ async function callMcpTool(cwd, serverName, toolName, input) {
|
|
|
27513
27804
|
artifacts: []
|
|
27514
27805
|
};
|
|
27515
27806
|
}
|
|
27807
|
+
function renderPromptContent(result) {
|
|
27808
|
+
return result.messages.map((message) => {
|
|
27809
|
+
if (message.content.type === "text") {
|
|
27810
|
+
return `[${message.role}] ${message.content.text}`;
|
|
27811
|
+
}
|
|
27812
|
+
if (message.content.type === "resource") {
|
|
27813
|
+
const resource = message.content.resource;
|
|
27814
|
+
return `[${message.role}] resource ${resource.uri}
|
|
27815
|
+
${"text" in resource ? resource.text : `[binary ${resource.mimeType ?? "resource"}]`}`;
|
|
27816
|
+
}
|
|
27817
|
+
if (message.content.type === "resource_link") {
|
|
27818
|
+
return `[${message.role}] resource-link ${message.content.uri}`;
|
|
27819
|
+
}
|
|
27820
|
+
return `[${message.role}] ${JSON.stringify(message.content, null, 2)}`;
|
|
27821
|
+
}).join("\n\n");
|
|
27822
|
+
}
|
|
27823
|
+
async function invokeMcpPrompt(cwd, serverName, promptName, args) {
|
|
27824
|
+
const config2 = await loadMcpConfig(cwd);
|
|
27825
|
+
const server = config2.mcpServers[serverName];
|
|
27826
|
+
if (!server || server.enabled === false) {
|
|
27827
|
+
throw new Error(`MCP server ${serverName} is not configured or is disabled.`);
|
|
27828
|
+
}
|
|
27829
|
+
const result = await withMcpClient(cwd, serverName, server, async (client) => client.getPrompt({
|
|
27830
|
+
name: promptName,
|
|
27831
|
+
arguments: args
|
|
27832
|
+
}));
|
|
27833
|
+
return {
|
|
27834
|
+
serverName,
|
|
27835
|
+
promptName,
|
|
27836
|
+
...result.description ? {
|
|
27837
|
+
description: result.description
|
|
27838
|
+
} : {},
|
|
27839
|
+
content: renderPromptContent(result)
|
|
27840
|
+
};
|
|
27841
|
+
}
|
|
27842
|
+
async function readMcpResource(cwd, serverName, uri) {
|
|
27843
|
+
const config2 = await loadMcpConfig(cwd);
|
|
27844
|
+
const server = config2.mcpServers[serverName];
|
|
27845
|
+
if (!server || server.enabled === false) {
|
|
27846
|
+
throw new Error(`MCP server ${serverName} is not configured or is disabled.`);
|
|
27847
|
+
}
|
|
27848
|
+
const result = await withMcpClient(cwd, serverName, server, async (client) => client.readResource({
|
|
27849
|
+
uri
|
|
27850
|
+
}));
|
|
27851
|
+
const content = result.contents.map((item) => "text" in item ? `resource: ${item.uri}
|
|
27852
|
+
${item.text}` : `resource: ${item.uri}
|
|
27853
|
+
[binary ${item.mimeType ?? "resource"}]`).join("\n\n");
|
|
27854
|
+
return {
|
|
27855
|
+
serverName,
|
|
27856
|
+
uri,
|
|
27857
|
+
content
|
|
27858
|
+
};
|
|
27859
|
+
}
|
|
27516
27860
|
async function registerMcpToolsForWorkspace(cwd, registry2, runtime) {
|
|
27517
27861
|
const tools = await discoverMcpTools(cwd);
|
|
27518
27862
|
for (const tool of tools) {
|
|
@@ -27536,7 +27880,7 @@ async function registerMcpToolsForWorkspace(cwd, registry2, runtime) {
|
|
|
27536
27880
|
|
|
27537
27881
|
// ../agent-runtime/dist/autonomous.js
|
|
27538
27882
|
var MAX_TOOL_OUTPUT_CHARS = 4e3;
|
|
27539
|
-
var MAX_PARSE_RETRIES =
|
|
27883
|
+
var MAX_PARSE_RETRIES = 1;
|
|
27540
27884
|
var DEFAULT_MAX_REPAIR_ATTEMPTS = 2;
|
|
27541
27885
|
var CONTEXT_FILE_READ_LIMIT = 3;
|
|
27542
27886
|
var SESSION_NOTE_LIMIT = 4;
|
|
@@ -27552,6 +27896,14 @@ var BOOTSTRAP_CONTEXT_FILES = [
|
|
|
27552
27896
|
"README.md",
|
|
27553
27897
|
"package.json"
|
|
27554
27898
|
];
|
|
27899
|
+
async function fileExists(cwd, filePath) {
|
|
27900
|
+
try {
|
|
27901
|
+
await (0, import_promises12.access)(import_node_path12.default.join(cwd, filePath));
|
|
27902
|
+
return true;
|
|
27903
|
+
} catch {
|
|
27904
|
+
return false;
|
|
27905
|
+
}
|
|
27906
|
+
}
|
|
27555
27907
|
function createAgentActionSchema(allowedTools) {
|
|
27556
27908
|
return external_exports.discriminatedUnion("type", [
|
|
27557
27909
|
external_exports.object({
|
|
@@ -28165,6 +28517,7 @@ var AutonomousTaskExecutor = class {
|
|
|
28165
28517
|
signal: options.signal,
|
|
28166
28518
|
approvalMode: this.config.approvalMode,
|
|
28167
28519
|
sandboxMode: this.config.sandboxMode,
|
|
28520
|
+
trustedDirectories: this.config.trustedDirectories,
|
|
28168
28521
|
agentRole: task.agentRole,
|
|
28169
28522
|
sessionId,
|
|
28170
28523
|
taskId: task.id,
|
|
@@ -28174,6 +28527,7 @@ var AutonomousTaskExecutor = class {
|
|
|
28174
28527
|
cwd: request.cwd,
|
|
28175
28528
|
approvalMode: this.config.approvalMode,
|
|
28176
28529
|
sandboxMode: this.config.sandboxMode,
|
|
28530
|
+
trustedDirectories: this.config.trustedDirectories,
|
|
28177
28531
|
agentRole: task.agentRole,
|
|
28178
28532
|
sessionId,
|
|
28179
28533
|
taskId: task.id,
|
|
@@ -28244,7 +28598,13 @@ var AutonomousTaskExecutor = class {
|
|
|
28244
28598
|
...BOOTSTRAP_CONTEXT_FILES,
|
|
28245
28599
|
...filesToRead
|
|
28246
28600
|
] : BOOTSTRAP_CONTEXT_FILES)).slice(0, CONTEXT_FILE_READ_LIMIT + 4);
|
|
28601
|
+
const existingContextFiles = [];
|
|
28247
28602
|
for (const filePath of fallbackFiles) {
|
|
28603
|
+
if (await fileExists(request.cwd, filePath)) {
|
|
28604
|
+
existingContextFiles.push(filePath);
|
|
28605
|
+
}
|
|
28606
|
+
}
|
|
28607
|
+
for (const filePath of existingContextFiles) {
|
|
28248
28608
|
const readResult = await runPreflightTool("file.read", {
|
|
28249
28609
|
path: filePath
|
|
28250
28610
|
}, "Load an existing repo-defining file before the first model action.");
|
|
@@ -28256,12 +28616,23 @@ var AutonomousTaskExecutor = class {
|
|
|
28256
28616
|
const contextRootCwd = options.contextRootCwd ?? request.cwd;
|
|
28257
28617
|
const savedSession = await loadLatestSession(contextRootCwd).catch(() => null);
|
|
28258
28618
|
const savedSessionSummary = summarizeSavedSessionContext(sessionId, savedSession);
|
|
28619
|
+
const recursiveMemory = await loadMarkdownMemoryContext(request.cwd, {
|
|
28620
|
+
maxFiles: 10,
|
|
28621
|
+
maxCharsPerFile: 4e3
|
|
28622
|
+
});
|
|
28259
28623
|
const userMemory = await readMarkdownIfExists(resolveUserMemoryPath());
|
|
28260
28624
|
const projectMemory = await readMarkdownIfExists(resolveProjectMemoryPath(request.cwd));
|
|
28261
28625
|
const customAgentMemory = customOverlay ? await readMarkdownIfExists(import_node_path12.default.join(resolveAgentMemoryDir(request.cwd), `${customOverlay.definition.id}.md`)) : null;
|
|
28262
28626
|
if (savedSessionSummary.length > 0) {
|
|
28263
28627
|
contextMessages.unshift(savedSessionSummary.join("\n"));
|
|
28264
28628
|
}
|
|
28629
|
+
if (recursiveMemory.length > 0) {
|
|
28630
|
+
contextMessages.unshift([
|
|
28631
|
+
"Recursive markdown memory context:",
|
|
28632
|
+
...recursiveMemory.map((record2) => `File: ${record2.filePath}
|
|
28633
|
+
${truncateForModel(record2.content)}`)
|
|
28634
|
+
].join("\n\n"));
|
|
28635
|
+
}
|
|
28265
28636
|
if (userMemory) {
|
|
28266
28637
|
contextMessages.unshift(`Global user memory:
|
|
28267
28638
|
${truncateForModel(userMemory)}`);
|
|
@@ -28306,6 +28677,7 @@ ${truncateForModel(customAgentMemory)}`);
|
|
|
28306
28677
|
signal: options.signal,
|
|
28307
28678
|
approvalMode: this.config.approvalMode,
|
|
28308
28679
|
sandboxMode: this.config.sandboxMode,
|
|
28680
|
+
trustedDirectories: this.config.trustedDirectories,
|
|
28309
28681
|
agentRole: task.agentRole,
|
|
28310
28682
|
operatorApproved,
|
|
28311
28683
|
sessionId,
|
|
@@ -28318,6 +28690,7 @@ ${truncateForModel(customAgentMemory)}`);
|
|
|
28318
28690
|
cwd: request.cwd,
|
|
28319
28691
|
approvalMode: this.config.approvalMode,
|
|
28320
28692
|
sandboxMode: this.config.sandboxMode,
|
|
28693
|
+
trustedDirectories: this.config.trustedDirectories,
|
|
28321
28694
|
agentRole: task.agentRole,
|
|
28322
28695
|
operatorApproved,
|
|
28323
28696
|
sessionId,
|
|
@@ -28516,14 +28889,16 @@ ${truncateForModel(customAgentMemory)}`);
|
|
|
28516
28889
|
let responseText = "";
|
|
28517
28890
|
let parsedAction = null;
|
|
28518
28891
|
for (let attempt = 0; attempt <= MAX_PARSE_RETRIES; attempt += 1) {
|
|
28519
|
-
|
|
28520
|
-
|
|
28521
|
-
|
|
28522
|
-
|
|
28523
|
-
|
|
28524
|
-
|
|
28525
|
-
|
|
28526
|
-
|
|
28892
|
+
if (attempt === 0) {
|
|
28893
|
+
await emitProgress({
|
|
28894
|
+
type: "task-note",
|
|
28895
|
+
sessionId,
|
|
28896
|
+
taskId: task.id,
|
|
28897
|
+
agentRole: task.agentRole,
|
|
28898
|
+
step,
|
|
28899
|
+
message: "Thinking through the next safe action."
|
|
28900
|
+
});
|
|
28901
|
+
}
|
|
28527
28902
|
let response;
|
|
28528
28903
|
try {
|
|
28529
28904
|
response = await brain.client.generateText({
|
|
@@ -28591,20 +28966,20 @@ ${truncateForModel(customAgentMemory)}`);
|
|
|
28591
28966
|
response: response.text,
|
|
28592
28967
|
runtimeNote: `${parseSummary} ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
28593
28968
|
});
|
|
28969
|
+
const inferredFallbackAction = inferFallbackActionFromResponse(response.text, task, request, allowedTools);
|
|
28970
|
+
if (inferredFallbackAction) {
|
|
28971
|
+
parsedAction = inferredFallbackAction;
|
|
28972
|
+
await emitProgress({
|
|
28973
|
+
type: "task-note",
|
|
28974
|
+
sessionId,
|
|
28975
|
+
taskId: task.id,
|
|
28976
|
+
agentRole: task.agentRole,
|
|
28977
|
+
step,
|
|
28978
|
+
message: `Interpreted the model draft as ${inferredFallbackAction.tool}.`
|
|
28979
|
+
});
|
|
28980
|
+
break;
|
|
28981
|
+
}
|
|
28594
28982
|
if (attempt === MAX_PARSE_RETRIES) {
|
|
28595
|
-
const inferredFallbackAction = inferFallbackActionFromResponse(response.text, task, request, allowedTools);
|
|
28596
|
-
if (inferredFallbackAction) {
|
|
28597
|
-
parsedAction = inferredFallbackAction;
|
|
28598
|
-
await emitProgress({
|
|
28599
|
-
type: "task-note",
|
|
28600
|
-
sessionId,
|
|
28601
|
-
taskId: task.id,
|
|
28602
|
-
agentRole: task.agentRole,
|
|
28603
|
-
step,
|
|
28604
|
-
message: `Model stayed out of structured mode; inferred ${inferredFallbackAction.tool} from the response.`
|
|
28605
|
-
});
|
|
28606
|
-
break;
|
|
28607
|
-
}
|
|
28608
28983
|
const transcriptPath2 = await writeTranscriptArtifact(request.cwd, sessionId, task.id, transcript);
|
|
28609
28984
|
artifacts.add(transcriptPath2);
|
|
28610
28985
|
await emitProgress({
|
|
@@ -28629,7 +29004,7 @@ ${truncateForModel(customAgentMemory)}`);
|
|
|
28629
29004
|
taskId: task.id,
|
|
28630
29005
|
agentRole: task.agentRole,
|
|
28631
29006
|
step,
|
|
28632
|
-
message:
|
|
29007
|
+
message: "Normalizing the model draft into one safe machine-readable action."
|
|
28633
29008
|
});
|
|
28634
29009
|
messages.push({
|
|
28635
29010
|
role: "assistant",
|
|
@@ -28795,6 +29170,47 @@ function normalizeGoal(goal) {
|
|
|
28795
29170
|
}
|
|
28796
29171
|
function looksLikeStaticSiteGoal(goal) {
|
|
28797
29172
|
const lower = goal.toLowerCase();
|
|
29173
|
+
const backendSignals = [
|
|
29174
|
+
"api",
|
|
29175
|
+
"database",
|
|
29176
|
+
"backend",
|
|
29177
|
+
"server",
|
|
29178
|
+
"migration",
|
|
29179
|
+
"schema",
|
|
29180
|
+
"prisma",
|
|
29181
|
+
"postgres",
|
|
29182
|
+
"sqlite",
|
|
29183
|
+
"auth",
|
|
29184
|
+
"billing",
|
|
29185
|
+
"webhook"
|
|
29186
|
+
];
|
|
29187
|
+
const pageSignals = [
|
|
29188
|
+
"page",
|
|
29189
|
+
"landing",
|
|
29190
|
+
"lnding",
|
|
29191
|
+
"homepage",
|
|
29192
|
+
"home page",
|
|
29193
|
+
"site",
|
|
29194
|
+
"website",
|
|
29195
|
+
"ui",
|
|
29196
|
+
"hero",
|
|
29197
|
+
"layout",
|
|
29198
|
+
"screen"
|
|
29199
|
+
];
|
|
29200
|
+
const polishSignals = [
|
|
29201
|
+
"animate",
|
|
29202
|
+
"animated",
|
|
29203
|
+
"animation",
|
|
29204
|
+
"motion",
|
|
29205
|
+
"rich",
|
|
29206
|
+
"richer",
|
|
29207
|
+
"polish",
|
|
29208
|
+
"styled",
|
|
29209
|
+
"styling",
|
|
29210
|
+
"visual",
|
|
29211
|
+
"redesign",
|
|
29212
|
+
"revamp"
|
|
29213
|
+
];
|
|
28798
29214
|
if (lower.includes("landing page") || lower.includes("landing") || lower.includes("lnding") || lower.includes("homepage") || lower.includes("home page") || lower.includes("marketing page") || lower.includes("storefront") || lower.includes("restaurant website") || lower.includes("restaurant site") || lower.includes("static site")) {
|
|
28799
29215
|
return true;
|
|
28800
29216
|
}
|
|
@@ -28804,6 +29220,12 @@ function looksLikeStaticSiteGoal(goal) {
|
|
|
28804
29220
|
if (lower.includes("restaurant") && (lower.includes("page") || lower.includes("site") || lower.includes("website") || lower.includes("landing") || lower.includes("lnding"))) {
|
|
28805
29221
|
return true;
|
|
28806
29222
|
}
|
|
29223
|
+
if (pageSignals.some((signal) => lower.includes(signal)) && polishSignals.some((signal) => lower.includes(signal)) && !backendSignals.some((signal) => lower.includes(signal))) {
|
|
29224
|
+
return true;
|
|
29225
|
+
}
|
|
29226
|
+
if (lower.includes("blog") && (lower.includes("make") || lower.includes("improve") || lower.includes("enhance") || lower.includes("redesign")) && !backendSignals.some((signal) => lower.includes(signal))) {
|
|
29227
|
+
return true;
|
|
29228
|
+
}
|
|
28807
29229
|
return false;
|
|
28808
29230
|
}
|
|
28809
29231
|
function inferProjectShape(goal) {
|
|
@@ -29577,7 +29999,7 @@ function terminalTaskIds(tasks) {
|
|
|
29577
29999
|
const terminalIds = tasks.filter((task) => !referencedIds.has(task.id)).map((task) => task.id);
|
|
29578
30000
|
return terminalIds.length > 0 ? terminalIds : tasks.map((task) => task.id);
|
|
29579
30001
|
}
|
|
29580
|
-
function
|
|
30002
|
+
function integratePlanTaskExpansion(plan, taskId, expandedTasks, note) {
|
|
29581
30003
|
const terminalIds = terminalTaskIds(expandedTasks);
|
|
29582
30004
|
const milestones = plan.milestones.map((milestone) => ({
|
|
29583
30005
|
...milestone,
|
|
@@ -29687,7 +30109,7 @@ async function generateExpandedTasks(request, plan, task, invocation, repoSummar
|
|
|
29687
30109
|
const normalizedTasks = normalizeExpandedTasks(plan, task, payload, "model");
|
|
29688
30110
|
const note = `Planner expanded ${task.id} into ${normalizedTasks.length} subtasks via ${invocation.modelLabel ?? "planner model"}: ${normalizedTasks.map((candidate) => candidate.id).join(", ")}.`;
|
|
29689
30111
|
return {
|
|
29690
|
-
plan:
|
|
30112
|
+
plan: integratePlanTaskExpansion(plan, task.id, normalizedTasks, note),
|
|
29691
30113
|
source: "model",
|
|
29692
30114
|
expandedTaskId: task.id,
|
|
29693
30115
|
createdTaskIds: normalizedTasks.map((candidate) => candidate.id),
|
|
@@ -29716,7 +30138,7 @@ async function generateExpandedTasks(request, plan, task, invocation, repoSummar
|
|
|
29716
30138
|
}
|
|
29717
30139
|
const note = `Planner fell back to deterministic subtask expansion for ${task.id}: ${fallbackTasks.map((candidate) => candidate.id).join(", ")}.`;
|
|
29718
30140
|
return {
|
|
29719
|
-
plan:
|
|
30141
|
+
plan: integratePlanTaskExpansion(plan, task.id, fallbackTasks, note),
|
|
29720
30142
|
source: "fallback",
|
|
29721
30143
|
expandedTaskId: task.id,
|
|
29722
30144
|
createdTaskIds: fallbackTasks.map((candidate) => candidate.id),
|
|
@@ -29761,7 +30183,7 @@ function expandPlanTaskFallback(plan, taskId) {
|
|
|
29761
30183
|
}
|
|
29762
30184
|
const note = `Planner deterministically expanded ${task.id} into ${fallbackTasks.length} subtasks: ${fallbackTasks.map((candidate) => candidate.id).join(", ")}.`;
|
|
29763
30185
|
return {
|
|
29764
|
-
plan:
|
|
30186
|
+
plan: integratePlanTaskExpansion(plan, task.id, fallbackTasks, note),
|
|
29765
30187
|
source: "fallback",
|
|
29766
30188
|
expandedTaskId: task.id,
|
|
29767
30189
|
createdTaskIds: fallbackTasks.map((candidate) => candidate.id),
|
|
@@ -30695,6 +31117,19 @@ function maybeAppendNote(notes, note) {
|
|
|
30695
31117
|
note
|
|
30696
31118
|
];
|
|
30697
31119
|
}
|
|
31120
|
+
function slugify2(value) {
|
|
31121
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-");
|
|
31122
|
+
}
|
|
31123
|
+
function createUniqueTaskId2(baseId, existingIds) {
|
|
31124
|
+
let candidate = baseId;
|
|
31125
|
+
let index = 2;
|
|
31126
|
+
while (existingIds.has(candidate)) {
|
|
31127
|
+
candidate = `${baseId}-${index}`;
|
|
31128
|
+
index += 1;
|
|
31129
|
+
}
|
|
31130
|
+
existingIds.add(candidate);
|
|
31131
|
+
return candidate;
|
|
31132
|
+
}
|
|
30698
31133
|
function mergeUnique(items) {
|
|
30699
31134
|
return Array.from(new Set(items.filter((item) => item.trim().length > 0)));
|
|
30700
31135
|
}
|
|
@@ -31778,6 +32213,53 @@ var ExecutionOrchestrator = class {
|
|
|
31778
32213
|
plan
|
|
31779
32214
|
};
|
|
31780
32215
|
}
|
|
32216
|
+
const matchedTeam = await selectAgentTeam(request.cwd, candidate, request);
|
|
32217
|
+
if (matchedTeam && matchedTeam.members.length > 1) {
|
|
32218
|
+
const existingIds = new Set(flattenPlanTasks(plan).filter((task) => task.id !== candidate.id).map((task) => task.id));
|
|
32219
|
+
const teamMemberIds = matchedTeam.members.map((member) => member.id);
|
|
32220
|
+
const generatedTaskIds = matchedTeam.members.map((member, index) => createUniqueTaskId2(`${candidate.id}-${slugify2(member.id) || `member-${index + 1}`}`, existingIds));
|
|
32221
|
+
const teamTasks = matchedTeam.members.map((member, index) => {
|
|
32222
|
+
const taskId = generatedTaskIds[index];
|
|
32223
|
+
const dependsOn = matchedTeam.team.strategy === "parallel" ? [
|
|
32224
|
+
...candidate.dependsOn
|
|
32225
|
+
] : index === 0 ? [
|
|
32226
|
+
...candidate.dependsOn
|
|
32227
|
+
] : [
|
|
32228
|
+
generatedTaskIds[index - 1] ?? candidate.dependsOn[0] ?? ""
|
|
32229
|
+
].filter((value) => value.length > 0);
|
|
32230
|
+
return {
|
|
32231
|
+
...candidate,
|
|
32232
|
+
id: taskId,
|
|
32233
|
+
title: `${candidate.title} (${member.label})`,
|
|
32234
|
+
description: [
|
|
32235
|
+
candidate.description,
|
|
32236
|
+
`Assigned team member: ${member.label} (${member.id}).`,
|
|
32237
|
+
member.purpose ? `Purpose: ${member.purpose}` : "",
|
|
32238
|
+
matchedTeam.team.description ? `Team context: ${matchedTeam.team.description}` : ""
|
|
32239
|
+
].filter((part) => part.length > 0).join("\n\n"),
|
|
32240
|
+
agentRole: member.baseRole,
|
|
32241
|
+
dependsOn,
|
|
32242
|
+
acceptanceCriteria: index === matchedTeam.members.length - 1 ? candidate.acceptanceCriteria : [
|
|
32243
|
+
`Advance ${candidate.title.toLowerCase()} from the ${member.label} perspective.`,
|
|
32244
|
+
"Leave clear handoff notes and concrete changed-file intent for the next team member."
|
|
32245
|
+
],
|
|
32246
|
+
outputs: index === matchedTeam.members.length - 1 ? candidate.outputs : [
|
|
32247
|
+
`Team handoff from ${member.id}`
|
|
32248
|
+
],
|
|
32249
|
+
originTaskId: candidate.id,
|
|
32250
|
+
swarmDepth: (candidate.swarmDepth ?? 0) + 1,
|
|
32251
|
+
customAgentId: member.id,
|
|
32252
|
+
teamId: matchedTeam.team.id,
|
|
32253
|
+
teamMemberIds
|
|
32254
|
+
};
|
|
32255
|
+
});
|
|
32256
|
+
const note = `Agent team ${matchedTeam.team.label} expanded ${candidate.id} into ${teamTasks.length} ${matchedTeam.team.strategy} subtasks: ${teamTasks.map((task) => task.id).join(", ")}.`;
|
|
32257
|
+
return {
|
|
32258
|
+
plan: integratePlanTaskExpansion(plan, candidate.id, teamTasks, note),
|
|
32259
|
+
note,
|
|
32260
|
+
expandedTaskId: candidate.id
|
|
32261
|
+
};
|
|
32262
|
+
}
|
|
31781
32263
|
const repoContext = latestRepoAnalysisContext(events);
|
|
31782
32264
|
const config2 = await loadConfig(request.cwd);
|
|
31783
32265
|
if (!config2) {
|
|
@@ -32486,21 +32968,24 @@ async function listMemoryPaths(cwd) {
|
|
|
32486
32968
|
function createConfigCommand() {
|
|
32487
32969
|
return new Command("config").description("Show the current config, memory, and MCP file locations.").action(async () => {
|
|
32488
32970
|
const cwd = import_node_process5.default.cwd();
|
|
32489
|
-
const
|
|
32971
|
+
const layers = await loadConfigLayers(cwd);
|
|
32490
32972
|
const memory = await listMemoryPaths(cwd);
|
|
32491
|
-
console.log(`config: ${
|
|
32973
|
+
console.log(`config.user: ${resolveGlobalConfigPath()}`);
|
|
32974
|
+
console.log(`config.project: ${resolveConfigPath(cwd)}`);
|
|
32492
32975
|
console.log(`mcp: ${resolveMcpConfigPath(cwd)}`);
|
|
32493
32976
|
console.log(`memory.project: ${memory.projectMemoryPath}`);
|
|
32494
32977
|
console.log(`memory.user: ${memory.userMemoryPath}`);
|
|
32495
32978
|
console.log(`memory.agents: ${memory.agentMemoryDir}`);
|
|
32496
|
-
if (!
|
|
32979
|
+
if (!layers.resolved) {
|
|
32497
32980
|
console.log("No config found.");
|
|
32498
32981
|
return;
|
|
32499
32982
|
}
|
|
32500
|
-
console.log(`
|
|
32501
|
-
console.log(`
|
|
32502
|
-
console.log(`
|
|
32503
|
-
console.log(`
|
|
32983
|
+
console.log(`layers.user: ${layers.user ? "present" : "missing"}`);
|
|
32984
|
+
console.log(`layers.project: ${layers.project ? "present" : "missing"}`);
|
|
32985
|
+
console.log(`providers: ${layers.resolved.providers.length}`);
|
|
32986
|
+
console.log(`approval: ${layers.resolved.approvalMode}`);
|
|
32987
|
+
console.log(`sandbox: ${layers.resolved.sandboxMode}`);
|
|
32988
|
+
console.log(`trusted directories: ${layers.resolved.trustedDirectories.length}`);
|
|
32504
32989
|
});
|
|
32505
32990
|
}
|
|
32506
32991
|
|
|
@@ -32734,14 +33219,90 @@ async function renderMcpInventory(cwd, name) {
|
|
|
32734
33219
|
}
|
|
32735
33220
|
return filtered.flatMap((server) => [
|
|
32736
33221
|
`${server.name}`,
|
|
33222
|
+
...server.warning ? [
|
|
33223
|
+
` warning: ${server.warning}`
|
|
33224
|
+
] : [],
|
|
32737
33225
|
` tools: ${server.tools.length}`,
|
|
32738
33226
|
...server.tools.slice(0, 20).map((tool) => ` - ${tool.toolName} (${tool.permission})`),
|
|
32739
33227
|
` prompts: ${server.prompts.length}`,
|
|
32740
|
-
...server.prompts.slice(0, 10).
|
|
33228
|
+
...server.prompts.slice(0, 10).flatMap((prompt) => [
|
|
33229
|
+
` - ${prompt.name}${prompt.arguments.length > 0 ? ` (${prompt.arguments.map((argument) => `${argument.name}${argument.required ? "*" : ""}`).join(", ")})` : ""}`,
|
|
33230
|
+
` command: /mcp__${server.name}__${prompt.name}`
|
|
33231
|
+
]),
|
|
32741
33232
|
` resources: ${server.resources.length}`,
|
|
32742
|
-
...server.resources.slice(0, 10).
|
|
33233
|
+
...server.resources.slice(0, 10).flatMap((resource) => [
|
|
33234
|
+
` - ${resource.name} -> ${resource.uri}`,
|
|
33235
|
+
` attach: @${server.name}:${resource.uri}`
|
|
33236
|
+
]),
|
|
33237
|
+
` resource templates: ${server.resourceTemplates.length}`,
|
|
33238
|
+
...server.resourceTemplates.slice(0, 10).map((resourceTemplate) => ` - ${resourceTemplate.name} -> ${resourceTemplate.uriTemplate}`)
|
|
33239
|
+
]);
|
|
33240
|
+
}
|
|
33241
|
+
async function renderMcpPromptList(cwd, name) {
|
|
33242
|
+
const inventory = await loadMcpServerInventory(cwd);
|
|
33243
|
+
const filtered = name ? inventory.filter((server) => server.name === name) : inventory;
|
|
33244
|
+
if (filtered.length === 0) {
|
|
33245
|
+
return [
|
|
33246
|
+
name ? `No MCP prompt inventory found for ${name}.` : "No MCP prompt inventory available."
|
|
33247
|
+
];
|
|
33248
|
+
}
|
|
33249
|
+
return filtered.flatMap((server) => [
|
|
33250
|
+
`${server.name}`,
|
|
33251
|
+
...server.warning ? [
|
|
33252
|
+
` warning: ${server.warning}`
|
|
33253
|
+
] : [],
|
|
33254
|
+
...server.prompts.length > 0 ? server.prompts.flatMap((prompt) => [
|
|
33255
|
+
` - ${prompt.name}${prompt.arguments.length > 0 ? ` (${prompt.arguments.map((argument) => `${argument.name}${argument.required ? "*" : ""}`).join(", ")})` : ""}`,
|
|
33256
|
+
` command: /mcp__${server.name}__${prompt.name}`
|
|
33257
|
+
]) : [
|
|
33258
|
+
" - no prompts"
|
|
33259
|
+
]
|
|
32743
33260
|
]);
|
|
32744
33261
|
}
|
|
33262
|
+
async function renderMcpResourceList(cwd, name) {
|
|
33263
|
+
const inventory = await loadMcpServerInventory(cwd);
|
|
33264
|
+
const filtered = name ? inventory.filter((server) => server.name === name) : inventory;
|
|
33265
|
+
if (filtered.length === 0) {
|
|
33266
|
+
return [
|
|
33267
|
+
name ? `No MCP resource inventory found for ${name}.` : "No MCP resource inventory available."
|
|
33268
|
+
];
|
|
33269
|
+
}
|
|
33270
|
+
return filtered.flatMap((server) => [
|
|
33271
|
+
`${server.name}`,
|
|
33272
|
+
...server.warning ? [
|
|
33273
|
+
` warning: ${server.warning}`
|
|
33274
|
+
] : [],
|
|
33275
|
+
...server.resources.length > 0 ? server.resources.flatMap((resource) => [
|
|
33276
|
+
` - ${resource.name} -> ${resource.uri}`,
|
|
33277
|
+
` attach: @${server.name}:${resource.uri}`
|
|
33278
|
+
]) : [
|
|
33279
|
+
" - no resources"
|
|
33280
|
+
],
|
|
33281
|
+
...server.resourceTemplates.length > 0 ? [
|
|
33282
|
+
" templates:",
|
|
33283
|
+
...server.resourceTemplates.map((resourceTemplate) => ` - ${resourceTemplate.name} -> ${resourceTemplate.uriTemplate}`)
|
|
33284
|
+
] : []
|
|
33285
|
+
]);
|
|
33286
|
+
}
|
|
33287
|
+
async function renderMcpPromptInvocation(cwd, serverName, promptName, args) {
|
|
33288
|
+
const result = await invokeMcpPrompt(cwd, serverName, promptName, args);
|
|
33289
|
+
return [
|
|
33290
|
+
`${result.serverName}/${result.promptName}`,
|
|
33291
|
+
...result.description ? [
|
|
33292
|
+
`description: ${result.description}`
|
|
33293
|
+
] : [],
|
|
33294
|
+
"",
|
|
33295
|
+
result.content
|
|
33296
|
+
];
|
|
33297
|
+
}
|
|
33298
|
+
async function renderMcpResourceRead(cwd, serverName, uri) {
|
|
33299
|
+
const result = await readMcpResource(cwd, serverName, uri);
|
|
33300
|
+
return [
|
|
33301
|
+
`${result.serverName} ${result.uri}`,
|
|
33302
|
+
"",
|
|
33303
|
+
result.content
|
|
33304
|
+
];
|
|
33305
|
+
}
|
|
32745
33306
|
|
|
32746
33307
|
// src/commands/mcp.ts
|
|
32747
33308
|
function collectValues(value, previous = []) {
|
|
@@ -32791,6 +33352,34 @@ function createMcpCommand() {
|
|
|
32791
33352
|
console.log(line);
|
|
32792
33353
|
}
|
|
32793
33354
|
});
|
|
33355
|
+
command.command("discover").description("Show MCP tools, prompts-as-commands, and resource attachment syntax.").argument("[name]", "Optional server name").action(async (name) => {
|
|
33356
|
+
for (const line of await renderMcpInventory(import_node_process8.default.cwd(), name)) {
|
|
33357
|
+
console.log(line);
|
|
33358
|
+
}
|
|
33359
|
+
});
|
|
33360
|
+
command.command("prompts").description("List MCP prompts.").argument("[name]", "Optional server name").action(async (name) => {
|
|
33361
|
+
for (const line of await renderMcpPromptList(import_node_process8.default.cwd(), name)) {
|
|
33362
|
+
console.log(line);
|
|
33363
|
+
}
|
|
33364
|
+
});
|
|
33365
|
+
command.command("resources").description("List MCP resources and resource templates.").argument("[name]", "Optional server name").action(async (name) => {
|
|
33366
|
+
for (const line of await renderMcpResourceList(import_node_process8.default.cwd(), name)) {
|
|
33367
|
+
console.log(line);
|
|
33368
|
+
}
|
|
33369
|
+
});
|
|
33370
|
+
command.command("prompt").description("Invoke an MCP prompt and print the rendered content.").argument("<server>", "Server name").argument("<prompt>", "Prompt name").argument("[args...]", "Prompt args in key=value form").action(async (server, prompt, rawArgs = []) => {
|
|
33371
|
+
const args = Object.fromEntries(
|
|
33372
|
+
rawArgs.map((entry) => entry.split("=", 2)).filter((parts) => parts.length === 2 && parts[0].length > 0)
|
|
33373
|
+
);
|
|
33374
|
+
for (const line of await renderMcpPromptInvocation(import_node_process8.default.cwd(), server, prompt, args)) {
|
|
33375
|
+
console.log(line);
|
|
33376
|
+
}
|
|
33377
|
+
});
|
|
33378
|
+
command.command("read").description("Read one MCP resource by URI.").argument("<server>", "Server name").argument("<uri>", "Resource URI").action(async (server, uri) => {
|
|
33379
|
+
for (const line of await renderMcpResourceRead(import_node_process8.default.cwd(), server, uri)) {
|
|
33380
|
+
console.log(line);
|
|
33381
|
+
}
|
|
33382
|
+
});
|
|
32794
33383
|
return command;
|
|
32795
33384
|
}
|
|
32796
33385
|
|
|
@@ -33252,7 +33841,7 @@ function createModelsCommand() {
|
|
|
33252
33841
|
const exists = models.some((item) => item.id === model) || provider.models.includes(model);
|
|
33253
33842
|
if (!exists) {
|
|
33254
33843
|
throw new Error(
|
|
33255
|
-
`Model "${model}" was not found for provider "${provider.id}". Run \`kimbho
|
|
33844
|
+
`Model "${model}" was not found for provider "${provider.id}". Run \`kimbho model find ${model}\` or re-run with --force.`
|
|
33256
33845
|
);
|
|
33257
33846
|
}
|
|
33258
33847
|
} catch (error2) {
|
|
@@ -33595,27 +34184,49 @@ function createPlanCommand() {
|
|
|
33595
34184
|
|
|
33596
34185
|
// src/commands/permissions.ts
|
|
33597
34186
|
var import_node_process13 = __toESM(require("node:process"), 1);
|
|
34187
|
+
var import_node_path19 = __toESM(require("node:path"), 1);
|
|
34188
|
+
function getScope(options) {
|
|
34189
|
+
return options.scope === "user" ? "user" : "project";
|
|
34190
|
+
}
|
|
34191
|
+
async function loadScopedConfig(scope, cwd) {
|
|
34192
|
+
const direct = scope === "user" ? await loadUserConfig() : await loadProjectConfig(cwd);
|
|
34193
|
+
const resolved = await loadConfig(cwd);
|
|
34194
|
+
return {
|
|
34195
|
+
direct,
|
|
34196
|
+
resolved
|
|
34197
|
+
};
|
|
34198
|
+
}
|
|
34199
|
+
async function saveScopedConfig(scope, cwd, config2) {
|
|
34200
|
+
return scope === "user" ? saveUserConfig(config2) : saveConfig(config2, cwd);
|
|
34201
|
+
}
|
|
33598
34202
|
function createPermissionsCommand() {
|
|
33599
34203
|
const command = new Command("permissions").description("Manage approval mode, sandbox mode, and trusted directories.");
|
|
33600
|
-
command.command("status").description("Show permission settings.").action(async () => {
|
|
33601
|
-
const
|
|
33602
|
-
|
|
34204
|
+
command.command("status").description("Show permission settings.").option("--scope <scope>", "project or user", "project").action(async (options) => {
|
|
34205
|
+
const scope = getScope(options);
|
|
34206
|
+
const { direct, resolved } = await loadScopedConfig(scope, import_node_process13.default.cwd());
|
|
34207
|
+
console.log(`scope: ${scope}`);
|
|
34208
|
+
console.log(`direct config: ${direct ? "present" : "missing"}`);
|
|
34209
|
+
if (!resolved) {
|
|
33603
34210
|
throw new Error("No config found. Run `kimbho init` first.");
|
|
33604
34211
|
}
|
|
33605
|
-
|
|
33606
|
-
console.log(`
|
|
33607
|
-
console.log(`
|
|
33608
|
-
|
|
34212
|
+
const display = direct ?? resolved;
|
|
34213
|
+
console.log(`approval: ${display.approvalMode}`);
|
|
34214
|
+
console.log(`sandbox: ${display.sandboxMode}`);
|
|
34215
|
+
console.log(`trusted directories: ${display.trustedDirectories.length}`);
|
|
34216
|
+
for (const directory of display.trustedDirectories) {
|
|
33609
34217
|
console.log(` - ${directory}`);
|
|
33610
34218
|
}
|
|
33611
34219
|
});
|
|
33612
|
-
command.command("set").description("Set approval mode or sandbox mode.").option("--approval <mode>", "manual or auto").option("--sandbox <mode>", "read-only, workspace-write, or full").action(async (options) => {
|
|
33613
|
-
const
|
|
33614
|
-
|
|
34220
|
+
command.command("set").description("Set approval mode or sandbox mode.").option("--scope <scope>", "project or user", "project").option("--approval <mode>", "manual or auto").option("--sandbox <mode>", "read-only, workspace-write, or full").action(async (options) => {
|
|
34221
|
+
const scope = getScope(options);
|
|
34222
|
+
const cwd = import_node_process13.default.cwd();
|
|
34223
|
+
const { direct, resolved } = await loadScopedConfig(scope, cwd);
|
|
34224
|
+
if (!resolved && !direct) {
|
|
33615
34225
|
throw new Error("No config found. Run `kimbho init` first.");
|
|
33616
34226
|
}
|
|
34227
|
+
const base = direct ?? resolved ?? createDefaultConfig();
|
|
33617
34228
|
const next = {
|
|
33618
|
-
...
|
|
34229
|
+
...base,
|
|
33619
34230
|
...options.approval ? {
|
|
33620
34231
|
approvalMode: options.approval
|
|
33621
34232
|
} : {},
|
|
@@ -33623,32 +34234,40 @@ function createPermissionsCommand() {
|
|
|
33623
34234
|
sandboxMode: options.sandbox
|
|
33624
34235
|
} : {}
|
|
33625
34236
|
};
|
|
33626
|
-
const outputPath = await
|
|
34237
|
+
const outputPath = await saveScopedConfig(scope, cwd, next);
|
|
33627
34238
|
console.log(`Updated ${outputPath}`);
|
|
33628
34239
|
});
|
|
33629
|
-
command.command("trust").description("Add a trusted directory.").argument("<path>", "Directory to trust").action(async (trustedPath) => {
|
|
33630
|
-
const
|
|
33631
|
-
|
|
34240
|
+
command.command("trust").description("Add a trusted directory.").argument("<path>", "Directory to trust").option("--scope <scope>", "project or user", "project").action(async (trustedPath, options) => {
|
|
34241
|
+
const scope = getScope(options);
|
|
34242
|
+
const cwd = import_node_process13.default.cwd();
|
|
34243
|
+
const { direct, resolved } = await loadScopedConfig(scope, cwd);
|
|
34244
|
+
if (!resolved && !direct) {
|
|
33632
34245
|
throw new Error("No config found. Run `kimbho init` first.");
|
|
33633
34246
|
}
|
|
33634
|
-
const
|
|
33635
|
-
|
|
34247
|
+
const base = direct ?? resolved ?? createDefaultConfig();
|
|
34248
|
+
const normalizedPath = import_node_path19.default.resolve(cwd, trustedPath);
|
|
34249
|
+
const outputPath = await saveScopedConfig(scope, cwd, {
|
|
34250
|
+
...base,
|
|
33636
34251
|
trustedDirectories: Array.from(/* @__PURE__ */ new Set([
|
|
33637
|
-
...
|
|
33638
|
-
|
|
34252
|
+
...base.trustedDirectories,
|
|
34253
|
+
normalizedPath
|
|
33639
34254
|
]))
|
|
33640
|
-
}
|
|
34255
|
+
});
|
|
33641
34256
|
console.log(`Updated ${outputPath}`);
|
|
33642
34257
|
});
|
|
33643
|
-
command.command("untrust").description("Remove a trusted directory.").argument("<path>", "Directory to remove").action(async (trustedPath) => {
|
|
33644
|
-
const
|
|
33645
|
-
|
|
34258
|
+
command.command("untrust").description("Remove a trusted directory.").argument("<path>", "Directory to remove").option("--scope <scope>", "project or user", "project").action(async (trustedPath, options) => {
|
|
34259
|
+
const scope = getScope(options);
|
|
34260
|
+
const cwd = import_node_process13.default.cwd();
|
|
34261
|
+
const { direct, resolved } = await loadScopedConfig(scope, cwd);
|
|
34262
|
+
if (!resolved && !direct) {
|
|
33646
34263
|
throw new Error("No config found. Run `kimbho init` first.");
|
|
33647
34264
|
}
|
|
33648
|
-
const
|
|
33649
|
-
|
|
33650
|
-
|
|
33651
|
-
|
|
34265
|
+
const base = direct ?? resolved ?? createDefaultConfig();
|
|
34266
|
+
const normalizedPath = import_node_path19.default.resolve(cwd, trustedPath);
|
|
34267
|
+
const outputPath = await saveScopedConfig(scope, cwd, {
|
|
34268
|
+
...base,
|
|
34269
|
+
trustedDirectories: base.trustedDirectories.filter((directory) => directory !== trustedPath && directory !== normalizedPath)
|
|
34270
|
+
});
|
|
33652
34271
|
console.log(`Updated ${outputPath}`);
|
|
33653
34272
|
});
|
|
33654
34273
|
return command;
|
|
@@ -33762,7 +34381,7 @@ function createProvidersCommand() {
|
|
|
33762
34381
|
|
|
33763
34382
|
// src/commands/review.ts
|
|
33764
34383
|
var import_promises17 = require("node:fs/promises");
|
|
33765
|
-
var
|
|
34384
|
+
var import_node_path20 = __toESM(require("node:path"), 1);
|
|
33766
34385
|
var import_node_process15 = __toESM(require("node:process"), 1);
|
|
33767
34386
|
function summarizeChangedFiles2(diff) {
|
|
33768
34387
|
const files = /* @__PURE__ */ new Set();
|
|
@@ -33846,7 +34465,7 @@ ${diff.stdout}`
|
|
|
33846
34465
|
}
|
|
33847
34466
|
}
|
|
33848
34467
|
await ensureKimbhoDir(cwd);
|
|
33849
|
-
const artifactPath =
|
|
34468
|
+
const artifactPath = import_node_path20.default.join(resolveKimbhoDir(cwd), "logs", `review-${Date.now()}.md`);
|
|
33850
34469
|
await (0, import_promises17.writeFile)(artifactPath, [
|
|
33851
34470
|
`# Review`,
|
|
33852
34471
|
``,
|
|
@@ -34080,6 +34699,12 @@ function normalizeCliTokens(tokens) {
|
|
|
34080
34699
|
}
|
|
34081
34700
|
function createProgram(onOpenShell) {
|
|
34082
34701
|
const program2 = new Command();
|
|
34702
|
+
const legacyProviders = createProvidersCommand();
|
|
34703
|
+
const legacyModels = createModelsCommand();
|
|
34704
|
+
const legacyBrains = createBrainsCommand();
|
|
34705
|
+
legacyProviders._hidden = true;
|
|
34706
|
+
legacyModels._hidden = true;
|
|
34707
|
+
legacyBrains._hidden = true;
|
|
34083
34708
|
program2.name("kimbho").description(KIMBHO_DESCRIPTION).version(KIMBHO_VERSION);
|
|
34084
34709
|
program2.addCommand(createInitCommand());
|
|
34085
34710
|
program2.addCommand(createPlanCommand());
|
|
@@ -34090,9 +34715,9 @@ function createProgram(onOpenShell) {
|
|
|
34090
34715
|
program2.addCommand(createMcpCommand());
|
|
34091
34716
|
program2.addCommand(createModelCommand());
|
|
34092
34717
|
program2.addCommand(createAgentsCommand());
|
|
34093
|
-
program2.addCommand(
|
|
34094
|
-
program2.addCommand(
|
|
34095
|
-
program2.addCommand(
|
|
34718
|
+
program2.addCommand(legacyProviders);
|
|
34719
|
+
program2.addCommand(legacyModels);
|
|
34720
|
+
program2.addCommand(legacyBrains);
|
|
34096
34721
|
program2.addCommand(createRunCommand());
|
|
34097
34722
|
program2.addCommand(createResumeCommand());
|
|
34098
34723
|
program2.addCommand(createFixCommand());
|
|
@@ -34108,7 +34733,7 @@ function createProgram(onOpenShell) {
|
|
|
34108
34733
|
// src/shell.ts
|
|
34109
34734
|
var import_node_readline = require("node:readline");
|
|
34110
34735
|
var import_promises18 = require("node:readline/promises");
|
|
34111
|
-
var
|
|
34736
|
+
var import_node_path21 = __toESM(require("node:path"), 1);
|
|
34112
34737
|
var import_node_process18 = __toESM(require("node:process"), 1);
|
|
34113
34738
|
|
|
34114
34739
|
// src/agent-management.ts
|
|
@@ -34162,6 +34787,7 @@ var TOP_LEVEL_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
34162
34787
|
"help",
|
|
34163
34788
|
"init",
|
|
34164
34789
|
"mcp",
|
|
34790
|
+
"mcp__",
|
|
34165
34791
|
"memory",
|
|
34166
34792
|
"model",
|
|
34167
34793
|
"models",
|
|
@@ -34266,6 +34892,61 @@ var PLAN_PREFIXES = [
|
|
|
34266
34892
|
function color(code, value) {
|
|
34267
34893
|
return `${code}${value}${RESET}`;
|
|
34268
34894
|
}
|
|
34895
|
+
function extractMcpResourceReferences(prompt) {
|
|
34896
|
+
const matches = prompt.match(/@[A-Za-z0-9_-]+:[^\s]+/g) ?? [];
|
|
34897
|
+
return matches.flatMap((token) => {
|
|
34898
|
+
const withoutAt = token.slice(1);
|
|
34899
|
+
const separatorIndex = withoutAt.indexOf(":");
|
|
34900
|
+
if (separatorIndex === -1) {
|
|
34901
|
+
return [];
|
|
34902
|
+
}
|
|
34903
|
+
return [
|
|
34904
|
+
{
|
|
34905
|
+
token,
|
|
34906
|
+
serverName: withoutAt.slice(0, separatorIndex),
|
|
34907
|
+
uri: withoutAt.slice(separatorIndex + 1)
|
|
34908
|
+
}
|
|
34909
|
+
];
|
|
34910
|
+
});
|
|
34911
|
+
}
|
|
34912
|
+
async function hydratePromptWithMcpResources(cwd, prompt) {
|
|
34913
|
+
const references = extractMcpResourceReferences(prompt);
|
|
34914
|
+
if (references.length === 0) {
|
|
34915
|
+
return {
|
|
34916
|
+
prompt,
|
|
34917
|
+
notes: []
|
|
34918
|
+
};
|
|
34919
|
+
}
|
|
34920
|
+
const blocks = [];
|
|
34921
|
+
const notes = [];
|
|
34922
|
+
for (const reference of references) {
|
|
34923
|
+
try {
|
|
34924
|
+
const rendered = await renderMcpResourceRead(cwd, reference.serverName, reference.uri);
|
|
34925
|
+
notes.push(`attached MCP resource ${reference.token}`);
|
|
34926
|
+
blocks.push([
|
|
34927
|
+
`Attached MCP resource ${reference.token}:`,
|
|
34928
|
+
...rendered
|
|
34929
|
+
].join("\n"));
|
|
34930
|
+
} catch (error2) {
|
|
34931
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
34932
|
+
notes.push(`failed to attach ${reference.token}: ${message}`);
|
|
34933
|
+
}
|
|
34934
|
+
}
|
|
34935
|
+
if (blocks.length === 0) {
|
|
34936
|
+
return {
|
|
34937
|
+
prompt,
|
|
34938
|
+
notes
|
|
34939
|
+
};
|
|
34940
|
+
}
|
|
34941
|
+
return {
|
|
34942
|
+
prompt: [
|
|
34943
|
+
prompt,
|
|
34944
|
+
"",
|
|
34945
|
+
...blocks
|
|
34946
|
+
].join("\n"),
|
|
34947
|
+
notes
|
|
34948
|
+
};
|
|
34949
|
+
}
|
|
34269
34950
|
function createExecutionTelemetry() {
|
|
34270
34951
|
return {
|
|
34271
34952
|
toolCalls: 0,
|
|
@@ -34535,6 +35216,11 @@ function renderHelp() {
|
|
|
34535
35216
|
"/mcp add <name> --command <cmd> [--arg <value>] [--env KEY=VALUE]",
|
|
34536
35217
|
" Add an MCP stdio server to .mcp.json.",
|
|
34537
35218
|
"/mcp tools [server] Discover tools/prompts/resources from MCP servers.",
|
|
35219
|
+
"/mcp prompts [server] List MCP prompts.",
|
|
35220
|
+
"/mcp resources [server] List MCP resources and templates.",
|
|
35221
|
+
"/mcp prompt <server> <prompt> [key=value ...]",
|
|
35222
|
+
" Render an MCP prompt.",
|
|
35223
|
+
"/mcp read <server> <uri> Read one MCP resource.",
|
|
34538
35224
|
"/agents List custom agents and teams.",
|
|
34539
35225
|
"/agents create <id> --base <role> Create a markdown custom agent.",
|
|
34540
35226
|
"/agents team create <id> <agent...> Create a markdown team file.",
|
|
@@ -34571,7 +35257,7 @@ function renderStartupCard(cwd, state) {
|
|
|
34571
35257
|
renderCardLine("shortcuts", "/ask /run /model /permissions /memory /mcp /quit")
|
|
34572
35258
|
];
|
|
34573
35259
|
if (!state.configured) {
|
|
34574
|
-
cardLines.push("setup: run /init or /
|
|
35260
|
+
cardLines.push("setup: run /init or /model add <template> to create .kimbho/config.json");
|
|
34575
35261
|
}
|
|
34576
35262
|
return renderBox(cardLines);
|
|
34577
35263
|
}
|
|
@@ -34863,6 +35549,12 @@ function hasRenderableDiff(toolId, output) {
|
|
|
34863
35549
|
}
|
|
34864
35550
|
return false;
|
|
34865
35551
|
}
|
|
35552
|
+
function isMutationTool(toolId) {
|
|
35553
|
+
return toolId === "file.write" || toolId === "file.patch" || toolId === "scaffold.generate";
|
|
35554
|
+
}
|
|
35555
|
+
function renderMutationArtifacts(artifacts, label = "changed", maxItems = 4) {
|
|
35556
|
+
return artifacts.slice(0, maxItems).map((artifact) => ` ${color(DIM, `${label}: ${shortenMiddle(artifact, 120)}`)}`);
|
|
35557
|
+
}
|
|
34866
35558
|
function colorDiffLine(line) {
|
|
34867
35559
|
if (line.startsWith("diff --git ")) {
|
|
34868
35560
|
const match = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
|
|
@@ -34921,14 +35613,26 @@ function renderShellSessionSummary(snapshot, planPath, sessionPath) {
|
|
|
34921
35613
|
lines.push(color(BOLD, "Activity"));
|
|
34922
35614
|
for (const event of snapshot.events.slice(-8)) {
|
|
34923
35615
|
lines.push(`- ${renderEventType(event.type)} | ${event.agentRole ?? "session"} | ${event.message}`);
|
|
35616
|
+
let landedMutation = false;
|
|
34924
35617
|
for (const toolResult of event.toolResults.slice(-4)) {
|
|
34925
35618
|
lines.push(` ${toolResult.success ? "ok" : "fail"} ${toolResult.toolId}: ${toolResult.summary}`);
|
|
34926
35619
|
if (toolResult.stdout && hasRenderableDiff(toolResult.toolId, toolResult.stdout)) {
|
|
35620
|
+
landedMutation = landedMutation || isMutationTool(toolResult.toolId);
|
|
34927
35621
|
lines.push(...renderDiffPreview(toolResult.stdout, 6));
|
|
34928
35622
|
}
|
|
34929
35623
|
if ((toolResult.toolId.startsWith("process.") || toolResult.toolId === "http.fetch" || toolResult.toolId.startsWith("browser.") || toolResult.toolId.startsWith("repo.")) && toolResult.stdout) {
|
|
34930
35624
|
lines.push(...renderTextPreview(toolResult.stdout, 6));
|
|
34931
35625
|
}
|
|
35626
|
+
if (toolResult.success && isMutationTool(toolResult.toolId) && toolResult.artifacts.length > 0) {
|
|
35627
|
+
landedMutation = true;
|
|
35628
|
+
lines.push(...renderMutationArtifacts(
|
|
35629
|
+
toolResult.artifacts,
|
|
35630
|
+
toolResult.toolId === "scaffold.generate" ? "created" : "changed"
|
|
35631
|
+
));
|
|
35632
|
+
}
|
|
35633
|
+
}
|
|
35634
|
+
if (event.type === "task-blocked" && !landedMutation) {
|
|
35635
|
+
lines.push(` ${color(DIM, "no safe edit landed before this task blocked.")}`);
|
|
34932
35636
|
}
|
|
34933
35637
|
for (const artifact of event.artifacts.slice(-3)) {
|
|
34934
35638
|
lines.push(` artifact: ${artifact}`);
|
|
@@ -35041,7 +35745,11 @@ function renderLiveExecutionEvent(event) {
|
|
|
35041
35745
|
case "tool-finished":
|
|
35042
35746
|
return [
|
|
35043
35747
|
` ${event.toolResult.success ? color(CYAN, "ok") : color(AMBER, "fail")} ${event.toolResult.toolId} ${event.toolResult.summary}`,
|
|
35044
|
-
...event.toolResult.stdout && hasRenderableDiff(event.toolResult.toolId, event.toolResult.stdout) ? renderDiffPreview(event.toolResult.stdout, 8) : (event.toolResult.toolId.startsWith("process.") || event.toolResult.toolId === "http.fetch" || event.toolResult.toolId.startsWith("browser.") || event.toolResult.toolId.startsWith("repo.")) && event.toolResult.stdout ? renderTextPreview(event.toolResult.stdout, 8) : []
|
|
35748
|
+
...event.toolResult.stdout && hasRenderableDiff(event.toolResult.toolId, event.toolResult.stdout) ? renderDiffPreview(event.toolResult.stdout, 8) : (event.toolResult.toolId.startsWith("process.") || event.toolResult.toolId === "http.fetch" || event.toolResult.toolId.startsWith("browser.") || event.toolResult.toolId.startsWith("repo.")) && event.toolResult.stdout ? renderTextPreview(event.toolResult.stdout, 8) : [],
|
|
35749
|
+
...event.toolResult.success && isMutationTool(event.toolResult.toolId) && event.toolResult.artifacts.length > 0 ? renderMutationArtifacts(
|
|
35750
|
+
event.toolResult.artifacts,
|
|
35751
|
+
event.toolResult.toolId === "scaffold.generate" ? "created" : "changed"
|
|
35752
|
+
) : []
|
|
35045
35753
|
];
|
|
35046
35754
|
default:
|
|
35047
35755
|
return [];
|
|
@@ -35190,13 +35898,18 @@ function clearAllConversations(runtime) {
|
|
|
35190
35898
|
}
|
|
35191
35899
|
}
|
|
35192
35900
|
async function handleChatPrompt(cwd, prompt, runtime) {
|
|
35901
|
+
const hydrated = await hydratePromptWithMcpResources(cwd, prompt);
|
|
35193
35902
|
const config2 = await loadConfig(cwd);
|
|
35194
35903
|
if (!config2) {
|
|
35195
|
-
throw new Error("No config found. Run /init or /
|
|
35904
|
+
throw new Error("No config found. Run /init or /model add <template> first.");
|
|
35196
35905
|
}
|
|
35197
35906
|
const registry2 = createDefaultBrainProviderRegistry(cwd);
|
|
35198
35907
|
const resolver = new BrainResolver(config2, registry2);
|
|
35199
35908
|
const brain = await resolver.resolve(runtime.focusRole);
|
|
35909
|
+
const memoryContext = await loadMarkdownMemoryContext(cwd, {
|
|
35910
|
+
maxFiles: 8,
|
|
35911
|
+
maxCharsPerFile: 3e3
|
|
35912
|
+
});
|
|
35200
35913
|
const compactionPath = await compactConversationIfNeeded(cwd, runtime, runtime.focusRole);
|
|
35201
35914
|
if (compactionPath) {
|
|
35202
35915
|
console.log(color(DIM, `[compacting] condensed ${runtime.focusRole} chat context -> ${compactionPath}`));
|
|
@@ -35206,7 +35919,7 @@ async function handleChatPrompt(cwd, prompt, runtime) {
|
|
|
35206
35919
|
...history,
|
|
35207
35920
|
{
|
|
35208
35921
|
role: "user",
|
|
35209
|
-
content: prompt
|
|
35922
|
+
content: hydrated.prompt
|
|
35210
35923
|
}
|
|
35211
35924
|
]);
|
|
35212
35925
|
let result;
|
|
@@ -35219,6 +35932,11 @@ async function handleChatPrompt(cwd, prompt, runtime) {
|
|
|
35219
35932
|
...brain.settings.promptPreamble || runtime.conversationSummaries[runtime.focusRole] ? {
|
|
35220
35933
|
systemPrompt: [
|
|
35221
35934
|
brain.settings.promptPreamble,
|
|
35935
|
+
memoryContext.length > 0 ? [
|
|
35936
|
+
"Workspace memory:",
|
|
35937
|
+
...memoryContext.map((record2) => `File: ${record2.filePath}
|
|
35938
|
+
${record2.content}`)
|
|
35939
|
+
].join("\n\n") : null,
|
|
35222
35940
|
runtime.conversationSummaries[runtime.focusRole] ? `Compacted conversation summary:
|
|
35223
35941
|
${runtime.conversationSummaries[runtime.focusRole]}` : null
|
|
35224
35942
|
].filter((value) => Boolean(value)).join("\n\n")
|
|
@@ -35245,16 +35963,20 @@ ${runtime.conversationSummaries[runtime.focusRole]}` : null
|
|
|
35245
35963
|
]);
|
|
35246
35964
|
runtime.conversations[runtime.focusRole] = nextConversation;
|
|
35247
35965
|
console.log(color(DIM, `[${brain.role}] ${brain.provider.id}/${brain.model}`));
|
|
35966
|
+
for (const note of hydrated.notes) {
|
|
35967
|
+
console.log(color(DIM, note));
|
|
35968
|
+
}
|
|
35248
35969
|
if (result.usage) {
|
|
35249
35970
|
console.log(color(DIM, `tokens: ${result.usage.inputTokens} in / ${result.usage.outputTokens} out`));
|
|
35250
35971
|
}
|
|
35251
35972
|
console.log(renderTerminalMarkdown(result.text));
|
|
35252
35973
|
}
|
|
35253
35974
|
async function runGoalExecution(cwd, goal, runtime) {
|
|
35975
|
+
const hydrated = await hydratePromptWithMcpResources(cwd, goal);
|
|
35254
35976
|
const orchestrator = new ExecutionOrchestrator();
|
|
35255
|
-
const workspace = await resolveExecutionWorkspace(cwd,
|
|
35977
|
+
const workspace = await resolveExecutionWorkspace(cwd, hydrated.prompt);
|
|
35256
35978
|
const request = {
|
|
35257
|
-
goal,
|
|
35979
|
+
goal: hydrated.prompt,
|
|
35258
35980
|
mode: "run",
|
|
35259
35981
|
cwd: workspace.cwd,
|
|
35260
35982
|
workspaceState: workspace.workspaceState,
|
|
@@ -35269,6 +35991,9 @@ async function runGoalExecution(cwd, goal, runtime) {
|
|
|
35269
35991
|
};
|
|
35270
35992
|
const planningSpinner = new ShellActivityIndicator("planning");
|
|
35271
35993
|
console.log(color(DIM, `Working on: ${goal}`));
|
|
35994
|
+
for (const note of hydrated.notes) {
|
|
35995
|
+
console.log(color(DIM, note));
|
|
35996
|
+
}
|
|
35272
35997
|
for (const note of workspace.notes) {
|
|
35273
35998
|
console.log(color(DIM, note));
|
|
35274
35999
|
}
|
|
@@ -35529,7 +36254,7 @@ async function printLatestPlanSummary(cwd) {
|
|
|
35529
36254
|
async function handleApprovalModeCommand(cwd, tokens) {
|
|
35530
36255
|
const config2 = await loadConfig(cwd);
|
|
35531
36256
|
if (!config2) {
|
|
35532
|
-
throw new Error("No config found. Run /init or /
|
|
36257
|
+
throw new Error("No config found. Run /init or /model add <template> first.");
|
|
35533
36258
|
}
|
|
35534
36259
|
const subcommand = tokens[1]?.trim().toLowerCase();
|
|
35535
36260
|
if (!subcommand || subcommand === "status") {
|
|
@@ -35549,44 +36274,55 @@ async function handleApprovalModeCommand(cwd, tokens) {
|
|
|
35549
36274
|
console.log(`approval mode: ${subcommand}`);
|
|
35550
36275
|
}
|
|
35551
36276
|
async function printConfigSummary(cwd) {
|
|
35552
|
-
const
|
|
36277
|
+
const layers = await loadConfigLayers(cwd);
|
|
35553
36278
|
const paths = await listMemoryPaths(cwd);
|
|
35554
|
-
console.log(`config: ${resolveConfigPath(cwd)}`);
|
|
36279
|
+
console.log(`config.project: ${resolveConfigPath(cwd)}`);
|
|
36280
|
+
console.log(`config.user: ${resolveGlobalConfigPath()}`);
|
|
35555
36281
|
console.log(`mcp: ${resolveMcpConfigPath(cwd)}`);
|
|
35556
36282
|
console.log(`memory.project: ${paths.projectMemoryPath}`);
|
|
35557
36283
|
console.log(`memory.user: ${paths.userMemoryPath}`);
|
|
35558
36284
|
console.log(`memory.agents: ${paths.agentMemoryDir}`);
|
|
35559
|
-
if (!
|
|
36285
|
+
if (!layers.resolved) {
|
|
35560
36286
|
console.log("No config found. Run /init first.");
|
|
35561
36287
|
return;
|
|
35562
36288
|
}
|
|
36289
|
+
console.log(`layers: user=${layers.user ? "yes" : "no"} project=${layers.project ? "yes" : "no"}`);
|
|
36290
|
+
const config2 = layers.resolved;
|
|
35563
36291
|
console.log(`providers: ${config2.providers.length}`);
|
|
35564
36292
|
console.log(`approval: ${config2.approvalMode}`);
|
|
35565
36293
|
console.log(`sandbox: ${config2.sandboxMode}`);
|
|
35566
36294
|
console.log(`trusted directories: ${config2.trustedDirectories.length}`);
|
|
35567
36295
|
}
|
|
35568
36296
|
async function handlePermissionsCommand(cwd, tokens) {
|
|
35569
|
-
const
|
|
35570
|
-
|
|
36297
|
+
const subcommand = tokens[1]?.trim().toLowerCase();
|
|
36298
|
+
const scopeToken = tokens.find((token, index) => index > 0 && (token === "user" || token === "project"));
|
|
36299
|
+
const scope = scopeToken === "user" ? "user" : "project";
|
|
36300
|
+
const direct = scope === "user" ? await loadUserConfig() : await loadProjectConfig(cwd);
|
|
36301
|
+
const resolved = await loadConfig(cwd);
|
|
36302
|
+
if (!resolved && !direct) {
|
|
35571
36303
|
throw new Error("No config found. Run /init or /model add <template> first.");
|
|
35572
36304
|
}
|
|
35573
|
-
const
|
|
36305
|
+
const effective = direct ?? resolved ?? createDefaultConfig();
|
|
36306
|
+
const saveScoped = async (next) => scope === "user" ? saveUserConfig(next) : saveConfig(next, cwd);
|
|
35574
36307
|
if (!subcommand || subcommand === "show" || subcommand === "status") {
|
|
35575
|
-
console.log(`
|
|
35576
|
-
console.log(`
|
|
35577
|
-
console.log(`
|
|
35578
|
-
|
|
36308
|
+
console.log(`scope: ${scope}`);
|
|
36309
|
+
console.log(`direct config: ${direct ? "present" : "missing"}`);
|
|
36310
|
+
console.log(`approval: ${effective.approvalMode}`);
|
|
36311
|
+
console.log(`sandbox: ${effective.sandboxMode}`);
|
|
36312
|
+
console.log(`trusted directories: ${effective.trustedDirectories.length}`);
|
|
36313
|
+
for (const directory of effective.trustedDirectories) {
|
|
35579
36314
|
console.log(` - ${directory}`);
|
|
35580
36315
|
}
|
|
35581
36316
|
return;
|
|
35582
36317
|
}
|
|
35583
36318
|
if (subcommand === "auto" || subcommand === "manual") {
|
|
35584
|
-
const outputPath = await
|
|
35585
|
-
...
|
|
36319
|
+
const outputPath = await saveScoped({
|
|
36320
|
+
...effective,
|
|
35586
36321
|
approvalMode: subcommand
|
|
35587
|
-
}
|
|
36322
|
+
});
|
|
35588
36323
|
console.log(`Updated ${outputPath}`);
|
|
35589
36324
|
console.log(`approval mode: ${subcommand}`);
|
|
36325
|
+
console.log(`scope: ${scope}`);
|
|
35590
36326
|
return;
|
|
35591
36327
|
}
|
|
35592
36328
|
if (subcommand === "sandbox") {
|
|
@@ -35598,12 +36334,13 @@ async function handlePermissionsCommand(cwd, tokens) {
|
|
|
35598
36334
|
].includes(mode)) {
|
|
35599
36335
|
throw new Error("Usage: /permissions sandbox <read-only|workspace-write|full>");
|
|
35600
36336
|
}
|
|
35601
|
-
const outputPath = await
|
|
35602
|
-
...
|
|
36337
|
+
const outputPath = await saveScoped({
|
|
36338
|
+
...effective,
|
|
35603
36339
|
sandboxMode: mode
|
|
35604
|
-
}
|
|
36340
|
+
});
|
|
35605
36341
|
console.log(`Updated ${outputPath}`);
|
|
35606
36342
|
console.log(`sandbox: ${mode}`);
|
|
36343
|
+
console.log(`scope: ${scope}`);
|
|
35607
36344
|
return;
|
|
35608
36345
|
}
|
|
35609
36346
|
if (subcommand === "trust" || subcommand === "untrust") {
|
|
@@ -35611,19 +36348,21 @@ async function handlePermissionsCommand(cwd, tokens) {
|
|
|
35611
36348
|
if (!target) {
|
|
35612
36349
|
throw new Error(`Usage: /permissions ${subcommand} <path>`);
|
|
35613
36350
|
}
|
|
36351
|
+
const normalizedTarget = import_node_path21.default.resolve(cwd, target);
|
|
35614
36352
|
const trustedDirectories = subcommand === "trust" ? Array.from(/* @__PURE__ */ new Set([
|
|
35615
|
-
...
|
|
35616
|
-
|
|
35617
|
-
])) :
|
|
35618
|
-
const outputPath = await
|
|
35619
|
-
...
|
|
36353
|
+
...effective.trustedDirectories,
|
|
36354
|
+
normalizedTarget
|
|
36355
|
+
])) : effective.trustedDirectories.filter((directory) => directory !== target && directory !== normalizedTarget);
|
|
36356
|
+
const outputPath = await saveScoped({
|
|
36357
|
+
...effective,
|
|
35620
36358
|
trustedDirectories
|
|
35621
|
-
}
|
|
36359
|
+
});
|
|
35622
36360
|
console.log(`Updated ${outputPath}`);
|
|
35623
|
-
console.log(`${subcommand === "trust" ? "Trusted" : "Removed"} ${
|
|
36361
|
+
console.log(`${subcommand === "trust" ? "Trusted" : "Removed"} ${normalizedTarget}`);
|
|
36362
|
+
console.log(`scope: ${scope}`);
|
|
35624
36363
|
return;
|
|
35625
36364
|
}
|
|
35626
|
-
throw new Error("Usage: /permissions [show|auto|manual|sandbox <mode>|trust <path>|untrust <path>]");
|
|
36365
|
+
throw new Error("Usage: /permissions [show|auto|manual|sandbox <mode>|trust <path>|untrust <path>] [project|user]");
|
|
35627
36366
|
}
|
|
35628
36367
|
async function handleMemoryCommand(cwd, tokens) {
|
|
35629
36368
|
const subcommand = tokens[1]?.trim().toLowerCase();
|
|
@@ -35650,7 +36389,7 @@ async function handleMemoryCommand(cwd, tokens) {
|
|
|
35650
36389
|
}
|
|
35651
36390
|
let filePath;
|
|
35652
36391
|
if (scope === "init") {
|
|
35653
|
-
filePath =
|
|
36392
|
+
filePath = import_node_path21.default.join(cwd, "kimbho_init.md");
|
|
35654
36393
|
} else if (scope === "project") {
|
|
35655
36394
|
filePath = resolveProjectMemoryPath(cwd);
|
|
35656
36395
|
} else if (scope === "user") {
|
|
@@ -35660,7 +36399,7 @@ async function handleMemoryCommand(cwd, tokens) {
|
|
|
35660
36399
|
if (!agentId) {
|
|
35661
36400
|
throw new Error("Usage: /memory show agent <agent-id>");
|
|
35662
36401
|
}
|
|
35663
|
-
filePath =
|
|
36402
|
+
filePath = import_node_path21.default.join(resolveAgentMemoryDir(cwd), `${agentId}.md`);
|
|
35664
36403
|
} else {
|
|
35665
36404
|
throw new Error("Usage: /memory show <init|project|user|agent> [id]");
|
|
35666
36405
|
}
|
|
@@ -35728,6 +36467,45 @@ async function handleMcpCommand(cwd, tokens) {
|
|
|
35728
36467
|
}
|
|
35729
36468
|
return;
|
|
35730
36469
|
}
|
|
36470
|
+
if (subcommand === "prompts") {
|
|
36471
|
+
const name = tokens[2]?.trim();
|
|
36472
|
+
for (const line of await renderMcpPromptList(cwd, name)) {
|
|
36473
|
+
console.log(line);
|
|
36474
|
+
}
|
|
36475
|
+
return;
|
|
36476
|
+
}
|
|
36477
|
+
if (subcommand === "resources") {
|
|
36478
|
+
const name = tokens[2]?.trim();
|
|
36479
|
+
for (const line of await renderMcpResourceList(cwd, name)) {
|
|
36480
|
+
console.log(line);
|
|
36481
|
+
}
|
|
36482
|
+
return;
|
|
36483
|
+
}
|
|
36484
|
+
if (subcommand === "prompt") {
|
|
36485
|
+
const serverName = tokens[2]?.trim();
|
|
36486
|
+
const promptName = tokens[3]?.trim();
|
|
36487
|
+
if (!serverName || !promptName) {
|
|
36488
|
+
throw new Error("Usage: /mcp prompt <server> <prompt> [key=value ...]");
|
|
36489
|
+
}
|
|
36490
|
+
const args = Object.fromEntries(
|
|
36491
|
+
tokens.slice(4).map((entry) => entry.split("=", 2)).filter((parts) => parts.length === 2 && parts[0].length > 0)
|
|
36492
|
+
);
|
|
36493
|
+
for (const line of await renderMcpPromptInvocation(cwd, serverName, promptName, args)) {
|
|
36494
|
+
console.log(line);
|
|
36495
|
+
}
|
|
36496
|
+
return;
|
|
36497
|
+
}
|
|
36498
|
+
if (subcommand === "read") {
|
|
36499
|
+
const serverName = tokens[2]?.trim();
|
|
36500
|
+
const uri = tokens.slice(3).join(" ").trim();
|
|
36501
|
+
if (!serverName || !uri) {
|
|
36502
|
+
throw new Error("Usage: /mcp read <server> <uri>");
|
|
36503
|
+
}
|
|
36504
|
+
for (const line of await renderMcpResourceRead(cwd, serverName, uri)) {
|
|
36505
|
+
console.log(line);
|
|
36506
|
+
}
|
|
36507
|
+
return;
|
|
36508
|
+
}
|
|
35731
36509
|
if (subcommand === "remove") {
|
|
35732
36510
|
const name = tokens[2]?.trim();
|
|
35733
36511
|
if (!name) {
|
|
@@ -35791,7 +36569,7 @@ async function handleMcpCommand(cwd, tokens) {
|
|
|
35791
36569
|
console.log(`Added MCP server ${name}`);
|
|
35792
36570
|
return;
|
|
35793
36571
|
}
|
|
35794
|
-
throw new Error("Usage: /mcp [list|tools [server]|
|
|
36572
|
+
throw new Error("Usage: /mcp [list|tools [server]|prompts [server]|resources [server]|prompt <server> <prompt>|read <server> <uri>|add <name> --command <cmd>|remove <name>|enable <name>|disable <name>]");
|
|
35795
36573
|
}
|
|
35796
36574
|
async function handleAgentsCommand(cwd, tokens) {
|
|
35797
36575
|
const subcommand = tokens[1]?.trim().toLowerCase();
|
|
@@ -35922,11 +36700,12 @@ async function handleModelSurfaceCommand(cwd, tokens, runtime) {
|
|
|
35922
36700
|
throw new Error("Usage: /model [show|providers|templates|add <tpl>|use <provider> [model]|find [search]|select <n>|focus <role>|check]");
|
|
35923
36701
|
}
|
|
35924
36702
|
async function createPlanOnly(cwd, goal) {
|
|
36703
|
+
const hydrated = await hydratePromptWithMcpResources(cwd, goal);
|
|
35925
36704
|
const request = {
|
|
35926
|
-
goal,
|
|
36705
|
+
goal: hydrated.prompt,
|
|
35927
36706
|
mode: "plan",
|
|
35928
36707
|
cwd,
|
|
35929
|
-
workspaceState: await inferPlanningWorkspaceState(cwd,
|
|
36708
|
+
workspaceState: await inferPlanningWorkspaceState(cwd, hydrated.prompt),
|
|
35930
36709
|
constraints: []
|
|
35931
36710
|
};
|
|
35932
36711
|
const activity = new ShellActivityIndicator("planning");
|
|
@@ -35939,6 +36718,9 @@ async function createPlanOnly(cwd, goal) {
|
|
|
35939
36718
|
}
|
|
35940
36719
|
const plan = planResult.plan;
|
|
35941
36720
|
const planPath = await savePlan(plan, cwd);
|
|
36721
|
+
for (const note of hydrated.notes) {
|
|
36722
|
+
console.log(color(DIM, note));
|
|
36723
|
+
}
|
|
35942
36724
|
for (const line of renderPlanGenerationNotes(planResult)) {
|
|
35943
36725
|
console.log(line);
|
|
35944
36726
|
}
|
|
@@ -36111,7 +36893,7 @@ function renderModelLine2(model) {
|
|
|
36111
36893
|
async function printProviderList(cwd, focusRole) {
|
|
36112
36894
|
const config2 = await loadConfig(cwd);
|
|
36113
36895
|
if (!config2) {
|
|
36114
|
-
console.log("No config found. Run /init or /
|
|
36896
|
+
console.log("No config found. Run /init or /model add <template> first.");
|
|
36115
36897
|
return;
|
|
36116
36898
|
}
|
|
36117
36899
|
const activeProviderId = config2.brains[focusRole].providerId;
|
|
@@ -36163,7 +36945,7 @@ async function addProviderFromTemplate(cwd, options) {
|
|
|
36163
36945
|
async function printProviderHealth(cwd) {
|
|
36164
36946
|
const config2 = await loadConfig(cwd);
|
|
36165
36947
|
if (!config2) {
|
|
36166
|
-
console.log("No config found. Run /init or /
|
|
36948
|
+
console.log("No config found. Run /init or /model add <template> first.");
|
|
36167
36949
|
return;
|
|
36168
36950
|
}
|
|
36169
36951
|
const registry2 = createDefaultBrainProviderRegistry(cwd);
|
|
@@ -36180,7 +36962,7 @@ async function printProviderHealth(cwd) {
|
|
|
36180
36962
|
async function printBrainAssignments(cwd) {
|
|
36181
36963
|
const config2 = await loadConfig(cwd);
|
|
36182
36964
|
if (!config2) {
|
|
36183
|
-
console.log("No config found. Run /init or /
|
|
36965
|
+
console.log("No config found. Run /init or /model add <template> first.");
|
|
36184
36966
|
return;
|
|
36185
36967
|
}
|
|
36186
36968
|
for (const role of BRAIN_ROLES) {
|
|
@@ -36218,7 +37000,7 @@ async function handleProvidersCommand(cwd, tokens, runtime) {
|
|
|
36218
37000
|
if (options.baseUrl) {
|
|
36219
37001
|
console.log(`Base URL ${options.baseUrl}`);
|
|
36220
37002
|
}
|
|
36221
|
-
console.log(`Next: /
|
|
37003
|
+
console.log(`Next: /model use ${resolvedProviderId}`);
|
|
36222
37004
|
return;
|
|
36223
37005
|
}
|
|
36224
37006
|
if (subcommand === "use") {
|
|
@@ -36258,7 +37040,7 @@ async function handleBrainCommand(cwd, tokens, runtime) {
|
|
|
36258
37040
|
async function handleModelsCommand(cwd, tokens, runtime) {
|
|
36259
37041
|
const config2 = await loadConfig(cwd);
|
|
36260
37042
|
if (!config2) {
|
|
36261
|
-
throw new Error("No config found. Run /init or /
|
|
37043
|
+
throw new Error("No config found. Run /init or /model add <template> first.");
|
|
36262
37044
|
}
|
|
36263
37045
|
const providerId = config2.brains[runtime.focusRole].providerId;
|
|
36264
37046
|
const provider = findProviderById(config2, providerId);
|
|
@@ -36301,12 +37083,12 @@ async function handleModelsCommand(cwd, tokens, runtime) {
|
|
|
36301
37083
|
console.log(` ${index + 1}. ${renderModelLine2(model)}`);
|
|
36302
37084
|
}
|
|
36303
37085
|
console.log(``);
|
|
36304
|
-
console.log("Use /select <number> or /use-
|
|
37086
|
+
console.log("Use /model select <number> or /model use <provider-id> <model-id> to assign one to all roles.");
|
|
36305
37087
|
}
|
|
36306
37088
|
async function handleModelSelection(cwd, modelId, runtime) {
|
|
36307
37089
|
const config2 = await loadConfig(cwd);
|
|
36308
37090
|
if (!config2) {
|
|
36309
|
-
throw new Error("No config found. Run /init or /
|
|
37091
|
+
throw new Error("No config found. Run /init or /model add <template> first.");
|
|
36310
37092
|
}
|
|
36311
37093
|
const providerId = config2.brains[runtime.focusRole].providerId;
|
|
36312
37094
|
const provider = findProviderById(config2, providerId);
|
|
@@ -36415,6 +37197,23 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
|
|
|
36415
37197
|
if (!head) {
|
|
36416
37198
|
return cwd;
|
|
36417
37199
|
}
|
|
37200
|
+
if (head.startsWith("mcp__")) {
|
|
37201
|
+
const parts = head.split("__").filter((part) => part.length > 0);
|
|
37202
|
+
if (parts.length < 3) {
|
|
37203
|
+
throw new Error("Usage: /mcp__<server>__<prompt> [key=value ...]");
|
|
37204
|
+
}
|
|
37205
|
+
const serverName = parts[1];
|
|
37206
|
+
const promptName = parts[2];
|
|
37207
|
+
if (!serverName || !promptName) {
|
|
37208
|
+
throw new Error("Usage: /mcp__<server>__<prompt> [key=value ...]");
|
|
37209
|
+
}
|
|
37210
|
+
const args = Object.fromEntries(
|
|
37211
|
+
tokens.slice(1).map((entry) => entry.split("=", 2)).filter((pair) => pair.length === 2 && pair[0].length > 0)
|
|
37212
|
+
);
|
|
37213
|
+
const rendered = await renderMcpPromptInvocation(cwd, serverName, promptName, args);
|
|
37214
|
+
await handleChatPrompt(cwd, rendered.join("\n"), runtime);
|
|
37215
|
+
return cwd;
|
|
37216
|
+
}
|
|
36418
37217
|
if (!firstToken?.startsWith("/") && !TOP_LEVEL_COMMANDS.has(head) && !head.startsWith("-")) {
|
|
36419
37218
|
const intent = inferPromptIntent(trimmed);
|
|
36420
37219
|
if (intent === "run") {
|