@kody-ade/kody-engine 0.4.157 → 0.4.158

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 +370 -301
  2. package/package.json +1 -1
package/dist/bin/kody.js CHANGED
@@ -650,16 +650,16 @@ var init_issue = __esm({
650
650
  });
651
651
 
652
652
  // src/prompt.ts
653
- import * as fs20 from "fs";
654
- import * as path19 from "path";
653
+ import * as fs21 from "fs";
654
+ import * as path20 from "path";
655
655
  function loadProjectConventions(projectDir) {
656
656
  const out = [];
657
657
  for (const rel of CONVENTION_FILES) {
658
- const abs = path19.join(projectDir, rel);
659
- if (!fs20.existsSync(abs)) continue;
658
+ const abs = path20.join(projectDir, rel);
659
+ if (!fs21.existsSync(abs)) continue;
660
660
  let content;
661
661
  try {
662
- content = fs20.readFileSync(abs, "utf-8");
662
+ content = fs21.readFileSync(abs, "utf-8");
663
663
  } catch {
664
664
  continue;
665
665
  }
@@ -807,28 +807,28 @@ var loadMemoryContext_exports = {};
807
807
  __export(loadMemoryContext_exports, {
808
808
  loadMemoryContext: () => loadMemoryContext
809
809
  });
810
- import * as fs32 from "fs";
811
- import * as path30 from "path";
810
+ import * as fs33 from "fs";
811
+ import * as path31 from "path";
812
812
  function collectPages(memoryAbs) {
813
813
  const out = [];
814
814
  walkMd(memoryAbs, (file) => {
815
815
  let stat;
816
816
  try {
817
- stat = fs32.statSync(file);
817
+ stat = fs33.statSync(file);
818
818
  } catch {
819
819
  return;
820
820
  }
821
821
  let raw;
822
822
  try {
823
- raw = fs32.readFileSync(file, "utf-8");
823
+ raw = fs33.readFileSync(file, "utf-8");
824
824
  } catch {
825
825
  return;
826
826
  }
827
827
  const fm = raw.match(/^---\s*\n([\s\S]*?)\n---/);
828
- const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path30.basename(file, ".md");
828
+ const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path31.basename(file, ".md");
829
829
  const updated = fm?.[1]?.match(/^updated:\s*([0-9T:.+\-Z]+)/m)?.[1]?.trim() ?? "";
830
830
  out.push({
831
- relPath: path30.relative(memoryAbs, file),
831
+ relPath: path31.relative(memoryAbs, file),
832
832
  title,
833
833
  updated,
834
834
  content: raw.length > PER_PAGE_MAX_BYTES ? raw.slice(0, PER_PAGE_MAX_BYTES) + TRUNCATED_SUFFIX : raw,
@@ -896,16 +896,16 @@ function walkMd(root, visit) {
896
896
  const dir = stack.pop();
897
897
  let names;
898
898
  try {
899
- names = fs32.readdirSync(dir);
899
+ names = fs33.readdirSync(dir);
900
900
  } catch {
901
901
  continue;
902
902
  }
903
903
  for (const name of names) {
904
904
  if (name.startsWith(".")) continue;
905
- const full = path30.join(dir, name);
905
+ const full = path31.join(dir, name);
906
906
  let stat;
907
907
  try {
908
- stat = fs32.statSync(full);
908
+ stat = fs33.statSync(full);
909
909
  } catch {
910
910
  continue;
911
911
  }
@@ -928,8 +928,8 @@ var init_loadMemoryContext = __esm({
928
928
  TRUNCATED_SUFFIX = "\n\n\u2026 (truncated)";
929
929
  loadMemoryContext = async (ctx) => {
930
930
  if (typeof ctx.data.memoryContext === "string") return;
931
- const memoryAbs = path30.join(ctx.cwd, MEMORY_DIR_RELATIVE);
932
- if (!fs32.existsSync(memoryAbs)) {
931
+ const memoryAbs = path31.join(ctx.cwd, MEMORY_DIR_RELATIVE);
932
+ if (!fs33.existsSync(memoryAbs)) {
933
933
  ctx.data.memoryContext = "";
934
934
  return;
935
935
  }
@@ -1061,7 +1061,7 @@ var init_loadPriorArt = __esm({
1061
1061
  // package.json
1062
1062
  var package_default = {
1063
1063
  name: "@kody-ade/kody-engine",
1064
- version: "0.4.157",
1064
+ version: "0.4.158",
1065
1065
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
1066
1066
  license: "MIT",
1067
1067
  type: "module",
@@ -1118,8 +1118,8 @@ var package_default = {
1118
1118
 
1119
1119
  // src/chat-cli.ts
1120
1120
  import { execFileSync as execFileSync31 } from "child_process";
1121
- import * as fs42 from "fs";
1122
- import * as path38 from "path";
1121
+ import * as fs43 from "fs";
1122
+ import * as path39 from "path";
1123
1123
 
1124
1124
  // src/chat/events.ts
1125
1125
  import * as fs from "fs";
@@ -1185,8 +1185,8 @@ function makeRunId(sessionId, suffix) {
1185
1185
  }
1186
1186
 
1187
1187
  // src/chat/loop.ts
1188
- import * as fs10 from "fs";
1189
- import * as path10 from "path";
1188
+ import * as fs11 from "fs";
1189
+ import * as path11 from "path";
1190
1190
 
1191
1191
  // src/task-artifacts.ts
1192
1192
  import fs2 from "fs";
@@ -2156,6 +2156,65 @@ function seedInitialMessage(file, message) {
2156
2156
  return true;
2157
2157
  }
2158
2158
 
2159
+ // src/chat/attachments.ts
2160
+ import * as fs10 from "fs";
2161
+ import * as path10 from "path";
2162
+ var INLINE_ATTACHMENT_RE = /(?:\[(?:Image|File): ([^\]]*)\]\n)?data:([\w.+-]+\/[\w.+-]+);base64,([A-Za-z0-9+/=]+)/g;
2163
+ var EXT_BY_MIME = {
2164
+ "image/png": "png",
2165
+ "image/jpeg": "jpg",
2166
+ "image/jpg": "jpg",
2167
+ "image/gif": "gif",
2168
+ "image/webp": "webp",
2169
+ "image/bmp": "bmp",
2170
+ "image/svg+xml": "svg",
2171
+ "image/avif": "avif"
2172
+ };
2173
+ function extFor(mime) {
2174
+ return EXT_BY_MIME[mime.toLowerCase()] ?? mime.split("/")[1]?.replace(/[^\w]/g, "") ?? "bin";
2175
+ }
2176
+ function attachmentsDir(cwd, sessionId) {
2177
+ return path10.join(cwd, ".kody", "tmp", "attachments", sessionId);
2178
+ }
2179
+ function prepareAttachments(turns, cwd, sessionId) {
2180
+ const lastUserIdx = (() => {
2181
+ for (let i = turns.length - 1; i >= 0; i--) {
2182
+ if (turns[i].role === "user") return i;
2183
+ }
2184
+ return -1;
2185
+ })();
2186
+ const imagePaths = [];
2187
+ let imageCounter = 0;
2188
+ const rewritten = turns.map((turn, idx) => {
2189
+ if (!turn.content.includes("base64,")) return turn;
2190
+ const isLastUser = idx === lastUserIdx;
2191
+ const newContent = turn.content.replace(
2192
+ INLINE_ATTACHMENT_RE,
2193
+ (_match, label, mime, data) => {
2194
+ const name = (label ?? "").trim() || "attachment";
2195
+ const isImage = mime.toLowerCase().startsWith("image/");
2196
+ if (!isLastUser || !isImage) {
2197
+ return `[${isImage ? "Image" : "File"}: ${name}${isLastUser ? "" : " \u2014 omitted from history"}]`;
2198
+ }
2199
+ try {
2200
+ const dir = attachmentsDir(cwd, sessionId);
2201
+ fs10.mkdirSync(dir, { recursive: true });
2202
+ const filePath = path10.join(dir, `${imageCounter}.${extFor(mime)}`);
2203
+ fs10.writeFileSync(filePath, Buffer.from(data, "base64"));
2204
+ imageCounter += 1;
2205
+ imagePaths.push(filePath);
2206
+ return `[Image "${name}" is attached \u2014 saved to ${filePath}. Use the Read tool on that exact path to view it before answering.]`;
2207
+ } catch {
2208
+ return `[Image: ${name} (could not be materialised)]`;
2209
+ }
2210
+ }
2211
+ );
2212
+ if (newContent === turn.content) return turn;
2213
+ return { ...turn, content: newContent };
2214
+ });
2215
+ return { turns: rewritten, imagePaths };
2216
+ }
2217
+
2159
2218
  // src/chat/loop.ts
2160
2219
  var CHAT_SYSTEM_PROMPT = [
2161
2220
  "You are Kody, an AI assistant for the Kody Operations Dashboard. Reply to the",
@@ -2259,7 +2318,7 @@ function buildExecutableCatalog() {
2259
2318
  const entries = [];
2260
2319
  for (const { name, profilePath } of discovered) {
2261
2320
  try {
2262
- const raw = JSON.parse(fs10.readFileSync(profilePath, "utf-8"));
2321
+ const raw = JSON.parse(fs11.readFileSync(profilePath, "utf-8"));
2263
2322
  const describe = typeof raw.describe === "string" ? raw.describe : "";
2264
2323
  const firstSentence = describe.split(/(?<=[.!?])\s+/, 1)[0] ?? "";
2265
2324
  entries.push({ name, describe: firstSentence.trim() });
@@ -2294,6 +2353,7 @@ async function runChatTurn(opts) {
2294
2353
  await emit(opts.sink, "chat.error", opts.sessionId, "error", { error });
2295
2354
  return { exitCode: 64, error };
2296
2355
  }
2356
+ const { turns: promptTurns, imagePaths } = prepareAttachments(turns, opts.cwd, opts.sessionId);
2297
2357
  const basePrompt = opts.systemPrompt ?? CHAT_SYSTEM_PROMPT;
2298
2358
  const catalog = buildExecutableCatalog();
2299
2359
  const taskArtifactsPaths = prepareTaskArtifactsDir(opts.cwd, opts.sessionId);
@@ -2306,16 +2366,25 @@ async function runChatTurn(opts) {
2306
2366
  const memoryBlock = readMemoryIndexBlock(opts.cwd);
2307
2367
  const instructionsBlock = readInstructionsBlock(opts.cwd);
2308
2368
  const crossRepoBlock = opts.reposRoot ? CROSS_REPO_PROMPT : null;
2369
+ const imageBlock = imagePaths.length > 0 ? [
2370
+ "# Attached images",
2371
+ "The user attached one or more images on this turn. They are saved as",
2372
+ "files in this workspace and referenced inline in the conversation as",
2373
+ '`[Image "\u2026" is attached \u2014 saved to <path>]`. You CAN view them: call',
2374
+ "the Read tool on each of those exact paths BEFORE answering. Never tell",
2375
+ "the user you cannot see images \u2014 Read the file and describe what you see."
2376
+ ].join("\n") : null;
2309
2377
  const systemPrompt = [
2310
2378
  basePrompt,
2311
2379
  contextBlock,
2312
2380
  memoryBlock,
2313
2381
  instructionsBlock,
2314
2382
  crossRepoBlock,
2383
+ imageBlock,
2315
2384
  catalog,
2316
2385
  artifactAddendum
2317
2386
  ].filter((s) => typeof s === "string" && s.length > 0).join("\n\n");
2318
- const prompt = buildPrompt(turns);
2387
+ const prompt = buildPrompt(promptTurns);
2319
2388
  let progressSeq = 0;
2320
2389
  const invoke = opts.invokeAgent ?? ((p) => runAgent({
2321
2390
  prompt: p,
@@ -2417,10 +2486,10 @@ async function emit(sink, type, sessionId, suffix, payload) {
2417
2486
  var MEMORY_INDEX_REL = ".kody/memory/INDEX.md";
2418
2487
  var MAX_INDEX_BYTES = 8e3;
2419
2488
  function readMemoryIndexBlock(cwd) {
2420
- const indexPath = path10.join(cwd, MEMORY_INDEX_REL);
2489
+ const indexPath = path11.join(cwd, MEMORY_INDEX_REL);
2421
2490
  let raw;
2422
2491
  try {
2423
- raw = fs10.readFileSync(indexPath, "utf-8");
2492
+ raw = fs11.readFileSync(indexPath, "utf-8");
2424
2493
  } catch {
2425
2494
  return "";
2426
2495
  }
@@ -2438,17 +2507,17 @@ function readMemoryIndexBlock(cwd) {
2438
2507
  var CONTEXT_DIR_REL = ".kody/context";
2439
2508
  var MAX_CONTEXT_BYTES = 12e3;
2440
2509
  function readContextBlock(cwd) {
2441
- const dir = path10.join(cwd, CONTEXT_DIR_REL);
2510
+ const dir = path11.join(cwd, CONTEXT_DIR_REL);
2442
2511
  let files;
2443
2512
  try {
2444
- files = fs10.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
2513
+ files = fs11.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
2445
2514
  } catch {
2446
2515
  return "";
2447
2516
  }
2448
2517
  const sections = [];
2449
2518
  for (const file of files) {
2450
2519
  try {
2451
- const content = fs10.readFileSync(path10.join(dir, file), "utf-8").trim();
2520
+ const content = fs11.readFileSync(path11.join(dir, file), "utf-8").trim();
2452
2521
  if (content) sections.push(`### ${file.replace(/\.md$/, "")}
2453
2522
 
2454
2523
  ${content}`);
@@ -2469,10 +2538,10 @@ ${content}`);
2469
2538
  var INSTRUCTIONS_REL = ".kody/instructions.md";
2470
2539
  var MAX_INSTRUCTIONS_BYTES = 8e3;
2471
2540
  function readInstructionsBlock(cwd) {
2472
- const instructionsPath = path10.join(cwd, INSTRUCTIONS_REL);
2541
+ const instructionsPath = path11.join(cwd, INSTRUCTIONS_REL);
2473
2542
  let raw;
2474
2543
  try {
2475
- raw = fs10.readFileSync(instructionsPath, "utf-8");
2544
+ raw = fs11.readFileSync(instructionsPath, "utf-8");
2476
2545
  } catch {
2477
2546
  return "";
2478
2547
  }
@@ -2491,8 +2560,8 @@ function readInstructionsBlock(cwd) {
2491
2560
  // src/chat/modes/interactive.ts
2492
2561
  init_issue();
2493
2562
  import { execFileSync as execFileSync3 } from "child_process";
2494
- import * as fs11 from "fs";
2495
- import * as path11 from "path";
2563
+ import * as fs12 from "fs";
2564
+ import * as path12 from "path";
2496
2565
 
2497
2566
  // src/chat/inbox.ts
2498
2567
  import { execFileSync as execFileSync2 } from "child_process";
@@ -2651,9 +2720,9 @@ function findNextUserTurn(turns, fromIdx) {
2651
2720
  return -1;
2652
2721
  }
2653
2722
  function commitTurn(cwd, sessionId, _verbose) {
2654
- const sessionRel = path11.relative(cwd, sessionFilePath(cwd, sessionId));
2655
- const eventsRel = path11.relative(cwd, eventsFilePath(cwd, sessionId));
2656
- const rels = [sessionRel, eventsRel].filter((p) => fs11.existsSync(path11.join(cwd, p)));
2723
+ const sessionRel = path12.relative(cwd, sessionFilePath(cwd, sessionId));
2724
+ const eventsRel = path12.relative(cwd, eventsFilePath(cwd, sessionId));
2725
+ const rels = [sessionRel, eventsRel].filter((p) => fs12.existsSync(path12.join(cwd, p)));
2657
2726
  if (rels.length === 0) return;
2658
2727
  const repository = process.env.GITHUB_REPOSITORY;
2659
2728
  if (!repository) {
@@ -2665,8 +2734,8 @@ function commitTurn(cwd, sessionId, _verbose) {
2665
2734
  }
2666
2735
  const branch = defaultBranch(cwd) ?? "main";
2667
2736
  for (const rel of rels) {
2668
- const repoPath = rel.split(path11.sep).join("/");
2669
- const localText = fs11.readFileSync(path11.join(cwd, rel), "utf-8");
2737
+ const repoPath = rel.split(path12.sep).join("/");
2738
+ const localText = fs12.readFileSync(path12.join(cwd, rel), "utf-8");
2670
2739
  putJsonlViaContents(repository, branch, repoPath, localText, sessionId, cwd);
2671
2740
  }
2672
2741
  }
@@ -2756,8 +2825,8 @@ async function emit2(sink, type, sessionId, suffix, payload) {
2756
2825
 
2757
2826
  // src/kody-cli.ts
2758
2827
  import { execFileSync as execFileSync30 } from "child_process";
2759
- import * as fs41 from "fs";
2760
- import * as path37 from "path";
2828
+ import * as fs42 from "fs";
2829
+ import * as path38 from "path";
2761
2830
 
2762
2831
  // src/app-auth.ts
2763
2832
  import { createSign } from "crypto";
@@ -2830,7 +2899,7 @@ async function mintAppInstallationToken(creds) {
2830
2899
  }
2831
2900
 
2832
2901
  // src/dispatch.ts
2833
- import * as fs12 from "fs";
2902
+ import * as fs13 from "fs";
2834
2903
 
2835
2904
  // src/cron-match.ts
2836
2905
  var FIELD_BOUNDS = [
@@ -2914,10 +2983,10 @@ function autoDispatch(opts) {
2914
2983
  }
2915
2984
  const eventName = process.env.GITHUB_EVENT_NAME;
2916
2985
  const eventPath = process.env.GITHUB_EVENT_PATH;
2917
- if (!eventName || !eventPath || !fs12.existsSync(eventPath)) return null;
2986
+ if (!eventName || !eventPath || !fs13.existsSync(eventPath)) return null;
2918
2987
  let event = {};
2919
2988
  try {
2920
- event = JSON.parse(fs12.readFileSync(eventPath, "utf-8"));
2989
+ event = JSON.parse(fs13.readFileSync(eventPath, "utf-8"));
2921
2990
  } catch {
2922
2991
  return null;
2923
2992
  }
@@ -2998,7 +3067,7 @@ function autoDispatchTyped(opts) {
2998
3067
  if (legacy) return { kind: "route", ...legacy };
2999
3068
  const eventName = process.env.GITHUB_EVENT_NAME;
3000
3069
  const eventPath = process.env.GITHUB_EVENT_PATH;
3001
- if (!eventName || !eventPath || !fs12.existsSync(eventPath)) {
3070
+ if (!eventName || !eventPath || !fs13.existsSync(eventPath)) {
3002
3071
  return { kind: "silent", reason: "no GHA event context" };
3003
3072
  }
3004
3073
  if (eventName !== "issue_comment") {
@@ -3006,7 +3075,7 @@ function autoDispatchTyped(opts) {
3006
3075
  }
3007
3076
  let event = {};
3008
3077
  try {
3009
- event = JSON.parse(fs12.readFileSync(eventPath, "utf-8"));
3078
+ event = JSON.parse(fs13.readFileSync(eventPath, "utf-8"));
3010
3079
  } catch {
3011
3080
  return { kind: "silent", reason: "GHA event payload unreadable" };
3012
3081
  }
@@ -3044,7 +3113,7 @@ function dispatchScheduledWatches(opts) {
3044
3113
  for (const exe of listExecutables()) {
3045
3114
  let raw;
3046
3115
  try {
3047
- raw = fs12.readFileSync(exe.profilePath, "utf-8");
3116
+ raw = fs13.readFileSync(exe.profilePath, "utf-8");
3048
3117
  } catch {
3049
3118
  continue;
3050
3119
  }
@@ -3164,8 +3233,8 @@ function coerceBare(spec, value) {
3164
3233
 
3165
3234
  // src/executor.ts
3166
3235
  import { execFileSync as execFileSync29, spawn as spawn9 } from "child_process";
3167
- import * as fs40 from "fs";
3168
- import * as path36 from "path";
3236
+ import * as fs41 from "fs";
3237
+ import * as path37 from "path";
3169
3238
 
3170
3239
  // src/discipline.ts
3171
3240
  var DISCIPLINE = `# Working discipline (applies to this entire task)
@@ -3216,8 +3285,8 @@ init_events();
3216
3285
  init_issue();
3217
3286
 
3218
3287
  // src/profile.ts
3219
- import * as fs13 from "fs";
3220
- import * as path12 from "path";
3288
+ import * as fs14 from "fs";
3289
+ import * as path13 from "path";
3221
3290
 
3222
3291
  // src/profile-error.ts
3223
3292
  var ProfileError = class extends Error {
@@ -3385,12 +3454,12 @@ var KNOWN_PROFILE_KEYS = /* @__PURE__ */ new Set([
3385
3454
  "preloadContext"
3386
3455
  ]);
3387
3456
  function loadProfile(profilePath) {
3388
- if (!fs13.existsSync(profilePath)) {
3457
+ if (!fs14.existsSync(profilePath)) {
3389
3458
  throw new ProfileError(profilePath, "file not found");
3390
3459
  }
3391
3460
  let raw;
3392
3461
  try {
3393
- raw = JSON.parse(fs13.readFileSync(profilePath, "utf-8"));
3462
+ raw = JSON.parse(fs14.readFileSync(profilePath, "utf-8"));
3394
3463
  } catch (err) {
3395
3464
  throw new ProfileError(profilePath, `invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
3396
3465
  }
@@ -3401,7 +3470,7 @@ function loadProfile(profilePath) {
3401
3470
  const unknownKeys = Object.keys(r).filter((k) => !KNOWN_PROFILE_KEYS.has(k));
3402
3471
  if (unknownKeys.length > 0) {
3403
3472
  process.stderr.write(
3404
- `[kody profile] ${path12.basename(path12.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
3473
+ `[kody profile] ${path13.basename(path13.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
3405
3474
  `
3406
3475
  );
3407
3476
  }
@@ -3462,7 +3531,7 @@ function loadProfile(profilePath) {
3462
3531
  // Phase 5 in-process handoff opt-in. Default false; containers
3463
3532
  // flip to true after end-to-end verification.
3464
3533
  preloadContext: r.preloadContext === true,
3465
- dir: path12.dirname(profilePath)
3534
+ dir: path13.dirname(profilePath)
3466
3535
  };
3467
3536
  if (lifecycle) {
3468
3537
  applyLifecycle(profile, profilePath);
@@ -3833,9 +3902,9 @@ function errMsg(err) {
3833
3902
 
3834
3903
  // src/litellm.ts
3835
3904
  import { execFileSync as execFileSync4, spawn as spawn3 } from "child_process";
3836
- import * as fs14 from "fs";
3905
+ import * as fs15 from "fs";
3837
3906
  import * as os2 from "os";
3838
- import * as path13 from "path";
3907
+ import * as path14 from "path";
3839
3908
  async function checkLitellmHealth(url) {
3840
3909
  try {
3841
3910
  const response = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3e3) });
@@ -3887,13 +3956,13 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
3887
3956
  let child;
3888
3957
  let logPath;
3889
3958
  const spawnProxy = () => {
3890
- const configPath = path13.join(os2.tmpdir(), `kody-litellm-${Date.now()}.yaml`);
3891
- fs14.writeFileSync(configPath, generateLitellmConfigYaml(model));
3959
+ const configPath = path14.join(os2.tmpdir(), `kody-litellm-${Date.now()}.yaml`);
3960
+ fs15.writeFileSync(configPath, generateLitellmConfigYaml(model));
3892
3961
  const args = cmd === "litellm" ? ["--config", configPath, "--port", port] : ["-m", "litellm", "--config", configPath, "--port", port];
3893
- const nextLogPath = path13.join(os2.tmpdir(), `kody-litellm-${Date.now()}.log`);
3894
- const outFd = fs14.openSync(nextLogPath, "w");
3962
+ const nextLogPath = path14.join(os2.tmpdir(), `kody-litellm-${Date.now()}.log`);
3963
+ const outFd = fs15.openSync(nextLogPath, "w");
3895
3964
  child = spawn3(cmd, args, { stdio: ["ignore", outFd, outFd], detached: true, env: childEnv });
3896
- fs14.closeSync(outFd);
3965
+ fs15.closeSync(outFd);
3897
3966
  logPath = nextLogPath;
3898
3967
  };
3899
3968
  const waitForHealth = async () => {
@@ -3907,7 +3976,7 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
3907
3976
  const readLogTail = () => {
3908
3977
  if (!logPath) return "";
3909
3978
  try {
3910
- return fs14.readFileSync(logPath, "utf-8").slice(-2e3);
3979
+ return fs15.readFileSync(logPath, "utf-8").slice(-2e3);
3911
3980
  } catch {
3912
3981
  return "";
3913
3982
  }
@@ -3946,10 +4015,10 @@ ${tail}`
3946
4015
  return { url, kill: killChild, ensureHealthy };
3947
4016
  }
3948
4017
  function readDotenvApiKeys(projectDir) {
3949
- const dotenvPath = path13.join(projectDir, ".env");
3950
- if (!fs14.existsSync(dotenvPath)) return {};
4018
+ const dotenvPath = path14.join(projectDir, ".env");
4019
+ if (!fs15.existsSync(dotenvPath)) return {};
3951
4020
  const result = {};
3952
- for (const rawLine of fs14.readFileSync(dotenvPath, "utf-8").split("\n")) {
4021
+ for (const rawLine of fs15.readFileSync(dotenvPath, "utf-8").split("\n")) {
3953
4022
  const line = rawLine.trim();
3954
4023
  if (!line || line.startsWith("#")) continue;
3955
4024
  const match = line.match(/^([A-Z_][A-Z0-9_]*_API_KEY)=(.*)$/);
@@ -3972,25 +4041,25 @@ function stripBlockingEnv(env) {
3972
4041
  }
3973
4042
 
3974
4043
  // src/subagents.ts
3975
- import * as fs16 from "fs";
3976
- import * as path15 from "path";
4044
+ import * as fs17 from "fs";
4045
+ import * as path16 from "path";
3977
4046
 
3978
4047
  // src/scripts/buildSyntheticPlugin.ts
3979
- import * as fs15 from "fs";
4048
+ import * as fs16 from "fs";
3980
4049
  import * as os3 from "os";
3981
- import * as path14 from "path";
4050
+ import * as path15 from "path";
3982
4051
  function getPluginsCatalogRoot() {
3983
- const here = path14.dirname(new URL(import.meta.url).pathname);
4052
+ const here = path15.dirname(new URL(import.meta.url).pathname);
3984
4053
  const candidates = [
3985
- path14.join(here, "..", "plugins"),
4054
+ path15.join(here, "..", "plugins"),
3986
4055
  // dev: src/scripts → src/plugins
3987
- path14.join(here, "..", "..", "plugins"),
4056
+ path15.join(here, "..", "..", "plugins"),
3988
4057
  // built: dist/scripts → dist/plugins
3989
- path14.join(here, "..", "..", "src", "plugins")
4058
+ path15.join(here, "..", "..", "src", "plugins")
3990
4059
  // fallback
3991
4060
  ];
3992
4061
  for (const c of candidates) {
3993
- if (fs15.existsSync(c) && fs15.statSync(c).isDirectory()) return c;
4062
+ if (fs16.existsSync(c) && fs16.statSync(c).isDirectory()) return c;
3994
4063
  }
3995
4064
  return candidates[0];
3996
4065
  }
@@ -4000,45 +4069,45 @@ var buildSyntheticPlugin = async (ctx, profile) => {
4000
4069
  if (!needsSynthetic) return;
4001
4070
  const catalog = getPluginsCatalogRoot();
4002
4071
  const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
4003
- const root = path14.join(os3.tmpdir(), `kody-synth-${runId}`);
4004
- fs15.mkdirSync(path14.join(root, ".claude-plugin"), { recursive: true });
4072
+ const root = path15.join(os3.tmpdir(), `kody-synth-${runId}`);
4073
+ fs16.mkdirSync(path15.join(root, ".claude-plugin"), { recursive: true });
4005
4074
  const resolvePart = (bucket, entry) => {
4006
- const local = path14.join(profile.dir, bucket, entry);
4007
- if (fs15.existsSync(local)) return local;
4008
- const central = path14.join(catalog, bucket, entry);
4009
- if (fs15.existsSync(central)) return central;
4075
+ const local = path15.join(profile.dir, bucket, entry);
4076
+ if (fs16.existsSync(local)) return local;
4077
+ const central = path15.join(catalog, bucket, entry);
4078
+ if (fs16.existsSync(central)) return central;
4010
4079
  throw new Error(
4011
4080
  `buildSyntheticPlugin: ${bucket} entry '${entry}' not found in executable dir (${profile.dir}/${bucket}/) or catalog (${catalog}/${bucket}/)`
4012
4081
  );
4013
4082
  };
4014
4083
  if (cc.skills.length > 0) {
4015
- const dst = path14.join(root, "skills");
4016
- fs15.mkdirSync(dst, { recursive: true });
4084
+ const dst = path15.join(root, "skills");
4085
+ fs16.mkdirSync(dst, { recursive: true });
4017
4086
  for (const name of cc.skills) {
4018
- copyDir(resolvePart("skills", name), path14.join(dst, name));
4087
+ copyDir(resolvePart("skills", name), path15.join(dst, name));
4019
4088
  }
4020
4089
  }
4021
4090
  if (cc.commands.length > 0) {
4022
- const dst = path14.join(root, "commands");
4023
- fs15.mkdirSync(dst, { recursive: true });
4091
+ const dst = path15.join(root, "commands");
4092
+ fs16.mkdirSync(dst, { recursive: true });
4024
4093
  for (const name of cc.commands) {
4025
- fs15.copyFileSync(resolvePart("commands", `${name}.md`), path14.join(dst, `${name}.md`));
4094
+ fs16.copyFileSync(resolvePart("commands", `${name}.md`), path15.join(dst, `${name}.md`));
4026
4095
  }
4027
4096
  }
4028
4097
  if (cc.hooks.length > 0) {
4029
- const dst = path14.join(root, "hooks");
4030
- fs15.mkdirSync(dst, { recursive: true });
4098
+ const dst = path15.join(root, "hooks");
4099
+ fs16.mkdirSync(dst, { recursive: true });
4031
4100
  const merged = { hooks: {} };
4032
4101
  for (const name of cc.hooks) {
4033
4102
  const src = resolvePart("hooks", `${name}.json`);
4034
- const parsed = JSON.parse(fs15.readFileSync(src, "utf-8"));
4103
+ const parsed = JSON.parse(fs16.readFileSync(src, "utf-8"));
4035
4104
  for (const [event, entries] of Object.entries(parsed.hooks ?? {})) {
4036
4105
  if (!Array.isArray(entries)) continue;
4037
4106
  if (!merged.hooks[event]) merged.hooks[event] = [];
4038
4107
  merged.hooks[event].push(...entries);
4039
4108
  }
4040
4109
  }
4041
- fs15.writeFileSync(path14.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
4110
+ fs16.writeFileSync(path15.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
4042
4111
  `);
4043
4112
  }
4044
4113
  const manifest = {
@@ -4048,17 +4117,17 @@ var buildSyntheticPlugin = async (ctx, profile) => {
4048
4117
  };
4049
4118
  if (cc.skills.length > 0) manifest.skills = ["./skills/"];
4050
4119
  if (cc.commands.length > 0) manifest.commands = ["./commands/"];
4051
- fs15.writeFileSync(path14.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
4120
+ fs16.writeFileSync(path15.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
4052
4121
  `);
4053
4122
  ctx.data.syntheticPluginPath = root;
4054
4123
  };
4055
4124
  function copyDir(src, dst) {
4056
- fs15.mkdirSync(dst, { recursive: true });
4057
- for (const ent of fs15.readdirSync(src, { withFileTypes: true })) {
4058
- const s = path14.join(src, ent.name);
4059
- const d = path14.join(dst, ent.name);
4125
+ fs16.mkdirSync(dst, { recursive: true });
4126
+ for (const ent of fs16.readdirSync(src, { withFileTypes: true })) {
4127
+ const s = path15.join(src, ent.name);
4128
+ const d = path15.join(dst, ent.name);
4060
4129
  if (ent.isDirectory()) copyDir(s, d);
4061
- else if (ent.isFile()) fs15.copyFileSync(s, d);
4130
+ else if (ent.isFile()) fs16.copyFileSync(s, d);
4062
4131
  }
4063
4132
  }
4064
4133
 
@@ -4075,10 +4144,10 @@ function splitFrontmatter(raw) {
4075
4144
  return { fm, body: (match[2] ?? "").trim() };
4076
4145
  }
4077
4146
  function resolveAgentFile(profileDir, name) {
4078
- const local = path15.join(profileDir, "agents", `${name}.md`);
4079
- if (fs16.existsSync(local)) return local;
4080
- const central = path15.join(getPluginsCatalogRoot(), "agents", `${name}.md`);
4081
- if (fs16.existsSync(central)) return central;
4147
+ const local = path16.join(profileDir, "agents", `${name}.md`);
4148
+ if (fs17.existsSync(local)) return local;
4149
+ const central = path16.join(getPluginsCatalogRoot(), "agents", `${name}.md`);
4150
+ if (fs17.existsSync(central)) return central;
4082
4151
  throw new Error(
4083
4152
  `loadSubagents: agent '${name}' not found in ${profileDir}/agents/ or shared catalog`
4084
4153
  );
@@ -4088,7 +4157,7 @@ function loadSubagents(profile) {
4088
4157
  if (!names || names.length === 0) return void 0;
4089
4158
  const agents = {};
4090
4159
  for (const name of names) {
4091
- const { fm, body } = splitFrontmatter(fs16.readFileSync(resolveAgentFile(profile.dir, name), "utf-8"));
4160
+ const { fm, body } = splitFrontmatter(fs17.readFileSync(resolveAgentFile(profile.dir, name), "utf-8"));
4092
4161
  if (!body) throw new Error(`loadSubagents: agent '${name}' has an empty prompt body`);
4093
4162
  const def = {
4094
4163
  description: fm.description ?? `Subagent ${name}`,
@@ -4184,8 +4253,8 @@ function pushWithRetry(opts = {}) {
4184
4253
  }
4185
4254
 
4186
4255
  // src/commit.ts
4187
- import * as fs17 from "fs";
4188
- import * as path16 from "path";
4256
+ import * as fs18 from "fs";
4257
+ import * as path17 from "path";
4189
4258
  var FORBIDDEN_PATH_PREFIXES = [
4190
4259
  ".kody/",
4191
4260
  ".kody-engine/",
@@ -4241,18 +4310,18 @@ function tryGit(args, cwd) {
4241
4310
  }
4242
4311
  function abortUnfinishedGitOps(cwd) {
4243
4312
  const aborted = [];
4244
- const gitDir = path16.join(cwd ?? process.cwd(), ".git");
4245
- if (!fs17.existsSync(gitDir)) return aborted;
4246
- if (fs17.existsSync(path16.join(gitDir, "MERGE_HEAD"))) {
4313
+ const gitDir = path17.join(cwd ?? process.cwd(), ".git");
4314
+ if (!fs18.existsSync(gitDir)) return aborted;
4315
+ if (fs18.existsSync(path17.join(gitDir, "MERGE_HEAD"))) {
4247
4316
  if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
4248
4317
  }
4249
- if (fs17.existsSync(path16.join(gitDir, "CHERRY_PICK_HEAD"))) {
4318
+ if (fs18.existsSync(path17.join(gitDir, "CHERRY_PICK_HEAD"))) {
4250
4319
  if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
4251
4320
  }
4252
- if (fs17.existsSync(path16.join(gitDir, "REVERT_HEAD"))) {
4321
+ if (fs18.existsSync(path17.join(gitDir, "REVERT_HEAD"))) {
4253
4322
  if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
4254
4323
  }
4255
- if (fs17.existsSync(path16.join(gitDir, "rebase-merge")) || fs17.existsSync(path16.join(gitDir, "rebase-apply"))) {
4324
+ if (fs18.existsSync(path17.join(gitDir, "rebase-merge")) || fs18.existsSync(path17.join(gitDir, "rebase-apply"))) {
4256
4325
  if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
4257
4326
  }
4258
4327
  try {
@@ -4308,7 +4377,7 @@ function normalizeCommitMessage(raw) {
4308
4377
  function commitAndPush(branch, agentMessage, cwd) {
4309
4378
  const allChanged = listChangedFiles(cwd);
4310
4379
  const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
4311
- const mergeHeadExists = fs17.existsSync(path16.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
4380
+ const mergeHeadExists = fs18.existsSync(path17.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
4312
4381
  if (allowedFiles.length === 0 && !mergeHeadExists) {
4313
4382
  return { committed: false, pushed: false, sha: "", message: "" };
4314
4383
  }
@@ -4641,20 +4710,20 @@ var advanceFlow = async (ctx, profile) => {
4641
4710
  // src/scripts/brainServe.ts
4642
4711
  init_repoWorkspace();
4643
4712
  import { createServer } from "http";
4644
- import * as fs19 from "fs";
4645
- import * as path18 from "path";
4713
+ import * as fs20 from "fs";
4714
+ import * as path19 from "path";
4646
4715
 
4647
4716
  // src/scripts/brainTurnLog.ts
4648
- import * as fs18 from "fs";
4649
- import * as path17 from "path";
4717
+ import * as fs19 from "fs";
4718
+ import * as path18 from "path";
4650
4719
  var live = /* @__PURE__ */ new Map();
4651
4720
  function eventsPath(dir, chatId) {
4652
- return path17.join(dir, ".kody", "brain-events", `${chatId}.jsonl`);
4721
+ return path18.join(dir, ".kody", "brain-events", `${chatId}.jsonl`);
4653
4722
  }
4654
4723
  function lastPersistedSeq(dir, chatId) {
4655
4724
  const p = eventsPath(dir, chatId);
4656
- if (!fs18.existsSync(p)) return 0;
4657
- const lines = fs18.readFileSync(p, "utf-8").split("\n").filter(Boolean);
4725
+ if (!fs19.existsSync(p)) return 0;
4726
+ const lines = fs19.readFileSync(p, "utf-8").split("\n").filter(Boolean);
4658
4727
  if (lines.length === 0) return 0;
4659
4728
  try {
4660
4729
  return JSON.parse(lines[lines.length - 1]).seq || 0;
@@ -4664,9 +4733,9 @@ function lastPersistedSeq(dir, chatId) {
4664
4733
  }
4665
4734
  function readSince(dir, chatId, since) {
4666
4735
  const p = eventsPath(dir, chatId);
4667
- if (!fs18.existsSync(p)) return [];
4736
+ if (!fs19.existsSync(p)) return [];
4668
4737
  const out = [];
4669
- for (const line of fs18.readFileSync(p, "utf-8").split("\n")) {
4738
+ for (const line of fs19.readFileSync(p, "utf-8").split("\n")) {
4670
4739
  if (!line) continue;
4671
4740
  try {
4672
4741
  const rec = JSON.parse(line);
@@ -4692,12 +4761,12 @@ function beginTurn(dir, chatId) {
4692
4761
  };
4693
4762
  live.set(chatId, state);
4694
4763
  const p = eventsPath(dir, chatId);
4695
- fs18.mkdirSync(path17.dirname(p), { recursive: true });
4764
+ fs19.mkdirSync(path18.dirname(p), { recursive: true });
4696
4765
  return (event) => {
4697
4766
  state.seq += 1;
4698
4767
  const rec = { seq: state.seq, turn, ts: Date.now(), event };
4699
4768
  try {
4700
- fs18.appendFileSync(p, JSON.stringify(rec) + "\n");
4769
+ fs19.appendFileSync(p, JSON.stringify(rec) + "\n");
4701
4770
  } catch (err) {
4702
4771
  process.stderr.write(
4703
4772
  `[brain-turn-log] append failed for ${chatId}: ${err instanceof Error ? err.message : String(err)}
@@ -4735,7 +4804,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
4735
4804
  event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
4736
4805
  };
4737
4806
  try {
4738
- fs18.appendFileSync(eventsPath(dir, chatId), JSON.stringify(rec) + "\n");
4807
+ fs19.appendFileSync(eventsPath(dir, chatId), JSON.stringify(rec) + "\n");
4739
4808
  } catch {
4740
4809
  }
4741
4810
  state.status = "ended";
@@ -4961,7 +5030,7 @@ async function handleChatTurn(req, res, chatId, opts) {
4961
5030
  const repo = strField(body, "repo");
4962
5031
  const repoToken = strField(body, "repoToken");
4963
5032
  const sessionFile = sessionFilePath(opts.cwd, chatId);
4964
- fs19.mkdirSync(path18.dirname(sessionFile), { recursive: true });
5033
+ fs20.mkdirSync(path19.dirname(sessionFile), { recursive: true });
4965
5034
  appendTurn(sessionFile, {
4966
5035
  role: "user",
4967
5036
  content: message,
@@ -5008,7 +5077,7 @@ async function handleChatTurn(req, res, chatId, opts) {
5008
5077
  function buildServer(opts) {
5009
5078
  const runTurn = opts.runTurn ?? runChatTurn;
5010
5079
  const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
5011
- const reposRoot = opts.reposRoot ?? path18.join(path18.dirname(path18.resolve(opts.cwd)), "repos");
5080
+ const reposRoot = opts.reposRoot ?? path19.join(path19.dirname(path19.resolve(opts.cwd)), "repos");
5012
5081
  return createServer(async (req, res) => {
5013
5082
  if (!req.method || !req.url) {
5014
5083
  sendJson(res, 400, { error: "bad request" });
@@ -5263,13 +5332,13 @@ function defaultLabelMap() {
5263
5332
  }
5264
5333
 
5265
5334
  // src/scripts/commitAndPush.ts
5266
- import * as fs21 from "fs";
5267
- import * as path20 from "path";
5335
+ import * as fs22 from "fs";
5336
+ import * as path21 from "path";
5268
5337
  init_events();
5269
5338
  var DEFAULT_COMMIT_MESSAGE = "chore: kody changes";
5270
5339
  function sentinelPathForStage(cwd, profileName) {
5271
5340
  const runId = resolveRunId();
5272
- return path20.join(cwd, ".kody", "runs", runId, `commit-${profileName}.lock`);
5341
+ return path21.join(cwd, ".kody", "runs", runId, `commit-${profileName}.lock`);
5273
5342
  }
5274
5343
  var commitAndPush2 = async (ctx, profile) => {
5275
5344
  const branch = ctx.data.branch;
@@ -5279,9 +5348,9 @@ var commitAndPush2 = async (ctx, profile) => {
5279
5348
  }
5280
5349
  const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
5281
5350
  const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name) : null;
5282
- if (sentinel && fs21.existsSync(sentinel)) {
5351
+ if (sentinel && fs22.existsSync(sentinel)) {
5283
5352
  try {
5284
- const replay = JSON.parse(fs21.readFileSync(sentinel, "utf-8"));
5353
+ const replay = JSON.parse(fs22.readFileSync(sentinel, "utf-8"));
5285
5354
  ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
5286
5355
  if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
5287
5356
  if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
@@ -5334,8 +5403,8 @@ var commitAndPush2 = async (ctx, profile) => {
5334
5403
  const result = ctx.data.commitResult;
5335
5404
  if (sentinel && result?.committed) {
5336
5405
  try {
5337
- fs21.mkdirSync(path20.dirname(sentinel), { recursive: true });
5338
- fs21.writeFileSync(
5406
+ fs22.mkdirSync(path21.dirname(sentinel), { recursive: true });
5407
+ fs22.writeFileSync(
5339
5408
  sentinel,
5340
5409
  JSON.stringify(
5341
5410
  {
@@ -5396,14 +5465,14 @@ function ensureStateBranch(owner, repo, cwd) {
5396
5465
  }
5397
5466
 
5398
5467
  // src/goal/state.ts
5399
- import * as fs22 from "fs";
5400
- import * as path21 from "path";
5468
+ import * as fs23 from "fs";
5469
+ import * as path22 from "path";
5401
5470
  var VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "awaiting-merge", "done"]);
5402
5471
  var GoalStateError = class extends Error {
5403
- constructor(path39, message) {
5404
- super(`Invalid goal state at ${path39}:
5472
+ constructor(path40, message) {
5473
+ super(`Invalid goal state at ${path40}:
5405
5474
  ${message}`);
5406
- this.path = path39;
5475
+ this.path = path40;
5407
5476
  this.name = "GoalStateError";
5408
5477
  }
5409
5478
  path;
@@ -5543,20 +5612,20 @@ function describeCommitMessage(goal) {
5543
5612
  }
5544
5613
 
5545
5614
  // src/scripts/composePrompt.ts
5546
- import * as fs23 from "fs";
5547
- import * as path22 from "path";
5615
+ import * as fs24 from "fs";
5616
+ import * as path23 from "path";
5548
5617
  var MUSTACHE = /\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g;
5549
5618
  var composePrompt = async (ctx, profile) => {
5550
5619
  const explicit = ctx.data.promptTemplate;
5551
5620
  const mode = ctx.args.mode;
5552
5621
  const candidates = [
5553
- explicit ? path22.join(profile.dir, explicit) : null,
5554
- mode ? path22.join(profile.dir, "prompts", `${mode}.md`) : null,
5555
- path22.join(profile.dir, "prompt.md")
5622
+ explicit ? path23.join(profile.dir, explicit) : null,
5623
+ mode ? path23.join(profile.dir, "prompts", `${mode}.md`) : null,
5624
+ path23.join(profile.dir, "prompt.md")
5556
5625
  ].filter(Boolean);
5557
5626
  let templatePath = "";
5558
5627
  for (const c of candidates) {
5559
- if (fs23.existsSync(c)) {
5628
+ if (fs24.existsSync(c)) {
5560
5629
  templatePath = c;
5561
5630
  break;
5562
5631
  }
@@ -5564,7 +5633,7 @@ var composePrompt = async (ctx, profile) => {
5564
5633
  if (!templatePath) {
5565
5634
  throw new Error(`profile at ${profile.dir}: no prompt template found (tried ${candidates.join(", ")})`);
5566
5635
  }
5567
- const template = fs23.readFileSync(templatePath, "utf-8");
5636
+ const template = fs24.readFileSync(templatePath, "utf-8");
5568
5637
  const tokens = {
5569
5638
  ...stringifyAll(ctx.args, "args."),
5570
5639
  ...stringifyAll(ctx.data, ""),
@@ -6342,15 +6411,15 @@ function filterGoalTaskPrs(prs, taskIssueNumbers) {
6342
6411
 
6343
6412
  // src/scripts/diagMcp.ts
6344
6413
  import { execFileSync as execFileSync10 } from "child_process";
6345
- import * as fs24 from "fs";
6414
+ import * as fs25 from "fs";
6346
6415
  import * as os4 from "os";
6347
- import * as path23 from "path";
6416
+ import * as path24 from "path";
6348
6417
  var diagMcp = async (_ctx) => {
6349
6418
  const home = os4.homedir();
6350
- const cacheDir = path23.join(home, ".cache", "ms-playwright");
6419
+ const cacheDir = path24.join(home, ".cache", "ms-playwright");
6351
6420
  let entries = [];
6352
6421
  try {
6353
- entries = fs24.readdirSync(cacheDir);
6422
+ entries = fs25.readdirSync(cacheDir);
6354
6423
  } catch {
6355
6424
  }
6356
6425
  const hasChromium = entries.some((e) => e.startsWith("chromium"));
@@ -6376,17 +6445,17 @@ var diagMcp = async (_ctx) => {
6376
6445
  };
6377
6446
 
6378
6447
  // src/scripts/discoverQaContext.ts
6379
- import * as fs26 from "fs";
6380
- import * as path25 from "path";
6448
+ import * as fs27 from "fs";
6449
+ import * as path26 from "path";
6381
6450
 
6382
6451
  // src/scripts/frameworkDetectors.ts
6383
- import * as fs25 from "fs";
6384
- import * as path24 from "path";
6452
+ import * as fs26 from "fs";
6453
+ import * as path25 from "path";
6385
6454
  function detectFrameworks(cwd) {
6386
6455
  const out = [];
6387
6456
  let deps = {};
6388
6457
  try {
6389
- const pkg = JSON.parse(fs25.readFileSync(path24.join(cwd, "package.json"), "utf-8"));
6458
+ const pkg = JSON.parse(fs26.readFileSync(path25.join(cwd, "package.json"), "utf-8"));
6390
6459
  deps = { ...pkg.dependencies, ...pkg.devDependencies };
6391
6460
  } catch {
6392
6461
  return out;
@@ -6423,7 +6492,7 @@ function detectFrameworks(cwd) {
6423
6492
  }
6424
6493
  function findFile(cwd, candidates) {
6425
6494
  for (const c of candidates) {
6426
- if (fs25.existsSync(path24.join(cwd, c))) return c;
6495
+ if (fs26.existsSync(path25.join(cwd, c))) return c;
6427
6496
  }
6428
6497
  return null;
6429
6498
  }
@@ -6436,18 +6505,18 @@ var COLLECTION_DIRS = [
6436
6505
  function discoverPayloadCollections(cwd) {
6437
6506
  const out = [];
6438
6507
  for (const dir of COLLECTION_DIRS) {
6439
- const full = path24.join(cwd, dir);
6440
- if (!fs25.existsSync(full)) continue;
6508
+ const full = path25.join(cwd, dir);
6509
+ if (!fs26.existsSync(full)) continue;
6441
6510
  let files;
6442
6511
  try {
6443
- files = fs25.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
6512
+ files = fs26.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
6444
6513
  } catch {
6445
6514
  continue;
6446
6515
  }
6447
6516
  for (const file of files) {
6448
6517
  try {
6449
- const filePath = path24.join(full, file);
6450
- const content = fs25.readFileSync(filePath, "utf-8").slice(0, 1e4);
6518
+ const filePath = path25.join(full, file);
6519
+ const content = fs26.readFileSync(filePath, "utf-8").slice(0, 1e4);
6451
6520
  const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
6452
6521
  if (!slugMatch) continue;
6453
6522
  const slug = slugMatch[1];
@@ -6461,7 +6530,7 @@ function discoverPayloadCollections(cwd) {
6461
6530
  out.push({
6462
6531
  name,
6463
6532
  slug,
6464
- filePath: path24.relative(cwd, filePath),
6533
+ filePath: path25.relative(cwd, filePath),
6465
6534
  fields: fields.slice(0, 20),
6466
6535
  hasAdmin
6467
6536
  });
@@ -6475,28 +6544,28 @@ var ADMIN_COMPONENT_DIRS = ["src/ui/admin", "src/admin/components", "src/compone
6475
6544
  function discoverAdminComponents(cwd, collections) {
6476
6545
  const out = [];
6477
6546
  for (const dir of ADMIN_COMPONENT_DIRS) {
6478
- const full = path24.join(cwd, dir);
6479
- if (!fs25.existsSync(full)) continue;
6547
+ const full = path25.join(cwd, dir);
6548
+ if (!fs26.existsSync(full)) continue;
6480
6549
  let entries;
6481
6550
  try {
6482
- entries = fs25.readdirSync(full, { withFileTypes: true });
6551
+ entries = fs26.readdirSync(full, { withFileTypes: true });
6483
6552
  } catch {
6484
6553
  continue;
6485
6554
  }
6486
6555
  for (const entry of entries) {
6487
- const entryPath = path24.join(full, entry.name);
6556
+ const entryPath = path25.join(full, entry.name);
6488
6557
  let name;
6489
6558
  let filePath;
6490
6559
  if (entry.isDirectory()) {
6491
6560
  const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
6492
- (f) => fs25.existsSync(path24.join(entryPath, f))
6561
+ (f) => fs26.existsSync(path25.join(entryPath, f))
6493
6562
  );
6494
6563
  if (!indexFile) continue;
6495
6564
  name = entry.name;
6496
- filePath = path24.relative(cwd, path24.join(entryPath, indexFile));
6565
+ filePath = path25.relative(cwd, path25.join(entryPath, indexFile));
6497
6566
  } else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
6498
6567
  name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
6499
- filePath = path24.relative(cwd, entryPath);
6568
+ filePath = path25.relative(cwd, entryPath);
6500
6569
  } else {
6501
6570
  continue;
6502
6571
  }
@@ -6504,7 +6573,7 @@ function discoverAdminComponents(cwd, collections) {
6504
6573
  if (collections) {
6505
6574
  for (const col of collections) {
6506
6575
  try {
6507
- const colContent = fs25.readFileSync(path24.join(cwd, col.filePath), "utf-8");
6576
+ const colContent = fs26.readFileSync(path25.join(cwd, col.filePath), "utf-8");
6508
6577
  if (colContent.includes(name)) {
6509
6578
  usedInCollection = col.slug;
6510
6579
  break;
@@ -6523,8 +6592,8 @@ function scanApiRoutes(cwd) {
6523
6592
  const out = [];
6524
6593
  const appDirs = ["src/app", "app"];
6525
6594
  for (const appDir of appDirs) {
6526
- const apiDir = path24.join(cwd, appDir, "api");
6527
- if (!fs25.existsSync(apiDir)) continue;
6595
+ const apiDir = path25.join(cwd, appDir, "api");
6596
+ if (!fs26.existsSync(apiDir)) continue;
6528
6597
  walkApiRoutes(apiDir, "/api", cwd, out);
6529
6598
  break;
6530
6599
  }
@@ -6533,14 +6602,14 @@ function scanApiRoutes(cwd) {
6533
6602
  function walkApiRoutes(dir, prefix, cwd, out) {
6534
6603
  let entries;
6535
6604
  try {
6536
- entries = fs25.readdirSync(dir, { withFileTypes: true });
6605
+ entries = fs26.readdirSync(dir, { withFileTypes: true });
6537
6606
  } catch {
6538
6607
  return;
6539
6608
  }
6540
6609
  const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
6541
6610
  if (routeFile) {
6542
6611
  try {
6543
- const content = fs25.readFileSync(path24.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
6612
+ const content = fs26.readFileSync(path25.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
6544
6613
  const methods = HTTP_METHODS.filter(
6545
6614
  (m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
6546
6615
  );
@@ -6548,7 +6617,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
6548
6617
  out.push({
6549
6618
  path: prefix,
6550
6619
  methods,
6551
- filePath: path24.relative(cwd, path24.join(dir, routeFile.name))
6620
+ filePath: path25.relative(cwd, path25.join(dir, routeFile.name))
6552
6621
  });
6553
6622
  }
6554
6623
  } catch {
@@ -6559,7 +6628,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
6559
6628
  if (entry.name === "node_modules" || entry.name === ".next") continue;
6560
6629
  let segment = entry.name;
6561
6630
  if (segment.startsWith("(") && segment.endsWith(")")) {
6562
- walkApiRoutes(path24.join(dir, entry.name), prefix, cwd, out);
6631
+ walkApiRoutes(path25.join(dir, entry.name), prefix, cwd, out);
6563
6632
  continue;
6564
6633
  }
6565
6634
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -6567,7 +6636,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
6567
6636
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
6568
6637
  segment = `:${segment.slice(1, -1)}`;
6569
6638
  }
6570
- walkApiRoutes(path24.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
6639
+ walkApiRoutes(path25.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
6571
6640
  }
6572
6641
  }
6573
6642
  var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
@@ -6587,10 +6656,10 @@ var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
6587
6656
  function scanEnvVars(cwd) {
6588
6657
  const candidates = [".env.example", ".env.local.example", ".env.template"];
6589
6658
  for (const envFile of candidates) {
6590
- const envPath = path24.join(cwd, envFile);
6591
- if (!fs25.existsSync(envPath)) continue;
6659
+ const envPath = path25.join(cwd, envFile);
6660
+ if (!fs26.existsSync(envPath)) continue;
6592
6661
  try {
6593
- const content = fs25.readFileSync(envPath, "utf-8");
6662
+ const content = fs26.readFileSync(envPath, "utf-8");
6594
6663
  const vars = [];
6595
6664
  for (const line of content.split("\n")) {
6596
6665
  const trimmed = line.trim();
@@ -6638,9 +6707,9 @@ function runQaDiscovery(cwd) {
6638
6707
  }
6639
6708
  function detectDevServer(cwd, out) {
6640
6709
  try {
6641
- const pkg = JSON.parse(fs26.readFileSync(path25.join(cwd, "package.json"), "utf-8"));
6710
+ const pkg = JSON.parse(fs27.readFileSync(path26.join(cwd, "package.json"), "utf-8"));
6642
6711
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
6643
- const pm = fs26.existsSync(path25.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs26.existsSync(path25.join(cwd, "yarn.lock")) ? "yarn" : fs26.existsSync(path25.join(cwd, "bun.lockb")) ? "bun" : "npm";
6712
+ const pm = fs27.existsSync(path26.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs27.existsSync(path26.join(cwd, "yarn.lock")) ? "yarn" : fs27.existsSync(path26.join(cwd, "bun.lockb")) ? "bun" : "npm";
6644
6713
  if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
6645
6714
  if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
6646
6715
  else if (allDeps.vite) out.devPort = 5173;
@@ -6650,8 +6719,8 @@ function detectDevServer(cwd, out) {
6650
6719
  function scanFrontendRoutes(cwd, out) {
6651
6720
  const appDirs = ["src/app", "app"];
6652
6721
  for (const appDir of appDirs) {
6653
- const full = path25.join(cwd, appDir);
6654
- if (!fs26.existsSync(full)) continue;
6722
+ const full = path26.join(cwd, appDir);
6723
+ if (!fs27.existsSync(full)) continue;
6655
6724
  walkFrontendRoutes(full, "", out);
6656
6725
  break;
6657
6726
  }
@@ -6659,7 +6728,7 @@ function scanFrontendRoutes(cwd, out) {
6659
6728
  function walkFrontendRoutes(dir, prefix, out) {
6660
6729
  let entries;
6661
6730
  try {
6662
- entries = fs26.readdirSync(dir, { withFileTypes: true });
6731
+ entries = fs27.readdirSync(dir, { withFileTypes: true });
6663
6732
  } catch {
6664
6733
  return;
6665
6734
  }
@@ -6676,7 +6745,7 @@ function walkFrontendRoutes(dir, prefix, out) {
6676
6745
  if (entry.name === "node_modules" || entry.name === ".next") continue;
6677
6746
  let segment = entry.name;
6678
6747
  if (segment.startsWith("(") && segment.endsWith(")")) {
6679
- walkFrontendRoutes(path25.join(dir, entry.name), prefix, out);
6748
+ walkFrontendRoutes(path26.join(dir, entry.name), prefix, out);
6680
6749
  continue;
6681
6750
  }
6682
6751
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -6684,7 +6753,7 @@ function walkFrontendRoutes(dir, prefix, out) {
6684
6753
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
6685
6754
  segment = `:${segment.slice(1, -1)}`;
6686
6755
  }
6687
- walkFrontendRoutes(path25.join(dir, entry.name), `${prefix}/${segment}`, out);
6756
+ walkFrontendRoutes(path26.join(dir, entry.name), `${prefix}/${segment}`, out);
6688
6757
  }
6689
6758
  }
6690
6759
  function detectAuthFiles(cwd, out) {
@@ -6701,23 +6770,23 @@ function detectAuthFiles(cwd, out) {
6701
6770
  "src/app/api/oauth"
6702
6771
  ];
6703
6772
  for (const c of candidates) {
6704
- if (fs26.existsSync(path25.join(cwd, c))) out.authFiles.push(c);
6773
+ if (fs27.existsSync(path26.join(cwd, c))) out.authFiles.push(c);
6705
6774
  }
6706
6775
  }
6707
6776
  function detectRoles(cwd, out) {
6708
6777
  const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
6709
6778
  for (const rp of rolePaths) {
6710
- const dir = path25.join(cwd, rp);
6711
- if (!fs26.existsSync(dir)) continue;
6779
+ const dir = path26.join(cwd, rp);
6780
+ if (!fs27.existsSync(dir)) continue;
6712
6781
  let files;
6713
6782
  try {
6714
- files = fs26.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
6783
+ files = fs27.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
6715
6784
  } catch {
6716
6785
  continue;
6717
6786
  }
6718
6787
  for (const f of files) {
6719
6788
  try {
6720
- const content = fs26.readFileSync(path25.join(dir, f), "utf-8").slice(0, 5e3);
6789
+ const content = fs27.readFileSync(path26.join(dir, f), "utf-8").slice(0, 5e3);
6721
6790
  const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
6722
6791
  if (roleMatches) {
6723
6792
  for (const m of roleMatches) {
@@ -6901,8 +6970,8 @@ function failedAction3(reason) {
6901
6970
  }
6902
6971
 
6903
6972
  // src/scripts/dispatchJobFileTicks.ts
6904
- import * as fs28 from "fs";
6905
- import * as path27 from "path";
6973
+ import * as fs29 from "fs";
6974
+ import * as path28 from "path";
6906
6975
 
6907
6976
  // src/scripts/jobFrontmatter.ts
6908
6977
  var SCHEDULE_EVERY_VALUES = [
@@ -7171,8 +7240,8 @@ var ContentsApiBackend = class {
7171
7240
  };
7172
7241
 
7173
7242
  // src/scripts/jobState/localFileBackend.ts
7174
- import * as fs27 from "fs";
7175
- import * as path26 from "path";
7243
+ import * as fs28 from "fs";
7244
+ import * as path27 from "path";
7176
7245
  var LocalFileBackend = class {
7177
7246
  name = "local-file";
7178
7247
  cwd;
@@ -7187,7 +7256,7 @@ var LocalFileBackend = class {
7187
7256
  if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
7188
7257
  this.cwd = opts.cwd;
7189
7258
  this.jobsDir = opts.jobsDir;
7190
- this.absDir = path26.join(opts.cwd, opts.jobsDir);
7259
+ this.absDir = path27.join(opts.cwd, opts.jobsDir);
7191
7260
  this.owner = opts.owner;
7192
7261
  this.repo = opts.repo;
7193
7262
  this.cache = opts.cache ?? defaultCacheAdapter();
@@ -7202,7 +7271,7 @@ var LocalFileBackend = class {
7202
7271
  `);
7203
7272
  return;
7204
7273
  }
7205
- fs27.mkdirSync(this.absDir, { recursive: true });
7274
+ fs28.mkdirSync(this.absDir, { recursive: true });
7206
7275
  const prefix = this.cacheKeyPrefix();
7207
7276
  const probeKey = `${prefix}probe-${Date.now()}`;
7208
7277
  try {
@@ -7231,7 +7300,7 @@ var LocalFileBackend = class {
7231
7300
  `);
7232
7301
  return;
7233
7302
  }
7234
- if (!fs27.existsSync(this.absDir)) {
7303
+ if (!fs28.existsSync(this.absDir)) {
7235
7304
  return;
7236
7305
  }
7237
7306
  const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
@@ -7247,11 +7316,11 @@ var LocalFileBackend = class {
7247
7316
  }
7248
7317
  load(slug) {
7249
7318
  const relPath = stateFilePath(this.jobsDir, slug);
7250
- const absPath = path26.join(this.cwd, relPath);
7251
- if (!fs27.existsSync(absPath)) {
7319
+ const absPath = path27.join(this.cwd, relPath);
7320
+ if (!fs28.existsSync(absPath)) {
7252
7321
  return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
7253
7322
  }
7254
- const raw = fs27.readFileSync(absPath, "utf-8");
7323
+ const raw = fs28.readFileSync(absPath, "utf-8");
7255
7324
  let parsed;
7256
7325
  try {
7257
7326
  parsed = JSON.parse(raw);
@@ -7268,10 +7337,10 @@ var LocalFileBackend = class {
7268
7337
  if (!loaded.created && isStateUnchanged(loaded.state, next)) {
7269
7338
  return false;
7270
7339
  }
7271
- const absPath = path26.join(this.cwd, loaded.path);
7272
- fs27.mkdirSync(path26.dirname(absPath), { recursive: true });
7340
+ const absPath = path27.join(this.cwd, loaded.path);
7341
+ fs28.mkdirSync(path27.dirname(absPath), { recursive: true });
7273
7342
  const body = JSON.stringify(next, null, 2) + "\n";
7274
- fs27.writeFileSync(absPath, body, "utf-8");
7343
+ fs28.writeFileSync(absPath, body, "utf-8");
7275
7344
  return true;
7276
7345
  }
7277
7346
  cacheKeyPrefix() {
@@ -7349,7 +7418,7 @@ var dispatchJobFileTicks = async (ctx, _profile, args) => {
7349
7418
  await backend.hydrate();
7350
7419
  }
7351
7420
  try {
7352
- const slugs = listJobSlugs(path27.join(ctx.cwd, jobsDir));
7421
+ const slugs = listJobSlugs(path28.join(ctx.cwd, jobsDir));
7353
7422
  ctx.data.jobSlugCount = slugs.length;
7354
7423
  if (slugs.length === 0) {
7355
7424
  process.stdout.write(`[jobs] no job files in ${jobsDir}
@@ -7462,17 +7531,17 @@ function formatAgo(ms) {
7462
7531
  }
7463
7532
  function readJobFrontmatter(cwd, jobsDir, slug) {
7464
7533
  try {
7465
- const raw = fs28.readFileSync(path27.join(cwd, jobsDir, `${slug}.md`), "utf-8");
7534
+ const raw = fs29.readFileSync(path28.join(cwd, jobsDir, `${slug}.md`), "utf-8");
7466
7535
  return splitFrontmatter2(raw).frontmatter;
7467
7536
  } catch {
7468
7537
  return {};
7469
7538
  }
7470
7539
  }
7471
7540
  function listJobSlugs(absDir) {
7472
- if (!fs28.existsSync(absDir)) return [];
7541
+ if (!fs29.existsSync(absDir)) return [];
7473
7542
  let entries;
7474
7543
  try {
7475
- entries = fs28.readdirSync(absDir, { withFileTypes: true });
7544
+ entries = fs29.readdirSync(absDir, { withFileTypes: true });
7476
7545
  } catch {
7477
7546
  return [];
7478
7547
  }
@@ -8265,7 +8334,7 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch2, cwd, baseBranch
8265
8334
 
8266
8335
  // src/gha.ts
8267
8336
  import { execFileSync as execFileSync16 } from "child_process";
8268
- import * as fs29 from "fs";
8337
+ import * as fs30 from "fs";
8269
8338
  function getRunUrl() {
8270
8339
  const server = process.env.GITHUB_SERVER_URL;
8271
8340
  const repo = process.env.GITHUB_REPOSITORY;
@@ -8276,10 +8345,10 @@ function getRunUrl() {
8276
8345
  function reactToTriggerComment(cwd) {
8277
8346
  if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
8278
8347
  const eventPath = process.env.GITHUB_EVENT_PATH;
8279
- if (!eventPath || !fs29.existsSync(eventPath)) return;
8348
+ if (!eventPath || !fs30.existsSync(eventPath)) return;
8280
8349
  let event = null;
8281
8350
  try {
8282
- event = JSON.parse(fs29.readFileSync(eventPath, "utf-8"));
8351
+ event = JSON.parse(fs30.readFileSync(eventPath, "utf-8"));
8283
8352
  } catch {
8284
8353
  return;
8285
8354
  }
@@ -8573,12 +8642,12 @@ var handleAbandonedGoal = async (ctx) => {
8573
8642
 
8574
8643
  // src/scripts/initFlow.ts
8575
8644
  import { execFileSync as execFileSync18 } from "child_process";
8576
- import * as fs30 from "fs";
8577
- import * as path28 from "path";
8645
+ import * as fs31 from "fs";
8646
+ import * as path29 from "path";
8578
8647
  function detectPackageManager(cwd) {
8579
- if (fs30.existsSync(path28.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
8580
- if (fs30.existsSync(path28.join(cwd, "yarn.lock"))) return "yarn";
8581
- if (fs30.existsSync(path28.join(cwd, "bun.lockb"))) return "bun";
8648
+ if (fs31.existsSync(path29.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
8649
+ if (fs31.existsSync(path29.join(cwd, "yarn.lock"))) return "yarn";
8650
+ if (fs31.existsSync(path29.join(cwd, "bun.lockb"))) return "bun";
8582
8651
  return "npm";
8583
8652
  }
8584
8653
  function qualityCommandsFor(pm) {
@@ -8707,36 +8776,36 @@ function performInit(cwd, force) {
8707
8776
  const pm = detectPackageManager(cwd);
8708
8777
  const ownerRepo = detectOwnerRepo(cwd);
8709
8778
  const defaultBranch2 = defaultBranchFromGit(cwd);
8710
- const configPath = path28.join(cwd, "kody.config.json");
8711
- if (fs30.existsSync(configPath) && !force) {
8779
+ const configPath = path29.join(cwd, "kody.config.json");
8780
+ if (fs31.existsSync(configPath) && !force) {
8712
8781
  skipped.push("kody.config.json");
8713
8782
  } else {
8714
8783
  const cfg = makeConfig(pm, ownerRepo, defaultBranch2);
8715
- fs30.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
8784
+ fs31.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
8716
8785
  `);
8717
8786
  wrote.push("kody.config.json");
8718
8787
  }
8719
- const workflowDir = path28.join(cwd, ".github", "workflows");
8720
- const workflowPath = path28.join(workflowDir, "kody.yml");
8721
- if (fs30.existsSync(workflowPath) && !force) {
8788
+ const workflowDir = path29.join(cwd, ".github", "workflows");
8789
+ const workflowPath = path29.join(workflowDir, "kody.yml");
8790
+ if (fs31.existsSync(workflowPath) && !force) {
8722
8791
  skipped.push(".github/workflows/kody.yml");
8723
8792
  } else {
8724
- fs30.mkdirSync(workflowDir, { recursive: true });
8725
- fs30.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
8793
+ fs31.mkdirSync(workflowDir, { recursive: true });
8794
+ fs31.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
8726
8795
  wrote.push(".github/workflows/kody.yml");
8727
8796
  }
8728
8797
  const builtinJobs = listBuiltinJobs();
8729
8798
  if (builtinJobs.length > 0) {
8730
- const jobsDir = path28.join(cwd, ".kody", "duties");
8731
- fs30.mkdirSync(jobsDir, { recursive: true });
8799
+ const jobsDir = path29.join(cwd, ".kody", "duties");
8800
+ fs31.mkdirSync(jobsDir, { recursive: true });
8732
8801
  for (const job of builtinJobs) {
8733
- const rel = path28.join(".kody", "duties", `${job.slug}.md`);
8734
- const target = path28.join(cwd, rel);
8735
- if (fs30.existsSync(target) && !force) {
8802
+ const rel = path29.join(".kody", "duties", `${job.slug}.md`);
8803
+ const target = path29.join(cwd, rel);
8804
+ if (fs31.existsSync(target) && !force) {
8736
8805
  skipped.push(rel);
8737
8806
  continue;
8738
8807
  }
8739
- fs30.writeFileSync(target, fs30.readFileSync(job.filePath, "utf-8"));
8808
+ fs31.writeFileSync(target, fs31.readFileSync(job.filePath, "utf-8"));
8740
8809
  wrote.push(rel);
8741
8810
  }
8742
8811
  }
@@ -8748,12 +8817,12 @@ function performInit(cwd, force) {
8748
8817
  continue;
8749
8818
  }
8750
8819
  if (profile.kind !== "scheduled" || !profile.schedule) continue;
8751
- const target = path28.join(workflowDir, `kody-${exe.name}.yml`);
8752
- if (fs30.existsSync(target) && !force) {
8820
+ const target = path29.join(workflowDir, `kody-${exe.name}.yml`);
8821
+ if (fs31.existsSync(target) && !force) {
8753
8822
  skipped.push(`.github/workflows/kody-${exe.name}.yml`);
8754
8823
  continue;
8755
8824
  }
8756
- fs30.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
8825
+ fs31.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
8757
8826
  wrote.push(`.github/workflows/kody-${exe.name}.yml`);
8758
8827
  }
8759
8828
  let labels;
@@ -8937,8 +9006,8 @@ var loadIssueStateComment = async (ctx, _profile, args) => {
8937
9006
  };
8938
9007
 
8939
9008
  // src/scripts/loadJobFromFile.ts
8940
- import * as fs31 from "fs";
8941
- import * as path29 from "path";
9009
+ import * as fs32 from "fs";
9010
+ import * as path30 from "path";
8942
9011
  var loadJobFromFile = async (ctx, _profile, args) => {
8943
9012
  const jobsDir = String(args?.jobsDir ?? ".kody/duties");
8944
9013
  const workersDir = String(args?.workersDir ?? ".kody/staff");
@@ -8947,11 +9016,11 @@ var loadJobFromFile = async (ctx, _profile, args) => {
8947
9016
  if (!slug) {
8948
9017
  throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
8949
9018
  }
8950
- const absPath = path29.join(ctx.cwd, jobsDir, `${slug}.md`);
8951
- if (!fs31.existsSync(absPath)) {
9019
+ const absPath = path30.join(ctx.cwd, jobsDir, `${slug}.md`);
9020
+ if (!fs32.existsSync(absPath)) {
8952
9021
  throw new Error(`loadJobFromFile: job file not found: ${absPath}`);
8953
9022
  }
8954
- const raw = fs31.readFileSync(absPath, "utf-8");
9023
+ const raw = fs32.readFileSync(absPath, "utf-8");
8955
9024
  const { title, body } = parseJobFile(raw, slug);
8956
9025
  const frontmatter = splitFrontmatter2(raw).frontmatter;
8957
9026
  const mentions = (frontmatter.mentions ?? []).map((login) => `@${login}`).join(" ");
@@ -8959,13 +9028,13 @@ var loadJobFromFile = async (ctx, _profile, args) => {
8959
9028
  let workerTitle = "";
8960
9029
  let workerPersona = "";
8961
9030
  if (workerSlug) {
8962
- const workerPath = path29.join(ctx.cwd, workersDir, `${workerSlug}.md`);
8963
- if (!fs31.existsSync(workerPath)) {
9031
+ const workerPath = path30.join(ctx.cwd, workersDir, `${workerSlug}.md`);
9032
+ if (!fs32.existsSync(workerPath)) {
8964
9033
  throw new Error(
8965
9034
  `loadJobFromFile: duty '${slug}' declares staff '${workerSlug}' but ${workerPath} does not exist`
8966
9035
  );
8967
9036
  }
8968
- const workerRaw = fs31.readFileSync(workerPath, "utf-8");
9037
+ const workerRaw = fs32.readFileSync(workerPath, "utf-8");
8969
9038
  const parsed = parseJobFile(workerRaw, workerSlug);
8970
9039
  workerTitle = parsed.title;
8971
9040
  workerPersona = parsed.body;
@@ -9008,18 +9077,18 @@ init_loadMemoryContext();
9008
9077
  init_loadPriorArt();
9009
9078
 
9010
9079
  // src/scripts/loadQaContext.ts
9011
- import * as fs34 from "fs";
9012
- import * as path32 from "path";
9080
+ import * as fs35 from "fs";
9081
+ import * as path33 from "path";
9013
9082
 
9014
9083
  // src/scripts/kodyVariables.ts
9015
- import * as fs33 from "fs";
9016
- import * as path31 from "path";
9084
+ import * as fs34 from "fs";
9085
+ import * as path32 from "path";
9017
9086
  var KODY_VARIABLES_REL_PATH = ".kody/variables.json";
9018
9087
  function readKodyVariables(cwd) {
9019
- const full = path31.join(cwd, KODY_VARIABLES_REL_PATH);
9088
+ const full = path32.join(cwd, KODY_VARIABLES_REL_PATH);
9020
9089
  let raw;
9021
9090
  try {
9022
- raw = fs33.readFileSync(full, "utf-8");
9091
+ raw = fs34.readFileSync(full, "utf-8");
9023
9092
  } catch {
9024
9093
  return {};
9025
9094
  }
@@ -9068,18 +9137,18 @@ function readProfileStaff(raw) {
9068
9137
  return { staff: staff ?? legacy ?? ["kody"], body };
9069
9138
  }
9070
9139
  function readProfile(cwd) {
9071
- const dir = path32.join(cwd, CONTEXT_DIR_REL_PATH);
9072
- if (!fs34.existsSync(dir)) return "";
9140
+ const dir = path33.join(cwd, CONTEXT_DIR_REL_PATH);
9141
+ if (!fs35.existsSync(dir)) return "";
9073
9142
  let entries;
9074
9143
  try {
9075
- entries = fs34.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
9144
+ entries = fs35.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
9076
9145
  } catch {
9077
9146
  return "";
9078
9147
  }
9079
9148
  const blocks = [];
9080
9149
  for (const file of entries) {
9081
9150
  try {
9082
- const raw = fs34.readFileSync(path32.join(dir, file), "utf-8");
9151
+ const raw = fs35.readFileSync(path33.join(dir, file), "utf-8");
9083
9152
  const { staff, body } = readProfileStaff(raw);
9084
9153
  if (!staff.includes(QA_STAFF) && !staff.includes(ALL_STAFF)) continue;
9085
9154
  blocks.push(`## ${file}
@@ -9116,8 +9185,8 @@ var loadQaContext = async (ctx) => {
9116
9185
  init_events();
9117
9186
 
9118
9187
  // src/taskContext.ts
9119
- import * as fs35 from "fs";
9120
- import * as path33 from "path";
9188
+ import * as fs36 from "fs";
9189
+ import * as path34 from "path";
9121
9190
  var TASK_CONTEXT_SCHEMA_VERSION = 1;
9122
9191
  function buildTaskContext(args) {
9123
9192
  return {
@@ -9133,10 +9202,10 @@ function buildTaskContext(args) {
9133
9202
  }
9134
9203
  function persistTaskContext(cwd, ctx) {
9135
9204
  try {
9136
- const dir = path33.join(cwd, ".kody", "runs", ctx.runId);
9137
- fs35.mkdirSync(dir, { recursive: true });
9138
- const file = path33.join(dir, "task-context.json");
9139
- fs35.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
9205
+ const dir = path34.join(cwd, ".kody", "runs", ctx.runId);
9206
+ fs36.mkdirSync(dir, { recursive: true });
9207
+ const file = path34.join(dir, "task-context.json");
9208
+ fs36.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
9140
9209
  `);
9141
9210
  return file;
9142
9211
  } catch (err) {
@@ -9184,19 +9253,19 @@ var loadTaskState = async (ctx) => {
9184
9253
  };
9185
9254
 
9186
9255
  // src/scripts/loadWorkerAdhoc.ts
9187
- import * as fs36 from "fs";
9188
- import * as path34 from "path";
9256
+ import * as fs37 from "fs";
9257
+ import * as path35 from "path";
9189
9258
  var loadWorkerAdhoc = async (ctx, _profile, args) => {
9190
9259
  const workersDir = String(args?.workersDir ?? ".kody/staff");
9191
9260
  const workerSlug = String(ctx.args.worker ?? "").trim();
9192
9261
  if (!workerSlug) {
9193
9262
  throw new Error("loadWorkerAdhoc: ctx.args.worker must be a non-empty slug");
9194
9263
  }
9195
- const workerPath = path34.join(ctx.cwd, workersDir, `${workerSlug}.md`);
9196
- if (!fs36.existsSync(workerPath)) {
9264
+ const workerPath = path35.join(ctx.cwd, workersDir, `${workerSlug}.md`);
9265
+ if (!fs37.existsSync(workerPath)) {
9197
9266
  throw new Error(`loadWorkerAdhoc: worker persona not found: ${workerPath}`);
9198
9267
  }
9199
- const { title, body } = parsePersona(fs36.readFileSync(workerPath, "utf-8"), workerSlug);
9268
+ const { title, body } = parsePersona(fs37.readFileSync(workerPath, "utf-8"), workerSlug);
9200
9269
  const message = resolveMessage(ctx.args.message);
9201
9270
  if (!message) {
9202
9271
  throw new Error(
@@ -9216,9 +9285,9 @@ function resolveMessage(messageArg) {
9216
9285
  }
9217
9286
  function readCommentBody() {
9218
9287
  const eventPath = process.env.GITHUB_EVENT_PATH;
9219
- if (!eventPath || !fs36.existsSync(eventPath)) return "";
9288
+ if (!eventPath || !fs37.existsSync(eventPath)) return "";
9220
9289
  try {
9221
- const event = JSON.parse(fs36.readFileSync(eventPath, "utf-8"));
9290
+ const event = JSON.parse(fs37.readFileSync(eventPath, "utf-8"));
9222
9291
  return String(event.comment?.body ?? "");
9223
9292
  } catch {
9224
9293
  return "";
@@ -9888,8 +9957,8 @@ var FlyClient = class {
9888
9957
  get fetch() {
9889
9958
  return this.opts.fetchImpl ?? fetch;
9890
9959
  }
9891
- async call(path39, init = {}) {
9892
- const res = await this.fetch(`${FLY_API_BASE}${path39}`, {
9960
+ async call(path40, init = {}) {
9961
+ const res = await this.fetch(`${FLY_API_BASE}${path40}`, {
9893
9962
  method: init.method ?? "GET",
9894
9963
  headers: {
9895
9964
  Authorization: `Bearer ${this.opts.token}`,
@@ -9900,7 +9969,7 @@ var FlyClient = class {
9900
9969
  if (res.status === 404 && init.allow404) return null;
9901
9970
  if (!res.ok) {
9902
9971
  const text = await res.text().catch(() => "");
9903
- throw new Error(`Fly API ${res.status} on ${path39}: ${text.slice(0, 200) || res.statusText}`);
9972
+ throw new Error(`Fly API ${res.status} on ${path40}: ${text.slice(0, 200) || res.statusText}`);
9904
9973
  }
9905
9974
  if (res.status === 204) return null;
9906
9975
  const raw = await res.text();
@@ -11576,7 +11645,7 @@ function resolveBaseOverride(value) {
11576
11645
  // src/scripts/runnerServe.ts
11577
11646
  import { spawn as spawn5 } from "child_process";
11578
11647
  import { createServer as createServer3 } from "http";
11579
- import * as fs37 from "fs";
11648
+ import * as fs38 from "fs";
11580
11649
  var DEFAULT_PORT2 = 8080;
11581
11650
  var DEFAULT_WORKDIR = "/workspace/repo";
11582
11651
  function getApiKey2() {
@@ -11657,8 +11726,8 @@ async function defaultRunJob(job) {
11657
11726
  const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
11658
11727
  const branch = job.ref ?? "main";
11659
11728
  const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
11660
- fs37.rmSync(workdir, { recursive: true, force: true });
11661
- fs37.mkdirSync(workdir, { recursive: true });
11729
+ fs38.rmSync(workdir, { recursive: true, force: true });
11730
+ fs38.mkdirSync(workdir, { recursive: true });
11662
11731
  const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
11663
11732
  const interactive = job.mode === "interactive";
11664
11733
  const scheduled = job.mode === "scheduled";
@@ -11799,8 +11868,8 @@ var runnerServe = async (ctx) => {
11799
11868
 
11800
11869
  // src/scripts/runTickScript.ts
11801
11870
  import { spawnSync as spawnSync2 } from "child_process";
11802
- import * as fs38 from "fs";
11803
- import * as path35 from "path";
11871
+ import * as fs39 from "fs";
11872
+ import * as path36 from "path";
11804
11873
  var runTickScript = async (ctx, _profile, args) => {
11805
11874
  ctx.skipAgent = true;
11806
11875
  const jobsDir = String(args?.jobsDir ?? ".kody/duties");
@@ -11812,13 +11881,13 @@ var runTickScript = async (ctx, _profile, args) => {
11812
11881
  ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
11813
11882
  return;
11814
11883
  }
11815
- const jobPath = path35.join(ctx.cwd, jobsDir, `${slug}.md`);
11816
- if (!fs38.existsSync(jobPath)) {
11884
+ const jobPath = path36.join(ctx.cwd, jobsDir, `${slug}.md`);
11885
+ if (!fs39.existsSync(jobPath)) {
11817
11886
  ctx.output.exitCode = 99;
11818
11887
  ctx.output.reason = `runTickScript: job file not found: ${jobPath}`;
11819
11888
  return;
11820
11889
  }
11821
- const raw = fs38.readFileSync(jobPath, "utf-8");
11890
+ const raw = fs39.readFileSync(jobPath, "utf-8");
11822
11891
  const { frontmatter } = splitFrontmatter2(raw);
11823
11892
  const tickScript = frontmatter.tickScript;
11824
11893
  if (!tickScript) {
@@ -11826,8 +11895,8 @@ var runTickScript = async (ctx, _profile, args) => {
11826
11895
  ctx.output.reason = `runTickScript: job ${slug} has no \`tickScript:\` frontmatter \u2014 route via job-tick instead`;
11827
11896
  return;
11828
11897
  }
11829
- const scriptPath = path35.isAbsolute(tickScript) ? tickScript : path35.join(ctx.cwd, tickScript);
11830
- if (!fs38.existsSync(scriptPath)) {
11898
+ const scriptPath = path36.isAbsolute(tickScript) ? tickScript : path36.join(ctx.cwd, tickScript);
11899
+ if (!fs39.existsSync(scriptPath)) {
11831
11900
  ctx.output.exitCode = 99;
11832
11901
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
11833
11902
  return;
@@ -12951,7 +13020,7 @@ var writeJobStateFile = async (ctx, _profile, agentResult, args) => {
12951
13020
  };
12952
13021
 
12953
13022
  // src/scripts/writeRunSummary.ts
12954
- import * as fs39 from "fs";
13023
+ import * as fs40 from "fs";
12955
13024
  var writeRunSummary = async (ctx, profile) => {
12956
13025
  const summaryPath = process.env.GITHUB_STEP_SUMMARY;
12957
13026
  if (!summaryPath) return;
@@ -12973,7 +13042,7 @@ var writeRunSummary = async (ctx, profile) => {
12973
13042
  if (reason) lines.push(`- **Reason:** ${reason}`);
12974
13043
  lines.push("");
12975
13044
  try {
12976
- fs39.appendFileSync(summaryPath, `${lines.join("\n")}
13045
+ fs40.appendFileSync(summaryPath, `${lines.join("\n")}
12977
13046
  `);
12978
13047
  } catch {
12979
13048
  }
@@ -13241,9 +13310,9 @@ async function runExecutable(profileName, input) {
13241
13310
  })
13242
13311
  };
13243
13312
  })() : null;
13244
- const ndjsonDir = path36.join(input.cwd, ".kody");
13313
+ const ndjsonDir = path37.join(input.cwd, ".kody");
13245
13314
  const invokeAgent = async (prompt) => {
13246
- const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path36.isAbsolute(p) ? p : path36.resolve(profile.dir, p)).filter((p) => p.length > 0);
13315
+ const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path37.isAbsolute(p) ? p : path37.resolve(profile.dir, p)).filter((p) => p.length > 0);
13247
13316
  const syntheticPath = ctx.data.syntheticPluginPath;
13248
13317
  const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
13249
13318
  const agents = loadSubagents(profile);
@@ -13457,7 +13526,7 @@ function clearStampedLifecycleLabels(profile, ctx) {
13457
13526
  function getProfileInputsForChild(profileName, _cwd) {
13458
13527
  try {
13459
13528
  const profilePath = resolveProfilePath(profileName);
13460
- if (!fs40.existsSync(profilePath)) return null;
13529
+ if (!fs41.existsSync(profilePath)) return null;
13461
13530
  return loadProfile(profilePath).inputs;
13462
13531
  } catch {
13463
13532
  return null;
@@ -13466,17 +13535,17 @@ function getProfileInputsForChild(profileName, _cwd) {
13466
13535
  function resolveProfilePath(profileName) {
13467
13536
  const found = resolveExecutable(profileName);
13468
13537
  if (found) return found;
13469
- const here = path36.dirname(new URL(import.meta.url).pathname);
13538
+ const here = path37.dirname(new URL(import.meta.url).pathname);
13470
13539
  const candidates = [
13471
- path36.join(here, "executables", profileName, "profile.json"),
13540
+ path37.join(here, "executables", profileName, "profile.json"),
13472
13541
  // same-dir sibling (dev)
13473
- path36.join(here, "..", "executables", profileName, "profile.json"),
13542
+ path37.join(here, "..", "executables", profileName, "profile.json"),
13474
13543
  // up one (prod: dist/bin → dist/executables)
13475
- path36.join(here, "..", "src", "executables", profileName, "profile.json")
13544
+ path37.join(here, "..", "src", "executables", profileName, "profile.json")
13476
13545
  // fallback
13477
13546
  ];
13478
13547
  for (const c of candidates) {
13479
- if (fs40.existsSync(c)) return c;
13548
+ if (fs41.existsSync(c)) return c;
13480
13549
  }
13481
13550
  return candidates[0];
13482
13551
  }
@@ -13576,8 +13645,8 @@ function resolveShellTimeoutMs(entry) {
13576
13645
  var SIGKILL_GRACE_MS = 5e3;
13577
13646
  async function runShellEntry(entry, ctx, profile) {
13578
13647
  const shellName = entry.shell;
13579
- const shellPath = path36.join(profile.dir, shellName);
13580
- if (!fs40.existsSync(shellPath)) {
13648
+ const shellPath = path37.join(profile.dir, shellName);
13649
+ if (!fs41.existsSync(shellPath)) {
13581
13650
  ctx.skipAgent = true;
13582
13651
  ctx.output.exitCode = 99;
13583
13652
  ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
@@ -14083,9 +14152,9 @@ async function resolveAuthToken(env = process.env) {
14083
14152
  return void 0;
14084
14153
  }
14085
14154
  function detectPackageManager2(cwd) {
14086
- if (fs41.existsSync(path37.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
14087
- if (fs41.existsSync(path37.join(cwd, "yarn.lock"))) return "yarn";
14088
- if (fs41.existsSync(path37.join(cwd, "bun.lockb"))) return "bun";
14155
+ if (fs42.existsSync(path38.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
14156
+ if (fs42.existsSync(path38.join(cwd, "yarn.lock"))) return "yarn";
14157
+ if (fs42.existsSync(path38.join(cwd, "bun.lockb"))) return "bun";
14089
14158
  return "npm";
14090
14159
  }
14091
14160
  function shellOut(cmd, args, cwd, stream = true) {
@@ -14172,11 +14241,11 @@ function configureGitIdentity(cwd) {
14172
14241
  }
14173
14242
  function postFailureTail(issueNumber, cwd, reason) {
14174
14243
  if (!issueNumber) return;
14175
- const logPath = path37.join(cwd, ".kody", "last-run.jsonl");
14244
+ const logPath = path38.join(cwd, ".kody", "last-run.jsonl");
14176
14245
  let tail = "";
14177
14246
  try {
14178
- if (fs41.existsSync(logPath)) {
14179
- const content = fs41.readFileSync(logPath, "utf-8");
14247
+ if (fs42.existsSync(logPath)) {
14248
+ const content = fs42.readFileSync(logPath, "utf-8");
14180
14249
  tail = content.slice(-3e3);
14181
14250
  }
14182
14251
  } catch {
@@ -14201,7 +14270,7 @@ async function runCi(argv) {
14201
14270
  return 0;
14202
14271
  }
14203
14272
  const args = parseCiArgs(argv);
14204
- const cwd = args.cwd ? path37.resolve(args.cwd) : process.cwd();
14273
+ const cwd = args.cwd ? path38.resolve(args.cwd) : process.cwd();
14205
14274
  let earlyConfig;
14206
14275
  try {
14207
14276
  earlyConfig = loadConfig(cwd);
@@ -14211,9 +14280,9 @@ async function runCi(argv) {
14211
14280
  const eventName = process.env.GITHUB_EVENT_NAME;
14212
14281
  const dispatchEventPath = process.env.GITHUB_EVENT_PATH;
14213
14282
  let manualWorkflowDispatch = false;
14214
- if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs41.existsSync(dispatchEventPath)) {
14283
+ if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs42.existsSync(dispatchEventPath)) {
14215
14284
  try {
14216
- const evt = JSON.parse(fs41.readFileSync(dispatchEventPath, "utf-8"));
14285
+ const evt = JSON.parse(fs42.readFileSync(dispatchEventPath, "utf-8"));
14217
14286
  const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
14218
14287
  const sessionInput = String(evt?.inputs?.sessionId ?? "");
14219
14288
  manualWorkflowDispatch = !sessionInput && !(Number.isFinite(issueInput) && issueInput > 0);
@@ -14474,12 +14543,12 @@ function parseChatArgs(argv, env = process.env) {
14474
14543
  return result;
14475
14544
  }
14476
14545
  function commitChatFiles(cwd, sessionId, verbose) {
14477
- const sessionFile = path38.relative(cwd, sessionFilePath(cwd, sessionId));
14478
- const eventsFile = path38.relative(cwd, eventsFilePath(cwd, sessionId));
14546
+ const sessionFile = path39.relative(cwd, sessionFilePath(cwd, sessionId));
14547
+ const eventsFile = path39.relative(cwd, eventsFilePath(cwd, sessionId));
14479
14548
  const safeSession = sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
14480
- const tasksDir = path38.join(".kody", "tasks", safeSession);
14549
+ const tasksDir = path39.join(".kody", "tasks", safeSession);
14481
14550
  const candidatePaths = [sessionFile, eventsFile, tasksDir];
14482
- const paths = candidatePaths.filter((p) => fs42.existsSync(path38.join(cwd, p)));
14551
+ const paths = candidatePaths.filter((p) => fs43.existsSync(path39.join(cwd, p)));
14483
14552
  if (paths.length === 0) return;
14484
14553
  const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
14485
14554
  try {
@@ -14523,7 +14592,7 @@ async function runChat(argv) {
14523
14592
  ${CHAT_HELP}`);
14524
14593
  return 64;
14525
14594
  }
14526
- const cwd = args.cwd ? path38.resolve(args.cwd) : process.cwd();
14595
+ const cwd = args.cwd ? path39.resolve(args.cwd) : process.cwd();
14527
14596
  const sessionId = args.sessionId;
14528
14597
  const unpackedSecrets = unpackAllSecrets();
14529
14598
  if (unpackedSecrets > 0) {
@@ -14575,7 +14644,7 @@ ${CHAT_HELP}`);
14575
14644
  const sink = buildSink(cwd, sessionId, args.dashboardUrl);
14576
14645
  const meta = readMeta(sessionFile);
14577
14646
  process.stdout.write(
14578
- `\u2192 kody:chat: session file=${sessionFile} exists=${fs42.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
14647
+ `\u2192 kody:chat: session file=${sessionFile} exists=${fs43.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
14579
14648
  `
14580
14649
  );
14581
14650
  try {