@kody-ade/kody-engine 0.3.77 → 0.3.79

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 +84 -17
  2. package/package.json +1 -1
package/dist/bin/kody.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // package.json
4
4
  var package_default = {
5
5
  name: "@kody-ade/kody-engine",
6
- version: "0.3.77",
6
+ version: "0.3.79",
7
7
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
8
8
  license: "MIT",
9
9
  type: "module",
@@ -51,7 +51,7 @@ var package_default = {
51
51
  };
52
52
 
53
53
  // src/chat-cli.ts
54
- import { execFileSync as execFileSync28 } from "child_process";
54
+ import { execFileSync as execFileSync29 } from "child_process";
55
55
  import * as fs28 from "fs";
56
56
  import * as path25 from "path";
57
57
 
@@ -731,13 +731,27 @@ async function runInteractiveMode(opts) {
731
731
  const hardCapMs = opts.meta.hardCapMs ?? DEFAULT_HARD_CAP_MS;
732
732
  const startedAt = Date.now();
733
733
  const deadlineMs = startedAt + hardCapMs;
734
+ const runId = process.env.GITHUB_RUN_ID;
735
+ const repository = process.env.GITHUB_REPOSITORY;
736
+ const serverUrl = process.env.GITHUB_SERVER_URL ?? "https://github.com";
737
+ const runUrl = runId && repository ? `${serverUrl}/${repository}/actions/runs/${runId}` : void 0;
738
+ process.stdout.write(`\u2192 kody:chat:interactive: emitting chat.ready (idleExitMs=${idleExitMs}, hardCapMs=${hardCapMs}, runUrl=${runUrl ?? "n/a"})
739
+ `);
734
740
  await emit2(opts.sink, "chat.ready", opts.sessionId, "ready", {
735
741
  sessionId: opts.sessionId,
736
742
  startedAt: new Date(startedAt).toISOString(),
737
743
  idleExitMs,
738
- hardCapMs
744
+ hardCapMs,
745
+ ...runId ? { runId } : {},
746
+ ...runUrl ? { runUrl } : {}
739
747
  });
740
- if (!opts.skipGit) commitTurn(opts.cwd, opts.sessionId, opts.verbose ?? false);
748
+ if (!opts.skipGit) {
749
+ process.stdout.write(`\u2192 kody:chat:interactive: committing chat.ready event to git
750
+ `);
751
+ commitTurn(opts.cwd, opts.sessionId, opts.verbose ?? false);
752
+ process.stdout.write(`\u2192 kody:chat:interactive: chat.ready committed; entering poll loop
753
+ `);
754
+ }
741
755
  let watermark = 0;
742
756
  let turnsCompleted = 0;
743
757
  while (true) {
@@ -834,7 +848,7 @@ async function emit2(sink, type, sessionId, suffix, payload) {
834
848
  }
835
849
 
836
850
  // src/kody-cli.ts
837
- import { execFileSync as execFileSync27 } from "child_process";
851
+ import { execFileSync as execFileSync28 } from "child_process";
838
852
  import * as fs27 from "fs";
839
853
  import * as path24 from "path";
840
854
 
@@ -1195,7 +1209,7 @@ function coerceBare(spec, value) {
1195
1209
  }
1196
1210
 
1197
1211
  // src/executor.ts
1198
- import { spawn as spawn3 } from "child_process";
1212
+ import { execFileSync as execFileSync27, spawn as spawn3 } from "child_process";
1199
1213
  import * as fs26 from "fs";
1200
1214
  import * as path23 from "path";
1201
1215
 
@@ -7539,6 +7553,7 @@ async function runContainerLoop(profile, ctx, input) {
7539
7553
  const child = children[currentIdx];
7540
7554
  process.stderr.write(`[kody container] step ${iteration}: invoking ${child.exec}
7541
7555
  `);
7556
+ resetWorkingTree(input.cwd);
7542
7557
  const priorState = readContainerState(ctx, child, reader);
7543
7558
  if (priorState.core?.prUrl) knownPrUrl = priorState.core.prUrl;
7544
7559
  const priorAction = priorState.executables?.[child.exec]?.lastAction;
@@ -7595,11 +7610,40 @@ async function runContainerLoop(profile, ctx, input) {
7595
7610
  ctx.output.reason = `child "${child.exec}" crashed: ${msg}`;
7596
7611
  return;
7597
7612
  }
7613
+ const priorAttempts = priorState.core?.attempts?.[child.exec] ?? 0;
7598
7614
  const next = readContainerState(ctx, child, reader);
7599
7615
  if (next.core?.prUrl) knownPrUrl = next.core.prUrl;
7616
+ const nextAttempts = next.core?.attempts?.[child.exec] ?? 0;
7617
+ const nextChildAction = next.executables?.[child.exec]?.lastAction;
7618
+ const childWrote = nextAttempts > priorAttempts && nextChildAction != null;
7619
+ if (childWrote && nextChildAction) {
7620
+ actionType = nextChildAction.type;
7621
+ } else {
7622
+ const childTag = child.exec.toUpperCase().replace(/-/g, "_");
7623
+ actionType = childOut.exitCode === 0 ? `${childTag}_COMPLETED` : `${childTag}_FAILED`;
7624
+ const synthetic = {
7625
+ type: actionType,
7626
+ payload: {
7627
+ synthesized: true,
7628
+ child: child.exec,
7629
+ exitCode: childOut.exitCode,
7630
+ reason: childOut.reason
7631
+ },
7632
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
7633
+ };
7634
+ if (!next.core) {
7635
+ next.core = {
7636
+ phase: "idle",
7637
+ status: "pending",
7638
+ currentExecutable: null,
7639
+ lastOutcome: synthetic,
7640
+ attempts: {}
7641
+ };
7642
+ } else {
7643
+ next.core.lastOutcome = synthetic;
7644
+ }
7645
+ }
7600
7646
  ctx.data.taskState = next;
7601
- const actionFromState = next.core?.lastOutcome?.type;
7602
- actionType = actionFromState ?? (childOut.exitCode === 0 ? "RUN_COMPLETED" : "RUN_FAILED");
7603
7647
  }
7604
7648
  const route = child.next[actionType] ?? child.next["*"];
7605
7649
  if (!route) {
@@ -7633,6 +7677,19 @@ async function runContainerLoop(profile, ctx, input) {
7633
7677
  currentIdx = nextIdx;
7634
7678
  }
7635
7679
  }
7680
+ function resetWorkingTree(cwd) {
7681
+ try {
7682
+ execFileSync27("git", ["reset", "--hard", "HEAD"], {
7683
+ cwd,
7684
+ stdio: ["ignore", "pipe", "pipe"],
7685
+ timeout: 3e4
7686
+ });
7687
+ } catch (err) {
7688
+ const msg = err instanceof Error ? err.message : String(err);
7689
+ process.stderr.write(`[kody container] working-tree reset skipped: ${msg}
7690
+ `);
7691
+ }
7692
+ }
7636
7693
  function readContainerState(ctx, child, reader) {
7637
7694
  const issueNumber = ctx.args.issue;
7638
7695
  const cached = ctx.data.taskState;
@@ -7781,7 +7838,7 @@ function detectPackageManager2(cwd) {
7781
7838
  }
7782
7839
  function shellOut(cmd, args, cwd, stream = true) {
7783
7840
  try {
7784
- execFileSync27(cmd, args, {
7841
+ execFileSync28(cmd, args, {
7785
7842
  cwd,
7786
7843
  stdio: stream ? "inherit" : "pipe",
7787
7844
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" }
@@ -7794,7 +7851,7 @@ function shellOut(cmd, args, cwd, stream = true) {
7794
7851
  }
7795
7852
  function isOnPath(bin) {
7796
7853
  try {
7797
- execFileSync27("which", [bin], { stdio: "pipe" });
7854
+ execFileSync28("which", [bin], { stdio: "pipe" });
7798
7855
  return true;
7799
7856
  } catch {
7800
7857
  return false;
@@ -7828,7 +7885,7 @@ function installLitellmIfNeeded(cwd) {
7828
7885
  } catch {
7829
7886
  }
7830
7887
  try {
7831
- execFileSync27("python3", ["-c", "import litellm"], { stdio: "pipe" });
7888
+ execFileSync28("python3", ["-c", "import litellm"], { stdio: "pipe" });
7832
7889
  process.stdout.write("\u2192 kody: litellm already installed\n");
7833
7890
  return 0;
7834
7891
  } catch {
@@ -7838,16 +7895,16 @@ function installLitellmIfNeeded(cwd) {
7838
7895
  }
7839
7896
  function configureGitIdentity(cwd) {
7840
7897
  try {
7841
- const name = execFileSync27("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
7898
+ const name = execFileSync28("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
7842
7899
  if (name) return;
7843
7900
  } catch {
7844
7901
  }
7845
7902
  try {
7846
- execFileSync27("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
7903
+ execFileSync28("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
7847
7904
  } catch {
7848
7905
  }
7849
7906
  try {
7850
- execFileSync27("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
7907
+ execFileSync28("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
7851
7908
  cwd,
7852
7909
  stdio: "pipe"
7853
7910
  });
@@ -8118,9 +8175,9 @@ function commitChatFiles(cwd, sessionId, verbose) {
8118
8175
  if (paths.length === 0) return;
8119
8176
  const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
8120
8177
  try {
8121
- execFileSync28("git", ["add", "-f", ...paths], opts);
8122
- execFileSync28("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
8123
- execFileSync28("git", ["push", "--quiet", "origin", "HEAD"], opts);
8178
+ execFileSync29("git", ["add", "-f", ...paths], opts);
8179
+ execFileSync29("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
8180
+ execFileSync29("git", ["push", "--quiet", "origin", "HEAD"], opts);
8124
8181
  } catch (err) {
8125
8182
  const msg = err instanceof Error ? err.message : String(err);
8126
8183
  process.stderr.write(`[kody:chat] commit/push skipped: ${msg}
@@ -8179,11 +8236,15 @@ ${CHAT_HELP}`);
8179
8236
  return 99;
8180
8237
  }
8181
8238
  }
8239
+ process.stdout.write(`\u2192 kody:chat: starting litellm proxy (model=${model.provider}/${model.model})
8240
+ `);
8182
8241
  let litellm = null;
8183
8242
  try {
8184
8243
  litellm = await startLitellmIfNeeded(model, cwd);
8185
8244
  } catch (err) {
8186
8245
  const msg = err instanceof Error ? err.message : String(err);
8246
+ process.stderr.write(`\u2192 kody:chat: litellm startup FAILED: ${msg}
8247
+ `);
8187
8248
  const sink2 = buildSink(cwd, sessionId, args.dashboardUrl);
8188
8249
  await sink2.emit({
8189
8250
  event: "chat.error",
@@ -8193,10 +8254,16 @@ ${CHAT_HELP}`);
8193
8254
  });
8194
8255
  return 99;
8195
8256
  }
8257
+ process.stdout.write(`\u2192 kody:chat: litellm proxy ready (url=${litellm?.url ?? "skipped"})
8258
+ `);
8196
8259
  const sessionFile = sessionFilePath(cwd, sessionId);
8197
8260
  if (args.initMessage) seedInitialMessage(sessionFile, args.initMessage);
8198
8261
  const sink = buildSink(cwd, sessionId, args.dashboardUrl);
8199
8262
  const meta = readMeta(sessionFile);
8263
+ process.stdout.write(
8264
+ `\u2192 kody:chat: session file=${sessionFile} exists=${fs28.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
8265
+ `
8266
+ );
8200
8267
  try {
8201
8268
  if (meta?.mode === "interactive") {
8202
8269
  const result2 = await runInteractiveMode({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.3.77",
3
+ "version": "0.3.79",
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",