@kody-ade/kody-engine 0.4.88 → 0.4.89

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 +417 -350
  2. package/package.json +1 -1
package/dist/bin/kody.js CHANGED
@@ -19,8 +19,8 @@ __export(events_exports, {
19
19
  resolveRunId: () => resolveRunId
20
20
  });
21
21
  import * as crypto from "crypto";
22
- import * as fs3 from "fs";
23
- import * as path3 from "path";
22
+ import * as fs4 from "fs";
23
+ import * as path4 from "path";
24
24
  function resolveRunId() {
25
25
  if (cachedRunId) return cachedRunId;
26
26
  if (process.env.KODY_RUN_ID) {
@@ -49,17 +49,17 @@ function emitEvent(cwd, ev) {
49
49
  runId,
50
50
  ...ev
51
51
  };
52
- const eventsPath2 = path3.join(cwd, ".kody", "runs", runId, "events.jsonl");
53
- fs3.mkdirSync(path3.dirname(eventsPath2), { recursive: true });
54
- fs3.appendFileSync(eventsPath2, `${JSON.stringify(fullEvent)}
52
+ const eventsPath2 = path4.join(cwd, ".kody", "runs", runId, "events.jsonl");
53
+ fs4.mkdirSync(path4.dirname(eventsPath2), { recursive: true });
54
+ fs4.appendFileSync(eventsPath2, `${JSON.stringify(fullEvent)}
55
55
  `);
56
56
  } catch {
57
57
  }
58
58
  }
59
59
  function readEvents(cwd, runId) {
60
- const eventsPath2 = path3.join(cwd, ".kody", "runs", runId, "events.jsonl");
61
- if (!fs3.existsSync(eventsPath2)) return [];
62
- const lines = fs3.readFileSync(eventsPath2, "utf-8").split("\n");
60
+ const eventsPath2 = path4.join(cwd, ".kody", "runs", runId, "events.jsonl");
61
+ if (!fs4.existsSync(eventsPath2)) return [];
62
+ const lines = fs4.readFileSync(eventsPath2, "utf-8").split("\n");
63
63
  const out = [];
64
64
  for (const line of lines) {
65
65
  const trimmed = line.trim();
@@ -72,11 +72,11 @@ function readEvents(cwd, runId) {
72
72
  return out;
73
73
  }
74
74
  function listRuns(cwd) {
75
- const runsDir = path3.join(cwd, ".kody", "runs");
76
- if (!fs3.existsSync(runsDir)) return [];
77
- return fs3.readdirSync(runsDir).filter((name) => {
75
+ const runsDir = path4.join(cwd, ".kody", "runs");
76
+ if (!fs4.existsSync(runsDir)) return [];
77
+ return fs4.readdirSync(runsDir).filter((name) => {
78
78
  try {
79
- return fs3.statSync(path3.join(runsDir, name)).isDirectory();
79
+ return fs4.statSync(path4.join(runsDir, name)).isDirectory();
80
80
  } catch {
81
81
  return false;
82
82
  }
@@ -469,16 +469,16 @@ var init_issue = __esm({
469
469
  });
470
470
 
471
471
  // src/prompt.ts
472
- import * as fs16 from "fs";
473
- import * as path14 from "path";
472
+ import * as fs17 from "fs";
473
+ import * as path15 from "path";
474
474
  function loadProjectConventions(projectDir) {
475
475
  const out = [];
476
476
  for (const rel of CONVENTION_FILES) {
477
- const abs = path14.join(projectDir, rel);
478
- if (!fs16.existsSync(abs)) continue;
477
+ const abs = path15.join(projectDir, rel);
478
+ if (!fs17.existsSync(abs)) continue;
479
479
  let content;
480
480
  try {
481
- content = fs16.readFileSync(abs, "utf-8");
481
+ content = fs17.readFileSync(abs, "utf-8");
482
482
  } catch {
483
483
  continue;
484
484
  }
@@ -626,28 +626,28 @@ var loadMemoryContext_exports = {};
626
626
  __export(loadMemoryContext_exports, {
627
627
  loadMemoryContext: () => loadMemoryContext
628
628
  });
629
- import * as fs30 from "fs";
630
- import * as path28 from "path";
629
+ import * as fs31 from "fs";
630
+ import * as path29 from "path";
631
631
  function collectPages(memoryAbs) {
632
632
  const out = [];
633
633
  walkMd(memoryAbs, (file) => {
634
634
  let stat;
635
635
  try {
636
- stat = fs30.statSync(file);
636
+ stat = fs31.statSync(file);
637
637
  } catch {
638
638
  return;
639
639
  }
640
640
  let raw;
641
641
  try {
642
- raw = fs30.readFileSync(file, "utf-8");
642
+ raw = fs31.readFileSync(file, "utf-8");
643
643
  } catch {
644
644
  return;
645
645
  }
646
646
  const fm = raw.match(/^---\s*\n([\s\S]*?)\n---/);
647
- const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path28.basename(file, ".md");
647
+ const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path29.basename(file, ".md");
648
648
  const updated = fm?.[1]?.match(/^updated:\s*([0-9T:.+\-Z]+)/m)?.[1]?.trim() ?? "";
649
649
  out.push({
650
- relPath: path28.relative(memoryAbs, file),
650
+ relPath: path29.relative(memoryAbs, file),
651
651
  title,
652
652
  updated,
653
653
  content: raw.length > PER_PAGE_MAX_BYTES ? raw.slice(0, PER_PAGE_MAX_BYTES) + TRUNCATED_SUFFIX : raw,
@@ -715,16 +715,16 @@ function walkMd(root, visit) {
715
715
  const dir = stack.pop();
716
716
  let names;
717
717
  try {
718
- names = fs30.readdirSync(dir);
718
+ names = fs31.readdirSync(dir);
719
719
  } catch {
720
720
  continue;
721
721
  }
722
722
  for (const name of names) {
723
723
  if (name.startsWith(".")) continue;
724
- const full = path28.join(dir, name);
724
+ const full = path29.join(dir, name);
725
725
  let stat;
726
726
  try {
727
- stat = fs30.statSync(full);
727
+ stat = fs31.statSync(full);
728
728
  } catch {
729
729
  continue;
730
730
  }
@@ -747,8 +747,8 @@ var init_loadMemoryContext = __esm({
747
747
  TRUNCATED_SUFFIX = "\n\n\u2026 (truncated)";
748
748
  loadMemoryContext = async (ctx) => {
749
749
  if (typeof ctx.data.memoryContext === "string") return;
750
- const memoryAbs = path28.join(ctx.cwd, MEMORY_DIR_RELATIVE);
751
- if (!fs30.existsSync(memoryAbs)) {
750
+ const memoryAbs = path29.join(ctx.cwd, MEMORY_DIR_RELATIVE);
751
+ if (!fs31.existsSync(memoryAbs)) {
752
752
  ctx.data.memoryContext = "";
753
753
  return;
754
754
  }
@@ -877,7 +877,7 @@ var init_loadPriorArt = __esm({
877
877
  // package.json
878
878
  var package_default = {
879
879
  name: "@kody-ade/kody-engine",
880
- version: "0.4.88",
880
+ version: "0.4.89",
881
881
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
882
882
  license: "MIT",
883
883
  type: "module",
@@ -932,8 +932,8 @@ var package_default = {
932
932
 
933
933
  // src/chat-cli.ts
934
934
  import { execFileSync as execFileSync31 } from "child_process";
935
- import * as fs36 from "fs";
936
- import * as path33 from "path";
935
+ import * as fs37 from "fs";
936
+ import * as path34 from "path";
937
937
 
938
938
  // src/chat/events.ts
939
939
  import * as fs from "fs";
@@ -999,16 +999,79 @@ function makeRunId(sessionId, suffix) {
999
999
  }
1000
1000
 
1001
1001
  // src/chat/loop.ts
1002
- import * as fs7 from "fs";
1002
+ import * as fs8 from "fs";
1003
1003
 
1004
1004
  // src/agent.ts
1005
- import * as fs4 from "fs";
1006
- import * as path4 from "path";
1005
+ import * as fs5 from "fs";
1006
+ import * as path5 from "path";
1007
1007
  import { query } from "@anthropic-ai/claude-agent-sdk";
1008
1008
 
1009
- // src/config.ts
1009
+ // src/claudeBinary.ts
1010
1010
  import * as fs2 from "fs";
1011
+ import { createRequire } from "module";
1012
+ import * as os from "os";
1011
1013
  import * as path2 from "path";
1014
+ var SDK_PKG = "@anthropic-ai/claude-agent-sdk";
1015
+ function candidateSpecs(platform, arch) {
1016
+ const ext = platform === "win32" ? ".exe" : "";
1017
+ const pkgs = platform === "linux" ? [`${SDK_PKG}-linux-${arch}-musl`, `${SDK_PKG}-linux-${arch}`] : [`${SDK_PKG}-${platform}-${arch}`];
1018
+ return pkgs.map((p) => `${p}/claude${ext}`);
1019
+ }
1020
+ function readSdkVersion(req) {
1021
+ try {
1022
+ const entry = req.resolve(SDK_PKG);
1023
+ const pkgDir = path2.dirname(entry);
1024
+ const raw = fs2.readFileSync(path2.join(pkgDir, "package.json"), "utf8");
1025
+ const v = JSON.parse(raw)?.version;
1026
+ return typeof v === "string" && v.length > 0 ? v : "unknown";
1027
+ } catch {
1028
+ return "unknown";
1029
+ }
1030
+ }
1031
+ var cached;
1032
+ function ensureStableClaudeBinary() {
1033
+ if (cached !== void 0) return cached;
1034
+ try {
1035
+ const req = createRequire(import.meta.url);
1036
+ const sdkEntry = req.resolve(SDK_PKG);
1037
+ const sdkReq = createRequire(sdkEntry);
1038
+ let source = null;
1039
+ for (const spec of candidateSpecs(process.platform, process.arch)) {
1040
+ try {
1041
+ source = sdkReq.resolve(spec);
1042
+ break;
1043
+ } catch {
1044
+ }
1045
+ }
1046
+ if (!source || !fs2.existsSync(source)) {
1047
+ cached = null;
1048
+ return cached;
1049
+ }
1050
+ const ext = process.platform === "win32" ? ".exe" : "";
1051
+ const version = readSdkVersion(req);
1052
+ const destDir = path2.join(os.tmpdir(), "kody-claude-sdk", version);
1053
+ const dest = path2.join(destDir, `claude${ext}`);
1054
+ const srcSize = fs2.statSync(source).size;
1055
+ if (fs2.existsSync(dest) && fs2.statSync(dest).size === srcSize) {
1056
+ cached = dest;
1057
+ return cached;
1058
+ }
1059
+ fs2.mkdirSync(destDir, { recursive: true });
1060
+ const tmp = path2.join(destDir, `.claude.${process.pid}.${Date.now()}.tmp`);
1061
+ fs2.copyFileSync(source, tmp);
1062
+ fs2.chmodSync(tmp, 493);
1063
+ fs2.renameSync(tmp, dest);
1064
+ cached = dest;
1065
+ return cached;
1066
+ } catch {
1067
+ cached = null;
1068
+ return cached;
1069
+ }
1070
+ }
1071
+
1072
+ // src/config.ts
1073
+ import * as fs3 from "fs";
1074
+ import * as path3 from "path";
1012
1075
  var LITELLM_DEFAULT_PORT = 4e3;
1013
1076
  var LITELLM_DEFAULT_URL = `http://localhost:${LITELLM_DEFAULT_PORT}`;
1014
1077
  function parseProviderModel(s) {
@@ -1026,13 +1089,13 @@ function needsLitellmProxy(model) {
1026
1089
  return model.provider !== "claude" && model.provider !== "anthropic";
1027
1090
  }
1028
1091
  function loadConfig(projectDir = process.cwd()) {
1029
- const configPath = path2.join(projectDir, "kody.config.json");
1030
- if (!fs2.existsSync(configPath)) {
1092
+ const configPath = path3.join(projectDir, "kody.config.json");
1093
+ if (!fs3.existsSync(configPath)) {
1031
1094
  throw new Error(`kody.config.json not found at ${configPath}`);
1032
1095
  }
1033
1096
  let raw;
1034
1097
  try {
1035
- raw = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
1098
+ raw = JSON.parse(fs3.readFileSync(configPath, "utf-8"));
1036
1099
  } catch (err) {
1037
1100
  const msg = err instanceof Error ? err.message : String(err);
1038
1101
  throw new Error(`kody.config.json is invalid JSON: ${msg}`);
@@ -1295,10 +1358,10 @@ function resolveTurnTimeoutMs(opts) {
1295
1358
  return DEFAULT_TURN_TIMEOUT_MS;
1296
1359
  }
1297
1360
  async function runAgent(opts) {
1298
- const ndjsonDir = opts.ndjsonDir ?? path4.join(opts.cwd, ".kody");
1299
- fs4.mkdirSync(ndjsonDir, { recursive: true });
1300
- const ndjsonPath = path4.join(ndjsonDir, "last-run.jsonl");
1301
- const fullLog = fs4.createWriteStream(ndjsonPath, { flags: "w" });
1361
+ const ndjsonDir = opts.ndjsonDir ?? path5.join(opts.cwd, ".kody");
1362
+ fs5.mkdirSync(ndjsonDir, { recursive: true });
1363
+ const ndjsonPath = path5.join(ndjsonDir, "last-run.jsonl");
1364
+ const fullLog = fs5.createWriteStream(ndjsonPath, { flags: "w" });
1302
1365
  const env = {
1303
1366
  ...process.env,
1304
1367
  SKIP_HOOKS: "1",
@@ -1382,6 +1445,10 @@ async function runAgent(opts) {
1382
1445
  };
1383
1446
  }
1384
1447
  queryOptions.settingSources = opts.settingSources ?? ["project", "local"];
1448
+ const stableBinary = ensureStableClaudeBinary();
1449
+ if (stableBinary) {
1450
+ queryOptions.pathToClaudeCodeExecutable = stableBinary;
1451
+ }
1385
1452
  const result = query({
1386
1453
  prompt: opts.prompt,
1387
1454
  // biome-ignore lint/suspicious/noExplicitAny: SDK options type is narrow; mcpServers is runtime-passthrough.
@@ -1525,48 +1592,48 @@ async function runAgent(opts) {
1525
1592
  }
1526
1593
 
1527
1594
  // src/registry.ts
1528
- import * as fs5 from "fs";
1529
- import * as path5 from "path";
1595
+ import * as fs6 from "fs";
1596
+ import * as path6 from "path";
1530
1597
  function getExecutablesRoot() {
1531
- const here = path5.dirname(new URL(import.meta.url).pathname);
1598
+ const here = path6.dirname(new URL(import.meta.url).pathname);
1532
1599
  const candidates = [
1533
- path5.join(here, "executables"),
1600
+ path6.join(here, "executables"),
1534
1601
  // dev: src/
1535
- path5.join(here, "..", "executables"),
1602
+ path6.join(here, "..", "executables"),
1536
1603
  // built: dist/bin → dist/executables
1537
- path5.join(here, "..", "src", "executables")
1604
+ path6.join(here, "..", "src", "executables")
1538
1605
  // fallback
1539
1606
  ];
1540
1607
  for (const c of candidates) {
1541
- if (fs5.existsSync(c) && fs5.statSync(c).isDirectory()) return c;
1608
+ if (fs6.existsSync(c) && fs6.statSync(c).isDirectory()) return c;
1542
1609
  }
1543
1610
  return candidates[0];
1544
1611
  }
1545
1612
  function getProjectExecutablesRoot() {
1546
- return path5.join(process.cwd(), ".kody", "executables");
1613
+ return path6.join(process.cwd(), ".kody", "executables");
1547
1614
  }
1548
1615
  function getBuiltinJobsRoot() {
1549
- const here = path5.dirname(new URL(import.meta.url).pathname);
1616
+ const here = path6.dirname(new URL(import.meta.url).pathname);
1550
1617
  const candidates = [
1551
- path5.join(here, "jobs"),
1618
+ path6.join(here, "jobs"),
1552
1619
  // dev: src/
1553
- path5.join(here, "..", "jobs"),
1620
+ path6.join(here, "..", "jobs"),
1554
1621
  // built: dist/bin → dist/jobs
1555
- path5.join(here, "..", "src", "jobs")
1622
+ path6.join(here, "..", "src", "jobs")
1556
1623
  // fallback
1557
1624
  ];
1558
1625
  for (const c of candidates) {
1559
- if (fs5.existsSync(c) && fs5.statSync(c).isDirectory()) return c;
1626
+ if (fs6.existsSync(c) && fs6.statSync(c).isDirectory()) return c;
1560
1627
  }
1561
1628
  return candidates[0];
1562
1629
  }
1563
1630
  function listBuiltinJobs(root = getBuiltinJobsRoot()) {
1564
- if (!fs5.existsSync(root) || !fs5.statSync(root).isDirectory()) return [];
1631
+ if (!fs6.existsSync(root) || !fs6.statSync(root).isDirectory()) return [];
1565
1632
  const out = [];
1566
- for (const ent of fs5.readdirSync(root, { withFileTypes: true })) {
1633
+ for (const ent of fs6.readdirSync(root, { withFileTypes: true })) {
1567
1634
  if (!ent.isFile() || !ent.name.endsWith(".md")) continue;
1568
1635
  const slug = ent.name.slice(0, -3);
1569
- out.push({ slug, filePath: path5.join(root, ent.name) });
1636
+ out.push({ slug, filePath: path6.join(root, ent.name) });
1570
1637
  }
1571
1638
  out.sort((a, b) => a.slug.localeCompare(b.slug));
1572
1639
  return out;
@@ -1579,13 +1646,13 @@ function listExecutables(roots = getExecutableRoots()) {
1579
1646
  const seen = /* @__PURE__ */ new Set();
1580
1647
  const out = [];
1581
1648
  for (const root of rootList) {
1582
- if (!fs5.existsSync(root)) continue;
1583
- const entries = fs5.readdirSync(root, { withFileTypes: true });
1649
+ if (!fs6.existsSync(root)) continue;
1650
+ const entries = fs6.readdirSync(root, { withFileTypes: true });
1584
1651
  for (const ent of entries) {
1585
1652
  if (!ent.isDirectory()) continue;
1586
1653
  if (seen.has(ent.name)) continue;
1587
- const profilePath = path5.join(root, ent.name, "profile.json");
1588
- if (fs5.existsSync(profilePath) && fs5.statSync(profilePath).isFile()) {
1654
+ const profilePath = path6.join(root, ent.name, "profile.json");
1655
+ if (fs6.existsSync(profilePath) && fs6.statSync(profilePath).isFile()) {
1589
1656
  out.push({ name: ent.name, profilePath });
1590
1657
  seen.add(ent.name);
1591
1658
  }
@@ -1597,8 +1664,8 @@ function resolveExecutable(name, roots = getExecutableRoots()) {
1597
1664
  if (!isSafeName(name)) return null;
1598
1665
  const rootList = typeof roots === "string" ? [roots] : roots;
1599
1666
  for (const root of rootList) {
1600
- const profilePath = path5.join(root, name, "profile.json");
1601
- if (fs5.existsSync(profilePath) && fs5.statSync(profilePath).isFile()) {
1667
+ const profilePath = path6.join(root, name, "profile.json");
1668
+ if (fs6.existsSync(profilePath) && fs6.statSync(profilePath).isFile()) {
1602
1669
  return profilePath;
1603
1670
  }
1604
1671
  }
@@ -1614,7 +1681,7 @@ function getProfileInputs(name, roots = getExecutableRoots()) {
1614
1681
  const profilePath = resolveExecutable(name, roots);
1615
1682
  if (!profilePath) return null;
1616
1683
  try {
1617
- const raw = JSON.parse(fs5.readFileSync(profilePath, "utf-8"));
1684
+ const raw = JSON.parse(fs6.readFileSync(profilePath, "utf-8"));
1618
1685
  if (!raw || typeof raw !== "object" || !Array.isArray(raw.inputs)) return [];
1619
1686
  return raw.inputs;
1620
1687
  } catch {
@@ -1644,14 +1711,14 @@ function parseGenericFlags(argv) {
1644
1711
  }
1645
1712
 
1646
1713
  // src/chat/session.ts
1647
- import * as fs6 from "fs";
1648
- import * as path6 from "path";
1714
+ import * as fs7 from "fs";
1715
+ import * as path7 from "path";
1649
1716
  function sessionFilePath(cwd, sessionId) {
1650
- return path6.join(cwd, ".kody", "sessions", `${sessionId}.jsonl`);
1717
+ return path7.join(cwd, ".kody", "sessions", `${sessionId}.jsonl`);
1651
1718
  }
1652
1719
  function readMeta(file) {
1653
- if (!fs6.existsSync(file)) return null;
1654
- const raw = fs6.readFileSync(file, "utf-8");
1720
+ if (!fs7.existsSync(file)) return null;
1721
+ const raw = fs7.readFileSync(file, "utf-8");
1655
1722
  const firstLine2 = raw.split("\n", 1)[0]?.trim();
1656
1723
  if (!firstLine2) return null;
1657
1724
  try {
@@ -1664,8 +1731,8 @@ function readMeta(file) {
1664
1731
  }
1665
1732
  }
1666
1733
  function readSession(file) {
1667
- if (!fs6.existsSync(file)) return [];
1668
- const raw = fs6.readFileSync(file, "utf-8").trim();
1734
+ if (!fs7.existsSync(file)) return [];
1735
+ const raw = fs7.readFileSync(file, "utf-8").trim();
1669
1736
  if (!raw) return [];
1670
1737
  const turns = [];
1671
1738
  for (const line of raw.split("\n")) {
@@ -1681,14 +1748,14 @@ function readSession(file) {
1681
1748
  return turns;
1682
1749
  }
1683
1750
  function appendTurn(file, turn) {
1684
- fs6.mkdirSync(path6.dirname(file), { recursive: true });
1751
+ fs7.mkdirSync(path7.dirname(file), { recursive: true });
1685
1752
  const line = JSON.stringify({
1686
1753
  role: turn.role,
1687
1754
  content: turn.content,
1688
1755
  timestamp: turn.timestamp,
1689
1756
  toolCalls: turn.toolCalls ?? []
1690
1757
  });
1691
- fs6.appendFileSync(file, `${line}
1758
+ fs7.appendFileSync(file, `${line}
1692
1759
  `);
1693
1760
  }
1694
1761
  function seedInitialMessage(file, message) {
@@ -1798,7 +1865,7 @@ function buildExecutableCatalog() {
1798
1865
  const entries = [];
1799
1866
  for (const { name, profilePath } of discovered) {
1800
1867
  try {
1801
- const raw = JSON.parse(fs7.readFileSync(profilePath, "utf-8"));
1868
+ const raw = JSON.parse(fs8.readFileSync(profilePath, "utf-8"));
1802
1869
  const describe = typeof raw.describe === "string" ? raw.describe : "";
1803
1870
  const firstSentence = describe.split(/(?<=[.!?])\s+/, 1)[0] ?? "";
1804
1871
  entries.push({ name, describe: firstSentence.trim() });
@@ -1922,9 +1989,9 @@ async function emit(sink, type, sessionId, suffix, payload) {
1922
1989
 
1923
1990
  // src/chat/modes/interactive.ts
1924
1991
  import { execFileSync as execFileSync2 } from "child_process";
1925
- import * as fs8 from "fs";
1926
- import * as os from "os";
1927
- import * as path7 from "path";
1992
+ import * as fs9 from "fs";
1993
+ import * as os2 from "os";
1994
+ import * as path8 from "path";
1928
1995
 
1929
1996
  // src/chat/inbox.ts
1930
1997
  import { execFileSync } from "child_process";
@@ -2081,9 +2148,9 @@ function findNextUserTurn(turns, fromIdx) {
2081
2148
  return -1;
2082
2149
  }
2083
2150
  function commitTurn(cwd, sessionId, verbose) {
2084
- const sessionRel = path7.relative(cwd, sessionFilePath(cwd, sessionId));
2085
- const eventsRel = path7.relative(cwd, eventsFilePath(cwd, sessionId));
2086
- const paths = [sessionRel, eventsRel].filter((p) => fs8.existsSync(path7.join(cwd, p)));
2151
+ const sessionRel = path8.relative(cwd, sessionFilePath(cwd, sessionId));
2152
+ const eventsRel = path8.relative(cwd, eventsFilePath(cwd, sessionId));
2153
+ const paths = [sessionRel, eventsRel].filter((p) => fs9.existsSync(path8.join(cwd, p)));
2087
2154
  if (paths.length === 0) return;
2088
2155
  const startBranch = currentBranch2(cwd);
2089
2156
  const eventsBranch = defaultBranch(cwd) ?? "main";
@@ -2093,17 +2160,17 @@ function commitTurn(cwd, sessionId, verbose) {
2093
2160
  }
2094
2161
  const stdio = verbose ? "inherit" : "pipe";
2095
2162
  const exec = (args) => execFileSync2("git", args, { cwd, stdio });
2096
- const worktreeDir = fs8.mkdtempSync(path7.join(os.tmpdir(), "kody-events-"));
2163
+ const worktreeDir = fs9.mkdtempSync(path8.join(os2.tmpdir(), "kody-events-"));
2097
2164
  let worktreeAdded = false;
2098
2165
  try {
2099
2166
  exec(["fetch", "--quiet", "origin", eventsBranch]);
2100
2167
  exec(["worktree", "add", "--detach", "--quiet", worktreeDir, `origin/${eventsBranch}`]);
2101
2168
  worktreeAdded = true;
2102
2169
  for (const rel of paths) {
2103
- const src = path7.join(cwd, rel);
2104
- const dst = path7.join(worktreeDir, rel);
2105
- fs8.mkdirSync(path7.dirname(dst), { recursive: true });
2106
- fs8.copyFileSync(src, dst);
2170
+ const src = path8.join(cwd, rel);
2171
+ const dst = path8.join(worktreeDir, rel);
2172
+ fs9.mkdirSync(path8.dirname(dst), { recursive: true });
2173
+ fs9.copyFileSync(src, dst);
2107
2174
  }
2108
2175
  commitPathsAndPush(worktreeDir, paths, sessionId, verbose, `HEAD:${eventsBranch}`);
2109
2176
  } catch (err) {
@@ -2118,7 +2185,7 @@ function commitTurn(cwd, sessionId, verbose) {
2118
2185
  }
2119
2186
  }
2120
2187
  try {
2121
- fs8.rmSync(worktreeDir, { recursive: true, force: true });
2188
+ fs9.rmSync(worktreeDir, { recursive: true, force: true });
2122
2189
  } catch {
2123
2190
  }
2124
2191
  }
@@ -2214,11 +2281,11 @@ async function emit2(sink, type, sessionId, suffix, payload) {
2214
2281
 
2215
2282
  // src/kody-cli.ts
2216
2283
  import { execFileSync as execFileSync30 } from "child_process";
2217
- import * as fs35 from "fs";
2218
- import * as path32 from "path";
2284
+ import * as fs36 from "fs";
2285
+ import * as path33 from "path";
2219
2286
 
2220
2287
  // src/dispatch.ts
2221
- import * as fs9 from "fs";
2288
+ import * as fs10 from "fs";
2222
2289
 
2223
2290
  // src/cron-match.ts
2224
2291
  var FIELD_BOUNDS = [
@@ -2302,10 +2369,10 @@ function autoDispatch(opts) {
2302
2369
  }
2303
2370
  const eventName = process.env.GITHUB_EVENT_NAME;
2304
2371
  const eventPath = process.env.GITHUB_EVENT_PATH;
2305
- if (!eventName || !eventPath || !fs9.existsSync(eventPath)) return null;
2372
+ if (!eventName || !eventPath || !fs10.existsSync(eventPath)) return null;
2306
2373
  let event = {};
2307
2374
  try {
2308
- event = JSON.parse(fs9.readFileSync(eventPath, "utf-8"));
2375
+ event = JSON.parse(fs10.readFileSync(eventPath, "utf-8"));
2309
2376
  } catch {
2310
2377
  return null;
2311
2378
  }
@@ -2378,7 +2445,7 @@ function autoDispatchTyped(opts) {
2378
2445
  if (legacy) return { kind: "route", ...legacy };
2379
2446
  const eventName = process.env.GITHUB_EVENT_NAME;
2380
2447
  const eventPath = process.env.GITHUB_EVENT_PATH;
2381
- if (!eventName || !eventPath || !fs9.existsSync(eventPath)) {
2448
+ if (!eventName || !eventPath || !fs10.existsSync(eventPath)) {
2382
2449
  return { kind: "silent", reason: "no GHA event context" };
2383
2450
  }
2384
2451
  if (eventName !== "issue_comment") {
@@ -2386,7 +2453,7 @@ function autoDispatchTyped(opts) {
2386
2453
  }
2387
2454
  let event = {};
2388
2455
  try {
2389
- event = JSON.parse(fs9.readFileSync(eventPath, "utf-8"));
2456
+ event = JSON.parse(fs10.readFileSync(eventPath, "utf-8"));
2390
2457
  } catch {
2391
2458
  return { kind: "silent", reason: "GHA event payload unreadable" };
2392
2459
  }
@@ -2420,7 +2487,7 @@ function dispatchScheduledWatches(opts) {
2420
2487
  for (const exe of listExecutables()) {
2421
2488
  let raw;
2422
2489
  try {
2423
- raw = fs9.readFileSync(exe.profilePath, "utf-8");
2490
+ raw = fs10.readFileSync(exe.profilePath, "utf-8");
2424
2491
  } catch {
2425
2492
  continue;
2426
2493
  }
@@ -2537,16 +2604,16 @@ init_issue();
2537
2604
 
2538
2605
  // src/executor.ts
2539
2606
  import { execFileSync as execFileSync29, spawn as spawn6 } from "child_process";
2540
- import * as fs34 from "fs";
2541
- import * as path31 from "path";
2607
+ import * as fs35 from "fs";
2608
+ import * as path32 from "path";
2542
2609
  init_events();
2543
2610
 
2544
2611
  // src/lifecycleLabels.ts
2545
2612
  init_issue();
2546
2613
 
2547
2614
  // src/profile.ts
2548
- import * as fs10 from "fs";
2549
- import * as path8 from "path";
2615
+ import * as fs11 from "fs";
2616
+ import * as path9 from "path";
2550
2617
 
2551
2618
  // src/profile-error.ts
2552
2619
  var ProfileError = class extends Error {
@@ -2712,12 +2779,12 @@ var KNOWN_PROFILE_KEYS = /* @__PURE__ */ new Set([
2712
2779
  "preloadContext"
2713
2780
  ]);
2714
2781
  function loadProfile(profilePath) {
2715
- if (!fs10.existsSync(profilePath)) {
2782
+ if (!fs11.existsSync(profilePath)) {
2716
2783
  throw new ProfileError(profilePath, "file not found");
2717
2784
  }
2718
2785
  let raw;
2719
2786
  try {
2720
- raw = JSON.parse(fs10.readFileSync(profilePath, "utf-8"));
2787
+ raw = JSON.parse(fs11.readFileSync(profilePath, "utf-8"));
2721
2788
  } catch (err) {
2722
2789
  throw new ProfileError(profilePath, `invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
2723
2790
  }
@@ -2728,7 +2795,7 @@ function loadProfile(profilePath) {
2728
2795
  const unknownKeys = Object.keys(r).filter((k) => !KNOWN_PROFILE_KEYS.has(k));
2729
2796
  if (unknownKeys.length > 0) {
2730
2797
  process.stderr.write(
2731
- `[kody profile] ${path8.basename(path8.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
2798
+ `[kody profile] ${path9.basename(path9.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
2732
2799
  `
2733
2800
  );
2734
2801
  }
@@ -2789,7 +2856,7 @@ function loadProfile(profilePath) {
2789
2856
  // Phase 5 in-process handoff opt-in. Default false; containers
2790
2857
  // flip to true after end-to-end verification.
2791
2858
  preloadContext: r.preloadContext === true,
2792
- dir: path8.dirname(profilePath)
2859
+ dir: path9.dirname(profilePath)
2793
2860
  };
2794
2861
  if (lifecycle) {
2795
2862
  applyLifecycle(profile, profilePath);
@@ -3159,9 +3226,9 @@ function errMsg(err) {
3159
3226
 
3160
3227
  // src/litellm.ts
3161
3228
  import { execFileSync as execFileSync4, spawn as spawn2 } from "child_process";
3162
- import * as fs11 from "fs";
3163
- import * as os2 from "os";
3164
- import * as path9 from "path";
3229
+ import * as fs12 from "fs";
3230
+ import * as os3 from "os";
3231
+ import * as path10 from "path";
3165
3232
  async function checkLitellmHealth(url) {
3166
3233
  try {
3167
3234
  const response = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3e3) });
@@ -3208,20 +3275,20 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
3208
3275
  throw new Error("litellm not installed \u2014 run: pip install 'litellm[proxy]'");
3209
3276
  }
3210
3277
  }
3211
- const configPath = path9.join(os2.tmpdir(), `kody-litellm-${Date.now()}.yaml`);
3212
- fs11.writeFileSync(configPath, generateLitellmConfigYaml(model));
3278
+ const configPath = path10.join(os3.tmpdir(), `kody-litellm-${Date.now()}.yaml`);
3279
+ fs12.writeFileSync(configPath, generateLitellmConfigYaml(model));
3213
3280
  const portMatch = url.match(/:(\d+)/);
3214
3281
  const port = portMatch ? portMatch[1] : "4000";
3215
3282
  const args = cmd === "litellm" ? ["--config", configPath, "--port", port] : ["-m", "litellm", "--config", configPath, "--port", port];
3216
3283
  const dotenvVars = readDotenvApiKeys(projectDir);
3217
- const logPath = path9.join(os2.tmpdir(), `kody-litellm-${Date.now()}.log`);
3218
- const outFd = fs11.openSync(logPath, "w");
3284
+ const logPath = path10.join(os3.tmpdir(), `kody-litellm-${Date.now()}.log`);
3285
+ const outFd = fs12.openSync(logPath, "w");
3219
3286
  const child = spawn2(cmd, args, {
3220
3287
  stdio: ["ignore", outFd, outFd],
3221
3288
  detached: true,
3222
3289
  env: stripBlockingEnv({ ...process.env, ...dotenvVars })
3223
3290
  });
3224
- fs11.closeSync(outFd);
3291
+ fs12.closeSync(outFd);
3225
3292
  const timeoutMs = resolveLitellmTimeoutMs();
3226
3293
  const deadline = Date.now() + timeoutMs;
3227
3294
  while (Date.now() < deadline) {
@@ -3240,7 +3307,7 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
3240
3307
  }
3241
3308
  let logTail = "";
3242
3309
  try {
3243
- logTail = fs11.readFileSync(logPath, "utf-8").slice(-2e3);
3310
+ logTail = fs12.readFileSync(logPath, "utf-8").slice(-2e3);
3244
3311
  } catch {
3245
3312
  }
3246
3313
  try {
@@ -3252,10 +3319,10 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
3252
3319
  ${logTail}`);
3253
3320
  }
3254
3321
  function readDotenvApiKeys(projectDir) {
3255
- const dotenvPath = path9.join(projectDir, ".env");
3256
- if (!fs11.existsSync(dotenvPath)) return {};
3322
+ const dotenvPath = path10.join(projectDir, ".env");
3323
+ if (!fs12.existsSync(dotenvPath)) return {};
3257
3324
  const result = {};
3258
- for (const rawLine of fs11.readFileSync(dotenvPath, "utf-8").split("\n")) {
3325
+ for (const rawLine of fs12.readFileSync(dotenvPath, "utf-8").split("\n")) {
3259
3326
  const line = rawLine.trim();
3260
3327
  if (!line || line.startsWith("#")) continue;
3261
3328
  const match = line.match(/^([A-Z_][A-Z0-9_]*_API_KEY)=(.*)$/);
@@ -3279,8 +3346,8 @@ function stripBlockingEnv(env) {
3279
3346
 
3280
3347
  // src/commit.ts
3281
3348
  import { execFileSync as execFileSync5 } from "child_process";
3282
- import * as fs12 from "fs";
3283
- import * as path10 from "path";
3349
+ import * as fs13 from "fs";
3350
+ import * as path11 from "path";
3284
3351
  var FORBIDDEN_PATH_PREFIXES = [
3285
3352
  ".kody/",
3286
3353
  ".kody-engine/",
@@ -3340,18 +3407,18 @@ function tryGit(args, cwd) {
3340
3407
  }
3341
3408
  function abortUnfinishedGitOps(cwd) {
3342
3409
  const aborted = [];
3343
- const gitDir = path10.join(cwd ?? process.cwd(), ".git");
3344
- if (!fs12.existsSync(gitDir)) return aborted;
3345
- if (fs12.existsSync(path10.join(gitDir, "MERGE_HEAD"))) {
3410
+ const gitDir = path11.join(cwd ?? process.cwd(), ".git");
3411
+ if (!fs13.existsSync(gitDir)) return aborted;
3412
+ if (fs13.existsSync(path11.join(gitDir, "MERGE_HEAD"))) {
3346
3413
  if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
3347
3414
  }
3348
- if (fs12.existsSync(path10.join(gitDir, "CHERRY_PICK_HEAD"))) {
3415
+ if (fs13.existsSync(path11.join(gitDir, "CHERRY_PICK_HEAD"))) {
3349
3416
  if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
3350
3417
  }
3351
- if (fs12.existsSync(path10.join(gitDir, "REVERT_HEAD"))) {
3418
+ if (fs13.existsSync(path11.join(gitDir, "REVERT_HEAD"))) {
3352
3419
  if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
3353
3420
  }
3354
- if (fs12.existsSync(path10.join(gitDir, "rebase-merge")) || fs12.existsSync(path10.join(gitDir, "rebase-apply"))) {
3421
+ if (fs13.existsSync(path11.join(gitDir, "rebase-merge")) || fs13.existsSync(path11.join(gitDir, "rebase-apply"))) {
3355
3422
  if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
3356
3423
  }
3357
3424
  try {
@@ -3407,7 +3474,7 @@ function normalizeCommitMessage(raw) {
3407
3474
  function commitAndPush(branch, agentMessage, cwd) {
3408
3475
  const allChanged = listChangedFiles(cwd);
3409
3476
  const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
3410
- const mergeHeadExists = fs12.existsSync(path10.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
3477
+ const mergeHeadExists = fs13.existsSync(path11.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
3411
3478
  if (allowedFiles.length === 0 && !mergeHeadExists) {
3412
3479
  return { committed: false, pushed: false, sha: "", message: "" };
3413
3480
  }
@@ -3723,20 +3790,20 @@ var advanceFlow = async (ctx, profile) => {
3723
3790
 
3724
3791
  // src/scripts/brainServe.ts
3725
3792
  import { createServer } from "http";
3726
- import * as fs14 from "fs";
3727
- import * as path12 from "path";
3793
+ import * as fs15 from "fs";
3794
+ import * as path13 from "path";
3728
3795
 
3729
3796
  // src/scripts/brainTurnLog.ts
3730
- import * as fs13 from "fs";
3731
- import * as path11 from "path";
3797
+ import * as fs14 from "fs";
3798
+ import * as path12 from "path";
3732
3799
  var live = /* @__PURE__ */ new Map();
3733
3800
  function eventsPath(dir, chatId) {
3734
- return path11.join(dir, ".kody", "brain-events", `${chatId}.jsonl`);
3801
+ return path12.join(dir, ".kody", "brain-events", `${chatId}.jsonl`);
3735
3802
  }
3736
3803
  function lastPersistedSeq(dir, chatId) {
3737
3804
  const p = eventsPath(dir, chatId);
3738
- if (!fs13.existsSync(p)) return 0;
3739
- const lines = fs13.readFileSync(p, "utf-8").split("\n").filter(Boolean);
3805
+ if (!fs14.existsSync(p)) return 0;
3806
+ const lines = fs14.readFileSync(p, "utf-8").split("\n").filter(Boolean);
3740
3807
  if (lines.length === 0) return 0;
3741
3808
  try {
3742
3809
  return JSON.parse(lines[lines.length - 1]).seq || 0;
@@ -3746,9 +3813,9 @@ function lastPersistedSeq(dir, chatId) {
3746
3813
  }
3747
3814
  function readSince(dir, chatId, since) {
3748
3815
  const p = eventsPath(dir, chatId);
3749
- if (!fs13.existsSync(p)) return [];
3816
+ if (!fs14.existsSync(p)) return [];
3750
3817
  const out = [];
3751
- for (const line of fs13.readFileSync(p, "utf-8").split("\n")) {
3818
+ for (const line of fs14.readFileSync(p, "utf-8").split("\n")) {
3752
3819
  if (!line) continue;
3753
3820
  try {
3754
3821
  const rec = JSON.parse(line);
@@ -3774,12 +3841,12 @@ function beginTurn(dir, chatId) {
3774
3841
  };
3775
3842
  live.set(chatId, state);
3776
3843
  const p = eventsPath(dir, chatId);
3777
- fs13.mkdirSync(path11.dirname(p), { recursive: true });
3844
+ fs14.mkdirSync(path12.dirname(p), { recursive: true });
3778
3845
  return (event) => {
3779
3846
  state.seq += 1;
3780
3847
  const rec = { seq: state.seq, turn, ts: Date.now(), event };
3781
3848
  try {
3782
- fs13.appendFileSync(p, JSON.stringify(rec) + "\n");
3849
+ fs14.appendFileSync(p, JSON.stringify(rec) + "\n");
3783
3850
  } catch (err) {
3784
3851
  process.stderr.write(
3785
3852
  `[brain-turn-log] append failed for ${chatId}: ${err instanceof Error ? err.message : String(err)}
@@ -3817,7 +3884,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
3817
3884
  event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
3818
3885
  };
3819
3886
  try {
3820
- fs13.appendFileSync(eventsPath(dir, chatId), JSON.stringify(rec) + "\n");
3887
+ fs14.appendFileSync(eventsPath(dir, chatId), JSON.stringify(rec) + "\n");
3821
3888
  } catch {
3822
3889
  }
3823
3890
  state.status = "ended";
@@ -4034,7 +4101,7 @@ async function handleChatTurn(req, res, chatId, opts) {
4034
4101
  return;
4035
4102
  }
4036
4103
  const sessionFile = sessionFilePath(opts.cwd, chatId);
4037
- fs14.mkdirSync(path12.dirname(sessionFile), { recursive: true });
4104
+ fs15.mkdirSync(path13.dirname(sessionFile), { recursive: true });
4038
4105
  appendTurn(sessionFile, {
4039
4106
  role: "user",
4040
4107
  content: message,
@@ -4174,21 +4241,21 @@ var brainServe = async (ctx) => {
4174
4241
  };
4175
4242
 
4176
4243
  // src/scripts/buildSyntheticPlugin.ts
4177
- import * as fs15 from "fs";
4178
- import * as os3 from "os";
4179
- import * as path13 from "path";
4244
+ import * as fs16 from "fs";
4245
+ import * as os4 from "os";
4246
+ import * as path14 from "path";
4180
4247
  function getPluginsCatalogRoot() {
4181
- const here = path13.dirname(new URL(import.meta.url).pathname);
4248
+ const here = path14.dirname(new URL(import.meta.url).pathname);
4182
4249
  const candidates = [
4183
- path13.join(here, "..", "plugins"),
4250
+ path14.join(here, "..", "plugins"),
4184
4251
  // dev: src/scripts → src/plugins
4185
- path13.join(here, "..", "..", "plugins"),
4252
+ path14.join(here, "..", "..", "plugins"),
4186
4253
  // built: dist/scripts → dist/plugins
4187
- path13.join(here, "..", "..", "src", "plugins")
4254
+ path14.join(here, "..", "..", "src", "plugins")
4188
4255
  // fallback
4189
4256
  ];
4190
4257
  for (const c of candidates) {
4191
- if (fs15.existsSync(c) && fs15.statSync(c).isDirectory()) return c;
4258
+ if (fs16.existsSync(c) && fs16.statSync(c).isDirectory()) return c;
4192
4259
  }
4193
4260
  return candidates[0];
4194
4261
  }
@@ -4198,52 +4265,52 @@ var buildSyntheticPlugin = async (ctx, profile) => {
4198
4265
  if (!needsSynthetic) return;
4199
4266
  const catalog = getPluginsCatalogRoot();
4200
4267
  const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
4201
- const root = path13.join(os3.tmpdir(), `kody-synth-${runId}`);
4202
- fs15.mkdirSync(path13.join(root, ".claude-plugin"), { recursive: true });
4268
+ const root = path14.join(os4.tmpdir(), `kody-synth-${runId}`);
4269
+ fs16.mkdirSync(path14.join(root, ".claude-plugin"), { recursive: true });
4203
4270
  const resolvePart = (bucket, entry) => {
4204
- const local = path13.join(profile.dir, bucket, entry);
4205
- if (fs15.existsSync(local)) return local;
4206
- const central = path13.join(catalog, bucket, entry);
4207
- if (fs15.existsSync(central)) return central;
4271
+ const local = path14.join(profile.dir, bucket, entry);
4272
+ if (fs16.existsSync(local)) return local;
4273
+ const central = path14.join(catalog, bucket, entry);
4274
+ if (fs16.existsSync(central)) return central;
4208
4275
  throw new Error(
4209
4276
  `buildSyntheticPlugin: ${bucket} entry '${entry}' not found in executable dir (${profile.dir}/${bucket}/) or catalog (${catalog}/${bucket}/)`
4210
4277
  );
4211
4278
  };
4212
4279
  if (cc.skills.length > 0) {
4213
- const dst = path13.join(root, "skills");
4214
- fs15.mkdirSync(dst, { recursive: true });
4280
+ const dst = path14.join(root, "skills");
4281
+ fs16.mkdirSync(dst, { recursive: true });
4215
4282
  for (const name of cc.skills) {
4216
- copyDir(resolvePart("skills", name), path13.join(dst, name));
4283
+ copyDir(resolvePart("skills", name), path14.join(dst, name));
4217
4284
  }
4218
4285
  }
4219
4286
  if (cc.commands.length > 0) {
4220
- const dst = path13.join(root, "commands");
4221
- fs15.mkdirSync(dst, { recursive: true });
4287
+ const dst = path14.join(root, "commands");
4288
+ fs16.mkdirSync(dst, { recursive: true });
4222
4289
  for (const name of cc.commands) {
4223
- fs15.copyFileSync(resolvePart("commands", `${name}.md`), path13.join(dst, `${name}.md`));
4290
+ fs16.copyFileSync(resolvePart("commands", `${name}.md`), path14.join(dst, `${name}.md`));
4224
4291
  }
4225
4292
  }
4226
4293
  if (cc.subagents.length > 0) {
4227
- const dst = path13.join(root, "agents");
4228
- fs15.mkdirSync(dst, { recursive: true });
4294
+ const dst = path14.join(root, "agents");
4295
+ fs16.mkdirSync(dst, { recursive: true });
4229
4296
  for (const name of cc.subagents) {
4230
- fs15.copyFileSync(resolvePart("agents", `${name}.md`), path13.join(dst, `${name}.md`));
4297
+ fs16.copyFileSync(resolvePart("agents", `${name}.md`), path14.join(dst, `${name}.md`));
4231
4298
  }
4232
4299
  }
4233
4300
  if (cc.hooks.length > 0) {
4234
- const dst = path13.join(root, "hooks");
4235
- fs15.mkdirSync(dst, { recursive: true });
4301
+ const dst = path14.join(root, "hooks");
4302
+ fs16.mkdirSync(dst, { recursive: true });
4236
4303
  const merged = { hooks: {} };
4237
4304
  for (const name of cc.hooks) {
4238
4305
  const src = resolvePart("hooks", `${name}.json`);
4239
- const parsed = JSON.parse(fs15.readFileSync(src, "utf-8"));
4306
+ const parsed = JSON.parse(fs16.readFileSync(src, "utf-8"));
4240
4307
  for (const [event, entries] of Object.entries(parsed.hooks ?? {})) {
4241
4308
  if (!Array.isArray(entries)) continue;
4242
4309
  if (!merged.hooks[event]) merged.hooks[event] = [];
4243
4310
  merged.hooks[event].push(...entries);
4244
4311
  }
4245
4312
  }
4246
- fs15.writeFileSync(path13.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
4313
+ fs16.writeFileSync(path14.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
4247
4314
  `);
4248
4315
  }
4249
4316
  const manifest = {
@@ -4254,17 +4321,17 @@ var buildSyntheticPlugin = async (ctx, profile) => {
4254
4321
  if (cc.skills.length > 0) manifest.skills = ["./skills/"];
4255
4322
  if (cc.commands.length > 0) manifest.commands = ["./commands/"];
4256
4323
  if (cc.subagents.length > 0) manifest.agents = cc.subagents.map((n) => `./agents/${n}.md`);
4257
- fs15.writeFileSync(path13.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
4324
+ fs16.writeFileSync(path14.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
4258
4325
  `);
4259
4326
  ctx.data.syntheticPluginPath = root;
4260
4327
  };
4261
4328
  function copyDir(src, dst) {
4262
- fs15.mkdirSync(dst, { recursive: true });
4263
- for (const ent of fs15.readdirSync(src, { withFileTypes: true })) {
4264
- const s = path13.join(src, ent.name);
4265
- const d = path13.join(dst, ent.name);
4329
+ fs16.mkdirSync(dst, { recursive: true });
4330
+ for (const ent of fs16.readdirSync(src, { withFileTypes: true })) {
4331
+ const s = path14.join(src, ent.name);
4332
+ const d = path14.join(dst, ent.name);
4266
4333
  if (ent.isDirectory()) copyDir(s, d);
4267
- else if (ent.isFile()) fs15.copyFileSync(s, d);
4334
+ else if (ent.isFile()) fs16.copyFileSync(s, d);
4268
4335
  }
4269
4336
  }
4270
4337
 
@@ -4405,13 +4472,13 @@ function defaultLabelMap() {
4405
4472
  }
4406
4473
 
4407
4474
  // src/scripts/commitAndPush.ts
4408
- import * as fs17 from "fs";
4409
- import * as path15 from "path";
4475
+ import * as fs18 from "fs";
4476
+ import * as path16 from "path";
4410
4477
  init_events();
4411
4478
  var DEFAULT_COMMIT_MESSAGE = "chore: kody changes";
4412
4479
  function sentinelPathForStage(cwd, profileName) {
4413
4480
  const runId = resolveRunId();
4414
- return path15.join(cwd, ".kody", "runs", runId, `commit-${profileName}.lock`);
4481
+ return path16.join(cwd, ".kody", "runs", runId, `commit-${profileName}.lock`);
4415
4482
  }
4416
4483
  var commitAndPush2 = async (ctx, profile) => {
4417
4484
  const branch = ctx.data.branch;
@@ -4421,9 +4488,9 @@ var commitAndPush2 = async (ctx, profile) => {
4421
4488
  }
4422
4489
  const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
4423
4490
  const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name) : null;
4424
- if (sentinel && fs17.existsSync(sentinel)) {
4491
+ if (sentinel && fs18.existsSync(sentinel)) {
4425
4492
  try {
4426
- const replay = JSON.parse(fs17.readFileSync(sentinel, "utf-8"));
4493
+ const replay = JSON.parse(fs18.readFileSync(sentinel, "utf-8"));
4427
4494
  ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
4428
4495
  if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
4429
4496
  if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
@@ -4476,8 +4543,8 @@ var commitAndPush2 = async (ctx, profile) => {
4476
4543
  const result = ctx.data.commitResult;
4477
4544
  if (sentinel && result?.committed) {
4478
4545
  try {
4479
- fs17.mkdirSync(path15.dirname(sentinel), { recursive: true });
4480
- fs17.writeFileSync(
4546
+ fs18.mkdirSync(path16.dirname(sentinel), { recursive: true });
4547
+ fs18.writeFileSync(
4481
4548
  sentinel,
4482
4549
  JSON.stringify(
4483
4550
  {
@@ -4498,11 +4565,11 @@ var commitAndPush2 = async (ctx, profile) => {
4498
4565
 
4499
4566
  // src/scripts/commitGoalState.ts
4500
4567
  import { execFileSync as execFileSync9 } from "child_process";
4501
- import * as path16 from "path";
4568
+ import * as path17 from "path";
4502
4569
  var commitGoalState = async (ctx) => {
4503
4570
  const goal = ctx.data.goal;
4504
4571
  if (!goal) return;
4505
- const stateRel = path16.posix.join(".kody", "goals", goal.id, "state.json");
4572
+ const stateRel = path17.posix.join(".kody", "goals", goal.id, "state.json");
4506
4573
  try {
4507
4574
  execFileSync9("git", ["add", stateRel], { cwd: ctx.cwd, stdio: "pipe" });
4508
4575
  } catch (err) {
@@ -4547,20 +4614,20 @@ function describeCommitMessage(goal) {
4547
4614
  }
4548
4615
 
4549
4616
  // src/scripts/composePrompt.ts
4550
- import * as fs18 from "fs";
4551
- import * as path17 from "path";
4617
+ import * as fs19 from "fs";
4618
+ import * as path18 from "path";
4552
4619
  var MUSTACHE = /\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g;
4553
4620
  var composePrompt = async (ctx, profile) => {
4554
4621
  const explicit = ctx.data.promptTemplate;
4555
4622
  const mode = ctx.args.mode;
4556
4623
  const candidates = [
4557
- explicit ? path17.join(profile.dir, explicit) : null,
4558
- mode ? path17.join(profile.dir, "prompts", `${mode}.md`) : null,
4559
- path17.join(profile.dir, "prompt.md")
4624
+ explicit ? path18.join(profile.dir, explicit) : null,
4625
+ mode ? path18.join(profile.dir, "prompts", `${mode}.md`) : null,
4626
+ path18.join(profile.dir, "prompt.md")
4560
4627
  ].filter(Boolean);
4561
4628
  let templatePath = "";
4562
4629
  for (const c of candidates) {
4563
- if (fs18.existsSync(c)) {
4630
+ if (fs19.existsSync(c)) {
4564
4631
  templatePath = c;
4565
4632
  break;
4566
4633
  }
@@ -4568,7 +4635,7 @@ var composePrompt = async (ctx, profile) => {
4568
4635
  if (!templatePath) {
4569
4636
  throw new Error(`profile at ${profile.dir}: no prompt template found (tried ${candidates.join(", ")})`);
4570
4637
  }
4571
- const template = fs18.readFileSync(templatePath, "utf-8");
4638
+ const template = fs19.readFileSync(templatePath, "utf-8");
4572
4639
  const tokens = {
4573
4640
  ...stringifyAll(ctx.args, "args."),
4574
4641
  ...stringifyAll(ctx.data, ""),
@@ -4647,8 +4714,8 @@ function formatToolsUsage(profile) {
4647
4714
  // src/scripts/createQaGoal.ts
4648
4715
  init_issue();
4649
4716
  import { execFileSync as execFileSync10 } from "child_process";
4650
- import * as fs19 from "fs";
4651
- import * as path18 from "path";
4717
+ import * as fs20 from "fs";
4718
+ import * as path19 from "path";
4652
4719
 
4653
4720
  // src/scripts/postReviewResult.ts
4654
4721
  init_issue();
@@ -4901,8 +4968,8 @@ function createOrUpdateManifestIssue(number, manifest, cwd) {
4901
4968
  return { number: Number(m[1]), created: true };
4902
4969
  }
4903
4970
  function writeStateFile(cwd, goalId, lastDispatchedIssue) {
4904
- const dir = path18.join(cwd, ".kody", "goals", goalId);
4905
- fs19.mkdirSync(dir, { recursive: true });
4971
+ const dir = path19.join(cwd, ".kody", "goals", goalId);
4972
+ fs20.mkdirSync(dir, { recursive: true });
4906
4973
  const state = {
4907
4974
  version: 1,
4908
4975
  state: "active",
@@ -4910,8 +4977,8 @@ function writeStateFile(cwd, goalId, lastDispatchedIssue) {
4910
4977
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
4911
4978
  ...typeof lastDispatchedIssue === "number" ? { lastDispatchedIssue } : {}
4912
4979
  };
4913
- const filePath = path18.join(dir, "state.json");
4914
- fs19.writeFileSync(filePath, `${JSON.stringify(state, null, 2)}
4980
+ const filePath = path19.join(dir, "state.json");
4981
+ fs20.writeFileSync(filePath, `${JSON.stringify(state, null, 2)}
4915
4982
  `);
4916
4983
  return filePath;
4917
4984
  }
@@ -5420,15 +5487,15 @@ function filterGoalTaskPrs(prs, taskIssueNumbers) {
5420
5487
 
5421
5488
  // src/scripts/diagMcp.ts
5422
5489
  import { execFileSync as execFileSync11 } from "child_process";
5423
- import * as fs20 from "fs";
5424
- import * as os4 from "os";
5425
- import * as path19 from "path";
5490
+ import * as fs21 from "fs";
5491
+ import * as os5 from "os";
5492
+ import * as path20 from "path";
5426
5493
  var diagMcp = async (_ctx) => {
5427
- const home = os4.homedir();
5428
- const cacheDir = path19.join(home, ".cache", "ms-playwright");
5494
+ const home = os5.homedir();
5495
+ const cacheDir = path20.join(home, ".cache", "ms-playwright");
5429
5496
  let entries = [];
5430
5497
  try {
5431
- entries = fs20.readdirSync(cacheDir);
5498
+ entries = fs21.readdirSync(cacheDir);
5432
5499
  } catch {
5433
5500
  }
5434
5501
  const hasChromium = entries.some((e) => e.startsWith("chromium"));
@@ -5454,17 +5521,17 @@ var diagMcp = async (_ctx) => {
5454
5521
  };
5455
5522
 
5456
5523
  // src/scripts/discoverQaContext.ts
5457
- import * as fs22 from "fs";
5458
- import * as path21 from "path";
5524
+ import * as fs23 from "fs";
5525
+ import * as path22 from "path";
5459
5526
 
5460
5527
  // src/scripts/frameworkDetectors.ts
5461
- import * as fs21 from "fs";
5462
- import * as path20 from "path";
5528
+ import * as fs22 from "fs";
5529
+ import * as path21 from "path";
5463
5530
  function detectFrameworks(cwd) {
5464
5531
  const out = [];
5465
5532
  let deps = {};
5466
5533
  try {
5467
- const pkg = JSON.parse(fs21.readFileSync(path20.join(cwd, "package.json"), "utf-8"));
5534
+ const pkg = JSON.parse(fs22.readFileSync(path21.join(cwd, "package.json"), "utf-8"));
5468
5535
  deps = { ...pkg.dependencies, ...pkg.devDependencies };
5469
5536
  } catch {
5470
5537
  return out;
@@ -5501,7 +5568,7 @@ function detectFrameworks(cwd) {
5501
5568
  }
5502
5569
  function findFile(cwd, candidates) {
5503
5570
  for (const c of candidates) {
5504
- if (fs21.existsSync(path20.join(cwd, c))) return c;
5571
+ if (fs22.existsSync(path21.join(cwd, c))) return c;
5505
5572
  }
5506
5573
  return null;
5507
5574
  }
@@ -5514,18 +5581,18 @@ var COLLECTION_DIRS = [
5514
5581
  function discoverPayloadCollections(cwd) {
5515
5582
  const out = [];
5516
5583
  for (const dir of COLLECTION_DIRS) {
5517
- const full = path20.join(cwd, dir);
5518
- if (!fs21.existsSync(full)) continue;
5584
+ const full = path21.join(cwd, dir);
5585
+ if (!fs22.existsSync(full)) continue;
5519
5586
  let files;
5520
5587
  try {
5521
- files = fs21.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
5588
+ files = fs22.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
5522
5589
  } catch {
5523
5590
  continue;
5524
5591
  }
5525
5592
  for (const file of files) {
5526
5593
  try {
5527
- const filePath = path20.join(full, file);
5528
- const content = fs21.readFileSync(filePath, "utf-8").slice(0, 1e4);
5594
+ const filePath = path21.join(full, file);
5595
+ const content = fs22.readFileSync(filePath, "utf-8").slice(0, 1e4);
5529
5596
  const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
5530
5597
  if (!slugMatch) continue;
5531
5598
  const slug = slugMatch[1];
@@ -5539,7 +5606,7 @@ function discoverPayloadCollections(cwd) {
5539
5606
  out.push({
5540
5607
  name,
5541
5608
  slug,
5542
- filePath: path20.relative(cwd, filePath),
5609
+ filePath: path21.relative(cwd, filePath),
5543
5610
  fields: fields.slice(0, 20),
5544
5611
  hasAdmin
5545
5612
  });
@@ -5553,28 +5620,28 @@ var ADMIN_COMPONENT_DIRS = ["src/ui/admin", "src/admin/components", "src/compone
5553
5620
  function discoverAdminComponents(cwd, collections) {
5554
5621
  const out = [];
5555
5622
  for (const dir of ADMIN_COMPONENT_DIRS) {
5556
- const full = path20.join(cwd, dir);
5557
- if (!fs21.existsSync(full)) continue;
5623
+ const full = path21.join(cwd, dir);
5624
+ if (!fs22.existsSync(full)) continue;
5558
5625
  let entries;
5559
5626
  try {
5560
- entries = fs21.readdirSync(full, { withFileTypes: true });
5627
+ entries = fs22.readdirSync(full, { withFileTypes: true });
5561
5628
  } catch {
5562
5629
  continue;
5563
5630
  }
5564
5631
  for (const entry of entries) {
5565
- const entryPath = path20.join(full, entry.name);
5632
+ const entryPath = path21.join(full, entry.name);
5566
5633
  let name;
5567
5634
  let filePath;
5568
5635
  if (entry.isDirectory()) {
5569
5636
  const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
5570
- (f) => fs21.existsSync(path20.join(entryPath, f))
5637
+ (f) => fs22.existsSync(path21.join(entryPath, f))
5571
5638
  );
5572
5639
  if (!indexFile) continue;
5573
5640
  name = entry.name;
5574
- filePath = path20.relative(cwd, path20.join(entryPath, indexFile));
5641
+ filePath = path21.relative(cwd, path21.join(entryPath, indexFile));
5575
5642
  } else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
5576
5643
  name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
5577
- filePath = path20.relative(cwd, entryPath);
5644
+ filePath = path21.relative(cwd, entryPath);
5578
5645
  } else {
5579
5646
  continue;
5580
5647
  }
@@ -5582,7 +5649,7 @@ function discoverAdminComponents(cwd, collections) {
5582
5649
  if (collections) {
5583
5650
  for (const col of collections) {
5584
5651
  try {
5585
- const colContent = fs21.readFileSync(path20.join(cwd, col.filePath), "utf-8");
5652
+ const colContent = fs22.readFileSync(path21.join(cwd, col.filePath), "utf-8");
5586
5653
  if (colContent.includes(name)) {
5587
5654
  usedInCollection = col.slug;
5588
5655
  break;
@@ -5601,8 +5668,8 @@ function scanApiRoutes(cwd) {
5601
5668
  const out = [];
5602
5669
  const appDirs = ["src/app", "app"];
5603
5670
  for (const appDir of appDirs) {
5604
- const apiDir = path20.join(cwd, appDir, "api");
5605
- if (!fs21.existsSync(apiDir)) continue;
5671
+ const apiDir = path21.join(cwd, appDir, "api");
5672
+ if (!fs22.existsSync(apiDir)) continue;
5606
5673
  walkApiRoutes(apiDir, "/api", cwd, out);
5607
5674
  break;
5608
5675
  }
@@ -5611,14 +5678,14 @@ function scanApiRoutes(cwd) {
5611
5678
  function walkApiRoutes(dir, prefix, cwd, out) {
5612
5679
  let entries;
5613
5680
  try {
5614
- entries = fs21.readdirSync(dir, { withFileTypes: true });
5681
+ entries = fs22.readdirSync(dir, { withFileTypes: true });
5615
5682
  } catch {
5616
5683
  return;
5617
5684
  }
5618
5685
  const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
5619
5686
  if (routeFile) {
5620
5687
  try {
5621
- const content = fs21.readFileSync(path20.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
5688
+ const content = fs22.readFileSync(path21.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
5622
5689
  const methods = HTTP_METHODS.filter(
5623
5690
  (m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
5624
5691
  );
@@ -5626,7 +5693,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
5626
5693
  out.push({
5627
5694
  path: prefix,
5628
5695
  methods,
5629
- filePath: path20.relative(cwd, path20.join(dir, routeFile.name))
5696
+ filePath: path21.relative(cwd, path21.join(dir, routeFile.name))
5630
5697
  });
5631
5698
  }
5632
5699
  } catch {
@@ -5637,7 +5704,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
5637
5704
  if (entry.name === "node_modules" || entry.name === ".next") continue;
5638
5705
  let segment = entry.name;
5639
5706
  if (segment.startsWith("(") && segment.endsWith(")")) {
5640
- walkApiRoutes(path20.join(dir, entry.name), prefix, cwd, out);
5707
+ walkApiRoutes(path21.join(dir, entry.name), prefix, cwd, out);
5641
5708
  continue;
5642
5709
  }
5643
5710
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -5645,7 +5712,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
5645
5712
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
5646
5713
  segment = `:${segment.slice(1, -1)}`;
5647
5714
  }
5648
- walkApiRoutes(path20.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
5715
+ walkApiRoutes(path21.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
5649
5716
  }
5650
5717
  }
5651
5718
  var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
@@ -5665,10 +5732,10 @@ var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
5665
5732
  function scanEnvVars(cwd) {
5666
5733
  const candidates = [".env.example", ".env.local.example", ".env.template"];
5667
5734
  for (const envFile of candidates) {
5668
- const envPath = path20.join(cwd, envFile);
5669
- if (!fs21.existsSync(envPath)) continue;
5735
+ const envPath = path21.join(cwd, envFile);
5736
+ if (!fs22.existsSync(envPath)) continue;
5670
5737
  try {
5671
- const content = fs21.readFileSync(envPath, "utf-8");
5738
+ const content = fs22.readFileSync(envPath, "utf-8");
5672
5739
  const vars = [];
5673
5740
  for (const line of content.split("\n")) {
5674
5741
  const trimmed = line.trim();
@@ -5716,9 +5783,9 @@ function runQaDiscovery(cwd) {
5716
5783
  }
5717
5784
  function detectDevServer(cwd, out) {
5718
5785
  try {
5719
- const pkg = JSON.parse(fs22.readFileSync(path21.join(cwd, "package.json"), "utf-8"));
5786
+ const pkg = JSON.parse(fs23.readFileSync(path22.join(cwd, "package.json"), "utf-8"));
5720
5787
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
5721
- const pm = fs22.existsSync(path21.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs22.existsSync(path21.join(cwd, "yarn.lock")) ? "yarn" : fs22.existsSync(path21.join(cwd, "bun.lockb")) ? "bun" : "npm";
5788
+ const pm = fs23.existsSync(path22.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs23.existsSync(path22.join(cwd, "yarn.lock")) ? "yarn" : fs23.existsSync(path22.join(cwd, "bun.lockb")) ? "bun" : "npm";
5722
5789
  if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
5723
5790
  if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
5724
5791
  else if (allDeps.vite) out.devPort = 5173;
@@ -5728,8 +5795,8 @@ function detectDevServer(cwd, out) {
5728
5795
  function scanFrontendRoutes(cwd, out) {
5729
5796
  const appDirs = ["src/app", "app"];
5730
5797
  for (const appDir of appDirs) {
5731
- const full = path21.join(cwd, appDir);
5732
- if (!fs22.existsSync(full)) continue;
5798
+ const full = path22.join(cwd, appDir);
5799
+ if (!fs23.existsSync(full)) continue;
5733
5800
  walkFrontendRoutes(full, "", out);
5734
5801
  break;
5735
5802
  }
@@ -5737,7 +5804,7 @@ function scanFrontendRoutes(cwd, out) {
5737
5804
  function walkFrontendRoutes(dir, prefix, out) {
5738
5805
  let entries;
5739
5806
  try {
5740
- entries = fs22.readdirSync(dir, { withFileTypes: true });
5807
+ entries = fs23.readdirSync(dir, { withFileTypes: true });
5741
5808
  } catch {
5742
5809
  return;
5743
5810
  }
@@ -5754,7 +5821,7 @@ function walkFrontendRoutes(dir, prefix, out) {
5754
5821
  if (entry.name === "node_modules" || entry.name === ".next") continue;
5755
5822
  let segment = entry.name;
5756
5823
  if (segment.startsWith("(") && segment.endsWith(")")) {
5757
- walkFrontendRoutes(path21.join(dir, entry.name), prefix, out);
5824
+ walkFrontendRoutes(path22.join(dir, entry.name), prefix, out);
5758
5825
  continue;
5759
5826
  }
5760
5827
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -5762,7 +5829,7 @@ function walkFrontendRoutes(dir, prefix, out) {
5762
5829
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
5763
5830
  segment = `:${segment.slice(1, -1)}`;
5764
5831
  }
5765
- walkFrontendRoutes(path21.join(dir, entry.name), `${prefix}/${segment}`, out);
5832
+ walkFrontendRoutes(path22.join(dir, entry.name), `${prefix}/${segment}`, out);
5766
5833
  }
5767
5834
  }
5768
5835
  function detectAuthFiles(cwd, out) {
@@ -5779,23 +5846,23 @@ function detectAuthFiles(cwd, out) {
5779
5846
  "src/app/api/oauth"
5780
5847
  ];
5781
5848
  for (const c of candidates) {
5782
- if (fs22.existsSync(path21.join(cwd, c))) out.authFiles.push(c);
5849
+ if (fs23.existsSync(path22.join(cwd, c))) out.authFiles.push(c);
5783
5850
  }
5784
5851
  }
5785
5852
  function detectRoles(cwd, out) {
5786
5853
  const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
5787
5854
  for (const rp of rolePaths) {
5788
- const dir = path21.join(cwd, rp);
5789
- if (!fs22.existsSync(dir)) continue;
5855
+ const dir = path22.join(cwd, rp);
5856
+ if (!fs23.existsSync(dir)) continue;
5790
5857
  let files;
5791
5858
  try {
5792
- files = fs22.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
5859
+ files = fs23.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
5793
5860
  } catch {
5794
5861
  continue;
5795
5862
  }
5796
5863
  for (const f of files) {
5797
5864
  try {
5798
- const content = fs22.readFileSync(path21.join(dir, f), "utf-8").slice(0, 5e3);
5865
+ const content = fs23.readFileSync(path22.join(dir, f), "utf-8").slice(0, 5e3);
5799
5866
  const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
5800
5867
  if (roleMatches) {
5801
5868
  for (const m of roleMatches) {
@@ -6028,8 +6095,8 @@ function failedAction3(reason) {
6028
6095
  }
6029
6096
 
6030
6097
  // src/scripts/dispatchJobFileTicks.ts
6031
- import * as fs24 from "fs";
6032
- import * as path23 from "path";
6098
+ import * as fs25 from "fs";
6099
+ import * as path24 from "path";
6033
6100
 
6034
6101
  // src/scripts/jobFrontmatter.ts
6035
6102
  var SCHEDULE_EVERY_VALUES = [
@@ -6288,8 +6355,8 @@ var ContentsApiBackend = class {
6288
6355
  };
6289
6356
 
6290
6357
  // src/scripts/jobState/localFileBackend.ts
6291
- import * as fs23 from "fs";
6292
- import * as path22 from "path";
6358
+ import * as fs24 from "fs";
6359
+ import * as path23 from "path";
6293
6360
  var LocalFileBackend = class {
6294
6361
  name = "local-file";
6295
6362
  cwd;
@@ -6304,7 +6371,7 @@ var LocalFileBackend = class {
6304
6371
  if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
6305
6372
  this.cwd = opts.cwd;
6306
6373
  this.jobsDir = opts.jobsDir;
6307
- this.absDir = path22.join(opts.cwd, opts.jobsDir);
6374
+ this.absDir = path23.join(opts.cwd, opts.jobsDir);
6308
6375
  this.owner = opts.owner;
6309
6376
  this.repo = opts.repo;
6310
6377
  this.cache = opts.cache ?? defaultCacheAdapter();
@@ -6319,7 +6386,7 @@ var LocalFileBackend = class {
6319
6386
  `);
6320
6387
  return;
6321
6388
  }
6322
- fs23.mkdirSync(this.absDir, { recursive: true });
6389
+ fs24.mkdirSync(this.absDir, { recursive: true });
6323
6390
  const prefix = this.cacheKeyPrefix();
6324
6391
  const probeKey = `${prefix}probe-${Date.now()}`;
6325
6392
  try {
@@ -6348,7 +6415,7 @@ var LocalFileBackend = class {
6348
6415
  `);
6349
6416
  return;
6350
6417
  }
6351
- if (!fs23.existsSync(this.absDir)) {
6418
+ if (!fs24.existsSync(this.absDir)) {
6352
6419
  return;
6353
6420
  }
6354
6421
  const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
@@ -6364,11 +6431,11 @@ var LocalFileBackend = class {
6364
6431
  }
6365
6432
  load(slug) {
6366
6433
  const relPath = stateFilePath(this.jobsDir, slug);
6367
- const absPath = path22.join(this.cwd, relPath);
6368
- if (!fs23.existsSync(absPath)) {
6434
+ const absPath = path23.join(this.cwd, relPath);
6435
+ if (!fs24.existsSync(absPath)) {
6369
6436
  return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
6370
6437
  }
6371
- const raw = fs23.readFileSync(absPath, "utf-8");
6438
+ const raw = fs24.readFileSync(absPath, "utf-8");
6372
6439
  let parsed;
6373
6440
  try {
6374
6441
  parsed = JSON.parse(raw);
@@ -6385,10 +6452,10 @@ var LocalFileBackend = class {
6385
6452
  if (!loaded.created && isStateUnchanged(loaded.state, next)) {
6386
6453
  return false;
6387
6454
  }
6388
- const absPath = path22.join(this.cwd, loaded.path);
6389
- fs23.mkdirSync(path22.dirname(absPath), { recursive: true });
6455
+ const absPath = path23.join(this.cwd, loaded.path);
6456
+ fs24.mkdirSync(path23.dirname(absPath), { recursive: true });
6390
6457
  const body = JSON.stringify(next, null, 2) + "\n";
6391
- fs23.writeFileSync(absPath, body, "utf-8");
6458
+ fs24.writeFileSync(absPath, body, "utf-8");
6392
6459
  return true;
6393
6460
  }
6394
6461
  cacheKeyPrefix() {
@@ -6466,7 +6533,7 @@ var dispatchJobFileTicks = async (ctx, _profile, args) => {
6466
6533
  await backend.hydrate();
6467
6534
  }
6468
6535
  try {
6469
- const slugs = listJobSlugs(path23.join(ctx.cwd, jobsDir));
6536
+ const slugs = listJobSlugs(path24.join(ctx.cwd, jobsDir));
6470
6537
  ctx.data.jobSlugCount = slugs.length;
6471
6538
  if (slugs.length === 0) {
6472
6539
  process.stdout.write(`[jobs] no job files in ${jobsDir}
@@ -6571,17 +6638,17 @@ function formatAgo(ms) {
6571
6638
  }
6572
6639
  function readJobFrontmatter(cwd, jobsDir, slug) {
6573
6640
  try {
6574
- const raw = fs24.readFileSync(path23.join(cwd, jobsDir, `${slug}.md`), "utf-8");
6641
+ const raw = fs25.readFileSync(path24.join(cwd, jobsDir, `${slug}.md`), "utf-8");
6575
6642
  return splitFrontmatter(raw).frontmatter;
6576
6643
  } catch {
6577
6644
  return {};
6578
6645
  }
6579
6646
  }
6580
6647
  function listJobSlugs(absDir) {
6581
- if (!fs24.existsSync(absDir)) return [];
6648
+ if (!fs25.existsSync(absDir)) return [];
6582
6649
  let entries;
6583
6650
  try {
6584
- entries = fs24.readdirSync(absDir, { withFileTypes: true });
6651
+ entries = fs25.readdirSync(absDir, { withFileTypes: true });
6585
6652
  } catch {
6586
6653
  return [];
6587
6654
  }
@@ -7290,7 +7357,7 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch2, cwd, baseBranch
7290
7357
 
7291
7358
  // src/gha.ts
7292
7359
  import { execFileSync as execFileSync16 } from "child_process";
7293
- import * as fs25 from "fs";
7360
+ import * as fs26 from "fs";
7294
7361
  function getRunUrl() {
7295
7362
  const server = process.env.GITHUB_SERVER_URL;
7296
7363
  const repo = process.env.GITHUB_REPOSITORY;
@@ -7301,10 +7368,10 @@ function getRunUrl() {
7301
7368
  function reactToTriggerComment(cwd) {
7302
7369
  if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
7303
7370
  const eventPath = process.env.GITHUB_EVENT_PATH;
7304
- if (!eventPath || !fs25.existsSync(eventPath)) return;
7371
+ if (!eventPath || !fs26.existsSync(eventPath)) return;
7305
7372
  let event = null;
7306
7373
  try {
7307
- event = JSON.parse(fs25.readFileSync(eventPath, "utf-8"));
7374
+ event = JSON.parse(fs26.readFileSync(eventPath, "utf-8"));
7308
7375
  } catch {
7309
7376
  return;
7310
7377
  }
@@ -7597,22 +7664,22 @@ var handleAbandonedGoal = async (ctx) => {
7597
7664
 
7598
7665
  // src/scripts/initFlow.ts
7599
7666
  import { execFileSync as execFileSync18 } from "child_process";
7600
- import * as fs27 from "fs";
7601
- import * as path25 from "path";
7667
+ import * as fs28 from "fs";
7668
+ import * as path26 from "path";
7602
7669
 
7603
7670
  // src/scripts/loadQaGuide.ts
7604
- import * as fs26 from "fs";
7605
- import * as path24 from "path";
7671
+ import * as fs27 from "fs";
7672
+ import * as path25 from "path";
7606
7673
  var QA_GUIDE_REL_PATH = ".kody/qa-guide.md";
7607
7674
  var loadQaGuide = async (ctx) => {
7608
- const full = path24.join(ctx.cwd, QA_GUIDE_REL_PATH);
7609
- if (!fs26.existsSync(full)) {
7675
+ const full = path25.join(ctx.cwd, QA_GUIDE_REL_PATH);
7676
+ if (!fs27.existsSync(full)) {
7610
7677
  ctx.data.qaGuide = "";
7611
7678
  ctx.data.qaGuidePath = "";
7612
7679
  return;
7613
7680
  }
7614
7681
  try {
7615
- ctx.data.qaGuide = fs26.readFileSync(full, "utf-8");
7682
+ ctx.data.qaGuide = fs27.readFileSync(full, "utf-8");
7616
7683
  ctx.data.qaGuidePath = QA_GUIDE_REL_PATH;
7617
7684
  } catch {
7618
7685
  ctx.data.qaGuide = "";
@@ -7622,9 +7689,9 @@ var loadQaGuide = async (ctx) => {
7622
7689
 
7623
7690
  // src/scripts/initFlow.ts
7624
7691
  function detectPackageManager(cwd) {
7625
- if (fs27.existsSync(path25.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
7626
- if (fs27.existsSync(path25.join(cwd, "yarn.lock"))) return "yarn";
7627
- if (fs27.existsSync(path25.join(cwd, "bun.lockb"))) return "bun";
7692
+ if (fs28.existsSync(path26.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
7693
+ if (fs28.existsSync(path26.join(cwd, "yarn.lock"))) return "yarn";
7694
+ if (fs28.existsSync(path26.join(cwd, "bun.lockb"))) return "bun";
7628
7695
  return "npm";
7629
7696
  }
7630
7697
  function qualityCommandsFor(pm) {
@@ -7746,48 +7813,48 @@ function performInit(cwd, force) {
7746
7813
  const pm = detectPackageManager(cwd);
7747
7814
  const ownerRepo = detectOwnerRepo(cwd);
7748
7815
  const defaultBranch2 = defaultBranchFromGit(cwd);
7749
- const configPath = path25.join(cwd, "kody.config.json");
7750
- if (fs27.existsSync(configPath) && !force) {
7816
+ const configPath = path26.join(cwd, "kody.config.json");
7817
+ if (fs28.existsSync(configPath) && !force) {
7751
7818
  skipped.push("kody.config.json");
7752
7819
  } else {
7753
7820
  const cfg = makeConfig(pm, ownerRepo, defaultBranch2);
7754
- fs27.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
7821
+ fs28.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
7755
7822
  `);
7756
7823
  wrote.push("kody.config.json");
7757
7824
  }
7758
- const workflowDir = path25.join(cwd, ".github", "workflows");
7759
- const workflowPath = path25.join(workflowDir, "kody.yml");
7760
- if (fs27.existsSync(workflowPath) && !force) {
7825
+ const workflowDir = path26.join(cwd, ".github", "workflows");
7826
+ const workflowPath = path26.join(workflowDir, "kody.yml");
7827
+ if (fs28.existsSync(workflowPath) && !force) {
7761
7828
  skipped.push(".github/workflows/kody.yml");
7762
7829
  } else {
7763
- fs27.mkdirSync(workflowDir, { recursive: true });
7764
- fs27.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
7830
+ fs28.mkdirSync(workflowDir, { recursive: true });
7831
+ fs28.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
7765
7832
  wrote.push(".github/workflows/kody.yml");
7766
7833
  }
7767
- const hasUi = fs27.existsSync(path25.join(cwd, "src/app")) || fs27.existsSync(path25.join(cwd, "app")) || fs27.existsSync(path25.join(cwd, "pages"));
7834
+ const hasUi = fs28.existsSync(path26.join(cwd, "src/app")) || fs28.existsSync(path26.join(cwd, "app")) || fs28.existsSync(path26.join(cwd, "pages"));
7768
7835
  if (hasUi) {
7769
- const qaGuidePath = path25.join(cwd, QA_GUIDE_REL_PATH);
7770
- if (fs27.existsSync(qaGuidePath) && !force) {
7836
+ const qaGuidePath = path26.join(cwd, QA_GUIDE_REL_PATH);
7837
+ if (fs28.existsSync(qaGuidePath) && !force) {
7771
7838
  skipped.push(QA_GUIDE_REL_PATH);
7772
7839
  } else {
7773
- fs27.mkdirSync(path25.dirname(qaGuidePath), { recursive: true });
7840
+ fs28.mkdirSync(path26.dirname(qaGuidePath), { recursive: true });
7774
7841
  const discovery = runQaDiscovery(cwd);
7775
- fs27.writeFileSync(qaGuidePath, generateQaGuideTemplate(discovery));
7842
+ fs28.writeFileSync(qaGuidePath, generateQaGuideTemplate(discovery));
7776
7843
  wrote.push(QA_GUIDE_REL_PATH);
7777
7844
  }
7778
7845
  }
7779
7846
  const builtinJobs = listBuiltinJobs();
7780
7847
  if (builtinJobs.length > 0) {
7781
- const jobsDir = path25.join(cwd, ".kody", "jobs");
7782
- fs27.mkdirSync(jobsDir, { recursive: true });
7848
+ const jobsDir = path26.join(cwd, ".kody", "jobs");
7849
+ fs28.mkdirSync(jobsDir, { recursive: true });
7783
7850
  for (const job of builtinJobs) {
7784
- const rel = path25.join(".kody", "jobs", `${job.slug}.md`);
7785
- const target = path25.join(cwd, rel);
7786
- if (fs27.existsSync(target) && !force) {
7851
+ const rel = path26.join(".kody", "jobs", `${job.slug}.md`);
7852
+ const target = path26.join(cwd, rel);
7853
+ if (fs28.existsSync(target) && !force) {
7787
7854
  skipped.push(rel);
7788
7855
  continue;
7789
7856
  }
7790
- fs27.writeFileSync(target, fs27.readFileSync(job.filePath, "utf-8"));
7857
+ fs28.writeFileSync(target, fs28.readFileSync(job.filePath, "utf-8"));
7791
7858
  wrote.push(rel);
7792
7859
  }
7793
7860
  }
@@ -7799,12 +7866,12 @@ function performInit(cwd, force) {
7799
7866
  continue;
7800
7867
  }
7801
7868
  if (profile.kind !== "scheduled" || !profile.schedule) continue;
7802
- const target = path25.join(workflowDir, `kody-${exe.name}.yml`);
7803
- if (fs27.existsSync(target) && !force) {
7869
+ const target = path26.join(workflowDir, `kody-${exe.name}.yml`);
7870
+ if (fs28.existsSync(target) && !force) {
7804
7871
  skipped.push(`.github/workflows/kody-${exe.name}.yml`);
7805
7872
  continue;
7806
7873
  }
7807
- fs27.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
7874
+ fs28.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
7808
7875
  wrote.push(`.github/workflows/kody-${exe.name}.yml`);
7809
7876
  }
7810
7877
  let labels;
@@ -7882,14 +7949,14 @@ init_loadConventions();
7882
7949
  init_loadCoverageRules();
7883
7950
 
7884
7951
  // src/goal/state.ts
7885
- import * as fs28 from "fs";
7886
- import * as path26 from "path";
7952
+ import * as fs29 from "fs";
7953
+ import * as path27 from "path";
7887
7954
  var VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "awaiting-merge", "done"]);
7888
7955
  var GoalStateError = class extends Error {
7889
- constructor(path34, message) {
7890
- super(`Invalid goal state at ${path34}:
7956
+ constructor(path35, message) {
7957
+ super(`Invalid goal state at ${path35}:
7891
7958
  ${message}`);
7892
- this.path = path34;
7959
+ this.path = path35;
7893
7960
  this.name = "GoalStateError";
7894
7961
  }
7895
7962
  path;
@@ -7937,16 +8004,16 @@ function serializeGoalState(s) {
7937
8004
  `;
7938
8005
  }
7939
8006
  function goalStatePath(cwd, goalId) {
7940
- return path26.join(cwd, ".kody", "goals", goalId, "state.json");
8007
+ return path27.join(cwd, ".kody", "goals", goalId, "state.json");
7941
8008
  }
7942
8009
  function readGoalState(cwd, goalId) {
7943
8010
  const file = goalStatePath(cwd, goalId);
7944
- if (!fs28.existsSync(file)) {
8011
+ if (!fs29.existsSync(file)) {
7945
8012
  throw new GoalStateError(file, "file not found");
7946
8013
  }
7947
8014
  let raw;
7948
8015
  try {
7949
- raw = JSON.parse(fs28.readFileSync(file, "utf-8"));
8016
+ raw = JSON.parse(fs29.readFileSync(file, "utf-8"));
7950
8017
  } catch (err) {
7951
8018
  throw new GoalStateError(file, `invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
7952
8019
  }
@@ -7954,8 +8021,8 @@ function readGoalState(cwd, goalId) {
7954
8021
  }
7955
8022
  function writeGoalState(cwd, goalId, state) {
7956
8023
  const file = goalStatePath(cwd, goalId);
7957
- fs28.mkdirSync(path26.dirname(file), { recursive: true });
7958
- fs28.writeFileSync(file, serializeGoalState(state), "utf-8");
8024
+ fs29.mkdirSync(path27.dirname(file), { recursive: true });
8025
+ fs29.writeFileSync(file, serializeGoalState(state), "utf-8");
7959
8026
  }
7960
8027
  function nowIso() {
7961
8028
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
@@ -8052,8 +8119,8 @@ var loadIssueStateComment = async (ctx, _profile, args) => {
8052
8119
  };
8053
8120
 
8054
8121
  // src/scripts/loadJobFromFile.ts
8055
- import * as fs29 from "fs";
8056
- import * as path27 from "path";
8122
+ import * as fs30 from "fs";
8123
+ import * as path28 from "path";
8057
8124
  var loadJobFromFile = async (ctx, _profile, args) => {
8058
8125
  const jobsDir = String(args?.jobsDir ?? ".kody/jobs");
8059
8126
  const slugArg = String(args?.slugArg ?? "job");
@@ -8061,11 +8128,11 @@ var loadJobFromFile = async (ctx, _profile, args) => {
8061
8128
  if (!slug) {
8062
8129
  throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
8063
8130
  }
8064
- const absPath = path27.join(ctx.cwd, jobsDir, `${slug}.md`);
8065
- if (!fs29.existsSync(absPath)) {
8131
+ const absPath = path28.join(ctx.cwd, jobsDir, `${slug}.md`);
8132
+ if (!fs30.existsSync(absPath)) {
8066
8133
  throw new Error(`loadJobFromFile: job file not found: ${absPath}`);
8067
8134
  }
8068
- const raw = fs29.readFileSync(absPath, "utf-8");
8135
+ const raw = fs30.readFileSync(absPath, "utf-8");
8069
8136
  const { title, body } = parseJobFile(raw, slug);
8070
8137
  const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
8071
8138
  const loaded = await backend.load(slug);
@@ -8104,8 +8171,8 @@ init_loadPriorArt();
8104
8171
  init_events();
8105
8172
 
8106
8173
  // src/taskContext.ts
8107
- import * as fs31 from "fs";
8108
- import * as path29 from "path";
8174
+ import * as fs32 from "fs";
8175
+ import * as path30 from "path";
8109
8176
  var TASK_CONTEXT_SCHEMA_VERSION = 1;
8110
8177
  function buildTaskContext(args) {
8111
8178
  return {
@@ -8121,10 +8188,10 @@ function buildTaskContext(args) {
8121
8188
  }
8122
8189
  function persistTaskContext(cwd, ctx) {
8123
8190
  try {
8124
- const dir = path29.join(cwd, ".kody", "runs", ctx.runId);
8125
- fs31.mkdirSync(dir, { recursive: true });
8126
- const file = path29.join(dir, "task-context.json");
8127
- fs31.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
8191
+ const dir = path30.join(cwd, ".kody", "runs", ctx.runId);
8192
+ fs32.mkdirSync(dir, { recursive: true });
8193
+ const file = path30.join(dir, "task-context.json");
8194
+ fs32.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
8128
8195
  `);
8129
8196
  return file;
8130
8197
  } catch (err) {
@@ -9487,8 +9554,8 @@ function resolveBaseOverride(value) {
9487
9554
 
9488
9555
  // src/scripts/runTickScript.ts
9489
9556
  import { spawnSync } from "child_process";
9490
- import * as fs32 from "fs";
9491
- import * as path30 from "path";
9557
+ import * as fs33 from "fs";
9558
+ import * as path31 from "path";
9492
9559
  var runTickScript = async (ctx, _profile, args) => {
9493
9560
  ctx.skipAgent = true;
9494
9561
  const jobsDir = String(args?.jobsDir ?? ".kody/jobs");
@@ -9500,13 +9567,13 @@ var runTickScript = async (ctx, _profile, args) => {
9500
9567
  ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
9501
9568
  return;
9502
9569
  }
9503
- const jobPath = path30.join(ctx.cwd, jobsDir, `${slug}.md`);
9504
- if (!fs32.existsSync(jobPath)) {
9570
+ const jobPath = path31.join(ctx.cwd, jobsDir, `${slug}.md`);
9571
+ if (!fs33.existsSync(jobPath)) {
9505
9572
  ctx.output.exitCode = 99;
9506
9573
  ctx.output.reason = `runTickScript: job file not found: ${jobPath}`;
9507
9574
  return;
9508
9575
  }
9509
- const raw = fs32.readFileSync(jobPath, "utf-8");
9576
+ const raw = fs33.readFileSync(jobPath, "utf-8");
9510
9577
  const { frontmatter } = splitFrontmatter(raw);
9511
9578
  const tickScript = frontmatter.tickScript;
9512
9579
  if (!tickScript) {
@@ -9514,8 +9581,8 @@ var runTickScript = async (ctx, _profile, args) => {
9514
9581
  ctx.output.reason = `runTickScript: job ${slug} has no \`tickScript:\` frontmatter \u2014 route via job-tick instead`;
9515
9582
  return;
9516
9583
  }
9517
- const scriptPath = path30.isAbsolute(tickScript) ? tickScript : path30.join(ctx.cwd, tickScript);
9518
- if (!fs32.existsSync(scriptPath)) {
9584
+ const scriptPath = path31.isAbsolute(tickScript) ? tickScript : path31.join(ctx.cwd, tickScript);
9585
+ if (!fs33.existsSync(scriptPath)) {
9519
9586
  ctx.output.exitCode = 99;
9520
9587
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
9521
9588
  return;
@@ -10537,7 +10604,7 @@ var writeJobStateFile = async (ctx, _profile, _agentResult, args) => {
10537
10604
  };
10538
10605
 
10539
10606
  // src/scripts/writeRunSummary.ts
10540
- import * as fs33 from "fs";
10607
+ import * as fs34 from "fs";
10541
10608
  var writeRunSummary = async (ctx, profile) => {
10542
10609
  const summaryPath = process.env.GITHUB_STEP_SUMMARY;
10543
10610
  if (!summaryPath) return;
@@ -10559,7 +10626,7 @@ var writeRunSummary = async (ctx, profile) => {
10559
10626
  if (reason) lines.push(`- **Reason:** ${reason}`);
10560
10627
  lines.push("");
10561
10628
  try {
10562
- fs33.appendFileSync(summaryPath, `${lines.join("\n")}
10629
+ fs34.appendFileSync(summaryPath, `${lines.join("\n")}
10563
10630
  `);
10564
10631
  } catch {
10565
10632
  }
@@ -10783,9 +10850,9 @@ async function runExecutable(profileName, input) {
10783
10850
  data: { ...input.preloadedData ?? {} },
10784
10851
  output: { exitCode: 0 }
10785
10852
  };
10786
- const ndjsonDir = path31.join(input.cwd, ".kody");
10853
+ const ndjsonDir = path32.join(input.cwd, ".kody");
10787
10854
  const invokeAgent = async (prompt) => {
10788
- const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path31.isAbsolute(p) ? p : path31.resolve(profile.dir, p)).filter((p) => p.length > 0);
10855
+ const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path32.isAbsolute(p) ? p : path32.resolve(profile.dir, p)).filter((p) => p.length > 0);
10789
10856
  const syntheticPath = ctx.data.syntheticPluginPath;
10790
10857
  const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
10791
10858
  return runAgent({
@@ -10980,7 +11047,7 @@ function clearStampedLifecycleLabels(profile, ctx) {
10980
11047
  function getProfileInputsForChild(profileName, _cwd) {
10981
11048
  try {
10982
11049
  const profilePath = resolveProfilePath(profileName);
10983
- if (!fs34.existsSync(profilePath)) return null;
11050
+ if (!fs35.existsSync(profilePath)) return null;
10984
11051
  return loadProfile(profilePath).inputs;
10985
11052
  } catch {
10986
11053
  return null;
@@ -10989,17 +11056,17 @@ function getProfileInputsForChild(profileName, _cwd) {
10989
11056
  function resolveProfilePath(profileName) {
10990
11057
  const found = resolveExecutable(profileName);
10991
11058
  if (found) return found;
10992
- const here = path31.dirname(new URL(import.meta.url).pathname);
11059
+ const here = path32.dirname(new URL(import.meta.url).pathname);
10993
11060
  const candidates = [
10994
- path31.join(here, "executables", profileName, "profile.json"),
11061
+ path32.join(here, "executables", profileName, "profile.json"),
10995
11062
  // same-dir sibling (dev)
10996
- path31.join(here, "..", "executables", profileName, "profile.json"),
11063
+ path32.join(here, "..", "executables", profileName, "profile.json"),
10997
11064
  // up one (prod: dist/bin → dist/executables)
10998
- path31.join(here, "..", "src", "executables", profileName, "profile.json")
11065
+ path32.join(here, "..", "src", "executables", profileName, "profile.json")
10999
11066
  // fallback
11000
11067
  ];
11001
11068
  for (const c of candidates) {
11002
- if (fs34.existsSync(c)) return c;
11069
+ if (fs35.existsSync(c)) return c;
11003
11070
  }
11004
11071
  return candidates[0];
11005
11072
  }
@@ -11099,8 +11166,8 @@ function resolveShellTimeoutMs(entry) {
11099
11166
  var SIGKILL_GRACE_MS = 5e3;
11100
11167
  async function runShellEntry(entry, ctx, profile) {
11101
11168
  const shellName = entry.shell;
11102
- const shellPath = path31.join(profile.dir, shellName);
11103
- if (!fs34.existsSync(shellPath)) {
11169
+ const shellPath = path32.join(profile.dir, shellName);
11170
+ if (!fs35.existsSync(shellPath)) {
11104
11171
  ctx.skipAgent = true;
11105
11172
  ctx.output.exitCode = 99;
11106
11173
  ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
@@ -11440,8 +11507,8 @@ function resetWorkingTree2(cwd) {
11440
11507
  }
11441
11508
  function readContainerState(ctx, child, reader) {
11442
11509
  const issueNumber = ctx.args.issue;
11443
- const cached = ctx.data.taskState;
11444
- const prUrl = cached?.core?.prUrl;
11510
+ const cached2 = ctx.data.taskState;
11511
+ const prUrl = cached2?.core?.prUrl;
11445
11512
  const prNumber = prUrl ? parsePrNumber4(prUrl) : null;
11446
11513
  if (child.target === "pr" && prNumber) {
11447
11514
  try {
@@ -11455,8 +11522,8 @@ function readContainerState(ctx, child, reader) {
11455
11522
  } catch {
11456
11523
  }
11457
11524
  }
11458
- if (cached && typeof cached === "object") {
11459
- return cached;
11525
+ if (cached2 && typeof cached2 === "object") {
11526
+ return cached2;
11460
11527
  }
11461
11528
  return {
11462
11529
  schemaVersion: 1,
@@ -11579,9 +11646,9 @@ function resolveAuthToken(env = process.env) {
11579
11646
  return token;
11580
11647
  }
11581
11648
  function detectPackageManager2(cwd) {
11582
- if (fs35.existsSync(path32.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
11583
- if (fs35.existsSync(path32.join(cwd, "yarn.lock"))) return "yarn";
11584
- if (fs35.existsSync(path32.join(cwd, "bun.lockb"))) return "bun";
11649
+ if (fs36.existsSync(path33.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
11650
+ if (fs36.existsSync(path33.join(cwd, "yarn.lock"))) return "yarn";
11651
+ if (fs36.existsSync(path33.join(cwd, "bun.lockb"))) return "bun";
11585
11652
  return "npm";
11586
11653
  }
11587
11654
  function shellOut(cmd, args, cwd, stream = true) {
@@ -11668,11 +11735,11 @@ function configureGitIdentity(cwd) {
11668
11735
  }
11669
11736
  function postFailureTail(issueNumber, cwd, reason) {
11670
11737
  if (!issueNumber) return;
11671
- const logPath = path32.join(cwd, ".kody", "last-run.jsonl");
11738
+ const logPath = path33.join(cwd, ".kody", "last-run.jsonl");
11672
11739
  let tail = "";
11673
11740
  try {
11674
- if (fs35.existsSync(logPath)) {
11675
- const content = fs35.readFileSync(logPath, "utf-8");
11741
+ if (fs36.existsSync(logPath)) {
11742
+ const content = fs36.readFileSync(logPath, "utf-8");
11676
11743
  tail = content.slice(-3e3);
11677
11744
  }
11678
11745
  } catch {
@@ -11697,7 +11764,7 @@ async function runCi(argv) {
11697
11764
  return 0;
11698
11765
  }
11699
11766
  const args = parseCiArgs(argv);
11700
- const cwd = args.cwd ? path32.resolve(args.cwd) : process.cwd();
11767
+ const cwd = args.cwd ? path33.resolve(args.cwd) : process.cwd();
11701
11768
  let earlyConfig;
11702
11769
  try {
11703
11770
  earlyConfig = loadConfig(cwd);
@@ -11707,9 +11774,9 @@ async function runCi(argv) {
11707
11774
  const eventName = process.env.GITHUB_EVENT_NAME;
11708
11775
  const dispatchEventPath = process.env.GITHUB_EVENT_PATH;
11709
11776
  let manualWorkflowDispatch = false;
11710
- if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs35.existsSync(dispatchEventPath)) {
11777
+ if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs36.existsSync(dispatchEventPath)) {
11711
11778
  try {
11712
- const evt = JSON.parse(fs35.readFileSync(dispatchEventPath, "utf-8"));
11779
+ const evt = JSON.parse(fs36.readFileSync(dispatchEventPath, "utf-8"));
11713
11780
  const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
11714
11781
  const sessionInput = String(evt?.inputs?.sessionId ?? "");
11715
11782
  manualWorkflowDispatch = !sessionInput && !(Number.isFinite(issueInput) && issueInput > 0);
@@ -11968,9 +12035,9 @@ function parseChatArgs(argv, env = process.env) {
11968
12035
  return result;
11969
12036
  }
11970
12037
  function commitChatFiles(cwd, sessionId, verbose) {
11971
- const sessionFile = path33.relative(cwd, sessionFilePath(cwd, sessionId));
11972
- const eventsFile = path33.relative(cwd, eventsFilePath(cwd, sessionId));
11973
- const paths = [sessionFile, eventsFile].filter((p) => fs36.existsSync(path33.join(cwd, p)));
12038
+ const sessionFile = path34.relative(cwd, sessionFilePath(cwd, sessionId));
12039
+ const eventsFile = path34.relative(cwd, eventsFilePath(cwd, sessionId));
12040
+ const paths = [sessionFile, eventsFile].filter((p) => fs37.existsSync(path34.join(cwd, p)));
11974
12041
  if (paths.length === 0) return;
11975
12042
  const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
11976
12043
  try {
@@ -12008,7 +12075,7 @@ async function runChat(argv) {
12008
12075
  ${CHAT_HELP}`);
12009
12076
  return 64;
12010
12077
  }
12011
- const cwd = args.cwd ? path33.resolve(args.cwd) : process.cwd();
12078
+ const cwd = args.cwd ? path34.resolve(args.cwd) : process.cwd();
12012
12079
  const sessionId = args.sessionId;
12013
12080
  const unpackedSecrets = unpackAllSecrets();
12014
12081
  if (unpackedSecrets > 0) {
@@ -12060,7 +12127,7 @@ ${CHAT_HELP}`);
12060
12127
  const sink = buildSink(cwd, sessionId, args.dashboardUrl);
12061
12128
  const meta = readMeta(sessionFile);
12062
12129
  process.stdout.write(
12063
- `\u2192 kody:chat: session file=${sessionFile} exists=${fs36.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
12130
+ `\u2192 kody:chat: session file=${sessionFile} exists=${fs37.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
12064
12131
  `
12065
12132
  );
12066
12133
  try {