@kody-ade/kody-engine 0.4.302 → 0.4.303

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 +79 -1
  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.303",
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 {
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.303",
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",