@kody-ade/kody-engine 0.4.430 → 0.4.431

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.430",
18
+ version: "0.4.431",
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",
@@ -54,6 +54,7 @@ var init_package = __esm({
54
54
  "@anthropic-ai/claude-agent-sdk": "0.2.119",
55
55
  "@kody-ade/agency-domain": "0.5.1",
56
56
  "@modelcontextprotocol/sdk": "^1.29.0",
57
+ ajv: "^8.18.0",
57
58
  convex: "^1.17.0",
58
59
  zod: "^4.0.0"
59
60
  },
@@ -255,6 +256,7 @@ function loadConfig(projectDir = process.cwd()) {
255
256
  ...parsePerImplementationReasoningEffort(agent.perImplementationReasoningEffort),
256
257
  ...parseAgentReasoningEffort(agent.reasoningEffort)
257
258
  },
259
+ execution: parseExecutionConfig(raw.execution),
258
260
  issueContext: parseIssueContext(raw.issueContext),
259
261
  testRequirements: parseTestRequirements(raw.testRequirements),
260
262
  defaultImplementation: typeof raw.defaultImplementation === "string" && raw.defaultImplementation.length > 0 ? raw.defaultImplementation : "run",
@@ -267,6 +269,18 @@ function loadConfig(projectDir = process.cwd()) {
267
269
  access: parseAccessConfig(raw.access)
268
270
  };
269
271
  }
