@kody-ade/kody-engine-lite 0.1.89 → 0.1.91

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/cli.js CHANGED
@@ -145,6 +145,22 @@ var init_agent_runner = __esm({
145
145
  });
146
146
 
147
147
  // src/definitions.ts
148
+ var definitions_exports = {};
149
+ __export(definitions_exports, {
150
+ STAGES: () => STAGES,
151
+ applyTimeoutOverrides: () => applyTimeoutOverrides,
152
+ getStage: () => getStage
153
+ });
154
+ function getStage(name) {
155
+ return STAGES.find((s) => s.name === name);
156
+ }
157
+ function applyTimeoutOverrides(overrides) {
158
+ for (const stage of STAGES) {
159
+ if (overrides[stage.name] != null) {
160
+ stage.timeout = overrides[stage.name] * 1e3;
161
+ }
162
+ }
163
+ }
148
164
  var STAGES;
149
165
  var init_definitions = __esm({
150
166
  "src/definitions.ts"() {
@@ -287,6 +303,7 @@ function getProjectConfig() {
287
303
  ...raw.agent,
288
304
  modelMap: { ...DEFAULT_CONFIG.agent.modelMap, ...raw.agent?.modelMap }
289
305
  },
306
+ timeouts: raw.timeouts ?? void 0,
290
307
  contextTiers: raw.contextTiers ? { ...DEFAULT_CONFIG.contextTiers, ...raw.contextTiers } : DEFAULT_CONFIG.contextTiers,
291
308
  mcp: raw.mcp ? { enabled: false, servers: {}, stages: ["build", "verify", "review", "review-fix"], ...raw.mcp } : void 0
292
309
  };
@@ -1661,6 +1678,9 @@ async function executeAgentStage(ctx, def) {
1661
1678
  }
1662
1679
  const prompt = buildFullPrompt(def.name, ctx.taskId, ctx.taskDir, ctx.projectDir, ctx.input.feedback);
1663
1680
  const model = resolveModel(def.modelTier, def.name);
1681
+ if (ctx.input.feedback && def.name === "build") {
1682
+ logger.info(` feedback: ${ctx.input.feedback.slice(0, 200)}${ctx.input.feedback.length > 200 ? "..." : ""}`);
1683
+ }
1664
1684
  const config = getProjectConfig();
1665
1685
  const runnerName = config.agent.stageRunners?.[def.name] ?? config.agent.defaultRunner ?? Object.keys(ctx.runners)[0] ?? "claude";
1666
1686
  logger.info(` runner=${runnerName} model=${model} timeout=${def.timeout / 1e3}s`);
@@ -2651,7 +2671,18 @@ function checkQuestionsAfterStage(ctx, def, state) {
2651
2671
  }
2652
2672
  function autoDetectComplexity(ctx, def) {
2653
2673
  if (def.name !== "taskify") return null;
2654
- if (ctx.input.complexity) return null;
2674
+ if (ctx.input.complexity) {
2675
+ const complexity = ctx.input.complexity;
2676
+ const activeStages = filterByComplexity(STAGES, complexity);
2677
+ logger.info(` Complexity override: ${complexity} (${activeStages.map((s) => s.name).join(" \u2192 ")})`);
2678
+ if (ctx.input.issueNumber && !ctx.input.local) {
2679
+ try {
2680
+ setLifecycleLabel(ctx.input.issueNumber, complexity);
2681
+ } catch {
2682
+ }
2683
+ }
2684
+ return { complexity, activeStages };
2685
+ }
2655
2686
  try {
2656
2687
  const taskJsonPath = path14.join(ctx.taskDir, "task.json");
2657
2688
  if (!fs14.existsSync(taskJsonPath)) return null;
@@ -3177,6 +3208,25 @@ async function runPipeline(ctx) {
3177
3208
  acquireLock(ctx.taskDir);
3178
3209
  try {
3179
3210
  return await runPipelineInner(ctx);
3211
+ } catch (err) {
3212
+ try {
3213
+ const state = loadState(ctx.taskId, ctx.taskDir);
3214
+ if (state && state.state === "running") {
3215
+ state.state = "failed";
3216
+ for (const stage of STAGES) {
3217
+ if (state.stages[stage.name]?.state === "running") {
3218
+ state.stages[stage.name] = {
3219
+ ...state.stages[stage.name],
3220
+ state: "failed",
3221
+ error: "Pipeline crashed unexpectedly"
3222
+ };
3223
+ }
3224
+ }
3225
+ writeState(state, ctx.taskDir);
3226
+ }
3227
+ } catch {
3228
+ }
3229
+ throw err;
3180
3230
  } finally {
3181
3231
  releaseLock(ctx.taskDir);
3182
3232
  }
@@ -4113,6 +4163,10 @@ ${input.feedback}`);
4113
4163
  }
4114
4164
  }
4115
4165
  const config = getProjectConfig();
4166
+ if (config.timeouts) {
4167
+ const { applyTimeoutOverrides: applyTimeoutOverrides2 } = await Promise.resolve().then(() => (init_definitions(), definitions_exports));
4168
+ applyTimeoutOverrides2(config.timeouts);
4169
+ }
4116
4170
  let litellmProcess = await ensureLitellmProxy(config, projectDir);
4117
4171
  await runModelHealthCheck(config);
4118
4172
  const cleanupLitellm = () => {
@@ -63,6 +63,20 @@
63
63
  },
64
64
  "additionalProperties": false
65
65
  },
66
+ "timeouts": {
67
+ "type": "object",
68
+ "description": "Per-stage timeout overrides in seconds. Defaults: taskify=600, plan=600, build=2400, verify=300, review=600, review-fix=1200, ship=240",
69
+ "properties": {
70
+ "taskify": { "type": "number", "description": "Taskify stage timeout in seconds", "default": 600 },
71
+ "plan": { "type": "number", "description": "Plan stage timeout in seconds", "default": 600 },
72
+ "build": { "type": "number", "description": "Build stage timeout in seconds", "default": 2400 },
73
+ "verify": { "type": "number", "description": "Verify stage timeout in seconds", "default": 300 },
74
+ "review": { "type": "number", "description": "Review stage timeout in seconds", "default": 600 },
75
+ "review-fix": { "type": "number", "description": "Review-fix stage timeout in seconds", "default": 1200 },
76
+ "ship": { "type": "number", "description": "Ship stage timeout in seconds", "default": 240 }
77
+ },
78
+ "additionalProperties": false
79
+ },
66
80
  "agent": {
67
81
  "type": "object",
68
82
  "description": "Agent execution configuration",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine-lite",
3
- "version": "0.1.89",
3
+ "version": "0.1.91",
4
4
  "description": "Autonomous SDLC pipeline: Kody orchestration + Claude Code + LiteLLM",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -42,6 +42,14 @@ Questions rules:
42
42
  Good questions: "Should the search be case-sensitive?", "Which users should have access?", "Should this work offline?"
43
43
  Bad questions: "What framework should I use?", "Where should I put the file?", "What's the project structure?"
44
44
 
45
+ If the task is already implemented (files exist, tests pass):
46
+ - Still output valid JSON — never output plain text
47
+ - Set task_type to "chore"
48
+ - Set risk_level to "low"
49
+ - Set title to "Verify existing implementation of <feature>"
50
+ - Set description to explain that the work already exists and what was verified
51
+ - Set scope to the existing file paths
52
+
45
53
  Guidelines:
46
54
  - scope must contain exact file paths (use Glob to discover them)
47
55
  - title must be actionable ("Add X", "Fix Y", "Refactor Z")
@@ -99,8 +99,9 @@ jobs:
99
99
  - name: Parse inputs
100
100
  if: steps.safety.outputs.valid == 'true'
101
101
  id: parse
102
+ env:
103
+ BODY: ${{ github.event.comment.body }}
102
104
  run: |
103
- BODY="${{ github.event.comment.body }}"
104
105
  # Extract: @kody [mode] [task-id] [--from stage]
105
106
  KODY_ARGS=$(echo "$BODY" | grep -oP '(?:@kody|/kody)\s+\K.*' || echo "")
106
107
  MODE=$(echo "$KODY_ARGS" | awk '{print $1}')