@kody-ade/kody-engine 0.2.19 → 0.2.21
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.21",
|
|
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;
|
|
@@ -2735,6 +2830,29 @@ ${truncate2(r.stderr, 2e3)}
|
|
|
2735
2830
|
`);
|
|
2736
2831
|
}
|
|
2737
2832
|
|
|
2833
|
+
// src/scripts/resolveArtifacts.ts
|
|
2834
|
+
var resolveArtifacts = async (ctx, profile) => {
|
|
2835
|
+
if (profile.inputArtifacts.length === 0) return;
|
|
2836
|
+
const state = ctx.data.taskState;
|
|
2837
|
+
const available = state?.artifacts ?? {};
|
|
2838
|
+
const resolved = {};
|
|
2839
|
+
const missing = [];
|
|
2840
|
+
for (const spec of profile.inputArtifacts) {
|
|
2841
|
+
const found = available[spec.name];
|
|
2842
|
+
if (found && typeof found.content === "string") {
|
|
2843
|
+
resolved[spec.name] = found.content;
|
|
2844
|
+
} else if (spec.required) {
|
|
2845
|
+
missing.push(spec.name);
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
ctx.data.artifacts = resolved;
|
|
2849
|
+
if (missing.length > 0) {
|
|
2850
|
+
ctx.skipAgent = true;
|
|
2851
|
+
ctx.output.exitCode = 64;
|
|
2852
|
+
ctx.output.reason = `required input artifacts missing from task state: ${missing.join(", ")}`;
|
|
2853
|
+
}
|
|
2854
|
+
};
|
|
2855
|
+
|
|
2738
2856
|
// src/scripts/resolveFlow.ts
|
|
2739
2857
|
import { execFileSync as execFileSync12 } from "child_process";
|
|
2740
2858
|
var CONFLICT_DIFF_MAX_BYTES = 4e4;
|
|
@@ -2912,6 +3030,94 @@ function synthesizeAction(ctx) {
|
|
|
2912
3030
|
};
|
|
2913
3031
|
}
|
|
2914
3032
|
|
|
3033
|
+
// src/scripts/syncFlow.ts
|
|
3034
|
+
import { execFileSync as execFileSync13 } from "child_process";
|
|
3035
|
+
var syncFlow = async (ctx) => {
|
|
3036
|
+
ctx.skipAgent = true;
|
|
3037
|
+
const prNumber = ctx.args.pr;
|
|
3038
|
+
const pr = getPr(prNumber, ctx.cwd);
|
|
3039
|
+
if (pr.state !== "OPEN") {
|
|
3040
|
+
bail2(ctx, prNumber, `PR #${prNumber} is not OPEN (state: ${pr.state})`);
|
|
3041
|
+
return;
|
|
3042
|
+
}
|
|
3043
|
+
ctx.data.pr = pr;
|
|
3044
|
+
ctx.data.commentTargetType = "pr";
|
|
3045
|
+
ctx.data.commentTargetNumber = prNumber;
|
|
3046
|
+
checkoutPrBranch(prNumber, ctx.cwd);
|
|
3047
|
+
ctx.data.branch = getCurrentBranch(ctx.cwd);
|
|
3048
|
+
const baseBranch = pr.baseRefName || ctx.config.git.defaultBranch;
|
|
3049
|
+
ctx.data.baseBranch = baseBranch;
|
|
3050
|
+
const headBefore = revParseHead(ctx.cwd);
|
|
3051
|
+
const mergeStatus = mergeBase(baseBranch, ctx.cwd);
|
|
3052
|
+
if (mergeStatus === "error") {
|
|
3053
|
+
bail2(ctx, prNumber, `failed to merge origin/${baseBranch} (non-conflict error); see runner log`);
|
|
3054
|
+
return;
|
|
3055
|
+
}
|
|
3056
|
+
if (mergeStatus === "conflict") {
|
|
3057
|
+
bail2(
|
|
3058
|
+
ctx,
|
|
3059
|
+
prNumber,
|
|
3060
|
+
`merge from origin/${baseBranch} produced conflicts \u2014 run \`@kody2 resolve\` to let kody2 resolve them`
|
|
3061
|
+
);
|
|
3062
|
+
return;
|
|
3063
|
+
}
|
|
3064
|
+
const headAfter = revParseHead(ctx.cwd);
|
|
3065
|
+
if (headAfter === headBefore) {
|
|
3066
|
+
ctx.output.exitCode = 0;
|
|
3067
|
+
ctx.output.reason = `already up to date with origin/${baseBranch}`;
|
|
3068
|
+
tryPostPr5(prNumber, `\u2139\uFE0F kody2 sync: already up to date with origin/${baseBranch}`, ctx.cwd);
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
3071
|
+
try {
|
|
3072
|
+
pushBranch(ctx.data.branch, ctx.cwd);
|
|
3073
|
+
} catch (err) {
|
|
3074
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3075
|
+
bail2(ctx, prNumber, `merge succeeded but push failed: ${msg}`);
|
|
3076
|
+
return;
|
|
3077
|
+
}
|
|
3078
|
+
ctx.output.exitCode = 0;
|
|
3079
|
+
ctx.output.reason = `merged origin/${baseBranch} into ${ctx.data.branch}`;
|
|
3080
|
+
const runUrl = getRunUrl();
|
|
3081
|
+
const runSuffix = runUrl ? ` ([logs](${runUrl}))` : "";
|
|
3082
|
+
tryPostPr5(
|
|
3083
|
+
prNumber,
|
|
3084
|
+
`\u2705 kody2 sync: merged \`origin/${baseBranch}\` into \`${ctx.data.branch}\`${runSuffix}`,
|
|
3085
|
+
ctx.cwd
|
|
3086
|
+
);
|
|
3087
|
+
};
|
|
3088
|
+
function bail2(ctx, prNumber, reason) {
|
|
3089
|
+
ctx.output.exitCode = 1;
|
|
3090
|
+
ctx.output.reason = reason;
|
|
3091
|
+
const runUrl = getRunUrl();
|
|
3092
|
+
const runSuffix = runUrl ? ` ([logs](${runUrl}))` : "";
|
|
3093
|
+
tryPostPr5(prNumber, `\u274C kody2 sync could not complete${runSuffix}: ${reason}`, ctx.cwd);
|
|
3094
|
+
}
|
|
3095
|
+
function revParseHead(cwd) {
|
|
3096
|
+
try {
|
|
3097
|
+
return execFileSync13("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
|
|
3098
|
+
} catch {
|
|
3099
|
+
return "";
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
function pushBranch(branch, cwd) {
|
|
3103
|
+
const env = { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" };
|
|
3104
|
+
try {
|
|
3105
|
+
execFileSync13("git", ["push", "-u", "origin", branch], { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
|
|
3106
|
+
} catch {
|
|
3107
|
+
execFileSync13("git", ["push", "--force-with-lease", "-u", "origin", branch], {
|
|
3108
|
+
cwd,
|
|
3109
|
+
env,
|
|
3110
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3111
|
+
});
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
function tryPostPr5(prNumber, body, cwd) {
|
|
3115
|
+
try {
|
|
3116
|
+
postPrReviewComment(prNumber, body, cwd);
|
|
3117
|
+
} catch {
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
|
|
2915
3121
|
// src/verify.ts
|
|
2916
3122
|
import { spawn as spawn2 } from "child_process";
|
|
2917
3123
|
var TAIL_CHARS = 4e3;
|
|
@@ -3111,6 +3317,7 @@ var preflightScripts = {
|
|
|
3111
3317
|
fixCiFlow,
|
|
3112
3318
|
resolveFlow,
|
|
3113
3319
|
reviewFlow,
|
|
3320
|
+
syncFlow,
|
|
3114
3321
|
initFlow,
|
|
3115
3322
|
releaseFlow,
|
|
3116
3323
|
watchStalePrsFlow,
|
|
@@ -3119,6 +3326,7 @@ var preflightScripts = {
|
|
|
3119
3326
|
loadConventions,
|
|
3120
3327
|
loadCoverageRules,
|
|
3121
3328
|
buildSyntheticPlugin,
|
|
3329
|
+
resolveArtifacts,
|
|
3122
3330
|
composePrompt
|
|
3123
3331
|
};
|
|
3124
3332
|
var postflightScripts = {
|
|
@@ -3129,6 +3337,7 @@ var postflightScripts = {
|
|
|
3129
3337
|
ensurePr: ensurePr2,
|
|
3130
3338
|
postIssueComment: postIssueComment2,
|
|
3131
3339
|
postReviewResult,
|
|
3340
|
+
persistArtifacts,
|
|
3132
3341
|
writeRunSummary,
|
|
3133
3342
|
saveTaskState
|
|
3134
3343
|
};
|
|
@@ -3138,7 +3347,7 @@ var allScriptNames = /* @__PURE__ */ new Set([
|
|
|
3138
3347
|
]);
|
|
3139
3348
|
|
|
3140
3349
|
// src/tools.ts
|
|
3141
|
-
import { execFileSync as
|
|
3350
|
+
import { execFileSync as execFileSync14 } from "child_process";
|
|
3142
3351
|
function verifyCliTools(tools, cwd) {
|
|
3143
3352
|
const out = [];
|
|
3144
3353
|
for (const t of tools) out.push(verifyOne(t, cwd));
|
|
@@ -3171,7 +3380,7 @@ function verifyOne(tool, cwd) {
|
|
|
3171
3380
|
}
|
|
3172
3381
|
function runShell2(cmd, cwd, timeoutMs = 3e4) {
|
|
3173
3382
|
try {
|
|
3174
|
-
|
|
3383
|
+
execFileSync14("sh", ["-c", cmd], { cwd, stdio: "pipe", timeout: timeoutMs });
|
|
3175
3384
|
return true;
|
|
3176
3385
|
} catch {
|
|
3177
3386
|
return false;
|
|
@@ -3409,7 +3618,7 @@ function finish(out) {
|
|
|
3409
3618
|
}
|
|
3410
3619
|
|
|
3411
3620
|
// src/kody2-cli.ts
|
|
3412
|
-
import { execFileSync as
|
|
3621
|
+
import { execFileSync as execFileSync15 } from "child_process";
|
|
3413
3622
|
import * as fs16 from "fs";
|
|
3414
3623
|
import * as path13 from "path";
|
|
3415
3624
|
|
|
@@ -3456,6 +3665,9 @@ function autoDispatch(opts) {
|
|
|
3456
3665
|
if (/\breview\b/.test(afterTag)) {
|
|
3457
3666
|
return { executable: "review", cliArgs: { pr: targetNum }, target: targetNum };
|
|
3458
3667
|
}
|
|
3668
|
+
if (/\bsync\b/.test(afterTag)) {
|
|
3669
|
+
return { executable: "sync", cliArgs: { pr: targetNum }, target: targetNum };
|
|
3670
|
+
}
|
|
3459
3671
|
const feedback = extractFeedback(afterTag);
|
|
3460
3672
|
return {
|
|
3461
3673
|
executable: "fix",
|
|
@@ -3586,7 +3798,7 @@ function detectPackageManager2(cwd) {
|
|
|
3586
3798
|
}
|
|
3587
3799
|
function shellOut(cmd, args, cwd, stream = true) {
|
|
3588
3800
|
try {
|
|
3589
|
-
|
|
3801
|
+
execFileSync15(cmd, args, {
|
|
3590
3802
|
cwd,
|
|
3591
3803
|
stdio: stream ? "inherit" : "pipe",
|
|
3592
3804
|
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" }
|
|
@@ -3599,7 +3811,7 @@ function shellOut(cmd, args, cwd, stream = true) {
|
|
|
3599
3811
|
}
|
|
3600
3812
|
function isOnPath(bin) {
|
|
3601
3813
|
try {
|
|
3602
|
-
|
|
3814
|
+
execFileSync15("which", [bin], { stdio: "pipe" });
|
|
3603
3815
|
return true;
|
|
3604
3816
|
} catch {
|
|
3605
3817
|
return false;
|
|
@@ -3633,7 +3845,7 @@ function installLitellmIfNeeded(cwd) {
|
|
|
3633
3845
|
} catch {
|
|
3634
3846
|
}
|
|
3635
3847
|
try {
|
|
3636
|
-
|
|
3848
|
+
execFileSync15("python3", ["-c", "import litellm"], { stdio: "pipe" });
|
|
3637
3849
|
process.stdout.write("\u2192 kody2: litellm already installed\n");
|
|
3638
3850
|
return 0;
|
|
3639
3851
|
} catch {
|
|
@@ -3643,16 +3855,16 @@ function installLitellmIfNeeded(cwd) {
|
|
|
3643
3855
|
}
|
|
3644
3856
|
function configureGitIdentity(cwd) {
|
|
3645
3857
|
try {
|
|
3646
|
-
const name =
|
|
3858
|
+
const name = execFileSync15("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
|
|
3647
3859
|
if (name) return;
|
|
3648
3860
|
} catch {
|
|
3649
3861
|
}
|
|
3650
3862
|
try {
|
|
3651
|
-
|
|
3863
|
+
execFileSync15("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
|
|
3652
3864
|
} catch {
|
|
3653
3865
|
}
|
|
3654
3866
|
try {
|
|
3655
|
-
|
|
3867
|
+
execFileSync15("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
|
|
3656
3868
|
cwd,
|
|
3657
3869
|
stdio: "pipe"
|
|
3658
3870
|
});
|
|
@@ -48,6 +48,9 @@
|
|
|
48
48
|
{
|
|
49
49
|
"script": "parseAgentResult"
|
|
50
50
|
},
|
|
51
|
+
{
|
|
52
|
+
"script": "persistArtifacts"
|
|
53
|
+
},
|
|
51
54
|
{
|
|
52
55
|
"script": "writeRunSummary"
|
|
53
56
|
},
|
|
@@ -60,6 +63,13 @@
|
|
|
60
63
|
"actionTypes": [
|
|
61
64
|
"PLAN_COMPLETED",
|
|
62
65
|
"PLAN_FAILED"
|
|
66
|
+
],
|
|
67
|
+
"artifacts": [
|
|
68
|
+
{
|
|
69
|
+
"name": "plan",
|
|
70
|
+
"format": "markdown",
|
|
71
|
+
"from": "prSummary"
|
|
72
|
+
}
|
|
63
73
|
]
|
|
64
74
|
}
|
|
65
75
|
}
|
|
@@ -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.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sync",
|
|
3
|
+
"describe": "Merge the default (base) branch into a PR branch and push. No agent.",
|
|
4
|
+
"inputs": [
|
|
5
|
+
{
|
|
6
|
+
"name": "pr",
|
|
7
|
+
"flag": "--pr",
|
|
8
|
+
"type": "int",
|
|
9
|
+
"required": true,
|
|
10
|
+
"describe": "GitHub PR number to update from its base branch."
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"claudeCode": {
|
|
14
|
+
"model": "inherit",
|
|
15
|
+
"permissionMode": "acceptEdits",
|
|
16
|
+
"maxTurns": null,
|
|
17
|
+
"systemPromptAppend": null,
|
|
18
|
+
"tools": [],
|
|
19
|
+
"hooks": [],
|
|
20
|
+
"skills": [],
|
|
21
|
+
"commands": [],
|
|
22
|
+
"subagents": [],
|
|
23
|
+
"plugins": [],
|
|
24
|
+
"mcpServers": []
|
|
25
|
+
},
|
|
26
|
+
"cliTools": [],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"preflight": [
|
|
29
|
+
{
|
|
30
|
+
"script": "syncFlow"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"postflight": []
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -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.21",
|
|
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",
|