@kody-ade/kody-engine 0.4.66 → 0.4.67
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/kody.js +174 -15
- package/dist/executables/goal-scheduler/scheduler.sh +0 -0
- package/dist/executables/release-deploy/deploy.sh +0 -0
- package/dist/executables/release-prepare/prepare.sh +0 -0
- package/dist/executables/release-publish/publish.sh +0 -0
- package/dist/executables/resolve/apply-prefer.sh +0 -0
- package/dist/executables/revert/revert.sh +0 -0
- package/dist/executables/ui-review/profile.json +1 -0
- package/package.json +15 -14
package/dist/bin/kody.js
CHANGED
|
@@ -864,7 +864,7 @@ var init_loadPriorArt = __esm({
|
|
|
864
864
|
// package.json
|
|
865
865
|
var package_default = {
|
|
866
866
|
name: "@kody-ade/kody-engine",
|
|
867
|
-
version: "0.4.
|
|
867
|
+
version: "0.4.67",
|
|
868
868
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
869
869
|
license: "MIT",
|
|
870
870
|
type: "module",
|
|
@@ -2328,7 +2328,7 @@ function coerceBare(spec, value) {
|
|
|
2328
2328
|
init_issue();
|
|
2329
2329
|
|
|
2330
2330
|
// src/executor.ts
|
|
2331
|
-
import { execFileSync as execFileSync29, spawn as
|
|
2331
|
+
import { execFileSync as execFileSync29, spawn as spawn6 } from "child_process";
|
|
2332
2332
|
import * as fs31 from "fs";
|
|
2333
2333
|
import * as path29 from "path";
|
|
2334
2334
|
init_events();
|
|
@@ -9038,6 +9038,164 @@ function postKodyComment(target, issueNumber, state, next, cwd) {
|
|
|
9038
9038
|
}
|
|
9039
9039
|
}
|
|
9040
9040
|
|
|
9041
|
+
// src/scripts/startLocalServer.ts
|
|
9042
|
+
import { spawn as spawn3 } from "child_process";
|
|
9043
|
+
import { existsSync as existsSync26, readFileSync as readFileSync24 } from "fs";
|
|
9044
|
+
import { join as join27 } from "path";
|
|
9045
|
+
var READY_TIMEOUT_MS = 12e4;
|
|
9046
|
+
var READY_POLL_MS = 1e3;
|
|
9047
|
+
var INSTALL_TIMEOUT_MS = 3e5;
|
|
9048
|
+
var FETCH_TIMEOUT_MS = 2e3;
|
|
9049
|
+
var DEFAULT_PORT = 3e3;
|
|
9050
|
+
var startLocalServer = async (ctx) => {
|
|
9051
|
+
if (urlAlreadyResolved(ctx)) {
|
|
9052
|
+
process.stderr.write("[kody startLocalServer] preview URL already set \u2014 skipping\n");
|
|
9053
|
+
return;
|
|
9054
|
+
}
|
|
9055
|
+
const pkg = readPackageJson(ctx.cwd);
|
|
9056
|
+
if (!pkg) return;
|
|
9057
|
+
const scriptName = pickScript(pkg.scripts);
|
|
9058
|
+
if (!scriptName) {
|
|
9059
|
+
process.stderr.write("[kody startLocalServer] no dev/start script in package.json \u2014 skipping\n");
|
|
9060
|
+
return;
|
|
9061
|
+
}
|
|
9062
|
+
const pm = detectPackageManager2(ctx.cwd);
|
|
9063
|
+
const port = pickPort();
|
|
9064
|
+
await ensureDependenciesInstalled(pm, ctx.cwd);
|
|
9065
|
+
const url = `http://localhost:${port}`;
|
|
9066
|
+
process.stderr.write(`[kody startLocalServer] spawning '${pm} run ${scriptName}' on ${url}
|
|
9067
|
+
`);
|
|
9068
|
+
const child = spawnServer(pm, scriptName, port, ctx.cwd);
|
|
9069
|
+
registerProcessCleanup(child);
|
|
9070
|
+
const ready = await waitForReady(url, READY_TIMEOUT_MS);
|
|
9071
|
+
if (!ready) {
|
|
9072
|
+
safeKill(child);
|
|
9073
|
+
throw new Error(
|
|
9074
|
+
`startLocalServer: dev server at ${url} did not become reachable within ${READY_TIMEOUT_MS}ms`
|
|
9075
|
+
);
|
|
9076
|
+
}
|
|
9077
|
+
process.env.PREVIEW_URL = url;
|
|
9078
|
+
ctx.data.qaServerPid = child.pid;
|
|
9079
|
+
ctx.data.qaServerScript = scriptName;
|
|
9080
|
+
process.stderr.write(`[kody startLocalServer] ready: ${url}
|
|
9081
|
+
`);
|
|
9082
|
+
};
|
|
9083
|
+
function urlAlreadyResolved(ctx) {
|
|
9084
|
+
const fromFlag = typeof ctx.args.previewUrl === "string" ? ctx.args.previewUrl.trim() : "";
|
|
9085
|
+
if (fromFlag.length > 0) return true;
|
|
9086
|
+
const fromEnv = (process.env.PREVIEW_URL ?? "").trim();
|
|
9087
|
+
return fromEnv.length > 0;
|
|
9088
|
+
}
|
|
9089
|
+
function readPackageJson(cwd) {
|
|
9090
|
+
const path32 = join27(cwd, "package.json");
|
|
9091
|
+
if (!existsSync26(path32)) {
|
|
9092
|
+
process.stderr.write("[kody startLocalServer] no package.json \u2014 skipping\n");
|
|
9093
|
+
return null;
|
|
9094
|
+
}
|
|
9095
|
+
try {
|
|
9096
|
+
const raw = JSON.parse(readFileSync24(path32, "utf8"));
|
|
9097
|
+
return { scripts: raw.scripts ?? {} };
|
|
9098
|
+
} catch (err) {
|
|
9099
|
+
process.stderr.write(
|
|
9100
|
+
`[kody startLocalServer] could not parse package.json: ${err.message}
|
|
9101
|
+
`
|
|
9102
|
+
);
|
|
9103
|
+
return null;
|
|
9104
|
+
}
|
|
9105
|
+
}
|
|
9106
|
+
function pickScript(scripts) {
|
|
9107
|
+
if (typeof scripts.dev === "string" && scripts.dev.length > 0) return "dev";
|
|
9108
|
+
if (typeof scripts.start === "string" && scripts.start.length > 0) return "start";
|
|
9109
|
+
return null;
|
|
9110
|
+
}
|
|
9111
|
+
function detectPackageManager2(cwd) {
|
|
9112
|
+
if (existsSync26(join27(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
9113
|
+
if (existsSync26(join27(cwd, "yarn.lock"))) return "yarn";
|
|
9114
|
+
return "npm";
|
|
9115
|
+
}
|
|
9116
|
+
function pickPort() {
|
|
9117
|
+
const fromEnv = Number((process.env.PREVIEW_PORT ?? "").trim());
|
|
9118
|
+
if (Number.isInteger(fromEnv) && fromEnv > 0) return fromEnv;
|
|
9119
|
+
return DEFAULT_PORT;
|
|
9120
|
+
}
|
|
9121
|
+
async function ensureDependenciesInstalled(pm, cwd) {
|
|
9122
|
+
if (existsSync26(join27(cwd, "node_modules"))) return;
|
|
9123
|
+
process.stderr.write(`[kody startLocalServer] installing dependencies via ${pm}
|
|
9124
|
+
`);
|
|
9125
|
+
await runOnce(pm, installArgs(pm), cwd, INSTALL_TIMEOUT_MS);
|
|
9126
|
+
}
|
|
9127
|
+
function installArgs(pm) {
|
|
9128
|
+
if (pm === "pnpm") return ["install", "--frozen-lockfile"];
|
|
9129
|
+
if (pm === "yarn") return ["install", "--frozen-lockfile"];
|
|
9130
|
+
return ["ci"];
|
|
9131
|
+
}
|
|
9132
|
+
function spawnServer(pm, scriptName, port, cwd) {
|
|
9133
|
+
const child = spawn3(pm, ["run", scriptName], {
|
|
9134
|
+
cwd,
|
|
9135
|
+
env: { ...process.env, PORT: String(port), NODE_ENV: "development" },
|
|
9136
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
9137
|
+
detached: false
|
|
9138
|
+
});
|
|
9139
|
+
child.stdout?.on("data", (b) => process.stderr.write(`[qa-server] ${b.toString("utf8")}`));
|
|
9140
|
+
child.stderr?.on("data", (b) => process.stderr.write(`[qa-server] ${b.toString("utf8")}`));
|
|
9141
|
+
return child;
|
|
9142
|
+
}
|
|
9143
|
+
function registerProcessCleanup(child) {
|
|
9144
|
+
const cleanup = () => safeKill(child);
|
|
9145
|
+
process.on("exit", cleanup);
|
|
9146
|
+
process.on("SIGINT", cleanup);
|
|
9147
|
+
process.on("SIGTERM", cleanup);
|
|
9148
|
+
}
|
|
9149
|
+
function safeKill(child) {
|
|
9150
|
+
try {
|
|
9151
|
+
child.kill("SIGTERM");
|
|
9152
|
+
} catch {
|
|
9153
|
+
}
|
|
9154
|
+
}
|
|
9155
|
+
async function runOnce(cmd, args, cwd, timeoutMs) {
|
|
9156
|
+
await new Promise((resolve4, reject) => {
|
|
9157
|
+
const c = spawn3(cmd, args, { cwd, stdio: "inherit" });
|
|
9158
|
+
const timer = setTimeout(() => {
|
|
9159
|
+
try {
|
|
9160
|
+
c.kill("SIGKILL");
|
|
9161
|
+
} catch {
|
|
9162
|
+
}
|
|
9163
|
+
reject(new Error(`${cmd} ${args.join(" ")} timed out after ${timeoutMs}ms`));
|
|
9164
|
+
}, timeoutMs);
|
|
9165
|
+
c.on("exit", (code) => {
|
|
9166
|
+
clearTimeout(timer);
|
|
9167
|
+
if (code === 0) {
|
|
9168
|
+
resolve4();
|
|
9169
|
+
return;
|
|
9170
|
+
}
|
|
9171
|
+
reject(new Error(`${cmd} ${args.join(" ")} exited with code ${code}`));
|
|
9172
|
+
});
|
|
9173
|
+
c.on("error", (err) => {
|
|
9174
|
+
clearTimeout(timer);
|
|
9175
|
+
reject(err);
|
|
9176
|
+
});
|
|
9177
|
+
});
|
|
9178
|
+
}
|
|
9179
|
+
async function waitForReady(url, timeoutMs) {
|
|
9180
|
+
const deadline = Date.now() + timeoutMs;
|
|
9181
|
+
while (Date.now() < deadline) {
|
|
9182
|
+
if (await probe(url)) return true;
|
|
9183
|
+
await sleep2(READY_POLL_MS);
|
|
9184
|
+
}
|
|
9185
|
+
return false;
|
|
9186
|
+
}
|
|
9187
|
+
async function probe(url) {
|
|
9188
|
+
try {
|
|
9189
|
+
const res = await fetch(url, { method: "GET", signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
|
|
9190
|
+
return res.status < 500;
|
|
9191
|
+
} catch {
|
|
9192
|
+
return false;
|
|
9193
|
+
}
|
|
9194
|
+
}
|
|
9195
|
+
function sleep2(ms) {
|
|
9196
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
9197
|
+
}
|
|
9198
|
+
|
|
9041
9199
|
// src/scripts/syncFlow.ts
|
|
9042
9200
|
import { execFileSync as execFileSync26 } from "child_process";
|
|
9043
9201
|
init_issue();
|
|
@@ -9168,7 +9326,7 @@ var verify = async (ctx) => {
|
|
|
9168
9326
|
};
|
|
9169
9327
|
|
|
9170
9328
|
// src/scripts/verifyReproFails.ts
|
|
9171
|
-
import { spawn as
|
|
9329
|
+
import { spawn as spawn4 } from "child_process";
|
|
9172
9330
|
var TEST_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
9173
9331
|
var TAIL_CHARS2 = 8e3;
|
|
9174
9332
|
var ANSI_RE2 = /\x1B\[[0-?]*[ -/]*[@-~]/g;
|
|
@@ -9237,7 +9395,7 @@ function stripAnsi2(s) {
|
|
|
9237
9395
|
}
|
|
9238
9396
|
function runCommand2(command, cwd) {
|
|
9239
9397
|
return new Promise((resolve4) => {
|
|
9240
|
-
const child =
|
|
9398
|
+
const child = spawn4(command, {
|
|
9241
9399
|
cwd,
|
|
9242
9400
|
shell: true,
|
|
9243
9401
|
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" },
|
|
@@ -9300,17 +9458,17 @@ var waitForCi = async (ctx, _profile, _agentResult, args) => {
|
|
|
9300
9458
|
return;
|
|
9301
9459
|
}
|
|
9302
9460
|
const fixCiAttempts = state?.core.attempts?.["fix-ci"] ?? 0;
|
|
9303
|
-
await
|
|
9461
|
+
await sleep3(initialWaitSeconds * 1e3);
|
|
9304
9462
|
const deadline = Date.now() + timeoutMinutes * 6e4;
|
|
9305
9463
|
let lastSummary = "";
|
|
9306
9464
|
while (Date.now() < deadline) {
|
|
9307
9465
|
const rows = fetchChecks(prNumber, ctx.cwd);
|
|
9308
9466
|
if (rows === null) {
|
|
9309
|
-
await
|
|
9467
|
+
await sleep3(pollSeconds * 1e3);
|
|
9310
9468
|
continue;
|
|
9311
9469
|
}
|
|
9312
9470
|
if (rows.length === 0) {
|
|
9313
|
-
await
|
|
9471
|
+
await sleep3(pollSeconds * 1e3);
|
|
9314
9472
|
continue;
|
|
9315
9473
|
}
|
|
9316
9474
|
const summary = summarize(rows);
|
|
@@ -9353,7 +9511,7 @@ var waitForCi = async (ctx, _profile, _agentResult, args) => {
|
|
|
9353
9511
|
tryPostPr7(prNumber, `\u2705 kody waitForCi: all ${rows.length} checks green on PR #${prNumber}`, ctx.cwd);
|
|
9354
9512
|
return;
|
|
9355
9513
|
}
|
|
9356
|
-
await
|
|
9514
|
+
await sleep3(pollSeconds * 1e3);
|
|
9357
9515
|
}
|
|
9358
9516
|
ctx.data.action = mkAction("CI_TIMEOUT", {
|
|
9359
9517
|
reason: `CI did not complete within ${timeoutMinutes} minutes`,
|
|
@@ -9405,12 +9563,12 @@ function tryPostPr7(prNumber, body, cwd) {
|
|
|
9405
9563
|
} catch {
|
|
9406
9564
|
}
|
|
9407
9565
|
}
|
|
9408
|
-
function
|
|
9566
|
+
function sleep3(ms) {
|
|
9409
9567
|
return new Promise((res) => setTimeout(res, ms));
|
|
9410
9568
|
}
|
|
9411
9569
|
|
|
9412
9570
|
// src/scripts/warmupMcp.ts
|
|
9413
|
-
import { spawn as
|
|
9571
|
+
import { spawn as spawn5 } from "child_process";
|
|
9414
9572
|
var PER_SERVER_TIMEOUT_MS = 6e4;
|
|
9415
9573
|
var PER_REQUEST_TIMEOUT_MS = 2e4;
|
|
9416
9574
|
var warmupMcp = async (_ctx, profile) => {
|
|
@@ -9432,7 +9590,7 @@ var warmupMcp = async (_ctx, profile) => {
|
|
|
9432
9590
|
}
|
|
9433
9591
|
};
|
|
9434
9592
|
async function warmupOne(command, args, env) {
|
|
9435
|
-
const child =
|
|
9593
|
+
const child = spawn5(command, args, {
|
|
9436
9594
|
stdio: ["pipe", "pipe", "pipe"],
|
|
9437
9595
|
env: env ? { ...process.env, ...env } : process.env
|
|
9438
9596
|
});
|
|
@@ -9672,6 +9830,7 @@ var preflightScripts = {
|
|
|
9672
9830
|
buildSyntheticPlugin,
|
|
9673
9831
|
resolveArtifacts,
|
|
9674
9832
|
discoverQaContext,
|
|
9833
|
+
startLocalServer,
|
|
9675
9834
|
resolvePreviewUrl,
|
|
9676
9835
|
resolveQaUrl,
|
|
9677
9836
|
composePrompt,
|
|
@@ -10194,7 +10353,7 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
10194
10353
|
env[`KODY_CFG_${k}`] = v;
|
|
10195
10354
|
}
|
|
10196
10355
|
const timeoutMs = resolveShellTimeoutMs(entry);
|
|
10197
|
-
const child =
|
|
10356
|
+
const child = spawn6("bash", [shellPath, ...positional], {
|
|
10198
10357
|
cwd: ctx.cwd,
|
|
10199
10358
|
env,
|
|
10200
10359
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -10657,7 +10816,7 @@ function resolveAuthToken(env = process.env) {
|
|
|
10657
10816
|
if (token && !env.GH_TOKEN) env.GH_TOKEN = token;
|
|
10658
10817
|
return token;
|
|
10659
10818
|
}
|
|
10660
|
-
function
|
|
10819
|
+
function detectPackageManager3(cwd) {
|
|
10661
10820
|
if (fs32.existsSync(path30.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
10662
10821
|
if (fs32.existsSync(path30.join(cwd, "yarn.lock"))) return "yarn";
|
|
10663
10822
|
if (fs32.existsSync(path30.join(cwd, "bun.lockb"))) return "bun";
|
|
@@ -10859,7 +11018,7 @@ ${CI_HELP}`);
|
|
|
10859
11018
|
`);
|
|
10860
11019
|
resolveAuthToken();
|
|
10861
11020
|
reactToTriggerComment(cwd);
|
|
10862
|
-
const pm = args.packageManager ??
|
|
11021
|
+
const pm = args.packageManager ?? detectPackageManager3(cwd);
|
|
10863
11022
|
process.stdout.write(`\u2192 kody: package manager = ${pm}
|
|
10864
11023
|
`);
|
|
10865
11024
|
if (!args.skipInstall) {
|
|
@@ -10931,7 +11090,7 @@ async function runScheduledFanOut(cwd, args, opts) {
|
|
|
10931
11090
|
if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s) from ALL_SECRETS
|
|
10932
11091
|
`);
|
|
10933
11092
|
resolveAuthToken();
|
|
10934
|
-
const pm = args.packageManager ??
|
|
11093
|
+
const pm = args.packageManager ?? detectPackageManager3(cwd);
|
|
10935
11094
|
process.stdout.write(`\u2192 kody: package manager = ${pm}
|
|
10936
11095
|
`);
|
|
10937
11096
|
if (!args.skipInstall) {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.67",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -12,6 +12,18 @@
|
|
|
12
12
|
"templates",
|
|
13
13
|
"kody.config.schema.json"
|
|
14
14
|
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"kody": "tsx bin/kody.ts",
|
|
17
|
+
"build": "tsup && node scripts/copy-assets.cjs",
|
|
18
|
+
"test": "vitest run tests/unit tests/int --no-coverage",
|
|
19
|
+
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
20
|
+
"test:all": "vitest run tests --no-coverage",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"lint": "biome check",
|
|
23
|
+
"lint:fix": "biome check --write",
|
|
24
|
+
"format": "biome format --write",
|
|
25
|
+
"prepublishOnly": "pnpm build"
|
|
26
|
+
},
|
|
15
27
|
"dependencies": {
|
|
16
28
|
"@actions/cache": "^6.0.0",
|
|
17
29
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
@@ -33,16 +45,5 @@
|
|
|
33
45
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
34
46
|
},
|
|
35
47
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
36
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
37
|
-
|
|
38
|
-
"kody": "tsx bin/kody.ts",
|
|
39
|
-
"build": "tsup && node scripts/copy-assets.cjs",
|
|
40
|
-
"test": "vitest run tests/unit tests/int --no-coverage",
|
|
41
|
-
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
42
|
-
"test:all": "vitest run tests --no-coverage",
|
|
43
|
-
"typecheck": "tsc --noEmit",
|
|
44
|
-
"lint": "biome check",
|
|
45
|
-
"lint:fix": "biome check --write",
|
|
46
|
-
"format": "biome format --write"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
48
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
49
|
+
}
|