@kody-ade/kody-engine 0.3.6 → 0.3.7

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
@@ -3,7 +3,7 @@
3
3
  // package.json
4
4
  var package_default = {
5
5
  name: "@kody-ade/kody-engine",
6
- version: "0.3.6",
6
+ version: "0.3.7",
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",
@@ -50,9 +50,9 @@ var package_default = {
50
50
  };
51
51
 
52
52
  // src/chat-cli.ts
53
- import { execFileSync as execFileSync21 } from "child_process";
54
- import * as fs22 from "fs";
55
- import * as path19 from "path";
53
+ import { execFileSync as execFileSync22 } from "child_process";
54
+ import * as fs23 from "fs";
55
+ import * as path20 from "path";
56
56
 
57
57
  // src/chat/events.ts
58
58
  import * as fs from "fs";
@@ -263,7 +263,7 @@ function renderEvent(msg, opts = {}) {
263
263
  }
264
264
  switch (msg.type) {
265
265
  case "system":
266
- return null;
266
+ return formatSystemEvent(msg);
267
267
  case "assistant":
268
268
  return formatAssistant(msg, opts);
269
269
  case "user":
@@ -309,6 +309,14 @@ ${truncate(text, 4e3)}`);
309
309
  }
310
310
  return lines.length > 0 ? lines.join("\n") : null;
311
311
  }
312
+ function formatSystemEvent(msg) {
313
+ if (msg.subtype !== "init") return null;
314
+ const servers = msg.mcp_servers ?? [];
315
+ if (servers.length === 0) return null;
316
+ const lines = servers.map((s) => ` - ${s.name}: ${s.status ?? "unknown"}`);
317
+ return `[mcp servers]
318
+ ${lines.join("\n")}`;
319
+ }
312
320
  function formatResult(msg) {
313
321
  const ok = msg.subtype === "success";
314
322
  const tag = ok ? "SESSION ok" : `SESSION failed (${msg.subtype ?? "unknown"})`;
@@ -568,9 +576,9 @@ async function emit(sink, type, sessionId, suffix, payload) {
568
576
  }
569
577
 
570
578
  // src/kody-cli.ts
571
- import { execFileSync as execFileSync20 } from "child_process";
572
- import * as fs21 from "fs";
573
- import * as path18 from "path";
579
+ import { execFileSync as execFileSync21 } from "child_process";
580
+ import * as fs22 from "fs";
581
+ import * as path19 from "path";
574
582
 
575
583
  // src/dispatch.ts
576
584
  import * as fs6 from "fs";
@@ -787,8 +795,8 @@ function coerceBare(spec, value) {
787
795
  }
788
796
 
789
797
  // src/executor.ts
790
- import * as fs20 from "fs";
791
- import * as path17 from "path";
798
+ import * as fs21 from "fs";
799
+ import * as path18 from "path";
792
800
 
793
801
  // src/litellm.ts
794
802
  import { execFileSync, spawn } from "child_process";
@@ -2036,18 +2044,53 @@ function formatToolsUsage(profile) {
2036
2044
  return lines.join("\n");
2037
2045
  }
2038
2046
 
2047
+ // src/scripts/diagMcp.ts
2048
+ import { execFileSync as execFileSync7 } from "child_process";
2049
+ import * as fs13 from "fs";
2050
+ import * as os3 from "os";
2051
+ import * as path12 from "path";
2052
+ var diagMcp = async (_ctx) => {
2053
+ const home = os3.homedir();
2054
+ const cacheDir = path12.join(home, ".cache", "ms-playwright");
2055
+ let entries = [];
2056
+ try {
2057
+ entries = fs13.readdirSync(cacheDir);
2058
+ } catch {
2059
+ }
2060
+ const hasChromium = entries.some((e) => e.startsWith("chromium"));
2061
+ process.stderr.write(
2062
+ `[kody diag] ms-playwright cache: ${entries.length === 0 ? "EMPTY (or missing)" : entries.join(", ")}
2063
+ `
2064
+ );
2065
+ process.stderr.write(`[kody diag] chromium present: ${hasChromium ? "yes" : "no"}
2066
+ `);
2067
+ try {
2068
+ const v = execFileSync7("npx", ["-y", "@playwright/mcp@latest", "--version"], {
2069
+ stdio: "pipe",
2070
+ timeout: 6e4,
2071
+ encoding: "utf8"
2072
+ }).trim();
2073
+ process.stderr.write(`[kody diag] @playwright/mcp version: ${v}
2074
+ `);
2075
+ } catch (e) {
2076
+ const err = e instanceof Error ? e.message : String(e);
2077
+ process.stderr.write(`[kody diag] @playwright/mcp spawn FAILED: ${err}
2078
+ `);
2079
+ }
2080
+ };
2081
+
2039
2082
  // src/scripts/discoverQaContext.ts
2040
- import * as fs14 from "fs";
2041
- import * as path13 from "path";
2083
+ import * as fs15 from "fs";
2084
+ import * as path14 from "path";
2042
2085
 
2043
2086
  // src/scripts/frameworkDetectors.ts
2044
- import * as fs13 from "fs";
2045
- import * as path12 from "path";
2087
+ import * as fs14 from "fs";
2088
+ import * as path13 from "path";
2046
2089
  function detectFrameworks(cwd) {
2047
2090
  const out = [];
2048
2091
  let deps = {};
2049
2092
  try {
2050
- const pkg = JSON.parse(fs13.readFileSync(path12.join(cwd, "package.json"), "utf-8"));
2093
+ const pkg = JSON.parse(fs14.readFileSync(path13.join(cwd, "package.json"), "utf-8"));
2051
2094
  deps = { ...pkg.dependencies, ...pkg.devDependencies };
2052
2095
  } catch {
2053
2096
  return out;
@@ -2084,7 +2127,7 @@ function detectFrameworks(cwd) {
2084
2127
  }
2085
2128
  function findFile(cwd, candidates) {
2086
2129
  for (const c of candidates) {
2087
- if (fs13.existsSync(path12.join(cwd, c))) return c;
2130
+ if (fs14.existsSync(path13.join(cwd, c))) return c;
2088
2131
  }
2089
2132
  return null;
2090
2133
  }
@@ -2097,18 +2140,18 @@ var COLLECTION_DIRS = [
2097
2140
  function discoverPayloadCollections(cwd) {
2098
2141
  const out = [];
2099
2142
  for (const dir of COLLECTION_DIRS) {
2100
- const full = path12.join(cwd, dir);
2101
- if (!fs13.existsSync(full)) continue;
2143
+ const full = path13.join(cwd, dir);
2144
+ if (!fs14.existsSync(full)) continue;
2102
2145
  let files;
2103
2146
  try {
2104
- files = fs13.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
2147
+ files = fs14.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
2105
2148
  } catch {
2106
2149
  continue;
2107
2150
  }
2108
2151
  for (const file of files) {
2109
2152
  try {
2110
- const filePath = path12.join(full, file);
2111
- const content = fs13.readFileSync(filePath, "utf-8").slice(0, 1e4);
2153
+ const filePath = path13.join(full, file);
2154
+ const content = fs14.readFileSync(filePath, "utf-8").slice(0, 1e4);
2112
2155
  const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
2113
2156
  if (!slugMatch) continue;
2114
2157
  const slug = slugMatch[1];
@@ -2122,7 +2165,7 @@ function discoverPayloadCollections(cwd) {
2122
2165
  out.push({
2123
2166
  name,
2124
2167
  slug,
2125
- filePath: path12.relative(cwd, filePath),
2168
+ filePath: path13.relative(cwd, filePath),
2126
2169
  fields: fields.slice(0, 20),
2127
2170
  hasAdmin
2128
2171
  });
@@ -2136,28 +2179,28 @@ var ADMIN_COMPONENT_DIRS = ["src/ui/admin", "src/admin/components", "src/compone
2136
2179
  function discoverAdminComponents(cwd, collections) {
2137
2180
  const out = [];
2138
2181
  for (const dir of ADMIN_COMPONENT_DIRS) {
2139
- const full = path12.join(cwd, dir);
2140
- if (!fs13.existsSync(full)) continue;
2182
+ const full = path13.join(cwd, dir);
2183
+ if (!fs14.existsSync(full)) continue;
2141
2184
  let entries;
2142
2185
  try {
2143
- entries = fs13.readdirSync(full, { withFileTypes: true });
2186
+ entries = fs14.readdirSync(full, { withFileTypes: true });
2144
2187
  } catch {
2145
2188
  continue;
2146
2189
  }
2147
2190
  for (const entry of entries) {
2148
- const entryPath = path12.join(full, entry.name);
2191
+ const entryPath = path13.join(full, entry.name);
2149
2192
  let name;
2150
2193
  let filePath;
2151
2194
  if (entry.isDirectory()) {
2152
2195
  const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
2153
- (f) => fs13.existsSync(path12.join(entryPath, f))
2196
+ (f) => fs14.existsSync(path13.join(entryPath, f))
2154
2197
  );
2155
2198
  if (!indexFile) continue;
2156
2199
  name = entry.name;
2157
- filePath = path12.relative(cwd, path12.join(entryPath, indexFile));
2200
+ filePath = path13.relative(cwd, path13.join(entryPath, indexFile));
2158
2201
  } else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
2159
2202
  name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
2160
- filePath = path12.relative(cwd, entryPath);
2203
+ filePath = path13.relative(cwd, entryPath);
2161
2204
  } else {
2162
2205
  continue;
2163
2206
  }
@@ -2165,7 +2208,7 @@ function discoverAdminComponents(cwd, collections) {
2165
2208
  if (collections) {
2166
2209
  for (const col of collections) {
2167
2210
  try {
2168
- const colContent = fs13.readFileSync(path12.join(cwd, col.filePath), "utf-8");
2211
+ const colContent = fs14.readFileSync(path13.join(cwd, col.filePath), "utf-8");
2169
2212
  if (colContent.includes(name)) {
2170
2213
  usedInCollection = col.slug;
2171
2214
  break;
@@ -2184,8 +2227,8 @@ function scanApiRoutes(cwd) {
2184
2227
  const out = [];
2185
2228
  const appDirs = ["src/app", "app"];
2186
2229
  for (const appDir of appDirs) {
2187
- const apiDir = path12.join(cwd, appDir, "api");
2188
- if (!fs13.existsSync(apiDir)) continue;
2230
+ const apiDir = path13.join(cwd, appDir, "api");
2231
+ if (!fs14.existsSync(apiDir)) continue;
2189
2232
  walkApiRoutes(apiDir, "/api", cwd, out);
2190
2233
  break;
2191
2234
  }
@@ -2194,20 +2237,20 @@ function scanApiRoutes(cwd) {
2194
2237
  function walkApiRoutes(dir, prefix, cwd, out) {
2195
2238
  let entries;
2196
2239
  try {
2197
- entries = fs13.readdirSync(dir, { withFileTypes: true });
2240
+ entries = fs14.readdirSync(dir, { withFileTypes: true });
2198
2241
  } catch {
2199
2242
  return;
2200
2243
  }
2201
2244
  const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
2202
2245
  if (routeFile) {
2203
2246
  try {
2204
- const content = fs13.readFileSync(path12.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
2247
+ const content = fs14.readFileSync(path13.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
2205
2248
  const methods = HTTP_METHODS.filter((m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content));
2206
2249
  if (methods.length > 0) {
2207
2250
  out.push({
2208
2251
  path: prefix,
2209
2252
  methods,
2210
- filePath: path12.relative(cwd, path12.join(dir, routeFile.name))
2253
+ filePath: path13.relative(cwd, path13.join(dir, routeFile.name))
2211
2254
  });
2212
2255
  }
2213
2256
  } catch {
@@ -2218,7 +2261,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
2218
2261
  if (entry.name === "node_modules" || entry.name === ".next") continue;
2219
2262
  let segment = entry.name;
2220
2263
  if (segment.startsWith("(") && segment.endsWith(")")) {
2221
- walkApiRoutes(path12.join(dir, entry.name), prefix, cwd, out);
2264
+ walkApiRoutes(path13.join(dir, entry.name), prefix, cwd, out);
2222
2265
  continue;
2223
2266
  }
2224
2267
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -2226,7 +2269,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
2226
2269
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
2227
2270
  segment = `:${segment.slice(1, -1)}`;
2228
2271
  }
2229
- walkApiRoutes(path12.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
2272
+ walkApiRoutes(path13.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
2230
2273
  }
2231
2274
  }
2232
2275
  var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
@@ -2246,10 +2289,10 @@ var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
2246
2289
  function scanEnvVars(cwd) {
2247
2290
  const candidates = [".env.example", ".env.local.example", ".env.template"];
2248
2291
  for (const envFile of candidates) {
2249
- const envPath = path12.join(cwd, envFile);
2250
- if (!fs13.existsSync(envPath)) continue;
2292
+ const envPath = path13.join(cwd, envFile);
2293
+ if (!fs14.existsSync(envPath)) continue;
2251
2294
  try {
2252
- const content = fs13.readFileSync(envPath, "utf-8");
2295
+ const content = fs14.readFileSync(envPath, "utf-8");
2253
2296
  const vars = [];
2254
2297
  for (const line of content.split("\n")) {
2255
2298
  const trimmed = line.trim();
@@ -2297,9 +2340,9 @@ function runQaDiscovery(cwd) {
2297
2340
  }
2298
2341
  function detectDevServer(cwd, out) {
2299
2342
  try {
2300
- const pkg = JSON.parse(fs14.readFileSync(path13.join(cwd, "package.json"), "utf-8"));
2343
+ const pkg = JSON.parse(fs15.readFileSync(path14.join(cwd, "package.json"), "utf-8"));
2301
2344
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
2302
- const pm = fs14.existsSync(path13.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs14.existsSync(path13.join(cwd, "yarn.lock")) ? "yarn" : fs14.existsSync(path13.join(cwd, "bun.lockb")) ? "bun" : "npm";
2345
+ const pm = fs15.existsSync(path14.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs15.existsSync(path14.join(cwd, "yarn.lock")) ? "yarn" : fs15.existsSync(path14.join(cwd, "bun.lockb")) ? "bun" : "npm";
2303
2346
  if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
2304
2347
  if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
2305
2348
  else if (allDeps.vite) out.devPort = 5173;
@@ -2309,8 +2352,8 @@ function detectDevServer(cwd, out) {
2309
2352
  function scanFrontendRoutes(cwd, out) {
2310
2353
  const appDirs = ["src/app", "app"];
2311
2354
  for (const appDir of appDirs) {
2312
- const full = path13.join(cwd, appDir);
2313
- if (!fs14.existsSync(full)) continue;
2355
+ const full = path14.join(cwd, appDir);
2356
+ if (!fs15.existsSync(full)) continue;
2314
2357
  walkFrontendRoutes(full, "", out);
2315
2358
  break;
2316
2359
  }
@@ -2318,7 +2361,7 @@ function scanFrontendRoutes(cwd, out) {
2318
2361
  function walkFrontendRoutes(dir, prefix, out) {
2319
2362
  let entries;
2320
2363
  try {
2321
- entries = fs14.readdirSync(dir, { withFileTypes: true });
2364
+ entries = fs15.readdirSync(dir, { withFileTypes: true });
2322
2365
  } catch {
2323
2366
  return;
2324
2367
  }
@@ -2335,7 +2378,7 @@ function walkFrontendRoutes(dir, prefix, out) {
2335
2378
  if (entry.name === "node_modules" || entry.name === ".next") continue;
2336
2379
  let segment = entry.name;
2337
2380
  if (segment.startsWith("(") && segment.endsWith(")")) {
2338
- walkFrontendRoutes(path13.join(dir, entry.name), prefix, out);
2381
+ walkFrontendRoutes(path14.join(dir, entry.name), prefix, out);
2339
2382
  continue;
2340
2383
  }
2341
2384
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -2343,7 +2386,7 @@ function walkFrontendRoutes(dir, prefix, out) {
2343
2386
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
2344
2387
  segment = `:${segment.slice(1, -1)}`;
2345
2388
  }
2346
- walkFrontendRoutes(path13.join(dir, entry.name), `${prefix}/${segment}`, out);
2389
+ walkFrontendRoutes(path14.join(dir, entry.name), `${prefix}/${segment}`, out);
2347
2390
  }
2348
2391
  }
2349
2392
  function detectAuthFiles(cwd, out) {
@@ -2360,23 +2403,23 @@ function detectAuthFiles(cwd, out) {
2360
2403
  "src/app/api/oauth"
2361
2404
  ];
2362
2405
  for (const c of candidates) {
2363
- if (fs14.existsSync(path13.join(cwd, c))) out.authFiles.push(c);
2406
+ if (fs15.existsSync(path14.join(cwd, c))) out.authFiles.push(c);
2364
2407
  }
2365
2408
  }
2366
2409
  function detectRoles(cwd, out) {
2367
2410
  const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
2368
2411
  for (const rp of rolePaths) {
2369
- const dir = path13.join(cwd, rp);
2370
- if (!fs14.existsSync(dir)) continue;
2412
+ const dir = path14.join(cwd, rp);
2413
+ if (!fs15.existsSync(dir)) continue;
2371
2414
  let files;
2372
2415
  try {
2373
- files = fs14.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
2416
+ files = fs15.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
2374
2417
  } catch {
2375
2418
  continue;
2376
2419
  }
2377
2420
  for (const f of files) {
2378
2421
  try {
2379
- const content = fs14.readFileSync(path13.join(dir, f), "utf-8").slice(0, 5e3);
2422
+ const content = fs15.readFileSync(path14.join(dir, f), "utf-8").slice(0, 5e3);
2380
2423
  const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
2381
2424
  if (roleMatches) {
2382
2425
  for (const m of roleMatches) {
@@ -2522,7 +2565,7 @@ var discoverQaContext = async (ctx) => {
2522
2565
  };
2523
2566
 
2524
2567
  // src/scripts/dispatch.ts
2525
- import { execFileSync as execFileSync7 } from "child_process";
2568
+ import { execFileSync as execFileSync8 } from "child_process";
2526
2569
  var API_TIMEOUT_MS3 = 3e4;
2527
2570
  var dispatch = async (ctx, _profile, _agentResult, args) => {
2528
2571
  const next = args?.next;
@@ -2545,7 +2588,7 @@ var dispatch = async (ctx, _profile, _agentResult, args) => {
2545
2588
  const sub = usePr ? "pr" : "issue";
2546
2589
  const body = `@kody ${next}`;
2547
2590
  try {
2548
- execFileSync7("gh", [sub, "comment", String(targetNumber), "--body", body], {
2591
+ execFileSync8("gh", [sub, "comment", String(targetNumber), "--body", body], {
2549
2592
  timeout: API_TIMEOUT_MS3,
2550
2593
  cwd: ctx.cwd,
2551
2594
  stdio: ["ignore", "pipe", "pipe"]
@@ -2565,7 +2608,7 @@ function parsePr(url) {
2565
2608
  }
2566
2609
 
2567
2610
  // src/issue.ts
2568
- import { execFileSync as execFileSync8 } from "child_process";
2611
+ import { execFileSync as execFileSync9 } from "child_process";
2569
2612
  var API_TIMEOUT_MS4 = 3e4;
2570
2613
  function ghToken2() {
2571
2614
  return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
@@ -2573,7 +2616,7 @@ function ghToken2() {
2573
2616
  function gh2(args, options) {
2574
2617
  const token = ghToken2();
2575
2618
  const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
2576
- return execFileSync8("gh", args, {
2619
+ return execFileSync9("gh", args, {
2577
2620
  encoding: "utf-8",
2578
2621
  timeout: API_TIMEOUT_MS4,
2579
2622
  cwd: options?.cwd,
@@ -2861,7 +2904,7 @@ function computeFailureReason(ctx) {
2861
2904
  }
2862
2905
 
2863
2906
  // src/scripts/finishFlow.ts
2864
- import { execFileSync as execFileSync9 } from "child_process";
2907
+ import { execFileSync as execFileSync10 } from "child_process";
2865
2908
 
2866
2909
  // src/lifecycleLabels.ts
2867
2910
  var KODY_NAMESPACE = "kody";
@@ -3020,7 +3063,7 @@ var finishFlow = async (ctx, _profile, _agentResult, args) => {
3020
3063
  **PR:** ${state.core.prUrl}` : "";
3021
3064
  const body = `${icon} kody flow \`${flowName}\` finished \u2014 \`${reason}\`${prSuffix}`;
3022
3065
  try {
3023
- execFileSync9("gh", ["issue", "comment", String(issueNumber), "--body", body], {
3066
+ execFileSync10("gh", ["issue", "comment", String(issueNumber), "--body", body], {
3024
3067
  timeout: API_TIMEOUT_MS5,
3025
3068
  cwd: ctx.cwd,
3026
3069
  stdio: ["ignore", "pipe", "pipe"]
@@ -3034,7 +3077,7 @@ var finishFlow = async (ctx, _profile, _agentResult, args) => {
3034
3077
  };
3035
3078
 
3036
3079
  // src/branch.ts
3037
- import { execFileSync as execFileSync10 } from "child_process";
3080
+ import { execFileSync as execFileSync11 } from "child_process";
3038
3081
  var UncommittedChangesError = class extends Error {
3039
3082
  constructor(branch) {
3040
3083
  super(`Uncommitted changes on branch '${branch}' \u2014 refusing to run to protect work in progress`);
@@ -3044,7 +3087,7 @@ var UncommittedChangesError = class extends Error {
3044
3087
  branch;
3045
3088
  };
3046
3089
  function git2(args, cwd) {
3047
- return execFileSync10("git", args, {
3090
+ return execFileSync11("git", args, {
3048
3091
  encoding: "utf-8",
3049
3092
  timeout: 3e4,
3050
3093
  cwd,
@@ -3069,7 +3112,7 @@ function checkoutPrBranch(prNumber, cwd) {
3069
3112
  SKIP_HOOKS: "1",
3070
3113
  GH_TOKEN: process.env.GH_PAT?.trim() || process.env.GH_TOKEN || ""
3071
3114
  };
3072
- execFileSync10("gh", ["pr", "checkout", String(prNumber)], {
3115
+ execFileSync11("gh", ["pr", "checkout", String(prNumber)], {
3073
3116
  cwd,
3074
3117
  env,
3075
3118
  stdio: ["ignore", "pipe", "pipe"],
@@ -3136,8 +3179,8 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch, cwd) {
3136
3179
  }
3137
3180
 
3138
3181
  // src/gha.ts
3139
- import { execFileSync as execFileSync11 } from "child_process";
3140
- import * as fs15 from "fs";
3182
+ import { execFileSync as execFileSync12 } from "child_process";
3183
+ import * as fs16 from "fs";
3141
3184
  function getRunUrl() {
3142
3185
  const server = process.env.GITHUB_SERVER_URL;
3143
3186
  const repo = process.env.GITHUB_REPOSITORY;
@@ -3148,10 +3191,10 @@ function getRunUrl() {
3148
3191
  function reactToTriggerComment(cwd) {
3149
3192
  if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
3150
3193
  const eventPath = process.env.GITHUB_EVENT_PATH;
3151
- if (!eventPath || !fs15.existsSync(eventPath)) return;
3194
+ if (!eventPath || !fs16.existsSync(eventPath)) return;
3152
3195
  let event = null;
3153
3196
  try {
3154
- event = JSON.parse(fs15.readFileSync(eventPath, "utf-8"));
3197
+ event = JSON.parse(fs16.readFileSync(eventPath, "utf-8"));
3155
3198
  } catch {
3156
3199
  return;
3157
3200
  }
@@ -3179,7 +3222,7 @@ function reactToTriggerComment(cwd) {
3179
3222
  for (let attempt = 0; attempt < 3; attempt++) {
3180
3223
  if (attempt > 0) sleepMs(attempt === 1 ? 500 : 1500);
3181
3224
  try {
3182
- execFileSync11("gh", args, opts);
3225
+ execFileSync12("gh", args, opts);
3183
3226
  return;
3184
3227
  } catch (err) {
3185
3228
  lastErr = err;
@@ -3192,13 +3235,13 @@ function reactToTriggerComment(cwd) {
3192
3235
  }
3193
3236
  function sleepMs(ms) {
3194
3237
  try {
3195
- execFileSync11("sleep", [(ms / 1e3).toString()], { stdio: "ignore", timeout: ms + 1e3 });
3238
+ execFileSync12("sleep", [(ms / 1e3).toString()], { stdio: "ignore", timeout: ms + 1e3 });
3196
3239
  } catch {
3197
3240
  }
3198
3241
  }
3199
3242
 
3200
3243
  // src/workflow.ts
3201
- import { execFileSync as execFileSync12 } from "child_process";
3244
+ import { execFileSync as execFileSync13 } from "child_process";
3202
3245
  var GH_TIMEOUT_MS = 3e4;
3203
3246
  function ghToken3() {
3204
3247
  return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
@@ -3206,7 +3249,7 @@ function ghToken3() {
3206
3249
  function gh3(args, cwd) {
3207
3250
  const token = ghToken3();
3208
3251
  const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
3209
- return execFileSync12("gh", args, {
3252
+ return execFileSync13("gh", args, {
3210
3253
  encoding: "utf-8",
3211
3254
  timeout: GH_TIMEOUT_MS,
3212
3255
  cwd,
@@ -3390,23 +3433,23 @@ function tryPostPr2(prNumber, body, cwd) {
3390
3433
  }
3391
3434
 
3392
3435
  // src/scripts/initFlow.ts
3393
- import { execFileSync as execFileSync13 } from "child_process";
3394
- import * as fs17 from "fs";
3395
- import * as path15 from "path";
3436
+ import { execFileSync as execFileSync14 } from "child_process";
3437
+ import * as fs18 from "fs";
3438
+ import * as path16 from "path";
3396
3439
 
3397
3440
  // src/scripts/loadQaGuide.ts
3398
- import * as fs16 from "fs";
3399
- import * as path14 from "path";
3441
+ import * as fs17 from "fs";
3442
+ import * as path15 from "path";
3400
3443
  var QA_GUIDE_REL_PATH = ".kody/qa-guide.md";
3401
3444
  var loadQaGuide = async (ctx) => {
3402
- const full = path14.join(ctx.cwd, QA_GUIDE_REL_PATH);
3403
- if (!fs16.existsSync(full)) {
3445
+ const full = path15.join(ctx.cwd, QA_GUIDE_REL_PATH);
3446
+ if (!fs17.existsSync(full)) {
3404
3447
  ctx.data.qaGuide = "";
3405
3448
  ctx.data.qaGuidePath = "";
3406
3449
  return;
3407
3450
  }
3408
3451
  try {
3409
- ctx.data.qaGuide = fs16.readFileSync(full, "utf-8");
3452
+ ctx.data.qaGuide = fs17.readFileSync(full, "utf-8");
3410
3453
  ctx.data.qaGuidePath = QA_GUIDE_REL_PATH;
3411
3454
  } catch {
3412
3455
  ctx.data.qaGuide = "";
@@ -3416,9 +3459,9 @@ var loadQaGuide = async (ctx) => {
3416
3459
 
3417
3460
  // src/scripts/initFlow.ts
3418
3461
  function detectPackageManager(cwd) {
3419
- if (fs17.existsSync(path15.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
3420
- if (fs17.existsSync(path15.join(cwd, "yarn.lock"))) return "yarn";
3421
- if (fs17.existsSync(path15.join(cwd, "bun.lockb"))) return "bun";
3462
+ if (fs18.existsSync(path16.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
3463
+ if (fs18.existsSync(path16.join(cwd, "yarn.lock"))) return "yarn";
3464
+ if (fs18.existsSync(path16.join(cwd, "bun.lockb"))) return "bun";
3422
3465
  return "npm";
3423
3466
  }
3424
3467
  function qualityCommandsFor(pm) {
@@ -3431,7 +3474,7 @@ function qualityCommandsFor(pm) {
3431
3474
  function detectOwnerRepo(cwd) {
3432
3475
  let url;
3433
3476
  try {
3434
- url = execFileSync13("git", ["remote", "get-url", "origin"], {
3477
+ url = execFileSync14("git", ["remote", "get-url", "origin"], {
3435
3478
  cwd,
3436
3479
  encoding: "utf-8",
3437
3480
  stdio: ["ignore", "pipe", "pipe"]
@@ -3515,7 +3558,7 @@ jobs:
3515
3558
  `;
3516
3559
  function defaultBranchFromGit(cwd) {
3517
3560
  try {
3518
- const ref = execFileSync13("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
3561
+ const ref = execFileSync14("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
3519
3562
  cwd,
3520
3563
  encoding: "utf-8",
3521
3564
  stdio: ["ignore", "pipe", "pipe"]
@@ -3523,7 +3566,7 @@ function defaultBranchFromGit(cwd) {
3523
3566
  return ref.replace("refs/remotes/origin/", "");
3524
3567
  } catch {
3525
3568
  try {
3526
- return execFileSync13("git", ["branch", "--show-current"], {
3569
+ return execFileSync14("git", ["branch", "--show-current"], {
3527
3570
  cwd,
3528
3571
  encoding: "utf-8",
3529
3572
  stdio: ["ignore", "pipe", "pipe"]
@@ -3539,33 +3582,33 @@ function performInit(cwd, force) {
3539
3582
  const pm = detectPackageManager(cwd);
3540
3583
  const ownerRepo = detectOwnerRepo(cwd);
3541
3584
  const defaultBranch = defaultBranchFromGit(cwd);
3542
- const configPath = path15.join(cwd, "kody.config.json");
3543
- if (fs17.existsSync(configPath) && !force) {
3585
+ const configPath = path16.join(cwd, "kody.config.json");
3586
+ if (fs18.existsSync(configPath) && !force) {
3544
3587
  skipped.push("kody.config.json");
3545
3588
  } else {
3546
3589
  const cfg = makeConfig(pm, ownerRepo, defaultBranch);
3547
- fs17.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
3590
+ fs18.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
3548
3591
  `);
3549
3592
  wrote.push("kody.config.json");
3550
3593
  }
3551
- const workflowDir = path15.join(cwd, ".github", "workflows");
3552
- const workflowPath = path15.join(workflowDir, "kody.yml");
3553
- if (fs17.existsSync(workflowPath) && !force) {
3594
+ const workflowDir = path16.join(cwd, ".github", "workflows");
3595
+ const workflowPath = path16.join(workflowDir, "kody.yml");
3596
+ if (fs18.existsSync(workflowPath) && !force) {
3554
3597
  skipped.push(".github/workflows/kody.yml");
3555
3598
  } else {
3556
- fs17.mkdirSync(workflowDir, { recursive: true });
3557
- fs17.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
3599
+ fs18.mkdirSync(workflowDir, { recursive: true });
3600
+ fs18.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
3558
3601
  wrote.push(".github/workflows/kody.yml");
3559
3602
  }
3560
- const hasUi = fs17.existsSync(path15.join(cwd, "src/app")) || fs17.existsSync(path15.join(cwd, "app")) || fs17.existsSync(path15.join(cwd, "pages"));
3603
+ const hasUi = fs18.existsSync(path16.join(cwd, "src/app")) || fs18.existsSync(path16.join(cwd, "app")) || fs18.existsSync(path16.join(cwd, "pages"));
3561
3604
  if (hasUi) {
3562
- const qaGuidePath = path15.join(cwd, QA_GUIDE_REL_PATH);
3563
- if (fs17.existsSync(qaGuidePath) && !force) {
3605
+ const qaGuidePath = path16.join(cwd, QA_GUIDE_REL_PATH);
3606
+ if (fs18.existsSync(qaGuidePath) && !force) {
3564
3607
  skipped.push(QA_GUIDE_REL_PATH);
3565
3608
  } else {
3566
- fs17.mkdirSync(path15.dirname(qaGuidePath), { recursive: true });
3609
+ fs18.mkdirSync(path16.dirname(qaGuidePath), { recursive: true });
3567
3610
  const discovery = runQaDiscovery(cwd);
3568
- fs17.writeFileSync(qaGuidePath, generateQaGuideTemplate(discovery));
3611
+ fs18.writeFileSync(qaGuidePath, generateQaGuideTemplate(discovery));
3569
3612
  wrote.push(QA_GUIDE_REL_PATH);
3570
3613
  }
3571
3614
  }
@@ -3577,12 +3620,12 @@ function performInit(cwd, force) {
3577
3620
  continue;
3578
3621
  }
3579
3622
  if (profile.kind !== "scheduled" || !profile.schedule) continue;
3580
- const target = path15.join(workflowDir, `kody-${exe.name}.yml`);
3581
- if (fs17.existsSync(target) && !force) {
3623
+ const target = path16.join(workflowDir, `kody-${exe.name}.yml`);
3624
+ if (fs18.existsSync(target) && !force) {
3582
3625
  skipped.push(`.github/workflows/kody-${exe.name}.yml`);
3583
3626
  continue;
3584
3627
  }
3585
- fs17.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
3628
+ fs18.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
3586
3629
  wrote.push(`.github/workflows/kody-${exe.name}.yml`);
3587
3630
  }
3588
3631
  let labels;
@@ -3908,7 +3951,7 @@ var persistFlowState = async (ctx) => {
3908
3951
  };
3909
3952
 
3910
3953
  // src/scripts/postClassification.ts
3911
- import { execFileSync as execFileSync14 } from "child_process";
3954
+ import { execFileSync as execFileSync15 } from "child_process";
3912
3955
  var API_TIMEOUT_MS6 = 3e4;
3913
3956
  var VALID_CLASSES2 = /* @__PURE__ */ new Set(["feature", "bug", "spec", "chore"]);
3914
3957
  var postClassification = async (ctx) => {
@@ -3938,7 +3981,7 @@ var postClassification = async (ctx) => {
3938
3981
  ctx.cwd
3939
3982
  );
3940
3983
  try {
3941
- execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", `@kody ${classification}`], {
3984
+ execFileSync15("gh", ["issue", "comment", String(issueNumber), "--body", `@kody ${classification}`], {
3942
3985
  cwd: ctx.cwd,
3943
3986
  timeout: API_TIMEOUT_MS6,
3944
3987
  stdio: ["ignore", "pipe", "pipe"]
@@ -3972,7 +4015,7 @@ function parseClassification(prSummary) {
3972
4015
  }
3973
4016
  function tryAuditComment(issueNumber, body, cwd) {
3974
4017
  try {
3975
- execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", body], {
4018
+ execFileSync15("gh", ["issue", "comment", String(issueNumber), "--body", body], {
3976
4019
  cwd,
3977
4020
  timeout: API_TIMEOUT_MS6,
3978
4021
  stdio: ["ignore", "pipe", "pipe"]
@@ -4156,9 +4199,9 @@ REVIEW_POSTED=https://github.com/${ctx.config.github.owner}/${ctx.config.github.
4156
4199
  };
4157
4200
 
4158
4201
  // src/scripts/releaseFlow.ts
4159
- import { execFileSync as execFileSync15, spawnSync } from "child_process";
4160
- import * as fs18 from "fs";
4161
- import * as path16 from "path";
4202
+ import { execFileSync as execFileSync16, spawnSync } from "child_process";
4203
+ import * as fs19 from "fs";
4204
+ import * as path17 from "path";
4162
4205
  function notifyIssue(issueNumber, body, cwd) {
4163
4206
  if (!issueNumber || issueNumber <= 0) return;
4164
4207
  try {
@@ -4181,12 +4224,12 @@ function bumpVersion(current, bump) {
4181
4224
  return `${major}.${minor}.${patch}`;
4182
4225
  }
4183
4226
  function updateVersionInFile(file, newVersion, cwd) {
4184
- const abs = path16.join(cwd, file);
4185
- if (!fs18.existsSync(abs)) return false;
4186
- const content = fs18.readFileSync(abs, "utf-8");
4227
+ const abs = path17.join(cwd, file);
4228
+ if (!fs19.existsSync(abs)) return false;
4229
+ const content = fs19.readFileSync(abs, "utf-8");
4187
4230
  const updated = content.replace(/"version"\s*:\s*"[^"]+"/, `"version": "${newVersion}"`);
4188
4231
  if (updated === content) return false;
4189
- fs18.writeFileSync(abs, updated);
4232
+ fs19.writeFileSync(abs, updated);
4190
4233
  return true;
4191
4234
  }
4192
4235
  var FIRST_RELEASE_COMMIT_CAP = 100;
@@ -4196,7 +4239,7 @@ function generateChangelog(cwd, newVersion, lastTag) {
4196
4239
  else logArgs.splice(1, 0, `-n${FIRST_RELEASE_COMMIT_CAP}`, "HEAD");
4197
4240
  let log = "";
4198
4241
  try {
4199
- log = execFileSync15("git", logArgs, {
4242
+ log = execFileSync16("git", logArgs, {
4200
4243
  cwd,
4201
4244
  encoding: "utf-8",
4202
4245
  stdio: ["ignore", "pipe", "pipe"]
@@ -4237,23 +4280,23 @@ function generateChangelog(cwd, newVersion, lastTag) {
4237
4280
  return parts.join("\n");
4238
4281
  }
4239
4282
  function prependChangelog(cwd, entry) {
4240
- const p = path16.join(cwd, "CHANGELOG.md");
4283
+ const p = path17.join(cwd, "CHANGELOG.md");
4241
4284
  const header = "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n";
4242
- if (fs18.existsSync(p)) {
4243
- const prior = fs18.readFileSync(p, "utf-8");
4285
+ if (fs19.existsSync(p)) {
4286
+ const prior = fs19.readFileSync(p, "utf-8");
4244
4287
  if (/^#\s*Changelog\b/m.test(prior)) {
4245
4288
  const idx = prior.indexOf("\n", prior.indexOf("# Changelog"));
4246
- fs18.writeFileSync(p, `${prior.slice(0, idx + 1)}
4289
+ fs19.writeFileSync(p, `${prior.slice(0, idx + 1)}
4247
4290
  ${entry}${prior.slice(idx + 1)}`);
4248
4291
  } else {
4249
- fs18.writeFileSync(p, `${header}${entry}${prior}`);
4292
+ fs19.writeFileSync(p, `${header}${entry}${prior}`);
4250
4293
  }
4251
4294
  } else {
4252
- fs18.writeFileSync(p, `${header}${entry}`);
4295
+ fs19.writeFileSync(p, `${header}${entry}`);
4253
4296
  }
4254
4297
  }
4255
4298
  function git3(args, cwd, timeout = 6e4) {
4256
- return execFileSync15("git", args, {
4299
+ return execFileSync16("git", args, {
4257
4300
  encoding: "utf-8",
4258
4301
  timeout,
4259
4302
  cwd,
@@ -4320,13 +4363,13 @@ function buildIssueNotice(mode, dryRun, ctx) {
4320
4363
  }
4321
4364
  async function runPrepare(args) {
4322
4365
  const { cwd, bump, dryRun, versionFiles, ctx } = args;
4323
- const pkgPath = path16.join(cwd, "package.json");
4324
- if (!fs18.existsSync(pkgPath)) {
4366
+ const pkgPath = path17.join(cwd, "package.json");
4367
+ if (!fs19.existsSync(pkgPath)) {
4325
4368
  ctx.output.exitCode = 99;
4326
4369
  ctx.output.reason = "release prepare: package.json not found";
4327
4370
  return;
4328
4371
  }
4329
- const pkg = JSON.parse(fs18.readFileSync(pkgPath, "utf-8"));
4372
+ const pkg = JSON.parse(fs19.readFileSync(pkgPath, "utf-8"));
4330
4373
  if (typeof pkg.version !== "string") {
4331
4374
  ctx.output.exitCode = 99;
4332
4375
  ctx.output.reason = "release prepare: package.json has no version";
@@ -4401,8 +4444,8 @@ Merge this and then run \`kody release --mode finalize\`.`;
4401
4444
  }
4402
4445
  async function runFinalize(args) {
4403
4446
  const { cwd, dryRun, timeoutMs, releaseCfg, ctx } = args;
4404
- const pkgPath = path16.join(cwd, "package.json");
4405
- const pkg = JSON.parse(fs18.readFileSync(pkgPath, "utf-8"));
4447
+ const pkgPath = path17.join(cwd, "package.json");
4448
+ const pkg = JSON.parse(fs19.readFileSync(pkgPath, "utf-8"));
4406
4449
  if (typeof pkg.version !== "string") {
4407
4450
  ctx.output.exitCode = 99;
4408
4451
  ctx.output.reason = "release finalize: package.json has no version";
@@ -4580,7 +4623,7 @@ var resolveArtifacts = async (ctx, profile) => {
4580
4623
  };
4581
4624
 
4582
4625
  // src/scripts/resolveFlow.ts
4583
- import { execFileSync as execFileSync16 } from "child_process";
4626
+ import { execFileSync as execFileSync17 } from "child_process";
4584
4627
  var CONFLICT_DIFF_MAX_BYTES = 4e4;
4585
4628
  var resolveFlow = async (ctx) => {
4586
4629
  const prNumber = ctx.args.pr;
@@ -4632,7 +4675,7 @@ var resolveFlow = async (ctx) => {
4632
4675
  };
4633
4676
  function getConflictedFiles(cwd) {
4634
4677
  try {
4635
- const out = execFileSync16("git", ["diff", "--name-only", "--diff-filter=U"], {
4678
+ const out = execFileSync17("git", ["diff", "--name-only", "--diff-filter=U"], {
4636
4679
  encoding: "utf-8",
4637
4680
  cwd,
4638
4681
  env: { ...process.env, HUSKY: "0" }
@@ -4647,7 +4690,7 @@ function getConflictMarkersPreview(files, cwd, maxBytes = CONFLICT_DIFF_MAX_BYTE
4647
4690
  let total = 0;
4648
4691
  for (const f of files) {
4649
4692
  try {
4650
- const content = execFileSync16("cat", [f], { encoding: "utf-8", cwd }).toString();
4693
+ const content = execFileSync17("cat", [f], { encoding: "utf-8", cwd }).toString();
4651
4694
  const snippet = `### ${f}
4652
4695
 
4653
4696
  \`\`\`
@@ -4811,7 +4854,7 @@ var skipAgent = async (ctx) => {
4811
4854
  };
4812
4855
 
4813
4856
  // src/scripts/startFlow.ts
4814
- import { execFileSync as execFileSync17 } from "child_process";
4857
+ import { execFileSync as execFileSync18 } from "child_process";
4815
4858
  var API_TIMEOUT_MS7 = 3e4;
4816
4859
  var startFlow = async (ctx, profile, _agentResult, args) => {
4817
4860
  const entry = args?.entry;
@@ -4845,7 +4888,7 @@ function postKodyComment(target, issueNumber, state, next, cwd) {
4845
4888
  const sub = target === "pr" && state?.core.prUrl ? "pr" : "issue";
4846
4889
  const body = `@kody ${next}`;
4847
4890
  try {
4848
- execFileSync17("gh", [sub, "comment", String(targetNumber), "--body", body], {
4891
+ execFileSync18("gh", [sub, "comment", String(targetNumber), "--body", body], {
4849
4892
  timeout: API_TIMEOUT_MS7,
4850
4893
  cwd,
4851
4894
  stdio: ["ignore", "pipe", "pipe"]
@@ -4865,7 +4908,7 @@ function parsePr2(url) {
4865
4908
  }
4866
4909
 
4867
4910
  // src/scripts/syncFlow.ts
4868
- import { execFileSync as execFileSync18 } from "child_process";
4911
+ import { execFileSync as execFileSync19 } from "child_process";
4869
4912
  var syncFlow = async (ctx) => {
4870
4913
  ctx.skipAgent = true;
4871
4914
  const prNumber = ctx.args.pr;
@@ -4924,7 +4967,7 @@ function bail2(ctx, prNumber, reason) {
4924
4967
  }
4925
4968
  function revParseHead(cwd) {
4926
4969
  try {
4927
- return execFileSync18("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
4970
+ return execFileSync19("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
4928
4971
  } catch {
4929
4972
  return "";
4930
4973
  }
@@ -4932,9 +4975,9 @@ function revParseHead(cwd) {
4932
4975
  function pushBranch(branch, cwd) {
4933
4976
  const env = { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" };
4934
4977
  try {
4935
- execFileSync18("git", ["push", "-u", "origin", branch], { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
4978
+ execFileSync19("git", ["push", "-u", "origin", branch], { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
4936
4979
  } catch {
4937
- execFileSync18("git", ["push", "--force-with-lease", "-u", "origin", branch], {
4980
+ execFileSync19("git", ["push", "--force-with-lease", "-u", "origin", branch], {
4938
4981
  cwd,
4939
4982
  env,
4940
4983
  stdio: ["ignore", "pipe", "pipe"]
@@ -5102,7 +5145,7 @@ var watchStalePrsFlow = async (ctx) => {
5102
5145
  };
5103
5146
 
5104
5147
  // src/scripts/writeRunSummary.ts
5105
- import * as fs19 from "fs";
5148
+ import * as fs20 from "fs";
5106
5149
  var writeRunSummary = async (ctx, profile) => {
5107
5150
  const summaryPath = process.env.GITHUB_STEP_SUMMARY;
5108
5151
  if (!summaryPath) return;
@@ -5124,7 +5167,7 @@ var writeRunSummary = async (ctx, profile) => {
5124
5167
  if (reason) lines.push(`- **Reason:** ${reason}`);
5125
5168
  lines.push("");
5126
5169
  try {
5127
- fs19.appendFileSync(summaryPath, `${lines.join("\n")}
5170
+ fs20.appendFileSync(summaryPath, `${lines.join("\n")}
5128
5171
  `);
5129
5172
  } catch {
5130
5173
  }
@@ -5154,7 +5197,8 @@ var preflightScripts = {
5154
5197
  composePrompt,
5155
5198
  setLifecycleLabel,
5156
5199
  skipAgent,
5157
- classifyByLabel
5200
+ classifyByLabel,
5201
+ diagMcp
5158
5202
  };
5159
5203
  var postflightScripts = {
5160
5204
  parseAgentResult: parseAgentResult2,
@@ -5185,7 +5229,7 @@ var allScriptNames = /* @__PURE__ */ new Set([
5185
5229
  ]);
5186
5230
 
5187
5231
  // src/tools.ts
5188
- import { execFileSync as execFileSync19 } from "child_process";
5232
+ import { execFileSync as execFileSync20 } from "child_process";
5189
5233
  function verifyCliTools(tools, cwd) {
5190
5234
  const out = [];
5191
5235
  for (const t of tools) out.push(verifyOne(t, cwd));
@@ -5218,7 +5262,7 @@ function verifyOne(tool, cwd) {
5218
5262
  }
5219
5263
  function runShell2(cmd, cwd, timeoutMs = 3e4) {
5220
5264
  try {
5221
- execFileSync19("sh", ["-c", cmd], { cwd, stdio: "pipe", timeout: timeoutMs });
5265
+ execFileSync20("sh", ["-c", cmd], { cwd, stdio: "pipe", timeout: timeoutMs });
5222
5266
  return true;
5223
5267
  } catch {
5224
5268
  return false;
@@ -5286,9 +5330,9 @@ async function runExecutable(profileName, input) {
5286
5330
  data: {},
5287
5331
  output: { exitCode: 0 }
5288
5332
  };
5289
- const ndjsonDir = path17.join(input.cwd, ".kody");
5333
+ const ndjsonDir = path18.join(input.cwd, ".kody");
5290
5334
  const invokeAgent = async (prompt) => {
5291
- const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path17.isAbsolute(p) ? p : path17.resolve(profile.dir, p)).filter((p) => p.length > 0);
5335
+ const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path18.isAbsolute(p) ? p : path18.resolve(profile.dir, p)).filter((p) => p.length > 0);
5292
5336
  const syntheticPath = ctx.data.syntheticPluginPath;
5293
5337
  const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
5294
5338
  return runAgent({
@@ -5355,17 +5399,17 @@ async function runExecutable(profileName, input) {
5355
5399
  }
5356
5400
  }
5357
5401
  function resolveProfilePath(profileName) {
5358
- const here = path17.dirname(new URL(import.meta.url).pathname);
5402
+ const here = path18.dirname(new URL(import.meta.url).pathname);
5359
5403
  const candidates = [
5360
- path17.join(here, "executables", profileName, "profile.json"),
5404
+ path18.join(here, "executables", profileName, "profile.json"),
5361
5405
  // same-dir sibling (dev)
5362
- path17.join(here, "..", "executables", profileName, "profile.json"),
5406
+ path18.join(here, "..", "executables", profileName, "profile.json"),
5363
5407
  // up one (prod: dist/bin → dist/executables)
5364
- path17.join(here, "..", "src", "executables", profileName, "profile.json")
5408
+ path18.join(here, "..", "src", "executables", profileName, "profile.json")
5365
5409
  // fallback
5366
5410
  ];
5367
5411
  for (const c of candidates) {
5368
- if (fs20.existsSync(c)) return c;
5412
+ if (fs21.existsSync(c)) return c;
5369
5413
  }
5370
5414
  return candidates[0];
5371
5415
  }
@@ -5541,14 +5585,14 @@ function resolveAuthToken(env = process.env) {
5541
5585
  return token;
5542
5586
  }
5543
5587
  function detectPackageManager2(cwd) {
5544
- if (fs21.existsSync(path18.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
5545
- if (fs21.existsSync(path18.join(cwd, "yarn.lock"))) return "yarn";
5546
- if (fs21.existsSync(path18.join(cwd, "bun.lockb"))) return "bun";
5588
+ if (fs22.existsSync(path19.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
5589
+ if (fs22.existsSync(path19.join(cwd, "yarn.lock"))) return "yarn";
5590
+ if (fs22.existsSync(path19.join(cwd, "bun.lockb"))) return "bun";
5547
5591
  return "npm";
5548
5592
  }
5549
5593
  function shellOut(cmd, args, cwd, stream = true) {
5550
5594
  try {
5551
- execFileSync20(cmd, args, {
5595
+ execFileSync21(cmd, args, {
5552
5596
  cwd,
5553
5597
  stdio: stream ? "inherit" : "pipe",
5554
5598
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" }
@@ -5561,7 +5605,7 @@ function shellOut(cmd, args, cwd, stream = true) {
5561
5605
  }
5562
5606
  function isOnPath(bin) {
5563
5607
  try {
5564
- execFileSync20("which", [bin], { stdio: "pipe" });
5608
+ execFileSync21("which", [bin], { stdio: "pipe" });
5565
5609
  return true;
5566
5610
  } catch {
5567
5611
  return false;
@@ -5595,7 +5639,7 @@ function installLitellmIfNeeded(cwd) {
5595
5639
  } catch {
5596
5640
  }
5597
5641
  try {
5598
- execFileSync20("python3", ["-c", "import litellm"], { stdio: "pipe" });
5642
+ execFileSync21("python3", ["-c", "import litellm"], { stdio: "pipe" });
5599
5643
  process.stdout.write("\u2192 kody: litellm already installed\n");
5600
5644
  return 0;
5601
5645
  } catch {
@@ -5605,16 +5649,16 @@ function installLitellmIfNeeded(cwd) {
5605
5649
  }
5606
5650
  function configureGitIdentity(cwd) {
5607
5651
  try {
5608
- const name = execFileSync20("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
5652
+ const name = execFileSync21("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
5609
5653
  if (name) return;
5610
5654
  } catch {
5611
5655
  }
5612
5656
  try {
5613
- execFileSync20("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
5657
+ execFileSync21("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
5614
5658
  } catch {
5615
5659
  }
5616
5660
  try {
5617
- execFileSync20("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
5661
+ execFileSync21("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
5618
5662
  cwd,
5619
5663
  stdio: "pipe"
5620
5664
  });
@@ -5623,11 +5667,11 @@ function configureGitIdentity(cwd) {
5623
5667
  }
5624
5668
  function postFailureTail(issueNumber, cwd, reason) {
5625
5669
  if (!issueNumber) return;
5626
- const logPath = path18.join(cwd, ".kody", "last-run.jsonl");
5670
+ const logPath = path19.join(cwd, ".kody", "last-run.jsonl");
5627
5671
  let tail = "";
5628
5672
  try {
5629
- if (fs21.existsSync(logPath)) {
5630
- const content = fs21.readFileSync(logPath, "utf-8");
5673
+ if (fs22.existsSync(logPath)) {
5674
+ const content = fs22.readFileSync(logPath, "utf-8");
5631
5675
  tail = content.slice(-3e3);
5632
5676
  }
5633
5677
  } catch {
@@ -5652,7 +5696,7 @@ async function runCi(argv) {
5652
5696
  return 0;
5653
5697
  }
5654
5698
  const args = parseCiArgs(argv);
5655
- const cwd = args.cwd ? path18.resolve(args.cwd) : process.cwd();
5699
+ const cwd = args.cwd ? path19.resolve(args.cwd) : process.cwd();
5656
5700
  let earlyConfig;
5657
5701
  try {
5658
5702
  earlyConfig = loadConfig(cwd);
@@ -5785,15 +5829,15 @@ function parseChatArgs(argv, env = process.env) {
5785
5829
  return result;
5786
5830
  }
5787
5831
  function commitChatFiles(cwd, sessionId, verbose) {
5788
- const sessionFile = path19.relative(cwd, sessionFilePath(cwd, sessionId));
5789
- const eventsFile = path19.relative(cwd, eventsFilePath(cwd, sessionId));
5790
- const paths = [sessionFile, eventsFile].filter((p) => fs22.existsSync(path19.join(cwd, p)));
5832
+ const sessionFile = path20.relative(cwd, sessionFilePath(cwd, sessionId));
5833
+ const eventsFile = path20.relative(cwd, eventsFilePath(cwd, sessionId));
5834
+ const paths = [sessionFile, eventsFile].filter((p) => fs23.existsSync(path20.join(cwd, p)));
5791
5835
  if (paths.length === 0) return;
5792
5836
  const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
5793
5837
  try {
5794
- execFileSync21("git", ["add", ...paths], opts);
5795
- execFileSync21("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
5796
- execFileSync21("git", ["push", "--quiet", "origin", "HEAD"], opts);
5838
+ execFileSync22("git", ["add", ...paths], opts);
5839
+ execFileSync22("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
5840
+ execFileSync22("git", ["push", "--quiet", "origin", "HEAD"], opts);
5797
5841
  } catch (err) {
5798
5842
  const msg = err instanceof Error ? err.message : String(err);
5799
5843
  process.stderr.write(`[kody:chat] commit/push skipped: ${msg}
@@ -5825,7 +5869,7 @@ async function runChat(argv) {
5825
5869
  ${CHAT_HELP}`);
5826
5870
  return 64;
5827
5871
  }
5828
- const cwd = args.cwd ? path19.resolve(args.cwd) : process.cwd();
5872
+ const cwd = args.cwd ? path20.resolve(args.cwd) : process.cwd();
5829
5873
  const sessionId = args.sessionId;
5830
5874
  const unpackedSecrets = unpackAllSecrets();
5831
5875
  if (unpackedSecrets > 0) {
@@ -58,6 +58,9 @@
58
58
  "description": "kody: researching the issue"
59
59
  }
60
60
  },
61
+ {
62
+ "script": "diagMcp"
63
+ },
61
64
  {
62
65
  "script": "loadIssueContext"
63
66
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
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",