@kody-ade/kody-engine 0.4.534 → 0.4.536
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/kody.js
CHANGED
|
@@ -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.536",
|
|
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",
|
|
@@ -1956,6 +1956,7 @@ function parseCapabilityContract(raw) {
|
|
|
1956
1956
|
if (parsed.execution !== void 0 && parsed.execution !== "agent" && parsed.execution !== "script") {
|
|
1957
1957
|
throw new Error('contract.json execution must be "agent" or "script"');
|
|
1958
1958
|
}
|
|
1959
|
+
const requirements = parseCapabilityRequirements(parsed.requirements);
|
|
1959
1960
|
const secrets = parsed.secrets === void 0 ? void 0 : Array.isArray(parsed.secrets) && parsed.secrets.every((name) => typeof name === "string" && /^[A-Z][A-Z0-9_]*$/.test(name)) ? [...new Set(parsed.secrets)] : null;
|
|
1960
1961
|
if (secrets === null) {
|
|
1961
1962
|
throw new Error("contract.json secrets must contain valid environment variable names");
|
|
@@ -1978,13 +1979,14 @@ function parseCapabilityContract(raw) {
|
|
|
1978
1979
|
throw new Error('contract.json requiredSubagents are supported only when execution is "agent"');
|
|
1979
1980
|
}
|
|
1980
1981
|
const unsupported = Object.keys(parsed).filter(
|
|
1981
|
-
(key) => key !== "execution" && key !== "secrets" && key !== "timeoutMs" && key !== "requiredSubagents" && key !== "input" && key !== "output"
|
|
1982
|
+
(key) => key !== "execution" && key !== "requirements" && key !== "secrets" && key !== "timeoutMs" && key !== "requiredSubagents" && key !== "input" && key !== "output"
|
|
1982
1983
|
);
|
|
1983
1984
|
if (unsupported.length > 0) {
|
|
1984
1985
|
throw new Error(`contract.json contains unsupported fields: ${unsupported.join(", ")}`);
|
|
1985
1986
|
}
|
|
1986
1987
|
return {
|
|
1987
1988
|
...parsed.execution ? { execution: parsed.execution } : {},
|
|
1989
|
+
...requirements ? { requirements } : {},
|
|
1988
1990
|
...secrets ? { secrets } : {},
|
|
1989
1991
|
...timeoutMs !== void 0 ? { timeoutMs } : {},
|
|
1990
1992
|
...requiredSubagents ? { requiredSubagents } : {},
|
|
@@ -1992,6 +1994,28 @@ function parseCapabilityContract(raw) {
|
|
|
1992
1994
|
output: parsed.output
|
|
1993
1995
|
};
|
|
1994
1996
|
}
|
|
1997
|
+
function parseCapabilityRequirements(raw) {
|
|
1998
|
+
if (raw === void 0) return void 0;
|
|
1999
|
+
if (!isPlainObject(raw)) throw new Error("contract.json requirements must be an object");
|
|
2000
|
+
const unsupported = Object.keys(raw).filter((key) => key !== "browser" && key !== "qaCredentials");
|
|
2001
|
+
if (unsupported.length > 0) {
|
|
2002
|
+
throw new Error(`contract.json requirements contains unsupported fields: ${unsupported.join(", ")}`);
|
|
2003
|
+
}
|
|
2004
|
+
if (raw.browser !== void 0 && typeof raw.browser !== "boolean") {
|
|
2005
|
+
throw new Error("contract.json requirements.browser must be boolean");
|
|
2006
|
+
}
|
|
2007
|
+
if (raw.qaCredentials !== void 0 && typeof raw.qaCredentials !== "boolean") {
|
|
2008
|
+
throw new Error("contract.json requirements.qaCredentials must be boolean");
|
|
2009
|
+
}
|
|
2010
|
+
if (raw.qaCredentials === true && raw.browser !== true) {
|
|
2011
|
+
throw new Error("contract.json requirements.qaCredentials requires browser");
|
|
2012
|
+
}
|
|
2013
|
+
const requirements = {
|
|
2014
|
+
...raw.browser === true ? { browser: true } : {},
|
|
2015
|
+
...raw.qaCredentials === true ? { qaCredentials: true } : {}
|
|
2016
|
+
};
|
|
2017
|
+
return Object.keys(requirements).length > 0 ? requirements : void 0;
|
|
2018
|
+
}
|
|
1995
2019
|
function isRegularFile(filePath) {
|
|
1996
2020
|
try {
|
|
1997
2021
|
const stat = fs6.lstatSync(filePath);
|
|
@@ -2638,6 +2662,16 @@ function createKodyApiBackendClient(env = process.env) {
|
|
|
2638
2662
|
mutation: (fn, args) => callKodyApi("mutation", fn, args, env)
|
|
2639
2663
|
};
|
|
2640
2664
|
}
|
|
2665
|
+
async function notifyWorkflowCompleted(notification, env = process.env) {
|
|
2666
|
+
const token = await githubOidcToken(env);
|
|
2667
|
+
const response = await fetch(`${resolveKodyApiUrl(env)}/api/kody/engine/workflow-completed`, {
|
|
2668
|
+
method: "POST",
|
|
2669
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|
|
2670
|
+
body: JSON.stringify(notification),
|
|
2671
|
+
signal: AbortSignal.timeout(3e4)
|
|
2672
|
+
});
|
|
2673
|
+
if (!response.ok) throw new Error(`Kody workflow completion request failed (${response.status})`);
|
|
2674
|
+
}
|
|
2641
2675
|
async function readRuntimeSecretFromKody(name, env = process.env) {
|
|
2642
2676
|
const token = await githubOidcToken(env);
|
|
2643
2677
|
const response = await fetch(`${resolveKodyApiUrl(env)}/api/kody/engine/secret`, {
|
|
@@ -15866,6 +15900,9 @@ var init_loadSimpleCapability = __esm({
|
|
|
15866
15900
|
ctx.data.jobCapability = slug;
|
|
15867
15901
|
ctx.data.capabilityInput = input;
|
|
15868
15902
|
ctx.data.capabilityExecution = capability.contract?.execution ?? "agent";
|
|
15903
|
+
if (capability.contract?.requirements) {
|
|
15904
|
+
ctx.data.capabilityRequirements = capability.contract.requirements;
|
|
15905
|
+
}
|
|
15869
15906
|
if (ctx.data.capabilityExecution === "agent") {
|
|
15870
15907
|
registerCapabilitySubagents(profile, toolRoot, toolFiles);
|
|
15871
15908
|
}
|
|
@@ -17693,6 +17730,53 @@ var init_prepareBrowserAuth = __esm({
|
|
|
17693
17730
|
}
|
|
17694
17731
|
});
|
|
17695
17732
|
|
|
17733
|
+
// src/scripts/prepareSimpleCapabilityRuntime.ts
|
|
17734
|
+
function requirementsFrom(ctx) {
|
|
17735
|
+
const raw = ctx.data.capabilityRequirements;
|
|
17736
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
17737
|
+
}
|
|
17738
|
+
function configureBrowser(profile) {
|
|
17739
|
+
if (!profile.claudeCode.tools.includes("mcp__playwright")) {
|
|
17740
|
+
profile.claudeCode.tools = [...profile.claudeCode.tools, "mcp__playwright"];
|
|
17741
|
+
}
|
|
17742
|
+
if (!profile.claudeCode.mcpServers.some(({ name }) => name === PLAYWRIGHT_SERVER.name)) {
|
|
17743
|
+
profile.claudeCode.mcpServers = [...profile.claudeCode.mcpServers, PLAYWRIGHT_SERVER];
|
|
17744
|
+
}
|
|
17745
|
+
}
|
|
17746
|
+
function appendPrompt(ctx, section) {
|
|
17747
|
+
const prompt = typeof ctx.data.prompt === "string" ? ctx.data.prompt.trim() : "";
|
|
17748
|
+
ctx.data.prompt = [prompt, section.trim()].filter(Boolean).join("\n\n");
|
|
17749
|
+
}
|
|
17750
|
+
var PLAYWRIGHT_SERVER, prepareSimpleCapabilityRuntime;
|
|
17751
|
+
var init_prepareSimpleCapabilityRuntime = __esm({
|
|
17752
|
+
"src/scripts/prepareSimpleCapabilityRuntime.ts"() {
|
|
17753
|
+
"use strict";
|
|
17754
|
+
init_loadQaContext();
|
|
17755
|
+
PLAYWRIGHT_SERVER = {
|
|
17756
|
+
name: "playwright",
|
|
17757
|
+
command: "npx",
|
|
17758
|
+
args: ["-y", "--package=@playwright/mcp@latest", "--", "playwright-mcp", "--headless"]
|
|
17759
|
+
};
|
|
17760
|
+
prepareSimpleCapabilityRuntime = async (ctx, profile) => {
|
|
17761
|
+
const requirements = requirementsFrom(ctx);
|
|
17762
|
+
if (!requirements.browser) return;
|
|
17763
|
+
configureBrowser(profile);
|
|
17764
|
+
if (!requirements.qaCredentials) return;
|
|
17765
|
+
await loadQaContext(ctx, profile);
|
|
17766
|
+
appendPrompt(
|
|
17767
|
+
ctx,
|
|
17768
|
+
[
|
|
17769
|
+
"## QA authentication",
|
|
17770
|
+
"",
|
|
17771
|
+
String(ctx.data.qaAuthBlock ?? ""),
|
|
17772
|
+
"",
|
|
17773
|
+
"If the changed surface requires authentication and the credentials are missing or the login is rejected, return a blocked result with a safe explanation. Do not include usernames, passwords, tokens, or other credential values in the result."
|
|
17774
|
+
].join("\n")
|
|
17775
|
+
);
|
|
17776
|
+
};
|
|
17777
|
+
}
|
|
17778
|
+
});
|
|
17779
|
+
|
|
17696
17780
|
// src/capabilityDelivery.ts
|
|
17697
17781
|
function capabilityDeliveryTarget(input) {
|
|
17698
17782
|
if (!input || typeof input !== "object" || Array.isArray(input)) return null;
|
|
@@ -20973,6 +21057,7 @@ var init_scripts = __esm({
|
|
|
20973
21057
|
init_postResearchComment();
|
|
20974
21058
|
init_postReviewResult();
|
|
20975
21059
|
init_prepareBrowserAuth();
|
|
21060
|
+
init_prepareSimpleCapabilityRuntime();
|
|
20976
21061
|
init_prepareCapabilityDelivery();
|
|
20977
21062
|
init_promoteQaGoal();
|
|
20978
21063
|
init_publishReport();
|
|
@@ -21036,6 +21121,7 @@ var init_scripts = __esm({
|
|
|
21036
21121
|
loadPriorArt,
|
|
21037
21122
|
loadQaContext,
|
|
21038
21123
|
prepareBrowserAuth,
|
|
21124
|
+
prepareSimpleCapabilityRuntime,
|
|
21039
21125
|
prepareCapabilityDelivery,
|
|
21040
21126
|
buildSyntheticPlugin,
|
|
21041
21127
|
resolveArtifacts,
|
|
@@ -22554,6 +22640,18 @@ async function runJob(job, base) {
|
|
|
22554
22640
|
if (valid.workflowRunId && workflowIdentity && base.config && result.workflowState) {
|
|
22555
22641
|
await writeWorkflowRunState(base.config, base.cwd, workflowIdentity, valid.workflowRunId, result.workflowState);
|
|
22556
22642
|
}
|
|
22643
|
+
if (valid.workflowRunId && workflowIdentity && hasGitHubActionsIdentity()) {
|
|
22644
|
+
const facts = result.workflowState?.facts ?? {};
|
|
22645
|
+
const pr = typeof facts.pr === "number" ? facts.pr : typeof valid.cliArgs.pr === "number" ? valid.cliArgs.pr : void 0;
|
|
22646
|
+
const headSha = typeof facts.headSha === "string" ? facts.headSha : typeof valid.cliArgs.headSha === "string" ? valid.cliArgs.headSha : void 0;
|
|
22647
|
+
await notifyWorkflowCompleted({
|
|
22648
|
+
workflowId: workflowIdentity,
|
|
22649
|
+
runId: valid.workflowRunId,
|
|
22650
|
+
status: result.workflowState?.status === "blocked" ? "blocked" : result.exitCode === 0 ? "success" : "failed",
|
|
22651
|
+
...result.reason ? { summary: result.reason } : {},
|
|
22652
|
+
...pr !== void 0 || headSha !== void 0 ? { output: { ...pr !== void 0 ? { pr } : {}, ...headSha ? { headSha } : {} } } : {}
|
|
22653
|
+
});
|
|
22654
|
+
}
|
|
22557
22655
|
return result;
|
|
22558
22656
|
}
|
|
22559
22657
|
if (!profileName) {
|
|
@@ -22886,7 +22984,8 @@ async function runGraphCapabilityWorkflow(parent, workflow, capability, base, ch
|
|
|
22886
22984
|
};
|
|
22887
22985
|
if (!state.completedStepIds.includes(step.id)) state.completedStepIds.push(step.id);
|
|
22888
22986
|
if (result.exitCode !== 0 && !canContinueWorkflow(step, outcome)) {
|
|
22889
|
-
|
|
22987
|
+
const lastResult = result.capabilityResults?.at(-1);
|
|
22988
|
+
state.status = lastResult?.status === "blocked" ? "blocked" : "failed";
|
|
22890
22989
|
state.blocker = result.reason ?? `workflow step ${step.id} failed`;
|
|
22891
22990
|
await checkpoint?.(state);
|
|
22892
22991
|
return withWorkflowBoundaryEval(capability, { ...result, workflowState: state });
|
|
@@ -22929,14 +23028,17 @@ async function runGraphCapabilityWorkflow(parent, workflow, capability, base, ch
|
|
|
22929
23028
|
}
|
|
22930
23029
|
async function completeWorkflowAtTerminal(capability, state, output, checkpoint) {
|
|
22931
23030
|
const result = output.capabilityResults?.at(-1);
|
|
22932
|
-
|
|
22933
|
-
|
|
22934
|
-
|
|
23031
|
+
const customStatus = output.capabilityOutput && typeof output.capabilityOutput === "object" && !Array.isArray(output.capabilityOutput) && typeof output.capabilityOutput.status === "string" ? output.capabilityOutput.status : void 0;
|
|
23032
|
+
const terminalFailure = result?.status === "fail" || customStatus === "fail" ? "failed" : result?.status === "blocked" || customStatus === "blocked" ? "blocked" : null;
|
|
23033
|
+
if (terminalFailure) {
|
|
23034
|
+
const summary = result?.summary ?? (typeof output.capabilityOutput?.summary === "string" ? output.capabilityOutput.summary : "Workflow ended without a usable result");
|
|
23035
|
+
state.status = terminalFailure;
|
|
23036
|
+
state.blocker = summary;
|
|
22935
23037
|
await checkpoint?.(state);
|
|
22936
23038
|
return withWorkflowBoundaryEval(capability, {
|
|
22937
23039
|
...output,
|
|
22938
|
-
exitCode:
|
|
22939
|
-
reason:
|
|
23040
|
+
exitCode: terminalFailure === "failed" ? 1 : 64,
|
|
23041
|
+
reason: summary,
|
|
22940
23042
|
workflowState: state
|
|
22941
23043
|
});
|
|
22942
23044
|
}
|
|
@@ -23239,6 +23341,7 @@ var init_job = __esm({
|
|
|
23239
23341
|
init_registry();
|
|
23240
23342
|
init_runIndex();
|
|
23241
23343
|
init_publishReport();
|
|
23344
|
+
init_kody_api_client();
|
|
23242
23345
|
init_simpleCapabilityRuntime();
|
|
23243
23346
|
init_state_backend();
|
|
23244
23347
|
init_workflowDefinitions();
|
|
@@ -38,6 +38,10 @@
|
|
|
38
38
|
"scripts": {
|
|
39
39
|
"preflight": [
|
|
40
40
|
{ "script": "loadSimpleCapability" },
|
|
41
|
+
{
|
|
42
|
+
"script": "prepareSimpleCapabilityRuntime",
|
|
43
|
+
"runWhen": { "data.capabilityExecution": "agent" }
|
|
44
|
+
},
|
|
41
45
|
{
|
|
42
46
|
"script": "runSimpleCapabilityScript",
|
|
43
47
|
"runWhen": { "data.capabilityExecution": "script" }
|
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.536",
|
|
4
4
|
"description": "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|