@kody-ade/kody-engine 0.4.75 → 0.4.77

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/kody.js CHANGED
@@ -460,16 +460,16 @@ var init_issue = __esm({
460
460
  });
461
461
 
462
462
  // src/prompt.ts
463
- import * as fs13 from "fs";
463
+ import * as fs14 from "fs";
464
464
  import * as path12 from "path";
465
465
  function loadProjectConventions(projectDir) {
466
466
  const out = [];
467
467
  for (const rel of CONVENTION_FILES) {
468
468
  const abs = path12.join(projectDir, rel);
469
- if (!fs13.existsSync(abs)) continue;
469
+ if (!fs14.existsSync(abs)) continue;
470
470
  let content;
471
471
  try {
472
- content = fs13.readFileSync(abs, "utf-8");
472
+ content = fs14.readFileSync(abs, "utf-8");
473
473
  } catch {
474
474
  continue;
475
475
  }
@@ -617,20 +617,20 @@ var loadMemoryContext_exports = {};
617
617
  __export(loadMemoryContext_exports, {
618
618
  loadMemoryContext: () => loadMemoryContext
619
619
  });
620
- import * as fs27 from "fs";
620
+ import * as fs28 from "fs";
621
621
  import * as path26 from "path";
622
622
  function collectPages(memoryAbs) {
623
623
  const out = [];
624
624
  walkMd(memoryAbs, (file) => {
625
625
  let stat;
626
626
  try {
627
- stat = fs27.statSync(file);
627
+ stat = fs28.statSync(file);
628
628
  } catch {
629
629
  return;
630
630
  }
631
631
  let raw;
632
632
  try {
633
- raw = fs27.readFileSync(file, "utf-8");
633
+ raw = fs28.readFileSync(file, "utf-8");
634
634
  } catch {
635
635
  return;
636
636
  }
@@ -706,7 +706,7 @@ function walkMd(root, visit) {
706
706
  const dir = stack.pop();
707
707
  let names;
708
708
  try {
709
- names = fs27.readdirSync(dir);
709
+ names = fs28.readdirSync(dir);
710
710
  } catch {
711
711
  continue;
712
712
  }
@@ -715,7 +715,7 @@ function walkMd(root, visit) {
715
715
  const full = path26.join(dir, name);
716
716
  let stat;
717
717
  try {
718
- stat = fs27.statSync(full);
718
+ stat = fs28.statSync(full);
719
719
  } catch {
720
720
  continue;
721
721
  }
@@ -739,7 +739,7 @@ var init_loadMemoryContext = __esm({
739
739
  loadMemoryContext = async (ctx) => {
740
740
  if (typeof ctx.data.memoryContext === "string") return;
741
741
  const memoryAbs = path26.join(ctx.cwd, MEMORY_DIR_RELATIVE);
742
- if (!fs27.existsSync(memoryAbs)) {
742
+ if (!fs28.existsSync(memoryAbs)) {
743
743
  ctx.data.memoryContext = "";
744
744
  return;
745
745
  }
@@ -868,12 +868,12 @@ var init_loadPriorArt = __esm({
868
868
  // package.json
869
869
  var package_default = {
870
870
  name: "@kody-ade/kody-engine",
871
- version: "0.4.75",
871
+ version: "0.4.77",
872
872
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
873
873
  license: "MIT",
874
874
  type: "module",
875
875
  bin: {
876
- kody: "dist/bin/kody.js"
876
+ "kody-engine": "dist/bin/kody.js"
877
877
  },
878
878
  files: [
879
879
  "dist",
@@ -881,7 +881,7 @@ var package_default = {
881
881
  "kody.config.schema.json"
882
882
  ],
883
883
  scripts: {
884
- kody: "tsx bin/kody.ts",
884
+ "kody:run": "tsx bin/kody.ts",
885
885
  serve: "tsx bin/kody.ts serve",
886
886
  "serve:vscode": "tsx bin/kody.ts serve vscode",
887
887
  "serve:claude": "tsx bin/kody.ts serve claude",
@@ -923,7 +923,7 @@ var package_default = {
923
923
 
924
924
  // src/chat-cli.ts
925
925
  import { execFileSync as execFileSync31 } from "child_process";
926
- import * as fs34 from "fs";
926
+ import * as fs35 from "fs";
927
927
  import * as path32 from "path";
928
928
 
929
929
  // src/chat/events.ts
@@ -989,6 +989,9 @@ function makeRunId(sessionId, suffix) {
989
989
  return `chat-${sessionId}-${suffix}`;
990
990
  }
991
991
 
992
+ // src/chat/loop.ts
993
+ import * as fs7 from "fs";
994
+
992
995
  // src/agent.ts
993
996
  import * as fs4 from "fs";
994
997
  import * as path4 from "path";
@@ -1512,15 +1515,134 @@ async function runAgent(opts) {
1512
1515
  };
1513
1516
  }
1514
1517
 
1515
- // src/chat/session.ts
1518
+ // src/registry.ts
1516
1519
  import * as fs5 from "fs";
1517
1520
  import * as path5 from "path";
1521
+ function getExecutablesRoot() {
1522
+ const here = path5.dirname(new URL(import.meta.url).pathname);
1523
+ const candidates = [
1524
+ path5.join(here, "executables"),
1525
+ // dev: src/
1526
+ path5.join(here, "..", "executables"),
1527
+ // built: dist/bin → dist/executables
1528
+ path5.join(here, "..", "src", "executables")
1529
+ // fallback
1530
+ ];
1531
+ for (const c of candidates) {
1532
+ if (fs5.existsSync(c) && fs5.statSync(c).isDirectory()) return c;
1533
+ }
1534
+ return candidates[0];
1535
+ }
1536
+ function getProjectExecutablesRoot() {
1537
+ return path5.join(process.cwd(), ".kody", "executables");
1538
+ }
1539
+ function getBuiltinJobsRoot() {
1540
+ const here = path5.dirname(new URL(import.meta.url).pathname);
1541
+ const candidates = [
1542
+ path5.join(here, "jobs"),
1543
+ // dev: src/
1544
+ path5.join(here, "..", "jobs"),
1545
+ // built: dist/bin → dist/jobs
1546
+ path5.join(here, "..", "src", "jobs")
1547
+ // fallback
1548
+ ];
1549
+ for (const c of candidates) {
1550
+ if (fs5.existsSync(c) && fs5.statSync(c).isDirectory()) return c;
1551
+ }
1552
+ return candidates[0];
1553
+ }
1554
+ function listBuiltinJobs(root = getBuiltinJobsRoot()) {
1555
+ if (!fs5.existsSync(root) || !fs5.statSync(root).isDirectory()) return [];
1556
+ const out = [];
1557
+ for (const ent of fs5.readdirSync(root, { withFileTypes: true })) {
1558
+ if (!ent.isFile() || !ent.name.endsWith(".md")) continue;
1559
+ const slug = ent.name.slice(0, -3);
1560
+ out.push({ slug, filePath: path5.join(root, ent.name) });
1561
+ }
1562
+ out.sort((a, b) => a.slug.localeCompare(b.slug));
1563
+ return out;
1564
+ }
1565
+ function getExecutableRoots() {
1566
+ return [getProjectExecutablesRoot(), getExecutablesRoot()];
1567
+ }
1568
+ function listExecutables(roots = getExecutableRoots()) {
1569
+ const rootList = typeof roots === "string" ? [roots] : roots;
1570
+ const seen = /* @__PURE__ */ new Set();
1571
+ const out = [];
1572
+ for (const root of rootList) {
1573
+ if (!fs5.existsSync(root)) continue;
1574
+ const entries = fs5.readdirSync(root, { withFileTypes: true });
1575
+ for (const ent of entries) {
1576
+ if (!ent.isDirectory()) continue;
1577
+ if (seen.has(ent.name)) continue;
1578
+ const profilePath = path5.join(root, ent.name, "profile.json");
1579
+ if (fs5.existsSync(profilePath) && fs5.statSync(profilePath).isFile()) {
1580
+ out.push({ name: ent.name, profilePath });
1581
+ seen.add(ent.name);
1582
+ }
1583
+ }
1584
+ }
1585
+ return out.sort((a, b) => a.name.localeCompare(b.name));
1586
+ }
1587
+ function resolveExecutable(name, roots = getExecutableRoots()) {
1588
+ if (!isSafeName(name)) return null;
1589
+ const rootList = typeof roots === "string" ? [roots] : roots;
1590
+ for (const root of rootList) {
1591
+ const profilePath = path5.join(root, name, "profile.json");
1592
+ if (fs5.existsSync(profilePath) && fs5.statSync(profilePath).isFile()) {
1593
+ return profilePath;
1594
+ }
1595
+ }
1596
+ return null;
1597
+ }
1598
+ function hasExecutable(name, roots = getExecutableRoots()) {
1599
+ return resolveExecutable(name, roots) !== null;
1600
+ }
1601
+ function isSafeName(name) {
1602
+ return /^[a-z][a-z0-9-]*$/.test(name) && !name.includes("..");
1603
+ }
1604
+ function getProfileInputs(name, roots = getExecutableRoots()) {
1605
+ const profilePath = resolveExecutable(name, roots);
1606
+ if (!profilePath) return null;
1607
+ try {
1608
+ const raw = JSON.parse(fs5.readFileSync(profilePath, "utf-8"));
1609
+ if (!raw || typeof raw !== "object" || !Array.isArray(raw.inputs)) return [];
1610
+ return raw.inputs;
1611
+ } catch {
1612
+ return null;
1613
+ }
1614
+ }
1615
+ function parseGenericFlags(argv) {
1616
+ const args = {};
1617
+ const positional = [];
1618
+ for (let i = 0; i < argv.length; i++) {
1619
+ const arg = argv[i];
1620
+ if (!arg.startsWith("--")) {
1621
+ positional.push(arg);
1622
+ continue;
1623
+ }
1624
+ const key = arg.slice(2);
1625
+ const next = argv[i + 1];
1626
+ const value = next !== void 0 && !next.startsWith("--") ? (i++, next) : true;
1627
+ args[key] = value;
1628
+ if (key.includes("-")) {
1629
+ const camel = key.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
1630
+ if (camel !== key && args[camel] === void 0) args[camel] = value;
1631
+ }
1632
+ }
1633
+ if (positional.length > 0) args._ = positional;
1634
+ return args;
1635
+ }
1636
+
1637
+ // src/chat/session.ts
1638
+ import * as fs6 from "fs";
1639
+ import * as path6 from "path";
1518
1640
  function sessionFilePath(cwd, sessionId) {
1519
- return path5.join(cwd, ".kody", "sessions", `${sessionId}.jsonl`);
1641
+ return path6.join(cwd, ".kody", "sessions", `${sessionId}.jsonl`);
1520
1642
  }
1521
1643
  function readMeta(file) {
1522
- if (!fs5.existsSync(file)) return null;
1523
- const raw = fs5.readFileSync(file, "utf-8");
1644
+ if (!fs6.existsSync(file)) return null;
1645
+ const raw = fs6.readFileSync(file, "utf-8");
1524
1646
  const firstLine2 = raw.split("\n", 1)[0]?.trim();
1525
1647
  if (!firstLine2) return null;
1526
1648
  try {
@@ -1533,8 +1655,8 @@ function readMeta(file) {
1533
1655
  }
1534
1656
  }
1535
1657
  function readSession(file) {
1536
- if (!fs5.existsSync(file)) return [];
1537
- const raw = fs5.readFileSync(file, "utf-8").trim();
1658
+ if (!fs6.existsSync(file)) return [];
1659
+ const raw = fs6.readFileSync(file, "utf-8").trim();
1538
1660
  if (!raw) return [];
1539
1661
  const turns = [];
1540
1662
  for (const line of raw.split("\n")) {
@@ -1550,14 +1672,14 @@ function readSession(file) {
1550
1672
  return turns;
1551
1673
  }
1552
1674
  function appendTurn(file, turn) {
1553
- fs5.mkdirSync(path5.dirname(file), { recursive: true });
1675
+ fs6.mkdirSync(path6.dirname(file), { recursive: true });
1554
1676
  const line = JSON.stringify({
1555
1677
  role: turn.role,
1556
1678
  content: turn.content,
1557
1679
  timestamp: turn.timestamp,
1558
1680
  toolCalls: turn.toolCalls ?? []
1559
1681
  });
1560
- fs5.appendFileSync(file, `${line}
1682
+ fs6.appendFileSync(file, `${line}
1561
1683
  `);
1562
1684
  }
1563
1685
  function seedInitialMessage(file, message) {
@@ -1635,6 +1757,38 @@ var CHAT_SYSTEM_PROMPT = [
1635
1757
  "Do not invent file paths, commit SHAs, line numbers, or command output. If you",
1636
1758
  "cite something concrete, you must have just read or run it in this session."
1637
1759
  ].join("\n");
1760
+ function buildExecutableCatalog() {
1761
+ let discovered;
1762
+ try {
1763
+ discovered = listExecutables();
1764
+ } catch {
1765
+ return "";
1766
+ }
1767
+ const entries = [];
1768
+ for (const { name, profilePath } of discovered) {
1769
+ try {
1770
+ const raw = JSON.parse(fs7.readFileSync(profilePath, "utf-8"));
1771
+ const describe = typeof raw.describe === "string" ? raw.describe : "";
1772
+ const firstSentence = describe.split(/(?<=[.!?])\s+/, 1)[0] ?? "";
1773
+ entries.push({ name, describe: firstSentence.trim() });
1774
+ } catch {
1775
+ }
1776
+ }
1777
+ if (entries.length === 0) return "";
1778
+ const lines = [
1779
+ "",
1780
+ "# Available executables",
1781
+ "These run inside the engine, NOT inside this chat. You cannot invoke them",
1782
+ "directly \u2014 to run one, tell the user to post `@kody <name>` (with any flags)",
1783
+ "as a comment on the relevant issue or PR. The dispatcher binds the issue/PR",
1784
+ "number to the executable's inputs automatically.",
1785
+ ""
1786
+ ];
1787
+ for (const e of entries) {
1788
+ lines.push(`- \`${e.name}\` \u2014 ${e.describe || "(no description)"}`);
1789
+ }
1790
+ return lines.join("\n");
1791
+ }
1638
1792
  async function runChatTurn(opts) {
1639
1793
  const turns = readSession(opts.sessionFile);
1640
1794
  if (turns.length === 0) {
@@ -1648,7 +1802,11 @@ async function runChatTurn(opts) {
1648
1802
  await emit(opts.sink, "chat.error", opts.sessionId, "error", { error });
1649
1803
  return { exitCode: 64, error };
1650
1804
  }
1651
- const systemPrompt = opts.systemPrompt ?? CHAT_SYSTEM_PROMPT;
1805
+ const basePrompt = opts.systemPrompt ?? CHAT_SYSTEM_PROMPT;
1806
+ const catalog = buildExecutableCatalog();
1807
+ const systemPrompt = catalog ? `${basePrompt}
1808
+
1809
+ ${catalog}` : basePrompt;
1652
1810
  const prompt = buildPrompt(turns);
1653
1811
  let progressSeq = 0;
1654
1812
  const invoke = opts.invokeAgent ?? ((p) => runAgent({
@@ -1728,9 +1886,9 @@ async function emit(sink, type, sessionId, suffix, payload) {
1728
1886
 
1729
1887
  // src/chat/modes/interactive.ts
1730
1888
  import { execFileSync as execFileSync2 } from "child_process";
1731
- import * as fs6 from "fs";
1889
+ import * as fs8 from "fs";
1732
1890
  import * as os from "os";
1733
- import * as path6 from "path";
1891
+ import * as path7 from "path";
1734
1892
 
1735
1893
  // src/chat/inbox.ts
1736
1894
  import { execFileSync } from "child_process";
@@ -1887,9 +2045,9 @@ function findNextUserTurn(turns, fromIdx) {
1887
2045
  return -1;
1888
2046
  }
1889
2047
  function commitTurn(cwd, sessionId, verbose) {
1890
- const sessionRel = path6.relative(cwd, sessionFilePath(cwd, sessionId));
1891
- const eventsRel = path6.relative(cwd, eventsFilePath(cwd, sessionId));
1892
- const paths = [sessionRel, eventsRel].filter((p) => fs6.existsSync(path6.join(cwd, p)));
2048
+ const sessionRel = path7.relative(cwd, sessionFilePath(cwd, sessionId));
2049
+ const eventsRel = path7.relative(cwd, eventsFilePath(cwd, sessionId));
2050
+ const paths = [sessionRel, eventsRel].filter((p) => fs8.existsSync(path7.join(cwd, p)));
1893
2051
  if (paths.length === 0) return;
1894
2052
  const startBranch = currentBranch2(cwd);
1895
2053
  const eventsBranch = defaultBranch(cwd) ?? "main";
@@ -1899,17 +2057,17 @@ function commitTurn(cwd, sessionId, verbose) {
1899
2057
  }
1900
2058
  const stdio = verbose ? "inherit" : "pipe";
1901
2059
  const exec = (args) => execFileSync2("git", args, { cwd, stdio });
1902
- const worktreeDir = fs6.mkdtempSync(path6.join(os.tmpdir(), "kody-events-"));
2060
+ const worktreeDir = fs8.mkdtempSync(path7.join(os.tmpdir(), "kody-events-"));
1903
2061
  let worktreeAdded = false;
1904
2062
  try {
1905
2063
  exec(["fetch", "--quiet", "origin", eventsBranch]);
1906
2064
  exec(["worktree", "add", "--detach", "--quiet", worktreeDir, `origin/${eventsBranch}`]);
1907
2065
  worktreeAdded = true;
1908
2066
  for (const rel of paths) {
1909
- const src = path6.join(cwd, rel);
1910
- const dst = path6.join(worktreeDir, rel);
1911
- fs6.mkdirSync(path6.dirname(dst), { recursive: true });
1912
- fs6.copyFileSync(src, dst);
2067
+ const src = path7.join(cwd, rel);
2068
+ const dst = path7.join(worktreeDir, rel);
2069
+ fs8.mkdirSync(path7.dirname(dst), { recursive: true });
2070
+ fs8.copyFileSync(src, dst);
1913
2071
  }
1914
2072
  commitPathsAndPush(worktreeDir, paths, sessionId, verbose, `HEAD:${eventsBranch}`);
1915
2073
  } catch (err) {
@@ -1924,7 +2082,7 @@ function commitTurn(cwd, sessionId, verbose) {
1924
2082
  }
1925
2083
  }
1926
2084
  try {
1927
- fs6.rmSync(worktreeDir, { recursive: true, force: true });
2085
+ fs8.rmSync(worktreeDir, { recursive: true, force: true });
1928
2086
  } catch {
1929
2087
  }
1930
2088
  }
@@ -2020,11 +2178,11 @@ async function emit2(sink, type, sessionId, suffix, payload) {
2020
2178
 
2021
2179
  // src/kody-cli.ts
2022
2180
  import { execFileSync as execFileSync30 } from "child_process";
2023
- import * as fs33 from "fs";
2181
+ import * as fs34 from "fs";
2024
2182
  import * as path31 from "path";
2025
2183
 
2026
2184
  // src/dispatch.ts
2027
- import * as fs8 from "fs";
2185
+ import * as fs9 from "fs";
2028
2186
 
2029
2187
  // src/cron-match.ts
2030
2188
  var FIELD_BOUNDS = [
@@ -2088,125 +2246,6 @@ function cronMatchesInWindow(spec, end, windowSec) {
2088
2246
  return false;
2089
2247
  }
2090
2248
 
2091
- // src/registry.ts
2092
- import * as fs7 from "fs";
2093
- import * as path7 from "path";
2094
- function getExecutablesRoot() {
2095
- const here = path7.dirname(new URL(import.meta.url).pathname);
2096
- const candidates = [
2097
- path7.join(here, "executables"),
2098
- // dev: src/
2099
- path7.join(here, "..", "executables"),
2100
- // built: dist/bin → dist/executables
2101
- path7.join(here, "..", "src", "executables")
2102
- // fallback
2103
- ];
2104
- for (const c of candidates) {
2105
- if (fs7.existsSync(c) && fs7.statSync(c).isDirectory()) return c;
2106
- }
2107
- return candidates[0];
2108
- }
2109
- function getProjectExecutablesRoot() {
2110
- return path7.join(process.cwd(), ".kody", "executables");
2111
- }
2112
- function getBuiltinJobsRoot() {
2113
- const here = path7.dirname(new URL(import.meta.url).pathname);
2114
- const candidates = [
2115
- path7.join(here, "jobs"),
2116
- // dev: src/
2117
- path7.join(here, "..", "jobs"),
2118
- // built: dist/bin → dist/jobs
2119
- path7.join(here, "..", "src", "jobs")
2120
- // fallback
2121
- ];
2122
- for (const c of candidates) {
2123
- if (fs7.existsSync(c) && fs7.statSync(c).isDirectory()) return c;
2124
- }
2125
- return candidates[0];
2126
- }
2127
- function listBuiltinJobs(root = getBuiltinJobsRoot()) {
2128
- if (!fs7.existsSync(root) || !fs7.statSync(root).isDirectory()) return [];
2129
- const out = [];
2130
- for (const ent of fs7.readdirSync(root, { withFileTypes: true })) {
2131
- if (!ent.isFile() || !ent.name.endsWith(".md")) continue;
2132
- const slug = ent.name.slice(0, -3);
2133
- out.push({ slug, filePath: path7.join(root, ent.name) });
2134
- }
2135
- out.sort((a, b) => a.slug.localeCompare(b.slug));
2136
- return out;
2137
- }
2138
- function getExecutableRoots() {
2139
- return [getProjectExecutablesRoot(), getExecutablesRoot()];
2140
- }
2141
- function listExecutables(roots = getExecutableRoots()) {
2142
- const rootList = typeof roots === "string" ? [roots] : roots;
2143
- const seen = /* @__PURE__ */ new Set();
2144
- const out = [];
2145
- for (const root of rootList) {
2146
- if (!fs7.existsSync(root)) continue;
2147
- const entries = fs7.readdirSync(root, { withFileTypes: true });
2148
- for (const ent of entries) {
2149
- if (!ent.isDirectory()) continue;
2150
- if (seen.has(ent.name)) continue;
2151
- const profilePath = path7.join(root, ent.name, "profile.json");
2152
- if (fs7.existsSync(profilePath) && fs7.statSync(profilePath).isFile()) {
2153
- out.push({ name: ent.name, profilePath });
2154
- seen.add(ent.name);
2155
- }
2156
- }
2157
- }
2158
- return out.sort((a, b) => a.name.localeCompare(b.name));
2159
- }
2160
- function resolveExecutable(name, roots = getExecutableRoots()) {
2161
- if (!isSafeName(name)) return null;
2162
- const rootList = typeof roots === "string" ? [roots] : roots;
2163
- for (const root of rootList) {
2164
- const profilePath = path7.join(root, name, "profile.json");
2165
- if (fs7.existsSync(profilePath) && fs7.statSync(profilePath).isFile()) {
2166
- return profilePath;
2167
- }
2168
- }
2169
- return null;
2170
- }
2171
- function hasExecutable(name, roots = getExecutableRoots()) {
2172
- return resolveExecutable(name, roots) !== null;
2173
- }
2174
- function isSafeName(name) {
2175
- return /^[a-z][a-z0-9-]*$/.test(name) && !name.includes("..");
2176
- }
2177
- function getProfileInputs(name, roots = getExecutableRoots()) {
2178
- const profilePath = resolveExecutable(name, roots);
2179
- if (!profilePath) return null;
2180
- try {
2181
- const raw = JSON.parse(fs7.readFileSync(profilePath, "utf-8"));
2182
- if (!raw || typeof raw !== "object" || !Array.isArray(raw.inputs)) return [];
2183
- return raw.inputs;
2184
- } catch {
2185
- return null;
2186
- }
2187
- }
2188
- function parseGenericFlags(argv) {
2189
- const args = {};
2190
- const positional = [];
2191
- for (let i = 0; i < argv.length; i++) {
2192
- const arg = argv[i];
2193
- if (!arg.startsWith("--")) {
2194
- positional.push(arg);
2195
- continue;
2196
- }
2197
- const key = arg.slice(2);
2198
- const next = argv[i + 1];
2199
- const value = next !== void 0 && !next.startsWith("--") ? (i++, next) : true;
2200
- args[key] = value;
2201
- if (key.includes("-")) {
2202
- const camel = key.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
2203
- if (camel !== key && args[camel] === void 0) args[camel] = value;
2204
- }
2205
- }
2206
- if (positional.length > 0) args._ = positional;
2207
- return args;
2208
- }
2209
-
2210
2249
  // src/dispatch.ts
2211
2250
  var POLITE_WORDS = /* @__PURE__ */ new Set([
2212
2251
  "please",
@@ -2227,10 +2266,10 @@ function autoDispatch(opts) {
2227
2266
  }
2228
2267
  const eventName = process.env.GITHUB_EVENT_NAME;
2229
2268
  const eventPath = process.env.GITHUB_EVENT_PATH;
2230
- if (!eventName || !eventPath || !fs8.existsSync(eventPath)) return null;
2269
+ if (!eventName || !eventPath || !fs9.existsSync(eventPath)) return null;
2231
2270
  let event = {};
2232
2271
  try {
2233
- event = JSON.parse(fs8.readFileSync(eventPath, "utf-8"));
2272
+ event = JSON.parse(fs9.readFileSync(eventPath, "utf-8"));
2234
2273
  } catch {
2235
2274
  return null;
2236
2275
  }
@@ -2303,7 +2342,7 @@ function autoDispatchTyped(opts) {
2303
2342
  if (legacy) return { kind: "route", ...legacy };
2304
2343
  const eventName = process.env.GITHUB_EVENT_NAME;
2305
2344
  const eventPath = process.env.GITHUB_EVENT_PATH;
2306
- if (!eventName || !eventPath || !fs8.existsSync(eventPath)) {
2345
+ if (!eventName || !eventPath || !fs9.existsSync(eventPath)) {
2307
2346
  return { kind: "silent", reason: "no GHA event context" };
2308
2347
  }
2309
2348
  if (eventName !== "issue_comment") {
@@ -2311,7 +2350,7 @@ function autoDispatchTyped(opts) {
2311
2350
  }
2312
2351
  let event = {};
2313
2352
  try {
2314
- event = JSON.parse(fs8.readFileSync(eventPath, "utf-8"));
2353
+ event = JSON.parse(fs9.readFileSync(eventPath, "utf-8"));
2315
2354
  } catch {
2316
2355
  return { kind: "silent", reason: "GHA event payload unreadable" };
2317
2356
  }
@@ -2345,7 +2384,7 @@ function dispatchScheduledWatches(opts) {
2345
2384
  for (const exe of listExecutables()) {
2346
2385
  let raw;
2347
2386
  try {
2348
- raw = fs8.readFileSync(exe.profilePath, "utf-8");
2387
+ raw = fs9.readFileSync(exe.profilePath, "utf-8");
2349
2388
  } catch {
2350
2389
  continue;
2351
2390
  }
@@ -2462,7 +2501,7 @@ init_issue();
2462
2501
 
2463
2502
  // src/executor.ts
2464
2503
  import { execFileSync as execFileSync29, spawn as spawn6 } from "child_process";
2465
- import * as fs32 from "fs";
2504
+ import * as fs33 from "fs";
2466
2505
  import * as path30 from "path";
2467
2506
  init_events();
2468
2507
 
@@ -2470,7 +2509,7 @@ init_events();
2470
2509
  init_issue();
2471
2510
 
2472
2511
  // src/profile.ts
2473
- import * as fs9 from "fs";
2512
+ import * as fs10 from "fs";
2474
2513
  import * as path8 from "path";
2475
2514
 
2476
2515
  // src/profile-error.ts
@@ -2637,12 +2676,12 @@ var KNOWN_PROFILE_KEYS = /* @__PURE__ */ new Set([
2637
2676
  "preloadContext"
2638
2677
  ]);
2639
2678
  function loadProfile(profilePath) {
2640
- if (!fs9.existsSync(profilePath)) {
2679
+ if (!fs10.existsSync(profilePath)) {
2641
2680
  throw new ProfileError(profilePath, "file not found");
2642
2681
  }
2643
2682
  let raw;
2644
2683
  try {
2645
- raw = JSON.parse(fs9.readFileSync(profilePath, "utf-8"));
2684
+ raw = JSON.parse(fs10.readFileSync(profilePath, "utf-8"));
2646
2685
  } catch (err) {
2647
2686
  throw new ProfileError(profilePath, `invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
2648
2687
  }
@@ -3084,7 +3123,7 @@ function errMsg(err) {
3084
3123
 
3085
3124
  // src/litellm.ts
3086
3125
  import { execFileSync as execFileSync4, spawn as spawn2 } from "child_process";
3087
- import * as fs10 from "fs";
3126
+ import * as fs11 from "fs";
3088
3127
  import * as os2 from "os";
3089
3128
  import * as path9 from "path";
3090
3129
  async function checkLitellmHealth(url) {
@@ -3134,19 +3173,19 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
3134
3173
  }
3135
3174
  }
3136
3175
  const configPath = path9.join(os2.tmpdir(), `kody-litellm-${Date.now()}.yaml`);
3137
- fs10.writeFileSync(configPath, generateLitellmConfigYaml(model));
3176
+ fs11.writeFileSync(configPath, generateLitellmConfigYaml(model));
3138
3177
  const portMatch = url.match(/:(\d+)/);
3139
3178
  const port = portMatch ? portMatch[1] : "4000";
3140
3179
  const args = cmd === "litellm" ? ["--config", configPath, "--port", port] : ["-m", "litellm", "--config", configPath, "--port", port];
3141
3180
  const dotenvVars = readDotenvApiKeys(projectDir);
3142
3181
  const logPath = path9.join(os2.tmpdir(), `kody-litellm-${Date.now()}.log`);
3143
- const outFd = fs10.openSync(logPath, "w");
3182
+ const outFd = fs11.openSync(logPath, "w");
3144
3183
  const child = spawn2(cmd, args, {
3145
3184
  stdio: ["ignore", outFd, outFd],
3146
3185
  detached: true,
3147
3186
  env: stripBlockingEnv({ ...process.env, ...dotenvVars })
3148
3187
  });
3149
- fs10.closeSync(outFd);
3188
+ fs11.closeSync(outFd);
3150
3189
  const timeoutMs = resolveLitellmTimeoutMs();
3151
3190
  const deadline = Date.now() + timeoutMs;
3152
3191
  while (Date.now() < deadline) {
@@ -3165,7 +3204,7 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
3165
3204
  }
3166
3205
  let logTail = "";
3167
3206
  try {
3168
- logTail = fs10.readFileSync(logPath, "utf-8").slice(-2e3);
3207
+ logTail = fs11.readFileSync(logPath, "utf-8").slice(-2e3);
3169
3208
  } catch {
3170
3209
  }
3171
3210
  try {
@@ -3178,9 +3217,9 @@ ${logTail}`);
3178
3217
  }
3179
3218
  function readDotenvApiKeys(projectDir) {
3180
3219
  const dotenvPath = path9.join(projectDir, ".env");
3181
- if (!fs10.existsSync(dotenvPath)) return {};
3220
+ if (!fs11.existsSync(dotenvPath)) return {};
3182
3221
  const result = {};
3183
- for (const rawLine of fs10.readFileSync(dotenvPath, "utf-8").split("\n")) {
3222
+ for (const rawLine of fs11.readFileSync(dotenvPath, "utf-8").split("\n")) {
3184
3223
  const line = rawLine.trim();
3185
3224
  if (!line || line.startsWith("#")) continue;
3186
3225
  const match = line.match(/^([A-Z_][A-Z0-9_]*_API_KEY)=(.*)$/);
@@ -3204,7 +3243,7 @@ function stripBlockingEnv(env) {
3204
3243
 
3205
3244
  // src/commit.ts
3206
3245
  import { execFileSync as execFileSync5 } from "child_process";
3207
- import * as fs11 from "fs";
3246
+ import * as fs12 from "fs";
3208
3247
  import * as path10 from "path";
3209
3248
  var FORBIDDEN_PATH_PREFIXES = [
3210
3249
  ".kody/",
@@ -3262,17 +3301,17 @@ function tryGit(args, cwd) {
3262
3301
  function abortUnfinishedGitOps(cwd) {
3263
3302
  const aborted = [];
3264
3303
  const gitDir = path10.join(cwd ?? process.cwd(), ".git");
3265
- if (!fs11.existsSync(gitDir)) return aborted;
3266
- if (fs11.existsSync(path10.join(gitDir, "MERGE_HEAD"))) {
3304
+ if (!fs12.existsSync(gitDir)) return aborted;
3305
+ if (fs12.existsSync(path10.join(gitDir, "MERGE_HEAD"))) {
3267
3306
  if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
3268
3307
  }
3269
- if (fs11.existsSync(path10.join(gitDir, "CHERRY_PICK_HEAD"))) {
3308
+ if (fs12.existsSync(path10.join(gitDir, "CHERRY_PICK_HEAD"))) {
3270
3309
  if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
3271
3310
  }
3272
- if (fs11.existsSync(path10.join(gitDir, "REVERT_HEAD"))) {
3311
+ if (fs12.existsSync(path10.join(gitDir, "REVERT_HEAD"))) {
3273
3312
  if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
3274
3313
  }
3275
- if (fs11.existsSync(path10.join(gitDir, "rebase-merge")) || fs11.existsSync(path10.join(gitDir, "rebase-apply"))) {
3314
+ if (fs12.existsSync(path10.join(gitDir, "rebase-merge")) || fs12.existsSync(path10.join(gitDir, "rebase-apply"))) {
3276
3315
  if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
3277
3316
  }
3278
3317
  try {
@@ -3328,7 +3367,7 @@ function normalizeCommitMessage(raw) {
3328
3367
  function commitAndPush(branch, agentMessage, cwd) {
3329
3368
  const allChanged = listChangedFiles(cwd);
3330
3369
  const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
3331
- const mergeHeadExists = fs11.existsSync(path10.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
3370
+ const mergeHeadExists = fs12.existsSync(path10.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
3332
3371
  if (allowedFiles.length === 0 && !mergeHeadExists) {
3333
3372
  return { committed: false, pushed: false, sha: "", message: "" };
3334
3373
  }
@@ -3640,7 +3679,7 @@ var advanceFlow = async (ctx, profile) => {
3640
3679
  };
3641
3680
 
3642
3681
  // src/scripts/buildSyntheticPlugin.ts
3643
- import * as fs12 from "fs";
3682
+ import * as fs13 from "fs";
3644
3683
  import * as os3 from "os";
3645
3684
  import * as path11 from "path";
3646
3685
  function getPluginsCatalogRoot() {
@@ -3654,7 +3693,7 @@ function getPluginsCatalogRoot() {
3654
3693
  // fallback
3655
3694
  ];
3656
3695
  for (const c of candidates) {
3657
- if (fs12.existsSync(c) && fs12.statSync(c).isDirectory()) return c;
3696
+ if (fs13.existsSync(c) && fs13.statSync(c).isDirectory()) return c;
3658
3697
  }
3659
3698
  return candidates[0];
3660
3699
  }
@@ -3665,51 +3704,51 @@ var buildSyntheticPlugin = async (ctx, profile) => {
3665
3704
  const catalog = getPluginsCatalogRoot();
3666
3705
  const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
3667
3706
  const root = path11.join(os3.tmpdir(), `kody-synth-${runId}`);
3668
- fs12.mkdirSync(path11.join(root, ".claude-plugin"), { recursive: true });
3707
+ fs13.mkdirSync(path11.join(root, ".claude-plugin"), { recursive: true });
3669
3708
  const resolvePart = (bucket, entry) => {
3670
3709
  const local = path11.join(profile.dir, bucket, entry);
3671
- if (fs12.existsSync(local)) return local;
3710
+ if (fs13.existsSync(local)) return local;
3672
3711
  const central = path11.join(catalog, bucket, entry);
3673
- if (fs12.existsSync(central)) return central;
3712
+ if (fs13.existsSync(central)) return central;
3674
3713
  throw new Error(
3675
3714
  `buildSyntheticPlugin: ${bucket} entry '${entry}' not found in executable dir (${profile.dir}/${bucket}/) or catalog (${catalog}/${bucket}/)`
3676
3715
  );
3677
3716
  };
3678
3717
  if (cc.skills.length > 0) {
3679
3718
  const dst = path11.join(root, "skills");
3680
- fs12.mkdirSync(dst, { recursive: true });
3719
+ fs13.mkdirSync(dst, { recursive: true });
3681
3720
  for (const name of cc.skills) {
3682
3721
  copyDir(resolvePart("skills", name), path11.join(dst, name));
3683
3722
  }
3684
3723
  }
3685
3724
  if (cc.commands.length > 0) {
3686
3725
  const dst = path11.join(root, "commands");
3687
- fs12.mkdirSync(dst, { recursive: true });
3726
+ fs13.mkdirSync(dst, { recursive: true });
3688
3727
  for (const name of cc.commands) {
3689
- fs12.copyFileSync(resolvePart("commands", `${name}.md`), path11.join(dst, `${name}.md`));
3728
+ fs13.copyFileSync(resolvePart("commands", `${name}.md`), path11.join(dst, `${name}.md`));
3690
3729
  }
3691
3730
  }
3692
3731
  if (cc.subagents.length > 0) {
3693
3732
  const dst = path11.join(root, "agents");
3694
- fs12.mkdirSync(dst, { recursive: true });
3733
+ fs13.mkdirSync(dst, { recursive: true });
3695
3734
  for (const name of cc.subagents) {
3696
- fs12.copyFileSync(resolvePart("agents", `${name}.md`), path11.join(dst, `${name}.md`));
3735
+ fs13.copyFileSync(resolvePart("agents", `${name}.md`), path11.join(dst, `${name}.md`));
3697
3736
  }
3698
3737
  }
3699
3738
  if (cc.hooks.length > 0) {
3700
3739
  const dst = path11.join(root, "hooks");
3701
- fs12.mkdirSync(dst, { recursive: true });
3740
+ fs13.mkdirSync(dst, { recursive: true });
3702
3741
  const merged = { hooks: {} };
3703
3742
  for (const name of cc.hooks) {
3704
3743
  const src = resolvePart("hooks", `${name}.json`);
3705
- const parsed = JSON.parse(fs12.readFileSync(src, "utf-8"));
3744
+ const parsed = JSON.parse(fs13.readFileSync(src, "utf-8"));
3706
3745
  for (const [event, entries] of Object.entries(parsed.hooks ?? {})) {
3707
3746
  if (!Array.isArray(entries)) continue;
3708
3747
  if (!merged.hooks[event]) merged.hooks[event] = [];
3709
3748
  merged.hooks[event].push(...entries);
3710
3749
  }
3711
3750
  }
3712
- fs12.writeFileSync(path11.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
3751
+ fs13.writeFileSync(path11.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
3713
3752
  `);
3714
3753
  }
3715
3754
  const manifest = {
@@ -3720,17 +3759,17 @@ var buildSyntheticPlugin = async (ctx, profile) => {
3720
3759
  if (cc.skills.length > 0) manifest.skills = ["./skills/"];
3721
3760
  if (cc.commands.length > 0) manifest.commands = ["./commands/"];
3722
3761
  if (cc.subagents.length > 0) manifest.agents = cc.subagents.map((n) => `./agents/${n}.md`);
3723
- fs12.writeFileSync(path11.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
3762
+ fs13.writeFileSync(path11.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
3724
3763
  `);
3725
3764
  ctx.data.syntheticPluginPath = root;
3726
3765
  };
3727
3766
  function copyDir(src, dst) {
3728
- fs12.mkdirSync(dst, { recursive: true });
3729
- for (const ent of fs12.readdirSync(src, { withFileTypes: true })) {
3767
+ fs13.mkdirSync(dst, { recursive: true });
3768
+ for (const ent of fs13.readdirSync(src, { withFileTypes: true })) {
3730
3769
  const s = path11.join(src, ent.name);
3731
3770
  const d = path11.join(dst, ent.name);
3732
3771
  if (ent.isDirectory()) copyDir(s, d);
3733
- else if (ent.isFile()) fs12.copyFileSync(s, d);
3772
+ else if (ent.isFile()) fs13.copyFileSync(s, d);
3734
3773
  }
3735
3774
  }
3736
3775
 
@@ -3871,7 +3910,7 @@ function defaultLabelMap() {
3871
3910
  }
3872
3911
 
3873
3912
  // src/scripts/commitAndPush.ts
3874
- import * as fs14 from "fs";
3913
+ import * as fs15 from "fs";
3875
3914
  import * as path13 from "path";
3876
3915
  init_events();
3877
3916
  var DEFAULT_COMMIT_MESSAGE = "chore: kody changes";
@@ -3887,9 +3926,9 @@ var commitAndPush2 = async (ctx, profile) => {
3887
3926
  }
3888
3927
  const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
3889
3928
  const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name) : null;
3890
- if (sentinel && fs14.existsSync(sentinel)) {
3929
+ if (sentinel && fs15.existsSync(sentinel)) {
3891
3930
  try {
3892
- const replay = JSON.parse(fs14.readFileSync(sentinel, "utf-8"));
3931
+ const replay = JSON.parse(fs15.readFileSync(sentinel, "utf-8"));
3893
3932
  ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
3894
3933
  if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
3895
3934
  if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
@@ -3942,8 +3981,8 @@ var commitAndPush2 = async (ctx, profile) => {
3942
3981
  const result = ctx.data.commitResult;
3943
3982
  if (sentinel && result?.committed) {
3944
3983
  try {
3945
- fs14.mkdirSync(path13.dirname(sentinel), { recursive: true });
3946
- fs14.writeFileSync(
3984
+ fs15.mkdirSync(path13.dirname(sentinel), { recursive: true });
3985
+ fs15.writeFileSync(
3947
3986
  sentinel,
3948
3987
  JSON.stringify(
3949
3988
  {
@@ -4012,7 +4051,7 @@ function describeCommitMessage(goal) {
4012
4051
  }
4013
4052
 
4014
4053
  // src/scripts/composePrompt.ts
4015
- import * as fs15 from "fs";
4054
+ import * as fs16 from "fs";
4016
4055
  import * as path15 from "path";
4017
4056
  var MUSTACHE = /\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g;
4018
4057
  var composePrompt = async (ctx, profile) => {
@@ -4025,7 +4064,7 @@ var composePrompt = async (ctx, profile) => {
4025
4064
  ].filter(Boolean);
4026
4065
  let templatePath = "";
4027
4066
  for (const c of candidates) {
4028
- if (fs15.existsSync(c)) {
4067
+ if (fs16.existsSync(c)) {
4029
4068
  templatePath = c;
4030
4069
  break;
4031
4070
  }
@@ -4033,7 +4072,7 @@ var composePrompt = async (ctx, profile) => {
4033
4072
  if (!templatePath) {
4034
4073
  throw new Error(`profile at ${profile.dir}: no prompt template found (tried ${candidates.join(", ")})`);
4035
4074
  }
4036
- const template = fs15.readFileSync(templatePath, "utf-8");
4075
+ const template = fs16.readFileSync(templatePath, "utf-8");
4037
4076
  const tokens = {
4038
4077
  ...stringifyAll(ctx.args, "args."),
4039
4078
  ...stringifyAll(ctx.data, ""),
@@ -4112,7 +4151,7 @@ function formatToolsUsage(profile) {
4112
4151
  // src/scripts/createQaGoal.ts
4113
4152
  init_issue();
4114
4153
  import { execFileSync as execFileSync10 } from "child_process";
4115
- import * as fs16 from "fs";
4154
+ import * as fs17 from "fs";
4116
4155
  import * as path16 from "path";
4117
4156
 
4118
4157
  // src/scripts/postReviewResult.ts
@@ -4367,7 +4406,7 @@ function createOrUpdateManifestIssue(number, manifest, cwd) {
4367
4406
  }
4368
4407
  function writeStateFile(cwd, goalId, lastDispatchedIssue) {
4369
4408
  const dir = path16.join(cwd, ".kody", "goals", goalId);
4370
- fs16.mkdirSync(dir, { recursive: true });
4409
+ fs17.mkdirSync(dir, { recursive: true });
4371
4410
  const state = {
4372
4411
  version: 1,
4373
4412
  state: "active",
@@ -4376,7 +4415,7 @@ function writeStateFile(cwd, goalId, lastDispatchedIssue) {
4376
4415
  ...typeof lastDispatchedIssue === "number" ? { lastDispatchedIssue } : {}
4377
4416
  };
4378
4417
  const filePath = path16.join(dir, "state.json");
4379
- fs16.writeFileSync(filePath, `${JSON.stringify(state, null, 2)}
4418
+ fs17.writeFileSync(filePath, `${JSON.stringify(state, null, 2)}
4380
4419
  `);
4381
4420
  return filePath;
4382
4421
  }
@@ -4872,7 +4911,7 @@ function filterGoalTaskPrs(prs, taskIssueNumbers) {
4872
4911
 
4873
4912
  // src/scripts/diagMcp.ts
4874
4913
  import { execFileSync as execFileSync11 } from "child_process";
4875
- import * as fs17 from "fs";
4914
+ import * as fs18 from "fs";
4876
4915
  import * as os4 from "os";
4877
4916
  import * as path17 from "path";
4878
4917
  var diagMcp = async (_ctx) => {
@@ -4880,7 +4919,7 @@ var diagMcp = async (_ctx) => {
4880
4919
  const cacheDir = path17.join(home, ".cache", "ms-playwright");
4881
4920
  let entries = [];
4882
4921
  try {
4883
- entries = fs17.readdirSync(cacheDir);
4922
+ entries = fs18.readdirSync(cacheDir);
4884
4923
  } catch {
4885
4924
  }
4886
4925
  const hasChromium = entries.some((e) => e.startsWith("chromium"));
@@ -4906,17 +4945,17 @@ var diagMcp = async (_ctx) => {
4906
4945
  };
4907
4946
 
4908
4947
  // src/scripts/discoverQaContext.ts
4909
- import * as fs19 from "fs";
4948
+ import * as fs20 from "fs";
4910
4949
  import * as path19 from "path";
4911
4950
 
4912
4951
  // src/scripts/frameworkDetectors.ts
4913
- import * as fs18 from "fs";
4952
+ import * as fs19 from "fs";
4914
4953
  import * as path18 from "path";
4915
4954
  function detectFrameworks(cwd) {
4916
4955
  const out = [];
4917
4956
  let deps = {};
4918
4957
  try {
4919
- const pkg = JSON.parse(fs18.readFileSync(path18.join(cwd, "package.json"), "utf-8"));
4958
+ const pkg = JSON.parse(fs19.readFileSync(path18.join(cwd, "package.json"), "utf-8"));
4920
4959
  deps = { ...pkg.dependencies, ...pkg.devDependencies };
4921
4960
  } catch {
4922
4961
  return out;
@@ -4953,7 +4992,7 @@ function detectFrameworks(cwd) {
4953
4992
  }
4954
4993
  function findFile(cwd, candidates) {
4955
4994
  for (const c of candidates) {
4956
- if (fs18.existsSync(path18.join(cwd, c))) return c;
4995
+ if (fs19.existsSync(path18.join(cwd, c))) return c;
4957
4996
  }
4958
4997
  return null;
4959
4998
  }
@@ -4967,17 +5006,17 @@ function discoverPayloadCollections(cwd) {
4967
5006
  const out = [];
4968
5007
  for (const dir of COLLECTION_DIRS) {
4969
5008
  const full = path18.join(cwd, dir);
4970
- if (!fs18.existsSync(full)) continue;
5009
+ if (!fs19.existsSync(full)) continue;
4971
5010
  let files;
4972
5011
  try {
4973
- files = fs18.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
5012
+ files = fs19.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
4974
5013
  } catch {
4975
5014
  continue;
4976
5015
  }
4977
5016
  for (const file of files) {
4978
5017
  try {
4979
5018
  const filePath = path18.join(full, file);
4980
- const content = fs18.readFileSync(filePath, "utf-8").slice(0, 1e4);
5019
+ const content = fs19.readFileSync(filePath, "utf-8").slice(0, 1e4);
4981
5020
  const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
4982
5021
  if (!slugMatch) continue;
4983
5022
  const slug = slugMatch[1];
@@ -5006,10 +5045,10 @@ function discoverAdminComponents(cwd, collections) {
5006
5045
  const out = [];
5007
5046
  for (const dir of ADMIN_COMPONENT_DIRS) {
5008
5047
  const full = path18.join(cwd, dir);
5009
- if (!fs18.existsSync(full)) continue;
5048
+ if (!fs19.existsSync(full)) continue;
5010
5049
  let entries;
5011
5050
  try {
5012
- entries = fs18.readdirSync(full, { withFileTypes: true });
5051
+ entries = fs19.readdirSync(full, { withFileTypes: true });
5013
5052
  } catch {
5014
5053
  continue;
5015
5054
  }
@@ -5019,7 +5058,7 @@ function discoverAdminComponents(cwd, collections) {
5019
5058
  let filePath;
5020
5059
  if (entry.isDirectory()) {
5021
5060
  const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
5022
- (f) => fs18.existsSync(path18.join(entryPath, f))
5061
+ (f) => fs19.existsSync(path18.join(entryPath, f))
5023
5062
  );
5024
5063
  if (!indexFile) continue;
5025
5064
  name = entry.name;
@@ -5034,7 +5073,7 @@ function discoverAdminComponents(cwd, collections) {
5034
5073
  if (collections) {
5035
5074
  for (const col of collections) {
5036
5075
  try {
5037
- const colContent = fs18.readFileSync(path18.join(cwd, col.filePath), "utf-8");
5076
+ const colContent = fs19.readFileSync(path18.join(cwd, col.filePath), "utf-8");
5038
5077
  if (colContent.includes(name)) {
5039
5078
  usedInCollection = col.slug;
5040
5079
  break;
@@ -5054,7 +5093,7 @@ function scanApiRoutes(cwd) {
5054
5093
  const appDirs = ["src/app", "app"];
5055
5094
  for (const appDir of appDirs) {
5056
5095
  const apiDir = path18.join(cwd, appDir, "api");
5057
- if (!fs18.existsSync(apiDir)) continue;
5096
+ if (!fs19.existsSync(apiDir)) continue;
5058
5097
  walkApiRoutes(apiDir, "/api", cwd, out);
5059
5098
  break;
5060
5099
  }
@@ -5063,14 +5102,14 @@ function scanApiRoutes(cwd) {
5063
5102
  function walkApiRoutes(dir, prefix, cwd, out) {
5064
5103
  let entries;
5065
5104
  try {
5066
- entries = fs18.readdirSync(dir, { withFileTypes: true });
5105
+ entries = fs19.readdirSync(dir, { withFileTypes: true });
5067
5106
  } catch {
5068
5107
  return;
5069
5108
  }
5070
5109
  const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
5071
5110
  if (routeFile) {
5072
5111
  try {
5073
- const content = fs18.readFileSync(path18.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
5112
+ const content = fs19.readFileSync(path18.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
5074
5113
  const methods = HTTP_METHODS.filter(
5075
5114
  (m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
5076
5115
  );
@@ -5118,9 +5157,9 @@ function scanEnvVars(cwd) {
5118
5157
  const candidates = [".env.example", ".env.local.example", ".env.template"];
5119
5158
  for (const envFile of candidates) {
5120
5159
  const envPath = path18.join(cwd, envFile);
5121
- if (!fs18.existsSync(envPath)) continue;
5160
+ if (!fs19.existsSync(envPath)) continue;
5122
5161
  try {
5123
- const content = fs18.readFileSync(envPath, "utf-8");
5162
+ const content = fs19.readFileSync(envPath, "utf-8");
5124
5163
  const vars = [];
5125
5164
  for (const line of content.split("\n")) {
5126
5165
  const trimmed = line.trim();
@@ -5168,9 +5207,9 @@ function runQaDiscovery(cwd) {
5168
5207
  }
5169
5208
  function detectDevServer(cwd, out) {
5170
5209
  try {
5171
- const pkg = JSON.parse(fs19.readFileSync(path19.join(cwd, "package.json"), "utf-8"));
5210
+ const pkg = JSON.parse(fs20.readFileSync(path19.join(cwd, "package.json"), "utf-8"));
5172
5211
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
5173
- const pm = fs19.existsSync(path19.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs19.existsSync(path19.join(cwd, "yarn.lock")) ? "yarn" : fs19.existsSync(path19.join(cwd, "bun.lockb")) ? "bun" : "npm";
5212
+ const pm = fs20.existsSync(path19.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs20.existsSync(path19.join(cwd, "yarn.lock")) ? "yarn" : fs20.existsSync(path19.join(cwd, "bun.lockb")) ? "bun" : "npm";
5174
5213
  if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
5175
5214
  if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
5176
5215
  else if (allDeps.vite) out.devPort = 5173;
@@ -5181,7 +5220,7 @@ function scanFrontendRoutes(cwd, out) {
5181
5220
  const appDirs = ["src/app", "app"];
5182
5221
  for (const appDir of appDirs) {
5183
5222
  const full = path19.join(cwd, appDir);
5184
- if (!fs19.existsSync(full)) continue;
5223
+ if (!fs20.existsSync(full)) continue;
5185
5224
  walkFrontendRoutes(full, "", out);
5186
5225
  break;
5187
5226
  }
@@ -5189,7 +5228,7 @@ function scanFrontendRoutes(cwd, out) {
5189
5228
  function walkFrontendRoutes(dir, prefix, out) {
5190
5229
  let entries;
5191
5230
  try {
5192
- entries = fs19.readdirSync(dir, { withFileTypes: true });
5231
+ entries = fs20.readdirSync(dir, { withFileTypes: true });
5193
5232
  } catch {
5194
5233
  return;
5195
5234
  }
@@ -5231,23 +5270,23 @@ function detectAuthFiles(cwd, out) {
5231
5270
  "src/app/api/oauth"
5232
5271
  ];
5233
5272
  for (const c of candidates) {
5234
- if (fs19.existsSync(path19.join(cwd, c))) out.authFiles.push(c);
5273
+ if (fs20.existsSync(path19.join(cwd, c))) out.authFiles.push(c);
5235
5274
  }
5236
5275
  }
5237
5276
  function detectRoles(cwd, out) {
5238
5277
  const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
5239
5278
  for (const rp of rolePaths) {
5240
5279
  const dir = path19.join(cwd, rp);
5241
- if (!fs19.existsSync(dir)) continue;
5280
+ if (!fs20.existsSync(dir)) continue;
5242
5281
  let files;
5243
5282
  try {
5244
- files = fs19.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
5283
+ files = fs20.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
5245
5284
  } catch {
5246
5285
  continue;
5247
5286
  }
5248
5287
  for (const f of files) {
5249
5288
  try {
5250
- const content = fs19.readFileSync(path19.join(dir, f), "utf-8").slice(0, 5e3);
5289
+ const content = fs20.readFileSync(path19.join(dir, f), "utf-8").slice(0, 5e3);
5251
5290
  const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
5252
5291
  if (roleMatches) {
5253
5292
  for (const m of roleMatches) {
@@ -5480,7 +5519,7 @@ function failedAction3(reason) {
5480
5519
  }
5481
5520
 
5482
5521
  // src/scripts/dispatchJobFileTicks.ts
5483
- import * as fs21 from "fs";
5522
+ import * as fs22 from "fs";
5484
5523
  import * as path21 from "path";
5485
5524
 
5486
5525
  // src/scripts/jobFrontmatter.ts
@@ -5736,7 +5775,7 @@ var ContentsApiBackend = class {
5736
5775
  };
5737
5776
 
5738
5777
  // src/scripts/jobState/localFileBackend.ts
5739
- import * as fs20 from "fs";
5778
+ import * as fs21 from "fs";
5740
5779
  import * as path20 from "path";
5741
5780
  var LocalFileBackend = class {
5742
5781
  name = "local-file";
@@ -5767,7 +5806,7 @@ var LocalFileBackend = class {
5767
5806
  `);
5768
5807
  return;
5769
5808
  }
5770
- fs20.mkdirSync(this.absDir, { recursive: true });
5809
+ fs21.mkdirSync(this.absDir, { recursive: true });
5771
5810
  const prefix = this.cacheKeyPrefix();
5772
5811
  const probeKey = `${prefix}probe-${Date.now()}`;
5773
5812
  try {
@@ -5796,7 +5835,7 @@ var LocalFileBackend = class {
5796
5835
  `);
5797
5836
  return;
5798
5837
  }
5799
- if (!fs20.existsSync(this.absDir)) {
5838
+ if (!fs21.existsSync(this.absDir)) {
5800
5839
  return;
5801
5840
  }
5802
5841
  const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
@@ -5813,10 +5852,10 @@ var LocalFileBackend = class {
5813
5852
  load(slug) {
5814
5853
  const relPath = stateFilePath(this.jobsDir, slug);
5815
5854
  const absPath = path20.join(this.cwd, relPath);
5816
- if (!fs20.existsSync(absPath)) {
5855
+ if (!fs21.existsSync(absPath)) {
5817
5856
  return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
5818
5857
  }
5819
- const raw = fs20.readFileSync(absPath, "utf-8");
5858
+ const raw = fs21.readFileSync(absPath, "utf-8");
5820
5859
  let parsed;
5821
5860
  try {
5822
5861
  parsed = JSON.parse(raw);
@@ -5834,9 +5873,9 @@ var LocalFileBackend = class {
5834
5873
  return false;
5835
5874
  }
5836
5875
  const absPath = path20.join(this.cwd, loaded.path);
5837
- fs20.mkdirSync(path20.dirname(absPath), { recursive: true });
5876
+ fs21.mkdirSync(path20.dirname(absPath), { recursive: true });
5838
5877
  const body = JSON.stringify(next, null, 2) + "\n";
5839
- fs20.writeFileSync(absPath, body, "utf-8");
5878
+ fs21.writeFileSync(absPath, body, "utf-8");
5840
5879
  return true;
5841
5880
  }
5842
5881
  cacheKeyPrefix() {
@@ -6012,17 +6051,17 @@ function formatAgo(ms) {
6012
6051
  }
6013
6052
  function readJobFrontmatter(cwd, jobsDir, slug) {
6014
6053
  try {
6015
- const raw = fs21.readFileSync(path21.join(cwd, jobsDir, `${slug}.md`), "utf-8");
6054
+ const raw = fs22.readFileSync(path21.join(cwd, jobsDir, `${slug}.md`), "utf-8");
6016
6055
  return splitFrontmatter(raw).frontmatter;
6017
6056
  } catch {
6018
6057
  return {};
6019
6058
  }
6020
6059
  }
6021
6060
  function listJobSlugs(absDir) {
6022
- if (!fs21.existsSync(absDir)) return [];
6061
+ if (!fs22.existsSync(absDir)) return [];
6023
6062
  let entries;
6024
6063
  try {
6025
- entries = fs21.readdirSync(absDir, { withFileTypes: true });
6064
+ entries = fs22.readdirSync(absDir, { withFileTypes: true });
6026
6065
  } catch {
6027
6066
  return [];
6028
6067
  }
@@ -6705,7 +6744,7 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch2, cwd, baseBranch
6705
6744
 
6706
6745
  // src/gha.ts
6707
6746
  import { execFileSync as execFileSync16 } from "child_process";
6708
- import * as fs22 from "fs";
6747
+ import * as fs23 from "fs";
6709
6748
  function getRunUrl() {
6710
6749
  const server = process.env.GITHUB_SERVER_URL;
6711
6750
  const repo = process.env.GITHUB_REPOSITORY;
@@ -6716,10 +6755,10 @@ function getRunUrl() {
6716
6755
  function reactToTriggerComment(cwd) {
6717
6756
  if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
6718
6757
  const eventPath = process.env.GITHUB_EVENT_PATH;
6719
- if (!eventPath || !fs22.existsSync(eventPath)) return;
6758
+ if (!eventPath || !fs23.existsSync(eventPath)) return;
6720
6759
  let event = null;
6721
6760
  try {
6722
- event = JSON.parse(fs22.readFileSync(eventPath, "utf-8"));
6761
+ event = JSON.parse(fs23.readFileSync(eventPath, "utf-8"));
6723
6762
  } catch {
6724
6763
  return;
6725
6764
  }
@@ -7008,22 +7047,22 @@ var handleAbandonedGoal = async (ctx) => {
7008
7047
 
7009
7048
  // src/scripts/initFlow.ts
7010
7049
  import { execFileSync as execFileSync18 } from "child_process";
7011
- import * as fs24 from "fs";
7050
+ import * as fs25 from "fs";
7012
7051
  import * as path23 from "path";
7013
7052
 
7014
7053
  // src/scripts/loadQaGuide.ts
7015
- import * as fs23 from "fs";
7054
+ import * as fs24 from "fs";
7016
7055
  import * as path22 from "path";
7017
7056
  var QA_GUIDE_REL_PATH = ".kody/qa-guide.md";
7018
7057
  var loadQaGuide = async (ctx) => {
7019
7058
  const full = path22.join(ctx.cwd, QA_GUIDE_REL_PATH);
7020
- if (!fs23.existsSync(full)) {
7059
+ if (!fs24.existsSync(full)) {
7021
7060
  ctx.data.qaGuide = "";
7022
7061
  ctx.data.qaGuidePath = "";
7023
7062
  return;
7024
7063
  }
7025
7064
  try {
7026
- ctx.data.qaGuide = fs23.readFileSync(full, "utf-8");
7065
+ ctx.data.qaGuide = fs24.readFileSync(full, "utf-8");
7027
7066
  ctx.data.qaGuidePath = QA_GUIDE_REL_PATH;
7028
7067
  } catch {
7029
7068
  ctx.data.qaGuide = "";
@@ -7033,9 +7072,9 @@ var loadQaGuide = async (ctx) => {
7033
7072
 
7034
7073
  // src/scripts/initFlow.ts
7035
7074
  function detectPackageManager(cwd) {
7036
- if (fs24.existsSync(path23.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
7037
- if (fs24.existsSync(path23.join(cwd, "yarn.lock"))) return "yarn";
7038
- if (fs24.existsSync(path23.join(cwd, "bun.lockb"))) return "bun";
7075
+ if (fs25.existsSync(path23.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
7076
+ if (fs25.existsSync(path23.join(cwd, "yarn.lock"))) return "yarn";
7077
+ if (fs25.existsSync(path23.join(cwd, "bun.lockb"))) return "bun";
7039
7078
  return "npm";
7040
7079
  }
7041
7080
  function qualityCommandsFor(pm) {
@@ -7129,7 +7168,7 @@ jobs:
7129
7168
 
7130
7169
  - env:
7131
7170
  ALL_SECRETS: \${{ toJSON(secrets) }}
7132
- run: npx -y -p @kody-ade/kody-engine@latest kody ci --issue \${{ github.event.inputs.issue_number || github.event.issue.number }}
7171
+ run: npx -y -p @kody-ade/kody-engine@latest kody-engine ci --issue \${{ github.event.inputs.issue_number || github.event.issue.number }}
7133
7172
  `;
7134
7173
  function defaultBranchFromGit(cwd) {
7135
7174
  try {
@@ -7158,47 +7197,47 @@ function performInit(cwd, force) {
7158
7197
  const ownerRepo = detectOwnerRepo(cwd);
7159
7198
  const defaultBranch2 = defaultBranchFromGit(cwd);
7160
7199
  const configPath = path23.join(cwd, "kody.config.json");
7161
- if (fs24.existsSync(configPath) && !force) {
7200
+ if (fs25.existsSync(configPath) && !force) {
7162
7201
  skipped.push("kody.config.json");
7163
7202
  } else {
7164
7203
  const cfg = makeConfig(pm, ownerRepo, defaultBranch2);
7165
- fs24.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
7204
+ fs25.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
7166
7205
  `);
7167
7206
  wrote.push("kody.config.json");
7168
7207
  }
7169
7208
  const workflowDir = path23.join(cwd, ".github", "workflows");
7170
7209
  const workflowPath = path23.join(workflowDir, "kody.yml");
7171
- if (fs24.existsSync(workflowPath) && !force) {
7210
+ if (fs25.existsSync(workflowPath) && !force) {
7172
7211
  skipped.push(".github/workflows/kody.yml");
7173
7212
  } else {
7174
- fs24.mkdirSync(workflowDir, { recursive: true });
7175
- fs24.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
7213
+ fs25.mkdirSync(workflowDir, { recursive: true });
7214
+ fs25.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
7176
7215
  wrote.push(".github/workflows/kody.yml");
7177
7216
  }
7178
- const hasUi = fs24.existsSync(path23.join(cwd, "src/app")) || fs24.existsSync(path23.join(cwd, "app")) || fs24.existsSync(path23.join(cwd, "pages"));
7217
+ const hasUi = fs25.existsSync(path23.join(cwd, "src/app")) || fs25.existsSync(path23.join(cwd, "app")) || fs25.existsSync(path23.join(cwd, "pages"));
7179
7218
  if (hasUi) {
7180
7219
  const qaGuidePath = path23.join(cwd, QA_GUIDE_REL_PATH);
7181
- if (fs24.existsSync(qaGuidePath) && !force) {
7220
+ if (fs25.existsSync(qaGuidePath) && !force) {
7182
7221
  skipped.push(QA_GUIDE_REL_PATH);
7183
7222
  } else {
7184
- fs24.mkdirSync(path23.dirname(qaGuidePath), { recursive: true });
7223
+ fs25.mkdirSync(path23.dirname(qaGuidePath), { recursive: true });
7185
7224
  const discovery = runQaDiscovery(cwd);
7186
- fs24.writeFileSync(qaGuidePath, generateQaGuideTemplate(discovery));
7225
+ fs25.writeFileSync(qaGuidePath, generateQaGuideTemplate(discovery));
7187
7226
  wrote.push(QA_GUIDE_REL_PATH);
7188
7227
  }
7189
7228
  }
7190
7229
  const builtinJobs = listBuiltinJobs();
7191
7230
  if (builtinJobs.length > 0) {
7192
7231
  const jobsDir = path23.join(cwd, ".kody", "jobs");
7193
- fs24.mkdirSync(jobsDir, { recursive: true });
7232
+ fs25.mkdirSync(jobsDir, { recursive: true });
7194
7233
  for (const job of builtinJobs) {
7195
7234
  const rel = path23.join(".kody", "jobs", `${job.slug}.md`);
7196
7235
  const target = path23.join(cwd, rel);
7197
- if (fs24.existsSync(target) && !force) {
7236
+ if (fs25.existsSync(target) && !force) {
7198
7237
  skipped.push(rel);
7199
7238
  continue;
7200
7239
  }
7201
- fs24.writeFileSync(target, fs24.readFileSync(job.filePath, "utf-8"));
7240
+ fs25.writeFileSync(target, fs25.readFileSync(job.filePath, "utf-8"));
7202
7241
  wrote.push(rel);
7203
7242
  }
7204
7243
  }
@@ -7211,11 +7250,11 @@ function performInit(cwd, force) {
7211
7250
  }
7212
7251
  if (profile.kind !== "scheduled" || !profile.schedule) continue;
7213
7252
  const target = path23.join(workflowDir, `kody-${exe.name}.yml`);
7214
- if (fs24.existsSync(target) && !force) {
7253
+ if (fs25.existsSync(target) && !force) {
7215
7254
  skipped.push(`.github/workflows/kody-${exe.name}.yml`);
7216
7255
  continue;
7217
7256
  }
7218
- fs24.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
7257
+ fs25.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
7219
7258
  wrote.push(`.github/workflows/kody-${exe.name}.yml`);
7220
7259
  }
7221
7260
  let labels;
@@ -7255,7 +7294,7 @@ jobs:
7255
7294
  node-version: 22
7256
7295
  - env:
7257
7296
  GH_TOKEN: \${{ secrets.KODY_TOKEN || github.token }}
7258
- run: npx -y -p @kody-ade/kody-engine@latest kody ${name}
7297
+ run: npx -y -p @kody-ade/kody-engine@latest kody-engine ${name}
7259
7298
  `;
7260
7299
  }
7261
7300
  var initFlow = async (ctx) => {
@@ -7293,7 +7332,7 @@ init_loadConventions();
7293
7332
  init_loadCoverageRules();
7294
7333
 
7295
7334
  // src/goal/state.ts
7296
- import * as fs25 from "fs";
7335
+ import * as fs26 from "fs";
7297
7336
  import * as path24 from "path";
7298
7337
  var VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "done"]);
7299
7338
  var GoalStateError = class extends Error {
@@ -7348,12 +7387,12 @@ function goalStatePath(cwd, goalId) {
7348
7387
  }
7349
7388
  function readGoalState(cwd, goalId) {
7350
7389
  const file = goalStatePath(cwd, goalId);
7351
- if (!fs25.existsSync(file)) {
7390
+ if (!fs26.existsSync(file)) {
7352
7391
  throw new GoalStateError(file, "file not found");
7353
7392
  }
7354
7393
  let raw;
7355
7394
  try {
7356
- raw = JSON.parse(fs25.readFileSync(file, "utf-8"));
7395
+ raw = JSON.parse(fs26.readFileSync(file, "utf-8"));
7357
7396
  } catch (err) {
7358
7397
  throw new GoalStateError(file, `invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
7359
7398
  }
@@ -7361,8 +7400,8 @@ function readGoalState(cwd, goalId) {
7361
7400
  }
7362
7401
  function writeGoalState(cwd, goalId, state) {
7363
7402
  const file = goalStatePath(cwd, goalId);
7364
- fs25.mkdirSync(path24.dirname(file), { recursive: true });
7365
- fs25.writeFileSync(file, serializeGoalState(state), "utf-8");
7403
+ fs26.mkdirSync(path24.dirname(file), { recursive: true });
7404
+ fs26.writeFileSync(file, serializeGoalState(state), "utf-8");
7366
7405
  }
7367
7406
  function nowIso() {
7368
7407
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
@@ -7464,7 +7503,7 @@ var loadIssueStateComment = async (ctx, _profile, args) => {
7464
7503
  };
7465
7504
 
7466
7505
  // src/scripts/loadJobFromFile.ts
7467
- import * as fs26 from "fs";
7506
+ import * as fs27 from "fs";
7468
7507
  import * as path25 from "path";
7469
7508
  var loadJobFromFile = async (ctx, _profile, args) => {
7470
7509
  const jobsDir = String(args?.jobsDir ?? ".kody/jobs");
@@ -7474,10 +7513,10 @@ var loadJobFromFile = async (ctx, _profile, args) => {
7474
7513
  throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
7475
7514
  }
7476
7515
  const absPath = path25.join(ctx.cwd, jobsDir, `${slug}.md`);
7477
- if (!fs26.existsSync(absPath)) {
7516
+ if (!fs27.existsSync(absPath)) {
7478
7517
  throw new Error(`loadJobFromFile: job file not found: ${absPath}`);
7479
7518
  }
7480
- const raw = fs26.readFileSync(absPath, "utf-8");
7519
+ const raw = fs27.readFileSync(absPath, "utf-8");
7481
7520
  const { title, body } = parseJobFile(raw, slug);
7482
7521
  const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
7483
7522
  const loaded = await backend.load(slug);
@@ -7516,7 +7555,7 @@ init_loadPriorArt();
7516
7555
  init_events();
7517
7556
 
7518
7557
  // src/taskContext.ts
7519
- import * as fs28 from "fs";
7558
+ import * as fs29 from "fs";
7520
7559
  import * as path27 from "path";
7521
7560
  var TASK_CONTEXT_SCHEMA_VERSION = 1;
7522
7561
  function buildTaskContext(args) {
@@ -7534,9 +7573,9 @@ function buildTaskContext(args) {
7534
7573
  function persistTaskContext(cwd, ctx) {
7535
7574
  try {
7536
7575
  const dir = path27.join(cwd, ".kody", "runs", ctx.runId);
7537
- fs28.mkdirSync(dir, { recursive: true });
7576
+ fs29.mkdirSync(dir, { recursive: true });
7538
7577
  const file = path27.join(dir, "task-context.json");
7539
- fs28.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
7578
+ fs29.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
7540
7579
  `);
7541
7580
  return file;
7542
7581
  } catch (err) {
@@ -8893,7 +8932,7 @@ function resolveBaseOverride(value) {
8893
8932
 
8894
8933
  // src/scripts/runTickScript.ts
8895
8934
  import { spawnSync } from "child_process";
8896
- import * as fs29 from "fs";
8935
+ import * as fs30 from "fs";
8897
8936
  import * as path28 from "path";
8898
8937
  var runTickScript = async (ctx, _profile, args) => {
8899
8938
  ctx.skipAgent = true;
@@ -8907,12 +8946,12 @@ var runTickScript = async (ctx, _profile, args) => {
8907
8946
  return;
8908
8947
  }
8909
8948
  const jobPath = path28.join(ctx.cwd, jobsDir, `${slug}.md`);
8910
- if (!fs29.existsSync(jobPath)) {
8949
+ if (!fs30.existsSync(jobPath)) {
8911
8950
  ctx.output.exitCode = 99;
8912
8951
  ctx.output.reason = `runTickScript: job file not found: ${jobPath}`;
8913
8952
  return;
8914
8953
  }
8915
- const raw = fs29.readFileSync(jobPath, "utf-8");
8954
+ const raw = fs30.readFileSync(jobPath, "utf-8");
8916
8955
  const { frontmatter } = splitFrontmatter(raw);
8917
8956
  const tickScript = frontmatter.tickScript;
8918
8957
  if (!tickScript) {
@@ -8921,7 +8960,7 @@ var runTickScript = async (ctx, _profile, args) => {
8921
8960
  return;
8922
8961
  }
8923
8962
  const scriptPath = path28.isAbsolute(tickScript) ? tickScript : path28.join(ctx.cwd, tickScript);
8924
- if (!fs29.existsSync(scriptPath)) {
8963
+ if (!fs30.existsSync(scriptPath)) {
8925
8964
  ctx.output.exitCode = 99;
8926
8965
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
8927
8966
  return;
@@ -9024,7 +9063,7 @@ function buildChildEnv(parent, force) {
9024
9063
 
9025
9064
  // src/scripts/brainServe.ts
9026
9065
  import { createServer } from "http";
9027
- import * as fs30 from "fs";
9066
+ import * as fs31 from "fs";
9028
9067
  import * as path29 from "path";
9029
9068
  var DEFAULT_PORT = 8080;
9030
9069
  function getApiKey() {
@@ -9136,7 +9175,7 @@ async function handleChatTurn(req, res, chatId, opts) {
9136
9175
  return;
9137
9176
  }
9138
9177
  const sessionFile = sessionFilePath(opts.cwd, chatId);
9139
- fs30.mkdirSync(path29.dirname(sessionFile), { recursive: true });
9178
+ fs31.mkdirSync(path29.dirname(sessionFile), { recursive: true });
9140
9179
  appendTurn(sessionFile, {
9141
9180
  role: "user",
9142
9181
  content: message,
@@ -10095,7 +10134,7 @@ var writeJobStateFile = async (ctx, _profile, _agentResult, args) => {
10095
10134
  };
10096
10135
 
10097
10136
  // src/scripts/writeRunSummary.ts
10098
- import * as fs31 from "fs";
10137
+ import * as fs32 from "fs";
10099
10138
  var writeRunSummary = async (ctx, profile) => {
10100
10139
  const summaryPath = process.env.GITHUB_STEP_SUMMARY;
10101
10140
  if (!summaryPath) return;
@@ -10117,7 +10156,7 @@ var writeRunSummary = async (ctx, profile) => {
10117
10156
  if (reason) lines.push(`- **Reason:** ${reason}`);
10118
10157
  lines.push("");
10119
10158
  try {
10120
- fs31.appendFileSync(summaryPath, `${lines.join("\n")}
10159
+ fs32.appendFileSync(summaryPath, `${lines.join("\n")}
10121
10160
  `);
10122
10161
  } catch {
10123
10162
  }
@@ -10537,7 +10576,7 @@ function clearStampedLifecycleLabels(profile, ctx) {
10537
10576
  function getProfileInputsForChild(profileName, _cwd) {
10538
10577
  try {
10539
10578
  const profilePath = resolveProfilePath(profileName);
10540
- if (!fs32.existsSync(profilePath)) return null;
10579
+ if (!fs33.existsSync(profilePath)) return null;
10541
10580
  return loadProfile(profilePath).inputs;
10542
10581
  } catch {
10543
10582
  return null;
@@ -10556,7 +10595,7 @@ function resolveProfilePath(profileName) {
10556
10595
  // fallback
10557
10596
  ];
10558
10597
  for (const c of candidates) {
10559
- if (fs32.existsSync(c)) return c;
10598
+ if (fs33.existsSync(c)) return c;
10560
10599
  }
10561
10600
  return candidates[0];
10562
10601
  }
@@ -10657,7 +10696,7 @@ var SIGKILL_GRACE_MS = 5e3;
10657
10696
  async function runShellEntry(entry, ctx, profile) {
10658
10697
  const shellName = entry.shell;
10659
10698
  const shellPath = path30.join(profile.dir, shellName);
10660
- if (!fs32.existsSync(shellPath)) {
10699
+ if (!fs33.existsSync(shellPath)) {
10661
10700
  ctx.skipAgent = true;
10662
10701
  ctx.output.exitCode = 99;
10663
10702
  ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
@@ -11136,9 +11175,9 @@ function resolveAuthToken(env = process.env) {
11136
11175
  return token;
11137
11176
  }
11138
11177
  function detectPackageManager2(cwd) {
11139
- if (fs33.existsSync(path31.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
11140
- if (fs33.existsSync(path31.join(cwd, "yarn.lock"))) return "yarn";
11141
- if (fs33.existsSync(path31.join(cwd, "bun.lockb"))) return "bun";
11178
+ if (fs34.existsSync(path31.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
11179
+ if (fs34.existsSync(path31.join(cwd, "yarn.lock"))) return "yarn";
11180
+ if (fs34.existsSync(path31.join(cwd, "bun.lockb"))) return "bun";
11142
11181
  return "npm";
11143
11182
  }
11144
11183
  function shellOut(cmd, args, cwd, stream = true) {
@@ -11228,8 +11267,8 @@ function postFailureTail(issueNumber, cwd, reason) {
11228
11267
  const logPath = path31.join(cwd, ".kody", "last-run.jsonl");
11229
11268
  let tail = "";
11230
11269
  try {
11231
- if (fs33.existsSync(logPath)) {
11232
- const content = fs33.readFileSync(logPath, "utf-8");
11270
+ if (fs34.existsSync(logPath)) {
11271
+ const content = fs34.readFileSync(logPath, "utf-8");
11233
11272
  tail = content.slice(-3e3);
11234
11273
  }
11235
11274
  } catch {
@@ -11264,9 +11303,9 @@ async function runCi(argv) {
11264
11303
  const eventName = process.env.GITHUB_EVENT_NAME;
11265
11304
  const dispatchEventPath = process.env.GITHUB_EVENT_PATH;
11266
11305
  let manualWorkflowDispatch = false;
11267
- if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs33.existsSync(dispatchEventPath)) {
11306
+ if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs34.existsSync(dispatchEventPath)) {
11268
11307
  try {
11269
- const evt = JSON.parse(fs33.readFileSync(dispatchEventPath, "utf-8"));
11308
+ const evt = JSON.parse(fs34.readFileSync(dispatchEventPath, "utf-8"));
11270
11309
  const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
11271
11310
  const sessionInput = String(evt?.inputs?.sessionId ?? "");
11272
11311
  manualWorkflowDispatch = !sessionInput && !(Number.isFinite(issueInput) && issueInput > 0);
@@ -11527,7 +11566,7 @@ function parseChatArgs(argv, env = process.env) {
11527
11566
  function commitChatFiles(cwd, sessionId, verbose) {
11528
11567
  const sessionFile = path32.relative(cwd, sessionFilePath(cwd, sessionId));
11529
11568
  const eventsFile = path32.relative(cwd, eventsFilePath(cwd, sessionId));
11530
- const paths = [sessionFile, eventsFile].filter((p) => fs34.existsSync(path32.join(cwd, p)));
11569
+ const paths = [sessionFile, eventsFile].filter((p) => fs35.existsSync(path32.join(cwd, p)));
11531
11570
  if (paths.length === 0) return;
11532
11571
  const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
11533
11572
  try {
@@ -11617,7 +11656,7 @@ ${CHAT_HELP}`);
11617
11656
  const sink = buildSink(cwd, sessionId, args.dashboardUrl);
11618
11657
  const meta = readMeta(sessionFile);
11619
11658
  process.stdout.write(
11620
- `\u2192 kody:chat: session file=${sessionFile} exists=${fs34.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
11659
+ `\u2192 kody:chat: session file=${sessionFile} exists=${fs35.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
11621
11660
  `
11622
11661
  );
11623
11662
  try {
@@ -11856,20 +11895,20 @@ function formatMs(ms) {
11856
11895
  }
11857
11896
 
11858
11897
  // src/entry.ts
11859
- var HELP_TEXT = `kody \u2014 single-session autonomous engineer
11898
+ var HELP_TEXT = `kody-engine \u2014 single-session autonomous engineer
11860
11899
 
11861
11900
  Usage:
11862
- kody run --issue <N> [--cwd <path>] [--verbose|--quiet]
11863
- kody fix --pr <N> [--feedback "..."] [--cwd <path>] [--verbose|--quiet]
11864
- kody fix-ci --pr <N> [--run-id <ID>] [--cwd <path>] [--verbose|--quiet]
11865
- kody resolve --pr <N> [--cwd <path>] [--verbose|--quiet]
11866
- kody review --pr <N> [--cwd <path>] [--verbose|--quiet]
11867
- kody <other> [--cwd <path>] [--verbose|--quiet]
11868
- kody ci --issue <N> [preflight flags \u2014 see: kody ci --help]
11869
- kody chat [chat flags \u2014 see: kody chat --help]
11870
- kody stats [--since 7d|--run <id>|--json|--cwd <path>]
11871
- kody help
11872
- kody version
11901
+ kody-engine run --issue <N> [--cwd <path>] [--verbose|--quiet]
11902
+ kody-engine fix --pr <N> [--feedback "..."] [--cwd <path>] [--verbose|--quiet]
11903
+ kody-engine fix-ci --pr <N> [--run-id <ID>] [--cwd <path>] [--verbose|--quiet]
11904
+ kody-engine resolve --pr <N> [--cwd <path>] [--verbose|--quiet]
11905
+ kody-engine review --pr <N> [--cwd <path>] [--verbose|--quiet]
11906
+ kody-engine <other> [--cwd <path>] [--verbose|--quiet]
11907
+ kody-engine ci --issue <N> [preflight flags \u2014 see: kody-engine ci --help]
11908
+ kody-engine chat [chat flags \u2014 see: kody-engine chat --help]
11909
+ kody-engine stats [--since 7d|--run <id>|--json|--cwd <path>]
11910
+ kody-engine help
11911
+ kody-engine version
11873
11912
 
11874
11913
  Each top-level command (run, fix, fix-ci, resolve, review, \u2026) is a discovered
11875
11914
  executable under \`src/executables/<name>/profile.json\`. Drop in a new