@kody-ade/kody-engine 0.4.278 → 0.4.280
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 -102
- 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.280",
|
|
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]);
|
|
@@ -12415,11 +12415,6 @@ on:
|
|
|
12415
12415
|
required: false
|
|
12416
12416
|
type: string
|
|
12417
12417
|
default: ""
|
|
12418
|
-
executable:
|
|
12419
|
-
description: "Legacy alias for capability action"
|
|
12420
|
-
required: false
|
|
12421
|
-
type: string
|
|
12422
|
-
default: ""
|
|
12423
12418
|
issue_comment:
|
|
12424
12419
|
types: [created]
|
|
12425
12420
|
|
|
@@ -12658,7 +12653,7 @@ function retryDelaysMs() {
|
|
|
12658
12653
|
}
|
|
12659
12654
|
function sleep(ms) {
|
|
12660
12655
|
if (ms <= 0) return Promise.resolve();
|
|
12661
|
-
return new Promise((
|
|
12656
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
12662
12657
|
}
|
|
12663
12658
|
async function fetchGoalStateWithRetry(config, goalId, cwd) {
|
|
12664
12659
|
let state = fetchGoalState(config, goalId, cwd);
|
|
@@ -15326,7 +15321,7 @@ var init_previewBuildHelpers = __esm({
|
|
|
15326
15321
|
// src/scripts/previewBuildRun.ts
|
|
15327
15322
|
import { spawn as spawn4 } from "child_process";
|
|
15328
15323
|
async function runCmd(cmd, args, opts = {}) {
|
|
15329
|
-
await new Promise((
|
|
15324
|
+
await new Promise((resolve9, reject) => {
|
|
15330
15325
|
const child = spawn4(cmd, args, {
|
|
15331
15326
|
cwd: opts.cwd,
|
|
15332
15327
|
env: { ...process.env, ...opts.env ?? {} },
|
|
@@ -15338,7 +15333,7 @@ async function runCmd(cmd, args, opts = {}) {
|
|
|
15338
15333
|
}
|
|
15339
15334
|
child.on("error", reject);
|
|
15340
15335
|
child.on("close", (code) => {
|
|
15341
|
-
if (code === 0)
|
|
15336
|
+
if (code === 0) resolve9();
|
|
15342
15337
|
else reject(new Error(`${cmd} ${args.join(" ")} exited ${code}`));
|
|
15343
15338
|
});
|
|
15344
15339
|
});
|
|
@@ -16462,7 +16457,7 @@ function stripAnsi2(s) {
|
|
|
16462
16457
|
return s.replace(ANSI_RE2, "");
|
|
16463
16458
|
}
|
|
16464
16459
|
function runCommand2(command, cwd) {
|
|
16465
|
-
return new Promise((
|
|
16460
|
+
return new Promise((resolve9) => {
|
|
16466
16461
|
const child = spawn5(command, {
|
|
16467
16462
|
cwd,
|
|
16468
16463
|
shell: true,
|
|
@@ -16489,11 +16484,11 @@ function runCommand2(command, cwd) {
|
|
|
16489
16484
|
}, TEST_TIMEOUT_MS);
|
|
16490
16485
|
child.on("exit", (code) => {
|
|
16491
16486
|
clearTimeout(timer);
|
|
16492
|
-
|
|
16487
|
+
resolve9({ exitCode: code ?? -1, output: Buffer.concat(buffers).toString("utf-8") });
|
|
16493
16488
|
});
|
|
16494
16489
|
child.on("error", (err) => {
|
|
16495
16490
|
clearTimeout(timer);
|
|
16496
|
-
|
|
16491
|
+
resolve9({ exitCode: -1, output: err.message });
|
|
16497
16492
|
});
|
|
16498
16493
|
});
|
|
16499
16494
|
}
|
|
@@ -16898,21 +16893,21 @@ function lineStream(stream) {
|
|
|
16898
16893
|
tryDeliver();
|
|
16899
16894
|
});
|
|
16900
16895
|
return {
|
|
16901
|
-
next: (timeoutMs) => new Promise((
|
|
16896
|
+
next: (timeoutMs) => new Promise((resolve9) => {
|
|
16902
16897
|
if (queue.length > 0) {
|
|
16903
|
-
|
|
16898
|
+
resolve9(queue.shift());
|
|
16904
16899
|
return;
|
|
16905
16900
|
}
|
|
16906
16901
|
if (ended) {
|
|
16907
|
-
|
|
16902
|
+
resolve9(null);
|
|
16908
16903
|
return;
|
|
16909
16904
|
}
|
|
16910
|
-
waiter =
|
|
16905
|
+
waiter = resolve9;
|
|
16911
16906
|
const t = setTimeout(
|
|
16912
16907
|
() => {
|
|
16913
|
-
if (waiter ===
|
|
16908
|
+
if (waiter === resolve9) {
|
|
16914
16909
|
waiter = null;
|
|
16915
|
-
|
|
16910
|
+
resolve9(null);
|
|
16916
16911
|
}
|
|
16917
16912
|
},
|
|
16918
16913
|
Math.max(0, timeoutMs)
|
|
@@ -17295,42 +17290,111 @@ var init_scripts = __esm({
|
|
|
17295
17290
|
});
|
|
17296
17291
|
|
|
17297
17292
|
// src/stateWorkspace.ts
|
|
17293
|
+
import { execFileSync as execFileSync24 } from "child_process";
|
|
17294
|
+
import * as crypto3 from "crypto";
|
|
17298
17295
|
import * as fs43 from "fs";
|
|
17296
|
+
import * as os7 from "os";
|
|
17299
17297
|
import * as path41 from "path";
|
|
17300
17298
|
function writeLocalFile(cwd, relativePath, content) {
|
|
17301
17299
|
const fullPath = path41.join(cwd, relativePath);
|
|
17302
17300
|
fs43.mkdirSync(path41.dirname(fullPath), { recursive: true });
|
|
17303
17301
|
fs43.writeFileSync(fullPath, content);
|
|
17304
17302
|
}
|
|
17305
|
-
function
|
|
17306
|
-
const
|
|
17307
|
-
|
|
17308
|
-
|
|
17309
|
-
|
|
17310
|
-
|
|
17311
|
-
|
|
17312
|
-
|
|
17313
|
-
|
|
17314
|
-
|
|
17315
|
-
|
|
17316
|
-
|
|
17317
|
-
|
|
17318
|
-
}
|
|
17303
|
+
function copyPath(source, target) {
|
|
17304
|
+
const st = fs43.lstatSync(source);
|
|
17305
|
+
fs43.rmSync(target, { recursive: true, force: true });
|
|
17306
|
+
if (st.isSymbolicLink()) return;
|
|
17307
|
+
fs43.mkdirSync(path41.dirname(target), { recursive: true });
|
|
17308
|
+
fs43.cpSync(source, target, { recursive: true, force: true });
|
|
17309
|
+
}
|
|
17310
|
+
function overlayDirectoryChildren(cwd, sourceDir, localDir) {
|
|
17311
|
+
if (!fs43.existsSync(sourceDir)) return;
|
|
17312
|
+
for (const entry of fs43.readdirSync(sourceDir, { withFileTypes: true })) {
|
|
17313
|
+
const source = path41.join(sourceDir, entry.name);
|
|
17314
|
+
const target = path41.join(cwd, localDir, entry.name);
|
|
17315
|
+
copyPath(source, target);
|
|
17319
17316
|
}
|
|
17320
17317
|
}
|
|
17321
17318
|
function hydrateStateWorkspace(config, cwd) {
|
|
17319
|
+
if (process.env.VITEST && process.env[TEST_FETCH_ENV] !== "1") return;
|
|
17320
|
+
const parsed = parseStateRepo(config);
|
|
17321
|
+
const hydrateKey = `${path41.resolve(cwd)}|${parsed.owner}/${parsed.repo}|${parsed.basePath}|${STATE_BRANCH}`;
|
|
17322
|
+
if (hydratedWorkspaces.has(hydrateKey)) return;
|
|
17323
|
+
const snapshotRoot = fetchStateSnapshot(parsed);
|
|
17322
17324
|
for (const mapping of DIR_MAPPINGS) {
|
|
17323
|
-
|
|
17325
|
+
overlayDirectoryChildren(cwd, path41.join(snapshotRoot, mapping.stateDir), mapping.localDir);
|
|
17324
17326
|
}
|
|
17325
17327
|
for (const mapping of FILE_MAPPINGS) {
|
|
17326
|
-
const
|
|
17327
|
-
if (
|
|
17328
|
+
const source = path41.join(snapshotRoot, mapping.statePath);
|
|
17329
|
+
if (fs43.existsSync(source) && !fs43.lstatSync(source).isSymbolicLink() && fs43.statSync(source).isFile()) {
|
|
17330
|
+
writeLocalFile(cwd, mapping.localPath, fs43.readFileSync(source, "utf-8"));
|
|
17331
|
+
}
|
|
17332
|
+
}
|
|
17333
|
+
hydratedWorkspaces.add(hydrateKey);
|
|
17334
|
+
}
|
|
17335
|
+
function fetchStateSnapshot(parsed) {
|
|
17336
|
+
const cacheDir = path41.join(cacheRoot2(), cacheKey2(parsed));
|
|
17337
|
+
const url = `https://github.com/${parsed.owner}/${parsed.repo}.git`;
|
|
17338
|
+
try {
|
|
17339
|
+
fs43.mkdirSync(path41.dirname(cacheDir), { recursive: true });
|
|
17340
|
+
if (!fs43.existsSync(path41.join(cacheDir, ".git"))) {
|
|
17341
|
+
fs43.rmSync(cacheDir, { recursive: true, force: true });
|
|
17342
|
+
runGit3(["clone", "--no-checkout", "--filter=blob:none", url, cacheDir]);
|
|
17343
|
+
}
|
|
17344
|
+
runGit3(["-C", cacheDir, "remote", "set-url", "origin", url]);
|
|
17345
|
+
runGit3(["-C", cacheDir, "fetch", "--depth=1", "origin", STATE_BRANCH]);
|
|
17346
|
+
runGit3(["-C", cacheDir, "sparse-checkout", "init", "--cone"]);
|
|
17347
|
+
runGit3(["-C", cacheDir, "sparse-checkout", "set", parsed.basePath]);
|
|
17348
|
+
runGit3(["-C", cacheDir, "checkout", "--force", "--detach", "FETCH_HEAD"]);
|
|
17349
|
+
runGit3(["-C", cacheDir, "clean", "-fdx"]);
|
|
17350
|
+
} catch (err) {
|
|
17351
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
17352
|
+
throw new Error(
|
|
17353
|
+
`stateWorkspace: failed to fetch ${parsed.owner}/${parsed.repo}:${parsed.basePath}@${STATE_BRANCH}: ${msg}`
|
|
17354
|
+
);
|
|
17355
|
+
}
|
|
17356
|
+
return path41.join(cacheDir, parsed.basePath);
|
|
17357
|
+
}
|
|
17358
|
+
function cacheRoot2() {
|
|
17359
|
+
return process.env[CACHE_ENV2]?.trim() || path41.join(os7.homedir(), ".cache", "kody", "state-repo");
|
|
17360
|
+
}
|
|
17361
|
+
function cacheKey2(parsed) {
|
|
17362
|
+
return crypto3.createHash("sha256").update(`${parsed.owner}/${parsed.repo}#${STATE_BRANCH}#${parsed.basePath}`).digest("hex").slice(0, 24);
|
|
17363
|
+
}
|
|
17364
|
+
function runGit3(args) {
|
|
17365
|
+
try {
|
|
17366
|
+
execFileSync24("git", args, {
|
|
17367
|
+
encoding: "utf-8",
|
|
17368
|
+
env: githubAuthEnv(),
|
|
17369
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
17370
|
+
timeout: 12e4
|
|
17371
|
+
});
|
|
17372
|
+
} catch (err) {
|
|
17373
|
+
const stderr = err.stderr;
|
|
17374
|
+
const detail = Buffer.isBuffer(stderr) ? stderr.toString("utf-8").trim() : typeof stderr === "string" ? stderr.trim() : "";
|
|
17375
|
+
throw new Error(detail || `git ${args[0] ?? "command"} failed`);
|
|
17328
17376
|
}
|
|
17329
17377
|
}
|
|
17330
|
-
|
|
17378
|
+
function githubAuthEnv() {
|
|
17379
|
+
const token = githubToken();
|
|
17380
|
+
if (!token) return process.env;
|
|
17381
|
+
const encoded = Buffer.from(`x-access-token:${token}`).toString("base64");
|
|
17382
|
+
const existingCount = /^\d+$/.test(process.env.GIT_CONFIG_COUNT ?? "") ? Number(process.env.GIT_CONFIG_COUNT) : 0;
|
|
17383
|
+
return {
|
|
17384
|
+
...process.env,
|
|
17385
|
+
GIT_CONFIG_COUNT: String(existingCount + 1),
|
|
17386
|
+
[`GIT_CONFIG_KEY_${existingCount}`]: "http.https://github.com/.extraheader",
|
|
17387
|
+
[`GIT_CONFIG_VALUE_${existingCount}`]: `AUTHORIZATION: basic ${encoded}`
|
|
17388
|
+
};
|
|
17389
|
+
}
|
|
17390
|
+
function githubToken() {
|
|
17391
|
+
return process.env.KODY_TOKEN?.trim() || process.env.GH_TOKEN?.trim() || process.env.GITHUB_TOKEN?.trim() || process.env.GH_PAT?.trim() || void 0;
|
|
17392
|
+
}
|
|
17393
|
+
var DIR_MAPPINGS, FILE_MAPPINGS, CACHE_ENV2, TEST_FETCH_ENV, hydratedWorkspaces;
|
|
17331
17394
|
var init_stateWorkspace = __esm({
|
|
17332
17395
|
"src/stateWorkspace.ts"() {
|
|
17333
17396
|
"use strict";
|
|
17397
|
+
init_stateBranch();
|
|
17334
17398
|
init_stateRepo();
|
|
17335
17399
|
DIR_MAPPINGS = [
|
|
17336
17400
|
{ stateDir: "executables", localDir: path41.join(".kody", "executables") },
|
|
@@ -17344,11 +17408,14 @@ var init_stateWorkspace = __esm({
|
|
|
17344
17408
|
{ statePath: "variables.json", localPath: path41.join(".kody", "variables.json") },
|
|
17345
17409
|
{ statePath: "secrets.enc", localPath: path41.join(".kody", "secrets.enc") }
|
|
17346
17410
|
];
|
|
17411
|
+
CACHE_ENV2 = "KODY_STATE_REPO_CACHE";
|
|
17412
|
+
TEST_FETCH_ENV = "KODY_STATE_WORKSPACE_FETCH_FOR_TESTS";
|
|
17413
|
+
hydratedWorkspaces = /* @__PURE__ */ new Set();
|
|
17347
17414
|
}
|
|
17348
17415
|
});
|
|
17349
17416
|
|
|
17350
17417
|
// src/tools.ts
|
|
17351
|
-
import { execFileSync as
|
|
17418
|
+
import { execFileSync as execFileSync25 } from "child_process";
|
|
17352
17419
|
function verifyCliTools(tools, cwd) {
|
|
17353
17420
|
const out = [];
|
|
17354
17421
|
for (const t of tools) out.push(verifyOne(t, cwd));
|
|
@@ -17385,7 +17452,7 @@ function verifyOne(tool6, cwd) {
|
|
|
17385
17452
|
}
|
|
17386
17453
|
function runShell(cmd, cwd, timeoutMs = 3e4) {
|
|
17387
17454
|
try {
|
|
17388
|
-
const stdout =
|
|
17455
|
+
const stdout = execFileSync25("sh", ["-c", cmd], {
|
|
17389
17456
|
cwd,
|
|
17390
17457
|
stdio: ["ignore", "pipe", "pipe"],
|
|
17391
17458
|
timeout: timeoutMs,
|
|
@@ -18131,14 +18198,14 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
18131
18198
|
let killTimer;
|
|
18132
18199
|
let escalateTimer;
|
|
18133
18200
|
const result = await new Promise(
|
|
18134
|
-
(
|
|
18201
|
+
(resolve9) => {
|
|
18135
18202
|
let settled = false;
|
|
18136
18203
|
const settle = (code, signal, spawnErr) => {
|
|
18137
18204
|
if (settled) return;
|
|
18138
18205
|
settled = true;
|
|
18139
18206
|
if (killTimer) clearTimeout(killTimer);
|
|
18140
18207
|
if (escalateTimer) clearTimeout(escalateTimer);
|
|
18141
|
-
|
|
18208
|
+
resolve9({ code, signal, spawnErr });
|
|
18142
18209
|
};
|
|
18143
18210
|
child.on("error", (err) => settle(null, null, err));
|
|
18144
18211
|
child.on("close", (code, signal) => settle(code, signal));
|
|
@@ -19377,7 +19444,7 @@ _\u2026 (instructions truncated)_` : trimmed;
|
|
|
19377
19444
|
init_config();
|
|
19378
19445
|
|
|
19379
19446
|
// src/kody-cli.ts
|
|
19380
|
-
import { execFileSync as
|
|
19447
|
+
import { execFileSync as execFileSync26 } from "child_process";
|
|
19381
19448
|
import * as fs46 from "fs";
|
|
19382
19449
|
import * as path45 from "path";
|
|
19383
19450
|
|
|
@@ -20034,7 +20101,7 @@ function recoverCheckoutToken(env = process.env, cwd = process.cwd()) {
|
|
|
20034
20101
|
if (env.GITHUB_TOKEN?.trim()) return env.GITHUB_TOKEN.trim();
|
|
20035
20102
|
let header = "";
|
|
20036
20103
|
try {
|
|
20037
|
-
header =
|
|
20104
|
+
header = execFileSync26("git", ["config", "--local", "--get", "http.https://github.com/.extraheader"], {
|
|
20038
20105
|
cwd,
|
|
20039
20106
|
encoding: "utf-8",
|
|
20040
20107
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -20096,7 +20163,7 @@ function shouldChainScheduledWatch(match) {
|
|
|
20096
20163
|
}
|
|
20097
20164
|
function shellOut(cmd, args, cwd, stream = true) {
|
|
20098
20165
|
try {
|
|
20099
|
-
|
|
20166
|
+
execFileSync26(cmd, args, {
|
|
20100
20167
|
cwd,
|
|
20101
20168
|
stdio: stream ? "inherit" : "pipe",
|
|
20102
20169
|
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" }
|
|
@@ -20109,7 +20176,7 @@ function shellOut(cmd, args, cwd, stream = true) {
|
|
|
20109
20176
|
}
|
|
20110
20177
|
function isOnPath(bin) {
|
|
20111
20178
|
try {
|
|
20112
|
-
|
|
20179
|
+
execFileSync26("which", [bin], { stdio: "pipe" });
|
|
20113
20180
|
return true;
|
|
20114
20181
|
} catch {
|
|
20115
20182
|
return false;
|
|
@@ -20150,7 +20217,7 @@ function installLitellmIfNeeded(cwd) {
|
|
|
20150
20217
|
} catch {
|
|
20151
20218
|
}
|
|
20152
20219
|
try {
|
|
20153
|
-
|
|
20220
|
+
execFileSync26("python3", ["-c", "import litellm"], { stdio: "pipe" });
|
|
20154
20221
|
process.stdout.write("\u2192 kody: litellm already installed\n");
|
|
20155
20222
|
return 0;
|
|
20156
20223
|
} catch {
|
|
@@ -20160,16 +20227,16 @@ function installLitellmIfNeeded(cwd) {
|
|
|
20160
20227
|
}
|
|
20161
20228
|
function configureGitIdentity(cwd) {
|
|
20162
20229
|
try {
|
|
20163
|
-
const name =
|
|
20230
|
+
const name = execFileSync26("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
|
|
20164
20231
|
if (name) return;
|
|
20165
20232
|
} catch {
|
|
20166
20233
|
}
|
|
20167
20234
|
try {
|
|
20168
|
-
|
|
20235
|
+
execFileSync26("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
|
|
20169
20236
|
} catch {
|
|
20170
20237
|
}
|
|
20171
20238
|
try {
|
|
20172
|
-
|
|
20239
|
+
execFileSync26("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
|
|
20173
20240
|
cwd,
|
|
20174
20241
|
stdio: "pipe"
|
|
20175
20242
|
});
|
|
@@ -20779,17 +20846,17 @@ function authOk(req, expected) {
|
|
|
20779
20846
|
return false;
|
|
20780
20847
|
}
|
|
20781
20848
|
function readJsonBody(req) {
|
|
20782
|
-
return new Promise((
|
|
20849
|
+
return new Promise((resolve9, reject) => {
|
|
20783
20850
|
const chunks = [];
|
|
20784
20851
|
req.on("data", (c) => chunks.push(c));
|
|
20785
20852
|
req.on("end", () => {
|
|
20786
20853
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
20787
20854
|
if (!raw.trim()) {
|
|
20788
|
-
|
|
20855
|
+
resolve9({});
|
|
20789
20856
|
return;
|
|
20790
20857
|
}
|
|
20791
20858
|
try {
|
|
20792
|
-
|
|
20859
|
+
resolve9(JSON.parse(raw));
|
|
20793
20860
|
} catch (err) {
|
|
20794
20861
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
20795
20862
|
}
|
|
@@ -21141,11 +21208,11 @@ async function brainServe(opts) {
|
|
|
21141
21208
|
model,
|
|
21142
21209
|
litellmUrl
|
|
21143
21210
|
});
|
|
21144
|
-
await new Promise((
|
|
21211
|
+
await new Promise((resolve9) => {
|
|
21145
21212
|
server.listen(port, "0.0.0.0", () => {
|
|
21146
21213
|
process.stdout.write(`[brain-serve] listening on 0.0.0.0:${port} (cwd=${opts.cwd})
|
|
21147
21214
|
`);
|
|
21148
|
-
|
|
21215
|
+
resolve9();
|
|
21149
21216
|
});
|
|
21150
21217
|
});
|
|
21151
21218
|
const shutdown = (signal) => {
|
|
@@ -21398,14 +21465,14 @@ async function startBrainProxy(opts) {
|
|
|
21398
21465
|
const { httpServer, handler } = buildBrainProxy(opts);
|
|
21399
21466
|
const port = opts.port ?? 0;
|
|
21400
21467
|
const host = opts.host ?? "127.0.0.1";
|
|
21401
|
-
await new Promise((
|
|
21468
|
+
await new Promise((resolve9) => httpServer.listen(port, host, () => resolve9()));
|
|
21402
21469
|
const addr = httpServer.address();
|
|
21403
21470
|
return {
|
|
21404
21471
|
httpServer,
|
|
21405
21472
|
port: addr.port,
|
|
21406
21473
|
url: `http://${host}:${addr.port}`,
|
|
21407
|
-
stop: () => new Promise((
|
|
21408
|
-
httpServer.close(() =>
|
|
21474
|
+
stop: () => new Promise((resolve9) => {
|
|
21475
|
+
httpServer.close(() => resolve9());
|
|
21409
21476
|
}),
|
|
21410
21477
|
handler
|
|
21411
21478
|
};
|
|
@@ -21555,23 +21622,23 @@ function buildMcpHttpServer(opts) {
|
|
|
21555
21622
|
httpServer,
|
|
21556
21623
|
routes,
|
|
21557
21624
|
port,
|
|
21558
|
-
stop: () => new Promise((
|
|
21625
|
+
stop: () => new Promise((resolve9) => {
|
|
21559
21626
|
let pending = transports.size;
|
|
21560
21627
|
if (pending === 0) {
|
|
21561
|
-
httpServer.close(() =>
|
|
21628
|
+
httpServer.close(() => resolve9());
|
|
21562
21629
|
return;
|
|
21563
21630
|
}
|
|
21564
21631
|
for (const transport of transports.values()) {
|
|
21565
21632
|
void transport.close().finally(() => {
|
|
21566
21633
|
pending--;
|
|
21567
|
-
if (pending === 0) httpServer.close(() =>
|
|
21634
|
+
if (pending === 0) httpServer.close(() => resolve9());
|
|
21568
21635
|
});
|
|
21569
21636
|
}
|
|
21570
21637
|
})
|
|
21571
21638
|
};
|
|
21572
21639
|
}
|
|
21573
21640
|
function listenMcpHttpServer(server, host = "127.0.0.1") {
|
|
21574
|
-
return new Promise((
|
|
21641
|
+
return new Promise((resolve9, reject) => {
|
|
21575
21642
|
server.httpServer.once("error", reject);
|
|
21576
21643
|
server.httpServer.listen(server.port, host, () => {
|
|
21577
21644
|
server.httpServer.off("error", reject);
|
|
@@ -21579,7 +21646,7 @@ function listenMcpHttpServer(server, host = "127.0.0.1") {
|
|
|
21579
21646
|
if (addr && typeof addr === "object") {
|
|
21580
21647
|
server.port = addr.port;
|
|
21581
21648
|
}
|
|
21582
|
-
|
|
21649
|
+
resolve9();
|
|
21583
21650
|
});
|
|
21584
21651
|
});
|
|
21585
21652
|
}
|
|
@@ -21668,7 +21735,7 @@ import * as fs50 from "fs";
|
|
|
21668
21735
|
import * as path49 from "path";
|
|
21669
21736
|
|
|
21670
21737
|
// src/chat/inbox.ts
|
|
21671
|
-
import { execFileSync as
|
|
21738
|
+
import { execFileSync as execFileSync27 } from "child_process";
|
|
21672
21739
|
var DEFAULT_POLL_MS = 3e3;
|
|
21673
21740
|
async function waitForNextUserMessage(opts) {
|
|
21674
21741
|
const pollMs = opts.pollIntervalMs ?? DEFAULT_POLL_MS;
|
|
@@ -21692,13 +21759,13 @@ async function waitForNextUserMessage(opts) {
|
|
|
21692
21759
|
try {
|
|
21693
21760
|
const branch = currentBranch(opts.cwd);
|
|
21694
21761
|
if (branch) {
|
|
21695
|
-
|
|
21696
|
-
|
|
21762
|
+
execFileSync27("git", ["fetch", "--quiet", "origin", branch], { cwd: opts.cwd, stdio: "pipe" });
|
|
21763
|
+
execFileSync27("git", ["merge", "--ff-only", "--quiet", `origin/${branch}`], {
|
|
21697
21764
|
cwd: opts.cwd,
|
|
21698
21765
|
stdio: "pipe"
|
|
21699
21766
|
});
|
|
21700
21767
|
} else {
|
|
21701
|
-
|
|
21768
|
+
execFileSync27("git", ["fetch", "--quiet", "--all"], { cwd: opts.cwd, stdio: "pipe" });
|
|
21702
21769
|
}
|
|
21703
21770
|
} catch (err) {
|
|
21704
21771
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -21720,11 +21787,11 @@ async function waitForNextUserMessage(opts) {
|
|
|
21720
21787
|
}
|
|
21721
21788
|
}
|
|
21722
21789
|
function sleep3(ms) {
|
|
21723
|
-
return new Promise((
|
|
21790
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
21724
21791
|
}
|
|
21725
21792
|
function currentBranch(cwd) {
|
|
21726
21793
|
try {
|
|
21727
|
-
const out =
|
|
21794
|
+
const out = execFileSync27("git", ["symbolic-ref", "--short", "HEAD"], {
|
|
21728
21795
|
cwd,
|
|
21729
21796
|
stdio: ["ignore", "pipe", "ignore"]
|
|
21730
21797
|
});
|
|
@@ -22823,14 +22890,14 @@ function sendJson2(res, status, body) {
|
|
|
22823
22890
|
res.end(JSON.stringify(body));
|
|
22824
22891
|
}
|
|
22825
22892
|
function readJsonBody2(req) {
|
|
22826
|
-
return new Promise((
|
|
22893
|
+
return new Promise((resolve9, reject) => {
|
|
22827
22894
|
const chunks = [];
|
|
22828
22895
|
req.on("data", (c) => chunks.push(c));
|
|
22829
22896
|
req.on("end", () => {
|
|
22830
22897
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
22831
|
-
if (!raw.trim()) return
|
|
22898
|
+
if (!raw.trim()) return resolve9({});
|
|
22832
22899
|
try {
|
|
22833
|
-
|
|
22900
|
+
resolve9(JSON.parse(raw));
|
|
22834
22901
|
} catch (err) {
|
|
22835
22902
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
22836
22903
|
}
|
|
@@ -22921,8 +22988,8 @@ function synthesizeLegacyClaimRequest(input) {
|
|
|
22921
22988
|
async function poolServe() {
|
|
22922
22989
|
const masterRaw = process.env.KODY_MASTER_KEY?.trim();
|
|
22923
22990
|
if (!masterRaw) throw new Error("KODY_MASTER_KEY required for pool-serve");
|
|
22924
|
-
const
|
|
22925
|
-
if (!
|
|
22991
|
+
const githubToken2 = process.env.GITHUB_TOKEN?.trim();
|
|
22992
|
+
if (!githubToken2) throw new Error("GITHUB_TOKEN required for pool-serve (reads per-repo vaults)");
|
|
22926
22993
|
const master = masterKeyBytes(masterRaw);
|
|
22927
22994
|
const poolApiKey = derivePoolApiKey(master);
|
|
22928
22995
|
const runnerApiKey = deriveRunnerApiKey(master);
|
|
@@ -22935,7 +23002,7 @@ async function poolServe() {
|
|
|
22935
23002
|
const apiPort = envInt2("POOL_API_PORT", 4100);
|
|
22936
23003
|
const healthTimeoutMs = envInt2("POOL_HEALTH_TIMEOUT_MS", 12e4);
|
|
22937
23004
|
const registry = new PoolRegistry({
|
|
22938
|
-
githubToken,
|
|
23005
|
+
githubToken: githubToken2,
|
|
22939
23006
|
masterKey: master,
|
|
22940
23007
|
base: {
|
|
22941
23008
|
min,
|
|
@@ -23012,10 +23079,10 @@ async function poolServe() {
|
|
|
23012
23079
|
}
|
|
23013
23080
|
});
|
|
23014
23081
|
const apiHost = process.env.POOL_API_HOST ?? "::";
|
|
23015
|
-
await new Promise((
|
|
23082
|
+
await new Promise((resolve9) => {
|
|
23016
23083
|
server.listen(apiPort, apiHost, () => {
|
|
23017
23084
|
log(`listening on ${apiHost}:${apiPort} (min=${min}, app=${app}, region=${region})`);
|
|
23018
|
-
|
|
23085
|
+
resolve9();
|
|
23019
23086
|
});
|
|
23020
23087
|
});
|
|
23021
23088
|
const shutdown = (signal) => {
|
|
@@ -23054,17 +23121,17 @@ function authOk2(req, expected) {
|
|
|
23054
23121
|
return false;
|
|
23055
23122
|
}
|
|
23056
23123
|
function readJsonBody3(req) {
|
|
23057
|
-
return new Promise((
|
|
23124
|
+
return new Promise((resolve9, reject) => {
|
|
23058
23125
|
const chunks = [];
|
|
23059
23126
|
req.on("data", (c) => chunks.push(c));
|
|
23060
23127
|
req.on("end", () => {
|
|
23061
23128
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
23062
23129
|
if (!raw.trim()) {
|
|
23063
|
-
|
|
23130
|
+
resolve9({});
|
|
23064
23131
|
return;
|
|
23065
23132
|
}
|
|
23066
23133
|
try {
|
|
23067
|
-
|
|
23134
|
+
resolve9(JSON.parse(raw));
|
|
23068
23135
|
} catch (err) {
|
|
23069
23136
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
23070
23137
|
}
|
|
@@ -23083,8 +23150,8 @@ function parseJob(body) {
|
|
|
23083
23150
|
if (!jobId) return { error: "jobId required" };
|
|
23084
23151
|
const repo = typeof b.repo === "string" ? b.repo.trim() : "";
|
|
23085
23152
|
if (!/^[^/\s]+\/[^/\s]+$/.test(repo)) return { error: "repo must be 'owner/name'" };
|
|
23086
|
-
const
|
|
23087
|
-
if (!
|
|
23153
|
+
const githubToken2 = typeof b.githubToken === "string" ? b.githubToken.trim() : "";
|
|
23154
|
+
if (!githubToken2) return { error: "githubToken required" };
|
|
23088
23155
|
const action = typeof b.action === "string" && b.action.trim() ? b.action.trim() : void 0;
|
|
23089
23156
|
const message = typeof b.message === "string" && b.message.trim() ? b.message.trim() : void 0;
|
|
23090
23157
|
const mode = b.mode === "interactive" ? "interactive" : b.mode === "scheduled" ? "scheduled" : "issue";
|
|
@@ -23096,7 +23163,7 @@ function parseJob(body) {
|
|
|
23096
23163
|
message
|
|
23097
23164
|
});
|
|
23098
23165
|
if ("error" in runRequest) return { error: runRequest.error };
|
|
23099
|
-
const job = { jobId, repo, githubToken, runRequest: runRequest.request };
|
|
23166
|
+
const job = { jobId, repo, githubToken: githubToken2, runRequest: runRequest.request };
|
|
23100
23167
|
if (job.runRequest.target.type === "issue") {
|
|
23101
23168
|
job.issueNumber = job.runRequest.target.id;
|
|
23102
23169
|
} else if (job.runRequest.target.type === "chat") {
|
|
@@ -23198,13 +23265,13 @@ async function defaultRunJob(job) {
|
|
|
23198
23265
|
...interactive && job.idleExitMs ? { KODY_IDLE_EXIT_MS: String(job.idleExitMs) } : {},
|
|
23199
23266
|
...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
|
|
23200
23267
|
};
|
|
23201
|
-
const run = (cmd, args, cwd) => new Promise((
|
|
23268
|
+
const run = (cmd, args, cwd) => new Promise((resolve9) => {
|
|
23202
23269
|
const child = spawn8(cmd, args, { stdio: "inherit", env: childEnv, cwd });
|
|
23203
|
-
child.on("exit", (code) =>
|
|
23270
|
+
child.on("exit", (code) => resolve9(code ?? 0));
|
|
23204
23271
|
child.on("error", (err) => {
|
|
23205
23272
|
process.stderr.write(`[runner-serve] ${cmd} failed: ${err.message}
|
|
23206
23273
|
`);
|
|
23207
|
-
|
|
23274
|
+
resolve9(1);
|
|
23208
23275
|
});
|
|
23209
23276
|
});
|
|
23210
23277
|
process.stdout.write(`[runner-serve] job ${job.jobId}: cloning ${job.repo}@${branch}
|
|
@@ -23280,11 +23347,11 @@ async function runnerServe() {
|
|
|
23280
23347
|
const port = Number(process.env.PORT ?? DEFAULT_PORT2);
|
|
23281
23348
|
const server = buildServer2({ apiKey });
|
|
23282
23349
|
const host = process.env.RUNNER_HOST ?? "::";
|
|
23283
|
-
await new Promise((
|
|
23350
|
+
await new Promise((resolve9) => {
|
|
23284
23351
|
server.listen(port, host, () => {
|
|
23285
23352
|
process.stdout.write(`[runner-serve] listening on ${host}:${port} (idle, awaiting job)
|
|
23286
23353
|
`);
|
|
23287
|
-
|
|
23354
|
+
resolve9();
|
|
23288
23355
|
});
|
|
23289
23356
|
});
|
|
23290
23357
|
const shutdown = (signal) => {
|
|
@@ -23353,14 +23420,14 @@ async function serve(opts) {
|
|
|
23353
23420
|
`);
|
|
23354
23421
|
const args = ["--dangerously-skip-permissions", "--model", model.model];
|
|
23355
23422
|
const child = spawn9("claude", args, { stdio: "inherit", env: editorEnv, cwd: opts.cwd });
|
|
23356
|
-
const exitCode = await new Promise((
|
|
23357
|
-
child.on("exit", (code) =>
|
|
23423
|
+
const exitCode = await new Promise((resolve9) => {
|
|
23424
|
+
child.on("exit", (code) => resolve9(code ?? 0));
|
|
23358
23425
|
child.on("error", (err) => {
|
|
23359
23426
|
process.stderr.write(`[kody serve] failed to launch Claude Code: ${err.message}
|
|
23360
23427
|
`);
|
|
23361
23428
|
process.stderr.write(` Install: https://docs.anthropic.com/claude/docs/claude-code
|
|
23362
23429
|
`);
|
|
23363
|
-
|
|
23430
|
+
resolve9(1);
|
|
23364
23431
|
});
|
|
23365
23432
|
});
|
|
23366
23433
|
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.280",
|
|
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
|
+
}
|