@kody-ade/kody-engine 0.1.3 → 0.1.5

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.mjs CHANGED
@@ -214,14 +214,14 @@ var init_registry = __esm({
214
214
  },
215
215
  test: {
216
216
  outputFile: "test.md",
217
- timeout: ms("20m"),
217
+ timeout: ms("40m"),
218
218
  complexityThreshold: 0,
219
219
  contextFiles: ["spec.md", "clarified.md", "plan.md", "task.json"],
220
220
  type: "agent"
221
221
  },
222
222
  build: {
223
223
  outputFile: "build.md",
224
- timeout: ms("45m"),
224
+ timeout: ms("60m"),
225
225
  complexityThreshold: 0,
226
226
  contextFiles: [
227
227
  "spec.md",
@@ -248,7 +248,14 @@ var init_registry = __esm({
248
248
  outputFile: "review.md",
249
249
  timeout: ms("15m"),
250
250
  complexityThreshold: 30,
251
- contextFiles: ["review.md", "build.md", "plan.md", "context.md", "spec.md", "clarified.md"],
251
+ contextFiles: [
252
+ "review.md",
253
+ "build.md",
254
+ "plan.md",
255
+ "context.md",
256
+ "spec.md",
257
+ "clarified.md"
258
+ ],
252
259
  type: "agent"
253
260
  },
254
261
  fix: {
@@ -317,7 +324,12 @@ var init_registry = __esm({
317
324
  "pr"
318
325
  ];
319
326
  SPEC_ORDER_TURBO = ["taskify"];
320
- IMPL_ORDER_TURBO = ["build", "commit", "verify", "pr"];
327
+ IMPL_ORDER_TURBO = [
328
+ "build",
329
+ "commit",
330
+ "verify",
331
+ "pr"
332
+ ];
321
333
  FIX_FULL_ORDER = [
322
334
  "taskify",
323
335
  "architect",
@@ -7953,10 +7965,16 @@ async function runPipeline(ctx, pipeline, hooks, rebuildPipeline) {
7953
7965
  }
7954
7966
  if (!ctx.input.dryRun && !ctx.input.local) {
7955
7967
  try {
7956
- const currentBranch = execFileSync13("git", ["branch", "--show-current"], {
7957
- encoding: "utf-8"
7958
- }).trim();
7959
- const isFeatureBranch = !["dev", "main", "master"].includes(currentBranch);
7968
+ const currentBranch = execFileSync13(
7969
+ "git",
7970
+ ["branch", "--show-current"],
7971
+ {
7972
+ encoding: "utf-8"
7973
+ }
7974
+ ).trim();
7975
+ const isFeatureBranch = !["dev", "main", "master"].includes(
7976
+ currentBranch
7977
+ );
7960
7978
  if (isFeatureBranch) {
7961
7979
  commitPipelineFiles({
7962
7980
  taskDir: ctx.taskDir,
@@ -7969,7 +7987,10 @@ async function runPipeline(ctx, pipeline, hooks, rebuildPipeline) {
7969
7987
  logger.info(" \u2713 Pushed fresh running status.json to branch");
7970
7988
  }
7971
7989
  } catch (earlyPushErr) {
7972
- logger.warn({ err: earlyPushErr }, "Early status push failed (non-fatal)");
7990
+ logger.warn(
7991
+ { err: earlyPushErr },
7992
+ "Early status push failed (non-fatal)"
7993
+ );
7973
7994
  }
7974
7995
  }
7975
7996
  } else {
@@ -7990,7 +8011,9 @@ async function runPipeline(ctx, pipeline, hooks, rebuildPipeline) {
7990
8011
  }
7991
8012
  }
7992
8013
  if (state.state === "paused") {
7993
- const anyPausedStage = Object.values(state.stages).some((s) => s.state === "paused");
8014
+ const anyPausedStage = Object.values(state.stages).some(
8015
+ (s) => s.state === "paused"
8016
+ );
7994
8017
  if (!anyPausedStage) {
7995
8018
  state = {
7996
8019
  ...state,
@@ -8023,7 +8046,11 @@ async function runPipeline(ctx, pipeline, hooks, rebuildPipeline) {
8023
8046
  const recoveredState = recoverStaleStages(currentState);
8024
8047
  if (recoveredState !== currentState) {
8025
8048
  logger.info("\u26A0\uFE0F Periodic recovery: reset stale running stages");
8026
- logRecovery("stale-stage-recovery", ctx.taskId, "Reset stale running stages");
8049
+ logRecovery(
8050
+ "stale-stage-recovery",
8051
+ ctx.taskId,
8052
+ "Reset stale running stages"
8053
+ );
8027
8054
  state = recoveredState;
8028
8055
  writeState(ctx.taskId, state);
8029
8056
  }
@@ -8035,7 +8062,10 @@ async function runPipeline(ctx, pipeline, hooks, rebuildPipeline) {
8035
8062
  const newOrder = flattenPipelineOrder(pipeline.order);
8036
8063
  for (const stageName of newOrder) {
8037
8064
  if (!state.stages[stageName]) {
8038
- state = updateStage(state, stageName, { state: "pending", retries: 0 });
8065
+ state = updateStage(state, stageName, {
8066
+ state: "pending",
8067
+ retries: 0
8068
+ });
8039
8069
  }
8040
8070
  }
8041
8071
  writeState(ctx.taskId, state);
@@ -8076,7 +8106,9 @@ async function runPipeline(ctx, pipeline, hooks, rebuildPipeline) {
8076
8106
  const stageState = failedStage?.[1];
8077
8107
  const stageOutcome = stageState?.state || "unknown";
8078
8108
  const stageError = stageState?.error ? `: ${stageState.error}` : "";
8079
- throw new Error(`Pipeline failed at stage: ${stageName} (${stageOutcome})${stageError}`);
8109
+ throw new Error(
8110
+ `Pipeline failed at stage: ${stageName} (${stageOutcome})${stageError}`
8111
+ );
8080
8112
  }
8081
8113
  return state;
8082
8114
  }
@@ -8122,7 +8154,10 @@ async function executeSingleStep(ctx, pipeline, state, stageName) {
8122
8154
  logger.info(` ${stageName} already completed, skipping`);
8123
8155
  return state;
8124
8156
  }
8125
- state = updateStage(state, stageName, { state: "running", startedAt: (/* @__PURE__ */ new Date()).toISOString() });
8157
+ state = updateStage(state, stageName, {
8158
+ state: "running",
8159
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
8160
+ });
8126
8161
  writeState(ctx.taskId, state);
8127
8162
  logStageStart(stageName, ctx.taskId);
8128
8163
  if (ctx.input.dryRun) {
@@ -8144,7 +8179,30 @@ async function executeSingleStep(ctx, pipeline, state, stageName) {
8144
8179
  const handler = getHandler(def.name, def.type);
8145
8180
  const result = await handler.execute(ctx, def);
8146
8181
  ciGroupEnd();
8147
- return await handleStageResult(ctx, pipeline, state, stageName, result, def);
8182
+ if (result.outcome === "failed" || result.outcome === "timed_out") {
8183
+ if (def.postActions && !ctx.input.dryRun) {
8184
+ try {
8185
+ for (const action of def.postActions) {
8186
+ await executePostAction(ctx, action, state);
8187
+ }
8188
+ } catch (postError) {
8189
+ logger.error(
8190
+ { err: postError },
8191
+ ` Post-action failed for ${stageName}:`
8192
+ );
8193
+ }
8194
+ }
8195
+ const errorMessage = `${stageName} ${result.outcome === "timed_out" ? "timed out" : "failed"}: ${result.reason || "unknown"}`;
8196
+ throw new Error(errorMessage);
8197
+ }
8198
+ return await handleStageResult(
8199
+ ctx,
8200
+ pipeline,
8201
+ state,
8202
+ stageName,
8203
+ result,
8204
+ def
8205
+ );
8148
8206
  } catch (error) {
8149
8207
  ciGroupEnd();
8150
8208
  if (error instanceof PipelinePausedError) {
@@ -8202,7 +8260,10 @@ async function executeSingleStep(ctx, pipeline, state, stageName) {
8202
8260
  return completeState(state, "failed");
8203
8261
  }
8204
8262
  } catch (observerError) {
8205
- logger.error({ err: observerError }, `[StateMachine] Observer error, falling back`);
8263
+ logger.error(
8264
+ { err: observerError },
8265
+ `[StateMachine] Observer error, falling back`
8266
+ );
8206
8267
  state = updateStage(state, stageName, {
8207
8268
  state: "failed",
8208
8269
  error: errorMessage
@@ -8249,7 +8310,10 @@ async function executeParallelStep(ctx, pipeline, state, stageNames) {
8249
8310
  stagesToRun.map(async (stageName) => {
8250
8311
  const def = pipeline.stages.get(stageName);
8251
8312
  if (!def) {
8252
- throw new StageError(`Stage '${stageName}' not found in pipeline definitions`, stageName);
8313
+ throw new StageError(
8314
+ `Stage '${stageName}' not found in pipeline definitions`,
8315
+ stageName
8316
+ );
8253
8317
  }
8254
8318
  if (def.shouldSkip) {
8255
8319
  const skipResult = def.shouldSkip(ctx);
@@ -8348,7 +8412,10 @@ async function executeParallelStep(ctx, pipeline, state, stageNames) {
8348
8412
  pausedStage = stageName;
8349
8413
  continue;
8350
8414
  }
8351
- logger.error({ err: postError }, ` Post-action failed for parallel stage ${stageName}:`);
8415
+ logger.error(
8416
+ { err: postError },
8417
+ ` Post-action failed for parallel stage ${stageName}:`
8418
+ );
8352
8419
  const postErrorMsg = postError instanceof Error ? postError.message : String(postError);
8353
8420
  state = updateStage(state, stageName, {
8354
8421
  state: "failed",
@@ -8374,7 +8441,10 @@ async function executeParallelStep(ctx, pipeline, state, stageNames) {
8374
8441
  error: stageResult.reason || "timed out"
8375
8442
  });
8376
8443
  if (!isAdvisory) {
8377
- criticalFailures.push({ name: stageName, reason: stageResult.reason || "timed out" });
8444
+ criticalFailures.push({
8445
+ name: stageName,
8446
+ reason: stageResult.reason || "timed out"
8447
+ });
8378
8448
  }
8379
8449
  } else if (stageResult.outcome === "failed") {
8380
8450
  const isAdvisory = pipeline.stages.get(stageName)?.advisory === true;
@@ -8383,20 +8453,28 @@ async function executeParallelStep(ctx, pipeline, state, stageNames) {
8383
8453
  state: "failed",
8384
8454
  error: stageResult.reason || "failed"
8385
8455
  });
8386
- advisoryFailures.push({ name: stageName, reason: stageResult.reason || "failed" });
8456
+ advisoryFailures.push({
8457
+ name: stageName,
8458
+ reason: stageResult.reason || "failed"
8459
+ });
8387
8460
  } else {
8388
8461
  state = updateStage(state, stageName, {
8389
8462
  state: "failed",
8390
8463
  error: stageResult.reason || "failed"
8391
8464
  });
8392
- criticalFailures.push({ name: stageName, reason: stageResult.reason || "failed" });
8465
+ criticalFailures.push({
8466
+ name: stageName,
8467
+ reason: stageResult.reason || "failed"
8468
+ });
8393
8469
  }
8394
8470
  }
8395
8471
  }
8396
8472
  if (criticalFailures.length > 0) {
8397
8473
  const errors = criticalFailures.map((f) => f.reason).join("; ");
8398
8474
  const names = criticalFailures.map((f) => f.name);
8399
- logger.error(` \u274C Parallel stages [${names.join(", ")}] failed: ${errors}`);
8475
+ logger.error(
8476
+ ` \u274C Parallel stages [${names.join(", ")}] failed: ${errors}`
8477
+ );
8400
8478
  if (ctx.input.issueNumber) {
8401
8479
  setLifecycleLabel(ctx.input.issueNumber, "kody:failed");
8402
8480
  }
@@ -8422,7 +8500,12 @@ async function handleStageResult(ctx, pipeline, state, stageName, result, def) {
8422
8500
  cost: result.cost,
8423
8501
  sessionId: result.sessionId
8424
8502
  });
8425
- logStageComplete(stageName, ctx.taskId, "completed", elapsed ? elapsed * 1e3 : void 0);
8503
+ logStageComplete(
8504
+ stageName,
8505
+ ctx.taskId,
8506
+ "completed",
8507
+ elapsed ? elapsed * 1e3 : void 0
8508
+ );
8426
8509
  if (result.sessionId) {
8427
8510
  ctx.lastSessionId = result.sessionId;
8428
8511
  }