@kody-ade/kody-engine 0.4.507 → 0.4.509

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 +376 -352
  2. package/package.json +1 -1
package/dist/bin/kody.js CHANGED
@@ -15,7 +15,7 @@ var init_package = __esm({
15
15
  "package.json"() {
16
16
  package_default = {
17
17
  name: "@kody-ade/kody-engine",
18
- version: "0.4.507",
18
+ version: "0.4.509",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -620,8 +620,9 @@ function formatResult(msg) {
620
620
  function summarizeToolInput(toolName, input = {}) {
621
621
  if (toolName === "Agent") {
622
622
  const agent = summarizeSingleLineValue(input.subagent_type, "unknown", 80);
623
- const model = summarizeSingleLineValue(input.model, "inherit", 80);
624
- return `: ${agent} model=${model}`;
623
+ const requestedModel = summarizeSingleLineValue(input.model, "inherit", 80);
624
+ const ignoredOverride = requestedModel === "inherit" ? "" : ` (ignored override=${requestedModel})`;
625
+ return `: ${agent} model=inherit${ignoredOverride}`;
625
626
  }
626
627
  if (toolName === "Bash" && typeof input.command === "string") {
627
628
  const cmd = input.command.split("\n")[0];
@@ -698,6 +699,178 @@ var init_runtimePaths = __esm({
698
699
  }
699
700
  });
700
701
 
702
+ // src/scripts/buildSyntheticPlugin.ts
703
+ import * as fs3 from "fs";
704
+ import * as os3 from "os";
705
+ import * as path4 from "path";
706
+ function getPluginsCatalogRoot() {
707
+ const here = path4.dirname(new URL(import.meta.url).pathname);
708
+ const candidates = [
709
+ path4.join(here, "..", "plugins"),
710
+ // dev: src/scripts → src/plugins
711
+ path4.join(here, "..", "..", "plugins"),
712
+ // built: dist/scripts → dist/plugins
713
+ path4.join(here, "..", "..", "src", "plugins")
714
+ // fallback
715
+ ];
716
+ for (const c of candidates) {
717
+ if (fs3.existsSync(c) && fs3.statSync(c).isDirectory()) return c;
718
+ }
719
+ return candidates[0];
720
+ }
721
+ function copyDir(src, dst) {
722
+ fs3.mkdirSync(dst, { recursive: true });
723
+ for (const ent of fs3.readdirSync(src, { withFileTypes: true })) {
724
+ const s = path4.join(src, ent.name);
725
+ const d = path4.join(dst, ent.name);
726
+ if (ent.isDirectory()) copyDir(s, d);
727
+ else if (ent.isFile()) fs3.copyFileSync(s, d);
728
+ }
729
+ }
730
+ var buildSyntheticPlugin;
731
+ var init_buildSyntheticPlugin = __esm({
732
+ "src/scripts/buildSyntheticPlugin.ts"() {
733
+ "use strict";
734
+ buildSyntheticPlugin = async (ctx, profile) => {
735
+ const cc = profile.claudeCode;
736
+ const needsSynthetic = cc.skills.length > 0 || cc.commands.length > 0 || cc.hooks.length > 0;
737
+ if (!needsSynthetic) return;
738
+ const catalog = getPluginsCatalogRoot();
739
+ const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
740
+ const root = path4.join(os3.tmpdir(), `kody-synth-${runId}`);
741
+ fs3.mkdirSync(path4.join(root, ".claude-plugin"), { recursive: true });
742
+ const resolvePart = (bucket, entry) => {
743
+ const local = path4.join(profile.dir, bucket, entry);
744
+ if (fs3.existsSync(local)) return local;
745
+ const shared = path4.resolve(profile.dir, "..", "..", "shared", bucket, entry);
746
+ if (fs3.existsSync(shared)) return shared;
747
+ const central = path4.join(catalog, bucket, entry);
748
+ if (fs3.existsSync(central)) return central;
749
+ throw new Error(
750
+ `buildSyntheticPlugin: ${bucket} entry '${entry}' not found in implementation dir (${profile.dir}/${bucket}/), Store shared assets (${path4.dirname(shared)}/), or catalog (${catalog}/${bucket}/)`
751
+ );
752
+ };
753
+ if (cc.skills.length > 0) {
754
+ const dst = path4.join(root, "skills");
755
+ fs3.mkdirSync(dst, { recursive: true });
756
+ for (const name of cc.skills) {
757
+ copyDir(resolvePart("skills", name), path4.join(dst, name));
758
+ }
759
+ }
760
+ if (cc.commands.length > 0) {
761
+ const dst = path4.join(root, "commands");
762
+ fs3.mkdirSync(dst, { recursive: true });
763
+ for (const name of cc.commands) {
764
+ fs3.copyFileSync(resolvePart("commands", `${name}.md`), path4.join(dst, `${name}.md`));
765
+ }
766
+ }
767
+ if (cc.hooks.length > 0) {
768
+ const dst = path4.join(root, "hooks");
769
+ fs3.mkdirSync(dst, { recursive: true });
770
+ const merged = { hooks: {} };
771
+ for (const name of cc.hooks) {
772
+ const src = resolvePart("hooks", `${name}.json`);
773
+ const parsed = JSON.parse(fs3.readFileSync(src, "utf-8"));
774
+ for (const [event, entries] of Object.entries(parsed.hooks ?? {})) {
775
+ if (!Array.isArray(entries)) continue;
776
+ if (!merged.hooks[event]) merged.hooks[event] = [];
777
+ merged.hooks[event].push(...entries);
778
+ }
779
+ }
780
+ fs3.writeFileSync(path4.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
781
+ `);
782
+ }
783
+ const manifest = {
784
+ name: `kody-synth-${profile.name}`,
785
+ version: "1.0.0",
786
+ description: `Synthetic plugin assembled by Kody for profile '${profile.name}' at runtime.`
787
+ };
788
+ if (cc.skills.length > 0) manifest.skills = ["./skills/"];
789
+ if (cc.commands.length > 0) manifest.commands = ["./commands/"];
790
+ fs3.writeFileSync(path4.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
791
+ `);
792
+ ctx.data.syntheticPluginPath = root;
793
+ };
794
+ }
795
+ });
796
+
797
+ // src/subagents.ts
798
+ import * as fs4 from "fs";
799
+ import * as path5 from "path";
800
+ async function enforceSubagentModelInheritance(input) {
801
+ const toolInput = input.tool_input;
802
+ if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return {};
803
+ const updatedInput = { ...toolInput };
804
+ delete updatedInput.model;
805
+ return {
806
+ hookSpecificOutput: {
807
+ hookEventName: "PreToolUse",
808
+ updatedInput
809
+ }
810
+ };
811
+ }
812
+ function splitFrontmatter(raw) {
813
+ const match = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(raw);
814
+ if (!match) return { fm: {}, body: raw.trim() };
815
+ const fm = {};
816
+ for (const line of match[1].split("\n")) {
817
+ const idx = line.indexOf(":");
818
+ if (idx === -1) continue;
819
+ fm[line.slice(0, idx).trim()] = line.slice(idx + 1).trim();
820
+ }
821
+ return { fm, body: (match[2] ?? "").trim() };
822
+ }
823
+ function resolveAgentFile(profileDir, name) {
824
+ const local = path5.join(profileDir, "agents", `${name}.md`);
825
+ if (fs4.existsSync(local)) return local;
826
+ const shared = path5.resolve(profileDir, "..", "..", "shared", "agents", `${name}.md`);
827
+ if (fs4.existsSync(shared)) return shared;
828
+ const central = path5.join(getPluginsCatalogRoot(), "agents", `${name}.md`);
829
+ if (fs4.existsSync(central)) return central;
830
+ throw new Error(
831
+ `loadSubagents: agent '${name}' not found in ${profileDir}/agents/, hydrated shared assets, or engine catalog`
832
+ );
833
+ }
834
+ function captureSubagentTemplates(profile) {
835
+ const names = profile.claudeCode.subagents;
836
+ if (!names || names.length === 0) return {};
837
+ const out = {};
838
+ for (const name of names) {
839
+ try {
840
+ out[name] = fs4.readFileSync(resolveAgentFile(profile.dir, name), "utf-8");
841
+ } catch {
842
+ }
843
+ }
844
+ return out;
845
+ }
846
+ function loadSubagents(profile) {
847
+ const names = profile.claudeCode.subagents;
848
+ if (!names || names.length === 0) return void 0;
849
+ const agents = {};
850
+ for (const name of names) {
851
+ const raw = profile.subagentTemplates?.[name] ?? fs4.readFileSync(resolveAgentFile(profile.dir, name), "utf-8");
852
+ const { fm, body } = splitFrontmatter(raw);
853
+ if (!body) throw new Error(`loadSubagents: agent '${name}' has an empty prompt body`);
854
+ const def = {
855
+ description: fm.description ?? `Subagent ${name}`,
856
+ prompt: body,
857
+ model: "inherit"
858
+ };
859
+ if (fm.tools) {
860
+ const tools = fm.tools.split(",").map((t) => t.trim()).filter(Boolean);
861
+ if (tools.length > 0) def.tools = tools;
862
+ }
863
+ agents[fm.name || name] = def;
864
+ }
865
+ return agents;
866
+ }
867
+ var init_subagents = __esm({
868
+ "src/subagents.ts"() {
869
+ "use strict";
870
+ init_buildSyntheticPlugin();
871
+ }
872
+ });
873
+
701
874
  // src/events.ts
702
875
  var events_exports = {};
703
876
  __export(events_exports, {
@@ -708,8 +881,8 @@ __export(events_exports, {
708
881
  resolveRunId: () => resolveRunId
709
882
  });
710
883
  import * as crypto from "crypto";
711
- import * as fs3 from "fs";
712
- import * as path4 from "path";
884
+ import * as fs5 from "fs";
885
+ import * as path6 from "path";
713
886
  function resolveRunId() {
714
887
  if (process.env.KODY_RUN_ID) {
715
888
  cachedRunId = process.env.KODY_RUN_ID;
@@ -742,16 +915,16 @@ function emitEvent(cwd, ev) {
742
915
  ...ev
743
916
  };
744
917
  const file = eventsPath(cwd, runId);
745
- fs3.mkdirSync(path4.dirname(file), { recursive: true });
746
- fs3.appendFileSync(file, `${JSON.stringify(fullEvent)}
918
+ fs5.mkdirSync(path6.dirname(file), { recursive: true });
919
+ fs5.appendFileSync(file, `${JSON.stringify(fullEvent)}
747
920
  `);
748
921
  } catch {
749
922
  }
750
923
  }
751
924
  function readEvents(cwd, runId) {
752
925
  const file = eventsPath(cwd, runId);
753
- if (!fs3.existsSync(file)) return [];
754
- const lines = fs3.readFileSync(file, "utf-8").split("\n");
926
+ if (!fs5.existsSync(file)) return [];
927
+ const lines = fs5.readFileSync(file, "utf-8").split("\n");
755
928
  const out = [];
756
929
  for (const line of lines) {
757
930
  const trimmed = line.trim();
@@ -765,10 +938,10 @@ function readEvents(cwd, runId) {
765
938
  }
766
939
  function listRuns(cwd) {
767
940
  const runsDir = runtimeStatePath(cwd, "agent-runs");
768
- if (!fs3.existsSync(runsDir)) return [];
769
- return fs3.readdirSync(runsDir).filter((name) => {
941
+ if (!fs5.existsSync(runsDir)) return [];
942
+ return fs5.readdirSync(runsDir).filter((name) => {
770
943
  try {
771
- return fs3.statSync(path4.join(runsDir, name)).isDirectory();
944
+ return fs5.statSync(path6.join(runsDir, name)).isDirectory();
772
945
  } catch {
773
946
  return false;
774
947
  }
@@ -1690,8 +1863,8 @@ var init_issue = __esm({
1690
1863
  });
1691
1864
 
1692
1865
  // src/capabilityFolders.ts
1693
- import * as fs4 from "fs";
1694
- import * as path5 from "path";
1866
+ import * as fs6 from "fs";
1867
+ import * as path7 from "path";
1695
1868
  function capabilityOutputConditionPaths(config) {
1696
1869
  if (config.outputSchema) {
1697
1870
  return new Set(schemaPropertyPaths(config.outputSchema, "result"));
@@ -1706,32 +1879,32 @@ function capabilityOutputConditionPaths(config) {
1706
1879
  ]);
1707
1880
  }
1708
1881
  function listCapabilityFolderSlugs(absDir) {
1709
- if (!fs4.existsSync(absDir)) return [];
1882
+ if (!fs6.existsSync(absDir)) return [];
1710
1883
  let entries;
1711
1884
  try {
1712
- entries = fs4.readdirSync(absDir, { withFileTypes: true });
1885
+ entries = fs6.readdirSync(absDir, { withFileTypes: true });
1713
1886
  } catch {
1714
1887
  return [];
1715
1888
  }
1716
- return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).filter((e) => isCapabilityFolder(path5.join(absDir, e.name))).map((e) => e.name).sort();
1889
+ return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).filter((e) => isCapabilityFolder(path7.join(absDir, e.name))).map((e) => e.name).sort();
1717
1890
  }
1718
1891
  function isCapabilityFolder(dir) {
1719
- if (!fs4.existsSync(path5.join(dir, CAPABILITY_BODY_FILE))) return false;
1720
- const entries = fs4.readdirSync(dir, { withFileTypes: true });
1892
+ if (!fs6.existsSync(path7.join(dir, CAPABILITY_BODY_FILE))) return false;
1893
+ const entries = fs6.readdirSync(dir, { withFileTypes: true });
1721
1894
  return entries.every(
1722
1895
  (entry) => entry.name === CAPABILITY_BODY_FILE || entry.name === CAPABILITY_CONTRACT_FILE || entry.isDirectory() && (entry.name === "skills" || entry.name === "tools")
1723
1896
  );
1724
1897
  }
1725
1898
  function readCapabilityFolder(root, slug) {
1726
- const dir = path5.join(root, slug);
1727
- const bodyPath = path5.join(dir, CAPABILITY_BODY_FILE);
1728
- const contractPath = path5.join(dir, CAPABILITY_CONTRACT_FILE);
1729
- if (!fs4.existsSync(bodyPath) || !fs4.statSync(bodyPath).isFile()) return null;
1899
+ const dir = path7.join(root, slug);
1900
+ const bodyPath = path7.join(dir, CAPABILITY_BODY_FILE);
1901
+ const contractPath = path7.join(dir, CAPABILITY_CONTRACT_FILE);
1902
+ if (!fs6.existsSync(bodyPath) || !fs6.statSync(bodyPath).isFile()) return null;
1730
1903
  if (!isCapabilityFolder(dir)) return null;
1731
1904
  try {
1732
- const rawBody = fs4.readFileSync(bodyPath, "utf-8");
1733
- const contract = fs4.existsSync(contractPath) ? parseCapabilityContract(fs4.readFileSync(contractPath, "utf-8")) : void 0;
1734
- if (contract?.execution === "script" && !isRegularFile(path5.join(dir, "tools", "run.sh"))) {
1905
+ const rawBody = fs6.readFileSync(bodyPath, "utf-8");
1906
+ const contract = fs6.existsSync(contractPath) ? parseCapabilityContract(fs6.readFileSync(contractPath, "utf-8")) : void 0;
1907
+ if (contract?.execution === "script" && !isRegularFile(path7.join(dir, "tools", "run.sh"))) {
1735
1908
  throw new Error('script-backed Capability requires a regular "tools/run.sh" file');
1736
1909
  }
1737
1910
  const { title, body } = parseCapabilityBody(rawBody, slug);
@@ -1802,7 +1975,7 @@ function parseCapabilityContract(raw) {
1802
1975
  }
1803
1976
  function isRegularFile(filePath) {
1804
1977
  try {
1805
- const stat = fs4.lstatSync(filePath);
1978
+ const stat = fs6.lstatSync(filePath);
1806
1979
  return stat.isFile() && !stat.isSymbolicLink();
1807
1980
  } catch {
1808
1981
  return false;
@@ -1961,51 +2134,51 @@ var init_capabilityFolders = __esm({
1961
2134
  });
1962
2135
 
1963
2136
  // src/definition-paths.ts
1964
- import * as fs5 from "fs";
1965
- import * as path6 from "path";
2137
+ import * as fs7 from "fs";
2138
+ import * as path8 from "path";
1966
2139
  function definitionsRoot(cwd = process.cwd()) {
1967
2140
  const override = process.env.KODY_DEFINITIONS_ROOT?.trim();
1968
2141
  const overrideCwd = process.env.KODY_DEFINITIONS_ROOT_CWD?.trim();
1969
- if (override && overrideCwd && path6.resolve(cwd) === path6.resolve(overrideCwd)) {
1970
- return storeCatalogRoot(path6.resolve(override));
2142
+ if (override && overrideCwd && path8.resolve(cwd) === path8.resolve(overrideCwd)) {
2143
+ return storeCatalogRoot(path8.resolve(override));
1971
2144
  }
1972
- const hydrated = path6.join(cwd, ".kody-engine", "definitions");
1973
- if (fs5.existsSync(hydrated)) return hydrated;
1974
- return override ? storeCatalogRoot(path6.resolve(override)) : hydrated;
2145
+ const hydrated = path8.join(cwd, ".kody-engine", "definitions");
2146
+ if (fs7.existsSync(hydrated)) return hydrated;
2147
+ return override ? storeCatalogRoot(path8.resolve(override)) : hydrated;
1975
2148
  }
1976
2149
  function hasExplicitDefinitionsRoot(cwd = process.cwd(), env = process.env) {
1977
2150
  const root = env.KODY_DEFINITIONS_ROOT?.trim();
1978
2151
  const rootCwd = env.KODY_DEFINITIONS_ROOT_CWD?.trim();
1979
- return Boolean(root && rootCwd && path6.resolve(cwd) === path6.resolve(rootCwd));
2152
+ return Boolean(root && rootCwd && path8.resolve(cwd) === path8.resolve(rootCwd));
1980
2153
  }
1981
2154
  function capabilitiesRoot(cwd = process.cwd()) {
1982
- return storeAssetRoot(cwd, "capabilities") ?? path6.join(definitionsRoot(cwd), "capabilities");
2155
+ return storeAssetRoot(cwd, "capabilities") ?? path8.join(definitionsRoot(cwd), "capabilities");
1983
2156
  }
1984
2157
  function implementationsRoot(cwd = process.cwd()) {
1985
- return path6.join(definitionsRoot(cwd), "implementations");
2158
+ return path8.join(definitionsRoot(cwd), "implementations");
1986
2159
  }
1987
2160
  function agentsRoot(cwd = process.cwd()) {
1988
- return storeAssetRoot(cwd, "agent") ?? path6.join(definitionsRoot(cwd), "agents");
2161
+ return storeAssetRoot(cwd, "agent") ?? path8.join(definitionsRoot(cwd), "agents");
1989
2162
  }
1990
2163
  function storeCatalogRoot(root) {
1991
2164
  const manifest = readStoreManifest(root);
1992
- const roots = ["capabilities", "workflows", "loops"].map((kind) => manifest?.assetRoots?.[kind]).filter((value) => typeof value === "string" && Boolean(value.trim())).map((value) => path6.dirname(value));
1993
- return roots.length === 3 && new Set(roots).size === 1 ? path6.join(root, roots[0]) : root;
2165
+ const roots = ["capabilities", "workflows", "loops"].map((kind) => manifest?.assetRoots?.[kind]).filter((value) => typeof value === "string" && Boolean(value.trim())).map((value) => path8.dirname(value));
2166
+ return roots.length === 3 && new Set(roots).size === 1 ? path8.join(root, roots[0]) : root;
1994
2167
  }
1995
2168
  function storeAssetRoot(cwd, kind) {
1996
2169
  const override = process.env.KODY_DEFINITIONS_ROOT?.trim();
1997
2170
  if (!override) return null;
1998
2171
  const overrideCwd = process.env.KODY_DEFINITIONS_ROOT_CWD?.trim();
1999
- if (overrideCwd && path6.resolve(cwd) !== path6.resolve(overrideCwd)) return null;
2000
- const root = path6.resolve(override);
2172
+ if (overrideCwd && path8.resolve(cwd) !== path8.resolve(overrideCwd)) return null;
2173
+ const root = path8.resolve(override);
2001
2174
  const configured = readStoreManifest(root)?.assetRoots?.[kind];
2002
- return typeof configured === "string" && configured.trim() ? path6.join(root, configured) : null;
2175
+ return typeof configured === "string" && configured.trim() ? path8.join(root, configured) : null;
2003
2176
  }
2004
2177
  function readStoreManifest(root) {
2005
- const file = path6.join(root, "kody-store.json");
2006
- if (!fs5.existsSync(file)) return null;
2178
+ const file = path8.join(root, "kody-store.json");
2179
+ if (!fs7.existsSync(file)) return null;
2007
2180
  try {
2008
- return JSON.parse(fs5.readFileSync(file, "utf8"));
2181
+ return JSON.parse(fs7.readFileSync(file, "utf8"));
2009
2182
  } catch {
2010
2183
  return null;
2011
2184
  }
@@ -2017,32 +2190,32 @@ var init_definition_paths = __esm({
2017
2190
  });
2018
2191
 
2019
2192
  // src/registry.ts
2020
- import * as fs6 from "fs";
2021
- import * as path7 from "path";
2193
+ import * as fs8 from "fs";
2194
+ import * as path9 from "path";
2022
2195
  function getImplementationsRoot() {
2023
- const here = path7.dirname(new URL(import.meta.url).pathname);
2196
+ const here = path9.dirname(new URL(import.meta.url).pathname);
2024
2197
  const candidates = [
2025
- path7.join(here, "implementations"),
2198
+ path9.join(here, "implementations"),
2026
2199
  // dev: src/
2027
- path7.join(here, "..", "implementations"),
2200
+ path9.join(here, "..", "implementations"),
2028
2201
  // built: dist/bin → dist/implementations
2029
- path7.join(here, "..", "src", "implementations")
2202
+ path9.join(here, "..", "src", "implementations")
2030
2203
  // fallback
2031
2204
  ];
2032
2205
  for (const c of candidates) {
2033
- if (fs6.existsSync(c) && fs6.statSync(c).isDirectory()) return c;
2206
+ if (fs8.existsSync(c) && fs8.statSync(c).isDirectory()) return c;
2034
2207
  }
2035
2208
  return candidates[0];
2036
2209
  }
2037
2210
  function getRuntimeServicesRoot() {
2038
- const here = path7.dirname(new URL(import.meta.url).pathname);
2211
+ const here = path9.dirname(new URL(import.meta.url).pathname);
2039
2212
  const candidates = [
2040
- path7.join(here, "runtime-services"),
2041
- path7.join(here, "..", "runtime-services"),
2042
- path7.join(here, "..", "src", "runtime-services")
2213
+ path9.join(here, "runtime-services"),
2214
+ path9.join(here, "..", "runtime-services"),
2215
+ path9.join(here, "..", "src", "runtime-services")
2043
2216
  ];
2044
2217
  for (const candidate of candidates) {
2045
- if (fs6.existsSync(candidate) && fs6.statSync(candidate).isDirectory()) return candidate;
2218
+ if (fs8.existsSync(candidate) && fs8.statSync(candidate).isDirectory()) return candidate;
2046
2219
  }
2047
2220
  return candidates[0];
2048
2221
  }
@@ -2050,17 +2223,17 @@ function getProjectCapabilitiesRoot() {
2050
2223
  return capabilitiesRoot();
2051
2224
  }
2052
2225
  function getBuiltinCapabilitiesRoot() {
2053
- const here = path7.dirname(new URL(import.meta.url).pathname);
2226
+ const here = path9.dirname(new URL(import.meta.url).pathname);
2054
2227
  const candidates = [
2055
- path7.join(here, "capabilities"),
2228
+ path9.join(here, "capabilities"),
2056
2229
  // dev: src/
2057
- path7.join(here, "..", "capabilities"),
2230
+ path9.join(here, "..", "capabilities"),
2058
2231
  // built: dist/bin → dist/capabilities
2059
- path7.join(here, "..", "src", "capabilities")
2232
+ path9.join(here, "..", "src", "capabilities")
2060
2233
  // fallback
2061
2234
  ];
2062
2235
  for (const c of candidates) {
2063
- if (fs6.existsSync(c) && fs6.statSync(c).isDirectory()) return c;
2236
+ if (fs8.existsSync(c) && fs8.statSync(c).isDirectory()) return c;
2064
2237
  }
2065
2238
  return candidates[0];
2066
2239
  }
@@ -2083,14 +2256,14 @@ function listImplementations(roots = getImplementationRoots()) {
2083
2256
  const seen = /* @__PURE__ */ new Set();
2084
2257
  const out = [];
2085
2258
  for (const root of rootList) {
2086
- if (!fs6.existsSync(root)) continue;
2259
+ if (!fs8.existsSync(root)) continue;
2087
2260
  const requireImplementationProfile = isCapabilityRoot(root);
2088
- const entries = fs6.readdirSync(root, { withFileTypes: true });
2261
+ const entries = fs8.readdirSync(root, { withFileTypes: true });
2089
2262
  for (const ent of entries) {
2090
2263
  if (!ent.isDirectory()) continue;
2091
2264
  if (seen.has(ent.name)) continue;
2092
2265
  const profilePath = implementationRuntimePath(root, ent.name);
2093
- if (fs6.existsSync(profilePath) && fs6.statSync(profilePath).isFile() && isImplementationProfile(profilePath, requireImplementationProfile)) {
2266
+ if (fs8.existsSync(profilePath) && fs8.statSync(profilePath).isFile() && isImplementationProfile(profilePath, requireImplementationProfile)) {
2094
2267
  out.push({ name: ent.name, profilePath });
2095
2268
  seen.add(ent.name);
2096
2269
  }
@@ -2110,7 +2283,7 @@ function resolveImplementationCandidates(name, roots = getRuntimeProfileRootsFor
2110
2283
  const out = [];
2111
2284
  for (const root of rootList) {
2112
2285
  const profilePath = implementationRuntimePath(root, name);
2113
- if (fs6.existsSync(profilePath) && fs6.statSync(profilePath).isFile() && isImplementationProfile(profilePath, isCapabilityRoot(root))) {
2286
+ if (fs8.existsSync(profilePath) && fs8.statSync(profilePath).isFile() && isImplementationProfile(profilePath, isCapabilityRoot(root))) {
2114
2287
  out.push(profilePath);
2115
2288
  }
2116
2289
  }
@@ -2179,7 +2352,7 @@ function implementationDeclaresInput(implementation, inputName, cwd = process.cw
2179
2352
  const profilePath = resolveImplementation(implementation, getRuntimeProfileRootsForCwd(cwd));
2180
2353
  if (!profilePath) return false;
2181
2354
  try {
2182
- const document = JSON.parse(fs6.readFileSync(profilePath, "utf-8"));
2355
+ const document = JSON.parse(fs8.readFileSync(profilePath, "utf-8"));
2183
2356
  const raw = document.config ?? document;
2184
2357
  if (!Array.isArray(raw.inputs)) return false;
2185
2358
  return raw.inputs.some((entry) => {
@@ -2195,29 +2368,29 @@ function isSafeName(name) {
2195
2368
  return /^[a-z][a-z0-9-]*$/.test(name) && !name.includes("..");
2196
2369
  }
2197
2370
  function isCapabilityRoot(root) {
2198
- const normalized = path7.normalize(root);
2199
- if (path7.basename(normalized) === "capabilities") return true;
2371
+ const normalized = path9.normalize(root);
2372
+ if (path9.basename(normalized) === "capabilities") return true;
2200
2373
  const knownRoots = [getProjectCapabilitiesRoot(), getBuiltinCapabilitiesRoot()];
2201
- return knownRoots.some((candidate) => candidate && path7.normalize(candidate) === normalized);
2374
+ return knownRoots.some((candidate) => candidate && path9.normalize(candidate) === normalized);
2202
2375
  }
2203
2376
  function implementationRuntimePath(root, name) {
2204
- const runtimePath = path7.join(root, name, "runtime.json");
2205
- if (fs6.existsSync(runtimePath)) return runtimePath;
2206
- const internalProfilePath = path7.join(root, name, "profile.json");
2207
- if (fs6.existsSync(internalProfilePath)) return internalProfilePath;
2208
- return path7.join(root, name, CAPABILITY_PROFILE_FILE);
2377
+ const runtimePath = path9.join(root, name, "runtime.json");
2378
+ if (fs8.existsSync(runtimePath)) return runtimePath;
2379
+ const internalProfilePath = path9.join(root, name, "profile.json");
2380
+ if (fs8.existsSync(internalProfilePath)) return internalProfilePath;
2381
+ return path9.join(root, name, CAPABILITY_PROFILE_FILE);
2209
2382
  }
2210
2383
  function isImplementationProfile(profilePath, requireImplementationProfile) {
2211
2384
  if (!requireImplementationProfile) return true;
2212
2385
  try {
2213
- const raw = JSON.parse(fs6.readFileSync(profilePath, "utf-8"));
2386
+ const raw = JSON.parse(fs8.readFileSync(profilePath, "utf-8"));
2214
2387
  return typeof raw.role === "string" && PUBLIC_IMPLEMENTATION_ROLES.has(raw.role);
2215
2388
  } catch {
2216
2389
  return false;
2217
2390
  }
2218
2391
  }
2219
2392
  function listFolderCapabilityActions(root, source) {
2220
- if (!fs6.existsSync(root) || !fs6.statSync(root).isDirectory()) return [];
2393
+ if (!fs8.existsSync(root) || !fs8.statSync(root).isDirectory()) return [];
2221
2394
  const out = [];
2222
2395
  for (const slug of listCapabilityFolderSlugs(root)) {
2223
2396
  if (!isSafeName(slug)) continue;
@@ -2249,7 +2422,7 @@ function hasUnresolvedExplicitImplementation(capability, implementation) {
2249
2422
  return resolveImplementation(implementation) === null;
2250
2423
  }
2251
2424
  function listBuiltinCapabilityActions(root = getBuiltinCapabilitiesRoot()) {
2252
- if (!fs6.existsSync(root) || !fs6.statSync(root).isDirectory()) return [];
2425
+ if (!fs8.existsSync(root) || !fs8.statSync(root).isDirectory()) return [];
2253
2426
  const out = [];
2254
2427
  for (const slug of listCapabilityFolderSlugs(root)) {
2255
2428
  if (!isSafeName(slug)) continue;
@@ -2274,7 +2447,7 @@ function getProfileInputs(name, roots = getImplementationRoots()) {
2274
2447
  const profilePath = resolveImplementation(name, roots);
2275
2448
  if (!profilePath) return null;
2276
2449
  try {
2277
- const document = JSON.parse(fs6.readFileSync(profilePath, "utf-8"));
2450
+ const document = JSON.parse(fs8.readFileSync(profilePath, "utf-8"));
2278
2451
  if (!document || typeof document !== "object") return [];
2279
2452
  const raw = "config" in document && document.config && typeof document.config === "object" ? document.config : document;
2280
2453
  if (!Array.isArray(raw.inputs)) return [];
@@ -3312,8 +3485,8 @@ var init_capabilityMcp = __esm({
3312
3485
 
3313
3486
  // src/repoWorkspace.ts
3314
3487
  import { spawn as spawn2, spawnSync } from "child_process";
3315
- import * as fs7 from "fs";
3316
- import * as path8 from "path";
3488
+ import * as fs9 from "fs";
3489
+ import * as path10 from "path";
3317
3490
  function buildCloneProcess(repo, token, baseEnv = process.env) {
3318
3491
  const url = `https://github.com/${repo}.git`;
3319
3492
  const env = { ...baseEnv };
@@ -3328,10 +3501,10 @@ function buildCloneProcess(repo, token, baseEnv = process.env) {
3328
3501
  async function resolveAndClone(reposRoot, repo, repoToken, cloneRepo) {
3329
3502
  const name = repo?.trim();
3330
3503
  if (!name || !REPO_RE.test(name)) return null;
3331
- const root = path8.resolve(reposRoot);
3332
- const dir = path8.resolve(root, name);
3333
- if (dir !== root && !dir.startsWith(root + path8.sep)) return null;
3334
- if (fs7.existsSync(path8.join(dir, ".git"))) return dir;
3504
+ const root = path10.resolve(reposRoot);
3505
+ const dir = path10.resolve(root, name);
3506
+ if (dir !== root && !dir.startsWith(root + path10.sep)) return null;
3507
+ if (fs9.existsSync(path10.join(dir, ".git"))) return dir;
3335
3508
  const inflight = repoClones.get(dir);
3336
3509
  if (inflight) {
3337
3510
  await inflight;
@@ -3363,7 +3536,7 @@ var init_repoWorkspace = __esm({
3363
3536
  repoClones = /* @__PURE__ */ new Map();
3364
3537
  GIT_CREDENTIAL_HELPER = `!f() { if [ "$1" = get ] && [ -n "$GITHUB_TOKEN" ]; then printf '%s\\n' username=x-access-token "password=$GITHUB_TOKEN"; fi; }; f`;
3365
3538
  defaultCloneRepo = (repo, token, dir) => {
3366
- fs7.mkdirSync(path8.dirname(dir), { recursive: true });
3539
+ fs9.mkdirSync(path10.dirname(dir), { recursive: true });
3367
3540
  const clone = buildCloneProcess(repo, token);
3368
3541
  return new Promise((resolve19, reject) => {
3369
3542
  const child = spawn2("git", ["clone", "--depth=1", clone.url, dir], {
@@ -3457,8 +3630,8 @@ var init_fetchRepoMcp = __esm({
3457
3630
  });
3458
3631
 
3459
3632
  // src/agent.ts
3460
- import * as fs8 from "fs";
3461
- import * as path9 from "path";
3633
+ import * as fs10 from "fs";
3634
+ import * as path11 from "path";
3462
3635
  import { query } from "@anthropic-ai/claude-agent-sdk";
3463
3636
  function classifySubtype(subtype) {
3464
3637
  if (!subtype) return "generic_failed";
@@ -3527,8 +3700,8 @@ function buildAgentEnvironment(baseEnv, repoToken, requestEnvironment) {
3527
3700
  }
3528
3701
  async function runAgent(opts) {
3529
3702
  const ndjsonDir = opts.ndjsonDir ?? agentRunDir(opts.cwd);
3530
- fs8.mkdirSync(ndjsonDir, { recursive: true });
3531
- const ndjsonPath = path9.join(ndjsonDir, "last-run.jsonl");
3703
+ fs10.mkdirSync(ndjsonDir, { recursive: true });
3704
+ const ndjsonPath = path11.join(ndjsonDir, "last-run.jsonl");
3532
3705
  const env = buildAgentEnvironment(process.env, opts.repoToken, opts.environment);
3533
3706
  if (opts.litellmUrl) {
3534
3707
  env.ANTHROPIC_BASE_URL = opts.litellmUrl;
@@ -3547,7 +3720,7 @@ async function runAgent(opts) {
3547
3720
  for (let attempt = 0; ; attempt++) {
3548
3721
  let ndjsonWriteFailed = false;
3549
3722
  let ndjsonWriteError;
3550
- const fullLog = fs8.createWriteStream(ndjsonPath, { flags: "w" });
3723
+ const fullLog = fs10.createWriteStream(ndjsonPath, { flags: "w" });
3551
3724
  fullLog.on("error", (err) => {
3552
3725
  ndjsonWriteFailed = true;
3553
3726
  ndjsonWriteError = err instanceof Error ? err.message : String(err);
@@ -3571,7 +3744,15 @@ async function runAgent(opts) {
3571
3744
  // opt-in tools like fetch_repo can be appended below.
3572
3745
  allowedTools: [...opts.allowedToolsOverride ?? DEFAULT_ALLOWED_TOOLS],
3573
3746
  permissionMode: opts.permissionModeOverride ?? "acceptEdits",
3574
- env
3747
+ env,
3748
+ hooks: {
3749
+ PreToolUse: [
3750
+ {
3751
+ matcher: "Agent",
3752
+ hooks: [enforceSubagentModelInheritance]
3753
+ }
3754
+ ]
3755
+ }
3575
3756
  };
3576
3757
  const additionalDirectories = new Set(opts.additionalDirectories ?? []);
3577
3758
  const mcpEntries = [];
@@ -3902,6 +4083,7 @@ var init_agent = __esm({
3902
4083
  init_config();
3903
4084
  init_format();
3904
4085
  init_runtimePaths();
4086
+ init_subagents();
3905
4087
  DEFAULT_ALLOWED_TOOLS = ["Bash", "Edit", "Read", "Write", "Glob", "Grep"];
3906
4088
  DEFAULT_TURN_TIMEOUT_MS = 6e5;
3907
4089
  MAX_CONNECTION_RETRIES = 2;
@@ -3920,8 +4102,8 @@ var init_agent = __esm({
3920
4102
  });
3921
4103
 
3922
4104
  // src/agents.ts
3923
- import * as fs9 from "fs";
3924
- import * as path10 from "path";
4105
+ import * as fs11 from "fs";
4106
+ import * as path12 from "path";
3925
4107
  function stripFrontmatter(raw) {
3926
4108
  const match = /^---\n[\s\S]*?\n---\n?([\s\S]*)$/.exec(raw);
3927
4109
  return (match ? match[1] : raw).trim();
@@ -3929,9 +4111,9 @@ function stripFrontmatter(raw) {
3929
4111
  function loadAgentIdentity(cwd, slug, agentsDir = agentsRoot(cwd)) {
3930
4112
  const trimmed = slug.trim();
3931
4113
  if (!trimmed) throw new Error("loadAgentIdentity: empty agent slug");
3932
- const agentPath = resolveAgentFile(cwd, trimmed, agentsDir);
3933
- if (fs9.existsSync(agentPath)) {
3934
- const body = stripFrontmatter(fs9.readFileSync(agentPath, "utf-8"));
4114
+ const agentPath = resolveAgentFile2(cwd, trimmed, agentsDir);
4115
+ if (fs11.existsSync(agentPath)) {
4116
+ const body = stripFrontmatter(fs11.readFileSync(agentPath, "utf-8"));
3935
4117
  if (body) return body;
3936
4118
  const builtinForEmpty = BUILTIN_AGENTS[trimmed];
3937
4119
  if (builtinForEmpty) return builtinForEmpty;
@@ -3941,9 +4123,9 @@ function loadAgentIdentity(cwd, slug, agentsDir = agentsRoot(cwd)) {
3941
4123
  if (builtin) return builtin;
3942
4124
  throw new Error(`loadAgentIdentity: agent '${trimmed}' declared but ${agentPath} does not exist`);
3943
4125
  }
3944
- function resolveAgentFile(cwd, slug, agentsDir = agentsRoot(cwd)) {
3945
- const localPath = path10.resolve(cwd, agentsDir, `${slug}.md`);
3946
- if (fs9.existsSync(localPath)) return localPath;
4126
+ function resolveAgentFile2(cwd, slug, agentsDir = agentsRoot(cwd)) {
4127
+ const localPath = path12.resolve(cwd, agentsDir, `${slug}.md`);
4128
+ if (fs11.existsSync(localPath)) return localPath;
3947
4129
  return localPath;
3948
4130
  }
3949
4131
  function frameAgentIdentity(slug, agent) {
@@ -3975,14 +4157,14 @@ var init_agents = __esm({
3975
4157
  });
3976
4158
 
3977
4159
  // src/task-artifacts.ts
3978
- import fs10 from "fs";
3979
- import path11 from "path";
4160
+ import fs12 from "fs";
4161
+ import path13 from "path";
3980
4162
  import posixPath from "path/posix";
3981
4163
  function prepareTaskArtifactsDir(cwd, taskId) {
3982
4164
  const safeId = String(taskId).replace(/[^a-zA-Z0-9._-]/g, "_");
3983
4165
  const absDir = runtimeStatePath(cwd, "task-artifacts", safeId);
3984
4166
  const relDir = absDir;
3985
- fs10.mkdirSync(absDir, { recursive: true });
4167
+ fs12.mkdirSync(absDir, { recursive: true });
3986
4168
  return { taskId: safeId, absDir, relDir };
3987
4169
  }
3988
4170
  function initializeTaskArtifacts(artifacts, metadata = { taskType: "job" }) {
@@ -4012,16 +4194,16 @@ function initializeTaskArtifacts(artifacts, metadata = { taskType: "job" }) {
4012
4194
  "handoff-notes.md": "Baseline handoff: the agent did not provide additional notes.\n"
4013
4195
  };
4014
4196
  for (const file of TASK_ARTIFACT_FILES) {
4015
- const full = path11.join(artifacts.absDir, file);
4016
- if (!fs10.existsSync(full)) fs10.writeFileSync(full, defaults[file], "utf8");
4197
+ const full = path13.join(artifacts.absDir, file);
4198
+ if (!fs12.existsSync(full)) fs12.writeFileSync(full, defaults[file], "utf8");
4017
4199
  }
4018
4200
  }
4019
4201
  function verifyTaskArtifacts(absDir) {
4020
4202
  const missing = [];
4021
4203
  for (const name of TASK_ARTIFACT_FILES) {
4022
- const full = path11.join(absDir, name);
4204
+ const full = path13.join(absDir, name);
4023
4205
  try {
4024
- const stat = fs10.statSync(full);
4206
+ const stat = fs12.statSync(full);
4025
4207
  if (!stat.isFile() || stat.size === 0) missing.push(name);
4026
4208
  } catch {
4027
4209
  missing.push(name);
@@ -4037,11 +4219,11 @@ async function persistTaskArtifactsToState(config, _cwd, artifacts) {
4037
4219
  if (hasStateBackendConfig() && tenantId2) {
4038
4220
  const backend = createStateBackendFromEnv();
4039
4221
  for (const file of TASK_ARTIFACT_FILES) {
4040
- const full = path11.join(artifacts.absDir, file);
4041
- if (!fs10.existsSync(full)) continue;
4042
- const stat = fs10.statSync(full);
4222
+ const full = path13.join(artifacts.absDir, file);
4223
+ if (!fs12.existsSync(full)) continue;
4224
+ const stat = fs12.statSync(full);
4043
4225
  if (!stat.isFile() || stat.size === 0) continue;
4044
- const content = fs10.readFileSync(full, "utf-8");
4226
+ const content = fs12.readFileSync(full, "utf-8");
4045
4227
  const kind = file.replace(/\.(json|md)$/, "");
4046
4228
  let doc = content;
4047
4229
  if (file.endsWith(".json")) {
@@ -4402,8 +4584,8 @@ var init_workflowValidation = __esm({
4402
4584
  });
4403
4585
 
4404
4586
  // src/workflowDefinitions.ts
4405
- import * as fs16 from "fs";
4406
- import * as path17 from "path";
4587
+ import * as fs18 from "fs";
4588
+ import * as path19 from "path";
4407
4589
  function isWorkflowDefinitionId(value) {
4408
4590
  return WORKFLOW_ID_PATTERN.test(value);
4409
4591
  }
@@ -4446,12 +4628,12 @@ function readWorkflowDefinition(_config, cwd, id) {
4446
4628
  const root = cwd ?? process.cwd();
4447
4629
  const relativePath = workflowDefinitionPath(id);
4448
4630
  const candidates = [
4449
- path17.join(root, ".kody-engine", "runtime", relativePath),
4450
- path17.join(definitionsRoot(root), relativePath)
4631
+ path19.join(root, ".kody-engine", "runtime", relativePath),
4632
+ path19.join(definitionsRoot(root), relativePath)
4451
4633
  ];
4452
4634
  for (const filePath of candidates) {
4453
- if (!fs16.existsSync(filePath)) continue;
4454
- const workflow = parseWorkflowDefinition(fs16.readFileSync(filePath, "utf8"));
4635
+ if (!fs18.existsSync(filePath)) continue;
4636
+ const workflow = parseWorkflowDefinition(fs18.readFileSync(filePath, "utf8"));
4455
4637
  if (workflow) return workflow;
4456
4638
  }
4457
4639
  return null;
@@ -4459,7 +4641,7 @@ function readWorkflowDefinition(_config, cwd, id) {
4459
4641
  function workflowDefinitionToCapabilityFolder(id, workflow, source = workflowDefinitionPath(id)) {
4460
4642
  return {
4461
4643
  slug: id,
4462
- dir: path17.dirname(source),
4644
+ dir: path19.dirname(source),
4463
4645
  profilePath: source,
4464
4646
  bodyPath: source,
4465
4647
  title: workflow.name,
@@ -4514,7 +4696,7 @@ var init_workflowDefinitions = __esm({
4514
4696
 
4515
4697
  // src/gha.ts
4516
4698
  import { execFileSync as execFileSync2 } from "child_process";
4517
- import * as fs19 from "fs";
4699
+ import * as fs21 from "fs";
4518
4700
  function getRunUrl() {
4519
4701
  const server = process.env.GITHUB_SERVER_URL;
4520
4702
  const repo = process.env.GITHUB_REPOSITORY;
@@ -4525,10 +4707,10 @@ function getRunUrl() {
4525
4707
  function reactToTriggerComment(cwd) {
4526
4708
  if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
4527
4709
  const eventPath = process.env.GITHUB_EVENT_PATH;
4528
- if (!eventPath || !fs19.existsSync(eventPath)) return;
4710
+ if (!eventPath || !fs21.existsSync(eventPath)) return;
4529
4711
  let event = null;
4530
4712
  try {
4531
- event = JSON.parse(fs19.readFileSync(eventPath, "utf-8"));
4713
+ event = JSON.parse(fs21.readFileSync(eventPath, "utf-8"));
4532
4714
  } catch {
4533
4715
  return;
4534
4716
  }
@@ -5109,166 +5291,6 @@ var init_lifecycles = __esm({
5109
5291
  }
5110
5292
  });
5111
5293
 
5112
- // src/scripts/buildSyntheticPlugin.ts
5113
- import * as fs20 from "fs";
5114
- import * as os3 from "os";
5115
- import * as path19 from "path";
5116
- function getPluginsCatalogRoot() {
5117
- const here = path19.dirname(new URL(import.meta.url).pathname);
5118
- const candidates = [
5119
- path19.join(here, "..", "plugins"),
5120
- // dev: src/scripts → src/plugins
5121
- path19.join(here, "..", "..", "plugins"),
5122
- // built: dist/scripts → dist/plugins
5123
- path19.join(here, "..", "..", "src", "plugins")
5124
- // fallback
5125
- ];
5126
- for (const c of candidates) {
5127
- if (fs20.existsSync(c) && fs20.statSync(c).isDirectory()) return c;
5128
- }
5129
- return candidates[0];
5130
- }
5131
- function copyDir(src, dst) {
5132
- fs20.mkdirSync(dst, { recursive: true });
5133
- for (const ent of fs20.readdirSync(src, { withFileTypes: true })) {
5134
- const s = path19.join(src, ent.name);
5135
- const d = path19.join(dst, ent.name);
5136
- if (ent.isDirectory()) copyDir(s, d);
5137
- else if (ent.isFile()) fs20.copyFileSync(s, d);
5138
- }
5139
- }
5140
- var buildSyntheticPlugin;
5141
- var init_buildSyntheticPlugin = __esm({
5142
- "src/scripts/buildSyntheticPlugin.ts"() {
5143
- "use strict";
5144
- buildSyntheticPlugin = async (ctx, profile) => {
5145
- const cc = profile.claudeCode;
5146
- const needsSynthetic = cc.skills.length > 0 || cc.commands.length > 0 || cc.hooks.length > 0;
5147
- if (!needsSynthetic) return;
5148
- const catalog = getPluginsCatalogRoot();
5149
- const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
5150
- const root = path19.join(os3.tmpdir(), `kody-synth-${runId}`);
5151
- fs20.mkdirSync(path19.join(root, ".claude-plugin"), { recursive: true });
5152
- const resolvePart = (bucket, entry) => {
5153
- const local = path19.join(profile.dir, bucket, entry);
5154
- if (fs20.existsSync(local)) return local;
5155
- const shared = path19.resolve(profile.dir, "..", "..", "shared", bucket, entry);
5156
- if (fs20.existsSync(shared)) return shared;
5157
- const central = path19.join(catalog, bucket, entry);
5158
- if (fs20.existsSync(central)) return central;
5159
- throw new Error(
5160
- `buildSyntheticPlugin: ${bucket} entry '${entry}' not found in implementation dir (${profile.dir}/${bucket}/), Store shared assets (${path19.dirname(shared)}/), or catalog (${catalog}/${bucket}/)`
5161
- );
5162
- };
5163
- if (cc.skills.length > 0) {
5164
- const dst = path19.join(root, "skills");
5165
- fs20.mkdirSync(dst, { recursive: true });
5166
- for (const name of cc.skills) {
5167
- copyDir(resolvePart("skills", name), path19.join(dst, name));
5168
- }
5169
- }
5170
- if (cc.commands.length > 0) {
5171
- const dst = path19.join(root, "commands");
5172
- fs20.mkdirSync(dst, { recursive: true });
5173
- for (const name of cc.commands) {
5174
- fs20.copyFileSync(resolvePart("commands", `${name}.md`), path19.join(dst, `${name}.md`));
5175
- }
5176
- }
5177
- if (cc.hooks.length > 0) {
5178
- const dst = path19.join(root, "hooks");
5179
- fs20.mkdirSync(dst, { recursive: true });
5180
- const merged = { hooks: {} };
5181
- for (const name of cc.hooks) {
5182
- const src = resolvePart("hooks", `${name}.json`);
5183
- const parsed = JSON.parse(fs20.readFileSync(src, "utf-8"));
5184
- for (const [event, entries] of Object.entries(parsed.hooks ?? {})) {
5185
- if (!Array.isArray(entries)) continue;
5186
- if (!merged.hooks[event]) merged.hooks[event] = [];
5187
- merged.hooks[event].push(...entries);
5188
- }
5189
- }
5190
- fs20.writeFileSync(path19.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
5191
- `);
5192
- }
5193
- const manifest = {
5194
- name: `kody-synth-${profile.name}`,
5195
- version: "1.0.0",
5196
- description: `Synthetic plugin assembled by Kody for profile '${profile.name}' at runtime.`
5197
- };
5198
- if (cc.skills.length > 0) manifest.skills = ["./skills/"];
5199
- if (cc.commands.length > 0) manifest.commands = ["./commands/"];
5200
- fs20.writeFileSync(path19.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
5201
- `);
5202
- ctx.data.syntheticPluginPath = root;
5203
- };
5204
- }
5205
- });
5206
-
5207
- // src/subagents.ts
5208
- import * as fs21 from "fs";
5209
- import * as path20 from "path";
5210
- function splitFrontmatter(raw) {
5211
- const match = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(raw);
5212
- if (!match) return { fm: {}, body: raw.trim() };
5213
- const fm = {};
5214
- for (const line of match[1].split("\n")) {
5215
- const idx = line.indexOf(":");
5216
- if (idx === -1) continue;
5217
- fm[line.slice(0, idx).trim()] = line.slice(idx + 1).trim();
5218
- }
5219
- return { fm, body: (match[2] ?? "").trim() };
5220
- }
5221
- function resolveAgentFile2(profileDir, name) {
5222
- const local = path20.join(profileDir, "agents", `${name}.md`);
5223
- if (fs21.existsSync(local)) return local;
5224
- const shared = path20.resolve(profileDir, "..", "..", "shared", "agents", `${name}.md`);
5225
- if (fs21.existsSync(shared)) return shared;
5226
- const central = path20.join(getPluginsCatalogRoot(), "agents", `${name}.md`);
5227
- if (fs21.existsSync(central)) return central;
5228
- throw new Error(
5229
- `loadSubagents: agent '${name}' not found in ${profileDir}/agents/, hydrated shared assets, or engine catalog`
5230
- );
5231
- }
5232
- function captureSubagentTemplates(profile) {
5233
- const names = profile.claudeCode.subagents;
5234
- if (!names || names.length === 0) return {};
5235
- const out = {};
5236
- for (const name of names) {
5237
- try {
5238
- out[name] = fs21.readFileSync(resolveAgentFile2(profile.dir, name), "utf-8");
5239
- } catch {
5240
- }
5241
- }
5242
- return out;
5243
- }
5244
- function loadSubagents(profile) {
5245
- const names = profile.claudeCode.subagents;
5246
- if (!names || names.length === 0) return void 0;
5247
- const agents = {};
5248
- for (const name of names) {
5249
- const raw = profile.subagentTemplates?.[name] ?? fs21.readFileSync(resolveAgentFile2(profile.dir, name), "utf-8");
5250
- const { fm, body } = splitFrontmatter(raw);
5251
- if (!body) throw new Error(`loadSubagents: agent '${name}' has an empty prompt body`);
5252
- const def = {
5253
- description: fm.description ?? `Subagent ${name}`,
5254
- prompt: body
5255
- };
5256
- if (fm.tools) {
5257
- const tools = fm.tools.split(",").map((t) => t.trim()).filter(Boolean);
5258
- if (tools.length > 0) def.tools = tools;
5259
- }
5260
- if (fm.model) def.model = fm.model;
5261
- agents[fm.name || name] = def;
5262
- }
5263
- return agents;
5264
- }
5265
- var init_subagents = __esm({
5266
- "src/subagents.ts"() {
5267
- "use strict";
5268
- init_buildSyntheticPlugin();
5269
- }
5270
- });
5271
-
5272
5294
  // src/profile.ts
5273
5295
  import { createHash as createHash3 } from "crypto";
5274
5296
  import * as fs22 from "fs";
@@ -15014,7 +15036,7 @@ var init_loadAgentAdhoc = __esm({
15014
15036
  if (!agentSlug) {
15015
15037
  throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
15016
15038
  }
15017
- const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
15039
+ const agentPath = resolveAgentFile2(ctx.cwd, agentSlug, agentsDir);
15018
15040
  if (!fs39.existsSync(agentPath)) {
15019
15041
  throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
15020
15042
  }
@@ -15439,7 +15461,7 @@ var init_loadJobFromFile = __esm({
15439
15461
  let agentTitle = "";
15440
15462
  let agentIdentity = "";
15441
15463
  if (agentSlug) {
15442
- const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
15464
+ const agentPath = resolveAgentFile2(ctx.cwd, agentSlug, agentsDir);
15443
15465
  if (!fs40.existsSync(agentPath)) {
15444
15466
  throw new Error(
15445
15467
  `loadJobFromFile: capability '${slug}' declares agent '${agentSlug}' but ${agentPath} does not exist`
@@ -22991,13 +23013,13 @@ init_agents();
22991
23013
  init_config();
22992
23014
  init_registry();
22993
23015
  init_task_artifacts();
22994
- import * as fs14 from "fs";
22995
- import * as path15 from "path";
23016
+ import * as fs16 from "fs";
23017
+ import * as path17 from "path";
22996
23018
 
22997
23019
  // src/chat/attachments.ts
22998
23020
  init_runtimePaths();
22999
- import * as fs11 from "fs";
23000
- import * as path12 from "path";
23021
+ import * as fs13 from "fs";
23022
+ import * as path14 from "path";
23001
23023
  var INLINE_ATTACHMENT_RE = /(?:\[(?:Image|File): ([^\]]*)\]\n)?data:([\w.+-]+\/[\w.+-]+);base64,([A-Za-z0-9+/=]+)/g;
23002
23024
  var EXT_BY_MIME = {
23003
23025
  "image/png": "png",
@@ -23030,11 +23052,11 @@ function prepareAttachments(turns, cwd, sessionId) {
23030
23052
  if (!isImage) return `[File: ${name}]`;
23031
23053
  try {
23032
23054
  if (!dirEnsured) {
23033
- fs11.mkdirSync(dir, { recursive: true });
23055
+ fs13.mkdirSync(dir, { recursive: true });
23034
23056
  dirEnsured = true;
23035
23057
  }
23036
- const filePath = path12.join(dir, `${imageCounter}.${extFor(mime)}`);
23037
- fs11.writeFileSync(filePath, Buffer.from(data, "base64"));
23058
+ const filePath = path14.join(dir, `${imageCounter}.${extFor(mime)}`);
23059
+ fs13.writeFileSync(filePath, Buffer.from(data, "base64"));
23038
23060
  imageCounter += 1;
23039
23061
  imagePaths.push(filePath);
23040
23062
  return `[Image "${name}" is attached \u2014 saved to ${filePath}. Use the Read tool on that exact path to view it.]`;
@@ -23051,8 +23073,8 @@ function prepareAttachments(turns, cwd, sessionId) {
23051
23073
 
23052
23074
  // src/chat/codex-app-server.ts
23053
23075
  import { spawn as spawn3 } from "child_process";
23054
- import * as fs12 from "fs";
23055
- import * as path13 from "path";
23076
+ import * as fs14 from "fs";
23077
+ import * as path15 from "path";
23056
23078
  import { createInterface } from "readline";
23057
23079
  function codexThreadStartParams(args) {
23058
23080
  return {
@@ -23223,11 +23245,11 @@ var CodexAppServerClient = class {
23223
23245
  };
23224
23246
  var clients = /* @__PURE__ */ new Map();
23225
23247
  function threadMapPath(cwd) {
23226
- return path13.join(cwd, ".kody-engine", "runtime", "codex-threads.json");
23248
+ return path15.join(cwd, ".kody-engine", "runtime", "codex-threads.json");
23227
23249
  }
23228
23250
  function readThreadMap(cwd) {
23229
23251
  try {
23230
- const value = JSON.parse(fs12.readFileSync(threadMapPath(cwd), "utf8"));
23252
+ const value = JSON.parse(fs14.readFileSync(threadMapPath(cwd), "utf8"));
23231
23253
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
23232
23254
  return Object.fromEntries(
23233
23255
  Object.entries(value).filter(
@@ -23240,8 +23262,8 @@ function readThreadMap(cwd) {
23240
23262
  }
23241
23263
  function writeThreadMap(cwd, map) {
23242
23264
  const file = threadMapPath(cwd);
23243
- fs12.mkdirSync(path13.dirname(file), { recursive: true });
23244
- fs12.writeFileSync(file, `${JSON.stringify(map, null, 2)}
23265
+ fs14.mkdirSync(path15.dirname(file), { recursive: true });
23266
+ fs14.writeFileSync(file, `${JSON.stringify(map, null, 2)}
23245
23267
  `);
23246
23268
  }
23247
23269
  async function runCodexChatTurn(args) {
@@ -23331,8 +23353,8 @@ async function runCodexChatTurn(args) {
23331
23353
  }
23332
23354
 
23333
23355
  // src/chat/events.ts
23334
- import * as fs13 from "fs";
23335
- import * as path14 from "path";
23356
+ import * as fs15 from "fs";
23357
+ import * as path16 from "path";
23336
23358
  import posixPath2 from "path/posix";
23337
23359
  var BackendEventSink = class {
23338
23360
  constructor(append, tenantId2, sessionId) {
@@ -23348,7 +23370,7 @@ var BackendEventSink = class {
23348
23370
  }
23349
23371
  };
23350
23372
  function eventsFilePath(cwd, sessionId) {
23351
- return path14.join(cwd, ".kody-engine", "runtime", "events", `${sessionId}.jsonl`);
23373
+ return path16.join(cwd, ".kody-engine", "runtime", "events", `${sessionId}.jsonl`);
23352
23374
  }
23353
23375
  var FileSink = class {
23354
23376
  constructor(file) {
@@ -23356,8 +23378,8 @@ var FileSink = class {
23356
23378
  }
23357
23379
  file;
23358
23380
  async emit(event) {
23359
- fs13.mkdirSync(path14.dirname(this.file), { recursive: true });
23360
- fs13.appendFileSync(this.file, `${JSON.stringify(event)}
23381
+ fs15.mkdirSync(path16.dirname(this.file), { recursive: true });
23382
+ fs15.appendFileSync(this.file, `${JSON.stringify(event)}
23361
23383
  `);
23362
23384
  }
23363
23385
  };
@@ -23600,7 +23622,7 @@ function buildImplementationCatalog() {
23600
23622
  const entries = [];
23601
23623
  for (const { name, profilePath } of discovered) {
23602
23624
  try {
23603
- const raw = JSON.parse(fs14.readFileSync(profilePath, "utf-8"));
23625
+ const raw = JSON.parse(fs16.readFileSync(profilePath, "utf-8"));
23604
23626
  const describe = typeof raw.describe === "string" ? raw.describe : "";
23605
23627
  const firstSentence = describe.split(/(?<=[.!?])\s+/, 1)[0] ?? "";
23606
23628
  entries.push({ name, describe: firstSentence.trim() });
@@ -23708,7 +23730,7 @@ async function runChatTurn(opts) {
23708
23730
  quiet: opts.quiet,
23709
23731
  additionalDirectories: [
23710
23732
  taskArtifactsPaths.absDir,
23711
- ...Array.from(new Set(imagePaths.map((p2) => path15.dirname(p2))))
23733
+ ...Array.from(new Set(imagePaths.map((p2) => path17.dirname(p2))))
23712
23734
  ],
23713
23735
  systemPromptAppend: systemPrompt,
23714
23736
  ...opts.reasoningEffort ? { reasoningEffort: opts.reasoningEffort } : {},
@@ -23892,10 +23914,10 @@ async function emit(sink, type, sessionId, suffix, payload) {
23892
23914
  var MEMORY_INDEX_REL = ".kody-engine/runtime/memory/INDEX.md";
23893
23915
  var MAX_INDEX_BYTES = 8e3;
23894
23916
  function readMemoryIndexBlock(cwd) {
23895
- const indexPath = path15.join(cwd, MEMORY_INDEX_REL);
23917
+ const indexPath = path17.join(cwd, MEMORY_INDEX_REL);
23896
23918
  let raw;
23897
23919
  try {
23898
- raw = fs14.readFileSync(indexPath, "utf-8");
23920
+ raw = fs16.readFileSync(indexPath, "utf-8");
23899
23921
  } catch {
23900
23922
  return "";
23901
23923
  }
@@ -23915,17 +23937,17 @@ _\u2026 (memory index truncated; use recall_search to read more)_` : trimmed;
23915
23937
  var CONTEXT_DIR_REL = ".kody-engine/runtime/context";
23916
23938
  var MAX_CONTEXT_BYTES = 12e3;
23917
23939
  function readContextBlock(cwd) {
23918
- const dir = path15.join(cwd, CONTEXT_DIR_REL);
23940
+ const dir = path17.join(cwd, CONTEXT_DIR_REL);
23919
23941
  let files;
23920
23942
  try {
23921
- files = fs14.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
23943
+ files = fs16.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
23922
23944
  } catch {
23923
23945
  return "";
23924
23946
  }
23925
23947
  const sections = [];
23926
23948
  for (const file of files) {
23927
23949
  try {
23928
- const content = fs14.readFileSync(path15.join(dir, file), "utf-8").trim();
23950
+ const content = fs16.readFileSync(path17.join(dir, file), "utf-8").trim();
23929
23951
  if (content) sections.push(`### ${file.replace(/\.md$/, "")}
23930
23952
 
23931
23953
  ${content}`);
@@ -23951,7 +23973,7 @@ var SYSTEM_PROMPT_OVERRIDE_REL = ".kody-engine/runtime/system-prompt.md";
23951
23973
  function readSystemPromptOverride(cwd) {
23952
23974
  let raw;
23953
23975
  try {
23954
- raw = fs14.readFileSync(path15.join(cwd, SYSTEM_PROMPT_OVERRIDE_REL), "utf-8");
23976
+ raw = fs16.readFileSync(path17.join(cwd, SYSTEM_PROMPT_OVERRIDE_REL), "utf-8");
23955
23977
  } catch {
23956
23978
  return null;
23957
23979
  }
@@ -23959,10 +23981,10 @@ function readSystemPromptOverride(cwd) {
23959
23981
  return trimmed.length > 0 ? trimmed : null;
23960
23982
  }
23961
23983
  function readInstructionsBlock(cwd) {
23962
- const instructionsPath = path15.join(cwd, INSTRUCTIONS_REL);
23984
+ const instructionsPath = path17.join(cwd, INSTRUCTIONS_REL);
23963
23985
  let raw;
23964
23986
  try {
23965
- raw = fs14.readFileSync(instructionsPath, "utf-8");
23987
+ raw = fs16.readFileSync(instructionsPath, "utf-8");
23966
23988
  } catch {
23967
23989
  return "";
23968
23990
  }
@@ -23996,15 +24018,15 @@ function resolveBrainDriver(runtime) {
23996
24018
  }
23997
24019
 
23998
24020
  // src/chat/session.ts
23999
- import * as fs15 from "fs";
24000
- import * as path16 from "path";
24021
+ import * as fs17 from "fs";
24022
+ import * as path18 from "path";
24001
24023
  import posixPath3 from "path/posix";
24002
24024
  function sessionFilePath(cwd, sessionId) {
24003
- return path16.join(cwd, ".kody-engine", "runtime", "sessions", `${sessionId}.jsonl`);
24025
+ return path18.join(cwd, ".kody-engine", "runtime", "sessions", `${sessionId}.jsonl`);
24004
24026
  }
24005
24027
  function readSession(file) {
24006
- if (!fs15.existsSync(file)) return [];
24007
- const raw = fs15.readFileSync(file, "utf-8").trim();
24028
+ if (!fs17.existsSync(file)) return [];
24029
+ const raw = fs17.readFileSync(file, "utf-8").trim();
24008
24030
  if (!raw) return [];
24009
24031
  const turns = [];
24010
24032
  for (const line of raw.split("\n")) {
@@ -24027,8 +24049,8 @@ init_config();
24027
24049
  init_state_backend();
24028
24050
  init_workflowDefinitions();
24029
24051
  import { createHash as createHash2 } from "crypto";
24030
- import * as fs17 from "fs";
24031
- import * as path18 from "path";
24052
+ import * as fs19 from "fs";
24053
+ import * as path20 from "path";
24032
24054
  var SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,127}$/;
24033
24055
  var REPOSITORY_OWNED_NAMESPACES = ["loops"];
24034
24056
  function assertSafeDefinitionPath(filePath) {
@@ -24060,9 +24082,9 @@ function verifyDefinition(definition) {
24060
24082
  }
24061
24083
  function writeBundle(root, bundle) {
24062
24084
  for (const [filePath, contents] of Object.entries(bundle.files)) {
24063
- const target = path18.join(root, filePath);
24064
- fs17.mkdirSync(path18.dirname(target), { recursive: true });
24065
- fs17.writeFileSync(target, contents, "utf8");
24085
+ const target = path20.join(root, filePath);
24086
+ fs19.mkdirSync(path20.dirname(target), { recursive: true });
24087
+ fs19.writeFileSync(target, contents, "utf8");
24066
24088
  }
24067
24089
  }
24068
24090
  function writeDefinition(root, kind, definition) {
@@ -24070,22 +24092,22 @@ function writeDefinition(root, kind, definition) {
24070
24092
  if (kind === "agent") {
24071
24093
  const raw = bundle.files["agent.md"];
24072
24094
  if (typeof raw !== "string") throw new Error(`agent definition ${definition.slug} is missing agent.md`);
24073
- fs17.writeFileSync(path18.join(root, "agents", `${definition.slug}.md`), raw, "utf8");
24095
+ fs19.writeFileSync(path20.join(root, "agents", `${definition.slug}.md`), raw, "utf8");
24074
24096
  return;
24075
24097
  }
24076
24098
  if (kind === "goal") {
24077
- writeBundle(path18.join(root, "goals", definition.slug), bundle);
24099
+ writeBundle(path20.join(root, "goals", definition.slug), bundle);
24078
24100
  return;
24079
24101
  }
24080
24102
  if (kind === "implementation") {
24081
- writeBundle(path18.join(root, "implementations", definition.slug), bundle);
24103
+ writeBundle(path20.join(root, "implementations", definition.slug), bundle);
24082
24104
  return;
24083
24105
  }
24084
24106
  if (kind === "asset") {
24085
- writeBundle(path18.join(root, "shared"), bundle);
24107
+ writeBundle(path20.join(root, "shared"), bundle);
24086
24108
  return;
24087
24109
  }
24088
- writeBundle(path18.join(root, "capabilities", definition.slug), bundle);
24110
+ writeBundle(path20.join(root, "capabilities", definition.slug), bundle);
24089
24111
  }
24090
24112
  function writeWorkflow(root, document) {
24091
24113
  const workflow = normalizeWorkflowDefinition(document.definition);
@@ -24093,28 +24115,28 @@ function writeWorkflow(root, document) {
24093
24115
  const contents = `${JSON.stringify(workflow, null, 2)}
24094
24116
  `;
24095
24117
  const bundle = { schemaVersion: 1, files: { "workflow.json": contents } };
24096
- const target = path18.join(root, workflowDefinitionPath(document.workflowId));
24097
- fs17.mkdirSync(path18.dirname(target), { recursive: true });
24098
- fs17.writeFileSync(target, contents, "utf8");
24118
+ const target = path20.join(root, workflowDefinitionPath(document.workflowId));
24119
+ fs19.mkdirSync(path20.dirname(target), { recursive: true });
24120
+ fs19.writeFileSync(target, contents, "utf8");
24099
24121
  return definitionVersion(bundle);
24100
24122
  }
24101
24123
  function preserveRepositoryDefinitions(root, staging) {
24102
24124
  for (const namespace of REPOSITORY_OWNED_NAMESPACES) {
24103
- const source = path18.join(root, namespace);
24104
- if (!fs17.existsSync(source)) continue;
24105
- fs17.cpSync(source, path18.join(staging, namespace), { recursive: true });
24125
+ const source = path20.join(root, namespace);
24126
+ if (!fs19.existsSync(source)) continue;
24127
+ fs19.cpSync(source, path20.join(staging, namespace), { recursive: true });
24106
24128
  }
24107
24129
  }
24108
24130
  async function hydrateDefinitions(options) {
24109
- const root = path18.join(options.cwd, ".kody-engine", "definitions");
24131
+ const root = path20.join(options.cwd, ".kody-engine", "definitions");
24110
24132
  const staging = `${root}.tmp-${process.pid}-${Date.now()}`;
24111
- fs17.rmSync(staging, { recursive: true, force: true });
24112
- fs17.mkdirSync(path18.join(staging, "agents"), { recursive: true });
24113
- fs17.mkdirSync(path18.join(staging, "capabilities"), { recursive: true });
24114
- fs17.mkdirSync(path18.join(staging, "goals"), { recursive: true });
24115
- fs17.mkdirSync(path18.join(staging, "implementations"), { recursive: true });
24116
- fs17.mkdirSync(path18.join(staging, "shared"), { recursive: true });
24117
- fs17.mkdirSync(path18.join(staging, "workflows"), { recursive: true });
24133
+ fs19.rmSync(staging, { recursive: true, force: true });
24134
+ fs19.mkdirSync(path20.join(staging, "agents"), { recursive: true });
24135
+ fs19.mkdirSync(path20.join(staging, "capabilities"), { recursive: true });
24136
+ fs19.mkdirSync(path20.join(staging, "goals"), { recursive: true });
24137
+ fs19.mkdirSync(path20.join(staging, "implementations"), { recursive: true });
24138
+ fs19.mkdirSync(path20.join(staging, "shared"), { recursive: true });
24139
+ fs19.mkdirSync(path20.join(staging, "workflows"), { recursive: true });
24118
24140
  try {
24119
24141
  const [capabilities, agents, goals, implementations, assets, workflows] = await Promise.all([
24120
24142
  options.backend.listDefinitions(options.tenantId, "capability"),
@@ -24155,13 +24177,13 @@ async function hydrateDefinitions(options) {
24155
24177
  hydratedAt: (/* @__PURE__ */ new Date()).toISOString(),
24156
24178
  versions: Object.fromEntries(Object.entries(versions).sort(([left], [right]) => left.localeCompare(right)))
24157
24179
  };
24158
- fs17.writeFileSync(path18.join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
24180
+ fs19.writeFileSync(path20.join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
24159
24181
  `, "utf8");
24160
- fs17.rmSync(root, { recursive: true, force: true });
24161
- fs17.renameSync(staging, root);
24182
+ fs19.rmSync(root, { recursive: true, force: true });
24183
+ fs19.renameSync(staging, root);
24162
24184
  return { root, tenantId: options.tenantId, versions: manifest.versions };
24163
24185
  } catch (error) {
24164
- fs17.rmSync(staging, { recursive: true, force: true });
24186
+ fs19.rmSync(staging, { recursive: true, force: true });
24165
24187
  throw error;
24166
24188
  }
24167
24189
  }
@@ -24313,7 +24335,7 @@ init_definition_paths();
24313
24335
 
24314
24336
  // src/dispatch.ts
24315
24337
  init_config();
24316
- import * as fs18 from "fs";
24338
+ import * as fs20 from "fs";
24317
24339
 
24318
24340
  // src/cron-match.ts
24319
24341
  var FIELD_BOUNDS = [
@@ -24420,10 +24442,10 @@ function autoDispatch(opts) {
24420
24442
  }
24421
24443
  const eventName = process.env.GITHUB_EVENT_NAME;
24422
24444
  const eventPath = process.env.GITHUB_EVENT_PATH;
24423
- if (!eventName || !eventPath || !fs18.existsSync(eventPath)) return null;
24445
+ if (!eventName || !eventPath || !fs20.existsSync(eventPath)) return null;
24424
24446
  let event = {};
24425
24447
  try {
24426
- event = JSON.parse(fs18.readFileSync(eventPath, "utf-8"));
24448
+ event = JSON.parse(fs20.readFileSync(eventPath, "utf-8"));
24427
24449
  } catch {
24428
24450
  return null;
24429
24451
  }
@@ -24547,7 +24569,7 @@ function autoDispatchTyped(opts) {
24547
24569
  if (legacy) return { kind: "route", ...legacy };
24548
24570
  const eventName = process.env.GITHUB_EVENT_NAME;
24549
24571
  const eventPath = process.env.GITHUB_EVENT_PATH;
24550
- if (!eventName || !eventPath || !fs18.existsSync(eventPath)) {
24572
+ if (!eventName || !eventPath || !fs20.existsSync(eventPath)) {
24551
24573
  return { kind: "silent", reason: "no GHA event context" };
24552
24574
  }
24553
24575
  if (eventName !== "issue_comment") {
@@ -24555,7 +24577,7 @@ function autoDispatchTyped(opts) {
24555
24577
  }
24556
24578
  let event = {};
24557
24579
  try {
24558
- event = JSON.parse(fs18.readFileSync(eventPath, "utf-8"));
24580
+ event = JSON.parse(fs20.readFileSync(eventPath, "utf-8"));
24559
24581
  } catch {
24560
24582
  return { kind: "silent", reason: "GHA event payload unreadable" };
24561
24583
  }
@@ -24609,7 +24631,7 @@ function dispatchScheduledWatches(opts) {
24609
24631
  for (const exe of listRuntimeProfilesForCwd(opts?.cwd ?? process.cwd())) {
24610
24632
  let raw;
24611
24633
  try {
24612
- raw = fs18.readFileSync(exe.profilePath, "utf-8");
24634
+ raw = fs20.readFileSync(exe.profilePath, "utf-8");
24613
24635
  } catch {
24614
24636
  continue;
24615
24637
  }
@@ -28411,7 +28433,9 @@ function envRunRequest(env = process.env) {
28411
28433
  const { target } = parsed.request;
28412
28434
  if (target.type === "chat") return { ...result, command: "chat", chatArgv: [] };
28413
28435
  if (target.type === "issue") return { ...result, command: "ci", ciArgv: ["--issue", String(target.id)] };
28414
- if (target.type === "goal" || target.type === "workflow") return { ...result, command: "ci", ciArgv: [] };
28436
+ if (target.type === "goal" || target.type === "loop" || target.type === "workflow") {
28437
+ return { ...result, command: "ci", ciArgv: [] };
28438
+ }
28415
28439
  return { ...result, errors: [`unsupported runRequest target: ${target.type ?? "unknown"}`] };
28416
28440
  }
28417
28441
  var HELP_TEXT = `kody-engine \u2014 single-session autonomous engineer
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.507",
3
+ "version": "0.4.509",
4
4
  "description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",