@kody-ade/kody-engine 0.4.546 → 0.4.548
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.
|
|
18
|
+
version: "0.4.548",
|
|
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",
|
|
@@ -2093,11 +2093,13 @@ function parseWorkflowStep(value) {
|
|
|
2093
2093
|
const delivery = stringField(raw.delivery);
|
|
2094
2094
|
const targetFact = stringField(raw.targetFact ?? raw.target_fact);
|
|
2095
2095
|
const hasInput = Object.hasOwn(raw, "input");
|
|
2096
|
+
const inputs = parseWorkflowInputBindings(raw.inputs);
|
|
2096
2097
|
const next = parseWorkflowTransitions(raw.next);
|
|
2097
2098
|
const report = parseReportPublication(raw.report);
|
|
2098
2099
|
return {
|
|
2099
2100
|
capability,
|
|
2100
2101
|
...hasInput ? { input: raw.input } : {},
|
|
2102
|
+
...inputs ? { inputs } : {},
|
|
2101
2103
|
...id && isSafeStepId(id) ? { id } : {},
|
|
2102
2104
|
...action && isSafeSlug(action) ? { action } : {},
|
|
2103
2105
|
...evidence ? { evidence } : {},
|
|
@@ -2112,6 +2114,15 @@ function parseWorkflowStep(value) {
|
|
|
2112
2114
|
...report ? { report } : {}
|
|
2113
2115
|
};
|
|
2114
2116
|
}
|
|
2117
|
+
function parseWorkflowInputBindings(value) {
|
|
2118
|
+
if (!isPlainObject(value)) return void 0;
|
|
2119
|
+
const entries = Object.entries(value).flatMap(([name, binding]) => {
|
|
2120
|
+
if (!/^[A-Za-z_][A-Za-z0-9_-]*$/.test(name) || !isPlainObject(binding)) return [];
|
|
2121
|
+
const from = stringField(binding.from);
|
|
2122
|
+
return from ? [[name, { from }]] : [];
|
|
2123
|
+
});
|
|
2124
|
+
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
2125
|
+
}
|
|
2115
2126
|
function parseWorkflowTransitions(value) {
|
|
2116
2127
|
const rawTransitions = Array.isArray(value) ? value : value === void 0 ? [] : [value];
|
|
2117
2128
|
const transitions = rawTransitions.map((raw) => {
|
|
@@ -4448,6 +4459,15 @@ function validateWorkflow(value, options = {}) {
|
|
|
4448
4459
|
if (step.input !== void 0 && !isJsonValue(step.input)) {
|
|
4449
4460
|
issue(issues, "invalid_input", `${base}.input`, "workflow step input must be one JSON value");
|
|
4450
4461
|
}
|
|
4462
|
+
if (step.input !== void 0 && step.inputs !== void 0) {
|
|
4463
|
+
issue(issues, "conflicting_inputs", base, "workflow step cannot declare both input and inputs");
|
|
4464
|
+
}
|
|
4465
|
+
validateInputBindings(
|
|
4466
|
+
step.inputs,
|
|
4467
|
+
`${base}.inputs`,
|
|
4468
|
+
issues,
|
|
4469
|
+
capability ? options.capabilityInputs?.get(capability) : void 0
|
|
4470
|
+
);
|
|
4451
4471
|
});
|
|
4452
4472
|
if (!graphMode) return issues;
|
|
4453
4473
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -4461,11 +4481,24 @@ function validateWorkflow(value, options = {}) {
|
|
|
4461
4481
|
}
|
|
4462
4482
|
const adjacency = /* @__PURE__ */ new Map();
|
|
4463
4483
|
const explicitEndSources = /* @__PURE__ */ new Set();
|
|
4484
|
+
const capabilitiesByStep = /* @__PURE__ */ new Map();
|
|
4485
|
+
steps.forEach((step) => {
|
|
4486
|
+
const id = text(step?.id);
|
|
4487
|
+
const capability = text(step?.capability ?? step?.action);
|
|
4488
|
+
if (id && capability) capabilitiesByStep.set(id, capability);
|
|
4489
|
+
});
|
|
4464
4490
|
steps.forEach((step, index) => {
|
|
4465
4491
|
if (!step) return;
|
|
4466
4492
|
const id = text(step.id);
|
|
4467
4493
|
if (!id) return;
|
|
4468
4494
|
const sourceCapability = text(step.capability ?? step.action);
|
|
4495
|
+
validateInputBindingSources(
|
|
4496
|
+
step.inputs,
|
|
4497
|
+
`steps[${index}].inputs`,
|
|
4498
|
+
issues,
|
|
4499
|
+
capabilitiesByStep,
|
|
4500
|
+
options.capabilityOutputs
|
|
4501
|
+
);
|
|
4469
4502
|
const transitions = transitionList(step.next);
|
|
4470
4503
|
adjacency.set(id, []);
|
|
4471
4504
|
if (transitions.length > maxTransitions) {
|
|
@@ -4581,6 +4614,63 @@ function validateWorkflow(value, options = {}) {
|
|
|
4581
4614
|
}
|
|
4582
4615
|
return issues;
|
|
4583
4616
|
}
|
|
4617
|
+
function validateInputBindings(value, path53, issues, declaredInputs) {
|
|
4618
|
+
if (value === void 0) return;
|
|
4619
|
+
const bindings = asRecord(value);
|
|
4620
|
+
if (!bindings || Object.keys(bindings).length === 0) {
|
|
4621
|
+
issue(issues, "invalid_inputs", path53, "workflow step inputs must contain at least one named mapping");
|
|
4622
|
+
return;
|
|
4623
|
+
}
|
|
4624
|
+
for (const [name, value2] of Object.entries(bindings)) {
|
|
4625
|
+
const bindingPath = `${path53}.${name}`;
|
|
4626
|
+
if (!/^[A-Za-z_][A-Za-z0-9_-]*$/.test(name)) {
|
|
4627
|
+
issue(issues, "invalid_input_name", bindingPath, `workflow input name ${name} is invalid`);
|
|
4628
|
+
}
|
|
4629
|
+
if (declaredInputs && !declaredInputs.has(name)) {
|
|
4630
|
+
issue(issues, "undeclared_input", bindingPath, `target capability does not declare input ${name}`);
|
|
4631
|
+
}
|
|
4632
|
+
const binding = asRecord(value2);
|
|
4633
|
+
const from = text(binding?.from);
|
|
4634
|
+
if (!binding || Object.keys(binding).some((field) => field !== "from") || !from || !SAFE_INPUT_SOURCE.test(from)) {
|
|
4635
|
+
issue(
|
|
4636
|
+
issues,
|
|
4637
|
+
"invalid_input_source",
|
|
4638
|
+
`${bindingPath}.from`,
|
|
4639
|
+
"workflow input mapping must read from workflow input/state or a prior step result"
|
|
4640
|
+
);
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
function validateInputBindingSources(value, path53, issues, capabilitiesByStep, capabilityOutputs) {
|
|
4645
|
+
const bindings = asRecord(value);
|
|
4646
|
+
if (!bindings) return;
|
|
4647
|
+
for (const [name, rawBinding] of Object.entries(bindings)) {
|
|
4648
|
+
const from = text(asRecord(rawBinding)?.from);
|
|
4649
|
+
if (!from?.startsWith("steps.")) continue;
|
|
4650
|
+
const parts = from.split(".");
|
|
4651
|
+
const sourceStep = parts[1];
|
|
4652
|
+
const sourceCapability = sourceStep ? capabilitiesByStep.get(sourceStep) : void 0;
|
|
4653
|
+
if (!sourceStep || !sourceCapability) {
|
|
4654
|
+
issue(
|
|
4655
|
+
issues,
|
|
4656
|
+
"missing_input_step",
|
|
4657
|
+
`${path53}.${name}.from`,
|
|
4658
|
+
`workflow input mapping references missing step ${sourceStep ?? "<none>"}`
|
|
4659
|
+
);
|
|
4660
|
+
continue;
|
|
4661
|
+
}
|
|
4662
|
+
const outputPath = parts.slice(2).join(".");
|
|
4663
|
+
const declaredOutputs = capabilityOutputs?.get(sourceCapability);
|
|
4664
|
+
if (declaredOutputs && !declaredOutputs.has(outputPath)) {
|
|
4665
|
+
issue(
|
|
4666
|
+
issues,
|
|
4667
|
+
"undeclared_step_output",
|
|
4668
|
+
`${path53}.${name}.from`,
|
|
4669
|
+
`workflow input mapping reads ${outputPath}, but step ${sourceStep} does not declare it`
|
|
4670
|
+
);
|
|
4671
|
+
}
|
|
4672
|
+
}
|
|
4673
|
+
}
|
|
4584
4674
|
function formatWorkflowValidationIssues(issues) {
|
|
4585
4675
|
return issues.map((entry) => `${entry.path}: ${entry.message}`);
|
|
4586
4676
|
}
|
|
@@ -4636,17 +4726,19 @@ function isJsonValue(value) {
|
|
|
4636
4726
|
function issue(issues, code, path53, message) {
|
|
4637
4727
|
issues.push({ code, path: path53, message });
|
|
4638
4728
|
}
|
|
4639
|
-
var SAFE_NAME, SAFE_STEP_ID, SAFE_DATA_PATH, SUPPORTED_STEP_FIELDS, SUPPORTED_TRANSITION_FIELDS;
|
|
4729
|
+
var SAFE_NAME, SAFE_STEP_ID, SAFE_DATA_PATH, SAFE_INPUT_SOURCE, SUPPORTED_STEP_FIELDS, SUPPORTED_TRANSITION_FIELDS;
|
|
4640
4730
|
var init_workflowValidation = __esm({
|
|
4641
4731
|
"src/workflowValidation.ts"() {
|
|
4642
4732
|
"use strict";
|
|
4643
4733
|
SAFE_NAME = /^[a-z][a-z0-9-]*$/;
|
|
4644
4734
|
SAFE_STEP_ID = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
4645
4735
|
SAFE_DATA_PATH = /^(facts|evidence|artifacts|result|workflow|lastOutcome)(?:\.[A-Za-z_][A-Za-z0-9_-]*)+$/;
|
|
4736
|
+
SAFE_INPUT_SOURCE = /^(?:workflow\.(?:input|facts|evidence)(?:\.[A-Za-z_][A-Za-z0-9_-]*)+|steps\.[A-Za-z][A-Za-z0-9_-]*\.result(?:\.[A-Za-z_][A-Za-z0-9_-]*)+)$/;
|
|
4646
4737
|
SUPPORTED_STEP_FIELDS = /* @__PURE__ */ new Set([
|
|
4647
4738
|
"id",
|
|
4648
4739
|
"capability",
|
|
4649
4740
|
"input",
|
|
4741
|
+
"inputs",
|
|
4650
4742
|
"action",
|
|
4651
4743
|
"evidence",
|
|
4652
4744
|
"target",
|
|
@@ -17743,53 +17835,6 @@ var init_prepareBrowserAuth = __esm({
|
|
|
17743
17835
|
}
|
|
17744
17836
|
});
|
|
17745
17837
|
|
|
17746
|
-
// src/scripts/prepareSimpleCapabilityRuntime.ts
|
|
17747
|
-
function requirementsFrom(ctx) {
|
|
17748
|
-
const raw = ctx.data.capabilityRequirements;
|
|
17749
|
-
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
17750
|
-
}
|
|
17751
|
-
function configureBrowser(profile) {
|
|
17752
|
-
if (!profile.claudeCode.tools.includes("mcp__playwright")) {
|
|
17753
|
-
profile.claudeCode.tools = [...profile.claudeCode.tools, "mcp__playwright"];
|
|
17754
|
-
}
|
|
17755
|
-
if (!profile.claudeCode.mcpServers.some(({ name }) => name === PLAYWRIGHT_SERVER.name)) {
|
|
17756
|
-
profile.claudeCode.mcpServers = [...profile.claudeCode.mcpServers, PLAYWRIGHT_SERVER];
|
|
17757
|
-
}
|
|
17758
|
-
}
|
|
17759
|
-
function appendPrompt(ctx, section) {
|
|
17760
|
-
const prompt = typeof ctx.data.prompt === "string" ? ctx.data.prompt.trim() : "";
|
|
17761
|
-
ctx.data.prompt = [prompt, section.trim()].filter(Boolean).join("\n\n");
|
|
17762
|
-
}
|
|
17763
|
-
var PLAYWRIGHT_SERVER, prepareSimpleCapabilityRuntime;
|
|
17764
|
-
var init_prepareSimpleCapabilityRuntime = __esm({
|
|
17765
|
-
"src/scripts/prepareSimpleCapabilityRuntime.ts"() {
|
|
17766
|
-
"use strict";
|
|
17767
|
-
init_loadQaContext();
|
|
17768
|
-
PLAYWRIGHT_SERVER = {
|
|
17769
|
-
name: "playwright",
|
|
17770
|
-
command: "npx",
|
|
17771
|
-
args: ["-y", "--package=@playwright/mcp@latest", "--", "playwright-mcp", "--headless"]
|
|
17772
|
-
};
|
|
17773
|
-
prepareSimpleCapabilityRuntime = async (ctx, profile) => {
|
|
17774
|
-
const requirements = requirementsFrom(ctx);
|
|
17775
|
-
if (!requirements.browser) return;
|
|
17776
|
-
configureBrowser(profile);
|
|
17777
|
-
if (!requirements.qaCredentials) return;
|
|
17778
|
-
await loadQaContext(ctx, profile);
|
|
17779
|
-
appendPrompt(
|
|
17780
|
-
ctx,
|
|
17781
|
-
[
|
|
17782
|
-
"## QA authentication",
|
|
17783
|
-
"",
|
|
17784
|
-
String(ctx.data.qaAuthBlock ?? ""),
|
|
17785
|
-
"",
|
|
17786
|
-
"If the changed surface requires authentication and the credentials are missing or the login is rejected, return a blocked result with a safe explanation. Do not include usernames, passwords, tokens, or other credential values in the result."
|
|
17787
|
-
].join("\n")
|
|
17788
|
-
);
|
|
17789
|
-
};
|
|
17790
|
-
}
|
|
17791
|
-
});
|
|
17792
|
-
|
|
17793
17838
|
// src/capabilityDelivery.ts
|
|
17794
17839
|
function capabilityDeliveryTarget(input) {
|
|
17795
17840
|
if (!input || typeof input !== "object" || Array.isArray(input)) return null;
|
|
@@ -17901,6 +17946,53 @@ var init_prepareCapabilityDelivery = __esm({
|
|
|
17901
17946
|
}
|
|
17902
17947
|
});
|
|
17903
17948
|
|
|
17949
|
+
// src/scripts/prepareSimpleCapabilityRuntime.ts
|
|
17950
|
+
function requirementsFrom(ctx) {
|
|
17951
|
+
const raw = ctx.data.capabilityRequirements;
|
|
17952
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
17953
|
+
}
|
|
17954
|
+
function configureBrowser(profile) {
|
|
17955
|
+
if (!profile.claudeCode.tools.includes("mcp__playwright")) {
|
|
17956
|
+
profile.claudeCode.tools = [...profile.claudeCode.tools, "mcp__playwright"];
|
|
17957
|
+
}
|
|
17958
|
+
if (!profile.claudeCode.mcpServers.some(({ name }) => name === PLAYWRIGHT_SERVER.name)) {
|
|
17959
|
+
profile.claudeCode.mcpServers = [...profile.claudeCode.mcpServers, PLAYWRIGHT_SERVER];
|
|
17960
|
+
}
|
|
17961
|
+
}
|
|
17962
|
+
function appendPrompt(ctx, section) {
|
|
17963
|
+
const prompt = typeof ctx.data.prompt === "string" ? ctx.data.prompt.trim() : "";
|
|
17964
|
+
ctx.data.prompt = [prompt, section.trim()].filter(Boolean).join("\n\n");
|
|
17965
|
+
}
|
|
17966
|
+
var PLAYWRIGHT_SERVER, prepareSimpleCapabilityRuntime;
|
|
17967
|
+
var init_prepareSimpleCapabilityRuntime = __esm({
|
|
17968
|
+
"src/scripts/prepareSimpleCapabilityRuntime.ts"() {
|
|
17969
|
+
"use strict";
|
|
17970
|
+
init_loadQaContext();
|
|
17971
|
+
PLAYWRIGHT_SERVER = {
|
|
17972
|
+
name: "playwright",
|
|
17973
|
+
command: "npx",
|
|
17974
|
+
args: ["-y", "--package=@playwright/mcp@latest", "--", "playwright-mcp", "--headless"]
|
|
17975
|
+
};
|
|
17976
|
+
prepareSimpleCapabilityRuntime = async (ctx, profile) => {
|
|
17977
|
+
const requirements = requirementsFrom(ctx);
|
|
17978
|
+
if (!requirements.browser) return;
|
|
17979
|
+
configureBrowser(profile);
|
|
17980
|
+
if (!requirements.qaCredentials) return;
|
|
17981
|
+
await loadQaContext(ctx, profile);
|
|
17982
|
+
appendPrompt(
|
|
17983
|
+
ctx,
|
|
17984
|
+
[
|
|
17985
|
+
"## QA authentication",
|
|
17986
|
+
"",
|
|
17987
|
+
String(ctx.data.qaAuthBlock ?? ""),
|
|
17988
|
+
"",
|
|
17989
|
+
"If the changed surface requires authentication and the credentials are missing or the login is rejected, return a blocked result with a safe explanation. Do not include usernames, passwords, tokens, or other credential values in the result."
|
|
17990
|
+
].join("\n")
|
|
17991
|
+
);
|
|
17992
|
+
};
|
|
17993
|
+
}
|
|
17994
|
+
});
|
|
17995
|
+
|
|
17904
17996
|
// src/scripts/promoteQaGoal.ts
|
|
17905
17997
|
var REPORT_JSON_OPEN2, promoteQaGoal;
|
|
17906
17998
|
var init_promoteQaGoal = __esm({
|
|
@@ -18463,45 +18555,6 @@ var init_requirePlanDeviations = __esm({
|
|
|
18463
18555
|
}
|
|
18464
18556
|
});
|
|
18465
18557
|
|
|
18466
|
-
// src/scripts/retryMissingDeliveryChange.ts
|
|
18467
|
-
function claimsChange(output) {
|
|
18468
|
-
if (!output || typeof output !== "object" || Array.isArray(output)) return false;
|
|
18469
|
-
const status = output.status;
|
|
18470
|
-
return status === "fixed" || status === "changed";
|
|
18471
|
-
}
|
|
18472
|
-
var retryMissingDeliveryChange;
|
|
18473
|
-
var init_retryMissingDeliveryChange = __esm({
|
|
18474
|
-
"src/scripts/retryMissingDeliveryChange.ts"() {
|
|
18475
|
-
"use strict";
|
|
18476
|
-
init_commit();
|
|
18477
|
-
init_parseAgentResult();
|
|
18478
|
-
init_parseSimpleCapabilityOutput();
|
|
18479
|
-
retryMissingDeliveryChange = async (ctx, profile) => {
|
|
18480
|
-
if (ctx.data.jobDelivery !== "pull-request") return;
|
|
18481
|
-
if (!claimsChange(ctx.data.capabilityOutput)) return;
|
|
18482
|
-
if (listChangedFiles(ctx.cwd).some((file) => !isForbiddenPath(file))) return;
|
|
18483
|
-
const invoker = ctx.data.__invokeAgent;
|
|
18484
|
-
const prompt = ctx.data.prompt;
|
|
18485
|
-
if (!invoker || !prompt) return;
|
|
18486
|
-
process.stderr.write("[kody] capability claimed a pull-request fix without a file change; retrying once\n");
|
|
18487
|
-
const retry = await invoker(
|
|
18488
|
-
[
|
|
18489
|
-
prompt,
|
|
18490
|
-
"",
|
|
18491
|
-
"# Missing delivery change (retry)",
|
|
18492
|
-
"",
|
|
18493
|
-
"Your previous result claimed the pull request was fixed, but no repository file changed.",
|
|
18494
|
-
"Inspect the supplied input and failure evidence, make the actual repair, and verify it.",
|
|
18495
|
-
"If no safe change is possible, return a blocked result instead of claiming fixed.",
|
|
18496
|
-
"This is the only retry."
|
|
18497
|
-
].join("\n")
|
|
18498
|
-
);
|
|
18499
|
-
await parseAgentResult2(ctx, profile, retry);
|
|
18500
|
-
await parseSimpleCapabilityOutput(ctx, profile, retry);
|
|
18501
|
-
};
|
|
18502
|
-
}
|
|
18503
|
-
});
|
|
18504
|
-
|
|
18505
18558
|
// src/scripts/resolveArtifacts.ts
|
|
18506
18559
|
var resolveArtifacts;
|
|
18507
18560
|
var init_resolveArtifacts = __esm({
|
|
@@ -21118,8 +21171,8 @@ var init_scripts = __esm({
|
|
|
21118
21171
|
init_postResearchComment();
|
|
21119
21172
|
init_postReviewResult();
|
|
21120
21173
|
init_prepareBrowserAuth();
|
|
21121
|
-
init_prepareSimpleCapabilityRuntime();
|
|
21122
21174
|
init_prepareCapabilityDelivery();
|
|
21175
|
+
init_prepareSimpleCapabilityRuntime();
|
|
21123
21176
|
init_promoteQaGoal();
|
|
21124
21177
|
init_publishReport();
|
|
21125
21178
|
init_recordClassification();
|
|
@@ -21127,7 +21180,6 @@ var init_scripts = __esm({
|
|
|
21127
21180
|
init_requireDeliveryArtifacts();
|
|
21128
21181
|
init_requireFeedbackActions();
|
|
21129
21182
|
init_requirePlanDeviations();
|
|
21130
|
-
init_retryMissingDeliveryChange();
|
|
21131
21183
|
init_resolveArtifacts();
|
|
21132
21184
|
init_resolveFlow();
|
|
21133
21185
|
init_resolvePreviewUrl();
|
|
@@ -21226,7 +21278,6 @@ var init_scripts = __esm({
|
|
|
21226
21278
|
requireFeedbackActions,
|
|
21227
21279
|
requireDeliveryArtifacts,
|
|
21228
21280
|
requirePlanDeviations,
|
|
21229
|
-
retryMissingDeliveryChange,
|
|
21230
21281
|
verify,
|
|
21231
21282
|
verifyWithRetry,
|
|
21232
21283
|
verifyReproFails,
|
|
@@ -22499,6 +22550,8 @@ function parseWorkflowRunState(raw) {
|
|
|
22499
22550
|
)
|
|
22500
22551
|
) : {};
|
|
22501
22552
|
const facts = state.facts && typeof state.facts === "object" && !Array.isArray(state.facts) ? state.facts : {};
|
|
22553
|
+
const input = state.input && typeof state.input === "object" && !Array.isArray(state.input) ? state.input : void 0;
|
|
22554
|
+
const steps = parseWorkflowSteps(state.steps);
|
|
22502
22555
|
const evidenceEntries = state.evidence && typeof state.evidence === "object" && !Array.isArray(state.evidence) ? Object.entries(state.evidence).filter((entry) => typeof entry[1] === "boolean") : [];
|
|
22503
22556
|
const artifacts = Array.isArray(state.artifacts) ? state.artifacts.filter(
|
|
22504
22557
|
(artifact) => !!artifact && typeof artifact === "object" && typeof artifact.label === "string" && (artifact.url === void 0 || typeof artifact.url === "string") && (artifact.path === void 0 || typeof artifact.path === "string")
|
|
@@ -22508,12 +22561,35 @@ function parseWorkflowRunState(raw) {
|
|
|
22508
22561
|
...typeof state.currentStepId === "string" ? { currentStepId: state.currentStepId } : {},
|
|
22509
22562
|
completedStepIds,
|
|
22510
22563
|
transitionCounts,
|
|
22564
|
+
...input ? { input: { ...input } } : {},
|
|
22565
|
+
...typeof state.definitionHash === "string" && state.definitionHash.trim() ? { definitionHash: state.definitionHash.trim() } : {},
|
|
22566
|
+
...steps ? { steps } : {},
|
|
22511
22567
|
facts: { ...facts },
|
|
22512
22568
|
evidence: Object.fromEntries(evidenceEntries),
|
|
22513
22569
|
artifacts: artifacts.map((artifact) => ({ ...artifact })),
|
|
22514
22570
|
...typeof state.blocker === "string" ? { blocker: state.blocker } : {}
|
|
22515
22571
|
};
|
|
22516
22572
|
}
|
|
22573
|
+
function parseWorkflowSteps(value) {
|
|
22574
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
22575
|
+
const steps = {};
|
|
22576
|
+
for (const [stepId, raw] of Object.entries(value)) {
|
|
22577
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) continue;
|
|
22578
|
+
const step = raw;
|
|
22579
|
+
if (step.status !== "running" && step.status !== "completed" && step.status !== "blocked" && step.status !== "failed") {
|
|
22580
|
+
continue;
|
|
22581
|
+
}
|
|
22582
|
+
steps[stepId] = {
|
|
22583
|
+
status: step.status,
|
|
22584
|
+
...typeof step.capability === "string" ? { capability: step.capability } : {},
|
|
22585
|
+
...Object.hasOwn(step, "input") ? { input: step.input } : {},
|
|
22586
|
+
...Object.hasOwn(step, "output") ? { output: step.output } : {},
|
|
22587
|
+
...typeof step.startedAt === "string" ? { startedAt: step.startedAt } : {},
|
|
22588
|
+
...typeof step.completedAt === "string" ? { completedAt: step.completedAt } : {}
|
|
22589
|
+
};
|
|
22590
|
+
}
|
|
22591
|
+
return Object.keys(steps).length > 0 ? steps : void 0;
|
|
22592
|
+
}
|
|
22517
22593
|
async function readWorkflowRunState(config, _cwd, workflowId, runId) {
|
|
22518
22594
|
const tenantId2 = runtimeTenant(config);
|
|
22519
22595
|
const row = await createStateBackendFromEnv().getWorkflowRun(tenantId2, workflowId, runId);
|
|
@@ -22556,6 +22632,7 @@ __export(job_exports, {
|
|
|
22556
22632
|
stableJobKey: () => stableJobKey,
|
|
22557
22633
|
validateJob: () => validateJob
|
|
22558
22634
|
});
|
|
22635
|
+
import { createHash as createHash8 } from "crypto";
|
|
22559
22636
|
function newJobId(flavor) {
|
|
22560
22637
|
localJobSeq += 1;
|
|
22561
22638
|
const runId = process.env.GITHUB_RUN_ID;
|
|
@@ -22844,6 +22921,8 @@ async function runLinearCapabilityWorkflow(parent, workflow, capability, base, c
|
|
|
22844
22921
|
workflowStepCount: workflow.steps.length,
|
|
22845
22922
|
workflowIssueNumber: workflowIssueNumber(parent),
|
|
22846
22923
|
workflowContext: workflowInputContext(parent.cliArgs),
|
|
22924
|
+
workflowInput: state.input ?? {},
|
|
22925
|
+
workflowStepResults: workflowStepResults(state.steps),
|
|
22847
22926
|
workflowFacts: parent.workflowFacts ?? {},
|
|
22848
22927
|
workflowStack: [
|
|
22849
22928
|
...Array.isArray(base.preloadedData?.workflowStack) ? base.preloadedData.workflowStack.filter((entry) => typeof entry === "string") : [],
|
|
@@ -22864,6 +22943,8 @@ async function runLinearCapabilityWorkflow(parent, workflow, capability, base, c
|
|
|
22864
22943
|
continue;
|
|
22865
22944
|
}
|
|
22866
22945
|
const child = workflowStepToJob(step, parent, chainData, base.cwd);
|
|
22946
|
+
beginWorkflowStep(state, step, child);
|
|
22947
|
+
await checkpoint?.(state);
|
|
22867
22948
|
process.stdout.write(
|
|
22868
22949
|
`\u2192 kody: workflow ${capability.slug} step ${index + 1}/${workflow.steps.length} \u2192 ${label}
|
|
22869
22950
|
|
|
@@ -22883,6 +22964,7 @@ async function runLinearCapabilityWorkflow(parent, workflow, capability, base, c
|
|
|
22883
22964
|
workflowContinueOn: step.continueOn ?? []
|
|
22884
22965
|
}
|
|
22885
22966
|
});
|
|
22967
|
+
finishWorkflowStep(state, step, result);
|
|
22886
22968
|
mergeWorkflowResults(state, result.capabilityResults);
|
|
22887
22969
|
if (result.capabilityOutput && typeof result.capabilityOutput === "object" && !Array.isArray(result.capabilityOutput)) {
|
|
22888
22970
|
Object.assign(state.facts, result.capabilityOutput);
|
|
@@ -22891,6 +22973,7 @@ async function runLinearCapabilityWorkflow(parent, workflow, capability, base, c
|
|
|
22891
22973
|
const prUrl = result.prUrl ?? result.taskState?.core.prUrl ?? (typeof chainData.workflowPrUrl === "string" ? chainData.workflowPrUrl : void 0);
|
|
22892
22974
|
chainData = {
|
|
22893
22975
|
...chainData,
|
|
22976
|
+
workflowStepResults: workflowStepResults(state.steps),
|
|
22894
22977
|
...result.taskState ? { taskState: result.taskState } : {},
|
|
22895
22978
|
...outcome ? { workflowLastOutcome: outcome } : {},
|
|
22896
22979
|
...result.capabilityOutput !== void 0 ? {
|
|
@@ -22922,6 +23005,7 @@ function isGraphWorkflow(workflow) {
|
|
|
22922
23005
|
function workflowError(workflow, base) {
|
|
22923
23006
|
const projectCapabilitiesRoot = hydratedCapabilitiesRoot(base.cwd);
|
|
22924
23007
|
const knownCapabilities = /* @__PURE__ */ new Set();
|
|
23008
|
+
const capabilityInputs = /* @__PURE__ */ new Map();
|
|
22925
23009
|
const capabilityOutputs = /* @__PURE__ */ new Map();
|
|
22926
23010
|
for (const step of workflow.steps) {
|
|
22927
23011
|
const action = step.action ?? step.capability;
|
|
@@ -22929,10 +23013,14 @@ function workflowError(workflow, base) {
|
|
|
22929
23013
|
const resolvedFolder = resolveCapabilityFolder(step.capability, projectCapabilitiesRoot);
|
|
22930
23014
|
if (!resolvedAction && !resolvedFolder) continue;
|
|
22931
23015
|
knownCapabilities.add(step.capability);
|
|
23016
|
+
const inputNames = resolvedFolder ? capabilityInputNames(resolvedFolder) : /* @__PURE__ */ new Set();
|
|
23017
|
+
if (inputNames.size > 0) capabilityInputs.set(step.capability, inputNames);
|
|
22932
23018
|
const outputPaths = resolvedFolder ? capabilityOutputConditionPaths(resolvedFolder.config) : /* @__PURE__ */ new Set();
|
|
22933
23019
|
if (outputPaths.size > 0) capabilityOutputs.set(step.capability, outputPaths);
|
|
22934
23020
|
}
|
|
22935
|
-
return formatWorkflowValidationIssues(
|
|
23021
|
+
return formatWorkflowValidationIssues(
|
|
23022
|
+
validateWorkflow(workflow, { knownCapabilities, capabilityInputs, capabilityOutputs })
|
|
23023
|
+
)[0] ?? null;
|
|
22936
23024
|
}
|
|
22937
23025
|
function initialWorkflowState(parent, workflow) {
|
|
22938
23026
|
const prior = parent.workflowState;
|
|
@@ -22942,6 +23030,8 @@ function initialWorkflowState(parent, workflow) {
|
|
|
22942
23030
|
status: "done",
|
|
22943
23031
|
completedStepIds: [...prior.completedStepIds],
|
|
22944
23032
|
transitionCounts: { ...prior.transitionCounts },
|
|
23033
|
+
...prior.input ? { input: { ...prior.input } } : {},
|
|
23034
|
+
...prior.steps ? { steps: cloneWorkflowSteps(prior.steps) } : {},
|
|
22945
23035
|
facts: { ...prior.facts },
|
|
22946
23036
|
evidence: { ...prior.evidence },
|
|
22947
23037
|
artifacts: prior.artifacts.map((artifact) => ({ ...artifact }))
|
|
@@ -22951,9 +23041,12 @@ function initialWorkflowState(parent, workflow) {
|
|
|
22951
23041
|
const currentStepId = prior?.currentStepId ?? firstStepId;
|
|
22952
23042
|
return {
|
|
22953
23043
|
status: "running",
|
|
23044
|
+
input: { ...prior?.input ?? workflowInputContext(parent.cliArgs) },
|
|
23045
|
+
definitionHash: prior?.definitionHash ?? workflowDefinitionHash(workflow),
|
|
22954
23046
|
...currentStepId ? { currentStepId } : {},
|
|
22955
23047
|
completedStepIds: [...prior?.completedStepIds ?? []],
|
|
22956
23048
|
transitionCounts: { ...prior?.transitionCounts ?? {} },
|
|
23049
|
+
steps: cloneWorkflowSteps(prior?.steps ?? {}),
|
|
22957
23050
|
facts: {
|
|
22958
23051
|
...workflowInputContext(parent.cliArgs),
|
|
22959
23052
|
...parent.workflowFacts ?? {},
|
|
@@ -22975,6 +23068,8 @@ function workflowChainData(parent, capability, base, state) {
|
|
|
22975
23068
|
workflowStepCount: capability.config.workflow?.steps.length ?? 0,
|
|
22976
23069
|
workflowIssueNumber: workflowIssueNumber(parent),
|
|
22977
23070
|
workflowContext: base.preloadedData?.workflowContext ?? workflowInputContext(parent.cliArgs),
|
|
23071
|
+
workflowInput: state.input ?? {},
|
|
23072
|
+
workflowStepResults: workflowStepResults(state.steps),
|
|
22978
23073
|
workflowFacts: state.facts,
|
|
22979
23074
|
workflowEvidence: state.evidence,
|
|
22980
23075
|
workflowArtifacts: state.artifacts,
|
|
@@ -23017,9 +23112,18 @@ async function runGraphCapabilityWorkflow(parent, workflow, capability, base, ch
|
|
|
23017
23112
|
const reason = error instanceof Error ? error.message : String(error);
|
|
23018
23113
|
state.status = "blocked";
|
|
23019
23114
|
state.blocker = reason;
|
|
23115
|
+
state.steps = state.steps ?? {};
|
|
23116
|
+
state.steps[step.id] = {
|
|
23117
|
+
capability: step.capability,
|
|
23118
|
+
status: "blocked",
|
|
23119
|
+
output: { status: "blocked", summary: reason },
|
|
23120
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23121
|
+
};
|
|
23020
23122
|
await checkpoint?.(state);
|
|
23021
23123
|
return { exitCode: 64, reason, workflowState: state };
|
|
23022
23124
|
}
|
|
23125
|
+
beginWorkflowStep(state, step, child);
|
|
23126
|
+
await checkpoint?.(state);
|
|
23023
23127
|
process.stdout.write(
|
|
23024
23128
|
`\u2192 kody: workflow ${capability.slug} step ${index + 1}/${workflow.steps.length} \u2192 ${label}
|
|
23025
23129
|
|
|
@@ -23044,6 +23148,7 @@ async function runGraphCapabilityWorkflow(parent, workflow, capability, base, ch
|
|
|
23044
23148
|
workflowContinueOn: step.continueOn ?? []
|
|
23045
23149
|
}
|
|
23046
23150
|
});
|
|
23151
|
+
finishWorkflowStep(state, step, result);
|
|
23047
23152
|
mergeWorkflowResults(state, result.capabilityResults);
|
|
23048
23153
|
if (result.capabilityOutput && typeof result.capabilityOutput === "object" && !Array.isArray(result.capabilityOutput)) {
|
|
23049
23154
|
Object.assign(state.facts, result.capabilityOutput);
|
|
@@ -23201,9 +23306,8 @@ function withWorkflowBoundaryEval(capability, result) {
|
|
|
23201
23306
|
function workflowStepToJob(step, parent, chainData, cwd) {
|
|
23202
23307
|
const action = step.action ?? step.capability;
|
|
23203
23308
|
const targetNumber = workflowStepTargetNumber(step, parent, chainData);
|
|
23204
|
-
const
|
|
23205
|
-
|
|
23206
|
-
};
|
|
23309
|
+
const mappedInputs = resolveWorkflowStepInputs(step, chainData);
|
|
23310
|
+
const rawArgs = mappedInputs ? { ...mappedInputs } : { ...parent.cliArgs };
|
|
23207
23311
|
if (step.target === "pr") {
|
|
23208
23312
|
if (typeof targetNumber !== "number") {
|
|
23209
23313
|
throw new InvalidJobError(`workflow step ${action} needs a PR target but no prior PR URL is available`);
|
|
@@ -23213,7 +23317,7 @@ function workflowStepToJob(step, parent, chainData, cwd) {
|
|
|
23213
23317
|
rawArgs.issue = targetNumber;
|
|
23214
23318
|
}
|
|
23215
23319
|
const genericInput = capabilityStepInput(
|
|
23216
|
-
step.input ??
|
|
23320
|
+
step.input ?? mappedInputs ?? chainData.workflowInput ?? genericInputFromArgs(rawArgs),
|
|
23217
23321
|
step.target,
|
|
23218
23322
|
targetNumber
|
|
23219
23323
|
);
|
|
@@ -23236,6 +23340,74 @@ function workflowStepToJob(step, parent, chainData, cwd) {
|
|
|
23236
23340
|
...parent.resultTarget ? { resultTarget: parent.resultTarget } : {}
|
|
23237
23341
|
};
|
|
23238
23342
|
}
|
|
23343
|
+
function resolveWorkflowStepInputs(step, chainData) {
|
|
23344
|
+
if (!step.inputs) return void 0;
|
|
23345
|
+
const source = {
|
|
23346
|
+
workflow: {
|
|
23347
|
+
input: chainData.workflowInput ?? {},
|
|
23348
|
+
facts: chainData.workflowFacts ?? {},
|
|
23349
|
+
evidence: chainData.workflowEvidence ?? {}
|
|
23350
|
+
},
|
|
23351
|
+
steps: chainData.workflowStepResults ?? {}
|
|
23352
|
+
};
|
|
23353
|
+
const input = {};
|
|
23354
|
+
for (const [name, binding] of Object.entries(step.inputs)) {
|
|
23355
|
+
const value = resolveDottedPath2(source, binding.from);
|
|
23356
|
+
if (value === void 0) {
|
|
23357
|
+
throw new InvalidJobError(`workflow step ${step.id ?? step.capability} needs missing input ${binding.from}`);
|
|
23358
|
+
}
|
|
23359
|
+
input[name] = value;
|
|
23360
|
+
}
|
|
23361
|
+
return input;
|
|
23362
|
+
}
|
|
23363
|
+
function capabilityInputNames(folder) {
|
|
23364
|
+
const properties = folder.config.inputSchema?.properties;
|
|
23365
|
+
if (!properties || typeof properties !== "object" || Array.isArray(properties)) return /* @__PURE__ */ new Set();
|
|
23366
|
+
return new Set(Object.keys(properties));
|
|
23367
|
+
}
|
|
23368
|
+
function workflowDefinitionHash(workflow) {
|
|
23369
|
+
return createHash8("sha256").update(stableJson(workflow)).digest("hex");
|
|
23370
|
+
}
|
|
23371
|
+
function stableJson(value) {
|
|
23372
|
+
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
23373
|
+
if (value && typeof value === "object") {
|
|
23374
|
+
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`).join(",")}}`;
|
|
23375
|
+
}
|
|
23376
|
+
return JSON.stringify(value);
|
|
23377
|
+
}
|
|
23378
|
+
function cloneWorkflowSteps(steps) {
|
|
23379
|
+
return Object.fromEntries(Object.entries(steps).map(([id, step]) => [id, { ...step }]));
|
|
23380
|
+
}
|
|
23381
|
+
function workflowStepResults(steps) {
|
|
23382
|
+
return Object.fromEntries(
|
|
23383
|
+
Object.entries(steps ?? {}).map(([id, step]) => [id, Object.hasOwn(step, "output") ? { result: step.output } : {}])
|
|
23384
|
+
);
|
|
23385
|
+
}
|
|
23386
|
+
function workflowStepAuditInput(job) {
|
|
23387
|
+
if (Object.hasOwn(job.cliArgs, "input")) return genericInputFromArgs(job.cliArgs);
|
|
23388
|
+
return { ...job.cliArgs };
|
|
23389
|
+
}
|
|
23390
|
+
function beginWorkflowStep(state, step, job) {
|
|
23391
|
+
const id = step.id ?? step.action ?? step.capability;
|
|
23392
|
+
state.steps = state.steps ?? {};
|
|
23393
|
+
state.steps[id] = {
|
|
23394
|
+
capability: step.capability,
|
|
23395
|
+
status: "running",
|
|
23396
|
+
input: workflowStepAuditInput(job),
|
|
23397
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23398
|
+
};
|
|
23399
|
+
}
|
|
23400
|
+
function finishWorkflowStep(state, step, result) {
|
|
23401
|
+
const id = step.id ?? step.action ?? step.capability;
|
|
23402
|
+
const prior = state.steps?.[id];
|
|
23403
|
+
state.steps = state.steps ?? {};
|
|
23404
|
+
state.steps[id] = {
|
|
23405
|
+
...prior ?? { capability: step.capability, status: "running" },
|
|
23406
|
+
status: result.exitCode === 0 ? "completed" : result.capabilityResults?.at(-1)?.status === "blocked" ? "blocked" : "failed",
|
|
23407
|
+
...result.capabilityOutput !== void 0 ? { output: result.capabilityOutput } : {},
|
|
23408
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23409
|
+
};
|
|
23410
|
+
}
|
|
23239
23411
|
function usesGenericCapabilityInput(action, cwd) {
|
|
23240
23412
|
const inputs = getCapabilityActionInputs(action, hydratedCapabilitiesRoot(cwd));
|
|
23241
23413
|
return Boolean(inputs?.length === 1 && inputs[0]?.name === "input" && inputs[0]?.flag === "--input");
|
|
@@ -23418,10 +23590,10 @@ var init_job = __esm({
|
|
|
23418
23590
|
init_config();
|
|
23419
23591
|
init_definition_paths();
|
|
23420
23592
|
init_executor();
|
|
23593
|
+
init_kody_api_client();
|
|
23421
23594
|
init_registry();
|
|
23422
23595
|
init_runIndex();
|
|
23423
23596
|
init_publishReport();
|
|
23424
|
-
init_kody_api_client();
|
|
23425
23597
|
init_simpleCapabilityRuntime();
|
|
23426
23598
|
init_state_backend();
|
|
23427
23599
|
init_workflowDefinitions();
|
|
@@ -595,9 +595,25 @@ export interface Job {
|
|
|
595
595
|
|
|
596
596
|
export interface WorkflowRunState {
|
|
597
597
|
status: "running" | "blocked" | "failed" | "done"
|
|
598
|
+
/** Immutable input supplied when this workflow run started. */
|
|
599
|
+
input?: Record<string, unknown>
|
|
600
|
+
/** Hash of the workflow definition used by this run. */
|
|
601
|
+
definitionHash?: string
|
|
598
602
|
currentStepId?: string
|
|
599
603
|
completedStepIds: string[]
|
|
600
604
|
transitionCounts: Record<string, number>
|
|
605
|
+
/** Exact per-step handoffs for audit, resume, and debugging. */
|
|
606
|
+
steps?: Record<
|
|
607
|
+
string,
|
|
608
|
+
{
|
|
609
|
+
capability?: string
|
|
610
|
+
status: "running" | "completed" | "blocked" | "failed"
|
|
611
|
+
input?: unknown
|
|
612
|
+
output?: unknown
|
|
613
|
+
startedAt?: string
|
|
614
|
+
completedAt?: string
|
|
615
|
+
}
|
|
616
|
+
>
|
|
601
617
|
facts: Record<string, unknown>
|
|
602
618
|
evidence: Record<string, boolean>
|
|
603
619
|
artifacts: Array<{ label: string; url?: string; path?: string }>
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Delivery
|
|
4
4
|
|
|
5
|
-
The delivery wrapper
|
|
6
|
-
|
|
5
|
+
The delivery wrapper has already checked out the requested target before you
|
|
6
|
+
start. Inspect and edit the current working tree. Do not fetch, checkout, sync,
|
|
7
|
+
merge, commit, push, or run any other git or GitHub write command; the wrapper
|
|
8
|
+
owns those operations.
|
|
7
9
|
|
|
8
10
|
After completing the capability work, finish with exactly this structure:
|
|
9
11
|
|
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.548",
|
|
4
4
|
"description": "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|