@kody-ade/kody-engine 0.4.302 → 0.4.304

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/kody.js +94 -2
  2. package/package.json +1 -1
package/dist/bin/kody.js CHANGED
@@ -15,7 +15,7 @@ var init_package = __esm({
15
15
  "package.json"() {
16
16
  package_default = {
17
17
  name: "@kody-ade/kody-engine",
18
- version: "0.4.302",
18
+ version: "0.4.304",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -10438,6 +10438,14 @@ var init_composePrompt = __esm({
10438
10438
 
10439
10439
  // src/scripts/postReviewResult.ts
10440
10440
  function inferVerdictFromReviewText(body) {
10441
+ const structuredVerdict = body.match(/"verdict"\s*:\s*"(pass|concerns|fail|partial)"/i);
10442
+ if (structuredVerdict) {
10443
+ const value = structuredVerdict[1].toUpperCase();
10444
+ return value === "PARTIAL" ? "CONCERNS" : value;
10445
+ }
10446
+ if (/\bpartial\b/i.test(body) && /\b(finding|gap|unverified|unverifiable|blocker|issue)s?\b/i.test(body)) {
10447
+ return "CONCERNS";
10448
+ }
10441
10449
  if (/\b(blocking|blocker|must fix|should not merge|regression|breaks|security risk)\b/i.test(body)) return "FAIL";
10442
10450
  if (/\b(actionable item|suggestions?|worth clarifying|worth checking|minor note|non-blocking|deserves a comment)\b/i.test(
10443
10451
  body
@@ -10565,6 +10573,8 @@ function buildGoalName(scope, verdict) {
10565
10573
  function splitReport(text) {
10566
10574
  const open = text.indexOf(REPORT_JSON_OPEN);
10567
10575
  if (open < 0) {
10576
+ const fallback = parseFallbackFindingsJson(text);
10577
+ if (fallback) return fallback;
10568
10578
  return { markdown: text.trim(), data: null, jsonError: "no JSON block marker" };
10569
10579
  }
10570
10580
  const closeRel = text.slice(open + REPORT_JSON_OPEN.length).indexOf(REPORT_JSON_CLOSE);
@@ -10590,6 +10600,74 @@ function splitReport(text) {
10590
10600
  const markdown = text.slice(0, open).trim();
10591
10601
  return { markdown, data: parsed, jsonError: parseError };
10592
10602
  }
10603
+ function parseFallbackFindingsJson(text) {
10604
+ const fences = [...text.matchAll(/```(?:json)?\s*([\s\S]*?)\s*```/gi)];
10605
+ for (let i = fences.length - 1; i >= 0; i--) {
10606
+ const match = fences[i];
10607
+ const raw = match[1]?.trim();
10608
+ if (!raw || !/"findings"\s*:/.test(raw)) continue;
10609
+ try {
10610
+ const parsed = JSON.parse(raw);
10611
+ if (!parsed || !Array.isArray(parsed.findings)) {
10612
+ return { markdown: removeFence(text, match).trim(), data: null, jsonError: "fallback JSON missing 'findings' array" };
10613
+ }
10614
+ return {
10615
+ markdown: removeFence(text, match).trim(),
10616
+ data: { findings: parsed.findings.map((f, idx) => normalizeFallbackFinding(f, idx)) }
10617
+ };
10618
+ } catch (err) {
10619
+ return {
10620
+ markdown: removeFence(text, match).trim(),
10621
+ data: null,
10622
+ jsonError: err instanceof Error ? err.message : String(err)
10623
+ };
10624
+ }
10625
+ }
10626
+ return null;
10627
+ }
10628
+ function removeFence(text, match) {
10629
+ const start = match.index ?? -1;
10630
+ if (start < 0) return text;
10631
+ return `${text.slice(0, start)}${text.slice(start + match[0].length)}`;
10632
+ }
10633
+ function normalizeFallbackFinding(raw, idx) {
10634
+ const finding = raw && typeof raw === "object" ? raw : {};
10635
+ const title = firstString(finding.title, finding.summary, finding.issue, finding.name) || `QA finding ${idx + 1}`;
10636
+ const route = firstString(finding.route, finding.url, finding.path);
10637
+ const expected = firstString(finding.expected) || "Expected behavior described in QA report.";
10638
+ const actual = firstString(finding.actual, finding.summary, finding.observed) || "Observed behavior described in QA report.";
10639
+ return {
10640
+ severity: normalizeSeverity(firstString(finding.severity, finding.priority)),
10641
+ title,
10642
+ ...route ? { route } : {},
10643
+ steps: firstString(finding.steps, finding.repro, finding.reproduction) || "See QA report.",
10644
+ expected,
10645
+ actual,
10646
+ evidence: evidenceString(finding.evidence)
10647
+ };
10648
+ }
10649
+ function firstString(...values) {
10650
+ for (const value of values) {
10651
+ if (typeof value === "string" && value.trim()) return value.trim();
10652
+ }
10653
+ return "";
10654
+ }
10655
+ function evidenceString(value) {
10656
+ if (typeof value === "string" && value.trim()) return value.trim();
10657
+ if (Array.isArray(value)) {
10658
+ const parts = value.filter((v) => typeof v === "string" && v.trim().length > 0).map((v) => v.trim());
10659
+ return parts.length > 0 ? parts.join(", ") : void 0;
10660
+ }
10661
+ return void 0;
10662
+ }
10663
+ function normalizeSeverity(value) {
10664
+ const v = value.trim().toUpperCase();
10665
+ if (v === "P0" || v === "CRITICAL") return "P0";
10666
+ if (v === "P1" || v === "HIGH" || v === "BLOCKER") return "P1";
10667
+ if (v === "P2" || v === "MEDIUM") return "P2";
10668
+ if (v === "P3" || v === "LOW" || v === "POLISH") return "P3";
10669
+ return "P2";
10670
+ }
10593
10671
  function loadManifest(cwd) {
10594
10672
  let issuesJson;
10595
10673
  try {
@@ -10891,7 +10969,7 @@ QA_GOAL_TARGETED=(no manifest issue) (id: ${goalId}, verdict: ${verdict})
10891
10969
  });
10892
10970
  ctx.output.exitCode = verdict === "FAIL" ? 1 : 0;
10893
10971
  }
10894
- var MANIFEST_LABEL, MANIFEST_TITLE, MANIFEST_START, MANIFEST_END, FINDING_LABEL, REPORT_JSON_OPEN, REPORT_JSON_CLOSE, SEVERITY_COLORS, createQaGoal;
10972
+ var MANIFEST_LABEL, MANIFEST_TITLE, MANIFEST_START, MANIFEST_END, FINDING_LABEL, QA_REPORT_LABEL, REPORT_JSON_OPEN, REPORT_JSON_CLOSE, SEVERITY_COLORS, createQaGoal;
10895
10973
  var init_createQaGoal = __esm({
10896
10974
  "src/scripts/createQaGoal.ts"() {
10897
10975
  "use strict";
@@ -10904,6 +10982,7 @@ var init_createQaGoal = __esm({
10904
10982
  MANIFEST_START = "<!-- kody-goals-start -->";
10905
10983
  MANIFEST_END = "<!-- kody-goals-end -->";
10906
10984
  FINDING_LABEL = "kody:qa-finding";
10985
+ QA_REPORT_LABEL = "kody:qa-report";
10907
10986
  REPORT_JSON_OPEN = "<!-- KODY_QA_REPORT_JSON";
10908
10987
  REPORT_JSON_CLOSE = "-->";
10909
10988
  SEVERITY_COLORS = {
@@ -10943,6 +11022,11 @@ var init_createQaGoal = __esm({
10943
11022
  ctx.data.action = failedAction2(ctx.output.reason);
10944
11023
  return;
10945
11024
  }
11025
+ try {
11026
+ ensureLabel(QA_REPORT_LABEL, "8b5cf6", "kody: QA report", ctx.cwd);
11027
+ gh(["issue", "edit", String(existingIssue), "--add-label", QA_REPORT_LABEL], { cwd: ctx.cwd });
11028
+ } catch {
11029
+ }
10946
11030
  process.stdout.write(
10947
11031
  `
10948
11032
  QA_REPORT_POSTED=https://github.com/${ctx.config.github.owner}/${ctx.config.github.repo}/issues/${existingIssue} (verdict: ${verdict})
@@ -14085,6 +14169,13 @@ function ensureLabel2(cwd) {
14085
14169
  return false;
14086
14170
  }
14087
14171
  }
14172
+ function markIssueWithReportLabel(issue, cwd) {
14173
+ if (!ensureLabel2(cwd)) return;
14174
+ try {
14175
+ gh(["issue", "edit", String(issue), "--add-label", QA_LABEL], { cwd });
14176
+ } catch {
14177
+ }
14178
+ }
14088
14179
  function createQaIssue(title, body, hasLabel, cwd) {
14089
14180
  const args = ["issue", "create", "--title", title, "--body-file", "-"];
14090
14181
  if (hasLabel) args.push("--label", QA_LABEL);
@@ -14126,6 +14217,7 @@ var init_openQaIssue = __esm({
14126
14217
  if (typeof existingIssue === "number" && Number.isFinite(existingIssue) && existingIssue > 0) {
14127
14218
  try {
14128
14219
  postIssueComment(existingIssue, reportBody, ctx.cwd);
14220
+ markIssueWithReportLabel(existingIssue, ctx.cwd);
14129
14221
  } catch (err) {
14130
14222
  const msg = err instanceof Error ? err.message : String(err);
14131
14223
  ctx.output.exitCode = 4;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.302",
3
+ "version": "0.4.304",
4
4
  "description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",