@kody-ade/kody-engine 0.4.99 → 0.4.100

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
@@ -877,7 +877,7 @@ var init_loadPriorArt = __esm({
877
877
  // package.json
878
878
  var package_default = {
879
879
  name: "@kody-ade/kody-engine",
880
- version: "0.4.99",
880
+ version: "0.4.100",
881
881
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
882
882
  license: "MIT",
883
883
  type: "module",
@@ -931,7 +931,7 @@ var package_default = {
931
931
  };
932
932
 
933
933
  // src/chat-cli.ts
934
- import { execFileSync as execFileSync31 } from "child_process";
934
+ import { execFileSync as execFileSync32 } from "child_process";
935
935
  import * as fs39 from "fs";
936
936
  import * as path36 from "path";
937
937
 
@@ -2356,7 +2356,7 @@ async function emit2(sink, type, sessionId, suffix, payload) {
2356
2356
  }
2357
2357
 
2358
2358
  // src/kody-cli.ts
2359
- import { execFileSync as execFileSync30 } from "child_process";
2359
+ import { execFileSync as execFileSync31 } from "child_process";
2360
2360
  import * as fs38 from "fs";
2361
2361
  import * as path35 from "path";
2362
2362
 
@@ -2679,7 +2679,7 @@ function coerceBare(spec, value) {
2679
2679
  init_issue();
2680
2680
 
2681
2681
  // src/executor.ts
2682
- import { execFileSync as execFileSync29, spawn as spawn6 } from "child_process";
2682
+ import { execFileSync as execFileSync30, spawn as spawn6 } from "child_process";
2683
2683
  import * as fs37 from "fs";
2684
2684
  import * as path34 from "path";
2685
2685
  init_events();
@@ -3423,7 +3423,85 @@ function stripBlockingEnv(env) {
3423
3423
  }
3424
3424
 
3425
3425
  // src/commit.ts
3426
+ import { execFileSync as execFileSync6 } from "child_process";
3427
+
3428
+ // src/pushWithRetry.ts
3426
3429
  import { execFileSync as execFileSync5 } from "child_process";
3430
+ var DEFAULT_MAX_RETRIES = 3;
3431
+ var DEFAULT_BACKOFF_MS = 1e3;
3432
+ var MAX_BACKOFF_MS = 6e4;
3433
+ var NON_FAST_FORWARD_RE = /non-fast-forward|fetch first|\(rejected\)|! \[rejected\]/i;
3434
+ function sleepSync(ms) {
3435
+ if (ms <= 0) return;
3436
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
3437
+ }
3438
+ function runGit(args, cwd) {
3439
+ try {
3440
+ const stdout = execFileSync5("git", args, {
3441
+ cwd,
3442
+ encoding: "utf-8",
3443
+ env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
3444
+ stdio: ["ignore", "pipe", "pipe"]
3445
+ });
3446
+ return { ok: true, stdout: stdout?.toString() ?? "", stderr: "" };
3447
+ } catch (err) {
3448
+ const e = err;
3449
+ const stderr = e.stderr?.toString() ?? e.message ?? "";
3450
+ const stdout = e.stdout?.toString() ?? "";
3451
+ return { ok: false, stdout, stderr };
3452
+ }
3453
+ }
3454
+ function resolveBranch(cwd, explicit) {
3455
+ if (explicit && explicit.trim()) return explicit.trim();
3456
+ const r = runGit(["symbolic-ref", "--short", "HEAD"], cwd);
3457
+ return r.ok ? r.stdout.trim() : "";
3458
+ }
3459
+ function pushWithRetry(opts = {}) {
3460
+ const cwd = opts.cwd ?? process.cwd();
3461
+ const maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
3462
+ const baseBackoff = opts.backoffMs ?? DEFAULT_BACKOFF_MS;
3463
+ const branch = resolveBranch(cwd, opts.branch);
3464
+ if (!branch) {
3465
+ return { ok: false, reason: "could not determine current branch (detached HEAD?)", attempts: 0 };
3466
+ }
3467
+ const pushArgs = opts.setUpstream ? ["push", "-u", "origin", `HEAD:${branch}`] : ["push", "origin", "HEAD"];
3468
+ let lastError = "";
3469
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
3470
+ const push = runGit(pushArgs, cwd);
3471
+ if (push.ok) return { ok: true, attempts: attempt };
3472
+ lastError = push.stderr || push.stdout || "(no error detail)";
3473
+ if (!NON_FAST_FORWARD_RE.test(lastError)) {
3474
+ return { ok: false, reason: `push failed (not retryable): ${lastError.trim().slice(-400)}`, attempts: attempt };
3475
+ }
3476
+ if (attempt === maxRetries) break;
3477
+ const fetch2 = runGit(["fetch", "origin", branch], cwd);
3478
+ if (!fetch2.ok) {
3479
+ return {
3480
+ ok: false,
3481
+ reason: `fetch failed during retry: ${(fetch2.stderr || fetch2.stdout).trim().slice(-400)}`,
3482
+ attempts: attempt
3483
+ };
3484
+ }
3485
+ const rebase = runGit(["rebase", `origin/${branch}`], cwd);
3486
+ if (!rebase.ok) {
3487
+ runGit(["rebase", "--abort"], cwd);
3488
+ return {
3489
+ ok: false,
3490
+ reason: `rebase onto origin/${branch} failed (conflict?): ${(rebase.stderr || rebase.stdout).trim().slice(-400)}`,
3491
+ attempts: attempt
3492
+ };
3493
+ }
3494
+ const delay = Math.min(baseBackoff * 2 ** (attempt - 1), MAX_BACKOFF_MS);
3495
+ sleepSync(delay);
3496
+ }
3497
+ return {
3498
+ ok: false,
3499
+ reason: `push rejected after ${maxRetries} attempts: ${lastError.trim().slice(-400)}`,
3500
+ attempts: maxRetries
3501
+ };
3502
+ }
3503
+
3504
+ // src/commit.ts
3427
3505
  import * as fs14 from "fs";
3428
3506
  import * as path12 from "path";
3429
3507
  var FORBIDDEN_PATH_PREFIXES = [
@@ -3452,13 +3530,9 @@ var CONVENTIONAL_PREFIXES = [
3452
3530
  "build:",
3453
3531
  "revert:"
3454
3532
  ];
3455
- var PUSH_RETRY_DELAYS_MS = [2e3, 4e3, 8e3];
3456
- function sleepSync(ms) {
3457
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
3458
- }
3459
3533
  function git(args, cwd) {
3460
3534
  try {
3461
- return execFileSync5("git", args, {
3535
+ return execFileSync6("git", args, {
3462
3536
  encoding: "utf-8",
3463
3537
  timeout: 12e4,
3464
3538
  cwd,
@@ -3517,7 +3591,7 @@ function isForbiddenPath(p) {
3517
3591
  return false;
3518
3592
  }
3519
3593
  function listChangedFiles(cwd) {
3520
- const raw = execFileSync5("git", ["status", "--porcelain=v1", "-z"], {
3594
+ const raw = execFileSync6("git", ["status", "--porcelain=v1", "-z"], {
3521
3595
  encoding: "utf-8",
3522
3596
  cwd,
3523
3597
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
@@ -3529,7 +3603,7 @@ function listChangedFiles(cwd) {
3529
3603
  }
3530
3604
  function listFilesInCommit(ref = "HEAD", cwd) {
3531
3605
  try {
3532
- const raw = execFileSync5("git", ["show", "--name-only", "--pretty=format:", "-z", ref], {
3606
+ const raw = execFileSync6("git", ["show", "--name-only", "--pretty=format:", "-z", ref], {
3533
3607
  encoding: "utf-8",
3534
3608
  cwd,
3535
3609
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
@@ -3573,28 +3647,11 @@ function commitAndPush(branch, agentMessage, cwd) {
3573
3647
  throw err;
3574
3648
  }
3575
3649
  const sha = git(["rev-parse", "HEAD"], cwd).slice(0, 7);
3576
- let pushError = "push failed (no error detail)";
3577
- for (let attempt = 0; attempt <= PUSH_RETRY_DELAYS_MS.length; attempt++) {
3578
- try {
3579
- git(["push", "-u", "origin", branch], cwd);
3580
- return { committed: true, pushed: true, sha, message };
3581
- } catch (firstErr) {
3582
- try {
3583
- git(["push", "--force-with-lease", "-u", "origin", branch], cwd);
3584
- return { committed: true, pushed: true, sha, message };
3585
- } catch (secondErr) {
3586
- const tail = (secondErr instanceof Error ? secondErr.message : String(secondErr)).slice(-400);
3587
- const initial = firstErr instanceof Error ? firstErr.message : String(firstErr);
3588
- pushError = `push failed: ${initial.slice(-200)} | force-with-lease failed: ${tail}`;
3589
- const delay = PUSH_RETRY_DELAYS_MS[attempt];
3590
- if (delay === void 0) break;
3591
- process.stderr.write(`[kody:commit] push failed (attempt ${attempt + 1}); retrying in ${delay}ms
3592
- `);
3593
- sleepSync(delay);
3594
- }
3595
- }
3650
+ const pushResult = pushWithRetry({ cwd, branch, setUpstream: true });
3651
+ if (pushResult.ok) {
3652
+ return { committed: true, pushed: true, sha, message };
3596
3653
  }
3597
- return { committed: true, pushed: false, sha, message, pushError };
3654
+ return { committed: true, pushed: false, sha, message, pushError: pushResult.reason };
3598
3655
  }
3599
3656
  function hasCommitsAhead(branch, defaultBranch2, cwd) {
3600
3657
  try {
@@ -3621,10 +3678,10 @@ var abortUnfinishedGitOps2 = async (ctx) => {
3621
3678
  };
3622
3679
 
3623
3680
  // src/scripts/advanceFlow.ts
3624
- import { execFileSync as execFileSync7 } from "child_process";
3681
+ import { execFileSync as execFileSync8 } from "child_process";
3625
3682
 
3626
3683
  // src/state.ts
3627
- import { execFileSync as execFileSync6 } from "child_process";
3684
+ import { execFileSync as execFileSync7 } from "child_process";
3628
3685
  var STATE_BEGIN = "<!-- kody:state:v1:begin -->";
3629
3686
  var STATE_END = "<!-- kody:state:v1:end -->";
3630
3687
  var HISTORY_MAX_ENTRIES = 20;
@@ -3650,7 +3707,7 @@ function ghToken2() {
3650
3707
  function gh2(args, input, cwd) {
3651
3708
  const token = ghToken2();
3652
3709
  const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
3653
- return execFileSync6("gh", args, {
3710
+ return execFileSync7("gh", args, {
3654
3711
  encoding: "utf-8",
3655
3712
  timeout: API_TIMEOUT_MS2,
3656
3713
  cwd,
@@ -3853,7 +3910,7 @@ var advanceFlow = async (ctx, profile) => {
3853
3910
  }
3854
3911
  const body = `@kody ${flow.name}`;
3855
3912
  try {
3856
- execFileSync7("gh", ["issue", "comment", String(flow.issueNumber), "--body", body], {
3913
+ execFileSync8("gh", ["issue", "comment", String(flow.issueNumber), "--body", body], {
3857
3914
  timeout: API_TIMEOUT_MS3,
3858
3915
  cwd: ctx.cwd,
3859
3916
  stdio: ["ignore", "pipe", "pipe"]
@@ -4414,7 +4471,7 @@ function copyDir(src, dst) {
4414
4471
  }
4415
4472
 
4416
4473
  // src/coverage.ts
4417
- import { execFileSync as execFileSync8 } from "child_process";
4474
+ import { execFileSync as execFileSync9 } from "child_process";
4418
4475
  function patternToRegex(pattern) {
4419
4476
  let s = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
4420
4477
  s = s.replace(/\*\*\//g, "\xA7S").replace(/\*\*/g, "\xA7A").replace(/\*/g, "[^/]*");
@@ -4432,7 +4489,7 @@ function renderSiblingPath(file, requireSibling) {
4432
4489
  }
4433
4490
  function safeGit(args, cwd) {
4434
4491
  try {
4435
- return execFileSync8("git", args, { encoding: "utf-8", cwd, env: { ...process.env, HUSKY: "0" } }).trim();
4492
+ return execFileSync9("git", args, { encoding: "utf-8", cwd, env: { ...process.env, HUSKY: "0" } }).trim();
4436
4493
  } catch {
4437
4494
  return "";
4438
4495
  }
@@ -4642,14 +4699,14 @@ var commitAndPush2 = async (ctx, profile) => {
4642
4699
  };
4643
4700
 
4644
4701
  // src/scripts/commitGoalState.ts
4645
- import { execFileSync as execFileSync9 } from "child_process";
4702
+ import { execFileSync as execFileSync10 } from "child_process";
4646
4703
  import * as path18 from "path";
4647
4704
  var commitGoalState = async (ctx) => {
4648
4705
  const goal = ctx.data.goal;
4649
4706
  if (!goal) return;
4650
4707
  const stateRel = path18.posix.join(".kody", "goals", goal.id, "state.json");
4651
4708
  try {
4652
- execFileSync9("git", ["add", stateRel], { cwd: ctx.cwd, stdio: "pipe" });
4709
+ execFileSync10("git", ["add", stateRel], { cwd: ctx.cwd, stdio: "pipe" });
4653
4710
  } catch (err) {
4654
4711
  process.stderr.write(
4655
4712
  `[goal-tick] commitGoalState: git add failed: ${err instanceof Error ? err.message : String(err)}
@@ -4658,13 +4715,13 @@ var commitGoalState = async (ctx) => {
4658
4715
  return;
4659
4716
  }
4660
4717
  try {
4661
- execFileSync9("git", ["diff", "--cached", "--quiet"], { cwd: ctx.cwd, stdio: "pipe" });
4718
+ execFileSync10("git", ["diff", "--cached", "--quiet"], { cwd: ctx.cwd, stdio: "pipe" });
4662
4719
  return;
4663
4720
  } catch {
4664
4721
  }
4665
4722
  const msg = describeCommitMessage(goal);
4666
4723
  try {
4667
- execFileSync9("git", ["commit", "-m", msg, "--quiet"], { cwd: ctx.cwd, stdio: "pipe" });
4724
+ execFileSync10("git", ["commit", "-m", msg, "--quiet"], { cwd: ctx.cwd, stdio: "pipe" });
4668
4725
  } catch (err) {
4669
4726
  process.stderr.write(
4670
4727
  `[goal-tick] commitGoalState: git commit failed: ${err instanceof Error ? err.message : String(err)}
@@ -4672,10 +4729,10 @@ var commitGoalState = async (ctx) => {
4672
4729
  );
4673
4730
  return;
4674
4731
  }
4675
- try {
4676
- execFileSync9("git", ["push", "--quiet"], { cwd: ctx.cwd, stdio: "pipe" });
4677
- } catch {
4678
- process.stderr.write("[goal-tick] commitGoalState: push failed (will retry next tick)\n");
4732
+ const result = pushWithRetry({ cwd: ctx.cwd });
4733
+ if (!result.ok) {
4734
+ process.stderr.write(`[goal-tick] commitGoalState: push failed (${result.reason}); will retry next tick
4735
+ `);
4679
4736
  }
4680
4737
  };
4681
4738
  function describeCommitMessage(goal) {
@@ -4791,7 +4848,7 @@ function formatToolsUsage(profile) {
4791
4848
 
4792
4849
  // src/scripts/createQaGoal.ts
4793
4850
  init_issue();
4794
- import { execFileSync as execFileSync10 } from "child_process";
4851
+ import { execFileSync as execFileSync11 } from "child_process";
4795
4852
  import * as fs21 from "fs";
4796
4853
  import * as path20 from "path";
4797
4854
 
@@ -5063,7 +5120,7 @@ function writeStateFile(cwd, goalId, lastDispatchedIssue) {
5063
5120
  function gitTry(args, cwd) {
5064
5121
  const env = { ...process.env, SKIP_HOOKS: "1", HUSKY: "0" };
5065
5122
  try {
5066
- execFileSync10("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"], env });
5123
+ execFileSync11("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"], env });
5067
5124
  return { ok: true, stderr: "" };
5068
5125
  } catch (err) {
5069
5126
  const e = err;
@@ -5564,7 +5621,7 @@ function filterGoalTaskPrs(prs, taskIssueNumbers) {
5564
5621
  }
5565
5622
 
5566
5623
  // src/scripts/diagMcp.ts
5567
- import { execFileSync as execFileSync11 } from "child_process";
5624
+ import { execFileSync as execFileSync12 } from "child_process";
5568
5625
  import * as fs22 from "fs";
5569
5626
  import * as os4 from "os";
5570
5627
  import * as path21 from "path";
@@ -5584,7 +5641,7 @@ var diagMcp = async (_ctx) => {
5584
5641
  process.stderr.write(`[kody diag] chromium present: ${hasChromium ? "yes" : "no"}
5585
5642
  `);
5586
5643
  try {
5587
- const v = execFileSync11("npx", ["-y", "--package=@playwright/mcp@latest", "--", "playwright-mcp", "--version"], {
5644
+ const v = execFileSync12("npx", ["-y", "--package=@playwright/mcp@latest", "--", "playwright-mcp", "--version"], {
5588
5645
  stdio: "pipe",
5589
5646
  timeout: 6e4,
5590
5647
  encoding: "utf8"
@@ -6086,7 +6143,7 @@ var discoverQaContext = async (ctx) => {
6086
6143
  };
6087
6144
 
6088
6145
  // src/scripts/dispatch.ts
6089
- import { execFileSync as execFileSync12 } from "child_process";
6146
+ import { execFileSync as execFileSync13 } from "child_process";
6090
6147
  var API_TIMEOUT_MS4 = 3e4;
6091
6148
  var dispatch = async (ctx, _profile, _agentResult, args) => {
6092
6149
  const next = args?.next;
@@ -6122,7 +6179,7 @@ var dispatch = async (ctx, _profile, _agentResult, args) => {
6122
6179
  const sub = usePr ? "pr" : "issue";
6123
6180
  const body = `@kody ${next}`;
6124
6181
  try {
6125
- execFileSync12("gh", [sub, "comment", String(targetNumber), "--body", body], {
6182
+ execFileSync13("gh", [sub, "comment", String(targetNumber), "--body", body], {
6126
6183
  timeout: API_TIMEOUT_MS4,
6127
6184
  cwd: ctx.cwd,
6128
6185
  stdio: ["ignore", "pipe", "pipe"]
@@ -6142,7 +6199,7 @@ function parsePr(url) {
6142
6199
  }
6143
6200
 
6144
6201
  // src/scripts/dispatchClassified.ts
6145
- import { execFileSync as execFileSync13 } from "child_process";
6202
+ import { execFileSync as execFileSync14 } from "child_process";
6146
6203
  var API_TIMEOUT_MS5 = 3e4;
6147
6204
  var VALID_CLASSES2 = /* @__PURE__ */ new Set(["feature", "bug", "spec", "chore"]);
6148
6205
  var dispatchClassified = async (ctx) => {
@@ -6166,7 +6223,7 @@ ${auditLine}
6166
6223
 
6167
6224
  ${stateBody}`;
6168
6225
  try {
6169
- execFileSync13("gh", ["issue", "comment", String(issueNumber), "--body", body], {
6226
+ execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", body], {
6170
6227
  cwd: ctx.cwd,
6171
6228
  timeout: API_TIMEOUT_MS5,
6172
6229
  stdio: ["ignore", "pipe", "pipe"]
@@ -7263,7 +7320,7 @@ var finalizeTerminal = async (ctx) => {
7263
7320
 
7264
7321
  // src/scripts/finishFlow.ts
7265
7322
  init_issue();
7266
- import { execFileSync as execFileSync14 } from "child_process";
7323
+ import { execFileSync as execFileSync15 } from "child_process";
7267
7324
  var TERMINAL_PHASE = {
7268
7325
  "review-passed": { phase: "shipped", status: "succeeded" },
7269
7326
  "fix-applied": { phase: "shipped", status: "succeeded" },
@@ -7303,7 +7360,7 @@ var finishFlow = async (ctx, profile, _agentResult, args) => {
7303
7360
  **PR:** ${state.core.prUrl}` : "";
7304
7361
  const body = `${icon} kody flow \`${flowName}\` finished \u2014 \`${reason}\`${prSuffix}`;
7305
7362
  try {
7306
- execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", body], {
7363
+ execFileSync15("gh", ["issue", "comment", String(issueNumber), "--body", body], {
7307
7364
  timeout: API_TIMEOUT_MS6,
7308
7365
  cwd: ctx.cwd,
7309
7366
  stdio: ["ignore", "pipe", "pipe"]
@@ -7333,9 +7390,9 @@ var finishFlow = async (ctx, profile, _agentResult, args) => {
7333
7390
  };
7334
7391
 
7335
7392
  // src/branch.ts
7336
- import { execFileSync as execFileSync15 } from "child_process";
7393
+ import { execFileSync as execFileSync16 } from "child_process";
7337
7394
  function git2(args, cwd) {
7338
- return execFileSync15("git", args, {
7395
+ return execFileSync16("git", args, {
7339
7396
  encoding: "utf-8",
7340
7397
  timeout: 3e4,
7341
7398
  cwd,
@@ -7352,11 +7409,11 @@ function getCurrentBranch(cwd) {
7352
7409
  }
7353
7410
  function resetWorkingTree(cwd) {
7354
7411
  try {
7355
- execFileSync15("git", ["reset", "--hard", "HEAD"], { cwd, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7412
+ execFileSync16("git", ["reset", "--hard", "HEAD"], { cwd, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7356
7413
  } catch {
7357
7414
  }
7358
7415
  try {
7359
- execFileSync15("git", ["clean", "-fd"], { cwd, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7416
+ execFileSync16("git", ["clean", "-fd"], { cwd, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7360
7417
  } catch {
7361
7418
  }
7362
7419
  }
@@ -7368,14 +7425,14 @@ function checkoutPrBranch(prNumber, cwd) {
7368
7425
  GH_TOKEN: process.env.GH_PAT?.trim() || process.env.GH_TOKEN || ""
7369
7426
  };
7370
7427
  try {
7371
- execFileSync15("git", ["reset", "--hard", "HEAD"], { cwd, env, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7428
+ execFileSync16("git", ["reset", "--hard", "HEAD"], { cwd, env, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7372
7429
  } catch {
7373
7430
  }
7374
7431
  try {
7375
- execFileSync15("git", ["clean", "-fd"], { cwd, env, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7432
+ execFileSync16("git", ["clean", "-fd"], { cwd, env, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7376
7433
  } catch {
7377
7434
  }
7378
- execFileSync15("gh", ["pr", "checkout", String(prNumber)], {
7435
+ execFileSync16("gh", ["pr", "checkout", String(prNumber)], {
7379
7436
  cwd,
7380
7437
  env,
7381
7438
  stdio: ["ignore", "pipe", "pipe"],
@@ -7501,7 +7558,7 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch2, cwd, baseBranch
7501
7558
  }
7502
7559
 
7503
7560
  // src/gha.ts
7504
- import { execFileSync as execFileSync16 } from "child_process";
7561
+ import { execFileSync as execFileSync17 } from "child_process";
7505
7562
  import * as fs27 from "fs";
7506
7563
  function getRunUrl() {
7507
7564
  const server = process.env.GITHUB_SERVER_URL;
@@ -7544,7 +7601,7 @@ function reactToTriggerComment(cwd) {
7544
7601
  for (let attempt = 0; attempt < 3; attempt++) {
7545
7602
  if (attempt > 0) sleepMs(attempt === 1 ? 500 : 1500);
7546
7603
  try {
7547
- execFileSync16("gh", args, opts);
7604
+ execFileSync17("gh", args, opts);
7548
7605
  return;
7549
7606
  } catch (err) {
7550
7607
  lastErr = err;
@@ -7557,7 +7614,7 @@ function reactToTriggerComment(cwd) {
7557
7614
  }
7558
7615
  function sleepMs(ms) {
7559
7616
  try {
7560
- execFileSync16("sleep", [(ms / 1e3).toString()], { stdio: "ignore", timeout: ms + 1e3 });
7617
+ execFileSync17("sleep", [(ms / 1e3).toString()], { stdio: "ignore", timeout: ms + 1e3 });
7561
7618
  } catch {
7562
7619
  }
7563
7620
  }
@@ -7566,7 +7623,7 @@ function sleepMs(ms) {
7566
7623
  init_issue();
7567
7624
 
7568
7625
  // src/workflow.ts
7569
- import { execFileSync as execFileSync17 } from "child_process";
7626
+ import { execFileSync as execFileSync18 } from "child_process";
7570
7627
  var GH_TIMEOUT_MS = 3e4;
7571
7628
  function ghToken3() {
7572
7629
  return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
@@ -7574,7 +7631,7 @@ function ghToken3() {
7574
7631
  function gh3(args, cwd) {
7575
7632
  const token = ghToken3();
7576
7633
  const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
7577
- return execFileSync17("gh", args, {
7634
+ return execFileSync18("gh", args, {
7578
7635
  encoding: "utf-8",
7579
7636
  timeout: GH_TIMEOUT_MS,
7580
7637
  cwd,
@@ -7808,7 +7865,7 @@ var handleAbandonedGoal = async (ctx) => {
7808
7865
  };
7809
7866
 
7810
7867
  // src/scripts/initFlow.ts
7811
- import { execFileSync as execFileSync18 } from "child_process";
7868
+ import { execFileSync as execFileSync19 } from "child_process";
7812
7869
  import * as fs29 from "fs";
7813
7870
  import * as path27 from "path";
7814
7871
 
@@ -7849,7 +7906,7 @@ function qualityCommandsFor(pm) {
7849
7906
  function detectOwnerRepo(cwd) {
7850
7907
  let url;
7851
7908
  try {
7852
- url = execFileSync18("git", ["remote", "get-url", "origin"], {
7909
+ url = execFileSync19("git", ["remote", "get-url", "origin"], {
7853
7910
  cwd,
7854
7911
  encoding: "utf-8",
7855
7912
  stdio: ["ignore", "pipe", "pipe"]
@@ -7934,7 +7991,7 @@ jobs:
7934
7991
  `;
7935
7992
  function defaultBranchFromGit(cwd) {
7936
7993
  try {
7937
- const ref = execFileSync18("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
7994
+ const ref = execFileSync19("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
7938
7995
  cwd,
7939
7996
  encoding: "utf-8",
7940
7997
  stdio: ["ignore", "pipe", "pipe"]
@@ -7942,7 +7999,7 @@ function defaultBranchFromGit(cwd) {
7942
7999
  return ref.replace("refs/remotes/origin/", "");
7943
8000
  } catch {
7944
8001
  try {
7945
- return execFileSync18("git", ["branch", "--show-current"], {
8002
+ return execFileSync19("git", ["branch", "--show-current"], {
7946
8003
  cwd,
7947
8004
  encoding: "utf-8",
7948
8005
  stdio: ["ignore", "pipe", "pipe"]
@@ -8484,7 +8541,7 @@ var markFlowSuccess = async (ctx) => {
8484
8541
  };
8485
8542
 
8486
8543
  // src/scripts/mergeReleasePr.ts
8487
- import { execFileSync as execFileSync19 } from "child_process";
8544
+ import { execFileSync as execFileSync20 } from "child_process";
8488
8545
  var API_TIMEOUT_MS7 = 6e4;
8489
8546
  var mergeReleasePr = async (ctx) => {
8490
8547
  const state = ctx.data.taskState;
@@ -8503,7 +8560,7 @@ var mergeReleasePr = async (ctx) => {
8503
8560
  process.stderr.write(`[kody mergeReleasePr] merging PR #${prNumber} (${prUrl})
8504
8561
  `);
8505
8562
  try {
8506
- const out = execFileSync19("gh", ["pr", "merge", String(prNumber), "--merge"], {
8563
+ const out = execFileSync20("gh", ["pr", "merge", String(prNumber), "--merge"], {
8507
8564
  timeout: API_TIMEOUT_MS7,
8508
8565
  cwd: ctx.cwd,
8509
8566
  stdio: ["ignore", "pipe", "pipe"]
@@ -9138,7 +9195,7 @@ ${body}`;
9138
9195
  }
9139
9196
 
9140
9197
  // src/scripts/recordClassification.ts
9141
- import { execFileSync as execFileSync20 } from "child_process";
9198
+ import { execFileSync as execFileSync21 } from "child_process";
9142
9199
  var API_TIMEOUT_MS8 = 3e4;
9143
9200
  var VALID_CLASSES3 = /* @__PURE__ */ new Set(["feature", "bug", "spec", "chore"]);
9144
9201
  var recordClassification = async (ctx) => {
@@ -9186,7 +9243,7 @@ function parseClassification(prSummary) {
9186
9243
  }
9187
9244
  function tryAuditComment(issueNumber, body, cwd) {
9188
9245
  try {
9189
- execFileSync20("gh", ["issue", "comment", String(issueNumber), "--body", body], {
9246
+ execFileSync21("gh", ["issue", "comment", String(issueNumber), "--body", body], {
9190
9247
  cwd,
9191
9248
  timeout: API_TIMEOUT_MS8,
9192
9249
  stdio: ["ignore", "pipe", "pipe"]
@@ -9300,7 +9357,7 @@ var resolveArtifacts = async (ctx, profile) => {
9300
9357
  };
9301
9358
 
9302
9359
  // src/scripts/resolveFlow.ts
9303
- import { execFileSync as execFileSync21 } from "child_process";
9360
+ import { execFileSync as execFileSync22 } from "child_process";
9304
9361
  init_issue();
9305
9362
  var CONFLICT_DIFF_MAX_BYTES = 4e4;
9306
9363
  var resolveFlow = async (ctx) => {
@@ -9394,7 +9451,7 @@ function buildPreferBlock(prefer, baseBranch) {
9394
9451
  }
9395
9452
  function getConflictedFiles(cwd) {
9396
9453
  try {
9397
- const out = execFileSync21("git", ["diff", "--name-only", "--diff-filter=U"], {
9454
+ const out = execFileSync22("git", ["diff", "--name-only", "--diff-filter=U"], {
9398
9455
  encoding: "utf-8",
9399
9456
  cwd,
9400
9457
  env: { ...process.env, HUSKY: "0" }
@@ -9409,7 +9466,7 @@ function getConflictMarkersPreview(files, cwd, maxBytes = CONFLICT_DIFF_MAX_BYTE
9409
9466
  let total = 0;
9410
9467
  for (const f of files) {
9411
9468
  try {
9412
- const content = execFileSync21("cat", [f], { encoding: "utf-8", cwd }).toString();
9469
+ const content = execFileSync22("cat", [f], { encoding: "utf-8", cwd }).toString();
9413
9470
  const snippet = `### ${f}
9414
9471
 
9415
9472
  \`\`\`
@@ -9433,12 +9490,12 @@ function tryPostPr3(prNumber, body, cwd) {
9433
9490
  function pushEmptyCommit(branch, cwd) {
9434
9491
  const env = { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" };
9435
9492
  try {
9436
- execFileSync21(
9493
+ execFileSync22(
9437
9494
  "git",
9438
9495
  ["commit", "--allow-empty", "-m", "chore: kody resolve refresh \u2014 empty commit to recompute mergeable status"],
9439
9496
  { cwd, env, stdio: ["ignore", "pipe", "pipe"] }
9440
9497
  );
9441
- execFileSync21("git", ["push", "-u", "origin", branch], {
9498
+ execFileSync22("git", ["push", "-u", "origin", branch], {
9442
9499
  cwd,
9443
9500
  env,
9444
9501
  stdio: ["ignore", "pipe", "pipe"]
@@ -9529,10 +9586,10 @@ var resolvePreviewUrl = async (ctx) => {
9529
9586
  };
9530
9587
 
9531
9588
  // src/scripts/resolveQaUrl.ts
9532
- import { execFileSync as execFileSync22 } from "child_process";
9589
+ import { execFileSync as execFileSync23 } from "child_process";
9533
9590
  function ghQuery(args, cwd) {
9534
9591
  try {
9535
- const out = execFileSync22("gh", args, {
9592
+ const out = execFileSync23("gh", args, {
9536
9593
  cwd,
9537
9594
  stdio: ["ignore", "pipe", "pipe"],
9538
9595
  encoding: "utf-8",
@@ -9602,7 +9659,7 @@ var resolveQaUrl = async (ctx) => {
9602
9659
  };
9603
9660
 
9604
9661
  // src/scripts/revertFlow.ts
9605
- import { execFileSync as execFileSync23 } from "child_process";
9662
+ import { execFileSync as execFileSync24 } from "child_process";
9606
9663
  init_issue();
9607
9664
  var SHA_RE = /^[0-9a-f]{4,40}$/i;
9608
9665
  var revertFlow = async (ctx) => {
@@ -9685,7 +9742,7 @@ function buildPrSummary(resolved) {
9685
9742
  return resolved.map((r) => `- Reverted \`${r.full.slice(0, 7)}\`${r.subject ? ` \u2014 ${r.subject}` : ""}`).join("\n");
9686
9743
  }
9687
9744
  function git3(args, cwd) {
9688
- return execFileSync23("git", args, {
9745
+ return execFileSync24("git", args, {
9689
9746
  encoding: "utf-8",
9690
9747
  timeout: 3e4,
9691
9748
  cwd,
@@ -9695,7 +9752,7 @@ function git3(args, cwd) {
9695
9752
  }
9696
9753
  function isAncestorOfHead(sha, cwd) {
9697
9754
  try {
9698
- execFileSync23("git", ["merge-base", "--is-ancestor", sha, "HEAD"], {
9755
+ execFileSync24("git", ["merge-base", "--is-ancestor", sha, "HEAD"], {
9699
9756
  cwd,
9700
9757
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
9701
9758
  stdio: ["ignore", "ignore", "ignore"]
@@ -10114,11 +10171,11 @@ var skipAgent = async (ctx) => {
10114
10171
  };
10115
10172
 
10116
10173
  // src/scripts/stageMergeConflicts.ts
10117
- import { execFileSync as execFileSync24 } from "child_process";
10174
+ import { execFileSync as execFileSync25 } from "child_process";
10118
10175
  var stageMergeConflicts = async (ctx) => {
10119
10176
  if (ctx.data.agentDone === false) return;
10120
10177
  try {
10121
- execFileSync24("git", ["add", "-A"], {
10178
+ execFileSync25("git", ["add", "-A"], {
10122
10179
  cwd: ctx.cwd,
10123
10180
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
10124
10181
  stdio: "pipe"
@@ -10129,7 +10186,7 @@ var stageMergeConflicts = async (ctx) => {
10129
10186
 
10130
10187
  // src/scripts/startFlow.ts
10131
10188
  init_issue();
10132
- import { execFileSync as execFileSync25 } from "child_process";
10189
+ import { execFileSync as execFileSync26 } from "child_process";
10133
10190
  var API_TIMEOUT_MS9 = 3e4;
10134
10191
  var startFlow = async (ctx, profile, _agentResult, args) => {
10135
10192
  const entry = args?.entry;
@@ -10163,7 +10220,7 @@ function postKodyComment(target, issueNumber, state, next, cwd) {
10163
10220
  const sub = target === "pr" && state?.core.prUrl ? "pr" : "issue";
10164
10221
  const body = `@kody ${next}`;
10165
10222
  try {
10166
- execFileSync25("gh", [sub, "comment", String(targetNumber), "--body", body], {
10223
+ execFileSync26("gh", [sub, "comment", String(targetNumber), "--body", body], {
10167
10224
  timeout: API_TIMEOUT_MS9,
10168
10225
  cwd,
10169
10226
  stdio: ["ignore", "pipe", "pipe"]
@@ -10177,7 +10234,7 @@ function postKodyComment(target, issueNumber, state, next, cwd) {
10177
10234
  }
10178
10235
 
10179
10236
  // src/scripts/syncFlow.ts
10180
- import { execFileSync as execFileSync26 } from "child_process";
10237
+ import { execFileSync as execFileSync27 } from "child_process";
10181
10238
  init_issue();
10182
10239
  var syncFlow = async (ctx, _profile, args) => {
10183
10240
  const announceOnSuccess = Boolean(args?.announceOnSuccess);
@@ -10242,21 +10299,15 @@ function bail2(ctx, prNumber, reason) {
10242
10299
  }
10243
10300
  function revParseHead(cwd) {
10244
10301
  try {
10245
- return execFileSync26("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
10302
+ return execFileSync27("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
10246
10303
  } catch {
10247
10304
  return "";
10248
10305
  }
10249
10306
  }
10250
10307
  function pushBranch(branch, cwd) {
10251
- const env = { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" };
10252
- try {
10253
- execFileSync26("git", ["push", "-u", "origin", branch], { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
10254
- } catch {
10255
- execFileSync26("git", ["push", "--force-with-lease", "-u", "origin", branch], {
10256
- cwd,
10257
- env,
10258
- stdio: ["ignore", "pipe", "pipe"]
10259
- });
10308
+ const result = pushWithRetry({ cwd: cwd ?? process.cwd(), branch, setUpstream: true });
10309
+ if (!result.ok) {
10310
+ throw new Error(result.reason);
10260
10311
  }
10261
10312
  }
10262
10313
  function tryPostPr6(prNumber, body, cwd) {
@@ -10505,7 +10556,7 @@ var verifyWithRetry = async (ctx) => {
10505
10556
 
10506
10557
  // src/scripts/waitForCi.ts
10507
10558
  init_issue();
10508
- import { execFileSync as execFileSync27 } from "child_process";
10559
+ import { execFileSync as execFileSync28 } from "child_process";
10509
10560
  var API_TIMEOUT_MS10 = 3e4;
10510
10561
  var waitForCi = async (ctx, _profile, _agentResult, args) => {
10511
10562
  const timeoutMinutes = numArg(args, "timeoutMinutes", 30);
@@ -10583,7 +10634,7 @@ var waitForCi = async (ctx, _profile, _agentResult, args) => {
10583
10634
  };
10584
10635
  function fetchChecks(prNumber, cwd) {
10585
10636
  try {
10586
- const raw = execFileSync27("gh", ["pr", "checks", String(prNumber), "--json", "bucket,state,name,workflow,link"], {
10637
+ const raw = execFileSync28("gh", ["pr", "checks", String(prNumber), "--json", "bucket,state,name,workflow,link"], {
10587
10638
  encoding: "utf-8",
10588
10639
  timeout: API_TIMEOUT_MS10,
10589
10640
  cwd,
@@ -10962,7 +11013,7 @@ var allScriptNames = /* @__PURE__ */ new Set([
10962
11013
  ]);
10963
11014
 
10964
11015
  // src/tools.ts
10965
- import { execFileSync as execFileSync28 } from "child_process";
11016
+ import { execFileSync as execFileSync29 } from "child_process";
10966
11017
  function verifyCliTools(tools, cwd) {
10967
11018
  const out = [];
10968
11019
  for (const t of tools) out.push(verifyOne(t, cwd));
@@ -10995,7 +11046,7 @@ function verifyOne(tool2, cwd) {
10995
11046
  }
10996
11047
  function runShell(cmd, cwd, timeoutMs = 3e4) {
10997
11048
  try {
10998
- execFileSync28("sh", ["-c", cmd], { cwd, stdio: "pipe", timeout: timeoutMs });
11049
+ execFileSync29("sh", ["-c", cmd], { cwd, stdio: "pipe", timeout: timeoutMs });
10999
11050
  return true;
11000
11051
  } catch {
11001
11052
  return false;
@@ -11759,7 +11810,7 @@ async function runContainerLoop(profile, ctx, input) {
11759
11810
  }
11760
11811
  function resetWorkingTree2(cwd) {
11761
11812
  try {
11762
- execFileSync29("git", ["reset", "--hard", "HEAD"], {
11813
+ execFileSync30("git", ["reset", "--hard", "HEAD"], {
11763
11814
  cwd,
11764
11815
  stdio: ["ignore", "pipe", "pipe"],
11765
11816
  timeout: 3e4
@@ -11918,7 +11969,7 @@ function detectPackageManager2(cwd) {
11918
11969
  }
11919
11970
  function shellOut(cmd, args, cwd, stream = true) {
11920
11971
  try {
11921
- execFileSync30(cmd, args, {
11972
+ execFileSync31(cmd, args, {
11922
11973
  cwd,
11923
11974
  stdio: stream ? "inherit" : "pipe",
11924
11975
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" }
@@ -11931,7 +11982,7 @@ function shellOut(cmd, args, cwd, stream = true) {
11931
11982
  }
11932
11983
  function isOnPath(bin) {
11933
11984
  try {
11934
- execFileSync30("which", [bin], { stdio: "pipe" });
11985
+ execFileSync31("which", [bin], { stdio: "pipe" });
11935
11986
  return true;
11936
11987
  } catch {
11937
11988
  return false;
@@ -11972,7 +12023,7 @@ function installLitellmIfNeeded(cwd) {
11972
12023
  } catch {
11973
12024
  }
11974
12025
  try {
11975
- execFileSync30("python3", ["-c", "import litellm"], { stdio: "pipe" });
12026
+ execFileSync31("python3", ["-c", "import litellm"], { stdio: "pipe" });
11976
12027
  process.stdout.write("\u2192 kody: litellm already installed\n");
11977
12028
  return 0;
11978
12029
  } catch {
@@ -11982,16 +12033,16 @@ function installLitellmIfNeeded(cwd) {
11982
12033
  }
11983
12034
  function configureGitIdentity(cwd) {
11984
12035
  try {
11985
- const name = execFileSync30("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
12036
+ const name = execFileSync31("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
11986
12037
  if (name) return;
11987
12038
  } catch {
11988
12039
  }
11989
12040
  try {
11990
- execFileSync30("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
12041
+ execFileSync31("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
11991
12042
  } catch {
11992
12043
  }
11993
12044
  try {
11994
- execFileSync30("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
12045
+ execFileSync31("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
11995
12046
  cwd,
11996
12047
  stdio: "pipe"
11997
12048
  });
@@ -12302,17 +12353,26 @@ function parseChatArgs(argv, env = process.env) {
12302
12353
  function commitChatFiles(cwd, sessionId, verbose) {
12303
12354
  const sessionFile = path36.relative(cwd, sessionFilePath(cwd, sessionId));
12304
12355
  const eventsFile = path36.relative(cwd, eventsFilePath(cwd, sessionId));
12305
- const paths = [sessionFile, eventsFile].filter((p) => fs39.existsSync(path36.join(cwd, p)));
12356
+ const safeSession = sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
12357
+ const tasksDir = path36.join(".kody", "tasks", safeSession);
12358
+ const candidatePaths = [sessionFile, eventsFile, tasksDir];
12359
+ const paths = candidatePaths.filter((p) => fs39.existsSync(path36.join(cwd, p)));
12306
12360
  if (paths.length === 0) return;
12307
12361
  const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
12308
12362
  try {
12309
- execFileSync31("git", ["add", "-f", ...paths], opts);
12310
- execFileSync31("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
12311
- execFileSync31("git", ["push", "--quiet", "origin", "HEAD"], opts);
12363
+ execFileSync32("git", ["add", "-f", ...paths], opts);
12364
+ execFileSync32("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
12312
12365
  } catch (err) {
12313
12366
  const msg = err instanceof Error ? err.message : String(err);
12314
- process.stderr.write(`[kody:chat] commit/push skipped: ${msg}
12367
+ process.stderr.write(`[kody:chat] commit skipped: ${msg}
12368
+ `);
12369
+ return;
12370
+ }
12371
+ const result = pushWithRetry({ cwd });
12372
+ if (!result.ok) {
12373
+ process.stderr.write(`[kody:chat] push FAILED after ${result.attempts} attempt(s): ${result.reason}
12315
12374
  `);
12375
+ throw new Error(`chat push failed: ${result.reason}`);
12316
12376
  }
12317
12377
  }
12318
12378
  function tryLoadConfig(cwd) {
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.99",
4
- "description": "kody autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
3
+ "version": "0.4.100",
4
+ "description": "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "bin": {
@@ -12,6 +12,23 @@
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
+ "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,21 +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:run": "tsx bin/kody.ts",
39
- "serve": "tsx bin/kody.ts serve",
40
- "serve:vscode": "tsx bin/kody.ts serve vscode",
41
- "serve:claude": "tsx bin/kody.ts serve claude",
42
- "build": "tsup && node scripts/copy-assets.cjs",
43
- "check:modularity": "tsx scripts/check-script-modularity.ts",
44
- "pretest": "pnpm check:modularity",
45
- "test": "vitest run tests/unit tests/int --no-coverage",
46
- "test:e2e": "vitest run tests/e2e --no-coverage",
47
- "test:all": "vitest run tests --no-coverage",
48
- "typecheck": "tsc --noEmit",
49
- "lint": "biome check",
50
- "lint:fix": "biome check --write",
51
- "format": "biome format --write"
52
- }
53
- }
53
+ "bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
54
+ }