@kody-ade/kody-engine 0.2.61 → 0.2.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/kody2.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // package.json
4
4
  var package_default = {
5
5
  name: "@kody-ade/kody-engine",
6
- version: "0.2.61",
6
+ version: "0.2.62",
7
7
  description: "kody2 \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
8
8
  license: "MIT",
9
9
  type: "module",
@@ -50,7 +50,7 @@ var package_default = {
50
50
  };
51
51
 
52
52
  // src/chat-cli.ts
53
- import { execFileSync as execFileSync23 } from "child_process";
53
+ import { execFileSync as execFileSync21 } from "child_process";
54
54
  import * as fs22 from "fs";
55
55
  import * as path19 from "path";
56
56
 
@@ -543,7 +543,7 @@ async function emit(sink, type, sessionId, suffix, payload) {
543
543
  }
544
544
 
545
545
  // src/kody2-cli.ts
546
- import { execFileSync as execFileSync22 } from "child_process";
546
+ import { execFileSync as execFileSync20 } from "child_process";
547
547
  import * as fs21 from "fs";
548
548
  import * as path18 from "path";
549
549
 
@@ -581,9 +581,6 @@ function autoDispatch(opts) {
581
581
  if (!targetNum) return null;
582
582
  const afterTag = extractAfterTag(body);
583
583
  if (isPr) {
584
- if (/\bapprove\b/.test(afterTag)) {
585
- return { executable: "approve", cliArgs: { pr: targetNum }, target: targetNum };
586
- }
587
584
  if (/\bfix-ci\b/.test(afterTag)) {
588
585
  return { executable: "fix-ci", cliArgs: { pr: targetNum }, target: targetNum };
589
586
  }
@@ -1241,206 +1238,6 @@ var advanceFlow = async (ctx, profile) => {
1241
1238
  }
1242
1239
  };
1243
1240
 
1244
- // src/scripts/applyApprovals.ts
1245
- import { execFileSync as execFileSync5 } from "child_process";
1246
-
1247
- // src/issue.ts
1248
- import { execFileSync as execFileSync4 } from "child_process";
1249
- var API_TIMEOUT_MS3 = 3e4;
1250
- function ghToken2() {
1251
- return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
1252
- }
1253
- function gh2(args, options) {
1254
- const token = ghToken2();
1255
- const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
1256
- return execFileSync4("gh", args, {
1257
- encoding: "utf-8",
1258
- timeout: API_TIMEOUT_MS3,
1259
- cwd: options?.cwd,
1260
- env,
1261
- input: options?.input,
1262
- stdio: options?.input ? ["pipe", "pipe", "pipe"] : ["inherit", "pipe", "pipe"]
1263
- }).trim();
1264
- }
1265
- function getIssue(issueNumber, cwd) {
1266
- const output = gh2(["issue", "view", String(issueNumber), "--json", "number,title,body,comments,labels"], { cwd });
1267
- const parsed = JSON.parse(output);
1268
- if (typeof parsed?.title !== "string") {
1269
- throw new Error(`Issue #${issueNumber}: unexpected response shape`);
1270
- }
1271
- return {
1272
- number: parsed.number ?? issueNumber,
1273
- title: parsed.title,
1274
- body: parsed.body ?? "",
1275
- comments: (parsed.comments ?? []).map((c) => ({
1276
- body: c.body ?? "",
1277
- author: c.author?.login ?? "unknown",
1278
- createdAt: c.createdAt ?? ""
1279
- })),
1280
- labels: Array.isArray(parsed.labels) ? parsed.labels.map((l) => l.name ?? "").filter((n) => n.length > 0) : []
1281
- };
1282
- }
1283
- function stripKody2Mentions(body) {
1284
- return body.replace(/(@)(kody2)/gi, "$1\u200B$2");
1285
- }
1286
- function postIssueComment(issueNumber, body, cwd) {
1287
- try {
1288
- gh2(["issue", "comment", String(issueNumber), "--body-file", "-"], { input: stripKody2Mentions(body), cwd });
1289
- } catch (err) {
1290
- process.stderr.write(
1291
- `[kody2] failed to post comment on #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
1292
- `
1293
- );
1294
- }
1295
- }
1296
- function truncate2(s, maxBytes) {
1297
- if (s.length <= maxBytes) return s;
1298
- return `${s.slice(0, maxBytes)}\u2026 (+${s.length - maxBytes} chars)`;
1299
- }
1300
- function getPr(prNumber, cwd) {
1301
- const output = gh2(["pr", "view", String(prNumber), "--json", "number,title,body,headRefName,baseRefName,state"], {
1302
- cwd
1303
- });
1304
- const parsed = JSON.parse(output);
1305
- if (typeof parsed?.title !== "string") {
1306
- throw new Error(`PR #${prNumber}: unexpected response shape`);
1307
- }
1308
- return {
1309
- number: parsed.number ?? prNumber,
1310
- title: parsed.title,
1311
- body: parsed.body ?? "",
1312
- headRefName: String(parsed.headRefName ?? ""),
1313
- baseRefName: String(parsed.baseRefName ?? ""),
1314
- state: String(parsed.state ?? "")
1315
- };
1316
- }
1317
- function getPrDiff(prNumber, cwd) {
1318
- try {
1319
- return gh2(["pr", "diff", String(prNumber)], { cwd });
1320
- } catch (err) {
1321
- process.stderr.write(
1322
- `[kody2] failed to fetch diff for PR #${prNumber}: ${err instanceof Error ? err.message : String(err)}
1323
- `
1324
- );
1325
- return "";
1326
- }
1327
- }
1328
- function getPrReviews(prNumber, cwd) {
1329
- try {
1330
- const output = gh2(["pr", "view", String(prNumber), "--json", "reviews"], { cwd });
1331
- const parsed = JSON.parse(output);
1332
- if (!Array.isArray(parsed?.reviews)) return [];
1333
- return parsed.reviews.map(
1334
- (r) => ({
1335
- body: r.body ?? "",
1336
- state: r.state ?? "",
1337
- author: r.author?.login ?? "unknown",
1338
- submittedAt: r.submittedAt ?? ""
1339
- })
1340
- );
1341
- } catch {
1342
- return [];
1343
- }
1344
- }
1345
- function getPrComments(prNumber, cwd) {
1346
- try {
1347
- const output = gh2(["pr", "view", String(prNumber), "--json", "comments"], { cwd });
1348
- const parsed = JSON.parse(output);
1349
- if (!Array.isArray(parsed?.comments)) return [];
1350
- return parsed.comments.map((c) => ({
1351
- body: c.body ?? "",
1352
- author: c.author?.login ?? "unknown",
1353
- createdAt: c.createdAt ?? ""
1354
- })).filter((c) => c.body.trim().length > 0);
1355
- } catch {
1356
- return [];
1357
- }
1358
- }
1359
- var VERDICT_HEADING = /(^|\n)\s*#{1,6}\s*Verdict\s*:/i;
1360
- function isReviewShaped(body) {
1361
- return VERDICT_HEADING.test(body);
1362
- }
1363
- function getPrLatestReviewBody(prNumber, cwd) {
1364
- const reviews = getPrReviews(prNumber, cwd).filter((r) => r.body.trim().length > 0).map((r) => ({ body: r.body, at: r.submittedAt }));
1365
- const comments = getPrComments(prNumber, cwd).filter((c) => isReviewShaped(c.body)).map((c) => ({ body: c.body, at: c.createdAt }));
1366
- const all = [...reviews, ...comments].sort((a, b) => (b.at || "").localeCompare(a.at || ""));
1367
- if (all.length > 0) return all[0].body;
1368
- const pr = getPr(prNumber, cwd);
1369
- return pr.body;
1370
- }
1371
- function postPrReviewComment(prNumber, body, cwd) {
1372
- try {
1373
- gh2(["pr", "comment", String(prNumber), "--body-file", "-"], { input: stripKody2Mentions(body), cwd });
1374
- } catch (err) {
1375
- process.stderr.write(
1376
- `[kody2] failed to post review comment on PR #${prNumber}: ${err instanceof Error ? err.message : String(err)}
1377
- `
1378
- );
1379
- }
1380
- }
1381
-
1382
- // src/scripts/applyApprovals.ts
1383
- var API_TIMEOUT_MS4 = 3e4;
1384
- var applyApprovals = async (ctx) => {
1385
- const issueArg = typeof ctx.args.issue === "number" ? ctx.args.issue : null;
1386
- const prArg = typeof ctx.args.pr === "number" ? ctx.args.pr : null;
1387
- const currentTarget = issueArg ? { type: "issue", number: issueArg } : prArg ? { type: "pr", number: prArg } : null;
1388
- if (!currentTarget) {
1389
- ctx.output.exitCode = 64;
1390
- ctx.output.reason = "approve: must be invoked with --issue or --pr";
1391
- return;
1392
- }
1393
- let state = null;
1394
- try {
1395
- state = readTaskState(currentTarget.type, currentTarget.number, ctx.cwd);
1396
- } catch {
1397
- state = null;
1398
- }
1399
- const issueNumber = currentTarget.type === "issue" ? currentTarget.number : state?.flow?.issueNumber ?? null;
1400
- const flowName = state?.flow?.name ?? null;
1401
- const confirmation = formatConfirmation(currentTarget, flowName, issueNumber);
1402
- try {
1403
- if (currentTarget.type === "issue") postIssueComment(currentTarget.number, confirmation, ctx.cwd);
1404
- else postPrReviewComment(currentTarget.number, confirmation, ctx.cwd);
1405
- } catch {
1406
- }
1407
- if (issueNumber && typeof flowName === "string" && flowName.length > 0) {
1408
- try {
1409
- execFileSync5("gh", ["issue", "comment", String(issueNumber), "--body", `@kody2 ${flowName}`], {
1410
- timeout: API_TIMEOUT_MS4,
1411
- cwd: ctx.cwd,
1412
- stdio: ["ignore", "pipe", "pipe"]
1413
- });
1414
- } catch (err) {
1415
- process.stderr.write(
1416
- `[kody2 approve] failed to re-trigger flow on issue #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
1417
- `
1418
- );
1419
- }
1420
- }
1421
- ctx.output.exitCode = 0;
1422
- };
1423
- function formatConfirmation(current, flowName, issueNumber) {
1424
- const lines = [];
1425
- lines.push("\u2705 **kody2 risk gates approved.**");
1426
- lines.push("");
1427
- lines.push("The approval is recorded as this comment \u2014 kody2 reads it directly on the next run.");
1428
- if (flowName && issueNumber) {
1429
- lines.push("");
1430
- if (current.type === "pr") {
1431
- lines.push(
1432
- `Re-triggering the \`${flowName}\` flow on the originating issue (#${issueNumber}) \u2014 it will resume from the existing branch/PR checkpoint.`
1433
- );
1434
- } else {
1435
- lines.push(`Re-triggering the \`${flowName}\` flow now \u2014 it will resume from the existing branch checkpoint.`);
1436
- }
1437
- } else {
1438
- lines.push("");
1439
- lines.push("No active flow found in task state. Post `@kody2 <command>` to resume manually.");
1440
- }
1441
- return lines.join("\n");
1442
- }
1443
-
1444
1241
  // src/scripts/buildSyntheticPlugin.ts
1445
1242
  import * as fs8 from "fs";
1446
1243
  import * as os2 from "os";
@@ -1535,7 +1332,7 @@ function copyDir(src, dst) {
1535
1332
  }
1536
1333
 
1537
1334
  // src/coverage.ts
1538
- import { execFileSync as execFileSync6 } from "child_process";
1335
+ import { execFileSync as execFileSync4 } from "child_process";
1539
1336
  function patternToRegex(pattern) {
1540
1337
  let s = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
1541
1338
  s = s.replace(/\*\*\//g, "\xA7S").replace(/\*\*/g, "\xA7A").replace(/\*/g, "[^/]*");
@@ -1553,7 +1350,7 @@ function renderSiblingPath(file, requireSibling) {
1553
1350
  }
1554
1351
  function safeGit(args, cwd) {
1555
1352
  try {
1556
- return execFileSync6("git", args, { encoding: "utf-8", cwd, env: { ...process.env, HUSKY: "0" } }).trim();
1353
+ return execFileSync4("git", args, { encoding: "utf-8", cwd, env: { ...process.env, HUSKY: "0" } }).trim();
1557
1354
  } catch {
1558
1355
  return "";
1559
1356
  }
@@ -1759,10 +1556,10 @@ function defaultLabelMap() {
1759
1556
  }
1760
1557
 
1761
1558
  // src/scripts/commitAndPush.ts
1762
- import { execFileSync as execFileSync8 } from "child_process";
1559
+ import { execFileSync as execFileSync6 } from "child_process";
1763
1560
 
1764
1561
  // src/commit.ts
1765
- import { execFileSync as execFileSync7 } from "child_process";
1562
+ import { execFileSync as execFileSync5 } from "child_process";
1766
1563
  import * as fs10 from "fs";
1767
1564
  import * as path9 from "path";
1768
1565
  var FORBIDDEN_PATH_PREFIXES = [
@@ -1792,7 +1589,7 @@ var CONVENTIONAL_PREFIXES = [
1792
1589
  ];
1793
1590
  function git(args, cwd) {
1794
1591
  try {
1795
- return execFileSync7("git", args, {
1592
+ return execFileSync5("git", args, {
1796
1593
  encoding: "utf-8",
1797
1594
  timeout: 12e4,
1798
1595
  cwd,
@@ -1850,7 +1647,7 @@ function isForbiddenPath(p) {
1850
1647
  return false;
1851
1648
  }
1852
1649
  function listChangedFiles(cwd) {
1853
- const raw = execFileSync7("git", ["status", "--porcelain=v1", "-z"], {
1650
+ const raw = execFileSync5("git", ["status", "--porcelain=v1", "-z"], {
1854
1651
  encoding: "utf-8",
1855
1652
  cwd,
1856
1653
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
@@ -1862,7 +1659,7 @@ function listChangedFiles(cwd) {
1862
1659
  }
1863
1660
  function listFilesInCommit(ref = "HEAD", cwd) {
1864
1661
  try {
1865
- const raw = execFileSync7("git", ["show", "--name-only", "--pretty=format:", "-z", ref], {
1662
+ const raw = execFileSync5("git", ["show", "--name-only", "--pretty=format:", "-z", ref], {
1866
1663
  encoding: "utf-8",
1867
1664
  cwd,
1868
1665
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
@@ -1942,7 +1739,7 @@ var commitAndPush2 = async (ctx, profile) => {
1942
1739
  const kind = profile.name;
1943
1740
  if (kind === "resolve") {
1944
1741
  try {
1945
- execFileSync8("git", ["add", "-A"], { cwd: ctx.cwd, env: { ...process.env, HUSKY: "0" }, stdio: "pipe" });
1742
+ execFileSync6("git", ["add", "-A"], { cwd: ctx.cwd, env: { ...process.env, HUSKY: "0" }, stdio: "pipe" });
1946
1743
  } catch {
1947
1744
  }
1948
1745
  } else {
@@ -2564,8 +2361,8 @@ var discoverQaContext = async (ctx) => {
2564
2361
  };
2565
2362
 
2566
2363
  // src/scripts/dispatch.ts
2567
- import { execFileSync as execFileSync9 } from "child_process";
2568
- var API_TIMEOUT_MS5 = 3e4;
2364
+ import { execFileSync as execFileSync7 } from "child_process";
2365
+ var API_TIMEOUT_MS3 = 3e4;
2569
2366
  var dispatch = async (ctx, _profile, _agentResult, args) => {
2570
2367
  const next = args?.next;
2571
2368
  if (!next) {
@@ -2587,8 +2384,8 @@ var dispatch = async (ctx, _profile, _agentResult, args) => {
2587
2384
  const sub = usePr ? "pr" : "issue";
2588
2385
  const body = `@kody2 ${next}`;
2589
2386
  try {
2590
- execFileSync9("gh", [sub, "comment", String(targetNumber), "--body", body], {
2591
- timeout: API_TIMEOUT_MS5,
2387
+ execFileSync7("gh", [sub, "comment", String(targetNumber), "--body", body], {
2388
+ timeout: API_TIMEOUT_MS3,
2592
2389
  cwd: ctx.cwd,
2593
2390
  stdio: ["ignore", "pipe", "pipe"]
2594
2391
  });
@@ -2606,6 +2403,141 @@ function parsePr(url) {
2606
2403
  return Number.isFinite(n) ? n : null;
2607
2404
  }
2608
2405
 
2406
+ // src/issue.ts
2407
+ import { execFileSync as execFileSync8 } from "child_process";
2408
+ var API_TIMEOUT_MS4 = 3e4;
2409
+ function ghToken2() {
2410
+ return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
2411
+ }
2412
+ function gh2(args, options) {
2413
+ const token = ghToken2();
2414
+ const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
2415
+ return execFileSync8("gh", args, {
2416
+ encoding: "utf-8",
2417
+ timeout: API_TIMEOUT_MS4,
2418
+ cwd: options?.cwd,
2419
+ env,
2420
+ input: options?.input,
2421
+ stdio: options?.input ? ["pipe", "pipe", "pipe"] : ["inherit", "pipe", "pipe"]
2422
+ }).trim();
2423
+ }
2424
+ function getIssue(issueNumber, cwd) {
2425
+ const output = gh2(["issue", "view", String(issueNumber), "--json", "number,title,body,comments,labels"], { cwd });
2426
+ const parsed = JSON.parse(output);
2427
+ if (typeof parsed?.title !== "string") {
2428
+ throw new Error(`Issue #${issueNumber}: unexpected response shape`);
2429
+ }
2430
+ return {
2431
+ number: parsed.number ?? issueNumber,
2432
+ title: parsed.title,
2433
+ body: parsed.body ?? "",
2434
+ comments: (parsed.comments ?? []).map((c) => ({
2435
+ body: c.body ?? "",
2436
+ author: c.author?.login ?? "unknown",
2437
+ createdAt: c.createdAt ?? ""
2438
+ })),
2439
+ labels: Array.isArray(parsed.labels) ? parsed.labels.map((l) => l.name ?? "").filter((n) => n.length > 0) : []
2440
+ };
2441
+ }
2442
+ function stripKody2Mentions(body) {
2443
+ return body.replace(/(@)(kody2)/gi, "$1\u200B$2");
2444
+ }
2445
+ function postIssueComment(issueNumber, body, cwd) {
2446
+ try {
2447
+ gh2(["issue", "comment", String(issueNumber), "--body-file", "-"], { input: stripKody2Mentions(body), cwd });
2448
+ } catch (err) {
2449
+ process.stderr.write(
2450
+ `[kody2] failed to post comment on #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
2451
+ `
2452
+ );
2453
+ }
2454
+ }
2455
+ function truncate2(s, maxBytes) {
2456
+ if (s.length <= maxBytes) return s;
2457
+ return `${s.slice(0, maxBytes)}\u2026 (+${s.length - maxBytes} chars)`;
2458
+ }
2459
+ function getPr(prNumber, cwd) {
2460
+ const output = gh2(["pr", "view", String(prNumber), "--json", "number,title,body,headRefName,baseRefName,state"], {
2461
+ cwd
2462
+ });
2463
+ const parsed = JSON.parse(output);
2464
+ if (typeof parsed?.title !== "string") {
2465
+ throw new Error(`PR #${prNumber}: unexpected response shape`);
2466
+ }
2467
+ return {
2468
+ number: parsed.number ?? prNumber,
2469
+ title: parsed.title,
2470
+ body: parsed.body ?? "",
2471
+ headRefName: String(parsed.headRefName ?? ""),
2472
+ baseRefName: String(parsed.baseRefName ?? ""),
2473
+ state: String(parsed.state ?? "")
2474
+ };
2475
+ }
2476
+ function getPrDiff(prNumber, cwd) {
2477
+ try {
2478
+ return gh2(["pr", "diff", String(prNumber)], { cwd });
2479
+ } catch (err) {
2480
+ process.stderr.write(
2481
+ `[kody2] failed to fetch diff for PR #${prNumber}: ${err instanceof Error ? err.message : String(err)}
2482
+ `
2483
+ );
2484
+ return "";
2485
+ }
2486
+ }
2487
+ function getPrReviews(prNumber, cwd) {
2488
+ try {
2489
+ const output = gh2(["pr", "view", String(prNumber), "--json", "reviews"], { cwd });
2490
+ const parsed = JSON.parse(output);
2491
+ if (!Array.isArray(parsed?.reviews)) return [];
2492
+ return parsed.reviews.map(
2493
+ (r) => ({
2494
+ body: r.body ?? "",
2495
+ state: r.state ?? "",
2496
+ author: r.author?.login ?? "unknown",
2497
+ submittedAt: r.submittedAt ?? ""
2498
+ })
2499
+ );
2500
+ } catch {
2501
+ return [];
2502
+ }
2503
+ }
2504
+ function getPrComments(prNumber, cwd) {
2505
+ try {
2506
+ const output = gh2(["pr", "view", String(prNumber), "--json", "comments"], { cwd });
2507
+ const parsed = JSON.parse(output);
2508
+ if (!Array.isArray(parsed?.comments)) return [];
2509
+ return parsed.comments.map((c) => ({
2510
+ body: c.body ?? "",
2511
+ author: c.author?.login ?? "unknown",
2512
+ createdAt: c.createdAt ?? ""
2513
+ })).filter((c) => c.body.trim().length > 0);
2514
+ } catch {
2515
+ return [];
2516
+ }
2517
+ }
2518
+ var VERDICT_HEADING = /(^|\n)\s*#{1,6}\s*Verdict\s*:/i;
2519
+ function isReviewShaped(body) {
2520
+ return VERDICT_HEADING.test(body);
2521
+ }
2522
+ function getPrLatestReviewBody(prNumber, cwd) {
2523
+ const reviews = getPrReviews(prNumber, cwd).filter((r) => r.body.trim().length > 0).map((r) => ({ body: r.body, at: r.submittedAt }));
2524
+ const comments = getPrComments(prNumber, cwd).filter((c) => isReviewShaped(c.body)).map((c) => ({ body: c.body, at: c.createdAt }));
2525
+ const all = [...reviews, ...comments].sort((a, b) => (b.at || "").localeCompare(a.at || ""));
2526
+ if (all.length > 0) return all[0].body;
2527
+ const pr = getPr(prNumber, cwd);
2528
+ return pr.body;
2529
+ }
2530
+ function postPrReviewComment(prNumber, body, cwd) {
2531
+ try {
2532
+ gh2(["pr", "comment", String(prNumber), "--body-file", "-"], { input: stripKody2Mentions(body), cwd });
2533
+ } catch (err) {
2534
+ process.stderr.write(
2535
+ `[kody2] failed to post review comment on PR #${prNumber}: ${err instanceof Error ? err.message : String(err)}
2536
+ `
2537
+ );
2538
+ }
2539
+ }
2540
+
2609
2541
  // src/pr.ts
2610
2542
  var TITLE_MAX = 72;
2611
2543
  function stripTitlePrefixes(raw) {
@@ -2771,7 +2703,7 @@ function computeFailureReason(ctx) {
2771
2703
  }
2772
2704
 
2773
2705
  // src/scripts/finishFlow.ts
2774
- import { execFileSync as execFileSync10 } from "child_process";
2706
+ import { execFileSync as execFileSync9 } from "child_process";
2775
2707
 
2776
2708
  // src/registry.ts
2777
2709
  import * as fs14 from "fs";
@@ -2959,7 +2891,7 @@ function errMsg(err) {
2959
2891
  }
2960
2892
 
2961
2893
  // src/scripts/finishFlow.ts
2962
- var API_TIMEOUT_MS6 = 3e4;
2894
+ var API_TIMEOUT_MS5 = 3e4;
2963
2895
  var STATUS_ICON = {
2964
2896
  "review-passed": "\u2705",
2965
2897
  "fix-applied": "\u2705",
@@ -2991,8 +2923,8 @@ var finishFlow = async (ctx, _profile, _agentResult, args) => {
2991
2923
  **PR:** ${state.core.prUrl}` : "";
2992
2924
  const body = `${icon} kody2 flow \`${flowName}\` finished \u2014 \`${reason}\`${prSuffix}`;
2993
2925
  try {
2994
- execFileSync10("gh", ["issue", "comment", String(issueNumber), "--body", body], {
2995
- timeout: API_TIMEOUT_MS6,
2926
+ execFileSync9("gh", ["issue", "comment", String(issueNumber), "--body", body], {
2927
+ timeout: API_TIMEOUT_MS5,
2996
2928
  cwd: ctx.cwd,
2997
2929
  stdio: ["ignore", "pipe", "pipe"]
2998
2930
  });
@@ -3005,7 +2937,7 @@ var finishFlow = async (ctx, _profile, _agentResult, args) => {
3005
2937
  };
3006
2938
 
3007
2939
  // src/branch.ts
3008
- import { execFileSync as execFileSync11 } from "child_process";
2940
+ import { execFileSync as execFileSync10 } from "child_process";
3009
2941
  var UncommittedChangesError = class extends Error {
3010
2942
  constructor(branch) {
3011
2943
  super(`Uncommitted changes on branch '${branch}' \u2014 refusing to run to protect work in progress`);
@@ -3015,7 +2947,7 @@ var UncommittedChangesError = class extends Error {
3015
2947
  branch;
3016
2948
  };
3017
2949
  function git2(args, cwd) {
3018
- return execFileSync11("git", args, {
2950
+ return execFileSync10("git", args, {
3019
2951
  encoding: "utf-8",
3020
2952
  timeout: 3e4,
3021
2953
  cwd,
@@ -3040,7 +2972,7 @@ function checkoutPrBranch(prNumber, cwd) {
3040
2972
  SKIP_HOOKS: "1",
3041
2973
  GH_TOKEN: process.env.GH_PAT?.trim() || process.env.GH_TOKEN || ""
3042
2974
  };
3043
- execFileSync11("gh", ["pr", "checkout", String(prNumber)], {
2975
+ execFileSync10("gh", ["pr", "checkout", String(prNumber)], {
3044
2976
  cwd,
3045
2977
  env,
3046
2978
  stdio: ["ignore", "pipe", "pipe"],
@@ -3107,7 +3039,7 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch, cwd) {
3107
3039
  }
3108
3040
 
3109
3041
  // src/gha.ts
3110
- import { execFileSync as execFileSync12 } from "child_process";
3042
+ import { execFileSync as execFileSync11 } from "child_process";
3111
3043
  import * as fs15 from "fs";
3112
3044
  function getRunUrl() {
3113
3045
  const server = process.env.GITHUB_SERVER_URL;
@@ -3150,7 +3082,7 @@ function reactToTriggerComment(cwd) {
3150
3082
  for (let attempt = 0; attempt < 3; attempt++) {
3151
3083
  if (attempt > 0) sleepMs(attempt === 1 ? 500 : 1500);
3152
3084
  try {
3153
- execFileSync12("gh", args, opts);
3085
+ execFileSync11("gh", args, opts);
3154
3086
  return;
3155
3087
  } catch (err) {
3156
3088
  lastErr = err;
@@ -3163,13 +3095,13 @@ function reactToTriggerComment(cwd) {
3163
3095
  }
3164
3096
  function sleepMs(ms) {
3165
3097
  try {
3166
- execFileSync12("sleep", [(ms / 1e3).toString()], { stdio: "ignore", timeout: ms + 1e3 });
3098
+ execFileSync11("sleep", [(ms / 1e3).toString()], { stdio: "ignore", timeout: ms + 1e3 });
3167
3099
  } catch {
3168
3100
  }
3169
3101
  }
3170
3102
 
3171
3103
  // src/workflow.ts
3172
- import { execFileSync as execFileSync13 } from "child_process";
3104
+ import { execFileSync as execFileSync12 } from "child_process";
3173
3105
  var GH_TIMEOUT_MS = 3e4;
3174
3106
  function ghToken3() {
3175
3107
  return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
@@ -3177,7 +3109,7 @@ function ghToken3() {
3177
3109
  function gh3(args, cwd) {
3178
3110
  const token = ghToken3();
3179
3111
  const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
3180
- return execFileSync13("gh", args, {
3112
+ return execFileSync12("gh", args, {
3181
3113
  encoding: "utf-8",
3182
3114
  timeout: GH_TIMEOUT_MS,
3183
3115
  cwd,
@@ -3361,7 +3293,7 @@ function tryPostPr2(prNumber, body, cwd) {
3361
3293
  }
3362
3294
 
3363
3295
  // src/scripts/initFlow.ts
3364
- import { execFileSync as execFileSync14 } from "child_process";
3296
+ import { execFileSync as execFileSync13 } from "child_process";
3365
3297
  import * as fs17 from "fs";
3366
3298
  import * as path15 from "path";
3367
3299
 
@@ -3402,7 +3334,7 @@ function qualityCommandsFor(pm) {
3402
3334
  function detectOwnerRepo(cwd) {
3403
3335
  let url;
3404
3336
  try {
3405
- url = execFileSync14("git", ["remote", "get-url", "origin"], {
3337
+ url = execFileSync13("git", ["remote", "get-url", "origin"], {
3406
3338
  cwd,
3407
3339
  encoding: "utf-8",
3408
3340
  stdio: ["ignore", "pipe", "pipe"]
@@ -3486,7 +3418,7 @@ jobs:
3486
3418
  `;
3487
3419
  function defaultBranchFromGit(cwd) {
3488
3420
  try {
3489
- const ref = execFileSync14("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
3421
+ const ref = execFileSync13("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
3490
3422
  cwd,
3491
3423
  encoding: "utf-8",
3492
3424
  stdio: ["ignore", "pipe", "pipe"]
@@ -3494,7 +3426,7 @@ function defaultBranchFromGit(cwd) {
3494
3426
  return ref.replace("refs/remotes/origin/", "");
3495
3427
  } catch {
3496
3428
  try {
3497
- return execFileSync14("git", ["branch", "--show-current"], {
3429
+ return execFileSync13("git", ["branch", "--show-current"], {
3498
3430
  cwd,
3499
3431
  encoding: "utf-8",
3500
3432
  stdio: ["ignore", "pipe", "pipe"]
@@ -3787,8 +3719,8 @@ var persistFlowState = async (ctx) => {
3787
3719
  };
3788
3720
 
3789
3721
  // src/scripts/postClassification.ts
3790
- import { execFileSync as execFileSync15 } from "child_process";
3791
- var API_TIMEOUT_MS7 = 3e4;
3722
+ import { execFileSync as execFileSync14 } from "child_process";
3723
+ var API_TIMEOUT_MS6 = 3e4;
3792
3724
  var VALID_CLASSES2 = /* @__PURE__ */ new Set(["feature", "bug", "spec", "chore"]);
3793
3725
  var postClassification = async (ctx) => {
3794
3726
  const issueNumber = ctx.args.issue;
@@ -3817,9 +3749,9 @@ var postClassification = async (ctx) => {
3817
3749
  ctx.cwd
3818
3750
  );
3819
3751
  try {
3820
- execFileSync15("gh", ["issue", "comment", String(issueNumber), "--body", `@kody2 ${classification}`], {
3752
+ execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", `@kody2 ${classification}`], {
3821
3753
  cwd: ctx.cwd,
3822
- timeout: API_TIMEOUT_MS7,
3754
+ timeout: API_TIMEOUT_MS6,
3823
3755
  stdio: ["ignore", "pipe", "pipe"]
3824
3756
  });
3825
3757
  } catch (err) {
@@ -3851,9 +3783,9 @@ function parseClassification(prSummary) {
3851
3783
  }
3852
3784
  function tryAuditComment(issueNumber, body, cwd) {
3853
3785
  try {
3854
- execFileSync15("gh", ["issue", "comment", String(issueNumber), "--body", body], {
3786
+ execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", body], {
3855
3787
  cwd,
3856
- timeout: API_TIMEOUT_MS7,
3788
+ timeout: API_TIMEOUT_MS6,
3857
3789
  stdio: ["ignore", "pipe", "pipe"]
3858
3790
  });
3859
3791
  } catch {
@@ -4035,7 +3967,7 @@ REVIEW_POSTED=https://github.com/${ctx.config.github.owner}/${ctx.config.github.
4035
3967
  };
4036
3968
 
4037
3969
  // src/scripts/releaseFlow.ts
4038
- import { execFileSync as execFileSync16, spawnSync } from "child_process";
3970
+ import { execFileSync as execFileSync15, spawnSync } from "child_process";
4039
3971
  import * as fs18 from "fs";
4040
3972
  import * as path16 from "path";
4041
3973
  function bumpVersion(current, bump) {
@@ -4065,7 +3997,7 @@ function generateChangelog(cwd, newVersion, lastTag) {
4065
3997
  const range = lastTag ? `${lastTag}..HEAD` : "HEAD";
4066
3998
  let log = "";
4067
3999
  try {
4068
- log = execFileSync16("git", ["log", range, "--pretty=format:%s||%h", "--no-merges"], {
4000
+ log = execFileSync15("git", ["log", range, "--pretty=format:%s||%h", "--no-merges"], {
4069
4001
  cwd,
4070
4002
  encoding: "utf-8",
4071
4003
  stdio: ["ignore", "pipe", "pipe"]
@@ -4122,7 +4054,7 @@ ${entry}${prior.slice(idx + 1)}`);
4122
4054
  }
4123
4055
  }
4124
4056
  function git3(args, cwd, timeout = 6e4) {
4125
- return execFileSync16("git", args, {
4057
+ return execFileSync15("git", args, {
4126
4058
  encoding: "utf-8",
4127
4059
  timeout,
4128
4060
  cwd,
@@ -4425,7 +4357,7 @@ var resolveArtifacts = async (ctx, profile) => {
4425
4357
  };
4426
4358
 
4427
4359
  // src/scripts/resolveFlow.ts
4428
- import { execFileSync as execFileSync17 } from "child_process";
4360
+ import { execFileSync as execFileSync16 } from "child_process";
4429
4361
  var CONFLICT_DIFF_MAX_BYTES = 4e4;
4430
4362
  var resolveFlow = async (ctx) => {
4431
4363
  const prNumber = ctx.args.pr;
@@ -4477,7 +4409,7 @@ var resolveFlow = async (ctx) => {
4477
4409
  };
4478
4410
  function getConflictedFiles(cwd) {
4479
4411
  try {
4480
- const out = execFileSync17("git", ["diff", "--name-only", "--diff-filter=U"], {
4412
+ const out = execFileSync16("git", ["diff", "--name-only", "--diff-filter=U"], {
4481
4413
  encoding: "utf-8",
4482
4414
  cwd,
4483
4415
  env: { ...process.env, HUSKY: "0" }
@@ -4492,7 +4424,7 @@ function getConflictMarkersPreview(files, cwd, maxBytes = CONFLICT_DIFF_MAX_BYTE
4492
4424
  let total = 0;
4493
4425
  for (const f of files) {
4494
4426
  try {
4495
- const content = execFileSync17("cat", [f], { encoding: "utf-8", cwd }).toString();
4427
+ const content = execFileSync16("cat", [f], { encoding: "utf-8", cwd }).toString();
4496
4428
  const snippet = `### ${f}
4497
4429
 
4498
4430
  \`\`\`
@@ -4560,295 +4492,6 @@ function tryPostPr4(prNumber, body, cwd) {
4560
4492
  }
4561
4493
  }
4562
4494
 
4563
- // src/scripts/riskGate.ts
4564
- import { execFileSync as execFileSync18 } from "child_process";
4565
- var ALL_GATES = ["secrets", "workflow-edit", "large-diff", "dep-change", "test-deletion"];
4566
- var WAITING_LABEL = "kody:waiting";
4567
- var ADVISORY_MARKER = "kody2 risk gate halted the flow";
4568
- var APPROVE_COMMAND = /(^|\s)@kody2\s+approve\b/i;
4569
- var DEFAULT_MAX_FILES = 20;
4570
- var DEFAULT_MAX_DELETIONS = 500;
4571
- var riskGate = async (ctx, profile, _agent, args) => {
4572
- const changedFiles = collectBranchChangedFiles(ctx);
4573
- const gatesToRun = parseGates(args?.gates);
4574
- const violations = evaluateGates(ctx, profile.name, changedFiles, gatesToRun, args);
4575
- if (violations.length === 0) {
4576
- ctx.data.riskGate = { violations: [], pending: [], decision: "allow" };
4577
- return;
4578
- }
4579
- const targetType = ctx.data.commentTargetType;
4580
- const targetNumber = Number(ctx.data.commentTargetNumber ?? 0);
4581
- const approved = hasApproval(ctx, targetType, targetNumber);
4582
- ctx.data.riskGate = {
4583
- violations,
4584
- pending: approved ? [] : violations,
4585
- decision: approved ? "allow" : "halt"
4586
- };
4587
- if (approved || !targetType || targetNumber <= 0) return;
4588
- try {
4589
- setKodyLabel(
4590
- targetNumber,
4591
- {
4592
- label: WAITING_LABEL,
4593
- color: "fbca04",
4594
- description: "kody2: awaiting human approval of risk gate(s)"
4595
- },
4596
- ctx.cwd
4597
- );
4598
- } catch {
4599
- }
4600
- const compareUrl = computeCompareUrl(ctx);
4601
- const body = formatAdvisory(violations, compareUrl);
4602
- try {
4603
- if (targetType === "issue") postIssueComment(targetNumber, body, ctx.cwd);
4604
- else postPrReviewComment(targetNumber, body, ctx.cwd);
4605
- } catch {
4606
- }
4607
- if (!ctx.output.reason) {
4608
- ctx.output.reason = `risk gate halt: ${violations.map((p) => p.name).join(", ")}`;
4609
- }
4610
- };
4611
- function hasApproval(ctx, targetType, targetNumber) {
4612
- const surfaces = [];
4613
- if (targetNumber > 0) surfaces.push(targetNumber);
4614
- if (targetType === "pr") {
4615
- const state = ctx.data.taskState;
4616
- const issueNum = state?.flow?.issueNumber;
4617
- if (typeof issueNum === "number" && issueNum > 0 && !surfaces.includes(issueNum)) {
4618
- surfaces.push(issueNum);
4619
- }
4620
- }
4621
- for (const n of surfaces) {
4622
- if (surfaceIsApproved(n, ctx.cwd)) return true;
4623
- }
4624
- return false;
4625
- }
4626
- function surfaceIsApproved(n, cwd) {
4627
- let comments = [];
4628
- try {
4629
- comments = getIssue(n, cwd).comments;
4630
- } catch {
4631
- return false;
4632
- }
4633
- const advisoryAt = latestAdvisoryTimestamp(comments);
4634
- for (const c of comments) {
4635
- if (!APPROVE_COMMAND.test(c.body)) continue;
4636
- if (advisoryAt !== null && c.createdAt <= advisoryAt) continue;
4637
- return true;
4638
- }
4639
- return false;
4640
- }
4641
- function latestAdvisoryTimestamp(comments) {
4642
- let latest = null;
4643
- for (const c of comments) {
4644
- if (!c.body.includes(ADVISORY_MARKER)) continue;
4645
- if (latest === null || c.createdAt > latest) latest = c.createdAt;
4646
- }
4647
- return latest;
4648
- }
4649
- function evaluateGates(ctx, profileName, changedFiles, gatesToRun, args) {
4650
- const violations = [];
4651
- if (gatesToRun.includes("secrets")) {
4652
- const hits = changedFiles.filter(isSecretPath);
4653
- if (hits.length > 0) {
4654
- violations.push({
4655
- name: "secrets",
4656
- severity: "hard",
4657
- reason: `secret/credential files touched: ${preview(hits)}`
4658
- });
4659
- }
4660
- }
4661
- if (gatesToRun.includes("workflow-edit")) {
4662
- const hits = changedFiles.filter((f) => f.startsWith(".github/workflows/"));
4663
- if (hits.length > 0) {
4664
- violations.push({
4665
- name: "workflow-edit",
4666
- severity: "soft",
4667
- reason: `CI workflow files modified: ${preview(hits)}`
4668
- });
4669
- }
4670
- }
4671
- if (gatesToRun.includes("large-diff")) {
4672
- const maxFiles = toPositiveInt(args?.maxFiles, DEFAULT_MAX_FILES);
4673
- const maxDeletions = toPositiveInt(args?.maxDeletions, DEFAULT_MAX_DELETIONS);
4674
- if (changedFiles.length > maxFiles) {
4675
- violations.push({
4676
- name: "large-diff",
4677
- severity: "soft",
4678
- reason: `${changedFiles.length} files changed (threshold: ${maxFiles})`
4679
- });
4680
- } else {
4681
- const stats = computeDiffStats(ctx);
4682
- if (stats && stats.deletions > maxDeletions) {
4683
- violations.push({
4684
- name: "large-diff",
4685
- severity: "soft",
4686
- reason: `${stats.deletions} lines deleted (threshold: ${maxDeletions})`
4687
- });
4688
- }
4689
- }
4690
- }
4691
- if (gatesToRun.includes("dep-change") && profileName !== "chore") {
4692
- const hits = changedFiles.filter(isDepFile);
4693
- if (hits.length > 0) {
4694
- violations.push({
4695
- name: "dep-change",
4696
- severity: "soft",
4697
- reason: `dependency/lockfile changes outside a chore flow: ${preview(hits)}`
4698
- });
4699
- }
4700
- }
4701
- if (gatesToRun.includes("test-deletion")) {
4702
- const deleted = listDeletedFilesInHeadCommit(ctx.cwd).filter(isTestFile);
4703
- if (deleted.length > 0) {
4704
- violations.push({
4705
- name: "test-deletion",
4706
- severity: "soft",
4707
- reason: `test files deleted: ${preview(deleted)}`
4708
- });
4709
- }
4710
- }
4711
- return violations;
4712
- }
4713
- function parseGates(spec) {
4714
- if (spec === void 0 || spec === null || spec === "") return ALL_GATES;
4715
- const list = String(spec).split(",").map((s) => s.trim()).filter(Boolean);
4716
- const valid = ALL_GATES;
4717
- const matched = list.filter((n) => valid.includes(n));
4718
- return matched.length > 0 ? matched : ALL_GATES;
4719
- }
4720
- function toPositiveInt(v, fallback) {
4721
- const n = typeof v === "number" ? v : parseInt(String(v ?? ""), 10);
4722
- return Number.isFinite(n) && n > 0 ? n : fallback;
4723
- }
4724
- function preview(list, max = 5) {
4725
- if (list.length <= max) return list.join(", ");
4726
- return `${list.slice(0, max).join(", ")} (+${list.length - max} more)`;
4727
- }
4728
- var SECRET_PATTERNS = [
4729
- /(^|\/)\.env(\.|$)/i,
4730
- /\.pem$/i,
4731
- /\.key$/i,
4732
- /(^|\/)(id_rsa|id_ed25519|id_ecdsa)(\.|$)/i,
4733
- // Match the keyword anywhere inside the filename, as a whole word (so e.g.
4734
- // `api-secrets.json`, `config/app.credentials.yaml`, `user-passwords.txt`
4735
- // all trip — while false friends like `secretary.md` do not).
4736
- /(^|\/)[^/]*\bsecrets?\b[^/]*$/i,
4737
- /(^|\/)[^/]*\bcredentials?\b[^/]*$/i,
4738
- /(^|\/)[^/]*\bpasswords?\b[^/]*$/i,
4739
- /(^|\/)[^/]*\bapi[-_]keys?\b[^/]*$/i,
4740
- /(^|\/)\.netrc$/i,
4741
- /(^|\/)\.npmrc$/i
4742
- ];
4743
- function isSecretPath(p) {
4744
- return SECRET_PATTERNS.some((r) => r.test(p));
4745
- }
4746
- var DEP_FILES = /* @__PURE__ */ new Set([
4747
- "package.json",
4748
- "pnpm-lock.yaml",
4749
- "package-lock.json",
4750
- "yarn.lock",
4751
- "requirements.txt",
4752
- "Pipfile",
4753
- "Pipfile.lock",
4754
- "poetry.lock",
4755
- "go.mod",
4756
- "go.sum",
4757
- "Cargo.toml",
4758
- "Cargo.lock",
4759
- "Gemfile",
4760
- "Gemfile.lock"
4761
- ]);
4762
- function isDepFile(p) {
4763
- return DEP_FILES.has(p.split("/").pop() ?? "");
4764
- }
4765
- function isTestFile(p) {
4766
- return /(^|\/)(tests?|__tests__|spec)\//i.test(p) || /\.(test|spec)\.[a-z0-9]+$/i.test(p);
4767
- }
4768
- function collectBranchChangedFiles(ctx) {
4769
- const base = ctx.config.git.defaultBranch;
4770
- for (const ref of [`origin/${base}...HEAD`, `${base}...HEAD`]) {
4771
- try {
4772
- const out = execFileSync18("git", ["diff", "--name-only", ref], {
4773
- cwd: ctx.cwd,
4774
- encoding: "utf-8",
4775
- stdio: ["pipe", "pipe", "pipe"]
4776
- });
4777
- const files = out.split("\n").map((s) => s.trim()).filter(Boolean);
4778
- if (files.length > 0) return files;
4779
- } catch {
4780
- }
4781
- }
4782
- return ctx.data.changedFiles ?? [];
4783
- }
4784
- function computeDiffStats(ctx) {
4785
- const base = ctx.config.git.defaultBranch;
4786
- for (const ref of [`origin/${base}...HEAD`, `${base}...HEAD`]) {
4787
- try {
4788
- const out = execFileSync18("git", ["diff", "--shortstat", ref], {
4789
- cwd: ctx.cwd,
4790
- encoding: "utf-8",
4791
- stdio: ["pipe", "pipe", "pipe"]
4792
- }).trim();
4793
- if (out) return parseShortstat(out);
4794
- } catch {
4795
- }
4796
- }
4797
- return null;
4798
- }
4799
- function parseShortstat(s) {
4800
- const ins = /(\d+)\s+insertions?/.exec(s);
4801
- const del = /(\d+)\s+deletions?/.exec(s);
4802
- return {
4803
- insertions: ins ? parseInt(ins[1], 10) : 0,
4804
- deletions: del ? parseInt(del[1], 10) : 0
4805
- };
4806
- }
4807
- function listDeletedFilesInHeadCommit(cwd) {
4808
- try {
4809
- const out = execFileSync18("git", ["show", "--name-status", "--pretty=format:", "HEAD"], {
4810
- cwd,
4811
- encoding: "utf-8",
4812
- stdio: ["pipe", "pipe", "pipe"]
4813
- });
4814
- return out.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("D ")).map((l) => l.slice(2).trim()).filter(Boolean);
4815
- } catch {
4816
- return [];
4817
- }
4818
- }
4819
- function formatAdvisory(violations, compareUrl) {
4820
- const lines = [];
4821
- lines.push(`\u23F8\uFE0F **${ADVISORY_MARKER}.**`);
4822
- lines.push("");
4823
- lines.push("The branch was pushed but **no PR was opened** \u2014 waiting for human approval:");
4824
- lines.push("");
4825
- for (const v of violations) {
4826
- lines.push(`- **\`${v.name}\`** _(${v.severity})_ \u2014 ${v.reason}`);
4827
- }
4828
- lines.push("");
4829
- if (compareUrl) {
4830
- lines.push(`\u{1F4CE} Review the branch diff: ${compareUrl}`);
4831
- lines.push("");
4832
- }
4833
- lines.push("**To approve and resume**, post a comment on this issue or PR:");
4834
- lines.push("");
4835
- lines.push("> `@kody2 approve`");
4836
- lines.push("");
4837
- lines.push(
4838
- "kody2 will open the PR and continue the flow from this checkpoint. No re-running the agent."
4839
- );
4840
- return lines.join("\n");
4841
- }
4842
- function computeCompareUrl(ctx) {
4843
- const branch = ctx.data.branch;
4844
- if (!branch) return null;
4845
- const owner = ctx.config.github?.owner;
4846
- const repo = ctx.config.github?.repo;
4847
- if (!owner || !repo) return null;
4848
- const base = ctx.config.git.defaultBranch;
4849
- return `https://github.com/${owner}/${repo}/compare/${base}...${branch}`;
4850
- }
4851
-
4852
4495
  // src/scripts/runFlow.ts
4853
4496
  var runFlow = async (ctx) => {
4854
4497
  const issueNumber = ctx.args.issue;
@@ -4945,8 +4588,8 @@ var skipAgent = async (ctx) => {
4945
4588
  };
4946
4589
 
4947
4590
  // src/scripts/startFlow.ts
4948
- import { execFileSync as execFileSync19 } from "child_process";
4949
- var API_TIMEOUT_MS8 = 3e4;
4591
+ import { execFileSync as execFileSync17 } from "child_process";
4592
+ var API_TIMEOUT_MS7 = 3e4;
4950
4593
  var startFlow = async (ctx, profile, _agentResult, args) => {
4951
4594
  const entry = args?.entry;
4952
4595
  if (!entry) {
@@ -4979,8 +4622,8 @@ function postKody2Comment(target, issueNumber, state, next, cwd) {
4979
4622
  const sub = target === "pr" && state?.core.prUrl ? "pr" : "issue";
4980
4623
  const body = `@kody2 ${next}`;
4981
4624
  try {
4982
- execFileSync19("gh", [sub, "comment", String(targetNumber), "--body", body], {
4983
- timeout: API_TIMEOUT_MS8,
4625
+ execFileSync17("gh", [sub, "comment", String(targetNumber), "--body", body], {
4626
+ timeout: API_TIMEOUT_MS7,
4984
4627
  cwd,
4985
4628
  stdio: ["ignore", "pipe", "pipe"]
4986
4629
  });
@@ -4999,7 +4642,7 @@ function parsePr2(url) {
4999
4642
  }
5000
4643
 
5001
4644
  // src/scripts/syncFlow.ts
5002
- import { execFileSync as execFileSync20 } from "child_process";
4645
+ import { execFileSync as execFileSync18 } from "child_process";
5003
4646
  var syncFlow = async (ctx) => {
5004
4647
  ctx.skipAgent = true;
5005
4648
  const prNumber = ctx.args.pr;
@@ -5058,7 +4701,7 @@ function bail2(ctx, prNumber, reason) {
5058
4701
  }
5059
4702
  function revParseHead(cwd) {
5060
4703
  try {
5061
- return execFileSync20("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
4704
+ return execFileSync18("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
5062
4705
  } catch {
5063
4706
  return "";
5064
4707
  }
@@ -5066,9 +4709,9 @@ function revParseHead(cwd) {
5066
4709
  function pushBranch(branch, cwd) {
5067
4710
  const env = { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" };
5068
4711
  try {
5069
- execFileSync20("git", ["push", "-u", "origin", branch], { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
4712
+ execFileSync18("git", ["push", "-u", "origin", branch], { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
5070
4713
  } catch {
5071
- execFileSync20("git", ["push", "--force-with-lease", "-u", "origin", branch], {
4714
+ execFileSync18("git", ["push", "--force-with-lease", "-u", "origin", branch], {
5072
4715
  cwd,
5073
4716
  env,
5074
4717
  stdio: ["ignore", "pipe", "pipe"]
@@ -5310,9 +4953,7 @@ var postflightScripts = {
5310
4953
  finishFlow,
5311
4954
  advanceFlow,
5312
4955
  persistFlowState,
5313
- postClassification,
5314
- riskGate,
5315
- applyApprovals
4956
+ postClassification
5316
4957
  };
5317
4958
  var allScriptNames = /* @__PURE__ */ new Set([
5318
4959
  ...Object.keys(preflightScripts),
@@ -5320,7 +4961,7 @@ var allScriptNames = /* @__PURE__ */ new Set([
5320
4961
  ]);
5321
4962
 
5322
4963
  // src/tools.ts
5323
- import { execFileSync as execFileSync21 } from "child_process";
4964
+ import { execFileSync as execFileSync19 } from "child_process";
5324
4965
  function verifyCliTools(tools, cwd) {
5325
4966
  const out = [];
5326
4967
  for (const t of tools) out.push(verifyOne(t, cwd));
@@ -5353,7 +4994,7 @@ function verifyOne(tool, cwd) {
5353
4994
  }
5354
4995
  function runShell2(cmd, cwd, timeoutMs = 3e4) {
5355
4996
  try {
5356
- execFileSync21("sh", ["-c", cmd], { cwd, stdio: "pipe", timeout: timeoutMs });
4997
+ execFileSync19("sh", ["-c", cmd], { cwd, stdio: "pipe", timeout: timeoutMs });
5357
4998
  return true;
5358
4999
  } catch {
5359
5000
  return false;
@@ -5683,7 +5324,7 @@ function detectPackageManager2(cwd) {
5683
5324
  }
5684
5325
  function shellOut(cmd, args, cwd, stream = true) {
5685
5326
  try {
5686
- execFileSync22(cmd, args, {
5327
+ execFileSync20(cmd, args, {
5687
5328
  cwd,
5688
5329
  stdio: stream ? "inherit" : "pipe",
5689
5330
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" }
@@ -5696,7 +5337,7 @@ function shellOut(cmd, args, cwd, stream = true) {
5696
5337
  }
5697
5338
  function isOnPath(bin) {
5698
5339
  try {
5699
- execFileSync22("which", [bin], { stdio: "pipe" });
5340
+ execFileSync20("which", [bin], { stdio: "pipe" });
5700
5341
  return true;
5701
5342
  } catch {
5702
5343
  return false;
@@ -5730,7 +5371,7 @@ function installLitellmIfNeeded(cwd) {
5730
5371
  } catch {
5731
5372
  }
5732
5373
  try {
5733
- execFileSync22("python3", ["-c", "import litellm"], { stdio: "pipe" });
5374
+ execFileSync20("python3", ["-c", "import litellm"], { stdio: "pipe" });
5734
5375
  process.stdout.write("\u2192 kody2: litellm already installed\n");
5735
5376
  return 0;
5736
5377
  } catch {
@@ -5740,16 +5381,16 @@ function installLitellmIfNeeded(cwd) {
5740
5381
  }
5741
5382
  function configureGitIdentity(cwd) {
5742
5383
  try {
5743
- const name = execFileSync22("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
5384
+ const name = execFileSync20("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
5744
5385
  if (name) return;
5745
5386
  } catch {
5746
5387
  }
5747
5388
  try {
5748
- execFileSync22("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
5389
+ execFileSync20("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
5749
5390
  } catch {
5750
5391
  }
5751
5392
  try {
5752
- execFileSync22("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
5393
+ execFileSync20("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
5753
5394
  cwd,
5754
5395
  stdio: "pipe"
5755
5396
  });
@@ -5926,9 +5567,9 @@ function commitChatFiles(cwd, sessionId, verbose) {
5926
5567
  if (paths.length === 0) return;
5927
5568
  const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
5928
5569
  try {
5929
- execFileSync23("git", ["add", ...paths], opts);
5930
- execFileSync23("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
5931
- execFileSync23("git", ["push", "--quiet", "origin", "HEAD"], opts);
5570
+ execFileSync21("git", ["add", ...paths], opts);
5571
+ execFileSync21("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
5572
+ execFileSync21("git", ["push", "--quiet", "origin", "HEAD"], opts);
5932
5573
  } catch (err) {
5933
5574
  const msg = err instanceof Error ? err.message : String(err);
5934
5575
  process.stderr.write(`[kody2:chat] commit/push skipped: ${msg}
@@ -49,21 +49,11 @@
49
49
  "description": "kody2: applying review feedback"
50
50
  }
51
51
  },
52
- {
53
- "script": "fixFlow"
54
- },
55
- {
56
- "script": "loadTaskState"
57
- },
58
- {
59
- "script": "loadConventions"
60
- },
61
- {
62
- "script": "loadCoverageRules"
63
- },
64
- {
65
- "script": "composePrompt"
66
- }
52
+ { "script": "fixFlow" },
53
+ { "script": "loadTaskState" },
54
+ { "script": "loadConventions" },
55
+ { "script": "loadCoverageRules" },
56
+ { "script": "composePrompt" }
67
57
  ],
68
58
  "postflight": [
69
59
  { "script": "parseAgentResult" },
@@ -71,12 +61,11 @@
71
61
  { "script": "verify" },
72
62
  { "script": "checkCoverageWithRetry" },
73
63
  { "script": "commitAndPush" },
74
- { "script": "riskGate" },
75
- { "script": "ensurePr", "runWhen": { "data.riskGate.decision": "allow" } },
76
- { "script": "postIssueComment", "runWhen": { "data.riskGate.decision": "allow" } },
64
+ { "script": "ensurePr" },
65
+ { "script": "postIssueComment" },
77
66
  { "script": "writeRunSummary" },
78
- { "script": "saveTaskState", "runWhen": { "data.riskGate.decision": "allow" } },
79
- { "script": "advanceFlow", "runWhen": { "data.riskGate.decision": "allow" } }
67
+ { "script": "saveTaskState" },
68
+ { "script": "advanceFlow" }
80
69
  ]
81
70
  },
82
71
  "output": {
@@ -42,24 +42,12 @@
42
42
  "description": "kody2: implementing the change"
43
43
  }
44
44
  },
45
- {
46
- "script": "runFlow"
47
- },
48
- {
49
- "script": "loadTaskState"
50
- },
51
- {
52
- "script": "resolveArtifacts"
53
- },
54
- {
55
- "script": "loadConventions"
56
- },
57
- {
58
- "script": "loadCoverageRules"
59
- },
60
- {
61
- "script": "composePrompt"
62
- }
45
+ { "script": "runFlow" },
46
+ { "script": "loadTaskState" },
47
+ { "script": "resolveArtifacts" },
48
+ { "script": "loadConventions" },
49
+ { "script": "loadCoverageRules" },
50
+ { "script": "composePrompt" }
63
51
  ],
64
52
  "postflight": [
65
53
  { "script": "parseAgentResult" },
@@ -67,13 +55,12 @@
67
55
  { "script": "verify" },
68
56
  { "script": "checkCoverageWithRetry" },
69
57
  { "script": "commitAndPush" },
70
- { "script": "riskGate" },
71
- { "script": "ensurePr", "runWhen": { "data.riskGate.decision": "allow" } },
72
- { "script": "postIssueComment", "runWhen": { "data.riskGate.decision": "allow" } },
58
+ { "script": "ensurePr" },
59
+ { "script": "postIssueComment" },
73
60
  { "script": "writeRunSummary" },
74
- { "script": "saveTaskState", "runWhen": { "data.riskGate.decision": "allow" } },
75
- { "script": "mirrorStateToPr", "runWhen": { "data.riskGate.decision": "allow" } },
76
- { "script": "advanceFlow", "runWhen": { "data.riskGate.decision": "allow" } }
61
+ { "script": "saveTaskState" },
62
+ { "script": "mirrorStateToPr" },
63
+ { "script": "advanceFlow" }
77
64
  ]
78
65
  },
79
66
  "input": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.2.61",
3
+ "version": "0.2.62",
4
4
  "description": "kody2 — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -20,8 +20,6 @@
20
20
  # 2. Pushes from kody2 won't trigger downstream workflows.
21
21
  # 3. Any commit that modifies `.github/workflows/*` is REJECTED by
22
22
  # GitHub — the default GITHUB_TOKEN can't touch workflow files.
23
- # (The `workflow-edit` risk gate is effectively unreachable without
24
- # a token carrying the `workflow` scope.)
25
23
  # Set KODY_TOKEN in repo Settings → Secrets → Actions.
26
24
 
27
25
  name: kody2
@@ -1,47 +0,0 @@
1
- {
2
- "name": "approve",
3
- "role": "utility",
4
- "describe": "Acknowledge pending risk gate(s) on an issue or PR: applies kody-approve:* labels on both the issue and its PR (if discoverable via task state), then re-triggers the paused flow. Invoked by `@kody2 approve`.",
5
- "inputs": [
6
- {
7
- "name": "issue",
8
- "flag": "--issue",
9
- "type": "int",
10
- "required": false,
11
- "describe": "Issue number (when approving on the originating issue)."
12
- },
13
- {
14
- "name": "pr",
15
- "flag": "--pr",
16
- "type": "int",
17
- "required": false,
18
- "describe": "PR number (when approving on the PR side)."
19
- }
20
- ],
21
- "claudeCode": {
22
- "model": "inherit",
23
- "permissionMode": "default",
24
- "maxTurns": 0,
25
- "maxThinkingTokens": null,
26
- "systemPromptAppend": null,
27
- "tools": [],
28
- "hooks": [],
29
- "skills": [],
30
- "commands": [],
31
- "subagents": [],
32
- "plugins": [],
33
- "mcpServers": []
34
- },
35
- "cliTools": [],
36
- "scripts": {
37
- "preflight": [
38
- { "script": "skipAgent" }
39
- ],
40
- "postflight": [
41
- { "script": "applyApprovals" }
42
- ]
43
- },
44
- "output": {
45
- "actionTypes": []
46
- }
47
- }
@@ -1 +0,0 @@
1
- (approve is an agent-less utility; this file is a placeholder kept to satisfy the profile layout convention.)