@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.
|
|
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
|
};
|
|
@@ -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.
|
|
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",
|