@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 +378 -42
- package/dist/capabilities/run/definition.json +42 -0
- package/dist/implementations/run/definition.json +13 -0
- package/dist/implementations/run/{profile.json → runtime.json} +1 -2
- package/dist/implementations/types.ts +8 -0
- package/package.json +2 -1
- package/dist/capabilities/run/profile.json +0 -6
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.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
|
|
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
|
|
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 [
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
2130
|
-
if (!
|
|
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
|
|
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
|
|
8733
|
+
return readJsonObject2(path24.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
|
|
8476
8734
|
}
|
|
8477
|
-
function
|
|
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
|
-
|
|
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
|
-
|
|
9568
|
-
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
15791
|
+
import { createDecipheriv, createHash as createHash5 } from "crypto";
|
|
15535
15792
|
function cacheKey(owner, repo, masterKey) {
|
|
15536
|
-
const keyHash =
|
|
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
|
|
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 =
|
|
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
|
|
18566
|
+
import { createDecipheriv as createDecipheriv2, createHash as createHash7, hkdfSync as hkdfSync2 } from "crypto";
|
|
18310
18567
|
function shortHash(s) {
|
|
18311
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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 || !
|
|
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
|
|
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:${
|
|
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
|
+
}
|
|
@@ -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.
|
|
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
|
},
|