@kody-ade/kody-engine 0.2.10 → 0.2.12
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 +5 -4
- package/dist/bin/kody2.js +92 -131
- package/dist/executables/fix/profile.json +68 -0
- package/dist/executables/fix-ci/profile.json +68 -0
- package/dist/executables/orchestrator/profile.json +0 -1
- package/dist/executables/plan/profile.json +0 -1
- package/dist/executables/resolve/profile.json +59 -0
- package/dist/executables/run/profile.json +61 -0
- package/package.json +2 -2
- package/dist/executables/build/profile.json +0 -99
- package/dist/executables/orchestrator/prompts/orchestrator.md +0 -56
- package/dist/executables/plan/prompts/plan.md +0 -42
- /package/dist/executables/{build/prompts/fix.md → fix/prompt.md} +0 -0
- /package/dist/executables/{build/prompts/fix-ci.md → fix-ci/prompt.md} +0 -0
- /package/dist/executables/{build/prompts/resolve.md → resolve/prompt.md} +0 -0
- /package/dist/executables/{build/prompts/run.md → run/prompt.md} +0 -0
package/README.md
CHANGED
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
│ kody2 CLI (@kody-ade/kody-engine) │
|
|
14
14
|
│ bin/kody2.ts — parses argv │
|
|
15
15
|
│ src/executor.ts — runs one profile │
|
|
16
|
-
│ src/executables
|
|
16
|
+
│ src/executables/<name>/profile.json │
|
|
17
17
|
│ src/scripts/*.ts — named hook catalog │
|
|
18
18
|
└─────────────────────────────────────────────┘
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
`run
|
|
21
|
+
Every top-level command is its own auto-discovered executable (`run`, `fix`, `fix-ci`, `resolve`, `review`, `plan`, `orchestrator`, `release`, `watch-*`, `init`). The router has no hardcoded command switch beyond `ci`/`help`/`version` — drop a new `src/executables/<name>/` directory with a `profile.json` + `prompt.md` and `kody2 <name>` starts working. The executor knows nothing about any specific command.
|
|
22
22
|
|
|
23
23
|
## Install in a consumer repo
|
|
24
24
|
|
|
@@ -31,13 +31,14 @@
|
|
|
31
31
|
## Commands
|
|
32
32
|
|
|
33
33
|
```
|
|
34
|
-
kody2 run --issue <N>
|
|
34
|
+
kody2 run --issue <N> # implement an issue
|
|
35
35
|
kody2 fix --pr <N> [--feedback ...] # apply PR review feedback
|
|
36
36
|
kody2 fix-ci --pr <N> [--run-id <ID>] # fix failing CI
|
|
37
37
|
kody2 resolve --pr <N> # merge default branch in, resolve conflicts
|
|
38
|
+
kody2 review --pr <N> # read-only structured PR review
|
|
38
39
|
kody2 ci --issue <N> # CI preflight + run
|
|
39
40
|
```
|
|
40
41
|
|
|
41
42
|
## Profiles
|
|
42
43
|
|
|
43
|
-
A profile is declarative JSON + an adjacent prompt. See `src/executables
|
|
44
|
+
A profile is declarative JSON + an adjacent `prompt.md`. See any directory under `src/executables/` for examples. Adding a new command = new directory + profile + prompt + registering any new scripts under `src/scripts/`. No executor, entry, or dispatch changes.
|
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.12",
|
|
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",
|
|
@@ -17,7 +17,7 @@ var package_default = {
|
|
|
17
17
|
],
|
|
18
18
|
scripts: {
|
|
19
19
|
kody2: "tsx bin/kody2.ts",
|
|
20
|
-
build: `tsup && node -e "require('fs').cpSync('src/executables',
|
|
20
|
+
build: `tsup && node -e "const fs=require('fs');fs.rmSync('dist/executables',{recursive:true,force:true});fs.cpSync('src/executables','dist/executables',{recursive:true})"`,
|
|
21
21
|
test: "vitest run tests/unit tests/int --no-coverage",
|
|
22
22
|
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
23
23
|
"test:all": "vitest run tests --no-coverage",
|
|
@@ -49,6 +49,15 @@ var package_default = {
|
|
|
49
49
|
bugs: "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
// src/executor.ts
|
|
53
|
+
import * as fs13 from "fs";
|
|
54
|
+
import * as path11 from "path";
|
|
55
|
+
|
|
56
|
+
// src/agent.ts
|
|
57
|
+
import * as fs2 from "fs";
|
|
58
|
+
import * as path2 from "path";
|
|
59
|
+
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
60
|
+
|
|
52
61
|
// src/config.ts
|
|
53
62
|
import * as fs from "fs";
|
|
54
63
|
import * as path from "path";
|
|
@@ -151,15 +160,6 @@ function getAnthropicApiKeyOrDummy() {
|
|
|
151
160
|
return process.env.ANTHROPIC_API_KEY || `sk-ant-api03-${"0".repeat(64)}`;
|
|
152
161
|
}
|
|
153
162
|
|
|
154
|
-
// src/executor.ts
|
|
155
|
-
import * as fs13 from "fs";
|
|
156
|
-
import * as path11 from "path";
|
|
157
|
-
|
|
158
|
-
// src/agent.ts
|
|
159
|
-
import * as fs2 from "fs";
|
|
160
|
-
import * as path2 from "path";
|
|
161
|
-
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
162
|
-
|
|
163
163
|
// src/format.ts
|
|
164
164
|
function renderEvent(msg, opts = {}) {
|
|
165
165
|
if (opts.quiet) {
|
|
@@ -919,13 +919,14 @@ function hasCommitsAhead(branch, defaultBranch, cwd) {
|
|
|
919
919
|
}
|
|
920
920
|
|
|
921
921
|
// src/scripts/commitAndPush.ts
|
|
922
|
-
var commitAndPush2 = async (ctx) => {
|
|
922
|
+
var commitAndPush2 = async (ctx, profile) => {
|
|
923
923
|
const branch = ctx.data.branch;
|
|
924
924
|
if (!branch) {
|
|
925
925
|
ctx.data.commitResult = { committed: false, pushed: false };
|
|
926
926
|
return;
|
|
927
927
|
}
|
|
928
|
-
|
|
928
|
+
const kind = profile.name;
|
|
929
|
+
if (kind === "resolve") {
|
|
929
930
|
try {
|
|
930
931
|
execFileSync4("git", ["add", "-A"], { cwd: ctx.cwd, env: { ...process.env, HUSKY: "0" }, stdio: "pipe" });
|
|
931
932
|
} catch {
|
|
@@ -937,7 +938,7 @@ var commitAndPush2 = async (ctx) => {
|
|
|
937
938
|
`);
|
|
938
939
|
}
|
|
939
940
|
}
|
|
940
|
-
const fallbackMsg = defaultCommitMessage(
|
|
941
|
+
const fallbackMsg = defaultCommitMessage(kind, ctx.data);
|
|
941
942
|
const message = ctx.data.commitMessage || fallbackMsg;
|
|
942
943
|
try {
|
|
943
944
|
const result = commitAndPush(branch, message, ctx.cwd);
|
|
@@ -1724,11 +1725,11 @@ function parseGenericFlags(argv) {
|
|
|
1724
1725
|
}
|
|
1725
1726
|
const key = arg.slice(2);
|
|
1726
1727
|
const next = argv[i + 1];
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
args[
|
|
1728
|
+
const value = next !== void 0 && !next.startsWith("--") ? (i++, next) : true;
|
|
1729
|
+
args[key] = value;
|
|
1730
|
+
if (key.includes("-")) {
|
|
1731
|
+
const camel = key.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
1732
|
+
if (camel !== key && args[camel] === void 0) args[camel] = value;
|
|
1732
1733
|
}
|
|
1733
1734
|
}
|
|
1734
1735
|
if (positional.length > 0) args._ = positional;
|
|
@@ -2949,10 +2950,10 @@ var watchStalePrsFlow = async (ctx) => {
|
|
|
2949
2950
|
|
|
2950
2951
|
// src/scripts/writeRunSummary.ts
|
|
2951
2952
|
import * as fs12 from "fs";
|
|
2952
|
-
var writeRunSummary = async (ctx) => {
|
|
2953
|
+
var writeRunSummary = async (ctx, profile) => {
|
|
2953
2954
|
const summaryPath = process.env.GITHUB_STEP_SUMMARY;
|
|
2954
2955
|
if (!summaryPath) return;
|
|
2955
|
-
const
|
|
2956
|
+
const executable = profile.name;
|
|
2956
2957
|
const issue = ctx.args.issue;
|
|
2957
2958
|
const pr = ctx.args.pr;
|
|
2958
2959
|
const target = issue ? `issue #${issue}` : pr ? `PR #${pr}` : "(unknown)";
|
|
@@ -2961,9 +2962,9 @@ var writeRunSummary = async (ctx) => {
|
|
|
2961
2962
|
const reason = ctx.output.reason;
|
|
2962
2963
|
const status = exitCode === 0 ? "\u2705 success" : exitCode === 3 ? "\u23ED\uFE0F no-op" : "\u26A0\uFE0F failed";
|
|
2963
2964
|
const lines = [];
|
|
2964
|
-
lines.push(`## kody2
|
|
2965
|
+
lines.push(`## kody2 ${executable} \u2014 ${status}`);
|
|
2965
2966
|
lines.push("");
|
|
2966
|
-
lines.push(`- **
|
|
2967
|
+
lines.push(`- **Executable:** \`${executable}\``);
|
|
2967
2968
|
lines.push(`- **Target:** ${target}`);
|
|
2968
2969
|
if (prUrl) lines.push(`- **PR:** ${prUrl}`);
|
|
2969
2970
|
lines.push(`- **Exit code:** ${exitCode}`);
|
|
@@ -3068,7 +3069,24 @@ async function runExecutable(profileName, input) {
|
|
|
3068
3069
|
if (firstFail) {
|
|
3069
3070
|
return finish({ exitCode: 99, reason: `required CLI tool check failed: ${firstFail.error}` });
|
|
3070
3071
|
}
|
|
3071
|
-
|
|
3072
|
+
let config;
|
|
3073
|
+
if (input.config) {
|
|
3074
|
+
config = input.config;
|
|
3075
|
+
} else if (input.skipConfig) {
|
|
3076
|
+
config = {
|
|
3077
|
+
quality: { typecheck: "", lint: "", testUnit: "" },
|
|
3078
|
+
git: { defaultBranch: "main" },
|
|
3079
|
+
github: { owner: "", repo: "" },
|
|
3080
|
+
agent: { model: "claude/claude-haiku-4-5-20251001" }
|
|
3081
|
+
};
|
|
3082
|
+
} else {
|
|
3083
|
+
try {
|
|
3084
|
+
config = loadConfig(input.cwd);
|
|
3085
|
+
} catch (err) {
|
|
3086
|
+
return finish({ exitCode: 99, reason: `config error: ${err instanceof Error ? err.message : String(err)}` });
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
const modelSpec = profile.claudeCode.model === "inherit" ? config.agent.model : profile.claudeCode.model;
|
|
3072
3090
|
let model;
|
|
3073
3091
|
try {
|
|
3074
3092
|
model = parseProviderModel(modelSpec);
|
|
@@ -3087,7 +3105,7 @@ async function runExecutable(profileName, input) {
|
|
|
3087
3105
|
const ctx = {
|
|
3088
3106
|
args,
|
|
3089
3107
|
cwd: input.cwd,
|
|
3090
|
-
config
|
|
3108
|
+
config,
|
|
3091
3109
|
verbose: input.verbose,
|
|
3092
3110
|
quiet: input.quiet,
|
|
3093
3111
|
data: {},
|
|
@@ -3168,6 +3186,20 @@ function resolveProfilePath(profileName) {
|
|
|
3168
3186
|
}
|
|
3169
3187
|
function validateInputs(specs, raw) {
|
|
3170
3188
|
const out = {};
|
|
3189
|
+
const allowedKeys = /* @__PURE__ */ new Set(["_", "cwd", "verbose", "quiet"]);
|
|
3190
|
+
for (const spec of specs) {
|
|
3191
|
+
const flagKey = spec.flag.replace(/^--/, "");
|
|
3192
|
+
allowedKeys.add(spec.name);
|
|
3193
|
+
allowedKeys.add(flagKey);
|
|
3194
|
+
if (flagKey.includes("-")) {
|
|
3195
|
+
allowedKeys.add(flagKey.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase()));
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
for (const key of Object.keys(raw)) {
|
|
3199
|
+
if (!allowedKeys.has(key)) {
|
|
3200
|
+
throw new Error(`unknown arg: --${key}`);
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3171
3203
|
for (const spec of specs) {
|
|
3172
3204
|
const v = raw[spec.name];
|
|
3173
3205
|
if (v === void 0 || v === null) continue;
|
|
@@ -3250,8 +3282,8 @@ function autoDispatch(opts) {
|
|
|
3250
3282
|
const explicit = opts?.explicit;
|
|
3251
3283
|
if (explicit?.issueNumber && explicit.issueNumber > 0) {
|
|
3252
3284
|
return {
|
|
3253
|
-
executable: "
|
|
3254
|
-
cliArgs: {
|
|
3285
|
+
executable: "run",
|
|
3286
|
+
cliArgs: { issue: explicit.issueNumber },
|
|
3255
3287
|
target: explicit.issueNumber
|
|
3256
3288
|
};
|
|
3257
3289
|
}
|
|
@@ -3267,7 +3299,7 @@ function autoDispatch(opts) {
|
|
|
3267
3299
|
if (eventName === "workflow_dispatch") {
|
|
3268
3300
|
const n = parseInt(String(event.inputs?.issue_number ?? ""), 10);
|
|
3269
3301
|
if (!Number.isNaN(n) && n > 0) {
|
|
3270
|
-
return { executable: "
|
|
3302
|
+
return { executable: "run", cliArgs: { issue: n }, target: n };
|
|
3271
3303
|
}
|
|
3272
3304
|
return null;
|
|
3273
3305
|
}
|
|
@@ -3279,35 +3311,35 @@ function autoDispatch(opts) {
|
|
|
3279
3311
|
const afterTag = extractAfterTag(body);
|
|
3280
3312
|
if (isPr) {
|
|
3281
3313
|
if (/\bfix-ci\b/.test(afterTag)) {
|
|
3282
|
-
return { executable: "
|
|
3314
|
+
return { executable: "fix-ci", cliArgs: { pr: targetNum }, target: targetNum };
|
|
3283
3315
|
}
|
|
3284
3316
|
if (/\bresolve\b/.test(afterTag)) {
|
|
3285
|
-
return { executable: "
|
|
3317
|
+
return { executable: "resolve", cliArgs: { pr: targetNum }, target: targetNum };
|
|
3318
|
+
}
|
|
3319
|
+
if (/\breview\b/.test(afterTag)) {
|
|
3320
|
+
return { executable: "review", cliArgs: { pr: targetNum }, target: targetNum };
|
|
3286
3321
|
}
|
|
3287
3322
|
const feedback = extractFeedback(afterTag);
|
|
3288
3323
|
return {
|
|
3289
|
-
executable: "
|
|
3290
|
-
cliArgs: {
|
|
3324
|
+
executable: "fix",
|
|
3325
|
+
cliArgs: { pr: targetNum, ...feedback ? { feedback } : {} },
|
|
3291
3326
|
target: targetNum
|
|
3292
3327
|
};
|
|
3293
3328
|
}
|
|
3294
3329
|
const sub = extractSubcommand(afterTag);
|
|
3295
|
-
const defaultExec = opts?.config?.defaultExecutable ?? "
|
|
3330
|
+
const defaultExec = opts?.config?.defaultExecutable ?? "run";
|
|
3296
3331
|
if (!sub) {
|
|
3297
3332
|
return asDispatch(defaultExec, targetNum);
|
|
3298
3333
|
}
|
|
3299
|
-
if (sub === "build") {
|
|
3300
|
-
return { executable: "build", cliArgs: { mode: "run", issue: targetNum }, target: targetNum };
|
|
3301
|
-
}
|
|
3302
3334
|
if (sub === "orchestrate" || sub === "orchestrator") {
|
|
3303
3335
|
return { executable: "orchestrator", cliArgs: { issue: targetNum }, target: targetNum };
|
|
3304
3336
|
}
|
|
3337
|
+
if (sub === "build") {
|
|
3338
|
+
return { executable: "run", cliArgs: { issue: targetNum }, target: targetNum };
|
|
3339
|
+
}
|
|
3305
3340
|
return asDispatch(sub, targetNum);
|
|
3306
3341
|
}
|
|
3307
3342
|
function asDispatch(executable, target) {
|
|
3308
|
-
if (executable === "build") {
|
|
3309
|
-
return { executable, cliArgs: { mode: "run", issue: target }, target };
|
|
3310
|
-
}
|
|
3311
3343
|
return { executable, cliArgs: { issue: target }, target };
|
|
3312
3344
|
}
|
|
3313
3345
|
function extractAfterTag(body) {
|
|
@@ -3537,8 +3569,8 @@ ${CI_HELP}`);
|
|
|
3537
3569
|
return 64;
|
|
3538
3570
|
}
|
|
3539
3571
|
const dispatch = autoFallback ?? {
|
|
3540
|
-
executable: "
|
|
3541
|
-
cliArgs: {
|
|
3572
|
+
executable: "run",
|
|
3573
|
+
cliArgs: { issue: args.issueNumber },
|
|
3542
3574
|
target: args.issueNumber
|
|
3543
3575
|
};
|
|
3544
3576
|
const issueNumber = dispatch.target;
|
|
@@ -3610,16 +3642,19 @@ ${CI_HELP}`);
|
|
|
3610
3642
|
var HELP_TEXT = `kody2 \u2014 single-session autonomous engineer
|
|
3611
3643
|
|
|
3612
3644
|
Usage:
|
|
3613
|
-
kody2 run --issue <N> [--cwd <path>] [--verbose|--quiet]
|
|
3614
|
-
kody2 ci --issue <N> [preflight flags \u2014 see: kody2 ci --help]
|
|
3645
|
+
kody2 run --issue <N> [--cwd <path>] [--verbose|--quiet]
|
|
3615
3646
|
kody2 fix --pr <N> [--feedback "..."] [--cwd <path>] [--verbose|--quiet]
|
|
3616
3647
|
kody2 fix-ci --pr <N> [--run-id <ID>] [--cwd <path>] [--verbose|--quiet]
|
|
3617
3648
|
kody2 resolve --pr <N> [--cwd <path>] [--verbose|--quiet]
|
|
3649
|
+
kody2 review --pr <N> [--cwd <path>] [--verbose|--quiet]
|
|
3650
|
+
kody2 <other> [--cwd <path>] [--verbose|--quiet]
|
|
3651
|
+
kody2 ci --issue <N> [preflight flags \u2014 see: kody2 ci --help]
|
|
3618
3652
|
kody2 help
|
|
3619
3653
|
kody2 version
|
|
3620
3654
|
|
|
3621
|
-
|
|
3622
|
-
executable
|
|
3655
|
+
Each top-level command (run, fix, fix-ci, resolve, review, \u2026) is a discovered
|
|
3656
|
+
executable under \`src/executables/<name>/profile.json\`. Drop in a new
|
|
3657
|
+
directory to add a new command.
|
|
3623
3658
|
|
|
3624
3659
|
Exit codes:
|
|
3625
3660
|
0 success (PR opened, verify passed \u2014 or resolve produced a merge commit)
|
|
@@ -3640,11 +3675,6 @@ function parseArgs(argv) {
|
|
|
3640
3675
|
if (cmd === "ci") {
|
|
3641
3676
|
return { ...result, command: "ci", ciArgv: argv.slice(1) };
|
|
3642
3677
|
}
|
|
3643
|
-
if (cmd === "run" || cmd === "fix" || cmd === "fix-ci" || cmd === "resolve") {
|
|
3644
|
-
result.command = cmd;
|
|
3645
|
-
parseCommandArgs(cmd, argv.slice(1), result);
|
|
3646
|
-
return result;
|
|
3647
|
-
}
|
|
3648
3678
|
if (hasExecutable(cmd)) {
|
|
3649
3679
|
result.command = "__executable__";
|
|
3650
3680
|
result.executableName = cmd;
|
|
@@ -3654,38 +3684,11 @@ function parseArgs(argv) {
|
|
|
3654
3684
|
if (result.cliArgs.quiet === true) result.quiet = true;
|
|
3655
3685
|
return result;
|
|
3656
3686
|
}
|
|
3657
|
-
const discovered = listExecutables().map((e) => e.name)
|
|
3658
|
-
const available = ["
|
|
3687
|
+
const discovered = listExecutables().map((e) => e.name);
|
|
3688
|
+
const available = ["ci", "help", "version", ...discovered];
|
|
3659
3689
|
result.errors.push(`unknown command: ${cmd} (available: ${available.join(", ")})`);
|
|
3660
3690
|
return result;
|
|
3661
3691
|
}
|
|
3662
|
-
function parseCommandArgs(cmd, rest, result) {
|
|
3663
|
-
for (let i = 0; i < rest.length; i++) {
|
|
3664
|
-
const arg = rest[i];
|
|
3665
|
-
if (arg === "--issue") {
|
|
3666
|
-
const n = parseInt(rest[++i] ?? "", 10);
|
|
3667
|
-
if (Number.isNaN(n) || n <= 0) result.errors.push("--issue requires a positive integer");
|
|
3668
|
-
else result.issueNumber = n;
|
|
3669
|
-
} else if (arg === "--pr") {
|
|
3670
|
-
const n = parseInt(rest[++i] ?? "", 10);
|
|
3671
|
-
if (Number.isNaN(n) || n <= 0) result.errors.push("--pr requires a positive integer");
|
|
3672
|
-
else result.prNumber = n;
|
|
3673
|
-
} else if (arg === "--feedback") {
|
|
3674
|
-
result.feedback = rest[++i];
|
|
3675
|
-
} else if (arg === "--run-id") {
|
|
3676
|
-
result.runId = rest[++i];
|
|
3677
|
-
} else if (arg === "--cwd") {
|
|
3678
|
-
result.cwd = rest[++i];
|
|
3679
|
-
} else if (arg === "--verbose") result.verbose = true;
|
|
3680
|
-
else if (arg === "--quiet") result.quiet = true;
|
|
3681
|
-
else if (arg === "--dry-run") result.dryRun = true;
|
|
3682
|
-
else result.errors.push(`unknown arg: ${arg}`);
|
|
3683
|
-
}
|
|
3684
|
-
if (cmd === "run" && !result.issueNumber) result.errors.push("--issue <N> is required for run");
|
|
3685
|
-
if (cmd === "fix" && !result.prNumber) result.errors.push("--pr <N> is required for fix");
|
|
3686
|
-
if (cmd === "fix-ci" && !result.prNumber) result.errors.push("--pr <N> is required for fix-ci");
|
|
3687
|
-
if (cmd === "resolve" && !result.prNumber) result.errors.push("--pr <N> is required for resolve");
|
|
3688
|
-
}
|
|
3689
3692
|
async function main(argv = process.argv.slice(2)) {
|
|
3690
3693
|
const args = parseArgs(argv);
|
|
3691
3694
|
if (args.errors.length > 0) {
|
|
@@ -3718,69 +3721,27 @@ ${HELP_TEXT}`);
|
|
|
3718
3721
|
}
|
|
3719
3722
|
const cwd = args.cwd ?? process.cwd();
|
|
3720
3723
|
const configlessCommands = /* @__PURE__ */ new Set(["init"]);
|
|
3721
|
-
const
|
|
3722
|
-
let config;
|
|
3723
|
-
if (needsConfig) {
|
|
3724
|
-
try {
|
|
3725
|
-
config = loadConfig(cwd);
|
|
3726
|
-
} catch (err) {
|
|
3727
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
3728
|
-
process.stderr.write(`[kody2] config error: ${msg}
|
|
3729
|
-
`);
|
|
3730
|
-
process.stdout.write(`PR_URL=FAILED: config error: ${msg}
|
|
3731
|
-
`);
|
|
3732
|
-
return 99;
|
|
3733
|
-
}
|
|
3734
|
-
} else {
|
|
3735
|
-
config = {
|
|
3736
|
-
quality: { typecheck: "", lint: "", testUnit: "" },
|
|
3737
|
-
git: { defaultBranch: "main" },
|
|
3738
|
-
github: { owner: "", repo: "" },
|
|
3739
|
-
agent: { model: "claude/claude-haiku-4-5-20251001" }
|
|
3740
|
-
};
|
|
3741
|
-
}
|
|
3742
|
-
if (args.command === "__executable__") {
|
|
3743
|
-
try {
|
|
3744
|
-
const result = await runExecutable(args.executableName, {
|
|
3745
|
-
cliArgs: args.cliArgs ?? {},
|
|
3746
|
-
cwd,
|
|
3747
|
-
config,
|
|
3748
|
-
verbose: args.verbose,
|
|
3749
|
-
quiet: args.quiet
|
|
3750
|
-
});
|
|
3751
|
-
return result.exitCode;
|
|
3752
|
-
} catch (err) {
|
|
3753
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
3754
|
-
process.stderr.write(`[kody2] ${args.executableName} crashed: ${msg}
|
|
3755
|
-
`);
|
|
3756
|
-
if (err instanceof Error && err.stack) process.stderr.write(`${err.stack}
|
|
3757
|
-
`);
|
|
3758
|
-
process.stdout.write(`PR_URL=FAILED: ${args.executableName} crashed: ${msg}
|
|
3759
|
-
`);
|
|
3760
|
-
return 99;
|
|
3761
|
-
}
|
|
3762
|
-
}
|
|
3763
|
-
const cliArgs = { mode: args.command };
|
|
3764
|
-
if (args.issueNumber !== void 0) cliArgs.issue = args.issueNumber;
|
|
3765
|
-
if (args.prNumber !== void 0) cliArgs.pr = args.prNumber;
|
|
3766
|
-
if (args.feedback !== void 0) cliArgs.feedback = args.feedback;
|
|
3767
|
-
if (args.runId !== void 0) cliArgs.runId = args.runId;
|
|
3724
|
+
const skipConfig = configlessCommands.has(args.executableName ?? "");
|
|
3768
3725
|
try {
|
|
3769
|
-
const result = await runExecutable(
|
|
3770
|
-
cliArgs,
|
|
3726
|
+
const result = await runExecutable(args.executableName, {
|
|
3727
|
+
cliArgs: args.cliArgs ?? {},
|
|
3771
3728
|
cwd,
|
|
3772
|
-
|
|
3729
|
+
skipConfig,
|
|
3773
3730
|
verbose: args.verbose,
|
|
3774
3731
|
quiet: args.quiet
|
|
3775
3732
|
});
|
|
3733
|
+
if (result.exitCode !== 0 && result.reason) {
|
|
3734
|
+
process.stderr.write(`error: ${result.reason}
|
|
3735
|
+
`);
|
|
3736
|
+
}
|
|
3776
3737
|
return result.exitCode;
|
|
3777
3738
|
} catch (err) {
|
|
3778
3739
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3779
|
-
process.stderr.write(`[kody2]
|
|
3740
|
+
process.stderr.write(`[kody2] ${args.executableName} crashed: ${msg}
|
|
3780
3741
|
`);
|
|
3781
3742
|
if (err instanceof Error && err.stack) process.stderr.write(`${err.stack}
|
|
3782
3743
|
`);
|
|
3783
|
-
process.stdout.write(`PR_URL=FAILED:
|
|
3744
|
+
process.stdout.write(`PR_URL=FAILED: ${args.executableName} crashed: ${msg}
|
|
3784
3745
|
`);
|
|
3785
3746
|
return 99;
|
|
3786
3747
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fix",
|
|
3
|
+
"describe": "Apply review feedback to an existing PR branch.",
|
|
4
|
+
|
|
5
|
+
"inputs": [
|
|
6
|
+
{
|
|
7
|
+
"name": "pr",
|
|
8
|
+
"flag": "--pr",
|
|
9
|
+
"type": "int",
|
|
10
|
+
"required": true,
|
|
11
|
+
"describe": "GitHub PR number to apply feedback to."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "feedback",
|
|
15
|
+
"flag": "--feedback",
|
|
16
|
+
"type": "string",
|
|
17
|
+
"required": false,
|
|
18
|
+
"describe": "Inline override. If absent, the flow reads the latest PR review comment."
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
|
|
22
|
+
"claudeCode": {
|
|
23
|
+
"model": "inherit",
|
|
24
|
+
"permissionMode": "acceptEdits",
|
|
25
|
+
"maxTurns": null,
|
|
26
|
+
"systemPromptAppend": null,
|
|
27
|
+
"tools": ["Read", "Write", "Edit", "Bash", "Grep", "Glob"],
|
|
28
|
+
"hooks": {
|
|
29
|
+
"PreToolUse": [],
|
|
30
|
+
"PostToolUse": [],
|
|
31
|
+
"Stop": []
|
|
32
|
+
},
|
|
33
|
+
"skills": [],
|
|
34
|
+
"commands": [],
|
|
35
|
+
"subagents": [],
|
|
36
|
+
"plugins": [],
|
|
37
|
+
"mcpServers": []
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
"cliTools": [],
|
|
41
|
+
|
|
42
|
+
"scripts": {
|
|
43
|
+
"preflight": [
|
|
44
|
+
{ "script": "fixFlow" },
|
|
45
|
+
{ "script": "loadTaskState" },
|
|
46
|
+
{ "script": "loadConventions" },
|
|
47
|
+
{ "script": "loadCoverageRules" },
|
|
48
|
+
{ "script": "composePrompt" }
|
|
49
|
+
],
|
|
50
|
+
"postflight": [
|
|
51
|
+
{ "script": "parseAgentResult" },
|
|
52
|
+
{ "script": "verify" },
|
|
53
|
+
{ "script": "checkCoverageWithRetry" },
|
|
54
|
+
{ "script": "commitAndPush" },
|
|
55
|
+
{ "script": "ensurePr" },
|
|
56
|
+
{ "script": "postIssueComment" },
|
|
57
|
+
{ "script": "writeRunSummary" },
|
|
58
|
+
{ "script": "saveTaskState" }
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
"output": {
|
|
62
|
+
"actionTypes": [
|
|
63
|
+
"FIX_COMPLETED",
|
|
64
|
+
"FIX_FAILED",
|
|
65
|
+
"AGENT_NOT_RUN"
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fix-ci",
|
|
3
|
+
"describe": "Fix a failing CI workflow on an existing PR.",
|
|
4
|
+
|
|
5
|
+
"inputs": [
|
|
6
|
+
{
|
|
7
|
+
"name": "pr",
|
|
8
|
+
"flag": "--pr",
|
|
9
|
+
"type": "int",
|
|
10
|
+
"required": true,
|
|
11
|
+
"describe": "GitHub PR number whose CI is failing."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "runId",
|
|
15
|
+
"flag": "--run-id",
|
|
16
|
+
"type": "string",
|
|
17
|
+
"required": false,
|
|
18
|
+
"describe": "Specific failed workflow run ID. Defaults to latest failed run on the PR branch."
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
|
|
22
|
+
"claudeCode": {
|
|
23
|
+
"model": "inherit",
|
|
24
|
+
"permissionMode": "acceptEdits",
|
|
25
|
+
"maxTurns": null,
|
|
26
|
+
"systemPromptAppend": null,
|
|
27
|
+
"tools": ["Read", "Write", "Edit", "Bash", "Grep", "Glob"],
|
|
28
|
+
"hooks": {
|
|
29
|
+
"PreToolUse": [],
|
|
30
|
+
"PostToolUse": [],
|
|
31
|
+
"Stop": []
|
|
32
|
+
},
|
|
33
|
+
"skills": [],
|
|
34
|
+
"commands": [],
|
|
35
|
+
"subagents": [],
|
|
36
|
+
"plugins": [],
|
|
37
|
+
"mcpServers": []
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
"cliTools": [],
|
|
41
|
+
|
|
42
|
+
"scripts": {
|
|
43
|
+
"preflight": [
|
|
44
|
+
{ "script": "fixCiFlow" },
|
|
45
|
+
{ "script": "loadTaskState" },
|
|
46
|
+
{ "script": "loadConventions" },
|
|
47
|
+
{ "script": "loadCoverageRules" },
|
|
48
|
+
{ "script": "composePrompt" }
|
|
49
|
+
],
|
|
50
|
+
"postflight": [
|
|
51
|
+
{ "script": "parseAgentResult" },
|
|
52
|
+
{ "script": "verify" },
|
|
53
|
+
{ "script": "checkCoverageWithRetry" },
|
|
54
|
+
{ "script": "commitAndPush" },
|
|
55
|
+
{ "script": "ensurePr" },
|
|
56
|
+
{ "script": "postIssueComment" },
|
|
57
|
+
{ "script": "writeRunSummary" },
|
|
58
|
+
{ "script": "saveTaskState" }
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
"output": {
|
|
62
|
+
"actionTypes": [
|
|
63
|
+
"FIX_CI_COMPLETED",
|
|
64
|
+
"FIX_CI_FAILED",
|
|
65
|
+
"AGENT_NOT_RUN"
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "resolve",
|
|
3
|
+
"describe": "Resolve merge conflicts between a PR branch and the default branch.",
|
|
4
|
+
|
|
5
|
+
"inputs": [
|
|
6
|
+
{
|
|
7
|
+
"name": "pr",
|
|
8
|
+
"flag": "--pr",
|
|
9
|
+
"type": "int",
|
|
10
|
+
"required": true,
|
|
11
|
+
"describe": "GitHub PR number whose branch has conflicts with the default branch."
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
|
|
15
|
+
"claudeCode": {
|
|
16
|
+
"model": "inherit",
|
|
17
|
+
"permissionMode": "acceptEdits",
|
|
18
|
+
"maxTurns": null,
|
|
19
|
+
"systemPromptAppend": null,
|
|
20
|
+
"tools": ["Read", "Write", "Edit", "Bash", "Grep", "Glob"],
|
|
21
|
+
"hooks": {
|
|
22
|
+
"PreToolUse": [],
|
|
23
|
+
"PostToolUse": [],
|
|
24
|
+
"Stop": []
|
|
25
|
+
},
|
|
26
|
+
"skills": [],
|
|
27
|
+
"commands": [],
|
|
28
|
+
"subagents": [],
|
|
29
|
+
"plugins": [],
|
|
30
|
+
"mcpServers": []
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
"cliTools": [],
|
|
34
|
+
|
|
35
|
+
"scripts": {
|
|
36
|
+
"preflight": [
|
|
37
|
+
{ "script": "resolveFlow" },
|
|
38
|
+
{ "script": "loadTaskState" },
|
|
39
|
+
{ "script": "loadConventions" },
|
|
40
|
+
{ "script": "loadCoverageRules" },
|
|
41
|
+
{ "script": "composePrompt" }
|
|
42
|
+
],
|
|
43
|
+
"postflight": [
|
|
44
|
+
{ "script": "parseAgentResult" },
|
|
45
|
+
{ "script": "commitAndPush" },
|
|
46
|
+
{ "script": "ensurePr" },
|
|
47
|
+
{ "script": "postIssueComment" },
|
|
48
|
+
{ "script": "writeRunSummary" },
|
|
49
|
+
{ "script": "saveTaskState" }
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"output": {
|
|
53
|
+
"actionTypes": [
|
|
54
|
+
"RESOLVE_COMPLETED",
|
|
55
|
+
"RESOLVE_FAILED",
|
|
56
|
+
"AGENT_NOT_RUN"
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "run",
|
|
3
|
+
"describe": "Implement a GitHub issue end-to-end: branch, code, commit, open PR.",
|
|
4
|
+
|
|
5
|
+
"inputs": [
|
|
6
|
+
{
|
|
7
|
+
"name": "issue",
|
|
8
|
+
"flag": "--issue",
|
|
9
|
+
"type": "int",
|
|
10
|
+
"required": true,
|
|
11
|
+
"describe": "GitHub issue number to implement."
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
|
|
15
|
+
"claudeCode": {
|
|
16
|
+
"model": "inherit",
|
|
17
|
+
"permissionMode": "acceptEdits",
|
|
18
|
+
"maxTurns": null,
|
|
19
|
+
"systemPromptAppend": null,
|
|
20
|
+
"tools": ["Read", "Write", "Edit", "Bash", "Grep", "Glob"],
|
|
21
|
+
"hooks": {
|
|
22
|
+
"PreToolUse": [],
|
|
23
|
+
"PostToolUse": [],
|
|
24
|
+
"Stop": []
|
|
25
|
+
},
|
|
26
|
+
"skills": [],
|
|
27
|
+
"commands": [],
|
|
28
|
+
"subagents": [],
|
|
29
|
+
"plugins": [],
|
|
30
|
+
"mcpServers": []
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
"cliTools": [],
|
|
34
|
+
|
|
35
|
+
"scripts": {
|
|
36
|
+
"preflight": [
|
|
37
|
+
{ "script": "runFlow" },
|
|
38
|
+
{ "script": "loadTaskState" },
|
|
39
|
+
{ "script": "loadConventions" },
|
|
40
|
+
{ "script": "loadCoverageRules" },
|
|
41
|
+
{ "script": "composePrompt" }
|
|
42
|
+
],
|
|
43
|
+
"postflight": [
|
|
44
|
+
{ "script": "parseAgentResult" },
|
|
45
|
+
{ "script": "verify" },
|
|
46
|
+
{ "script": "checkCoverageWithRetry" },
|
|
47
|
+
{ "script": "commitAndPush" },
|
|
48
|
+
{ "script": "ensurePr" },
|
|
49
|
+
{ "script": "postIssueComment" },
|
|
50
|
+
{ "script": "writeRunSummary" },
|
|
51
|
+
{ "script": "saveTaskState" }
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"output": {
|
|
55
|
+
"actionTypes": [
|
|
56
|
+
"RUN_COMPLETED",
|
|
57
|
+
"RUN_FAILED",
|
|
58
|
+
"AGENT_NOT_RUN"
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
}
|
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.12",
|
|
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",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
|
|
35
35
|
"scripts": {
|
|
36
36
|
"kody2": "tsx bin/kody2.ts",
|
|
37
|
-
"build": "tsup && node -e \"require('fs').cpSync('src/executables',
|
|
37
|
+
"build": "tsup && node -e \"const fs=require('fs');fs.rmSync('dist/executables',{recursive:true,force:true});fs.cpSync('src/executables','dist/executables',{recursive:true})\"",
|
|
38
38
|
"test": "vitest run tests/unit tests/int --no-coverage",
|
|
39
39
|
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
40
40
|
"test:all": "vitest run tests --no-coverage",
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "build",
|
|
3
|
-
"describe": "Implement a GitHub issue or apply PR feedback end-to-end.",
|
|
4
|
-
|
|
5
|
-
"inputs": [
|
|
6
|
-
{
|
|
7
|
-
"name": "mode",
|
|
8
|
-
"flag": "--mode",
|
|
9
|
-
"type": "enum",
|
|
10
|
-
"values": ["run", "fix", "fix-ci", "resolve"],
|
|
11
|
-
"required": true,
|
|
12
|
-
"describe": "Which Build mode to run."
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"name": "issue",
|
|
16
|
-
"flag": "--issue",
|
|
17
|
-
"type": "int",
|
|
18
|
-
"requiredWhen": { "mode": "run" },
|
|
19
|
-
"describe": "GitHub issue number to implement."
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
"name": "pr",
|
|
23
|
-
"flag": "--pr",
|
|
24
|
-
"type": "int",
|
|
25
|
-
"requiredWhen": { "mode": ["fix", "fix-ci", "resolve"] },
|
|
26
|
-
"describe": "GitHub PR number to operate on."
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"name": "feedback",
|
|
30
|
-
"flag": "--feedback",
|
|
31
|
-
"type": "string",
|
|
32
|
-
"required": false,
|
|
33
|
-
"describe": "Inline override for fix mode. If absent, the executor reads the latest PR review comment."
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
"name": "runId",
|
|
37
|
-
"flag": "--run-id",
|
|
38
|
-
"type": "string",
|
|
39
|
-
"required": false,
|
|
40
|
-
"describe": "Specific failed workflow run ID for fix-ci. Defaults to latest failed run on the PR branch."
|
|
41
|
-
}
|
|
42
|
-
],
|
|
43
|
-
|
|
44
|
-
"claudeCode": {
|
|
45
|
-
"model": "inherit",
|
|
46
|
-
"permissionMode": "acceptEdits",
|
|
47
|
-
"maxTurns": null,
|
|
48
|
-
"systemPromptAppend": null,
|
|
49
|
-
"tools": ["Read", "Write", "Edit", "Bash", "Grep", "Glob"],
|
|
50
|
-
"hooks": {
|
|
51
|
-
"PreToolUse": [],
|
|
52
|
-
"PostToolUse": [],
|
|
53
|
-
"Stop": []
|
|
54
|
-
},
|
|
55
|
-
"skills": [],
|
|
56
|
-
"commands": [],
|
|
57
|
-
"subagents": [],
|
|
58
|
-
"plugins": [],
|
|
59
|
-
"mcpServers": []
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
"cliTools": [],
|
|
63
|
-
|
|
64
|
-
"scripts": {
|
|
65
|
-
"preflight": [
|
|
66
|
-
{ "script": "runFlow", "runWhen": { "args.mode": "run" } },
|
|
67
|
-
{ "script": "fixFlow", "runWhen": { "args.mode": "fix" } },
|
|
68
|
-
{ "script": "fixCiFlow", "runWhen": { "args.mode": "fix-ci" } },
|
|
69
|
-
{ "script": "resolveFlow", "runWhen": { "args.mode": "resolve" } },
|
|
70
|
-
{ "script": "loadTaskState" },
|
|
71
|
-
{ "script": "loadConventions" },
|
|
72
|
-
{ "script": "loadCoverageRules" },
|
|
73
|
-
{ "script": "composePrompt" }
|
|
74
|
-
],
|
|
75
|
-
"postflight": [
|
|
76
|
-
{ "script": "parseAgentResult" },
|
|
77
|
-
{ "script": "verify", "runWhen": { "args.mode": ["run", "fix", "fix-ci"] } },
|
|
78
|
-
{ "script": "checkCoverageWithRetry", "runWhen": { "args.mode": ["run", "fix", "fix-ci"] } },
|
|
79
|
-
{ "script": "commitAndPush" },
|
|
80
|
-
{ "script": "ensurePr" },
|
|
81
|
-
{ "script": "postIssueComment" },
|
|
82
|
-
{ "script": "writeRunSummary" },
|
|
83
|
-
{ "script": "saveTaskState" }
|
|
84
|
-
]
|
|
85
|
-
},
|
|
86
|
-
"output": {
|
|
87
|
-
"actionTypes": [
|
|
88
|
-
"RUN_COMPLETED",
|
|
89
|
-
"RUN_FAILED",
|
|
90
|
-
"FIX_COMPLETED",
|
|
91
|
-
"FIX_FAILED",
|
|
92
|
-
"FIX_CI_COMPLETED",
|
|
93
|
-
"FIX_CI_FAILED",
|
|
94
|
-
"RESOLVE_COMPLETED",
|
|
95
|
-
"RESOLVE_FAILED",
|
|
96
|
-
"AGENT_NOT_RUN"
|
|
97
|
-
]
|
|
98
|
-
}
|
|
99
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
You are the **kody2 orchestrator** for issue #{{issue.number}} on {{repoOwner}}/{{repoName}}.
|
|
2
|
-
|
|
3
|
-
Your job: drive a 2-step flow **plan → build** by posting `@kody2 <subcommand>` comments on the issue and watching the state-comment for completion signals. You do NOT edit files. You do NOT run git. You use `gh` (via Bash) only to post comments and read the state-comment.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Issue #{{issue.number}}: {{issue.title}}
|
|
8
|
-
|
|
9
|
-
{{issue.body}}
|
|
10
|
-
|
|
11
|
-
# Required flow (plan-then-build)
|
|
12
|
-
|
|
13
|
-
1. **Kick off plan.** Post an issue comment with EXACTLY this body:
|
|
14
|
-
```
|
|
15
|
-
@kody2 plan
|
|
16
|
-
```
|
|
17
|
-
Use: `gh issue comment {{issue.number}} --body "@kody2 plan"` (in the cwd).
|
|
18
|
-
2. **Wait for plan to complete.** Poll the issue's state-comment every ~30s. The state-comment is the one whose body starts with `<!-- kody2:state:v1:begin -->`. Fetch it with:
|
|
19
|
-
```
|
|
20
|
-
gh api repos/{{repoOwner}}/{{repoName}}/issues/{{issue.number}}/comments --paginate --jq '.[] | select(.body | contains("kody2:state:v1:begin")) | .body'
|
|
21
|
-
```
|
|
22
|
-
Parse the JSON block inside the sentinels. Look for `core.lastOutcome.type == "PLAN_COMPLETED"`.
|
|
23
|
-
If `core.lastOutcome.type == "PLAN_FAILED"` OR if 10 minutes pass without completion → abort with:
|
|
24
|
-
```
|
|
25
|
-
FAILED: plan did not complete (<reason from state or "timeout">)
|
|
26
|
-
```
|
|
27
|
-
3. **Kick off build.** Post:
|
|
28
|
-
```
|
|
29
|
-
@kody2 build
|
|
30
|
-
```
|
|
31
|
-
Same `gh issue comment` command.
|
|
32
|
-
4. **Wait for build to complete.** Same poll technique. Look for `core.lastOutcome.type == "RUN_COMPLETED"` (build's success marker) or `RUN_FAILED`. If `RUN_FAILED` or 30 minutes pass → abort with `FAILED: build did not complete (...)`.
|
|
33
|
-
5. **Emit final summary.**
|
|
34
|
-
|
|
35
|
-
# Required final output
|
|
36
|
-
|
|
37
|
-
On success:
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
DONE
|
|
41
|
-
COMMIT_MSG: chore(orchestrator): plan-then-build for #{{issue.number}}
|
|
42
|
-
PR_SUMMARY:
|
|
43
|
-
- Posted `@kody2 plan` and observed PLAN_COMPLETED.
|
|
44
|
-
- Posted `@kody2 build` and observed RUN_COMPLETED.
|
|
45
|
-
- Final PR: <prUrl from state>
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
On failure, a single line: `FAILED: <concrete reason>`.
|
|
49
|
-
|
|
50
|
-
# Rules
|
|
51
|
-
|
|
52
|
-
- NEVER edit files. Read-only flow.
|
|
53
|
-
- NEVER run git. Only `gh` via Bash for comment posting and state polling.
|
|
54
|
-
- Between polls, sleep ~30 seconds. Do NOT poll faster than once every 30 seconds.
|
|
55
|
-
- Hard cap: 40 turns total across the whole flow. If you're approaching the cap, fail early with `FAILED: turn budget exhausted`.
|
|
56
|
-
- If you post an `@kody2` comment and the state-comment does NOT update within the poll window, the child executable likely didn't run — check the GitHub Actions runs tab URL via `gh run list --limit 5 --json conclusion,status,url` to diagnose, then fail with a concrete reason.
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
You are a senior engineer producing an **implementation plan** for the GitHub issue below. You will NOT write code. You will NOT run git or gh commands. You will NOT modify files. Your only outputs are:
|
|
2
|
-
|
|
3
|
-
1. Use Read / Grep / Glob / Bash (read-only) to study the codebase as much as needed.
|
|
4
|
-
2. Emit a final message with the plan wrapped in the required markers (see "Required output").
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Repo
|
|
9
|
-
- {{repoOwner}}/{{repoName}}, default branch: {{defaultBranch}}
|
|
10
|
-
|
|
11
|
-
# Issue #{{issue.number}}: {{issue.title}}
|
|
12
|
-
|
|
13
|
-
{{issue.body}}
|
|
14
|
-
|
|
15
|
-
Recent comments (most recent first, truncated):
|
|
16
|
-
{{issue.commentsFormatted}}
|
|
17
|
-
|
|
18
|
-
{{conventionsBlock}}
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
# Required output
|
|
23
|
-
|
|
24
|
-
Your FINAL message must be exactly this shape (no extra text before or after):
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
DONE
|
|
28
|
-
COMMIT_MSG: plan: <very short title>
|
|
29
|
-
PR_SUMMARY:
|
|
30
|
-
<A concrete implementation plan in markdown. Include:
|
|
31
|
-
- Files to change (with paths), and the change in each.
|
|
32
|
-
- New files to create, with their purpose and rough shape.
|
|
33
|
-
- Any ambiguities that need the human to resolve first.
|
|
34
|
-
- Verification checklist (typecheck / tests / lint expectations).
|
|
35
|
-
Keep to ~60 lines or less. No filler. No marketing language.>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
# Rules
|
|
39
|
-
- Read-only. Do NOT modify any file.
|
|
40
|
-
- Do NOT run git or gh commands.
|
|
41
|
-
- No speculative scope — plan only what the issue asks for.
|
|
42
|
-
- If the issue is ambiguous and you cannot make progress without input, output `FAILED: <what's unclear>` instead of a plan.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|