@kody-ade/kody-engine 0.4.579 → 0.4.581

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 +54 -8
  2. package/package.json +1 -1
package/dist/bin/kody.js CHANGED
@@ -15,7 +15,7 @@ var init_package = __esm({
15
15
  "package.json"() {
16
16
  package_default = {
17
17
  name: "@kody-ade/kody-engine",
18
- version: "0.4.579",
18
+ version: "0.4.581",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -8620,6 +8620,7 @@ var init_pushWithRetry = __esm({
8620
8620
 
8621
8621
  // src/commit.ts
8622
8622
  import { execFileSync as execFileSync6 } from "child_process";
8623
+ import { isDeepStrictEqual } from "util";
8623
8624
  import * as fs29 from "fs";
8624
8625
  import * as path28 from "path";
8625
8626
  function isGitHubYamlPath(filePath) {
@@ -8694,13 +8695,46 @@ function isExplicitlyAllowed(p, allowlist) {
8694
8695
  }
8695
8696
  function isForbiddenPath(p, deliveryPathAllowlist = []) {
8696
8697
  if (FORBIDDEN_PATH_EXACT.has(p)) return true;
8697
- for (const pre of FORBIDDEN_PATH_PREFIXES) if (p.startsWith(pre)) return true;
8698
8698
  for (const suf of FORBIDDEN_PATH_SUFFIXES) if (p.endsWith(suf)) return true;
8699
- if (isExplicitlyAllowed(p, deliveryPathAllowlist)) return false;
8699
+ if (isExplicitlyAllowed(p, deliveryPathAllowlist) && (p.startsWith(".kody-engine/definitions/loops/") || isGitHubYamlPath(p))) {
8700
+ return false;
8701
+ }
8702
+ for (const pre of FORBIDDEN_PATH_PREFIXES) if (p.startsWith(pre)) return true;
8700
8703
  if (isGitHubYamlPath(p)) return true;
8701
8704
  for (const pre of ALLOWED_PATH_PREFIXES) if (p.startsWith(pre)) return false;
8702
8705
  return false;
8703
8706
  }
8707
+ function isRecord(value) {
8708
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8709
+ }
8710
+ function isSafeConfigActivationChange(before, after) {
8711
+ if (!isRecord(before) || !isRecord(after)) return false;
8712
+ const beforeRest = { ...before };
8713
+ const afterRest = { ...after };
8714
+ for (const field of ACTIVATION_FIELDS) {
8715
+ const previous = before[field];
8716
+ const next = after[field];
8717
+ delete beforeRest[field];
8718
+ delete afterRest[field];
8719
+ if (previous === void 0 && next === void 0) continue;
8720
+ if (!Array.isArray(previous ?? []) || !Array.isArray(next)) return false;
8721
+ if (!next.every((value) => typeof value === "string")) return false;
8722
+ if (!previous.every((value) => typeof value === "string")) return false;
8723
+ const nextValues = new Set(next);
8724
+ if (!previous.every((value) => nextValues.has(value))) return false;
8725
+ }
8726
+ return isDeepStrictEqual(beforeRest, afterRest);
8727
+ }
8728
+ function isTrustedConfigActivationChange(filePath, deliveryPathAllowlist, cwd) {
8729
+ if (filePath !== "kody.config.json" || !deliveryPathAllowlist.includes(filePath)) return false;
8730
+ try {
8731
+ const before = JSON.parse(git(["show", "HEAD:kody.config.json"], cwd));
8732
+ const after = JSON.parse(fs29.readFileSync(path28.join(cwd ?? process.cwd(), filePath), "utf-8"));
8733
+ return isSafeConfigActivationChange(before, after);
8734
+ } catch {
8735
+ return false;
8736
+ }
8737
+ }
8704
8738
  function listChangedFiles(cwd) {
8705
8739
  const raw = execFileSync6("git", ["status", "--porcelain=v1", "-z", "--untracked-files=all"], {
8706
8740
  encoding: "utf-8",
@@ -8736,12 +8770,16 @@ function normalizeCommitMessage(raw) {
8736
8770
  }
8737
8771
  function commitAndPush(branch, agentMessage, cwd, deliveryPathAllowlist = []) {
8738
8772
  const allChanged = listChangedFiles(cwd);
8739
- const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f, deliveryPathAllowlist));
8773
+ const allowedFiles = allChanged.filter(
8774
+ (f) => !isForbiddenPath(f, deliveryPathAllowlist) || isTrustedConfigActivationChange(f, deliveryPathAllowlist, cwd)
8775
+ );
8740
8776
  const mergeHeadExists = fs29.existsSync(path28.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
8741
8777
  if (allowedFiles.length === 0 && !mergeHeadExists) {
8742
8778
  return { committed: false, pushed: false, sha: "", message: "" };
8743
8779
  }
8744
- const forbiddenFiles = allChanged.filter((f) => isForbiddenPath(f, deliveryPathAllowlist));
8780
+ const forbiddenFiles = allChanged.filter(
8781
+ (f) => isForbiddenPath(f, deliveryPathAllowlist) && !isTrustedConfigActivationChange(f, deliveryPathAllowlist, cwd)
8782
+ );
8745
8783
  for (const f of forbiddenFiles) {
8746
8784
  try {
8747
8785
  git(["reset", "-q", "--", f], cwd);
@@ -8785,7 +8823,7 @@ function hasCommitsAhead(branch, defaultBranch, cwd) {
8785
8823
  }
8786
8824
  }
8787
8825
  }
8788
- var FORBIDDEN_PATH_PREFIXES, ALLOWED_PATH_PREFIXES, FORBIDDEN_PATH_EXACT, FORBIDDEN_PATH_SUFFIXES, CONVENTIONAL_PREFIXES;
8826
+ var FORBIDDEN_PATH_PREFIXES, ALLOWED_PATH_PREFIXES, FORBIDDEN_PATH_EXACT, FORBIDDEN_PATH_SUFFIXES, ACTIVATION_FIELDS, CONVENTIONAL_PREFIXES;
8789
8827
  var init_commit = __esm({
8790
8828
  "src/commit.ts"() {
8791
8829
  "use strict";
@@ -8808,6 +8846,14 @@ var init_commit = __esm({
8808
8846
  ALLOWED_PATH_PREFIXES = [];
8809
8847
  FORBIDDEN_PATH_EXACT = /* @__PURE__ */ new Set([".env", ".kody-pip-requirements.txt", "kody.config.json"]);
8810
8848
  FORBIDDEN_PATH_SUFFIXES = [".log"];
8849
+ ACTIVATION_FIELDS = [
8850
+ "activeAgents",
8851
+ "activeCapabilities",
8852
+ "activeWorkflows",
8853
+ "activePipelines",
8854
+ "activeCommands",
8855
+ "activeFeatures"
8856
+ ];
8811
8857
  CONVENTIONAL_PREFIXES = [
8812
8858
  "feat:",
8813
8859
  "fix:",
@@ -8842,7 +8888,7 @@ var init_abortUnfinishedGitOps = __esm({
8842
8888
  });
8843
8889
 
8844
8890
  // src/scripts/deliveryOutcome.ts
8845
- function isRecord(input) {
8891
+ function isRecord2(input) {
8846
8892
  return !!input && typeof input === "object" && !Array.isArray(input);
8847
8893
  }
8848
8894
  function setDeliveryNotRequired(data, reason) {
@@ -8850,7 +8896,7 @@ function setDeliveryNotRequired(data, reason) {
8850
8896
  }
8851
8897
  function readDeliveryOutcome(data) {
8852
8898
  const raw = data.deliveryOutcome;
8853
- if (!isRecord(raw)) return null;
8899
+ if (!isRecord2(raw)) return null;
8854
8900
  if (raw.kind !== "not_required" || typeof raw.reason !== "string" || raw.reason.length === 0) return null;
8855
8901
  return { kind: "not_required", reason: raw.reason };
8856
8902
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.579",
3
+ "version": "0.4.581",
4
4
  "description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",