@kimbho/kimbho-cli 0.1.1 → 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 +3 -0
- package/dist/index.cjs +667 -150
- 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 {
|
|
@@ -3343,7 +3346,7 @@ var {
|
|
|
3343
3346
|
// package.json
|
|
3344
3347
|
var package_default = {
|
|
3345
3348
|
name: "@kimbho/kimbho-cli",
|
|
3346
|
-
version: "0.1.
|
|
3349
|
+
version: "0.1.2",
|
|
3347
3350
|
description: "Kimbho CLI is a terminal-native coding agent for planning, execution, and verification.",
|
|
3348
3351
|
type: "module",
|
|
3349
3352
|
engines: {
|
|
@@ -3559,6 +3562,10 @@ function listAgentProfiles() {
|
|
|
3559
3562
|
return Object.values(AGENT_CATALOG).sort((left, right) => left.role.localeCompare(right.role));
|
|
3560
3563
|
}
|
|
3561
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
|
+
|
|
3562
3569
|
// ../../node_modules/zod/v3/external.js
|
|
3563
3570
|
var external_exports = {};
|
|
3564
3571
|
__export(external_exports, {
|
|
@@ -4037,8 +4044,8 @@ function getErrorMap() {
|
|
|
4037
4044
|
|
|
4038
4045
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
4039
4046
|
var makeIssue = (params) => {
|
|
4040
|
-
const { data, path:
|
|
4041
|
-
const fullPath = [...
|
|
4047
|
+
const { data, path: path6, errorMaps, issueData } = params;
|
|
4048
|
+
const fullPath = [...path6, ...issueData.path || []];
|
|
4042
4049
|
const fullIssue = {
|
|
4043
4050
|
...issueData,
|
|
4044
4051
|
path: fullPath
|
|
@@ -4154,11 +4161,11 @@ var errorUtil;
|
|
|
4154
4161
|
|
|
4155
4162
|
// ../../node_modules/zod/v3/types.js
|
|
4156
4163
|
var ParseInputLazyPath = class {
|
|
4157
|
-
constructor(parent, value,
|
|
4164
|
+
constructor(parent, value, path6, key) {
|
|
4158
4165
|
this._cachedPath = [];
|
|
4159
4166
|
this.parent = parent;
|
|
4160
4167
|
this.data = value;
|
|
4161
|
-
this._path =
|
|
4168
|
+
this._path = path6;
|
|
4162
4169
|
this._key = key;
|
|
4163
4170
|
}
|
|
4164
4171
|
get path() {
|
|
@@ -7808,6 +7815,16 @@ var KimbhoConfigSchema = external_exports.object({
|
|
|
7808
7815
|
}
|
|
7809
7816
|
});
|
|
7810
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
|
+
|
|
7811
7828
|
// ../core/dist/contracts/session.js
|
|
7812
7829
|
var SessionStatusSchema = external_exports.enum([
|
|
7813
7830
|
"planned",
|
|
@@ -7816,6 +7833,22 @@ var SessionStatusSchema = external_exports.enum([
|
|
|
7816
7833
|
"blocked",
|
|
7817
7834
|
"completed"
|
|
7818
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
|
+
});
|
|
7819
7852
|
var SessionSnapshotSchema = external_exports.object({
|
|
7820
7853
|
id: external_exports.string().min(1),
|
|
7821
7854
|
goal: external_exports.string().min(1),
|
|
@@ -7827,8 +7860,10 @@ var SessionSnapshotSchema = external_exports.object({
|
|
|
7827
7860
|
plan: KimbhoPlanSchema,
|
|
7828
7861
|
readyTaskIds: external_exports.array(external_exports.string()).default([]),
|
|
7829
7862
|
blockedTaskIds: external_exports.array(external_exports.string()).default([]),
|
|
7863
|
+
completedTaskIds: external_exports.array(external_exports.string()).default([]),
|
|
7830
7864
|
assignedAgents: external_exports.array(AgentRoleSchema).default([]),
|
|
7831
|
-
notes: external_exports.array(external_exports.string()).default([])
|
|
7865
|
+
notes: external_exports.array(external_exports.string()).default([]),
|
|
7866
|
+
events: external_exports.array(SessionEventSchema).default([])
|
|
7832
7867
|
});
|
|
7833
7868
|
|
|
7834
7869
|
// ../core/dist/config/config.js
|
|
@@ -8116,14 +8151,6 @@ var ToolDescriptorSchema = external_exports.object({
|
|
|
8116
8151
|
producesArtifacts: external_exports.boolean().default(false),
|
|
8117
8152
|
allowedRoles: external_exports.array(AgentRoleSchema).default([])
|
|
8118
8153
|
});
|
|
8119
|
-
var ToolResultSchema = external_exports.object({
|
|
8120
|
-
toolId: external_exports.string().min(1),
|
|
8121
|
-
success: external_exports.boolean(),
|
|
8122
|
-
summary: external_exports.string().min(1),
|
|
8123
|
-
stdout: external_exports.string().optional(),
|
|
8124
|
-
stderr: external_exports.string().optional(),
|
|
8125
|
-
artifacts: external_exports.array(external_exports.string()).default([])
|
|
8126
|
-
});
|
|
8127
8154
|
|
|
8128
8155
|
// ../tools/dist/registry.js
|
|
8129
8156
|
var BUILTIN_TOOLS = [
|
|
@@ -8233,26 +8260,296 @@ function createDefaultToolRegistry() {
|
|
|
8233
8260
|
return new ToolRegistry(BUILTIN_TOOLS);
|
|
8234
8261
|
}
|
|
8235
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
|
+
|
|
8236
8458
|
// ../agent-runtime/dist/orchestrator.js
|
|
8237
8459
|
function createSessionId() {
|
|
8238
8460
|
return `session-${Date.now()}`;
|
|
8239
8461
|
}
|
|
8462
|
+
function createEventId(type, taskId) {
|
|
8463
|
+
return `${type}-${taskId ?? "session"}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
8464
|
+
}
|
|
8240
8465
|
function isTaskReady(task, completedTaskIds) {
|
|
8241
8466
|
return task.status === "pending" && task.dependsOn.every((taskId) => completedTaskIds.has(taskId));
|
|
8242
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
|
+
}
|
|
8243
8538
|
var ExecutionOrchestrator = class {
|
|
8244
8539
|
toolRegistry;
|
|
8245
|
-
|
|
8540
|
+
toolRuntime;
|
|
8541
|
+
constructor(toolRegistry = createDefaultToolRegistry(), toolRuntime = new ToolRuntime(toolRegistry)) {
|
|
8246
8542
|
this.toolRegistry = toolRegistry;
|
|
8543
|
+
this.toolRuntime = toolRuntime;
|
|
8247
8544
|
}
|
|
8248
|
-
buildEnvelope(request, plan) {
|
|
8545
|
+
buildEnvelope(request, plan, sessionId = createSessionId()) {
|
|
8249
8546
|
const tasks = flattenPlanTasks(plan);
|
|
8250
|
-
const completedTaskIds =
|
|
8547
|
+
const completedTaskIds = completedTaskIdsFromPlan(plan);
|
|
8251
8548
|
const readyTasks = tasks.filter((task) => isTaskReady(task, completedTaskIds));
|
|
8252
8549
|
const blockedTasks = tasks.filter((task) => task.status !== "completed" && !isTaskReady(task, completedTaskIds));
|
|
8253
8550
|
const assignedAgents = this.selectAgentsForTasks(readyTasks);
|
|
8254
8551
|
return {
|
|
8255
|
-
sessionId
|
|
8552
|
+
sessionId,
|
|
8256
8553
|
request,
|
|
8257
8554
|
plan,
|
|
8258
8555
|
readyTasks,
|
|
@@ -8260,9 +8557,9 @@ var ExecutionOrchestrator = class {
|
|
|
8260
8557
|
assignedAgents
|
|
8261
8558
|
};
|
|
8262
8559
|
}
|
|
8263
|
-
createSessionSnapshot(envelope) {
|
|
8560
|
+
createSessionSnapshot(envelope, overrides = {}) {
|
|
8264
8561
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
8265
|
-
const status = envelope.readyTasks.
|
|
8562
|
+
const status = deriveStatus(envelope.plan, envelope.readyTasks, envelope.blockedTasks);
|
|
8266
8563
|
return SessionSnapshotSchema.parse({
|
|
8267
8564
|
id: envelope.sessionId,
|
|
8268
8565
|
goal: envelope.request.goal,
|
|
@@ -8274,11 +8571,75 @@ var ExecutionOrchestrator = class {
|
|
|
8274
8571
|
plan: envelope.plan,
|
|
8275
8572
|
readyTaskIds: envelope.readyTasks.map((task) => task.id),
|
|
8276
8573
|
blockedTaskIds: envelope.blockedTasks.map((task) => task.id),
|
|
8574
|
+
completedTaskIds: Array.from(completedTaskIdsFromPlan(envelope.plan)),
|
|
8277
8575
|
assignedAgents: envelope.assignedAgents.map((agent) => agent.role),
|
|
8278
8576
|
notes: [
|
|
8279
|
-
"Initial session snapshot created from the current plan."
|
|
8280
|
-
|
|
8281
|
-
]
|
|
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
|
|
8282
8643
|
});
|
|
8283
8644
|
}
|
|
8284
8645
|
selectAgentsForTasks(tasks) {
|
|
@@ -8288,6 +8649,107 @@ var ExecutionOrchestrator = class {
|
|
|
8288
8649
|
toolsForAgent(role) {
|
|
8289
8650
|
return this.toolRegistry.byRole(role);
|
|
8290
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
|
+
}
|
|
8291
8753
|
};
|
|
8292
8754
|
|
|
8293
8755
|
// src/commands/agents.ts
|
|
@@ -8313,7 +8775,7 @@ function createAgentsCommand() {
|
|
|
8313
8775
|
}
|
|
8314
8776
|
|
|
8315
8777
|
// src/commands/brains.ts
|
|
8316
|
-
var
|
|
8778
|
+
var import_node_process2 = __toESM(require("node:process"), 1);
|
|
8317
8779
|
|
|
8318
8780
|
// ../brains/dist/templates.js
|
|
8319
8781
|
var BUILTIN_PROVIDER_TEMPLATES = [
|
|
@@ -8389,8 +8851,8 @@ function buildProviderFromTemplate(templateId, options = {}) {
|
|
|
8389
8851
|
}
|
|
8390
8852
|
|
|
8391
8853
|
// ../brains/dist/registry.js
|
|
8392
|
-
var
|
|
8393
|
-
var
|
|
8854
|
+
var import_promises5 = require("node:fs/promises");
|
|
8855
|
+
var import_node_path5 = __toESM(require("node:path"), 1);
|
|
8394
8856
|
var import_node_url = require("node:url");
|
|
8395
8857
|
function resolveApiKey(definition) {
|
|
8396
8858
|
if (!definition.apiKeyEnv) {
|
|
@@ -8828,8 +9290,8 @@ async function createCustomModuleProvider(definition, cwd) {
|
|
|
8828
9290
|
if (!definition.modulePath) {
|
|
8829
9291
|
throw new Error(`Provider "${definition.id}" requires modulePath.`);
|
|
8830
9292
|
}
|
|
8831
|
-
const modulePath =
|
|
8832
|
-
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);
|
|
8833
9295
|
const module2 = await import((0, import_node_url.pathToFileURL)(modulePath).href);
|
|
8834
9296
|
const createProvider = typeof module2.createProvider === "function" ? module2.createProvider : typeof module2.default === "function" ? module2.default : null;
|
|
8835
9297
|
if (!createProvider) {
|
|
@@ -8978,6 +9440,40 @@ function renderPlan(plan) {
|
|
|
8978
9440
|
function renderJson(value) {
|
|
8979
9441
|
return JSON.stringify(value, null, 2);
|
|
8980
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
|
+
}
|
|
8981
9477
|
|
|
8982
9478
|
// src/commands/brains.ts
|
|
8983
9479
|
function parseNumber(value) {
|
|
@@ -8993,7 +9489,7 @@ function requireConfigMessage() {
|
|
|
8993
9489
|
function createBrainsCommand() {
|
|
8994
9490
|
const command = new Command("brains").description("Inspect and assign the LLM brains used by Kimbho roles.");
|
|
8995
9491
|
command.command("list").description("List brain-role assignments.").option("--json", "Print roles as JSON", false).action(async (options) => {
|
|
8996
|
-
const config = await loadConfig(
|
|
9492
|
+
const config = await loadConfig(import_node_process2.default.cwd());
|
|
8997
9493
|
if (!config) {
|
|
8998
9494
|
requireConfigMessage();
|
|
8999
9495
|
}
|
|
@@ -9023,7 +9519,7 @@ function createBrainsCommand() {
|
|
|
9023
9519
|
}
|
|
9024
9520
|
});
|
|
9025
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) => {
|
|
9026
|
-
const config = await loadConfig(
|
|
9522
|
+
const config = await loadConfig(import_node_process2.default.cwd());
|
|
9027
9523
|
if (!config) {
|
|
9028
9524
|
requireConfigMessage();
|
|
9029
9525
|
}
|
|
@@ -9047,12 +9543,12 @@ function createBrainsCommand() {
|
|
|
9047
9543
|
promptPreamble: options.promptPreamble
|
|
9048
9544
|
} : {}
|
|
9049
9545
|
});
|
|
9050
|
-
const outputPath = await saveConfig(nextConfig,
|
|
9546
|
+
const outputPath = await saveConfig(nextConfig, import_node_process2.default.cwd());
|
|
9051
9547
|
console.log(`Updated ${outputPath}`);
|
|
9052
9548
|
console.log(`Brain ${role} -> ${provider.id}/${options.model ?? provider.defaultModel ?? "model not set"}`);
|
|
9053
9549
|
});
|
|
9054
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) => {
|
|
9055
|
-
const config = await loadConfig(
|
|
9551
|
+
const config = await loadConfig(import_node_process2.default.cwd());
|
|
9056
9552
|
if (!config) {
|
|
9057
9553
|
requireConfigMessage();
|
|
9058
9554
|
}
|
|
@@ -9078,10 +9574,10 @@ function createBrainsCommand() {
|
|
|
9078
9574
|
}
|
|
9079
9575
|
|
|
9080
9576
|
// src/commands/doctor.ts
|
|
9081
|
-
var
|
|
9082
|
-
var
|
|
9577
|
+
var import_node_process3 = __toESM(require("node:process"), 1);
|
|
9578
|
+
var import_node_child_process2 = require("node:child_process");
|
|
9083
9579
|
function commandVersion(binary) {
|
|
9084
|
-
const result = (0,
|
|
9580
|
+
const result = (0, import_node_child_process2.spawnSync)(binary, ["--version"], {
|
|
9085
9581
|
encoding: "utf8"
|
|
9086
9582
|
});
|
|
9087
9583
|
if (result.status === 0) {
|
|
@@ -9104,19 +9600,19 @@ function createDoctorCommand() {
|
|
|
9104
9600
|
{
|
|
9105
9601
|
name: "node",
|
|
9106
9602
|
ok: true,
|
|
9107
|
-
detail:
|
|
9603
|
+
detail: import_node_process3.default.version
|
|
9108
9604
|
},
|
|
9109
9605
|
commandVersion("npm"),
|
|
9110
9606
|
commandVersion("git"),
|
|
9111
9607
|
commandVersion("docker")
|
|
9112
9608
|
];
|
|
9113
|
-
const config = await loadConfig(
|
|
9114
|
-
const registry = createDefaultBrainProviderRegistry(
|
|
9609
|
+
const config = await loadConfig(import_node_process3.default.cwd());
|
|
9610
|
+
const registry = createDefaultBrainProviderRegistry(import_node_process3.default.cwd());
|
|
9115
9611
|
if (config) {
|
|
9116
9612
|
checks.push({
|
|
9117
9613
|
name: "config",
|
|
9118
9614
|
ok: true,
|
|
9119
|
-
detail: `${resolveConfigPath(
|
|
9615
|
+
detail: `${resolveConfigPath(import_node_process3.default.cwd())} (${config.providers.length} providers)`
|
|
9120
9616
|
});
|
|
9121
9617
|
for (const provider of config.providers) {
|
|
9122
9618
|
try {
|
|
@@ -9153,7 +9649,7 @@ function createDoctorCommand() {
|
|
|
9153
9649
|
checks.push({
|
|
9154
9650
|
name: "config",
|
|
9155
9651
|
ok: false,
|
|
9156
|
-
detail: `missing (${resolveConfigPath(
|
|
9652
|
+
detail: `missing (${resolveConfigPath(import_node_process3.default.cwd())})`
|
|
9157
9653
|
});
|
|
9158
9654
|
}
|
|
9159
9655
|
for (const check of checks) {
|
|
@@ -9163,13 +9659,13 @@ function createDoctorCommand() {
|
|
|
9163
9659
|
}
|
|
9164
9660
|
|
|
9165
9661
|
// src/commands/init.ts
|
|
9166
|
-
var
|
|
9662
|
+
var import_node_process4 = __toESM(require("node:process"), 1);
|
|
9167
9663
|
function createInitCommand() {
|
|
9168
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) => {
|
|
9169
|
-
const existing = await loadConfig(
|
|
9665
|
+
const existing = await loadConfig(import_node_process4.default.cwd());
|
|
9170
9666
|
if (existing && !options.force) {
|
|
9171
9667
|
console.error("Config already exists. Re-run with --force to overwrite it.");
|
|
9172
|
-
|
|
9668
|
+
import_node_process4.default.exitCode = 1;
|
|
9173
9669
|
return;
|
|
9174
9670
|
}
|
|
9175
9671
|
const templateId = options.template ?? (!options.driver ? "openai" : null);
|
|
@@ -9203,13 +9699,13 @@ function createInitCommand() {
|
|
|
9203
9699
|
defaultModel: options.model ?? provider.defaultModel,
|
|
9204
9700
|
fastModel: options.fastModel ?? options.model ?? provider.defaultModel
|
|
9205
9701
|
});
|
|
9206
|
-
const outputPath = await saveConfig(nextConfig,
|
|
9702
|
+
const outputPath = await saveConfig(nextConfig, import_node_process4.default.cwd());
|
|
9207
9703
|
console.log(`Created ${outputPath}`);
|
|
9208
9704
|
});
|
|
9209
9705
|
}
|
|
9210
9706
|
|
|
9211
9707
|
// src/commands/models.ts
|
|
9212
|
-
var
|
|
9708
|
+
var import_node_process5 = __toESM(require("node:process"), 1);
|
|
9213
9709
|
function parseInteger(value) {
|
|
9214
9710
|
const parsed = Number.parseInt(value, 10);
|
|
9215
9711
|
if (!Number.isFinite(parsed)) {
|
|
@@ -9260,7 +9756,7 @@ async function fetchProviderModels(provider, options) {
|
|
|
9260
9756
|
models: cachedModels
|
|
9261
9757
|
};
|
|
9262
9758
|
}
|
|
9263
|
-
const registry = createDefaultBrainProviderRegistry(
|
|
9759
|
+
const registry = createDefaultBrainProviderRegistry(import_node_process5.default.cwd());
|
|
9264
9760
|
try {
|
|
9265
9761
|
const models = await registry.listModels(provider, {
|
|
9266
9762
|
...options.search ? {
|
|
@@ -9287,7 +9783,7 @@ async function fetchProviderModels(provider, options) {
|
|
|
9287
9783
|
function createModelsCommand() {
|
|
9288
9784
|
const command = new Command("models").description("Discover and select models from configured providers.");
|
|
9289
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) => {
|
|
9290
|
-
let config = await loadConfig(
|
|
9786
|
+
let config = await loadConfig(import_node_process5.default.cwd());
|
|
9291
9787
|
if (!config) {
|
|
9292
9788
|
requireConfigMessage2();
|
|
9293
9789
|
}
|
|
@@ -9316,7 +9812,7 @@ function createModelsCommand() {
|
|
|
9316
9812
|
}
|
|
9317
9813
|
}
|
|
9318
9814
|
if (mutated) {
|
|
9319
|
-
await saveConfig(config,
|
|
9815
|
+
await saveConfig(config, import_node_process5.default.cwd());
|
|
9320
9816
|
}
|
|
9321
9817
|
if (options.json) {
|
|
9322
9818
|
console.log(renderJson(groups));
|
|
@@ -9333,7 +9829,7 @@ function createModelsCommand() {
|
|
|
9333
9829
|
}
|
|
9334
9830
|
});
|
|
9335
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) => {
|
|
9336
|
-
const config = await loadConfig(
|
|
9832
|
+
const config = await loadConfig(import_node_process5.default.cwd());
|
|
9337
9833
|
if (!config) {
|
|
9338
9834
|
requireConfigMessage2();
|
|
9339
9835
|
}
|
|
@@ -9341,7 +9837,7 @@ function createModelsCommand() {
|
|
|
9341
9837
|
if (!provider) {
|
|
9342
9838
|
throw new Error(`Unknown provider "${providerId}".`);
|
|
9343
9839
|
}
|
|
9344
|
-
const registry = createDefaultBrainProviderRegistry(
|
|
9840
|
+
const registry = createDefaultBrainProviderRegistry(import_node_process5.default.cwd());
|
|
9345
9841
|
const models = await registry.listModels(provider, {
|
|
9346
9842
|
...options.search ? {
|
|
9347
9843
|
search: options.search
|
|
@@ -9352,12 +9848,12 @@ function createModelsCommand() {
|
|
|
9352
9848
|
...provider,
|
|
9353
9849
|
models: Array.from(new Set(models.map((model) => model.id)))
|
|
9354
9850
|
});
|
|
9355
|
-
const outputPath = await saveConfig(nextConfig,
|
|
9851
|
+
const outputPath = await saveConfig(nextConfig, import_node_process5.default.cwd());
|
|
9356
9852
|
console.log(`Updated ${outputPath}`);
|
|
9357
9853
|
console.log(`Synced ${models.length} models for ${provider.id}`);
|
|
9358
9854
|
});
|
|
9359
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) => {
|
|
9360
|
-
let config = await loadConfig(
|
|
9856
|
+
let config = await loadConfig(import_node_process5.default.cwd());
|
|
9361
9857
|
if (!config) {
|
|
9362
9858
|
requireConfigMessage2();
|
|
9363
9859
|
}
|
|
@@ -9367,7 +9863,7 @@ function createModelsCommand() {
|
|
|
9367
9863
|
}
|
|
9368
9864
|
if (!options.force) {
|
|
9369
9865
|
try {
|
|
9370
|
-
const registry = createDefaultBrainProviderRegistry(
|
|
9866
|
+
const registry = createDefaultBrainProviderRegistry(import_node_process5.default.cwd());
|
|
9371
9867
|
const models = await registry.listModels(provider, {
|
|
9372
9868
|
search: model,
|
|
9373
9869
|
limit: 500
|
|
@@ -9407,7 +9903,7 @@ function createModelsCommand() {
|
|
|
9407
9903
|
} : {}
|
|
9408
9904
|
});
|
|
9409
9905
|
}
|
|
9410
|
-
const outputPath = await saveConfig(config,
|
|
9906
|
+
const outputPath = await saveConfig(config, import_node_process5.default.cwd());
|
|
9411
9907
|
console.log(`Updated ${outputPath}`);
|
|
9412
9908
|
console.log(`Selected ${provider.id}/${model}`);
|
|
9413
9909
|
if (options.role) {
|
|
@@ -9421,8 +9917,8 @@ function createModelsCommand() {
|
|
|
9421
9917
|
}
|
|
9422
9918
|
|
|
9423
9919
|
// src/commands/plan.ts
|
|
9424
|
-
var
|
|
9425
|
-
var
|
|
9920
|
+
var import_promises6 = require("node:fs/promises");
|
|
9921
|
+
var import_node_process6 = __toESM(require("node:process"), 1);
|
|
9426
9922
|
|
|
9427
9923
|
// ../planner/dist/planner.js
|
|
9428
9924
|
function normalizeGoal(goal) {
|
|
@@ -9726,7 +10222,7 @@ function createPlan(input) {
|
|
|
9726
10222
|
|
|
9727
10223
|
// src/commands/plan.ts
|
|
9728
10224
|
async function detectWorkspaceState(cwd) {
|
|
9729
|
-
const entries = await (0,
|
|
10225
|
+
const entries = await (0, import_promises6.readdir)(cwd);
|
|
9730
10226
|
const meaningfulEntries = entries.filter((entry) => entry !== ".kimbho" && !entry.startsWith("."));
|
|
9731
10227
|
return meaningfulEntries.length === 0 ? "empty" : "existing";
|
|
9732
10228
|
}
|
|
@@ -9737,7 +10233,7 @@ function createPlanCommand() {
|
|
|
9737
10233
|
(value, previous = []) => [...previous, value],
|
|
9738
10234
|
[]
|
|
9739
10235
|
).option("--json", "Print the plan as JSON", false).action(async (goal, options) => {
|
|
9740
|
-
const cwd =
|
|
10236
|
+
const cwd = import_node_process6.default.cwd();
|
|
9741
10237
|
const request = {
|
|
9742
10238
|
goal,
|
|
9743
10239
|
mode: "plan",
|
|
@@ -9774,14 +10270,14 @@ function createPlanCommand() {
|
|
|
9774
10270
|
}
|
|
9775
10271
|
|
|
9776
10272
|
// src/commands/providers.ts
|
|
9777
|
-
var
|
|
10273
|
+
var import_node_process7 = __toESM(require("node:process"), 1);
|
|
9778
10274
|
function requireConfigMessage3() {
|
|
9779
10275
|
throw new Error("No config found. Run `kimbho init` first.");
|
|
9780
10276
|
}
|
|
9781
10277
|
function createProvidersCommand() {
|
|
9782
10278
|
const command = new Command("providers").description("Manage configured model providers and built-in templates.");
|
|
9783
10279
|
command.command("list").description("List configured providers.").option("--json", "Print providers as JSON", false).action(async (options) => {
|
|
9784
|
-
const config = await loadConfig(
|
|
10280
|
+
const config = await loadConfig(import_node_process7.default.cwd());
|
|
9785
10281
|
if (!config) {
|
|
9786
10282
|
requireConfigMessage3();
|
|
9787
10283
|
}
|
|
@@ -9822,7 +10318,7 @@ function createProvidersCommand() {
|
|
|
9822
10318
|
(value, previous = []) => [...previous, value],
|
|
9823
10319
|
[]
|
|
9824
10320
|
).option("--module-path <path>", "Module path for a custom provider driver").action(async (options) => {
|
|
9825
|
-
const config = await loadConfig(
|
|
10321
|
+
const config = await loadConfig(import_node_process7.default.cwd());
|
|
9826
10322
|
if (!config) {
|
|
9827
10323
|
requireConfigMessage3();
|
|
9828
10324
|
}
|
|
@@ -9856,16 +10352,16 @@ function createProvidersCommand() {
|
|
|
9856
10352
|
} : {}
|
|
9857
10353
|
});
|
|
9858
10354
|
const nextConfig = upsertProvider(config, provider);
|
|
9859
|
-
const outputPath = await saveConfig(nextConfig,
|
|
10355
|
+
const outputPath = await saveConfig(nextConfig, import_node_process7.default.cwd());
|
|
9860
10356
|
console.log(`Updated ${outputPath}`);
|
|
9861
10357
|
console.log(`Provider ${provider.id} -> ${provider.driver}`);
|
|
9862
10358
|
});
|
|
9863
10359
|
command.command("check").description("Run health checks for the configured providers.").action(async () => {
|
|
9864
|
-
const config = await loadConfig(
|
|
10360
|
+
const config = await loadConfig(import_node_process7.default.cwd());
|
|
9865
10361
|
if (!config) {
|
|
9866
10362
|
requireConfigMessage3();
|
|
9867
10363
|
}
|
|
9868
|
-
const registry = createDefaultBrainProviderRegistry(
|
|
10364
|
+
const registry = createDefaultBrainProviderRegistry(import_node_process7.default.cwd());
|
|
9869
10365
|
for (const provider of config.providers) {
|
|
9870
10366
|
try {
|
|
9871
10367
|
const result = await registry.healthCheck(provider);
|
|
@@ -9880,52 +10376,67 @@ function createProvidersCommand() {
|
|
|
9880
10376
|
}
|
|
9881
10377
|
|
|
9882
10378
|
// src/commands/resume.ts
|
|
9883
|
-
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
|
+
}
|
|
9884
10387
|
function createResumeCommand() {
|
|
9885
|
-
return new Command("resume").description("Resume the latest saved Kimbho session snapshot.").option("--json", "Print the latest session as JSON", false).action(async (options) => {
|
|
9886
|
-
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);
|
|
9887
10391
|
if (!session) {
|
|
9888
10392
|
console.error("No saved session found. Run `kimbho run` first.");
|
|
9889
|
-
|
|
10393
|
+
import_node_process8.default.exitCode = 1;
|
|
9890
10394
|
return;
|
|
9891
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
|
+
}
|
|
9892
10402
|
if (options.json) {
|
|
9893
|
-
console.log(renderJson(
|
|
10403
|
+
console.log(renderJson(snapshot));
|
|
9894
10404
|
return;
|
|
9895
10405
|
}
|
|
9896
|
-
console.log(
|
|
9897
|
-
console.log(`Goal: ${session.goal}`);
|
|
9898
|
-
console.log(`Status: ${session.status}`);
|
|
9899
|
-
console.log(`Ready tasks: ${session.readyTaskIds.join(", ") || "none"}`);
|
|
9900
|
-
console.log(`Blocked tasks: ${session.blockedTaskIds.join(", ") || "none"}`);
|
|
9901
|
-
console.log(`Assigned agents: ${session.assignedAgents.join(", ") || "none"}`);
|
|
9902
|
-
console.log(`Notes: ${session.notes.join(" | ") || "none"}`);
|
|
10406
|
+
console.log(renderSession(snapshot));
|
|
9903
10407
|
});
|
|
9904
10408
|
}
|
|
9905
10409
|
|
|
9906
10410
|
// src/commands/run.ts
|
|
9907
|
-
var
|
|
9908
|
-
var
|
|
10411
|
+
var import_promises7 = require("node:fs/promises");
|
|
10412
|
+
var import_node_process9 = __toESM(require("node:process"), 1);
|
|
9909
10413
|
async function detectWorkspaceState2(cwd) {
|
|
9910
|
-
const entries = await (0,
|
|
10414
|
+
const entries = await (0, import_promises7.readdir)(cwd);
|
|
9911
10415
|
const meaningfulEntries = entries.filter((entry) => entry !== ".kimbho" && !entry.startsWith("."));
|
|
9912
10416
|
return meaningfulEntries.length === 0 ? "empty" : "existing";
|
|
9913
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
|
+
}
|
|
9914
10425
|
function createRunCommand() {
|
|
9915
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(
|
|
9916
10427
|
"--constraint <constraint>",
|
|
9917
10428
|
"Explicit execution constraint; can be provided multiple times",
|
|
9918
10429
|
(value, previous = []) => [...previous, value],
|
|
9919
10430
|
[]
|
|
9920
|
-
).option("--json", "Print the session snapshot as JSON", false).action(async (goal, options) => {
|
|
9921
|
-
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();
|
|
9922
10433
|
const orchestrator = new ExecutionOrchestrator();
|
|
9923
10434
|
let request;
|
|
9924
10435
|
let planPath = null;
|
|
9925
10436
|
let plan = goal ? null : await loadLatestPlan(cwd);
|
|
9926
10437
|
if (!plan && !goal) {
|
|
9927
10438
|
console.error("No saved plan found. Pass a goal or run `kimbho plan` first.");
|
|
9928
|
-
|
|
10439
|
+
import_node_process9.default.exitCode = 1;
|
|
9929
10440
|
return;
|
|
9930
10441
|
}
|
|
9931
10442
|
if (goal) {
|
|
@@ -9950,7 +10461,10 @@ function createRunCommand() {
|
|
|
9950
10461
|
};
|
|
9951
10462
|
}
|
|
9952
10463
|
const envelope = orchestrator.buildEnvelope(request, plan);
|
|
9953
|
-
const
|
|
10464
|
+
const initialSnapshot = orchestrator.createSessionSnapshot(envelope);
|
|
10465
|
+
const snapshot = options.snapshotOnly ? initialSnapshot : await orchestrator.continueSession(initialSnapshot, {
|
|
10466
|
+
maxAutoTasks: options.maxAutoTasks
|
|
10467
|
+
});
|
|
9954
10468
|
const sessionPath = await saveSession(snapshot, cwd);
|
|
9955
10469
|
if (options.json) {
|
|
9956
10470
|
console.log(
|
|
@@ -9964,15 +10478,12 @@ function createRunCommand() {
|
|
|
9964
10478
|
}
|
|
9965
10479
|
console.log(renderPlan(plan));
|
|
9966
10480
|
console.log("");
|
|
9967
|
-
console.log(
|
|
9968
|
-
console.log(
|
|
10481
|
+
console.log(renderSession(snapshot));
|
|
10482
|
+
console.log("");
|
|
9969
10483
|
if (planPath) {
|
|
9970
10484
|
console.log(`Saved plan: ${planPath}`);
|
|
9971
10485
|
}
|
|
9972
|
-
console.log(`
|
|
9973
|
-
console.log(`Ready tasks: ${snapshot.readyTaskIds.join(", ") || "none"}`);
|
|
9974
|
-
console.log(`Blocked tasks: ${snapshot.blockedTaskIds.join(", ") || "none"}`);
|
|
9975
|
-
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}`);
|
|
9976
10487
|
});
|
|
9977
10488
|
}
|
|
9978
10489
|
|
|
@@ -10040,8 +10551,8 @@ function createProgram(onOpenShell) {
|
|
|
10040
10551
|
}
|
|
10041
10552
|
|
|
10042
10553
|
// src/shell.ts
|
|
10043
|
-
var
|
|
10044
|
-
var
|
|
10554
|
+
var import_promises8 = require("node:readline/promises");
|
|
10555
|
+
var import_node_process10 = __toESM(require("node:process"), 1);
|
|
10045
10556
|
var AMBER = "\x1B[38;5;214m";
|
|
10046
10557
|
var BOLD = "\x1B[1m";
|
|
10047
10558
|
var DIM = "\x1B[2m";
|
|
@@ -10269,10 +10780,10 @@ function toCommandTokens(input) {
|
|
|
10269
10780
|
return tokens;
|
|
10270
10781
|
}
|
|
10271
10782
|
async function runInteractiveShell(options) {
|
|
10272
|
-
const readline = (0,
|
|
10273
|
-
input:
|
|
10274
|
-
output:
|
|
10275
|
-
terminal: Boolean(
|
|
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)
|
|
10276
10787
|
});
|
|
10277
10788
|
let closed = false;
|
|
10278
10789
|
readline.on("SIGINT", () => {
|
|
@@ -10309,8 +10820,8 @@ async function runInteractiveShell(options) {
|
|
|
10309
10820
|
continue;
|
|
10310
10821
|
}
|
|
10311
10822
|
if (trimmed === "/clear" || trimmed === "clear") {
|
|
10312
|
-
if (
|
|
10313
|
-
|
|
10823
|
+
if (import_node_process10.default.stdout.isTTY) {
|
|
10824
|
+
import_node_process10.default.stdout.write("\x1Bc");
|
|
10314
10825
|
}
|
|
10315
10826
|
state = await getShellSessionState(options.cwd);
|
|
10316
10827
|
printHeader(options.cwd, state);
|
|
@@ -10326,33 +10837,39 @@ async function runInteractiveShell(options) {
|
|
|
10326
10837
|
const message = error instanceof Error ? error.message : String(error);
|
|
10327
10838
|
console.error(message);
|
|
10328
10839
|
} finally {
|
|
10329
|
-
|
|
10840
|
+
import_node_process10.default.exitCode = 0;
|
|
10330
10841
|
}
|
|
10331
10842
|
if (!closed) {
|
|
10332
10843
|
console.log("");
|
|
10333
10844
|
}
|
|
10334
10845
|
}
|
|
10335
10846
|
readline.close();
|
|
10336
|
-
|
|
10847
|
+
import_node_process10.default.exitCode = 0;
|
|
10337
10848
|
console.log(color(DIM, "Leaving Kimbho."));
|
|
10338
10849
|
}
|
|
10339
10850
|
|
|
10340
10851
|
// src/index.ts
|
|
10341
10852
|
async function dispatchCliTokens(tokens) {
|
|
10342
|
-
const
|
|
10343
|
-
|
|
10344
|
-
|
|
10345
|
-
|
|
10346
|
-
|
|
10347
|
-
|
|
10348
|
-
|
|
10349
|
-
|
|
10350
|
-
|
|
10351
|
-
|
|
10352
|
-
|
|
10353
|
-
|
|
10354
|
-
|
|
10355
|
-
|
|
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
|
+
});
|
|
10356
10873
|
}
|
|
10357
10874
|
async function openShell() {
|
|
10358
10875
|
await runInteractiveShell({
|