@kimbho/kimbho-cli 0.1.0 → 0.1.2
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/README.md +17 -0
- package/dist/index.cjs +1070 -148
- package/dist/index.cjs.map +4 -4
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1147,9 +1147,9 @@ var require_command = __commonJS({
|
|
|
1147
1147
|
"../../node_modules/commander/lib/command.js"(exports2) {
|
|
1148
1148
|
var EventEmitter = require("node:events").EventEmitter;
|
|
1149
1149
|
var childProcess = require("node:child_process");
|
|
1150
|
-
var
|
|
1150
|
+
var path6 = require("node:path");
|
|
1151
1151
|
var fs = require("node:fs");
|
|
1152
|
-
var
|
|
1152
|
+
var process12 = require("node:process");
|
|
1153
1153
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
1154
1154
|
var { CommanderError: CommanderError2 } = require_error();
|
|
1155
1155
|
var { Help: Help2, stripColor } = require_help();
|
|
@@ -1196,13 +1196,13 @@ var require_command = __commonJS({
|
|
|
1196
1196
|
this._showSuggestionAfterError = true;
|
|
1197
1197
|
this._savedState = null;
|
|
1198
1198
|
this._outputConfiguration = {
|
|
1199
|
-
writeOut: (str) =>
|
|
1200
|
-
writeErr: (str) =>
|
|
1199
|
+
writeOut: (str) => process12.stdout.write(str),
|
|
1200
|
+
writeErr: (str) => process12.stderr.write(str),
|
|
1201
1201
|
outputError: (str, write) => write(str),
|
|
1202
|
-
getOutHelpWidth: () =>
|
|
1203
|
-
getErrHelpWidth: () =>
|
|
1204
|
-
getOutHasColors: () => useColor() ?? (
|
|
1205
|
-
getErrHasColors: () => useColor() ?? (
|
|
1202
|
+
getOutHelpWidth: () => process12.stdout.isTTY ? process12.stdout.columns : void 0,
|
|
1203
|
+
getErrHelpWidth: () => process12.stderr.isTTY ? process12.stderr.columns : void 0,
|
|
1204
|
+
getOutHasColors: () => useColor() ?? (process12.stdout.isTTY && process12.stdout.hasColors?.()),
|
|
1205
|
+
getErrHasColors: () => useColor() ?? (process12.stderr.isTTY && process12.stderr.hasColors?.()),
|
|
1206
1206
|
stripColor: (str) => stripColor(str)
|
|
1207
1207
|
};
|
|
1208
1208
|
this._hidden = false;
|
|
@@ -1585,7 +1585,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1585
1585
|
if (this._exitCallback) {
|
|
1586
1586
|
this._exitCallback(new CommanderError2(exitCode, code, message));
|
|
1587
1587
|
}
|
|
1588
|
-
|
|
1588
|
+
process12.exit(exitCode);
|
|
1589
1589
|
}
|
|
1590
1590
|
/**
|
|
1591
1591
|
* Register callback `fn` for the command.
|
|
@@ -1983,16 +1983,16 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1983
1983
|
}
|
|
1984
1984
|
parseOptions = parseOptions || {};
|
|
1985
1985
|
if (argv === void 0 && parseOptions.from === void 0) {
|
|
1986
|
-
if (
|
|
1986
|
+
if (process12.versions?.electron) {
|
|
1987
1987
|
parseOptions.from = "electron";
|
|
1988
1988
|
}
|
|
1989
|
-
const execArgv =
|
|
1989
|
+
const execArgv = process12.execArgv ?? [];
|
|
1990
1990
|
if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
|
|
1991
1991
|
parseOptions.from = "eval";
|
|
1992
1992
|
}
|
|
1993
1993
|
}
|
|
1994
1994
|
if (argv === void 0) {
|
|
1995
|
-
argv =
|
|
1995
|
+
argv = process12.argv;
|
|
1996
1996
|
}
|
|
1997
1997
|
this.rawArgs = argv.slice();
|
|
1998
1998
|
let userArgs;
|
|
@@ -2003,7 +2003,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2003
2003
|
userArgs = argv.slice(2);
|
|
2004
2004
|
break;
|
|
2005
2005
|
case "electron":
|
|
2006
|
-
if (
|
|
2006
|
+
if (process12.defaultApp) {
|
|
2007
2007
|
this._scriptPath = argv[1];
|
|
2008
2008
|
userArgs = argv.slice(2);
|
|
2009
2009
|
} else {
|
|
@@ -2147,9 +2147,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2147
2147
|
let launchWithNode = false;
|
|
2148
2148
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
2149
2149
|
function findFile(baseDir, baseName) {
|
|
2150
|
-
const localBin =
|
|
2150
|
+
const localBin = path6.resolve(baseDir, baseName);
|
|
2151
2151
|
if (fs.existsSync(localBin)) return localBin;
|
|
2152
|
-
if (sourceExt.includes(
|
|
2152
|
+
if (sourceExt.includes(path6.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 = path6.resolve(
|
|
2171
|
+
path6.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 = path6.basename(
|
|
2179
2179
|
this._scriptPath,
|
|
2180
|
-
|
|
2180
|
+
path6.extname(this._scriptPath)
|
|
2181
2181
|
);
|
|
2182
2182
|
if (legacyName !== this._name) {
|
|
2183
2183
|
localFile = findFile(
|
|
@@ -2188,13 +2188,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2188
2188
|
}
|
|
2189
2189
|
executableFile = localFile || executableFile;
|
|
2190
2190
|
}
|
|
2191
|
-
launchWithNode = sourceExt.includes(
|
|
2191
|
+
launchWithNode = sourceExt.includes(path6.extname(executableFile));
|
|
2192
2192
|
let proc;
|
|
2193
|
-
if (
|
|
2193
|
+
if (process12.platform !== "win32") {
|
|
2194
2194
|
if (launchWithNode) {
|
|
2195
2195
|
args.unshift(executableFile);
|
|
2196
|
-
args = incrementNodeInspectorPort(
|
|
2197
|
-
proc = childProcess.spawn(
|
|
2196
|
+
args = incrementNodeInspectorPort(process12.execArgv).concat(args);
|
|
2197
|
+
proc = childProcess.spawn(process12.argv[0], args, { stdio: "inherit" });
|
|
2198
2198
|
} else {
|
|
2199
2199
|
proc = childProcess.spawn(executableFile, args, { stdio: "inherit" });
|
|
2200
2200
|
}
|
|
@@ -2205,13 +2205,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2205
2205
|
subcommand._name
|
|
2206
2206
|
);
|
|
2207
2207
|
args.unshift(executableFile);
|
|
2208
|
-
args = incrementNodeInspectorPort(
|
|
2209
|
-
proc = childProcess.spawn(
|
|
2208
|
+
args = incrementNodeInspectorPort(process12.execArgv).concat(args);
|
|
2209
|
+
proc = childProcess.spawn(process12.execPath, args, { stdio: "inherit" });
|
|
2210
2210
|
}
|
|
2211
2211
|
if (!proc.killed) {
|
|
2212
2212
|
const signals = ["SIGUSR1", "SIGUSR2", "SIGTERM", "SIGINT", "SIGHUP"];
|
|
2213
2213
|
signals.forEach((signal) => {
|
|
2214
|
-
|
|
2214
|
+
process12.on(signal, () => {
|
|
2215
2215
|
if (proc.killed === false && proc.exitCode === null) {
|
|
2216
2216
|
proc.kill(signal);
|
|
2217
2217
|
}
|
|
@@ -2222,7 +2222,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2222
2222
|
proc.on("close", (code) => {
|
|
2223
2223
|
code = code ?? 1;
|
|
2224
2224
|
if (!exitCallback) {
|
|
2225
|
-
|
|
2225
|
+
process12.exit(code);
|
|
2226
2226
|
} else {
|
|
2227
2227
|
exitCallback(
|
|
2228
2228
|
new CommanderError2(
|
|
@@ -2244,7 +2244,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2244
2244
|
throw new Error(`'${executableFile}' not executable`);
|
|
2245
2245
|
}
|
|
2246
2246
|
if (!exitCallback) {
|
|
2247
|
-
|
|
2247
|
+
process12.exit(1);
|
|
2248
2248
|
} else {
|
|
2249
2249
|
const wrappedError = new CommanderError2(
|
|
2250
2250
|
1,
|
|
@@ -2739,13 +2739,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2739
2739
|
*/
|
|
2740
2740
|
_parseOptionsEnv() {
|
|
2741
2741
|
this.options.forEach((option) => {
|
|
2742
|
-
if (option.envVar && option.envVar in
|
|
2742
|
+
if (option.envVar && option.envVar in process12.env) {
|
|
2743
2743
|
const optionKey = option.attributeName();
|
|
2744
2744
|
if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
|
|
2745
2745
|
this.getOptionValueSource(optionKey)
|
|
2746
2746
|
)) {
|
|
2747
2747
|
if (option.required || option.optional) {
|
|
2748
|
-
this.emit(`optionEnv:${option.name()}`,
|
|
2748
|
+
this.emit(`optionEnv:${option.name()}`, process12.env[option.envVar]);
|
|
2749
2749
|
} else {
|
|
2750
2750
|
this.emit(`optionEnv:${option.name()}`);
|
|
2751
2751
|
}
|
|
@@ -3035,7 +3035,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3035
3035
|
* @return {Command}
|
|
3036
3036
|
*/
|
|
3037
3037
|
nameFromFilename(filename) {
|
|
3038
|
-
this._name =
|
|
3038
|
+
this._name = path6.basename(filename, path6.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(path7) {
|
|
3053
|
+
if (path7 === void 0) return this._executableDir;
|
|
3054
|
+
this._executableDir = path7;
|
|
3055
3055
|
return this;
|
|
3056
3056
|
}
|
|
3057
3057
|
/**
|
|
@@ -3200,7 +3200,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3200
3200
|
*/
|
|
3201
3201
|
help(contextOptions) {
|
|
3202
3202
|
this.outputHelp(contextOptions);
|
|
3203
|
-
let exitCode = Number(
|
|
3203
|
+
let exitCode = Number(process12.exitCode ?? 0);
|
|
3204
3204
|
if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
|
|
3205
3205
|
exitCode = 1;
|
|
3206
3206
|
}
|
|
@@ -3290,9 +3290,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3290
3290
|
});
|
|
3291
3291
|
}
|
|
3292
3292
|
function useColor() {
|
|
3293
|
-
if (
|
|
3293
|
+
if (process12.env.NO_COLOR || process12.env.FORCE_COLOR === "0" || process12.env.FORCE_COLOR === "false")
|
|
3294
3294
|
return false;
|
|
3295
|
-
if (
|
|
3295
|
+
if (process12.env.FORCE_COLOR || process12.env.CLICOLOR_FORCE !== void 0)
|
|
3296
3296
|
return true;
|
|
3297
3297
|
return void 0;
|
|
3298
3298
|
}
|
|
@@ -3323,6 +3323,9 @@ var require_commander = __commonJS({
|
|
|
3323
3323
|
}
|
|
3324
3324
|
});
|
|
3325
3325
|
|
|
3326
|
+
// src/index.ts
|
|
3327
|
+
var import_node_child_process3 = require("node:child_process");
|
|
3328
|
+
|
|
3326
3329
|
// ../../node_modules/commander/esm.mjs
|
|
3327
3330
|
var import_index = __toESM(require_commander(), 1);
|
|
3328
3331
|
var {
|
|
@@ -3340,6 +3343,55 @@ var {
|
|
|
3340
3343
|
Help
|
|
3341
3344
|
} = import_index.default;
|
|
3342
3345
|
|
|
3346
|
+
// package.json
|
|
3347
|
+
var package_default = {
|
|
3348
|
+
name: "@kimbho/kimbho-cli",
|
|
3349
|
+
version: "0.1.2",
|
|
3350
|
+
description: "Kimbho CLI is a terminal-native coding agent for planning, execution, and verification.",
|
|
3351
|
+
type: "module",
|
|
3352
|
+
engines: {
|
|
3353
|
+
node: ">=20.0.0"
|
|
3354
|
+
},
|
|
3355
|
+
preferGlobal: true,
|
|
3356
|
+
bin: {
|
|
3357
|
+
kimbho: "dist/index.cjs"
|
|
3358
|
+
},
|
|
3359
|
+
main: "dist/index.cjs",
|
|
3360
|
+
exports: {
|
|
3361
|
+
".": {
|
|
3362
|
+
default: "./dist/index.cjs"
|
|
3363
|
+
}
|
|
3364
|
+
},
|
|
3365
|
+
files: [
|
|
3366
|
+
"dist",
|
|
3367
|
+
"README.md"
|
|
3368
|
+
],
|
|
3369
|
+
publishConfig: {
|
|
3370
|
+
access: "public"
|
|
3371
|
+
},
|
|
3372
|
+
scripts: {
|
|
3373
|
+
build: "npm run clean && npm run build:bundle && npm run chmod:bin",
|
|
3374
|
+
"build:bundle": "esbuild src/index.ts --bundle --platform=node --format=cjs --sourcemap --outfile=dist/index.cjs --banner:js='#!/usr/bin/env node'",
|
|
3375
|
+
"chmod:bin": `node -e "require('node:fs').chmodSync('dist/index.cjs', 0o755)"`,
|
|
3376
|
+
clean: `node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"`,
|
|
3377
|
+
prepack: "npm run build"
|
|
3378
|
+
},
|
|
3379
|
+
dependencies: {
|
|
3380
|
+
commander: "^13.1.0"
|
|
3381
|
+
},
|
|
3382
|
+
devDependencies: {
|
|
3383
|
+
"@kimbho/agent-runtime": "file:../agent-runtime",
|
|
3384
|
+
"@kimbho/brains": "file:../brains",
|
|
3385
|
+
"@kimbho/core": "file:../core",
|
|
3386
|
+
"@kimbho/planner": "file:../planner",
|
|
3387
|
+
"@kimbho/tools": "file:../tools"
|
|
3388
|
+
}
|
|
3389
|
+
};
|
|
3390
|
+
|
|
3391
|
+
// src/metadata.ts
|
|
3392
|
+
var KIMBHO_VERSION = package_default.version;
|
|
3393
|
+
var KIMBHO_DESCRIPTION = "Kimbho CLI: a terminal-native coding agent for planning and execution.";
|
|
3394
|
+
|
|
3343
3395
|
// ../agent-runtime/dist/agents/catalog.js
|
|
3344
3396
|
var AGENT_CATALOG = {
|
|
3345
3397
|
"session-orchestrator": {
|
|
@@ -3510,6 +3562,10 @@ function listAgentProfiles() {
|
|
|
3510
3562
|
return Object.values(AGENT_CATALOG).sort((left, right) => left.role.localeCompare(right.role));
|
|
3511
3563
|
}
|
|
3512
3564
|
|
|
3565
|
+
// ../agent-runtime/dist/orchestrator.js
|
|
3566
|
+
var import_promises4 = require("node:fs/promises");
|
|
3567
|
+
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
3568
|
+
|
|
3513
3569
|
// ../../node_modules/zod/v3/external.js
|
|
3514
3570
|
var external_exports = {};
|
|
3515
3571
|
__export(external_exports, {
|
|
@@ -3988,8 +4044,8 @@ function getErrorMap() {
|
|
|
3988
4044
|
|
|
3989
4045
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
3990
4046
|
var makeIssue = (params) => {
|
|
3991
|
-
const { data, path:
|
|
3992
|
-
const fullPath = [...
|
|
4047
|
+
const { data, path: path6, errorMaps, issueData } = params;
|
|
4048
|
+
const fullPath = [...path6, ...issueData.path || []];
|
|
3993
4049
|
const fullIssue = {
|
|
3994
4050
|
...issueData,
|
|
3995
4051
|
path: fullPath
|
|
@@ -4105,11 +4161,11 @@ var errorUtil;
|
|
|
4105
4161
|
|
|
4106
4162
|
// ../../node_modules/zod/v3/types.js
|
|
4107
4163
|
var ParseInputLazyPath = class {
|
|
4108
|
-
constructor(parent, value,
|
|
4164
|
+
constructor(parent, value, path6, key) {
|
|
4109
4165
|
this._cachedPath = [];
|
|
4110
4166
|
this.parent = parent;
|
|
4111
4167
|
this.data = value;
|
|
4112
|
-
this._path =
|
|
4168
|
+
this._path = path6;
|
|
4113
4169
|
this._key = key;
|
|
4114
4170
|
}
|
|
4115
4171
|
get path() {
|
|
@@ -7759,6 +7815,16 @@ var KimbhoConfigSchema = external_exports.object({
|
|
|
7759
7815
|
}
|
|
7760
7816
|
});
|
|
7761
7817
|
|
|
7818
|
+
// ../core/dist/contracts/execution.js
|
|
7819
|
+
var ToolResultSchema = external_exports.object({
|
|
7820
|
+
toolId: external_exports.string().min(1),
|
|
7821
|
+
success: external_exports.boolean(),
|
|
7822
|
+
summary: external_exports.string().min(1),
|
|
7823
|
+
stdout: external_exports.string().optional(),
|
|
7824
|
+
stderr: external_exports.string().optional(),
|
|
7825
|
+
artifacts: external_exports.array(external_exports.string()).default([])
|
|
7826
|
+
});
|
|
7827
|
+
|
|
7762
7828
|
// ../core/dist/contracts/session.js
|
|
7763
7829
|
var SessionStatusSchema = external_exports.enum([
|
|
7764
7830
|
"planned",
|
|
@@ -7767,6 +7833,22 @@ var SessionStatusSchema = external_exports.enum([
|
|
|
7767
7833
|
"blocked",
|
|
7768
7834
|
"completed"
|
|
7769
7835
|
]);
|
|
7836
|
+
var SessionEventTypeSchema = external_exports.enum([
|
|
7837
|
+
"task-started",
|
|
7838
|
+
"task-completed",
|
|
7839
|
+
"task-blocked",
|
|
7840
|
+
"note"
|
|
7841
|
+
]);
|
|
7842
|
+
var SessionEventSchema = external_exports.object({
|
|
7843
|
+
id: external_exports.string().min(1),
|
|
7844
|
+
timestamp: external_exports.string().datetime(),
|
|
7845
|
+
type: SessionEventTypeSchema,
|
|
7846
|
+
taskId: external_exports.string().min(1).optional(),
|
|
7847
|
+
agentRole: AgentRoleSchema.optional(),
|
|
7848
|
+
message: external_exports.string().min(1),
|
|
7849
|
+
toolResults: external_exports.array(ToolResultSchema).default([]),
|
|
7850
|
+
artifacts: external_exports.array(external_exports.string()).default([])
|
|
7851
|
+
});
|
|
7770
7852
|
var SessionSnapshotSchema = external_exports.object({
|
|
7771
7853
|
id: external_exports.string().min(1),
|
|
7772
7854
|
goal: external_exports.string().min(1),
|
|
@@ -7778,8 +7860,10 @@ var SessionSnapshotSchema = external_exports.object({
|
|
|
7778
7860
|
plan: KimbhoPlanSchema,
|
|
7779
7861
|
readyTaskIds: external_exports.array(external_exports.string()).default([]),
|
|
7780
7862
|
blockedTaskIds: external_exports.array(external_exports.string()).default([]),
|
|
7863
|
+
completedTaskIds: external_exports.array(external_exports.string()).default([]),
|
|
7781
7864
|
assignedAgents: external_exports.array(AgentRoleSchema).default([]),
|
|
7782
|
-
notes: external_exports.array(external_exports.string()).default([])
|
|
7865
|
+
notes: external_exports.array(external_exports.string()).default([]),
|
|
7866
|
+
events: external_exports.array(SessionEventSchema).default([])
|
|
7783
7867
|
});
|
|
7784
7868
|
|
|
7785
7869
|
// ../core/dist/config/config.js
|
|
@@ -8067,14 +8151,6 @@ var ToolDescriptorSchema = external_exports.object({
|
|
|
8067
8151
|
producesArtifacts: external_exports.boolean().default(false),
|
|
8068
8152
|
allowedRoles: external_exports.array(AgentRoleSchema).default([])
|
|
8069
8153
|
});
|
|
8070
|
-
var ToolResultSchema = external_exports.object({
|
|
8071
|
-
toolId: external_exports.string().min(1),
|
|
8072
|
-
success: external_exports.boolean(),
|
|
8073
|
-
summary: external_exports.string().min(1),
|
|
8074
|
-
stdout: external_exports.string().optional(),
|
|
8075
|
-
stderr: external_exports.string().optional(),
|
|
8076
|
-
artifacts: external_exports.array(external_exports.string()).default([])
|
|
8077
|
-
});
|
|
8078
8154
|
|
|
8079
8155
|
// ../tools/dist/registry.js
|
|
8080
8156
|
var BUILTIN_TOOLS = [
|
|
@@ -8184,26 +8260,296 @@ function createDefaultToolRegistry() {
|
|
|
8184
8260
|
return new ToolRegistry(BUILTIN_TOOLS);
|
|
8185
8261
|
}
|
|
8186
8262
|
|
|
8263
|
+
// ../tools/dist/runtime.js
|
|
8264
|
+
var import_promises3 = require("node:fs/promises");
|
|
8265
|
+
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
8266
|
+
var import_node_process = __toESM(require("node:process"), 1);
|
|
8267
|
+
var import_node_child_process = require("node:child_process");
|
|
8268
|
+
var import_node_os = require("node:os");
|
|
8269
|
+
var DEFAULT_CAPTURE_LIMIT = 16e3;
|
|
8270
|
+
function truncateOutput(value) {
|
|
8271
|
+
if (!value) {
|
|
8272
|
+
return value;
|
|
8273
|
+
}
|
|
8274
|
+
if (value.length <= DEFAULT_CAPTURE_LIMIT) {
|
|
8275
|
+
return value;
|
|
8276
|
+
}
|
|
8277
|
+
const omitted = value.length - DEFAULT_CAPTURE_LIMIT;
|
|
8278
|
+
return `${value.slice(0, DEFAULT_CAPTURE_LIMIT)}
|
|
8279
|
+
... [truncated ${omitted} chars]`;
|
|
8280
|
+
}
|
|
8281
|
+
function resolveWorkspacePath(cwd, filePath) {
|
|
8282
|
+
const resolved = import_node_path3.default.resolve(cwd, filePath);
|
|
8283
|
+
const relative = import_node_path3.default.relative(cwd, resolved);
|
|
8284
|
+
if (relative.startsWith("..") || import_node_path3.default.isAbsolute(relative)) {
|
|
8285
|
+
throw new Error(`Path "${filePath}" escapes the workspace.`);
|
|
8286
|
+
}
|
|
8287
|
+
return resolved;
|
|
8288
|
+
}
|
|
8289
|
+
async function runSpawn(command, args, cwd, timeoutMs) {
|
|
8290
|
+
return new Promise((resolve, reject) => {
|
|
8291
|
+
const child = (0, import_node_child_process.spawn)(command, args, {
|
|
8292
|
+
cwd,
|
|
8293
|
+
env: import_node_process.default.env,
|
|
8294
|
+
stdio: [
|
|
8295
|
+
"ignore",
|
|
8296
|
+
"pipe",
|
|
8297
|
+
"pipe"
|
|
8298
|
+
]
|
|
8299
|
+
});
|
|
8300
|
+
const stdout = [];
|
|
8301
|
+
const stderr = [];
|
|
8302
|
+
let settled = false;
|
|
8303
|
+
let timedOut = false;
|
|
8304
|
+
const timer = setTimeout(() => {
|
|
8305
|
+
timedOut = true;
|
|
8306
|
+
child.kill("SIGTERM");
|
|
8307
|
+
setTimeout(() => child.kill("SIGKILL"), 1e3).unref();
|
|
8308
|
+
}, timeoutMs);
|
|
8309
|
+
child.stdout.on("data", (chunk) => {
|
|
8310
|
+
stdout.push(String(chunk));
|
|
8311
|
+
});
|
|
8312
|
+
child.stderr.on("data", (chunk) => {
|
|
8313
|
+
stderr.push(String(chunk));
|
|
8314
|
+
});
|
|
8315
|
+
child.on("error", (error) => {
|
|
8316
|
+
if (settled) {
|
|
8317
|
+
return;
|
|
8318
|
+
}
|
|
8319
|
+
settled = true;
|
|
8320
|
+
clearTimeout(timer);
|
|
8321
|
+
reject(error);
|
|
8322
|
+
});
|
|
8323
|
+
child.on("close", (code) => {
|
|
8324
|
+
if (settled) {
|
|
8325
|
+
return;
|
|
8326
|
+
}
|
|
8327
|
+
settled = true;
|
|
8328
|
+
clearTimeout(timer);
|
|
8329
|
+
resolve({
|
|
8330
|
+
code,
|
|
8331
|
+
stdout: stdout.join(""),
|
|
8332
|
+
stderr: stderr.join(""),
|
|
8333
|
+
timedOut
|
|
8334
|
+
});
|
|
8335
|
+
});
|
|
8336
|
+
});
|
|
8337
|
+
}
|
|
8338
|
+
async function runShellCommand(toolId, command, cwd, timeoutMs) {
|
|
8339
|
+
const shell = import_node_process.default.env.SHELL ?? "/bin/sh";
|
|
8340
|
+
const result = await runSpawn(shell, [
|
|
8341
|
+
"-lc",
|
|
8342
|
+
command
|
|
8343
|
+
], cwd, timeoutMs);
|
|
8344
|
+
const success = !result.timedOut && result.code === 0;
|
|
8345
|
+
const summary = result.timedOut ? `Command timed out after ${timeoutMs}ms.` : success ? `Command completed successfully.` : `Command exited with code ${result.code ?? "unknown"}.`;
|
|
8346
|
+
return ToolResultSchema.parse({
|
|
8347
|
+
toolId,
|
|
8348
|
+
success,
|
|
8349
|
+
summary,
|
|
8350
|
+
stdout: truncateOutput(result.stdout),
|
|
8351
|
+
stderr: truncateOutput(result.stderr)
|
|
8352
|
+
});
|
|
8353
|
+
}
|
|
8354
|
+
async function executeFileRead(input, context) {
|
|
8355
|
+
const rawPath = typeof input.path === "string" ? input.path : null;
|
|
8356
|
+
if (!rawPath) {
|
|
8357
|
+
throw new Error("file.read requires a string path.");
|
|
8358
|
+
}
|
|
8359
|
+
const targetPath = resolveWorkspacePath(context.cwd, rawPath);
|
|
8360
|
+
const contents = await (0, import_promises3.readFile)(targetPath, "utf8");
|
|
8361
|
+
return ToolResultSchema.parse({
|
|
8362
|
+
toolId: "file.read",
|
|
8363
|
+
success: true,
|
|
8364
|
+
summary: `Read ${import_node_path3.default.relative(context.cwd, targetPath) || import_node_path3.default.basename(targetPath)}.`,
|
|
8365
|
+
stdout: truncateOutput(contents),
|
|
8366
|
+
artifacts: [
|
|
8367
|
+
targetPath
|
|
8368
|
+
]
|
|
8369
|
+
});
|
|
8370
|
+
}
|
|
8371
|
+
async function executeShell(input, context, timeoutMs) {
|
|
8372
|
+
const command = typeof input.command === "string" ? input.command : null;
|
|
8373
|
+
if (!command) {
|
|
8374
|
+
throw new Error("shell.exec requires a command string.");
|
|
8375
|
+
}
|
|
8376
|
+
return runShellCommand("shell.exec", command, context.cwd, timeoutMs);
|
|
8377
|
+
}
|
|
8378
|
+
async function executeGitStatus(_input, context, timeoutMs) {
|
|
8379
|
+
return runShellCommand("git.status", "git status --short --branch", context.cwd, timeoutMs);
|
|
8380
|
+
}
|
|
8381
|
+
async function executeTests(input, context, timeoutMs) {
|
|
8382
|
+
const command = typeof input.command === "string" && input.command.trim().length > 0 ? input.command : "npm test";
|
|
8383
|
+
const result = await runShellCommand("tests.run", command, context.cwd, timeoutMs);
|
|
8384
|
+
return ToolResultSchema.parse({
|
|
8385
|
+
...result,
|
|
8386
|
+
summary: result.success ? `Verification command passed: ${command}` : `Verification command failed: ${command}`
|
|
8387
|
+
});
|
|
8388
|
+
}
|
|
8389
|
+
async function executeFilePatch(input, context, timeoutMs) {
|
|
8390
|
+
const patch = typeof input.patch === "string" ? input.patch : null;
|
|
8391
|
+
if (!patch) {
|
|
8392
|
+
throw new Error("file.patch requires a unified diff in the patch field.");
|
|
8393
|
+
}
|
|
8394
|
+
const tempDir = await (0, import_promises3.mkdtemp)(import_node_path3.default.join((0, import_node_os.tmpdir)(), "kimbho-patch-"));
|
|
8395
|
+
const patchPath = import_node_path3.default.join(tempDir, "change.patch");
|
|
8396
|
+
try {
|
|
8397
|
+
await (0, import_promises3.writeFile)(patchPath, patch, "utf8");
|
|
8398
|
+
const result = await runSpawn("git", [
|
|
8399
|
+
"apply",
|
|
8400
|
+
"--recount",
|
|
8401
|
+
"--whitespace=nowarn",
|
|
8402
|
+
patchPath
|
|
8403
|
+
], context.cwd, timeoutMs);
|
|
8404
|
+
const success = !result.timedOut && result.code === 0;
|
|
8405
|
+
return ToolResultSchema.parse({
|
|
8406
|
+
toolId: "file.patch",
|
|
8407
|
+
success,
|
|
8408
|
+
summary: success ? "Patch applied successfully." : result.timedOut ? `Patch timed out after ${timeoutMs}ms.` : `Patch failed with code ${result.code ?? "unknown"}.`,
|
|
8409
|
+
stdout: truncateOutput(result.stdout),
|
|
8410
|
+
stderr: truncateOutput(result.stderr),
|
|
8411
|
+
artifacts: []
|
|
8412
|
+
});
|
|
8413
|
+
} finally {
|
|
8414
|
+
await (0, import_promises3.rm)(tempDir, { recursive: true, force: true });
|
|
8415
|
+
}
|
|
8416
|
+
}
|
|
8417
|
+
var ToolRuntime = class {
|
|
8418
|
+
registry;
|
|
8419
|
+
executors;
|
|
8420
|
+
constructor(registry = createDefaultToolRegistry()) {
|
|
8421
|
+
this.registry = registry;
|
|
8422
|
+
this.executors = /* @__PURE__ */ new Map([
|
|
8423
|
+
[
|
|
8424
|
+
"file.read",
|
|
8425
|
+
(input, context) => executeFileRead(input, context)
|
|
8426
|
+
],
|
|
8427
|
+
[
|
|
8428
|
+
"file.patch",
|
|
8429
|
+
executeFilePatch
|
|
8430
|
+
],
|
|
8431
|
+
[
|
|
8432
|
+
"shell.exec",
|
|
8433
|
+
executeShell
|
|
8434
|
+
],
|
|
8435
|
+
[
|
|
8436
|
+
"git.status",
|
|
8437
|
+
executeGitStatus
|
|
8438
|
+
],
|
|
8439
|
+
[
|
|
8440
|
+
"tests.run",
|
|
8441
|
+
executeTests
|
|
8442
|
+
]
|
|
8443
|
+
]);
|
|
8444
|
+
}
|
|
8445
|
+
async run(toolId, input, context) {
|
|
8446
|
+
const descriptor = this.registry.get(toolId);
|
|
8447
|
+
if (!descriptor) {
|
|
8448
|
+
throw new Error(`Unknown tool "${toolId}".`);
|
|
8449
|
+
}
|
|
8450
|
+
const executor = this.executors.get(toolId);
|
|
8451
|
+
if (!executor) {
|
|
8452
|
+
throw new Error(`No executor registered for "${toolId}".`);
|
|
8453
|
+
}
|
|
8454
|
+
return executor(input, context, descriptor.timeoutMs);
|
|
8455
|
+
}
|
|
8456
|
+
};
|
|
8457
|
+
|
|
8187
8458
|
// ../agent-runtime/dist/orchestrator.js
|
|
8188
8459
|
function createSessionId() {
|
|
8189
8460
|
return `session-${Date.now()}`;
|
|
8190
8461
|
}
|
|
8462
|
+
function createEventId(type, taskId) {
|
|
8463
|
+
return `${type}-${taskId ?? "session"}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
8464
|
+
}
|
|
8191
8465
|
function isTaskReady(task, completedTaskIds) {
|
|
8192
8466
|
return task.status === "pending" && task.dependsOn.every((taskId) => completedTaskIds.has(taskId));
|
|
8193
8467
|
}
|
|
8468
|
+
function completedTaskIdsFromPlan(plan) {
|
|
8469
|
+
return new Set(flattenPlanTasks(plan).filter((task) => task.status === "completed").map((task) => task.id));
|
|
8470
|
+
}
|
|
8471
|
+
function deriveStatus(plan, readyTasks, blockedTasks) {
|
|
8472
|
+
const tasks = flattenPlanTasks(plan);
|
|
8473
|
+
const completed = tasks.filter((task) => task.status === "completed").length;
|
|
8474
|
+
if (completed === tasks.length && tasks.length > 0) {
|
|
8475
|
+
return "completed";
|
|
8476
|
+
}
|
|
8477
|
+
if (readyTasks.length > 0) {
|
|
8478
|
+
return completed > 0 ? "running" : "ready";
|
|
8479
|
+
}
|
|
8480
|
+
if (blockedTasks.length > 0) {
|
|
8481
|
+
return "blocked";
|
|
8482
|
+
}
|
|
8483
|
+
return "planned";
|
|
8484
|
+
}
|
|
8485
|
+
function updateTaskStatus(plan, taskId, status) {
|
|
8486
|
+
const milestones = plan.milestones.map((milestone) => ({
|
|
8487
|
+
...milestone,
|
|
8488
|
+
tasks: milestone.tasks.map((task) => task.id === taskId ? {
|
|
8489
|
+
...task,
|
|
8490
|
+
status
|
|
8491
|
+
} : task)
|
|
8492
|
+
}));
|
|
8493
|
+
return {
|
|
8494
|
+
...plan,
|
|
8495
|
+
milestones
|
|
8496
|
+
};
|
|
8497
|
+
}
|
|
8498
|
+
function maybeAppendNote(notes, note) {
|
|
8499
|
+
return notes.at(-1) === note ? notes : [
|
|
8500
|
+
...notes,
|
|
8501
|
+
note
|
|
8502
|
+
];
|
|
8503
|
+
}
|
|
8504
|
+
function renderToolResultSection(results) {
|
|
8505
|
+
return results.map((result) => {
|
|
8506
|
+
const lines = [
|
|
8507
|
+
`## ${result.toolId}`,
|
|
8508
|
+
`- success: ${result.success ? "yes" : "no"}`,
|
|
8509
|
+
`- summary: ${result.summary}`
|
|
8510
|
+
];
|
|
8511
|
+
if (result.stdout) {
|
|
8512
|
+
lines.push("");
|
|
8513
|
+
lines.push("```text");
|
|
8514
|
+
lines.push(result.stdout);
|
|
8515
|
+
lines.push("```");
|
|
8516
|
+
}
|
|
8517
|
+
if (result.stderr) {
|
|
8518
|
+
lines.push("");
|
|
8519
|
+
lines.push("```text");
|
|
8520
|
+
lines.push(result.stderr);
|
|
8521
|
+
lines.push("```");
|
|
8522
|
+
}
|
|
8523
|
+
return lines.join("\n");
|
|
8524
|
+
}).join("\n\n");
|
|
8525
|
+
}
|
|
8526
|
+
function extractPackageScripts(toolResults) {
|
|
8527
|
+
const packageResult = toolResults.find((result) => result.artifacts.some((artifact) => artifact.endsWith("package.json")) && result.stdout);
|
|
8528
|
+
if (!packageResult?.stdout) {
|
|
8529
|
+
return [];
|
|
8530
|
+
}
|
|
8531
|
+
try {
|
|
8532
|
+
const parsed = JSON.parse(packageResult.stdout);
|
|
8533
|
+
return Object.keys(parsed.scripts ?? {}).sort();
|
|
8534
|
+
} catch {
|
|
8535
|
+
return [];
|
|
8536
|
+
}
|
|
8537
|
+
}
|
|
8194
8538
|
var ExecutionOrchestrator = class {
|
|
8195
8539
|
toolRegistry;
|
|
8196
|
-
|
|
8540
|
+
toolRuntime;
|
|
8541
|
+
constructor(toolRegistry = createDefaultToolRegistry(), toolRuntime = new ToolRuntime(toolRegistry)) {
|
|
8197
8542
|
this.toolRegistry = toolRegistry;
|
|
8543
|
+
this.toolRuntime = toolRuntime;
|
|
8198
8544
|
}
|
|
8199
|
-
buildEnvelope(request, plan) {
|
|
8545
|
+
buildEnvelope(request, plan, sessionId = createSessionId()) {
|
|
8200
8546
|
const tasks = flattenPlanTasks(plan);
|
|
8201
|
-
const completedTaskIds =
|
|
8547
|
+
const completedTaskIds = completedTaskIdsFromPlan(plan);
|
|
8202
8548
|
const readyTasks = tasks.filter((task) => isTaskReady(task, completedTaskIds));
|
|
8203
8549
|
const blockedTasks = tasks.filter((task) => task.status !== "completed" && !isTaskReady(task, completedTaskIds));
|
|
8204
8550
|
const assignedAgents = this.selectAgentsForTasks(readyTasks);
|
|
8205
8551
|
return {
|
|
8206
|
-
sessionId
|
|
8552
|
+
sessionId,
|
|
8207
8553
|
request,
|
|
8208
8554
|
plan,
|
|
8209
8555
|
readyTasks,
|
|
@@ -8211,9 +8557,9 @@ var ExecutionOrchestrator = class {
|
|
|
8211
8557
|
assignedAgents
|
|
8212
8558
|
};
|
|
8213
8559
|
}
|
|
8214
|
-
createSessionSnapshot(envelope) {
|
|
8560
|
+
createSessionSnapshot(envelope, overrides = {}) {
|
|
8215
8561
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
8216
|
-
const status = envelope.readyTasks.
|
|
8562
|
+
const status = deriveStatus(envelope.plan, envelope.readyTasks, envelope.blockedTasks);
|
|
8217
8563
|
return SessionSnapshotSchema.parse({
|
|
8218
8564
|
id: envelope.sessionId,
|
|
8219
8565
|
goal: envelope.request.goal,
|
|
@@ -8225,11 +8571,75 @@ var ExecutionOrchestrator = class {
|
|
|
8225
8571
|
plan: envelope.plan,
|
|
8226
8572
|
readyTaskIds: envelope.readyTasks.map((task) => task.id),
|
|
8227
8573
|
blockedTaskIds: envelope.blockedTasks.map((task) => task.id),
|
|
8574
|
+
completedTaskIds: Array.from(completedTaskIdsFromPlan(envelope.plan)),
|
|
8228
8575
|
assignedAgents: envelope.assignedAgents.map((agent) => agent.role),
|
|
8229
8576
|
notes: [
|
|
8230
|
-
"Initial session snapshot created from the current plan."
|
|
8231
|
-
|
|
8232
|
-
]
|
|
8577
|
+
"Initial session snapshot created from the current plan."
|
|
8578
|
+
],
|
|
8579
|
+
events: [],
|
|
8580
|
+
...overrides
|
|
8581
|
+
});
|
|
8582
|
+
}
|
|
8583
|
+
async continueSession(session, options = {}) {
|
|
8584
|
+
let workingPlan = session.plan;
|
|
8585
|
+
let notes = [
|
|
8586
|
+
...session.notes
|
|
8587
|
+
];
|
|
8588
|
+
let events = [
|
|
8589
|
+
...session.events
|
|
8590
|
+
];
|
|
8591
|
+
const maxAutoTasks = options.maxAutoTasks ?? 2;
|
|
8592
|
+
let executedTasks = 0;
|
|
8593
|
+
while (executedTasks < maxAutoTasks) {
|
|
8594
|
+
const envelope = this.buildEnvelope(session.request, workingPlan, session.id);
|
|
8595
|
+
const autoTask = envelope.readyTasks.find((task) => this.canAutoExecuteTask(task));
|
|
8596
|
+
if (!autoTask) {
|
|
8597
|
+
const nextTask = envelope.readyTasks[0];
|
|
8598
|
+
if (nextTask) {
|
|
8599
|
+
const note = `Execution paused at ${nextTask.id} (${nextTask.title}): no built-in executor is wired for ${nextTask.agentRole} yet.`;
|
|
8600
|
+
notes = maybeAppendNote(notes, note);
|
|
8601
|
+
}
|
|
8602
|
+
return this.createSessionSnapshot(this.buildEnvelope(session.request, workingPlan, session.id), {
|
|
8603
|
+
startedAt: session.startedAt,
|
|
8604
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8605
|
+
notes,
|
|
8606
|
+
events
|
|
8607
|
+
});
|
|
8608
|
+
}
|
|
8609
|
+
events.push({
|
|
8610
|
+
id: createEventId("task-started", autoTask.id),
|
|
8611
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8612
|
+
type: "task-started",
|
|
8613
|
+
taskId: autoTask.id,
|
|
8614
|
+
agentRole: autoTask.agentRole,
|
|
8615
|
+
message: `Started ${autoTask.id}: ${autoTask.title}`,
|
|
8616
|
+
toolResults: [],
|
|
8617
|
+
artifacts: []
|
|
8618
|
+
});
|
|
8619
|
+
const outcome = await this.executeTask(session.id, autoTask, session.request, workingPlan);
|
|
8620
|
+
workingPlan = updateTaskStatus(workingPlan, autoTask.id, outcome.status === "completed" ? "completed" : "blocked");
|
|
8621
|
+
notes = maybeAppendNote(notes, outcome.summary);
|
|
8622
|
+
events.push({
|
|
8623
|
+
id: createEventId(outcome.status === "completed" ? "task-completed" : "task-blocked", autoTask.id),
|
|
8624
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8625
|
+
type: outcome.status === "completed" ? "task-completed" : "task-blocked",
|
|
8626
|
+
taskId: autoTask.id,
|
|
8627
|
+
agentRole: autoTask.agentRole,
|
|
8628
|
+
message: outcome.summary,
|
|
8629
|
+
toolResults: outcome.toolResults,
|
|
8630
|
+
artifacts: outcome.artifacts
|
|
8631
|
+
});
|
|
8632
|
+
executedTasks += 1;
|
|
8633
|
+
}
|
|
8634
|
+
const postLimitEnvelope = this.buildEnvelope(session.request, workingPlan, session.id);
|
|
8635
|
+
if (postLimitEnvelope.readyTasks.length > 0) {
|
|
8636
|
+
notes = maybeAppendNote(notes, `Auto execution limit reached after ${executedTasks} task${executedTasks === 1 ? "" : "s"}.`);
|
|
8637
|
+
}
|
|
8638
|
+
return this.createSessionSnapshot(postLimitEnvelope, {
|
|
8639
|
+
startedAt: session.startedAt,
|
|
8640
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8641
|
+
notes,
|
|
8642
|
+
events
|
|
8233
8643
|
});
|
|
8234
8644
|
}
|
|
8235
8645
|
selectAgentsForTasks(tasks) {
|
|
@@ -8239,6 +8649,107 @@ var ExecutionOrchestrator = class {
|
|
|
8239
8649
|
toolsForAgent(role) {
|
|
8240
8650
|
return this.toolRegistry.byRole(role);
|
|
8241
8651
|
}
|
|
8652
|
+
canAutoExecuteTask(task) {
|
|
8653
|
+
return task.agentRole === "repo-analyst" || task.agentRole === "planner";
|
|
8654
|
+
}
|
|
8655
|
+
async executeTask(sessionId, task, request, plan) {
|
|
8656
|
+
if (task.agentRole === "repo-analyst") {
|
|
8657
|
+
return this.executeRepoAnalysisTask(sessionId, task, request);
|
|
8658
|
+
}
|
|
8659
|
+
if (task.agentRole === "planner") {
|
|
8660
|
+
return this.executePlannerTask(sessionId, task, request, plan);
|
|
8661
|
+
}
|
|
8662
|
+
return {
|
|
8663
|
+
status: "blocked",
|
|
8664
|
+
summary: `Task ${task.id} is ready, but no executor is available for ${task.agentRole}.`,
|
|
8665
|
+
toolResults: [],
|
|
8666
|
+
artifacts: []
|
|
8667
|
+
};
|
|
8668
|
+
}
|
|
8669
|
+
async executeRepoAnalysisTask(sessionId, task, request) {
|
|
8670
|
+
const context = { cwd: request.cwd };
|
|
8671
|
+
const toolResults = await Promise.all([
|
|
8672
|
+
this.safeRunTool("git.status", {}, context),
|
|
8673
|
+
this.safeRunTool("file.read", { path: "package.json" }, context),
|
|
8674
|
+
this.safeRunTool("file.read", { path: "README.md" }, context)
|
|
8675
|
+
]);
|
|
8676
|
+
const successfulResults = toolResults.filter((result) => result.success);
|
|
8677
|
+
const scripts = extractPackageScripts(successfulResults);
|
|
8678
|
+
const artifactPath = await this.writeLogArtifact(sessionId, "repo-analysis", request.cwd, [
|
|
8679
|
+
`# Repo Analysis`,
|
|
8680
|
+
``,
|
|
8681
|
+
`Goal: ${request.goal}`,
|
|
8682
|
+
`Workspace: ${request.cwd}`,
|
|
8683
|
+
`Task: ${task.id} - ${task.title}`,
|
|
8684
|
+
``,
|
|
8685
|
+
`## Observations`,
|
|
8686
|
+
`- Successful tool probes: ${successfulResults.length}/${toolResults.length}`,
|
|
8687
|
+
`- Workspace state: ${request.workspaceState}`,
|
|
8688
|
+
`- Detected scripts: ${scripts.length > 0 ? scripts.join(", ") : "none"}`,
|
|
8689
|
+
``,
|
|
8690
|
+
renderToolResultSection(toolResults)
|
|
8691
|
+
].join("\n"));
|
|
8692
|
+
return {
|
|
8693
|
+
status: "completed",
|
|
8694
|
+
summary: `Completed ${task.id}: captured repo analysis and saved ${import_node_path4.default.basename(artifactPath)}.`,
|
|
8695
|
+
toolResults,
|
|
8696
|
+
artifacts: [
|
|
8697
|
+
artifactPath
|
|
8698
|
+
]
|
|
8699
|
+
};
|
|
8700
|
+
}
|
|
8701
|
+
async executePlannerTask(sessionId, task, request, plan) {
|
|
8702
|
+
const artifactPath = await this.writeLogArtifact(sessionId, "architecture-brief", request.cwd, [
|
|
8703
|
+
`# Architecture Brief`,
|
|
8704
|
+
``,
|
|
8705
|
+
`Goal: ${request.goal}`,
|
|
8706
|
+
`Summary: ${plan.summary}`,
|
|
8707
|
+
`Repo Strategy: ${plan.repoStrategy.mode} - ${plan.repoStrategy.reasoning}`,
|
|
8708
|
+
``,
|
|
8709
|
+
`## Assumptions`,
|
|
8710
|
+
...plan.assumptions.map((assumption) => `- ${assumption}`),
|
|
8711
|
+
``,
|
|
8712
|
+
`## Milestones`,
|
|
8713
|
+
...plan.milestones.flatMap((milestone) => [
|
|
8714
|
+
`### ${milestone.title}`,
|
|
8715
|
+
milestone.objective,
|
|
8716
|
+
...milestone.tasks.map((milestoneTask) => `- ${milestoneTask.id}: ${milestoneTask.title} [${milestoneTask.agentRole}]`),
|
|
8717
|
+
``
|
|
8718
|
+
]),
|
|
8719
|
+
`## Verification`,
|
|
8720
|
+
...plan.verificationChecklist.map((item) => `- ${item}`)
|
|
8721
|
+
].join("\n"));
|
|
8722
|
+
return {
|
|
8723
|
+
status: "completed",
|
|
8724
|
+
summary: `Completed ${task.id}: wrote architecture brief ${import_node_path4.default.basename(artifactPath)}.`,
|
|
8725
|
+
toolResults: [],
|
|
8726
|
+
artifacts: [
|
|
8727
|
+
artifactPath
|
|
8728
|
+
]
|
|
8729
|
+
};
|
|
8730
|
+
}
|
|
8731
|
+
async safeRunTool(toolId, input, context) {
|
|
8732
|
+
try {
|
|
8733
|
+
return await this.toolRuntime.run(toolId, input, context);
|
|
8734
|
+
} catch (error) {
|
|
8735
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8736
|
+
return {
|
|
8737
|
+
toolId,
|
|
8738
|
+
success: false,
|
|
8739
|
+
summary: `${toolId} failed: ${message}`,
|
|
8740
|
+
stderr: message,
|
|
8741
|
+
artifacts: []
|
|
8742
|
+
};
|
|
8743
|
+
}
|
|
8744
|
+
}
|
|
8745
|
+
async writeLogArtifact(sessionId, label, cwd, content) {
|
|
8746
|
+
await ensureKimbhoDir(cwd);
|
|
8747
|
+
const logsDir = import_node_path4.default.join(resolveKimbhoDir(cwd), "logs");
|
|
8748
|
+
const outputPath = import_node_path4.default.join(logsDir, `${sessionId}-${label}.md`);
|
|
8749
|
+
await (0, import_promises4.writeFile)(outputPath, `${content}
|
|
8750
|
+
`, "utf8");
|
|
8751
|
+
return outputPath;
|
|
8752
|
+
}
|
|
8242
8753
|
};
|
|
8243
8754
|
|
|
8244
8755
|
// src/commands/agents.ts
|
|
@@ -8264,7 +8775,7 @@ function createAgentsCommand() {
|
|
|
8264
8775
|
}
|
|
8265
8776
|
|
|
8266
8777
|
// src/commands/brains.ts
|
|
8267
|
-
var
|
|
8778
|
+
var import_node_process2 = __toESM(require("node:process"), 1);
|
|
8268
8779
|
|
|
8269
8780
|
// ../brains/dist/templates.js
|
|
8270
8781
|
var BUILTIN_PROVIDER_TEMPLATES = [
|
|
@@ -8340,8 +8851,8 @@ function buildProviderFromTemplate(templateId, options = {}) {
|
|
|
8340
8851
|
}
|
|
8341
8852
|
|
|
8342
8853
|
// ../brains/dist/registry.js
|
|
8343
|
-
var
|
|
8344
|
-
var
|
|
8854
|
+
var import_promises5 = require("node:fs/promises");
|
|
8855
|
+
var import_node_path5 = __toESM(require("node:path"), 1);
|
|
8345
8856
|
var import_node_url = require("node:url");
|
|
8346
8857
|
function resolveApiKey(definition) {
|
|
8347
8858
|
if (!definition.apiKeyEnv) {
|
|
@@ -8779,8 +9290,8 @@ async function createCustomModuleProvider(definition, cwd) {
|
|
|
8779
9290
|
if (!definition.modulePath) {
|
|
8780
9291
|
throw new Error(`Provider "${definition.id}" requires modulePath.`);
|
|
8781
9292
|
}
|
|
8782
|
-
const modulePath =
|
|
8783
|
-
await (0,
|
|
9293
|
+
const modulePath = import_node_path5.default.isAbsolute(definition.modulePath) ? definition.modulePath : import_node_path5.default.join(cwd, definition.modulePath);
|
|
9294
|
+
await (0, import_promises5.access)(modulePath);
|
|
8784
9295
|
const module2 = await import((0, import_node_url.pathToFileURL)(modulePath).href);
|
|
8785
9296
|
const createProvider = typeof module2.createProvider === "function" ? module2.createProvider : typeof module2.default === "function" ? module2.default : null;
|
|
8786
9297
|
if (!createProvider) {
|
|
@@ -8929,6 +9440,40 @@ function renderPlan(plan) {
|
|
|
8929
9440
|
function renderJson(value) {
|
|
8930
9441
|
return JSON.stringify(value, null, 2);
|
|
8931
9442
|
}
|
|
9443
|
+
function renderSession(session) {
|
|
9444
|
+
const taskCounts = countTasksByStatus(session.plan);
|
|
9445
|
+
const lines = [
|
|
9446
|
+
`Session: ${session.id}`,
|
|
9447
|
+
`Goal: ${session.goal}`,
|
|
9448
|
+
`Status: ${session.status}`,
|
|
9449
|
+
`Tasks: ${flattenPlanTasks(session.plan).length} total | completed ${taskCounts.completed} | pending ${taskCounts.pending} | blocked ${taskCounts.blocked}`,
|
|
9450
|
+
`Assigned agents: ${session.assignedAgents.join(", ") || "none"}`,
|
|
9451
|
+
`Ready tasks: ${session.readyTaskIds.join(", ") || "none"}`,
|
|
9452
|
+
`Blocked tasks: ${session.blockedTaskIds.join(", ") || "none"}`
|
|
9453
|
+
];
|
|
9454
|
+
if (session.notes.length > 0) {
|
|
9455
|
+
lines.push("");
|
|
9456
|
+
lines.push("Notes:");
|
|
9457
|
+
for (const note of session.notes.slice(-5)) {
|
|
9458
|
+
lines.push(`- ${note}`);
|
|
9459
|
+
}
|
|
9460
|
+
}
|
|
9461
|
+
if (session.events.length > 0) {
|
|
9462
|
+
lines.push("");
|
|
9463
|
+
lines.push("Recent Events:");
|
|
9464
|
+
for (const event of session.events.slice(-5)) {
|
|
9465
|
+
const target = event.taskId ? `${event.taskId}` : "session";
|
|
9466
|
+
lines.push(`- ${event.type} | ${target} | ${event.message}`);
|
|
9467
|
+
for (const artifact of event.artifacts) {
|
|
9468
|
+
lines.push(` artifact: ${artifact}`);
|
|
9469
|
+
}
|
|
9470
|
+
for (const toolResult of event.toolResults) {
|
|
9471
|
+
lines.push(` tool: ${toolResult.toolId} | ${toolResult.success ? "ok" : "fail"} | ${toolResult.summary}`);
|
|
9472
|
+
}
|
|
9473
|
+
}
|
|
9474
|
+
}
|
|
9475
|
+
return lines.join("\n");
|
|
9476
|
+
}
|
|
8932
9477
|
|
|
8933
9478
|
// src/commands/brains.ts
|
|
8934
9479
|
function parseNumber(value) {
|
|
@@ -8944,7 +9489,7 @@ function requireConfigMessage() {
|
|
|
8944
9489
|
function createBrainsCommand() {
|
|
8945
9490
|
const command = new Command("brains").description("Inspect and assign the LLM brains used by Kimbho roles.");
|
|
8946
9491
|
command.command("list").description("List brain-role assignments.").option("--json", "Print roles as JSON", false).action(async (options) => {
|
|
8947
|
-
const config = await loadConfig(
|
|
9492
|
+
const config = await loadConfig(import_node_process2.default.cwd());
|
|
8948
9493
|
if (!config) {
|
|
8949
9494
|
requireConfigMessage();
|
|
8950
9495
|
}
|
|
@@ -8974,7 +9519,7 @@ function createBrainsCommand() {
|
|
|
8974
9519
|
}
|
|
8975
9520
|
});
|
|
8976
9521
|
command.command("assign").description("Assign a provider/model pair to a brain role.").requiredOption("--role <role>", "Brain role: planner, coder, reviewer, or fast").requiredOption("--provider <provider>", "Provider id to assign").option("--model <model>", "Model override for this role").option("--temperature <value>", "Temperature override", parseNumber).option("--max-tokens <value>", "Max token override", parseNumber).option("--prompt-preamble <text>", "Additional prompt preamble for this role").action(async (options) => {
|
|
8977
|
-
const config = await loadConfig(
|
|
9522
|
+
const config = await loadConfig(import_node_process2.default.cwd());
|
|
8978
9523
|
if (!config) {
|
|
8979
9524
|
requireConfigMessage();
|
|
8980
9525
|
}
|
|
@@ -8998,12 +9543,12 @@ function createBrainsCommand() {
|
|
|
8998
9543
|
promptPreamble: options.promptPreamble
|
|
8999
9544
|
} : {}
|
|
9000
9545
|
});
|
|
9001
|
-
const outputPath = await saveConfig(nextConfig,
|
|
9546
|
+
const outputPath = await saveConfig(nextConfig, import_node_process2.default.cwd());
|
|
9002
9547
|
console.log(`Updated ${outputPath}`);
|
|
9003
9548
|
console.log(`Brain ${role} -> ${provider.id}/${options.model ?? provider.defaultModel ?? "model not set"}`);
|
|
9004
9549
|
});
|
|
9005
9550
|
command.command("test").description("Send a prompt through one configured brain role.").argument("<role>", "Brain role to invoke").argument("<prompt>", "Prompt to send").action(async (role, prompt) => {
|
|
9006
|
-
const config = await loadConfig(
|
|
9551
|
+
const config = await loadConfig(import_node_process2.default.cwd());
|
|
9007
9552
|
if (!config) {
|
|
9008
9553
|
requireConfigMessage();
|
|
9009
9554
|
}
|
|
@@ -9029,10 +9574,10 @@ function createBrainsCommand() {
|
|
|
9029
9574
|
}
|
|
9030
9575
|
|
|
9031
9576
|
// src/commands/doctor.ts
|
|
9032
|
-
var
|
|
9033
|
-
var
|
|
9577
|
+
var import_node_process3 = __toESM(require("node:process"), 1);
|
|
9578
|
+
var import_node_child_process2 = require("node:child_process");
|
|
9034
9579
|
function commandVersion(binary) {
|
|
9035
|
-
const result = (0,
|
|
9580
|
+
const result = (0, import_node_child_process2.spawnSync)(binary, ["--version"], {
|
|
9036
9581
|
encoding: "utf8"
|
|
9037
9582
|
});
|
|
9038
9583
|
if (result.status === 0) {
|
|
@@ -9055,19 +9600,19 @@ function createDoctorCommand() {
|
|
|
9055
9600
|
{
|
|
9056
9601
|
name: "node",
|
|
9057
9602
|
ok: true,
|
|
9058
|
-
detail:
|
|
9603
|
+
detail: import_node_process3.default.version
|
|
9059
9604
|
},
|
|
9060
9605
|
commandVersion("npm"),
|
|
9061
9606
|
commandVersion("git"),
|
|
9062
9607
|
commandVersion("docker")
|
|
9063
9608
|
];
|
|
9064
|
-
const config = await loadConfig(
|
|
9065
|
-
const registry = createDefaultBrainProviderRegistry(
|
|
9609
|
+
const config = await loadConfig(import_node_process3.default.cwd());
|
|
9610
|
+
const registry = createDefaultBrainProviderRegistry(import_node_process3.default.cwd());
|
|
9066
9611
|
if (config) {
|
|
9067
9612
|
checks.push({
|
|
9068
9613
|
name: "config",
|
|
9069
9614
|
ok: true,
|
|
9070
|
-
detail: `${resolveConfigPath(
|
|
9615
|
+
detail: `${resolveConfigPath(import_node_process3.default.cwd())} (${config.providers.length} providers)`
|
|
9071
9616
|
});
|
|
9072
9617
|
for (const provider of config.providers) {
|
|
9073
9618
|
try {
|
|
@@ -9104,7 +9649,7 @@ function createDoctorCommand() {
|
|
|
9104
9649
|
checks.push({
|
|
9105
9650
|
name: "config",
|
|
9106
9651
|
ok: false,
|
|
9107
|
-
detail: `missing (${resolveConfigPath(
|
|
9652
|
+
detail: `missing (${resolveConfigPath(import_node_process3.default.cwd())})`
|
|
9108
9653
|
});
|
|
9109
9654
|
}
|
|
9110
9655
|
for (const check of checks) {
|
|
@@ -9114,13 +9659,13 @@ function createDoctorCommand() {
|
|
|
9114
9659
|
}
|
|
9115
9660
|
|
|
9116
9661
|
// src/commands/init.ts
|
|
9117
|
-
var
|
|
9662
|
+
var import_node_process4 = __toESM(require("node:process"), 1);
|
|
9118
9663
|
function createInitCommand() {
|
|
9119
9664
|
return new Command("init").description("Create a local .kimbho/config.json file with an initial brain/provider setup.").option("--template <template>", "Provider template to use for the initial provider").option("--provider-id <id>", "Identifier for the initial provider").option("--driver <driver>", "Provider driver to use when no template is supplied").option("--label <label>", "Human-readable provider label").option("--model <model>", "Default model to use for planner/coder/reviewer brains").option("--fast-model <model>", "Model to use for the fast utility brain").option("--api-key-env <env>", "Environment variable that stores the provider API key").option("--base-url <url>", "Base URL or endpoint for the provider driver").option("--module-path <path>", "Module path for a custom provider driver").option("--force", "Overwrite an existing config file", false).action(async (options) => {
|
|
9120
|
-
const existing = await loadConfig(
|
|
9665
|
+
const existing = await loadConfig(import_node_process4.default.cwd());
|
|
9121
9666
|
if (existing && !options.force) {
|
|
9122
9667
|
console.error("Config already exists. Re-run with --force to overwrite it.");
|
|
9123
|
-
|
|
9668
|
+
import_node_process4.default.exitCode = 1;
|
|
9124
9669
|
return;
|
|
9125
9670
|
}
|
|
9126
9671
|
const templateId = options.template ?? (!options.driver ? "openai" : null);
|
|
@@ -9154,13 +9699,13 @@ function createInitCommand() {
|
|
|
9154
9699
|
defaultModel: options.model ?? provider.defaultModel,
|
|
9155
9700
|
fastModel: options.fastModel ?? options.model ?? provider.defaultModel
|
|
9156
9701
|
});
|
|
9157
|
-
const outputPath = await saveConfig(nextConfig,
|
|
9702
|
+
const outputPath = await saveConfig(nextConfig, import_node_process4.default.cwd());
|
|
9158
9703
|
console.log(`Created ${outputPath}`);
|
|
9159
9704
|
});
|
|
9160
9705
|
}
|
|
9161
9706
|
|
|
9162
9707
|
// src/commands/models.ts
|
|
9163
|
-
var
|
|
9708
|
+
var import_node_process5 = __toESM(require("node:process"), 1);
|
|
9164
9709
|
function parseInteger(value) {
|
|
9165
9710
|
const parsed = Number.parseInt(value, 10);
|
|
9166
9711
|
if (!Number.isFinite(parsed)) {
|
|
@@ -9211,7 +9756,7 @@ async function fetchProviderModels(provider, options) {
|
|
|
9211
9756
|
models: cachedModels
|
|
9212
9757
|
};
|
|
9213
9758
|
}
|
|
9214
|
-
const registry = createDefaultBrainProviderRegistry(
|
|
9759
|
+
const registry = createDefaultBrainProviderRegistry(import_node_process5.default.cwd());
|
|
9215
9760
|
try {
|
|
9216
9761
|
const models = await registry.listModels(provider, {
|
|
9217
9762
|
...options.search ? {
|
|
@@ -9238,7 +9783,7 @@ async function fetchProviderModels(provider, options) {
|
|
|
9238
9783
|
function createModelsCommand() {
|
|
9239
9784
|
const command = new Command("models").description("Discover and select models from configured providers.");
|
|
9240
9785
|
command.command("list").description("List models for one provider or all configured providers.").argument("[provider]", "Optional provider id to inspect").option("--search <term>", "Filter the returned models by search text").option("--limit <count>", "Maximum number of models to print", parseInteger, 25).option("--cached", "Use cached models from config instead of remote discovery", false).option("--sync", "Persist discovered model ids back into config", false).option("--json", "Print models as JSON", false).action(async (providerId, options) => {
|
|
9241
|
-
let config = await loadConfig(
|
|
9786
|
+
let config = await loadConfig(import_node_process5.default.cwd());
|
|
9242
9787
|
if (!config) {
|
|
9243
9788
|
requireConfigMessage2();
|
|
9244
9789
|
}
|
|
@@ -9267,7 +9812,7 @@ function createModelsCommand() {
|
|
|
9267
9812
|
}
|
|
9268
9813
|
}
|
|
9269
9814
|
if (mutated) {
|
|
9270
|
-
await saveConfig(config,
|
|
9815
|
+
await saveConfig(config, import_node_process5.default.cwd());
|
|
9271
9816
|
}
|
|
9272
9817
|
if (options.json) {
|
|
9273
9818
|
console.log(renderJson(groups));
|
|
@@ -9284,7 +9829,7 @@ function createModelsCommand() {
|
|
|
9284
9829
|
}
|
|
9285
9830
|
});
|
|
9286
9831
|
command.command("sync").description("Fetch remote models for one provider and cache the ids in config.").argument("<provider>", "Provider id to sync").option("--search <term>", "Optional search filter to limit what gets cached").option("--limit <count>", "Maximum number of models to cache", parseInteger, 200).action(async (providerId, options) => {
|
|
9287
|
-
const config = await loadConfig(
|
|
9832
|
+
const config = await loadConfig(import_node_process5.default.cwd());
|
|
9288
9833
|
if (!config) {
|
|
9289
9834
|
requireConfigMessage2();
|
|
9290
9835
|
}
|
|
@@ -9292,7 +9837,7 @@ function createModelsCommand() {
|
|
|
9292
9837
|
if (!provider) {
|
|
9293
9838
|
throw new Error(`Unknown provider "${providerId}".`);
|
|
9294
9839
|
}
|
|
9295
|
-
const registry = createDefaultBrainProviderRegistry(
|
|
9840
|
+
const registry = createDefaultBrainProviderRegistry(import_node_process5.default.cwd());
|
|
9296
9841
|
const models = await registry.listModels(provider, {
|
|
9297
9842
|
...options.search ? {
|
|
9298
9843
|
search: options.search
|
|
@@ -9303,12 +9848,12 @@ function createModelsCommand() {
|
|
|
9303
9848
|
...provider,
|
|
9304
9849
|
models: Array.from(new Set(models.map((model) => model.id)))
|
|
9305
9850
|
});
|
|
9306
|
-
const outputPath = await saveConfig(nextConfig,
|
|
9851
|
+
const outputPath = await saveConfig(nextConfig, import_node_process5.default.cwd());
|
|
9307
9852
|
console.log(`Updated ${outputPath}`);
|
|
9308
9853
|
console.log(`Synced ${models.length} models for ${provider.id}`);
|
|
9309
9854
|
});
|
|
9310
9855
|
command.command("use").description("Select a model for a provider and optionally assign it to a brain role.").argument("<model>", "Model id to select").requiredOption("--provider <provider>", "Provider id to use").option("--role <role>", "Brain role to assign: planner, coder, reviewer, or fast").option("--set-default", "Also set this model as the provider default", false).option("--force", "Skip remote model validation", false).option("--temperature <value>", "Temperature override for the role", parseNumber2).option("--max-tokens <value>", "Max token override for the role", parseInteger).action(async (model, options) => {
|
|
9311
|
-
let config = await loadConfig(
|
|
9856
|
+
let config = await loadConfig(import_node_process5.default.cwd());
|
|
9312
9857
|
if (!config) {
|
|
9313
9858
|
requireConfigMessage2();
|
|
9314
9859
|
}
|
|
@@ -9318,7 +9863,7 @@ function createModelsCommand() {
|
|
|
9318
9863
|
}
|
|
9319
9864
|
if (!options.force) {
|
|
9320
9865
|
try {
|
|
9321
|
-
const registry = createDefaultBrainProviderRegistry(
|
|
9866
|
+
const registry = createDefaultBrainProviderRegistry(import_node_process5.default.cwd());
|
|
9322
9867
|
const models = await registry.listModels(provider, {
|
|
9323
9868
|
search: model,
|
|
9324
9869
|
limit: 500
|
|
@@ -9358,7 +9903,7 @@ function createModelsCommand() {
|
|
|
9358
9903
|
} : {}
|
|
9359
9904
|
});
|
|
9360
9905
|
}
|
|
9361
|
-
const outputPath = await saveConfig(config,
|
|
9906
|
+
const outputPath = await saveConfig(config, import_node_process5.default.cwd());
|
|
9362
9907
|
console.log(`Updated ${outputPath}`);
|
|
9363
9908
|
console.log(`Selected ${provider.id}/${model}`);
|
|
9364
9909
|
if (options.role) {
|
|
@@ -9372,8 +9917,8 @@ function createModelsCommand() {
|
|
|
9372
9917
|
}
|
|
9373
9918
|
|
|
9374
9919
|
// src/commands/plan.ts
|
|
9375
|
-
var
|
|
9376
|
-
var
|
|
9920
|
+
var import_promises6 = require("node:fs/promises");
|
|
9921
|
+
var import_node_process6 = __toESM(require("node:process"), 1);
|
|
9377
9922
|
|
|
9378
9923
|
// ../planner/dist/planner.js
|
|
9379
9924
|
function normalizeGoal(goal) {
|
|
@@ -9677,7 +10222,7 @@ function createPlan(input) {
|
|
|
9677
10222
|
|
|
9678
10223
|
// src/commands/plan.ts
|
|
9679
10224
|
async function detectWorkspaceState(cwd) {
|
|
9680
|
-
const entries = await (0,
|
|
10225
|
+
const entries = await (0, import_promises6.readdir)(cwd);
|
|
9681
10226
|
const meaningfulEntries = entries.filter((entry) => entry !== ".kimbho" && !entry.startsWith("."));
|
|
9682
10227
|
return meaningfulEntries.length === 0 ? "empty" : "existing";
|
|
9683
10228
|
}
|
|
@@ -9688,7 +10233,7 @@ function createPlanCommand() {
|
|
|
9688
10233
|
(value, previous = []) => [...previous, value],
|
|
9689
10234
|
[]
|
|
9690
10235
|
).option("--json", "Print the plan as JSON", false).action(async (goal, options) => {
|
|
9691
|
-
const cwd =
|
|
10236
|
+
const cwd = import_node_process6.default.cwd();
|
|
9692
10237
|
const request = {
|
|
9693
10238
|
goal,
|
|
9694
10239
|
mode: "plan",
|
|
@@ -9725,14 +10270,14 @@ function createPlanCommand() {
|
|
|
9725
10270
|
}
|
|
9726
10271
|
|
|
9727
10272
|
// src/commands/providers.ts
|
|
9728
|
-
var
|
|
10273
|
+
var import_node_process7 = __toESM(require("node:process"), 1);
|
|
9729
10274
|
function requireConfigMessage3() {
|
|
9730
10275
|
throw new Error("No config found. Run `kimbho init` first.");
|
|
9731
10276
|
}
|
|
9732
10277
|
function createProvidersCommand() {
|
|
9733
10278
|
const command = new Command("providers").description("Manage configured model providers and built-in templates.");
|
|
9734
10279
|
command.command("list").description("List configured providers.").option("--json", "Print providers as JSON", false).action(async (options) => {
|
|
9735
|
-
const config = await loadConfig(
|
|
10280
|
+
const config = await loadConfig(import_node_process7.default.cwd());
|
|
9736
10281
|
if (!config) {
|
|
9737
10282
|
requireConfigMessage3();
|
|
9738
10283
|
}
|
|
@@ -9773,7 +10318,7 @@ function createProvidersCommand() {
|
|
|
9773
10318
|
(value, previous = []) => [...previous, value],
|
|
9774
10319
|
[]
|
|
9775
10320
|
).option("--module-path <path>", "Module path for a custom provider driver").action(async (options) => {
|
|
9776
|
-
const config = await loadConfig(
|
|
10321
|
+
const config = await loadConfig(import_node_process7.default.cwd());
|
|
9777
10322
|
if (!config) {
|
|
9778
10323
|
requireConfigMessage3();
|
|
9779
10324
|
}
|
|
@@ -9807,16 +10352,16 @@ function createProvidersCommand() {
|
|
|
9807
10352
|
} : {}
|
|
9808
10353
|
});
|
|
9809
10354
|
const nextConfig = upsertProvider(config, provider);
|
|
9810
|
-
const outputPath = await saveConfig(nextConfig,
|
|
10355
|
+
const outputPath = await saveConfig(nextConfig, import_node_process7.default.cwd());
|
|
9811
10356
|
console.log(`Updated ${outputPath}`);
|
|
9812
10357
|
console.log(`Provider ${provider.id} -> ${provider.driver}`);
|
|
9813
10358
|
});
|
|
9814
10359
|
command.command("check").description("Run health checks for the configured providers.").action(async () => {
|
|
9815
|
-
const config = await loadConfig(
|
|
10360
|
+
const config = await loadConfig(import_node_process7.default.cwd());
|
|
9816
10361
|
if (!config) {
|
|
9817
10362
|
requireConfigMessage3();
|
|
9818
10363
|
}
|
|
9819
|
-
const registry = createDefaultBrainProviderRegistry(
|
|
10364
|
+
const registry = createDefaultBrainProviderRegistry(import_node_process7.default.cwd());
|
|
9820
10365
|
for (const provider of config.providers) {
|
|
9821
10366
|
try {
|
|
9822
10367
|
const result = await registry.healthCheck(provider);
|
|
@@ -9831,52 +10376,67 @@ function createProvidersCommand() {
|
|
|
9831
10376
|
}
|
|
9832
10377
|
|
|
9833
10378
|
// src/commands/resume.ts
|
|
9834
|
-
var
|
|
10379
|
+
var import_node_process8 = __toESM(require("node:process"), 1);
|
|
10380
|
+
function parseCount(value) {
|
|
10381
|
+
const parsed = Number(value);
|
|
10382
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
10383
|
+
throw new Error(`Expected a positive integer, received "${value}".`);
|
|
10384
|
+
}
|
|
10385
|
+
return parsed;
|
|
10386
|
+
}
|
|
9835
10387
|
function createResumeCommand() {
|
|
9836
|
-
return new Command("resume").description("Resume the latest saved Kimbho session snapshot.").option("--json", "Print the latest session as JSON", false).action(async (options) => {
|
|
9837
|
-
const
|
|
10388
|
+
return new Command("resume").description("Resume the latest saved Kimbho session snapshot.").option("--json", "Print the latest session as JSON", false).option("--execute", "Continue auto-executing the ready-task frontier", false).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount, 2).action(async (options) => {
|
|
10389
|
+
const cwd = import_node_process8.default.cwd();
|
|
10390
|
+
const session = await loadLatestSession(cwd);
|
|
9838
10391
|
if (!session) {
|
|
9839
10392
|
console.error("No saved session found. Run `kimbho run` first.");
|
|
9840
|
-
|
|
10393
|
+
import_node_process8.default.exitCode = 1;
|
|
9841
10394
|
return;
|
|
9842
10395
|
}
|
|
10396
|
+
const snapshot = options.execute ? await new ExecutionOrchestrator().continueSession(session, {
|
|
10397
|
+
maxAutoTasks: options.maxAutoTasks
|
|
10398
|
+
}) : session;
|
|
10399
|
+
if (options.execute) {
|
|
10400
|
+
await saveSession(snapshot, cwd);
|
|
10401
|
+
}
|
|
9843
10402
|
if (options.json) {
|
|
9844
|
-
console.log(renderJson(
|
|
10403
|
+
console.log(renderJson(snapshot));
|
|
9845
10404
|
return;
|
|
9846
10405
|
}
|
|
9847
|
-
console.log(
|
|
9848
|
-
console.log(`Goal: ${session.goal}`);
|
|
9849
|
-
console.log(`Status: ${session.status}`);
|
|
9850
|
-
console.log(`Ready tasks: ${session.readyTaskIds.join(", ") || "none"}`);
|
|
9851
|
-
console.log(`Blocked tasks: ${session.blockedTaskIds.join(", ") || "none"}`);
|
|
9852
|
-
console.log(`Assigned agents: ${session.assignedAgents.join(", ") || "none"}`);
|
|
9853
|
-
console.log(`Notes: ${session.notes.join(" | ") || "none"}`);
|
|
10406
|
+
console.log(renderSession(snapshot));
|
|
9854
10407
|
});
|
|
9855
10408
|
}
|
|
9856
10409
|
|
|
9857
10410
|
// src/commands/run.ts
|
|
9858
|
-
var
|
|
9859
|
-
var
|
|
10411
|
+
var import_promises7 = require("node:fs/promises");
|
|
10412
|
+
var import_node_process9 = __toESM(require("node:process"), 1);
|
|
9860
10413
|
async function detectWorkspaceState2(cwd) {
|
|
9861
|
-
const entries = await (0,
|
|
10414
|
+
const entries = await (0, import_promises7.readdir)(cwd);
|
|
9862
10415
|
const meaningfulEntries = entries.filter((entry) => entry !== ".kimbho" && !entry.startsWith("."));
|
|
9863
10416
|
return meaningfulEntries.length === 0 ? "empty" : "existing";
|
|
9864
10417
|
}
|
|
10418
|
+
function parseCount2(value) {
|
|
10419
|
+
const parsed = Number(value);
|
|
10420
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
10421
|
+
throw new Error(`Expected a positive integer, received "${value}".`);
|
|
10422
|
+
}
|
|
10423
|
+
return parsed;
|
|
10424
|
+
}
|
|
9865
10425
|
function createRunCommand() {
|
|
9866
10426
|
return new Command("run").description("Create or load a plan, then open a runnable Kimbho session snapshot.").argument("[goal]", "Optional goal; if omitted, Kimbho will use the latest saved plan").option("--stack <stack>", "Preferred stack or preset").option(
|
|
9867
10427
|
"--constraint <constraint>",
|
|
9868
10428
|
"Explicit execution constraint; can be provided multiple times",
|
|
9869
10429
|
(value, previous = []) => [...previous, value],
|
|
9870
10430
|
[]
|
|
9871
|
-
).option("--json", "Print the session snapshot as JSON", false).action(async (goal, options) => {
|
|
9872
|
-
const cwd =
|
|
10431
|
+
).option("--json", "Print the session snapshot as JSON", false).option("--snapshot-only", "Create the session without auto-executing ready tasks", false).option("--max-auto-tasks <count>", "Maximum ready tasks to auto-execute", parseCount2, 2).action(async (goal, options) => {
|
|
10432
|
+
const cwd = import_node_process9.default.cwd();
|
|
9873
10433
|
const orchestrator = new ExecutionOrchestrator();
|
|
9874
10434
|
let request;
|
|
9875
10435
|
let planPath = null;
|
|
9876
10436
|
let plan = goal ? null : await loadLatestPlan(cwd);
|
|
9877
10437
|
if (!plan && !goal) {
|
|
9878
10438
|
console.error("No saved plan found. Pass a goal or run `kimbho plan` first.");
|
|
9879
|
-
|
|
10439
|
+
import_node_process9.default.exitCode = 1;
|
|
9880
10440
|
return;
|
|
9881
10441
|
}
|
|
9882
10442
|
if (goal) {
|
|
@@ -9901,7 +10461,10 @@ function createRunCommand() {
|
|
|
9901
10461
|
};
|
|
9902
10462
|
}
|
|
9903
10463
|
const envelope = orchestrator.buildEnvelope(request, plan);
|
|
9904
|
-
const
|
|
10464
|
+
const initialSnapshot = orchestrator.createSessionSnapshot(envelope);
|
|
10465
|
+
const snapshot = options.snapshotOnly ? initialSnapshot : await orchestrator.continueSession(initialSnapshot, {
|
|
10466
|
+
maxAutoTasks: options.maxAutoTasks
|
|
10467
|
+
});
|
|
9905
10468
|
const sessionPath = await saveSession(snapshot, cwd);
|
|
9906
10469
|
if (options.json) {
|
|
9907
10470
|
console.log(
|
|
@@ -9915,15 +10478,12 @@ function createRunCommand() {
|
|
|
9915
10478
|
}
|
|
9916
10479
|
console.log(renderPlan(plan));
|
|
9917
10480
|
console.log("");
|
|
9918
|
-
console.log(
|
|
9919
|
-
console.log(
|
|
10481
|
+
console.log(renderSession(snapshot));
|
|
10482
|
+
console.log("");
|
|
9920
10483
|
if (planPath) {
|
|
9921
10484
|
console.log(`Saved plan: ${planPath}`);
|
|
9922
10485
|
}
|
|
9923
|
-
console.log(`
|
|
9924
|
-
console.log(`Ready tasks: ${snapshot.readyTaskIds.join(", ") || "none"}`);
|
|
9925
|
-
console.log(`Blocked tasks: ${snapshot.blockedTaskIds.join(", ") || "none"}`);
|
|
9926
|
-
console.log("Next step: wire executors into `run` so ready tasks can be acted on instead of only snapshotted.");
|
|
10486
|
+
console.log(`Saved session: ${sessionPath}`);
|
|
9927
10487
|
});
|
|
9928
10488
|
}
|
|
9929
10489
|
|
|
@@ -9948,36 +10508,398 @@ function createReviewCommand() {
|
|
|
9948
10508
|
);
|
|
9949
10509
|
}
|
|
9950
10510
|
|
|
9951
|
-
// src/
|
|
9952
|
-
var
|
|
9953
|
-
program2.name("kimbho").description("Kimbho CLI: a terminal-native coding agent for planning and execution.").version("0.1.0");
|
|
9954
|
-
program2.addCommand(createInitCommand());
|
|
9955
|
-
program2.addCommand(createPlanCommand());
|
|
9956
|
-
program2.addCommand(createDoctorCommand());
|
|
9957
|
-
program2.addCommand(createAgentsCommand());
|
|
9958
|
-
program2.addCommand(createProvidersCommand());
|
|
9959
|
-
program2.addCommand(createModelsCommand());
|
|
9960
|
-
program2.addCommand(createBrainsCommand());
|
|
9961
|
-
program2.addCommand(createRunCommand());
|
|
9962
|
-
program2.addCommand(createResumeCommand());
|
|
9963
|
-
program2.addCommand(createFixCommand());
|
|
9964
|
-
program2.addCommand(createReviewCommand());
|
|
9965
|
-
var normalizedArgv = process.argv.map(
|
|
9966
|
-
(value, index) => index === 2 && value.startsWith("/") ? value.slice(1) : value
|
|
9967
|
-
);
|
|
9968
|
-
var modelsSubcommands = /* @__PURE__ */ new Set([
|
|
10511
|
+
// src/program.ts
|
|
10512
|
+
var MODELS_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
9969
10513
|
"help",
|
|
9970
10514
|
"list",
|
|
9971
10515
|
"sync",
|
|
9972
10516
|
"use"
|
|
9973
10517
|
]);
|
|
9974
|
-
|
|
9975
|
-
const
|
|
9976
|
-
if (
|
|
9977
|
-
|
|
10518
|
+
function normalizeCliTokens(tokens) {
|
|
10519
|
+
const normalized = [...tokens];
|
|
10520
|
+
if (normalized[0]?.startsWith("/")) {
|
|
10521
|
+
normalized[0] = normalized[0].slice(1);
|
|
10522
|
+
}
|
|
10523
|
+
if (normalized[0] === "models") {
|
|
10524
|
+
const candidate = normalized[1];
|
|
10525
|
+
if (!candidate || candidate.startsWith("-") || !MODELS_SUBCOMMANDS.has(candidate)) {
|
|
10526
|
+
normalized.splice(1, 0, "list");
|
|
10527
|
+
}
|
|
10528
|
+
}
|
|
10529
|
+
return normalized;
|
|
10530
|
+
}
|
|
10531
|
+
function createProgram(onOpenShell) {
|
|
10532
|
+
const program2 = new Command();
|
|
10533
|
+
program2.name("kimbho").description(KIMBHO_DESCRIPTION).version(KIMBHO_VERSION);
|
|
10534
|
+
program2.addCommand(createInitCommand());
|
|
10535
|
+
program2.addCommand(createPlanCommand());
|
|
10536
|
+
program2.addCommand(createDoctorCommand());
|
|
10537
|
+
program2.addCommand(createAgentsCommand());
|
|
10538
|
+
program2.addCommand(createProvidersCommand());
|
|
10539
|
+
program2.addCommand(createModelsCommand());
|
|
10540
|
+
program2.addCommand(createBrainsCommand());
|
|
10541
|
+
program2.addCommand(createRunCommand());
|
|
10542
|
+
program2.addCommand(createResumeCommand());
|
|
10543
|
+
program2.addCommand(createFixCommand());
|
|
10544
|
+
program2.addCommand(createReviewCommand());
|
|
10545
|
+
if (onOpenShell) {
|
|
10546
|
+
program2.command("shell").description("Open the interactive Kimbho shell.").action(async () => {
|
|
10547
|
+
await onOpenShell();
|
|
10548
|
+
});
|
|
10549
|
+
}
|
|
10550
|
+
return program2;
|
|
10551
|
+
}
|
|
10552
|
+
|
|
10553
|
+
// src/shell.ts
|
|
10554
|
+
var import_promises8 = require("node:readline/promises");
|
|
10555
|
+
var import_node_process10 = __toESM(require("node:process"), 1);
|
|
10556
|
+
var AMBER = "\x1B[38;5;214m";
|
|
10557
|
+
var BOLD = "\x1B[1m";
|
|
10558
|
+
var DIM = "\x1B[2m";
|
|
10559
|
+
var RESET = "\x1B[0m";
|
|
10560
|
+
var TOP_LEVEL_COMMANDS = /* @__PURE__ */ new Set([
|
|
10561
|
+
"agents",
|
|
10562
|
+
"brains",
|
|
10563
|
+
"doctor",
|
|
10564
|
+
"fix",
|
|
10565
|
+
"help",
|
|
10566
|
+
"init",
|
|
10567
|
+
"model",
|
|
10568
|
+
"models",
|
|
10569
|
+
"new",
|
|
10570
|
+
"plan",
|
|
10571
|
+
"providers",
|
|
10572
|
+
"quit",
|
|
10573
|
+
"resume",
|
|
10574
|
+
"review",
|
|
10575
|
+
"run",
|
|
10576
|
+
"scaffold",
|
|
10577
|
+
"shell",
|
|
10578
|
+
"status"
|
|
10579
|
+
]);
|
|
10580
|
+
function color(code, value) {
|
|
10581
|
+
return `${code}${value}${RESET}`;
|
|
10582
|
+
}
|
|
10583
|
+
function renderBanner() {
|
|
10584
|
+
return [
|
|
10585
|
+
" _ ___ __ __ ____ ____ _ _ ___ ",
|
|
10586
|
+
"| |/ (_) \\/ | __ )| _ \\| | | |/ _ \\",
|
|
10587
|
+
"| ' /| | |\\/| | _ \\| | | | |_| | | | |",
|
|
10588
|
+
"| . \\| | | | | |_) | |_| | _ | |_| |",
|
|
10589
|
+
"|_|\\_\\_|_| |_|____/|____/|_| |_|\\___/ "
|
|
10590
|
+
].map((line) => color(AMBER, line)).join("\n");
|
|
10591
|
+
}
|
|
10592
|
+
async function getShellSessionState(cwd) {
|
|
10593
|
+
const config = await loadConfig(cwd);
|
|
10594
|
+
if (!config) {
|
|
10595
|
+
return {
|
|
10596
|
+
providerLabel: "unconfigured",
|
|
10597
|
+
providerId: "-",
|
|
10598
|
+
coderModel: "not set",
|
|
10599
|
+
plannerModel: "not set",
|
|
10600
|
+
approvalMode: "manual",
|
|
10601
|
+
sandboxMode: "workspace-write",
|
|
10602
|
+
stackPreset: "next-prisma-postgres",
|
|
10603
|
+
configured: false
|
|
10604
|
+
};
|
|
10605
|
+
}
|
|
10606
|
+
const coderSettings = config.brains.coder;
|
|
10607
|
+
const provider = findProviderById(config, coderSettings.providerId);
|
|
10608
|
+
return {
|
|
10609
|
+
providerLabel: provider?.label ?? provider?.id ?? "unknown",
|
|
10610
|
+
providerId: provider?.id ?? coderSettings.providerId,
|
|
10611
|
+
coderModel: resolveBrainModel(config, "coder") ?? "not set",
|
|
10612
|
+
plannerModel: resolveBrainModel(config, "planner") ?? "not set",
|
|
10613
|
+
approvalMode: config.approvalMode,
|
|
10614
|
+
sandboxMode: config.sandboxMode,
|
|
10615
|
+
stackPreset: config.stackPresets[0] ?? "none",
|
|
10616
|
+
configured: true
|
|
10617
|
+
};
|
|
10618
|
+
}
|
|
10619
|
+
function renderCardLine(label, value) {
|
|
10620
|
+
return `${label}: ${value}`;
|
|
10621
|
+
}
|
|
10622
|
+
function shortenMiddle(value, maxLength) {
|
|
10623
|
+
if (value.length <= maxLength) {
|
|
10624
|
+
return value;
|
|
10625
|
+
}
|
|
10626
|
+
const visible = maxLength - 3;
|
|
10627
|
+
const left = Math.ceil(visible / 2);
|
|
10628
|
+
const right = Math.floor(visible / 2);
|
|
10629
|
+
return `${value.slice(0, left)}...${value.slice(value.length - right)}`;
|
|
10630
|
+
}
|
|
10631
|
+
function renderBox(lines) {
|
|
10632
|
+
const width = lines.reduce((max, line) => Math.max(max, line.length), 0);
|
|
10633
|
+
const top = `+${"-".repeat(width + 2)}+`;
|
|
10634
|
+
return [
|
|
10635
|
+
top,
|
|
10636
|
+
...lines.map((line) => `| ${line.padEnd(width, " ")} |`),
|
|
10637
|
+
top
|
|
10638
|
+
].join("\n");
|
|
10639
|
+
}
|
|
10640
|
+
function renderHelp() {
|
|
10641
|
+
return [
|
|
10642
|
+
`${color(DIM, "Commands")}`,
|
|
10643
|
+
"/status Show the active model, provider, and workspace state.",
|
|
10644
|
+
"/plan <goal> Create a structured implementation plan.",
|
|
10645
|
+
"/run <goal> Start a Kimbho execution session for a goal.",
|
|
10646
|
+
"/new <goal> Alias for /run <goal>.",
|
|
10647
|
+
"/scaffold <goal> Alias for /run <goal> with scaffolding intent.",
|
|
10648
|
+
"/resume Show the latest saved session.",
|
|
10649
|
+
"/agents Inspect agent roles and the active session.",
|
|
10650
|
+
"/providers Manage model providers.",
|
|
10651
|
+
"/model Show the active planner/coder model selection.",
|
|
10652
|
+
"/models Discover and select provider models.",
|
|
10653
|
+
"/brains Inspect or assign planner/coder/reviewer brains.",
|
|
10654
|
+
"/doctor Check local environment and config.",
|
|
10655
|
+
"/clear Redraw the shell.",
|
|
10656
|
+
"/quit, /exit Leave the shell.",
|
|
10657
|
+
"",
|
|
10658
|
+
`${color(DIM, "Tip")}`,
|
|
10659
|
+
"Type a natural-language goal directly and Kimbho will treat it as /run <goal>."
|
|
10660
|
+
].join("\n");
|
|
10661
|
+
}
|
|
10662
|
+
function renderStartupCard(cwd, state) {
|
|
10663
|
+
const cardLines = [
|
|
10664
|
+
`${color(BOLD, "Kimbho CLI")} (v${KIMBHO_VERSION})`,
|
|
10665
|
+
renderCardLine("coder", state.coderModel),
|
|
10666
|
+
renderCardLine("planner", state.plannerModel),
|
|
10667
|
+
renderCardLine("provider", `${state.providerLabel} [${state.providerId}]`),
|
|
10668
|
+
renderCardLine("directory", shortenMiddle(cwd, 78)),
|
|
10669
|
+
renderCardLine("approval", state.approvalMode),
|
|
10670
|
+
renderCardLine("sandbox", state.sandboxMode),
|
|
10671
|
+
renderCardLine("preset", state.stackPreset),
|
|
10672
|
+
renderCardLine("shortcuts", "/help /status /plan /run /models /brains /quit")
|
|
10673
|
+
];
|
|
10674
|
+
if (!state.configured) {
|
|
10675
|
+
cardLines.push("setup: run /init to create .kimbho/config.json");
|
|
10676
|
+
}
|
|
10677
|
+
return renderBox(cardLines);
|
|
10678
|
+
}
|
|
10679
|
+
function formatPrompt(state) {
|
|
10680
|
+
const coderModel = state.coderModel === "not set" ? "unconfigured" : shortenMiddle(state.coderModel, 18);
|
|
10681
|
+
return `${color(AMBER, "kimbho")} ${color(DIM, `[${coderModel}]`)} > `;
|
|
10682
|
+
}
|
|
10683
|
+
function printHeader(cwd, state) {
|
|
10684
|
+
console.log(renderBanner());
|
|
10685
|
+
console.log(color(DIM, "Terminal-native coding agent"));
|
|
10686
|
+
console.log(renderStartupCard(cwd, state));
|
|
10687
|
+
console.log("");
|
|
10688
|
+
console.log(color(DIM, "Tip: describe the app or repo change you want, and Kimbho will route it into /run."));
|
|
10689
|
+
console.log(renderHelp());
|
|
10690
|
+
console.log("");
|
|
10691
|
+
}
|
|
10692
|
+
function tokenizeInput(input) {
|
|
10693
|
+
const tokens = [];
|
|
10694
|
+
let current = "";
|
|
10695
|
+
let quote = null;
|
|
10696
|
+
let escaping = false;
|
|
10697
|
+
for (const character of input) {
|
|
10698
|
+
if (escaping) {
|
|
10699
|
+
current += character;
|
|
10700
|
+
escaping = false;
|
|
10701
|
+
continue;
|
|
10702
|
+
}
|
|
10703
|
+
if (character === "\\") {
|
|
10704
|
+
escaping = true;
|
|
10705
|
+
continue;
|
|
10706
|
+
}
|
|
10707
|
+
if (quote) {
|
|
10708
|
+
if (character === quote) {
|
|
10709
|
+
quote = null;
|
|
10710
|
+
} else {
|
|
10711
|
+
current += character;
|
|
10712
|
+
}
|
|
10713
|
+
continue;
|
|
10714
|
+
}
|
|
10715
|
+
if (character === "'" || character === '"') {
|
|
10716
|
+
quote = character;
|
|
10717
|
+
continue;
|
|
10718
|
+
}
|
|
10719
|
+
if (/\s/.test(character)) {
|
|
10720
|
+
if (current) {
|
|
10721
|
+
tokens.push(current);
|
|
10722
|
+
current = "";
|
|
10723
|
+
}
|
|
10724
|
+
continue;
|
|
10725
|
+
}
|
|
10726
|
+
current += character;
|
|
10727
|
+
}
|
|
10728
|
+
if (quote) {
|
|
10729
|
+
throw new Error(`Unterminated ${quote === '"' ? "double" : "single"} quote.`);
|
|
10730
|
+
}
|
|
10731
|
+
if (escaping) {
|
|
10732
|
+
current += "\\";
|
|
10733
|
+
}
|
|
10734
|
+
if (current) {
|
|
10735
|
+
tokens.push(current);
|
|
10736
|
+
}
|
|
10737
|
+
return tokens;
|
|
10738
|
+
}
|
|
10739
|
+
function toCommandTokens(input) {
|
|
10740
|
+
const trimmed = input.trim();
|
|
10741
|
+
if (!trimmed) {
|
|
10742
|
+
return [];
|
|
10743
|
+
}
|
|
10744
|
+
const normalizedInput = trimmed.startsWith("kimbho ") ? trimmed.slice("kimbho ".length).trim() : trimmed;
|
|
10745
|
+
const tokens = tokenizeInput(normalizedInput);
|
|
10746
|
+
if (tokens.length === 0) {
|
|
10747
|
+
return [];
|
|
10748
|
+
}
|
|
10749
|
+
const firstToken = tokens[0];
|
|
10750
|
+
if (!firstToken) {
|
|
10751
|
+
return [];
|
|
10752
|
+
}
|
|
10753
|
+
const head = firstToken.startsWith("/") ? firstToken.slice(1) : firstToken;
|
|
10754
|
+
if (head === "new") {
|
|
10755
|
+
return [
|
|
10756
|
+
"run",
|
|
10757
|
+
normalizedInput.replace(/^\/?new\s+/, "")
|
|
10758
|
+
];
|
|
10759
|
+
}
|
|
10760
|
+
if (head === "scaffold") {
|
|
10761
|
+
const goal = normalizedInput.replace(/^\/?scaffold\s+/, "");
|
|
10762
|
+
return [
|
|
10763
|
+
"run",
|
|
10764
|
+
`scaffold ${goal}`.trim()
|
|
10765
|
+
];
|
|
10766
|
+
}
|
|
10767
|
+
if (head === "model") {
|
|
10768
|
+
return [
|
|
10769
|
+
"brains",
|
|
10770
|
+
"list"
|
|
10771
|
+
];
|
|
9978
10772
|
}
|
|
10773
|
+
if (!firstToken.startsWith("/") && !TOP_LEVEL_COMMANDS.has(head) && !head.startsWith("-")) {
|
|
10774
|
+
return [
|
|
10775
|
+
"run",
|
|
10776
|
+
normalizedInput
|
|
10777
|
+
];
|
|
10778
|
+
}
|
|
10779
|
+
tokens[0] = head;
|
|
10780
|
+
return tokens;
|
|
10781
|
+
}
|
|
10782
|
+
async function runInteractiveShell(options) {
|
|
10783
|
+
const readline = (0, import_promises8.createInterface)({
|
|
10784
|
+
input: import_node_process10.default.stdin,
|
|
10785
|
+
output: import_node_process10.default.stdout,
|
|
10786
|
+
terminal: Boolean(import_node_process10.default.stdin.isTTY && import_node_process10.default.stdout.isTTY)
|
|
10787
|
+
});
|
|
10788
|
+
let closed = false;
|
|
10789
|
+
readline.on("SIGINT", () => {
|
|
10790
|
+
closed = true;
|
|
10791
|
+
readline.close();
|
|
10792
|
+
});
|
|
10793
|
+
let state = await getShellSessionState(options.cwd);
|
|
10794
|
+
printHeader(options.cwd, state);
|
|
10795
|
+
while (!closed) {
|
|
10796
|
+
let line;
|
|
10797
|
+
try {
|
|
10798
|
+
state = await getShellSessionState(options.cwd);
|
|
10799
|
+
line = await readline.question(formatPrompt(state));
|
|
10800
|
+
} catch {
|
|
10801
|
+
break;
|
|
10802
|
+
}
|
|
10803
|
+
const trimmed = line.trim();
|
|
10804
|
+
if (!trimmed) {
|
|
10805
|
+
continue;
|
|
10806
|
+
}
|
|
10807
|
+
if (trimmed === "/exit" || trimmed === "exit" || trimmed === "quit" || trimmed === "/quit") {
|
|
10808
|
+
closed = true;
|
|
10809
|
+
break;
|
|
10810
|
+
}
|
|
10811
|
+
if (trimmed === "/help" || trimmed === "help" || trimmed === "?") {
|
|
10812
|
+
console.log(renderHelp());
|
|
10813
|
+
console.log("");
|
|
10814
|
+
continue;
|
|
10815
|
+
}
|
|
10816
|
+
if (trimmed === "/status" || trimmed === "status") {
|
|
10817
|
+
state = await getShellSessionState(options.cwd);
|
|
10818
|
+
console.log(renderStartupCard(options.cwd, state));
|
|
10819
|
+
console.log("");
|
|
10820
|
+
continue;
|
|
10821
|
+
}
|
|
10822
|
+
if (trimmed === "/clear" || trimmed === "clear") {
|
|
10823
|
+
if (import_node_process10.default.stdout.isTTY) {
|
|
10824
|
+
import_node_process10.default.stdout.write("\x1Bc");
|
|
10825
|
+
}
|
|
10826
|
+
state = await getShellSessionState(options.cwd);
|
|
10827
|
+
printHeader(options.cwd, state);
|
|
10828
|
+
continue;
|
|
10829
|
+
}
|
|
10830
|
+
try {
|
|
10831
|
+
const tokens = toCommandTokens(trimmed);
|
|
10832
|
+
if (tokens.length === 0) {
|
|
10833
|
+
continue;
|
|
10834
|
+
}
|
|
10835
|
+
await options.execute(tokens);
|
|
10836
|
+
} catch (error) {
|
|
10837
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10838
|
+
console.error(message);
|
|
10839
|
+
} finally {
|
|
10840
|
+
import_node_process10.default.exitCode = 0;
|
|
10841
|
+
}
|
|
10842
|
+
if (!closed) {
|
|
10843
|
+
console.log("");
|
|
10844
|
+
}
|
|
10845
|
+
}
|
|
10846
|
+
readline.close();
|
|
10847
|
+
import_node_process10.default.exitCode = 0;
|
|
10848
|
+
console.log(color(DIM, "Leaving Kimbho."));
|
|
10849
|
+
}
|
|
10850
|
+
|
|
10851
|
+
// src/index.ts
|
|
10852
|
+
async function dispatchCliTokens(tokens) {
|
|
10853
|
+
const normalizedTokens = normalizeCliTokens(tokens);
|
|
10854
|
+
await new Promise((resolve, reject) => {
|
|
10855
|
+
const child = (0, import_node_child_process3.spawn)(
|
|
10856
|
+
process.execPath,
|
|
10857
|
+
[
|
|
10858
|
+
...process.execArgv,
|
|
10859
|
+
process.argv[1] ?? "",
|
|
10860
|
+
...normalizedTokens
|
|
10861
|
+
],
|
|
10862
|
+
{
|
|
10863
|
+
cwd: process.cwd(),
|
|
10864
|
+
env: process.env,
|
|
10865
|
+
stdio: "inherit"
|
|
10866
|
+
}
|
|
10867
|
+
);
|
|
10868
|
+
child.on("error", reject);
|
|
10869
|
+
child.on("close", () => {
|
|
10870
|
+
resolve();
|
|
10871
|
+
});
|
|
10872
|
+
});
|
|
10873
|
+
}
|
|
10874
|
+
async function openShell() {
|
|
10875
|
+
await runInteractiveShell({
|
|
10876
|
+
cwd: process.cwd(),
|
|
10877
|
+
execute: dispatchCliTokens
|
|
10878
|
+
});
|
|
10879
|
+
}
|
|
10880
|
+
async function main() {
|
|
10881
|
+
const tokens = normalizeCliTokens(process.argv.slice(2));
|
|
10882
|
+
if (tokens.length === 0) {
|
|
10883
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
10884
|
+
await openShell();
|
|
10885
|
+
return;
|
|
10886
|
+
}
|
|
10887
|
+
const helpProgram = createProgram(openShell);
|
|
10888
|
+
await helpProgram.parseAsync([
|
|
10889
|
+
"node",
|
|
10890
|
+
"kimbho",
|
|
10891
|
+
"--help"
|
|
10892
|
+
]);
|
|
10893
|
+
return;
|
|
10894
|
+
}
|
|
10895
|
+
const program2 = createProgram(openShell);
|
|
10896
|
+
await program2.parseAsync([
|
|
10897
|
+
"node",
|
|
10898
|
+
"kimbho",
|
|
10899
|
+
...tokens
|
|
10900
|
+
]);
|
|
9979
10901
|
}
|
|
9980
|
-
|
|
10902
|
+
main().catch((error) => {
|
|
9981
10903
|
const message = error instanceof Error ? error.message : String(error);
|
|
9982
10904
|
console.error(message);
|
|
9983
10905
|
process.exitCode = 1;
|