@kody-ade/kody-engine 0.4.157 → 0.4.159

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 +365 -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.159",
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,60 @@ 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 imagePaths = [];
2181
+ let imageCounter = 0;
2182
+ let dirEnsured = false;
2183
+ const dir = attachmentsDir(cwd, sessionId);
2184
+ const rewritten = turns.map((turn) => {
2185
+ if (turn.role !== "user" || !turn.content.includes("base64,")) return turn;
2186
+ const newContent = turn.content.replace(
2187
+ INLINE_ATTACHMENT_RE,
2188
+ (_match, label, mime, data) => {
2189
+ const name = (label ?? "").trim() || "attachment";
2190
+ const isImage = mime.toLowerCase().startsWith("image/");
2191
+ if (!isImage) return `[File: ${name}]`;
2192
+ try {
2193
+ if (!dirEnsured) {
2194
+ fs10.mkdirSync(dir, { recursive: true });
2195
+ dirEnsured = true;
2196
+ }
2197
+ const filePath = path10.join(dir, `${imageCounter}.${extFor(mime)}`);
2198
+ fs10.writeFileSync(filePath, Buffer.from(data, "base64"));
2199
+ imageCounter += 1;
2200
+ imagePaths.push(filePath);
2201
+ return `[Image "${name}" is attached \u2014 saved to ${filePath}. Use the Read tool on that exact path to view it.]`;
2202
+ } catch {
2203
+ return `[Image: ${name} (could not be materialised)]`;
2204
+ }
2205
+ }
2206
+ );
2207
+ if (newContent === turn.content) return turn;
2208
+ return { ...turn, content: newContent };
2209
+ });
2210
+ return { turns: rewritten, imagePaths };
2211
+ }
2212
+
2159
2213
  // src/chat/loop.ts
