@kimbho/kimbho-cli 0.1.0 → 0.1.1
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 +14 -0
- package/dist/index.cjs +453 -48
- package/dist/index.cjs.map +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,12 +28,26 @@ npm install -g ./kimbho-kimbho-cli-0.1.0.tgz
|
|
|
28
28
|
## Usage
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
+
kimbho
|
|
32
|
+
kimbho shell
|
|
31
33
|
kimbho --help
|
|
32
34
|
kimbho init
|
|
33
35
|
kimbho plan "build a coding agent"
|
|
34
36
|
kimbho /models openrouter --search claude --limit 10
|
|
35
37
|
```
|
|
36
38
|
|
|
39
|
+
Bare `kimbho` opens the interactive shell. Within that shell, plain-English input is treated as `run <goal>`, and slash commands like `/plan`, `/run`, `/models`, and `/brains` are supported.
|
|
40
|
+
|
|
41
|
+
Useful shell commands:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
/status
|
|
45
|
+
/model
|
|
46
|
+
/plan build a coding agent
|
|
47
|
+
/run scaffold a SaaS starter
|
|
48
|
+
/quit
|
|
49
|
+
```
|
|
50
|
+
|
|
37
51
|
## Notes
|
|
38
52
|
|
|
39
53
|
- The published CLI bundles the internal Kimbho packages so installation does not depend on the monorepo layout.
|
package/dist/index.cjs
CHANGED
|
@@ -1149,7 +1149,7 @@ var require_command = __commonJS({
|
|
|
1149
1149
|
var childProcess = require("node:child_process");
|
|
1150
1150
|
var path4 = require("node:path");
|
|
1151
1151
|
var fs = require("node:fs");
|
|
1152
|
-
var
|
|
1152
|
+
var process11 = 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) => process11.stdout.write(str),
|
|
1200
|
+
writeErr: (str) => process11.stderr.write(str),
|
|
1201
1201
|
outputError: (str, write) => write(str),
|
|
1202
|
-
getOutHelpWidth: () =>
|
|
1203
|
-
getErrHelpWidth: () =>
|
|
1204
|
-
getOutHasColors: () => useColor() ?? (
|
|
1205
|
-
getErrHasColors: () => useColor() ?? (
|
|
1202
|
+
getOutHelpWidth: () => process11.stdout.isTTY ? process11.stdout.columns : void 0,
|
|
1203
|
+
getErrHelpWidth: () => process11.stderr.isTTY ? process11.stderr.columns : void 0,
|
|
1204
|
+
getOutHasColors: () => useColor() ?? (process11.stdout.isTTY && process11.stdout.hasColors?.()),
|
|
1205
|
+
getErrHasColors: () => useColor() ?? (process11.stderr.isTTY && process11.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
|
+
process11.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 (process11.versions?.electron) {
|
|
1987
1987
|
parseOptions.from = "electron";
|
|
1988
1988
|
}
|
|
1989
|
-
const execArgv =
|
|
1989
|
+
const execArgv = process11.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 = process11.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 (process11.defaultApp) {
|
|
2007
2007
|
this._scriptPath = argv[1];
|
|
2008
2008
|
userArgs = argv.slice(2);
|
|
2009
2009
|
} else {
|
|
@@ -2190,11 +2190,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2190
2190
|
}
|
|
2191
2191
|
launchWithNode = sourceExt.includes(path4.extname(executableFile));
|
|
2192
2192
|
let proc;
|
|
2193
|
-
if (
|
|
2193
|
+
if (process11.platform !== "win32") {
|
|
2194
2194
|
if (launchWithNode) {
|
|
2195
2195
|
args.unshift(executableFile);
|
|
2196
|
-
args = incrementNodeInspectorPort(
|
|
2197
|
-
proc = childProcess.spawn(
|
|
2196
|
+
args = incrementNodeInspectorPort(process11.execArgv).concat(args);
|
|
2197
|
+
proc = childProcess.spawn(process11.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(process11.execArgv).concat(args);
|
|
2209
|
+
proc = childProcess.spawn(process11.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
|
+
process11.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
|
+
process11.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
|
+
process11.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 process11.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()}`, process11.env[option.envVar]);
|
|
2749
2749
|
} else {
|
|
2750
2750
|
this.emit(`optionEnv:${option.name()}`);
|
|
2751
2751
|
}
|
|
@@ -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(process11.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 (process11.env.NO_COLOR || process11.env.FORCE_COLOR === "0" || process11.env.FORCE_COLOR === "false")
|
|
3294
3294
|
return false;
|
|
3295
|
-
if (
|
|
3295
|
+
if (process11.env.FORCE_COLOR || process11.env.CLICOLOR_FORCE !== void 0)
|
|
3296
3296
|
return true;
|
|
3297
3297
|
return void 0;
|
|
3298
3298
|
}
|
|
@@ -3340,6 +3340,55 @@ var {
|
|
|
3340
3340
|
Help
|
|
3341
3341
|
} = import_index.default;
|
|
3342
3342
|
|
|
3343
|
+
// package.json
|
|
3344
|
+
var package_default = {
|
|
3345
|
+
name: "@kimbho/kimbho-cli",
|
|
3346
|
+
version: "0.1.1",
|
|
3347
|
+
description: "Kimbho CLI is a terminal-native coding agent for planning, execution, and verification.",
|
|
3348
|
+
type: "module",
|
|
3349
|
+
engines: {
|
|
3350
|
+
node: ">=20.0.0"
|
|
3351
|
+
},
|
|
3352
|
+
preferGlobal: true,
|
|
3353
|
+
bin: {
|
|
3354
|
+
kimbho: "dist/index.cjs"
|
|
3355
|
+
},
|
|
3356
|
+
main: "dist/index.cjs",
|
|
3357
|
+
exports: {
|
|
3358
|
+
".": {
|
|
3359
|
+
default: "./dist/index.cjs"
|
|
3360
|
+
}
|
|
3361
|
+
},
|
|
3362
|
+
files: [
|
|
3363
|
+
"dist",
|
|
3364
|
+
"README.md"
|
|
3365
|
+
],
|
|
3366
|
+
publishConfig: {
|
|
3367
|
+
access: "public"
|
|
3368
|
+
},
|
|
3369
|
+
scripts: {
|
|
3370
|
+
build: "npm run clean && npm run build:bundle && npm run chmod:bin",
|
|
3371
|
+
"build:bundle": "esbuild src/index.ts --bundle --platform=node --format=cjs --sourcemap --outfile=dist/index.cjs --banner:js='#!/usr/bin/env node'",
|
|
3372
|
+
"chmod:bin": `node -e "require('node:fs').chmodSync('dist/index.cjs', 0o755)"`,
|
|
3373
|
+
clean: `node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"`,
|
|
3374
|
+
prepack: "npm run build"
|
|
3375
|
+
},
|
|
3376
|
+
dependencies: {
|
|
3377
|
+
commander: "^13.1.0"
|
|
3378
|
+
},
|
|
3379
|
+
devDependencies: {
|
|
3380
|
+
"@kimbho/agent-runtime": "file:../agent-runtime",
|
|
3381
|
+
"@kimbho/brains": "file:../brains",
|
|
3382
|
+
"@kimbho/core": "file:../core",
|
|
3383
|
+
"@kimbho/planner": "file:../planner",
|
|
3384
|
+
"@kimbho/tools": "file:../tools"
|
|
3385
|
+
}
|
|
3386
|
+
};
|
|
3387
|
+
|
|
3388
|
+
// src/metadata.ts
|
|
3389
|
+
var KIMBHO_VERSION = package_default.version;
|
|
3390
|
+
var KIMBHO_DESCRIPTION = "Kimbho CLI: a terminal-native coding agent for planning and execution.";
|
|
3391
|
+
|
|
3343
3392
|
// ../agent-runtime/dist/agents/catalog.js
|
|
3344
3393
|
var AGENT_CATALOG = {
|
|
3345
3394
|
"session-orchestrator": {
|
|
@@ -9948,36 +9997,392 @@ function createReviewCommand() {
|
|
|
9948
9997
|
);
|
|
9949
9998
|
}
|
|
9950
9999
|
|
|
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([
|
|
10000
|
+
// src/program.ts
|
|
10001
|
+
var MODELS_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
9969
10002
|
"help",
|
|
9970
10003
|
"list",
|
|
9971
10004
|
"sync",
|
|
9972
10005
|
"use"
|
|
9973
10006
|
]);
|
|
9974
|
-
|
|
9975
|
-
const
|
|
9976
|
-
if (
|
|
9977
|
-
|
|
10007
|
+
function normalizeCliTokens(tokens) {
|
|
10008
|
+
const normalized = [...tokens];
|
|
10009
|
+
if (normalized[0]?.startsWith("/")) {
|
|
10010
|
+
normalized[0] = normalized[0].slice(1);
|
|
10011
|
+
}
|
|
10012
|
+
if (normalized[0] === "models") {
|
|
10013
|
+
const candidate = normalized[1];
|
|
10014
|
+
if (!candidate || candidate.startsWith("-") || !MODELS_SUBCOMMANDS.has(candidate)) {
|
|
10015
|
+
normalized.splice(1, 0, "list");
|
|
10016
|
+
}
|
|
10017
|
+
}
|
|
10018
|
+
return normalized;
|
|
10019
|
+
}
|
|
10020
|
+
function createProgram(onOpenShell) {
|
|
10021
|
+
const program2 = new Command();
|
|
10022
|
+
program2.name("kimbho").description(KIMBHO_DESCRIPTION).version(KIMBHO_VERSION);
|
|
10023
|
+
program2.addCommand(createInitCommand());
|
|
10024
|
+
program2.addCommand(createPlanCommand());
|
|
10025
|
+
program2.addCommand(createDoctorCommand());
|
|
10026
|
+
program2.addCommand(createAgentsCommand());
|
|
10027
|
+
program2.addCommand(createProvidersCommand());
|
|
10028
|
+
program2.addCommand(createModelsCommand());
|
|
10029
|
+
program2.addCommand(createBrainsCommand());
|
|
10030
|
+
program2.addCommand(createRunCommand());
|
|
10031
|
+
program2.addCommand(createResumeCommand());
|
|
10032
|
+
program2.addCommand(createFixCommand());
|
|
10033
|
+
program2.addCommand(createReviewCommand());
|
|
10034
|
+
if (onOpenShell) {
|
|
10035
|
+
program2.command("shell").description("Open the interactive Kimbho shell.").action(async () => {
|
|
10036
|
+
await onOpenShell();
|
|
10037
|
+
});
|
|
10038
|
+
}
|
|
10039
|
+
return program2;
|
|
10040
|
+
}
|
|
10041
|
+
|
|
10042
|
+
// src/shell.ts
|
|
10043
|
+
var import_promises6 = require("node:readline/promises");
|
|
10044
|
+
var import_node_process9 = __toESM(require("node:process"), 1);
|
|
10045
|
+
var AMBER = "\x1B[38;5;214m";
|
|
10046
|
+
var BOLD = "\x1B[1m";
|
|
10047
|
+
var DIM = "\x1B[2m";
|
|
10048
|
+
var RESET = "\x1B[0m";
|
|
10049
|
+
var TOP_LEVEL_COMMANDS = /* @__PURE__ */ new Set([
|
|
10050
|
+
"agents",
|
|
10051
|
+
"brains",
|
|
10052
|
+
"doctor",
|
|
10053
|
+
"fix",
|
|
10054
|
+
"help",
|
|
10055
|
+
"init",
|
|
10056
|
+
"model",
|
|
10057
|
+
"models",
|
|
10058
|
+
"new",
|
|
10059
|
+
"plan",
|
|
10060
|
+
"providers",
|
|
10061
|
+
"quit",
|
|
10062
|
+
"resume",
|
|
10063
|
+
"review",
|
|
10064
|
+
"run",
|
|
10065
|
+
"scaffold",
|
|
10066
|
+
"shell",
|
|
10067
|
+
"status"
|
|
10068
|
+
]);
|
|
10069
|
+
function color(code, value) {
|
|
10070
|
+
return `${code}${value}${RESET}`;
|
|
10071
|
+
}
|
|
10072
|
+
function renderBanner() {
|
|
10073
|
+
return [
|
|
10074
|
+
" _ ___ __ __ ____ ____ _ _ ___ ",
|
|
10075
|
+
"| |/ (_) \\/ | __ )| _ \\| | | |/ _ \\",
|
|
10076
|
+
"| ' /| | |\\/| | _ \\| | | | |_| | | | |",
|
|
10077
|
+
"| . \\| | | | | |_) | |_| | _ | |_| |",
|
|
10078
|
+
"|_|\\_\\_|_| |_|____/|____/|_| |_|\\___/ "
|
|
10079
|
+
].map((line) => color(AMBER, line)).join("\n");
|
|
10080
|
+
}
|
|
10081
|
+
async function getShellSessionState(cwd) {
|
|
10082
|
+
const config = await loadConfig(cwd);
|
|
10083
|
+
if (!config) {
|
|
10084
|
+
return {
|
|
10085
|
+
providerLabel: "unconfigured",
|
|
10086
|
+
providerId: "-",
|
|
10087
|
+
coderModel: "not set",
|
|
10088
|
+
plannerModel: "not set",
|
|
10089
|
+
approvalMode: "manual",
|
|
10090
|
+
sandboxMode: "workspace-write",
|
|
10091
|
+
stackPreset: "next-prisma-postgres",
|
|
10092
|
+
configured: false
|
|
10093
|
+
};
|
|
10094
|
+
}
|
|
10095
|
+
const coderSettings = config.brains.coder;
|
|
10096
|
+
const provider = findProviderById(config, coderSettings.providerId);
|
|
10097
|
+
return {
|
|
10098
|
+
providerLabel: provider?.label ?? provider?.id ?? "unknown",
|
|
10099
|
+
providerId: provider?.id ?? coderSettings.providerId,
|
|
10100
|
+
coderModel: resolveBrainModel(config, "coder") ?? "not set",
|
|
10101
|
+
plannerModel: resolveBrainModel(config, "planner") ?? "not set",
|
|
10102
|
+
approvalMode: config.approvalMode,
|
|
10103
|
+
sandboxMode: config.sandboxMode,
|
|
10104
|
+
stackPreset: config.stackPresets[0] ?? "none",
|
|
10105
|
+
configured: true
|
|
10106
|
+
};
|
|
10107
|
+
}
|
|
10108
|
+
function renderCardLine(label, value) {
|
|
10109
|
+
return `${label}: ${value}`;
|
|
10110
|
+
}
|
|
10111
|
+
function shortenMiddle(value, maxLength) {
|
|
10112
|
+
if (value.length <= maxLength) {
|
|
10113
|
+
return value;
|
|
10114
|
+
}
|
|
10115
|
+
const visible = maxLength - 3;
|
|
10116
|
+
const left = Math.ceil(visible / 2);
|
|
10117
|
+
const right = Math.floor(visible / 2);
|
|
10118
|
+
return `${value.slice(0, left)}...${value.slice(value.length - right)}`;
|
|
10119
|
+
}
|
|
10120
|
+
function renderBox(lines) {
|
|
10121
|
+
const width = lines.reduce((max, line) => Math.max(max, line.length), 0);
|
|
10122
|
+
const top = `+${"-".repeat(width + 2)}+`;
|
|
10123
|
+
return [
|
|
10124
|
+
top,
|
|
10125
|
+
...lines.map((line) => `| ${line.padEnd(width, " ")} |`),
|
|
10126
|
+
top
|
|
10127
|
+
].join("\n");
|
|
10128
|
+
}
|
|
10129
|
+
function renderHelp() {
|
|
10130
|
+
return [
|
|
10131
|
+
`${color(DIM, "Commands")}`,
|
|
10132
|
+
"/status Show the active model, provider, and workspace state.",
|
|
10133
|
+
"/plan <goal> Create a structured implementation plan.",
|
|
10134
|
+
"/run <goal> Start a Kimbho execution session for a goal.",
|
|
10135
|
+
"/new <goal> Alias for /run <goal>.",
|
|
10136
|
+
"/scaffold <goal> Alias for /run <goal> with scaffolding intent.",
|
|
10137
|
+
"/resume Show the latest saved session.",
|
|
10138
|
+
"/agents Inspect agent roles and the active session.",
|
|
10139
|
+
"/providers Manage model providers.",
|
|
10140
|
+
"/model Show the active planner/coder model selection.",
|
|
10141
|
+
"/models Discover and select provider models.",
|
|
10142
|
+
"/brains Inspect or assign planner/coder/reviewer brains.",
|
|
10143
|
+
"/doctor Check local environment and config.",
|
|
10144
|
+
"/clear Redraw the shell.",
|
|
10145
|
+
"/quit, /exit Leave the shell.",
|
|
10146
|
+
"",
|
|
10147
|
+
`${color(DIM, "Tip")}`,
|
|
10148
|
+
"Type a natural-language goal directly and Kimbho will treat it as /run <goal>."
|
|
10149
|
+
].join("\n");
|
|
10150
|
+
}
|
|
10151
|
+
function renderStartupCard(cwd, state) {
|
|
10152
|
+
const cardLines = [
|
|
10153
|
+
`${color(BOLD, "Kimbho CLI")} (v${KIMBHO_VERSION})`,
|
|
10154
|
+
renderCardLine("coder", state.coderModel),
|
|
10155
|
+
renderCardLine("planner", state.plannerModel),
|
|
10156
|
+
renderCardLine("provider", `${state.providerLabel} [${state.providerId}]`),
|
|
10157
|
+
renderCardLine("directory", shortenMiddle(cwd, 78)),
|
|
10158
|
+
renderCardLine("approval", state.approvalMode),
|
|
10159
|
+
renderCardLine("sandbox", state.sandboxMode),
|
|
10160
|
+
renderCardLine("preset", state.stackPreset),
|
|
10161
|
+
renderCardLine("shortcuts", "/help /status /plan /run /models /brains /quit")
|
|
10162
|
+
];
|
|
10163
|
+
if (!state.configured) {
|
|
10164
|
+
cardLines.push("setup: run /init to create .kimbho/config.json");
|
|
10165
|
+
}
|
|
10166
|
+
return renderBox(cardLines);
|
|
10167
|
+
}
|
|
10168
|
+
function formatPrompt(state) {
|
|
10169
|
+
const coderModel = state.coderModel === "not set" ? "unconfigured" : shortenMiddle(state.coderModel, 18);
|
|
10170
|
+
return `${color(AMBER, "kimbho")} ${color(DIM, `[${coderModel}]`)} > `;
|
|
10171
|
+
}
|
|
10172
|
+
function printHeader(cwd, state) {
|
|
10173
|
+
console.log(renderBanner());
|
|
10174
|
+
console.log(color(DIM, "Terminal-native coding agent"));
|
|
10175
|
+
console.log(renderStartupCard(cwd, state));
|
|
10176
|
+
console.log("");
|
|
10177
|
+
console.log(color(DIM, "Tip: describe the app or repo change you want, and Kimbho will route it into /run."));
|
|
10178
|
+
console.log(renderHelp());
|
|
10179
|
+
console.log("");
|
|
10180
|
+
}
|
|
10181
|
+
function tokenizeInput(input) {
|
|
10182
|
+
const tokens = [];
|
|
10183
|
+
let current = "";
|
|
10184
|
+
let quote = null;
|
|
10185
|
+
let escaping = false;
|
|
10186
|
+
for (const character of input) {
|
|
10187
|
+
if (escaping) {
|
|
10188
|
+
current += character;
|
|
10189
|
+
escaping = false;
|
|
10190
|
+
continue;
|
|
10191
|
+
}
|
|
10192
|
+
if (character === "\\") {
|
|
10193
|
+
escaping = true;
|
|
10194
|
+
continue;
|
|
10195
|
+
}
|
|
10196
|
+
if (quote) {
|
|
10197
|
+
if (character === quote) {
|
|
10198
|
+
quote = null;
|
|
10199
|
+
} else {
|
|
10200
|
+
current += character;
|
|
10201
|
+
}
|
|
10202
|
+
continue;
|
|
10203
|
+
}
|
|
10204
|
+
if (character === "'" || character === '"') {
|
|
10205
|
+
quote = character;
|
|
10206
|
+
continue;
|
|
10207
|
+
}
|
|
10208
|
+
if (/\s/.test(character)) {
|
|
10209
|
+
if (current) {
|
|
10210
|
+
tokens.push(current);
|
|
10211
|
+
current = "";
|
|
10212
|
+
}
|
|
10213
|
+
continue;
|
|
10214
|
+
}
|
|
10215
|
+
current += character;
|
|
10216
|
+
}
|
|
10217
|
+
if (quote) {
|
|
10218
|
+
throw new Error(`Unterminated ${quote === '"' ? "double" : "single"} quote.`);
|
|
10219
|
+
}
|
|
10220
|
+
if (escaping) {
|
|
10221
|
+
current += "\\";
|
|
9978
10222
|
}
|
|
10223
|
+
if (current) {
|
|
10224
|
+
tokens.push(current);
|
|
10225
|
+
}
|
|
10226
|
+
return tokens;
|
|
10227
|
+
}
|
|
10228
|
+
function toCommandTokens(input) {
|
|
10229
|
+
const trimmed = input.trim();
|
|
10230
|
+
if (!trimmed) {
|
|
10231
|
+
return [];
|
|
10232
|
+
}
|
|
10233
|
+
const normalizedInput = trimmed.startsWith("kimbho ") ? trimmed.slice("kimbho ".length).trim() : trimmed;
|
|
10234
|
+
const tokens = tokenizeInput(normalizedInput);
|
|
10235
|
+
if (tokens.length === 0) {
|
|
10236
|
+
return [];
|
|
10237
|
+
}
|
|
10238
|
+
const firstToken = tokens[0];
|
|
10239
|
+
if (!firstToken) {
|
|
10240
|
+
return [];
|
|
10241
|
+
}
|
|
10242
|
+
const head = firstToken.startsWith("/") ? firstToken.slice(1) : firstToken;
|
|
10243
|
+
if (head === "new") {
|
|
10244
|
+
return [
|
|
10245
|
+
"run",
|
|
10246
|
+
normalizedInput.replace(/^\/?new\s+/, "")
|
|
10247
|
+
];
|
|
10248
|
+
}
|
|
10249
|
+
if (head === "scaffold") {
|
|
10250
|
+
const goal = normalizedInput.replace(/^\/?scaffold\s+/, "");
|
|
10251
|
+
return [
|
|
10252
|
+
"run",
|
|
10253
|
+
`scaffold ${goal}`.trim()
|
|
10254
|
+
];
|
|
10255
|
+
}
|
|
10256
|
+
if (head === "model") {
|
|
10257
|
+
return [
|
|
10258
|
+
"brains",
|
|
10259
|
+
"list"
|
|
10260
|
+
];
|
|
10261
|
+
}
|
|
10262
|
+
if (!firstToken.startsWith("/") && !TOP_LEVEL_COMMANDS.has(head) && !head.startsWith("-")) {
|
|
10263
|
+
return [
|
|
10264
|
+
"run",
|
|
10265
|
+
normalizedInput
|
|
10266
|
+
];
|
|
10267
|
+
}
|
|
10268
|
+
tokens[0] = head;
|
|
10269
|
+
return tokens;
|
|
10270
|
+
}
|
|
10271
|
+
async function runInteractiveShell(options) {
|
|
10272
|
+
const readline = (0, import_promises6.createInterface)({
|
|
10273
|
+
input: import_node_process9.default.stdin,
|
|
10274
|
+
output: import_node_process9.default.stdout,
|
|
10275
|
+
terminal: Boolean(import_node_process9.default.stdin.isTTY && import_node_process9.default.stdout.isTTY)
|
|
10276
|
+
});
|
|
10277
|
+
let closed = false;
|
|
10278
|
+
readline.on("SIGINT", () => {
|
|
10279
|
+
closed = true;
|
|
10280
|
+
readline.close();
|
|
10281
|
+
});
|
|
10282
|
+
let state = await getShellSessionState(options.cwd);
|
|
10283
|
+
printHeader(options.cwd, state);
|
|
10284
|
+
while (!closed) {
|
|
10285
|
+
let line;
|
|
10286
|
+
try {
|
|
10287
|
+
state = await getShellSessionState(options.cwd);
|
|
10288
|
+
line = await readline.question(formatPrompt(state));
|
|
10289
|
+
} catch {
|
|
10290
|
+
break;
|
|
10291
|
+
}
|
|
10292
|
+
const trimmed = line.trim();
|
|
10293
|
+
if (!trimmed) {
|
|
10294
|
+
continue;
|
|
10295
|
+
}
|
|
10296
|
+
if (trimmed === "/exit" || trimmed === "exit" || trimmed === "quit" || trimmed === "/quit") {
|
|
10297
|
+
closed = true;
|
|
10298
|
+
break;
|
|
10299
|
+
}
|
|
10300
|
+
if (trimmed === "/help" || trimmed === "help" || trimmed === "?") {
|
|
10301
|
+
console.log(renderHelp());
|
|
10302
|
+
console.log("");
|
|
10303
|
+
continue;
|
|
10304
|
+
}
|
|
10305
|
+
if (trimmed === "/status" || trimmed === "status") {
|
|
10306
|
+
state = await getShellSessionState(options.cwd);
|
|
10307
|
+
console.log(renderStartupCard(options.cwd, state));
|
|
10308
|
+
console.log("");
|
|
10309
|
+
continue;
|
|
10310
|
+
}
|
|
10311
|
+
if (trimmed === "/clear" || trimmed === "clear") {
|
|
10312
|
+
if (import_node_process9.default.stdout.isTTY) {
|
|
10313
|
+
import_node_process9.default.stdout.write("\x1Bc");
|
|
10314
|
+
}
|
|
10315
|
+
state = await getShellSessionState(options.cwd);
|
|
10316
|
+
printHeader(options.cwd, state);
|
|
10317
|
+
continue;
|
|
10318
|
+
}
|
|
10319
|
+
try {
|
|
10320
|
+
const tokens = toCommandTokens(trimmed);
|
|
10321
|
+
if (tokens.length === 0) {
|
|
10322
|
+
continue;
|
|
10323
|
+
}
|
|
10324
|
+
await options.execute(tokens);
|
|
10325
|
+
} catch (error) {
|
|
10326
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10327
|
+
console.error(message);
|
|
10328
|
+
} finally {
|
|
10329
|
+
import_node_process9.default.exitCode = 0;
|
|
10330
|
+
}
|
|
10331
|
+
if (!closed) {
|
|
10332
|
+
console.log("");
|
|
10333
|
+
}
|
|
10334
|
+
}
|
|
10335
|
+
readline.close();
|
|
10336
|
+
import_node_process9.default.exitCode = 0;
|
|
10337
|
+
console.log(color(DIM, "Leaving Kimbho."));
|
|
10338
|
+
}
|
|
10339
|
+
|
|
10340
|
+
// src/index.ts
|
|
10341
|
+
async function dispatchCliTokens(tokens) {
|
|
10342
|
+
const program2 = createProgram();
|
|
10343
|
+
program2.exitOverride();
|
|
10344
|
+
try {
|
|
10345
|
+
await program2.parseAsync([
|
|
10346
|
+
"node",
|
|
10347
|
+
"kimbho",
|
|
10348
|
+
...normalizeCliTokens(tokens)
|
|
10349
|
+
]);
|
|
10350
|
+
} catch (error) {
|
|
10351
|
+
if (error instanceof CommanderError) {
|
|
10352
|
+
return;
|
|
10353
|
+
}
|
|
10354
|
+
throw error;
|
|
10355
|
+
}
|
|
10356
|
+
}
|
|
10357
|
+
async function openShell() {
|
|
10358
|
+
await runInteractiveShell({
|
|
10359
|
+
cwd: process.cwd(),
|
|
10360
|
+
execute: dispatchCliTokens
|
|
10361
|
+
});
|
|
10362
|
+
}
|
|
10363
|
+
async function main() {
|
|
10364
|
+
const tokens = normalizeCliTokens(process.argv.slice(2));
|
|
10365
|
+
if (tokens.length === 0) {
|
|
10366
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
10367
|
+
await openShell();
|
|
10368
|
+
return;
|
|
10369
|
+
}
|
|
10370
|
+
const helpProgram = createProgram(openShell);
|
|
10371
|
+
await helpProgram.parseAsync([
|
|
10372
|
+
"node",
|
|
10373
|
+
"kimbho",
|
|
10374
|
+
"--help"
|
|
10375
|
+
]);
|
|
10376
|
+
return;
|
|
10377
|
+
}
|
|
10378
|
+
const program2 = createProgram(openShell);
|
|
10379
|
+
await program2.parseAsync([
|
|
10380
|
+
"node",
|
|
10381
|
+
"kimbho",
|
|
10382
|
+
...tokens
|
|
10383
|
+
]);
|
|
9979
10384
|
}
|
|
9980
|
-
|
|
10385
|
+
main().catch((error) => {
|
|
9981
10386
|
const message = error instanceof Error ? error.message : String(error);
|
|
9982
10387
|
console.error(message);
|
|
9983
10388
|
process.exitCode = 1;
|