@kody-ade/kody-engine 0.4.60 → 0.4.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.
Files changed (2) hide show
  1. package/dist/bin/kody.js +102 -28
  2. package/package.json +1 -1
package/dist/bin/kody.js CHANGED
@@ -10,6 +10,14 @@ var __export = (target, all) => {
10
10
  };
11
11
 
12
12
  // src/events.ts
13
+ var events_exports = {};
14
+ __export(events_exports, {
15
+ __resetRunIdCache: () => __resetRunIdCache,
16
+ emitEvent: () => emitEvent,
17
+ listRuns: () => listRuns,
18
+ readEvents: () => readEvents,
19
+ resolveRunId: () => resolveRunId
20
+ });
13
21
  import * as crypto from "crypto";
14
22
  import * as fs3 from "fs";
15
23
  import * as path3 from "path";
@@ -28,6 +36,10 @@ function resolveRunId() {
28
36
  process.env.KODY_RUN_ID = cachedRunId;
29
37
  return cachedRunId;
30
38
  }
39
+ function __resetRunIdCache() {
40
+ cachedRunId = null;
41
+ delete process.env.KODY_RUN_ID;
42
+ }
31
43
  function emitEvent(cwd, ev) {
32
44
  if (process.env.KODY_EVENTS === "0") return;
33
45
  try {
@@ -303,7 +315,7 @@ var init_verifyMcp = __esm({
303
315
  // package.json
304
316
  var package_default = {
305
317
  name: "@kody-ade/kody-engine",
306
- version: "0.4.60",
318
+ version: "0.4.62",
307
319
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
308
320
  license: "MIT",
309
321
  type: "module",
@@ -1918,6 +1930,27 @@ var VALID_PERMISSION_MODES = /* @__PURE__ */ new Set(["default", "acceptEdits",
1918
1930
  var VALID_ROLES = /* @__PURE__ */ new Set(["primitive", "orchestrator", "container", "watch", "utility"]);
1919
1931
  var VALID_CONTAINER_CHILD_TARGETS = /* @__PURE__ */ new Set(["issue", "pr"]);
1920
1932
  var VALID_PHASES = /* @__PURE__ */ new Set(["research", "planning", "implementing", "reviewing", "shipped", "failed", "idle"]);
1933
+ var KNOWN_PROFILE_KEYS = /* @__PURE__ */ new Set([
1934
+ "name",
1935
+ "describe",
1936
+ "role",
1937
+ "kind",
1938
+ "schedule",
1939
+ "phase",
1940
+ "inputs",
1941
+ "claudeCode",
1942
+ "cliTools",
1943
+ "scripts",
1944
+ "outputContract",
1945
+ "inputArtifacts",
1946
+ "outputArtifacts",
1947
+ "input",
1948
+ // legacy JSON name for inputArtifacts source
1949
+ "output",
1950
+ // legacy JSON name for outputArtifacts source
1951
+ "children",
1952
+ "resetBetweenChildren"
1953
+ ]);
1921
1954
  var ProfileError = class extends Error {
1922
1955
  constructor(profilePath, message) {
1923
1956
  super(`Invalid profile at ${profilePath}:
@@ -1941,6 +1974,13 @@ function loadProfile(profilePath) {
1941
1974
  throw new ProfileError(profilePath, "profile must be a JSON object");
1942
1975
  }
1943
1976
  const r = raw;
1977
+ const unknownKeys = Object.keys(r).filter((k) => !KNOWN_PROFILE_KEYS.has(k));
1978
+ if (unknownKeys.length > 0) {
1979
+ process.stderr.write(
1980
+ `[kody profile] ${path8.basename(path8.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
1981
+ `
1982
+ );
1983
+ }
1944
1984
  const kind = r.kind === "scheduled" ? "scheduled" : "oneshot";
1945
1985
  if (kind === "scheduled" && typeof r.schedule !== "string") {
1946
1986
  throw new ProfileError(profilePath, `kind: "scheduled" requires a "schedule" cron string`);
@@ -5738,54 +5778,61 @@ var finalizeGoal = async (ctx) => {
5738
5778
  if (!goal) return;
5739
5779
  process.stdout.write(`[goal-tick] all task(s) done \u2014 finalising goal ${goal.id}
5740
5780
  `);
5741
- const taskPrs = goal.openTaskPrs ?? [];
5742
- if (taskPrs.length === 0) {
5743
- process.stdout.write(`[goal-tick] no open task PRs \u2014 marking goal done without merge
5781
+ const leaf = goal.leafPr;
5782
+ if (!leaf) {
5783
+ process.stdout.write(`[goal-tick] no leaf PR \u2014 marking goal done without merge
5744
5784
  `);
5745
5785
  goal.state = "done";
5746
5786
  return;
5747
5787
  }
5748
- const ordered = [...taskPrs].sort((a, b) => extractIssueNumber(a) - extractIssueNumber(b));
5749
- for (const pr of ordered) {
5750
- if (pr.baseRefName === goal.defaultBranch) continue;
5788
+ if (leaf.baseRefName !== goal.defaultBranch) {
5751
5789
  process.stdout.write(
5752
- `[goal-tick] retargeting PR #${pr.number} base ${pr.baseRefName} \u2192 ${goal.defaultBranch}
5790
+ `[goal-tick] retargeting leaf PR #${leaf.number} base ${leaf.baseRefName} \u2192 ${goal.defaultBranch}
5753
5791
  `
5754
5792
  );
5755
- const retarget = editPrBase(pr.number, goal.defaultBranch, ctx.cwd);
5793
+ const retarget = editPrBase(leaf.number, goal.defaultBranch, ctx.cwd);
5756
5794
  if (!retarget.ok) {
5757
- process.stderr.write(`[goal-tick] finalizeGoal: editPrBase #${pr.number} failed: ${retarget.error}
5795
+ process.stderr.write(`[goal-tick] finalizeGoal: editPrBase #${leaf.number} failed: ${retarget.error}
5758
5796
  `);
5759
5797
  return;
5760
5798
  }
5761
5799
  }
5762
- for (const pr of ordered) {
5763
- if (pr.isDraft) {
5764
- process.stdout.write(`[goal-tick] promoting draft PR #${pr.number} \u2192 ready
5800
+ if (leaf.isDraft) {
5801
+ process.stdout.write(`[goal-tick] promoting draft leaf PR #${leaf.number} \u2192 ready
5765
5802
  `);
5766
- const ready = markPrReady(pr.number, ctx.cwd);
5767
- if (!ready.ok) {
5768
- process.stderr.write(`[goal-tick] finalizeGoal: markPrReady #${pr.number} failed: ${ready.error}
5803
+ const ready = markPrReady(leaf.number, ctx.cwd);
5804
+ if (!ready.ok) {
5805
+ process.stderr.write(`[goal-tick] finalizeGoal: markPrReady #${leaf.number} failed: ${ready.error}
5769
5806
  `);
5770
- return;
5771
- }
5807
+ return;
5772
5808
  }
5773
- process.stdout.write(`[goal-tick] squash-merging PR #${pr.number} \u2192 ${goal.defaultBranch} (head=${pr.headRefName})
5809
+ }
5810
+ process.stdout.write(
5811
+ `[goal-tick] squash-merging leaf PR #${leaf.number} \u2192 ${goal.defaultBranch} (cumulative goal diff)
5812
+ `
5813
+ );
5814
+ const merged = mergePrSquash(leaf.number, ctx.cwd);
5815
+ if (!merged.ok) {
5816
+ process.stderr.write(`[goal-tick] finalizeGoal: mergePrSquash #${leaf.number} failed: ${merged.error}
5774
5817
  `);
5775
- const merged = mergePrSquash(pr.number, ctx.cwd);
5776
- if (!merged.ok) {
5777
- process.stderr.write(`[goal-tick] finalizeGoal: mergePrSquash #${pr.number} failed: ${merged.error}
5818
+ return;
5819
+ }
5820
+ const others = (goal.openTaskPrs ?? []).filter((p) => p.number !== leaf.number);
5821
+ for (const pr of others) {
5822
+ process.stdout.write(`[goal-tick] closing intermediate stacked PR #${pr.number} (subsumed by leaf merge)
5823
+ `);
5824
+ const closed = closePr(
5825
+ pr.number,
5826
+ `_Stacked-PR finalize: this PR's content is included in the leaf squash to \`${goal.defaultBranch}\` (#${leaf.number})._`,
5827
+ ctx.cwd
5828
+ );
5829
+ if (!closed.ok) {
5830
+ process.stderr.write(`[goal-tick] finalizeGoal: closePr #${pr.number} failed: ${closed.error}
5778
5831
  `);
5779
- return;
5780
5832
  }
5781
5833
  }
5782
5834
  goal.state = "done";
5783
5835
  };
5784
- function extractIssueNumber(pr) {
5785
- const m = pr.headRefName.match(/^(\d+)-/);
5786
- if (m?.[1]) return Number.parseInt(m[1], 10);
5787
- return pr.number;
5788
- }
5789
5836
 
5790
5837
  // src/scripts/finishFlow.ts
5791
5838
  import { execFileSync as execFileSync14 } from "child_process";
@@ -9658,6 +9705,33 @@ async function runExecutable(profileName, input) {
9658
9705
  const msg = err instanceof Error ? err.message : String(err);
9659
9706
  process.stderr.write(`[kody] postflight "${label}" crashed: ${msg}
9660
9707
  `);
9708
+ try {
9709
+ const fsMod = await import("fs");
9710
+ const pathMod = await import("path");
9711
+ const { resolveRunId: resolveRunId2 } = await Promise.resolve().then(() => (init_events(), events_exports));
9712
+ const runId = resolveRunId2();
9713
+ const dir = pathMod.join(input.cwd, ".kody", "runs", runId, "crashes");
9714
+ fsMod.mkdirSync(dir, { recursive: true });
9715
+ const file = pathMod.join(
9716
+ dir,
9717
+ `${label.replace(/[^a-zA-Z0-9_-]/g, "_")}-${Date.now()}.json`
9718
+ );
9719
+ fsMod.writeFileSync(
9720
+ file,
9721
+ JSON.stringify(
9722
+ {
9723
+ executable: profileName,
9724
+ postflight: label,
9725
+ message: msg,
9726
+ stack: err instanceof Error ? err.stack : void 0,
9727
+ ts: (/* @__PURE__ */ new Date()).toISOString()
9728
+ },
9729
+ null,
9730
+ 2
9731
+ )
9732
+ );
9733
+ } catch {
9734
+ }
9661
9735
  const summary = `postflight ${label} crashed: ${msg}`;
9662
9736
  ctx.output.reason = ctx.output.reason ? `${ctx.output.reason}; ${summary}` : summary;
9663
9737
  if (ctx.output.exitCode === 0) ctx.output.exitCode = 99;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.60",
3
+ "version": "0.4.62",
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",