@kody-ade/kody-engine 0.4.535 → 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.535",
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);
@@ -15876,6 +15900,9 @@ var init_loadSimpleCapability = __esm({
15876
15900
  ctx.data.jobCapability = slug;
15877
15901
  ctx.data.capabilityInput = input;
15878
15902
  ctx.data.capabilityExecution = capability.contract?.execution ?? "agent";
15903
+ if (capability.contract?.requirements) {
15904
+ ctx.data.capabilityRequirements = capability.contract.requirements;
15905
+ }
15879
15906
  if (ctx.data.capabilityExecution === "agent") {
15880
15907
  registerCapabilitySubagents(profile, toolRoot, toolFiles);
15881
15908
  }
@@ -17703,6 +17730,53 @@ var init_prepareBrowserAuth = __esm({
17703
17730
  }
17704
17731
  });
17705
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
+
17706
17780
  // src/capabilityDelivery.ts
17707
17781
  function capabilityDeliveryTarget(input) {
17708
17782
  if (!input || typeof input !== "object" || Array.isArray(input)) return null;
@@ -20983,6 +21057,7 @@ var init_scripts = __esm({
20983
21057
  init_postResearchComment();
20984
21058
  init_postReviewResult();
20985
21059
  init_prepareBrowserAuth();
21060
+ init_prepareSimpleCapabilityRuntime();
20986
21061
  init_prepareCapabilityDelivery();
20987
21062
  init_promoteQaGoal();
20988
21063
  init_publishReport();
@@ -21046,6 +21121,7 @@ var init_scripts = __esm({
21046
21121
  loadPriorArt,
21047
21122
  loadQaContext,
21048
21123
  prepareBrowserAuth,
21124
+ prepareSimpleCapabilityRuntime,
21049
21125
  prepareCapabilityDelivery,
21050
21126
  buildSyntheticPlugin,
21051
21127
  resolveArtifacts,
@@ -22571,7 +22647,8 @@ async function runJob(job, base) {
22571
22647
  await notifyWorkflowCompleted({
22572
22648
  workflowId: workflowIdentity,
22573
22649
  runId: valid.workflowRunId,
22574
- status: result.exitCode === 0 ? "success" : "failed",
22650
+ status: result.workflowState?.status === "blocked" ? "blocked" : result.exitCode === 0 ? "success" : "failed",
22651
+ ...result.reason ? { summary: result.reason } : {},
22575
22652
  ...pr !== void 0 || headSha !== void 0 ? { output: { ...pr !== void 0 ? { pr } : {}, ...headSha ? { headSha } : {} } } : {}
22576
22653
  });
22577
22654
  }
@@ -22907,7 +22984,8 @@ async function runGraphCapabilityWorkflow(parent, workflow, capability, base, ch
22907
22984
  };
22908
22985
  if (!state.completedStepIds.includes(step.id)) state.completedStepIds.push(step.id);
22909
22986
  if (result.exitCode !== 0 && !canContinueWorkflow(step, outcome)) {
22910
- state.status = "failed";
22987
+ const lastResult = result.capabilityResults?.at(-1);
22988
+ state.status = lastResult?.status === "blocked" ? "blocked" : "failed";
22911
22989
  state.blocker = result.reason ?? `workflow step ${step.id} failed`;
22912
22990
  await checkpoint?.(state);
22913
22991
  return withWorkflowBoundaryEval(capability, { ...result, workflowState: state });
@@ -22950,14 +23028,17 @@ async function runGraphCapabilityWorkflow(parent, workflow, capability, base, ch
22950
23028
  }
22951
23029
  async function completeWorkflowAtTerminal(capability, state, output, checkpoint) {
22952
23030
  const result = output.capabilityResults?.at(-1);
22953
- if (result?.status === "fail" || result?.status === "blocked") {
22954
- state.status = result.status === "fail" ? "failed" : "blocked";
22955
- state.blocker = result.summary;
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;
22956
23037
  await checkpoint?.(state);
22957
23038
  return withWorkflowBoundaryEval(capability, {
22958
23039
  ...output,
22959
- exitCode: result.status === "fail" ? 1 : 64,
22960
- reason: result.summary,
23040
+ exitCode: terminalFailure === "failed" ? 1 : 64,
23041
+ reason: summary,
22961
23042
  workflowState: state
22962
23043
  });
22963
23044
  }
@@ -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.535",
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",