@kody-ade/kody-engine-lite 0.1.133 → 0.1.134
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +111 -5
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -1183,8 +1183,8 @@ async function tryStartLitellm(url, projectDir, generatedConfig) {
|
|
|
1183
1183
|
logger.info(` Loaded API keys: ${Object.keys(dotenvVars).join(", ")}`);
|
|
1184
1184
|
}
|
|
1185
1185
|
}
|
|
1186
|
-
const { spawn:
|
|
1187
|
-
const child =
|
|
1186
|
+
const { spawn: spawn3 } = await import("child_process");
|
|
1187
|
+
const child = spawn3(cmd, args2, {
|
|
1188
1188
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1189
1189
|
detached: true,
|
|
1190
1190
|
env: { ...process.env, ...dotenvVars }
|
|
@@ -2610,8 +2610,8 @@ async function startProxy(config, url) {
|
|
|
2610
2610
|
fs13.writeFileSync(CONFIG_PATH, config);
|
|
2611
2611
|
const portMatch = url.match(/:(\d+)/);
|
|
2612
2612
|
const port = portMatch ? portMatch[1] : "4099";
|
|
2613
|
-
const { spawn:
|
|
2614
|
-
const child =
|
|
2613
|
+
const { spawn: spawn3 } = await import("child_process");
|
|
2614
|
+
const child = spawn3("litellm", ["--config", CONFIG_PATH, "--port", port], {
|
|
2615
2615
|
stdio: ["ignore", "pipe", "pipe"],
|
|
2616
2616
|
detached: true,
|
|
2617
2617
|
env: process.env
|
|
@@ -3741,7 +3741,15 @@ function getDevServerInfo(taskDir) {
|
|
|
3741
3741
|
}
|
|
3742
3742
|
function getBrowserToolGuidance(stageName, taskDir) {
|
|
3743
3743
|
const devServer = getDevServerInfo(taskDir);
|
|
3744
|
-
const
|
|
3744
|
+
const engineManagedServer = process.env.KODY_DEV_SERVER_READY !== void 0;
|
|
3745
|
+
const serverReady = process.env.KODY_DEV_SERVER_READY === "true";
|
|
3746
|
+
const serverUrl = process.env.KODY_DEV_SERVER_URL ?? devServer?.url;
|
|
3747
|
+
const devServerBlock = engineManagedServer ? serverReady ? `
|
|
3748
|
+
### Dev Server
|
|
3749
|
+
The dev server is already running at ${serverUrl}. Do NOT start it yourself.
|
|
3750
|
+
You can use browser tools to navigate to ${serverUrl} directly.` : `
|
|
3751
|
+
### Dev Server
|
|
3752
|
+
The dev server failed to start (e.g. DB connection issues). Skip browser verification and proceed with code-only changes. Do NOT attempt to start the dev server yourself \u2014 it will hang.` : devServer ? `
|
|
3745
3753
|
### Dev Server Setup (REQUIRED before browsing)
|
|
3746
3754
|
You MUST start the dev server before using any browser navigation tools:
|
|
3747
3755
|
\`\`\`bash
|
|
@@ -3963,6 +3971,76 @@ var init_runner_selection = __esm({
|
|
|
3963
3971
|
}
|
|
3964
3972
|
});
|
|
3965
3973
|
|
|
3974
|
+
// src/dev-server.ts
|
|
3975
|
+
import { spawn as spawn2 } from "child_process";
|
|
3976
|
+
async function pollReady(url, timeoutSec) {
|
|
3977
|
+
const deadline = Date.now() + timeoutSec * 1e3;
|
|
3978
|
+
while (Date.now() < deadline) {
|
|
3979
|
+
try {
|
|
3980
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(2e3) });
|
|
3981
|
+
if (res.ok || res.status >= 200 && res.status < 400) return true;
|
|
3982
|
+
} catch {
|
|
3983
|
+
}
|
|
3984
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
3985
|
+
}
|
|
3986
|
+
return false;
|
|
3987
|
+
}
|
|
3988
|
+
async function startDevServer(opts) {
|
|
3989
|
+
const timeout = opts.readyTimeout ?? 30;
|
|
3990
|
+
const [cmd, ...args2] = opts.command.split(/\s+/);
|
|
3991
|
+
let child;
|
|
3992
|
+
try {
|
|
3993
|
+
child = spawn2(cmd, args2, {
|
|
3994
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
3995
|
+
detached: true,
|
|
3996
|
+
shell: true,
|
|
3997
|
+
env: { ...process.env, ...opts.envVars }
|
|
3998
|
+
});
|
|
3999
|
+
} catch (err) {
|
|
4000
|
+
logger.warn(` Dev server failed to spawn: ${err instanceof Error ? err.message : String(err)}`);
|
|
4001
|
+
return { ready: false, url: opts.url, pid: void 0, stop: () => {
|
|
4002
|
+
} };
|
|
4003
|
+
}
|
|
4004
|
+
let stderr = "";
|
|
4005
|
+
child.stderr?.on("data", (chunk) => {
|
|
4006
|
+
stderr += chunk.toString();
|
|
4007
|
+
});
|
|
4008
|
+
let exited = false;
|
|
4009
|
+
child.on("exit", () => {
|
|
4010
|
+
exited = true;
|
|
4011
|
+
});
|
|
4012
|
+
child.unref();
|
|
4013
|
+
const ready = await pollReady(opts.url, timeout);
|
|
4014
|
+
if (!ready) {
|
|
4015
|
+
if (exited) {
|
|
4016
|
+
logger.warn(` Dev server exited before becoming ready`);
|
|
4017
|
+
} else {
|
|
4018
|
+
logger.warn(` Dev server did not respond within ${timeout}s at ${opts.url}`);
|
|
4019
|
+
}
|
|
4020
|
+
if (stderr) {
|
|
4021
|
+
logger.warn(` Dev server stderr (last 500 chars): ${stderr.slice(-500)}`);
|
|
4022
|
+
}
|
|
4023
|
+
}
|
|
4024
|
+
const pid = child.pid;
|
|
4025
|
+
const stop = () => {
|
|
4026
|
+
try {
|
|
4027
|
+
if (pid) process.kill(-pid, "SIGTERM");
|
|
4028
|
+
} catch {
|
|
4029
|
+
}
|
|
4030
|
+
try {
|
|
4031
|
+
child.kill("SIGTERM");
|
|
4032
|
+
} catch {
|
|
4033
|
+
}
|
|
4034
|
+
};
|
|
4035
|
+
return { ready, url: opts.url, pid, stop };
|
|
4036
|
+
}
|
|
4037
|
+
var init_dev_server = __esm({
|
|
4038
|
+
"src/dev-server.ts"() {
|
|
4039
|
+
"use strict";
|
|
4040
|
+
init_logger();
|
|
4041
|
+
}
|
|
4042
|
+
});
|
|
4043
|
+
|
|
3966
4044
|
// src/stages/agent.ts
|
|
3967
4045
|
import * as fs19 from "fs";
|
|
3968
4046
|
import * as path17 from "path";
|
|
@@ -4020,6 +4098,29 @@ async function executeAgentStage(ctx, def) {
|
|
|
4020
4098
|
if (mcpConfigJson) {
|
|
4021
4099
|
logger.info(` MCP servers enabled for ${def.name}`);
|
|
4022
4100
|
}
|
|
4101
|
+
let devServerHandle = null;
|
|
4102
|
+
const ds = config.mcp?.devServer;
|
|
4103
|
+
if (mcpConfigJson && ds && taskHasUI(ctx.taskDir)) {
|
|
4104
|
+
logger.info(` Starting dev server: ${ds.command}`);
|
|
4105
|
+
const envVars = {};
|
|
4106
|
+
for (const varName of ds.env ?? []) {
|
|
4107
|
+
if (process.env[varName]) envVars[varName] = process.env[varName];
|
|
4108
|
+
}
|
|
4109
|
+
devServerHandle = await startDevServer({
|
|
4110
|
+
command: ds.command,
|
|
4111
|
+
url: ds.url,
|
|
4112
|
+
readyTimeout: ds.readyTimeout ?? 30,
|
|
4113
|
+
envVars
|
|
4114
|
+
});
|
|
4115
|
+
if (devServerHandle.ready) {
|
|
4116
|
+
logger.info(` Dev server ready at ${ds.url}`);
|
|
4117
|
+
extraEnv.KODY_DEV_SERVER_URL = ds.url;
|
|
4118
|
+
extraEnv.KODY_DEV_SERVER_READY = "true";
|
|
4119
|
+
} else {
|
|
4120
|
+
logger.warn(` Dev server not ready \u2014 Claude will work without browser verification`);
|
|
4121
|
+
extraEnv.KODY_DEV_SERVER_READY = "false";
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4023
4124
|
const runner = getRunnerForStage(ctx, def.name);
|
|
4024
4125
|
const maxRetries = def.maxRetries ?? 0;
|
|
4025
4126
|
let lastResult = await runner.run(def.name, prompt, model, def.timeout, ctx.taskDir, {
|
|
@@ -4047,6 +4148,10 @@ async function executeAgentStage(ctx, def) {
|
|
|
4047
4148
|
mcpConfigJson
|
|
4048
4149
|
});
|
|
4049
4150
|
}
|
|
4151
|
+
if (devServerHandle) {
|
|
4152
|
+
devServerHandle.stop();
|
|
4153
|
+
logger.info(` Dev server stopped`);
|
|
4154
|
+
}
|
|
4050
4155
|
if (lastResult.outcome !== "completed") {
|
|
4051
4156
|
return { outcome: lastResult.outcome, error: lastResult.error, retries };
|
|
4052
4157
|
}
|
|
@@ -4137,6 +4242,7 @@ var init_agent = __esm({
|
|
|
4137
4242
|
init_config();
|
|
4138
4243
|
init_mcp_config();
|
|
4139
4244
|
init_runner_selection();
|
|
4245
|
+
init_dev_server();
|
|
4140
4246
|
init_logger();
|
|
4141
4247
|
SESSION_GROUP = {
|
|
4142
4248
|
taskify: "explore",
|