@kody-ade/kody-engine 0.3.12 → 0.3.14
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 +530 -277
- package/dist/executables/fix/profile.json +1 -0
- package/dist/executables/fix-ci/profile.json +3 -0
- package/dist/executables/manager/profile.json +51 -0
- package/dist/executables/manager-tick/profile.json +72 -0
- package/dist/executables/manager-tick/prompt.md +54 -0
- package/dist/executables/resolve/profile.json +3 -0
- package/dist/executables/run/profile.json +1 -0
- package/package.json +1 -1
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.14",
|
|
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",
|
|
@@ -1163,11 +1163,187 @@ function parseScriptList(p, key, raw) {
|
|
|
1163
1163
|
return out;
|
|
1164
1164
|
}
|
|
1165
1165
|
|
|
1166
|
+
// src/commit.ts
|
|
1167
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
1168
|
+
import * as fs9 from "fs";
|
|
1169
|
+
import * as path8 from "path";
|
|
1170
|
+
var FORBIDDEN_PATH_PREFIXES = [
|
|
1171
|
+
".kody/",
|
|
1172
|
+
".kody-engine/",
|
|
1173
|
+
".kody/",
|
|
1174
|
+
".kody-lean/",
|
|
1175
|
+
// back-compat: stale runtime dir from kody-lean v0.5.x
|
|
1176
|
+
"node_modules/",
|
|
1177
|
+
"dist/",
|
|
1178
|
+
"build/"
|
|
1179
|
+
];
|
|
1180
|
+
var FORBIDDEN_PATH_EXACT = /* @__PURE__ */ new Set([".env", ".kody-pip-requirements.txt"]);
|
|
1181
|
+
var FORBIDDEN_PATH_SUFFIXES = [".log"];
|
|
1182
|
+
var CONVENTIONAL_PREFIXES = [
|
|
1183
|
+
"feat:",
|
|
1184
|
+
"fix:",
|
|
1185
|
+
"chore:",
|
|
1186
|
+
"docs:",
|
|
1187
|
+
"refactor:",
|
|
1188
|
+
"test:",
|
|
1189
|
+
"perf:",
|
|
1190
|
+
"ci:",
|
|
1191
|
+
"style:",
|
|
1192
|
+
"build:",
|
|
1193
|
+
"revert:"
|
|
1194
|
+
];
|
|
1195
|
+
function git(args, cwd) {
|
|
1196
|
+
try {
|
|
1197
|
+
return execFileSync2("git", args, {
|
|
1198
|
+
encoding: "utf-8",
|
|
1199
|
+
timeout: 12e4,
|
|
1200
|
+
cwd,
|
|
1201
|
+
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
|
|
1202
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
1203
|
+
}).trim();
|
|
1204
|
+
} catch (err) {
|
|
1205
|
+
const e = err;
|
|
1206
|
+
const stderr = e.stderr?.toString().trim() ?? "";
|
|
1207
|
+
const stdout = e.stdout?.toString().trim() ?? "";
|
|
1208
|
+
const status = e.status ?? "?";
|
|
1209
|
+
const detail = stderr || stdout || e.message || "(no output)";
|
|
1210
|
+
throw new Error(`git ${args.join(" ")} (exit ${status}):
|
|
1211
|
+
${detail}`);
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
function tryGit(args, cwd) {
|
|
1215
|
+
try {
|
|
1216
|
+
git(args, cwd);
|
|
1217
|
+
return true;
|
|
1218
|
+
} catch {
|
|
1219
|
+
return false;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
function abortUnfinishedGitOps(cwd) {
|
|
1223
|
+
const aborted = [];
|
|
1224
|
+
const gitDir = path8.join(cwd ?? process.cwd(), ".git");
|
|
1225
|
+
if (!fs9.existsSync(gitDir)) return aborted;
|
|
1226
|
+
if (fs9.existsSync(path8.join(gitDir, "MERGE_HEAD"))) {
|
|
1227
|
+
if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
|
|
1228
|
+
}
|
|
1229
|
+
if (fs9.existsSync(path8.join(gitDir, "CHERRY_PICK_HEAD"))) {
|
|
1230
|
+
if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
|
|
1231
|
+
}
|
|
1232
|
+
if (fs9.existsSync(path8.join(gitDir, "REVERT_HEAD"))) {
|
|
1233
|
+
if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
|
|
1234
|
+
}
|
|
1235
|
+
if (fs9.existsSync(path8.join(gitDir, "rebase-merge")) || fs9.existsSync(path8.join(gitDir, "rebase-apply"))) {
|
|
1236
|
+
if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
|
|
1237
|
+
}
|
|
1238
|
+
try {
|
|
1239
|
+
const unmerged = git(["diff", "--name-only", "--diff-filter=U"], cwd);
|
|
1240
|
+
if (unmerged) {
|
|
1241
|
+
tryGit(["reset", "--mixed", "HEAD"], cwd);
|
|
1242
|
+
aborted.push("unmerged-paths-reset");
|
|
1243
|
+
}
|
|
1244
|
+
} catch {
|
|
1245
|
+
}
|
|
1246
|
+
return aborted;
|
|
1247
|
+
}
|
|
1248
|
+
function isForbiddenPath(p) {
|
|
1249
|
+
if (FORBIDDEN_PATH_EXACT.has(p)) return true;
|
|
1250
|
+
for (const pre of FORBIDDEN_PATH_PREFIXES) if (p.startsWith(pre)) return true;
|
|
1251
|
+
for (const suf of FORBIDDEN_PATH_SUFFIXES) if (p.endsWith(suf)) return true;
|
|
1252
|
+
return false;
|
|
1253
|
+
}
|
|
1254
|
+
function listChangedFiles(cwd) {
|
|
1255
|
+
const raw = execFileSync2("git", ["status", "--porcelain=v1", "-z"], {
|
|
1256
|
+
encoding: "utf-8",
|
|
1257
|
+
cwd,
|
|
1258
|
+
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
|
|
1259
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
1260
|
+
});
|
|
1261
|
+
if (!raw) return [];
|
|
1262
|
+
const entries = raw.split("\0").filter((e) => e.length > 0);
|
|
1263
|
+
return entries.map((e) => e.slice(3)).filter(Boolean);
|
|
1264
|
+
}
|
|
1265
|
+
function listFilesInCommit(ref = "HEAD", cwd) {
|
|
1266
|
+
try {
|
|
1267
|
+
const raw = execFileSync2("git", ["show", "--name-only", "--pretty=format:", "-z", ref], {
|
|
1268
|
+
encoding: "utf-8",
|
|
1269
|
+
cwd,
|
|
1270
|
+
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
|
|
1271
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
1272
|
+
});
|
|
1273
|
+
return raw.split("\0").map((s) => s.trim()).filter(Boolean);
|
|
1274
|
+
} catch {
|
|
1275
|
+
return [];
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
function normalizeCommitMessage(raw) {
|
|
1279
|
+
const trimmed = raw.trim().replace(/^['"]|['"]$/g, "").trim();
|
|
1280
|
+
if (!trimmed) return "chore: kody update";
|
|
1281
|
+
const firstLine2 = trimmed.split("\n")[0];
|
|
1282
|
+
for (const prefix of CONVENTIONAL_PREFIXES) {
|
|
1283
|
+
if (firstLine2.toLowerCase().startsWith(prefix)) return trimmed;
|
|
1284
|
+
}
|
|
1285
|
+
return `chore: ${trimmed}`;
|
|
1286
|
+
}
|
|
1287
|
+
function commitAndPush(branch, agentMessage, cwd) {
|
|
1288
|
+
const allChanged = listChangedFiles(cwd);
|
|
1289
|
+
const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
|
|
1290
|
+
const mergeHeadExists = fs9.existsSync(path8.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
|
|
1291
|
+
if (allowedFiles.length === 0 && !mergeHeadExists) {
|
|
1292
|
+
return { committed: false, pushed: false, sha: "", message: "" };
|
|
1293
|
+
}
|
|
1294
|
+
for (const f of allowedFiles) {
|
|
1295
|
+
try {
|
|
1296
|
+
git(["add", "--", f], cwd);
|
|
1297
|
+
} catch {
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
const message = normalizeCommitMessage(agentMessage);
|
|
1301
|
+
try {
|
|
1302
|
+
git(["commit", "--no-gpg-sign", "-m", message], cwd);
|
|
1303
|
+
} catch (err) {
|
|
1304
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1305
|
+
if (/nothing to commit/i.test(msg)) {
|
|
1306
|
+
return { committed: false, pushed: false, sha: "", message };
|
|
1307
|
+
}
|
|
1308
|
+
throw err;
|
|
1309
|
+
}
|
|
1310
|
+
const sha = git(["rev-parse", "HEAD"], cwd).slice(0, 7);
|
|
1311
|
+
try {
|
|
1312
|
+
git(["push", "-u", "origin", branch], cwd);
|
|
1313
|
+
} catch {
|
|
1314
|
+
git(["push", "--force-with-lease", "-u", "origin", branch], cwd);
|
|
1315
|
+
}
|
|
1316
|
+
return { committed: true, pushed: true, sha, message };
|
|
1317
|
+
}
|
|
1318
|
+
function hasCommitsAhead(branch, defaultBranch, cwd) {
|
|
1319
|
+
try {
|
|
1320
|
+
const out = git(["rev-list", "--count", `origin/${defaultBranch}..${branch}`], cwd);
|
|
1321
|
+
return parseInt(out, 10) > 0;
|
|
1322
|
+
} catch {
|
|
1323
|
+
try {
|
|
1324
|
+
const out = git(["rev-list", "--count", `${defaultBranch}..${branch}`], cwd);
|
|
1325
|
+
return parseInt(out, 10) > 0;
|
|
1326
|
+
} catch {
|
|
1327
|
+
return false;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
// src/scripts/abortUnfinishedGitOps.ts
|
|
1333
|
+
var abortUnfinishedGitOps2 = async (ctx) => {
|
|
1334
|
+
if (ctx.data.agentDone === false) return;
|
|
1335
|
+
const aborted = abortUnfinishedGitOps(ctx.cwd);
|
|
1336
|
+
if (aborted.length > 0) {
|
|
1337
|
+
process.stderr.write(`[kody] cleaned up unfinished git ops: ${aborted.join(", ")}
|
|
1338
|
+
`);
|
|
1339
|
+
}
|
|
1340
|
+
};
|
|
1341
|
+
|
|
1166
1342
|
// src/scripts/advanceFlow.ts
|
|
1167
|
-
import { execFileSync as
|
|
1343
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
1168
1344
|
|
|
1169
1345
|
// src/state.ts
|
|
1170
|
-
import { execFileSync as
|
|
1346
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
1171
1347
|
var STATE_BEGIN = "<!-- kody:state:v1:begin -->";
|
|
1172
1348
|
var STATE_END = "<!-- kody:state:v1:end -->";
|
|
1173
1349
|
var HISTORY_MAX_ENTRIES = 20;
|
|
@@ -1193,7 +1369,7 @@ function ghToken() {
|
|
|
1193
1369
|
function gh(args, input, cwd) {
|
|
1194
1370
|
const token = ghToken();
|
|
1195
1371
|
const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
|
|
1196
|
-
return
|
|
1372
|
+
return execFileSync3("gh", args, {
|
|
1197
1373
|
encoding: "utf-8",
|
|
1198
1374
|
timeout: API_TIMEOUT_MS,
|
|
1199
1375
|
cwd,
|
|
@@ -1396,7 +1572,7 @@ var advanceFlow = async (ctx, profile) => {
|
|
|
1396
1572
|
}
|
|
1397
1573
|
const body = `@kody ${flow.name}`;
|
|
1398
1574
|
try {
|
|
1399
|
-
|
|
1575
|
+
execFileSync4("gh", ["issue", "comment", String(flow.issueNumber), "--body", body], {
|
|
1400
1576
|
timeout: API_TIMEOUT_MS2,
|
|
1401
1577
|
cwd: ctx.cwd,
|
|
1402
1578
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -1410,21 +1586,21 @@ var advanceFlow = async (ctx, profile) => {
|
|
|
1410
1586
|
};
|
|
1411
1587
|
|
|
1412
1588
|
// src/scripts/buildSyntheticPlugin.ts
|
|
1413
|
-
import * as
|
|
1589
|
+
import * as fs10 from "fs";
|
|
1414
1590
|
import * as os2 from "os";
|
|
1415
|
-
import * as
|
|
1591
|
+
import * as path9 from "path";
|
|
1416
1592
|
function getPluginsCatalogRoot() {
|
|
1417
|
-
const here =
|
|
1593
|
+
const here = path9.dirname(new URL(import.meta.url).pathname);
|
|
1418
1594
|
const candidates = [
|
|
1419
|
-
|
|
1595
|
+
path9.join(here, "..", "plugins"),
|
|
1420
1596
|
// dev: src/scripts → src/plugins
|
|
1421
|
-
|
|
1597
|
+
path9.join(here, "..", "..", "plugins"),
|
|
1422
1598
|
// built: dist/scripts → dist/plugins
|
|
1423
|
-
|
|
1599
|
+
path9.join(here, "..", "..", "src", "plugins")
|
|
1424
1600
|
// fallback
|
|
1425
1601
|
];
|
|
1426
1602
|
for (const c of candidates) {
|
|
1427
|
-
if (
|
|
1603
|
+
if (fs10.existsSync(c) && fs10.statSync(c).isDirectory()) return c;
|
|
1428
1604
|
}
|
|
1429
1605
|
return candidates[0];
|
|
1430
1606
|
}
|
|
@@ -1434,50 +1610,50 @@ var buildSyntheticPlugin = async (ctx, profile) => {
|
|
|
1434
1610
|
if (!needsSynthetic) return;
|
|
1435
1611
|
const catalog = getPluginsCatalogRoot();
|
|
1436
1612
|
const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1437
|
-
const root =
|
|
1438
|
-
|
|
1613
|
+
const root = path9.join(os2.tmpdir(), `kody-synth-${runId}`);
|
|
1614
|
+
fs10.mkdirSync(path9.join(root, ".claude-plugin"), { recursive: true });
|
|
1439
1615
|
if (cc.skills.length > 0) {
|
|
1440
|
-
const dst =
|
|
1441
|
-
|
|
1616
|
+
const dst = path9.join(root, "skills");
|
|
1617
|
+
fs10.mkdirSync(dst, { recursive: true });
|
|
1442
1618
|
for (const name of cc.skills) {
|
|
1443
|
-
const src =
|
|
1444
|
-
if (!
|
|
1445
|
-
copyDir(src,
|
|
1619
|
+
const src = path9.join(catalog, "skills", name);
|
|
1620
|
+
if (!fs10.existsSync(src)) throw new Error(`buildSyntheticPlugin: skill not found in catalog: ${name}`);
|
|
1621
|
+
copyDir(src, path9.join(dst, name));
|
|
1446
1622
|
}
|
|
1447
1623
|
}
|
|
1448
1624
|
if (cc.commands.length > 0) {
|
|
1449
|
-
const dst =
|
|
1450
|
-
|
|
1625
|
+
const dst = path9.join(root, "commands");
|
|
1626
|
+
fs10.mkdirSync(dst, { recursive: true });
|
|
1451
1627
|
for (const name of cc.commands) {
|
|
1452
|
-
const src =
|
|
1453
|
-
if (!
|
|
1454
|
-
|
|
1628
|
+
const src = path9.join(catalog, "commands", `${name}.md`);
|
|
1629
|
+
if (!fs10.existsSync(src)) throw new Error(`buildSyntheticPlugin: command not found in catalog: ${name}`);
|
|
1630
|
+
fs10.copyFileSync(src, path9.join(dst, `${name}.md`));
|
|
1455
1631
|
}
|
|
1456
1632
|
}
|
|
1457
1633
|
if (cc.subagents.length > 0) {
|
|
1458
|
-
const dst =
|
|
1459
|
-
|
|
1634
|
+
const dst = path9.join(root, "agents");
|
|
1635
|
+
fs10.mkdirSync(dst, { recursive: true });
|
|
1460
1636
|
for (const name of cc.subagents) {
|
|
1461
|
-
const src =
|
|
1462
|
-
if (!
|
|
1463
|
-
|
|
1637
|
+
const src = path9.join(catalog, "agents", `${name}.md`);
|
|
1638
|
+
if (!fs10.existsSync(src)) throw new Error(`buildSyntheticPlugin: subagent not found in catalog: ${name}`);
|
|
1639
|
+
fs10.copyFileSync(src, path9.join(dst, `${name}.md`));
|
|
1464
1640
|
}
|
|
1465
1641
|
}
|
|
1466
1642
|
if (cc.hooks.length > 0) {
|
|
1467
|
-
const dst =
|
|
1468
|
-
|
|
1643
|
+
const dst = path9.join(root, "hooks");
|
|
1644
|
+
fs10.mkdirSync(dst, { recursive: true });
|
|
1469
1645
|
const merged = { hooks: {} };
|
|
1470
1646
|
for (const name of cc.hooks) {
|
|
1471
|
-
const src =
|
|
1472
|
-
if (!
|
|
1473
|
-
const parsed = JSON.parse(
|
|
1647
|
+
const src = path9.join(catalog, "hooks", `${name}.json`);
|
|
1648
|
+
if (!fs10.existsSync(src)) throw new Error(`buildSyntheticPlugin: hook not found in catalog: ${name}`);
|
|
1649
|
+
const parsed = JSON.parse(fs10.readFileSync(src, "utf-8"));
|
|
1474
1650
|
for (const [event, entries] of Object.entries(parsed.hooks ?? {})) {
|
|
1475
1651
|
if (!Array.isArray(entries)) continue;
|
|
1476
1652
|
if (!merged.hooks[event]) merged.hooks[event] = [];
|
|
1477
1653
|
merged.hooks[event].push(...entries);
|
|
1478
1654
|
}
|
|
1479
1655
|
}
|
|
1480
|
-
|
|
1656
|
+
fs10.writeFileSync(path9.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
|
|
1481
1657
|
`);
|
|
1482
1658
|
}
|
|
1483
1659
|
const manifest = {
|
|
@@ -1488,22 +1664,22 @@ var buildSyntheticPlugin = async (ctx, profile) => {
|
|
|
1488
1664
|
if (cc.skills.length > 0) manifest.skills = ["./skills/"];
|
|
1489
1665
|
if (cc.commands.length > 0) manifest.commands = ["./commands/"];
|
|
1490
1666
|
if (cc.subagents.length > 0) manifest.agents = cc.subagents.map((n) => `./agents/${n}.md`);
|
|
1491
|
-
|
|
1667
|
+
fs10.writeFileSync(path9.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
|
|
1492
1668
|
`);
|
|
1493
1669
|
ctx.data.syntheticPluginPath = root;
|
|
1494
1670
|
};
|
|
1495
1671
|
function copyDir(src, dst) {
|
|
1496
|
-
|
|
1497
|
-
for (const ent of
|
|
1498
|
-
const s =
|
|
1499
|
-
const d =
|
|
1672
|
+
fs10.mkdirSync(dst, { recursive: true });
|
|
1673
|
+
for (const ent of fs10.readdirSync(src, { withFileTypes: true })) {
|
|
1674
|
+
const s = path9.join(src, ent.name);
|
|
1675
|
+
const d = path9.join(dst, ent.name);
|
|
1500
1676
|
if (ent.isDirectory()) copyDir(s, d);
|
|
1501
|
-
else if (ent.isFile())
|
|
1677
|
+
else if (ent.isFile()) fs10.copyFileSync(s, d);
|
|
1502
1678
|
}
|
|
1503
1679
|
}
|
|
1504
1680
|
|
|
1505
1681
|
// src/coverage.ts
|
|
1506
|
-
import { execFileSync as
|
|
1682
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
1507
1683
|
function patternToRegex(pattern) {
|
|
1508
1684
|
let s = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
1509
1685
|
s = s.replace(/\*\*\//g, "\xA7S").replace(/\*\*/g, "\xA7A").replace(/\*/g, "[^/]*");
|
|
@@ -1521,7 +1697,7 @@ function renderSiblingPath(file, requireSibling) {
|
|
|
1521
1697
|
}
|
|
1522
1698
|
function safeGit(args, cwd) {
|
|
1523
1699
|
try {
|
|
1524
|
-
return
|
|
1700
|
+
return execFileSync5("git", args, { encoding: "utf-8", cwd, env: { ...process.env, HUSKY: "0" } }).trim();
|
|
1525
1701
|
} catch {
|
|
1526
1702
|
return "";
|
|
1527
1703
|
}
|
|
@@ -1564,18 +1740,18 @@ function formatMissesForFeedback(misses) {
|
|
|
1564
1740
|
}
|
|
1565
1741
|
|
|
1566
1742
|
// src/prompt.ts
|
|
1567
|
-
import * as
|
|
1568
|
-
import * as
|
|
1743
|
+
import * as fs11 from "fs";
|
|
1744
|
+
import * as path10 from "path";
|
|
1569
1745
|
var CONVENTIONS_PER_FILE_MAX_BYTES = 3e4;
|
|
1570
1746
|
var CONVENTION_FILES = ["CLAUDE.md", "AGENTS.md"];
|
|
1571
1747
|
function loadProjectConventions(projectDir) {
|
|
1572
1748
|
const out = [];
|
|
1573
1749
|
for (const rel of CONVENTION_FILES) {
|
|
1574
|
-
const abs =
|
|
1575
|
-
if (!
|
|
1750
|
+
const abs = path10.join(projectDir, rel);
|
|
1751
|
+
if (!fs11.existsSync(abs)) continue;
|
|
1576
1752
|
let content;
|
|
1577
1753
|
try {
|
|
1578
|
-
content =
|
|
1754
|
+
content = fs11.readFileSync(abs, "utf-8");
|
|
1579
1755
|
} catch {
|
|
1580
1756
|
continue;
|
|
1581
1757
|
}
|
|
@@ -1735,176 +1911,8 @@ function defaultLabelMap() {
|
|
|
1735
1911
|
}
|
|
1736
1912
|
|
|
1737
1913
|
// src/scripts/commitAndPush.ts
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
// src/commit.ts
|
|
1741
|
-
import { execFileSync as execFileSync5 } from "child_process";
|
|
1742
|
-
import * as fs11 from "fs";
|
|
1743
|
-
import * as path10 from "path";
|
|
1744
|
-
var FORBIDDEN_PATH_PREFIXES = [
|
|
1745
|
-
".kody/",
|
|
1746
|
-
".kody-engine/",
|
|
1747
|
-
".kody/",
|
|
1748
|
-
".kody-lean/",
|
|
1749
|
-
// back-compat: stale runtime dir from kody-lean v0.5.x
|
|
1750
|
-
"node_modules/",
|
|
1751
|
-
"dist/",
|
|
1752
|
-
"build/"
|
|
1753
|
-
];
|
|
1754
|
-
var FORBIDDEN_PATH_EXACT = /* @__PURE__ */ new Set([".env", ".kody-pip-requirements.txt"]);
|
|
1755
|
-
var FORBIDDEN_PATH_SUFFIXES = [".log"];
|
|
1756
|
-
var CONVENTIONAL_PREFIXES = [
|
|
1757
|
-
"feat:",
|
|
1758
|
-
"fix:",
|
|
1759
|
-
"chore:",
|
|
1760
|
-
"docs:",
|
|
1761
|
-
"refactor:",
|
|
1762
|
-
"test:",
|
|
1763
|
-
"perf:",
|
|
1764
|
-
"ci:",
|
|
1765
|
-
"style:",
|
|
1766
|
-
"build:",
|
|
1767
|
-
"revert:"
|
|
1768
|
-
];
|
|
1769
|
-
function git(args, cwd) {
|
|
1770
|
-
try {
|
|
1771
|
-
return execFileSync5("git", args, {
|
|
1772
|
-
encoding: "utf-8",
|
|
1773
|
-
timeout: 12e4,
|
|
1774
|
-
cwd,
|
|
1775
|
-
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
|
|
1776
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
1777
|
-
}).trim();
|
|
1778
|
-
} catch (err) {
|
|
1779
|
-
const e = err;
|
|
1780
|
-
const stderr = e.stderr?.toString().trim() ?? "";
|
|
1781
|
-
const stdout = e.stdout?.toString().trim() ?? "";
|
|
1782
|
-
const status = e.status ?? "?";
|
|
1783
|
-
const detail = stderr || stdout || e.message || "(no output)";
|
|
1784
|
-
throw new Error(`git ${args.join(" ")} (exit ${status}):
|
|
1785
|
-
${detail}`);
|
|
1786
|
-
}
|
|
1787
|
-
}
|
|
1788
|
-
function tryGit(args, cwd) {
|
|
1789
|
-
try {
|
|
1790
|
-
git(args, cwd);
|
|
1791
|
-
return true;
|
|
1792
|
-
} catch {
|
|
1793
|
-
return false;
|
|
1794
|
-
}
|
|
1795
|
-
}
|
|
1796
|
-
function abortUnfinishedGitOps(cwd) {
|
|
1797
|
-
const aborted = [];
|
|
1798
|
-
const gitDir = path10.join(cwd ?? process.cwd(), ".git");
|
|
1799
|
-
if (!fs11.existsSync(gitDir)) return aborted;
|
|
1800
|
-
if (fs11.existsSync(path10.join(gitDir, "MERGE_HEAD"))) {
|
|
1801
|
-
if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
|
|
1802
|
-
}
|
|
1803
|
-
if (fs11.existsSync(path10.join(gitDir, "CHERRY_PICK_HEAD"))) {
|
|
1804
|
-
if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
|
|
1805
|
-
}
|
|
1806
|
-
if (fs11.existsSync(path10.join(gitDir, "REVERT_HEAD"))) {
|
|
1807
|
-
if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
|
|
1808
|
-
}
|
|
1809
|
-
if (fs11.existsSync(path10.join(gitDir, "rebase-merge")) || fs11.existsSync(path10.join(gitDir, "rebase-apply"))) {
|
|
1810
|
-
if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
|
|
1811
|
-
}
|
|
1812
|
-
try {
|
|
1813
|
-
const unmerged = git(["diff", "--name-only", "--diff-filter=U"], cwd);
|
|
1814
|
-
if (unmerged) {
|
|
1815
|
-
tryGit(["reset", "--mixed", "HEAD"], cwd);
|
|
1816
|
-
aborted.push("unmerged-paths-reset");
|
|
1817
|
-
}
|
|
1818
|
-
} catch {
|
|
1819
|
-
}
|
|
1820
|
-
return aborted;
|
|
1821
|
-
}
|
|
1822
|
-
function isForbiddenPath(p) {
|
|
1823
|
-
if (FORBIDDEN_PATH_EXACT.has(p)) return true;
|
|
1824
|
-
for (const pre of FORBIDDEN_PATH_PREFIXES) if (p.startsWith(pre)) return true;
|
|
1825
|
-
for (const suf of FORBIDDEN_PATH_SUFFIXES) if (p.endsWith(suf)) return true;
|
|
1826
|
-
return false;
|
|
1827
|
-
}
|
|
1828
|
-
function listChangedFiles(cwd) {
|
|
1829
|
-
const raw = execFileSync5("git", ["status", "--porcelain=v1", "-z"], {
|
|
1830
|
-
encoding: "utf-8",
|
|
1831
|
-
cwd,
|
|
1832
|
-
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
|
|
1833
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
1834
|
-
});
|
|
1835
|
-
if (!raw) return [];
|
|
1836
|
-
const entries = raw.split("\0").filter((e) => e.length > 0);
|
|
1837
|
-
return entries.map((e) => e.slice(3)).filter(Boolean);
|
|
1838
|
-
}
|
|
1839
|
-
function listFilesInCommit(ref = "HEAD", cwd) {
|
|
1840
|
-
try {
|
|
1841
|
-
const raw = execFileSync5("git", ["show", "--name-only", "--pretty=format:", "-z", ref], {
|
|
1842
|
-
encoding: "utf-8",
|
|
1843
|
-
cwd,
|
|
1844
|
-
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
|
|
1845
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
1846
|
-
});
|
|
1847
|
-
return raw.split("\0").map((s) => s.trim()).filter(Boolean);
|
|
1848
|
-
} catch {
|
|
1849
|
-
return [];
|
|
1850
|
-
}
|
|
1851
|
-
}
|
|
1852
|
-
function normalizeCommitMessage(raw) {
|
|
1853
|
-
const trimmed = raw.trim().replace(/^['"]|['"]$/g, "").trim();
|
|
1854
|
-
if (!trimmed) return "chore: kody update";
|
|
1855
|
-
const firstLine2 = trimmed.split("\n")[0];
|
|
1856
|
-
for (const prefix of CONVENTIONAL_PREFIXES) {
|
|
1857
|
-
if (firstLine2.toLowerCase().startsWith(prefix)) return trimmed;
|
|
1858
|
-
}
|
|
1859
|
-
return `chore: ${trimmed}`;
|
|
1860
|
-
}
|
|
1861
|
-
function commitAndPush(branch, agentMessage, cwd) {
|
|
1862
|
-
const allChanged = listChangedFiles(cwd);
|
|
1863
|
-
const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
|
|
1864
|
-
const mergeHeadExists = fs11.existsSync(path10.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
|
|
1865
|
-
if (allowedFiles.length === 0 && !mergeHeadExists) {
|
|
1866
|
-
return { committed: false, pushed: false, sha: "", message: "" };
|
|
1867
|
-
}
|
|
1868
|
-
for (const f of allowedFiles) {
|
|
1869
|
-
try {
|
|
1870
|
-
git(["add", "--", f], cwd);
|
|
1871
|
-
} catch {
|
|
1872
|
-
}
|
|
1873
|
-
}
|
|
1874
|
-
const message = normalizeCommitMessage(agentMessage);
|
|
1875
|
-
try {
|
|
1876
|
-
git(["commit", "--no-gpg-sign", "-m", message], cwd);
|
|
1877
|
-
} catch (err) {
|
|
1878
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1879
|
-
if (/nothing to commit/i.test(msg)) {
|
|
1880
|
-
return { committed: false, pushed: false, sha: "", message };
|
|
1881
|
-
}
|
|
1882
|
-
throw err;
|
|
1883
|
-
}
|
|
1884
|
-
const sha = git(["rev-parse", "HEAD"], cwd).slice(0, 7);
|
|
1885
|
-
try {
|
|
1886
|
-
git(["push", "-u", "origin", branch], cwd);
|
|
1887
|
-
} catch {
|
|
1888
|
-
git(["push", "--force-with-lease", "-u", "origin", branch], cwd);
|
|
1889
|
-
}
|
|
1890
|
-
return { committed: true, pushed: true, sha, message };
|
|
1891
|
-
}
|
|
1892
|
-
function hasCommitsAhead(branch, defaultBranch, cwd) {
|
|
1893
|
-
try {
|
|
1894
|
-
const out = git(["rev-list", "--count", `origin/${defaultBranch}..${branch}`], cwd);
|
|
1895
|
-
return parseInt(out, 10) > 0;
|
|
1896
|
-
} catch {
|
|
1897
|
-
try {
|
|
1898
|
-
const out = git(["rev-list", "--count", `${defaultBranch}..${branch}`], cwd);
|
|
1899
|
-
return parseInt(out, 10) > 0;
|
|
1900
|
-
} catch {
|
|
1901
|
-
return false;
|
|
1902
|
-
}
|
|
1903
|
-
}
|
|
1904
|
-
}
|
|
1905
|
-
|
|
1906
|
-
// src/scripts/commitAndPush.ts
|
|
1907
|
-
var commitAndPush2 = async (ctx, profile) => {
|
|
1914
|
+
var DEFAULT_COMMIT_MESSAGE = "chore: kody changes";
|
|
1915
|
+
var commitAndPush2 = async (ctx) => {
|
|
1908
1916
|
const branch = ctx.data.branch;
|
|
1909
1917
|
if (!branch) {
|
|
1910
1918
|
ctx.data.commitResult = { committed: false, pushed: false };
|
|
@@ -1915,21 +1923,7 @@ var commitAndPush2 = async (ctx, profile) => {
|
|
|
1915
1923
|
ctx.data.hasCommitsAhead = hasCommitsAhead(branch, ctx.config.git.defaultBranch, ctx.cwd);
|
|
1916
1924
|
return;
|
|
1917
1925
|
}
|
|
1918
|
-
const
|
|
1919
|
-
if (kind === "resolve") {
|
|
1920
|
-
try {
|
|
1921
|
-
execFileSync6("git", ["add", "-A"], { cwd: ctx.cwd, env: { ...process.env, HUSKY: "0" }, stdio: "pipe" });
|
|
1922
|
-
} catch {
|
|
1923
|
-
}
|
|
1924
|
-
} else {
|
|
1925
|
-
const aborted = abortUnfinishedGitOps(ctx.cwd);
|
|
1926
|
-
if (aborted.length > 0) {
|
|
1927
|
-
process.stderr.write(`[kody] cleaned up unfinished git ops: ${aborted.join(", ")}
|
|
1928
|
-
`);
|
|
1929
|
-
}
|
|
1930
|
-
}
|
|
1931
|
-
const fallbackMsg = defaultCommitMessage(kind, ctx.data);
|
|
1932
|
-
const message = ctx.data.commitMessage || fallbackMsg;
|
|
1926
|
+
const message = ctx.data.commitMessage || DEFAULT_COMMIT_MESSAGE;
|
|
1933
1927
|
try {
|
|
1934
1928
|
const result = commitAndPush(branch, message, ctx.cwd);
|
|
1935
1929
|
ctx.data.commitResult = result;
|
|
@@ -1941,20 +1935,6 @@ var commitAndPush2 = async (ctx, profile) => {
|
|
|
1941
1935
|
}
|
|
1942
1936
|
ctx.data.hasCommitsAhead = hasCommitsAhead(branch, ctx.config.git.defaultBranch, ctx.cwd);
|
|
1943
1937
|
};
|
|
1944
|
-
function defaultCommitMessage(mode, data) {
|
|
1945
|
-
switch (mode) {
|
|
1946
|
-
case "run":
|
|
1947
|
-
return `chore: kody changes for #${data.commentTargetNumber}`;
|
|
1948
|
-
case "fix":
|
|
1949
|
-
return `chore(fix): kody fix for PR #${data.commentTargetNumber}`;
|
|
1950
|
-
case "fix-ci":
|
|
1951
|
-
return `fix(ci): kody fix-ci for PR #${data.commentTargetNumber}`;
|
|
1952
|
-
case "resolve":
|
|
1953
|
-
return `fix: resolve merge conflicts with ${data.baseBranch}`;
|
|
1954
|
-
default:
|
|
1955
|
-
return `chore: kody changes`;
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
1938
|
|
|
1959
1939
|
// src/scripts/composePrompt.ts
|
|
1960
1940
|
import * as fs12 from "fs";
|
|
@@ -2055,7 +2035,7 @@ function formatToolsUsage(profile) {
|
|
|
2055
2035
|
}
|
|
2056
2036
|
|
|
2057
2037
|
// src/scripts/diagMcp.ts
|
|
2058
|
-
import { execFileSync as
|
|
2038
|
+
import { execFileSync as execFileSync6 } from "child_process";
|
|
2059
2039
|
import * as fs13 from "fs";
|
|
2060
2040
|
import * as os3 from "os";
|
|
2061
2041
|
import * as path12 from "path";
|
|
@@ -2075,7 +2055,7 @@ var diagMcp = async (_ctx) => {
|
|
|
2075
2055
|
process.stderr.write(`[kody diag] chromium present: ${hasChromium ? "yes" : "no"}
|
|
2076
2056
|
`);
|
|
2077
2057
|
try {
|
|
2078
|
-
const v =
|
|
2058
|
+
const v = execFileSync6(
|
|
2079
2059
|
"npx",
|
|
2080
2060
|
["-y", "--package=@playwright/mcp@latest", "--", "playwright-mcp", "--version"],
|
|
2081
2061
|
{ stdio: "pipe", timeout: 6e4, encoding: "utf8" }
|
|
@@ -2575,7 +2555,7 @@ var discoverQaContext = async (ctx) => {
|
|
|
2575
2555
|
};
|
|
2576
2556
|
|
|
2577
2557
|
// src/scripts/dispatch.ts
|
|
2578
|
-
import { execFileSync as
|
|
2558
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
2579
2559
|
var API_TIMEOUT_MS3 = 3e4;
|
|
2580
2560
|
var dispatch = async (ctx, _profile, _agentResult, args) => {
|
|
2581
2561
|
const next = args?.next;
|
|
@@ -2598,7 +2578,7 @@ var dispatch = async (ctx, _profile, _agentResult, args) => {
|
|
|
2598
2578
|
const sub = usePr ? "pr" : "issue";
|
|
2599
2579
|
const body = `@kody ${next}`;
|
|
2600
2580
|
try {
|
|
2601
|
-
|
|
2581
|
+
execFileSync7("gh", [sub, "comment", String(targetNumber), "--body", body], {
|
|
2602
2582
|
timeout: API_TIMEOUT_MS3,
|
|
2603
2583
|
cwd: ctx.cwd,
|
|
2604
2584
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -2618,7 +2598,7 @@ function parsePr(url) {
|
|
|
2618
2598
|
}
|
|
2619
2599
|
|
|
2620
2600
|
// src/issue.ts
|
|
2621
|
-
import { execFileSync as
|
|
2601
|
+
import { execFileSync as execFileSync8 } from "child_process";
|
|
2622
2602
|
var API_TIMEOUT_MS4 = 3e4;
|
|
2623
2603
|
function ghToken2() {
|
|
2624
2604
|
return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
|
|
@@ -2626,7 +2606,7 @@ function ghToken2() {
|
|
|
2626
2606
|
function gh2(args, options) {
|
|
2627
2607
|
const token = ghToken2();
|
|
2628
2608
|
const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
|
|
2629
|
-
return
|
|
2609
|
+
return execFileSync8("gh", args, {
|
|
2630
2610
|
encoding: "utf-8",
|
|
2631
2611
|
timeout: API_TIMEOUT_MS4,
|
|
2632
2612
|
cwd: options?.cwd,
|
|
@@ -2752,6 +2732,70 @@ function postPrReviewComment(prNumber, body, cwd) {
|
|
|
2752
2732
|
}
|
|
2753
2733
|
}
|
|
2754
2734
|
|
|
2735
|
+
// src/scripts/dispatchManagerTicks.ts
|
|
2736
|
+
var dispatchManagerTicks = async (ctx, _profile, args) => {
|
|
2737
|
+
ctx.skipAgent = true;
|
|
2738
|
+
const label = String(args?.label ?? "");
|
|
2739
|
+
const targetExecutable = String(args?.targetExecutable ?? "");
|
|
2740
|
+
if (!label) throw new Error("dispatchManagerTicks: `with.label` is required");
|
|
2741
|
+
if (!targetExecutable) throw new Error("dispatchManagerTicks: `with.targetExecutable` is required");
|
|
2742
|
+
const issueArg = String(args?.issueArg ?? "issue");
|
|
2743
|
+
const issues = listIssuesByLabel(label, ctx.cwd);
|
|
2744
|
+
ctx.data.managerIssueCount = issues.length;
|
|
2745
|
+
if (issues.length === 0) {
|
|
2746
|
+
process.stdout.write(`[manager] no open issues with label "${label}"
|
|
2747
|
+
`);
|
|
2748
|
+
return;
|
|
2749
|
+
}
|
|
2750
|
+
process.stdout.write(`[manager] ticking ${issues.length} issue(s) via ${targetExecutable}
|
|
2751
|
+
`);
|
|
2752
|
+
const results = [];
|
|
2753
|
+
for (const issue of issues) {
|
|
2754
|
+
process.stdout.write(`[manager] \u2192 tick #${issue.number}: ${issue.title}
|
|
2755
|
+
`);
|
|
2756
|
+
try {
|
|
2757
|
+
const out = await runExecutable(targetExecutable, {
|
|
2758
|
+
cliArgs: { [issueArg]: issue.number },
|
|
2759
|
+
cwd: ctx.cwd,
|
|
2760
|
+
config: ctx.config,
|
|
2761
|
+
verbose: ctx.verbose,
|
|
2762
|
+
quiet: ctx.quiet
|
|
2763
|
+
});
|
|
2764
|
+
results.push({ issue: issue.number, exitCode: out.exitCode, reason: out.reason });
|
|
2765
|
+
if (out.exitCode !== 0) {
|
|
2766
|
+
process.stderr.write(`[manager] tick #${issue.number} failed (exit ${out.exitCode}): ${out.reason ?? ""}
|
|
2767
|
+
`);
|
|
2768
|
+
}
|
|
2769
|
+
} catch (err) {
|
|
2770
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2771
|
+
process.stderr.write(`[manager] tick #${issue.number} crashed: ${msg}
|
|
2772
|
+
`);
|
|
2773
|
+
results.push({ issue: issue.number, exitCode: 99, reason: msg });
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
ctx.data.managerTickResults = results;
|
|
2777
|
+
ctx.output.exitCode = 0;
|
|
2778
|
+
};
|
|
2779
|
+
function listIssuesByLabel(label, cwd) {
|
|
2780
|
+
let raw = "";
|
|
2781
|
+
try {
|
|
2782
|
+
raw = gh2(
|
|
2783
|
+
["issue", "list", "--state", "open", "--label", label, "--limit", "100", "--json", "number,title"],
|
|
2784
|
+
{ cwd }
|
|
2785
|
+
);
|
|
2786
|
+
} catch {
|
|
2787
|
+
return [];
|
|
2788
|
+
}
|
|
2789
|
+
let list;
|
|
2790
|
+
try {
|
|
2791
|
+
list = JSON.parse(raw);
|
|
2792
|
+
} catch {
|
|
2793
|
+
return [];
|
|
2794
|
+
}
|
|
2795
|
+
if (!Array.isArray(list)) return [];
|
|
2796
|
+
return list.filter((x) => typeof x.number === "number" && typeof x.title === "string").map((x) => ({ number: x.number, title: x.title }));
|
|
2797
|
+
}
|
|
2798
|
+
|
|
2755
2799
|
// src/pr.ts
|
|
2756
2800
|
var TITLE_MAX = 72;
|
|
2757
2801
|
function stripTitlePrefixes(raw) {
|
|
@@ -2930,7 +2974,7 @@ function computeFailureReason(ctx) {
|
|
|
2930
2974
|
}
|
|
2931
2975
|
|
|
2932
2976
|
// src/scripts/finishFlow.ts
|
|
2933
|
-
import { execFileSync as
|
|
2977
|
+
import { execFileSync as execFileSync9 } from "child_process";
|
|
2934
2978
|
|
|
2935
2979
|
// src/lifecycleLabels.ts
|
|
2936
2980
|
var KODY_NAMESPACE = "kody";
|
|
@@ -3089,7 +3133,7 @@ var finishFlow = async (ctx, _profile, _agentResult, args) => {
|
|
|
3089
3133
|
**PR:** ${state.core.prUrl}` : "";
|
|
3090
3134
|
const body = `${icon} kody flow \`${flowName}\` finished \u2014 \`${reason}\`${prSuffix}`;
|
|
3091
3135
|
try {
|
|
3092
|
-
|
|
3136
|
+
execFileSync9("gh", ["issue", "comment", String(issueNumber), "--body", body], {
|
|
3093
3137
|
timeout: API_TIMEOUT_MS5,
|
|
3094
3138
|
cwd: ctx.cwd,
|
|
3095
3139
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -3103,7 +3147,7 @@ var finishFlow = async (ctx, _profile, _agentResult, args) => {
|
|
|
3103
3147
|
};
|
|
3104
3148
|
|
|
3105
3149
|
// src/branch.ts
|
|
3106
|
-
import { execFileSync as
|
|
3150
|
+
import { execFileSync as execFileSync10 } from "child_process";
|
|
3107
3151
|
var UncommittedChangesError = class extends Error {
|
|
3108
3152
|
constructor(branch) {
|
|
3109
3153
|
super(`Uncommitted changes on branch '${branch}' \u2014 refusing to run to protect work in progress`);
|
|
@@ -3113,7 +3157,7 @@ var UncommittedChangesError = class extends Error {
|
|
|
3113
3157
|
branch;
|
|
3114
3158
|
};
|
|
3115
3159
|
function git2(args, cwd) {
|
|
3116
|
-
return
|
|
3160
|
+
return execFileSync10("git", args, {
|
|
3117
3161
|
encoding: "utf-8",
|
|
3118
3162
|
timeout: 3e4,
|
|
3119
3163
|
cwd,
|
|
@@ -3138,7 +3182,7 @@ function checkoutPrBranch(prNumber, cwd) {
|
|
|
3138
3182
|
SKIP_HOOKS: "1",
|
|
3139
3183
|
GH_TOKEN: process.env.GH_PAT?.trim() || process.env.GH_TOKEN || ""
|
|
3140
3184
|
};
|
|
3141
|
-
|
|
3185
|
+
execFileSync10("gh", ["pr", "checkout", String(prNumber)], {
|
|
3142
3186
|
cwd,
|
|
3143
3187
|
env,
|
|
3144
3188
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -3205,7 +3249,7 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch, cwd) {
|
|
|
3205
3249
|
}
|
|
3206
3250
|
|
|
3207
3251
|
// src/gha.ts
|
|
3208
|
-
import { execFileSync as
|
|
3252
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
3209
3253
|
import * as fs16 from "fs";
|
|
3210
3254
|
function getRunUrl() {
|
|
3211
3255
|
const server = process.env.GITHUB_SERVER_URL;
|
|
@@ -3248,7 +3292,7 @@ function reactToTriggerComment(cwd) {
|
|
|
3248
3292
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
3249
3293
|
if (attempt > 0) sleepMs(attempt === 1 ? 500 : 1500);
|
|
3250
3294
|
try {
|
|
3251
|
-
|
|
3295
|
+
execFileSync11("gh", args, opts);
|
|
3252
3296
|
return;
|
|
3253
3297
|
} catch (err) {
|
|
3254
3298
|
lastErr = err;
|
|
@@ -3261,13 +3305,13 @@ function reactToTriggerComment(cwd) {
|
|
|
3261
3305
|
}
|
|
3262
3306
|
function sleepMs(ms) {
|
|
3263
3307
|
try {
|
|
3264
|
-
|
|
3308
|
+
execFileSync11("sleep", [(ms / 1e3).toString()], { stdio: "ignore", timeout: ms + 1e3 });
|
|
3265
3309
|
} catch {
|
|
3266
3310
|
}
|
|
3267
3311
|
}
|
|
3268
3312
|
|
|
3269
3313
|
// src/workflow.ts
|
|
3270
|
-
import { execFileSync as
|
|
3314
|
+
import { execFileSync as execFileSync12 } from "child_process";
|
|
3271
3315
|
var GH_TIMEOUT_MS = 3e4;
|
|
3272
3316
|
function ghToken3() {
|
|
3273
3317
|
return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
|
|
@@ -3275,7 +3319,7 @@ function ghToken3() {
|
|
|
3275
3319
|
function gh3(args, cwd) {
|
|
3276
3320
|
const token = ghToken3();
|
|
3277
3321
|
const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
|
|
3278
|
-
return
|
|
3322
|
+
return execFileSync12("gh", args, {
|
|
3279
3323
|
encoding: "utf-8",
|
|
3280
3324
|
timeout: GH_TIMEOUT_MS,
|
|
3281
3325
|
cwd,
|
|
@@ -3459,7 +3503,7 @@ function tryPostPr2(prNumber, body, cwd) {
|
|
|
3459
3503
|
}
|
|
3460
3504
|
|
|
3461
3505
|
// src/scripts/initFlow.ts
|
|
3462
|
-
import { execFileSync as
|
|
3506
|
+
import { execFileSync as execFileSync13 } from "child_process";
|
|
3463
3507
|
import * as fs18 from "fs";
|
|
3464
3508
|
import * as path16 from "path";
|
|
3465
3509
|
|
|
@@ -3500,7 +3544,7 @@ function qualityCommandsFor(pm) {
|
|
|
3500
3544
|
function detectOwnerRepo(cwd) {
|
|
3501
3545
|
let url;
|
|
3502
3546
|
try {
|
|
3503
|
-
url =
|
|
3547
|
+
url = execFileSync13("git", ["remote", "get-url", "origin"], {
|
|
3504
3548
|
cwd,
|
|
3505
3549
|
encoding: "utf-8",
|
|
3506
3550
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -3584,7 +3628,7 @@ jobs:
|
|
|
3584
3628
|
`;
|
|
3585
3629
|
function defaultBranchFromGit(cwd) {
|
|
3586
3630
|
try {
|
|
3587
|
-
const ref =
|
|
3631
|
+
const ref = execFileSync13("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
|
|
3588
3632
|
cwd,
|
|
3589
3633
|
encoding: "utf-8",
|
|
3590
3634
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -3592,7 +3636,7 @@ function defaultBranchFromGit(cwd) {
|
|
|
3592
3636
|
return ref.replace("refs/remotes/origin/", "");
|
|
3593
3637
|
} catch {
|
|
3594
3638
|
try {
|
|
3595
|
-
return
|
|
3639
|
+
return execFileSync13("git", ["branch", "--show-current"], {
|
|
3596
3640
|
cwd,
|
|
3597
3641
|
encoding: "utf-8",
|
|
3598
3642
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -3764,6 +3808,112 @@ var loadIssueContext = async (ctx) => {
|
|
|
3764
3808
|
ctx.data.commentTargetNumber = issueNumber;
|
|
3765
3809
|
};
|
|
3766
3810
|
|
|
3811
|
+
// src/scripts/issueStateComment.ts
|
|
3812
|
+
function isStateEnvelope(x) {
|
|
3813
|
+
if (x === null || typeof x !== "object") return false;
|
|
3814
|
+
const o = x;
|
|
3815
|
+
return o.version === 1 && typeof o.rev === "number" && Number.isInteger(o.rev) && o.rev >= 0 && typeof o.cursor === "string" && typeof o.done === "boolean" && o.data !== null && typeof o.data === "object" && !Array.isArray(o.data);
|
|
3816
|
+
}
|
|
3817
|
+
function formatStateCommentBody(marker, state) {
|
|
3818
|
+
return `<!-- ${marker} -->
|
|
3819
|
+
|
|
3820
|
+
\`\`\`json
|
|
3821
|
+
${JSON.stringify(state, null, 2)}
|
|
3822
|
+
\`\`\`
|
|
3823
|
+
`;
|
|
3824
|
+
}
|
|
3825
|
+
function parseStateCommentBody(marker, body) {
|
|
3826
|
+
const markerLine = `<!-- ${marker} -->`;
|
|
3827
|
+
if (!body.trimStart().startsWith(markerLine)) return null;
|
|
3828
|
+
const fenceOpen = body.indexOf("```json");
|
|
3829
|
+
if (fenceOpen === -1) return null;
|
|
3830
|
+
const after = body.slice(fenceOpen + "```json".length);
|
|
3831
|
+
const fenceClose = after.indexOf("```");
|
|
3832
|
+
if (fenceClose === -1) return null;
|
|
3833
|
+
const jsonText = after.slice(0, fenceClose).trim();
|
|
3834
|
+
let parsed;
|
|
3835
|
+
try {
|
|
3836
|
+
parsed = JSON.parse(jsonText);
|
|
3837
|
+
} catch {
|
|
3838
|
+
return null;
|
|
3839
|
+
}
|
|
3840
|
+
return isStateEnvelope(parsed) ? parsed : null;
|
|
3841
|
+
}
|
|
3842
|
+
function listIssueComments(owner, repo, issueNumber, cwd) {
|
|
3843
|
+
const raw = gh2(["api", "--paginate", `repos/${owner}/${repo}/issues/${issueNumber}/comments`], { cwd });
|
|
3844
|
+
let parsed;
|
|
3845
|
+
try {
|
|
3846
|
+
parsed = JSON.parse(raw);
|
|
3847
|
+
} catch {
|
|
3848
|
+
return [];
|
|
3849
|
+
}
|
|
3850
|
+
if (!Array.isArray(parsed)) return [];
|
|
3851
|
+
return parsed.filter((c) => typeof c.id === "number" && typeof c.node_id === "string" && typeof c.body === "string").map((c) => ({ id: c.id, node_id: c.node_id, body: c.body }));
|
|
3852
|
+
}
|
|
3853
|
+
function findStateComment2(owner, repo, issueNumber, marker, cwd) {
|
|
3854
|
+
const comments = listIssueComments(owner, repo, issueNumber, cwd);
|
|
3855
|
+
for (const c of comments) {
|
|
3856
|
+
const state = parseStateCommentBody(marker, c.body);
|
|
3857
|
+
if (!state) continue;
|
|
3858
|
+
return { commentId: c.id, commentNodeId: c.node_id, state };
|
|
3859
|
+
}
|
|
3860
|
+
return null;
|
|
3861
|
+
}
|
|
3862
|
+
function createStateComment(owner, repo, issueNumber, marker, state, cwd) {
|
|
3863
|
+
const body = formatStateCommentBody(marker, state);
|
|
3864
|
+
const raw = gh2(
|
|
3865
|
+
["api", "--method", "POST", `repos/${owner}/${repo}/issues/${issueNumber}/comments`, "--input", "-"],
|
|
3866
|
+
{ cwd, input: JSON.stringify({ body }) }
|
|
3867
|
+
);
|
|
3868
|
+
const parsed = JSON.parse(raw);
|
|
3869
|
+
try {
|
|
3870
|
+
minimizeComment(parsed.node_id, cwd);
|
|
3871
|
+
} catch {
|
|
3872
|
+
}
|
|
3873
|
+
return { commentId: parsed.id, commentNodeId: parsed.node_id, state };
|
|
3874
|
+
}
|
|
3875
|
+
function updateStateComment(owner, repo, commentId, commentNodeId, marker, state, cwd) {
|
|
3876
|
+
const body = formatStateCommentBody(marker, state);
|
|
3877
|
+
gh2(
|
|
3878
|
+
["api", "--method", "PATCH", `repos/${owner}/${repo}/issues/comments/${commentId}`, "--input", "-"],
|
|
3879
|
+
{ cwd, input: JSON.stringify({ body }) }
|
|
3880
|
+
);
|
|
3881
|
+
try {
|
|
3882
|
+
minimizeComment(commentNodeId, cwd);
|
|
3883
|
+
} catch {
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3886
|
+
function minimizeComment(nodeId, cwd) {
|
|
3887
|
+
const mutation = "mutation($id: ID!) { minimizeComment(input: { classifier: OUTDATED, subjectId: $id }) { minimizedComment { isMinimized } } }";
|
|
3888
|
+
gh2(["api", "graphql", "-f", `query=${mutation}`, "-f", `id=${nodeId}`], { cwd });
|
|
3889
|
+
}
|
|
3890
|
+
|
|
3891
|
+
// src/scripts/loadIssueStateComment.ts
|
|
3892
|
+
var loadIssueStateComment = async (ctx, _profile, args) => {
|
|
3893
|
+
const marker = String(args?.marker ?? "");
|
|
3894
|
+
if (!marker) {
|
|
3895
|
+
throw new Error("loadIssueStateComment: `with.marker` is required");
|
|
3896
|
+
}
|
|
3897
|
+
const issueArg = String(args?.issueArg ?? "issue");
|
|
3898
|
+
const issueNumber = Number(ctx.args[issueArg]);
|
|
3899
|
+
if (!Number.isFinite(issueNumber) || issueNumber <= 0) {
|
|
3900
|
+
throw new Error(`loadIssueStateComment: ctx.args.${issueArg} must be a positive integer`);
|
|
3901
|
+
}
|
|
3902
|
+
const owner = ctx.config.github.owner;
|
|
3903
|
+
const repo = ctx.config.github.repo;
|
|
3904
|
+
if (!owner || !repo) {
|
|
3905
|
+
throw new Error("loadIssueStateComment: ctx.config.github.owner/repo must be set");
|
|
3906
|
+
}
|
|
3907
|
+
const issue = getIssue(issueNumber, ctx.cwd);
|
|
3908
|
+
const loaded = findStateComment2(owner, repo, issueNumber, marker, ctx.cwd);
|
|
3909
|
+
ctx.data.stateMarker = marker;
|
|
3910
|
+
ctx.data.issueIntent = issue.body;
|
|
3911
|
+
ctx.data.issueTitle = issue.title;
|
|
3912
|
+
ctx.data.issueNumber = String(issueNumber);
|
|
3913
|
+
ctx.data.issueStateComment = loaded;
|
|
3914
|
+
ctx.data.issueStateJson = loaded ? JSON.stringify(loaded.state, null, 2) : "null";
|
|
3915
|
+
};
|
|
3916
|
+
|
|
3767
3917
|
// src/scripts/loadPriorArt.ts
|
|
3768
3918
|
var PER_PR_DIFF_MAX_BYTES = 8e3;
|
|
3769
3919
|
var TOTAL_MAX_BYTES = 3e4;
|
|
@@ -3931,6 +4081,53 @@ function makeAction(type, payload) {
|
|
|
3931
4081
|
return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
3932
4082
|
}
|
|
3933
4083
|
|
|
4084
|
+
// src/scripts/parseIssueStateFromAgentResult.ts
|
|
4085
|
+
function isPartialEnvelope(x) {
|
|
4086
|
+
if (x === null || typeof x !== "object") return false;
|
|
4087
|
+
const o = x;
|
|
4088
|
+
return typeof o.cursor === "string" && o.cursor.length > 0 && typeof o.done === "boolean" && o.data !== null && typeof o.data === "object" && !Array.isArray(o.data);
|
|
4089
|
+
}
|
|
4090
|
+
var parseIssueStateFromAgentResult = async (ctx, _profile, agentResult, args) => {
|
|
4091
|
+
const fenceLabel = String(args?.fenceLabel ?? "");
|
|
4092
|
+
if (!fenceLabel) {
|
|
4093
|
+
throw new Error("parseIssueStateFromAgentResult: `with.fenceLabel` is required");
|
|
4094
|
+
}
|
|
4095
|
+
if (!agentResult) {
|
|
4096
|
+
ctx.data.nextStateParseError = "agent did not run";
|
|
4097
|
+
return;
|
|
4098
|
+
}
|
|
4099
|
+
const fenceRegex = new RegExp("```" + escapeRegex(fenceLabel) + "\\s*\\n([\\s\\S]*?)\\n```", "m");
|
|
4100
|
+
const match = fenceRegex.exec(agentResult.finalText);
|
|
4101
|
+
if (!match) {
|
|
4102
|
+
ctx.data.nextStateParseError = `agent did not emit a \`${fenceLabel}\` fenced block`;
|
|
4103
|
+
return;
|
|
4104
|
+
}
|
|
4105
|
+
let parsed;
|
|
4106
|
+
try {
|
|
4107
|
+
parsed = JSON.parse(match[1].trim());
|
|
4108
|
+
} catch (err) {
|
|
4109
|
+
ctx.data.nextStateParseError = `state JSON parse error: ${err instanceof Error ? err.message : String(err)}`;
|
|
4110
|
+
return;
|
|
4111
|
+
}
|
|
4112
|
+
if (!isPartialEnvelope(parsed)) {
|
|
4113
|
+
ctx.data.nextStateParseError = "state must be an object with string `cursor`, object `data`, and boolean `done`";
|
|
4114
|
+
return;
|
|
4115
|
+
}
|
|
4116
|
+
const loaded = ctx.data.issueStateComment;
|
|
4117
|
+
const prevRev = loaded?.state.rev ?? 0;
|
|
4118
|
+
const next = {
|
|
4119
|
+
version: 1,
|
|
4120
|
+
rev: prevRev + 1,
|
|
4121
|
+
cursor: parsed.cursor,
|
|
4122
|
+
data: parsed.data,
|
|
4123
|
+
done: parsed.done
|
|
4124
|
+
};
|
|
4125
|
+
ctx.data.nextIssueState = next;
|
|
4126
|
+
};
|
|
4127
|
+
function escapeRegex(s) {
|
|
4128
|
+
return s.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
4129
|
+
}
|
|
4130
|
+
|
|
3934
4131
|
// src/scripts/persistArtifacts.ts
|
|
3935
4132
|
var persistArtifacts = async (ctx, profile) => {
|
|
3936
4133
|
if (profile.outputArtifacts.length === 0) return;
|
|
@@ -3977,7 +4174,7 @@ var persistFlowState = async (ctx) => {
|
|
|
3977
4174
|
};
|
|
3978
4175
|
|
|
3979
4176
|
// src/scripts/postClassification.ts
|
|
3980
|
-
import { execFileSync as
|
|
4177
|
+
import { execFileSync as execFileSync14 } from "child_process";
|
|
3981
4178
|
var API_TIMEOUT_MS6 = 3e4;
|
|
3982
4179
|
var VALID_CLASSES2 = /* @__PURE__ */ new Set(["feature", "bug", "spec", "chore"]);
|
|
3983
4180
|
var postClassification = async (ctx) => {
|
|
@@ -4007,7 +4204,7 @@ var postClassification = async (ctx) => {
|
|
|
4007
4204
|
ctx.cwd
|
|
4008
4205
|
);
|
|
4009
4206
|
try {
|
|
4010
|
-
|
|
4207
|
+
execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", `@kody ${classification}`], {
|
|
4011
4208
|
cwd: ctx.cwd,
|
|
4012
4209
|
timeout: API_TIMEOUT_MS6,
|
|
4013
4210
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -4041,7 +4238,7 @@ function parseClassification(prSummary) {
|
|
|
4041
4238
|
}
|
|
4042
4239
|
function tryAuditComment(issueNumber, body, cwd) {
|
|
4043
4240
|
try {
|
|
4044
|
-
|
|
4241
|
+
execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", body], {
|
|
4045
4242
|
cwd,
|
|
4046
4243
|
timeout: API_TIMEOUT_MS6,
|
|
4047
4244
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -4225,7 +4422,7 @@ REVIEW_POSTED=https://github.com/${ctx.config.github.owner}/${ctx.config.github.
|
|
|
4225
4422
|
};
|
|
4226
4423
|
|
|
4227
4424
|
// src/scripts/releaseFlow.ts
|
|
4228
|
-
import { execFileSync as
|
|
4425
|
+
import { execFileSync as execFileSync15, spawnSync } from "child_process";
|
|
4229
4426
|
import * as fs19 from "fs";
|
|
4230
4427
|
import * as path17 from "path";
|
|
4231
4428
|
function notifyIssue(issueNumber, body, cwd) {
|
|
@@ -4265,7 +4462,7 @@ function generateChangelog(cwd, newVersion, lastTag) {
|
|
|
4265
4462
|
else logArgs.splice(1, 0, `-n${FIRST_RELEASE_COMMIT_CAP}`, "HEAD");
|
|
4266
4463
|
let log = "";
|
|
4267
4464
|
try {
|
|
4268
|
-
log =
|
|
4465
|
+
log = execFileSync15("git", logArgs, {
|
|
4269
4466
|
cwd,
|
|
4270
4467
|
encoding: "utf-8",
|
|
4271
4468
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -4322,7 +4519,7 @@ ${entry}${prior.slice(idx + 1)}`);
|
|
|
4322
4519
|
}
|
|
4323
4520
|
}
|
|
4324
4521
|
function git3(args, cwd, timeout = 6e4) {
|
|
4325
|
-
return
|
|
4522
|
+
return execFileSync15("git", args, {
|
|
4326
4523
|
encoding: "utf-8",
|
|
4327
4524
|
timeout,
|
|
4328
4525
|
cwd,
|
|
@@ -4699,7 +4896,7 @@ var resolveArtifacts = async (ctx, profile) => {
|
|
|
4699
4896
|
};
|
|
4700
4897
|
|
|
4701
4898
|
// src/scripts/resolveFlow.ts
|
|
4702
|
-
import { execFileSync as
|
|
4899
|
+
import { execFileSync as execFileSync16 } from "child_process";
|
|
4703
4900
|
var CONFLICT_DIFF_MAX_BYTES = 4e4;
|
|
4704
4901
|
var resolveFlow = async (ctx) => {
|
|
4705
4902
|
const prNumber = ctx.args.pr;
|
|
@@ -4769,7 +4966,7 @@ function buildPreferBlock(prefer, baseBranch) {
|
|
|
4769
4966
|
}
|
|
4770
4967
|
function getConflictedFiles(cwd) {
|
|
4771
4968
|
try {
|
|
4772
|
-
const out =
|
|
4969
|
+
const out = execFileSync16("git", ["diff", "--name-only", "--diff-filter=U"], {
|
|
4773
4970
|
encoding: "utf-8",
|
|
4774
4971
|
cwd,
|
|
4775
4972
|
env: { ...process.env, HUSKY: "0" }
|
|
@@ -4784,7 +4981,7 @@ function getConflictMarkersPreview(files, cwd, maxBytes = CONFLICT_DIFF_MAX_BYTE
|
|
|
4784
4981
|
let total = 0;
|
|
4785
4982
|
for (const f of files) {
|
|
4786
4983
|
try {
|
|
4787
|
-
const content =
|
|
4984
|
+
const content = execFileSync16("cat", [f], { encoding: "utf-8", cwd }).toString();
|
|
4788
4985
|
const snippet = `### ${f}
|
|
4789
4986
|
|
|
4790
4987
|
\`\`\`
|
|
@@ -4947,6 +5144,20 @@ var skipAgent = async (ctx) => {
|
|
|
4947
5144
|
ctx.skipAgent = true;
|
|
4948
5145
|
};
|
|
4949
5146
|
|
|
5147
|
+
// src/scripts/stageMergeConflicts.ts
|
|
5148
|
+
import { execFileSync as execFileSync17 } from "child_process";
|
|
5149
|
+
var stageMergeConflicts = async (ctx) => {
|
|
5150
|
+
if (ctx.data.agentDone === false) return;
|
|
5151
|
+
try {
|
|
5152
|
+
execFileSync17("git", ["add", "-A"], {
|
|
5153
|
+
cwd: ctx.cwd,
|
|
5154
|
+
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
|
|
5155
|
+
stdio: "pipe"
|
|
5156
|
+
});
|
|
5157
|
+
} catch {
|
|
5158
|
+
}
|
|
5159
|
+
};
|
|
5160
|
+
|
|
4950
5161
|
// src/scripts/startFlow.ts
|
|
4951
5162
|
import { execFileSync as execFileSync18 } from "child_process";
|
|
4952
5163
|
var API_TIMEOUT_MS7 = 3e4;
|
|
@@ -5238,6 +5449,42 @@ var watchStalePrsFlow = async (ctx) => {
|
|
|
5238
5449
|
ctx.data.staleCount = stale.length;
|
|
5239
5450
|
};
|
|
5240
5451
|
|
|
5452
|
+
// src/scripts/writeIssueStateComment.ts
|
|
5453
|
+
var writeIssueStateComment = async (ctx, _profile, _agentResult, args) => {
|
|
5454
|
+
const marker = String(args?.marker ?? "");
|
|
5455
|
+
if (!marker) {
|
|
5456
|
+
throw new Error("writeIssueStateComment: `with.marker` is required");
|
|
5457
|
+
}
|
|
5458
|
+
const issueArg = String(args?.issueArg ?? "issue");
|
|
5459
|
+
const issueNumber = Number(ctx.args[issueArg]);
|
|
5460
|
+
if (!Number.isFinite(issueNumber) || issueNumber <= 0) {
|
|
5461
|
+
throw new Error(`writeIssueStateComment: ctx.args.${issueArg} must be a positive integer`);
|
|
5462
|
+
}
|
|
5463
|
+
const parseError = ctx.data.nextStateParseError;
|
|
5464
|
+
if (parseError) {
|
|
5465
|
+
process.stderr.write(`[kody] state write skipped: ${parseError}
|
|
5466
|
+
`);
|
|
5467
|
+
if (ctx.output.exitCode === 0) ctx.output.exitCode = 1;
|
|
5468
|
+
if (!ctx.output.reason) ctx.output.reason = `next-state parse failed: ${parseError}`;
|
|
5469
|
+
return;
|
|
5470
|
+
}
|
|
5471
|
+
const next = ctx.data.nextIssueState;
|
|
5472
|
+
if (!next) {
|
|
5473
|
+
return;
|
|
5474
|
+
}
|
|
5475
|
+
const owner = ctx.config.github.owner;
|
|
5476
|
+
const repo = ctx.config.github.repo;
|
|
5477
|
+
if (!owner || !repo) {
|
|
5478
|
+
throw new Error("writeIssueStateComment: ctx.config.github.owner/repo must be set");
|
|
5479
|
+
}
|
|
5480
|
+
const loaded = ctx.data.issueStateComment;
|
|
5481
|
+
if (loaded) {
|
|
5482
|
+
updateStateComment(owner, repo, loaded.commentId, loaded.commentNodeId, marker, next, ctx.cwd);
|
|
5483
|
+
} else {
|
|
5484
|
+
createStateComment(owner, repo, issueNumber, marker, next, ctx.cwd);
|
|
5485
|
+
}
|
|
5486
|
+
};
|
|
5487
|
+
|
|
5241
5488
|
// src/scripts/writeRunSummary.ts
|
|
5242
5489
|
import * as fs20 from "fs";
|
|
5243
5490
|
var writeRunSummary = async (ctx, profile) => {
|
|
@@ -5280,6 +5527,7 @@ var preflightScripts = {
|
|
|
5280
5527
|
watchStalePrsFlow,
|
|
5281
5528
|
loadTaskState,
|
|
5282
5529
|
loadIssueContext,
|
|
5530
|
+
loadIssueStateComment,
|
|
5283
5531
|
loadConventions,
|
|
5284
5532
|
loadCoverageRules,
|
|
5285
5533
|
loadPriorArt,
|
|
@@ -5292,14 +5540,19 @@ var preflightScripts = {
|
|
|
5292
5540
|
setLifecycleLabel,
|
|
5293
5541
|
skipAgent,
|
|
5294
5542
|
classifyByLabel,
|
|
5295
|
-
diagMcp
|
|
5543
|
+
diagMcp,
|
|
5544
|
+
dispatchManagerTicks
|
|
5296
5545
|
};
|
|
5297
5546
|
var postflightScripts = {
|
|
5298
5547
|
parseAgentResult: parseAgentResult2,
|
|
5548
|
+
parseIssueStateFromAgentResult,
|
|
5549
|
+
writeIssueStateComment,
|
|
5299
5550
|
requireFeedbackActions,
|
|
5300
5551
|
requirePlanDeviations,
|
|
5301
5552
|
verify,
|
|
5302
5553
|
checkCoverageWithRetry,
|
|
5554
|
+
abortUnfinishedGitOps: abortUnfinishedGitOps2,
|
|
5555
|
+
stageMergeConflicts,
|
|
5303
5556
|
commitAndPush: commitAndPush2,
|
|
5304
5557
|
ensurePr: ensurePr2,
|
|
5305
5558
|
postIssueComment: postIssueComment2,
|