@kody-ade/kody-engine-lite 0.1.79 → 0.1.81
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/cli.js +247 -35
- package/package.json +1 -1
- package/templates/kody.yml +3 -2
package/dist/bin/cli.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
4
|
var __esm = (fn, res) => function __init() {
|
|
4
5
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
6
|
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
6
11
|
|
|
7
12
|
// src/agent-runner.ts
|
|
8
13
|
import { spawn, execFileSync } from "child_process";
|
|
@@ -439,6 +444,41 @@ function syncWithDefault(cwd) {
|
|
|
439
444
|
logger.warn(` Merge conflict with origin/${defaultBranch} \u2014 skipping sync`);
|
|
440
445
|
}
|
|
441
446
|
}
|
|
447
|
+
function mergeDefault(cwd) {
|
|
448
|
+
const defaultBranch = getDefaultBranch(cwd);
|
|
449
|
+
const current = getCurrentBranch(cwd);
|
|
450
|
+
if (current === defaultBranch) return "clean";
|
|
451
|
+
try {
|
|
452
|
+
git(["fetch", "origin", defaultBranch], { cwd, timeout: 3e4 });
|
|
453
|
+
} catch {
|
|
454
|
+
logger.warn(" Failed to fetch latest from origin");
|
|
455
|
+
return "error";
|
|
456
|
+
}
|
|
457
|
+
try {
|
|
458
|
+
git(["merge", `origin/${defaultBranch}`, "--no-edit"], { cwd, timeout: 3e4 });
|
|
459
|
+
logger.info(` Merged origin/${defaultBranch} cleanly`);
|
|
460
|
+
return "clean";
|
|
461
|
+
} catch {
|
|
462
|
+
try {
|
|
463
|
+
const unmerged = git(["diff", "--name-only", "--diff-filter=U"], { cwd });
|
|
464
|
+
if (unmerged.trim()) return "conflict";
|
|
465
|
+
} catch {
|
|
466
|
+
}
|
|
467
|
+
try {
|
|
468
|
+
git(["merge", "--abort"], { cwd });
|
|
469
|
+
} catch {
|
|
470
|
+
}
|
|
471
|
+
return "error";
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
function getConflictedFiles(cwd) {
|
|
475
|
+
try {
|
|
476
|
+
const output = git(["diff", "--name-only", "--diff-filter=U"], { cwd });
|
|
477
|
+
return output ? output.split("\n") : [];
|
|
478
|
+
} catch {
|
|
479
|
+
return [];
|
|
480
|
+
}
|
|
481
|
+
}
|
|
442
482
|
function commitAll(message, cwd) {
|
|
443
483
|
const status = git(["status", "--porcelain"], { cwd });
|
|
444
484
|
if (!status) {
|
|
@@ -2920,8 +2960,16 @@ If no pipeline flaw is detected, set "pipelineFlaw" to null.
|
|
|
2920
2960
|
import * as fs15 from "fs";
|
|
2921
2961
|
import * as path15 from "path";
|
|
2922
2962
|
function ensureFeatureBranchIfNeeded(ctx) {
|
|
2923
|
-
if (ctx.input.
|
|
2924
|
-
if (
|
|
2963
|
+
if (ctx.input.dryRun) return;
|
|
2964
|
+
if (ctx.input.prNumber) {
|
|
2965
|
+
try {
|
|
2966
|
+
syncWithDefault(ctx.projectDir);
|
|
2967
|
+
} catch (err) {
|
|
2968
|
+
logger.warn(` Failed to sync with default branch: ${err}`);
|
|
2969
|
+
}
|
|
2970
|
+
return;
|
|
2971
|
+
}
|
|
2972
|
+
if (!ctx.input.issueNumber) return;
|
|
2925
2973
|
try {
|
|
2926
2974
|
const taskMdPath = path15.join(ctx.taskDir, "task.md");
|
|
2927
2975
|
const title = fs15.existsSync(taskMdPath) ? fs15.readFileSync(taskMdPath, "utf-8").split("\n")[0].slice(0, 50) : ctx.taskId;
|
|
@@ -3346,12 +3394,13 @@ function parseArgs() {
|
|
|
3346
3394
|
kody fix --task-id <id> [--cwd <path>] [--issue-number <n>] [--feedback "<text>"]
|
|
3347
3395
|
kody fix-ci [--pr-number <n>] [--ci-run-id <id>] [--cwd <path>] [--issue-number <n>] [--feedback "<text>"]
|
|
3348
3396
|
kody review [--pr-number <n>] [--issue-number <n>] [--cwd <path>] [--local]
|
|
3397
|
+
kody resolve --pr-number <n> [--cwd <path>] [--local]
|
|
3349
3398
|
kody status --task-id <id> [--cwd <path>]
|
|
3350
3399
|
kody --help`);
|
|
3351
3400
|
process.exit(0);
|
|
3352
3401
|
}
|
|
3353
3402
|
const command2 = args2[0];
|
|
3354
|
-
if (!["run", "rerun", "fix", "fix-ci", "status", "review"].includes(command2)) {
|
|
3403
|
+
if (!["run", "rerun", "fix", "fix-ci", "status", "review", "resolve"].includes(command2)) {
|
|
3355
3404
|
console.error(`Unknown command: ${command2}`);
|
|
3356
3405
|
process.exit(1);
|
|
3357
3406
|
}
|
|
@@ -3584,6 +3633,133 @@ var init_task_state = __esm({
|
|
|
3584
3633
|
}
|
|
3585
3634
|
});
|
|
3586
3635
|
|
|
3636
|
+
// src/resolve.ts
|
|
3637
|
+
var resolve_exports = {};
|
|
3638
|
+
__export(resolve_exports, {
|
|
3639
|
+
runResolve: () => runResolve
|
|
3640
|
+
});
|
|
3641
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
3642
|
+
function getConflictContext(cwd, files) {
|
|
3643
|
+
const parts = [];
|
|
3644
|
+
for (const file of files.slice(0, 10)) {
|
|
3645
|
+
try {
|
|
3646
|
+
const content = execFileSync11("git", ["diff", file], {
|
|
3647
|
+
cwd,
|
|
3648
|
+
encoding: "utf-8",
|
|
3649
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
3650
|
+
}).trim();
|
|
3651
|
+
parts.push(`### ${file}
|
|
3652
|
+
\`\`\`diff
|
|
3653
|
+
${content.slice(0, 3e3)}
|
|
3654
|
+
\`\`\``);
|
|
3655
|
+
} catch {
|
|
3656
|
+
parts.push(`### ${file}
|
|
3657
|
+
(could not read diff)`);
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
3660
|
+
return parts.join("\n\n");
|
|
3661
|
+
}
|
|
3662
|
+
async function runResolve(options) {
|
|
3663
|
+
const { prNumber, projectDir, runners, local } = options;
|
|
3664
|
+
const defaultBranch = getDefaultBranch(projectDir);
|
|
3665
|
+
logger.info(`Resolving PR #${prNumber} \u2014 merging ${defaultBranch}...`);
|
|
3666
|
+
const mergeResult = mergeDefault(projectDir);
|
|
3667
|
+
if (mergeResult === "error") {
|
|
3668
|
+
return { outcome: "failed", error: "Failed to merge default branch" };
|
|
3669
|
+
}
|
|
3670
|
+
if (mergeResult === "clean") {
|
|
3671
|
+
logger.info(" Clean merge \u2014 no conflicts");
|
|
3672
|
+
if (!local) {
|
|
3673
|
+
pushBranch(projectDir);
|
|
3674
|
+
}
|
|
3675
|
+
return { outcome: "merged" };
|
|
3676
|
+
}
|
|
3677
|
+
const conflictedFiles = getConflictedFiles(projectDir);
|
|
3678
|
+
if (conflictedFiles.length === 0) {
|
|
3679
|
+
return { outcome: "failed", error: "Merge reported conflict but no conflicted files found" };
|
|
3680
|
+
}
|
|
3681
|
+
logger.info(` ${conflictedFiles.length} conflicted file(s): ${conflictedFiles.join(", ")}`);
|
|
3682
|
+
const conflictContext = getConflictContext(projectDir, conflictedFiles);
|
|
3683
|
+
const prompt = buildResolvePrompt(conflictedFiles, conflictContext, defaultBranch);
|
|
3684
|
+
const config = getProjectConfig();
|
|
3685
|
+
const runnerName = config.agent.defaultRunner ?? Object.keys(runners)[0] ?? "claude";
|
|
3686
|
+
const runner = runners[runnerName];
|
|
3687
|
+
if (!runner) {
|
|
3688
|
+
return { outcome: "failed", error: `Runner "${runnerName}" not found` };
|
|
3689
|
+
}
|
|
3690
|
+
const model = resolveModel("mid");
|
|
3691
|
+
const extraEnv = {};
|
|
3692
|
+
if (needsLitellmProxy(config)) {
|
|
3693
|
+
extraEnv.ANTHROPIC_BASE_URL = getLitellmUrl();
|
|
3694
|
+
}
|
|
3695
|
+
logger.info(` Running agent to resolve conflicts (model=${model})...`);
|
|
3696
|
+
const result = await runner.run("resolve", prompt, model, 3e5, projectDir, {
|
|
3697
|
+
cwd: projectDir,
|
|
3698
|
+
env: extraEnv
|
|
3699
|
+
});
|
|
3700
|
+
if (result.outcome !== "completed") {
|
|
3701
|
+
return { outcome: "failed", error: `Agent failed: ${result.error}` };
|
|
3702
|
+
}
|
|
3703
|
+
logger.info(" Verifying resolution...");
|
|
3704
|
+
const verify = runQualityGates(projectDir, projectDir);
|
|
3705
|
+
if (!verify.pass) {
|
|
3706
|
+
const errorSummary = verify.errors.slice(0, 5).join("\n");
|
|
3707
|
+
logger.error(` Verification failed:
|
|
3708
|
+
${errorSummary}`);
|
|
3709
|
+
return { outcome: "failed", error: `Conflict resolution failed verification:
|
|
3710
|
+
${errorSummary}` };
|
|
3711
|
+
}
|
|
3712
|
+
logger.info(" Verification passed");
|
|
3713
|
+
commitAll(`chore: resolve merge conflicts with ${defaultBranch}`, projectDir);
|
|
3714
|
+
if (!local) {
|
|
3715
|
+
pushBranch(projectDir);
|
|
3716
|
+
try {
|
|
3717
|
+
const fileList = conflictedFiles.map((f) => `- \`${f}\``).join("\n");
|
|
3718
|
+
postPRComment(
|
|
3719
|
+
prNumber,
|
|
3720
|
+
`\u2705 **Merge conflicts resolved** with \`${defaultBranch}\`
|
|
3721
|
+
|
|
3722
|
+
**Conflicted files:**
|
|
3723
|
+
${fileList}
|
|
3724
|
+
|
|
3725
|
+
_Verification passed. Please review the resolution._`
|
|
3726
|
+
);
|
|
3727
|
+
} catch {
|
|
3728
|
+
}
|
|
3729
|
+
}
|
|
3730
|
+
return { outcome: "resolved" };
|
|
3731
|
+
}
|
|
3732
|
+
function buildResolvePrompt(files, conflictContext, defaultBranch) {
|
|
3733
|
+
return `You are resolving merge conflicts between a feature branch and the \`${defaultBranch}\` branch.
|
|
3734
|
+
|
|
3735
|
+
## Conflicted files
|
|
3736
|
+
${files.map((f) => `- ${f}`).join("\n")}
|
|
3737
|
+
|
|
3738
|
+
## Conflict diffs
|
|
3739
|
+
${conflictContext}
|
|
3740
|
+
|
|
3741
|
+
## Instructions
|
|
3742
|
+
1. Read each conflicted file
|
|
3743
|
+
2. Resolve the conflict markers (<<<<<<< / ======= / >>>>>>>) by combining both sides correctly:
|
|
3744
|
+
- For feature/business logic: preserve the PR branch's intent
|
|
3745
|
+
- For infrastructure/config/dependencies: prefer the \`${defaultBranch}\` branch
|
|
3746
|
+
- For imports/types: merge both sides
|
|
3747
|
+
3. Write the resolved file using the Edit or Write tool
|
|
3748
|
+
4. Do NOT add new features or refactor \u2014 only resolve the conflicts
|
|
3749
|
+
5. After resolving all files, run \`git add .\` to stage the resolution`;
|
|
3750
|
+
}
|
|
3751
|
+
var init_resolve = __esm({
|
|
3752
|
+
"src/resolve.ts"() {
|
|
3753
|
+
"use strict";
|
|
3754
|
+
init_git_utils();
|
|
3755
|
+
init_github_api();
|
|
3756
|
+
init_verify_runner();
|
|
3757
|
+
init_logger();
|
|
3758
|
+
init_context();
|
|
3759
|
+
init_config();
|
|
3760
|
+
}
|
|
3761
|
+
});
|
|
3762
|
+
|
|
3587
3763
|
// src/entry.ts
|
|
3588
3764
|
var entry_exports = {};
|
|
3589
3765
|
import * as fs21 from "fs";
|
|
@@ -3773,6 +3949,42 @@ async function main() {
|
|
|
3773
3949
|
}
|
|
3774
3950
|
process.exit(0);
|
|
3775
3951
|
}
|
|
3952
|
+
if (input.command === "resolve") {
|
|
3953
|
+
if (!input.prNumber) {
|
|
3954
|
+
console.error("--pr-number is required for resolve command");
|
|
3955
|
+
process.exit(1);
|
|
3956
|
+
}
|
|
3957
|
+
runPreflight();
|
|
3958
|
+
const config2 = getProjectConfig();
|
|
3959
|
+
const litellmProcess2 = await ensureLitellmProxy(config2, projectDir);
|
|
3960
|
+
await runModelHealthCheck(config2);
|
|
3961
|
+
const runners2 = createRunners(config2);
|
|
3962
|
+
const defaultRunnerName2 = config2.agent.defaultRunner ?? Object.keys(runners2)[0] ?? "claude";
|
|
3963
|
+
const defaultRunner2 = runners2[defaultRunnerName2];
|
|
3964
|
+
if (!defaultRunner2) {
|
|
3965
|
+
console.error(`Default runner "${defaultRunnerName2}" not configured`);
|
|
3966
|
+
process.exit(1);
|
|
3967
|
+
}
|
|
3968
|
+
const healthy2 = await defaultRunner2.healthCheck();
|
|
3969
|
+
if (!healthy2) {
|
|
3970
|
+
console.error(`Runner "${defaultRunnerName2}" health check failed`);
|
|
3971
|
+
process.exit(1);
|
|
3972
|
+
}
|
|
3973
|
+
const { runResolve: runResolve2 } = await Promise.resolve().then(() => (init_resolve(), resolve_exports));
|
|
3974
|
+
const result = await runResolve2({
|
|
3975
|
+
prNumber: input.prNumber,
|
|
3976
|
+
projectDir,
|
|
3977
|
+
runners: runners2,
|
|
3978
|
+
local: input.local ?? true
|
|
3979
|
+
});
|
|
3980
|
+
if (litellmProcess2) litellmProcess2.kill?.();
|
|
3981
|
+
if (result.outcome === "failed") {
|
|
3982
|
+
console.error(`Resolve failed: ${result.error}`);
|
|
3983
|
+
process.exit(1);
|
|
3984
|
+
}
|
|
3985
|
+
console.log(`Resolve: ${result.outcome}`);
|
|
3986
|
+
process.exit(0);
|
|
3987
|
+
}
|
|
3776
3988
|
logger.info("Preflight checks:");
|
|
3777
3989
|
runPreflight();
|
|
3778
3990
|
if (input.task) {
|
|
@@ -3992,7 +4204,7 @@ var init_entry = __esm({
|
|
|
3992
4204
|
// src/bin/cli.ts
|
|
3993
4205
|
import * as fs22 from "fs";
|
|
3994
4206
|
import * as path21 from "path";
|
|
3995
|
-
import { execFileSync as
|
|
4207
|
+
import { execFileSync as execFileSync12 } from "child_process";
|
|
3996
4208
|
import { fileURLToPath } from "url";
|
|
3997
4209
|
var __dirname = path21.dirname(fileURLToPath(import.meta.url));
|
|
3998
4210
|
var PKG_ROOT = path21.resolve(__dirname, "..", "..");
|
|
@@ -4003,7 +4215,7 @@ function getVersion() {
|
|
|
4003
4215
|
}
|
|
4004
4216
|
function checkCommand2(name, args2, fix) {
|
|
4005
4217
|
try {
|
|
4006
|
-
const output =
|
|
4218
|
+
const output = execFileSync12(name, args2, {
|
|
4007
4219
|
encoding: "utf-8",
|
|
4008
4220
|
timeout: 1e4,
|
|
4009
4221
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -4021,7 +4233,7 @@ function checkFile(filePath, description, fix) {
|
|
|
4021
4233
|
}
|
|
4022
4234
|
function checkGhAuth(cwd) {
|
|
4023
4235
|
try {
|
|
4024
|
-
const output =
|
|
4236
|
+
const output = execFileSync12("gh", ["auth", "status"], {
|
|
4025
4237
|
encoding: "utf-8",
|
|
4026
4238
|
timeout: 1e4,
|
|
4027
4239
|
cwd,
|
|
@@ -4039,7 +4251,7 @@ function checkGhAuth(cwd) {
|
|
|
4039
4251
|
}
|
|
4040
4252
|
function checkGhRepoAccess(cwd) {
|
|
4041
4253
|
try {
|
|
4042
|
-
const remote =
|
|
4254
|
+
const remote = execFileSync12("git", ["remote", "get-url", "origin"], {
|
|
4043
4255
|
encoding: "utf-8",
|
|
4044
4256
|
timeout: 5e3,
|
|
4045
4257
|
cwd,
|
|
@@ -4050,7 +4262,7 @@ function checkGhRepoAccess(cwd) {
|
|
|
4050
4262
|
return { name: "GitHub repo", ok: false, fix: "Set git remote origin to a GitHub URL" };
|
|
4051
4263
|
}
|
|
4052
4264
|
const repoSlug = `${match[1]}/${match[2]}`;
|
|
4053
|
-
|
|
4265
|
+
execFileSync12("gh", ["repo", "view", repoSlug, "--json", "name"], {
|
|
4054
4266
|
encoding: "utf-8",
|
|
4055
4267
|
timeout: 1e4,
|
|
4056
4268
|
cwd,
|
|
@@ -4063,7 +4275,7 @@ function checkGhRepoAccess(cwd) {
|
|
|
4063
4275
|
}
|
|
4064
4276
|
function checkGhSecret(repoSlug, secretName) {
|
|
4065
4277
|
try {
|
|
4066
|
-
const output =
|
|
4278
|
+
const output = execFileSync12("gh", ["secret", "list", "--repo", repoSlug], {
|
|
4067
4279
|
encoding: "utf-8",
|
|
4068
4280
|
timeout: 1e4,
|
|
4069
4281
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -4091,7 +4303,7 @@ function detectBasicConfig(cwd) {
|
|
|
4091
4303
|
else if (!fs22.existsSync(path21.join(cwd, "pnpm-lock.yaml")) && fs22.existsSync(path21.join(cwd, "package-lock.json"))) pm = "npm";
|
|
4092
4304
|
let defaultBranch = "main";
|
|
4093
4305
|
try {
|
|
4094
|
-
const ref =
|
|
4306
|
+
const ref = execFileSync12("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
|
|
4095
4307
|
encoding: "utf-8",
|
|
4096
4308
|
timeout: 5e3,
|
|
4097
4309
|
cwd,
|
|
@@ -4100,7 +4312,7 @@ function detectBasicConfig(cwd) {
|
|
|
4100
4312
|
defaultBranch = ref.replace("refs/remotes/origin/", "");
|
|
4101
4313
|
} catch {
|
|
4102
4314
|
try {
|
|
4103
|
-
|
|
4315
|
+
execFileSync12("git", ["rev-parse", "--verify", "origin/dev"], {
|
|
4104
4316
|
encoding: "utf-8",
|
|
4105
4317
|
timeout: 5e3,
|
|
4106
4318
|
cwd,
|
|
@@ -4113,7 +4325,7 @@ function detectBasicConfig(cwd) {
|
|
|
4113
4325
|
let owner = "";
|
|
4114
4326
|
let repo = "";
|
|
4115
4327
|
try {
|
|
4116
|
-
const remote =
|
|
4328
|
+
const remote = execFileSync12("git", ["remote", "get-url", "origin"], {
|
|
4117
4329
|
encoding: "utf-8",
|
|
4118
4330
|
timeout: 5e3,
|
|
4119
4331
|
cwd,
|
|
@@ -4305,7 +4517,7 @@ function initCommand(opts) {
|
|
|
4305
4517
|
if (filesToCommit.length > 0) {
|
|
4306
4518
|
try {
|
|
4307
4519
|
const fullPaths = filesToCommit.map((f) => path21.join(cwd, f));
|
|
4308
|
-
|
|
4520
|
+
execFileSync12("npx", ["prettier", "--write", ...fullPaths], {
|
|
4309
4521
|
cwd,
|
|
4310
4522
|
encoding: "utf-8",
|
|
4311
4523
|
timeout: 3e4,
|
|
@@ -4316,13 +4528,13 @@ function initCommand(opts) {
|
|
|
4316
4528
|
}
|
|
4317
4529
|
if (filesToCommit.length > 0) {
|
|
4318
4530
|
try {
|
|
4319
|
-
|
|
4320
|
-
const staged =
|
|
4531
|
+
execFileSync12("git", ["add", ...filesToCommit], { cwd, stdio: "pipe" });
|
|
4532
|
+
const staged = execFileSync12("git", ["diff", "--cached", "--name-only"], { cwd, encoding: "utf-8" }).trim();
|
|
4321
4533
|
if (staged) {
|
|
4322
|
-
|
|
4534
|
+
execFileSync12("git", ["commit", "-m", "chore: Add Kody Engine workflow and config\n\nAdd GitHub Actions workflow and auto-detected configuration for Kody Engine Lite."], { cwd, stdio: "pipe" });
|
|
4323
4535
|
console.log(` \u2713 Committed: ${filesToCommit.join(", ")}`);
|
|
4324
4536
|
try {
|
|
4325
|
-
|
|
4537
|
+
execFileSync12("git", ["push"], { cwd, stdio: "pipe", timeout: 6e4 });
|
|
4326
4538
|
console.log(" \u2713 Pushed to origin");
|
|
4327
4539
|
} catch {
|
|
4328
4540
|
console.log(" \u25CB Push failed \u2014 run 'git push' manually");
|
|
@@ -4416,7 +4628,7 @@ function ghComment(issueNumber, body, cwd) {
|
|
|
4416
4628
|
} catch {
|
|
4417
4629
|
}
|
|
4418
4630
|
if (!repoSlug) return;
|
|
4419
|
-
|
|
4631
|
+
execFileSync12("gh", [
|
|
4420
4632
|
"issue",
|
|
4421
4633
|
"comment",
|
|
4422
4634
|
String(issueNumber),
|
|
@@ -4549,7 +4761,7 @@ Output ONLY valid JSON. No markdown fences. No explanation.
|
|
|
4549
4761
|
${repoContext}`;
|
|
4550
4762
|
console.log(" \u23F3 Analyzing project...");
|
|
4551
4763
|
try {
|
|
4552
|
-
const output =
|
|
4764
|
+
const output = execFileSync12("claude", [
|
|
4553
4765
|
"--print",
|
|
4554
4766
|
"--model",
|
|
4555
4767
|
"haiku",
|
|
@@ -4652,7 +4864,7 @@ ${repoContext}
|
|
|
4652
4864
|
|
|
4653
4865
|
REMINDER: Output the full prompt template first (unchanged), then your three appended sections. Do NOT include "${contextPlaceholder}".`;
|
|
4654
4866
|
try {
|
|
4655
|
-
const output =
|
|
4867
|
+
const output = execFileSync12("claude", [
|
|
4656
4868
|
"--print",
|
|
4657
4869
|
"--model",
|
|
4658
4870
|
"haiku",
|
|
@@ -4709,7 +4921,7 @@ REMINDER: Output the full prompt template first (unchanged), then your three app
|
|
|
4709
4921
|
];
|
|
4710
4922
|
for (const label of labels) {
|
|
4711
4923
|
try {
|
|
4712
|
-
|
|
4924
|
+
execFileSync12("gh", [
|
|
4713
4925
|
"label",
|
|
4714
4926
|
"create",
|
|
4715
4927
|
label.name,
|
|
@@ -4729,7 +4941,7 @@ REMINDER: Output the full prompt template first (unchanged), then your three app
|
|
|
4729
4941
|
console.log(` \u2713 ${label.name}`);
|
|
4730
4942
|
} catch {
|
|
4731
4943
|
try {
|
|
4732
|
-
|
|
4944
|
+
execFileSync12("gh", ["label", "list", "--repo", repoSlug, "--search", label.name], {
|
|
4733
4945
|
cwd,
|
|
4734
4946
|
encoding: "utf-8",
|
|
4735
4947
|
timeout: 1e4,
|
|
@@ -4768,7 +4980,7 @@ REMINDER: Output the full prompt template first (unchanged), then your three app
|
|
|
4768
4980
|
try {
|
|
4769
4981
|
const fullPaths = filesToCommit.map((f) => path21.join(cwd, f));
|
|
4770
4982
|
for (let pass = 0; pass < 2; pass++) {
|
|
4771
|
-
|
|
4983
|
+
execFileSync12("npx", ["prettier", "--write", ...fullPaths], {
|
|
4772
4984
|
cwd,
|
|
4773
4985
|
encoding: "utf-8",
|
|
4774
4986
|
timeout: 3e4,
|
|
@@ -4783,13 +4995,13 @@ REMINDER: Output the full prompt template first (unchanged), then your three app
|
|
|
4783
4995
|
if (filesToCommit.length > 0) {
|
|
4784
4996
|
try {
|
|
4785
4997
|
if (isCI3) {
|
|
4786
|
-
const branchName = `kody
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
const staged =
|
|
4998
|
+
const branchName = `kody-bootstrap-${Date.now()}`;
|
|
4999
|
+
execFileSync12("git", ["checkout", "-b", branchName], { cwd, stdio: "pipe" });
|
|
5000
|
+
execFileSync12("git", ["add", ...filesToCommit], { cwd, stdio: "pipe" });
|
|
5001
|
+
const staged = execFileSync12("git", ["diff", "--cached", "--name-only"], { cwd, encoding: "utf-8" }).trim();
|
|
4790
5002
|
if (staged) {
|
|
4791
|
-
|
|
4792
|
-
|
|
5003
|
+
execFileSync12("git", ["commit", "-m", "chore: Add Kody project memory and step files\n\nBootstrap Kody Engine with project-specific architecture, conventions, and pipeline step files."], { cwd, stdio: "pipe" });
|
|
5004
|
+
execFileSync12("git", ["push", "-u", "origin", branchName], { cwd, stdio: "pipe", timeout: 6e4 });
|
|
4793
5005
|
console.log(` \u2713 Pushed branch: ${branchName}`);
|
|
4794
5006
|
let baseBranch = "main";
|
|
4795
5007
|
try {
|
|
@@ -4801,7 +5013,7 @@ REMINDER: Output the full prompt template first (unchanged), then your three app
|
|
|
4801
5013
|
} catch {
|
|
4802
5014
|
}
|
|
4803
5015
|
try {
|
|
4804
|
-
const prUrl =
|
|
5016
|
+
const prUrl = execFileSync12("gh", [
|
|
4805
5017
|
"pr",
|
|
4806
5018
|
"create",
|
|
4807
5019
|
"--title",
|
|
@@ -4840,13 +5052,13 @@ Create it manually.`, cwd);
|
|
|
4840
5052
|
console.log(" \u25CB No new changes to commit");
|
|
4841
5053
|
}
|
|
4842
5054
|
} else {
|
|
4843
|
-
|
|
4844
|
-
const staged =
|
|
5055
|
+
execFileSync12("git", ["add", ...filesToCommit], { cwd, stdio: "pipe" });
|
|
5056
|
+
const staged = execFileSync12("git", ["diff", "--cached", "--name-only"], { cwd, encoding: "utf-8" }).trim();
|
|
4845
5057
|
if (staged) {
|
|
4846
|
-
|
|
5058
|
+
execFileSync12("git", ["commit", "-m", "chore: Add Kody project memory and step files\n\nBootstrap Kody Engine with project-specific architecture, conventions, and pipeline step files."], { cwd, stdio: "pipe" });
|
|
4847
5059
|
console.log(` \u2713 Committed: ${filesToCommit.join(", ")}`);
|
|
4848
5060
|
try {
|
|
4849
|
-
|
|
5061
|
+
execFileSync12("git", ["push"], { cwd, stdio: "pipe", timeout: 6e4 });
|
|
4850
5062
|
console.log(" \u2713 Pushed to origin");
|
|
4851
5063
|
} catch {
|
|
4852
5064
|
console.log(" \u25CB Push failed \u2014 run 'git push' manually");
|
|
@@ -4967,7 +5179,7 @@ function installSkillsForProject(cwd) {
|
|
|
4967
5179
|
}
|
|
4968
5180
|
try {
|
|
4969
5181
|
console.log(` Installing: ${skill.label} (${skill.package})`);
|
|
4970
|
-
|
|
5182
|
+
execFileSync12("npx", ["skills", "add", skill.package, "--yes"], {
|
|
4971
5183
|
cwd,
|
|
4972
5184
|
encoding: "utf-8",
|
|
4973
5185
|
timeout: 6e4,
|
package/package.json
CHANGED
package/templates/kody.yml
CHANGED
|
@@ -119,7 +119,7 @@ jobs:
|
|
|
119
119
|
|
|
120
120
|
# Validate mode
|
|
121
121
|
case "$MODE" in
|
|
122
|
-
full|rerun|fix|fix-ci|status|approve|review|bootstrap) ;;
|
|
122
|
+
full|rerun|fix|fix-ci|status|approve|review|resolve|bootstrap) ;;
|
|
123
123
|
*)
|
|
124
124
|
# If first arg isn't a mode, it might be a task-id or nothing
|
|
125
125
|
if [ -n "$MODE" ] && [ "$MODE" != "" ]; then
|
|
@@ -219,7 +219,7 @@ jobs:
|
|
|
219
219
|
token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
|
|
220
220
|
|
|
221
221
|
- name: Checkout PR branch (for fix/rerun/review on PRs)
|
|
222
|
-
if: github.event.issue.pull_request && (needs.parse.outputs.mode == 'fix' || needs.parse.outputs.mode == 'fix-ci' || needs.parse.outputs.mode == 'rerun' || needs.parse.outputs.mode == 'review')
|
|
222
|
+
if: github.event.issue.pull_request && (needs.parse.outputs.mode == 'fix' || needs.parse.outputs.mode == 'fix-ci' || needs.parse.outputs.mode == 'rerun' || needs.parse.outputs.mode == 'review' || needs.parse.outputs.mode == 'resolve')
|
|
223
223
|
env:
|
|
224
224
|
GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
|
|
225
225
|
run: |
|
|
@@ -277,6 +277,7 @@ jobs:
|
|
|
277
277
|
[ "$MODE" = "fix" ] && CMD="fix"
|
|
278
278
|
[ "$MODE" = "fix-ci" ] && CMD="fix-ci"
|
|
279
279
|
[ "$MODE" = "review" ] && CMD="review"
|
|
280
|
+
[ "$MODE" = "resolve" ] && CMD="resolve"
|
|
280
281
|
ARGS="--issue-number $ISSUE_NUMBER"
|
|
281
282
|
[ -n "$TASK_ID" ] && ARGS="$ARGS --task-id $TASK_ID"
|
|
282
283
|
[ -n "$PR_NUMBER" ] && ARGS="$ARGS --pr-number $PR_NUMBER"
|