@kody-ade/kody-engine 0.4.33 → 0.4.35

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 +105 -7
  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.4.33",
6
+ version: "0.4.35",
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",
@@ -1178,6 +1178,42 @@ function autoDispatch(opts) {
1178
1178
  }
1179
1179
  return { executable, cliArgs: args, target: targetNum };
1180
1180
  }
1181
+ function autoDispatchTyped(opts) {
1182
+ const legacy = autoDispatch(opts);
1183
+ if (legacy) return { kind: "route", ...legacy };
1184
+ const eventName = process.env.GITHUB_EVENT_NAME;
1185
+ const eventPath = process.env.GITHUB_EVENT_PATH;
1186
+ if (!eventName || !eventPath || !fs7.existsSync(eventPath)) {
1187
+ return { kind: "silent", reason: "no GHA event context" };
1188
+ }
1189
+ if (eventName !== "issue_comment") {
1190
+ return { kind: "silent", reason: `event ${eventName} has no comment to inspect` };
1191
+ }
1192
+ let event = {};
1193
+ try {
1194
+ event = JSON.parse(fs7.readFileSync(eventPath, "utf-8"));
1195
+ } catch {
1196
+ return { kind: "silent", reason: "GHA event payload unreadable" };
1197
+ }
1198
+ const rawBody = String(event.comment?.body ?? "");
1199
+ const authorLogin = String(event.comment?.user?.login ?? "");
1200
+ const authorType = String(event.comment?.user?.type ?? "");
1201
+ if (!rawBody.toLowerCase().includes("@kody")) {
1202
+ return { kind: "silent", reason: "comment does not mention @kody" };
1203
+ }
1204
+ if (authorLogin === "kody-bot" || authorType === "Bot") {
1205
+ return { kind: "silent", reason: `bot-authored comment (${authorLogin || authorType})` };
1206
+ }
1207
+ const targetNum = Number(event.issue?.number ?? 0);
1208
+ const isPr = !!event.issue?.pull_request;
1209
+ if (!targetNum) {
1210
+ return { kind: "silent", reason: "comment has no associated issue/PR number" };
1211
+ }
1212
+ const afterTag = extractAfterTag(rawBody.toLowerCase());
1213
+ const token = extractSubcommand(afterTag) ?? "";
1214
+ const available = listExecutables().map((e) => e.name).filter((n) => !n.startsWith("goal-") && !n.startsWith("job-")).sort();
1215
+ return { kind: "unrecognized", token, target: targetNum, isPr, available };
1216
+ }
1181
1217
  function dispatchScheduledWatches(opts) {
1182
1218
  const now = opts?.now ?? /* @__PURE__ */ new Date();
1183
1219
  const envWindow = Number(process.env.KODY_SCHEDULE_WINDOW_SEC);
@@ -1298,11 +1334,6 @@ function coerceBare(spec, value) {
1298
1334
  return value;
1299
1335
  }
1300
1336
 
1301
- // src/executor.ts
1302
- import { execFileSync as execFileSync30, spawn as spawn5 } from "child_process";
1303
- import * as fs28 from "fs";
1304
- import * as path26 from "path";
1305
-
1306
1337
  // src/issue.ts
1307
1338
  import { execFileSync as execFileSync3 } from "child_process";
1308
1339
  var API_TIMEOUT_MS = 3e4;
@@ -1444,6 +1475,11 @@ function postPrReviewComment(prNumber, body, cwd) {
1444
1475
  }
1445
1476
  }
1446
1477
 
1478
+ // src/executor.ts
1479
+ import { execFileSync as execFileSync30, spawn as spawn5 } from "child_process";
1480
+ import * as fs28 from "fs";
1481
+ import * as path26 from "path";
1482
+
1447
1483
  // src/profile.ts
1448
1484
  import * as fs8 from "fs";
1449
1485
  import * as path7 from "path";
