@kody-ade/kody-engine 0.4.278 → 0.4.279
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 +169 -97
- package/package.json +24 -23
package/dist/bin/kody.js
CHANGED
|
@@ -15,7 +15,7 @@ var init_package = __esm({
|
|
|
15
15
|
"package.json"() {
|
|
16
16
|
package_default = {
|
|
17
17
|
name: "@kody-ade/kody-engine",
|
|
18
|
-
version: "0.4.
|
|
18
|
+
version: "0.4.279",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -147,11 +147,11 @@ var init_claudeBinary = __esm({
|
|
|
147
147
|
// src/issue.ts
|
|
148
148
|
import { execFileSync } from "child_process";
|
|
149
149
|
function ghToken(preferRepoToken = false) {
|
|
150
|
-
const
|
|
150
|
+
const githubToken2 = process.env.GITHUB_TOKEN?.trim();
|
|
151
151
|
const kodyToken = process.env.KODY_TOKEN?.trim();
|
|
152
152
|
const ghToken3 = process.env.GH_TOKEN?.trim();
|
|
153
153
|
const ghPat = process.env.GH_PAT?.trim();
|
|
154
|
-
return preferRepoToken ?
|
|
154
|
+
return preferRepoToken ? githubToken2 || kodyToken || ghToken3 || ghPat : ghPat || ghToken3 || kodyToken || githubToken2;
|
|
155
155
|
}
|
|
156
156
|
function gh(args, options) {
|
|
157
157
|
const token = ghToken(options?.preferRepoToken);
|
|
@@ -532,11 +532,11 @@ function branchApiPath(config, targetPath) {
|
|
|
532
532
|
}
|
|
533
533
|
function ensureStateBranch(config, cwd) {
|
|
534
534
|
const parsed = parseStateRepo(config);
|
|
535
|
-
const
|
|
536
|
-
if (ensuredStateBranches.has(
|
|
535
|
+
const cacheKey3 = `${parsed.owner}/${parsed.repo}:${STATE_BRANCH}`;
|
|
536
|
+
if (ensuredStateBranches.has(cacheKey3)) return;
|
|
537
537
|
try {
|
|
538
538
|
gh(["api", `/repos/${parsed.owner}/${parsed.repo}/git/ref/heads/${STATE_BRANCH}`], { cwd });
|
|
539
|
-
ensuredStateBranches.add(
|
|
539
|
+
ensuredStateBranches.add(cacheKey3);
|
|
540
540
|
return;
|
|
541
541
|
} catch (err) {
|
|
542
542
|
if (!is404(err)) throw err;
|
|
@@ -555,7 +555,7 @@ function ensureStateBranch(config, cwd) {
|
|
|
555
555
|
} catch (err) {
|
|
556
556
|
if (!isAlreadyExists(err)) throw err;
|
|
557
557
|
}
|
|
558
|
-
ensuredStateBranches.add(
|
|
558
|
+
ensuredStateBranches.add(cacheKey3);
|
|
559
559
|
}
|
|
560
560
|
function readStateText(config, cwd, filePath) {
|
|
561
561
|
const targetPath = stateRepoPath(config, filePath);
|
|
@@ -1208,7 +1208,7 @@ var init_events = __esm({
|
|
|
1208
1208
|
// src/verify.ts
|
|
1209
1209
|
import { spawn } from "child_process";
|
|
1210
1210
|
function runCommand(command, cwd) {
|
|
1211
|
-
return new Promise((
|
|
1211
|
+
return new Promise((resolve9) => {
|
|
1212
1212
|
const start = Date.now();
|
|
1213
1213
|
const child = spawn(command, {
|
|
1214
1214
|
cwd,
|
|
@@ -1237,11 +1237,11 @@ function runCommand(command, cwd) {
|
|
|
1237
1237
|
child.on("exit", (code) => {
|
|
1238
1238
|
clearTimeout(timer);
|
|
1239
1239
|
const tail = Buffer.concat(buffers).toString("utf-8").slice(-TAIL_CHARS);
|
|
1240
|
-
|
|
1240
|
+
resolve9({ exitCode: code ?? -1, durationMs: Date.now() - start, tail });
|
|
1241
1241
|
});
|
|
1242
1242
|
child.on("error", (err) => {
|
|
1243
1243
|
clearTimeout(timer);
|
|
1244
|
-
|
|
1244
|
+
resolve9({ exitCode: -1, durationMs: Date.now() - start, tail: err.message });
|
|
1245
1245
|
});
|
|
1246
1246
|
});
|
|
1247
1247
|
}
|
|
@@ -2884,7 +2884,7 @@ var init_repoWorkspace = __esm({
|
|
|
2884
2884
|
defaultCloneRepo = (repo, token, dir) => {
|
|
2885
2885
|
fs7.mkdirSync(path9.dirname(dir), { recursive: true });
|
|
2886
2886
|
const authUrl = token ? `https://x-access-token:${token}@github.com/${repo}.git` : `https://github.com/${repo}.git`;
|
|
2887
|
-
return new Promise((
|
|
2887
|
+
return new Promise((resolve9, reject) => {
|
|
2888
2888
|
const child = spawn2("git", ["clone", "--depth=1", authUrl, dir], {
|
|
2889
2889
|
stdio: "inherit"
|
|
2890
2890
|
});
|
|
@@ -2900,7 +2900,7 @@ var init_repoWorkspace = __esm({
|
|
|
2900
2900
|
spawnSync("git", ["-C", dir, "config", "user.email", email]);
|
|
2901
2901
|
} catch {
|
|
2902
2902
|
}
|
|
2903
|
-
|
|
2903
|
+
resolve9();
|
|
2904
2904
|
});
|
|
2905
2905
|
child.on("error", reject);
|
|
2906
2906
|
});
|
|
@@ -3208,10 +3208,10 @@ async function runAgent(opts) {
|
|
|
3208
3208
|
let timer;
|
|
3209
3209
|
let next;
|
|
3210
3210
|
if (turnTimeoutMs > 0) {
|
|
3211
|
-
const timeoutPromise = new Promise((
|
|
3211
|
+
const timeoutPromise = new Promise((resolve9) => {
|
|
3212
3212
|
timer = setTimeout(() => {
|
|
3213
3213
|
timedOut = true;
|
|
3214
|
-
|
|
3214
|
+
resolve9({ done: true, value: void 0 });
|
|
3215
3215
|
}, turnTimeoutMs);
|
|
3216
3216
|
});
|
|
3217
3217
|
next = await Promise.race([nextPromise, timeoutPromise]);
|
|
@@ -12658,7 +12658,7 @@ function retryDelaysMs() {
|
|
|
12658
12658
|
}
|
|
12659
12659
|
function sleep(ms) {
|
|
12660
12660
|
if (ms <= 0) return Promise.resolve();
|
|
12661
|
-
return new Promise((
|
|
12661
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
12662
12662
|
}
|
|
12663
12663
|
async function fetchGoalStateWithRetry(config, goalId, cwd) {
|
|
12664
12664
|
let state = fetchGoalState(config, goalId, cwd);
|
|
@@ -15326,7 +15326,7 @@ var init_previewBuildHelpers = __esm({
|
|
|
15326
15326
|
// src/scripts/previewBuildRun.ts
|
|
15327
15327
|
import { spawn as spawn4 } from "child_process";
|
|
15328
15328
|
async function runCmd(cmd, args, opts = {}) {
|
|
15329
|
-
await new Promise((
|
|
15329
|
+
await new Promise((resolve9, reject) => {
|
|
15330
15330
|
const child = spawn4(cmd, args, {
|
|
15331
15331
|
cwd: opts.cwd,
|
|
15332
15332
|
env: { ...process.env, ...opts.env ?? {} },
|
|
@@ -15338,7 +15338,7 @@ async function runCmd(cmd, args, opts = {}) {
|
|
|
15338
15338
|
}
|
|
15339
15339
|
child.on("error", reject);
|
|
15340
15340
|
child.on("close", (code) => {
|
|
15341
|
-
if (code === 0)
|
|
15341
|
+
if (code === 0) resolve9();
|
|
15342
15342
|
else reject(new Error(`${cmd} ${args.join(" ")} exited ${code}`));
|
|
15343
15343
|
});
|
|
15344
15344
|
});
|
|
@@ -16462,7 +16462,7 @@ function stripAnsi2(s) {
|
|
|
16462
16462
|
return s.replace(ANSI_RE2, "");
|
|
16463
16463
|
}
|
|
16464
16464
|
function runCommand2(command, cwd) {
|
|
16465
|
-
return new Promise((
|
|
16465
|
+
return new Promise((resolve9) => {
|
|
16466
16466
|
const child = spawn5(command, {
|
|
16467
16467
|
cwd,
|
|
16468
16468
|
shell: true,
|
|
@@ -16489,11 +16489,11 @@ function runCommand2(command, cwd) {
|
|
|
16489
16489
|
}, TEST_TIMEOUT_MS);
|
|
16490
16490
|
child.on("exit", (code) => {
|
|
16491
16491
|
clearTimeout(timer);
|
|
16492
|
-
|
|
16492
|
+
resolve9({ exitCode: code ?? -1, output: Buffer.concat(buffers).toString("utf-8") });
|
|
16493
16493
|
});
|
|
16494
16494
|
child.on("error", (err) => {
|
|
16495
16495
|
clearTimeout(timer);
|
|
16496
|
-
|
|
16496
|
+
resolve9({ exitCode: -1, output: err.message });
|
|
16497
16497
|
});
|
|
16498
16498
|
});
|
|
16499
16499
|
}
|
|
@@ -16898,21 +16898,21 @@ function lineStream(stream) {
|
|
|
16898
16898
|
tryDeliver();
|
|
16899
16899
|
});
|
|
16900
16900
|
return {
|
|
16901
|
-
next: (timeoutMs) => new Promise((
|
|
16901
|
+
next: (timeoutMs) => new Promise((resolve9) => {
|
|
16902
16902
|
if (queue.length > 0) {
|
|
16903
|
-
|
|
16903
|
+
resolve9(queue.shift());
|
|
16904
16904
|
return;
|
|
16905
16905
|
}
|
|
16906
16906
|
if (ended) {
|
|
16907
|
-
|
|
16907
|
+
resolve9(null);
|
|
16908
16908
|
return;
|
|
16909
16909
|
}
|
|
16910
|
-
waiter =
|
|
16910
|
+
waiter = resolve9;
|
|
16911
16911
|
const t = setTimeout(
|
|
16912
16912
|
() => {
|
|
16913
|
-
if (waiter ===
|
|
16913
|
+
if (waiter === resolve9) {
|
|
16914
16914
|
waiter = null;
|
|
16915
|
-
|
|
16915
|
+
resolve9(null);
|
|
16916
16916
|
}
|
|
16917
16917
|
},
|
|
16918
16918
|
Math.max(0, timeoutMs)
|
|
@@ -17295,42 +17295,111 @@ var init_scripts = __esm({
|
|
|
17295
17295
|
});
|
|
17296
17296
|
|
|
17297
17297
|
// src/stateWorkspace.ts
|
|
17298
|
+
import { execFileSync as execFileSync24 } from "child_process";
|
|
17299
|
+
import * as crypto3 from "crypto";
|
|
17298
17300
|
import * as fs43 from "fs";
|
|
17301
|
+
import * as os7 from "os";
|
|
17299
17302
|
import * as path41 from "path";
|
|
17300
17303
|
function writeLocalFile(cwd, relativePath, content) {
|
|
17301
17304
|
const fullPath = path41.join(cwd, relativePath);
|
|
17302
17305
|
fs43.mkdirSync(path41.dirname(fullPath), { recursive: true });
|
|
17303
17306
|
fs43.writeFileSync(fullPath, content);
|
|
17304
17307
|
}
|
|
17305
|
-
function
|
|
17306
|
-
const
|
|
17307
|
-
|
|
17308
|
-
|
|
17309
|
-
|
|
17310
|
-
|
|
17311
|
-
|
|
17312
|
-
|
|
17313
|
-
|
|
17314
|
-
|
|
17315
|
-
|
|
17316
|
-
|
|
17317
|
-
|
|
17318
|
-
}
|
|
17308
|
+
function copyPath(source, target) {
|
|
17309
|
+
const st = fs43.lstatSync(source);
|
|
17310
|
+
fs43.rmSync(target, { recursive: true, force: true });
|
|
17311
|
+
if (st.isSymbolicLink()) return;
|
|
17312
|
+
fs43.mkdirSync(path41.dirname(target), { recursive: true });
|
|
17313
|
+
fs43.cpSync(source, target, { recursive: true, force: true });
|
|
17314
|
+
}
|
|
17315
|
+
function overlayDirectoryChildren(cwd, sourceDir, localDir) {
|
|
17316
|
+
if (!fs43.existsSync(sourceDir)) return;
|
|
17317
|
+
for (const entry of fs43.readdirSync(sourceDir, { withFileTypes: true })) {
|
|
17318
|
+
const source = path41.join(sourceDir, entry.name);
|
|
17319
|
+
const target = path41.join(cwd, localDir, entry.name);
|
|
17320
|
+
copyPath(source, target);
|
|
17319
17321
|
}
|
|
17320
17322
|
}
|
|
17321
17323
|
function hydrateStateWorkspace(config, cwd) {
|
|
17324
|
+
if (process.env.VITEST && process.env[TEST_FETCH_ENV] !== "1") return;
|
|
17325
|
+
const parsed = parseStateRepo(config);
|
|
17326
|
+
const hydrateKey = `${path41.resolve(cwd)}|${parsed.owner}/${parsed.repo}|${parsed.basePath}|${STATE_BRANCH}`;
|
|
17327
|
+
if (hydratedWorkspaces.has(hydrateKey)) return;
|
|
17328
|
+
const snapshotRoot = fetchStateSnapshot(parsed);
|
|
17322
17329
|
for (const mapping of DIR_MAPPINGS) {
|
|
17323
|
-
|
|
17330
|
+
overlayDirectoryChildren(cwd, path41.join(snapshotRoot, mapping.stateDir), mapping.localDir);
|
|
17324
17331
|
}
|
|
17325
17332
|
for (const mapping of FILE_MAPPINGS) {
|
|
17326
|
-
const
|
|
17327
|
-
if (
|
|
17333
|
+
const source = path41.join(snapshotRoot, mapping.statePath);
|
|
17334
|
+
if (fs43.existsSync(source) && !fs43.lstatSync(source).isSymbolicLink() && fs43.statSync(source).isFile()) {
|
|
17335
|
+
writeLocalFile(cwd, mapping.localPath, fs43.readFileSync(source, "utf-8"));
|
|
17336
|
+
}
|
|
17328
17337
|
}
|
|
17338
|
+
hydratedWorkspaces.add(hydrateKey);
|
|
17329
17339
|
}
|
|
17330
|
-
|
|
17340
|
+
function fetchStateSnapshot(parsed) {
|
|
17341
|
+
const cacheDir = path41.join(cacheRoot2(), cacheKey2(parsed));
|
|
17342
|
+
const url = `https://github.com/${parsed.owner}/${parsed.repo}.git`;
|
|
17343
|
+
try {
|
|
17344
|
+
fs43.mkdirSync(path41.dirname(cacheDir), { recursive: true });
|
|
17345
|
+
if (!fs43.existsSync(path41.join(cacheDir, ".git"))) {
|
|
17346
|
+
fs43.rmSync(cacheDir, { recursive: true, force: true });
|
|
17347
|
+
runGit3(["clone", "--no-checkout", "--filter=blob:none", url, cacheDir]);
|
|
17348
|
+
}
|
|
17349
|
+
runGit3(["-C", cacheDir, "remote", "set-url", "origin", url]);
|
|
17350
|
+
runGit3(["-C", cacheDir, "fetch", "--depth=1", "origin", STATE_BRANCH]);
|
|
17351
|
+
runGit3(["-C", cacheDir, "sparse-checkout", "init", "--cone"]);
|
|
17352
|
+
runGit3(["-C", cacheDir, "sparse-checkout", "set", parsed.basePath]);
|
|
17353
|
+
runGit3(["-C", cacheDir, "checkout", "--force", "--detach", "FETCH_HEAD"]);
|
|
17354
|
+
runGit3(["-C", cacheDir, "clean", "-fdx"]);
|
|
17355
|
+
} catch (err) {
|
|
17356
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
17357
|
+
throw new Error(
|
|
17358
|
+
`stateWorkspace: failed to fetch ${parsed.owner}/${parsed.repo}:${parsed.basePath}@${STATE_BRANCH}: ${msg}`
|
|
17359
|
+
);
|
|
17360
|
+
}
|
|
17361
|
+
return path41.join(cacheDir, parsed.basePath);
|
|
17362
|
+
}
|
|
17363
|
+
function cacheRoot2() {
|
|
17364
|
+
return process.env[CACHE_ENV2]?.trim() || path41.join(os7.homedir(), ".cache", "kody", "state-repo");
|
|
17365
|
+
}
|
|
17366
|
+
function cacheKey2(parsed) {
|
|
17367
|
+
return crypto3.createHash("sha256").update(`${parsed.owner}/${parsed.repo}#${STATE_BRANCH}#${parsed.basePath}`).digest("hex").slice(0, 24);
|
|
17368
|
+
}
|
|
17369
|
+
function runGit3(args) {
|
|
17370
|
+
try {
|
|
17371
|
+
execFileSync24("git", args, {
|
|
17372
|
+
encoding: "utf-8",
|
|
17373
|
+
env: githubAuthEnv(),
|
|
17374
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
17375
|
+
timeout: 12e4
|
|
17376
|
+
});
|
|
17377
|
+
} catch (err) {
|
|
17378
|
+
const stderr = err.stderr;
|
|
17379
|
+
const detail = Buffer.isBuffer(stderr) ? stderr.toString("utf-8").trim() : typeof stderr === "string" ? stderr.trim() : "";
|
|
17380
|
+
throw new Error(detail || `git ${args[0] ?? "command"} failed`);
|
|
17381
|
+
}
|
|
17382
|
+
}
|
|
17383
|
+
function githubAuthEnv() {
|
|
17384
|
+
const token = githubToken();
|
|
17385
|
+
if (!token) return process.env;
|
|
17386
|
+
const encoded = Buffer.from(`x-access-token:${token}`).toString("base64");
|
|
17387
|
+
const existingCount = /^\d+$/.test(process.env.GIT_CONFIG_COUNT ?? "") ? Number(process.env.GIT_CONFIG_COUNT) : 0;
|
|
17388
|
+
return {
|
|
17389
|
+
...process.env,
|
|
17390
|
+
GIT_CONFIG_COUNT: String(existingCount + 1),
|
|
17391
|
+
[`GIT_CONFIG_KEY_${existingCount}`]: "http.https://github.com/.extraheader",
|
|
17392
|
+
[`GIT_CONFIG_VALUE_${existingCount}`]: `AUTHORIZATION: basic ${encoded}`
|
|
17393
|
+
};
|
|
17394
|
+
}
|
|
17395
|
+
function githubToken() {
|
|
17396
|
+
return process.env.KODY_TOKEN?.trim() || process.env.GH_TOKEN?.trim() || process.env.GITHUB_TOKEN?.trim() || process.env.GH_PAT?.trim() || void 0;
|
|
17397
|
+
}
|
|
17398
|
+
var DIR_MAPPINGS, FILE_MAPPINGS, CACHE_ENV2, TEST_FETCH_ENV, hydratedWorkspaces;
|
|
17331
17399
|
var init_stateWorkspace = __esm({
|
|
17332
17400
|
"src/stateWorkspace.ts"() {
|
|
17333
17401
|
"use strict";
|
|
17402
|
+
init_stateBranch();
|
|
17334
17403
|
init_stateRepo();
|
|
17335
17404
|
DIR_MAPPINGS = [
|
|
17336
17405
|
{ stateDir: "executables", localDir: path41.join(".kody", "executables") },
|
|
@@ -17344,11 +17413,14 @@ var init_stateWorkspace = __esm({
|
|
|
17344
17413
|
{ statePath: "variables.json", localPath: path41.join(".kody", "variables.json") },
|
|
17345
17414
|
{ statePath: "secrets.enc", localPath: path41.join(".kody", "secrets.enc") }
|
|
17346
17415
|
];
|
|
17416
|
+
CACHE_ENV2 = "KODY_STATE_REPO_CACHE";
|
|
17417
|
+
TEST_FETCH_ENV = "KODY_STATE_WORKSPACE_FETCH_FOR_TESTS";
|
|
17418
|
+
hydratedWorkspaces = /* @__PURE__ */ new Set();
|
|
17347
17419
|
}
|
|
17348
17420
|
});
|
|
17349
17421
|
|
|
17350
17422
|
// src/tools.ts
|
|
17351
|
-
import { execFileSync as
|
|
17423
|
+
import { execFileSync as execFileSync25 } from "child_process";
|
|
17352
17424
|
function verifyCliTools(tools, cwd) {
|
|
17353
17425
|
const out = [];
|
|
17354
17426
|
for (const t of tools) out.push(verifyOne(t, cwd));
|
|
@@ -17385,7 +17457,7 @@ function verifyOne(tool6, cwd) {
|
|
|
17385
17457
|
}
|
|
17386
17458
|
function runShell(cmd, cwd, timeoutMs = 3e4) {
|
|
17387
17459
|
try {
|
|
17388
|
-
const stdout =
|
|
17460
|
+
const stdout = execFileSync25("sh", ["-c", cmd], {
|
|
17389
17461
|
cwd,
|
|
17390
17462
|
stdio: ["ignore", "pipe", "pipe"],
|
|
17391
17463
|
timeout: timeoutMs,
|
|
@@ -18131,14 +18203,14 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
18131
18203
|
let killTimer;
|
|
18132
18204
|
let escalateTimer;
|
|
18133
18205
|
const result = await new Promise(
|
|
18134
|
-
(
|
|
18206
|
+
(resolve9) => {
|
|
18135
18207
|
let settled = false;
|
|
18136
18208
|
const settle = (code, signal, spawnErr) => {
|
|
18137
18209
|
if (settled) return;
|
|
18138
18210
|
settled = true;
|
|
18139
18211
|
if (killTimer) clearTimeout(killTimer);
|
|
18140
18212
|
if (escalateTimer) clearTimeout(escalateTimer);
|
|
18141
|
-
|
|
18213
|
+
resolve9({ code, signal, spawnErr });
|
|
18142
18214
|
};
|
|
18143
18215
|
child.on("error", (err) => settle(null, null, err));
|
|
18144
18216
|
child.on("close", (code, signal) => settle(code, signal));
|
|
@@ -19377,7 +19449,7 @@ _\u2026 (instructions truncated)_` : trimmed;
|
|
|
19377
19449
|
init_config();
|
|
19378
19450
|
|
|
19379
19451
|
// src/kody-cli.ts
|
|
19380
|
-
import { execFileSync as
|
|
19452
|
+
import { execFileSync as execFileSync26 } from "child_process";
|
|
19381
19453
|
import * as fs46 from "fs";
|
|
19382
19454
|
import * as path45 from "path";
|
|
19383
19455
|
|
|
@@ -20034,7 +20106,7 @@ function recoverCheckoutToken(env = process.env, cwd = process.cwd()) {
|
|
|
20034
20106
|
if (env.GITHUB_TOKEN?.trim()) return env.GITHUB_TOKEN.trim();
|
|
20035
20107
|
let header = "";
|
|
20036
20108
|
try {
|
|
20037
|
-
header =
|
|
20109
|
+
header = execFileSync26("git", ["config", "--local", "--get", "http.https://github.com/.extraheader"], {
|
|
20038
20110
|
cwd,
|
|
20039
20111
|
encoding: "utf-8",
|
|
20040
20112
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -20096,7 +20168,7 @@ function shouldChainScheduledWatch(match) {
|
|
|
20096
20168
|
}
|
|
20097
20169
|
function shellOut(cmd, args, cwd, stream = true) {
|
|
20098
20170
|
try {
|
|
20099
|
-
|
|
20171
|
+
execFileSync26(cmd, args, {
|
|
20100
20172
|
cwd,
|
|
20101
20173
|
stdio: stream ? "inherit" : "pipe",
|
|
20102
20174
|
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" }
|
|
@@ -20109,7 +20181,7 @@ function shellOut(cmd, args, cwd, stream = true) {
|
|
|
20109
20181
|
}
|
|
20110
20182
|
function isOnPath(bin) {
|
|
20111
20183
|
try {
|
|
20112
|
-
|
|
20184
|
+
execFileSync26("which", [bin], { stdio: "pipe" });
|
|
20113
20185
|
return true;
|
|
20114
20186
|
} catch {
|
|
20115
20187
|
return false;
|
|
@@ -20150,7 +20222,7 @@ function installLitellmIfNeeded(cwd) {
|
|
|
20150
20222
|
} catch {
|
|
20151
20223
|
}
|
|
20152
20224
|
try {
|
|
20153
|
-
|
|
20225
|
+
execFileSync26("python3", ["-c", "import litellm"], { stdio: "pipe" });
|
|
20154
20226
|
process.stdout.write("\u2192 kody: litellm already installed\n");
|
|
20155
20227
|
return 0;
|
|
20156
20228
|
} catch {
|
|
@@ -20160,16 +20232,16 @@ function installLitellmIfNeeded(cwd) {
|
|
|
20160
20232
|
}
|
|
20161
20233
|
function configureGitIdentity(cwd) {
|
|
20162
20234
|
try {
|
|
20163
|
-
const name =
|
|
20235
|
+
const name = execFileSync26("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
|
|
20164
20236
|
if (name) return;
|
|
20165
20237
|
} catch {
|
|
20166
20238
|
}
|
|
20167
20239
|
try {
|
|
20168
|
-
|
|
20240
|
+
execFileSync26("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
|
|
20169
20241
|
} catch {
|
|
20170
20242
|
}
|
|
20171
20243
|
try {
|
|
20172
|
-
|
|
20244
|
+
execFileSync26("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
|
|
20173
20245
|
cwd,
|
|
20174
20246
|
stdio: "pipe"
|
|
20175
20247
|
});
|
|
@@ -20779,17 +20851,17 @@ function authOk(req, expected) {
|
|
|
20779
20851
|
return false;
|
|
20780
20852
|
}
|
|
20781
20853
|
function readJsonBody(req) {
|
|
20782
|
-
return new Promise((
|
|
20854
|
+
return new Promise((resolve9, reject) => {
|
|
20783
20855
|
const chunks = [];
|
|
20784
20856
|
req.on("data", (c) => chunks.push(c));
|
|
20785
20857
|
req.on("end", () => {
|
|
20786
20858
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
20787
20859
|
if (!raw.trim()) {
|
|
20788
|
-
|
|
20860
|
+
resolve9({});
|
|
20789
20861
|
return;
|
|
20790
20862
|
}
|
|
20791
20863
|
try {
|
|
20792
|
-
|
|
20864
|
+
resolve9(JSON.parse(raw));
|
|
20793
20865
|
} catch (err) {
|
|
20794
20866
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
20795
20867
|
}
|
|
@@ -21141,11 +21213,11 @@ async function brainServe(opts) {
|
|
|
21141
21213
|
model,
|
|
21142
21214
|
litellmUrl
|
|
21143
21215
|
});
|
|
21144
|
-
await new Promise((
|
|
21216
|
+
await new Promise((resolve9) => {
|
|
21145
21217
|
server.listen(port, "0.0.0.0", () => {
|
|
21146
21218
|
process.stdout.write(`[brain-serve] listening on 0.0.0.0:${port} (cwd=${opts.cwd})
|
|
21147
21219
|
`);
|
|
21148
|
-
|
|
21220
|
+
resolve9();
|
|
21149
21221
|
});
|
|
21150
21222
|
});
|
|
21151
21223
|
const shutdown = (signal) => {
|
|
@@ -21398,14 +21470,14 @@ async function startBrainProxy(opts) {
|
|
|
21398
21470
|
const { httpServer, handler } = buildBrainProxy(opts);
|
|
21399
21471
|
const port = opts.port ?? 0;
|
|
21400
21472
|
const host = opts.host ?? "127.0.0.1";
|
|
21401
|
-
await new Promise((
|
|
21473
|
+
await new Promise((resolve9) => httpServer.listen(port, host, () => resolve9()));
|
|
21402
21474
|
const addr = httpServer.address();
|
|
21403
21475
|
return {
|
|
21404
21476
|
httpServer,
|
|
21405
21477
|
port: addr.port,
|
|
21406
21478
|
url: `http://${host}:${addr.port}`,
|
|
21407
|
-
stop: () => new Promise((
|
|
21408
|
-
httpServer.close(() =>
|
|
21479
|
+
stop: () => new Promise((resolve9) => {
|
|
21480
|
+
httpServer.close(() => resolve9());
|
|
21409
21481
|
}),
|
|
21410
21482
|
handler
|
|
21411
21483
|
};
|
|
@@ -21555,23 +21627,23 @@ function buildMcpHttpServer(opts) {
|
|
|
21555
21627
|
httpServer,
|
|
21556
21628
|
routes,
|
|
21557
21629
|
port,
|
|
21558
|
-
stop: () => new Promise((
|
|
21630
|
+
stop: () => new Promise((resolve9) => {
|
|
21559
21631
|
let pending = transports.size;
|
|
21560
21632
|
if (pending === 0) {
|
|
21561
|
-
httpServer.close(() =>
|
|
21633
|
+
httpServer.close(() => resolve9());
|
|
21562
21634
|
return;
|
|
21563
21635
|
}
|
|
21564
21636
|
for (const transport of transports.values()) {
|
|
21565
21637
|
void transport.close().finally(() => {
|
|
21566
21638
|
pending--;
|
|
21567
|
-
if (pending === 0) httpServer.close(() =>
|
|
21639
|
+
if (pending === 0) httpServer.close(() => resolve9());
|
|
21568
21640
|
});
|
|
21569
21641
|
}
|
|
21570
21642
|
})
|
|
21571
21643
|
};
|
|
21572
21644
|
}
|
|
21573
21645
|
function listenMcpHttpServer(server, host = "127.0.0.1") {
|
|
21574
|
-
return new Promise((
|
|
21646
|
+
return new Promise((resolve9, reject) => {
|
|
21575
21647
|
server.httpServer.once("error", reject);
|
|
21576
21648
|
server.httpServer.listen(server.port, host, () => {
|
|
21577
21649
|
server.httpServer.off("error", reject);
|
|
@@ -21579,7 +21651,7 @@ function listenMcpHttpServer(server, host = "127.0.0.1") {
|
|
|
21579
21651
|
if (addr && typeof addr === "object") {
|
|
21580
21652
|
server.port = addr.port;
|
|
21581
21653
|
}
|
|
21582
|
-
|
|
21654
|
+
resolve9();
|
|
21583
21655
|
});
|
|
21584
21656
|
});
|
|
21585
21657
|
}
|
|
@@ -21668,7 +21740,7 @@ import * as fs50 from "fs";
|
|
|
21668
21740
|
import * as path49 from "path";
|
|
21669
21741
|
|
|
21670
21742
|
// src/chat/inbox.ts
|
|
21671
|
-
import { execFileSync as
|
|
21743
|
+
import { execFileSync as execFileSync27 } from "child_process";
|
|
21672
21744
|
var DEFAULT_POLL_MS = 3e3;
|
|
21673
21745
|
async function waitForNextUserMessage(opts) {
|
|
21674
21746
|
const pollMs = opts.pollIntervalMs ?? DEFAULT_POLL_MS;
|
|
@@ -21692,13 +21764,13 @@ async function waitForNextUserMessage(opts) {
|
|
|
21692
21764
|
try {
|
|
21693
21765
|
const branch = currentBranch(opts.cwd);
|
|
21694
21766
|
if (branch) {
|
|
21695
|
-
|
|
21696
|
-
|
|
21767
|
+
execFileSync27("git", ["fetch", "--quiet", "origin", branch], { cwd: opts.cwd, stdio: "pipe" });
|
|
21768
|
+
execFileSync27("git", ["merge", "--ff-only", "--quiet", `origin/${branch}`], {
|
|
21697
21769
|
cwd: opts.cwd,
|
|
21698
21770
|
stdio: "pipe"
|
|
21699
21771
|
});
|
|
21700
21772
|
} else {
|
|
21701
|
-
|
|
21773
|
+
execFileSync27("git", ["fetch", "--quiet", "--all"], { cwd: opts.cwd, stdio: "pipe" });
|
|
21702
21774
|
}
|
|
21703
21775
|
} catch (err) {
|
|
21704
21776
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -21720,11 +21792,11 @@ async function waitForNextUserMessage(opts) {
|
|
|
21720
21792
|
}
|
|
21721
21793
|
}
|
|
21722
21794
|
function sleep3(ms) {
|
|
21723
|
-
return new Promise((
|
|
21795
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
21724
21796
|
}
|
|
21725
21797
|
function currentBranch(cwd) {
|
|
21726
21798
|
try {
|
|
21727
|
-
const out =
|
|
21799
|
+
const out = execFileSync27("git", ["symbolic-ref", "--short", "HEAD"], {
|
|
21728
21800
|
cwd,
|
|
21729
21801
|
stdio: ["ignore", "pipe", "ignore"]
|
|
21730
21802
|
});
|
|
@@ -22823,14 +22895,14 @@ function sendJson2(res, status, body) {
|
|
|
22823
22895
|
res.end(JSON.stringify(body));
|
|
22824
22896
|
}
|
|
22825
22897
|
function readJsonBody2(req) {
|
|
22826
|
-
return new Promise((
|
|
22898
|
+
return new Promise((resolve9, reject) => {
|
|
22827
22899
|
const chunks = [];
|
|
22828
22900
|
req.on("data", (c) => chunks.push(c));
|
|
22829
22901
|
req.on("end", () => {
|
|
22830
22902
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
22831
|
-
if (!raw.trim()) return
|
|
22903
|
+
if (!raw.trim()) return resolve9({});
|
|
22832
22904
|
try {
|
|
22833
|
-
|
|
22905
|
+
resolve9(JSON.parse(raw));
|
|
22834
22906
|
} catch (err) {
|
|
22835
22907
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
22836
22908
|
}
|
|
@@ -22921,8 +22993,8 @@ function synthesizeLegacyClaimRequest(input) {
|
|
|
22921
22993
|
async function poolServe() {
|
|
22922
22994
|
const masterRaw = process.env.KODY_MASTER_KEY?.trim();
|
|
22923
22995
|
if (!masterRaw) throw new Error("KODY_MASTER_KEY required for pool-serve");
|
|
22924
|
-
const
|
|
22925
|
-
if (!
|
|
22996
|
+
const githubToken2 = process.env.GITHUB_TOKEN?.trim();
|
|
22997
|
+
if (!githubToken2) throw new Error("GITHUB_TOKEN required for pool-serve (reads per-repo vaults)");
|
|
22926
22998
|
const master = masterKeyBytes(masterRaw);
|
|
22927
22999
|
const poolApiKey = derivePoolApiKey(master);
|
|
22928
23000
|
const runnerApiKey = deriveRunnerApiKey(master);
|
|
@@ -22935,7 +23007,7 @@ async function poolServe() {
|
|
|
22935
23007
|
const apiPort = envInt2("POOL_API_PORT", 4100);
|
|
22936
23008
|
const healthTimeoutMs = envInt2("POOL_HEALTH_TIMEOUT_MS", 12e4);
|
|
22937
23009
|
const registry = new PoolRegistry({
|
|
22938
|
-
githubToken,
|
|
23010
|
+
githubToken: githubToken2,
|
|
22939
23011
|
masterKey: master,
|
|
22940
23012
|
base: {
|
|
22941
23013
|
min,
|
|
@@ -23012,10 +23084,10 @@ async function poolServe() {
|
|
|
23012
23084
|
}
|
|
23013
23085
|
});
|
|
23014
23086
|
const apiHost = process.env.POOL_API_HOST ?? "::";
|
|
23015
|
-
await new Promise((
|
|
23087
|
+
await new Promise((resolve9) => {
|
|
23016
23088
|
server.listen(apiPort, apiHost, () => {
|
|
23017
23089
|
log(`listening on ${apiHost}:${apiPort} (min=${min}, app=${app}, region=${region})`);
|
|
23018
|
-
|
|
23090
|
+
resolve9();
|
|
23019
23091
|
});
|
|
23020
23092
|
});
|
|
23021
23093
|
const shutdown = (signal) => {
|
|
@@ -23054,17 +23126,17 @@ function authOk2(req, expected) {
|
|
|
23054
23126
|
return false;
|
|
23055
23127
|
}
|
|
23056
23128
|
function readJsonBody3(req) {
|
|
23057
|
-
return new Promise((
|
|
23129
|
+
return new Promise((resolve9, reject) => {
|
|
23058
23130
|
const chunks = [];
|
|
23059
23131
|
req.on("data", (c) => chunks.push(c));
|
|
23060
23132
|
req.on("end", () => {
|
|
23061
23133
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
23062
23134
|
if (!raw.trim()) {
|
|
23063
|
-
|
|
23135
|
+
resolve9({});
|
|
23064
23136
|
return;
|
|
23065
23137
|
}
|
|
23066
23138
|
try {
|
|
23067
|
-
|
|
23139
|
+
resolve9(JSON.parse(raw));
|
|
23068
23140
|
} catch (err) {
|
|
23069
23141
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
23070
23142
|
}
|
|
@@ -23083,8 +23155,8 @@ function parseJob(body) {
|
|
|
23083
23155
|
if (!jobId) return { error: "jobId required" };
|
|
23084
23156
|
const repo = typeof b.repo === "string" ? b.repo.trim() : "";
|
|
23085
23157
|
if (!/^[^/\s]+\/[^/\s]+$/.test(repo)) return { error: "repo must be 'owner/name'" };
|
|
23086
|
-
const
|
|
23087
|
-
if (!
|
|
23158
|
+
const githubToken2 = typeof b.githubToken === "string" ? b.githubToken.trim() : "";
|
|
23159
|
+
if (!githubToken2) return { error: "githubToken required" };
|
|
23088
23160
|
const action = typeof b.action === "string" && b.action.trim() ? b.action.trim() : void 0;
|
|
23089
23161
|
const message = typeof b.message === "string" && b.message.trim() ? b.message.trim() : void 0;
|
|
23090
23162
|
const mode = b.mode === "interactive" ? "interactive" : b.mode === "scheduled" ? "scheduled" : "issue";
|
|
@@ -23096,7 +23168,7 @@ function parseJob(body) {
|
|
|
23096
23168
|
message
|
|
23097
23169
|
});
|
|
23098
23170
|
if ("error" in runRequest) return { error: runRequest.error };
|
|
23099
|
-
const job = { jobId, repo, githubToken, runRequest: runRequest.request };
|
|
23171
|
+
const job = { jobId, repo, githubToken: githubToken2, runRequest: runRequest.request };
|
|
23100
23172
|
if (job.runRequest.target.type === "issue") {
|
|
23101
23173
|
job.issueNumber = job.runRequest.target.id;
|
|
23102
23174
|
} else if (job.runRequest.target.type === "chat") {
|
|
@@ -23198,13 +23270,13 @@ async function defaultRunJob(job) {
|
|
|
23198
23270
|
...interactive && job.idleExitMs ? { KODY_IDLE_EXIT_MS: String(job.idleExitMs) } : {},
|
|
23199
23271
|
...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
|
|
23200
23272
|
};
|
|
23201
|
-
const run = (cmd, args, cwd) => new Promise((
|
|
23273
|
+
const run = (cmd, args, cwd) => new Promise((resolve9) => {
|
|
23202
23274
|
const child = spawn8(cmd, args, { stdio: "inherit", env: childEnv, cwd });
|
|
23203
|
-
child.on("exit", (code) =>
|
|
23275
|
+
child.on("exit", (code) => resolve9(code ?? 0));
|
|
23204
23276
|
child.on("error", (err) => {
|
|
23205
23277
|
process.stderr.write(`[runner-serve] ${cmd} failed: ${err.message}
|
|
23206
23278
|
`);
|
|
23207
|
-
|
|
23279
|
+
resolve9(1);
|
|
23208
23280
|
});
|
|
23209
23281
|
});
|
|
23210
23282
|
process.stdout.write(`[runner-serve] job ${job.jobId}: cloning ${job.repo}@${branch}
|
|
@@ -23280,11 +23352,11 @@ async function runnerServe() {
|
|
|
23280
23352
|
const port = Number(process.env.PORT ?? DEFAULT_PORT2);
|
|
23281
23353
|
const server = buildServer2({ apiKey });
|
|
23282
23354
|
const host = process.env.RUNNER_HOST ?? "::";
|
|
23283
|
-
await new Promise((
|
|
23355
|
+
await new Promise((resolve9) => {
|
|
23284
23356
|
server.listen(port, host, () => {
|
|
23285
23357
|
process.stdout.write(`[runner-serve] listening on ${host}:${port} (idle, awaiting job)
|
|
23286
23358
|
`);
|
|
23287
|
-
|
|
23359
|
+
resolve9();
|
|
23288
23360
|
});
|
|
23289
23361
|
});
|
|
23290
23362
|
const shutdown = (signal) => {
|
|
@@ -23353,14 +23425,14 @@ async function serve(opts) {
|
|
|
23353
23425
|
`);
|
|
23354
23426
|
const args = ["--dangerously-skip-permissions", "--model", model.model];
|
|
23355
23427
|
const child = spawn9("claude", args, { stdio: "inherit", env: editorEnv, cwd: opts.cwd });
|
|
23356
|
-
const exitCode = await new Promise((
|
|
23357
|
-
child.on("exit", (code) =>
|
|
23428
|
+
const exitCode = await new Promise((resolve9) => {
|
|
23429
|
+
child.on("exit", (code) => resolve9(code ?? 0));
|
|
23358
23430
|
child.on("error", (err) => {
|
|
23359
23431
|
process.stderr.write(`[kody serve] failed to launch Claude Code: ${err.message}
|
|
23360
23432
|
`);
|
|
23361
23433
|
process.stderr.write(` Install: https://docs.anthropic.com/claude/docs/claude-code
|
|
23362
23434
|
`);
|
|
23363
|
-
|
|
23435
|
+
resolve9(1);
|
|
23364
23436
|
});
|
|
23365
23437
|
});
|
|
23366
23438
|
killProxy();
|
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.279",
|
|
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,27 @@
|
|
|
12
12
|
"templates",
|
|
13
13
|
"kody.config.schema.json"
|
|
14
14
|
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"kody:run": "tsx bin/kody.ts",
|
|
17
|
+
"serve": "tsx bin/kody.ts serve",
|
|
18
|
+
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
19
|
+
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
20
|
+
"clean:dist": "node scripts/clean-dist.cjs",
|
|
21
|
+
"build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
|
|
22
|
+
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
23
|
+
"pretest": "pnpm check:modularity",
|
|
24
|
+
"test": "vitest run tests/unit tests/int --coverage",
|
|
25
|
+
"posttest": "tsx scripts/check-coverage-floor.ts",
|
|
26
|
+
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
27
|
+
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
28
|
+
"test:all": "vitest run tests --no-coverage",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"lint": "biome check",
|
|
31
|
+
"lint:fix": "biome check --write",
|
|
32
|
+
"format": "biome format --write",
|
|
33
|
+
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner",
|
|
34
|
+
"prepublishOnly": "pnpm typecheck && vitest run tests/unit tests/int --no-coverage && pnpm build"
|
|
35
|
+
},
|
|
15
36
|
"dependencies": {
|
|
16
37
|
"@actions/cache": "^6.0.0",
|
|
17
38
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
@@ -35,25 +56,5 @@
|
|
|
35
56
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
36
57
|
},
|
|
37
58
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
38
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
39
|
-
|
|
40
|
-
"kody:run": "tsx bin/kody.ts",
|
|
41
|
-
"serve": "tsx bin/kody.ts serve",
|
|
42
|
-
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
43
|
-
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
44
|
-
"clean:dist": "node scripts/clean-dist.cjs",
|
|
45
|
-
"build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
|
|
46
|
-
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
47
|
-
"pretest": "pnpm check:modularity",
|
|
48
|
-
"test": "vitest run tests/unit tests/int --coverage",
|
|
49
|
-
"posttest": "tsx scripts/check-coverage-floor.ts",
|
|
50
|
-
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
51
|
-
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
52
|
-
"test:all": "vitest run tests --no-coverage",
|
|
53
|
-
"typecheck": "tsc --noEmit",
|
|
54
|
-
"lint": "biome check",
|
|
55
|
-
"lint:fix": "biome check --write",
|
|
56
|
-
"format": "biome format --write",
|
|
57
|
-
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner"
|
|
58
|
-
}
|
|
59
|
-
}
|
|
59
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
60
|
+
}
|