@kody-ade/kody-engine 0.4.131 → 0.4.133

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/kody.js CHANGED
@@ -880,7 +880,7 @@ var init_loadPriorArt = __esm({
880
880
  // package.json
881
881
  var package_default = {
882
882
  name: "@kody-ade/kody-engine",
883
- version: "0.4.131",
883
+ version: "0.4.133",
884
884
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
885
885
  license: "MIT",
886
886
  type: "module",
@@ -5736,6 +5736,14 @@ function closePr(prNumber, comment, cwd) {
5736
5736
  return fail(err);
5737
5737
  }
5738
5738
  }
5739
+ function mergePrSquash(prNumber, cwd) {
5740
+ try {
5741
+ gh(["pr", "merge", String(prNumber), "--squash", "--delete-branch"], { cwd });
5742
+ return { ok: true };
5743
+ } catch (err) {
5744
+ return fail(err);
5745
+ }
5746
+ }
5739
5747
  function editPrBase(prNumber, baseBranch, cwd) {
5740
5748
  try {
5741
5749
  gh(
@@ -8831,6 +8839,122 @@ var markFlowSuccess = async (ctx) => {
8831
8839
  }
8832
8840
  };
8833
8841
 
8842
+ // src/scripts/mergeFlow.ts
8843
+ init_issue();
8844
+ function readPr(prNumber, cwd) {
8845
+ const out = gh(
8846
+ [
8847
+ "pr",
8848
+ "view",
8849
+ String(prNumber),
8850
+ "--json",
8851
+ "state,isDraft,mergeable,mergeStateStatus,title,url"
8852
+ ],
8853
+ { cwd }
8854
+ );
8855
+ const p = JSON.parse(out);
8856
+ return {
8857
+ state: p.state ?? "UNKNOWN",
8858
+ isDraft: p.isDraft ?? false,
8859
+ mergeable: p.mergeable ?? "UNKNOWN",
8860
+ mergeStateStatus: p.mergeStateStatus ?? "UNKNOWN",
8861
+ title: p.title ?? "",
8862
+ url: p.url ?? ""
8863
+ };
8864
+ }
8865
+ function evaluateMergeGate(pr) {
8866
+ if (pr.state !== "OPEN") {
8867
+ return {
8868
+ ok: false,
8869
+ action: "MERGE_SKIPPED",
8870
+ reason: `PR is ${pr.state.toLowerCase()}, not open \u2014 nothing to merge.`
8871
+ };
8872
+ }
8873
+ if (pr.isDraft) {
8874
+ return { ok: false, action: "MERGE_BLOCKED", reason: "PR is still a draft." };
8875
+ }
8876
+ if (pr.mergeable === "CONFLICTING" || pr.mergeStateStatus === "DIRTY") {
8877
+ return {
8878
+ ok: false,
8879
+ action: "MERGE_BLOCKED",
8880
+ reason: "PR has conflicts with its base branch \u2014 resolve them first."
8881
+ };
8882
+ }
8883
+ if (pr.mergeable === "UNKNOWN" || pr.mergeStateStatus === "UNKNOWN") {
8884
+ return {
8885
+ ok: false,
8886
+ action: "MERGE_BLOCKED",
8887
+ reason: "GitHub is still computing mergeability \u2014 will retry next tick."
8888
+ };
8889
+ }
8890
+ if (pr.mergeStateStatus === "BEHIND") {
8891
+ return {
8892
+ ok: false,
8893
+ action: "MERGE_BLOCKED",
8894
+ reason: "PR branch is behind its base \u2014 update it before merging."
8895
+ };
8896
+ }
8897
+ if (pr.mergeStateStatus !== "CLEAN") {
8898
+ return {
8899
+ ok: false,
8900
+ action: "MERGE_BLOCKED",
8901
+ reason: `PR is not green (status: ${pr.mergeStateStatus}) \u2014 required checks or reviews are not satisfied.`
8902
+ };
8903
+ }
8904
+ return { ok: true };
8905
+ }
8906
+ var mergeFlow = async (ctx) => {
8907
+ ctx.skipAgent = true;
8908
+ const prNumber = Number(ctx.args.pr);
8909
+ if (!Number.isInteger(prNumber) || prNumber <= 0) {
8910
+ process.stderr.write(`[merge] invalid --pr value: ${String(ctx.args.pr)}
8911
+ `);
8912
+ ctx.data.mergeAction = "MERGE_BLOCKED";
8913
+ return;
8914
+ }
8915
+ let pr;
8916
+ try {
8917
+ pr = readPr(prNumber, ctx.cwd);
8918
+ } catch (err) {
8919
+ const msg = err instanceof Error ? err.message : String(err);
8920
+ process.stderr.write(`[merge] could not read PR #${prNumber}: ${msg}
8921
+ `);
8922
+ ctx.data.mergeAction = "MERGE_BLOCKED";
8923
+ return;
8924
+ }
8925
+ const verdict = evaluateMergeGate(pr);
8926
+ if (!verdict.ok) {
8927
+ process.stdout.write(`[merge] PR #${prNumber} not merged \u2014 ${verdict.reason}
8928
+ `);
8929
+ ctx.data.mergeAction = verdict.action;
8930
+ if (verdict.action === "MERGE_BLOCKED") {
8931
+ commentOnIssue(
8932
+ prNumber,
8933
+ `\u{1F6A6} _Auto-merge held: ${verdict.reason} Kody will retry once the PR is CLEAN._`,
8934
+ ctx.cwd
8935
+ );
8936
+ }
8937
+ return;
8938
+ }
8939
+ process.stdout.write(`[merge] PR #${prNumber} is CLEAN \u2014 squash-merging
8940
+ `);
8941
+ const merged = mergePrSquash(prNumber, ctx.cwd);
8942
+ if (!merged.ok) {
8943
+ process.stderr.write(`[merge] squash-merge of PR #${prNumber} failed: ${merged.error}
8944
+ `);
8945
+ ctx.data.mergeAction = "MERGE_BLOCKED";
8946
+ commentOnIssue(
8947
+ prNumber,
8948
+ `\u{1F6A6} _Auto-merge attempted but failed: ${merged.error}. Kody will retry next tick._`,
8949
+ ctx.cwd
8950
+ );
8951
+ return;
8952
+ }
8953
+ process.stdout.write(`[merge] PR #${prNumber} merged \u2705
8954
+ `);
8955
+ ctx.data.mergeAction = "MERGE_COMPLETED";
8956
+ };
8957
+
8834
8958
  // src/scripts/mergeReleasePr.ts
8835
8959
  import { execFileSync as execFileSync20 } from "child_process";
8836
8960
  var API_TIMEOUT_MS7 = 6e4;
@@ -11950,7 +12074,7 @@ function appendLine(owner, repo, cwd, record) {
11950
12074
  let existing = "";
11951
12075
  let sha;
11952
12076
  try {
11953
- const out = gh(["api", `/repos/${owner}/${repo}/contents/${filePath}`], { cwd });
12077
+ const out = gh(["api", `/repos/${owner}/${repo}/contents/${filePath}?ref=${STATE_BRANCH}`], { cwd });
11954
12078
  const json = JSON.parse(out);
11955
12079
  if (json.sha) sha = json.sha;
11956
12080
  if (json.content) existing = Buffer.from(json.content, "base64").toString("utf-8");
@@ -11960,9 +12084,12 @@ function appendLine(owner, repo, cwd, record) {
11960
12084
  `;
11961
12085
  const payload = {
11962
12086
  message: `chore(activity): ${record.action}`,
11963
- content: Buffer.from(body, "utf-8").toString("base64")
12087
+ content: Buffer.from(body, "utf-8").toString("base64"),
12088
+ // Keep this high-frequency feed off the default branch.
12089
+ branch: STATE_BRANCH
11964
12090
  };
11965
12091
  if (sha) payload.sha = sha;
12092
+ ensureStateBranch(owner, repo, cwd);
11966
12093
  gh(
11967
12094
  ["api", "--method", "PUT", `/repos/${owner}/${repo}/contents/${filePath}`, "--input", "-"],
11968
12095
  { cwd, input: JSON.stringify(payload) }
@@ -12252,6 +12379,7 @@ var preflightScripts = {
12252
12379
  revertFlow,
12253
12380
  reviewFlow,
12254
12381
  syncFlow,
12382
+ mergeFlow,
12255
12383
  initFlow,
12256
12384
  loadTaskState,
12257
12385
  loadTaskContext,
@@ -14028,6 +14156,7 @@ Usage:
14028
14156
  kody-engine fix --pr <N> [--feedback "..."] [--cwd <path>] [--verbose|--quiet]
14029
14157
  kody-engine fix-ci --pr <N> [--run-id <ID>] [--cwd <path>] [--verbose|--quiet]
14030
14158
  kody-engine resolve --pr <N> [--cwd <path>] [--verbose|--quiet]
14159
+ kody-engine merge --pr <N> [--cwd <path>] [--verbose|--quiet]
14031
14160
  kody-engine review --pr <N> [--cwd <path>] [--verbose|--quiet]
14032
14161
  kody-engine <other> [--cwd <path>] [--verbose|--quiet]
14033
14162
  kody-engine ci --issue <N> [preflight flags \u2014 see: kody-engine ci --help]
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "merge",
3
+ "role": "primitive",
4
+ "kind": "oneshot",
5
+ "describe": "Self-gating squash-merge of an open PR into its base. Deterministic, no agent: merges only when GitHub reports the PR CLEAN (mergeable + required checks/reviews satisfied); otherwise refuses and comments why. Used by the CTO qa-merge duty once a QA-goal PR has graduated.",
6
+ "inputs": [
7
+ {
8
+ "name": "pr",
9
+ "flag": "--pr",
10
+ "type": "int",
11
+ "required": true,
12
+ "describe": "GitHub PR number to merge. No-op (MERGE_SKIPPED) if already closed/merged; refuses (MERGE_BLOCKED) if draft, conflicting, or not yet CLEAN."
13
+ }
14
+ ],
15
+ "claudeCode": {
16
+ "model": "inherit",
17
+ "permissionMode": "default",
18
+ "maxTurns": null,
19
+ "maxThinkingTokens": null,
20
+ "systemPromptAppend": null,
21
+ "tools": [],
22
+ "hooks": [],
23
+ "skills": [],
24
+ "commands": [],
25
+ "subagents": [],
26
+ "plugins": [],
27
+ "mcpServers": []
28
+ },
29
+ "cliTools": [
30
+ {
31
+ "name": "gh",
32
+ "install": {
33
+ "required": true,
34
+ "checkCommand": "command -v gh"
35
+ },
36
+ "verify": "gh auth status",
37
+ "usage": "Reads PR mergeability (`gh pr view --json`) and merges (`gh pr merge --squash --delete-branch`).",
38
+ "allowedUses": ["pr", "api"]
39
+ }
40
+ ],
41
+ "inputArtifacts": [],
42
+ "outputArtifacts": [],
43
+ "scripts": {
44
+ "preflight": [
45
+ {
46
+ "script": "mergeFlow"
47
+ }
48
+ ],
49
+ "postflight": []
50
+ },
51
+ "output": {
52
+ "actionTypes": ["MERGE_COMPLETED", "MERGE_BLOCKED", "MERGE_SKIPPED"]
53
+ }
54
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.131",
3
+ "version": "0.4.133",
4
4
  "description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",