@kody-ade/kody-engine 0.4.561 → 0.4.563

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.563",
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
 
@@ -2484,6 +2538,10 @@ function resolveCapabilityAction(action, projectCapabilitiesRoot = getProjectCap
2484
2538
  if (!isSafeName(action)) return null;
2485
2539
  return listCapabilityActions(projectCapabilitiesRoot).find((d) => d.action === action) ?? null;
2486
2540
  }
2541
+ function resolveOperatorCapabilityAction(action, projectCapabilitiesRoot = getProjectCapabilitiesRoot()) {
2542
+ if (!isSafeName(action)) return null;
2543
+ return listBuiltinCapabilityActions(getBuiltinCapabilitiesRoot()).find((candidate) => candidate.action === action) ?? resolveCapabilityAction(action, projectCapabilitiesRoot);
2544
+ }
2487
2545
  function hasCapabilityAction(action, projectCapabilitiesRoot = getProjectCapabilitiesRoot()) {
2488
2546
  return resolveCapabilityAction(action, projectCapabilitiesRoot) !== null;
2489
2547
  }
@@ -2498,6 +2556,7 @@ function resolveCapabilityFolder(slug, projectCapabilitiesRoot = getProjectCapab
2498
2556
  function getCapabilityActionInputs(action, projectCapabilitiesRoot = getProjectCapabilitiesRoot()) {
2499
2557
  const resolved = resolveCapabilityAction(action, projectCapabilitiesRoot);
2500
2558
  if (!resolved) return null;
2559
+ if (resolved.source === "builtin") return getProfileInputs(resolved.implementation);
2501
2560
  const capability = resolveCapabilityFolder(resolved.capability, projectCapabilitiesRoot);
2502
2561
  if (capability && !capability.config.workflow) {
2503
2562
  return [
@@ -17251,7 +17310,7 @@ var init_parseSimpleCapabilityOutput = __esm({
17251
17310
  const outputSchema = isObject2(ctx.data.capabilityOutputSchema) ? ctx.data.capabilityOutputSchema : void 0;
17252
17311
  if (outputSchema) {
17253
17312
  try {
17254
- validateCapabilityContractValue("output", outputSchema, output);
17313
+ validateCapabilityContractOutput(outputSchema, output);
17255
17314
  } catch (error) {
17256
17315
  const reason2 = error instanceof Error ? error.message : String(error);
17257
17316
  ctx.output.exitCode = 64;
@@ -22221,8 +22280,7 @@ async function runImplementation(profileName, input) {
22221
22280
  const capabilityResults = Array.isArray(ctx.data.capabilityResults) ? ctx.data.capabilityResults : void 0;
22222
22281
  if (profile.canonicalContract) {
22223
22282
  try {
22224
- validateCapabilityContractValue(
22225
- "output",
22283
+ validateCapabilityContractOutput(
22226
22284
  profile.canonicalContract.outputSchema,
22227
22285
  capabilityResults?.at(-1) ?? {
22228
22286
  exitCode: ctx.output.exitCode ?? 0,
@@ -23197,11 +23255,11 @@ async function runCapabilityImplementationStep(valid, profileName, capabilityIde
23197
23255
  }
23198
23256
  function enforceCapabilityOutputContract(capability, result) {
23199
23257
  const schema = capability?.config.outputSchema;
23200
- if (result.exitCode !== 0 || !schema || !Object.hasOwn(result, "capabilityOutput")) {
23258
+ if (result.exitCode !== 0 || !schema) {
23201
23259
  return result;
23202
23260
  }
23203
23261
  try {
23204
- validateCapabilityContractValue("output", schema, result.capabilityOutput);
23262
+ validateCapabilityContractOutput(schema, result.capabilityOutput);
23205
23263
  return result;
23206
23264
  } catch (error) {
23207
23265
  const reason = error instanceof Error ? error.message : String(error);
@@ -23937,8 +23995,8 @@ var DEFAULT_INSTANT_AGENT, localJobSeq, InvalidJobError;
23937
23995
  var init_job = __esm({
23938
23996
  "src/job.ts"() {
23939
23997
  "use strict";
23940
- init_agencyBoundaryEval();
23941
23998
  init_capability_contract_validation();
23999
+ init_agencyBoundaryEval();
23942
24000
  init_capabilityFolders();
23943
24001
  init_config();
23944
24002
  init_definition_paths();
@@ -25519,10 +25577,10 @@ function primaryNumericInputName(implementation) {
25519
25577
  return intInput?.name ?? null;
25520
25578
  }
25521
25579
  function resolveOperatorAction(action, projectCapabilitiesRoot) {
25522
- return resolveCapabilityAction(action, projectCapabilitiesRoot);
25580
+ return resolveOperatorCapabilityAction(action, projectCapabilitiesRoot);
25523
25581
  }
25524
25582
  function resolveConfiguredAction(action, projectCapabilitiesRoot) {
25525
- return resolveCapabilityAction(action, projectCapabilitiesRoot);
25583
+ return resolveOperatorCapabilityAction(action, projectCapabilitiesRoot);
25526
25584
  }
25527
25585
  function requiredRoute(action, projectCapabilitiesRoot) {
25528
25586
  const route = resolveConfiguredAction(action, projectCapabilitiesRoot);
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.563",
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
+ }