@kody-ade/kody-engine 0.4.561 → 0.4.562

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.561",
18
+ version: "0.4.562",
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",
@@ -671,11 +671,22 @@ var init_format = __esm({
671
671
 
672
672
  // src/agency/capability-contract-validation.ts
673
673
  import Ajv from "ajv";
674
- function validateCapabilityContractValue(boundary, schema, value) {
675
- const validate = validator.compile(schema);
676
- if (!validate(value)) {
677
- throw new CapabilityContractValidationError(boundary, validate.errors ?? []);
678
- }
674
+ function createCapabilityContractValueValidator(compile) {
675
+ const compiled = /* @__PURE__ */ new WeakMap();
676
+ return (boundary, schema, value) => {
677
+ let validate = compiled.get(schema);
678
+ if (!validate) {
679
+ validate = compile(schema);
680
+ compiled.set(schema, validate);
681
+ }
682
+ if (!validate(value)) {
683
+ throw new CapabilityContractValidationError(boundary, validate.errors ?? []);
684
+ }
685
+ };
686
+ }
687
+ function validateCapabilityContractOutput(schema, value) {
688
+ if (value === void 0) throw new CapabilityContractMissingOutputError();
689
+ validateCapabilityContractValue("output", schema, value);
679
690
  }
680
691
  function capabilityContractInput(inputs, args, capabilityId, contractProperties = []) {
681
692
  const isGenericRunnerInput = inputs.some((input) => input.name === "input") && Object.hasOwn(args, "input");
@@ -693,7 +704,7 @@ function capabilityContractInput(inputs, args, capabilityId, contractProperties
693
704
  return value;
694
705
  }
695
706
  }
696
- var validator, CapabilityContractValidationError;
707
+ var validator, CapabilityContractValidationError, CapabilityContractMissingOutputError, validateCapabilityContractValue;
697
708
  var init_capability_contract_validation = __esm({
698
709
  "src/agency/capability-contract-validation.ts"() {
699
710
  "use strict";
@@ -717,6 +728,15 @@ var init_capability_contract_validation = __esm({
717
728
  boundary;
718
729
  errors;
719
730
  };
731
+ CapabilityContractMissingOutputError = class extends Error {
732
+ constructor() {
733
+ super("Capability output is missing despite its declared contract");
734
+ this.name = "CapabilityContractMissingOutputError";
735
+ }
736
+ };
737
+ validateCapabilityContractValue = createCapabilityContractValueValidator(
738
+ (schema) => validator.compile(schema)
739
+ );
720
740
  }
721
741
  });
722
742
 
@@ -731,7 +751,7 @@ function outputContractError(contract) {
731
751
  return `The required output file is missing or is not valid JSON: ${error instanceof Error ? error.message : String(error)}`;
732
752
  }
733
753
  try {
734
- validateCapabilityContractValue("output", contract.schema, value);
754
+ validateCapabilityContractOutput(contract.schema, value);
735
755
  return null;
736
756
  } catch (error) {
737
757
  return error instanceof Error ? error.message : String(error);
@@ -2012,20 +2032,52 @@ function listCapabilityFolderSlugs(absDir) {
2012
2032
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).filter((e) => isCapabilityFolder(path8.join(absDir, e.name))).map((e) => e.name).sort();
2013
2033
  }
2014
2034
  function isCapabilityFolder(dir) {
2015
- if (!fs7.existsSync(path8.join(dir, CAPABILITY_BODY_FILE))) return false;
2016
2035
  const entries = fs7.readdirSync(dir, { withFileTypes: true });
2036
+ const legacyBody = path8.join(dir, CAPABILITY_BODY_FILE);
2037
+ if (fs7.existsSync(legacyBody)) {
2038
+ return entries.every(
2039
+ (entry) => entry.name === CAPABILITY_BODY_FILE || entry.name === CAPABILITY_CONTRACT_FILE || entry.isDirectory() && (entry.name === "skills" || entry.name === "tools")
2040
+ );
2041
+ }
2042
+ const canonicalBody = path8.join(dir, CANONICAL_CAPABILITY_BODY_FILE);
2043
+ const canonicalDefinition = path8.join(dir, CANONICAL_CAPABILITY_DEFINITION_FILE);
2044
+ if (!fs7.existsSync(canonicalBody) || !fs7.existsSync(canonicalDefinition)) return false;
2017
2045
  return entries.every(
2018
- (entry) => entry.name === CAPABILITY_BODY_FILE || entry.name === CAPABILITY_CONTRACT_FILE || entry.isDirectory() && (entry.name === "skills" || entry.name === "tools")
2046
+ (entry) => entry.name === CANONICAL_CAPABILITY_BODY_FILE || entry.name === CANONICAL_CAPABILITY_DEFINITION_FILE
2019
2047
  );
2020
2048
  }
2021
2049
  function readCapabilityFolder(root, slug) {
2022
2050
  const dir = path8.join(root, slug);
2023
- const bodyPath = path8.join(dir, CAPABILITY_BODY_FILE);
2051
+ const legacyBodyPath = path8.join(dir, CAPABILITY_BODY_FILE);
2052
+ const canonicalBodyPath = path8.join(dir, CANONICAL_CAPABILITY_BODY_FILE);
2053
+ const bodyPath = fs7.existsSync(legacyBodyPath) ? legacyBodyPath : canonicalBodyPath;
2024
2054
  const contractPath = path8.join(dir, CAPABILITY_CONTRACT_FILE);
2025
2055
  if (!fs7.existsSync(bodyPath) || !fs7.statSync(bodyPath).isFile()) return null;
2026
2056
  if (!isCapabilityFolder(dir)) return null;
2027
2057
  try {
2028
2058
  const rawBody = fs7.readFileSync(bodyPath, "utf-8");
2059
+ if (bodyPath === canonicalBodyPath) {
2060
+ const definitionPath = path8.join(dir, CANONICAL_CAPABILITY_DEFINITION_FILE);
2061
+ const definition = JSON.parse(fs7.readFileSync(definitionPath, "utf-8"));
2062
+ if (definition.id !== slug || typeof definition.action !== "string") return null;
2063
+ const { title: title2, body: body2 } = parseCapabilityBody(rawBody, slug);
2064
+ return {
2065
+ slug,
2066
+ dir,
2067
+ profilePath: definitionPath,
2068
+ bodyPath,
2069
+ title: title2,
2070
+ body: body2,
2071
+ rawBody,
2072
+ config: {
2073
+ action: definition.action,
2074
+ describe: typeof definition.purpose === "string" ? definition.purpose : title2,
2075
+ ...isPlainObject(definition.inputSchema) ? { inputSchema: definition.inputSchema } : {},
2076
+ ...isPlainObject(definition.outputSchema) ? { outputSchema: definition.outputSchema } : {}
2077
+ },
2078
+ rawProfile: definition
2079
+ };
2080
+ }
2029
2081
  const contract = fs7.existsSync(contractPath) ? parseCapabilityContract(fs7.readFileSync(contractPath, "utf-8")) : void 0;
2030
2082
  if (contract?.execution === "script" && !isRegularFile(path8.join(dir, "tools", "run.sh"))) {
2031
2083
  throw new Error('script-backed Capability requires a regular "tools/run.sh" file');
@@ -2301,13 +2353,15 @@ function isSafeSlug(value) {
2301
2353
  function isSafeStepId(value) {
2302
2354
  return /^[A-Za-z][A-Za-z0-9_-]*$/.test(value) && !value.includes("..");
2303
2355
  }
2304
- var CAPABILITY_BODY_FILE, CAPABILITY_CONTRACT_FILE, CAPABILITY_PROFILE_FILE;
2356
+ var CAPABILITY_BODY_FILE, CAPABILITY_CONTRACT_FILE, CAPABILITY_PROFILE_FILE, CANONICAL_CAPABILITY_BODY_FILE, CANONICAL_CAPABILITY_DEFINITION_FILE;
2305
2357
  var init_capabilityFolders = __esm({
2306
2358
  "src/capabilityFolders.ts"() {
2307
2359
  "use strict";
2308
2360
  CAPABILITY_BODY_FILE = "instructions.md";
2309
2361
  CAPABILITY_CONTRACT_FILE = "contract.json";
2310
2362
  CAPABILITY_PROFILE_FILE = CAPABILITY_BODY_FILE;
2363
+ CANONICAL_CAPABILITY_BODY_FILE = "capability.md";
2364
+ CANONICAL_CAPABILITY_DEFINITION_FILE = "definition.json";
2311
2365
  }
2312
2366
  });
2313
2367
 
@@ -2498,6 +2552,7 @@ function resolveCapabilityFolder(slug, projectCapabilitiesRoot = getProjectCapab
2498
2552
  function getCapabilityActionInputs(action, projectCapabilitiesRoot = getProjectCapabilitiesRoot()) {
2499
2553
  const resolved = resolveCapabilityAction(action, projectCapabilitiesRoot);
2500
2554
  if (!resolved) return null;
2555
+ if (resolved.source === "builtin") return getProfileInputs(resolved.implementation);
2501
2556
  const capability = resolveCapabilityFolder(resolved.capability, projectCapabilitiesRoot);
2502
2557
  if (capability && !capability.config.workflow) {
2503
2558
  return [
@@ -17251,7 +17306,7 @@ var init_parseSimpleCapabilityOutput = __esm({
17251
17306
  const outputSchema = isObject2(ctx.data.capabilityOutputSchema) ? ctx.data.capabilityOutputSchema : void 0;
17252
17307
  if (outputSchema) {
17253
17308
  try {
17254
- validateCapabilityContractValue("output", outputSchema, output);
17309
+ validateCapabilityContractOutput(outputSchema, output);
17255
17310
  } catch (error) {
17256
17311
  const reason2 = error instanceof Error ? error.message : String(error);
17257
17312
  ctx.output.exitCode = 64;
@@ -22221,8 +22276,7 @@ async function runImplementation(profileName, input) {
22221
22276
  const capabilityResults = Array.isArray(ctx.data.capabilityResults) ? ctx.data.capabilityResults : void 0;
22222
22277
  if (profile.canonicalContract) {
22223
22278
  try {
22224
- validateCapabilityContractValue(
22225
- "output",
22279
+ validateCapabilityContractOutput(
22226
22280
  profile.canonicalContract.outputSchema,
22227
22281
  capabilityResults?.at(-1) ?? {
22228
22282
  exitCode: ctx.output.exitCode ?? 0,
@@ -23197,11 +23251,11 @@ async function runCapabilityImplementationStep(valid, profileName, capabilityIde
23197
23251
  }
23198
23252
  function enforceCapabilityOutputContract(capability, result) {
23199
23253
  const schema = capability?.config.outputSchema;
23200
- if (result.exitCode !== 0 || !schema || !Object.hasOwn(result, "capabilityOutput")) {
23254
+ if (result.exitCode !== 0 || !schema) {
23201
23255
  return result;
23202
23256
  }
23203
23257
  try {
23204
- validateCapabilityContractValue("output", schema, result.capabilityOutput);
23258
+ validateCapabilityContractOutput(schema, result.capabilityOutput);
23205
23259
  return result;
23206
23260
  } catch (error) {
23207
23261
  const reason = error instanceof Error ? error.message : String(error);
@@ -23937,8 +23991,8 @@ var DEFAULT_INSTANT_AGENT, localJobSeq, InvalidJobError;
23937
23991
  var init_job = __esm({
23938
23992
  "src/job.ts"() {
23939
23993
  "use strict";
23940
- init_agencyBoundaryEval();
23941
23994
  init_capability_contract_validation();
23995
+ init_agencyBoundaryEval();
23942
23996
  init_capabilityFolders();
23943
23997
  init_config();
23944
23998
  init_definition_paths();
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.561",
3
+ "version": "0.4.562",
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",
@@ -12,30 +12,6 @@
12
12
  "templates",
13
13
  "kody.config.schema.json"
14
14
  ],
15
- "scripts": {
16
- "kody:run": "tsx bin/kody.ts",
17
- "serve": "tsx bin/kody.ts serve",
18
- "serve:vscode": "tsx bin/kody.ts serve vscode",
19
- "serve:claude": "tsx bin/kody.ts serve claude",
20
- "clean:dist": "node scripts/clean-dist.cjs",
21
- "build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
22
- "check:modularity": "tsx scripts/check-script-modularity.ts",
23
- "pretest": "pnpm check:modularity",
24
- "test": "vitest run tests/unit tests/int --coverage",
25
- "posttest": "tsx scripts/check-coverage-floor.ts",
26
- "test:smoke": "vitest run tests/smoke --no-coverage",
27
- "test:e2e": "vitest run tests/e2e --no-coverage",
28
- "verify:live-release": "tsx scripts/live-release-gate.ts",
29
- "test:runtime-services": "node --test \"tests/runtime-services/*.test.mjs\"",
30
- "test:all": "vitest run tests --no-coverage",
31
- "typecheck": "tsc --noEmit",
32
- "lint": "biome check",
33
- "lint:fix": "biome check --write",
34
- "format": "biome format --write",
35
- "verify:package": "node scripts/verify-package-tarball.cjs",
36
- "brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain --build-arg KODY_ENGINE_REF=$(git rev-parse HEAD) -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner",
37
- "prepublishOnly": "pnpm typecheck && pnpm test:runtime-services && pnpm build && pnpm verify:package"
38
- },
39
15
  "dependencies": {
40
16
  "@actions/cache": "^6.0.0",
41
17
  "@anthropic-ai/claude-agent-sdk": "0.2.119",
@@ -62,5 +38,28 @@
62
38
  "url": "git+https://github.com/aharonyaircohen/kody-engine.git"
63
39
  },
64
40
  "homepage": "https://github.com/aharonyaircohen/kody-engine",
65
- "bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
66
- }
41
+ "bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
42
+ "scripts": {
43
+ "kody:run": "tsx bin/kody.ts",
44
+ "serve": "tsx bin/kody.ts serve",
45
+ "serve:vscode": "tsx bin/kody.ts serve vscode",
46
+ "serve:claude": "tsx bin/kody.ts serve claude",
47
+ "clean:dist": "node scripts/clean-dist.cjs",
48
+ "build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
49
+ "check:modularity": "tsx scripts/check-script-modularity.ts",
50
+ "pretest": "pnpm check:modularity",
51
+ "test": "vitest run tests/unit tests/int --coverage",
52
+ "posttest": "tsx scripts/check-coverage-floor.ts",
53
+ "test:smoke": "vitest run tests/smoke --no-coverage",
54
+ "test:e2e": "vitest run tests/e2e --no-coverage",
55
+ "verify:live-release": "tsx scripts/live-release-gate.ts",
56
+ "test:runtime-services": "node --test \"tests/runtime-services/*.test.mjs\"",
57
+ "test:all": "vitest run tests --no-coverage",
58
+ "typecheck": "tsc --noEmit",
59
+ "lint": "biome check",
60
+ "lint:fix": "biome check --write",
61
+ "format": "biome format --write",
62
+ "verify:package": "node scripts/verify-package-tarball.cjs",
63
+ "brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain --build-arg KODY_ENGINE_REF=$(git rev-parse HEAD) -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner"
64
+ }
65
+ }