@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.
Files changed (2) hide show
  1. package/dist/bin/kody.js +169 -102
  2. 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.278",
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 githubToken = process.env.GITHUB_TOKEN?.trim();
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 ? githubToken || kodyToken || ghToken3 || ghPat : ghPat || ghToken3 || kodyToken || githubToken;
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 cacheKey2 = `${parsed.owner}/${parsed.repo}:${STATE_BRANCH}`;
536
- if (ensuredStateBranches.has(cacheKey2)) return;
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(cacheKey2);
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(cacheKey2);
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((resolve8) => {
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
- resolve8({ exitCode: code ?? -1, durationMs: Date.now() - start, tail });
1240
+ resolve9({ exitCode: code ?? -1, durationMs: Date.now() - start, tail });
1241
1241
  });
1242
1242
  child.on("error", (err) => {
1243
1243
  clearTimeout(timer);
1244
- resolve8({ exitCode: -1, durationMs: Date.now() - start, tail: err.message });
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((resolve8, reject) => {
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
- resolve8();
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((resolve8) => {
3211
+ const timeoutPromise = new Promise((resolve9) => {
3212
3212
  timer = setTimeout(() => {
3213
3213
  timedOut = true;
3214
- resolve8({ done: true, value: void 0 });
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((resolve8) => setTimeout(resolve8, ms));
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((resolve8, reject) => {
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) resolve8();
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((resolve8) => {
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
- resolve8({ exitCode: code ?? -1, output: Buffer.concat(buffers).toString("utf-8") });
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
- resolve8({ exitCode: -1, output: err.message });
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((resolve8) => {
16896
+ next: (timeoutMs) => new Promise((resolve9) => {
16902
16897
  if (queue.length > 0) {
16903
- resolve8(queue.shift());
16898
+ resolve9(queue.shift());
16904
16899
  return;
16905
16900
  }
16906
16901
  if (ended) {
16907
- resolve8(null);
16902
+ resolve9(null);
16908
16903
  return;
16909
16904
  }
16910
- waiter = resolve8;
16905
+ waiter = resolve9;
16911
16906
  const t = setTimeout(
16912
16907
  () => {
16913
- if (waiter === resolve8) {
16908
+ if (waiter === resolve9) {
16914
16909
  waiter = null;
16915
- resolve8(null);
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 hydrateDirectory(config, cwd, stateDir, localDir) {
17306
- const entries = listStateDirectory(config, cwd, stateDir);
17307
- if (entries.length === 0) return;
17308
- for (const entry of entries) {
17309
- if (!entry.name || !entry.type) continue;
17310
- const childState = path41.posix.join(stateDir, entry.name);
17311
- const childLocal = path41.join(localDir, entry.name);
17312
- if (entry.type === "dir") {
17313
- fs43.rmSync(path41.join(cwd, childLocal), { recursive: true, force: true });
17314
- hydrateDirectory(config, cwd, childState, childLocal);
17315
- } else if (entry.type === "file") {
17316
- const file = readStateText(config, cwd, childState);
17317
- if (file) writeLocalFile(cwd, childLocal, file.content);
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
- hydrateDirectory(config, cwd, mapping.stateDir, mapping.localDir);
17325
+ overlayDirectoryChildren(cwd, path41.join(snapshotRoot, mapping.stateDir), mapping.localDir);
17324
17326
  }
17325
17327
  for (const mapping of FILE_MAPPINGS) {
17326
- const file = readStateText(config, cwd, mapping.statePath);
17327
- if (file) writeLocalFile(cwd, mapping.localPath, file.content);
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
- var DIR_MAPPINGS, FILE_MAPPINGS;
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 execFileSync24 } from "child_process";
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 = execFileSync24("sh", ["-c", cmd], {
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
- (resolve8) => {
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
- resolve8({ code, signal, spawnErr });
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 execFileSync25 } from "child_process";
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 = execFileSync25("git", ["config", "--local", "--get", "http.https://github.com/.extraheader"], {
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
- execFileSync25(cmd, args, {
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
- execFileSync25("which", [bin], { stdio: "pipe" });
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
- execFileSync25("python3", ["-c", "import litellm"], { stdio: "pipe" });
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 = execFileSync25("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
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
- execFileSync25("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
20235
+ execFileSync26("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
20169
20236
  } catch {
20170
20237
  }
20171
20238
  try {
20172
- execFileSync25("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
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((resolve8, reject) => {
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
- resolve8({});
20855
+ resolve9({});
20789
20856
  return;
20790
20857
  }
20791
20858
  try {
20792
- resolve8(JSON.parse(raw));
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((resolve8) => {
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
- resolve8();
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((resolve8) => httpServer.listen(port, host, () => resolve8()));
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((resolve8) => {
21408
- httpServer.close(() => resolve8());
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((resolve8) => {
21625
+ stop: () => new Promise((resolve9) => {
21559
21626
  let pending = transports.size;
21560
21627
  if (pending === 0) {
21561
- httpServer.close(() => resolve8());
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(() => resolve8());
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((resolve8, reject) => {
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
- resolve8();
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 execFileSync26 } from "child_process";
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
- execFileSync26("git", ["fetch", "--quiet", "origin", branch], { cwd: opts.cwd, stdio: "pipe" });
21696
- execFileSync26("git", ["merge", "--ff-only", "--quiet", `origin/${branch}`], {
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
- execFileSync26("git", ["fetch", "--quiet", "--all"], { cwd: opts.cwd, stdio: "pipe" });
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((resolve8) => setTimeout(resolve8, ms));
21790
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
21724
21791
  }
21725
21792
  function currentBranch(cwd) {
21726
21793
  try {
21727
- const out = execFileSync26("git", ["symbolic-ref", "--short", "HEAD"], {
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((resolve8, reject) => {
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 resolve8({});
22898
+ if (!raw.trim()) return resolve9({});
22832
22899
  try {
22833
- resolve8(JSON.parse(raw));
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 githubToken = process.env.GITHUB_TOKEN?.trim();
22925
- if (!githubToken) throw new Error("GITHUB_TOKEN required for pool-serve (reads per-repo vaults)");
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((resolve8) => {
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
- resolve8();
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((resolve8, reject) => {
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
- resolve8({});
23130
+ resolve9({});
23064
23131
  return;
23065
23132
  }
23066
23133
  try {
23067
- resolve8(JSON.parse(raw));
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 githubToken = typeof b.githubToken === "string" ? b.githubToken.trim() : "";
23087
- if (!githubToken) return { error: "githubToken required" };
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((resolve8) => {
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) => resolve8(code ?? 0));
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
- resolve8(1);
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((resolve8) => {
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
- resolve8();
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((resolve8) => {
23357
- child.on("exit", (code) => resolve8(code ?? 0));
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
- resolve8(1);
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.278",
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
- "scripts": {
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
+ }