@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 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.70",
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", "HEAD"]);
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 branch = currentBranch2(cwd);
1912
- if (branch) {
1913
- exec(["rebase", "--quiet", `origin/${branch}`]);
1914
- } else {
1915
- process.stderr.write(`[kody:chat:interactive] cannot rebase: no current branch
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 os from "os";
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(os.tmpdir(), `kody-litellm-${Date.now()}.yaml`);
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(os.tmpdir(), `kody-litellm-${Date.now()}.log`);
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, defaultBranch, cwd) {
3365
+ function hasCommitsAhead(branch, defaultBranch2, cwd) {
3308
3366
  try {
3309
- const out = git(["rev-list", "--count", `origin/${defaultBranch}..${branch}`], cwd);
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", `${defaultBranch}..${branch}`], cwd);
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 os2 from "os";
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(os2.tmpdir(), `kody-synth-${runId}`);
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 os3 from "os";
4869
+ import * as os4 from "os";
4807
4870
  import * as path17 from "path";
4808
4871
  var diagMcp = async (_ctx) => {
4809
- const home = os3.homedir();
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 hasUncommittedChanges(cwd) {
6495
- return git2(["status", "--porcelain", "--untracked-files=no"], cwd).length > 0;
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, defaultBranch, cwd, baseBranch) {
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 !== defaultBranch) {
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 = defaultBranch;
6610
- if (baseBranch && baseBranch !== defaultBranch) {
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, defaultBranch) {
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 defaultBranch = defaultBranchFromGit(cwd);
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, defaultBranch);
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
- try {
8794
- const branchInfo = ensureFeatureBranch(issueNumber, issue.title, ctx.config.git.defaultBranch, ctx.cwd, base ?? void 0);
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 noEditor = ctx.args.noEditor === true;
8974
- if (!noEditor) {
8975
- const env = { ...process.env };
8976
- if (usesProxy) {
8977
- env.ANTHROPIC_BASE_URL = url;
8978
- env.ANTHROPIC_API_KEY = getAnthropicApiKeyOrDummy();
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 cleanup = (signal, exitCode) => {
9094
+ const shutdown = (signal, exitCode) => {
9004
9095
  clearInterval(keepAlive);
9005
- if (handle) {
9006
- process.stdout.write(`[kody serve] received ${signal}, stopping LiteLLM proxy...
9096
+ process.stdout.write(`[kody serve] received ${signal}
9007
9097
  `);
9008
- try {
9009
- handle.kill();
9010
- } catch {
9011
- }
9012
- }
9098
+ killProxy();
9013
9099
  process.exit(exitCode);
9014
9100
  };
9015
- process.on("SIGINT", () => cleanup("SIGINT", 130));
9016
- process.on("SIGTERM", () => cleanup("SIGTERM", 143));
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
- resetWorkingTree(input.cwd);
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 resetWorkingTree(cwd) {
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 VS Code with ANTHROPIC_BASE_URL pointed at it. Long-lived — Ctrl+C to stop.",
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.70",
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
- "scripts": {
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
+ }