@kody-ade/kody-engine 0.2.33 → 0.2.34

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.33",
6
+ version: "0.2.34",
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",
@@ -393,9 +393,6 @@ async function runAgent(opts) {
393
393
  if (typeof opts.maxTurns === "number" && opts.maxTurns > 0) {
394
394
  queryOptions.maxTurns = opts.maxTurns;
395
395
  }
396
- if (typeof opts.maxThinkingTokens === "number" && opts.maxThinkingTokens > 0) {
397
- queryOptions.maxThinkingTokens = opts.maxThinkingTokens;
398
- }
399
396
  if (typeof opts.systemPromptAppend === "string" && opts.systemPromptAppend.length > 0) {
400
397
  queryOptions.systemPrompt = { type: "preset", preset: "claude_code", append: opts.systemPromptAppend };
401
398
  }
@@ -856,7 +853,6 @@ function parseClaudeCode(p, raw) {
856
853
  model: typeof r.model === "string" ? r.model : "inherit",
857
854
  permissionMode,
858
855
  maxTurns: typeof r.maxTurns === "number" ? r.maxTurns : null,
859
- maxThinkingTokens: typeof r.maxThinkingTokens === "number" ? r.maxThinkingTokens : null,
860
856
  systemPromptAppend: typeof r.systemPromptAppend === "string" ? r.systemPromptAppend : null,
861
857
  tools,
862
858
  hooks: Array.isArray(r.hooks) ? r.hooks : [],
@@ -3219,31 +3215,17 @@ ${truncate2(r.stderr, 2e3)}
3219
3215
 
3220
3216
  // src/scripts/requireFeedbackActions.ts
3221
3217
  var MIN_ITEMS = 1;
3222
- var ACTIONABLE_HEADINGS = /^#{1,6}\s+(Concerns|Suggestions|Bugs)\b/i;
3223
- var NEXT_HEADING = /^#{1,6}\s+/;
3224
3218
  var requireFeedbackActions = async (ctx, profile) => {
3225
3219
  if (!ctx.data.agentDone) return;
3226
3220
  const actions = String(ctx.data.feedbackActions ?? "").trim();
3227
3221
  const items = countActionItems(actions);
3222
+ ctx.data.feedbackAgentItemCount = items;
3228
3223
  if (items < MIN_ITEMS) {
3229
3224
  fail(
3230
3225
  ctx,
3231
3226
  profile,
3232
3227
  actions.length === 0 ? "agent omitted required FEEDBACK_ACTIONS block \u2014 cannot verify that review feedback was addressed" : "agent FEEDBACK_ACTIONS block listed no items \u2014 cannot verify that review feedback was addressed"
3233
3228
  );
3234
- return;
3235
- }
3236
- const reviewBody = String(ctx.data.feedback ?? "");
3237
- const expectedItems = countActionableReviewBullets(reviewBody);
3238
- ctx.data.feedbackReviewItemCount = expectedItems;
3239
- ctx.data.feedbackAgentItemCount = items;
3240
- if (expectedItems > 0 && items < expectedItems) {
3241
- fail(
3242
- ctx,
3243
- profile,
3244
- `agent FEEDBACK_ACTIONS listed ${items} item(s) but the review has ${expectedItems} actionable bullet(s) under ### Concerns / ### Suggestions / ### Bugs \u2014 every review item must be accounted for`
3245
- );
3246
- return;
3247
3229
  }
3248
3230
  };
3249
3231
  function fail(ctx, profile, reason) {
@@ -3265,25 +3247,6 @@ function countActionItems(block) {
3265
3247
  }
3266
3248
  return count;
3267
3249
  }
3268
- function countActionableReviewBullets(reviewBody) {
3269
- if (!reviewBody.trim()) return 0;
3270
- const lines = reviewBody.split("\n");
3271
- let count = 0;
3272
- let insideActionable = false;
3273
- for (const raw of lines) {
3274
- if (ACTIONABLE_HEADINGS.test(raw)) {
3275
- insideActionable = true;
3276
- continue;
3277
- }
3278
- if (insideActionable && NEXT_HEADING.test(raw)) {
3279
- insideActionable = false;
3280
- continue;
3281
- }
3282
- if (!insideActionable) continue;
3283
- if (/^[-*]\s+\S/.test(raw)) count++;
3284
- }
3285
- return count;
3286
- }
3287
3250
 
3288
3251
  // src/scripts/requirePlanDeviations.ts
3289
3252
  var requirePlanDeviations = async (ctx, profile) => {
@@ -3703,6 +3666,44 @@ function summarizeFeedbackActions(block) {
3703
3666
  }
3704
3667
  return summary;
3705
3668
  }
3669
+ function extractReviewFileRefs(reviewBody) {
3670
+ if (!reviewBody) return [];
3671
+ const found = /* @__PURE__ */ new Set();
3672
+ const backtick = /`([^`\s]+\.[a-zA-Z]{1,5})(?::\d+(?:-\d+)?)?`/g;
3673
+ let m;
3674
+ while ((m = backtick.exec(reviewBody)) !== null) {
3675
+ const raw = m[1];
3676
+ if (isPlausibleSourcePath(raw)) found.add(raw);
3677
+ }
3678
+ const bare = /(?<![A-Za-z0-9/_.-])((?:[A-Za-z0-9_./-]+\/)+[A-Za-z0-9_.-]+\.[a-zA-Z]{1,5})(?::\d+(?:-\d+)?)?/g;
3679
+ while ((m = bare.exec(reviewBody)) !== null) {
3680
+ const raw = m[1];
3681
+ if (isPlausibleSourcePath(raw)) found.add(raw);
3682
+ }
3683
+ return Array.from(found);
3684
+ }
3685
+ function isPlausibleSourcePath(p) {
3686
+ if (p.startsWith("http://") || p.startsWith("https://")) return false;
3687
+ if (p.startsWith("//")) return false;
3688
+ if (p.startsWith("/")) return false;
3689
+ if (!p.includes("/")) return false;
3690
+ if (/\.(md|rst|txt|png|jpg|jpeg|gif|svg|pdf)$/i.test(p)) return false;
3691
+ const firstSeg = p.slice(0, p.indexOf("/"));
3692
+ if (firstSeg.includes(".")) return false;
3693
+ return true;
3694
+ }
3695
+ function declinedFileRefs(feedbackActions, refs) {
3696
+ if (!feedbackActions.trim() || refs.length === 0) return /* @__PURE__ */ new Set();
3697
+ const declined = /* @__PURE__ */ new Set();
3698
+ for (const raw of feedbackActions.split("\n")) {
3699
+ if (!/^\s*[-*]\s+/.test(raw)) continue;
3700
+ if (!/\bdeclined\s*:/i.test(raw)) continue;
3701
+ for (const ref of refs) {
3702
+ if (raw.includes(ref)) declined.add(ref);
3703
+ }
3704
+ }
3705
+ return declined;
3706
+ }
3706
3707
  function makeAction2(type, payload) {
3707
3708
  return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
3708
3709
  }
@@ -3715,24 +3716,32 @@ var verifyFixAlignment = async (ctx, profile) => {
3715
3716
  ctx.data.feedbackActionsSummary = summary;
3716
3717
  const committed = Boolean(ctx.data.commitResult?.committed);
3717
3718
  if (summary.totalItems === 0) {
3718
- ctx.output.exitCode = 1;
3719
- ctx.output.reason = "fix produced no FEEDBACK_ACTIONS items";
3720
- ctx.data.agentDone = false;
3721
- ctx.data.action = makeAction2("FIX_FAILED", {
3722
- reason: ctx.output.reason,
3723
- feedbackActionsSummary: summary
3724
- });
3725
- return;
3719
+ return failOnce(ctx, "FIX_FAILED", "fix produced no FEEDBACK_ACTIONS items", summary);
3726
3720
  }
3727
3721
  if (summary.fixedItems > 0 && !committed) {
3728
- ctx.output.exitCode = 1;
3729
- ctx.output.reason = `fix claimed ${summary.fixedItems} fixed item(s) but produced no commit`;
3730
- ctx.data.agentDone = false;
3731
- ctx.data.action = makeAction2("FIX_FAILED", {
3732
- reason: ctx.output.reason,
3733
- feedbackActionsSummary: summary
3734
- });
3735
- return;
3722
+ return failOnce(
3723
+ ctx,
3724
+ "FIX_FAILED",
3725
+ `fix claimed ${summary.fixedItems} fixed item(s) but produced no commit`,
3726
+ summary
3727
+ );
3728
+ }
3729
+ const reviewBody = ctx.data.feedback ?? "";
3730
+ const refs = extractReviewFileRefs(reviewBody);
3731
+ const changedFiles = (ctx.data.changedFiles ?? []).map((f) => f.trim()).filter(Boolean);
3732
+ ctx.data.reviewFileRefs = refs;
3733
+ if (refs.length > 0 && committed) {
3734
+ const declined = declinedFileRefs(feedbackActions, refs);
3735
+ const missing = refs.filter((r) => !declined.has(r) && !changedFiles.some((f) => filesMatch(f, r)));
3736
+ if (missing.length > 0) {
3737
+ return failOnce(
3738
+ ctx,
3739
+ "FIX_FAILED",
3740
+ `fix did not touch review-named file(s): ${missing.join(", ")} \u2014 address them or mark declined with a reason`,
3741
+ summary,
3742
+ { missingFiles: missing, declinedFiles: Array.from(declined), changedFiles }
3743
+ );
3744
+ }
3736
3745
  }
3737
3746
  if (summary.fixedItems === 0 && summary.declinedItems > 0 && !committed) {
3738
3747
  ctx.data.action = makeAction2("FIX_DECLINED", {
@@ -3741,6 +3750,25 @@ var verifyFixAlignment = async (ctx, profile) => {
3741
3750
  });
3742
3751
  }
3743
3752
  };
3753
+ function failOnce(ctx, type, reason, summary, extra) {
3754
+ ctx.output.exitCode = 1;
3755
+ ctx.output.reason = reason;
3756
+ ctx.data.agentDone = false;
3757
+ ctx.data.action = makeAction2(type, {
3758
+ reason,
3759
+ feedbackActionsSummary: summary,
3760
+ ...extra ?? {}
3761
+ });
3762
+ }
3763
+ function filesMatch(changedPath, reviewRef) {
3764
+ if (changedPath === reviewRef) return true;
3765
+ if (changedPath.endsWith("/" + reviewRef)) return true;
3766
+ if (reviewRef.endsWith("/" + changedPath)) return true;
3767
+ const a = changedPath.split("/");
3768
+ const b = reviewRef.split("/");
3769
+ if (a[a.length - 1] !== b[b.length - 1]) return false;
3770
+ return a.length >= 2 && b.length >= 2 && a[a.length - 2] === b[b.length - 2];
3771
+ }
3744
3772
 
3745
3773
  // src/scripts/watchStalePrsFlow.ts
3746
3774
  function readWatchConfig(ctx) {
@@ -4000,7 +4028,6 @@ async function runExecutable(profileName, input) {
4000
4028
  mcpServers: profile.claudeCode.mcpServers,
4001
4029
  pluginPaths: pluginPaths.length > 0 ? pluginPaths : void 0,
4002
4030
  maxTurns: profile.claudeCode.maxTurns,
4003
- maxThinkingTokens: profile.claudeCode.maxThinkingTokens,
4004
4031
  systemPromptAppend: profile.claudeCode.systemPromptAppend,
4005
4032
  settingSources: profile.claudeCode.settingSources
4006
4033
  });
@@ -87,8 +87,6 @@ export interface ClaudeCodeSpec {
87
87
  permissionMode: "default" | "acceptEdits" | "plan" | "bypassPermissions"
88
88
  /** null = unbounded. */
89
89
  maxTurns: number | null
90
- /** Extended-thinking token budget. null = SDK default. */
91
- maxThinkingTokens: number | null
92
90
  /** Text appended on top of Claude Code's baseline system prompt. */
93
91
  systemPromptAppend: string | null
94
92
  /** SDK built-in tools this executable is allowed to use (capability pack). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.2.33",
3
+ "version": "0.2.34",
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",
@@ -12,18 +12,6 @@
12
12
  "templates",
13
13
  "kody.config.schema.json"
14
14
  ],
15
- "scripts": {
16
- "kody2": "tsx bin/kody2.ts",
17
- "build": "tsup && node scripts/copy-assets.cjs",
18
- "test": "vitest run tests/unit tests/int --no-coverage",
19
- "test:e2e": "vitest run tests/e2e --no-coverage",
20
- "test:all": "vitest run tests --no-coverage",
21
- "typecheck": "tsc --noEmit",
22
- "lint": "biome check",
23
- "lint:fix": "biome check --write",
24
- "format": "biome format --write",
25
- "prepublishOnly": "pnpm build"
26
- },
27
15
  "dependencies": {
28
16
  "@anthropic-ai/claude-agent-sdk": "0.2.92"
29
17
  },
@@ -43,5 +31,16 @@
43
31
  "url": "git+https://github.com/aharonyaircohen/kody-engine.git"
44
32
  },
45
33
  "homepage": "https://github.com/aharonyaircohen/kody-engine",
46
- "bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
47
- }
34
+ "bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
35
+ "scripts": {
36
+ "kody2": "tsx bin/kody2.ts",
37
+ "build": "tsup && node scripts/copy-assets.cjs",
38
+ "test": "vitest run tests/unit tests/int --no-coverage",
39
+ "test:e2e": "vitest run tests/e2e --no-coverage",
40
+ "test:all": "vitest run tests --no-coverage",
41
+ "typecheck": "tsc --noEmit",
42
+ "lint": "biome check",
43
+ "lint:fix": "biome check --write",
44
+ "format": "biome format --write"
45
+ }
46
+ }