@@ -8514,6 +8550,7 @@ function tryPostPr6(prNumber, body, cwd) {
8514
8550
  import { spawn as spawn2 } from "child_process";
8515
8551
  var TAIL_CHARS = 4e3;
8516
8552
  var COMMAND_TIMEOUT_MS = 10 * 60 * 1e3;
8553
+ var DEFAULT_TEST_RETRIES = 2;
8517
8554
  function runCommand(command, cwd) {
8518
8555
  return new Promise((resolve4) => {
8519
8556
  const start = Date.now();
@@ -8567,6 +8604,28 @@ async function verifyAll(config, cwd) {
8567
8604
  }
8568
8605
  return { ok: failed.length === 0, failed, details };
8569
8606
  }
8607
+ async function applyTestRetries(initial, testCommand, cwd, runner, testRetries = DEFAULT_TEST_RETRIES) {
8608
+ if (initial.ok) return { ...initial, recovered: [] };
8609
+ const recovered = [];
8610
+ const details = { ...initial.details };
8611
+ let failed = [...initial.failed];
8612
+ if (failed.includes("test") && testCommand && testRetries > 0) {
8613
+ for (let attempt = 1; attempt <= testRetries; attempt++) {
8614
+ const retry = await runner(testCommand, cwd);
8615
+ details[`test (retry ${attempt})`] = retry;
8616
+ if (retry.exitCode === 0) {
8617
+ failed = failed.filter((f) => f !== "test");
8618
+ recovered.push("test");
8619
+ break;
8620
+ }
8621
+ }
8622
+ }
8623
+ return { ok: failed.length === 0, failed, details, recovered };
8624
+ }
8625
+ async function verifyAllWithRetry(config, cwd, opts) {
8626
+ const initial = await verifyAll(config, cwd);
8627
+ return applyTestRetries(initial, config.quality.testUnit, cwd, runCommand, opts?.testRetries);
8628
+ }
8570
8629
  var ANSI_RE = /\x1B\[[0-?]*[ -/]*[@-~]/g;
8571
8630
  function stripAnsi(s) {
8572
8631
  return s.replace(ANSI_RE, "");
@@ -8579,6 +8638,13 @@ function summarizeFailure(result) {
8579
8638
  lines.push(`
8580
8639
  --- ${name} (exit ${d.exitCode}, ${(d.durationMs / 1e3).toFixed(1)}s) ---`);
8581
8640
  lines.push(stripAnsi(d.tail));
8641
+ for (let attempt = 1; ; attempt++) {
8642
+ const retry = result.details[`${name} (retry ${attempt})`];
8643
+ if (!retry) break;
8644
+ lines.push(`
8645
+ --- ${name} (retry ${attempt}: exit ${retry.exitCode}, ${(retry.durationMs / 1e3).toFixed(1)}s) ---`);
8646
+ lines.push(stripAnsi(retry.tail));
8647
+ }
8582
8648
  }
8583
8649
  return lines.join("\n");
8584
8650
  }
@@ -8586,9 +8652,16 @@ function summarizeFailure(result) {
8586
8652
  // src/scripts/verify.ts
8587
8653
  var verify = async (ctx) => {
8588
8654
  try {
8589
- const result = await verifyAll(ctx.config, ctx.cwd);
8655
+ const result = await verifyAllWithRetry(ctx.config, ctx.cwd);
8590
8656
  ctx.data.verifyOk = result.ok;
8591
8657
  ctx.data.verifyReason = result.ok ? "" : summarizeFailure(result);
8658
+ ctx.data.verifyRecovered = result.recovered ?? [];
8659
+ if (result.recovered && result.recovered.length > 0) {
8660
+ process.stderr.write(
8661
+ `[kody verify] caught flake on: ${result.recovered.join(", ")} (passed on retry)
8662
+ `
8663
+ );
8664
+ }
8592
8665
  } catch (err) {
8593
8666
  ctx.data.verifyOk = false;
8594
8667
  ctx.data.verifyReason = `verify crashed: ${err instanceof Error ? err.message : String(err)}`;
@@ -10063,6 +10136,31 @@ async function runCi(argv) {
10063
10136
  return runScheduledFanOut(cwd, args, { force: manualWorkflowDispatch });
10064
10137
  }
10065
10138
  if (!args.issueNumber && !autoFallback && process.env.GITHUB_EVENT_NAME) {
10139
+ const outcome = autoDispatchTyped({ config: earlyConfig });
10140
+ if (outcome.kind === "unrecognized") {
10141
+ const tokenLabel = outcome.token ? `\`${outcome.token}\`` : "an empty subcommand";
10142
+ const top = outcome.available.slice(0, 12).join(", ");
10143
+ const more = outcome.available.length > 12 ? `, \u2026 (${outcome.available.length - 12} more)` : "";
10144
+ const body = [
10145
+ `\u26A0\uFE0F kody: I don't recognize ${tokenLabel}.`,
10146
+ "",
10147
+ `Available subcommands: ${top}${more}`,
10148
+ "",
10149
+ "Examples: `@kody`, `@kody fix`, `@kody plan`, `@kody review`."
10150
+ ].join("\n");
10151
+ try {
10152
+ if (outcome.isPr) postPrReviewComment(outcome.target, body, cwd);
10153
+ else postIssueComment(outcome.target, body, cwd);
10154
+ } catch (err) {
10155
+ process.stderr.write(`[kody] dispatch: failed to post unrecognized-token feedback: ${err instanceof Error ? err.message : String(err)}
10156
+ `);
10157
+ }
10158
+ process.stdout.write(
10159
+ `\u2192 kody: unrecognized subcommand "${outcome.token}" on #${outcome.target} \u2014 feedback comment posted, exiting cleanly
10160
+ `
10161
+ );
10162
+ return 0;
10163
+ }
10066
10164
  process.stdout.write(`\u2192 kody: no action for event ${process.env.GITHUB_EVENT_NAME} \u2014 exiting cleanly
10067
10165
  `);
10068
10166
  return 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.33",
3
+ "version": "0.4.35",
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",