@kody-ade/kody-engine 0.2.20 → 0.2.22
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.22",
|
|
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",
|
|
@@ -488,6 +488,8 @@ function loadProfile(profilePath) {
|
|
|
488
488
|
cliTools: parseCliTools(profilePath, r.cliTools),
|
|
489
489
|
scripts: parseScripts(profilePath, r.scripts),
|
|
490
490
|
outputContract: r.outputContract,
|
|
491
|
+
inputArtifacts: parseInputArtifacts(profilePath, r.input),
|
|
492
|
+
outputArtifacts: parseOutputArtifacts(profilePath, r.output),
|
|
491
493
|
dir: path4.dirname(profilePath)
|
|
492
494
|
};
|
|
493
495
|
return profile;
|
|
@@ -601,6 +603,51 @@ function parseScripts(p, raw) {
|
|
|
601
603
|
postflight: parseScriptList(p, "postflight", r.postflight)
|
|
602
604
|
};
|
|
603
605
|
}
|
|
606
|
+
function parseInputArtifacts(p, raw) {
|
|
607
|
+
if (raw === void 0 || raw === null) return [];
|
|
608
|
+
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
609
|
+
throw new ProfileError(p, `"input" must be an object with an "artifacts" array`);
|
|
610
|
+
}
|
|
611
|
+
const list = raw.artifacts;
|
|
612
|
+
if (list === void 0 || list === null) return [];
|
|
613
|
+
if (!Array.isArray(list)) throw new ProfileError(p, `"input.artifacts" must be an array`);
|
|
614
|
+
const out = [];
|
|
615
|
+
for (const [i, item] of list.entries()) {
|
|
616
|
+
if (typeof item === "string") {
|
|
617
|
+
out.push({ name: item });
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
if (!item || typeof item !== "object") {
|
|
621
|
+
throw new ProfileError(p, `input.artifacts[${i}] must be a string or object`);
|
|
622
|
+
}
|
|
623
|
+
const r = item;
|
|
624
|
+
const name = requireString(p, r, "name");
|
|
625
|
+
const spec = { name };
|
|
626
|
+
if (typeof r.required === "boolean") spec.required = r.required;
|
|
627
|
+
out.push(spec);
|
|
628
|
+
}
|
|
629
|
+
return out;
|
|
630
|
+
}
|
|
631
|
+
function parseOutputArtifacts(p, raw) {
|
|
632
|
+
if (raw === void 0 || raw === null) return [];
|
|
633
|
+
if (typeof raw !== "object" || Array.isArray(raw)) return [];
|
|
634
|
+
const list = raw.artifacts;
|
|
635
|
+
if (list === void 0 || list === null) return [];
|
|
636
|
+
if (!Array.isArray(list)) throw new ProfileError(p, `"output.artifacts" must be an array`);
|
|
637
|
+
const out = [];
|
|
638
|
+
for (const [i, item] of list.entries()) {
|
|
639
|
+
if (!item || typeof item !== "object") {
|
|
640
|
+
throw new ProfileError(p, `output.artifacts[${i}] must be an object`);
|
|
641
|
+
}
|
|
642
|
+
const r = item;
|
|
643
|
+
out.push({
|
|
644
|
+
name: requireString(p, r, "name"),
|
|
645
|
+
format: typeof r.format === "string" ? r.format : "text",
|
|
646
|
+
from: requireString(p, r, "from")
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
return out;
|
|
650
|
+
}
|
|
604
651
|
function parseScriptList(p, key, raw) {
|
|
605
652
|
if (!Array.isArray(raw)) {
|
|
606
653
|
throw new ProfileError(p, `scripts.${key} must be an array`);
|
|
@@ -2126,6 +2173,7 @@ function emptyState() {
|
|
|
2126
2173
|
attempts: {}
|
|
2127
2174
|
},
|
|
2128
2175
|
executables: {},
|
|
2176
|
+
artifacts: {},
|
|
2129
2177
|
history: []
|
|
2130
2178
|
};
|
|
2131
2179
|
}
|
|
@@ -2172,6 +2220,7 @@ function parseStateComment(body) {
|
|
|
2172
2220
|
schemaVersion: 1,
|
|
2173
2221
|
core: { ...emptyState().core, ...parsed.core },
|
|
2174
2222
|
executables: parsed.executables ?? {},
|
|
2223
|
+
artifacts: parsed.artifacts && typeof parsed.artifacts === "object" ? parsed.artifacts : {},
|
|
2175
2224
|
history: Array.isArray(parsed.history) ? parsed.history : []
|
|
2176
2225
|
};
|
|
2177
2226
|
} catch {
|
|
@@ -2200,6 +2249,7 @@ function reduce(state, executable, action) {
|
|
|
2200
2249
|
phase: phaseFromAction(executable, action)
|
|
2201
2250
|
},
|
|
2202
2251
|
executables: newExecutables,
|
|
2252
|
+
artifacts: { ...state.artifacts ?? {} },
|
|
2203
2253
|
history: newHistory
|
|
2204
2254
|
};
|
|
2205
2255
|
}
|
|
@@ -2228,7 +2278,13 @@ function renderStateComment(state) {
|
|
|
2228
2278
|
lines.push("");
|
|
2229
2279
|
lines.push("```json");
|
|
2230
2280
|
lines.push(JSON.stringify(
|
|
2231
|
-
{
|
|
2281
|
+
{
|
|
2282
|
+
schemaVersion: state.schemaVersion,
|
|
2283
|
+
core: state.core,
|
|
2284
|
+
artifacts: state.artifacts ?? {},
|
|
2285
|
+
executables: state.executables,
|
|
2286
|
+
history: state.history
|
|
2287
|
+
},
|
|
2232
2288
|
null,
|
|
2233
2289
|
2
|
|
2234
2290
|
));
|
|
@@ -2249,6 +2305,10 @@ function renderStateComment(state) {
|
|
|
2249
2305
|
if (attempts) lines.push(`- **Attempts:** ${attempts}`);
|
|
2250
2306
|
if (state.core.prUrl) lines.push(`- **PR:** ${state.core.prUrl}`);
|
|
2251
2307
|
if (state.core.runUrl) lines.push(`- **Run:** ${state.core.runUrl}`);
|
|
2308
|
+
const artifactNames = Object.keys(state.artifacts ?? {});
|
|
2309
|
+
if (artifactNames.length > 0) {
|
|
2310
|
+
lines.push(`- **Artifacts:** ${artifactNames.map((n) => `\`${n}\``).join(", ")}`);
|
|
2311
|
+
}
|
|
2252
2312
|
lines.push("");
|
|
2253
2313
|
if (state.history.length > 0) {
|
|
2254
2314
|
lines.push("### Recent history");
|
|
@@ -2266,6 +2326,12 @@ function readTaskState(target, number, cwd) {
|
|
|
2266
2326
|
const existing = findStateComment(target, number, cwd);
|
|
2267
2327
|
return existing ? parseStateComment(existing.body) : emptyState();
|
|
2268
2328
|
}
|
|
2329
|
+
function setArtifact(state, name, artifact) {
|
|
2330
|
+
return {
|
|
2331
|
+
...state,
|
|
2332
|
+
artifacts: { ...state.artifacts ?? {}, [name]: artifact }
|
|
2333
|
+
};
|
|
2334
|
+
}
|
|
2269
2335
|
function writeTaskState(target, number, state, cwd) {
|
|
2270
2336
|
const body = renderStateComment(state);
|
|
2271
2337
|
const existing = findStateComment(target, number, cwd);
|
|
@@ -2329,6 +2395,35 @@ function makeAction(type, payload) {
|
|
|
2329
2395
|
return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
2330
2396
|
}
|
|
2331
2397
|
|
|
2398
|
+
// src/scripts/persistArtifacts.ts
|
|
2399
|
+
var persistArtifacts = async (ctx, profile) => {
|
|
2400
|
+
if (profile.outputArtifacts.length === 0) return;
|
|
2401
|
+
let state = ctx.data.taskState ?? emptyState();
|
|
2402
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2403
|
+
for (const spec of profile.outputArtifacts) {
|
|
2404
|
+
const content = readDottedString(ctx.data, spec.from);
|
|
2405
|
+
if (!content) continue;
|
|
2406
|
+
state = setArtifact(state, spec.name, {
|
|
2407
|
+
format: spec.format,
|
|
2408
|
+
producedBy: profile.name,
|
|
2409
|
+
createdAt: now,
|
|
2410
|
+
content
|
|
2411
|
+
});
|
|
2412
|
+
}
|
|
2413
|
+
ctx.data.taskState = state;
|
|
2414
|
+
};
|
|
2415
|
+
function readDottedString(source, dotted) {
|
|
2416
|
+
const parts = dotted.split(".");
|
|
2417
|
+
let cur = source;
|
|
2418
|
+
for (const p of parts) {
|
|
2419
|
+
if (cur === null || cur === void 0) return "";
|
|
2420
|
+
cur = cur[p];
|
|
2421
|
+
}
|
|
2422
|
+
if (typeof cur === "string") return cur;
|
|
2423
|
+
if (cur === null || cur === void 0) return "";
|
|
2424
|
+
return String(cur);
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2332
2427
|
// src/scripts/postIssueComment.ts
|
|
2333
2428
|
var postIssueComment2 = async (ctx) => {
|
|
2334
2429
|
if (ctx.skipAgent && ctx.output.exitCode !== void 0) return;
|
|
@@ -2384,6 +2479,28 @@ function postWith(type, n, body, cwd) {
|
|
|
2384
2479
|
}
|
|
2385
2480
|
}
|
|
2386
2481
|
|
|
2482
|
+
// src/scripts/postPlanComment.ts
|
|
2483
|
+
var postPlanComment = async (ctx) => {
|
|
2484
|
+
if (!ctx.data.agentDone) return;
|
|
2485
|
+
const targetType = ctx.data.commentTargetType;
|
|
2486
|
+
const targetNumber = Number(ctx.data.commentTargetNumber ?? 0);
|
|
2487
|
+
const plan = ctx.data.prSummary?.trim();
|
|
2488
|
+
if (targetType !== "issue" || !targetNumber || !plan) return;
|
|
2489
|
+
const body = renderPlanComment(targetNumber, plan);
|
|
2490
|
+
try {
|
|
2491
|
+
postIssueComment(targetNumber, body, ctx.cwd);
|
|
2492
|
+
} catch {
|
|
2493
|
+
}
|
|
2494
|
+
};
|
|
2495
|
+
function renderPlanComment(issueNumber, plan) {
|
|
2496
|
+
return `## Plan for issue #${issueNumber}
|
|
2497
|
+
|
|
2498
|
+
${plan}
|
|
2499
|
+
|
|
2500
|
+
---
|
|
2501
|
+
Comment \`@kody2 run\` to execute this plan.`;
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2387
2504
|
// src/scripts/postReviewResult.ts
|
|
2388
2505
|
function detectVerdict(body) {
|
|
2389
2506
|
const m = body.match(/##\s*Verdict\s*:\s*(PASS|CONCERNS|FAIL)\b/i);
|
|
@@ -2735,6 +2852,29 @@ ${truncate2(r.stderr, 2e3)}
|
|
|
2735
2852
|
`);
|
|
2736
2853
|
}
|
|
2737
2854
|
|
|
2855
|
+
// src/scripts/resolveArtifacts.ts
|
|
2856
|
+
var resolveArtifacts = async (ctx, profile) => {
|
|
2857
|
+
if (profile.inputArtifacts.length === 0) return;
|
|
2858
|
+
const state = ctx.data.taskState;
|
|
2859
|
+
const available = state?.artifacts ?? {};
|
|
2860
|
+
const resolved = {};
|
|
2861
|
+
const missing = [];
|
|
2862
|
+
for (const spec of profile.inputArtifacts) {
|
|
2863
|
+
const found = available[spec.name];
|
|
2864
|
+
if (found && typeof found.content === "string") {
|
|
2865
|
+
resolved[spec.name] = found.content;
|
|
2866
|
+
} else if (spec.required) {
|
|
2867
|
+
missing.push(spec.name);
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
ctx.data.artifacts = resolved;
|
|
2871
|
+
if (missing.length > 0) {
|
|
2872
|
+
ctx.skipAgent = true;
|
|
2873
|
+
ctx.output.exitCode = 64;
|
|
2874
|
+
ctx.output.reason = `required input artifacts missing from task state: ${missing.join(", ")}`;
|
|
2875
|
+
}
|
|
2876
|
+
};
|
|
2877
|
+
|
|
2738
2878
|
// src/scripts/resolveFlow.ts
|
|
2739
2879
|
import { execFileSync as execFileSync12 } from "child_process";
|
|
2740
2880
|
var CONFLICT_DIFF_MAX_BYTES = 4e4;
|
|
@@ -3208,6 +3348,7 @@ var preflightScripts = {
|
|
|
3208
3348
|
loadConventions,
|
|
3209
3349
|
loadCoverageRules,
|
|
3210
3350
|
buildSyntheticPlugin,
|
|
3351
|
+
resolveArtifacts,
|
|
3211
3352
|
composePrompt
|
|
3212
3353
|
};
|
|
3213
3354
|
var postflightScripts = {
|
|
@@ -3217,7 +3358,9 @@ var postflightScripts = {
|
|
|
3217
3358
|
commitAndPush: commitAndPush2,
|
|
3218
3359
|
ensurePr: ensurePr2,
|
|
3219
3360
|
postIssueComment: postIssueComment2,
|
|
3361
|
+
postPlanComment,
|
|
3220
3362
|
postReviewResult,
|
|
3363
|
+
persistArtifacts,
|
|
3221
3364
|
writeRunSummary,
|
|
3222
3365
|
saveTaskState
|
|
3223
3366
|
};
|
|
@@ -48,6 +48,12 @@
|
|
|
48
48
|
{
|
|
49
49
|
"script": "parseAgentResult"
|
|
50
50
|
},
|
|
51
|
+
{
|
|
52
|
+
"script": "persistArtifacts"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"script": "postPlanComment"
|
|
56
|
+
},
|
|
51
57
|
{
|
|
52
58
|
"script": "writeRunSummary"
|
|
53
59
|
},
|
|
@@ -60,6 +66,13 @@
|
|
|
60
66
|
"actionTypes": [
|
|
61
67
|
"PLAN_COMPLETED",
|
|
62
68
|
"PLAN_FAILED"
|
|
69
|
+
],
|
|
70
|
+
"artifacts": [
|
|
71
|
+
{
|
|
72
|
+
"name": "plan",
|
|
73
|
+
"format": "markdown",
|
|
74
|
+
"from": "prSummary"
|
|
75
|
+
}
|
|
63
76
|
]
|
|
64
77
|
}
|
|
65
78
|
}
|
|
@@ -39,6 +39,9 @@
|
|
|
39
39
|
{
|
|
40
40
|
"script": "loadTaskState"
|
|
41
41
|
},
|
|
42
|
+
{
|
|
43
|
+
"script": "resolveArtifacts"
|
|
44
|
+
},
|
|
42
45
|
{
|
|
43
46
|
"script": "loadConventions"
|
|
44
47
|
},
|
|
@@ -76,6 +79,11 @@
|
|
|
76
79
|
}
|
|
77
80
|
]
|
|
78
81
|
},
|
|
82
|
+
"input": {
|
|
83
|
+
"artifacts": [
|
|
84
|
+
{ "name": "plan", "required": false }
|
|
85
|
+
]
|
|
86
|
+
},
|
|
79
87
|
"output": {
|
|
80
88
|
"actionTypes": [
|
|
81
89
|
"RUN_COMPLETED",
|
|
@@ -7,6 +7,11 @@ You are Kody, an autonomous engineer. Take a GitHub issue from spec to a tested
|
|
|
7
7
|
{{conventionsBlock}}{{coverageBlock}}{{toolsUsage}}# Issue #{{issue.number}}: {{issue.title}}
|
|
8
8
|
{{issue.body}}
|
|
9
9
|
|
|
10
|
+
# Existing plan (produced by `@kody2 plan`, if present)
|
|
11
|
+
{{artifacts.plan}}
|
|
12
|
+
|
|
13
|
+
If the plan above is non-empty, TREAT IT AS AUTHORITATIVE — follow its file list and approach rather than inventing your own. Deviate only if the plan is wrong; if you do, say so explicitly. If the plan is empty, proceed from first principles.
|
|
14
|
+
|
|
10
15
|
# Required steps (all in this one session — no handoff)
|
|
11
16
|
1. **Research** — read the issue carefully. Use Grep/Glob/Read to investigate the codebase: locate relevant files, understand existing patterns, check related tests, identify constraints. Do not edit anything yet.
|
|
12
17
|
2. **Plan** — before any Edit/Write, output a short plan (5–10 lines): what files you'll change, the approach, what could go wrong. No fluff.
|
|
@@ -33,10 +33,39 @@ export interface Profile {
|
|
|
33
33
|
postflight: ScriptEntry[]
|
|
34
34
|
}
|
|
35
35
|
outputContract?: OutputContract
|
|
36
|
+
/**
|
|
37
|
+
* Declared artifacts consumed by this executable. The resolveArtifacts
|
|
38
|
+
* preflight loads each into ctx.data.artifacts[name] from the task-state
|
|
39
|
+
* comment. If `required: true` and the artifact is absent, the executable
|
|
40
|
+
* fails fast.
|
|
41
|
+
*/
|
|
42
|
+
inputArtifacts: InputArtifactSpec[]
|
|
43
|
+
/**
|
|
44
|
+
* Declared artifacts produced by this executable. The persistArtifacts
|
|
45
|
+
* postflight reads the named source field from ctx.data and writes an
|
|
46
|
+
* Artifact entry into the task-state comment's `artifacts` map.
|
|
47
|
+
*/
|
|
48
|
+
outputArtifacts: OutputArtifactSpec[]
|
|
36
49
|
/** Absolute directory the profile was loaded from. Used to resolve prompt.md. */
|
|
37
50
|
dir: string
|
|
38
51
|
}
|
|
39
52
|
|
|
53
|
+
export interface InputArtifactSpec {
|
|
54
|
+
/** Artifact name (the key in state.artifacts). */
|
|
55
|
+
name: string
|
|
56
|
+
/** If true, the executable fails when this artifact is missing from state. */
|
|
57
|
+
required?: boolean
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface OutputArtifactSpec {
|
|
61
|
+
/** Artifact name (the key in state.artifacts). */
|
|
62
|
+
name: string
|
|
63
|
+
/** Informational format tag ("markdown", "text", …). */
|
|
64
|
+
format: string
|
|
65
|
+
/** Dotted path into ctx.data to read the payload from (e.g. "prSummary"). */
|
|
66
|
+
from: string
|
|
67
|
+
}
|
|
68
|
+
|
|
40
69
|
export interface InputSpec {
|
|
41
70
|
name: string
|
|
42
71
|
flag: string
|
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.22",
|
|
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",
|