@kody-ade/kody-engine 0.2.27 → 0.2.29
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/kody2.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@kody-ade/kody-engine",
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.29",
|
|
7
7
|
description: "kody2 \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
8
8
|
license: "MIT",
|
|
9
9
|
type: "module",
|
|
@@ -1135,11 +1135,19 @@ function parseAgentResult(finalText) {
|
|
|
1135
1135
|
commitMessage: "",
|
|
1136
1136
|
prSummary: "",
|
|
1137
1137
|
feedbackActions: "",
|
|
1138
|
+
planDeviations: "",
|
|
1138
1139
|
failureReason: "agent produced no final message"
|
|
1139
1140
|
};
|
|
1140
1141
|
const failedMatch = text.match(/(?:^|\n)\s*FAILED\s*:\s*(.+?)\s*$/s);
|
|
1141
1142
|
if (failedMatch) {
|
|
1142
|
-
return {
|
|
1143
|
+
return {
|
|
1144
|
+
done: false,
|
|
1145
|
+
commitMessage: "",
|
|
1146
|
+
prSummary: "",
|
|
1147
|
+
feedbackActions: "",
|
|
1148
|
+
planDeviations: "",
|
|
1149
|
+
failureReason: failedMatch[1].trim()
|
|
1150
|
+
};
|
|
1143
1151
|
}
|
|
1144
1152
|
if (!/(^|\n)\s*DONE\b/i.test(text)) {
|
|
1145
1153
|
return {
|
|
@@ -1147,6 +1155,7 @@ function parseAgentResult(finalText) {
|
|
|
1147
1155
|
commitMessage: "",
|
|
1148
1156
|
prSummary: "",
|
|
1149
1157
|
feedbackActions: "",
|
|
1158
|
+
planDeviations: "",
|
|
1150
1159
|
failureReason: "no DONE or FAILED marker in agent output"
|
|
1151
1160
|
};
|
|
1152
1161
|
}
|
|
@@ -1155,15 +1164,24 @@ function parseAgentResult(finalText) {
|
|
|
1155
1164
|
const feedbackActions = extractBlock(
|
|
1156
1165
|
text,
|
|
1157
1166
|
/(?:^|\n)[ \t]*FEEDBACK_ACTIONS\s*:[ \t]*\n/i,
|
|
1158
|
-
/(?:^|\n)[ \t]*(?:COMMIT_MSG|PR_SUMMARY)\s*:/i
|
|
1167
|
+
/(?:^|\n)[ \t]*(?:PLAN_DEVIATIONS|COMMIT_MSG|PR_SUMMARY)\s*:/i
|
|
1168
|
+
);
|
|
1169
|
+
let planDeviations = extractBlock(
|
|
1170
|
+
text,
|
|
1171
|
+
/(?:^|\n)[ \t]*PLAN_DEVIATIONS\s*:[ \t]*\n/i,
|
|
1172
|
+
/(?:^|\n)[ \t]*(?:COMMIT_MSG|PR_SUMMARY|FEEDBACK_ACTIONS)\s*:/i
|
|
1159
1173
|
);
|
|
1174
|
+
if (!planDeviations) {
|
|
1175
|
+
const inline = text.match(/(?:^|\n)[ \t]*PLAN_DEVIATIONS\s*:[ \t]*(.+?)[ \t]*(?:\n|$)/i);
|
|
1176
|
+
if (inline) planDeviations = inline[1].trim();
|
|
1177
|
+
}
|
|
1160
1178
|
const summaryStart = text.search(/(^|\n)[ \t]*PR_SUMMARY\s*:[ \t]*\n/i);
|
|
1161
1179
|
let prSummary = "";
|
|
1162
1180
|
if (summaryStart !== -1) {
|
|
1163
1181
|
const afterMarker = text.slice(summaryStart).replace(/^[\s\S]*?PR_SUMMARY\s*:[ \t]*\n/i, "");
|
|
1164
1182
|
prSummary = afterMarker.replace(/\n\s*```\s*$/g, "").replace(/```\s*$/g, "").trim();
|
|
1165
1183
|
}
|
|
1166
|
-
return { done: true, commitMessage, prSummary, feedbackActions, failureReason: "" };
|
|
1184
|
+
return { done: true, commitMessage, prSummary, feedbackActions, planDeviations, failureReason: "" };
|
|
1167
1185
|
}
|
|
1168
1186
|
function extractBlock(text, startMarker, endMarker) {
|
|
1169
1187
|
const startIdx = text.search(startMarker);
|
|
@@ -2517,11 +2535,13 @@ function parseStateComment(body) {
|
|
|
2517
2535
|
const beginIdx = body.indexOf(STATE_BEGIN);
|
|
2518
2536
|
const endIdx = body.indexOf(STATE_END, beginIdx + 1);
|
|
2519
2537
|
if (beginIdx < 0 || endIdx < 0) return emptyState();
|
|
2520
|
-
const between = body.slice(beginIdx + STATE_BEGIN.length, endIdx);
|
|
2521
|
-
const
|
|
2522
|
-
|
|
2538
|
+
const between = body.slice(beginIdx + STATE_BEGIN.length, endIdx).trim();
|
|
2539
|
+
const OPEN = "```json";
|
|
2540
|
+
const CLOSE = "```";
|
|
2541
|
+
if (!between.startsWith(OPEN) || !between.endsWith(CLOSE)) return emptyState();
|
|
2542
|
+
const jsonStr = between.slice(OPEN.length, between.length - CLOSE.length).trim();
|
|
2523
2543
|
try {
|
|
2524
|
-
const parsed = JSON.parse(
|
|
2544
|
+
const parsed = JSON.parse(jsonStr);
|
|
2525
2545
|
if (parsed?.schemaVersion !== 1) return emptyState();
|
|
2526
2546
|
return {
|
|
2527
2547
|
schemaVersion: 1,
|
|
@@ -2682,6 +2702,7 @@ var parseAgentResult2 = async (ctx, profile, agentResult) => {
|
|
|
2682
2702
|
ctx.data.commitMessage = parsed.commitMessage;
|
|
2683
2703
|
ctx.data.prSummary = parsed.prSummary;
|
|
2684
2704
|
ctx.data.feedbackActions = parsed.feedbackActions;
|
|
2705
|
+
ctx.data.planDeviations = parsed.planDeviations;
|
|
2685
2706
|
ctx.data.agentFailureReason = parsed.failureReason;
|
|
2686
2707
|
ctx.data.agentOutcome = agentResult.outcome;
|
|
2687
2708
|
ctx.data.agentError = agentResult.error;
|
|
@@ -2754,7 +2775,8 @@ var postIssueComment2 = async (ctx) => {
|
|
|
2754
2775
|
}
|
|
2755
2776
|
const failureReason = computeFailureReason2(ctx);
|
|
2756
2777
|
const isFailure = failureReason.length > 0;
|
|
2757
|
-
const
|
|
2778
|
+
const justPushedToExistingPr = prAction === "updated" && commitResult?.committed === true;
|
|
2779
|
+
const successMsg = justPushedToExistingPr ? `\u2705 kody2 pushed to ${prUrl}` : prAction === "updated" ? `\u2139\uFE0F kody2 made no changes \u2014 PR: ${prUrl}` : `\u2705 kody2 PR opened: ${prUrl}`;
|
|
2758
2780
|
const failurePrSuffix = prUrl ? prAction === "updated" ? ` \u2014 PR: ${prUrl}` : ` \u2014 draft PR: ${prUrl}` : "";
|
|
2759
2781
|
const msg = isFailure ? `\u26A0\uFE0F kody2 FAILED: ${truncate2(failureReason, 1500)}${failurePrSuffix}` : successMsg;
|
|
2760
2782
|
postWith(targetType, targetNumber, msg, ctx.cwd);
|
|
@@ -2813,11 +2835,19 @@ function detectVerdict(body) {
|
|
|
2813
2835
|
if (!m) return "UNKNOWN";
|
|
2814
2836
|
return m[1].toUpperCase();
|
|
2815
2837
|
}
|
|
2838
|
+
function reviewAction(verdict, payload) {
|
|
2839
|
+
const type = verdict === "PASS" ? "REVIEW_PASS" : verdict === "CONCERNS" ? "REVIEW_CONCERNS" : verdict === "FAIL" ? "REVIEW_FAIL" : "REVIEW_COMPLETED";
|
|
2840
|
+
return { type, payload: { verdict, ...payload }, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
2841
|
+
}
|
|
2842
|
+
function failedAction(reason) {
|
|
2843
|
+
return { type: "REVIEW_FAILED", payload: { reason }, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
2844
|
+
}
|
|
2816
2845
|
var postReviewResult = async (ctx, _profile, agentResult) => {
|
|
2817
2846
|
const prNumber = ctx.data.commentTargetNumber;
|
|
2818
2847
|
if (!prNumber) {
|
|
2819
2848
|
ctx.output.exitCode = 99;
|
|
2820
2849
|
ctx.output.reason = "review postflight: no PR number in context";
|
|
2850
|
+
ctx.data.action = failedAction(ctx.output.reason);
|
|
2821
2851
|
return;
|
|
2822
2852
|
}
|
|
2823
2853
|
if (!agentResult || agentResult.outcome !== "completed") {
|
|
@@ -2828,6 +2858,7 @@ var postReviewResult = async (ctx, _profile, agentResult) => {
|
|
|
2828
2858
|
}
|
|
2829
2859
|
ctx.output.exitCode = 1;
|
|
2830
2860
|
ctx.output.reason = reason;
|
|
2861
|
+
ctx.data.action = failedAction(reason);
|
|
2831
2862
|
return;
|
|
2832
2863
|
}
|
|
2833
2864
|
const reviewBody = agentResult.finalText.trim();
|
|
@@ -2838,6 +2869,7 @@ var postReviewResult = async (ctx, _profile, agentResult) => {
|
|
|
2838
2869
|
}
|
|
2839
2870
|
ctx.output.exitCode = 1;
|
|
2840
2871
|
ctx.output.reason = "empty review body";
|
|
2872
|
+
ctx.data.action = failedAction("empty review body");
|
|
2841
2873
|
return;
|
|
2842
2874
|
}
|
|
2843
2875
|
try {
|
|
@@ -2846,10 +2878,13 @@ var postReviewResult = async (ctx, _profile, agentResult) => {
|
|
|
2846
2878
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2847
2879
|
ctx.output.exitCode = 4;
|
|
2848
2880
|
ctx.output.reason = `failed to post review comment: ${msg}`;
|
|
2881
|
+
ctx.data.action = failedAction(ctx.output.reason);
|
|
2849
2882
|
return;
|
|
2850
2883
|
}
|
|
2851
2884
|
const verdict = detectVerdict(reviewBody);
|
|
2852
2885
|
ctx.data.reviewVerdict = verdict;
|
|
2886
|
+
ctx.data.reviewBody = reviewBody;
|
|
2887
|
+
ctx.data.action = reviewAction(verdict, { bodyPreview: truncate2(reviewBody, 500) });
|
|
2853
2888
|
ctx.output.exitCode = verdict === "FAIL" ? 1 : 0;
|
|
2854
2889
|
process.stdout.write(
|
|
2855
2890
|
`
|
|
@@ -3156,33 +3191,108 @@ ${truncate2(r.stderr, 2e3)}
|
|
|
3156
3191
|
|
|
3157
3192
|
// src/scripts/requireFeedbackActions.ts
|
|
3158
3193
|
var MIN_ITEMS = 1;
|
|
3194
|
+
var ACTIONABLE_HEADINGS = /^#{1,6}\s+(Concerns|Suggestions|Bugs)\b/i;
|
|
3195
|
+
var NEXT_HEADING = /^#{1,6}\s+/;
|
|
3159
3196
|
var requireFeedbackActions = async (ctx, profile) => {
|
|
3160
3197
|
if (!ctx.data.agentDone) return;
|
|
3161
3198
|
const actions = String(ctx.data.feedbackActions ?? "").trim();
|
|
3162
3199
|
const items = countActionItems(actions);
|
|
3163
|
-
if (items
|
|
3164
|
-
|
|
3200
|
+
if (items < MIN_ITEMS) {
|
|
3201
|
+
fail(
|
|
3202
|
+
ctx,
|
|
3203
|
+
profile,
|
|
3204
|
+
actions.length === 0 ? "agent omitted required FEEDBACK_ACTIONS block \u2014 cannot verify that review feedback was addressed" : "agent FEEDBACK_ACTIONS block listed no items \u2014 cannot verify that review feedback was addressed"
|
|
3205
|
+
);
|
|
3206
|
+
return;
|
|
3207
|
+
}
|
|
3208
|
+
const reviewBody = String(ctx.data.feedback ?? "");
|
|
3209
|
+
const expectedItems = countActionableReviewBullets(reviewBody);
|
|
3210
|
+
ctx.data.feedbackReviewItemCount = expectedItems;
|
|
3211
|
+
ctx.data.feedbackAgentItemCount = items;
|
|
3212
|
+
if (expectedItems > 0 && items < expectedItems) {
|
|
3213
|
+
fail(
|
|
3214
|
+
ctx,
|
|
3215
|
+
profile,
|
|
3216
|
+
`agent FEEDBACK_ACTIONS listed ${items} item(s) but the review has ${expectedItems} actionable bullet(s) under ### Concerns / ### Suggestions / ### Bugs \u2014 every review item must be accounted for`
|
|
3217
|
+
);
|
|
3218
|
+
return;
|
|
3219
|
+
}
|
|
3220
|
+
};
|
|
3221
|
+
function fail(ctx, profile, reason) {
|
|
3165
3222
|
ctx.data.agentDone = false;
|
|
3166
3223
|
ctx.data.agentFailureReason = reason;
|
|
3167
3224
|
const modeSeg = profile.name.replace(/-/g, "_").toUpperCase();
|
|
3168
|
-
const
|
|
3225
|
+
const failedAction2 = {
|
|
3169
3226
|
type: `${modeSeg}_FAILED`,
|
|
3170
3227
|
payload: { reason },
|
|
3171
3228
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3172
3229
|
};
|
|
3173
|
-
ctx.data.action =
|
|
3174
|
-
}
|
|
3230
|
+
ctx.data.action = failedAction2;
|
|
3231
|
+
}
|
|
3175
3232
|
function countActionItems(block) {
|
|
3176
3233
|
if (!block.trim()) return 0;
|
|
3177
|
-
const lines = block.split("\n");
|
|
3178
3234
|
let count = 0;
|
|
3235
|
+
for (const raw of block.split("\n")) {
|
|
3236
|
+
if (/^\s*[-*]\s+/.test(raw)) count++;
|
|
3237
|
+
}
|
|
3238
|
+
return count;
|
|
3239
|
+
}
|
|
3240
|
+
function countActionableReviewBullets(reviewBody) {
|
|
3241
|
+
if (!reviewBody.trim()) return 0;
|
|
3242
|
+
const lines = reviewBody.split("\n");
|
|
3243
|
+
let count = 0;
|
|
3244
|
+
let insideActionable = false;
|
|
3179
3245
|
for (const raw of lines) {
|
|
3180
|
-
|
|
3181
|
-
|
|
3246
|
+
if (ACTIONABLE_HEADINGS.test(raw)) {
|
|
3247
|
+
insideActionable = true;
|
|
3248
|
+
continue;
|
|
3249
|
+
}
|
|
3250
|
+
if (insideActionable && NEXT_HEADING.test(raw)) {
|
|
3251
|
+
insideActionable = false;
|
|
3252
|
+
continue;
|
|
3253
|
+
}
|
|
3254
|
+
if (!insideActionable) continue;
|
|
3255
|
+
if (/^[-*]\s+\S/.test(raw)) count++;
|
|
3182
3256
|
}
|
|
3183
3257
|
return count;
|
|
3184
3258
|
}
|
|
3185
3259
|
|
|
3260
|
+
// src/scripts/requirePlanDeviations.ts
|
|
3261
|
+
var requirePlanDeviations = async (ctx, profile) => {
|
|
3262
|
+
if (!ctx.data.agentDone) return;
|
|
3263
|
+
const artifacts = ctx.data.artifacts ?? {};
|
|
3264
|
+
const planContent = (artifacts.plan ?? "").trim();
|
|
3265
|
+
if (!planContent) return;
|
|
3266
|
+
const raw = String(ctx.data.planDeviations ?? "").trim();
|
|
3267
|
+
if (raw.length === 0) {
|
|
3268
|
+
fail2(ctx, profile, "agent omitted required PLAN_DEVIATIONS block \u2014 cannot verify whether the plan was followed");
|
|
3269
|
+
return;
|
|
3270
|
+
}
|
|
3271
|
+
if (isNoneSentinel(raw)) return;
|
|
3272
|
+
const bullets = raw.split("\n").filter((l) => /^\s*[-*]\s+/.test(l));
|
|
3273
|
+
if (bullets.length === 0) {
|
|
3274
|
+
fail2(ctx, profile, "agent PLAN_DEVIATIONS block is not 'none' and lists no bullet items");
|
|
3275
|
+
return;
|
|
3276
|
+
}
|
|
3277
|
+
ctx.data.planDeviationCount = bullets.length;
|
|
3278
|
+
};
|
|
3279
|
+
function isNoneSentinel(block) {
|
|
3280
|
+
const stripped = block.split("\n").map((l) => l.replace(/^\s*[-*]\s*/, "").trim().toLowerCase()).filter((l) => l.length > 0);
|
|
3281
|
+
if (stripped.length !== 1) return false;
|
|
3282
|
+
return stripped[0] === "none";
|
|
3283
|
+
}
|
|
3284
|
+
function fail2(ctx, profile, reason) {
|
|
3285
|
+
ctx.data.agentDone = false;
|
|
3286
|
+
ctx.data.agentFailureReason = reason;
|
|
3287
|
+
const modeSeg = profile.name.replace(/-/g, "_").toUpperCase();
|
|
3288
|
+
const failedAction2 = {
|
|
3289
|
+
type: `${modeSeg}_FAILED`,
|
|
3290
|
+
payload: { reason },
|
|
3291
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3292
|
+
};
|
|
3293
|
+
ctx.data.action = failedAction2;
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3186
3296
|
// src/scripts/resolveArtifacts.ts
|
|
3187
3297
|
var resolveArtifacts = async (ctx, profile) => {
|
|
3188
3298
|
if (profile.inputArtifacts.length === 0) return;
|
|
@@ -3551,6 +3661,59 @@ var verify = async (ctx) => {
|
|
|
3551
3661
|
}
|
|
3552
3662
|
};
|
|
3553
3663
|
|
|
3664
|
+
// src/scripts/verifyFixAlignment.ts
|
|
3665
|
+
function summarizeFeedbackActions(block) {
|
|
3666
|
+
const summary = { totalItems: 0, fixedItems: 0, declinedItems: 0, unparsedLines: 0 };
|
|
3667
|
+
if (!block.trim()) return summary;
|
|
3668
|
+
for (const raw of block.split("\n")) {
|
|
3669
|
+
if (!/^\s*[-*]\s+/.test(raw)) continue;
|
|
3670
|
+
const line = raw.replace(/^\s*[-*]\s*/, "").trim();
|
|
3671
|
+
summary.totalItems++;
|
|
3672
|
+
if (/\bfixed\s*:/i.test(line)) summary.fixedItems++;
|
|
3673
|
+
else if (/\bdeclined\s*:/i.test(line)) summary.declinedItems++;
|
|
3674
|
+
else summary.unparsedLines++;
|
|
3675
|
+
}
|
|
3676
|
+
return summary;
|
|
3677
|
+
}
|
|
3678
|
+
function makeAction2(type, payload) {
|
|
3679
|
+
return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
3680
|
+
}
|
|
3681
|
+
var verifyFixAlignment = async (ctx, profile) => {
|
|
3682
|
+
if (profile.name !== "fix") return;
|
|
3683
|
+
if (ctx.skipAgent) return;
|
|
3684
|
+
if (!ctx.data.agentDone) return;
|
|
3685
|
+
const feedbackActions = ctx.data.feedbackActions ?? "";
|
|
3686
|
+
const summary = summarizeFeedbackActions(feedbackActions);
|
|
3687
|
+
ctx.data.feedbackActionsSummary = summary;
|
|
3688
|
+
const committed = Boolean(ctx.data.commitResult?.committed);
|
|
3689
|
+
if (summary.totalItems === 0) {
|
|
3690
|
+
ctx.output.exitCode = 1;
|
|
3691
|
+
ctx.output.reason = "fix produced no FEEDBACK_ACTIONS items";
|
|
3692
|
+
ctx.data.agentDone = false;
|
|
3693
|
+
ctx.data.action = makeAction2("FIX_FAILED", {
|
|
3694
|
+
reason: ctx.output.reason,
|
|
3695
|
+
feedbackActionsSummary: summary
|
|
3696
|
+
});
|
|
3697
|
+
return;
|
|
3698
|
+
}
|
|
3699
|
+
if (summary.fixedItems > 0 && !committed) {
|
|
3700
|
+
ctx.output.exitCode = 1;
|
|
3701
|
+
ctx.output.reason = `fix claimed ${summary.fixedItems} fixed item(s) but produced no commit`;
|
|
3702
|
+
ctx.data.agentDone = false;
|
|
3703
|
+
ctx.data.action = makeAction2("FIX_FAILED", {
|
|
3704
|
+
reason: ctx.output.reason,
|
|
3705
|
+
feedbackActionsSummary: summary
|
|
3706
|
+
});
|
|
3707
|
+
return;
|
|
3708
|
+
}
|
|
3709
|
+
if (summary.fixedItems === 0 && summary.declinedItems > 0 && !committed) {
|
|
3710
|
+
ctx.data.action = makeAction2("FIX_DECLINED", {
|
|
3711
|
+
feedbackActionsSummary: summary,
|
|
3712
|
+
note: "agent declined all feedback items; no commit made"
|
|
3713
|
+
});
|
|
3714
|
+
}
|
|
3715
|
+
};
|
|
3716
|
+
|
|
3554
3717
|
// src/scripts/watchStalePrsFlow.ts
|
|
3555
3718
|
function readWatchConfig(ctx) {
|
|
3556
3719
|
const cfg = ctx.config.watch;
|
|
@@ -3671,6 +3834,7 @@ var preflightScripts = {
|
|
|
3671
3834
|
var postflightScripts = {
|
|
3672
3835
|
parseAgentResult: parseAgentResult2,
|
|
3673
3836
|
requireFeedbackActions,
|
|
3837
|
+
requirePlanDeviations,
|
|
3674
3838
|
verify,
|
|
3675
3839
|
checkCoverageWithRetry,
|
|
3676
3840
|
commitAndPush: commitAndPush2,
|
|
@@ -3679,6 +3843,7 @@ var postflightScripts = {
|
|
|
3679
3843
|
postPlanComment,
|
|
3680
3844
|
postReviewResult,
|
|
3681
3845
|
persistArtifacts,
|
|
3846
|
+
verifyFixAlignment,
|
|
3682
3847
|
writeRunSummary,
|
|
3683
3848
|
saveTaskState
|
|
3684
3849
|
};
|
|
@@ -4346,6 +4511,14 @@ ${CHAT_HELP}`);
|
|
|
4346
4511
|
`);
|
|
4347
4512
|
return 64;
|
|
4348
4513
|
}
|
|
4514
|
+
if (needsLitellmProxy(model)) {
|
|
4515
|
+
const code = installLitellmIfNeeded(cwd);
|
|
4516
|
+
if (code !== 0) {
|
|
4517
|
+
process.stderr.write(`error: litellm install failed (exit ${code})
|
|
4518
|
+
`);
|
|
4519
|
+
return 99;
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
4349
4522
|
let litellm = null;
|
|
4350
4523
|
try {
|
|
4351
4524
|
litellm = await startLitellmIfNeeded(model, cwd);
|
|
@@ -34,6 +34,9 @@
|
|
|
34
34
|
{
|
|
35
35
|
"script": "reviewFlow"
|
|
36
36
|
},
|
|
37
|
+
{
|
|
38
|
+
"script": "loadTaskState"
|
|
39
|
+
},
|
|
37
40
|
{
|
|
38
41
|
"script": "loadConventions"
|
|
39
42
|
},
|
|
@@ -44,6 +47,9 @@
|
|
|
44
47
|
"postflight": [
|
|
45
48
|
{
|
|
46
49
|
"script": "postReviewResult"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"script": "saveTaskState"
|
|
47
53
|
}
|
|
48
54
|
]
|
|
49
55
|
}
|
|
@@ -10,17 +10,20 @@ You are Kody, an autonomous engineer. Take a GitHub issue from spec to a tested
|
|
|
10
10
|
# Existing plan (produced by `@kody2 plan`, if present)
|
|
11
11
|
{{artifacts.plan}}
|
|
12
12
|
|
|
13
|
-
If the plan above is non-empty, TREAT IT AS AUTHORITATIVE — follow its file list and approach rather than inventing your own. Deviate only if the plan is wrong; if you do,
|
|
13
|
+
If the plan above is non-empty, TREAT IT AS AUTHORITATIVE — follow its file list and approach rather than inventing your own. Deviate only if the plan is wrong; if you do, you MUST declare each deviation in the `PLAN_DEVIATIONS:` block of your final message (format below). Silent deviations are a hard failure, even if the code works. If the plan is empty, proceed from first principles and emit `PLAN_DEVIATIONS: none` in the final message.
|
|
14
14
|
|
|
15
15
|
# Required steps (all in this one session — no handoff)
|
|
16
16
|
1. **Research** — read the issue carefully. Use Grep/Glob/Read to investigate the codebase: locate relevant files, understand existing patterns, check related tests, identify constraints. Do not edit anything yet.
|
|
17
17
|
2. **Plan** — before any Edit/Write, output a short plan (5–10 lines): what files you'll change, the approach, what could go wrong. No fluff.
|
|
18
18
|
3. **Build** — Edit/Write to implement the change. Stay within the plan; if you discover the plan was wrong, briefly say so and adjust.
|
|
19
19
|
4. **Verify** — run each quality command with Bash. On failure, fix the root cause and re-run. When reporting that a command passed, you MUST have just run it and seen exit code 0 in this session — do not paraphrase prior output.
|
|
20
|
-
5. Your FINAL message must use this exact format (or a single `FAILED: <reason>` line on failure)
|
|
20
|
+
5. Your FINAL message must use this exact format (or a single `FAILED: <reason>` line on failure). The `PLAN_DEVIATIONS:` block is REQUIRED whenever a plan was provided.
|
|
21
21
|
|
|
22
22
|
```
|
|
23
23
|
DONE
|
|
24
|
+
PLAN_DEVIATIONS:
|
|
25
|
+
- <plan item> → <what you did instead> (reason: <why>)
|
|
26
|
+
- (repeat for each deviation; if you followed the plan exactly, write the single line `- none`)
|
|
24
27
|
COMMIT_MSG: <conventional-commit message, e.g. "feat: add X" or "fix: handle Y">
|
|
25
28
|
PR_SUMMARY:
|
|
26
29
|
<2-6 short bullet points naming the files/functions/endpoints you added or modified. No marketing fluff. No restating the issue.>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.29",
|
|
4
4
|
"description": "kody2 — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/templates/kody2.yml
CHANGED
|
@@ -76,13 +76,13 @@ jobs:
|
|
|
76
76
|
node-version: 22
|
|
77
77
|
|
|
78
78
|
- name: Write pip cache key for LiteLLM
|
|
79
|
-
run: echo "litellm[proxy]" >
|
|
79
|
+
run: echo "litellm[proxy]" > .kody2-pip-requirements.txt
|
|
80
80
|
|
|
81
81
|
- uses: actions/setup-python@v5
|
|
82
82
|
with:
|
|
83
83
|
python-version: "3.12"
|
|
84
84
|
cache: "pip"
|
|
85
|
-
cache-dependency-path:
|
|
85
|
+
cache-dependency-path: .kody2-pip-requirements.txt
|
|
86
86
|
|
|
87
87
|
- env:
|
|
88
88
|
ALL_SECRETS: ${{ toJSON(secrets) }}
|