@kody-ade/kody-engine 0.4.70 → 0.4.72
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 +158 -71
- 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/serve/profile.json +2 -10
- package/package.json +20 -17
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.72",
|
|
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",
|
|
@@ -879,6 +879,8 @@ var package_default = {
|
|
|
879
879
|
scripts: {
|
|
880
880
|
kody: "tsx bin/kody.ts",
|
|
881
881
|
serve: "tsx bin/kody.ts serve",
|
|
882
|
+
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
883
|
+
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
882
884
|
build: "tsup && node scripts/copy-assets.cjs",
|
|
883
885
|
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
884
886
|
pretest: "pnpm check:modularity",
|
|
@@ -1720,6 +1722,7 @@ async function emit(sink, type, sessionId, suffix, payload) {
|
|
|
1720
1722
|
// src/chat/modes/interactive.ts
|
|
1721
1723
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
1722
1724
|
import * as fs6 from "fs";
|
|
1725
|
+
import * as os from "os";
|
|
1723
1726
|
import * as path6 from "path";
|
|
1724
1727
|
|
|
1725
1728
|
// src/chat/inbox.ts
|
|
@@ -1881,6 +1884,45 @@ function commitTurn(cwd, sessionId, verbose) {
|
|
|
1881
1884
|
const eventsRel = path6.relative(cwd, eventsFilePath(cwd, sessionId));
|
|
1882
1885
|
const paths = [sessionRel, eventsRel].filter((p) => fs6.existsSync(path6.join(cwd, p)));
|
|
1883
1886
|
if (paths.length === 0) return;
|
|
1887
|
+
const startBranch = currentBranch2(cwd);
|
|
1888
|
+
const eventsBranch = defaultBranch(cwd) ?? "main";
|
|
1889
|
+
if (startBranch === eventsBranch) {
|
|
1890
|
+
commitPathsAndPush(cwd, paths, sessionId, verbose, "HEAD");
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
const stdio = verbose ? "inherit" : "pipe";
|
|
1894
|
+
const exec = (args) => execFileSync2("git", args, { cwd, stdio });
|
|
1895
|
+
const worktreeDir = fs6.mkdtempSync(path6.join(os.tmpdir(), "kody-events-"));
|
|
1896
|
+
let worktreeAdded = false;
|
|
1897
|
+
try {
|
|
1898
|
+
exec(["fetch", "--quiet", "origin", eventsBranch]);
|
|
1899
|
+
exec(["worktree", "add", "--detach", "--quiet", worktreeDir, `origin/${eventsBranch}`]);
|
|
1900
|
+
worktreeAdded = true;
|
|
1901
|
+
for (const rel of paths) {
|
|
1902
|
+
const src = path6.join(cwd, rel);
|
|
1903
|
+
const dst = path6.join(worktreeDir, rel);
|
|
1904
|
+
fs6.mkdirSync(path6.dirname(dst), { recursive: true });
|
|
1905
|
+
fs6.copyFileSync(src, dst);
|
|
1906
|
+
}
|
|
1907
|
+
commitPathsAndPush(worktreeDir, paths, sessionId, verbose, `HEAD:${eventsBranch}`);
|
|
1908
|
+
} catch (err) {
|
|
1909
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1910
|
+
process.stderr.write(`[kody:chat:interactive] worktree commit failed: ${msg}
|
|
1911
|
+
`);
|
|
1912
|
+
} finally {
|
|
1913
|
+
if (worktreeAdded) {
|
|
1914
|
+
try {
|
|
1915
|
+
exec(["worktree", "remove", "--force", "--quiet", worktreeDir]);
|
|
1916
|
+
} catch {
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
try {
|
|
1920
|
+
fs6.rmSync(worktreeDir, { recursive: true, force: true });
|
|
1921
|
+
} catch {
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
function commitPathsAndPush(cwd, paths, sessionId, verbose, pushSpec) {
|
|
1884
1926
|
const stdio = verbose ? "inherit" : "pipe";
|
|
1885
1927
|
const exec = (args) => execFileSync2("git", args, { cwd, stdio });
|
|
1886
1928
|
try {
|
|
@@ -1894,7 +1936,7 @@ function commitTurn(cwd, sessionId, verbose) {
|
|
|
1894
1936
|
}
|
|
1895
1937
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
1896
1938
|
try {
|
|
1897
|
-
exec(["push", "--quiet", "origin",
|
|
1939
|
+
exec(["push", "--quiet", "origin", pushSpec]);
|
|
1898
1940
|
return;
|
|
1899
1941
|
} catch (err) {
|
|
1900
1942
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -1908,14 +1950,16 @@ function commitTurn(cwd, sessionId, verbose) {
|
|
|
1908
1950
|
`);
|
|
1909
1951
|
try {
|
|
1910
1952
|
exec(["fetch", "--quiet", "origin"]);
|
|
1911
|
-
const
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
}
|
|
1915
|
-
|
|
1953
|
+
const upstream = pushSpec.includes(":") ? `origin/${pushSpec.split(":")[1]}` : (() => {
|
|
1954
|
+
const branch = currentBranch2(cwd);
|
|
1955
|
+
return branch ? `origin/${branch}` : null;
|
|
1956
|
+
})();
|
|
1957
|
+
if (!upstream) {
|
|
1958
|
+
process.stderr.write(`[kody:chat:interactive] cannot rebase: no upstream resolved
|
|
1916
1959
|
`);
|
|
1917
1960
|
return;
|
|
1918
1961
|
}
|
|
1962
|
+
exec(["rebase", "--quiet", upstream]);
|
|
1919
1963
|
} catch (rebaseErr) {
|
|
1920
1964
|
const rmsg = rebaseErr instanceof Error ? rebaseErr.message : String(rebaseErr);
|
|
1921
1965
|
process.stderr.write(`[kody:chat:interactive] rebase failed: ${rmsg}
|
|
@@ -1925,6 +1969,20 @@ function commitTurn(cwd, sessionId, verbose) {
|
|
|
1925
1969
|
}
|
|
1926
1970
|
}
|
|
1927
1971
|
}
|
|
1972
|
+
function defaultBranch(cwd) {
|
|
1973
|
+
try {
|
|
1974
|
+
const out = execFileSync2(
|
|
1975
|
+
"git",
|
|
1976
|
+
["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"],
|
|
1977
|
+
{ cwd, stdio: ["ignore", "pipe", "ignore"] }
|
|
1978
|
+
);
|
|
1979
|
+
const symbolic = out.toString("utf-8").trim();
|
|
1980
|
+
if (symbolic.startsWith("origin/")) return symbolic.slice("origin/".length);
|
|
1981
|
+
return symbolic || null;
|
|
1982
|
+
} catch {
|
|
1983
|
+
return null;
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1928
1986
|
function currentBranch2(cwd) {
|
|
1929
1987
|
try {
|
|
1930
1988
|
const out = execFileSync2("git", ["symbolic-ref", "--short", "HEAD"], {
|
|
@@ -3020,7 +3078,7 @@ function errMsg(err) {
|
|
|
3020
3078
|
// src/litellm.ts
|
|
3021
3079
|
import { execFileSync as execFileSync4, spawn as spawn2 } from "child_process";
|
|
3022
3080
|
import * as fs10 from "fs";
|
|
3023
|
-
import * as
|
|
3081
|
+
import * as os2 from "os";
|
|
3024
3082
|
import * as path9 from "path";
|
|
3025
3083
|
async function checkLitellmHealth(url) {
|
|
3026
3084
|
try {
|
|
@@ -3068,13 +3126,13 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
|
|
|
3068
3126
|
throw new Error("litellm not installed \u2014 run: pip install 'litellm[proxy]'");
|
|
3069
3127
|
}
|
|
3070
3128
|
}
|
|
3071
|
-
const configPath = path9.join(
|
|
3129
|
+
const configPath = path9.join(os2.tmpdir(), `kody-litellm-${Date.now()}.yaml`);
|
|
3072
3130
|
fs10.writeFileSync(configPath, generateLitellmConfigYaml(model));
|
|
3073
3131
|
const portMatch = url.match(/:(\d+)/);
|
|
3074
3132
|
const port = portMatch ? portMatch[1] : "4000";
|
|
3075
3133
|
const args = cmd === "litellm" ? ["--config", configPath, "--port", port] : ["-m", "litellm", "--config", configPath, "--port", port];
|
|
3076
3134
|
const dotenvVars = readDotenvApiKeys(projectDir);
|
|
3077
|
-
const logPath = path9.join(
|
|
3135
|
+
const logPath = path9.join(os2.tmpdir(), `kody-litellm-${Date.now()}.log`);
|
|
3078
3136
|
const outFd = fs10.openSync(logPath, "w");
|
|
3079
3137
|
const child = spawn2(cmd, args, {
|
|
3080
3138
|
stdio: ["ignore", outFd, outFd],
|
|
@@ -3304,13 +3362,13 @@ function commitAndPush(branch, agentMessage, cwd) {
|
|
|
3304
3362
|
}
|
|
3305
3363
|
}
|
|
3306
3364
|
}
|
|
3307
|
-
function hasCommitsAhead(branch,
|
|
3365
|
+
function hasCommitsAhead(branch, defaultBranch2, cwd) {
|
|
3308
3366
|
try {
|
|
3309
|
-
const out = git(["rev-list", "--count", `origin/${
|
|
3367
|
+
const out = git(["rev-list", "--count", `origin/${defaultBranch2}..${branch}`], cwd);
|
|
3310
3368
|
return parseInt(out, 10) > 0;
|
|
3311
3369
|
} catch {
|
|
3312
3370
|
try {
|
|
3313
|
-
const out = git(["rev-list", "--count", `${
|
|
3371
|
+
const out = git(["rev-list", "--count", `${defaultBranch2}..${branch}`], cwd);
|
|
3314
3372
|
return parseInt(out, 10) > 0;
|
|
3315
3373
|
} catch {
|
|
3316
3374
|
return false;
|
|
@@ -3576,7 +3634,7 @@ var advanceFlow = async (ctx, profile) => {
|
|
|
3576
3634
|
|
|
3577
3635
|
// src/scripts/buildSyntheticPlugin.ts
|
|
3578
3636
|
import * as fs12 from "fs";
|
|
3579
|
-
import * as
|
|
3637
|
+
import * as os3 from "os";
|
|
3580
3638
|
import * as path11 from "path";
|
|
3581
3639
|
function getPluginsCatalogRoot() {
|
|
3582
3640
|
const here = path11.dirname(new URL(import.meta.url).pathname);
|
|
@@ -3599,7 +3657,7 @@ var buildSyntheticPlugin = async (ctx, profile) => {
|
|
|
3599
3657
|
if (!needsSynthetic) return;
|
|
3600
3658
|
const catalog = getPluginsCatalogRoot();
|
|
3601
3659
|
const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
3602
|
-
const root = path11.join(
|
|
3660
|
+
const root = path11.join(os3.tmpdir(), `kody-synth-${runId}`);
|
|
3603
3661
|
fs12.mkdirSync(path11.join(root, ".claude-plugin"), { recursive: true });
|
|
3604
3662
|
const resolvePart = (bucket, entry) => {
|
|
3605
3663
|
const local = path11.join(profile.dir, bucket, entry);
|
|
@@ -3836,6 +3894,11 @@ var commitAndPush2 = async (ctx, profile) => {
|
|
|
3836
3894
|
} catch {
|
|
3837
3895
|
}
|
|
3838
3896
|
}
|
|
3897
|
+
if (ctx.data.verifyOk === false) {
|
|
3898
|
+
ctx.data.commitResult = { committed: false, pushed: false, skippedReason: "verifyFailed" };
|
|
3899
|
+
ctx.data.hasCommitsAhead = hasCommitsAhead(branch, ctx.config.git.defaultBranch, ctx.cwd);
|
|
3900
|
+
return;
|
|
3901
|
+
}
|
|
3839
3902
|
const markerMissing = ctx.data.agentMarkerMissing === true;
|
|
3840
3903
|
if (ctx.data.agentDone === false && !markerMissing) {
|
|
3841
3904
|
ctx.data.commitResult = { committed: false, pushed: false, skippedReason: "agentDone=false" };
|
|
@@ -4803,10 +4866,10 @@ function filterGoalTaskPrs(prs, taskIssueNumbers) {
|
|
|
4803
4866
|
// src/scripts/diagMcp.ts
|
|
4804
4867
|
import { execFileSync as execFileSync11 } from "child_process";
|
|
4805
4868
|
import * as fs17 from "fs";
|
|
4806
|
-
import * as
|
|
4869
|
+
import * as os4 from "os";
|
|
4807
4870
|
import * as path17 from "path";
|
|
4808
4871
|
var diagMcp = async (_ctx) => {
|
|
4809
|
-
const home =
|
|
4872
|
+
const home = os4.homedir();
|
|
4810
4873
|
const cacheDir = path17.join(home, ".cache", "ms-playwright");
|
|
4811
4874
|
let entries = [];
|
|
4812
4875
|
try {
|
|
@@ -6467,14 +6530,6 @@ var finishFlow = async (ctx, profile, _agentResult, args) => {
|
|
|
6467
6530
|
|
|
6468
6531
|
// src/branch.ts
|
|
6469
6532
|
import { execFileSync as execFileSync15 } from "child_process";
|
|
6470
|
-
var UncommittedChangesError = class extends Error {
|
|
6471
|
-
constructor(branch) {
|
|
6472
|
-
super(`Uncommitted changes on branch '${branch}' \u2014 refusing to run to protect work in progress`);
|
|
6473
|
-
this.branch = branch;
|
|
6474
|
-
this.name = "UncommittedChangesError";
|
|
6475
|
-
}
|
|
6476
|
-
branch;
|
|
6477
|
-
};
|
|
6478
6533
|
function git2(args, cwd) {
|
|
6479
6534
|
return execFileSync15("git", args, {
|
|
6480
6535
|
encoding: "utf-8",
|
|
@@ -6491,8 +6546,15 @@ function deriveBranchName(issueNumber, title) {
|
|
|
6491
6546
|
function getCurrentBranch(cwd) {
|
|
6492
6547
|
return git2(["branch", "--show-current"], cwd);
|
|
6493
6548
|
}
|
|
6494
|
-
function
|
|
6495
|
-
|
|
6549
|
+
function resetWorkingTree(cwd) {
|
|
6550
|
+
try {
|
|
6551
|
+
execFileSync15("git", ["reset", "--hard", "HEAD"], { cwd, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
|
|
6552
|
+
} catch {
|
|
6553
|
+
}
|
|
6554
|
+
try {
|
|
6555
|
+
execFileSync15("git", ["clean", "-fd"], { cwd, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
|
|
6556
|
+
} catch {
|
|
6557
|
+
}
|
|
6496
6558
|
}
|
|
6497
6559
|
function checkoutPrBranch(prNumber, cwd) {
|
|
6498
6560
|
const env = {
|
|
@@ -6539,14 +6601,13 @@ function mergeBase(baseBranch, cwd) {
|
|
|
6539
6601
|
return "error";
|
|
6540
6602
|
}
|
|
6541
6603
|
}
|
|
6542
|
-
function ensureFeatureBranch(issueNumber, title,
|
|
6604
|
+
function ensureFeatureBranch(issueNumber, title, defaultBranch2, cwd, baseBranch) {
|
|
6543
6605
|
const branchName = deriveBranchName(issueNumber, title);
|
|
6606
|
+
resetWorkingTree(cwd);
|
|
6544
6607
|
const current = getCurrentBranch(cwd);
|
|
6545
6608
|
if (current === branchName) {
|
|
6546
|
-
if (hasUncommittedChanges(cwd)) throw new UncommittedChangesError(branchName);
|
|
6547
6609
|
return { branch: branchName, created: false };
|
|
6548
6610
|
}
|
|
6549
|
-
if (hasUncommittedChanges(cwd)) throw new UncommittedChangesError(current || "(detached)");
|
|
6550
6611
|
try {
|
|
6551
6612
|
git2(["fetch", "origin"], cwd);
|
|
6552
6613
|
} catch {
|
|
@@ -6557,7 +6618,7 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch, cwd, baseBranch)
|
|
|
6557
6618
|
originBranchExists = true;
|
|
6558
6619
|
} catch {
|
|
6559
6620
|
}
|
|
6560
|
-
if (originBranchExists && baseBranch && baseBranch !==
|
|
6621
|
+
if (originBranchExists && baseBranch && baseBranch !== defaultBranch2) {
|
|
6561
6622
|
let baseExists = false;
|
|
6562
6623
|
try {
|
|
6563
6624
|
git2(["rev-parse", "--verify", `origin/${baseBranch}`], cwd);
|
|
@@ -6606,8 +6667,8 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch, cwd, baseBranch)
|
|
|
6606
6667
|
return { branch: branchName, created: false };
|
|
6607
6668
|
} catch {
|
|
6608
6669
|
}
|
|
6609
|
-
let forkPoint =
|
|
6610
|
-
if (baseBranch && baseBranch !==
|
|
6670
|
+
let forkPoint = defaultBranch2;
|
|
6671
|
+
if (baseBranch && baseBranch !== defaultBranch2) {
|
|
6611
6672
|
try {
|
|
6612
6673
|
git2(["rev-parse", "--verify", `origin/${baseBranch}`], cwd);
|
|
6613
6674
|
forkPoint = baseBranch;
|
|
@@ -6979,11 +7040,11 @@ function detectOwnerRepo(cwd) {
|
|
|
6979
7040
|
if (!m) return null;
|
|
6980
7041
|
return { owner: m[1], repo: m[2] };
|
|
6981
7042
|
}
|
|
6982
|
-
function makeConfig(pm, ownerRepo,
|
|
7043
|
+
function makeConfig(pm, ownerRepo, defaultBranch2) {
|
|
6983
7044
|
return {
|
|
6984
7045
|
$schema: "https://raw.githubusercontent.com/aharonyaircohen/kody-engine/main/kody.config.schema.json",
|
|
6985
7046
|
quality: qualityCommandsFor(pm),
|
|
6986
|
-
git: { defaultBranch },
|
|
7047
|
+
git: { defaultBranch: defaultBranch2 },
|
|
6987
7048
|
github: {
|
|
6988
7049
|
owner: ownerRepo?.owner ?? "OWNER",
|
|
6989
7050
|
repo: ownerRepo?.repo ?? "REPO"
|
|
@@ -7075,12 +7136,12 @@ function performInit(cwd, force) {
|
|
|
7075
7136
|
const skipped = [];
|
|
7076
7137
|
const pm = detectPackageManager(cwd);
|
|
7077
7138
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
7078
|
-
const
|
|
7139
|
+
const defaultBranch2 = defaultBranchFromGit(cwd);
|
|
7079
7140
|
const configPath = path23.join(cwd, "kody.config.json");
|
|
7080
7141
|
if (fs24.existsSync(configPath) && !force) {
|
|
7081
7142
|
skipped.push("kody.config.json");
|
|
7082
7143
|
} else {
|
|
7083
|
-
const cfg = makeConfig(pm, ownerRepo,
|
|
7144
|
+
const cfg = makeConfig(pm, ownerRepo, defaultBranch2);
|
|
7084
7145
|
fs24.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
7085
7146
|
`);
|
|
7086
7147
|
wrote.push("kody.config.json");
|
|
@@ -8790,19 +8851,8 @@ var runFlow = async (ctx) => {
|
|
|
8790
8851
|
process.stderr.write(`[kody runFlow] resolved base branch: ${base} (from --base)
|
|
8791
8852
|
`);
|
|
8792
8853
|
}
|
|
8793
|
-
|
|
8794
|
-
|
|
8795
|
-
ctx.data.branch = branchInfo.branch;
|
|
8796
|
-
} catch (err) {
|
|
8797
|
-
if (err instanceof UncommittedChangesError) {
|
|
8798
|
-
ctx.output.exitCode = 5;
|
|
8799
|
-
ctx.output.reason = err.message;
|
|
8800
|
-
ctx.skipAgent = true;
|
|
8801
|
-
tryPost(issueNumber, `\u26A0\uFE0F kody refused to start: ${err.message}`, ctx.cwd);
|
|
8802
|
-
return;
|
|
8803
|
-
}
|
|
8804
|
-
throw err;
|
|
8805
|
-
}
|
|
8854
|
+
const branchInfo = ensureFeatureBranch(issueNumber, issue.title, ctx.config.git.defaultBranch, ctx.cwd, base ?? void 0);
|
|
8855
|
+
ctx.data.branch = branchInfo.branch;
|
|
8806
8856
|
const runUrl = getRunUrl();
|
|
8807
8857
|
const startMsg = runUrl ? `\u2699\uFE0F kody started \u2014 branch \`${ctx.data.branch}\`, run ${runUrl}` : `\u2699\uFE0F kody started \u2014 branch \`${ctx.data.branch}\``;
|
|
8808
8858
|
tryPost(issueNumber, startMsg, ctx.cwd);
|
|
@@ -8954,8 +9004,23 @@ function buildChildEnv(parent, force) {
|
|
|
8954
9004
|
|
|
8955
9005
|
// src/scripts/serveFlow.ts
|
|
8956
9006
|
import { spawn as spawn3 } from "child_process";
|
|
9007
|
+
function parseTarget(positional) {
|
|
9008
|
+
if (!Array.isArray(positional) || positional.length === 0) return "none";
|
|
9009
|
+
const first = String(positional[0]).toLowerCase();
|
|
9010
|
+
if (first === "vscode" || first === "code") return "vscode";
|
|
9011
|
+
if (first === "claude") return "claude";
|
|
9012
|
+
throw new Error(`unknown serve subcommand: "${positional[0]}" (expected: vscode, claude, or omit)`);
|
|
9013
|
+
}
|
|
9014
|
+
function buildProxyEnv(url) {
|
|
9015
|
+
return {
|
|
9016
|
+
...process.env,
|
|
9017
|
+
ANTHROPIC_BASE_URL: url,
|
|
9018
|
+
ANTHROPIC_API_KEY: getAnthropicApiKeyOrDummy()
|
|
9019
|
+
};
|
|
9020
|
+
}
|
|
8957
9021
|
var serveFlow = async (ctx) => {
|
|
8958
9022
|
ctx.skipAgent = true;
|
|
9023
|
+
const target = parseTarget(ctx.args._);
|
|
8959
9024
|
const model = parseProviderModel(ctx.config.agent.model);
|
|
8960
9025
|
const usesProxy = needsLitellmProxy(model);
|
|
8961
9026
|
let handle = null;
|
|
@@ -8970,19 +9035,45 @@ var serveFlow = async (ctx) => {
|
|
|
8970
9035
|
`);
|
|
8971
9036
|
}
|
|
8972
9037
|
const url = handle?.url ?? LITELLM_DEFAULT_URL;
|
|
8973
|
-
const
|
|
8974
|
-
|
|
8975
|
-
|
|
8976
|
-
|
|
8977
|
-
|
|
8978
|
-
|
|
9038
|
+
const editorEnv = usesProxy ? buildProxyEnv(url) : { ...process.env };
|
|
9039
|
+
const killProxy = () => {
|
|
9040
|
+
if (handle) {
|
|
9041
|
+
process.stdout.write(`[kody serve] stopping LiteLLM proxy...
|
|
9042
|
+
`);
|
|
9043
|
+
try {
|
|
9044
|
+
handle.kill();
|
|
9045
|
+
} catch {
|
|
9046
|
+
}
|
|
8979
9047
|
}
|
|
9048
|
+
};
|
|
9049
|
+
if (target === "claude") {
|
|
9050
|
+
process.stdout.write(`[kody serve] launching Claude Code at ${ctx.cwd}
|
|
9051
|
+
`);
|
|
9052
|
+
if (usesProxy) process.stdout.write(` ANTHROPIC_BASE_URL=${url}
|
|
9053
|
+
`);
|
|
9054
|
+
const args = ["--dangerously-skip-permissions", "--model", model.model];
|
|
9055
|
+
const child = spawn3("claude", args, { stdio: "inherit", env: editorEnv, cwd: ctx.cwd });
|
|
9056
|
+
const exitCode = await new Promise((resolve4) => {
|
|
9057
|
+
child.on("exit", (code) => resolve4(code ?? 0));
|
|
9058
|
+
child.on("error", (err) => {
|
|
9059
|
+
process.stderr.write(`[kody serve] failed to launch Claude Code: ${err.message}
|
|
9060
|
+
`);
|
|
9061
|
+
process.stderr.write(` Install: https://docs.anthropic.com/claude/docs/claude-code
|
|
9062
|
+
`);
|
|
9063
|
+
resolve4(1);
|
|
9064
|
+
});
|
|
9065
|
+
});
|
|
9066
|
+
killProxy();
|
|
9067
|
+
ctx.output.exitCode = exitCode;
|
|
9068
|
+
return;
|
|
9069
|
+
}
|
|
9070
|
+
if (target === "vscode") {
|
|
8980
9071
|
process.stdout.write(`[kody serve] launching VS Code at ${ctx.cwd}
|
|
8981
9072
|
`);
|
|
8982
9073
|
if (usesProxy) process.stdout.write(` ANTHROPIC_BASE_URL=${url}
|
|
8983
9074
|
`);
|
|
8984
9075
|
try {
|
|
8985
|
-
const code = spawn3("code", [ctx.cwd], { stdio: "inherit", env, detached: true });
|
|
9076
|
+
const code = spawn3("code", [ctx.cwd], { stdio: "inherit", env: editorEnv, detached: true });
|
|
8986
9077
|
code.on("error", (err) => {
|
|
8987
9078
|
process.stderr.write(`[kody serve] failed to launch VS Code: ${err.message}
|
|
8988
9079
|
`);
|
|
@@ -9000,20 +9091,15 @@ var serveFlow = async (ctx) => {
|
|
|
9000
9091
|
`);
|
|
9001
9092
|
const keepAlive = setInterval(() => {
|
|
9002
9093
|
}, 6e4);
|
|
9003
|
-
const
|
|
9094
|
+
const shutdown = (signal, exitCode) => {
|
|
9004
9095
|
clearInterval(keepAlive);
|
|
9005
|
-
|
|
9006
|
-
process.stdout.write(`[kody serve] received ${signal}, stopping LiteLLM proxy...
|
|
9096
|
+
process.stdout.write(`[kody serve] received ${signal}
|
|
9007
9097
|
`);
|
|
9008
|
-
|
|
9009
|
-
handle.kill();
|
|
9010
|
-
} catch {
|
|
9011
|
-
}
|
|
9012
|
-
}
|
|
9098
|
+
killProxy();
|
|
9013
9099
|
process.exit(exitCode);
|
|
9014
9100
|
};
|
|
9015
|
-
process.on("SIGINT", () =>
|
|
9016
|
-
process.on("SIGTERM", () =>
|
|
9101
|
+
process.on("SIGINT", () => shutdown("SIGINT", 130));
|
|
9102
|
+
process.on("SIGTERM", () => shutdown("SIGTERM", 143));
|
|
9017
9103
|
await new Promise(() => {
|
|
9018
9104
|
});
|
|
9019
9105
|
};
|
|
@@ -10235,6 +10321,9 @@ function validateInputs(specs, raw) {
|
|
|
10235
10321
|
throw new Error(`unknown arg: --${key}`);
|
|
10236
10322
|
}
|
|
10237
10323
|
}
|
|
10324
|
+
if (Array.isArray(raw._)) {
|
|
10325
|
+
out._ = raw._;
|
|
10326
|
+
}
|
|
10238
10327
|
for (const spec of specs) {
|
|
10239
10328
|
const v = raw[spec.name];
|
|
10240
10329
|
if (v === void 0 || v === null) continue;
|
|
@@ -10475,7 +10564,7 @@ async function runContainerLoop(profile, ctx, input) {
|
|
|
10475
10564
|
process.stderr.write(`[kody container] step ${iteration}: invoking ${child.exec}
|
|
10476
10565
|
`);
|
|
10477
10566
|
if (profile.resetBetweenChildren !== false) {
|
|
10478
|
-
|
|
10567
|
+
resetWorkingTree2(input.cwd);
|
|
10479
10568
|
} else {
|
|
10480
10569
|
process.stderr.write(`[kody container] resetBetweenChildren=false; preserving tracked tree
|
|
10481
10570
|
`);
|
|
@@ -10638,7 +10727,7 @@ async function runContainerLoop(profile, ctx, input) {
|
|
|
10638
10727
|
currentIdx = nextIdx;
|
|
10639
10728
|
}
|
|
10640
10729
|
}
|
|
10641
|
-
function
|
|
10730
|
+
function resetWorkingTree2(cwd) {
|
|
10642
10731
|
try {
|
|
10643
10732
|
execFileSync29("git", ["reset", "--hard", "HEAD"], {
|
|
10644
10733
|
cwd,
|
|
@@ -10734,7 +10823,6 @@ Exit codes (inherited from kody run):
|
|
|
10734
10823
|
2 verify failed (no PR opened \u2014 branch pushed for inspection)
|
|
10735
10824
|
3 no commits to ship
|
|
10736
10825
|
4 PR creation failed
|
|
10737
|
-
5 uncommitted changes on target branch
|
|
10738
10826
|
99 wrapper crashed
|
|
10739
10827
|
`;
|
|
10740
10828
|
function parseCiArgs(argv) {
|
|
@@ -11538,7 +11626,6 @@ Exit codes:
|
|
|
11538
11626
|
2 verify failed (no PR opened \u2014 branch pushed for inspection) \u2014 skipped in resolve mode
|
|
11539
11627
|
3 no commits to ship (also the resolve clean-merge short-circuit)
|
|
11540
11628
|
4 PR creation failed
|
|
11541
|
-
5 uncommitted changes on target branch
|
|
11542
11629
|
64 invalid CLI args
|
|
11543
11630
|
99 wrapper crashed
|
|
11544
11631
|
`;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "serve",
|
|
3
3
|
"role": "utility",
|
|
4
|
-
"describe": "Start a LiteLLM proxy and launch
|
|
5
|
-
"inputs": [
|
|
6
|
-
{
|
|
7
|
-
"name": "noEditor",
|
|
8
|
-
"flag": "--no-editor",
|
|
9
|
-
"type": "bool",
|
|
10
|
-
"required": false,
|
|
11
|
-
"describe": "Run the LiteLLM proxy only; do not launch VS Code."
|
|
12
|
-
}
|
|
13
|
-
],
|
|
4
|
+
"describe": "Start a LiteLLM proxy and optionally launch an editor pointed at it. Usage: `kody serve` (proxy only), `kody serve vscode`, `kody serve claude`. Long-lived — Ctrl+C to stop.",
|
|
5
|
+
"inputs": [],
|
|
14
6
|
"claudeCode": {
|
|
15
7
|
"model": "inherit",
|
|
16
8
|
"permissionMode": "acceptEdits",
|
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.72",
|
|
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,23 @@
|
|
|
12
12
|
"templates",
|
|
13
13
|
"kody.config.schema.json"
|
|
14
14
|
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"kody": "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
|
+
"build": "tsup && node scripts/copy-assets.cjs",
|
|
21
|
+
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
22
|
+
"pretest": "pnpm check:modularity",
|
|
23
|
+
"test": "vitest run tests/unit tests/int --no-coverage",
|
|
24
|
+
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
25
|
+
"test:all": "vitest run tests --no-coverage",
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
27
|
+
"lint": "biome check",
|
|
28
|
+
"lint:fix": "biome check --write",
|
|
29
|
+
"format": "biome format --write",
|
|
30
|
+
"prepublishOnly": "pnpm build"
|
|
31
|
+
},
|
|
15
32
|
"dependencies": {
|
|
16
33
|
"@actions/cache": "^6.0.0",
|
|
17
34
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
@@ -33,19 +50,5 @@
|
|
|
33
50
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
34
51
|
},
|
|
35
52
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
36
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
37
|
-
|
|
38
|
-
"kody": "tsx bin/kody.ts",
|
|
39
|
-
"serve": "tsx bin/kody.ts serve",
|
|
40
|
-
"build": "tsup && node scripts/copy-assets.cjs",
|
|
41
|
-
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
42
|
-
"pretest": "pnpm check:modularity",
|
|
43
|
-
"test": "vitest run tests/unit tests/int --no-coverage",
|
|
44
|
-
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
45
|
-
"test:all": "vitest run tests --no-coverage",
|
|
46
|
-
"typecheck": "tsc --noEmit",
|
|
47
|
-
"lint": "biome check",
|
|
48
|
-
"lint:fix": "biome check --write",
|
|
49
|
-
"format": "biome format --write"
|
|
50
|
-
}
|
|
51
|
-
}
|
|
53
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
54
|
+
}
|