@kody-ade/kody-engine 0.1.4 → 0.1.6
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 +102 -22
- package/dist/bin/cli.mjs.map +1 -1
- package/package.json +1 -1
package/dist/bin/cli.mjs
CHANGED
|
@@ -7965,10 +7965,16 @@ async function runPipeline(ctx, pipeline, hooks, rebuildPipeline) {
|
|
|
7965
7965
|
}
|
|
7966
7966
|
if (!ctx.input.dryRun && !ctx.input.local) {
|
|
7967
7967
|
try {
|
|
7968
|
-
const currentBranch = execFileSync13(
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
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
|
+
);
|
|
7972
7978
|
if (isFeatureBranch) {
|
|
7973
7979
|
commitPipelineFiles({
|
|
7974
7980
|
taskDir: ctx.taskDir,
|
|
@@ -7981,7 +7987,10 @@ async function runPipeline(ctx, pipeline, hooks, rebuildPipeline) {
|
|
|
7981
7987
|
logger.info(" \u2713 Pushed fresh running status.json to branch");
|
|
7982
7988
|
}
|
|
7983
7989
|
} catch (earlyPushErr) {
|
|
7984
|
-
logger.warn(
|
|
7990
|
+
logger.warn(
|
|
7991
|
+
{ err: earlyPushErr },
|
|
7992
|
+
"Early status push failed (non-fatal)"
|
|
7993
|
+
);
|
|
7985
7994
|
}
|
|
7986
7995
|
}
|
|
7987
7996
|
} else {
|
|
@@ -8002,7 +8011,9 @@ async function runPipeline(ctx, pipeline, hooks, rebuildPipeline) {
|
|
|
8002
8011
|
}
|
|
8003
8012
|
}
|
|
8004
8013
|
if (state.state === "paused") {
|
|
8005
|
-
const anyPausedStage = Object.values(state.stages).some(
|
|
8014
|
+
const anyPausedStage = Object.values(state.stages).some(
|
|
8015
|
+
(s) => s.state === "paused"
|
|
8016
|
+
);
|
|
8006
8017
|
if (!anyPausedStage) {
|
|
8007
8018
|
state = {
|
|
8008
8019
|
...state,
|
|
@@ -8035,7 +8046,11 @@ async function runPipeline(ctx, pipeline, hooks, rebuildPipeline) {
|
|
|
8035
8046
|
const recoveredState = recoverStaleStages(currentState);
|
|
8036
8047
|
if (recoveredState !== currentState) {
|
|
8037
8048
|
logger.info("\u26A0\uFE0F Periodic recovery: reset stale running stages");
|
|
8038
|
-
logRecovery(
|
|
8049
|
+
logRecovery(
|
|
8050
|
+
"stale-stage-recovery",
|
|
8051
|
+
ctx.taskId,
|
|
8052
|
+
"Reset stale running stages"
|
|
8053
|
+
);
|
|
8039
8054
|
state = recoveredState;
|
|
8040
8055
|
writeState(ctx.taskId, state);
|
|
8041
8056
|
}
|
|
@@ -8047,7 +8062,10 @@ async function runPipeline(ctx, pipeline, hooks, rebuildPipeline) {
|
|
|
8047
8062
|
const newOrder = flattenPipelineOrder(pipeline.order);
|
|
8048
8063
|
for (const stageName of newOrder) {
|
|
8049
8064
|
if (!state.stages[stageName]) {
|
|
8050
|
-
state = updateStage(state, stageName, {
|
|
8065
|
+
state = updateStage(state, stageName, {
|
|
8066
|
+
state: "pending",
|
|
8067
|
+
retries: 0
|
|
8068
|
+
});
|
|
8051
8069
|
}
|
|
8052
8070
|
}
|
|
8053
8071
|
writeState(ctx.taskId, state);
|
|
@@ -8088,7 +8106,9 @@ async function runPipeline(ctx, pipeline, hooks, rebuildPipeline) {
|
|
|
8088
8106
|
const stageState = failedStage?.[1];
|
|
8089
8107
|
const stageOutcome = stageState?.state || "unknown";
|
|
8090
8108
|
const stageError = stageState?.error ? `: ${stageState.error}` : "";
|
|
8091
|
-
throw new Error(
|
|
8109
|
+
throw new Error(
|
|
8110
|
+
`Pipeline failed at stage: ${stageName} (${stageOutcome})${stageError}`
|
|
8111
|
+
);
|
|
8092
8112
|
}
|
|
8093
8113
|
return state;
|
|
8094
8114
|
}
|
|
@@ -8134,7 +8154,10 @@ async function executeSingleStep(ctx, pipeline, state, stageName) {
|
|
|
8134
8154
|
logger.info(` ${stageName} already completed, skipping`);
|
|
8135
8155
|
return state;
|
|
8136
8156
|
}
|
|
8137
|
-
state = updateStage(state, stageName, {
|
|
8157
|
+
state = updateStage(state, stageName, {
|
|
8158
|
+
state: "running",
|
|
8159
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8160
|
+
});
|
|
8138
8161
|
writeState(ctx.taskId, state);
|
|
8139
8162
|
logStageStart(stageName, ctx.taskId);
|
|
8140
8163
|
if (ctx.input.dryRun) {
|
|
@@ -8156,7 +8179,35 @@ async function executeSingleStep(ctx, pipeline, state, stageName) {
|
|
|
8156
8179
|
const handler = getHandler(def.name, def.type);
|
|
8157
8180
|
const result = await handler.execute(ctx, def);
|
|
8158
8181
|
ciGroupEnd();
|
|
8159
|
-
|
|
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 StageError(
|
|
8197
|
+
errorMessage,
|
|
8198
|
+
stageName,
|
|
8199
|
+
void 0,
|
|
8200
|
+
result.sessionId
|
|
8201
|
+
);
|
|
8202
|
+
}
|
|
8203
|
+
return await handleStageResult(
|
|
8204
|
+
ctx,
|
|
8205
|
+
pipeline,
|
|
8206
|
+
state,
|
|
8207
|
+
stageName,
|
|
8208
|
+
result,
|
|
8209
|
+
def
|
|
8210
|
+
);
|
|
8160
8211
|
} catch (error) {
|
|
8161
8212
|
ciGroupEnd();
|
|
8162
8213
|
if (error instanceof PipelinePausedError) {
|
|
@@ -8166,14 +8217,16 @@ async function executeSingleStep(ctx, pipeline, state, stageName) {
|
|
|
8166
8217
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
8167
8218
|
logger.error({ err: error }, ` \u274C ${stageName} failed:`);
|
|
8168
8219
|
logStageFail(stageName, ctx.taskId, errorMessage);
|
|
8169
|
-
const
|
|
8220
|
+
const stageSessionId = error instanceof StageError ? error.sessionId : void 0;
|
|
8221
|
+
const effectiveSessionId = stageSessionId || ctx.lastSessionId;
|
|
8222
|
+
const canObserve = ctx.serverUrl && effectiveSessionId && !ctx.input.dryRun;
|
|
8170
8223
|
if (canObserve && !def.advisory) {
|
|
8171
8224
|
try {
|
|
8172
8225
|
const observer = new PipelineObserver(
|
|
8173
8226
|
ctx.taskId,
|
|
8174
8227
|
ctx.taskDir,
|
|
8175
8228
|
ctx.serverUrl,
|
|
8176
|
-
|
|
8229
|
+
effectiveSessionId,
|
|
8177
8230
|
ctx.taskDir
|
|
8178
8231
|
// dataDir is taskDir/opencode-data derived in Observer
|
|
8179
8232
|
);
|
|
@@ -8214,7 +8267,10 @@ async function executeSingleStep(ctx, pipeline, state, stageName) {
|
|
|
8214
8267
|
return completeState(state, "failed");
|
|
8215
8268
|
}
|
|
8216
8269
|
} catch (observerError) {
|
|
8217
|
-
logger.error(
|
|
8270
|
+
logger.error(
|
|
8271
|
+
{ err: observerError },
|
|
8272
|
+
`[StateMachine] Observer error, falling back`
|
|
8273
|
+
);
|
|
8218
8274
|
state = updateStage(state, stageName, {
|
|
8219
8275
|
state: "failed",
|
|
8220
8276
|
error: errorMessage
|
|
@@ -8261,7 +8317,10 @@ async function executeParallelStep(ctx, pipeline, state, stageNames) {
|
|
|
8261
8317
|
stagesToRun.map(async (stageName) => {
|
|
8262
8318
|
const def = pipeline.stages.get(stageName);
|
|
8263
8319
|
if (!def) {
|
|
8264
|
-
throw new StageError(
|
|
8320
|
+
throw new StageError(
|
|
8321
|
+
`Stage '${stageName}' not found in pipeline definitions`,
|
|
8322
|
+
stageName
|
|
8323
|
+
);
|
|
8265
8324
|
}
|
|
8266
8325
|
if (def.shouldSkip) {
|
|
8267
8326
|
const skipResult = def.shouldSkip(ctx);
|
|
@@ -8360,7 +8419,10 @@ async function executeParallelStep(ctx, pipeline, state, stageNames) {
|
|
|
8360
8419
|
pausedStage = stageName;
|
|
8361
8420
|
continue;
|
|
8362
8421
|
}
|
|
8363
|
-
logger.error(
|
|
8422
|
+
logger.error(
|
|
8423
|
+
{ err: postError },
|
|
8424
|
+
` Post-action failed for parallel stage ${stageName}:`
|
|
8425
|
+
);
|
|
8364
8426
|
const postErrorMsg = postError instanceof Error ? postError.message : String(postError);
|
|
8365
8427
|
state = updateStage(state, stageName, {
|
|
8366
8428
|
state: "failed",
|
|
@@ -8386,7 +8448,10 @@ async function executeParallelStep(ctx, pipeline, state, stageNames) {
|
|
|
8386
8448
|
error: stageResult.reason || "timed out"
|
|
8387
8449
|
});
|
|
8388
8450
|
if (!isAdvisory) {
|
|
8389
|
-
criticalFailures.push({
|
|
8451
|
+
criticalFailures.push({
|
|
8452
|
+
name: stageName,
|
|
8453
|
+
reason: stageResult.reason || "timed out"
|
|
8454
|
+
});
|
|
8390
8455
|
}
|
|
8391
8456
|
} else if (stageResult.outcome === "failed") {
|
|
8392
8457
|
const isAdvisory = pipeline.stages.get(stageName)?.advisory === true;
|
|
@@ -8395,20 +8460,28 @@ async function executeParallelStep(ctx, pipeline, state, stageNames) {
|
|
|
8395
8460
|
state: "failed",
|
|
8396
8461
|
error: stageResult.reason || "failed"
|
|
8397
8462
|
});
|
|
8398
|
-
advisoryFailures.push({
|
|
8463
|
+
advisoryFailures.push({
|
|
8464
|
+
name: stageName,
|
|
8465
|
+
reason: stageResult.reason || "failed"
|
|
8466
|
+
});
|
|
8399
8467
|
} else {
|
|
8400
8468
|
state = updateStage(state, stageName, {
|
|
8401
8469
|
state: "failed",
|
|
8402
8470
|
error: stageResult.reason || "failed"
|
|
8403
8471
|
});
|
|
8404
|
-
criticalFailures.push({
|
|
8472
|
+
criticalFailures.push({
|
|
8473
|
+
name: stageName,
|
|
8474
|
+
reason: stageResult.reason || "failed"
|
|
8475
|
+
});
|
|
8405
8476
|
}
|
|
8406
8477
|
}
|
|
8407
8478
|
}
|
|
8408
8479
|
if (criticalFailures.length > 0) {
|
|
8409
8480
|
const errors = criticalFailures.map((f) => f.reason).join("; ");
|
|
8410
8481
|
const names = criticalFailures.map((f) => f.name);
|
|
8411
|
-
logger.error(
|
|
8482
|
+
logger.error(
|
|
8483
|
+
` \u274C Parallel stages [${names.join(", ")}] failed: ${errors}`
|
|
8484
|
+
);
|
|
8412
8485
|
if (ctx.input.issueNumber) {
|
|
8413
8486
|
setLifecycleLabel(ctx.input.issueNumber, "kody:failed");
|
|
8414
8487
|
}
|
|
@@ -8434,7 +8507,12 @@ async function handleStageResult(ctx, pipeline, state, stageName, result, def) {
|
|
|
8434
8507
|
cost: result.cost,
|
|
8435
8508
|
sessionId: result.sessionId
|
|
8436
8509
|
});
|
|
8437
|
-
logStageComplete(
|
|
8510
|
+
logStageComplete(
|
|
8511
|
+
stageName,
|
|
8512
|
+
ctx.taskId,
|
|
8513
|
+
"completed",
|
|
8514
|
+
elapsed ? elapsed * 1e3 : void 0
|
|
8515
|
+
);
|
|
8438
8516
|
if (result.sessionId) {
|
|
8439
8517
|
ctx.lastSessionId = result.sessionId;
|
|
8440
8518
|
}
|
|
@@ -8526,11 +8604,13 @@ var init_state_machine = __esm({
|
|
|
8526
8604
|
StageError = class extends Error {
|
|
8527
8605
|
stageName;
|
|
8528
8606
|
cause;
|
|
8529
|
-
|
|
8607
|
+
sessionId;
|
|
8608
|
+
constructor(message, stageName, cause, sessionId) {
|
|
8530
8609
|
super(message);
|
|
8531
8610
|
this.name = "StageError";
|
|
8532
8611
|
this.stageName = stageName;
|
|
8533
8612
|
this.cause = cause;
|
|
8613
|
+
this.sessionId = sessionId;
|
|
8534
8614
|
}
|
|
8535
8615
|
};
|
|
8536
8616
|
}
|