@kody-ade/kody-engine 0.4.565 → 0.4.566

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.
Files changed (2) hide show
  1. package/dist/bin/kody.js +56 -20
  2. package/package.json +1 -1
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.565",
18
+ version: "0.4.566",
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",
@@ -2289,6 +2289,7 @@ function parseWorkflowStep(value) {
2289
2289
  const target = stringField(raw.target);
2290
2290
  const delivery = stringField(raw.delivery);
2291
2291
  const targetFact = stringField(raw.targetFact ?? raw.target_fact);
2292
+ const timeoutSeconds = typeof raw.timeoutSeconds === "number" && Number.isInteger(raw.timeoutSeconds) && raw.timeoutSeconds > 0 && raw.timeoutSeconds <= 3600 ? raw.timeoutSeconds : void 0;
2292
2293
  const hasInput = Object.hasOwn(raw, "input");
2293
2294
  const inputs = parseWorkflowInputBindings(raw.inputs);
2294
2295
  const next = parseWorkflowTransitions(raw.next);
@@ -2304,6 +2305,7 @@ function parseWorkflowStep(value) {
2304
2305
  ...delivery === "pull-request" ? { delivery } : {},
2305
2306
  ...targetFact ? { targetFact } : {},
2306
2307
  ...reason ? { reason } : {},
2308
+ ...timeoutSeconds ? { timeoutSeconds } : {},
2307
2309
  ...next ? { next } : {},
2308
2310
  ...isPlainObject(raw.runWhen) ? { runWhen: raw.runWhen } : {},
2309
2311
  ...stringList(raw.continueOn ?? raw.continue_on).length > 0 ? { continueOn: stringList(raw.continueOn ?? raw.continue_on) } : {},
@@ -4722,6 +4724,15 @@ function validateWorkflow(value, options = {}) {
4722
4724
  if (step.input !== void 0 && step.inputs !== void 0) {
4723
4725
  issue(issues, "conflicting_inputs", base, "workflow step cannot declare both input and inputs");
4724
4726
  }
4727
+ const timeoutSeconds = step.timeoutSeconds;
4728
+ if (timeoutSeconds !== void 0 && (typeof timeoutSeconds !== "number" || !Number.isInteger(timeoutSeconds) || timeoutSeconds < 1 || timeoutSeconds > 3600)) {
4729
+ issue(
4730
+ issues,
4731
+ "invalid_step_timeout",
4732
+ `${base}.timeoutSeconds`,
4733
+ "workflow step timeoutSeconds must be an integer from 1 to 3600"
4734
+ );
4735
+ }
4725
4736
  validateInputBindings(
4726
4737
  step.inputs,
4727
4738
  `${base}.inputs`,
@@ -5005,6 +5016,7 @@ var init_workflowValidation = __esm({
5005
5016
  "delivery",
5006
5017
  "targetFact",
5007
5018
  "reason",
5019
+ "timeoutSeconds",
5008
5020
  "next",
5009
5021
  "runWhen",
5010
5022
  "continueOn",
@@ -23574,25 +23586,31 @@ async function runGraphCapabilityWorkflow(parent, workflow, capability, base, ch
23574
23586
 
23575
23587
  `
23576
23588
  );
23577
- result = await runJob(child, {
23578
- ...base,
23579
- preloadedData: {
23580
- ...chainData,
23581
- runSubjectType: "capability",
23582
- runSubjectId: step.capability,
23583
- runSubjectLabel: step.id,
23584
- workflowStep: step.id,
23585
- workflowStepIndex: index + 1,
23586
- workflowExecutionKey: graphWorkflowExecutionKey(
23587
- base.preloadedData?.workflowExecutionKey,
23588
- capability.slug,
23589
- step.id,
23590
- state.transitionCounts
23591
- ),
23592
- workflowStepReason: step.reason,
23593
- workflowContinueOn: step.continueOn ?? []
23594
- }
23595
- });
23589
+ const stepAbort = workflowStepAbortController(base.abortController, step.timeoutSeconds);
23590
+ try {
23591
+ result = await runJob(child, {
23592
+ ...base,
23593
+ abortController: stepAbort.controller,
23594
+ preloadedData: {
23595
+ ...chainData,
23596
+ runSubjectType: "capability",
23597
+ runSubjectId: step.capability,
23598
+ runSubjectLabel: step.id,
23599
+ workflowStep: step.id,
23600
+ workflowStepIndex: index + 1,
23601
+ workflowExecutionKey: graphWorkflowExecutionKey(
23602
+ base.preloadedData?.workflowExecutionKey,
23603
+ capability.slug,
23604
+ step.id,
23605
+ state.transitionCounts
23606
+ ),
23607
+ workflowStepReason: step.reason,
23608
+ workflowContinueOn: step.continueOn ?? []
23609
+ }
23610
+ });
23611
+ } finally {
23612
+ stepAbort.cleanup();
23613
+ }
23596
23614
  finishWorkflowStep(state, step, result);
23597
23615
  mergeWorkflowResults(state, result.capabilityResults);
23598
23616
  if (result.capabilityOutput && typeof result.capabilityOutput === "object" && !Array.isArray(result.capabilityOutput)) {
@@ -23900,6 +23918,24 @@ function canContinueWorkflow(step, outcome) {
23900
23918
  if (!outcome || !step.continueOn || step.continueOn.length === 0) return false;
23901
23919
  return step.continueOn.includes(outcome.type);
23902
23920
  }
23921
+ function workflowStepAbortController(parent, timeoutSeconds) {
23922
+ if (!timeoutSeconds) return { controller: parent, cleanup: () => void 0 };
23923
+ const controller = new AbortController();
23924
+ const forwardParentAbort = () => controller.abort(parent?.signal.reason);
23925
+ if (parent?.signal.aborted) forwardParentAbort();
23926
+ else parent?.signal.addEventListener("abort", forwardParentAbort, { once: true });
23927
+ const timer = setTimeout(() => {
23928
+ controller.abort(new Error(`workflow step timed out after ${timeoutSeconds}s`));
23929
+ }, timeoutSeconds * 1e3);
23930
+ timer.unref?.();
23931
+ return {
23932
+ controller,
23933
+ cleanup: () => {
23934
+ clearTimeout(timer);
23935
+ parent?.signal.removeEventListener("abort", forwardParentAbort);
23936
+ }
23937
+ };
23938
+ }
23903
23939
  function workflowOutcome(result) {
23904
23940
  return result.taskState?.core.lastOutcome ?? null;
23905
23941
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.565",
3
+ "version": "0.4.566",
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",