@kody-ade/kody-engine 0.4.508 → 0.4.510
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 +94 -7
- 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.510",
|
|
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",
|
|
@@ -809,6 +809,16 @@ async function enforceSubagentModelInheritance(input) {
|
|
|
809
809
|
}
|
|
810
810
|
};
|
|
811
811
|
}
|
|
812
|
+
function createSubagentInvocationHook(invokedSubagents) {
|
|
813
|
+
return async (input) => {
|
|
814
|
+
const toolInput = input.tool_input;
|
|
815
|
+
if (toolInput && typeof toolInput === "object" && !Array.isArray(toolInput)) {
|
|
816
|
+
const subagentType = toolInput.subagent_type;
|
|
817
|
+
if (typeof subagentType === "string" && subagentType.length > 0) invokedSubagents.add(subagentType);
|
|
818
|
+
}
|
|
819
|
+
return {};
|
|
820
|
+
};
|
|
821
|
+
}
|
|
812
822
|
function splitFrontmatter(raw) {
|
|
813
823
|
const match = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(raw);
|
|
814
824
|
if (!match) return { fm: {}, body: raw.trim() };
|
|
@@ -1959,8 +1969,17 @@ function parseCapabilityContract(raw) {
|
|
|
1959
1969
|
if (timeoutMs !== void 0 && parsed.execution !== "script") {
|
|
1960
1970
|
throw new Error('contract.json timeoutMs is supported only when execution is "script"');
|
|
1961
1971
|
}
|
|
1972
|
+
const requiredSubagents = parsed.requiredSubagents === void 0 ? void 0 : Array.isArray(parsed.requiredSubagents) && parsed.requiredSubagents.length > 0 && parsed.requiredSubagents.every(
|
|
1973
|
+
(name) => typeof name === "string" && /^[a-z][a-z0-9-]{0,63}$/.test(name)
|
|
1974
|
+
) ? [...new Set(parsed.requiredSubagents)] : null;
|
|
1975
|
+
if (requiredSubagents === null) {
|
|
1976
|
+
throw new Error("contract.json requiredSubagents must contain valid specialist names");
|
|
1977
|
+
}
|
|
1978
|
+
if (requiredSubagents && parsed.execution !== "agent") {
|
|
1979
|
+
throw new Error('contract.json requiredSubagents are supported only when execution is "agent"');
|
|
1980
|
+
}
|
|
1962
1981
|
const unsupported = Object.keys(parsed).filter(
|
|
1963
|
-
(key) => key !== "execution" && key !== "secrets" && key !== "timeoutMs" && key !== "input" && key !== "output"
|
|
1982
|
+
(key) => key !== "execution" && key !== "secrets" && key !== "timeoutMs" && key !== "requiredSubagents" && key !== "input" && key !== "output"
|
|
1964
1983
|
);
|
|
1965
1984
|
if (unsupported.length > 0) {
|
|
1966
1985
|
throw new Error(`contract.json contains unsupported fields: ${unsupported.join(", ")}`);
|
|
@@ -1969,6 +1988,7 @@ function parseCapabilityContract(raw) {
|
|
|
1969
1988
|
...parsed.execution ? { execution: parsed.execution } : {},
|
|
1970
1989
|
...secrets ? { secrets } : {},
|
|
1971
1990
|
...timeoutMs !== void 0 ? { timeoutMs } : {},
|
|
1991
|
+
...requiredSubagents ? { requiredSubagents } : {},
|
|
1972
1992
|
input: parsed.input,
|
|
1973
1993
|
output: parsed.output
|
|
1974
1994
|
};
|
|
@@ -3717,6 +3737,8 @@ async function runAgent(opts) {
|
|
|
3717
3737
|
let messageCount = 0;
|
|
3718
3738
|
let finalText = "";
|
|
3719
3739
|
let getSubmitted;
|
|
3740
|
+
const invokedSubagents = /* @__PURE__ */ new Set();
|
|
3741
|
+
const subagentInvocationHook = createSubagentInvocationHook(invokedSubagents);
|
|
3720
3742
|
for (let attempt = 0; ; attempt++) {
|
|
3721
3743
|
let ndjsonWriteFailed = false;
|
|
3722
3744
|
let ndjsonWriteError;
|
|
@@ -3751,6 +3773,12 @@ async function runAgent(opts) {
|
|
|
3751
3773
|
matcher: "Agent",
|
|
3752
3774
|
hooks: [enforceSubagentModelInheritance]
|
|
3753
3775
|
}
|
|
3776
|
+
],
|
|
3777
|
+
PostToolUse: [
|
|
3778
|
+
{
|
|
3779
|
+
matcher: "Agent",
|
|
3780
|
+
hooks: [subagentInvocationHook]
|
|
3781
|
+
}
|
|
3754
3782
|
]
|
|
3755
3783
|
}
|
|
3756
3784
|
};
|
|
@@ -4072,7 +4100,8 @@ async function runAgent(opts) {
|
|
|
4072
4100
|
durationMs: Date.now() - startedAt,
|
|
4073
4101
|
tokens,
|
|
4074
4102
|
costUsd,
|
|
4075
|
-
messageCount
|
|
4103
|
+
messageCount,
|
|
4104
|
+
invokedSubagents: [...invokedSubagents]
|
|
4076
4105
|
};
|
|
4077
4106
|
}
|
|
4078
4107
|
var DEFAULT_ALLOWED_TOOLS, DEFAULT_TURN_TIMEOUT_MS, MAX_CONNECTION_RETRIES, CONNECTION_RETRY_BASE_MS, MUTATING_FILE_TOOLS, BASH_WRITE_VERB, AGENT_KEEP_SECRETS;
|
|
@@ -15770,6 +15799,13 @@ var init_loadSimpleCapability = __esm({
|
|
|
15770
15799
|
if (ctx.data.capabilityExecution === "agent") {
|
|
15771
15800
|
registerCapabilitySubagents(profile, toolRoot, toolFiles);
|
|
15772
15801
|
}
|
|
15802
|
+
const requiredSubagents = capability.contract?.requiredSubagents ?? [];
|
|
15803
|
+
for (const required2 of requiredSubagents) {
|
|
15804
|
+
if (!profile.claudeCode.subagents.includes(required2)) {
|
|
15805
|
+
throw new Error(`Capability "${slug}" required specialist ${required2} is not available`);
|
|
15806
|
+
}
|
|
15807
|
+
}
|
|
15808
|
+
if (requiredSubagents.length > 0) ctx.data.requiredSubagents = requiredSubagents;
|
|
15773
15809
|
if (capability.contract?.execution === "script") {
|
|
15774
15810
|
ctx.data.capabilityScriptPath = path40.join(capability.dir, "tools", "run.sh");
|
|
15775
15811
|
ctx.data.capabilitySecretNames = capability.contract.secrets ?? [];
|
|
@@ -15827,7 +15863,14 @@ var init_loadSimpleCapability = __esm({
|
|
|
15827
15863
|
outputPath,
|
|
15828
15864
|
"The Engine reads this file as the authoritative result. Do not write markdown to it."
|
|
15829
15865
|
] : []
|
|
15830
|
-
] : ["Return one JSON value."]
|
|
15866
|
+
] : ["Return one JSON value."],
|
|
15867
|
+
...requiredSubagents.length > 0 ? [
|
|
15868
|
+
"",
|
|
15869
|
+
"## Required specialists",
|
|
15870
|
+
"",
|
|
15871
|
+
`You must invoke each of these private specialists before returning: ${requiredSubagents.join(", ")}.`,
|
|
15872
|
+
"The Engine verifies the actual Agent calls and blocks the capability if any are skipped."
|
|
15873
|
+
] : []
|
|
15831
15874
|
].join("\n");
|
|
15832
15875
|
};
|
|
15833
15876
|
}
|
|
@@ -16775,6 +16818,9 @@ var init_parseReproOutput = __esm({
|
|
|
16775
16818
|
|
|
16776
16819
|
// src/scripts/parseSimpleCapabilityOutput.ts
|
|
16777
16820
|
import * as fs45 from "fs";
|
|
16821
|
+
function stringList2(value) {
|
|
16822
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
16823
|
+
}
|
|
16778
16824
|
function readOutputFile(outputPath) {
|
|
16779
16825
|
if (!outputPath || !fs45.existsSync(outputPath)) return { found: false };
|
|
16780
16826
|
try {
|
|
@@ -16822,6 +16868,28 @@ var init_parseSimpleCapabilityOutput = __esm({
|
|
|
16822
16868
|
init_capability_contract_validation();
|
|
16823
16869
|
init_capabilityResult();
|
|
16824
16870
|
parseSimpleCapabilityOutput = async (ctx, _profile, agentResult) => {
|
|
16871
|
+
const requiredSubagents = stringList2(ctx.data.requiredSubagents);
|
|
16872
|
+
const invokedSubagents = new Set(agentResult?.invokedSubagents ?? []);
|
|
16873
|
+
const missingSubagents = requiredSubagents.filter((name) => !invokedSubagents.has(name));
|
|
16874
|
+
if (missingSubagents.length > 0) {
|
|
16875
|
+
const label = missingSubagents.length === 1 ? "specialist was" : "specialists were";
|
|
16876
|
+
const reason2 = `Required ${label} not invoked: ${missingSubagents.join(", ")}`;
|
|
16877
|
+
ctx.output.exitCode = 64;
|
|
16878
|
+
ctx.output.reason = reason2;
|
|
16879
|
+
ctx.data.capabilityOutput = { status: "blocked", reason: reason2, summary: reason2 };
|
|
16880
|
+
ctx.data.capabilityResults = [
|
|
16881
|
+
{
|
|
16882
|
+
version: 1,
|
|
16883
|
+
status: "blocked",
|
|
16884
|
+
summary: reason2,
|
|
16885
|
+
facts: {},
|
|
16886
|
+
artifacts: [],
|
|
16887
|
+
missingEvidence: [],
|
|
16888
|
+
blockers: [reason2]
|
|
16889
|
+
}
|
|
16890
|
+
];
|
|
16891
|
+
return;
|
|
16892
|
+
}
|
|
16825
16893
|
const outputPath = typeof ctx.data.capabilityOutputPath === "string" ? ctx.data.capabilityOutputPath : void 0;
|
|
16826
16894
|
const fileOutput = readOutputFile(outputPath);
|
|
16827
16895
|
const output = fileOutput.found ? fileOutput.value : Object.hasOwn(ctx.data, "capabilityScriptOutput") ? ctx.data.capabilityScriptOutput : parseOutput(agentResult?.finalText);
|
|
@@ -22560,7 +22628,8 @@ async function runGraphCapabilityWorkflow(parent, workflow, capability, base, ch
|
|
|
22560
22628
|
}
|
|
22561
22629
|
const transition = selectWorkflowTransition(step, chainData, state.transitionCounts);
|
|
22562
22630
|
if (!transition) {
|
|
22563
|
-
const
|
|
22631
|
+
const exhausted = exhaustedWorkflowTransitions(step, chainData, state.transitionCounts);
|
|
22632
|
+
const reason = exhausted.length > 0 ? `workflow step ${step.id} reached iteration limit: ${exhausted.join(", ")}` : `workflow step ${step.id} has no available connection`;
|
|
22564
22633
|
state.status = "blocked";
|
|
22565
22634
|
state.blocker = reason;
|
|
22566
22635
|
await checkpoint?.(state);
|
|
@@ -22636,6 +22705,15 @@ function selectWorkflowTransition(step, data, counts) {
|
|
|
22636
22705
|
}
|
|
22637
22706
|
return fallback;
|
|
22638
22707
|
}
|
|
22708
|
+
function exhaustedWorkflowTransitions(step, data, counts) {
|
|
22709
|
+
return (step.next ?? []).flatMap((transition) => {
|
|
22710
|
+
if (transition.maxIterations === void 0) return [];
|
|
22711
|
+
const key = `${step.id}->${transition.to}`;
|
|
22712
|
+
if ((counts[key] ?? 0) < transition.maxIterations) return [];
|
|
22713
|
+
const matches = transition.default === true || !transition.when || conditionMatches(transition.when, workflowConditionContext(data));
|
|
22714
|
+
return matches ? [`${key} (${transition.maxIterations})`] : [];
|
|
22715
|
+
});
|
|
22716
|
+
}
|
|
22639
22717
|
function workflowResultConditionPaths(transitions) {
|
|
22640
22718
|
return transitions.flatMap(
|
|
22641
22719
|
(transition) => Object.keys(transition.when ?? {}).filter((path53) => path53.startsWith("result."))
|
|
@@ -24840,8 +24918,13 @@ Exit codes (inherited from kody run):
|
|
|
24840
24918
|
2 verify failed (no PR opened \u2014 branch pushed for inspection)
|
|
24841
24919
|
3 no commits to ship
|
|
24842
24920
|
4 PR creation failed
|
|
24921
|
+
64 capability or workflow blocked by an invalid or exhausted route
|
|
24922
|
+
124 execution timed out
|
|
24843
24923
|
99 wrapper crashed
|
|
24844
24924
|
`;
|
|
24925
|
+
function normalizeJobExitCode(exitCode) {
|
|
24926
|
+
return Number.isInteger(exitCode) && exitCode >= 0 && exitCode <= 255 ? exitCode : 99;
|
|
24927
|
+
}
|
|
24845
24928
|
function parseCiArgs(argv) {
|
|
24846
24929
|
const result = { errors: [] };
|
|
24847
24930
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -25332,7 +25415,9 @@ async function runCi(argv) {
|
|
|
25332
25415
|
}
|
|
25333
25416
|
);
|
|
25334
25417
|
const ec = result.exitCode;
|
|
25335
|
-
|
|
25418
|
+
if (ec !== 0 && result.reason) process.stderr.write(`[kody] ${result.reason}
|
|
25419
|
+
`);
|
|
25420
|
+
return normalizeJobExitCode(ec);
|
|
25336
25421
|
}
|
|
25337
25422
|
if (!args.issueNumber && !autoFallback && runRequestFanOut) {
|
|
25338
25423
|
return runScheduledFanOut(cwd, args, { force: runRequestFanOutForce });
|
|
@@ -28433,7 +28518,9 @@ function envRunRequest(env = process.env) {
|
|
|
28433
28518
|
const { target } = parsed.request;
|
|
28434
28519
|
if (target.type === "chat") return { ...result, command: "chat", chatArgv: [] };
|
|
28435
28520
|
if (target.type === "issue") return { ...result, command: "ci", ciArgv: ["--issue", String(target.id)] };
|
|
28436
|
-
if (target.type === "goal" || target.type === "
|
|
28521
|
+
if (target.type === "goal" || target.type === "loop" || target.type === "workflow") {
|
|
28522
|
+
return { ...result, command: "ci", ciArgv: [] };
|
|
28523
|
+
}
|
|
28437
28524
|
return { ...result, errors: [`unsupported runRequest target: ${target.type ?? "unknown"}`] };
|
|
28438
28525
|
}
|
|
28439
28526
|
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.
|
|
3
|
+
"version": "0.4.510",
|
|
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",
|