@kody-ade/kody-engine-lite 0.1.49 → 0.1.51
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/README.md +65 -2
- package/dist/bin/cli.js +24 -5
- package/package.json +1 -1
- package/templates/kody.yml +19 -3
package/README.md
CHANGED
|
@@ -13,15 +13,17 @@ Most AI coding tools are **autocomplete** (Copilot) or **chat-based** (Cursor, C
|
|
|
13
13
|
|
|
14
14
|
| | Kody | Copilot Workspace | Devin | Cursor Agent |
|
|
15
15
|
|---|---|---|---|---|
|
|
16
|
+
| **Repo-aware instructions** | AI-customized per-stage prompts with your repo's patterns, gaps, and acceptance criteria | Generic prompts | Generic prompts | Generic prompts |
|
|
16
17
|
| **Runs in CI** | GitHub Actions | GitHub Cloud | Devin Cloud | Local IDE |
|
|
17
18
|
| **Fire and forget** | Yes | No — interactive | Partially | No — IDE must be open |
|
|
18
19
|
| **Pipeline stages** | 7 stages with quality gates | Plan → implement | Single agent | Single agent |
|
|
19
20
|
| **Shared sessions** | Stages share Claude Code sessions (no cold starts) | Single conversation | Single conversation | Single conversation |
|
|
20
21
|
| **Risk gate** | Pauses HIGH-risk for human approval | No | No | No |
|
|
21
22
|
| **AI failure diagnosis** | Classifies errors before retry (fixable/infra/abort) | No | No | No |
|
|
23
|
+
| **Incremental codebase improvement** | Step files encode gaps to fix — every task raises quality | No | No | No |
|
|
22
24
|
| **Model flexible** | Any LLM via LiteLLM | GitHub models only | Proprietary | Cursor models |
|
|
23
25
|
| **Open source** | MIT | Proprietary | Proprietary | Proprietary |
|
|
24
|
-
| **Cost** |
|
|
26
|
+
| **Cost** | **Free** with free-tier models (Gemini, etc.) or pay-per-use with any LLM | $10-39/month | $20-500/month | Subscription |
|
|
25
27
|
|
|
26
28
|
[Full comparison →](docs/COMPARISON.md)
|
|
27
29
|
|
|
@@ -117,7 +119,14 @@ cd your-project
|
|
|
117
119
|
kody-engine-lite init
|
|
118
120
|
```
|
|
119
121
|
|
|
120
|
-
This analyzes your project and generates
|
|
122
|
+
This analyzes your project and generates:
|
|
123
|
+
- **Workflow** (`.github/workflows/kody.yml`)
|
|
124
|
+
- **Config** (`kody.config.json` — auto-detected quality commands, git, GitHub settings)
|
|
125
|
+
- **Project memory** (`.kody/memory/` — architecture and conventions)
|
|
126
|
+
- **Customized step files** (`.kody/steps/` — see below)
|
|
127
|
+
- **GitHub labels** for lifecycle tracking
|
|
128
|
+
|
|
129
|
+
Then commits and pushes everything.
|
|
121
130
|
|
|
122
131
|
### 4. Use
|
|
123
132
|
|
|
@@ -172,6 +181,60 @@ kody-engine-lite init [--force]
|
|
|
172
181
|
|
|
173
182
|
## Key Features
|
|
174
183
|
|
|
184
|
+
### Repo-Aware Step Files (`.kody/steps/`)
|
|
185
|
+
|
|
186
|
+
**This is what separates Kody from every other AI coding tool.**
|
|
187
|
+
|
|
188
|
+
Most AI tools send the same generic prompt regardless of whether they're working on a Next.js app, a Go microservice, or a Python ML pipeline. Kody generates **customized instruction files for every pipeline stage**, tailored to your specific repository.
|
|
189
|
+
|
|
190
|
+
During `kody init`, Kody analyzes your codebase — your frameworks, patterns, conventions, file structure, even your anti-patterns — and produces 6 step files in `.kody/steps/`:
|
|
191
|
+
|
|
192
|
+
| Step File | What It Controls |
|
|
193
|
+
|-----------|-----------------|
|
|
194
|
+
| `taskify.md` | How tasks are classified and scoped for this repo |
|
|
195
|
+
| `plan.md` | Planning guidelines with your repo's architecture in mind |
|
|
196
|
+
| `build.md` | Coding instructions with your actual patterns as examples |
|
|
197
|
+
| `autofix.md` | How to fix verification failures using your toolchain |
|
|
198
|
+
| `review.md` | Review checklist calibrated to your repo's quality bar |
|
|
199
|
+
| `review-fix.md` | How to address review findings in your codebase |
|
|
200
|
+
|
|
201
|
+
Each step file contains three repo-specific sections:
|
|
202
|
+
- **Repo Patterns** — real code examples from your codebase (file paths, function signatures, snippets) showing what "good" looks like in your project
|
|
203
|
+
- **Improvement Areas** — gaps, anti-patterns, and inconsistencies the AI should fix when it touches related code (e.g., "collections missing access control", "services not using DI")
|
|
204
|
+
- **Acceptance Criteria** — a concrete checklist that defines "done" for each stage in your specific repo
|
|
205
|
+
|
|
206
|
+
**Why this matters:**
|
|
207
|
+
- Code produced by Kody **matches your existing patterns** — same naming, same abstractions, same file organization
|
|
208
|
+
- Known gaps get **incrementally fixed** — every task that touches a weak area leaves it better
|
|
209
|
+
- Quality bar is **explicit and auditable** — acceptance criteria are version-controlled in your repo, not hidden in a prompt
|
|
210
|
+
- **You own and customize** the instructions — edit `.kody/steps/build.md` to change how Kody writes code, no engine changes needed
|
|
211
|
+
- Re-run `kody init --force` after major refactors to **regenerate** step files from current state
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
# Example: .kody/steps/build.md (auto-generated, then customizable)
|
|
215
|
+
---
|
|
216
|
+
name: build
|
|
217
|
+
...
|
|
218
|
+
---
|
|
219
|
+
<original engine prompt preserved>
|
|
220
|
+
|
|
221
|
+
## Repo Patterns
|
|
222
|
+
**Collection pattern** (`src/collections/certificates.ts`):
|
|
223
|
+
- Always cast `relationTo` with `as CollectionSlug`
|
|
224
|
+
- Register every new collection in `src/payload.config.ts`
|
|
225
|
+
|
|
226
|
+
## Improvement Areas
|
|
227
|
+
- Collections missing access control — add `access` guards when touching
|
|
228
|
+
- Run `pnpm payload generate:types` after any schema change
|
|
229
|
+
|
|
230
|
+
## Acceptance Criteria
|
|
231
|
+
- [ ] `pnpm tsc --noEmit` exits with zero errors
|
|
232
|
+
- [ ] All new collections include explicit access control
|
|
233
|
+
- [ ] User-supplied strings sanitized via `src/security/sanitizers.ts`
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Other Features
|
|
237
|
+
|
|
175
238
|
- **Shared Sessions** — stages in the same group share a Claude Code session, eliminating cold-start codebase re-exploration ([details](docs/FEATURES.md#shared-sessions))
|
|
176
239
|
- **Risk Gate** — HIGH-risk tasks pause for human plan approval before building ([details](docs/FEATURES.md#risk-gate))
|
|
177
240
|
- **AI Failure Diagnosis** — classifies errors as fixable/infrastructure/pre-existing/abort before retry ([details](docs/FEATURES.md#ai-powered-failure-diagnosis))
|
package/dist/bin/cli.js
CHANGED
|
@@ -1651,9 +1651,14 @@ function executeShipStage(ctx, _def) {
|
|
|
1651
1651
|
const existingPr = getPRForBranch(head);
|
|
1652
1652
|
if (existingPr) {
|
|
1653
1653
|
updatePR(existingPr.number, body);
|
|
1654
|
-
if (
|
|
1654
|
+
if (!ctx.input.local) {
|
|
1655
|
+
const msg = `\u2705 Fix pushed to PR #${existingPr.number}: ${existingPr.url}`;
|
|
1655
1656
|
try {
|
|
1656
|
-
|
|
1657
|
+
if (ctx.input.prNumber) {
|
|
1658
|
+
postPRComment(ctx.input.prNumber, msg);
|
|
1659
|
+
} else if (ctx.input.issueNumber) {
|
|
1660
|
+
postComment(ctx.input.issueNumber, msg);
|
|
1661
|
+
}
|
|
1657
1662
|
} catch {
|
|
1658
1663
|
}
|
|
1659
1664
|
}
|
|
@@ -2872,7 +2877,8 @@ async function main() {
|
|
|
2872
2877
|
setGhCwd(projectDir);
|
|
2873
2878
|
logger.info(`Working directory: ${projectDir}`);
|
|
2874
2879
|
}
|
|
2875
|
-
|
|
2880
|
+
const isPRFix = input.command === "fix" && !!input.prNumber;
|
|
2881
|
+
if (input.issueNumber && input.command !== "review" && !isPRFix) {
|
|
2876
2882
|
const taskAction = resolveForIssue(input.issueNumber, projectDir);
|
|
2877
2883
|
logger.info(`Task action: ${taskAction.action}`);
|
|
2878
2884
|
if (taskAction.action === "already-completed") {
|
|
@@ -2904,7 +2910,9 @@ async function main() {
|
|
|
2904
2910
|
}
|
|
2905
2911
|
let taskId = input.taskId;
|
|
2906
2912
|
if (!taskId) {
|
|
2907
|
-
if (
|
|
2913
|
+
if (isPRFix) {
|
|
2914
|
+
taskId = `fix-pr-${input.prNumber}-${generateTaskId()}`;
|
|
2915
|
+
} else if (input.issueNumber) {
|
|
2908
2916
|
taskId = `${input.issueNumber}-${generateTaskId()}`;
|
|
2909
2917
|
} else if (input.command === "run" && input.task) {
|
|
2910
2918
|
taskId = generateTaskId();
|
|
@@ -3005,7 +3013,17 @@ async function main() {
|
|
|
3005
3013
|
fs20.writeFileSync(path19.join(taskDir, "task.md"), input.task);
|
|
3006
3014
|
}
|
|
3007
3015
|
const taskMdPath = path19.join(taskDir, "task.md");
|
|
3008
|
-
if (!fs20.existsSync(taskMdPath) && input.
|
|
3016
|
+
if (!fs20.existsSync(taskMdPath) && isPRFix && input.prNumber) {
|
|
3017
|
+
logger.info(`Fetching PR #${input.prNumber} details as task context...`);
|
|
3018
|
+
const prDetails = getPRDetails(input.prNumber);
|
|
3019
|
+
if (prDetails) {
|
|
3020
|
+
const taskContent = `# ${prDetails.title}
|
|
3021
|
+
|
|
3022
|
+
${prDetails.body ?? ""}`;
|
|
3023
|
+
fs20.writeFileSync(taskMdPath, taskContent);
|
|
3024
|
+
logger.info(` Task loaded from PR #${input.prNumber}: ${prDetails.title}`);
|
|
3025
|
+
}
|
|
3026
|
+
} else if (!fs20.existsSync(taskMdPath) && input.issueNumber) {
|
|
3009
3027
|
logger.info(`Fetching issue #${input.issueNumber} body as task...`);
|
|
3010
3028
|
const issue = getIssue(input.issueNumber);
|
|
3011
3029
|
if (issue) {
|
|
@@ -3092,6 +3110,7 @@ ${input.feedback}` : reviewContext;
|
|
|
3092
3110
|
fromStage: input.fromStage,
|
|
3093
3111
|
dryRun: input.dryRun,
|
|
3094
3112
|
issueNumber: input.issueNumber,
|
|
3113
|
+
prNumber: input.prNumber,
|
|
3095
3114
|
feedback: input.feedback,
|
|
3096
3115
|
local: input.local,
|
|
3097
3116
|
complexity: input.complexity
|
package/package.json
CHANGED
package/templates/kody.yml
CHANGED
|
@@ -54,6 +54,7 @@ jobs:
|
|
|
54
54
|
mode: ${{ steps.parse.outputs.mode }}
|
|
55
55
|
from_stage: ${{ steps.parse.outputs.from_stage }}
|
|
56
56
|
issue_number: ${{ steps.parse.outputs.issue_number }}
|
|
57
|
+
pr_number: ${{ steps.parse.outputs.pr_number }}
|
|
57
58
|
feedback: ${{ steps.parse.outputs.feedback }}
|
|
58
59
|
valid: ${{ steps.parse.outputs.valid }}
|
|
59
60
|
steps:
|
|
@@ -108,7 +109,7 @@ jobs:
|
|
|
108
109
|
|
|
109
110
|
# Validate mode
|
|
110
111
|
case "$MODE" in
|
|
111
|
-
full|rerun|fix|status|approve) ;;
|
|
112
|
+
full|rerun|fix|status|approve|review) ;;
|
|
112
113
|
*)
|
|
113
114
|
# If first arg isn't a mode, it might be a task-id or nothing
|
|
114
115
|
if [ -n "$MODE" ] && [ "$MODE" != "" ]; then
|
|
@@ -143,10 +144,22 @@ jobs:
|
|
|
143
144
|
TASK_ID="${ISSUE_NUM}-$(date +%y%m%d-%H%M%S)"
|
|
144
145
|
fi
|
|
145
146
|
|
|
147
|
+
# Detect if this comment is on a PR (PRs are issues in GitHub API)
|
|
148
|
+
PR_NUMBER=""
|
|
149
|
+
if [ -n "${{ github.event.issue.pull_request }}" ]; then
|
|
150
|
+
PR_NUMBER="$ISSUE_NUM"
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
# For review mode on a PR comment: use the PR number directly
|
|
154
|
+
if [ "$MODE" = "review" ] && [ -n "$PR_NUMBER" ]; then
|
|
155
|
+
TASK_ID="review-pr-${PR_NUMBER}-$(date +%y%m%d-%H%M%S)"
|
|
156
|
+
fi
|
|
157
|
+
|
|
146
158
|
echo "task_id=$TASK_ID" >> $GITHUB_OUTPUT
|
|
147
159
|
echo "mode=$MODE" >> $GITHUB_OUTPUT
|
|
148
160
|
echo "from_stage=$FROM_STAGE" >> $GITHUB_OUTPUT
|
|
149
161
|
echo "issue_number=$ISSUE_NUM" >> $GITHUB_OUTPUT
|
|
162
|
+
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
|
|
150
163
|
{
|
|
151
164
|
echo "feedback<<KODY_EOF"
|
|
152
165
|
echo "$FEEDBACK"
|
|
@@ -179,8 +192,8 @@ jobs:
|
|
|
179
192
|
persist-credentials: true
|
|
180
193
|
token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
|
|
181
194
|
|
|
182
|
-
- name: Checkout PR branch (for fix/rerun on PRs)
|
|
183
|
-
if: github.event.issue.pull_request && (needs.parse.outputs.mode == 'fix' || needs.parse.outputs.mode == 'rerun')
|
|
195
|
+
- name: Checkout PR branch (for fix/rerun/review on PRs)
|
|
196
|
+
if: github.event.issue.pull_request && (needs.parse.outputs.mode == 'fix' || needs.parse.outputs.mode == 'rerun' || needs.parse.outputs.mode == 'review')
|
|
184
197
|
env:
|
|
185
198
|
GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
|
|
186
199
|
run: |
|
|
@@ -219,6 +232,7 @@ jobs:
|
|
|
219
232
|
MODE: ${{ github.event.inputs.mode || needs.parse.outputs.mode || 'full' }}
|
|
220
233
|
FROM_STAGE: ${{ github.event.inputs.from_stage || needs.parse.outputs.from_stage }}
|
|
221
234
|
ISSUE_NUMBER: ${{ github.event.inputs.issue_number || needs.parse.outputs.issue_number }}
|
|
235
|
+
PR_NUMBER: ${{ needs.parse.outputs.pr_number }}
|
|
222
236
|
FEEDBACK: ${{ github.event.inputs.feedback || needs.parse.outputs.feedback }}
|
|
223
237
|
DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }}
|
|
224
238
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
@@ -226,8 +240,10 @@ jobs:
|
|
|
226
240
|
CMD="run"
|
|
227
241
|
[ "$MODE" = "rerun" ] && CMD="rerun"
|
|
228
242
|
[ "$MODE" = "fix" ] && CMD="fix"
|
|
243
|
+
[ "$MODE" = "review" ] && CMD="review"
|
|
229
244
|
ARGS="--issue-number $ISSUE_NUMBER"
|
|
230
245
|
[ -n "$TASK_ID" ] && ARGS="$ARGS --task-id $TASK_ID"
|
|
246
|
+
[ -n "$PR_NUMBER" ] && ARGS="$ARGS --pr-number $PR_NUMBER"
|
|
231
247
|
[ -n "$FROM_STAGE" ] && ARGS="$ARGS --from $FROM_STAGE"
|
|
232
248
|
[ -n "$FEEDBACK" ] && ARGS="$ARGS --feedback \"$FEEDBACK\""
|
|
233
249
|
[ "$DRY_RUN" = "true" ] && ARGS="$ARGS --dry-run"
|