@kody-ade/kody-engine-lite 0.1.47 → 0.1.49

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/cli.js +62 -3
  2. package/package.json +1 -1
package/dist/bin/cli.js CHANGED
@@ -651,6 +651,32 @@ function postPRComment(prNumber, body) {
651
651
  logger.warn(` Failed to post PR comment: ${err}`);
652
652
  }
653
653
  }
654
+ function submitPRReview(prNumber, body, event) {
655
+ const flag = event === "approve" ? "--approve" : "--request-changes";
656
+ try {
657
+ gh(
658
+ ["pr", "review", String(prNumber), flag, "--body-file", "-"],
659
+ { input: body }
660
+ );
661
+ logger.info(` PR review submitted on #${prNumber}: ${event}`);
662
+ } catch (err) {
663
+ logger.warn(` Failed to submit PR review: ${err}`);
664
+ }
665
+ }
666
+ function getLatestKodyReviewComment(prNumber) {
667
+ try {
668
+ const output = gh([
669
+ "api",
670
+ `repos/{owner}/{repo}/issues/${prNumber}/comments`,
671
+ "--jq",
672
+ '[.[] | select(.body | test("Kody Review"))] | last | .body'
673
+ ]);
674
+ return output.trim() || null;
675
+ } catch (err) {
676
+ logger.warn(` Failed to get review comments for PR #${prNumber}: ${err}`);
677
+ return null;
678
+ }
679
+ }
654
680
  var API_TIMEOUT_MS, LIFECYCLE_LABELS, _ghCwd;
655
681
  var init_github_api = __esm({
656
682
  "src/github-api.ts"() {
@@ -2593,10 +2619,22 @@ ${input.prBody ?? ""}`;
2593
2619
  taskDir
2594
2620
  };
2595
2621
  }
2622
+ function detectReviewVerdict(reviewContent) {
2623
+ const verdictMatch = reviewContent.match(/##\s*Verdict:\s*(PASS|FAIL)/i);
2624
+ if (verdictMatch) {
2625
+ return verdictMatch[1].toLowerCase();
2626
+ }
2627
+ const hasCritical = /###\s*Critical\s*\n(?!None\.)/i.test(reviewContent);
2628
+ const hasMajor = /###\s*Major\s*\n(?!None\.)/i.test(reviewContent);
2629
+ if (hasCritical || hasMajor) return "fail";
2630
+ return "pass";
2631
+ }
2596
2632
  function formatReviewComment(reviewContent, taskId) {
2633
+ const verdict = detectReviewVerdict(reviewContent);
2634
+ const cta = verdict === "fail" ? "\n\n> To fix these issues, comment: `@kody fix`\n> The review findings will be used automatically as context." : "";
2597
2635
  return `## \u{1F50D} Kody Review (\`${taskId}\`)
2598
2636
 
2599
- ${reviewContent}
2637
+ ${reviewContent}${cta}
2600
2638
 
2601
2639
  ---
2602
2640
  \u{1F916} Generated by Kody`;
@@ -2951,6 +2989,12 @@ async function main() {
2951
2989
  if (!input.local && prNumber) {
2952
2990
  const comment = formatReviewComment(result.reviewContent, taskId);
2953
2991
  postPRComment(prNumber, comment);
2992
+ const verdict = detectReviewVerdict(result.reviewContent);
2993
+ if (verdict === "fail") {
2994
+ submitPRReview(prNumber, comment, "request-changes");
2995
+ } else {
2996
+ submitPRReview(prNumber, comment, "approve");
2997
+ }
2954
2998
  }
2955
2999
  }
2956
3000
  process.exit(0);
@@ -2979,6 +3023,20 @@ ${issue.body ?? ""}`;
2979
3023
  if (input.command === "fix" && !input.fromStage) {
2980
3024
  input.fromStage = "build";
2981
3025
  }
3026
+ if (input.command === "fix" && input.prNumber) {
3027
+ const reviewComment = getLatestKodyReviewComment(input.prNumber);
3028
+ if (reviewComment) {
3029
+ logger.info(` Found Kody review comment on PR #${input.prNumber}, injecting as feedback`);
3030
+ const reviewContext = `## Review findings from PR #${input.prNumber}
3031
+
3032
+ ${reviewComment}`;
3033
+ input.feedback = input.feedback ? `${reviewContext}
3034
+
3035
+ ## Additional feedback
3036
+
3037
+ ${input.feedback}` : reviewContext;
3038
+ }
3039
+ }
2982
3040
  const config = getProjectConfig();
2983
3041
  let litellmProcess = null;
2984
3042
  const cleanupLitellm = () => {
@@ -3866,11 +3924,12 @@ ${srcEntries.join(", ")}
3866
3924
  cwd,
3867
3925
  stdio: ["pipe", "pipe", "pipe"]
3868
3926
  }).trim();
3869
- if (!output.includes("{{TASK_CONTEXT}}")) {
3927
+ const cleaned = output.replace(/^```(?:markdown|md)?\s*\n?/, "").replace(/\n?```\s*$/, "");
3928
+ if (!cleaned.includes("{{TASK_CONTEXT}}")) {
3870
3929
  console.log(` \u26A0 ${stage}.md \u2014 AI dropped {{TASK_CONTEXT}}, using default template`);
3871
3930
  fs21.writeFileSync(path20.join(stepsDir, `${stage}.md`), defaultPrompt);
3872
3931
  } else {
3873
- fs21.writeFileSync(path20.join(stepsDir, `${stage}.md`), output);
3932
+ fs21.writeFileSync(path20.join(stepsDir, `${stage}.md`), cleaned);
3874
3933
  }
3875
3934
  stepCount++;
3876
3935
  console.log(` \u2713 ${stage}.md`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine-lite",
3
- "version": "0.1.47",
3
+ "version": "0.1.49",
4
4
  "description": "Autonomous SDLC pipeline: Kody orchestration + Claude Code + LiteLLM",
5
5
  "license": "MIT",
6
6
  "type": "module",