@kody-ade/kody-engine 0.2.39 → 0.2.41

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.39",
6
+ version: "0.2.41",
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",
@@ -2855,6 +2855,24 @@ ${plan}
2855
2855
  Comment \`@kody2 run\` to execute this plan.`;
2856
2856
  }
2857
2857
 
2858
+ // src/scripts/postResearchComment.ts
2859
+ var postResearchComment = async (ctx) => {
2860
+ if (!ctx.data.agentDone) return;
2861
+ const targetType = ctx.data.commentTargetType;
2862
+ const targetNumber = Number(ctx.data.commentTargetNumber ?? 0);
2863
+ const body = ctx.data.prSummary?.trim();
2864
+ if (targetType !== "issue" || !targetNumber || !body) return;
2865
+ try {
2866
+ postIssueComment(targetNumber, renderResearchComment(targetNumber, body), ctx.cwd);
2867
+ } catch {
2868
+ }
2869
+ };
2870
+ function renderResearchComment(issueNumber, body) {
2871
+ return `## Research for issue #${issueNumber}
2872
+
2873
+ ${body}`;
2874
+ }
2875
+
2858
2876
  // src/scripts/postReviewResult.ts
2859
2877
  function detectVerdict(body) {
2860
2878
  const m = body.match(/##\s*Verdict\s*:\s*(PASS|CONCERNS|FAIL)\b/i);
@@ -3654,138 +3672,6 @@ var verify = async (ctx) => {
3654
3672
  }
3655
3673
  };
3656
3674
 
3657
- // src/scripts/verifyFixAlignment.ts
3658
- function summarizeFeedbackActions(block) {
3659
- const summary = { totalItems: 0, fixedItems: 0, declinedItems: 0, unparsedLines: 0 };
3660
- if (!block.trim()) return summary;
3661
- for (const raw of block.split("\n")) {
3662
- if (!/^\s*[-*]\s+/.test(raw)) continue;
3663
- const line = raw.replace(/^\s*[-*]\s*/, "").trim();
3664
- summary.totalItems++;
3665
- if (/\bfixed\s*:/i.test(line)) summary.fixedItems++;
3666
- else if (/\bdeclined\s*:/i.test(line)) summary.declinedItems++;
3667
- else summary.unparsedLines++;
3668
- }
3669
- return summary;
3670
- }
3671
- var ACTIONABLE_HEADING = /^#{1,6}\s+(Concerns|Suggestions|Bugs)\b/i;
3672
- var ANY_HEADING = /^#{1,6}\s+/;
3673
- function actionableSections(reviewBody) {
3674
- const lines = reviewBody.split("\n");
3675
- const kept = [];
3676
- let inside = false;
3677
- for (const raw of lines) {
3678
- if (ACTIONABLE_HEADING.test(raw)) {
3679
- inside = true;
3680
- kept.push(raw);
3681
- continue;
3682
- }
3683
- if (inside && ANY_HEADING.test(raw)) {
3684
- inside = false;
3685
- continue;
3686
- }
3687
- if (inside) kept.push(raw);
3688
- }
3689
- return kept.join("\n");
3690
- }
3691
- function extractReviewFileRefs(reviewBody) {
3692
- if (!reviewBody) return [];
3693
- const scoped = actionableSections(reviewBody);
3694
- if (!scoped.trim()) return [];
3695
- const found = /* @__PURE__ */ new Set();
3696
- const backtick = /`([^`\s]+\.[a-zA-Z]{1,5})(?::\d+(?:-\d+)?)?`/g;
3697
- let m;
3698
- while ((m = backtick.exec(scoped)) !== null) {
3699
- const raw = m[1];
3700
- if (isPlausibleSourcePath(raw)) found.add(raw);
3701
- }
3702
- const bare = /(?<![A-Za-z0-9/_.-])((?:[A-Za-z0-9_./-]+\/)+[A-Za-z0-9_.-]+\.[a-zA-Z]{1,5})(?::\d+(?:-\d+)?)?/g;
3703
- while ((m = bare.exec(scoped)) !== null) {
3704
- const raw = m[1];
3705
- if (isPlausibleSourcePath(raw)) found.add(raw);
3706
- }
3707
- return Array.from(found);
3708
- }
3709
- function isPlausibleSourcePath(p) {
3710
- if (p.startsWith("http://") || p.startsWith("https://")) return false;
3711
- if (p.startsWith("//")) return false;
3712
- if (p.startsWith("/")) return false;
3713
- if (!p.includes("/")) return false;
3714
- if (/\.(md|rst|txt|png|jpg|jpeg|gif|svg|pdf)$/i.test(p)) return false;
3715
- const firstSeg = p.slice(0, p.indexOf("/"));
3716
- if (firstSeg.includes(".")) return false;
3717
- return true;
3718
- }
3719
- function declinedFileRefs(feedbackActions, refs) {
3720
- if (!feedbackActions.trim() || refs.length === 0) return /* @__PURE__ */ new Set();
3721
- const declined = /* @__PURE__ */ new Set();
3722
- for (const raw of feedbackActions.split("\n")) {
3723
- if (!/^\s*[-*]\s+/.test(raw)) continue;
3724
- if (!/\bdeclined\s*:/i.test(raw)) continue;
3725
- for (const ref of refs) {
3726
- if (raw.includes(ref)) declined.add(ref);
3727
- }
3728
- }
3729
- return declined;
3730
- }
3731
- function makeAction2(type, payload) {
3732
- return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
3733
- }
3734
- var verifyFixAlignment = async (ctx, profile) => {
3735
- if (profile.name !== "fix") return;
3736
- if (ctx.skipAgent) return;
3737
- if (!ctx.data.agentDone) return;
3738
- const feedbackActions = ctx.data.feedbackActions ?? "";
3739
- const summary = summarizeFeedbackActions(feedbackActions);
3740
- ctx.data.feedbackActionsSummary = summary;
3741
- const committed = Boolean(ctx.data.commitResult?.committed);
3742
- if (summary.totalItems === 0) {
3743
- return failOnce(ctx, "FIX_FAILED", "fix produced no FEEDBACK_ACTIONS items", summary);
3744
- }
3745
- const reviewBody = ctx.data.feedback ?? "";
3746
- const refs = extractReviewFileRefs(reviewBody);
3747
- const changedFiles = (ctx.data.changedFiles ?? []).map((f) => f.trim()).filter(Boolean);
3748
- ctx.data.reviewFileRefs = refs;
3749
- if (refs.length > 0 && committed) {
3750
- const declined = declinedFileRefs(feedbackActions, refs);
3751
- const missing = refs.filter((r) => !declined.has(r) && !changedFiles.some((f) => filesMatch(f, r)));
3752
- if (missing.length > 0) {
3753
- return failOnce(
3754
- ctx,
3755
- "FIX_FAILED",
3756
- `fix did not touch review-named file(s): ${missing.join(", ")} \u2014 address them or mark declined with a reason`,
3757
- summary,
3758
- { missingFiles: missing, declinedFiles: Array.from(declined), changedFiles }
3759
- );
3760
- }
3761
- }
3762
- if (summary.fixedItems === 0 && summary.declinedItems > 0 && !committed) {
3763
- ctx.data.action = makeAction2("FIX_DECLINED", {
3764
- feedbackActionsSummary: summary,
3765
- note: "agent declined all feedback items; no commit made"
3766
- });
3767
- }
3768
- };
3769
- function failOnce(ctx, type, reason, summary, extra) {
3770
- ctx.output.exitCode = 1;
3771
- ctx.output.reason = reason;
3772
- ctx.data.agentDone = false;
3773
- ctx.data.action = makeAction2(type, {
3774
- reason,
3775
- feedbackActionsSummary: summary,
3776
- ...extra ?? {}
3777
- });
3778
- }
3779
- function filesMatch(changedPath, reviewRef) {
3780
- if (changedPath === reviewRef) return true;
3781
- if (changedPath.endsWith("/" + reviewRef)) return true;
3782
- if (reviewRef.endsWith("/" + changedPath)) return true;
3783
- const a = changedPath.split("/");
3784
- const b = reviewRef.split("/");
3785
- if (a[a.length - 1] !== b[b.length - 1]) return false;
3786
- return a.length >= 2 && b.length >= 2 && a[a.length - 2] === b[b.length - 2];
3787
- }
3788
-
3789
3675
  // src/scripts/watchStalePrsFlow.ts
3790
3676
  function readWatchConfig(ctx) {
3791
3677
  const cfg = ctx.config.watch;
@@ -3913,9 +3799,9 @@ var postflightScripts = {
3913
3799
  ensurePr: ensurePr2,
3914
3800
  postIssueComment: postIssueComment2,
3915
3801
  postPlanComment,
3802
+ postResearchComment,
3916
3803
  postReviewResult,
3917
3804
  persistArtifacts,
3918
- verifyFixAlignment,
3919
3805
  writeRunSummary,
3920
3806
  saveTaskState
3921
3807
  };
@@ -72,9 +72,6 @@
72
72
  {
73
73
  "script": "commitAndPush"
74
74
  },
75
- {
76
- "script": "verifyFixAlignment"
77
- },
78
75
  {
79
76
  "script": "ensurePr"
80
77
  },
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "research",
3
+ "describe": "Research an issue: understand the ask, map relevant repo context, and surface clarifying questions + gaps. Read-only — no branches, no commits, no prescribed next steps.",
4
+ "inputs": [
5
+ {
6
+ "name": "issue",
7
+ "flag": "--issue",
8
+ "type": "int",
9
+ "required": true,
10
+ "describe": "GitHub issue number to research."
11
+ }
12
+ ],
13
+ "claudeCode": {
14
+ "model": "inherit",
15
+ "permissionMode": "default",
16
+ "maxTurns": null,
17
+ "systemPromptAppend": null,
18
+ "tools": [
19
+ "Read",
20
+ "Grep",
21
+ "Glob",
22
+ "Bash"
23
+ ],
24
+ "hooks": [],
25
+ "skills": [],
26
+ "commands": [],
27
+ "subagents": [],
28
+ "plugins": [],
29
+ "mcpServers": []
30
+ },
31
+ "cliTools": [],
32
+ "scripts": {
33
+ "preflight": [
34
+ {
35
+ "script": "loadIssueContext"
36
+ },
37
+ {
38
+ "script": "loadTaskState"
39
+ },
40
+ {
41
+ "script": "loadConventions"
42
+ },
43
+ {
44
+ "script": "composePrompt"
45
+ }
46
+ ],
47
+ "postflight": [
48
+ {
49
+ "script": "parseAgentResult"
50
+ },
51
+ {
52
+ "script": "persistArtifacts"
53
+ },
54
+ {
55
+ "script": "postResearchComment"
56
+ },
57
+ {
58
+ "script": "writeRunSummary"
59
+ },
60
+ {
61
+ "script": "saveTaskState"
62
+ }
63
+ ]
64
+ },
65
+ "output": {
66
+ "actionTypes": [
67
+ "RESEARCH_COMPLETED",
68
+ "RESEARCH_FAILED"
69
+ ],
70
+ "artifacts": [
71
+ {
72
+ "name": "research",
73
+ "format": "markdown",
74
+ "from": "prSummary"
75
+ }
76
+ ]
77
+ }
78
+ }
@@ -0,0 +1,61 @@
1
+ You are a senior engineer **researching** a GitHub issue. Your job is to fill in missing information so a downstream planner (human or agent) can make a decision. You will NOT write code. You will NOT run git or gh commands. You will NOT modify files. You will NOT prescribe a next step.
2
+
3
+ Use Read / Grep / Glob / Bash (read-only) to study the codebase as much as needed. Then emit a final message with the research doc wrapped in the required markers (see "Required output").
4
+
5
+ ---
6
+
7
+ # Repo
8
+ - {{repoOwner}}/{{repoName}}, default branch: {{defaultBranch}}
9
+
10
+ # Issue #{{issue.number}}: {{issue.title}}
11
+
12
+ {{issue.body}}
13
+
14
+ Recent comments (most recent first, truncated):
15
+ {{issue.commentsFormatted}}
16
+
17
+ {{conventionsBlock}}
18
+
19
+ ---
20
+
21
+ # Required output
22
+
23
+ Your FINAL message must be exactly this shape (no extra text before or after):
24
+
25
+ ```
26
+ DONE
27
+ COMMIT_MSG: research: <very short title>
28
+ PR_SUMMARY:
29
+ <A research doc in markdown with EXACTLY these sections, in order:
30
+
31
+ ## Understood request
32
+ One paragraph restating what the issue is asking for, in your own words.
33
+
34
+ ## Repo context
35
+ Files, modules, and existing patterns most relevant to the request. Use
36
+ `path/to/file.ts` references. Note anything that constrains the solution
37
+ space (existing abstractions, invariants from AGENTS.md / CLAUDE.md).
38
+
39
+ ## Clarifying questions
40
+ Numbered list. Each question must include a one-line "Why:" explaining why
41
+ the answer changes the implementation. Skip if there are genuinely none.
42
+
43
+ ## Gaps & assumptions
44
+ What is unknown, and — for each gap — what assumption the implementer would
45
+ have to make if it stays unanswered.
46
+
47
+ ## Proposed scope
48
+ Two bullet lists: **In scope** and **Out of scope**. Keep tight: only what
49
+ the issue asks for; call out adjacent work that should NOT be bundled.
50
+
51
+ Keep the whole doc to ~80 lines or less. No filler. No marketing language.
52
+ Do NOT include a "Next steps" / "Recommendation" / "How to proceed" section —
53
+ research stops at findings.>
54
+ ```
55
+
56
+ # Rules
57
+ - Read-only. Do NOT modify any file.
58
+ - Do NOT run git or gh commands.
59
+ - Do NOT propose an implementation plan — that's the planner's job.
60
+ - Do NOT tell the user what command to run next.
61
+ - If the issue is empty or incomprehensible, output `FAILED: <why>` instead.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.2.39",
3
+ "version": "0.2.41",
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",