@kody-ade/kody-engine 0.3.50 → 0.3.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/kody.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.3.
|
|
6
|
+
version: "0.3.51",
|
|
7
7
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
8
8
|
license: "MIT",
|
|
9
9
|
type: "module",
|
|
@@ -50,7 +50,7 @@ var package_default = {
|
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
// src/chat-cli.ts
|
|
53
|
-
import { execFileSync as
|
|
53
|
+
import { execFileSync as execFileSync26 } from "child_process";
|
|
54
54
|
import * as fs26 from "fs";
|
|
55
55
|
import * as path23 from "path";
|
|
56
56
|
|
|
@@ -154,7 +154,7 @@ function loadConfig(projectDir = process.cwd()) {
|
|
|
154
154
|
throw new Error(`kody.config.json is invalid JSON: ${msg}`);
|
|
155
155
|
}
|
|
156
156
|
const quality = raw.quality ?? {};
|
|
157
|
-
const
|
|
157
|
+
const git5 = raw.git ?? {};
|
|
158
158
|
const github = raw.github ?? {};
|
|
159
159
|
const agent = raw.agent ?? {};
|
|
160
160
|
if (!agent.model || typeof agent.model !== "string") {
|
|
@@ -171,7 +171,7 @@ function loadConfig(projectDir = process.cwd()) {
|
|
|
171
171
|
testUnit: typeof quality.testUnit === "string" ? quality.testUnit : ""
|
|
172
172
|
},
|
|
173
173
|
git: {
|
|
174
|
-
defaultBranch: typeof
|
|
174
|
+
defaultBranch: typeof git5.defaultBranch === "string" ? git5.defaultBranch : "main"
|
|
175
175
|
},
|
|
176
176
|
github: {
|
|
177
177
|
owner: String(github.owner),
|
|
@@ -605,7 +605,7 @@ async function emit(sink, type, sessionId, suffix, payload) {
|
|
|
605
605
|
}
|
|
606
606
|
|
|
607
607
|
// src/kody-cli.ts
|
|
608
|
-
import { execFileSync as
|
|
608
|
+
import { execFileSync as execFileSync25 } from "child_process";
|
|
609
609
|
import * as fs25 from "fs";
|
|
610
610
|
import * as path22 from "path";
|
|
611
611
|
|
|
@@ -4632,6 +4632,14 @@ function walkMd(root, visit) {
|
|
|
4632
4632
|
}
|
|
4633
4633
|
}
|
|
4634
4634
|
|
|
4635
|
+
// src/scripts/markFlowSuccess.ts
|
|
4636
|
+
var markFlowSuccess = async (ctx) => {
|
|
4637
|
+
const exit = ctx.output.exitCode;
|
|
4638
|
+
if (exit === void 0 || exit === 0) {
|
|
4639
|
+
ctx.data.agentDone = true;
|
|
4640
|
+
}
|
|
4641
|
+
};
|
|
4642
|
+
|
|
4635
4643
|
// src/scripts/memorizeFlow.ts
|
|
4636
4644
|
import { execFileSync as execFileSync15 } from "child_process";
|
|
4637
4645
|
import * as fs22 from "fs";
|
|
@@ -5558,6 +5566,120 @@ function tryPostPr3(prNumber, body, cwd) {
|
|
|
5558
5566
|
}
|
|
5559
5567
|
}
|
|
5560
5568
|
|
|
5569
|
+
// src/scripts/revertFlow.ts
|
|
5570
|
+
import { execFileSync as execFileSync19 } from "child_process";
|
|
5571
|
+
var SHA_RE = /^[0-9a-f]{4,40}$/i;
|
|
5572
|
+
var revertFlow = async (ctx) => {
|
|
5573
|
+
const prNumber = ctx.args.pr;
|
|
5574
|
+
const pr = getPr(prNumber, ctx.cwd);
|
|
5575
|
+
if (pr.state !== "OPEN") {
|
|
5576
|
+
ctx.output.exitCode = 1;
|
|
5577
|
+
ctx.output.reason = `PR #${prNumber} is not OPEN (state: ${pr.state})`;
|
|
5578
|
+
ctx.skipAgent = true;
|
|
5579
|
+
return;
|
|
5580
|
+
}
|
|
5581
|
+
ctx.data.pr = pr;
|
|
5582
|
+
ctx.data.commentTargetType = "pr";
|
|
5583
|
+
ctx.data.commentTargetNumber = prNumber;
|
|
5584
|
+
checkoutPrBranch(prNumber, ctx.cwd);
|
|
5585
|
+
ctx.data.branch = getCurrentBranch(ctx.cwd);
|
|
5586
|
+
const shasArg = String(ctx.args.shas ?? "").trim();
|
|
5587
|
+
if (!shasArg) {
|
|
5588
|
+
ctx.output.exitCode = 64;
|
|
5589
|
+
ctx.output.reason = "no commit SHAs provided \u2014 usage: @kody revert <sha> [<sha> \u2026]";
|
|
5590
|
+
ctx.skipAgent = true;
|
|
5591
|
+
tryPostPr4(prNumber, `\u26A0\uFE0F kody revert FAILED: ${ctx.output.reason}`, ctx.cwd);
|
|
5592
|
+
return;
|
|
5593
|
+
}
|
|
5594
|
+
const requested = shasArg.split(/\s+/).filter((s) => s.length > 0);
|
|
5595
|
+
const bad = requested.filter((s) => !SHA_RE.test(s));
|
|
5596
|
+
if (bad.length > 0) {
|
|
5597
|
+
ctx.output.exitCode = 64;
|
|
5598
|
+
ctx.output.reason = `not valid SHA-shaped tokens: ${bad.join(", ")}`;
|
|
5599
|
+
ctx.skipAgent = true;
|
|
5600
|
+
tryPostPr4(prNumber, `\u26A0\uFE0F kody revert FAILED: ${ctx.output.reason}`, ctx.cwd);
|
|
5601
|
+
return;
|
|
5602
|
+
}
|
|
5603
|
+
const resolved = [];
|
|
5604
|
+
const unreachable = [];
|
|
5605
|
+
for (const s of requested) {
|
|
5606
|
+
let full;
|
|
5607
|
+
try {
|
|
5608
|
+
full = git4(["rev-parse", "--verify", `${s}^{commit}`], ctx.cwd);
|
|
5609
|
+
} catch {
|
|
5610
|
+
unreachable.push(s);
|
|
5611
|
+
continue;
|
|
5612
|
+
}
|
|
5613
|
+
if (!isAncestorOfHead(full, ctx.cwd)) {
|
|
5614
|
+
unreachable.push(s);
|
|
5615
|
+
continue;
|
|
5616
|
+
}
|
|
5617
|
+
let subject = "";
|
|
5618
|
+
try {
|
|
5619
|
+
subject = git4(["log", "-1", "--format=%s", full], ctx.cwd);
|
|
5620
|
+
} catch {
|
|
5621
|
+
}
|
|
5622
|
+
resolved.push({ input: s, full, subject });
|
|
5623
|
+
}
|
|
5624
|
+
if (unreachable.length > 0) {
|
|
5625
|
+
ctx.output.exitCode = 64;
|
|
5626
|
+
ctx.output.reason = `commit(s) not found in this PR branch: ${unreachable.join(", ")}`;
|
|
5627
|
+
ctx.skipAgent = true;
|
|
5628
|
+
tryPostPr4(prNumber, `\u26A0\uFE0F kody revert FAILED: ${ctx.output.reason}`, ctx.cwd);
|
|
5629
|
+
return;
|
|
5630
|
+
}
|
|
5631
|
+
ctx.args.shas = resolved.map((r) => r.full).join(" ");
|
|
5632
|
+
ctx.data.commitMessage = buildCommitMessage(resolved);
|
|
5633
|
+
ctx.data.prSummary = buildPrSummary(resolved);
|
|
5634
|
+
ctx.skipAgent = true;
|
|
5635
|
+
const runUrl = getRunUrl();
|
|
5636
|
+
const runSuffix = runUrl ? `, run ${runUrl}` : "";
|
|
5637
|
+
const shaList = resolved.map((r) => `\`${r.full.slice(0, 7)}\``).join(", ");
|
|
5638
|
+
tryPostPr4(
|
|
5639
|
+
prNumber,
|
|
5640
|
+
`\u2699\uFE0F kody revert started on \`${ctx.data.branch}\`${runSuffix} \u2014 reverting ${shaList}`,
|
|
5641
|
+
ctx.cwd
|
|
5642
|
+
);
|
|
5643
|
+
};
|
|
5644
|
+
function buildCommitMessage(resolved) {
|
|
5645
|
+
if (resolved.length === 1) {
|
|
5646
|
+
const { full, subject } = resolved[0];
|
|
5647
|
+
return subject ? `revert: "${subject}" (${full.slice(0, 7)})` : `revert: ${full.slice(0, 7)}`;
|
|
5648
|
+
}
|
|
5649
|
+
const shas = resolved.map((r) => r.full.slice(0, 7)).join(", ");
|
|
5650
|
+
return `revert: ${resolved.length} commit(s) (${shas})`;
|
|
5651
|
+
}
|
|
5652
|
+
function buildPrSummary(resolved) {
|
|
5653
|
+
return resolved.map((r) => `- Reverted \`${r.full.slice(0, 7)}\`${r.subject ? ` \u2014 ${r.subject}` : ""}`).join("\n");
|
|
5654
|
+
}
|
|
5655
|
+
function git4(args, cwd) {
|
|
5656
|
+
return execFileSync19("git", args, {
|
|
5657
|
+
encoding: "utf-8",
|
|
5658
|
+
timeout: 3e4,
|
|
5659
|
+
cwd,
|
|
5660
|
+
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
|
|
5661
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5662
|
+
}).trim();
|
|
5663
|
+
}
|
|
5664
|
+
function isAncestorOfHead(sha, cwd) {
|
|
5665
|
+
try {
|
|
5666
|
+
execFileSync19("git", ["merge-base", "--is-ancestor", sha, "HEAD"], {
|
|
5667
|
+
cwd,
|
|
5668
|
+
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
|
|
5669
|
+
stdio: ["ignore", "ignore", "ignore"]
|
|
5670
|
+
});
|
|
5671
|
+
return true;
|
|
5672
|
+
} catch {
|
|
5673
|
+
return false;
|
|
5674
|
+
}
|
|
5675
|
+
}
|
|
5676
|
+
function tryPostPr4(prNumber, body, cwd) {
|
|
5677
|
+
try {
|
|
5678
|
+
postPrReviewComment(prNumber, body, cwd);
|
|
5679
|
+
} catch {
|
|
5680
|
+
}
|
|
5681
|
+
}
|
|
5682
|
+
|
|
5561
5683
|
// src/scripts/resolvePreviewUrl.ts
|
|
5562
5684
|
var DEFAULT_PREVIEW_URL = "http://localhost:3000";
|
|
5563
5685
|
var resolvePreviewUrl = async (ctx) => {
|
|
@@ -5595,9 +5717,9 @@ var reviewFlow = async (ctx) => {
|
|
|
5595
5717
|
ctx.data.prDiff = getPrDiff(prNumber, ctx.cwd);
|
|
5596
5718
|
const runUrl = getRunUrl();
|
|
5597
5719
|
const runSuffix = runUrl ? `, run ${runUrl}` : "";
|
|
5598
|
-
|
|
5720
|
+
tryPostPr5(prNumber, `\u{1F440} kody review started on PR #${prNumber}${runSuffix}`, ctx.cwd);
|
|
5599
5721
|
};
|
|
5600
|
-
function
|
|
5722
|
+
function tryPostPr5(prNumber, body, cwd) {
|
|
5601
5723
|
try {
|
|
5602
5724
|
postPrReviewComment(prNumber, body, cwd);
|
|
5603
5725
|
} catch {
|
|
@@ -5710,11 +5832,11 @@ var skipAgent = async (ctx) => {
|
|
|
5710
5832
|
};
|
|
5711
5833
|
|
|
5712
5834
|
// src/scripts/stageMergeConflicts.ts
|
|
5713
|
-
import { execFileSync as
|
|
5835
|
+
import { execFileSync as execFileSync20 } from "child_process";
|
|
5714
5836
|
var stageMergeConflicts = async (ctx) => {
|
|
5715
5837
|
if (ctx.data.agentDone === false) return;
|
|
5716
5838
|
try {
|
|
5717
|
-
|
|
5839
|
+
execFileSync20("git", ["add", "-A"], {
|
|
5718
5840
|
cwd: ctx.cwd,
|
|
5719
5841
|
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
|
|
5720
5842
|
stdio: "pipe"
|
|
@@ -5724,7 +5846,7 @@ var stageMergeConflicts = async (ctx) => {
|
|
|
5724
5846
|
};
|
|
5725
5847
|
|
|
5726
5848
|
// src/scripts/startFlow.ts
|
|
5727
|
-
import { execFileSync as
|
|
5849
|
+
import { execFileSync as execFileSync21 } from "child_process";
|
|
5728
5850
|
var API_TIMEOUT_MS9 = 3e4;
|
|
5729
5851
|
var startFlow = async (ctx, profile, _agentResult, args) => {
|
|
5730
5852
|
const entry = args?.entry;
|
|
@@ -5758,7 +5880,7 @@ function postKodyComment(target, issueNumber, state, next, cwd) {
|
|
|
5758
5880
|
const sub = target === "pr" && state?.core.prUrl ? "pr" : "issue";
|
|
5759
5881
|
const body = `@kody ${next}`;
|
|
5760
5882
|
try {
|
|
5761
|
-
|
|
5883
|
+
execFileSync21("gh", [sub, "comment", String(targetNumber), "--body", body], {
|
|
5762
5884
|
timeout: API_TIMEOUT_MS9,
|
|
5763
5885
|
cwd,
|
|
5764
5886
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -5772,7 +5894,7 @@ function postKodyComment(target, issueNumber, state, next, cwd) {
|
|
|
5772
5894
|
}
|
|
5773
5895
|
|
|
5774
5896
|
// src/scripts/syncFlow.ts
|
|
5775
|
-
import { execFileSync as
|
|
5897
|
+
import { execFileSync as execFileSync22 } from "child_process";
|
|
5776
5898
|
var syncFlow = async (ctx, _profile, args) => {
|
|
5777
5899
|
const announceOnSuccess = Boolean(args?.announceOnSuccess);
|
|
5778
5900
|
const prNumber = ctx.args.pr;
|
|
@@ -5810,7 +5932,7 @@ var syncFlow = async (ctx, _profile, args) => {
|
|
|
5810
5932
|
if (announceOnSuccess) {
|
|
5811
5933
|
ctx.output.exitCode = 0;
|
|
5812
5934
|
ctx.output.reason = `already up to date with origin/${baseBranch}`;
|
|
5813
|
-
|
|
5935
|
+
tryPostPr6(prNumber, `\u2139\uFE0F kody sync: already up to date with origin/${baseBranch}`, ctx.cwd);
|
|
5814
5936
|
}
|
|
5815
5937
|
return;
|
|
5816
5938
|
}
|
|
@@ -5827,7 +5949,7 @@ var syncFlow = async (ctx, _profile, args) => {
|
|
|
5827
5949
|
ctx.output.reason = `merged origin/${baseBranch} into ${ctx.data.branch}`;
|
|
5828
5950
|
const runUrl = getRunUrl();
|
|
5829
5951
|
const runSuffix = runUrl ? ` ([logs](${runUrl}))` : "";
|
|
5830
|
-
|
|
5952
|
+
tryPostPr6(
|
|
5831
5953
|
prNumber,
|
|
5832
5954
|
`\u2705 kody sync: merged \`origin/${baseBranch}\` into \`${ctx.data.branch}\`${runSuffix}`,
|
|
5833
5955
|
ctx.cwd
|
|
@@ -5840,11 +5962,11 @@ function bail2(ctx, prNumber, reason) {
|
|
|
5840
5962
|
ctx.output.reason = reason;
|
|
5841
5963
|
const runUrl = getRunUrl();
|
|
5842
5964
|
const runSuffix = runUrl ? ` ([logs](${runUrl}))` : "";
|
|
5843
|
-
|
|
5965
|
+
tryPostPr6(prNumber, `\u274C kody sync could not complete${runSuffix}: ${reason}`, ctx.cwd);
|
|
5844
5966
|
}
|
|
5845
5967
|
function revParseHead(cwd) {
|
|
5846
5968
|
try {
|
|
5847
|
-
return
|
|
5969
|
+
return execFileSync22("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
|
|
5848
5970
|
} catch {
|
|
5849
5971
|
return "";
|
|
5850
5972
|
}
|
|
@@ -5852,16 +5974,16 @@ function revParseHead(cwd) {
|
|
|
5852
5974
|
function pushBranch(branch, cwd) {
|
|
5853
5975
|
const env = { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" };
|
|
5854
5976
|
try {
|
|
5855
|
-
|
|
5977
|
+
execFileSync22("git", ["push", "-u", "origin", branch], { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
|
|
5856
5978
|
} catch {
|
|
5857
|
-
|
|
5979
|
+
execFileSync22("git", ["push", "--force-with-lease", "-u", "origin", branch], {
|
|
5858
5980
|
cwd,
|
|
5859
5981
|
env,
|
|
5860
5982
|
stdio: ["ignore", "pipe", "pipe"]
|
|
5861
5983
|
});
|
|
5862
5984
|
}
|
|
5863
5985
|
}
|
|
5864
|
-
function
|
|
5986
|
+
function tryPostPr6(prNumber, body, cwd) {
|
|
5865
5987
|
try {
|
|
5866
5988
|
postPrReviewComment(prNumber, body, cwd);
|
|
5867
5989
|
} catch {
|
|
@@ -5965,7 +6087,7 @@ var verify = async (ctx) => {
|
|
|
5965
6087
|
};
|
|
5966
6088
|
|
|
5967
6089
|
// src/scripts/waitForCi.ts
|
|
5968
|
-
import { execFileSync as
|
|
6090
|
+
import { execFileSync as execFileSync23 } from "child_process";
|
|
5969
6091
|
var API_TIMEOUT_MS10 = 3e4;
|
|
5970
6092
|
var waitForCi = async (ctx, _profile, _agentResult, args) => {
|
|
5971
6093
|
const timeoutMinutes = numArg(args, "timeoutMinutes", 30);
|
|
@@ -5996,7 +6118,7 @@ var waitForCi = async (ctx, _profile, _agentResult, args) => {
|
|
|
5996
6118
|
const summary = summarize(rows);
|
|
5997
6119
|
if (summary !== lastSummary) {
|
|
5998
6120
|
lastSummary = summary;
|
|
5999
|
-
|
|
6121
|
+
tryPostPr7(prNumber, `\u23F3 kody waitForCi: ${summary}`, ctx.cwd);
|
|
6000
6122
|
}
|
|
6001
6123
|
const failed = rows.filter((r) => r.bucket === "fail" || r.bucket === "cancel");
|
|
6002
6124
|
const pending = rows.filter((r) => r.bucket === "pending");
|
|
@@ -6008,7 +6130,7 @@ var waitForCi = async (ctx, _profile, _agentResult, args) => {
|
|
|
6008
6130
|
failedChecks: detail,
|
|
6009
6131
|
prUrl
|
|
6010
6132
|
});
|
|
6011
|
-
|
|
6133
|
+
tryPostPr7(
|
|
6012
6134
|
prNumber,
|
|
6013
6135
|
`\u{1F6D1} kody waitForCi: giving up after ${fixCiAttempts} fix-ci attempts. Failed: ${detail}`,
|
|
6014
6136
|
ctx.cwd
|
|
@@ -6020,7 +6142,7 @@ var waitForCi = async (ctx, _profile, _agentResult, args) => {
|
|
|
6020
6142
|
maxAttempts: maxFixCiAttempts,
|
|
6021
6143
|
prUrl
|
|
6022
6144
|
});
|
|
6023
|
-
|
|
6145
|
+
tryPostPr7(
|
|
6024
6146
|
prNumber,
|
|
6025
6147
|
`\u274C kody waitForCi: CI failed (attempt ${fixCiAttempts + 1}/${maxFixCiAttempts}). Dispatching fix-ci. Failed: ${detail}`,
|
|
6026
6148
|
ctx.cwd
|
|
@@ -6030,7 +6152,7 @@ var waitForCi = async (ctx, _profile, _agentResult, args) => {
|
|
|
6030
6152
|
}
|
|
6031
6153
|
if (pending.length === 0) {
|
|
6032
6154
|
ctx.data.action = mkAction("CI_PASSED", { checks: rows.length, prUrl });
|
|
6033
|
-
|
|
6155
|
+
tryPostPr7(prNumber, `\u2705 kody waitForCi: all ${rows.length} checks green on PR #${prNumber}`, ctx.cwd);
|
|
6034
6156
|
return;
|
|
6035
6157
|
}
|
|
6036
6158
|
await sleep(pollSeconds * 1e3);
|
|
@@ -6039,11 +6161,11 @@ var waitForCi = async (ctx, _profile, _agentResult, args) => {
|
|
|
6039
6161
|
reason: `CI did not complete within ${timeoutMinutes} minutes`,
|
|
6040
6162
|
prUrl
|
|
6041
6163
|
});
|
|
6042
|
-
|
|
6164
|
+
tryPostPr7(prNumber, `\u231B kody waitForCi: timed out after ${timeoutMinutes} minutes`, ctx.cwd);
|
|
6043
6165
|
};
|
|
6044
6166
|
function fetchChecks(prNumber, cwd) {
|
|
6045
6167
|
try {
|
|
6046
|
-
const raw =
|
|
6168
|
+
const raw = execFileSync23("gh", ["pr", "checks", String(prNumber), "--json", "bucket,state,name,workflow,link"], {
|
|
6047
6169
|
encoding: "utf-8",
|
|
6048
6170
|
timeout: API_TIMEOUT_MS10,
|
|
6049
6171
|
cwd,
|
|
@@ -6079,7 +6201,7 @@ function numArg(args, key, fallback) {
|
|
|
6079
6201
|
}
|
|
6080
6202
|
return fallback;
|
|
6081
6203
|
}
|
|
6082
|
-
function
|
|
6204
|
+
function tryPostPr7(prNumber, body, cwd) {
|
|
6083
6205
|
try {
|
|
6084
6206
|
postPrReviewComment(prNumber, body, cwd);
|
|
6085
6207
|
} catch {
|
|
@@ -6252,6 +6374,7 @@ var preflightScripts = {
|
|
|
6252
6374
|
fixFlow,
|
|
6253
6375
|
fixCiFlow,
|
|
6254
6376
|
resolveFlow,
|
|
6377
|
+
revertFlow,
|
|
6255
6378
|
reviewFlow,
|
|
6256
6379
|
syncFlow,
|
|
6257
6380
|
initFlow,
|
|
@@ -6312,7 +6435,8 @@ var postflightScripts = {
|
|
|
6312
6435
|
notifyTerminal,
|
|
6313
6436
|
recordOutcome,
|
|
6314
6437
|
mergeReleasePr,
|
|
6315
|
-
waitForCi
|
|
6438
|
+
waitForCi,
|
|
6439
|
+
markFlowSuccess
|
|
6316
6440
|
};
|
|
6317
6441
|
var allScriptNames = /* @__PURE__ */ new Set([
|
|
6318
6442
|
...Object.keys(preflightScripts),
|
|
@@ -6320,7 +6444,7 @@ var allScriptNames = /* @__PURE__ */ new Set([
|
|
|
6320
6444
|
]);
|
|
6321
6445
|
|
|
6322
6446
|
// src/tools.ts
|
|
6323
|
-
import { execFileSync as
|
|
6447
|
+
import { execFileSync as execFileSync24 } from "child_process";
|
|
6324
6448
|
function verifyCliTools(tools, cwd) {
|
|
6325
6449
|
const out = [];
|
|
6326
6450
|
for (const t of tools) out.push(verifyOne(t, cwd));
|
|
@@ -6353,7 +6477,7 @@ function verifyOne(tool, cwd) {
|
|
|
6353
6477
|
}
|
|
6354
6478
|
function runShell(cmd, cwd, timeoutMs = 3e4) {
|
|
6355
6479
|
try {
|
|
6356
|
-
|
|
6480
|
+
execFileSync24("sh", ["-c", cmd], { cwd, stdio: "pipe", timeout: timeoutMs });
|
|
6357
6481
|
return true;
|
|
6358
6482
|
} catch {
|
|
6359
6483
|
return false;
|
|
@@ -6762,7 +6886,7 @@ function detectPackageManager2(cwd) {
|
|
|
6762
6886
|
}
|
|
6763
6887
|
function shellOut(cmd, args, cwd, stream = true) {
|
|
6764
6888
|
try {
|
|
6765
|
-
|
|
6889
|
+
execFileSync25(cmd, args, {
|
|
6766
6890
|
cwd,
|
|
6767
6891
|
stdio: stream ? "inherit" : "pipe",
|
|
6768
6892
|
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" }
|
|
@@ -6775,7 +6899,7 @@ function shellOut(cmd, args, cwd, stream = true) {
|
|
|
6775
6899
|
}
|
|
6776
6900
|
function isOnPath(bin) {
|
|
6777
6901
|
try {
|
|
6778
|
-
|
|
6902
|
+
execFileSync25("which", [bin], { stdio: "pipe" });
|
|
6779
6903
|
return true;
|
|
6780
6904
|
} catch {
|
|
6781
6905
|
return false;
|
|
@@ -6809,7 +6933,7 @@ function installLitellmIfNeeded(cwd) {
|
|
|
6809
6933
|
} catch {
|
|
6810
6934
|
}
|
|
6811
6935
|
try {
|
|
6812
|
-
|
|
6936
|
+
execFileSync25("python3", ["-c", "import litellm"], { stdio: "pipe" });
|
|
6813
6937
|
process.stdout.write("\u2192 kody: litellm already installed\n");
|
|
6814
6938
|
return 0;
|
|
6815
6939
|
} catch {
|
|
@@ -6819,16 +6943,16 @@ function installLitellmIfNeeded(cwd) {
|
|
|
6819
6943
|
}
|
|
6820
6944
|
function configureGitIdentity(cwd) {
|
|
6821
6945
|
try {
|
|
6822
|
-
const name =
|
|
6946
|
+
const name = execFileSync25("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
|
|
6823
6947
|
if (name) return;
|
|
6824
6948
|
} catch {
|
|
6825
6949
|
}
|
|
6826
6950
|
try {
|
|
6827
|
-
|
|
6951
|
+
execFileSync25("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
|
|
6828
6952
|
} catch {
|
|
6829
6953
|
}
|
|
6830
6954
|
try {
|
|
6831
|
-
|
|
6955
|
+
execFileSync25("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
|
|
6832
6956
|
cwd,
|
|
6833
6957
|
stdio: "pipe"
|
|
6834
6958
|
});
|
|
@@ -7099,9 +7223,9 @@ function commitChatFiles(cwd, sessionId, verbose) {
|
|
|
7099
7223
|
if (paths.length === 0) return;
|
|
7100
7224
|
const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
|
|
7101
7225
|
try {
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7226
|
+
execFileSync26("git", ["add", ...paths], opts);
|
|
7227
|
+
execFileSync26("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
|
|
7228
|
+
execFileSync26("git", ["push", "--quiet", "origin", "HEAD"], opts);
|
|
7105
7229
|
} catch (err) {
|
|
7106
7230
|
const msg = err instanceof Error ? err.message : String(err);
|
|
7107
7231
|
process.stderr.write(`[kody:chat] commit/push skipped: ${msg}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "revert",
|
|
3
|
+
"role": "primitive",
|
|
4
|
+
"describe": "Revert one or more commits on an existing PR branch via `git revert`. No agent — fully mechanical.",
|
|
5
|
+
"inputs": [
|
|
6
|
+
{
|
|
7
|
+
"name": "pr",
|
|
8
|
+
"flag": "--pr",
|
|
9
|
+
"type": "int",
|
|
10
|
+
"required": true,
|
|
11
|
+
"describe": "GitHub PR number whose branch to revert commits on."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "shas",
|
|
15
|
+
"flag": "--shas",
|
|
16
|
+
"type": "string",
|
|
17
|
+
"required": true,
|
|
18
|
+
"bindsCommentRest": true,
|
|
19
|
+
"describe": "One or more commit SHAs (whitespace-separated) to revert. Each must exist in the PR branch's history."
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"claudeCode": {
|
|
23
|
+
"model": "inherit",
|
|
24
|
+
"permissionMode": "acceptEdits",
|
|
25
|
+
"maxTurns": 0,
|
|
26
|
+
"maxThinkingTokens": null,
|
|
27
|
+
"systemPromptAppend": null,
|
|
28
|
+
"tools": [],
|
|
29
|
+
"hooks": [],
|
|
30
|
+
"skills": [],
|
|
31
|
+
"commands": [],
|
|
32
|
+
"subagents": [],
|
|
33
|
+
"plugins": [],
|
|
34
|
+
"mcpServers": []
|
|
35
|
+
},
|
|
36
|
+
"cliTools": [],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"preflight": [
|
|
39
|
+
{
|
|
40
|
+
"script": "setLifecycleLabel",
|
|
41
|
+
"with": {
|
|
42
|
+
"label": "kody:reverting",
|
|
43
|
+
"color": "cccccc",
|
|
44
|
+
"description": "kody: reverting commits"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{ "script": "revertFlow" },
|
|
48
|
+
{ "shell": "revert.sh" }
|
|
49
|
+
],
|
|
50
|
+
"postflight": [
|
|
51
|
+
{ "script": "markFlowSuccess" },
|
|
52
|
+
{ "script": "commitAndPush" },
|
|
53
|
+
{ "script": "ensurePr" },
|
|
54
|
+
{ "script": "postIssueComment" },
|
|
55
|
+
{ "script": "writeRunSummary" }
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
"output": {
|
|
59
|
+
"actionTypes": [
|
|
60
|
+
"REVERT_COMPLETED",
|
|
61
|
+
"REVERT_FAILED"
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# revert: stage `git revert` of one or more commits on the PR branch.
|
|
4
|
+
#
|
|
5
|
+
# Runs as a preflight shell entry after revertFlow has validated inputs and
|
|
6
|
+
# checked out the branch. revertFlow:
|
|
7
|
+
# - Resolved every requested SHA to its full form and re-set
|
|
8
|
+
# ctx.args.shas to a whitespace-separated list (we read it via
|
|
9
|
+
# KODY_ARG_SHAS).
|
|
10
|
+
# - Set ctx.skipAgent=true and ctx.data.commitMessage already, so the
|
|
11
|
+
# agent never runs and commitAndPush will use that message.
|
|
12
|
+
#
|
|
13
|
+
# This script does only the staging — `--no-commit` so commitAndPush
|
|
14
|
+
# (postflight) makes the actual commit. That keeps kody's invariant
|
|
15
|
+
# intact (only commitAndPush commits) and means the message comes from
|
|
16
|
+
# revertFlow, not from git's auto-generated revert subject.
|
|
17
|
+
#
|
|
18
|
+
# Exits:
|
|
19
|
+
# 0 — staged successfully
|
|
20
|
+
# 1+ — git revert failed (executor surfaces stderr; postflight bails)
|
|
21
|
+
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
|
|
24
|
+
shas="${KODY_ARG_SHAS:-}"
|
|
25
|
+
if [[ -z "$shas" ]]; then
|
|
26
|
+
echo "revert.sh: KODY_ARG_SHAS is empty (revertFlow should have set it)" >&2
|
|
27
|
+
exit 64
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# shellcheck disable=SC2086 # Intentional word-splitting on whitespace-separated SHAs.
|
|
31
|
+
git revert --no-commit --no-edit $shas
|
|
32
|
+
|
|
33
|
+
echo "revert.sh: staged revert of: $shas"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.51",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|