2160
2214
  var CHAT_SYSTEM_PROMPT = [
2161
2215
  "You are Kody, an AI assistant for the Kody Operations Dashboard. Reply to the",
@@ -2259,7 +2313,7 @@ function buildExecutableCatalog() {
2259
2313
  const entries = [];
2260
2314
  for (const { name, profilePath } of discovered) {
2261
2315
  try {
2262
- const raw = JSON.parse(fs10.readFileSync(profilePath, "utf-8"));
2316
+ const raw = JSON.parse(fs11.readFileSync(profilePath, "utf-8"));
2263
2317
  const describe = typeof raw.describe === "string" ? raw.describe : "";
2264
2318
  const firstSentence = describe.split(/(?<=[.!?])\s+/, 1)[0] ?? "";
2265
2319
  entries.push({ name, describe: firstSentence.trim() });
@@ -2294,6 +2348,7 @@ async function runChatTurn(opts) {
2294
2348
  await emit(opts.sink, "chat.error", opts.sessionId, "error", { error });
2295
2349
  return { exitCode: 64, error };
2296
2350
  }
2351
+ const { turns: promptTurns, imagePaths } = prepareAttachments(turns, opts.cwd, opts.sessionId);
2297
2352
  const basePrompt = opts.systemPrompt ?? CHAT_SYSTEM_PROMPT;
2298
2353
  const catalog = buildExecutableCatalog();
2299
2354
  const taskArtifactsPaths = prepareTaskArtifactsDir(opts.cwd, opts.sessionId);
@@ -2306,16 +2361,25 @@ async function runChatTurn(opts) {
2306
2361
  const memoryBlock = readMemoryIndexBlock(opts.cwd);
2307
2362
  const instructionsBlock = readInstructionsBlock(opts.cwd);
2308
2363
  const crossRepoBlock = opts.reposRoot ? CROSS_REPO_PROMPT : null;
2364
+ const imageBlock = imagePaths.length > 0 ? [
2365
+ "# Attached images",
2366
+ "The user attached one or more images on this turn. They are saved as",
2367
+ "files in this workspace and referenced inline in the conversation as",
2368
+ '`[Image "\u2026" is attached \u2014 saved to <path>]`. You CAN view them: call',
2369
+ "the Read tool on each of those exact paths BEFORE answering. Never tell",
2370
+ "the user you cannot see images \u2014 Read the file and describe what you see."
2371
+ ].join("\n") : null;
2309
2372
  const systemPrompt = [
2310
2373
  basePrompt,
2311
2374
  contextBlock,
2312
2375
  memoryBlock,
2313
2376
  instructionsBlock,
2314
2377
  crossRepoBlock,
2378
+ imageBlock,
2315
2379
  catalog,
2316
2380
  artifactAddendum
2317
2381
  ].filter((s) => typeof s === "string" && s.length > 0).join("\n\n");
2318
- const prompt = buildPrompt(turns);
2382
+ const prompt = buildPrompt(promptTurns);
2319
2383
  let progressSeq = 0;
2320
2384
  const invoke = opts.invokeAgent ?? ((p) => runAgent({
2321
2385
  prompt: p,
@@ -2417,10 +2481,10 @@ async function emit(sink, type, sessionId, suffix, payload) {
2417
2481
  var MEMORY_INDEX_REL = ".kody/memory/INDEX.md";
2418
2482
  var MAX_INDEX_BYTES = 8e3;
2419
2483
  function readMemoryIndexBlock(cwd) {
2420
- const indexPath = path10.join(cwd, MEMORY_INDEX_REL);
2484
+ const indexPath = path11.join(cwd, MEMORY_INDEX_REL);
2421
2485
  let raw;
2422
2486
  try {
2423
- raw = fs10.readFileSync(indexPath, "utf-8");
2487
+ raw = fs11.readFileSync(indexPath, "utf-8");
2424
2488
  } catch {
2425
2489
  return "";
2426
2490
  }
@@ -2438,17 +2502,17 @@ function readMemoryIndexBlock(cwd) {
2438
2502
  var CONTEXT_DIR_REL = ".kody/context";
2439
2503
  var MAX_CONTEXT_BYTES = 12e3;
2440
2504
  function readContextBlock(cwd) {
2441
- const dir = path10.join(cwd, CONTEXT_DIR_REL);
2505
+ const dir = path11.join(cwd, CONTEXT_DIR_REL);
2442
2506
  let files;
2443
2507
  try {
2444
- files = fs10.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
2508
+ files = fs11.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
2445
2509
  } catch {
2446
2510
  return "";
2447
2511
  }
2448
2512
  const sections = [];
2449
2513
  for (const file of files) {
2450
2514
  try {
2451
- const content = fs10.readFileSync(path10.join(dir, file), "utf-8").trim();
2515
+ const content = fs11.readFileSync(path11.join(dir, file), "utf-8").trim();
2452
2516
  if (content) sections.push(`### ${file.replace(/\.md$/, "")}
2453
2517
 
2454
2518
  ${content}`);
@@ -2469,10 +2533,10 @@ ${content}`);
2469
2533
  var INSTRUCTIONS_REL = ".kody/instructions.md";
2470
2534
  var MAX_INSTRUCTIONS_BYTES = 8e3;
2471
2535
  function readInstructionsBlock(cwd) {
2472
- const instructionsPath = path10.join(cwd, INSTRUCTIONS_REL);
2536
+ const instructionsPath = path11.join(cwd, INSTRUCTIONS_REL);
2473
2537
  let raw;
2474
2538
  try {
2475
- raw = fs10.readFileSync(instructionsPath, "utf-8");
2539
+ raw = fs11.readFileSync(instructionsPath, "utf-8");
2476
2540
  } catch {
2477
2541
  return "";
2478
2542
  }
@@ -2491,8 +2555,8 @@ function readInstructionsBlock(cwd) {
2491
2555
  // src/chat/modes/interactive.ts
2492
2556
  init_issue();
2493
2557
  import { execFileSync as execFileSync3 } from "child_process";
2494
- import * as fs11 from "fs";
2495
- import * as path11 from "path";
2558
+ import * as fs12 from "fs";
2559
+ import * as path12 from "path";
2496
2560
 
2497
2561
  // src/chat/inbox.ts
2498
2562
  import { execFileSync as execFileSync2 } from "child_process";
@@ -2651,9 +2715,9 @@ function findNextUserTurn(turns, fromIdx) {
2651
2715
  return -1;
2652
2716
  }
2653
2717
  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)));
2718
+ const sessionRel = path12.relative(cwd, sessionFilePath(cwd, sessionId));
2719
+ const eventsRel = path12.relative(cwd, eventsFilePath(cwd, sessionId));
2720
+ const rels = [sessionRel, eventsRel].filter((p) => fs12.existsSync(path12.join(cwd, p)));
2657
2721
  if (rels.length === 0) return;
2658
2722
  const repository = process.env.GITHUB_REPOSITORY;
2659
2723
  if (!repository) {
@@ -2665,8 +2729,8 @@ function commitTurn(cwd, sessionId, _verbose) {
2665
2729
  }
2666
2730
  const branch = defaultBranch(cwd) ?? "main";
2667
2731
  for (const rel of rels) {
2668
- const repoPath = rel.split(path11.sep).join("/");
2669
- const localText = fs11.readFileSync(path11.join(cwd, rel), "utf-8");
2732
+ const repoPath = rel.split(path12.sep).join("/");
2733
+ const localText = fs12.readFileSync(path12.join(cwd, rel), "utf-8");
2670
2734
  putJsonlViaContents(repository, branch, repoPath, localText, sessionId, cwd);
2671
2735
  }
2672
2736
  }
@@ -2756,8 +2820,8 @@ async function emit2(sink, type, sessionId, suffix, payload) {
2756
2820
 
2757
2821
  // src/kody-cli.ts
2758
2822
  import { execFileSync as execFileSync30 } from "child_process";
2759
- import * as fs41 from "fs";
2760
- import * as path37 from "path";
2823
+ import * as fs42 from "fs";
2824
+ import * as path38 from "path";
2761
2825
 
2762
2826
  // src/app-auth.ts
2763
2827
  import { createSign } from "crypto";
@@ -2830,7 +2894,7 @@ async function mintAppInstallationToken(creds) {
2830
2894
  }
2831
2895
 
2832
2896
  // src/dispatch.ts
2833
- import * as fs12 from "fs";
2897
+ import * as fs13 from "fs";
2834
2898
 
2835
2899
  // src/cron-match.ts
2836
2900
  var FIELD_BOUNDS = [
@@ -2914,10 +2978,10 @@ function autoDispatch(opts) {
2914
2978
  }
2915
2979
  const eventName = process.env.GITHUB_EVENT_NAME;
2916
2980
  const eventPath = process.env.GITHUB_EVENT_PATH;
2917
- if (!eventName || !eventPath || !fs12.existsSync(eventPath)) return null;
2981
+ if (!eventName || !eventPath || !fs13.existsSync(eventPath)) return null;
2918
2982
  let event = {};
2919
2983
  try {
2920
- event = JSON.parse(fs12.readFileSync(eventPath, "utf-8"));
2984
+ event = JSON.parse(fs13.readFileSync(eventPath, "utf-8"));
2921
2985
  } catch {
2922
2986
  return null;
2923
2987
  }
@@ -2998,7 +3062,7 @@ function autoDispatchTyped(opts) {
2998
3062
  if (legacy) return { kind: "route", ...legacy };
2999
3063
  const eventName = process.env.GITHUB_EVENT_NAME;
3000
3064
  const eventPath = process.env.GITHUB_EVENT_PATH;
3001
- if (!eventName || !eventPath || !fs12.existsSync(eventPath)) {
3065
+ if (!eventName || !eventPath || !fs13.existsSync(eventPath)) {
3002
3066
  return { kind: "silent", reason: "no GHA event context" };
3003
3067
  }
3004
3068
  if (eventName !== "issue_comment") {
@@ -3006,7 +3070,7 @@ function autoDispatchTyped(opts) {
3006
3070
  }
3007
3071
  let event = {};
3008
3072
  try {
3009
- event = JSON.parse(fs12.readFileSync(eventPath, "utf-8"));
3073
+ event = JSON.parse(fs13.readFileSync(eventPath, "utf-8"));
3010
3074
  } catch {
3011
3075
  return { kind: "silent", reason: "GHA event payload unreadable" };
3012
3076
  }
@@ -3044,7 +3108,7 @@ function dispatchScheduledWatches(opts) {
3044
3108
  for (const exe of listExecutables()) {
3045
3109
  let raw;
3046
3110
  try {
3047
- raw = fs12.readFileSync(exe.profilePath, "utf-8");
3111
+ raw = fs13.readFileSync(exe.profilePath, "utf-8");
3048
3112
  } catch {
3049
3113
  continue;
3050
3114
  }
@@ -3164,8 +3228,8 @@ function coerceBare(spec, value) {
3164
3228
 
3165
3229
  // src/executor.ts
3166
3230
  import { execFileSync as execFileSync29, spawn as spawn9 } from "child_process";
3167
- import * as fs40 from "fs";
3168
- import * as path36 from "path";
3231
+ import * as fs41 from "fs";
3232
+ import * as path37 from "path";
3169
3233
 
3170
3234
  // src/discipline.ts
3171
3235
  var DISCIPLINE = `# Working discipline (applies to this entire task)
@@ -3216,8 +3280,8 @@ init_events();
3216
3280
  init_issue();
3217
3281
 
3218
3282
  // src/profile.ts
3219
- import * as fs13 from "fs";
3220
- import * as path12 from "path";
3283
+ import * as fs14 from "fs";
3284
+ import * as path13 from "path";
3221
3285
 
3222
3286
  // src/profile-error.ts
3223
3287
  var ProfileError = class extends Error {
@@ -3385,12 +3449,12 @@ var KNOWN_PROFILE_KEYS = /* @__PURE__ */ new Set([
3385
3449
  "preloadContext"
3386
3450
  ]);
3387
3451
  function loadProfile(profilePath) {
3388
- if (!fs13.existsSync(profilePath)) {
3452
+ if (!fs14.existsSync(profilePath)) {
3389
3453
  throw new ProfileError(profilePath, "file not found");
3390
3454
  }
3391
3455
  let raw;
3392
3456
  try {
3393
- raw = JSON.parse(fs13.readFileSync(profilePath, "utf-8"));
3457
+ raw = JSON.parse(fs14.readFileSync(profilePath, "utf-8"));
3394
3458
  } catch (err) {
3395
3459
  throw new ProfileError(profilePath, `invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
3396
3460
  }
@@ -3401,7 +3465,7 @@ function loadProfile(profilePath) {
3401
3465
  const unknownKeys = Object.keys(r).filter((k) => !KNOWN_PROFILE_KEYS.has(k));
3402
3466
  if (unknownKeys.length > 0) {
3403
3467
  process.stderr.write(
3404
- `[kody profile] ${path12.basename(path12.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
3468
+ `[kody profile] ${path13.basename(path13.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
3405
3469
  `
3406
3470
  );
3407
3471
  }
@@ -3462,7 +3526,7 @@ function loadProfile(profilePath) {
3462
3526
  // Phase 5 in-process handoff opt-in. Default false; containers
3463
3527
  // flip to true after end-to-end verification.
3464
3528
  preloadContext: r.preloadContext === true,
3465
- dir: path12.dirname(profilePath)
3529
+ dir: path13.dirname(profilePath)
3466
3530
  };
3467
3531
  if (lifecycle) {
3468
3532
  applyLifecycle(profile, profilePath);
@@ -3833,9 +3897,9 @@ function errMsg(err) {
3833
3897
 
3834
3898
  // src/litellm.ts
3835
3899
  import { execFileSync as execFileSync4, spawn as spawn3 } from "child_process";
3836
- import * as fs14 from "fs";
3900
+ import * as fs15 from "fs";
3837
3901
  import * as os2 from "os";
3838
- import * as path13 from "path";
3902
+ import * as path14 from "path";
3839
3903
  async function checkLitellmHealth(url) {
3840
3904
  try {
3841
3905
  const response = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3e3) });
@@ -3887,13 +3951,13 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
3887
3951
  let child;
3888
3952
  let logPath;
3889
3953
  const spawnProxy = () => {
3890
- const configPath = path13.join(os2.tmpdir(), `kody-litellm-${Date.now()}.yaml`);
3891
- fs14.writeFileSync(configPath, generateLitellmConfigYaml(model));
3954
+ const configPath = path14.join(os2.tmpdir(), `kody-litellm-${Date.now()}.yaml`);
3955
+ fs15.writeFileSync(configPath, generateLitellmConfigYaml(model));
3892
3956
  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");
3957
+ const nextLogPath = path14.join(os2.tmpdir(), `kody-litellm-${Date.now()}.log`);
3958
+ const outFd = fs15.openSync(nextLogPath, "w");
3895
3959
  child = spawn3(cmd, args, { stdio: ["ignore", outFd, outFd], detached: true, env: childEnv });
3896
- fs14.closeSync(outFd);
3960
+ fs15.closeSync(outFd);
3897
3961
  logPath = nextLogPath;
3898
3962
  };
3899
3963
  const waitForHealth = async () => {
@@ -3907,7 +3971,7 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
3907
3971
  const readLogTail = () => {
3908
3972
  if (!logPath) return "";
3909
3973
  try {
3910
- return fs14.readFileSync(logPath, "utf-8").slice(-2e3);
3974
+ return fs15.readFileSync(logPath, "utf-8").slice(-2e3);
3911
3975
  } catch {
3912
3976
  return "";
3913
3977
  }
@@ -3946,10 +4010,10 @@ ${tail}`
3946
4010
  return { url, kill: killChild, ensureHealthy };
3947
4011
  }
3948
4012
  function readDotenvApiKeys(projectDir) {
3949
- const dotenvPath = path13.join(projectDir, ".env");
3950
- if (!fs14.existsSync(dotenvPath)) return {};
4013
+ const dotenvPath = path14.join(projectDir, ".env");
4014
+ if (!fs15.existsSync(dotenvPath)) return {};
3951
4015
  const result = {};
3952
- for (const rawLine of fs14.readFileSync(dotenvPath, "utf-8").split("\n")) {
4016
+ for (const rawLine of fs15.readFileSync(dotenvPath, "utf-8").split("\n")) {
3953
4017
  const line = rawLine.trim();
3954
4018
  if (!line || line.startsWith("#")) continue;
3955
4019
  const match = line.match(/^([A-Z_][A-Z0-9_]*_API_KEY)=(.*)$/);
@@ -3972,25 +4036,25 @@ function stripBlockingEnv(env) {
3972
4036
  }
3973
4037
 
3974
4038
  // src/subagents.ts
3975
- import * as fs16 from "fs";
3976
- import * as path15 from "path";
4039
+ import * as fs17 from "fs";
4040
+ import * as path16 from "path";
3977
4041
 
3978
4042
  // src/scripts/buildSyntheticPlugin.ts
3979
- import * as fs15 from "fs";
4043
+ import * as fs16 from "fs";
3980
4044
  import * as os3 from "os";
3981
- import * as path14 from "path";
4045
+ import * as path15 from "path";
3982
4046
  function getPluginsCatalogRoot() {
3983
- const here = path14.dirname(new URL(import.meta.url).pathname);
4047
+ const here = path15.dirname(new URL(import.meta.url).pathname);
3984
4048
  const candidates = [
3985
- path14.join(here, "..", "plugins"),
4049
+ path15.join(here, "..", "plugins"),
3986
4050
  // dev: src/scripts → src/plugins
3987
- path14.join(here, "..", "..", "plugins"),
4051
+ path15.join(here, "..", "..", "plugins"),
3988
4052
  // built: dist/scripts → dist/plugins
3989
- path14.join(here, "..", "..", "src", "plugins")
4053
+ path15.join(here, "..", "..", "src", "plugins")
3990
4054
  // fallback
3991
4055
  ];
3992
4056
  for (const c of candidates) {
3993
- if (fs15.existsSync(c) && fs15.statSync(c).isDirectory()) return c;
4057
+ if (fs16.existsSync(c) && fs16.statSync(c).isDirectory()) return c;
3994
4058
  }
3995
4059
  return candidates[0];
3996
4060
  }
@@ -4000,45 +4064,45 @@ var buildSyntheticPlugin = async (ctx, profile) => {
4000
4064
  if (!needsSynthetic) return;
4001
4065
  const catalog = getPluginsCatalogRoot();
4002
4066
  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 });
4067
+ const root = path15.join(os3.tmpdir(), `kody-synth-${runId}`);
4068
+ fs16.mkdirSync(path15.join(root, ".claude-plugin"), { recursive: true });
4005
4069
  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;
4070
+ const local = path15.join(profile.dir, bucket, entry);
4071
+ if (fs16.existsSync(local)) return local;
4072
+ const central = path15.join(catalog, bucket, entry);
4073
+ if (fs16.existsSync(central)) return central;
4010
4074
  throw new Error(
4011
4075
  `buildSyntheticPlugin: ${bucket} entry '${entry}' not found in executable dir (${profile.dir}/${bucket}/) or catalog (${catalog}/${bucket}/)`
4012
4076
  );
4013
4077
  };
4014
4078
  if (cc.skills.length > 0) {
4015
- const dst = path14.join(root, "skills");
4016
- fs15.mkdirSync(dst, { recursive: true });
4079
+ const dst = path15.join(root, "skills");
4080
+ fs16.mkdirSync(dst, { recursive: true });
4017
4081
  for (const name of cc.skills) {
4018
- copyDir(resolvePart("skills", name), path14.join(dst, name));
4082
+ copyDir(resolvePart("skills", name), path15.join(dst, name));
4019
4083
  }
4020
4084
  }
4021
4085
  if (cc.commands.length > 0) {
4022
- const dst = path14.join(root, "commands");
4023
- fs15.mkdirSync(dst, { recursive: true });
4086
+ const dst = path15.join(root, "commands");
4087
+ fs16.mkdirSync(dst, { recursive: true });
4024
4088
  for (const name of cc.commands) {
4025
- fs15.copyFileSync(resolvePart("commands", `${name}.md`), path14.join(dst, `${name}.md`));
4089
+ fs16.copyFileSync(resolvePart("commands", `${name}.md`), path15.join(dst, `${name}.md`));
4026
4090
  }
4027
4091
  }
4028
4092
  if (cc.hooks.length > 0) {
4029
- const dst = path14.join(root, "hooks");
4030
- fs15.mkdirSync(dst, { recursive: true });
4093
+ const dst = path15.join(root, "hooks");
4094
+ fs16.mkdirSync(dst, { recursive: true });
4031
4095
  const merged = { hooks: {} };
4032
4096
  for (const name of cc.hooks) {
4033
4097
  const src = resolvePart("hooks", `${name}.json`);
4034
- const parsed = JSON.parse(fs15.readFileSync(src, "utf-8"));
4098
+ const parsed = JSON.parse(fs16.readFileSync(src, "utf-8"));
4035
4099
  for (const [event, entries] of Object.entries(parsed.hooks ?? {})) {
4036
4100
  if (!Array.isArray(entries)) continue;
4037
4101
  if (!merged.hooks[event]) merged.hooks[event] = [];
4038
4102
  merged.hooks[event].push(...entries);
4039
4103
  }
4040
4104
  }
4041
- fs15.writeFileSync(path14.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
4105
+ fs16.writeFileSync(path15.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
4042
4106
  `);
4043
4107
  }
4044
4108
  const manifest = {
@@ -4048,17 +4112,17 @@ var buildSyntheticPlugin = async (ctx, profile) => {
4048
4112
  };
4049
4113
  if (cc.skills.length > 0) manifest.skills = ["./skills/"];
4050
4114
  if (cc.commands.length > 0) manifest.commands = ["./commands/"];
4051
- fs15.writeFileSync(path14.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
4115
+ fs16.writeFileSync(path15.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
4052
4116
  `);
4053
4117
  ctx.data.syntheticPluginPath = root;
4054
4118
  };
4055
4119
  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);
4120
+ fs16.mkdirSync(dst, { recursive: true });
4121
+ for (const ent of fs16.readdirSync(src, { withFileTypes: true })) {
4122
+ const s = path15.join(src, ent.name);
4123
+ const d = path15.join(dst, ent.name);
4060
4124
  if (ent.isDirectory()) copyDir(s, d);
4061
- else if (ent.isFile()) fs15.copyFileSync(s, d);
4125
+ else if (ent.isFile()) fs16.copyFileSync(s, d);
4062
4126
  }
4063
4127
  }
4064
4128
 
@@ -4075,10 +4139,10 @@ function splitFrontmatter(raw) {
4075
4139
  return { fm, body: (match[2] ?? "").trim() };
4076
4140
  }
4077
4141
  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;
4142
+ const local = path16.join(profileDir, "agents", `${name}.md`);
4143
+ if (fs17.existsSync(local)) return local;
4144
+ const central = path16.join(getPluginsCatalogRoot(), "agents", `${name}.md`);
4145
+ if (fs17.existsSync(central)) return central;
4082
4146
  throw new Error(
4083
4147
  `loadSubagents: agent '${name}' not found in ${profileDir}/agents/ or shared catalog`
4084
4148
  );
@@ -4088,7 +4152,7 @@ function loadSubagents(profile) {
4088
4152
  if (!names || names.length === 0) return void 0;
4089
4153
  const agents = {};
4090
4154
  for (const name of names) {
4091
- const { fm, body } = splitFrontmatter(fs16.readFileSync(resolveAgentFile(profile.dir, name), "utf-8"));
4155
+ const { fm, body } = splitFrontmatter(fs17.readFileSync(resolveAgentFile(profile.dir, name), "utf-8"));
4092
4156
  if (!body) throw new Error(`loadSubagents: agent '${name}' has an empty prompt body`);
4093
4157
  const def = {
4094
4158
  description: fm.description ?? `Subagent ${name}`,
@@ -4184,8 +4248,8 @@ function pushWithRetry(opts = {}) {
4184
4248
  }
4185
4249
 
4186
4250
  // src/commit.ts
4187
- import * as fs17 from "fs";
4188
- import * as path16 from "path";
4251
+ import * as fs18 from "fs";
4252
+ import * as path17 from "path";
4189
4253
  var FORBIDDEN_PATH_PREFIXES = [
4190
4254
  ".kody/",
4191
4255
  ".kody-engine/",
@@ -4241,18 +4305,18 @@ function tryGit(args, cwd) {
4241
4305
  }
4242
4306
  function abortUnfinishedGitOps(cwd) {
4243
4307
  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"))) {
4308
+ const gitDir = path17.join(cwd ?? process.cwd(), ".git");
4309
+ if (!fs18.existsSync(gitDir)) return aborted;
4310
+ if (fs18.existsSync(path17.join(gitDir, "MERGE_HEAD"))) {
4247
4311
  if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
4248
4312
  }
4249
- if (fs17.existsSync(path16.join(gitDir, "CHERRY_PICK_HEAD"))) {
4313
+ if (fs18.existsSync(path17.join(gitDir, "CHERRY_PICK_HEAD"))) {
4250
4314
  if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
4251
4315
  }
4252
- if (fs17.existsSync(path16.join(gitDir, "REVERT_HEAD"))) {
4316
+ if (fs18.existsSync(path17.join(gitDir, "REVERT_HEAD"))) {
4253
4317
  if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
4254
4318
  }
4255
- if (fs17.existsSync(path16.join(gitDir, "rebase-merge")) || fs17.existsSync(path16.join(gitDir, "rebase-apply"))) {
4319
+ if (fs18.existsSync(path17.join(gitDir, "rebase-merge")) || fs18.existsSync(path17.join(gitDir, "rebase-apply"))) {
4256
4320
  if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
4257
4321
  }
4258
4322
  try {
@@ -4308,7 +4372,7 @@ function normalizeCommitMessage(raw) {
4308
4372
  function commitAndPush(branch, agentMessage, cwd) {
4309
4373
  const allChanged = listChangedFiles(cwd);
4310
4374
  const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
4311
- const mergeHeadExists = fs17.existsSync(path16.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
4375
+ const mergeHeadExists = fs18.existsSync(path17.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
4312
4376
  if (allowedFiles.length === 0 && !mergeHeadExists) {
4313
4377
  return { committed: false, pushed: false, sha: "", message: "" };
4314
4378
  }
@@ -4641,20 +4705,20 @@ var advanceFlow = async (ctx, profile) => {
4641
4705
  // src/scripts/brainServe.ts
4642
4706
  init_repoWorkspace();
4643
4707
  import { createServer } from "http";
4644
- import * as fs19 from "fs";
4645
- import * as path18 from "path";
4708
+ import * as fs20 from "fs";
4709
+ import * as path19 from "path";
4646
4710
 
4647
4711
  // src/scripts/brainTurnLog.ts
4648
- import * as fs18 from "fs";
4649
- import * as path17 from "path";
4712
+ import * as fs19 from "fs";
4713
+ import * as path18 from "path";
4650
4714
  var live = /* @__PURE__ */ new Map();
4651
4715
  function eventsPath(dir, chatId) {
4652
- return path17.join(dir, ".kody", "brain-events", `${chatId}.jsonl`);
4716
+ return path18.join(dir, ".kody", "brain-events", `${chatId}.jsonl`);
4653
4717
  }
4654
4718
  function lastPersistedSeq(dir, chatId) {
4655
4719
  const p = eventsPath(dir, chatId);
4656
- if (!fs18.existsSync(p)) return 0;
4657
- const lines = fs18.readFileSync(p, "utf-8").split("\n").filter(Boolean);
4720
+ if (!fs19.existsSync(p)) return 0;
4721
+ const lines = fs19.readFileSync(p, "utf-8").split("\n").filter(Boolean);
4658
4722
  if (lines.length === 0) return 0;
4659
4723
  try {
4660
4724
  return JSON.parse(lines[lines.length - 1]).seq || 0;
@@ -4664,9 +4728,9 @@ function lastPersistedSeq(dir, chatId) {
4664
4728
  }
4665
4729
  function readSince(dir, chatId, since) {
4666
4730
  const p = eventsPath(dir, chatId);
4667
- if (!fs18.existsSync(p)) return [];
4731
+ if (!fs19.existsSync(p)) return [];
4668
4732
  const out = [];
4669
- for (const line of fs18.readFileSync(p, "utf-8").split("\n")) {
4733
+ for (const line of fs19.readFileSync(p, "utf-8").split("\n")) {
4670
4734
  if (!line) continue;
4671
4735
  try {
4672
4736
  const rec = JSON.parse(line);
@@ -4692,12 +4756,12 @@ function beginTurn(dir, chatId) {
4692
4756
  };
4693
4757
  live.set(chatId, state);
4694
4758
  const p = eventsPath(dir, chatId);
4695
- fs18.mkdirSync(path17.dirname(p), { recursive: true });
4759
+ fs19.mkdirSync(path18.dirname(p), { recursive: true });
4696
4760
  return (event) => {
4697
4761
  state.seq += 1;
4698
4762
  const rec = { seq: state.seq, turn, ts: Date.now(), event };
4699
4763
  try {
4700
- fs18.appendFileSync(p, JSON.stringify(rec) + "\n");
4764
+ fs19.appendFileSync(p, JSON.stringify(rec) + "\n");
4701
4765
  } catch (err) {
4702
4766
  process.stderr.write(
4703
4767
  `[brain-turn-log] append failed for ${chatId}: ${err instanceof Error ? err.message : String(err)}
@@ -4735,7 +4799,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
4735
4799
  event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
4736
4800
  };
4737
4801
  try {
4738
- fs18.appendFileSync(eventsPath(dir, chatId), JSON.stringify(rec) + "\n");
4802
+ fs19.appendFileSync(eventsPath(dir, chatId), JSON.stringify(rec) + "\n");
4739
4803
  } catch {
4740
4804
  }
4741
4805
  state.status = "ended";
@@ -4961,7 +5025,7 @@ async function handleChatTurn(req, res, chatId, opts) {
4961
5025
  const repo = strField(body, "repo");
4962
5026
  const repoToken = strField(body, "repoToken");
4963
5027
  const sessionFile = sessionFilePath(opts.cwd, chatId);
4964
- fs19.mkdirSync(path18.dirname(sessionFile), { recursive: true });
5028
+ fs20.mkdirSync(path19.dirname(sessionFile), { recursive: true });
4965
5029
  appendTurn(sessionFile, {
4966
5030
  role: "user",
4967
5031
  content: message,
@@ -5008,7 +5072,7 @@ async function handleChatTurn(req, res, chatId, opts) {
5008
5072
  function buildServer(opts) {
5009
5073
  const runTurn = opts.runTurn ?? runChatTurn;
5010
5074
  const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
5011
- const reposRoot = opts.reposRoot ?? path18.join(path18.dirname(path18.resolve(opts.cwd)), "repos");
5075
+ const reposRoot = opts.reposRoot ?? path19.join(path19.dirname(path19.resolve(opts.cwd)), "repos");
5012
5076
  return createServer(async (req, res) => {
5013
5077
  if (!req.method || !req.url) {
5014
5078
  sendJson(res, 400, { error: "bad request" });
@@ -5263,13 +5327,13 @@ function defaultLabelMap() {
5263
5327
  }
5264
5328
 
5265
5329
  // src/scripts/commitAndPush.ts
5266
- import * as fs21 from "fs";
5267
- import * as path20 from "path";
5330
+ import * as fs22 from "fs";
5331
+ import * as path21 from "path";
5268
5332
  init_events();
5269
5333
  var DEFAULT_COMMIT_MESSAGE = "chore: kody changes";
5270
5334
  function sentinelPathForStage(cwd, profileName) {
5271
5335
  const runId = resolveRunId();
5272
- return path20.join(cwd, ".kody", "runs", runId, `commit-${profileName}.lock`);
5336
+ return path21.join(cwd, ".kody", "runs", runId, `commit-${profileName}.lock`);
5273
5337
  }
5274
5338
  var commitAndPush2 = async (ctx, profile) => {
5275
5339
  const branch = ctx.data.branch;
@@ -5279,9 +5343,9 @@ var commitAndPush2 = async (ctx, profile) => {
5279
5343
  }
5280
5344
  const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
5281
5345
  const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name) : null;
5282
- if (sentinel && fs21.existsSync(sentinel)) {
5346
+ if (sentinel && fs22.existsSync(sentinel)) {
5283
5347
  try {
5284
- const replay = JSON.parse(fs21.readFileSync(sentinel, "utf-8"));
5348
+ const replay = JSON.parse(fs22.readFileSync(sentinel, "utf-8"));
5285
5349
  ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
5286
5350
  if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
5287
5351
  if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
@@ -5334,8 +5398,8 @@ var commitAndPush2 = async (ctx, profile) => {
5334
5398
  const result = ctx.data.commitResult;
5335
5399
  if (sentinel && result?.committed) {
5336
5400
  try {
5337
- fs21.mkdirSync(path20.dirname(sentinel), { recursive: true });
5338
- fs21.writeFileSync(
5401
+ fs22.mkdirSync(path21.dirname(sentinel), { recursive: true });
5402
+ fs22.writeFileSync(
5339
5403
  sentinel,
5340
5404
  JSON.stringify(
5341
5405
  {
@@ -5396,14 +5460,14 @@ function ensureStateBranch(owner, repo, cwd) {
5396
5460
  }
5397
5461
 
5398
5462
  // src/goal/state.ts
5399
- import * as fs22 from "fs";
5400
- import * as path21 from "path";
5463
+ import * as fs23 from "fs";
5464
+ import * as path22 from "path";
5401
5465
  var VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "awaiting-merge", "done"]);
5402
5466
  var GoalStateError = class extends Error {
5403
- constructor(path39, message) {
5404
- super(`Invalid goal state at ${path39}:
5467
+ constructor(path40, message) {
5468
+ super(`Invalid goal state at ${path40}:
5405
5469
  ${message}`);
5406
- this.path = path39;
5470
+ this.path = path40;
5407
5471
  this.name = "GoalStateError";
5408
5472
  }
5409
5473
  path;
@@ -5543,20 +5607,20 @@ function describeCommitMessage(goal) {
5543
5607
  }
5544
5608
 
5545
5609
  // src/scripts/composePrompt.ts
5546
- import * as fs23 from "fs";
5547
- import * as path22 from "path";
5610
+ import * as fs24 from "fs";
5611
+ import * as path23 from "path";
5548
5612
  var MUSTACHE = /\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g;
5549
5613
  var composePrompt = async (ctx, profile) => {
5550
5614
  const explicit = ctx.data.promptTemplate;
5551
5615
  const mode = ctx.args.mode;
5552
5616
  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")
5617
+ explicit ? path23.join(profile.dir, explicit) : null,
5618
+ mode ? path23.join(profile.dir, "prompts", `${mode}.md`) : null,
5619
+ path23.join(profile.dir, "prompt.md")
5556
5620
  ].filter(Boolean);
5557
5621
  let templatePath = "";
5558
5622
  for (const c of candidates) {
5559
- if (fs23.existsSync(c)) {
5623
+ if (fs24.existsSync(c)) {
5560
5624
  templatePath = c;
5561
5625
  break;
5562
5626
  }
@@ -5564,7 +5628,7 @@ var composePrompt = async (ctx, profile) => {
5564
5628
  if (!templatePath) {
5565
5629
  throw new Error(`profile at ${profile.dir}: no prompt template found (tried ${candidates.join(", ")})`);
5566
5630
  }
5567
- const template = fs23.readFileSync(templatePath, "utf-8");
5631
+ const template = fs24.readFileSync(templatePath, "utf-8");
5568
5632
  const tokens = {
5569
5633
  ...stringifyAll(ctx.args, "args."),
5570
5634
  ...stringifyAll(ctx.data, ""),
@@ -6342,15 +6406,15 @@ function filterGoalTaskPrs(prs, taskIssueNumbers) {
6342
6406
 
6343
6407
  // src/scripts/diagMcp.ts
6344
6408
  import { execFileSync as execFileSync10 } from "child_process";
6345
- import * as fs24 from "fs";
6409
+ import * as fs25 from "fs";
6346
6410
  import * as os4 from "os";
6347
- import * as path23 from "path";
6411
+ import * as path24 from "path";
6348
6412
  var diagMcp = async (_ctx) => {
6349
6413
  const home = os4.homedir();
6350
- const cacheDir = path23.join(home, ".cache", "ms-playwright");
6414
+ const cacheDir = path24.join(home, ".cache", "ms-playwright");
6351
6415
  let entries = [];
6352
6416
  try {
6353
- entries = fs24.readdirSync(cacheDir);
6417
+ entries = fs25.readdirSync(cacheDir);
6354
6418
  } catch {
6355
6419
  }
6356
6420
  const hasChromium = entries.some((e) => e.startsWith("chromium"));
@@ -6376,17 +6440,17 @@ var diagMcp = async (_ctx) => {
6376
6440
  };
6377
6441
 
6378
6442
  // src/scripts/discoverQaContext.ts
6379
- import * as fs26 from "fs";
6380
- import * as path25 from "path";
6443
+ import * as fs27 from "fs";
6444
+ import * as path26 from "path";
6381
6445
 
6382
6446
  // src/scripts/frameworkDetectors.ts
6383
- import * as fs25 from "fs";
6384
- import * as path24 from "path";
6447
+ import * as fs26 from "fs";
6448
+ import * as path25 from "path";
6385
6449
  function detectFrameworks(cwd) {
6386
6450
  const out = [];
6387
6451
  let deps = {};
6388
6452
  try {
6389
- const pkg = JSON.parse(fs25.readFileSync(path24.join(cwd, "package.json"), "utf-8"));
6453
+ const pkg = JSON.parse(fs26.readFileSync(path25.join(cwd, "package.json"), "utf-8"));
6390
6454
  deps = { ...pkg.dependencies, ...pkg.devDependencies };
6391
6455
  } catch {
6392
6456
  return out;
@@ -6423,7 +6487,7 @@ function detectFrameworks(cwd) {
6423
6487
  }
6424
6488
  function findFile(cwd, candidates) {
6425
6489
  for (const c of candidates) {
6426
- if (fs25.existsSync(path24.join(cwd, c))) return c;
6490
+ if (fs26.existsSync(path25.join(cwd, c))) return c;
6427
6491
  }
6428
6492
  return null;
6429
6493
  }
@@ -6436,18 +6500,18 @@ var COLLECTION_DIRS = [
6436
6500
  function discoverPayloadCollections(cwd) {
6437
6501
  const out = [];
6438
6502
  for (const dir of COLLECTION_DIRS) {
6439
- const full = path24.join(cwd, dir);
6440
- if (!fs25.existsSync(full)) continue;
6503
+ const full = path25.join(cwd, dir);
6504
+ if (!fs26.existsSync(full)) continue;
6441
6505
  let files;
6442
6506
  try {
6443
- files = fs25.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
6507
+ files = fs26.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
6444
6508
  } catch {
6445
6509
  continue;
6446
6510
  }
6447
6511
  for (const file of files) {
6448
6512
  try {
6449
- const filePath = path24.join(full, file);
6450
- const content = fs25.readFileSync(filePath, "utf-8").slice(0, 1e4);
6513
+ const filePath = path25.join(full, file);
6514
+ const content = fs26.readFileSync(filePath, "utf-8").slice(0, 1e4);
6451
6515
  const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
6452
6516
  if (!slugMatch) continue;
6453
6517
  const slug = slugMatch[1];
@@ -6461,7 +6525,7 @@ function discoverPayloadCollections(cwd) {
6461
6525
  out.push({
6462
6526
  name,
6463
6527
  slug,
6464
- filePath: path24.relative(cwd, filePath),
6528
+ filePath: path25.relative(cwd, filePath),
6465
6529
  fields: fields.slice(0, 20),
6466
6530
  hasAdmin
6467
6531
  });
@@ -6475,28 +6539,28 @@ var ADMIN_COMPONENT_DIRS = ["src/ui/admin", "src/admin/components", "src/compone
6475
6539
  function discoverAdminComponents(cwd, collections) {
6476
6540
  const out = [];
6477
6541
  for (const dir of ADMIN_COMPONENT_DIRS) {
6478
- const full = path24.join(cwd, dir);
6479
- if (!fs25.existsSync(full)) continue;
6542
+ const full = path25.join(cwd, dir);
6543
+ if (!fs26.existsSync(full)) continue;
6480
6544
  let entries;
6481
6545
  try {
6482
- entries = fs25.readdirSync(full, { withFileTypes: true });
6546
+ entries = fs26.readdirSync(full, { withFileTypes: true });
6483
6547
  } catch {
6484
6548
  continue;
6485
6549
  }
6486
6550
  for (const entry of entries) {
6487
- const entryPath = path24.join(full, entry.name);
6551
+ const entryPath = path25.join(full, entry.name);
6488
6552
  let name;
6489
6553
  let filePath;
6490
6554
  if (entry.isDirectory()) {
6491
6555
  const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
6492
- (f) => fs25.existsSync(path24.join(entryPath, f))
6556
+ (f) => fs26.existsSync(path25.join(entryPath, f))
6493
6557
  );
6494
6558
  if (!indexFile) continue;
6495
6559
  name = entry.name;
6496
- filePath = path24.relative(cwd, path24.join(entryPath, indexFile));
6560
+ filePath = path25.relative(cwd, path25.join(entryPath, indexFile));
6497
6561
  } else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
6498
6562
  name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
6499
- filePath = path24.relative(cwd, entryPath);
6563
+ filePath = path25.relative(cwd, entryPath);
6500
6564
  } else {
6501
6565
  continue;
6502
6566
  }
@@ -6504,7 +6568,7 @@ function discoverAdminComponents(cwd, collections) {
6504
6568
  if (collections) {
6505
6569
  for (const col of collections) {
6506
6570
  try {
6507
- const colContent = fs25.readFileSync(path24.join(cwd, col.filePath), "utf-8");
6571
+ const colContent = fs26.readFileSync(path25.join(cwd, col.filePath), "utf-8");
6508
6572
  if (colContent.includes(name)) {
6509
6573
  usedInCollection = col.slug;
6510
6574
  break;
@@ -6523,8 +6587,8 @@ function scanApiRoutes(cwd) {
6523
6587
  const out = [];
6524
6588
  const appDirs = ["src/app", "app"];
6525
6589
  for (const appDir of appDirs) {
6526
- const apiDir = path24.join(cwd, appDir, "api");
6527
- if (!fs25.existsSync(apiDir)) continue;
6590
+ const apiDir = path25.join(cwd, appDir, "api");
6591
+ if (!fs26.existsSync(apiDir)) continue;
6528
6592
  walkApiRoutes(apiDir, "/api", cwd, out);
6529
6593
  break;
6530
6594
  }
@@ -6533,14 +6597,14 @@ function scanApiRoutes(cwd) {
6533
6597
  function walkApiRoutes(dir, prefix, cwd, out) {
6534
6598
  let entries;
6535
6599
  try {
6536
- entries = fs25.readdirSync(dir, { withFileTypes: true });
6600
+ entries = fs26.readdirSync(dir, { withFileTypes: true });
6537
6601
  } catch {
6538
6602
  return;
6539
6603
  }
6540
6604
  const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
6541
6605
  if (routeFile) {
6542
6606
  try {
6543
- const content = fs25.readFileSync(path24.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
6607
+ const content = fs26.readFileSync(path25.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
6544
6608
  const methods = HTTP_METHODS.filter(
6545
6609
  (m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
6546
6610
  );
@@ -6548,7 +6612,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
6548
6612
  out.push({
6549
6613
  path: prefix,
6550
6614
  methods,
6551
- filePath: path24.relative(cwd, path24.join(dir, routeFile.name))
6615
+ filePath: path25.relative(cwd, path25.join(dir, routeFile.name))
6552
6616
  });
6553
6617
  }
6554
6618
  } catch {
@@ -6559,7 +6623,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
6559
6623
  if (entry.name === "node_modules" || entry.name === ".next") continue;
6560
6624
  let segment = entry.name;
6561
6625
  if (segment.startsWith("(") && segment.endsWith(")")) {
6562
- walkApiRoutes(path24.join(dir, entry.name), prefix, cwd, out);
6626
+ walkApiRoutes(path25.join(dir, entry.name), prefix, cwd, out);
6563
6627
  continue;
6564
6628
  }
6565
6629
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -6567,7 +6631,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
6567
6631
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
6568
6632
  segment = `:${segment.slice(1, -1)}`;
6569
6633
  }
6570
- walkApiRoutes(path24.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
6634
+ walkApiRoutes(path25.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
6571
6635
  }
6572
6636
  }
6573
6637
  var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
@@ -6587,10 +6651,10 @@ var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
6587
6651
  function scanEnvVars(cwd) {
6588
6652
  const candidates = [".env.example", ".env.local.example", ".env.template"];
6589
6653
  for (const envFile of candidates) {
6590
- const envPath = path24.join(cwd, envFile);
6591
- if (!fs25.existsSync(envPath)) continue;
6654
+ const envPath = path25.join(cwd, envFile);
6655
+ if (!fs26.existsSync(envPath)) continue;
6592
6656
  try {
6593
- const content = fs25.readFileSync(envPath, "utf-8");
6657
+ const content = fs26.readFileSync(envPath, "utf-8");
6594
6658
  const vars = [];
6595
6659
  for (const line of content.split("\n")) {
6596
6660
  const trimmed = line.trim();
@@ -6638,9 +6702,9 @@ function runQaDiscovery(cwd) {
6638
6702
  }
6639
6703
  function detectDevServer(cwd, out) {
6640
6704
  try {
6641
- const pkg = JSON.parse(fs26.readFileSync(path25.join(cwd, "package.json"), "utf-8"));
6705
+ const pkg = JSON.parse(fs27.readFileSync(path26.join(cwd, "package.json"), "utf-8"));
6642
6706
  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";
6707
+ 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
6708
  if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
6645
6709
  if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
6646
6710
  else if (allDeps.vite) out.devPort = 5173;
@@ -6650,8 +6714,8 @@ function detectDevServer(cwd, out) {
6650
6714
  function scanFrontendRoutes(cwd, out) {
6651
6715
  const appDirs = ["src/app", "app"];
6652
6716
  for (const appDir of appDirs) {
6653
- const full = path25.join(cwd, appDir);
6654
- if (!fs26.existsSync(full)) continue;
6717
+ const full = path26.join(cwd, appDir);
6718
+ if (!fs27.existsSync(full)) continue;
6655
6719
  walkFrontendRoutes(full, "", out);
6656
6720
  break;
6657
6721
  }
@@ -6659,7 +6723,7 @@ function scanFrontendRoutes(cwd, out) {
6659
6723
  function walkFrontendRoutes(dir, prefix, out) {
6660
6724
  let entries;
6661
6725
  try {
6662
- entries = fs26.readdirSync(dir, { withFileTypes: true });
6726
+ entries = fs27.readdirSync(dir, { withFileTypes: true });
6663
6727
  } catch {
6664
6728
  return;
6665
6729
  }
@@ -6676,7 +6740,7 @@ function walkFrontendRoutes(dir, prefix, out) {
6676
6740
  if (entry.name === "node_modules" || entry.name === ".next") continue;
6677
6741
  let segment = entry.name;
6678
6742
  if (segment.startsWith("(") && segment.endsWith(")")) {
6679
- walkFrontendRoutes(path25.join(dir, entry.name), prefix, out);
6743
+ walkFrontendRoutes(path26.join(dir, entry.name), prefix, out);
6680
6744
  continue;
6681
6745
  }
6682
6746
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -6684,7 +6748,7 @@ function walkFrontendRoutes(dir, prefix, out) {
6684
6748
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
6685
6749
  segment = `:${segment.slice(1, -1)}`;
6686
6750
  }
6687
- walkFrontendRoutes(path25.join(dir, entry.name), `${prefix}/${segment}`, out);
6751
+ walkFrontendRoutes(path26.join(dir, entry.name), `${prefix}/${segment}`, out);
6688
6752
  }
6689
6753
  }
6690
6754
  function detectAuthFiles(cwd, out) {
@@ -6701,23 +6765,23 @@ function detectAuthFiles(cwd, out) {
6701
6765
  "src/app/api/oauth"
6702
6766
  ];
6703
6767
  for (const c of candidates) {
6704
- if (fs26.existsSync(path25.join(cwd, c))) out.authFiles.push(c);
6768
+ if (fs27.existsSync(path26.join(cwd, c))) out.authFiles.push(c);
6705
6769
  }
6706
6770
  }
6707
6771
  function detectRoles(cwd, out) {
6708
6772
  const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
6709
6773
  for (const rp of rolePaths) {
6710
- const dir = path25.join(cwd, rp);
6711
- if (!fs26.existsSync(dir)) continue;
6774
+ const dir = path26.join(cwd, rp);
6775
+ if (!fs27.existsSync(dir)) continue;
6712
6776
  let files;
6713
6777
  try {
6714
- files = fs26.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
6778
+ files = fs27.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
6715
6779
  } catch {
6716
6780
  continue;
6717
6781
  }
6718
6782
  for (const f of files) {
6719
6783
  try {
6720
- const content = fs26.readFileSync(path25.join(dir, f), "utf-8").slice(0, 5e3);
6784
+ const content = fs27.readFileSync(path26.join(dir, f), "utf-8").slice(0, 5e3);
6721
6785
  const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
6722
6786
  if (roleMatches) {
6723
6787
  for (const m of roleMatches) {
@@ -6901,8 +6965,8 @@ function failedAction3(reason) {
6901
6965
  }
6902
6966
 
6903
6967
  // src/scripts/dispatchJobFileTicks.ts
6904
- import * as fs28 from "fs";
6905
- import * as path27 from "path";
6968
+ import * as fs29 from "fs";
6969
+ import * as path28 from "path";
6906
6970
 
6907
6971
  // src/scripts/jobFrontmatter.ts
6908
6972
  var SCHEDULE_EVERY_VALUES = [
@@ -7171,8 +7235,8 @@ var ContentsApiBackend = class {
7171
7235
  };
7172
7236
 
7173
7237
  // src/scripts/jobState/localFileBackend.ts
7174
- import * as fs27 from "fs";
7175
- import * as path26 from "path";
7238
+ import * as fs28 from "fs";
7239
+ import * as path27 from "path";
7176
7240
  var LocalFileBackend = class {
7177
7241
  name = "local-file";
7178
7242
  cwd;
@@ -7187,7 +7251,7 @@ var LocalFileBackend = class {
7187
7251
  if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
7188
7252
  this.cwd = opts.cwd;
7189
7253
  this.jobsDir = opts.jobsDir;
7190
- this.absDir = path26.join(opts.cwd, opts.jobsDir);
7254
+ this.absDir = path27.join(opts.cwd, opts.jobsDir);
7191
7255
  this.owner = opts.owner;
7192
7256
  this.repo = opts.repo;
7193
7257
  this.cache = opts.cache ?? defaultCacheAdapter();
@@ -7202,7 +7266,7 @@ var LocalFileBackend = class {
7202
7266
  `);
7203
7267
  return;
7204
7268
  }
7205
- fs27.mkdirSync(this.absDir, { recursive: true });
7269
+ fs28.mkdirSync(this.absDir, { recursive: true });
7206
7270
  const prefix = this.cacheKeyPrefix();
7207
7271
  const probeKey = `${prefix}probe-${Date.now()}`;
7208
7272
  try {
@@ -7231,7 +7295,7 @@ var LocalFileBackend = class {
7231
7295
  `);
7232
7296
  return;
7233
7297
  }
7234
- if (!fs27.existsSync(this.absDir)) {
7298
+ if (!fs28.existsSync(this.absDir)) {
7235
7299
  return;
7236
7300
  }
7237
7301
  const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
@@ -7247,11 +7311,11 @@ var LocalFileBackend = class {
7247
7311
  }
7248
7312
  load(slug) {
7249
7313
  const relPath = stateFilePath(this.jobsDir, slug);
7250
- const absPath = path26.join(this.cwd, relPath);
7251
- if (!fs27.existsSync(absPath)) {
7314
+ const absPath = path27.join(this.cwd, relPath);
7315
+ if (!fs28.existsSync(absPath)) {
7252
7316
  return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
7253
7317
  }
7254
- const raw = fs27.readFileSync(absPath, "utf-8");
7318
+ const raw = fs28.readFileSync(absPath, "utf-8");
7255
7319
  let parsed;
7256
7320
  try {
7257
7321
  parsed = JSON.parse(raw);
@@ -7268,10 +7332,10 @@ var LocalFileBackend = class {
7268
7332
  if (!loaded.created && isStateUnchanged(loaded.state, next)) {
7269
7333
  return false;
7270
7334
  }
7271
- const absPath = path26.join(this.cwd, loaded.path);
7272
- fs27.mkdirSync(path26.dirname(absPath), { recursive: true });
7335
+ const absPath = path27.join(this.cwd, loaded.path);
7336
+ fs28.mkdirSync(path27.dirname(absPath), { recursive: true });
7273
7337
  const body = JSON.stringify(next, null, 2) + "\n";
7274
- fs27.writeFileSync(absPath, body, "utf-8");
7338
+ fs28.writeFileSync(absPath, body, "utf-8");
7275
7339
  return true;
7276
7340
  }
7277
7341
  cacheKeyPrefix() {
@@ -7349,7 +7413,7 @@ var dispatchJobFileTicks = async (ctx, _profile, args) => {
7349
7413
  await backend.hydrate();
7350
7414
  }
7351
7415
  try {
7352
- const slugs = listJobSlugs(path27.join(ctx.cwd, jobsDir));
7416
+ const slugs = listJobSlugs(path28.join(ctx.cwd, jobsDir));
7353
7417
  ctx.data.jobSlugCount = slugs.length;
7354
7418
  if (slugs.length === 0) {
7355
7419
  process.stdout.write(`[jobs] no job files in ${jobsDir}
@@ -7462,17 +7526,17 @@ function formatAgo(ms) {
7462
7526
  }
7463
7527
  function readJobFrontmatter(cwd, jobsDir, slug) {
7464
7528
  try {
7465
- const raw = fs28.readFileSync(path27.join(cwd, jobsDir, `${slug}.md`), "utf-8");
7529
+ const raw = fs29.readFileSync(path28.join(cwd, jobsDir, `${slug}.md`), "utf-8");
7466
7530
  return splitFrontmatter2(raw).frontmatter;
7467
7531
  } catch {
7468
7532
  return {};
7469
7533
  }
7470
7534
  }
7471
7535
  function listJobSlugs(absDir) {
7472
- if (!fs28.existsSync(absDir)) return [];
7536
+ if (!fs29.existsSync(absDir)) return [];
7473
7537
  let entries;
7474
7538
  try {
7475
- entries = fs28.readdirSync(absDir, { withFileTypes: true });
7539
+ entries = fs29.readdirSync(absDir, { withFileTypes: true });
7476
7540
  } catch {
7477
7541
  return [];
7478
7542
  }
@@ -8265,7 +8329,7 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch2, cwd, baseBranch
8265
8329
 
8266
8330
  // src/gha.ts
8267
8331
  import { execFileSync as execFileSync16 } from "child_process";
8268
- import * as fs29 from "fs";
8332
+ import * as fs30 from "fs";
8269
8333
  function getRunUrl() {
8270
8334
  const server = process.env.GITHUB_SERVER_URL;
8271
8335
  const repo = process.env.GITHUB_REPOSITORY;
@@ -8276,10 +8340,10 @@ function getRunUrl() {
8276
8340
  function reactToTriggerComment(cwd) {
8277
8341
  if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
8278
8342
  const eventPath = process.env.GITHUB_EVENT_PATH;
8279
- if (!eventPath || !fs29.existsSync(eventPath)) return;
8343
+ if (!eventPath || !fs30.existsSync(eventPath)) return;
8280
8344
  let event = null;
8281
8345
  try {
8282
- event = JSON.parse(fs29.readFileSync(eventPath, "utf-8"));
8346
+ event = JSON.parse(fs30.readFileSync(eventPath, "utf-8"));
8283
8347
  } catch {
8284
8348
  return;
8285
8349
  }
@@ -8573,12 +8637,12 @@ var handleAbandonedGoal = async (ctx) => {
8573
8637
 
8574
8638
  // src/scripts/initFlow.ts
8575
8639
  import { execFileSync as execFileSync18 } from "child_process";
8576
- import * as fs30 from "fs";
8577
- import * as path28 from "path";
8640
+ import * as fs31 from "fs";
8641
+ import * as path29 from "path";
8578
8642
  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";
8643
+ if (fs31.existsSync(path29.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
8644
+ if (fs31.existsSync(path29.join(cwd, "yarn.lock"))) return "yarn";
8645
+ if (fs31.existsSync(path29.join(cwd, "bun.lockb"))) return "bun";
8582
8646
  return "npm";
8583
8647
  }
8584
8648
  function qualityCommandsFor(pm) {
@@ -8707,36 +8771,36 @@ function performInit(cwd, force) {
8707
8771
  const pm = detectPackageManager(cwd);
8708
8772
  const ownerRepo = detectOwnerRepo(cwd);
8709
8773
  const defaultBranch2 = defaultBranchFromGit(cwd);
8710
- const configPath = path28.join(cwd, "kody.config.json");
8711
- if (fs30.existsSync(configPath) && !force) {
8774
+ const configPath = path29.join(cwd, "kody.config.json");
8775
+ if (fs31.existsSync(configPath) && !force) {
8712
8776
  skipped.push("kody.config.json");
8713
8777
  } else {
8714
8778
  const cfg = makeConfig(pm, ownerRepo, defaultBranch2);
8715
- fs30.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
8779
+ fs31.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
8716
8780
  `);
8717
8781
  wrote.push("kody.config.json");
8718
8782
  }
8719
- const workflowDir = path28.join(cwd, ".github", "workflows");
8720
- const workflowPath = path28.join(workflowDir, "kody.yml");
8721
- if (fs30.existsSync(workflowPath) && !force) {
8783
+ const workflowDir = path29.join(cwd, ".github", "workflows");
8784
+ const workflowPath = path29.join(workflowDir, "kody.yml");
8785
+ if (fs31.existsSync(workflowPath) && !force) {
8722
8786
  skipped.push(".github/workflows/kody.yml");
8723
8787
  } else {
8724
- fs30.mkdirSync(workflowDir, { recursive: true });
8725
- fs30.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
8788
+ fs31.mkdirSync(workflowDir, { recursive: true });
8789
+ fs31.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
8726
8790
  wrote.push(".github/workflows/kody.yml");
8727
8791
  }
8728
8792
  const builtinJobs = listBuiltinJobs();
8729
8793
  if (builtinJobs.length > 0) {
8730
- const jobsDir = path28.join(cwd, ".kody", "duties");
8731
- fs30.mkdirSync(jobsDir, { recursive: true });
8794
+ const jobsDir = path29.join(cwd, ".kody", "duties");
8795
+ fs31.mkdirSync(jobsDir, { recursive: true });
8732
8796
  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) {
8797
+ const rel = path29.join(".kody", "duties", `${job.slug}.md`);
8798
+ const target = path29.join(cwd, rel);
8799
+ if (fs31.existsSync(target) && !force) {
8736
8800
  skipped.push(rel);
8737
8801
  continue;
8738
8802
  }
8739
- fs30.writeFileSync(target, fs30.readFileSync(job.filePath, "utf-8"));
8803
+ fs31.writeFileSync(target, fs31.readFileSync(job.filePath, "utf-8"));
8740
8804
  wrote.push(rel);
8741
8805
  }
8742
8806
  }
@@ -8748,12 +8812,12 @@ function performInit(cwd, force) {
8748
8812
  continue;
8749
8813
  }
8750
8814
  if (profile.kind !== "scheduled" || !profile.schedule) continue;
8751
- const target = path28.join(workflowDir, `kody-${exe.name}.yml`);
8752
- if (fs30.existsSync(target) && !force) {
8815
+ const target = path29.join(workflowDir, `kody-${exe.name}.yml`);
8816
+ if (fs31.existsSync(target) && !force) {
8753
8817
  skipped.push(`.github/workflows/kody-${exe.name}.yml`);
8754
8818
  continue;
8755
8819
  }
8756
- fs30.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
8820
+ fs31.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
8757
8821
  wrote.push(`.github/workflows/kody-${exe.name}.yml`);
8758
8822
  }
8759
8823
  let labels;
@@ -8937,8 +9001,8 @@ var loadIssueStateComment = async (ctx, _profile, args) => {
8937
9001
  };
8938
9002
 
8939
9003
  // src/scripts/loadJobFromFile.ts
8940
- import * as fs31 from "fs";
8941
- import * as path29 from "path";
9004
+ import * as fs32 from "fs";
9005
+ import * as path30 from "path";
8942
9006
  var loadJobFromFile = async (ctx, _profile, args) => {
8943
9007
  const jobsDir = String(args?.jobsDir ?? ".kody/duties");
8944
9008
  const workersDir = String(args?.workersDir ?? ".kody/staff");
@@ -8947,11 +9011,11 @@ var loadJobFromFile = async (ctx, _profile, args) => {
8947
9011
  if (!slug) {
8948
9012
  throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
8949
9013
  }
8950
- const absPath = path29.join(ctx.cwd, jobsDir, `${slug}.md`);
8951
- if (!fs31.existsSync(absPath)) {
9014
+ const absPath = path30.join(ctx.cwd, jobsDir, `${slug}.md`);
9015
+ if (!fs32.existsSync(absPath)) {
8952
9016
  throw new Error(`loadJobFromFile: job file not found: ${absPath}`);
8953
9017
  }
8954
- const raw = fs31.readFileSync(absPath, "utf-8");
9018
+ const raw = fs32.readFileSync(absPath, "utf-8");
8955
9019
  const { title, body } = parseJobFile(raw, slug);
8956
9020
  const frontmatter = splitFrontmatter2(raw).frontmatter;
8957
9021
  const mentions = (frontmatter.mentions ?? []).map((login) => `@${login}`).join(" ");
@@ -8959,13 +9023,13 @@ var loadJobFromFile = async (ctx, _profile, args) => {
8959
9023
  let workerTitle = "";
8960
9024
  let workerPersona = "";
8961
9025
  if (workerSlug) {
8962
- const workerPath = path29.join(ctx.cwd, workersDir, `${workerSlug}.md`);
8963
- if (!fs31.existsSync(workerPath)) {
9026
+ const workerPath = path30.join(ctx.cwd, workersDir, `${workerSlug}.md`);
9027
+ if (!fs32.existsSync(workerPath)) {
8964
9028
  throw new Error(
8965
9029
  `loadJobFromFile: duty '${slug}' declares staff '${workerSlug}' but ${workerPath} does not exist`
8966
9030
  );
8967
9031
  }
8968
- const workerRaw = fs31.readFileSync(workerPath, "utf-8");
9032
+ const workerRaw = fs32.readFileSync(workerPath, "utf-8");
8969
9033
  const parsed = parseJobFile(workerRaw, workerSlug);
8970
9034
  workerTitle = parsed.title;
8971
9035
  workerPersona = parsed.body;
@@ -9008,18 +9072,18 @@ init_loadMemoryContext();
9008
9072
  init_loadPriorArt();
9009
9073
 
9010
9074
  // src/scripts/loadQaContext.ts
9011
- import * as fs34 from "fs";
9012
- import * as path32 from "path";
9075
+ import * as fs35 from "fs";
9076
+ import * as path33 from "path";
9013
9077
 
9014
9078
  // src/scripts/kodyVariables.ts
9015
- import * as fs33 from "fs";
9016
- import * as path31 from "path";
9079
+ import * as fs34 from "fs";
9080
+ import * as path32 from "path";
9017
9081
  var KODY_VARIABLES_REL_PATH = ".kody/variables.json";
9018
9082
  function readKodyVariables(cwd) {
9019
- const full = path31.join(cwd, KODY_VARIABLES_REL_PATH);
9083
+ const full = path32.join(cwd, KODY_VARIABLES_REL_PATH);
9020
9084
  let raw;
9021
9085
  try {
9022
- raw = fs33.readFileSync(full, "utf-8");
9086
+ raw = fs34.readFileSync(full, "utf-8");
9023
9087
  } catch {
9024
9088
  return {};
9025
9089
  }
@@ -9068,18 +9132,18 @@ function readProfileStaff(raw) {
9068
9132
  return { staff: staff ?? legacy ?? ["kody"], body };
9069
9133
  }
9070
9134
  function readProfile(cwd) {
9071
- const dir = path32.join(cwd, CONTEXT_DIR_REL_PATH);
9072
- if (!fs34.existsSync(dir)) return "";
9135
+ const dir = path33.join(cwd, CONTEXT_DIR_REL_PATH);
9136
+ if (!fs35.existsSync(dir)) return "";
9073
9137
  let entries;
9074
9138
  try {
9075
- entries = fs34.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
9139
+ entries = fs35.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
9076
9140
  } catch {
9077
9141
  return "";
9078
9142
  }
9079
9143
  const blocks = [];
9080
9144
  for (const file of entries) {
9081
9145
  try {
9082
- const raw = fs34.readFileSync(path32.join(dir, file), "utf-8");
9146
+ const raw = fs35.readFileSync(path33.join(dir, file), "utf-8");
9083
9147
  const { staff, body } = readProfileStaff(raw);
9084
9148
  if (!staff.includes(QA_STAFF) && !staff.includes(ALL_STAFF)) continue;
9085
9149
  blocks.push(`## ${file}
@@ -9116,8 +9180,8 @@ var loadQaContext = async (ctx) => {
9116
9180
  init_events();
9117
9181
 
9118
9182
  // src/taskContext.ts
9119
- import * as fs35 from "fs";
9120
- import * as path33 from "path";
9183
+ import * as fs36 from "fs";
9184
+ import * as path34 from "path";
9121
9185
  var TASK_CONTEXT_SCHEMA_VERSION = 1;
9122
9186
  function buildTaskContext(args) {
9123
9187
  return {
@@ -9133,10 +9197,10 @@ function buildTaskContext(args) {
9133
9197
  }
9134
9198
  function persistTaskContext(cwd, ctx) {
9135
9199
  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)}
9200
+ const dir = path34.join(cwd, ".kody", "runs", ctx.runId);
9201
+ fs36.mkdirSync(dir, { recursive: true });
9202
+ const file = path34.join(dir, "task-context.json");
9203
+ fs36.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
9140
9204
  `);
9141
9205
  return file;
9142
9206
  } catch (err) {
@@ -9184,19 +9248,19 @@ var loadTaskState = async (ctx) => {
9184
9248
  };
9185
9249
 
9186
9250
  // src/scripts/loadWorkerAdhoc.ts
9187
- import * as fs36 from "fs";
9188
- import * as path34 from "path";
9251
+ import * as fs37 from "fs";
9252
+ import * as path35 from "path";
9189
9253
  var loadWorkerAdhoc = async (ctx, _profile, args) => {
9190
9254
  const workersDir = String(args?.workersDir ?? ".kody/staff");
9191
9255
  const workerSlug = String(ctx.args.worker ?? "").trim();
9192
9256
  if (!workerSlug) {
9193
9257
  throw new Error("loadWorkerAdhoc: ctx.args.worker must be a non-empty slug");
9194
9258
  }
9195
- const workerPath = path34.join(ctx.cwd, workersDir, `${workerSlug}.md`);
9196
- if (!fs36.existsSync(workerPath)) {
9259
+ const workerPath = path35.join(ctx.cwd, workersDir, `${workerSlug}.md`);
9260
+ if (!fs37.existsSync(workerPath)) {
9197
9261
  throw new Error(`loadWorkerAdhoc: worker persona not found: ${workerPath}`);
9198
9262
  }
9199
- const { title, body } = parsePersona(fs36.readFileSync(workerPath, "utf-8"), workerSlug);
9263
+ const { title, body } = parsePersona(fs37.readFileSync(workerPath, "utf-8"), workerSlug);
9200
9264
  const message = resolveMessage(ctx.args.message);
9201
9265
  if (!message) {
9202
9266
  throw new Error(
@@ -9216,9 +9280,9 @@ function resolveMessage(messageArg) {
9216
9280
  }
9217
9281
  function readCommentBody() {
9218
9282
  const eventPath = process.env.GITHUB_EVENT_PATH;
9219
- if (!eventPath || !fs36.existsSync(eventPath)) return "";
9283
+ if (!eventPath || !fs37.existsSync(eventPath)) return "";
9220
9284
  try {
9221
- const event = JSON.parse(fs36.readFileSync(eventPath, "utf-8"));
9285
+ const event = JSON.parse(fs37.readFileSync(eventPath, "utf-8"));
9222
9286
  return String(event.comment?.body ?? "");
9223
9287
  } catch {
9224
9288
  return "";
@@ -9888,8 +9952,8 @@ var FlyClient = class {
9888
9952
  get fetch() {
9889
9953
  return this.opts.fetchImpl ?? fetch;
9890
9954
  }
9891
- async call(path39, init = {}) {
9892
- const res = await this.fetch(`${FLY_API_BASE}${path39}`, {
9955
+ async call(path40, init = {}) {
9956
+ const res = await this.fetch(`${FLY_API_BASE}${path40}`, {
9893
9957
  method: init.method ?? "GET",
9894
9958
  headers: {
9895
9959
  Authorization: `Bearer ${this.opts.token}`,
@@ -9900,7 +9964,7 @@ var FlyClient = class {
9900
9964
  if (res.status === 404 && init.allow404) return null;
9901
9965
  if (!res.ok) {
9902
9966
  const text = await res.text().catch(() => "");
9903
- throw new Error(`Fly API ${res.status} on ${path39}: ${text.slice(0, 200) || res.statusText}`);
9967
+ throw new Error(`Fly API ${res.status} on ${path40}: ${text.slice(0, 200) || res.statusText}`);
9904
9968
  }
9905
9969
  if (res.status === 204) return null;
9906
9970
  const raw = await res.text();
@@ -11576,7 +11640,7 @@ function resolveBaseOverride(value) {
11576
11640
  // src/scripts/runnerServe.ts
11577
11641
  import { spawn as spawn5 } from "child_process";
11578
11642
  import { createServer as createServer3 } from "http";
11579
- import * as fs37 from "fs";
11643
+ import * as fs38 from "fs";
11580
11644
  var DEFAULT_PORT2 = 8080;
11581
11645
  var DEFAULT_WORKDIR = "/workspace/repo";
11582
11646
  function getApiKey2() {
@@ -11657,8 +11721,8 @@ async function defaultRunJob(job) {
11657
11721
  const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
11658
11722
  const branch = job.ref ?? "main";
11659
11723
  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 });
11724
+ fs38.rmSync(workdir, { recursive: true, force: true });
11725
+ fs38.mkdirSync(workdir, { recursive: true });
11662
11726
  const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
11663
11727
  const interactive = job.mode === "interactive";
11664
11728
  const scheduled = job.mode === "scheduled";
@@ -11799,8 +11863,8 @@ var runnerServe = async (ctx) => {
11799
11863
 
11800
11864
  // src/scripts/runTickScript.ts
11801
11865
  import { spawnSync as spawnSync2 } from "child_process";
11802
- import * as fs38 from "fs";
11803
- import * as path35 from "path";
11866
+ import * as fs39 from "fs";
11867
+ import * as path36 from "path";
11804
11868
  var runTickScript = async (ctx, _profile, args) => {
11805
11869
  ctx.skipAgent = true;
11806
11870
  const jobsDir = String(args?.jobsDir ?? ".kody/duties");
@@ -11812,13 +11876,13 @@ var runTickScript = async (ctx, _profile, args) => {
11812
11876
  ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
11813
11877
  return;
11814
11878
  }
11815
- const jobPath = path35.join(ctx.cwd, jobsDir, `${slug}.md`);
11816
- if (!fs38.existsSync(jobPath)) {
11879
+ const jobPath = path36.join(ctx.cwd, jobsDir, `${slug}.md`);
11880
+ if (!fs39.existsSync(jobPath)) {
11817
11881
  ctx.output.exitCode = 99;
11818
11882
  ctx.output.reason = `runTickScript: job file not found: ${jobPath}`;
11819
11883
  return;
11820
11884
  }
11821
- const raw = fs38.readFileSync(jobPath, "utf-8");
11885
+ const raw = fs39.readFileSync(jobPath, "utf-8");
11822
11886
  const { frontmatter } = splitFrontmatter2(raw);
11823
11887
  const tickScript = frontmatter.tickScript;
11824
11888
  if (!tickScript) {
@@ -11826,8 +11890,8 @@ var runTickScript = async (ctx, _profile, args) => {
11826
11890
  ctx.output.reason = `runTickScript: job ${slug} has no \`tickScript:\` frontmatter \u2014 route via job-tick instead`;
11827
11891
  return;
11828
11892
  }
11829
- const scriptPath = path35.isAbsolute(tickScript) ? tickScript : path35.join(ctx.cwd, tickScript);
11830
- if (!fs38.existsSync(scriptPath)) {
11893
+ const scriptPath = path36.isAbsolute(tickScript) ? tickScript : path36.join(ctx.cwd, tickScript);
11894
+ if (!fs39.existsSync(scriptPath)) {
11831
11895
  ctx.output.exitCode = 99;
11832
11896
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
11833
11897
  return;
@@ -12951,7 +13015,7 @@ var writeJobStateFile = async (ctx, _profile, agentResult, args) => {
12951
13015
  };
12952
13016
 
12953
13017
  // src/scripts/writeRunSummary.ts
12954
- import * as fs39 from "fs";
13018
+ import * as fs40 from "fs";
12955
13019
  var writeRunSummary = async (ctx, profile) => {
12956
13020
  const summaryPath = process.env.GITHUB_STEP_SUMMARY;
12957
13021
  if (!summaryPath) return;
@@ -12973,7 +13037,7 @@ var writeRunSummary = async (ctx, profile) => {
12973
13037
  if (reason) lines.push(`- **Reason:** ${reason}`);
12974
13038
  lines.push("");
12975
13039
  try {
12976
- fs39.appendFileSync(summaryPath, `${lines.join("\n")}
13040
+ fs40.appendFileSync(summaryPath, `${lines.join("\n")}
12977
13041
  `);
12978
13042
  } catch {
12979
13043
  }
@@ -13241,9 +13305,9 @@ async function runExecutable(profileName, input) {
13241
13305
  })
13242
13306
  };
13243
13307
  })() : null;
13244
- const ndjsonDir = path36.join(input.cwd, ".kody");
13308
+ const ndjsonDir = path37.join(input.cwd, ".kody");
13245
13309
  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);
13310
+ const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path37.isAbsolute(p) ? p : path37.resolve(profile.dir, p)).filter((p) => p.length > 0);
13247
13311
  const syntheticPath = ctx.data.syntheticPluginPath;
13248
13312
  const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
13249
13313
  const agents = loadSubagents(profile);
@@ -13457,7 +13521,7 @@ function clearStampedLifecycleLabels(profile, ctx) {
13457
13521
  function getProfileInputsForChild(profileName, _cwd) {
13458
13522
  try {
13459
13523
  const profilePath = resolveProfilePath(profileName);
13460
- if (!fs40.existsSync(profilePath)) return null;
13524
+ if (!fs41.existsSync(profilePath)) return null;
13461
13525
  return loadProfile(profilePath).inputs;
13462
13526
  } catch {
13463
13527
  return null;
@@ -13466,17 +13530,17 @@ function getProfileInputsForChild(profileName, _cwd) {
13466
13530
  function resolveProfilePath(profileName) {
13467
13531
  const found = resolveExecutable(profileName);
13468
13532
  if (found) return found;
13469
- const here = path36.dirname(new URL(import.meta.url).pathname);
13533
+ const here = path37.dirname(new URL(import.meta.url).pathname);
13470
13534
  const candidates = [
13471
- path36.join(here, "executables", profileName, "profile.json"),
13535
+ path37.join(here, "executables", profileName, "profile.json"),
13472
13536
  // same-dir sibling (dev)
13473
- path36.join(here, "..", "executables", profileName, "profile.json"),
13537
+ path37.join(here, "..", "executables", profileName, "profile.json"),
13474
13538
  // up one (prod: dist/bin → dist/executables)
13475
- path36.join(here, "..", "src", "executables", profileName, "profile.json")
13539
+ path37.join(here, "..", "src", "executables", profileName, "profile.json")
13476
13540
  // fallback
13477
13541
  ];
13478
13542
  for (const c of candidates) {
13479
- if (fs40.existsSync(c)) return c;
13543
+ if (fs41.existsSync(c)) return c;
13480
13544
  }
13481
13545
  return candidates[0];
13482
13546
  }
@@ -13576,8 +13640,8 @@ function resolveShellTimeoutMs(entry) {
13576
13640
  var SIGKILL_GRACE_MS = 5e3;
13577
13641
  async function runShellEntry(entry, ctx, profile) {
13578
13642
  const shellName = entry.shell;
13579
- const shellPath = path36.join(profile.dir, shellName);
13580
- if (!fs40.existsSync(shellPath)) {
13643
+ const shellPath = path37.join(profile.dir, shellName);
13644
+ if (!fs41.existsSync(shellPath)) {
13581
13645
  ctx.skipAgent = true;
13582
13646
  ctx.output.exitCode = 99;
13583
13647
  ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
@@ -14083,9 +14147,9 @@ async function resolveAuthToken(env = process.env) {
14083
14147
  return void 0;
14084
14148
  }
14085
14149
  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";
14150
+ if (fs42.existsSync(path38.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
14151
+ if (fs42.existsSync(path38.join(cwd, "yarn.lock"))) return "yarn";
14152
+ if (fs42.existsSync(path38.join(cwd, "bun.lockb"))) return "bun";
14089
14153
  return "npm";
14090
14154
  }
14091
14155
  function shellOut(cmd, args, cwd, stream = true) {
@@ -14172,11 +14236,11 @@ function configureGitIdentity(cwd) {
14172
14236
  }
14173
14237
  function postFailureTail(issueNumber, cwd, reason) {
14174
14238
  if (!issueNumber) return;
14175
- const logPath = path37.join(cwd, ".kody", "last-run.jsonl");
14239
+ const logPath = path38.join(cwd, ".kody", "last-run.jsonl");
14176
14240
  let tail = "";
14177
14241
  try {
14178
- if (fs41.existsSync(logPath)) {
14179
- const content = fs41.readFileSync(logPath, "utf-8");
14242
+ if (fs42.existsSync(logPath)) {
14243
+ const content = fs42.readFileSync(logPath, "utf-8");
14180
14244
  tail = content.slice(-3e3);
14181
14245
  }
14182
14246
  } catch {
@@ -14201,7 +14265,7 @@ async function runCi(argv) {
14201
14265
  return 0;
14202
14266
  }
14203
14267
  const args = parseCiArgs(argv);
14204
- const cwd = args.cwd ? path37.resolve(args.cwd) : process.cwd();
14268
+ const cwd = args.cwd ? path38.resolve(args.cwd) : process.cwd();
14205
14269
  let earlyConfig;
14206
14270
  try {
14207
14271
  earlyConfig = loadConfig(cwd);
@@ -14211,9 +14275,9 @@ async function runCi(argv) {
14211
14275
  const eventName = process.env.GITHUB_EVENT_NAME;
14212
14276
  const dispatchEventPath = process.env.GITHUB_EVENT_PATH;
14213
14277
  let manualWorkflowDispatch = false;
14214
- if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs41.existsSync(dispatchEventPath)) {
14278
+ if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs42.existsSync(dispatchEventPath)) {
14215
14279
  try {
14216
- const evt = JSON.parse(fs41.readFileSync(dispatchEventPath, "utf-8"));
14280
+ const evt = JSON.parse(fs42.readFileSync(dispatchEventPath, "utf-8"));
14217
14281
  const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
14218
14282
  const sessionInput = String(evt?.inputs?.sessionId ?? "");
14219
14283
  manualWorkflowDispatch = !sessionInput && !(Number.isFinite(issueInput) && issueInput > 0);
@@ -14474,12 +14538,12 @@ function parseChatArgs(argv, env = process.env) {
14474
14538
  return result;
14475
14539
  }
14476
14540
  function commitChatFiles(cwd, sessionId, verbose) {
14477
- const sessionFile = path38.relative(cwd, sessionFilePath(cwd, sessionId));
14478
- const eventsFile = path38.relative(cwd, eventsFilePath(cwd, sessionId));
14541
+ const sessionFile = path39.relative(cwd, sessionFilePath(cwd, sessionId));
14542
+ const eventsFile = path39.relative(cwd, eventsFilePath(cwd, sessionId));
14479
14543
  const safeSession = sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
14480
- const tasksDir = path38.join(".kody", "tasks", safeSession);
14544
+ const tasksDir = path39.join(".kody", "tasks", safeSession);
14481
14545
  const candidatePaths = [sessionFile, eventsFile, tasksDir];
14482
- const paths = candidatePaths.filter((p) => fs42.existsSync(path38.join(cwd, p)));
14546
+ const paths = candidatePaths.filter((p) => fs43.existsSync(path39.join(cwd, p)));
14483
14547
  if (paths.length === 0) return;
14484
14548
  const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
14485
14549
  try {
@@ -14523,7 +14587,7 @@ async function runChat(argv) {
14523
14587
  ${CHAT_HELP}`);
14524
14588
  return 64;
14525
14589
  }
14526
- const cwd = args.cwd ? path38.resolve(args.cwd) : process.cwd();
14590
+ const cwd = args.cwd ? path39.resolve(args.cwd) : process.cwd();
14527
14591
  const sessionId = args.sessionId;
14528
14592
  const unpackedSecrets = unpackAllSecrets();
14529
14593
  if (unpackedSecrets > 0) {
@@ -14575,7 +14639,7 @@ ${CHAT_HELP}`);
14575
14639
  const sink = buildSink(cwd, sessionId, args.dashboardUrl);
14576
14640
  const meta = readMeta(sessionFile);
14577
14641
  process.stdout.write(
14578
- `\u2192 kody:chat: session file=${sessionFile} exists=${fs42.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
14642
+ `\u2192 kody:chat: session file=${sessionFile} exists=${fs43.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
14579
14643
  `
14580
14644
  );
14581
14645
  try {