@kody-ade/kody-engine 0.4.156 → 0.4.157

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.
Files changed (2) hide show
  1. package/dist/bin/kody.js +58 -17
  2. package/package.json +1 -1
package/dist/bin/kody.js CHANGED
@@ -1061,7 +1061,7 @@ var init_loadPriorArt = __esm({
1061
1061
  // package.json
1062
1062
  var package_default = {
1063
1063
  name: "@kody-ade/kody-engine",
1064
- version: "0.4.156",
1064
+ version: "0.4.157",
1065
1065
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
1066
1066
  license: "MIT",
1067
1067
  type: "module",
@@ -2935,7 +2935,7 @@ function autoDispatch(opts) {
2935
2935
  const authorLogin = String(event.comment?.user?.login ?? "");
2936
2936
  const authorType = String(event.comment?.user?.type ?? "");
2937
2937
  if (!rawBody.toLowerCase().includes("@kody")) return null;
2938
- if (authorLogin === "kody-bot" || authorType === "Bot") return null;
2938
+ const isBotAuthor = authorLogin === "kody-bot" || authorType === "Bot";
2939
2939
  if (!associationAllowed(event, opts?.config)) return null;
2940
2940
  const body = rawBody.toLowerCase();
2941
2941
  const targetNum = Number(event.issue?.number ?? 0);
@@ -2962,6 +2962,13 @@ function autoDispatch(opts) {
2962
2962
  if (!executable && !firstToken) {
2963
2963
  executable = isPr ? opts?.config?.defaultPrExecutable ?? "fix" : opts?.config?.defaultExecutable ?? null;
2964
2964
  }
2965
+ if (isBotAuthor && !consumedFirstToken) {
2966
+ process.stderr.write(
2967
+ `[kody] dispatch: ignoring bot comment without an explicit command (author=${authorLogin || authorType}, firstToken=${firstToken ?? "<none>"})
2968
+ `
2969
+ );
2970
+ return null;
2971
+ }
2965
2972
  if (!executable) {
2966
2973
  const profileMissing = aliased ? getProfileInputs(aliased) === null : true;
2967
2974
  process.stderr.write(
@@ -4562,40 +4569,73 @@ function writeTaskState(target, number, state, cwd) {
4562
4569
 
4563
4570
  // src/scripts/advanceFlow.ts
4564
4571
  var API_TIMEOUT_MS3 = 3e4;
4572
+ var FLOW_HOP_CAP = 25;
4573
+ function ghComment(issueNumber, body, cwd, label) {
4574
+ try {
4575
+ execFileSync8("gh", ["issue", "comment", String(issueNumber), "--body", body], {
4576
+ timeout: API_TIMEOUT_MS3,
4577
+ cwd,
4578
+ stdio: ["ignore", "pipe", "pipe"]
4579
+ });
4580
+ } catch (err) {
4581
+ process.stderr.write(
4582
+ `[kody advanceFlow] ${label} on issue #${issueNumber} failed: ${err instanceof Error ? err.message : String(err)}
4583
+ `
4584
+ );
4585
+ }
4586
+ }
4565
4587
  var advanceFlow = async (ctx, profile) => {
4566
4588
  const state = ctx.data.taskState;
4567
4589
  const flow = state?.flow;
4568
4590
  if (!flow?.issueNumber) return;
4591
+ const curState = state;
4592
+ let issueState;
4593
+ try {
4594
+ issueState = readTaskState("issue", flow.issueNumber, ctx.cwd);
4595
+ } catch {
4596
+ issueState = curState;
4597
+ }
4569
4598
  const targetType = ctx.data.commentTargetType;
4570
4599
  const action = ctx.data.action;
4600
+ let nextIssueState = issueState;
4571
4601
  if (targetType === "pr" && action) {
4602
+ nextIssueState = reduce(issueState, profile.name, action, profile.phase);
4603
+ if (state?.core.prUrl && !nextIssueState.core.prUrl) nextIssueState.core.prUrl = state.core.prUrl;
4604
+ }
4605
+ const prevHops = issueState.flow?.hops ?? flow.hops ?? 0;
4606
+ const hops = prevHops + 1;
4607
+ if (hops > FLOW_HOP_CAP) {
4608
+ nextIssueState.flow = void 0;
4572
4609
  try {
4573
- const issueState = readTaskState("issue", flow.issueNumber, ctx.cwd);
4574
- issueState.flow = flow;
4575
- const next = reduce(issueState, profile.name, action, profile.phase);
4576
- if (state?.core.prUrl && !next.core.prUrl) next.core.prUrl = state.core.prUrl;
4577
- next.flow = flow;
4578
- writeTaskState("issue", flow.issueNumber, next, ctx.cwd);
4610
+ writeTaskState("issue", flow.issueNumber, nextIssueState, ctx.cwd);
4579
4611
  } catch (err) {
4580
4612
  process.stderr.write(
4581
- `[kody advanceFlow] failed to mirror action to issue #${flow.issueNumber}: ${err instanceof Error ? err.message : String(err)}
4613
+ `[kody advanceFlow] failed to clear looping flow on issue #${flow.issueNumber}: ${err instanceof Error ? err.message : String(err)}
4582
4614
  `
4583
4615
  );
4584
4616
  }
4617
+ ghComment(
4618
+ flow.issueNumber,
4619
+ `\u26A0\uFE0F kody: flow \`${flow.name}\` stopped after ${FLOW_HOP_CAP} steps without completing (loop guard). Re-trigger manually if this was intended.`,
4620
+ ctx.cwd,
4621
+ "loop-guard notice"
4622
+ );
4623
+ process.stderr.write(
4624
+ `[kody advanceFlow] flow '${flow.name}' on issue #${flow.issueNumber} hit hop cap ${FLOW_HOP_CAP}; stopping
4625
+ `
4626
+ );
4627
+ return;
4585
4628
  }
4586
- const body = `@kody ${flow.name}`;
4629
+ nextIssueState.flow = { ...flow, hops };
4587
4630
  try {
4588
- execFileSync8("gh", ["issue", "comment", String(flow.issueNumber), "--body", body], {
4589
- timeout: API_TIMEOUT_MS3,
4590
- cwd: ctx.cwd,
4591
- stdio: ["ignore", "pipe", "pipe"]
4592
- });
4631
+ writeTaskState("issue", flow.issueNumber, nextIssueState, ctx.cwd);
4593
4632
  } catch (err) {
4594
4633
  process.stderr.write(
4595
- `[kody advanceFlow] failed to re-trigger orchestrator on issue #${flow.issueNumber}: ${err instanceof Error ? err.message : String(err)}
4634
+ `[kody advanceFlow] failed to persist hop count on issue #${flow.issueNumber}: ${err instanceof Error ? err.message : String(err)}
4596
4635
  `
4597
4636
  );
4598
4637
  }
4638
+ ghComment(flow.issueNumber, `@kody ${flow.name}`, ctx.cwd, "re-trigger orchestrator");
4599
4639
  };
4600
4640
 
4601
4641
  // src/scripts/brainServe.ts
@@ -12124,7 +12164,8 @@ var startFlow = async (ctx, profile, _agentResult, args) => {
12124
12164
  name: flowName,
12125
12165
  step: entry,
12126
12166
  issueNumber,
12127
- startedAt: (/* @__PURE__ */ new Date()).toISOString()
12167
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
12168
+ hops: 0
12128
12169
  };
12129
12170
  }
12130
12171
  postKodyComment(target, issueNumber, state, entry, ctx.cwd);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.156",
3
+ "version": "0.4.157",
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",