@kody-ade/kody-engine 0.4.290 → 0.4.292

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 +136 -68
  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.290",
18
+ version: "0.4.292",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -667,7 +667,7 @@ function parseReasoningEffort(raw) {
667
667
  function parseProviderModel(s) {
668
668
  const slash = s.indexOf("/");
669
669
  if (slash <= 0 || slash === s.length - 1) {
670
- throw new Error(`Invalid model spec '${s}' \u2014 expected 'provider/model' (e.g. 'minimax/MiniMax-M2.7-highspeed')`);
670
+ throw new Error(`Invalid model spec '${s}' \u2014 expected 'provider/model' (e.g. 'minimax/MiniMax-M3')`);
671
671
  }
672
672
  return { provider: s.slice(0, slash), model: s.slice(slash + 1) };
673
673
  }
@@ -710,6 +710,9 @@ function parseModelRuntimeConfig(modelSpec, rawConfig) {
710
710
  if (protocol === "openai") out.litellmProvider = "openai";
711
711
  return out;
712
712
  }
713
+ function litellmModelGroup(model) {
714
+ return model.spec?.trim() || model.model;
715
+ }
713
716
  function providerApiKeyEnvVar(provider) {
714
717
  if (provider === "anthropic" || provider === "claude") return "ANTHROPIC_API_KEY";
715
718
  return `${provider.toUpperCase()}_API_KEY`;
@@ -735,7 +738,7 @@ function loadConfig(projectDir = process.cwd()) {
735
738
  const github = recordValue(raw.github) ?? {};
736
739
  const agent = recordValue(raw.agent) ?? {};
737
740
  if (!agent.model || typeof agent.model !== "string") {
738
- throw new Error(`kody.config.json: agent.model is required (e.g. "minimax/MiniMax-M2.7-highspeed")`);
741
+ throw new Error(`kody.config.json: agent.model is required (e.g. "minimax/MiniMax-M3")`);
739
742
  }
740
743
  if (!github.owner || !github.repo) {
741
744
  throw new Error(`kody.config.json: github.owner and github.repo are required`);
@@ -836,10 +839,7 @@ function parseCompanyConfig(raw) {
836
839
  const r = raw;
837
840
  const out = {};
838
841
  if (r.activeCapabilities !== void 0)
839
- out.activeCapabilities = parseSlugArray(
840
- r.activeCapabilities,
841
- "company.activeCapabilities"
842
- );
842
+ out.activeCapabilities = parseSlugArray(r.activeCapabilities, "company.activeCapabilities");
843
843
  if (r.activeGoals !== void 0) out.activeGoals = parseGoalActivations(r.activeGoals);
844
844
  return Object.keys(out).length > 0 ? out : void 0;
845
845
  }
@@ -2022,12 +2022,16 @@ function getCompanyStoreRoot() {
2022
2022
  function getCompanyStoreAssetRoot(kind) {
2023
2023
  const root = getCompanyStoreRoot();
2024
2024
  if (!root) return null;
2025
+ const manifestRoot = resolveManifestAssetRoot(root, kind);
2026
+ if (manifestRoot) return manifestRoot;
2025
2027
  const folderByKind = {
2026
2028
  capabilities: "capabilities",
2027
2029
  goals: "goals",
2028
2030
  agents: "agents",
2029
2031
  workflows: "workflows"
2030
2032
  };
2033
+ const rootLayoutPath = path7.join(root, folderByKind[kind]);
2034
+ if (fs5.existsSync(rootLayoutPath)) return rootLayoutPath;
2031
2035
  return path7.join(root, ".kody", folderByKind[kind]);
2032
2036
  }
2033
2037
  function resolveCompanyStore() {
@@ -2065,9 +2069,27 @@ function fetchCompanyStore(repo, ref) {
2065
2069
  function localStoreRoot(repo) {
2066
2070
  if (!path7.isAbsolute(repo) && !repo.startsWith(".")) return null;
2067
2071
  const root = path7.resolve(repo);
2068
- if (!fs5.existsSync(path7.join(root, ".kody"))) return null;
2072
+ if (!fs5.existsSync(path7.join(root, ".kody")) && !fs5.existsSync(path7.join(root, STORE_MANIFEST))) return null;
2069
2073
  return root;
2070
2074
  }
2075
+ function resolveManifestAssetRoot(root, kind) {
2076
+ const manifestPath = path7.join(root, STORE_MANIFEST);
2077
+ if (!fs5.existsSync(manifestPath)) return null;
2078
+ try {
2079
+ const raw = JSON.parse(fs5.readFileSync(manifestPath, "utf8"));
2080
+ const candidates = kind === "agents" ? ["agents", "agent"] : [kind];
2081
+ for (const key of candidates) {
2082
+ const value = raw.assetRoots?.[key];
2083
+ if (typeof value !== "string" || !value.trim()) continue;
2084
+ return path7.resolve(root, value);
2085
+ }
2086
+ } catch (err) {
2087
+ const msg = err instanceof Error ? err.message : String(err);
2088
+ process.stderr.write(`[company-store] failed to read ${manifestPath}: ${msg}
2089
+ `);
2090
+ }
2091
+ return null;
2092
+ }
2071
2093
  function repoToGitUrl(repo) {
2072
2094
  if (/^(https?:|ssh:|git@|file:)/.test(repo)) return repo;
2073
2095
  if (isGitHubShorthand(repo)) {
@@ -2098,7 +2120,7 @@ function setupGithubGitAuth() {
2098
2120
  } catch {
2099
2121
  }
2100
2122
  }
2101
- var DEFAULT_COMPANY_STORE, DEFAULT_COMPANY_STORE_REF, STORE_ENV, REF_ENV, CACHE_ENV, memo;
2123
+ var DEFAULT_COMPANY_STORE, DEFAULT_COMPANY_STORE_REF, STORE_ENV, REF_ENV, CACHE_ENV, STORE_MANIFEST, memo;
2102
2124
  var init_companyStore = __esm({
2103
2125
  "src/companyStore.ts"() {
2104
2126
  "use strict";
@@ -2107,6 +2129,7 @@ var init_companyStore = __esm({
2107
2129
  STORE_ENV = "KODY_COMPANY_STORE";
2108
2130
  REF_ENV = "KODY_COMPANY_STORE_REF";
2109
2131
  CACHE_ENV = "KODY_COMPANY_STORE_CACHE";
2132
+ STORE_MANIFEST = "kody-store.json";
2110
2133
  memo = null;
2111
2134
  }
2112
2135
  });
@@ -2153,11 +2176,7 @@ function getBuiltinCapabilitiesRoot() {
2153
2176
  function getExecutableRoots() {
2154
2177
  const projectCapabilitiesRoot = getProjectCapabilitiesRoot();
2155
2178
  const storeCapabilitiesRoot = getCompanyStoreCapabilitiesRoot();
2156
- return [
2157
- projectCapabilitiesRoot,
2158
- ...storeCapabilitiesRoot ? [storeCapabilitiesRoot] : [],
2159
- getExecutablesRoot()
2160
- ];
2179
+ return [projectCapabilitiesRoot, ...storeCapabilitiesRoot ? [storeCapabilitiesRoot] : [], getExecutablesRoot()];
2161
2180
  }
2162
2181
  function getCapabilityRoots(projectCapabilitiesRoot = getProjectCapabilitiesRoot()) {
2163
2182
  const storeCapabilitiesRoot = getCompanyStoreCapabilitiesRoot();
@@ -2207,8 +2226,7 @@ function listCapabilityActions(projectCapabilitiesRoot = getProjectCapabilitiesR
2207
2226
  seen.add(action.action);
2208
2227
  out.push(action);
2209
2228
  };
2210
- for (const action of listFolderCapabilityActions(projectCapabilitiesRoot, "project-folder"))
2211
- add(action);
2229
+ for (const action of listFolderCapabilityActions(projectCapabilitiesRoot, "project-folder")) add(action);
2212
2230
  const storeCapabilitiesRoot = getCompanyStoreCapabilitiesRoot();
2213
2231
  if (storeCapabilitiesRoot) {
2214
2232
  for (const action of listFolderCapabilityActions(storeCapabilitiesRoot, "company-store")) add(action);
@@ -2265,7 +2283,9 @@ function isSafeName(name) {
2265
2283
  }
2266
2284
  function isCapabilityRoot(root) {
2267
2285
  const normalized = path8.normalize(root);
2268
- return path8.basename(normalized) === "capabilities" && path8.basename(path8.dirname(normalized)) === ".kody";
2286
+ if (path8.basename(normalized) === "capabilities") return true;
2287
+ const knownRoots = [getProjectCapabilitiesRoot(), getCompanyStoreCapabilitiesRoot(), getBuiltinCapabilitiesRoot()];
2288
+ return knownRoots.some((candidate) => candidate && path8.normalize(candidate) === normalized);
2269
2289
  }
2270
2290
  function isImplementationProfile(profilePath, requireImplementationProfile) {
2271
2291
  if (!requireImplementationProfile) return true;
@@ -3124,7 +3144,7 @@ async function runAgent(opts) {
3124
3144
  let noWorkSuccess = false;
3125
3145
  try {
3126
3146
  const queryOptions = {
3127
- model: opts.model.model,
3147
+ model: opts.litellmUrl ? litellmModelGroup(opts.model) : opts.model.model,
3128
3148
  cwd: opts.cwd,
3129
3149
  // Fresh array (never mutate the shared DEFAULT_ALLOWED_TOOLS const) so
3130
3150
  // opt-in tools like fetch_repo can be appended below.
@@ -3160,18 +3180,18 @@ async function runAgent(opts) {
3160
3180
  }
3161
3181
  if (opts.enableCapabilityTool) {
3162
3182
  const { buildCapabilityMcpServer: buildCapabilityMcpServer2 } = await Promise.resolve().then(() => (init_capabilityMcp(), capabilityMcp_exports));
3163
- if (!opts.dutyRepoSlug) {
3183
+ if (!opts.capabilityRepoSlug) {
3164
3184
  throw new Error(
3165
- "enableCapabilityTool requires dutyRepoSlug (owner/name) \u2014 set kody.config.json github.{owner,repo} or GITHUB_REPOSITORY env var"
3185
+ "enableCapabilityTool requires capabilityRepoSlug (owner/name) \u2014 set kody.config.json github.{owner,repo} or GITHUB_REPOSITORY env var"
3166
3186
  );
3167
3187
  }
3168
- const dutyHandle = buildCapabilityMcpServer2({
3169
- repoSlug: opts.dutyRepoSlug,
3188
+ const capabilityHandle = buildCapabilityMcpServer2({
3189
+ repoSlug: opts.capabilityRepoSlug,
3170
3190
  state: opts.capabilityState,
3171
3191
  operatorMention: opts.capabilityOperatorMention ?? "",
3172
3192
  ...opts.capabilitySlug ? { capabilitySlug: opts.capabilitySlug } : {}
3173
3193
  });
3174
- mcpEntries.push(["kody-capability", dutyHandle.server]);
3194
+ mcpEntries.push(["kody-capability", capabilityHandle.server]);
3175
3195
  }
3176
3196
  if (opts.enableDashboardCmsTool) {
3177
3197
  const { buildDashboardCmsMcpServer: buildDashboardCmsMcpServer2, DASHBOARD_CMS_MCP_TOOL_NAMES: DASHBOARD_CMS_MCP_TOOL_NAMES2 } = await Promise.resolve().then(() => (init_dashboardCmsMcp(), dashboardCmsMcp_exports));
@@ -5899,6 +5919,7 @@ var init_lifecycleLabels = __esm({
5899
5919
  // src/litellm.ts
5900
5920
  import { execFileSync as execFileSync5, spawn as spawn3 } from "child_process";
5901
5921
  import * as fs23 from "fs";
5922
+ import * as net from "net";
5902
5923
  import * as os5 from "os";
5903
5924
  import * as path22 from "path";
5904
5925
  async function checkLitellmHealth(url) {
@@ -5917,10 +5938,11 @@ function resolveLitellmTimeoutMs() {
5917
5938
  function generateLitellmConfigYaml(model) {
5918
5939
  const apiKeyVar = model.apiKeyEnvVar ?? providerApiKeyEnvVar(model.provider);
5919
5940
  const litellmProvider = model.litellmProvider ?? model.provider;
5941
+ const modelGroup = litellmModelGroup(model);
5920
5942
  const providerParams = model.baseURL ? [["api_base", model.baseURL]] : [];
5921
5943
  return [
5922
5944
  "model_list:",
5923
- ` - model_name: ${model.model}`,
5945
+ ` - model_name: ${modelGroup}`,
5924
5946
  ` litellm_params:`,
5925
5947
  ` model: ${litellmProvider}/${model.model}`,
5926
5948
  ` api_key: os.environ/${apiKeyVar}`,
@@ -5931,6 +5953,16 @@ function generateLitellmConfigYaml(model) {
5931
5953
  ""
5932
5954
  ].join("\n");
5933
5955
  }
5956
+ async function litellmServesModel(url, modelGroup) {
5957
+ try {
5958
+ const response = await fetch(`${url.replace(/\/+$/, "")}/v1/models`, { signal: AbortSignal.timeout(3e3) });
5959
+ if (!response.ok) return false;
5960
+ const payload = await response.json();
5961
+ return (payload.data ?? []).some((entry) => entry.id === modelGroup);
5962
+ } catch {
5963
+ return false;
5964
+ }
5965
+ }
5934
5966
  function litellmImportable() {
5935
5967
  try {
5936
5968
  execFileSync5("python3", ["-c", "import litellm"], { timeout: 1e4, stdio: "pipe" });
@@ -5982,12 +6014,14 @@ function resolveLitellmCommand() {
5982
6014
  async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL) {
5983
6015
  if (!needsLitellmProxy(model)) return null;
5984
6016
  const cmd = resolveLitellmCommand();
5985
- const portMatch = url.match(/:(\d+)/);
5986
- const port = portMatch ? portMatch[1] : "4000";
6017
+ let activeUrl = url.replace(/\/+$/, "");
6018
+ const modelGroup = litellmModelGroup(model);
5987
6019
  const childEnv = stripBlockingEnv({ ...process.env, ...readDotenvApiKeys(projectDir) });
5988
6020
  let child;
5989
6021
  let logPath;
5990
6022
  const spawnProxy = () => {
6023
+ const portMatch = activeUrl.match(/:(\d+)/);
6024
+ const port = portMatch ? portMatch[1] : "4000";
5991
6025
  const configPath = path22.join(os5.tmpdir(), `kody-local-litellm-${Date.now()}.yaml`);
5992
6026
  fs23.writeFileSync(configPath, generateLitellmConfigYaml(model));
5993
6027
  const args = ["--config", configPath, "--port", port];
@@ -6001,7 +6035,7 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
6001
6035
  const deadline = Date.now() + resolveLitellmTimeoutMs();
6002
6036
  while (Date.now() < deadline) {
6003
6037
  await new Promise((r) => setTimeout(r, LITELLM_HEALTH_POLL_INTERVAL_MS));
6004
- if (await checkLitellmHealth(url)) return true;
6038
+ if (await checkLitellmHealth(activeUrl)) return true;
6005
6039
  }
6006
6040
  return false;
6007
6041
  };
@@ -6032,7 +6066,7 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
6032
6066
  }, 2e3).unref?.();
6033
6067
  };
6034
6068
  const ensureHealthy = async () => {
6035
- if (await checkLitellmHealth(url)) return true;
6069
+ if (await checkLitellmHealth(activeUrl)) return true;
6036
6070
  const tail = readLogTail();
6037
6071
  process.stderr.write(
6038
6072
  `[kody litellm] proxy unreachable mid-run; restarting.${tail ? ` Last log:
@@ -6043,9 +6077,17 @@ ${tail}
6043
6077
  spawnProxy();
6044
6078
  return waitForHealth();
6045
6079
  };
6046
- const isHealthy = () => checkLitellmHealth(url);
6047
- if (await checkLitellmHealth(url)) {
6048
- return { url, kill: killChild, isHealthy, ensureHealthy };
6080
+ const isHealthy = () => checkLitellmHealth(activeUrl);
6081
+ if (await checkLitellmHealth(activeUrl)) {
6082
+ if (await litellmServesModel(activeUrl, modelGroup)) {
6083
+ return { url: activeUrl, kill: killChild, isHealthy, ensureHealthy };
6084
+ }
6085
+ const staleUrl = activeUrl;
6086
+ activeUrl = await nextAvailableLitellmUrl(activeUrl);
6087
+ process.stderr.write(
6088
+ `[kody litellm] existing proxy at ${staleUrl} does not serve ${modelGroup}; starting a separate proxy at ${activeUrl}
6089
+ `
6090
+ );
6049
6091
  }
6050
6092
  spawnProxy();
6051
6093
  if (!await waitForHealth()) {
@@ -6057,7 +6099,30 @@ ${tail}
6057
6099
  ${tail}`
6058
6100
  );
6059
6101
  }
6060
- return { url, kill: killChild, isHealthy, ensureHealthy };
6102
+ return { url: activeUrl, kill: killChild, isHealthy, ensureHealthy };
6103
+ }
6104
+ async function nextAvailableLitellmUrl(url) {
6105
+ const parsed = new URL(url);
6106
+ const startPort = Number(parsed.port || "4000");
6107
+ const host = parsed.hostname === "localhost" ? "127.0.0.1" : parsed.hostname;
6108
+ for (let offset = 1; offset <= 50; offset++) {
6109
+ const port = startPort + offset;
6110
+ if (await canListen(port, host)) {
6111
+ parsed.port = String(port);
6112
+ return parsed.origin;
6113
+ }
6114
+ }
6115
+ throw new Error(`no free LiteLLM port found after ${startPort}`);
6116
+ }
6117
+ function canListen(port, host) {
6118
+ return new Promise((resolve10) => {
6119
+ const server = net.createServer();
6120
+ server.once("error", () => resolve10(false));
6121
+ server.once("listening", () => {
6122
+ server.close(() => resolve10(true));
6123
+ });
6124
+ server.listen(port, host);
6125
+ });
6061
6126
  }
6062
6127
  function readDotenvApiKeys(projectDir) {
6063
6128
  const dotenvPath = path22.join(projectDir, ".env");
@@ -8130,7 +8195,7 @@ async function planGoalCapabilitySchedule(opts) {
8130
8195
  }
8131
8196
  };
8132
8197
  }
8133
- const dispatch2 = dutyDispatch(capability);
8198
+ const dispatch2 = capabilityDispatch(capability);
8134
8199
  statuses[due.slug] = markCapabilitySelected(statuses[due.slug], now);
8135
8200
  return {
8136
8201
  kind: "dispatch",
@@ -8190,7 +8255,7 @@ async function describeCapabilitySchedule(capability, slug2, backend, previous)
8190
8255
  lastFiredAt
8191
8256
  };
8192
8257
  }
8193
- function dutyDispatch(capability) {
8258
+ function capabilityDispatch(capability) {
8194
8259
  const { executable, cliArgs } = resolveCapabilityExecution(capability);
8195
8260
  return { capability: capability.slug, executable, cliArgs };
8196
8261
  }
@@ -9724,7 +9789,7 @@ var init_applyCapabilityReports = __esm({
9724
9789
  init_stateStore();
9725
9790
  applyCapabilityReports = async (ctx, _profile, agentResult) => {
9726
9791
  const reports = collectReports(ctx.data.capabilityReports, agentResult);
9727
- const results = collectResults(ctx.data.dutyResults, agentResult);
9792
+ const results = collectResults(ctx.data.capabilityResults ?? ctx.data.dutyResults, agentResult);
9728
9793
  const resultGoalId = typeof ctx.args.goal === "string" && ctx.args.goal.length > 0 ? ctx.args.goal : null;
9729
9794
  const explicitEvidence = typeof ctx.args.evidence === "string" && ctx.args.evidence.length > 0 ? ctx.args.evidence : void 0;
9730
9795
  const evidenceItems = collectGoalCapabilityEvidence(reports, results, resultGoalId, explicitEvidence);
@@ -10243,7 +10308,7 @@ function formatCapabilityReference(data, profileName) {
10243
10308
  if (capabilitySchedule) {
10244
10309
  lines.push(`- Cadence: \`${capabilitySchedule}\``);
10245
10310
  }
10246
- const capabilityBody = pickToken(data, "dutyIntent", "jobIntent");
10311
+ const capabilityBody = pickToken(data, "capabilityIntent", "jobIntent", "dutyIntent");
10247
10312
  if (capabilityBody) {
10248
10313
  lines.push("", "## Capability body", "", capabilityBody);
10249
10314
  }
@@ -12566,7 +12631,7 @@ function makeConfig(pm, ownerRepo, defaultBranch) {
12566
12631
  repo: ownerRepo?.repo ?? "REPO"
12567
12632
  },
12568
12633
  agent: {
12569
- model: "minimax/MiniMax-M2.7-highspeed"
12634
+ model: "minimax/MiniMax-M3"
12570
12635
  }
12571
12636
  };
12572
12637
  }
@@ -17806,10 +17871,11 @@ function collectShellSideChannels(ctx, stdout) {
17806
17871
  const prior = Array.isArray(ctx.data.capabilityReports) ? ctx.data.capabilityReports : [];
17807
17872
  ctx.data.capabilityReports = [...prior, ...capabilityReports];
17808
17873
  }
17809
- const dutyResults = parseCapabilityResultsFromText(stdout);
17810
- if (dutyResults.length > 0) {
17811
- const prior = Array.isArray(ctx.data.dutyResults) ? ctx.data.dutyResults : [];
17812
- ctx.data.dutyResults = [...prior, ...dutyResults];
17874
+ const capabilityResults = parseCapabilityResultsFromText(stdout);
17875
+ if (capabilityResults.length > 0) {
17876
+ const prior = Array.isArray(ctx.data.capabilityResults) ? ctx.data.capabilityResults : Array.isArray(ctx.data.dutyResults) ? ctx.data.dutyResults : [];
17877
+ ctx.data.capabilityResults = [...prior, ...capabilityResults];
17878
+ ctx.data.dutyResults = ctx.data.capabilityResults;
17813
17879
  }
17814
17880
  }
17815
17881
  function operatorRequestBlock(why) {
@@ -18025,7 +18091,7 @@ async function runExecutable(profileName, input) {
18025
18091
  // owner/repo from kody.config.json; envelope falls back to GITHUB_REPOSITORY
18026
18092
  // for tester repos that don't set config.github (the file isn't always
18027
18093
  // checked in). Either way, capabilityMcp needs "owner/name" to hit the compare API.
18028
- dutyRepoSlug: config.github?.owner && config.github?.repo ? `${config.github.owner}/${config.github.repo}` : process.env.GITHUB_REPOSITORY?.trim() || void 0,
18094
+ capabilityRepoSlug: config.github?.owner && config.github?.repo ? `${config.github.owner}/${config.github.repo}` : process.env.GITHUB_REPOSITORY?.trim() || void 0,
18029
18095
  verifyToolMaxAttempts: profile.claudeCode.verifyAttempts ?? null,
18030
18096
  verifyConfig: profile.claudeCode.enableVerifyTool ? config : void 0,
18031
18097
  executableName: profileName,
@@ -18814,6 +18880,7 @@ async function runCapabilityImplementationStep(valid, profileName, capabilityIde
18814
18880
  if (capabilityContext) {
18815
18881
  preloadedData.capabilitySlug = capabilityContext.slug;
18816
18882
  preloadedData.capabilityTitle = capabilityContext.title;
18883
+ preloadedData.capabilityIntent = capabilityContext.body;
18817
18884
  preloadedData.dutyIntent = capabilityContext.body;
18818
18885
  preloadedData.jobIntent = capabilityContext.body;
18819
18886
  if (preloadedData.jobCapability === void 0) preloadedData.jobCapability = capabilityContext.slug;
@@ -19065,7 +19132,7 @@ var init_job = __esm({
19065
19132
  init_package();
19066
19133
 
19067
19134
  // src/servers/brain-proxy.ts
19068
- import { createServer as createServer2 } from "http";
19135
+ import { createServer as createServer3 } from "http";
19069
19136
  import { URL as URL2 } from "url";
19070
19137
 
19071
19138
  // src/servers/brain-protocol.ts
@@ -19169,11 +19236,12 @@ function translateOpenAISseToBrain(opts) {
19169
19236
 
19170
19237
  // src/servers/brain-serve.ts
19171
19238
  import * as fs48 from "fs";
19172
- import { createServer } from "http";
19239
+ import { createServer as createServer2 } from "http";
19173
19240
  import * as path47 from "path";
19174
19241
 
19175
19242
  // src/chat/loop.ts
19176
19243
  init_agent();
19244
+ init_config();
19177
19245
  init_registry();
19178
19246
  init_task_artifacts();
19179
19247
  import * as fs13 from "fs";
@@ -19498,11 +19566,11 @@ function buildExecutableCatalog() {
19498
19566
  if (entries.length === 0) return "";
19499
19567
  const lines = [
19500
19568
  "",
19501
- "# Available executables",
19569
+ "# Available capability implementations",
19502
19570
  "These run inside the engine, NOT inside this chat. You cannot invoke them",
19503
- "directly \u2014 to run one, tell the user to post `@kody <name>` (with any flags)",
19571
+ "directly \u2014 to run one, tell the user to post the matching `@kody <action>`",
19504
19572
  "as a comment on the relevant issue or PR. The dispatcher binds the issue/PR",
19505
- "number to the executable's inputs automatically.",
19573
+ "number to the implementation inputs automatically.",
19506
19574
  ""
19507
19575
  ];
19508
19576
  for (const e of entries) {
@@ -19677,7 +19745,7 @@ async function runOpenAIChatTurn(args) {
19677
19745
  method: "POST",
19678
19746
  headers: { "Content-Type": "application/json" },
19679
19747
  body: JSON.stringify({
19680
- model: opts.model.model,
19748
+ model: litellmModelGroup(opts.model),
19681
19749
  messages: [
19682
19750
  { role: "system", content: systemPrompt },
19683
19751
  ...turns.map((turn) => ({
@@ -20718,12 +20786,12 @@ async function runCi(argv) {
20718
20786
  const evt = JSON.parse(fs46.readFileSync(dispatchEventPath, "utf-8"));
20719
20787
  const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
20720
20788
  const sessionInput = String(evt?.inputs?.sessionId ?? "");
20721
- const dutyInput = String(evt?.inputs?.capability ?? evt?.inputs?.executable ?? "").trim();
20789
+ const capabilityInput = String(evt?.inputs?.capability ?? evt?.inputs?.executable ?? "").trim();
20722
20790
  const messageInput = String(evt?.inputs?.message ?? "").trim();
20723
20791
  const noTarget = !sessionInput && !(Number.isFinite(issueInput) && issueInput > 0);
20724
- if (noTarget && dutyInput) {
20725
- forceRunAction = dutyInput;
20726
- if (dutyInput === "goal-manager" && messageInput) {
20792
+ if (noTarget && capabilityInput) {
20793
+ forceRunAction = capabilityInput;
20794
+ if (capabilityInput === "goal-manager" && messageInput) {
20727
20795
  forceRunCliArgs = { goal: messageInput };
20728
20796
  }
20729
20797
  } else {
@@ -20736,8 +20804,8 @@ async function runCi(argv) {
20736
20804
  if (forceRunAction) {
20737
20805
  const config = earlyConfig ?? loadConfig(cwd);
20738
20806
  const manualGoalManager = forceRunAction === "goal-manager";
20739
- const dutyRoute = manualGoalManager ? null : resolveCapabilityAction(forceRunAction);
20740
- const scheduledWatchRoute = manualGoalManager || dutyRoute ? void 0 : dispatchScheduledWatches({ force: true }).find(
20807
+ const capabilityRoute = manualGoalManager ? null : resolveCapabilityAction(forceRunAction);
20808
+ const scheduledWatchRoute = manualGoalManager || capabilityRoute ? void 0 : dispatchScheduledWatches({ force: true }).find(
20741
20809
  (match) => match.action === forceRunAction || match.executable === forceRunAction
20742
20810
  );
20743
20811
  const route = manualGoalManager ? {
@@ -20745,7 +20813,7 @@ async function runCi(argv) {
20745
20813
  capability: "goal-manager",
20746
20814
  executable: "goal-manager",
20747
20815
  cliArgs: forceRunCliArgs
20748
- } : dutyRoute ?? scheduledWatchRoute;
20816
+ } : capabilityRoute ?? scheduledWatchRoute;
20749
20817
  if (!route) {
20750
20818
  process.stderr.write(`[kody] manual one-shot action '${forceRunAction}' has no capability action
20751
20819
  `);
@@ -21527,7 +21595,7 @@ function buildServer(opts) {
21527
21595
  const runTurn = opts.runTurn ?? runChatTurn;
21528
21596
  const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
21529
21597
  const reposRoot = opts.reposRoot ?? path47.join(path47.dirname(path47.resolve(opts.cwd)), "repos");
21530
- return createServer(async (req, res) => {
21598
+ return createServer2(async (req, res) => {
21531
21599
  if (!req.method || !req.url) {
21532
21600
  sendJson(res, 400, { error: "bad request" });
21533
21601
  return;
@@ -21725,7 +21793,7 @@ function buildBrainProxy(opts) {
21725
21793
  res.writeHead(404, { "Content-Type": "application/json" });
21726
21794
  res.end(JSON.stringify({ error: "not found" }));
21727
21795
  };
21728
- const httpServer = createServer2((req, res) => {
21796
+ const httpServer = createServer3((req, res) => {
21729
21797
  void handler(req, res);
21730
21798
  });
21731
21799
  return { httpServer, handler };
@@ -21946,7 +22014,7 @@ init_fetchRepoMcp();
21946
22014
 
21947
22015
  // src/servers/mcpHttpServer.ts
21948
22016
  import { randomUUID } from "crypto";
21949
- import { createServer as createServer3 } from "http";
22017
+ import { createServer as createServer4 } from "http";
21950
22018
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
21951
22019
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
21952
22020
  function buildMcpHttpServer(opts) {
@@ -22005,7 +22073,7 @@ function buildMcpHttpServer(opts) {
22005
22073
  res.end(JSON.stringify({ error: "internal error" }));
22006
22074
  }
22007
22075
  };
22008
- const httpServer = createServer3((req, res) => {
22076
+ const httpServer = createServer4((req, res) => {
22009
22077
  if (req.url === "/healthz" || req.url === "/health") {
22010
22078
  res.writeHead(200, { "Content-Type": "application/json" });
22011
22079
  res.end(JSON.stringify({ ok: true, routes: Array.from(routes.keys()) }));
@@ -22598,7 +22666,7 @@ init_job();
22598
22666
  init_registry();
22599
22667
 
22600
22668
  // src/servers/pool-serve.ts
22601
- import { createServer as createServer4 } from "http";
22669
+ import { createServer as createServer5 } from "http";
22602
22670
 
22603
22671
  // src/github-health.ts
22604
22672
  var STATUS_URL = "https://www.githubstatus.com/api/v2/components.json";
@@ -23416,9 +23484,9 @@ async function poolServe() {
23416
23484
  const tick = setInterval(() => {
23417
23485
  registry.resyncAll().catch((err) => log(`resync tick failed: ${err instanceof Error ? err.message : String(err)}`));
23418
23486
  }, refillMs);
23419
- const dutyTickEnabled = (process.env.POOL_CAPABILITY_TICK ?? "1") !== "0";
23420
- const dutyTickMs = envInt2("POOL_CAPABILITY_TICK_MS", 15 * 6e4);
23421
- const dutyTick = dutyTickEnabled ? setInterval(() => {
23487
+ const capabilityTickEnabled = (process.env.POOL_CAPABILITY_TICK ?? "1") !== "0";
23488
+ const capabilityTickMs = envInt2("POOL_CAPABILITY_TICK_MS", 15 * 6e4);
23489
+ const capabilityTick = capabilityTickEnabled ? setInterval(() => {
23422
23490
  runCapabilityFallbackTick({
23423
23491
  isDegraded: () => gitHubActionsDegraded(),
23424
23492
  activeRepos: () => registry.activeRepos(),
@@ -23427,8 +23495,8 @@ async function poolServe() {
23427
23495
  }).catch(
23428
23496
  (err) => log(`capability fallback tick failed: ${err instanceof Error ? err.message : String(err)}`)
23429
23497
  );
23430
- }, dutyTickMs) : null;
23431
- const server = createServer4(async (req, res) => {
23498
+ }, capabilityTickMs) : null;
23499
+ const server = createServer5(async (req, res) => {
23432
23500
  try {
23433
23501
  if (!req.method || !req.url) return sendJson2(res, 400, { error: "bad request" });
23434
23502
  const url = new URL(req.url, "http://localhost");
@@ -23484,7 +23552,7 @@ async function poolServe() {
23484
23552
  const shutdown = (signal) => {
23485
23553
  log(`${signal} \u2014 shutting down`);
23486
23554
  clearInterval(tick);
23487
- if (dutyTick) clearInterval(dutyTick);
23555
+ if (capabilityTick) clearInterval(capabilityTick);
23488
23556
  server.close(() => process.exit(0));
23489
23557
  };
23490
23558
  process.once("SIGINT", () => shutdown("SIGINT"));
@@ -23497,7 +23565,7 @@ async function poolServe() {
23497
23565
  // src/servers/runner-serve.ts
23498
23566
  import { spawn as spawn8 } from "child_process";
23499
23567
  import * as fs51 from "fs";
23500
- import { createServer as createServer5 } from "http";
23568
+ import { createServer as createServer6 } from "http";
23501
23569
  var DEFAULT_PORT2 = 8080;
23502
23570
  var DEFAULT_WORKDIR = "/workspace/repo";
23503
23571
  function getApiKey3() {
@@ -23694,7 +23762,7 @@ async function defaultRunJob(job) {
23694
23762
  function buildServer2(opts) {
23695
23763
  const runJob2 = opts.runJob ?? defaultRunJob;
23696
23764
  let busy = false;
23697
- return createServer5(async (req, res) => {
23765
+ return createServer6(async (req, res) => {
23698
23766
  if (!req.method || !req.url) {
23699
23767
  sendJson3(res, 400, { error: "bad request" });
23700
23768
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.290",
3
+ "version": "0.4.292",
4
4
  "description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",