@kimbho/kimbho-cli 0.1.6 → 0.1.7
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 +2 -0
- package/dist/index.cjs +564 -99
- package/dist/index.cjs.map +4 -4
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1147,7 +1147,7 @@ var require_command = __commonJS({
|
|
|
1147
1147
|
"../../node_modules/commander/lib/command.js"(exports2) {
|
|
1148
1148
|
var EventEmitter = require("node:events").EventEmitter;
|
|
1149
1149
|
var childProcess = require("node:child_process");
|
|
1150
|
-
var
|
|
1150
|
+
var path14 = require("node:path");
|
|
1151
1151
|
var fs = require("node:fs");
|
|
1152
1152
|
var process14 = require("node:process");
|
|
1153
1153
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
@@ -2147,9 +2147,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2147
2147
|
let launchWithNode = false;
|
|
2148
2148
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
2149
2149
|
function findFile(baseDir, baseName) {
|
|
2150
|
-
const localBin =
|
|
2150
|
+
const localBin = path14.resolve(baseDir, baseName);
|
|
2151
2151
|
if (fs.existsSync(localBin)) return localBin;
|
|
2152
|
-
if (sourceExt.includes(
|
|
2152
|
+
if (sourceExt.includes(path14.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 = path14.resolve(
|
|
2171
|
+
path14.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 = path14.basename(
|
|
2179
2179
|
this._scriptPath,
|
|
2180
|
-
|
|
2180
|
+
path14.extname(this._scriptPath)
|
|
2181
2181
|
);
|
|
2182
2182
|
if (legacyName !== this._name) {
|
|
2183
2183
|
localFile = findFile(
|
|
@@ -2188,7 +2188,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2188
2188
|
}
|
|
2189
2189
|
executableFile = localFile || executableFile;
|
|
2190
2190
|
}
|
|
2191
|
-
launchWithNode = sourceExt.includes(
|
|
2191
|
+
launchWithNode = sourceExt.includes(path14.extname(executableFile));
|
|
2192
2192
|
let proc;
|
|
2193
2193
|
if (process14.platform !== "win32") {
|
|
2194
2194
|
if (launchWithNode) {
|
|
@@ -3035,7 +3035,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3035
3035
|
* @return {Command}
|
|
3036
3036
|
*/
|
|
3037
3037
|
nameFromFilename(filename) {
|
|
3038
|
-
this._name =
|
|
3038
|
+
this._name = path14.basename(filename, path14.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(path15) {
|
|
3053
|
+
if (path15 === void 0) return this._executableDir;
|
|
3054
|
+
this._executableDir = path15;
|
|
3055
3055
|
return this;
|
|
3056
3056
|
}
|
|
3057
3057
|
/**
|
|
@@ -3346,7 +3346,7 @@ var {
|
|
|
3346
3346
|
// package.json
|
|
3347
3347
|
var package_default = {
|
|
3348
3348
|
name: "@kimbho/kimbho-cli",
|
|
3349
|
-
version: "0.1.
|
|
3349
|
+
version: "0.1.7",
|
|
3350
3350
|
description: "Kimbho CLI is a terminal-native coding agent for planning, execution, and verification.",
|
|
3351
3351
|
type: "module",
|
|
3352
3352
|
engines: {
|
|
@@ -4140,8 +4140,8 @@ function getErrorMap() {
|
|
|
4140
4140
|
|
|
4141
4141
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
4142
4142
|
var makeIssue = (params) => {
|
|
4143
|
-
const { data, path:
|
|
4144
|
-
const fullPath = [...
|
|
4143
|
+
const { data, path: path14, errorMaps, issueData } = params;
|
|
4144
|
+
const fullPath = [...path14, ...issueData.path || []];
|
|
4145
4145
|
const fullIssue = {
|
|
4146
4146
|
...issueData,
|
|
4147
4147
|
path: fullPath
|
|
@@ -4257,11 +4257,11 @@ var errorUtil;
|
|
|
4257
4257
|
|
|
4258
4258
|
// ../../node_modules/zod/v3/types.js
|
|
4259
4259
|
var ParseInputLazyPath = class {
|
|
4260
|
-
constructor(parent, value,
|
|
4260
|
+
constructor(parent, value, path14, key) {
|
|
4261
4261
|
this._cachedPath = [];
|
|
4262
4262
|
this.parent = parent;
|
|
4263
4263
|
this.data = value;
|
|
4264
|
-
this._path =
|
|
4264
|
+
this._path = path14;
|
|
4265
4265
|
this._key = key;
|
|
4266
4266
|
}
|
|
4267
4267
|
get path() {
|
|
@@ -9353,9 +9353,15 @@ var AutonomousTaskExecutor = class {
|
|
|
9353
9353
|
try {
|
|
9354
9354
|
result = await this.toolRuntime.run(toolId, input, options.signal ? {
|
|
9355
9355
|
cwd: request.cwd,
|
|
9356
|
-
signal: options.signal
|
|
9356
|
+
signal: options.signal,
|
|
9357
|
+
approvalMode: this.config.approvalMode,
|
|
9358
|
+
sandboxMode: this.config.sandboxMode,
|
|
9359
|
+
agentRole: task.agentRole
|
|
9357
9360
|
} : {
|
|
9358
|
-
cwd: request.cwd
|
|
9361
|
+
cwd: request.cwd,
|
|
9362
|
+
approvalMode: this.config.approvalMode,
|
|
9363
|
+
sandboxMode: this.config.sandboxMode,
|
|
9364
|
+
agentRole: task.agentRole
|
|
9359
9365
|
});
|
|
9360
9366
|
} catch (error) {
|
|
9361
9367
|
if (isAbortError(error)) {
|
|
@@ -9639,9 +9645,15 @@ var AutonomousTaskExecutor = class {
|
|
|
9639
9645
|
try {
|
|
9640
9646
|
result = await this.toolRuntime.run(parsedAction.tool, parsedAction.input, options.signal ? {
|
|
9641
9647
|
cwd: request.cwd,
|
|
9642
|
-
signal: options.signal
|
|
9648
|
+
signal: options.signal,
|
|
9649
|
+
approvalMode: this.config.approvalMode,
|
|
9650
|
+
sandboxMode: this.config.sandboxMode,
|
|
9651
|
+
agentRole: task.agentRole
|
|
9643
9652
|
} : {
|
|
9644
|
-
cwd: request.cwd
|
|
9653
|
+
cwd: request.cwd,
|
|
9654
|
+
approvalMode: this.config.approvalMode,
|
|
9655
|
+
sandboxMode: this.config.sandboxMode,
|
|
9656
|
+
agentRole: task.agentRole
|
|
9645
9657
|
});
|
|
9646
9658
|
} catch (error) {
|
|
9647
9659
|
if (isAbortError(error)) {
|
|
@@ -10740,7 +10752,12 @@ async function loadTypeScript() {
|
|
|
10740
10752
|
return module2;
|
|
10741
10753
|
}
|
|
10742
10754
|
async function walkWorkspace(root, current = root, results = []) {
|
|
10743
|
-
const entries = await (0, import_promises7.readdir)(current, { withFileTypes: true })
|
|
10755
|
+
const entries = await (0, import_promises7.readdir)(current, { withFileTypes: true }).catch((error) => {
|
|
10756
|
+
if (error.code === "EACCES" || error.code === "EPERM" || error.code === "ENOENT") {
|
|
10757
|
+
return [];
|
|
10758
|
+
}
|
|
10759
|
+
throw error;
|
|
10760
|
+
});
|
|
10744
10761
|
for (const entry of entries) {
|
|
10745
10762
|
const fullPath = import_node_path7.default.join(current, entry.name);
|
|
10746
10763
|
const relativePath = import_node_path7.default.relative(root, fullPath);
|
|
@@ -11627,6 +11644,111 @@ function resolveWorkspacePath(cwd, filePath) {
|
|
|
11627
11644
|
}
|
|
11628
11645
|
return resolved;
|
|
11629
11646
|
}
|
|
11647
|
+
var READ_ONLY_SHELL_PREFIXES = [
|
|
11648
|
+
"pwd",
|
|
11649
|
+
"ls",
|
|
11650
|
+
"find ",
|
|
11651
|
+
"rg ",
|
|
11652
|
+
"grep ",
|
|
11653
|
+
"cat ",
|
|
11654
|
+
"sed ",
|
|
11655
|
+
"head ",
|
|
11656
|
+
"tail ",
|
|
11657
|
+
"git status",
|
|
11658
|
+
"git diff",
|
|
11659
|
+
"git rev-parse",
|
|
11660
|
+
"git branch",
|
|
11661
|
+
"git log",
|
|
11662
|
+
"git show",
|
|
11663
|
+
"npm ls",
|
|
11664
|
+
"pnpm ls",
|
|
11665
|
+
"yarn list"
|
|
11666
|
+
];
|
|
11667
|
+
var DESTRUCTIVE_SHELL_PATTERNS = [
|
|
11668
|
+
/\brm\s+-rf\b/i,
|
|
11669
|
+
/\brm\s+-fr\b/i,
|
|
11670
|
+
/\bgit\s+reset\s+--hard\b/i,
|
|
11671
|
+
/\bgit\s+clean\s+-f(d|x|fd|fdx)\b/i,
|
|
11672
|
+
/\bgit\s+checkout\s+--\b/i,
|
|
11673
|
+
/\bmv\s+.+\s+\/dev\/null\b/i,
|
|
11674
|
+
/\bdd\s+if=/i,
|
|
11675
|
+
/\bmkfs(\.| )/i,
|
|
11676
|
+
/\bsudo\b/i
|
|
11677
|
+
];
|
|
11678
|
+
var PROTECTED_WRITE_PREFIXES = [
|
|
11679
|
+
".git",
|
|
11680
|
+
".kimbho/config.json",
|
|
11681
|
+
".kimbho/sessions",
|
|
11682
|
+
".kimbho/plans"
|
|
11683
|
+
];
|
|
11684
|
+
function isReadOnlyShellCommand2(command) {
|
|
11685
|
+
const normalized = command.trim().toLowerCase();
|
|
11686
|
+
return READ_ONLY_SHELL_PREFIXES.some((prefix) => normalized === prefix || normalized.startsWith(prefix));
|
|
11687
|
+
}
|
|
11688
|
+
function isDestructiveShellCommand(command) {
|
|
11689
|
+
return DESTRUCTIVE_SHELL_PATTERNS.some((pattern) => pattern.test(command));
|
|
11690
|
+
}
|
|
11691
|
+
function normalizeArtifactRelativePath(cwd, absolutePath) {
|
|
11692
|
+
const relative = import_node_path9.default.relative(cwd, absolutePath) || import_node_path9.default.basename(absolutePath);
|
|
11693
|
+
return relative.replace(/\\/g, "/");
|
|
11694
|
+
}
|
|
11695
|
+
function isProtectedWritePath(relativePath) {
|
|
11696
|
+
return PROTECTED_WRITE_PREFIXES.some((prefix) => relativePath === prefix || relativePath.startsWith(`${prefix}/`));
|
|
11697
|
+
}
|
|
11698
|
+
function extractProspectiveWriteTargets(toolId, input, cwd) {
|
|
11699
|
+
if (toolId === "file.write" && typeof input.path === "string") {
|
|
11700
|
+
return [
|
|
11701
|
+
normalizeArtifactRelativePath(cwd, resolveWorkspacePath(cwd, input.path))
|
|
11702
|
+
];
|
|
11703
|
+
}
|
|
11704
|
+
if (toolId === "file.patch" && typeof input.patch === "string") {
|
|
11705
|
+
return extractPatchArtifacts(cwd, input.patch).map((artifactPath) => normalizeArtifactRelativePath(cwd, artifactPath));
|
|
11706
|
+
}
|
|
11707
|
+
if (toolId === "scaffold.generate") {
|
|
11708
|
+
return [
|
|
11709
|
+
"(scaffold workspace)"
|
|
11710
|
+
];
|
|
11711
|
+
}
|
|
11712
|
+
return [];
|
|
11713
|
+
}
|
|
11714
|
+
function createPolicyFailure(toolId, reason) {
|
|
11715
|
+
return ToolResultSchema.parse({
|
|
11716
|
+
toolId,
|
|
11717
|
+
success: false,
|
|
11718
|
+
summary: reason,
|
|
11719
|
+
stderr: reason,
|
|
11720
|
+
artifacts: []
|
|
11721
|
+
});
|
|
11722
|
+
}
|
|
11723
|
+
function enforceToolPolicy(toolId, input, descriptor, context) {
|
|
11724
|
+
if (!descriptor) {
|
|
11725
|
+
return null;
|
|
11726
|
+
}
|
|
11727
|
+
const sandboxMode = context.sandboxMode ?? "workspace-write";
|
|
11728
|
+
const approvalMode = context.approvalMode ?? "manual";
|
|
11729
|
+
const command = typeof input.command === "string" ? input.command : "";
|
|
11730
|
+
if (sandboxMode === "read-only") {
|
|
11731
|
+
if (toolId === "shell.exec" && isReadOnlyShellCommand2(command)) {
|
|
11732
|
+
return null;
|
|
11733
|
+
}
|
|
11734
|
+
if (descriptor.permission !== "safe") {
|
|
11735
|
+
return createPolicyFailure(toolId, `Blocked ${toolId} because sandbox mode is read-only.`);
|
|
11736
|
+
}
|
|
11737
|
+
}
|
|
11738
|
+
if (toolId === "shell.exec" && isDestructiveShellCommand(command)) {
|
|
11739
|
+
if (!context.operatorApproved && approvalMode !== "auto") {
|
|
11740
|
+
return createPolicyFailure(toolId, `Blocked destructive shell command under manual approval mode: ${command}`);
|
|
11741
|
+
}
|
|
11742
|
+
}
|
|
11743
|
+
if ((toolId === "file.write" || toolId === "file.patch") && sandboxMode === "workspace-write") {
|
|
11744
|
+
const targets = extractProspectiveWriteTargets(toolId, input, context.cwd);
|
|
11745
|
+
const protectedTargets = targets.filter((target) => isProtectedWritePath(target));
|
|
11746
|
+
if (protectedTargets.length > 0) {
|
|
11747
|
+
return createPolicyFailure(toolId, `Blocked write to protected workspace paths: ${protectedTargets.join(", ")}`);
|
|
11748
|
+
}
|
|
11749
|
+
}
|
|
11750
|
+
return null;
|
|
11751
|
+
}
|
|
11630
11752
|
async function runSpawn(command, args, cwd, timeoutMs, signal) {
|
|
11631
11753
|
return new Promise((resolve, reject) => {
|
|
11632
11754
|
if (signal?.aborted) {
|
|
@@ -12447,6 +12569,10 @@ var ToolRuntime = class {
|
|
|
12447
12569
|
if (!executor) {
|
|
12448
12570
|
throw new Error(`No executor registered for "${toolId}".`);
|
|
12449
12571
|
}
|
|
12572
|
+
const policyFailure = enforceToolPolicy(toolId, input, descriptor, context);
|
|
12573
|
+
if (policyFailure) {
|
|
12574
|
+
return policyFailure;
|
|
12575
|
+
}
|
|
12450
12576
|
return executor(input, context, descriptor.timeoutMs);
|
|
12451
12577
|
}
|
|
12452
12578
|
};
|
|
@@ -12747,6 +12873,66 @@ async function cleanupWorktree(cwd, worktreePath, signal) {
|
|
|
12747
12873
|
force: true
|
|
12748
12874
|
});
|
|
12749
12875
|
}
|
|
12876
|
+
async function writeConflictBundle(input) {
|
|
12877
|
+
await ensureKimbhoDir(input.mainCwd);
|
|
12878
|
+
const logsDir = import_node_path10.default.join(resolveKimbhoDir(input.mainCwd), "logs");
|
|
12879
|
+
const baseName = import_node_path10.default.basename(input.originalPatchArtifactPath, ".patch");
|
|
12880
|
+
const outputPath = import_node_path10.default.join(logsDir, `${baseName}-integration-conflict.md`);
|
|
12881
|
+
const lines = [
|
|
12882
|
+
"# Integration Conflict",
|
|
12883
|
+
"",
|
|
12884
|
+
`- summary: ${input.summary}`,
|
|
12885
|
+
`- original patch: ${input.originalPatchArtifactPath}`,
|
|
12886
|
+
...input.refreshedPatchArtifactPath ? [
|
|
12887
|
+
`- refreshed patch: ${input.refreshedPatchArtifactPath}`
|
|
12888
|
+
] : [],
|
|
12889
|
+
`- changed files: ${input.changedFiles.length > 0 ? input.changedFiles.join(", ") : "(unknown)"}`,
|
|
12890
|
+
"",
|
|
12891
|
+
"## Notes",
|
|
12892
|
+
...input.notes.map((note) => `- ${note}`),
|
|
12893
|
+
""
|
|
12894
|
+
];
|
|
12895
|
+
if (input.directApplyStdout || input.directApplyStderr) {
|
|
12896
|
+
lines.push("## Direct Apply");
|
|
12897
|
+
if (input.directApplyStdout) {
|
|
12898
|
+
lines.push("");
|
|
12899
|
+
lines.push("```text");
|
|
12900
|
+
lines.push(input.directApplyStdout);
|
|
12901
|
+
lines.push("```");
|
|
12902
|
+
}
|
|
12903
|
+
if (input.directApplyStderr) {
|
|
12904
|
+
lines.push("");
|
|
12905
|
+
lines.push("```text");
|
|
12906
|
+
lines.push(input.directApplyStderr);
|
|
12907
|
+
lines.push("```");
|
|
12908
|
+
}
|
|
12909
|
+
lines.push("");
|
|
12910
|
+
}
|
|
12911
|
+
if (input.replayStdout || input.replayStderr) {
|
|
12912
|
+
lines.push("## Replay Attempt");
|
|
12913
|
+
if (input.replayStdout) {
|
|
12914
|
+
lines.push("");
|
|
12915
|
+
lines.push("```text");
|
|
12916
|
+
lines.push(input.replayStdout);
|
|
12917
|
+
lines.push("```");
|
|
12918
|
+
}
|
|
12919
|
+
if (input.replayStderr) {
|
|
12920
|
+
lines.push("");
|
|
12921
|
+
lines.push("```text");
|
|
12922
|
+
lines.push(input.replayStderr);
|
|
12923
|
+
lines.push("```");
|
|
12924
|
+
}
|
|
12925
|
+
lines.push("");
|
|
12926
|
+
}
|
|
12927
|
+
lines.push("## Operator Next Steps");
|
|
12928
|
+
lines.push("- Inspect the original patch and the refreshed patch if present.");
|
|
12929
|
+
lines.push("- Compare the listed changed files against the current workspace diff.");
|
|
12930
|
+
lines.push("- Resolve the conflict manually or re-run the task after adjusting overlapping files.");
|
|
12931
|
+
lines.push("");
|
|
12932
|
+
await (0, import_promises10.writeFile)(outputPath, `${lines.join("\n")}
|
|
12933
|
+
`, "utf8");
|
|
12934
|
+
return outputPath;
|
|
12935
|
+
}
|
|
12750
12936
|
async function readTextFileIfPresent(filePath) {
|
|
12751
12937
|
return (0, import_promises10.readFile)(filePath, "utf8").catch((error) => {
|
|
12752
12938
|
if (error.code === "ENOENT") {
|
|
@@ -12848,6 +13034,16 @@ async function createReplayWorktree(cwd, basePatchArtifactPath, signal) {
|
|
|
12848
13034
|
async function replayPatchOnLatestWorkspace(mainCwd, sourceWorktreePath, originalPatchArtifactPath, changedFilesSummary, signal) {
|
|
12849
13035
|
const replayWorktree = await createReplayWorktree(mainCwd, originalPatchArtifactPath, signal);
|
|
12850
13036
|
if (!replayWorktree) {
|
|
13037
|
+
const notes2 = [
|
|
13038
|
+
`Replay sandbox creation failed. Original patch preserved at ${originalPatchArtifactPath}.`
|
|
13039
|
+
];
|
|
13040
|
+
const conflictArtifactPath = await writeConflictBundle({
|
|
13041
|
+
mainCwd,
|
|
13042
|
+
originalPatchArtifactPath,
|
|
13043
|
+
changedFiles: changedFilesSummary ? changedFilesSummary.split(", ").map((item) => item.replace(/ \(\+\d+ more\)$/, "")) : [],
|
|
13044
|
+
notes: notes2,
|
|
13045
|
+
summary: changedFilesSummary ? `Failed to replay the isolated worktree diff because no git replay sandbox could be created. Files involved: ${changedFilesSummary}.` : "Failed to replay the isolated worktree diff because no git replay sandbox could be created."
|
|
13046
|
+
});
|
|
12851
13047
|
return {
|
|
12852
13048
|
toolResults: [
|
|
12853
13049
|
{
|
|
@@ -12855,16 +13051,16 @@ async function replayPatchOnLatestWorkspace(mainCwd, sourceWorktreePath, origina
|
|
|
12855
13051
|
success: false,
|
|
12856
13052
|
summary: changedFilesSummary ? `Failed to replay the isolated worktree diff because no git replay sandbox could be created. Files involved: ${changedFilesSummary}.` : "Failed to replay the isolated worktree diff because no git replay sandbox could be created.",
|
|
12857
13053
|
artifacts: [
|
|
12858
|
-
originalPatchArtifactPath
|
|
13054
|
+
originalPatchArtifactPath,
|
|
13055
|
+
conflictArtifactPath
|
|
12859
13056
|
]
|
|
12860
13057
|
}
|
|
12861
13058
|
],
|
|
12862
13059
|
artifacts: [
|
|
12863
|
-
originalPatchArtifactPath
|
|
12864
|
-
|
|
12865
|
-
notes: [
|
|
12866
|
-
`Replay sandbox creation failed. Original patch preserved at ${originalPatchArtifactPath}.`
|
|
13060
|
+
originalPatchArtifactPath,
|
|
13061
|
+
conflictArtifactPath
|
|
12867
13062
|
],
|
|
13063
|
+
notes: notes2,
|
|
12868
13064
|
integrationFailed: true
|
|
12869
13065
|
};
|
|
12870
13066
|
}
|
|
@@ -12887,16 +13083,34 @@ async function replayPatchOnLatestWorkspace(mainCwd, sourceWorktreePath, origina
|
|
|
12887
13083
|
if (replayApplyResult.code !== 0) {
|
|
12888
13084
|
const textualReplay = await attemptTextualReplayMerge(mainCwd, replayWorktree.worktreePath, sourceWorktreePath, changedFiles, signal);
|
|
12889
13085
|
if (!textualReplay.success) {
|
|
13086
|
+
const failureSummary = changedFilesSummary ? `Failed to replay the isolated worktree diff onto the latest workspace snapshot. Files involved: ${changedFilesSummary}.` : "Failed to replay the isolated worktree diff onto the latest workspace snapshot.";
|
|
13087
|
+
const failureNotes = [
|
|
13088
|
+
...notes,
|
|
13089
|
+
textualReplay.note,
|
|
13090
|
+
`Replay failed in the retry sandbox. Original patch preserved at ${originalPatchArtifactPath}.`
|
|
13091
|
+
];
|
|
13092
|
+
const conflictArtifactPath = await writeConflictBundle({
|
|
13093
|
+
mainCwd,
|
|
13094
|
+
originalPatchArtifactPath,
|
|
13095
|
+
changedFiles,
|
|
13096
|
+
notes: failureNotes,
|
|
13097
|
+
summary: failureSummary,
|
|
13098
|
+
directApplyStdout: replayApplyResult.stdout,
|
|
13099
|
+
directApplyStderr: replayApplyResult.stderr,
|
|
13100
|
+
replayStdout: textualReplay.stdout,
|
|
13101
|
+
replayStderr: textualReplay.stderr
|
|
13102
|
+
});
|
|
13103
|
+
artifacts.add(conflictArtifactPath);
|
|
12890
13104
|
toolResults.push({
|
|
12891
13105
|
toolId: "file.patch",
|
|
12892
13106
|
success: false,
|
|
12893
|
-
summary:
|
|
13107
|
+
summary: failureSummary,
|
|
12894
13108
|
stdout: replayApplyResult.stdout || textualReplay.stdout,
|
|
12895
13109
|
stderr: replayApplyResult.stderr || textualReplay.stderr,
|
|
12896
13110
|
artifacts: Array.from(artifacts)
|
|
12897
13111
|
});
|
|
12898
13112
|
notes.push(textualReplay.note);
|
|
12899
|
-
notes.push(`Replay failed in the retry sandbox. Original patch preserved at ${originalPatchArtifactPath}.`);
|
|
13113
|
+
notes.push(`Replay failed in the retry sandbox. Original patch preserved at ${originalPatchArtifactPath}. Conflict bundle saved to ${conflictArtifactPath}.`);
|
|
12900
13114
|
return {
|
|
12901
13115
|
toolResults,
|
|
12902
13116
|
artifacts: Array.from(artifacts),
|
|
@@ -12948,15 +13162,31 @@ async function replayPatchOnLatestWorkspace(mainCwd, sourceWorktreePath, origina
|
|
|
12948
13162
|
replayWorktree.patchArtifactPath
|
|
12949
13163
|
], signal);
|
|
12950
13164
|
if (replayCheckResult.code !== 0) {
|
|
13165
|
+
const failureSummary = changedFilesSummary ? `Replayed patch still does not apply cleanly to the latest main workspace. Files involved: ${changedFilesSummary}.` : "Replayed patch still does not apply cleanly to the latest main workspace.";
|
|
13166
|
+
const failureNotes = [
|
|
13167
|
+
...notes,
|
|
13168
|
+
`Replay generated a refreshed patch, but it still does not apply cleanly. Refreshed patch preserved at ${replayWorktree.patchArtifactPath}.`
|
|
13169
|
+
];
|
|
13170
|
+
const conflictArtifactPath = await writeConflictBundle({
|
|
13171
|
+
mainCwd,
|
|
13172
|
+
originalPatchArtifactPath,
|
|
13173
|
+
changedFiles,
|
|
13174
|
+
notes: failureNotes,
|
|
13175
|
+
summary: failureSummary,
|
|
13176
|
+
replayStdout: replayCheckResult.stdout,
|
|
13177
|
+
replayStderr: replayCheckResult.stderr,
|
|
13178
|
+
refreshedPatchArtifactPath: replayWorktree.patchArtifactPath
|
|
13179
|
+
});
|
|
13180
|
+
artifacts.add(conflictArtifactPath);
|
|
12951
13181
|
toolResults.push({
|
|
12952
13182
|
toolId: "file.patch",
|
|
12953
13183
|
success: false,
|
|
12954
|
-
summary:
|
|
13184
|
+
summary: failureSummary,
|
|
12955
13185
|
stdout: replayCheckResult.stdout,
|
|
12956
13186
|
stderr: replayCheckResult.stderr,
|
|
12957
13187
|
artifacts: Array.from(artifacts)
|
|
12958
13188
|
});
|
|
12959
|
-
notes.push(`Replay generated a refreshed patch, but it still does not apply cleanly. Refreshed patch preserved at ${replayWorktree.patchArtifactPath}.`);
|
|
13189
|
+
notes.push(`Replay generated a refreshed patch, but it still does not apply cleanly. Refreshed patch preserved at ${replayWorktree.patchArtifactPath}. Conflict bundle saved to ${conflictArtifactPath}.`);
|
|
12960
13190
|
return {
|
|
12961
13191
|
toolResults,
|
|
12962
13192
|
artifacts: Array.from(artifacts),
|
|
@@ -12972,15 +13202,31 @@ async function replayPatchOnLatestWorkspace(mainCwd, sourceWorktreePath, origina
|
|
|
12972
13202
|
replayWorktree.patchArtifactPath
|
|
12973
13203
|
], signal);
|
|
12974
13204
|
if (replayMainApplyResult.code !== 0) {
|
|
13205
|
+
const failureSummary = changedFilesSummary ? `Failed to apply the refreshed replay patch back to the main workspace. Files involved: ${changedFilesSummary}.` : "Failed to apply the refreshed replay patch back to the main workspace.";
|
|
13206
|
+
const failureNotes = [
|
|
13207
|
+
...notes,
|
|
13208
|
+
`Replay patch could not be applied back to the main workspace. Refreshed patch preserved at ${replayWorktree.patchArtifactPath}.`
|
|
13209
|
+
];
|
|
13210
|
+
const conflictArtifactPath = await writeConflictBundle({
|
|
13211
|
+
mainCwd,
|
|
13212
|
+
originalPatchArtifactPath,
|
|
13213
|
+
changedFiles,
|
|
13214
|
+
notes: failureNotes,
|
|
13215
|
+
summary: failureSummary,
|
|
13216
|
+
replayStdout: replayMainApplyResult.stdout,
|
|
13217
|
+
replayStderr: replayMainApplyResult.stderr,
|
|
13218
|
+
refreshedPatchArtifactPath: replayWorktree.patchArtifactPath
|
|
13219
|
+
});
|
|
13220
|
+
artifacts.add(conflictArtifactPath);
|
|
12975
13221
|
toolResults.push({
|
|
12976
13222
|
toolId: "file.patch",
|
|
12977
13223
|
success: false,
|
|
12978
|
-
summary:
|
|
13224
|
+
summary: failureSummary,
|
|
12979
13225
|
stdout: replayMainApplyResult.stdout,
|
|
12980
13226
|
stderr: replayMainApplyResult.stderr,
|
|
12981
13227
|
artifacts: Array.from(artifacts)
|
|
12982
13228
|
});
|
|
12983
|
-
notes.push(`Replay patch could not be applied back to the main workspace. Refreshed patch preserved at ${replayWorktree.patchArtifactPath}.`);
|
|
13229
|
+
notes.push(`Replay patch could not be applied back to the main workspace. Refreshed patch preserved at ${replayWorktree.patchArtifactPath}. Conflict bundle saved to ${conflictArtifactPath}.`);
|
|
12984
13230
|
return {
|
|
12985
13231
|
toolResults,
|
|
12986
13232
|
artifacts: Array.from(artifacts),
|
|
@@ -13574,6 +13820,11 @@ var ExecutionOrchestrator = class {
|
|
|
13574
13820
|
}
|
|
13575
13821
|
const scaffoldResult = await this.safeRunTool("scaffold.generate", scaffoldInput, {
|
|
13576
13822
|
cwd: request.cwd,
|
|
13823
|
+
...config ? {
|
|
13824
|
+
approvalMode: config.approvalMode,
|
|
13825
|
+
sandboxMode: config.sandboxMode,
|
|
13826
|
+
agentRole: task.agentRole
|
|
13827
|
+
} : {},
|
|
13577
13828
|
...options.signal ? {
|
|
13578
13829
|
signal: options.signal
|
|
13579
13830
|
} : {}
|
|
@@ -13608,6 +13859,11 @@ var ExecutionOrchestrator = class {
|
|
|
13608
13859
|
}
|
|
13609
13860
|
const repoIndexResult = await this.safeRunTool("repo.index", {}, {
|
|
13610
13861
|
cwd: request.cwd,
|
|
13862
|
+
...config ? {
|
|
13863
|
+
approvalMode: config.approvalMode,
|
|
13864
|
+
sandboxMode: config.sandboxMode,
|
|
13865
|
+
agentRole: task.agentRole
|
|
13866
|
+
} : {},
|
|
13611
13867
|
...options.signal ? {
|
|
13612
13868
|
signal: options.signal
|
|
13613
13869
|
} : {}
|
|
@@ -13727,7 +13983,9 @@ var ExecutionOrchestrator = class {
|
|
|
13727
13983
|
async executeRepoAnalysisTask(sessionId, task, request, emitProgress, signal) {
|
|
13728
13984
|
const context = { cwd: request.cwd };
|
|
13729
13985
|
const toolResults = [];
|
|
13730
|
-
const probes = [
|
|
13986
|
+
const probes = request.workspaceState === "empty" ? [
|
|
13987
|
+
{ toolId: "repo.index", input: {} }
|
|
13988
|
+
] : [
|
|
13731
13989
|
{ toolId: "repo.index", input: {} },
|
|
13732
13990
|
{ toolId: "git.status", input: {} },
|
|
13733
13991
|
{ toolId: "file.read", input: { path: "package.json" } },
|
|
@@ -14420,7 +14678,6 @@ function createModelsCommand() {
|
|
|
14420
14678
|
}
|
|
14421
14679
|
|
|
14422
14680
|
// src/commands/plan.ts
|
|
14423
|
-
var import_promises12 = require("node:fs/promises");
|
|
14424
14681
|
var import_node_process7 = __toESM(require("node:process"), 1);
|
|
14425
14682
|
|
|
14426
14683
|
// ../planner/dist/planner.js
|
|
@@ -14429,6 +14686,9 @@ function normalizeGoal(goal) {
|
|
|
14429
14686
|
}
|
|
14430
14687
|
function inferProjectShape(goal) {
|
|
14431
14688
|
const lower = goal.toLowerCase();
|
|
14689
|
+
if (lower.includes("landing page") || lower.includes("homepage") || lower.includes("marketing page") || lower.includes("storefront") || lower.includes("restaurant website") || lower.includes("restaurant site") || lower.includes("static site")) {
|
|
14690
|
+
return "static-site";
|
|
14691
|
+
}
|
|
14432
14692
|
if (lower.includes("agent") || lower.includes("cli") || lower.includes("terminal")) {
|
|
14433
14693
|
return "cli-agent";
|
|
14434
14694
|
}
|
|
@@ -14453,7 +14713,7 @@ function buildTask(id, title, description, agentRole, type, dependsOn, acceptanc
|
|
|
14453
14713
|
};
|
|
14454
14714
|
}
|
|
14455
14715
|
function foundationMilestone(shape) {
|
|
14456
|
-
const objective = shape === "cli-agent" ? "Establish the CLI monorepo, shared contracts, and first operational commands." : "Establish the application structure, baseline tooling, and implementation scaffolding.";
|
|
14716
|
+
const objective = shape === "cli-agent" ? "Establish the CLI monorepo, shared contracts, and first operational commands." : shape === "static-site" ? "Establish the site structure, initial content direction, and deterministic scaffold." : "Establish the application structure, baseline tooling, and implementation scaffolding.";
|
|
14457
14717
|
return {
|
|
14458
14718
|
id: "m1-foundation",
|
|
14459
14719
|
title: "Foundation",
|
|
@@ -14498,6 +14758,27 @@ function foundationMilestone(shape) {
|
|
|
14498
14758
|
};
|
|
14499
14759
|
}
|
|
14500
14760
|
function implementationMilestone(shape) {
|
|
14761
|
+
if (shape === "static-site") {
|
|
14762
|
+
return {
|
|
14763
|
+
id: "m2-experience",
|
|
14764
|
+
title: "Experience",
|
|
14765
|
+
objective: "Refine the landing-page experience, content, and responsive presentation.",
|
|
14766
|
+
tasks: [
|
|
14767
|
+
buildTask("t4-experience", "Tailor the landing-page experience", "Customize the generated landing page so the layout, copy, and visual direction fit the requested business or venue.", "frontend-specialist", "implementation", [
|
|
14768
|
+
"t3-scaffold"
|
|
14769
|
+
], [
|
|
14770
|
+
"The page reflects the requested business domain and tone.",
|
|
14771
|
+
"The layout is responsive and visually coherent."
|
|
14772
|
+
], [
|
|
14773
|
+
"Customized landing page"
|
|
14774
|
+
], [
|
|
14775
|
+
"index.html",
|
|
14776
|
+
"styles.css",
|
|
14777
|
+
"src/"
|
|
14778
|
+
], "medium")
|
|
14779
|
+
]
|
|
14780
|
+
};
|
|
14781
|
+
}
|
|
14501
14782
|
if (shape === "cli-agent") {
|
|
14502
14783
|
return {
|
|
14503
14784
|
id: "m2-runtime",
|
|
@@ -14614,6 +14895,8 @@ function verificationMilestone(shape) {
|
|
|
14614
14895
|
"t6-runtime",
|
|
14615
14896
|
"t7-tools",
|
|
14616
14897
|
"t8-shell"
|
|
14898
|
+
] : shape === "static-site" ? [
|
|
14899
|
+
"t4-experience"
|
|
14617
14900
|
] : [
|
|
14618
14901
|
"t5-backend",
|
|
14619
14902
|
"t6-frontend"
|
|
@@ -14656,6 +14939,9 @@ function deriveAssumptions(shape, request) {
|
|
|
14656
14939
|
if (shape === "full-stack-app") {
|
|
14657
14940
|
assumptions.push("The product needs a frontend, backend, and persistence layer.");
|
|
14658
14941
|
}
|
|
14942
|
+
if (shape === "static-site") {
|
|
14943
|
+
assumptions.push("The initial deliverable can ship as a static site without backend infrastructure.");
|
|
14944
|
+
}
|
|
14659
14945
|
if (request.constraints.length > 0) {
|
|
14660
14946
|
assumptions.push(`The plan must honor ${request.constraints.length} explicit user constraints.`);
|
|
14661
14947
|
}
|
|
@@ -14676,6 +14962,13 @@ function deriveOpenQuestions(shape) {
|
|
|
14676
14962
|
"What external services or APIs must be integrated?"
|
|
14677
14963
|
];
|
|
14678
14964
|
}
|
|
14965
|
+
if (shape === "static-site") {
|
|
14966
|
+
return [
|
|
14967
|
+
"What brand voice and visual direction should the page follow?",
|
|
14968
|
+
"Which sections are required on the first version of the landing page?",
|
|
14969
|
+
"What primary call to action should the page drive?"
|
|
14970
|
+
];
|
|
14971
|
+
}
|
|
14679
14972
|
return [
|
|
14680
14973
|
"Which stack and deployment target should be preferred?",
|
|
14681
14974
|
"What user journeys count as the minimum viable release?"
|
|
@@ -14689,6 +14982,9 @@ function deriveVerificationChecklist(shape) {
|
|
|
14689
14982
|
if (shape === "cli-agent") {
|
|
14690
14983
|
checklist.push("CLI commands render correctly and save plan artifacts.");
|
|
14691
14984
|
checklist.push("Plan contracts remain schema-valid across packages.");
|
|
14985
|
+
} else if (shape === "static-site") {
|
|
14986
|
+
checklist.push("The page renders cleanly on desktop and mobile-sized viewports.");
|
|
14987
|
+
checklist.push("Primary calls to action and anchor navigation work.");
|
|
14692
14988
|
} else if (shape === "full-stack-app") {
|
|
14693
14989
|
checklist.push("The build, lint, and test flows pass.");
|
|
14694
14990
|
checklist.push("Primary UI and API paths are smoke-tested.");
|
|
@@ -14702,6 +14998,9 @@ function buildSummary(shape, goal) {
|
|
|
14702
14998
|
if (shape === "full-stack-app") {
|
|
14703
14999
|
return `Deliver the full-stack implementation for "${goal}" through staged architecture, implementation, and verification milestones.`;
|
|
14704
15000
|
}
|
|
15001
|
+
if (shape === "static-site") {
|
|
15002
|
+
return `Deliver a polished landing-page implementation for "${goal}" through scaffold, refinement, and verification milestones.`;
|
|
15003
|
+
}
|
|
14705
15004
|
return `Deliver "${goal}" through structured analysis, implementation, and verification milestones.`;
|
|
14706
15005
|
}
|
|
14707
15006
|
function createPlan(input) {
|
|
@@ -14734,12 +15033,176 @@ function createPlan(input) {
|
|
|
14734
15033
|
});
|
|
14735
15034
|
}
|
|
14736
15035
|
|
|
14737
|
-
// src/
|
|
15036
|
+
// src/workspace.ts
|
|
15037
|
+
var import_promises12 = require("node:fs/promises");
|
|
15038
|
+
var import_node_path12 = __toESM(require("node:path"), 1);
|
|
15039
|
+
var PROJECT_MARKERS = /* @__PURE__ */ new Set([
|
|
15040
|
+
".git",
|
|
15041
|
+
"package.json",
|
|
15042
|
+
"tsconfig.json",
|
|
15043
|
+
"pnpm-workspace.yaml",
|
|
15044
|
+
"turbo.json",
|
|
15045
|
+
"vite.config.ts",
|
|
15046
|
+
"vite.config.js",
|
|
15047
|
+
"next.config.ts",
|
|
15048
|
+
"next.config.js",
|
|
15049
|
+
"src",
|
|
15050
|
+
"app",
|
|
15051
|
+
"pages",
|
|
15052
|
+
"prisma",
|
|
15053
|
+
"pyproject.toml",
|
|
15054
|
+
"Cargo.toml",
|
|
15055
|
+
"go.mod"
|
|
15056
|
+
]);
|
|
15057
|
+
var GREENFIELD_KEYWORDS = [
|
|
15058
|
+
"build",
|
|
15059
|
+
"create",
|
|
15060
|
+
"make",
|
|
15061
|
+
"scaffold",
|
|
15062
|
+
"generate",
|
|
15063
|
+
"new app",
|
|
15064
|
+
"new project",
|
|
15065
|
+
"landing page",
|
|
15066
|
+
"homepage",
|
|
15067
|
+
"marketing page",
|
|
15068
|
+
"storefront",
|
|
15069
|
+
"website"
|
|
15070
|
+
];
|
|
15071
|
+
var EXISTING_REPO_PATTERNS = [
|
|
15072
|
+
/\bthis repo\b/i,
|
|
15073
|
+
/\bthis repository\b/i,
|
|
15074
|
+
/\bthis project\b/i,
|
|
15075
|
+
/\bthis codebase\b/i,
|
|
15076
|
+
/\bcurrent repo\b/i,
|
|
15077
|
+
/\bcurrent project\b/i,
|
|
15078
|
+
/\bexisting repo\b/i,
|
|
15079
|
+
/\bexisting project\b/i,
|
|
15080
|
+
/\bin this repo\b/i,
|
|
15081
|
+
/\bin this project\b/i
|
|
15082
|
+
];
|
|
15083
|
+
var WORKSPACE_NAME_STOP_WORDS = /* @__PURE__ */ new Set([
|
|
15084
|
+
"a",
|
|
15085
|
+
"an",
|
|
15086
|
+
"and",
|
|
15087
|
+
"app",
|
|
15088
|
+
"application",
|
|
15089
|
+
"build",
|
|
15090
|
+
"create",
|
|
15091
|
+
"for",
|
|
15092
|
+
"generate",
|
|
15093
|
+
"make",
|
|
15094
|
+
"new",
|
|
15095
|
+
"page",
|
|
15096
|
+
"please",
|
|
15097
|
+
"project",
|
|
15098
|
+
"scaffold",
|
|
15099
|
+
"site",
|
|
15100
|
+
"that",
|
|
15101
|
+
"the",
|
|
15102
|
+
"to",
|
|
15103
|
+
"website",
|
|
15104
|
+
"with"
|
|
15105
|
+
]);
|
|
15106
|
+
async function readEntries(cwd) {
|
|
15107
|
+
try {
|
|
15108
|
+
return await (0, import_promises12.readdir)(cwd);
|
|
15109
|
+
} catch {
|
|
15110
|
+
return [];
|
|
15111
|
+
}
|
|
15112
|
+
}
|
|
15113
|
+
async function readMeaningfulEntries(cwd) {
|
|
15114
|
+
const entries = await readEntries(cwd);
|
|
15115
|
+
return entries.filter((entry) => entry !== ".kimbho" && !entry.startsWith("."));
|
|
15116
|
+
}
|
|
15117
|
+
async function isProjectWorkspace(cwd) {
|
|
15118
|
+
const entries = await readEntries(cwd);
|
|
15119
|
+
return entries.some((entry) => PROJECT_MARKERS.has(entry));
|
|
15120
|
+
}
|
|
15121
|
+
function isGreenfieldGoal(goal) {
|
|
15122
|
+
const normalized = goal.trim().toLowerCase();
|
|
15123
|
+
if (!normalized || EXISTING_REPO_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
15124
|
+
return false;
|
|
15125
|
+
}
|
|
15126
|
+
return GREENFIELD_KEYWORDS.some((keyword) => normalized.includes(keyword));
|
|
15127
|
+
}
|
|
15128
|
+
function sanitizeWorkspaceName(value) {
|
|
15129
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-");
|
|
15130
|
+
}
|
|
15131
|
+
function inferWorkspaceName(goal) {
|
|
15132
|
+
const normalized = goal.trim().toLowerCase();
|
|
15133
|
+
const trailingContext = normalized.split(/\bfor\b/).at(-1)?.trim() ?? normalized;
|
|
15134
|
+
const contextWords = trailingContext.split(/\s+/).map((word) => sanitizeWorkspaceName(word)).filter((word) => word.length > 0 && !WORKSPACE_NAME_STOP_WORDS.has(word));
|
|
15135
|
+
const goalWords = normalized.split(/\s+/).map((word) => sanitizeWorkspaceName(word)).filter((word) => word.length > 0 && !WORKSPACE_NAME_STOP_WORDS.has(word));
|
|
15136
|
+
const preferred = [
|
|
15137
|
+
...contextWords,
|
|
15138
|
+
...goalWords
|
|
15139
|
+
];
|
|
15140
|
+
const deduped = Array.from(new Set(preferred)).slice(0, 4);
|
|
15141
|
+
const candidate = sanitizeWorkspaceName(deduped.join("-"));
|
|
15142
|
+
return candidate.length > 0 ? candidate : "kimbho-app";
|
|
15143
|
+
}
|
|
15144
|
+
async function chooseWorkspacePath(baseCwd, workspaceName) {
|
|
15145
|
+
const basePath = import_node_path12.default.join(baseCwd, workspaceName);
|
|
15146
|
+
let attempt = 0;
|
|
15147
|
+
while (attempt < 50) {
|
|
15148
|
+
const suffix = attempt === 0 ? "" : `-${attempt + 1}`;
|
|
15149
|
+
const candidatePath = `${basePath}${suffix}`;
|
|
15150
|
+
const entries = await readMeaningfulEntries(candidatePath);
|
|
15151
|
+
if (entries.length === 0) {
|
|
15152
|
+
return candidatePath;
|
|
15153
|
+
}
|
|
15154
|
+
attempt += 1;
|
|
15155
|
+
}
|
|
15156
|
+
return `${basePath}-${Date.now()}`;
|
|
15157
|
+
}
|
|
14738
15158
|
async function detectWorkspaceState(cwd) {
|
|
14739
|
-
|
|
14740
|
-
|
|
15159
|
+
if (await isProjectWorkspace(cwd)) {
|
|
15160
|
+
return "existing";
|
|
15161
|
+
}
|
|
15162
|
+
const meaningfulEntries = await readMeaningfulEntries(cwd);
|
|
14741
15163
|
return meaningfulEntries.length === 0 ? "empty" : "existing";
|
|
14742
15164
|
}
|
|
15165
|
+
async function inferPlanningWorkspaceState(cwd, goal) {
|
|
15166
|
+
const existingState = await detectWorkspaceState(cwd);
|
|
15167
|
+
if (existingState === "empty" || await isProjectWorkspace(cwd) || !isGreenfieldGoal(goal)) {
|
|
15168
|
+
return existingState;
|
|
15169
|
+
}
|
|
15170
|
+
return "empty";
|
|
15171
|
+
}
|
|
15172
|
+
async function resolveExecutionWorkspace(cwd, goal) {
|
|
15173
|
+
const workspaceState = await detectWorkspaceState(cwd);
|
|
15174
|
+
if (workspaceState === "empty" || await isProjectWorkspace(cwd) || !isGreenfieldGoal(goal)) {
|
|
15175
|
+
return {
|
|
15176
|
+
cwd,
|
|
15177
|
+
workspaceState,
|
|
15178
|
+
notes: []
|
|
15179
|
+
};
|
|
15180
|
+
}
|
|
15181
|
+
const workspaceName = inferWorkspaceName(goal);
|
|
15182
|
+
const targetCwd = await chooseWorkspacePath(cwd, workspaceName);
|
|
15183
|
+
await (0, import_promises12.mkdir)(targetCwd, { recursive: true });
|
|
15184
|
+
const notes = [
|
|
15185
|
+
`Created workspace ${targetCwd} for this greenfield build because ${cwd} is not a project workspace.`
|
|
15186
|
+
];
|
|
15187
|
+
let inheritedConfigPath;
|
|
15188
|
+
const sourceConfig = await loadConfig(cwd);
|
|
15189
|
+
const targetConfig = await loadConfig(targetCwd);
|
|
15190
|
+
if (sourceConfig && !targetConfig) {
|
|
15191
|
+
inheritedConfigPath = await saveConfig(sourceConfig, targetCwd);
|
|
15192
|
+
notes.push(`Copied the active Kimbho config into ${targetCwd} so model/provider settings carry over.`);
|
|
15193
|
+
}
|
|
15194
|
+
return {
|
|
15195
|
+
cwd: targetCwd,
|
|
15196
|
+
workspaceState: await detectWorkspaceState(targetCwd),
|
|
15197
|
+
createdWorkspacePath: targetCwd,
|
|
15198
|
+
...inheritedConfigPath ? {
|
|
15199
|
+
inheritedConfigPath
|
|
15200
|
+
} : {},
|
|
15201
|
+
notes
|
|
15202
|
+
};
|
|
15203
|
+
}
|
|
15204
|
+
|
|
15205
|
+
// src/commands/plan.ts
|
|
14743
15206
|
function createPlanCommand() {
|
|
14744
15207
|
return new Command("plan").description("Generate a structured Kimbho execution plan for the provided goal.").argument("<goal>", "High-level product or engineering goal").option("--stack <stack>", "Preferred stack or preset").option(
|
|
14745
15208
|
"--constraint <constraint>",
|
|
@@ -14752,7 +15215,7 @@ function createPlanCommand() {
|
|
|
14752
15215
|
goal,
|
|
14753
15216
|
mode: "plan",
|
|
14754
15217
|
cwd,
|
|
14755
|
-
workspaceState: await
|
|
15218
|
+
workspaceState: await inferPlanningWorkspaceState(cwd, goal),
|
|
14756
15219
|
stackPreference: options.stack,
|
|
14757
15220
|
constraints: options.constraint
|
|
14758
15221
|
};
|
|
@@ -14891,7 +15354,7 @@ function createProvidersCommand() {
|
|
|
14891
15354
|
|
|
14892
15355
|
// src/commands/review.ts
|
|
14893
15356
|
var import_promises13 = require("node:fs/promises");
|
|
14894
|
-
var
|
|
15357
|
+
var import_node_path13 = __toESM(require("node:path"), 1);
|
|
14895
15358
|
var import_node_process9 = __toESM(require("node:process"), 1);
|
|
14896
15359
|
function summarizeChangedFiles2(diff) {
|
|
14897
15360
|
const files = /* @__PURE__ */ new Set();
|
|
@@ -14975,7 +15438,7 @@ ${diff.stdout}`
|
|
|
14975
15438
|
}
|
|
14976
15439
|
}
|
|
14977
15440
|
await ensureKimbhoDir(cwd);
|
|
14978
|
-
const artifactPath =
|
|
15441
|
+
const artifactPath = import_node_path13.default.join(resolveKimbhoDir(cwd), "logs", `review-${Date.now()}.md`);
|
|
14979
15442
|
await (0, import_promises13.writeFile)(artifactPath, [
|
|
14980
15443
|
`# Review`,
|
|
14981
15444
|
``,
|
|
@@ -15030,7 +15493,7 @@ function parseCount(value) {
|
|
|
15030
15493
|
return parsed;
|
|
15031
15494
|
}
|
|
15032
15495
|
function createResumeCommand() {
|
|
15033
|
-
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,
|
|
15496
|
+
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, 3).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount, 2).action(async (options) => {
|
|
15034
15497
|
const cwd = import_node_process10.default.cwd();
|
|
15035
15498
|
const session = await loadLatestSession(cwd);
|
|
15036
15499
|
if (!session) {
|
|
@@ -15055,13 +15518,7 @@ function createResumeCommand() {
|
|
|
15055
15518
|
}
|
|
15056
15519
|
|
|
15057
15520
|
// src/commands/run.ts
|
|
15058
|
-
var import_promises14 = require("node:fs/promises");
|
|
15059
15521
|
var import_node_process11 = __toESM(require("node:process"), 1);
|
|
15060
|
-
async function detectWorkspaceState2(cwd) {
|
|
15061
|
-
const entries = await (0, import_promises14.readdir)(cwd);
|
|
15062
|
-
const meaningfulEntries = entries.filter((entry) => entry !== ".kimbho" && !entry.startsWith("."));
|
|
15063
|
-
return meaningfulEntries.length === 0 ? "empty" : "existing";
|
|
15064
|
-
}
|
|
15065
15522
|
function parseCount2(value) {
|
|
15066
15523
|
const parsed = Number(value);
|
|
15067
15524
|
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
@@ -15075,7 +15532,7 @@ function createRunCommand() {
|
|
|
15075
15532
|
"Explicit execution constraint; can be provided multiple times",
|
|
15076
15533
|
(value, previous = []) => [...previous, value],
|
|
15077
15534
|
[]
|
|
15078
|
-
).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,
|
|
15535
|
+
).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, 3).option("--max-agent-steps <count>", "Maximum tool/model steps per autonomous task", parseCount2, 8).option("--max-repair-attempts <count>", "Maximum failed verification cycles per autonomous task", parseCount2, 2).action(async (goal, options) => {
|
|
15079
15536
|
const cwd = import_node_process11.default.cwd();
|
|
15080
15537
|
const orchestrator = new ExecutionOrchestrator();
|
|
15081
15538
|
let request;
|
|
@@ -15087,22 +15544,26 @@ function createRunCommand() {
|
|
|
15087
15544
|
return;
|
|
15088
15545
|
}
|
|
15089
15546
|
if (goal) {
|
|
15547
|
+
const workspace = await resolveExecutionWorkspace(cwd, goal);
|
|
15090
15548
|
request = {
|
|
15091
15549
|
goal,
|
|
15092
15550
|
mode: "run",
|
|
15093
|
-
cwd,
|
|
15094
|
-
workspaceState:
|
|
15551
|
+
cwd: workspace.cwd,
|
|
15552
|
+
workspaceState: workspace.workspaceState,
|
|
15095
15553
|
stackPreference: options.stack,
|
|
15096
15554
|
constraints: options.constraint
|
|
15097
15555
|
};
|
|
15098
15556
|
plan = createPlan(request);
|
|
15099
|
-
planPath = await savePlan(plan, cwd);
|
|
15557
|
+
planPath = await savePlan(plan, workspace.cwd);
|
|
15558
|
+
for (const note of workspace.notes) {
|
|
15559
|
+
console.log(note);
|
|
15560
|
+
}
|
|
15100
15561
|
} else {
|
|
15101
15562
|
request = {
|
|
15102
15563
|
goal: plan.goal,
|
|
15103
15564
|
mode: "run",
|
|
15104
15565
|
cwd,
|
|
15105
|
-
workspaceState:
|
|
15566
|
+
workspaceState: plan.repoStrategy.mode === "greenfield" ? "empty" : "existing",
|
|
15106
15567
|
stackPreference: options.stack,
|
|
15107
15568
|
constraints: options.constraint
|
|
15108
15569
|
};
|
|
@@ -15114,7 +15575,7 @@ function createRunCommand() {
|
|
|
15114
15575
|
maxAgentSteps: options.maxAgentSteps,
|
|
15115
15576
|
maxRepairAttempts: options.maxRepairAttempts
|
|
15116
15577
|
});
|
|
15117
|
-
const sessionPath = await saveSession(snapshot, cwd);
|
|
15578
|
+
const sessionPath = await saveSession(snapshot, request.cwd);
|
|
15118
15579
|
if (options.json) {
|
|
15119
15580
|
console.log(
|
|
15120
15581
|
renderJson({
|
|
@@ -15133,6 +15594,9 @@ function createRunCommand() {
|
|
|
15133
15594
|
console.log(`Saved plan: ${planPath}`);
|
|
15134
15595
|
}
|
|
15135
15596
|
console.log(`Saved session: ${sessionPath}`);
|
|
15597
|
+
if (request.cwd !== cwd) {
|
|
15598
|
+
console.log(`Continue in: cd ${request.cwd}`);
|
|
15599
|
+
}
|
|
15136
15600
|
});
|
|
15137
15601
|
}
|
|
15138
15602
|
|
|
@@ -15193,8 +15657,7 @@ function createProgram(onOpenShell) {
|
|
|
15193
15657
|
}
|
|
15194
15658
|
|
|
15195
15659
|
// src/shell.ts
|
|
15196
|
-
var
|
|
15197
|
-
var import_promises16 = require("node:readline/promises");
|
|
15660
|
+
var import_promises14 = require("node:readline/promises");
|
|
15198
15661
|
var import_node_process12 = __toESM(require("node:process"), 1);
|
|
15199
15662
|
var AMBER = "\x1B[38;5;214m";
|
|
15200
15663
|
var CYAN = "\x1B[38;5;45m";
|
|
@@ -15241,7 +15704,7 @@ var BRAIN_ROLES = [
|
|
|
15241
15704
|
"fast"
|
|
15242
15705
|
];
|
|
15243
15706
|
var MAX_CHAT_MESSAGES = 12;
|
|
15244
|
-
var DEFAULT_MAX_AUTO_TASKS =
|
|
15707
|
+
var DEFAULT_MAX_AUTO_TASKS = 3;
|
|
15245
15708
|
var DEFAULT_MAX_AGENT_STEPS = 8;
|
|
15246
15709
|
var DEFAULT_MAX_REPAIR_ATTEMPTS2 = 2;
|
|
15247
15710
|
var EXECUTION_PREFIXES = [
|
|
@@ -15524,11 +15987,6 @@ function printHeader(cwd, state) {
|
|
|
15524
15987
|
console.log(renderHelp());
|
|
15525
15988
|
console.log("");
|
|
15526
15989
|
}
|
|
15527
|
-
async function detectWorkspaceState3(cwd) {
|
|
15528
|
-
const entries = await (0, import_promises15.readdir)(cwd);
|
|
15529
|
-
const meaningfulEntries = entries.filter((entry) => entry !== ".kimbho" && !entry.startsWith("."));
|
|
15530
|
-
return meaningfulEntries.length === 0 ? "empty" : "existing";
|
|
15531
|
-
}
|
|
15532
15990
|
function inferPromptIntent(input) {
|
|
15533
15991
|
const normalized = input.trim().toLowerCase();
|
|
15534
15992
|
if (!normalized) {
|
|
@@ -15952,15 +16410,16 @@ async function handleChatPrompt(cwd, prompt, runtime) {
|
|
|
15952
16410
|
}
|
|
15953
16411
|
async function runGoalExecution(cwd, goal, runtime) {
|
|
15954
16412
|
const orchestrator = new ExecutionOrchestrator();
|
|
16413
|
+
const workspace = await resolveExecutionWorkspace(cwd, goal);
|
|
15955
16414
|
const request = {
|
|
15956
16415
|
goal,
|
|
15957
16416
|
mode: "run",
|
|
15958
|
-
cwd,
|
|
15959
|
-
workspaceState:
|
|
16417
|
+
cwd: workspace.cwd,
|
|
16418
|
+
workspaceState: workspace.workspaceState,
|
|
15960
16419
|
constraints: []
|
|
15961
16420
|
};
|
|
15962
16421
|
const plan = createPlan(request);
|
|
15963
|
-
const planPath = await savePlan(plan, cwd);
|
|
16422
|
+
const planPath = await savePlan(plan, request.cwd);
|
|
15964
16423
|
const envelope = orchestrator.buildEnvelope(request, plan);
|
|
15965
16424
|
const initialSnapshot = orchestrator.createSessionSnapshot(envelope);
|
|
15966
16425
|
const startedAt = Date.now();
|
|
@@ -15980,8 +16439,8 @@ async function runGoalExecution(cwd, goal, runtime) {
|
|
|
15980
16439
|
label: goal
|
|
15981
16440
|
};
|
|
15982
16441
|
console.log(color(DIM, `Working on: ${goal}`));
|
|
15983
|
-
|
|
15984
|
-
console.log(color(DIM,
|
|
16442
|
+
for (const note of workspace.notes) {
|
|
16443
|
+
console.log(color(DIM, note));
|
|
15985
16444
|
}
|
|
15986
16445
|
console.log(renderShellPlanPreview(plan).join("\n"));
|
|
15987
16446
|
console.log(renderRunStartCard(liveBoard));
|
|
@@ -16019,11 +16478,13 @@ async function runGoalExecution(cwd, goal, runtime) {
|
|
|
16019
16478
|
} finally {
|
|
16020
16479
|
runtime.activeExecution = null;
|
|
16021
16480
|
}
|
|
16022
|
-
const sessionPath = await saveSession(snapshot, cwd);
|
|
16481
|
+
const sessionPath = await saveSession(snapshot, request.cwd);
|
|
16482
|
+
runtime.currentCwd = request.cwd;
|
|
16023
16483
|
console.log("");
|
|
16024
16484
|
console.log(color(DIM, `elapsed: ${((Date.now() - startedAt) / 1e3).toFixed(1)}s`));
|
|
16025
16485
|
console.log(color(DIM, renderExecutionTelemetry(telemetry, startedAt)));
|
|
16026
16486
|
console.log(renderShellSessionSummary(snapshot, planPath, sessionPath));
|
|
16487
|
+
return request.cwd;
|
|
16027
16488
|
}
|
|
16028
16489
|
async function resumeGoalExecution(cwd, runtime) {
|
|
16029
16490
|
const session = await loadLatestSession(cwd);
|
|
@@ -16099,7 +16560,7 @@ async function createPlanOnly(cwd, goal) {
|
|
|
16099
16560
|
goal,
|
|
16100
16561
|
mode: "plan",
|
|
16101
16562
|
cwd,
|
|
16102
|
-
workspaceState: await
|
|
16563
|
+
workspaceState: await inferPlanningWorkspaceState(cwd, goal),
|
|
16103
16564
|
constraints: []
|
|
16104
16565
|
};
|
|
16105
16566
|
const plan = createPlan(request);
|
|
@@ -16543,18 +17004,18 @@ function toExternalCommandTokens(input, state) {
|
|
|
16543
17004
|
async function handleShellCommand(cwd, input, state, runtime, execute) {
|
|
16544
17005
|
const trimmed = input.trim();
|
|
16545
17006
|
if (!trimmed) {
|
|
16546
|
-
return;
|
|
17007
|
+
return cwd;
|
|
16547
17008
|
}
|
|
16548
17009
|
if (trimmed === "/exit" || trimmed === "exit" || trimmed === "quit" || trimmed === "/quit") {
|
|
16549
17010
|
throw new Error("__kimbho_exit__");
|
|
16550
17011
|
}
|
|
16551
17012
|
if (trimmed === "/help" || trimmed === "help" || trimmed === "?") {
|
|
16552
17013
|
console.log(renderHelp());
|
|
16553
|
-
return;
|
|
17014
|
+
return cwd;
|
|
16554
17015
|
}
|
|
16555
17016
|
if (trimmed === "/status" || trimmed === "status") {
|
|
16556
17017
|
console.log(renderStartupCard(cwd, state));
|
|
16557
|
-
return;
|
|
17018
|
+
return cwd;
|
|
16558
17019
|
}
|
|
16559
17020
|
if (trimmed === "/clear" || trimmed === "clear") {
|
|
16560
17021
|
if (import_node_process12.default.stdout.isTTY) {
|
|
@@ -16562,28 +17023,28 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
|
|
|
16562
17023
|
}
|
|
16563
17024
|
const nextState = await getShellSessionState(cwd, runtime.focusRole);
|
|
16564
17025
|
printHeader(cwd, nextState);
|
|
16565
|
-
return;
|
|
17026
|
+
return cwd;
|
|
16566
17027
|
}
|
|
16567
17028
|
const { tokens, head } = normalizeInputTokens(trimmed);
|
|
16568
17029
|
const firstToken = tokens[0];
|
|
16569
17030
|
const isSlashCommand = firstToken?.startsWith("/") ?? false;
|
|
16570
17031
|
if (!head) {
|
|
16571
|
-
return;
|
|
17032
|
+
return cwd;
|
|
16572
17033
|
}
|
|
16573
17034
|
if (!firstToken?.startsWith("/") && !TOP_LEVEL_COMMANDS.has(head) && !head.startsWith("-")) {
|
|
16574
17035
|
const intent = inferPromptIntent(trimmed);
|
|
16575
17036
|
if (intent === "run") {
|
|
16576
|
-
await runGoalExecution(cwd, trimmed, runtime);
|
|
17037
|
+
const nextCwd = await runGoalExecution(cwd, trimmed, runtime);
|
|
16577
17038
|
clearAllConversations(runtime);
|
|
16578
17039
|
runtime.lastModels = null;
|
|
16579
|
-
return;
|
|
17040
|
+
return nextCwd;
|
|
16580
17041
|
}
|
|
16581
17042
|
if (intent === "plan") {
|
|
16582
17043
|
await createPlanOnly(cwd, normalizePlanPrompt(trimmed));
|
|
16583
|
-
return;
|
|
17044
|
+
return cwd;
|
|
16584
17045
|
}
|
|
16585
17046
|
await handleChatPrompt(cwd, trimmed, runtime);
|
|
16586
|
-
return;
|
|
17047
|
+
return cwd;
|
|
16587
17048
|
}
|
|
16588
17049
|
if (head === "provider" || head === "providers") {
|
|
16589
17050
|
const subcommand = tokens[1];
|
|
@@ -16593,7 +17054,7 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
|
|
|
16593
17054
|
"providers",
|
|
16594
17055
|
...tokens.slice(1)
|
|
16595
17056
|
], runtime);
|
|
16596
|
-
return;
|
|
17057
|
+
return cwd;
|
|
16597
17058
|
}
|
|
16598
17059
|
}
|
|
16599
17060
|
if (head === "brain" || head === "brains") {
|
|
@@ -16605,12 +17066,12 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
|
|
|
16605
17066
|
"brain",
|
|
16606
17067
|
...tokens.slice(1)
|
|
16607
17068
|
], runtime);
|
|
16608
|
-
return;
|
|
17069
|
+
return cwd;
|
|
16609
17070
|
}
|
|
16610
17071
|
}
|
|
16611
17072
|
if (head === "model") {
|
|
16612
17073
|
await printBrainAssignments(cwd);
|
|
16613
|
-
return;
|
|
17074
|
+
return cwd;
|
|
16614
17075
|
}
|
|
16615
17076
|
if (head === "ask" || head === "chat") {
|
|
16616
17077
|
const prompt = tokens.slice(1).join(" ").trim();
|
|
@@ -16618,19 +17079,19 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
|
|
|
16618
17079
|
throw new Error(`Usage: /${head} <prompt>`);
|
|
16619
17080
|
}
|
|
16620
17081
|
await handleChatPrompt(cwd, prompt, runtime);
|
|
16621
|
-
return;
|
|
17082
|
+
return cwd;
|
|
16622
17083
|
}
|
|
16623
17084
|
if (head === "reset-chat") {
|
|
16624
17085
|
clearConversation(runtime, runtime.focusRole);
|
|
16625
17086
|
console.log(`Cleared ${runtime.focusRole} conversation history.`);
|
|
16626
|
-
return;
|
|
17087
|
+
return cwd;
|
|
16627
17088
|
}
|
|
16628
17089
|
if (head === "models") {
|
|
16629
17090
|
await handleModelsCommand(cwd, [
|
|
16630
17091
|
"models",
|
|
16631
17092
|
...tokens.slice(1)
|
|
16632
17093
|
], runtime);
|
|
16633
|
-
return;
|
|
17094
|
+
return cwd;
|
|
16634
17095
|
}
|
|
16635
17096
|
if (head === "use-model") {
|
|
16636
17097
|
const modelId = tokens.slice(1).join(" ").trim();
|
|
@@ -16638,50 +17099,51 @@ async function handleShellCommand(cwd, input, state, runtime, execute) {
|
|
|
16638
17099
|
throw new Error("Usage: /use-model <model-id>");
|
|
16639
17100
|
}
|
|
16640
17101
|
await handleModelSelection(cwd, modelId, runtime);
|
|
16641
|
-
return;
|
|
17102
|
+
return cwd;
|
|
16642
17103
|
}
|
|
16643
17104
|
if (head === "select") {
|
|
16644
17105
|
await handleSelectCommand(cwd, [
|
|
16645
17106
|
"select",
|
|
16646
17107
|
...tokens.slice(1)
|
|
16647
17108
|
], runtime);
|
|
16648
|
-
return;
|
|
17109
|
+
return cwd;
|
|
16649
17110
|
}
|
|
16650
17111
|
if (head === "run" || head === "new" || head === "scaffold") {
|
|
16651
17112
|
const goal = head === "run" ? tokens.slice(1).join(" ").trim() : head === "new" ? tokens.slice(1).join(" ").trim() : `scaffold ${tokens.slice(1).join(" ").trim()}`.trim();
|
|
16652
17113
|
if (!goal) {
|
|
16653
17114
|
throw new Error(`Usage: /${head} <goal>`);
|
|
16654
17115
|
}
|
|
16655
|
-
await runGoalExecution(cwd, goal, runtime);
|
|
17116
|
+
const nextCwd = await runGoalExecution(cwd, goal, runtime);
|
|
16656
17117
|
clearAllConversations(runtime);
|
|
16657
17118
|
runtime.lastModels = null;
|
|
16658
|
-
return;
|
|
17119
|
+
return nextCwd;
|
|
16659
17120
|
}
|
|
16660
17121
|
if (head === "plan") {
|
|
16661
17122
|
if (!isSlashCommand) {
|
|
16662
17123
|
await createPlanOnly(cwd, normalizePlanPrompt(trimmed));
|
|
16663
|
-
return;
|
|
17124
|
+
return cwd;
|
|
16664
17125
|
}
|
|
16665
17126
|
const goal = tokens.slice(1).join(" ").trim();
|
|
16666
17127
|
if (!goal) {
|
|
16667
17128
|
await printLatestPlanSummary(cwd);
|
|
16668
|
-
return;
|
|
17129
|
+
return cwd;
|
|
16669
17130
|
}
|
|
16670
17131
|
await createPlanOnly(cwd, goal);
|
|
16671
|
-
return;
|
|
17132
|
+
return cwd;
|
|
16672
17133
|
}
|
|
16673
17134
|
if (head === "resume") {
|
|
16674
17135
|
await resumeGoalExecution(cwd, runtime);
|
|
16675
|
-
return;
|
|
17136
|
+
return cwd;
|
|
16676
17137
|
}
|
|
16677
17138
|
const externalTokens = toExternalCommandTokens(trimmed, state);
|
|
16678
17139
|
if (externalTokens.length === 0) {
|
|
16679
|
-
return;
|
|
17140
|
+
return cwd;
|
|
16680
17141
|
}
|
|
16681
17142
|
await execute(externalTokens);
|
|
17143
|
+
return cwd;
|
|
16682
17144
|
}
|
|
16683
17145
|
async function runInteractiveShell(options) {
|
|
16684
|
-
const readline = (0,
|
|
17146
|
+
const readline = (0, import_promises14.createInterface)({
|
|
16685
17147
|
input: import_node_process12.default.stdin,
|
|
16686
17148
|
output: import_node_process12.default.stdout,
|
|
16687
17149
|
terminal: Boolean(import_node_process12.default.stdin.isTTY && import_node_process12.default.stdout.isTTY)
|
|
@@ -16689,6 +17151,7 @@ async function runInteractiveShell(options) {
|
|
|
16689
17151
|
const runtime = {
|
|
16690
17152
|
focusRole: "coder",
|
|
16691
17153
|
lastModels: null,
|
|
17154
|
+
currentCwd: options.cwd,
|
|
16692
17155
|
activeExecution: null,
|
|
16693
17156
|
conversations: {
|
|
16694
17157
|
planner: [],
|
|
@@ -16697,6 +17160,7 @@ async function runInteractiveShell(options) {
|
|
|
16697
17160
|
fast: []
|
|
16698
17161
|
}
|
|
16699
17162
|
};
|
|
17163
|
+
let currentCwd = options.cwd;
|
|
16700
17164
|
let closed = false;
|
|
16701
17165
|
readline.on("SIGINT", () => {
|
|
16702
17166
|
if (runtime.activeExecution) {
|
|
@@ -16708,18 +17172,19 @@ async function runInteractiveShell(options) {
|
|
|
16708
17172
|
closed = true;
|
|
16709
17173
|
readline.close();
|
|
16710
17174
|
});
|
|
16711
|
-
let state = await getShellSessionState(
|
|
16712
|
-
printHeader(
|
|
17175
|
+
let state = await getShellSessionState(currentCwd, runtime.focusRole);
|
|
17176
|
+
printHeader(currentCwd, state);
|
|
16713
17177
|
while (!closed) {
|
|
16714
17178
|
let line;
|
|
16715
17179
|
try {
|
|
16716
|
-
state = await getShellSessionState(
|
|
17180
|
+
state = await getShellSessionState(currentCwd, runtime.focusRole);
|
|
16717
17181
|
line = await readline.question(formatPrompt(state));
|
|
16718
17182
|
} catch {
|
|
16719
17183
|
break;
|
|
16720
17184
|
}
|
|
16721
17185
|
try {
|
|
16722
|
-
await handleShellCommand(
|
|
17186
|
+
currentCwd = await handleShellCommand(currentCwd, line, state, runtime, options.execute);
|
|
17187
|
+
runtime.currentCwd = currentCwd;
|
|
16723
17188
|
} catch (error) {
|
|
16724
17189
|
const message = error instanceof Error ? error.message : String(error);
|
|
16725
17190
|
if (message === "__kimbho_exit__") {
|