@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.
- package/dist/bin/kody.js +136 -68
- 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.
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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.
|
|
3183
|
+
if (!opts.capabilityRepoSlug) {
|
|
3164
3184
|
throw new Error(
|
|
3165
|
-
"enableCapabilityTool requires
|
|
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
|
|
3169
|
-
repoSlug: opts.
|
|
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",
|
|
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: ${
|
|
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
|
-
|
|
5986
|
-
const
|
|
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(
|
|
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(
|
|
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(
|
|
6047
|
-
if (await checkLitellmHealth(
|
|
6048
|
-
|
|
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 =
|
|
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
|
|
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, "
|
|
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-
|
|
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
|
|
17810
|
-
if (
|
|
17811
|
-
const prior = Array.isArray(ctx.data.dutyResults) ? ctx.data.dutyResults : [];
|
|
17812
|
-
ctx.data.
|
|
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
|
-
|
|
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
|
|
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
|
|
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 <
|
|
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
|
|
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
|
|
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
|
|
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 &&
|
|
20725
|
-
forceRunAction =
|
|
20726
|
-
if (
|
|
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
|
|
20740
|
-
const scheduledWatchRoute = manualGoalManager ||
|
|
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
|
-
} :
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
23420
|
-
const
|
|
23421
|
-
const
|
|
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
|
-
},
|
|
23431
|
-
const server =
|
|
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 (
|
|
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
|
|
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
|
|
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.
|
|
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",
|