272
+ function parseExecutionConfig(value) {
273
+ const execution = recordValue(value);
274
+ const bindings = recordValue(execution?.capabilityBindings);
275
+ if (!bindings) return void 0;
276
+ const capabilityBindings = {};
277
+ for (const [capabilityId, implementationId] of Object.entries(bindings)) {
278
+ if (/^[a-z][a-z0-9-]*$/.test(capabilityId) && typeof implementationId === "string" && /^[a-z][a-z0-9-]*$/.test(implementationId)) {
279
+ capabilityBindings[capabilityId] = implementationId;
280
+ }
281
+ }
282
+ return Object.keys(capabilityBindings).length > 0 ? { capabilityBindings } : void 0;
283
+ }
270
284
  function parseAccessConfig(raw) {
271
285
  if (raw === void 0 || raw === null) {
272
286
  return { allowedAssociations: [...DEFAULT_ALLOWED_ASSOCIATIONS] };
@@ -1631,10 +1645,71 @@ var init_issue = __esm({
1631
1645
  }
1632
1646
  });
1633
1647
 
1648
+ // src/agency/implementation-resolution.ts
1649
+ function resolveCapabilityImplementation(input) {
1650
+ const compatible = input.implementations.filter(
1651
+ (implementation) => implementation.capabilityRef.id === input.capabilityId && implementation.compatibleCapabilityRevision === input.capabilityRevision
1652
+ );
1653
+ if (input.explicitOverride) {
1654
+ if (!input.authorizeOverride?.(input.explicitOverride)) {
1655
+ throw new ImplementationResolutionError(`Implementation override "${input.explicitOverride}" is not authorized`);
1656
+ }
1657
+ return selectNamed(input.explicitOverride, input, compatible, "override");
1658
+ }
1659
+ if (input.repositoryBinding) {
1660
+ return selectNamed(input.repositoryBinding, input, compatible, "repository binding");
1661
+ }
1662
+ if (compatible.length === 1) return compatible[0];
1663
+ if (compatible.length === 0) {
1664
+ throw new ImplementationResolutionError(
1665
+ `No compatible Implementation is available for Capability "${input.capabilityId}" at revision "${input.capabilityRevision}"`
1666
+ );
1667
+ }
1668
+ throw new ImplementationResolutionError(
1669
+ `Capability "${input.capabilityId}" has ${compatible.length} compatible Implementations; configure a repository binding`
1670
+ );
1671
+ }
1672
+ function selectNamed(id, input, compatible, source) {
1673
+ const known = input.implementations.find((implementation) => implementation.id === id);
1674
+ if (!known) {
1675
+ throw new ImplementationResolutionError(`Implementation ${source} "${id}" is not available`);
1676
+ }
1677
+ const selected = compatible.find((implementation) => implementation.id === id);
1678
+ if (!selected) {
1679
+ throw new ImplementationResolutionError(
1680
+ `Implementation ${source} "${id}" is not compatible with Capability "${input.capabilityId}" at revision "${input.capabilityRevision}"`
1681
+ );
1682
+ }
1683
+ return selected;
1684
+ }
1685
+ var ImplementationResolutionError;
1686
+ var init_implementation_resolution = __esm({
1687
+ "src/agency/implementation-resolution.ts"() {
1688
+ "use strict";
1689
+ ImplementationResolutionError = class extends Error {
1690
+ constructor(message) {
1691
+ super(message);
1692
+ this.name = "ImplementationResolutionError";
1693
+ }
1694
+ };
1695
+ }
1696
+ });
1697
+
1634
1698
  // src/capabilityFolders.ts
1635
1699
  import * as fs4 from "fs";
1636
1700
  import * as path5 from "path";
1637
1701
  function capabilityOutputConditionPaths(config) {
1702
+ if (config.outputSchema) {
1703
+ const properties = isPlainObject(config.outputSchema.properties) ? config.outputSchema.properties : void 0;
1704
+ const factContract = isPlainObject(properties?.facts) ? properties.facts : void 0;
1705
+ const facts = isPlainObject(factContract?.properties) ? factContract.properties : void 0;
1706
+ return /* @__PURE__ */ new Set([
1707
+ ...properties?.status ? ["result.status"] : [],
1708
+ ...properties?.summary ? ["result.summary"] : [],
1709
+ ...properties?.resultClass ? ["result.resultClass"] : [],
1710
+ ...Object.keys(facts ?? {}).map((fact) => `result.facts.${fact}`)
1711
+ ]);
1712
+ }
1638
1713
  const result = config.output?.result;
1639
1714
  if (!result) return /* @__PURE__ */ new Set();
1640
1715
  return /* @__PURE__ */ new Set([
@@ -1655,16 +1730,19 @@ function listCapabilityFolderSlugs(absDir) {
1655
1730
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).filter((e) => isCapabilityFolder(path5.join(absDir, e.name))).map((e) => e.name).sort();
1656
1731
  }
1657
1732
  function isCapabilityFolder(dir) {
1658
- return fs4.existsSync(path5.join(dir, CAPABILITY_PROFILE_FILE)) && fs4.existsSync(path5.join(dir, CAPABILITY_BODY_FILE));
1733
+ return (fs4.existsSync(path5.join(dir, CAPABILITY_DEFINITION_FILE)) || fs4.existsSync(path5.join(dir, CAPABILITY_PROFILE_FILE))) && fs4.existsSync(path5.join(dir, CAPABILITY_BODY_FILE));
1659
1734
  }
1660
1735
  function readCapabilityFolder(root, slug) {
1661
1736
  const dir = path5.join(root, slug);
1662
- const profilePath = path5.join(dir, CAPABILITY_PROFILE_FILE);
1737
+ const definitionPath = path5.join(dir, CAPABILITY_DEFINITION_FILE);
1738
+ const legacyProfilePath = path5.join(dir, CAPABILITY_PROFILE_FILE);
1739
+ const profilePath = fs4.existsSync(definitionPath) ? definitionPath : legacyProfilePath;
1663
1740
  const bodyPath = path5.join(dir, CAPABILITY_BODY_FILE);
1664
1741
  if (!fs4.existsSync(profilePath) || !fs4.statSync(profilePath).isFile()) return null;
1665
1742
  if (!fs4.existsSync(bodyPath) || !fs4.statSync(bodyPath).isFile()) return null;
1666
1743
  try {
1667
- const rawProfile = JSON.parse(fs4.readFileSync(profilePath, "utf-8"));
1744
+ const rawDefinition = JSON.parse(fs4.readFileSync(profilePath, "utf-8"));
1745
+ const rawProfile = rawDefinition;
1668
1746
  const rawBody = fs4.readFileSync(bodyPath, "utf-8");
1669
1747
  const { title, body } = parseCapabilityBody(rawBody, slug);
1670
1748
  return {
@@ -1700,11 +1778,12 @@ function parseCapabilityConfig(raw) {
1700
1778
  capabilityToolMode: parseCapabilityToolMode(raw.capabilityToolMode),
1701
1779
  implementations,
1702
1780
  role: stringField(raw.role),
1703
- describe: stringField(raw.describe),
1781
+ describe: stringField(raw.describe) ?? stringField(raw.purpose),
1704
1782
  stage: stringField(raw.stage),
1705
1783
  readsFrom: stringList(raw.readsFrom ?? raw.reads_from),
1706
1784
  writesTo: stringList(raw.writesTo ?? raw.writes_to),
1707
1785
  output: parseCapabilityOutput(raw.output),
1786
+ outputSchema: isPlainObject(raw.outputSchema) ? raw.outputSchema : void 0,
1708
1787
  workflow: parseCapabilityWorkflow(raw.workflow)
1709
1788
  };
1710
1789
  }
@@ -1873,11 +1952,12 @@ function isSafeSlug(value) {
1873
1952
  function isSafeStepId(value) {
1874
1953
  return /^[A-Za-z][A-Za-z0-9_-]*$/.test(value) && !value.includes("..");
1875
1954
  }
1876
- var CAPABILITY_PROFILE_FILE, CAPABILITY_BODY_FILE;
1955
+ var CAPABILITY_PROFILE_FILE, CAPABILITY_DEFINITION_FILE, CAPABILITY_BODY_FILE;
1877
1956
  var init_capabilityFolders = __esm({
1878
1957
  "src/capabilityFolders.ts"() {
1879
1958
  "use strict";
1880
1959
  CAPABILITY_PROFILE_FILE = "profile.json";
1960
+ CAPABILITY_DEFINITION_FILE = "definition.json";
1881
1961
  CAPABILITY_BODY_FILE = "capability.md";
1882
1962
  }
1883
1963
  });
@@ -1903,6 +1983,9 @@ function hasExplicitDefinitionsRoot(cwd = process.cwd(), env = process.env) {
1903
1983
  function capabilitiesRoot(cwd = process.cwd()) {
1904
1984
  return path6.join(definitionsRoot(cwd), "capabilities");
1905
1985
  }
1986
+ function implementationsRoot(cwd = process.cwd()) {
1987
+ return path6.join(definitionsRoot(cwd), "implementations");
1988
+ }
1906
1989
  function agentsRoot(cwd = process.cwd()) {
1907
1990
  return path6.join(definitionsRoot(cwd), "agents");
1908
1991
  }
@@ -1913,6 +1996,7 @@ var init_definition_paths = __esm({
1913
1996
  });
1914
1997
 
1915
1998
  // src/registry.ts
1999
+ import { createHash as createHash2 } from "crypto";
1916
2000
  import * as fs6 from "fs";
1917
2001
  import * as path7 from "path";
1918
2002
  function getImplementationsRoot() {
@@ -1952,7 +2036,7 @@ function getImplementationRoots() {
1952
2036
  return getImplementationRootsForCwd(process.cwd());
1953
2037
  }
1954
2038
  function getImplementationRootsForCwd(cwd) {
1955
- return [capabilitiesRoot(cwd), getImplementationsRoot()];
2039
+ return [implementationsRoot(cwd), getImplementationsRoot()];
1956
2040
  }
1957
2041
  function getCapabilityRoots(projectCapabilitiesRoot = getProjectCapabilitiesRoot()) {
1958
2042
  return [projectCapabilitiesRoot, getBuiltinCapabilitiesRoot()];
@@ -1968,7 +2052,7 @@ function listImplementations(roots = getImplementationRoots()) {
1968
2052
  for (const ent of entries) {
1969
2053
  if (!ent.isDirectory()) continue;
1970
2054
  if (seen.has(ent.name)) continue;
1971
- const profilePath = path7.join(root, ent.name, CAPABILITY_PROFILE_FILE);
2055
+ const profilePath = implementationRuntimePath(root, ent.name);
1972
2056
  if (fs6.existsSync(profilePath) && fs6.statSync(profilePath).isFile() && isImplementationProfile(profilePath, requireImplementationProfile)) {
1973
2057
  out.push({ name: ent.name, profilePath });
1974
2058
  seen.add(ent.name);
@@ -1985,7 +2069,7 @@ function resolveImplementationCandidates(name, roots = getImplementationRoots())
1985
2069
  const rootList = typeof roots === "string" ? [roots] : roots;
1986
2070
  const out = [];
1987
2071
  for (const root of rootList) {
1988
- const profilePath = path7.join(root, name, "profile.json");
2072
+ const profilePath = implementationRuntimePath(root, name);
1989
2073
  if (fs6.existsSync(profilePath) && fs6.statSync(profilePath).isFile() && isImplementationProfile(profilePath, isCapabilityRoot(root))) {
1990
2074
  out.push(profilePath);
1991
2075
  }
@@ -2023,9 +2107,43 @@ function resolveCapabilityFolder(slug, projectCapabilitiesRoot = getProjectCapab
2023
2107
  function getCapabilityActionInputs(action, projectCapabilitiesRoot = getProjectCapabilitiesRoot()) {
2024
2108
  const resolved = resolveCapabilityAction(action, projectCapabilitiesRoot);
2025
2109
  if (!resolved) return null;
2110
+ const capability = resolveCapabilityFolder(resolved.capability, projectCapabilitiesRoot);
2111
+ if (capability && path7.basename(capability.profilePath) === "definition.json") {
2112
+ const schema = capability.rawProfile.inputSchema;
2113
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) return [];
2114
+ const properties = schema.properties;
2115
+ if (!properties || typeof properties !== "object" || Array.isArray(properties)) return [];
2116
+ const required2 = new Set(
2117
+ Array.isArray(schema.required) ? schema.required.filter((value) => typeof value === "string") : []
2118
+ );
2119
+ return Object.entries(properties).map(([name, value]) => {
2120
+ const property = value && typeof value === "object" && !Array.isArray(value) ? value : {};
2121
+ const type = property.type === "integer" ? "int" : property.type === "boolean" ? "bool" : Array.isArray(property.enum) ? "enum" : "string";
2122
+ return {
2123
+ name,
2124
+ flag: `--${name}`,
2125
+ type,
2126
+ required: required2.has(name),
2127
+ ...type === "enum" && Array.isArray(property.enum) ? { values: property.enum.filter((item) => typeof item === "string") } : {},
2128
+ describe: typeof property.description === "string" ? property.description : name
2129
+ };
2130
+ });
2131
+ }
2026
2132
  return getProfileInputs(resolved.implementation);
2027
2133
  }
2028
2134
  function resolveCapabilityExecution(capability, cwd = process.cwd()) {
2135
+ if (path7.basename(capability.profilePath) === "definition.json") {
2136
+ const implementations = readExternalImplementations(cwd);
2137
+ const definition = JSON.parse(fs6.readFileSync(capability.profilePath, "utf-8"));
2138
+ const capabilityRevision = createHash2("sha256").update(canonical(definition)).digest("hex");
2139
+ const selected = resolveCapabilityImplementation({
2140
+ capabilityId: capability.slug,
2141
+ capabilityRevision,
2142
+ implementations,
2143
+ repositoryBinding: repositoryImplementationBinding(capability.slug, cwd)
2144
+ });
2145
+ return { implementation: selected.id, cliArgs: {} };
2146
+ }
2029
2147
  const firstWorkflowStep = capability.config.workflow?.steps[0];
2030
2148
  if (firstWorkflowStep) {
2031
2149
  const implementation2 = firstWorkflowStep.implementation ?? firstWorkflowStep.capability;
@@ -2035,11 +2153,42 @@ function resolveCapabilityExecution(capability, cwd = process.cwd()) {
2035
2153
  const cliArgs = implementationDeclaresInput(implementation, "capability", cwd) ? { capability: capability.slug } : {};
2036
2154
  return { implementation, cliArgs };
2037
2155
  }
2156
+ function repositoryImplementationBinding(capabilityId, cwd) {
2157
+ try {
2158
+ return loadConfig(cwd).execution?.capabilityBindings[capabilityId];
2159
+ } catch {
2160
+ return void 0;
2161
+ }
2162
+ }
2163
+ function readExternalImplementations(cwd) {
2164
+ const root = implementationsRoot(cwd);
2165
+ if (!fs6.existsSync(root)) return [];
2166
+ const definitions = [];
2167
+ for (const entry of fs6.readdirSync(root, { withFileTypes: true })) {
2168
+ if (!entry.isDirectory() || !isSafeName(entry.name)) continue;
2169
+ const definitionPath = path7.join(root, entry.name, "definition.json");
2170
+ if (!fs6.existsSync(definitionPath)) continue;
2171
+ try {
2172
+ const definition = JSON.parse(fs6.readFileSync(definitionPath, "utf-8"));
2173
+ definitions.push(definition);
2174
+ } catch {
2175
+ }
2176
+ }
2177
+ return definitions;
2178
+ }
2179
+ function canonical(value) {
2180
+ if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
2181
+ if (value && typeof value === "object") {
2182
+ return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${canonical(item)}`).join(",")}}`;
2183
+ }
2184
+ return JSON.stringify(value);
2185
+ }
2038
2186
  function implementationDeclaresInput(implementation, inputName, cwd = process.cwd()) {
2039
2187
  const profilePath = resolveImplementation(implementation, getImplementationRootsForCwd(cwd));
2040
2188
  if (!profilePath) return false;
2041
2189
  try {
2042
- const raw = JSON.parse(fs6.readFileSync(profilePath, "utf-8"));
2190
+ const document = JSON.parse(fs6.readFileSync(profilePath, "utf-8"));
2191
+ const raw = document.config ?? document;
2043
2192
  if (!Array.isArray(raw.inputs)) return false;
2044
2193
  return raw.inputs.some((entry) => {
2045
2194
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) return false;
@@ -2059,6 +2208,10 @@ function isCapabilityRoot(root) {
2059
2208
  const knownRoots = [getProjectCapabilitiesRoot(), getBuiltinCapabilitiesRoot()];
2060
2209
  return knownRoots.some((candidate) => candidate && path7.normalize(candidate) === normalized);
2061
2210
  }
2211
+ function implementationRuntimePath(root, name) {
2212
+ const runtimePath = path7.join(root, name, "runtime.json");
2213
+ return fs6.existsSync(runtimePath) ? runtimePath : path7.join(root, name, CAPABILITY_PROFILE_FILE);
2214
+ }
2062
2215
  function isImplementationProfile(profilePath, requireImplementationProfile) {
2063
2216
  if (!requireImplementationProfile) return true;
2064
2217
  try {
@@ -2126,8 +2279,10 @@ function getProfileInputs(name, roots = getImplementationRoots()) {
2126
2279
  const profilePath = resolveImplementation(name, roots);
2127
2280
  if (!profilePath) return null;
2128
2281
  try {
2129
- const raw = JSON.parse(fs6.readFileSync(profilePath, "utf-8"));
2130
- if (!raw || typeof raw !== "object" || !Array.isArray(raw.inputs)) return [];
2282
+ const document = JSON.parse(fs6.readFileSync(profilePath, "utf-8"));
2283
+ if (!document || typeof document !== "object") return [];
2284
+ const raw = "config" in document && document.config && typeof document.config === "object" ? document.config : document;
2285
+ if (!Array.isArray(raw.inputs)) return [];
2131
2286
  return raw.inputs;
2132
2287
  } catch {
2133
2288
  return null;
@@ -2162,7 +2317,9 @@ var PUBLIC_IMPLEMENTATION_ROLES;
2162
2317
  var init_registry = __esm({
2163
2318
  "src/registry.ts"() {
2164
2319
  "use strict";
2320
+ init_implementation_resolution();
2165
2321
  init_capabilityFolders();
2322
+ init_config();
2166
2323
  init_definition_paths();
2167
2324
  PUBLIC_IMPLEMENTATION_ROLES = /* @__PURE__ */ new Set(["primitive", "orchestrator", "container", "watch", "utility"]);
2168
2325
  }
@@ -4166,6 +4323,40 @@ var init_agencyBoundaryEval = __esm({
4166
4323
  }
4167
4324
  });
4168
4325
 
4326
+ // src/agency/capability-contract-validation.ts
4327
+ import Ajv from "ajv";
4328
+ function validateCapabilityContractValue(boundary, schema, value) {
4329
+ const validate = validator.compile(schema);
4330
+ if (!validate(value)) {
4331
+ throw new CapabilityContractValidationError(boundary, validate.errors ?? []);
4332
+ }
4333
+ }
4334
+ var validator, CapabilityContractValidationError;
4335
+ var init_capability_contract_validation = __esm({
4336
+ "src/agency/capability-contract-validation.ts"() {
4337
+ "use strict";
4338
+ validator = new Ajv({
4339
+ allErrors: true,
4340
+ strict: true,
4341
+ validateFormats: false
4342
+ });
4343
+ CapabilityContractValidationError = class extends Error {
4344
+ constructor(boundary, errors) {
4345
+ super(
4346
+ `Capability ${boundary} does not match its canonical contract: ${validator.errorsText([...errors], {
4347
+ separator: "; "
4348
+ })}`
4349
+ );
4350
+ this.boundary = boundary;
4351
+ this.errors = errors;
4352
+ this.name = "CapabilityContractValidationError";
4353
+ }
4354
+ boundary;
4355
+ errors;
4356
+ };
4357
+ }
4358
+ });
4359
+
4169
4360
  // src/capabilityReport.ts
4170
4361
  function parseCapabilityReportsFromText(text2) {
4171
4362
  const reports = [];
@@ -4715,6 +4906,7 @@ var init_subagents = __esm({
4715
4906
  });
4716
4907
 
4717
4908
  // src/profile.ts
4909
+ import { createHash as createHash3 } from "crypto";
4718
4910
  import * as fs20 from "fs";
4719
4911
  import * as path19 from "path";
4720
4912
  function loadProfile(profilePath) {
@@ -4730,7 +4922,8 @@ function loadProfile(profilePath) {
4730
4922
  if (!raw || typeof raw !== "object") {
4731
4923
  throw new ProfileError(profilePath, "profile must be a JSON object");
4732
4924
  }
4733
- const r = raw;
4925
+ const document = raw;
4926
+ const r = compileRuntimeDocument(profilePath, document);
4734
4927
  const unknownKeys = Object.keys(r).filter((k) => !KNOWN_PROFILE_KEYS.has(k));
4735
4928
  if (unknownKeys.length > 0) {
4736
4929
  process.stderr.write(
@@ -4877,6 +5070,67 @@ function loadProfile(profilePath) {
4877
5070
  profile.subagentTemplates = captureSubagentTemplates(profile);
4878
5071
  return profile;
4879
5072
  }
5073
+ function compileRuntimeDocument(runtimePath, document) {
5074
+ if (path19.basename(runtimePath) !== "runtime.json") return document;
5075
+ if (document.adapter !== "kody-engine-profile") {
5076
+ throw new ProfileError(runtimePath, "unsupported runtime adapter document");
5077
+ }
5078
+ const implementationDir = path19.dirname(runtimePath);
5079
+ const implementation = readJsonObject(path19.join(implementationDir, "definition.json"), "Implementation definition");
5080
+ const definitionsRoot2 = path19.dirname(path19.dirname(implementationDir));
5081
+ const capabilityId = implementation.capabilityRef && typeof implementation.capabilityRef === "object" && !Array.isArray(implementation.capabilityRef) ? implementation.capabilityRef.id : void 0;
5082
+ if (typeof capabilityId !== "string" || !capabilityId) {
5083
+ throw new ProfileError(runtimePath, "Implementation capabilityRef is invalid");
5084
+ }
5085
+ const capability = readJsonObject(
5086
+ path19.join(definitionsRoot2, "capabilities", capabilityId, "definition.json"),
5087
+ "Capability definition"
5088
+ );
5089
+ const {
5090
+ adapter: _adapter,
5091
+ inputBindings: _inputBindings,
5092
+ outputBindings: _outputBindings,
5093
+ requirements: _requirements,
5094
+ config: nestedConfig,
5095
+ ...inlineConfig
5096
+ } = document;
5097
+ const config = nestedConfig && typeof nestedConfig === "object" && !Array.isArray(nestedConfig) ? nestedConfig : inlineConfig;
5098
+ const agentRef = implementation.agentRef && typeof implementation.agentRef === "object" && !Array.isArray(implementation.agentRef) ? implementation.agentRef.id : void 0;
5099
+ return {
5100
+ ...config,
5101
+ name: implementation.id,
5102
+ action: capability.action,
5103
+ describe: capability.purpose,
5104
+ inputs: config.inputs ?? [],
5105
+ agent: agentRef,
5106
+ canonicalContract: {
5107
+ capabilityId,
5108
+ capabilityRevision: createHash3("sha256").update(canonical2(capability)).digest("hex"),
5109
+ implementationId: String(implementation.id),
5110
+ implementationRevision: createHash3("sha256").update(canonical2(implementation)).digest("hex"),
5111
+ inputSchema: capability.inputSchema,
5112
+ outputSchema: capability.outputSchema
5113
+ }
5114
+ };
5115
+ }
5116
+ function canonical2(value) {
5117
+ if (Array.isArray(value)) return `[${value.map(canonical2).join(",")}]`;
5118
+ if (value && typeof value === "object") {
5119
+ return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${canonical2(item)}`).join(",")}}`;
5120
+ }
5121
+ return JSON.stringify(value);
5122
+ }
5123
+ function readJsonObject(filePath, label) {
5124
+ try {
5125
+ const value = JSON.parse(fs20.readFileSync(filePath, "utf-8"));
5126
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
5127
+ throw new Error("must be an object");
5128
+ }
5129
+ return value;
5130
+ } catch (error) {
5131
+ throw new ProfileError(filePath, `${label} is invalid: ${error instanceof Error ? error.message : String(error)}`);
5132
+ }
5133
+ }
4880
5134
  function parseCapabilityToolMode2(profilePath, raw) {
4881
5135
  if (raw === void 0 || raw === null || raw === "") return void 0;
4882
5136
  if (raw === "lock" || raw === "append") return raw;
@@ -5256,6 +5510,7 @@ var init_profile = __esm({
5256
5510
  VALID_CONTAINER_CHILD_TARGETS = /* @__PURE__ */ new Set(["issue", "pr"]);
5257
5511
  VALID_PHASES = /* @__PURE__ */ new Set(["research", "planning", "implementing", "reviewing", "shipped", "failed", "idle"]);
5258
5512
  KNOWN_PROFILE_KEYS = /* @__PURE__ */ new Set([
5513
+ "canonicalContract",
5259
5514
  "name",
5260
5515
  "action",
5261
5516
  "implementation",
@@ -6899,6 +7154,9 @@ function runIndexRowFromJobContext(input) {
6899
7154
  capability: stringValue(input.data.jobCapability) ?? void 0,
6900
7155
  workflow: workflow ?? void 0,
6901
7156
  implementation: stringValue(input.data.selectedImplementation) ?? input.profileName,
7157
+ parentRunId: stringValue(input.data.parentRunId) ?? void 0,
7158
+ capabilityRevision: stringValue(input.data.capabilityRevision) ?? void 0,
7159
+ implementationRevision: stringValue(input.data.implementationRevision) ?? void 0,
6902
7160
  agent: stringValue(input.data.jobAgent) ?? input.profile.agent ?? void 0,
6903
7161
  model: stringValue(input.data.jobModel) ?? void 0,
6904
7162
  modelProvider: stringValue(input.data.jobModelProvider) ?? void 0,
@@ -6963,7 +7221,7 @@ function statusFromExitCode(exitCode) {
6963
7221
  return exitCode === 0 ? "success" : "failed";
6964
7222
  }
6965
7223
  function isRunSubjectType(value) {
6966
- return value === "goal" || value === "loop" || value === "workflow";
7224
+ return value === "goal" || value === "loop" || value === "workflow" || value === "capability";
6967
7225
  }
6968
7226
  function stagedRunIndexRows(data) {
6969
7227
  const value = data[STAGED_RUN_INDEX_ROWS_KEY];
@@ -8472,9 +8730,9 @@ function goalInstanceTime(state) {
8472
8730
  return Number.isNaN(parsed) ? 0 : parsed;
8473
8731
  }
8474
8732
  function loadGoalTemplate(cwd, targetId) {
8475
- return readJsonObject(path24.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
8733
+ return readJsonObject2(path24.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
8476
8734
  }
8477
- function readJsonObject(filePath) {
8735
+ function readJsonObject2(filePath) {
8478
8736
  if (!fs27.existsSync(filePath)) return null;
8479
8737
  const parsed = JSON.parse(fs27.readFileSync(filePath, "utf8"));
8480
8738
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -9504,6 +9762,7 @@ async function planGoalCapabilitySchedule(opts) {
9504
9762
  capability2,
9505
9763
  slug,
9506
9764
  backend,
9765
+ opts.cwd,
9507
9766
  opts.previousScheduleState?.capabilities[slug]
9508
9767
  );
9509
9768
  statuses[slug] = status;
@@ -9558,21 +9817,19 @@ async function planGoalCapabilitySchedule(opts) {
9558
9817
  }
9559
9818
  };
9560
9819
  }
9561
- async function describeCapabilitySchedule(capability, slug, backend, previous) {
9820
+ async function describeCapabilitySchedule(capability, slug, backend, cwd, previous) {
9562
9821
  if (!capability) return { slug, state: "blocked", reason: "capability folder missing" };
9563
- const { config } = capability;
9564
- if (config.disabled === true) {
9822
+ if (capability.config.disabled === true) {
9565
9823
  return { slug, title: capability.title, state: "disabled", reason: "disabled" };
9566
9824
  }
9567
- if (!config.agent || config.agent.trim().length === 0) {
9568
- return { slug, title: capability.title, state: "blocked", reason: "no agent assigned" };
9569
- }
9570
- if (config.implementations && config.implementations.length > 1) {
9825
+ try {
9826
+ resolveCapabilityExecution(capability, cwd);
9827
+ } catch (error) {
9571
9828
  return {
9572
9829
  slug,
9573
9830
  title: capability.title,
9574
9831
  state: "blocked",
9575
- reason: "multi-implementation capability needs task-jobs route"
9832
+ reason: error instanceof Error ? error.message : "Implementation unavailable"
9576
9833
  };
9577
9834
  }
9578
9835
  let lastFiredAt = validIso(previous?.lastFiredAt) ? previous?.lastFiredAt : void 0;
@@ -13242,7 +13499,7 @@ var init_triggerDispatcher = __esm({
13242
13499
  });
13243
13500
 
13244
13501
  // src/goal/policyResolver.ts
13245
- import { createHash as createHash2 } from "crypto";
13502
+ import { createHash as createHash4 } from "crypto";
13246
13503
  function resolveDispatchPolicy(input) {
13247
13504
  const operation = input.catalog.operations.get(input.owner.definition.operationId);
13248
13505
  if (!operation) throw new Error(`Dispatch blocked: Operation "${input.owner.definition.operationId}" is unresolved`);
@@ -13260,7 +13517,7 @@ function resolveDispatchPolicy(input) {
13260
13517
  const snapshotValue = { policy, constraints };
13261
13518
  return {
13262
13519
  snapshot: {
13263
- hash: createHash2("sha256").update(stableJson(snapshotValue)).digest("hex"),
13520
+ hash: createHash4("sha256").update(stableJson(snapshotValue)).digest("hex"),
13264
13521
  ...snapshotValue
13265
13522
  },
13266
13523
  operation,
@@ -15531,9 +15788,9 @@ var init_kodyVariables = __esm({
15531
15788
  });
15532
15789
 
15533
15790
  // src/backendVault.ts
15534
- import { createDecipheriv, createHash as createHash3 } from "crypto";
15791
+ import { createDecipheriv, createHash as createHash5 } from "crypto";
15535
15792
  function cacheKey(owner, repo, masterKey) {
15536
- const keyHash = createHash3("sha256").update(masterKey).digest("hex").slice(0, 16);
15793
+ const keyHash = createHash5("sha256").update(masterKey).digest("hex").slice(0, 16);
15537
15794
  return `${owner}/${repo}:${keyHash}`.toLowerCase();
15538
15795
  }
15539
15796
  function decryptVault(payload, masterKey) {
@@ -16182,7 +16439,7 @@ var init_notifyTerminal = __esm({
16182
16439
  });
16183
16440
 
16184
16441
  // src/scripts/openAgencyModelReviewPr.ts
16185
- import { createHash as createHash4 } from "crypto";
16442
+ import { createHash as createHash6 } from "crypto";
16186
16443
  function parseAgencyModelProposal(raw) {
16187
16444
  const text2 = raw.trim();
16188
16445
  const jsonText = (text2.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/i)?.[1] ?? text2).trim();
@@ -16234,7 +16491,7 @@ function normalizeBundleFiles(bundle) {
16234
16491
  });
16235
16492
  }
16236
16493
  function buildProposalId(issueNumber, bundle, sourceLabel) {
16237
- const digest = createHash4("sha256").update(JSON.stringify({ issueNumber, sourceLabel, title: bundle.title, files: normalizeBundleFiles(bundle) })).digest("hex").slice(0, 16);
16494
+ const digest = createHash6("sha256").update(JSON.stringify({ issueNumber, sourceLabel, title: bundle.title, files: normalizeBundleFiles(bundle) })).digest("hex").slice(0, 16);
16238
16495
  return `issue-${issueNumber}-${digest}`;
16239
16496
  }
16240
16497
  function isDryRun(ctx) {
@@ -18306,9 +18563,9 @@ var init_runFlow = __esm({
18306
18563
  });
18307
18564
 
18308
18565
  // src/scripts/previewBuildHelpers.ts
18309
- import { createDecipheriv as createDecipheriv2, createHash as createHash5, hkdfSync as hkdfSync2 } from "crypto";
18566
+ import { createDecipheriv as createDecipheriv2, createHash as createHash7, hkdfSync as hkdfSync2 } from "crypto";
18310
18567
  function shortHash(s) {
18311
- return createHash5("sha256").update(s).digest("hex").slice(0, 6);
18568
+ return createHash7("sha256").update(s).digest("hex").slice(0, 6);
18312
18569
  }
18313
18570
  function previewAppName(repo, pr) {
18314
18571
  const [owner, name] = repo.split("/");
@@ -18341,7 +18598,7 @@ function formatPreviewComment(args) {
18341
18598
  ].join("\n");
18342
18599
  }
18343
18600
  function defaultImageTag(repo, ref) {
18344
- return createHash5("sha256").update(`${repo}@${ref}`).digest("hex").slice(0, 12);
18601
+ return createHash7("sha256").update(`${repo}@${ref}`).digest("hex").slice(0, 12);
18345
18602
  }
18346
18603
  var init_previewBuildHelpers = __esm({
18347
18604
  "src/scripts/previewBuildHelpers.ts"() {
@@ -20747,6 +21004,9 @@ async function runImplementation(profileName, input) {
20747
21004
  let args;
20748
21005
  try {
20749
21006
  args = validateInputs(profile.inputs, input.cliArgs);
21007
+ if (profile.canonicalContract) {
21008
+ validateCapabilityContractValue("input", profile.canonicalContract.inputSchema, args);
21009
+ }
20750
21010
  } catch (err) {
20751
21011
  return finishAndEnd({ exitCode: 64, reason: err instanceof Error ? err.message : String(err) });
20752
21012
  }
@@ -20807,6 +21067,12 @@ async function runImplementation(profileName, input) {
20807
21067
  ctx.data.jobModelProvider = model.provider;
20808
21068
  ctx.data.jobModelName = model.model;
20809
21069
  if (reasoningEffort) ctx.data.jobReasoningEffort = reasoningEffort;
21070
+ if (profile.canonicalContract) {
21071
+ ctx.data.jobCapability = profile.canonicalContract.capabilityId;
21072
+ ctx.data.selectedImplementation = profile.canonicalContract.implementationId;
21073
+ ctx.data.capabilityRevision = profile.canonicalContract.capabilityRevision;
21074
+ ctx.data.implementationRevision = profile.canonicalContract.implementationRevision;
21075
+ }
20810
21076
  const runIndexStartedAt = new Date(stageStartedAt).toISOString();
20811
21077
  if (!input.skipConfig) {
20812
21078
  await upsertRunIndexRowBestEffortAsync(
@@ -21116,6 +21382,25 @@ async function runImplementation(profileName, input) {
21116
21382
  outcome: postOutcome
21117
21383
  });
21118
21384
  }
21385
+ const capabilityResults = Array.isArray(ctx.data.capabilityResults) ? ctx.data.capabilityResults : void 0;
21386
+ if (profile.canonicalContract) {
21387
+ try {
21388
+ validateCapabilityContractValue(
21389
+ "output",
21390
+ profile.canonicalContract.outputSchema,
21391
+ capabilityResults?.at(-1) ?? {
21392
+ exitCode: ctx.output.exitCode ?? 0,
21393
+ reason: ctx.output.reason,
21394
+ prUrl: ctx.output.prUrl
21395
+ }
21396
+ );
21397
+ } catch (error) {
21398
+ return finishAndEnd({
21399
+ exitCode: 99,
21400
+ reason: error instanceof Error ? error.message : String(error)
21401
+ });
21402
+ }
21403
+ }
21119
21404
  return finishAndEnd({
21120
21405
  exitCode: ctx.output.exitCode ?? 0,
21121
21406
  prUrl: ctx.output.prUrl,
@@ -21124,7 +21409,7 @@ async function runImplementation(profileName, input) {
21124
21409
  nextJob: ctx.output.nextJob,
21125
21410
  afterNextJob: ctx.output.afterNextJob,
21126
21411
  taskState: ctx.data.taskState,
21127
- capabilityResults: Array.isArray(ctx.data.capabilityResults) ? ctx.data.capabilityResults : void 0
21412
+ capabilityResults
21128
21413
  });
21129
21414
  } catch (err) {
21130
21415
  const msg = err instanceof Error ? err.message : String(err);
@@ -21328,10 +21613,7 @@ function resolveProfilePath(profileName, cwd = process.cwd()) {
21328
21613
  return candidates[0];
21329
21614
  }
21330
21615
  function loadRunnableProfile(profileName, cwd) {
21331
- const candidates = resolveImplementationCandidates(
21332
- profileName,
21333
- getImplementationRootsForCwd(cwd)
21334
- );
21616
+ const candidates = resolveImplementationCandidates(profileName, getImplementationRootsForCwd(cwd));
21335
21617
  const skipped = [];
21336
21618
  for (const profilePath2 of candidates) {
21337
21619
  const profile2 = loadProfile(profilePath2);
@@ -21583,6 +21865,7 @@ var MUTATING_POSTFLIGHTS, SHELL_MARKER_RE, TASK_ARTIFACT_WRITE_TOOLS, MAX_CHAIN_
21583
21865
  var init_executor = __esm({
21584
21866
  "src/executor.ts"() {
21585
21867
  "use strict";
21868
+ init_capability_contract_validation();
21586
21869
  init_agent();
21587
21870
  init_agents();
21588
21871
  init_capabilityReport();
@@ -21786,7 +22069,52 @@ async function runJob(job, base) {
21786
22069
  ...valid.workflowState ?? persistedState ? { workflowState: valid.workflowState ?? persistedState ?? void 0 } : {}
21787
22070
  };
21788
22071
  const checkpoint = valid.workflowRunId && workflowIdentity && base.config ? (state) => writeWorkflowRunState(base.config, base.cwd, workflowIdentity, valid.workflowRunId, state) : void 0;
21789
- const result = await runCapabilityWorkflow(workflowJob, workflow, workflowCapability, base, checkpoint);
22072
+ const parentRunId = `workflow:${workflowIdentity}:${valid.workflowRunId ?? newJobId(valid.flavor)}`;
22073
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
22074
+ const parentRow = {
22075
+ version: 1,
22076
+ id: parentRunId,
22077
+ subjectType: "workflow",
22078
+ subjectId: workflowIdentity,
22079
+ subjectLabel: workflowCapability.title,
22080
+ status: "running",
22081
+ title: workflowCapability.title,
22082
+ startedAt,
22083
+ updatedAt: startedAt,
22084
+ workflow: workflowIdentity,
22085
+ kodyRunId: valid.workflowRunId,
22086
+ sourceType: "job"
22087
+ };
22088
+ const persistRun = Boolean(base.config && !base.skipConfig && hasStateBackendConfig());
22089
+ if (base.config && persistRun) {
22090
+ await upsertRunIndexRowBestEffortAsync(base.config, base.cwd, parentRow);
22091
+ }
22092
+ const workflowBase = {
22093
+ ...base,
22094
+ preloadedData: { ...base.preloadedData ?? {}, parentRunId }
22095
+ };
22096
+ let result;
22097
+ try {
22098
+ result = await runCapabilityWorkflow(workflowJob, workflow, workflowCapability, workflowBase, checkpoint);
22099
+ } catch (error) {
22100
+ if (base.config && persistRun) {
22101
+ await upsertRunIndexRowBestEffortAsync(base.config, base.cwd, {
22102
+ ...parentRow,
22103
+ status: "failed",
22104
+ summary: error instanceof Error ? error.message : String(error),
22105
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
22106
+ });
22107
+ }
22108
+ throw error;
22109
+ }
22110
+ if (base.config && persistRun) {
22111
+ await upsertRunIndexRowBestEffortAsync(base.config, base.cwd, {
22112
+ ...parentRow,
22113
+ status: result.exitCode === 0 ? "success" : "failed",
22114
+ summary: result.reason,
22115
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
22116
+ });
22117
+ }
21790
22118
  if (valid.workflowRunId && workflowIdentity && base.config && result.workflowState) {
21791
22119
  await writeWorkflowRunState(base.config, base.cwd, workflowIdentity, valid.workflowRunId, result.workflowState);
21792
22120
  }
@@ -21926,6 +22254,9 @@ async function runLinearCapabilityWorkflow(parent, workflow, capability, base) {
21926
22254
  ...base,
21927
22255
  preloadedData: {
21928
22256
  ...chainData,
22257
+ runSubjectType: "capability",
22258
+ runSubjectId: step.capability,
22259
+ runSubjectLabel: label,
21929
22260
  workflowStep: label,
21930
22261
  workflowStepIndex: index + 1,
21931
22262
  workflowStepReason: step.reason,
@@ -22070,6 +22401,9 @@ async function runGraphCapabilityWorkflow(parent, workflow, capability, base, ch
22070
22401
  ...base,
22071
22402
  preloadedData: {
22072
22403
  ...chainData,
22404
+ runSubjectType: "capability",
22405
+ runSubjectId: step.capability,
22406
+ runSubjectLabel: step.id,
22073
22407
  workflowStep: step.id,
22074
22408
  workflowStepIndex: index + 1,
22075
22409
  workflowStepReason: step.reason,
@@ -22323,7 +22657,7 @@ function hydratedCapabilitiesRoot(cwd) {
22323
22657
  return path46.join(cwd, ".kody-engine", "definitions", "capabilities");
22324
22658
  }
22325
22659
  function loadWorkflowContext(slug, base) {
22326
- if (!slug || !base.config || !isWorkflowDefinitionId(slug)) return null;
22660
+ if (!slug || !isWorkflowDefinitionId(slug)) return null;
22327
22661
  const workflow = readWorkflowDefinition(base.config, base.cwd, slug);
22328
22662
  return workflow ? workflowDefinitionToCapabilityFolder(slug, workflow) : null;
22329
22663
  }
@@ -22359,6 +22693,8 @@ var init_job = __esm({
22359
22693
  init_capabilityFolders();
22360
22694
  init_executor();
22361
22695
  init_registry();
22696
+ init_runIndex();
22697
+ init_state_backend();
22362
22698
  init_workflowDefinitions();
22363
22699
  init_workflowRunState();
22364
22700
  init_workflowValidation();
@@ -26384,7 +26720,7 @@ init_definition_paths();
26384
26720
 
26385
26721
  // src/definition-hydration.ts
26386
26722
  init_state_backend();
26387
- import { createHash as createHash6 } from "crypto";
26723
+ import { createHash as createHash8 } from "crypto";
26388
26724
  import * as fs50 from "fs";
26389
26725
  import * as path51 from "path";
26390
26726
  var SLUG_RE2 = /^[a-z0-9][a-z0-9_-]{0,63}$/;
@@ -26405,7 +26741,7 @@ function normalizeDefinitionBundle(bundle) {
26405
26741
  return { schemaVersion: 1, files };
26406
26742
  }
26407
26743
  function definitionVersion(bundle) {
26408
- return `sha256:${createHash6("sha256").update(JSON.stringify(normalizeDefinitionBundle(bundle))).digest("hex")}`;
26744
+ return `sha256:${createHash8("sha256").update(JSON.stringify(normalizeDefinitionBundle(bundle))).digest("hex")}`;
26409
26745
  }
26410
26746
  function verifyDefinition(definition) {
26411
26747
  if (!SLUG_RE2.test(definition.slug)) throw new Error(`invalid definition slug: ${definition.slug}`);
@@ -0,0 +1,42 @@
1
+ {
2
+ "id": "run",
3
+ "action": "run",
4
+ "purpose": "Implement one GitHub issue end-to-end.",
5
+ "inputSchema": {
6
+ "type": "object",
7
+ "properties": {
8
+ "issue": {
9
+ "type": "integer",
10
+ "description": "GitHub issue number to implement."
11
+ },
12
+ "base": {
13
+ "type": "string",
14
+ "description": "Optional safe base branch override for manual branch targeting (see resolveBaseOverride in runFlow.ts)."
15
+ }
16
+ },
17
+ "required": [
18
+ "issue"
19
+ ],
20
+ "additionalProperties": false
21
+ },
22
+ "outputSchema": {
23
+ "type": "object",
24
+ "properties": {
25
+ "reason": {
26
+ "type": "string"
27
+ },
28
+ "summary": {
29
+ "type": "string"
30
+ },
31
+ "data": {
32
+ "type": "object",
33
+ "additionalProperties": true
34
+ }
35
+ },
36
+ "additionalProperties": true
37
+ },
38
+ "effects": [],
39
+ "permissions": [],
40
+ "success": "The requested issue is implemented and the canonical result is returned.",
41
+ "failure": "The issue cannot be implemented safely or no valid canonical result is returned."
42
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "id": "run",
3
+ "capabilityRef": {
4
+ "kind": "capability",
5
+ "id": "run"
6
+ },
7
+ "compatibleCapabilityRevision": "c50fdcd64daedbcde4428b2985a68a8a11ece518f00a0f5a0c0a2c9d38b5e9c1",
8
+ "type": "agent",
9
+ "agentRef": {
10
+ "kind": "agent",
11
+ "id": "kody"
12
+ }
13
+ }
@@ -1,7 +1,6 @@
1
1
  {
2
- "name": "run",
2
+ "adapter": "kody-engine-profile",
3
3
  "role": "primitive",
4
- "describe": "Implement a GitHub issue end-to-end: branch, code, commit, open PR.",
5
4
  "inputs": [
6
5
  {
7
6
  "name": "issue",
@@ -40,6 +40,14 @@ export interface AuthSpec {
40
40
  }
41
41
 
42
42
  export interface Profile {
43
+ canonicalContract?: {
44
+ capabilityId: string
45
+ capabilityRevision: string
46
+ implementationId: string
47
+ implementationRevision: string
48
+ inputSchema: Record<string, unknown>
49
+ outputSchema: Record<string, unknown>
50
+ }
43
51
  name: string
44
52
  /**
45
53
  * Public action name owned by a capability. A user may type `@kody <action>`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.430",
3
+ "version": "0.4.431",
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",
@@ -17,6 +17,7 @@
17
17
  "@anthropic-ai/claude-agent-sdk": "0.2.119",
18
18
  "@kody-ade/agency-domain": "0.5.1",
19
19
  "@modelcontextprotocol/sdk": "^1.29.0",
20
+ "ajv": "^8.18.0",
20
21
  "convex": "^1.17.0",
21
22
  "zod": "^4.0.0"
22
23
  },
@@ -1,6 +0,0 @@
1
- {
2
- "name": "run",
3
- "action": "run",
4
- "implementation": "run",
5
- "describe": "Implement a GitHub issue end-to-end."
6
- }