@kody-ade/kody-engine 0.4.55 → 0.4.57

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
@@ -3,7 +3,7 @@
3
3
  // package.json
4
4
  var package_default = {
5
5
  name: "@kody-ade/kody-engine",
6
- version: "0.4.55",
6
+ version: "0.4.57",
7
7
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
8
8
  license: "MIT",
9
9
  type: "module",
@@ -52,8 +52,8 @@ var package_default = {
52
52
 
53
53
  // src/chat-cli.ts
54
54
  import { execFileSync as execFileSync31 } from "child_process";
55
- import * as fs31 from "fs";
56
- import * as path29 from "path";
55
+ import * as fs32 from "fs";
56
+ import * as path30 from "path";
57
57
 
58
58
  // src/chat/events.ts
59
59
  import * as fs from "fs";
@@ -472,7 +472,19 @@ async function runAgent(opts) {
472
472
  queryOptions.maxThinkingTokens = opts.maxThinkingTokens;
473
473
  }
474
474
  if (typeof opts.systemPromptAppend === "string" && opts.systemPromptAppend.length > 0) {
475
- queryOptions.systemPrompt = { type: "preset", preset: "claude_code", append: opts.systemPromptAppend };
475
+ const systemPrompt = {
476
+ type: "preset",
477
+ preset: "claude_code",
478
+ append: opts.systemPromptAppend
479
+ };
480
+ if (opts.cacheable) systemPrompt.excludeDynamicSections = true;
481
+ queryOptions.systemPrompt = systemPrompt;
482
+ } else if (opts.cacheable) {
483
+ queryOptions.systemPrompt = {
484
+ type: "preset",
485
+ preset: "claude_code",
486
+ excludeDynamicSections: true
487
+ };
476
488
  }
477
489
  queryOptions.settingSources = opts.settingSources ?? ["project", "local"];
478
490
  const result = query({
@@ -1001,8 +1013,8 @@ async function emit2(sink, type, sessionId, suffix, payload) {
1001
1013
 
1002
1014
  // src/kody-cli.ts
1003
1015
  import { execFileSync as execFileSync30 } from "child_process";
1004
- import * as fs30 from "fs";
1005
- import * as path28 from "path";
1016
+ import * as fs31 from "fs";
1017
+ import * as path29 from "path";
1006
1018
 
1007
1019
  // src/dispatch.ts
1008
1020
  import * as fs7 from "fs";
@@ -1581,8 +1593,8 @@ function postPrReviewComment(prNumber, body, cwd) {
1581
1593
 
1582
1594
  // src/executor.ts
1583
1595
  import { execFileSync as execFileSync29, spawn as spawn5 } from "child_process";
1584
- import * as fs29 from "fs";
1585
- import * as path27 from "path";
1596
+ import * as fs30 from "fs";
1597
+ import * as path28 from "path";
1586
1598
 
1587
1599
  // src/events.ts
1588
1600
  import * as crypto from "crypto";
@@ -1779,6 +1791,7 @@ function parseClaudeCode(p, raw) {
1779
1791
  maxThinkingTokens: typeof r.maxThinkingTokens === "number" ? r.maxThinkingTokens : null,
1780
1792
  maxTurnTimeoutSec: typeof r.maxTurnTimeoutSec === "number" ? r.maxTurnTimeoutSec : null,
1781
1793
  systemPromptAppend: typeof r.systemPromptAppend === "string" ? r.systemPromptAppend : null,
1794
+ cacheable: r.cacheable === true,
1782
1795
  tools,
1783
1796
  hooks: Array.isArray(r.hooks) ? r.hooks : [],
1784
1797
  skills: Array.isArray(r.skills) ? r.skills : [],
@@ -5429,6 +5442,19 @@ var finalizeGoal = async (ctx) => {
5429
5442
  return;
5430
5443
  }
5431
5444
  const ordered = [...taskPrs].sort((a, b) => extractIssueNumber(a) - extractIssueNumber(b));
5445
+ for (const pr of ordered) {
5446
+ if (pr.baseRefName === goal.defaultBranch) continue;
5447
+ process.stdout.write(
5448
+ `[goal-tick] retargeting PR #${pr.number} base ${pr.baseRefName} \u2192 ${goal.defaultBranch}
5449
+ `
5450
+ );
5451
+ const retarget = editPrBase(pr.number, goal.defaultBranch, ctx.cwd);
5452
+ if (!retarget.ok) {
5453
+ process.stderr.write(`[goal-tick] finalizeGoal: editPrBase #${pr.number} failed: ${retarget.error}
5454
+ `);
5455
+ return;
5456
+ }
5457
+ }
5432
5458
  for (const pr of ordered) {
5433
5459
  if (pr.isDraft) {
5434
5460
  process.stdout.write(`[goal-tick] promoting draft PR #${pr.number} \u2192 ready
@@ -5436,18 +5462,6 @@ var finalizeGoal = async (ctx) => {
5436
5462
  const ready = markPrReady(pr.number, ctx.cwd);
5437
5463
  if (!ready.ok) {
5438
5464
  process.stderr.write(`[goal-tick] finalizeGoal: markPrReady #${pr.number} failed: ${ready.error}
5439
- `);
5440
- return;
5441
- }
5442
- }
5443
- if (pr.baseRefName !== goal.defaultBranch) {
5444
- process.stdout.write(
5445
- `[goal-tick] retargeting PR #${pr.number} base ${pr.baseRefName} \u2192 ${goal.defaultBranch}
5446
- `
5447
- );
5448
- const retarget = editPrBase(pr.number, goal.defaultBranch, ctx.cwd);
5449
- if (!retarget.ok) {
5450
- process.stderr.write(`[goal-tick] finalizeGoal: editPrBase #${pr.number} failed: ${retarget.error}
5451
5465
  `);
5452
5466
  return;
5453
5467
  }
@@ -6297,10 +6311,10 @@ import * as fs24 from "fs";
6297
6311
  import * as path23 from "path";
6298
6312
  var VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "done"]);
6299
6313
  var GoalStateError = class extends Error {
6300
- constructor(path30, message) {
6301
- super(`Invalid goal state at ${path30}:
6314
+ constructor(path31, message) {
6315
+ super(`Invalid goal state at ${path31}:
6302
6316
  ${message}`);
6303
- this.path = path30;
6317
+ this.path = path31;
6304
6318
  this.name = "GoalStateError";
6305
6319
  }
6306
6320
  path;
@@ -6730,6 +6744,63 @@ function formatReviewComments(raw) {
6730
6744
  }
6731
6745
  }
6732
6746
 
6747
+ // src/taskContext.ts
6748
+ import * as fs27 from "fs";
6749
+ import * as path26 from "path";
6750
+ var TASK_CONTEXT_SCHEMA_VERSION = 1;
6751
+ function buildTaskContext(args) {
6752
+ return {
6753
+ schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
6754
+ builtAt: (/* @__PURE__ */ new Date()).toISOString(),
6755
+ runId: args.runId,
6756
+ issue: args.issue,
6757
+ conventions: args.conventions ?? [],
6758
+ priorArt: args.priorArt ?? "",
6759
+ memoryContext: args.memoryContext ?? "",
6760
+ coverageRules: args.coverageRules ?? []
6761
+ };
6762
+ }
6763
+ function persistTaskContext(cwd, ctx) {
6764
+ try {
6765
+ const dir = path26.join(cwd, ".kody", "runs", ctx.runId);
6766
+ fs27.mkdirSync(dir, { recursive: true });
6767
+ const file = path26.join(dir, "task-context.json");
6768
+ fs27.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
6769
+ `);
6770
+ return file;
6771
+ } catch (err) {
6772
+ const msg = err instanceof Error ? err.message : String(err);
6773
+ process.stderr.write(`[kody taskContext] persist failed: ${msg}
6774
+ `);
6775
+ return null;
6776
+ }
6777
+ }
6778
+
6779
+ // src/scripts/loadTaskContext.ts
6780
+ var loadTaskContext = async (ctx) => {
6781
+ const runId = resolveRunId();
6782
+ const rawIssue = ctx.data.issue;
6783
+ const issue = rawIssue ? {
6784
+ ...rawIssue,
6785
+ commentsFormatted: rawIssue.commentsFormatted ?? "",
6786
+ labelsFormatted: rawIssue.labelsFormatted ?? ""
6787
+ } : void 0;
6788
+ const taskContext = buildTaskContext({
6789
+ runId,
6790
+ issue,
6791
+ conventions: ctx.data.conventions,
6792
+ priorArt: typeof ctx.data.priorArt === "string" ? ctx.data.priorArt : "",
6793
+ memoryContext: typeof ctx.data.memoryContext === "string" ? ctx.data.memoryContext : "",
6794
+ coverageRules: ctx.data.coverageRules
6795
+ });
6796
+ ctx.data.taskContext = taskContext;
6797
+ const persistedPath = persistTaskContext(ctx.cwd, taskContext);
6798
+ if (persistedPath && ctx.verbose) {
6799
+ process.stderr.write(`[kody taskContext] persisted ${persistedPath}
6800
+ `);
6801
+ }
6802
+ };
6803
+
6733
6804
  // src/scripts/loadTaskState.ts
6734
6805
  var loadTaskState = async (ctx) => {
6735
6806
  const target = ctx.data.commentTargetType;
@@ -8049,8 +8120,8 @@ function resolveBaseOverride(value) {
8049
8120
 
8050
8121
  // src/scripts/runTickScript.ts
8051
8122
  import { spawnSync } from "child_process";
8052
- import * as fs27 from "fs";
8053
- import * as path26 from "path";
8123
+ import * as fs28 from "fs";
8124
+ import * as path27 from "path";
8054
8125
  var runTickScript = async (ctx, _profile, args) => {
8055
8126
  ctx.skipAgent = true;
8056
8127
  const jobsDir = String(args?.jobsDir ?? ".kody/jobs");
@@ -8062,13 +8133,13 @@ var runTickScript = async (ctx, _profile, args) => {
8062
8133
  ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
8063
8134
  return;
8064
8135
  }
8065
- const jobPath = path26.join(ctx.cwd, jobsDir, `${slug}.md`);
8066
- if (!fs27.existsSync(jobPath)) {
8136
+ const jobPath = path27.join(ctx.cwd, jobsDir, `${slug}.md`);
8137
+ if (!fs28.existsSync(jobPath)) {
8067
8138
  ctx.output.exitCode = 99;
8068
8139
  ctx.output.reason = `runTickScript: job file not found: ${jobPath}`;
8069
8140
  return;
8070
8141
  }
8071
- const raw = fs27.readFileSync(jobPath, "utf-8");
8142
+ const raw = fs28.readFileSync(jobPath, "utf-8");
8072
8143
  const { frontmatter } = splitFrontmatter(raw);
8073
8144
  const tickScript = frontmatter.tickScript;
8074
8145
  if (!tickScript) {
@@ -8076,8 +8147,8 @@ var runTickScript = async (ctx, _profile, args) => {
8076
8147
  ctx.output.reason = `runTickScript: job ${slug} has no \`tickScript:\` frontmatter \u2014 route via job-tick instead`;
8077
8148
  return;
8078
8149
  }
8079
- const scriptPath = path26.isAbsolute(tickScript) ? tickScript : path26.join(ctx.cwd, tickScript);
8080
- if (!fs27.existsSync(scriptPath)) {
8150
+ const scriptPath = path27.isAbsolute(tickScript) ? tickScript : path27.join(ctx.cwd, tickScript);
8151
+ if (!fs28.existsSync(scriptPath)) {
8081
8152
  ctx.output.exitCode = 99;
8082
8153
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
8083
8154
  return;
@@ -9014,7 +9085,7 @@ var writeJobStateFile = async (ctx, _profile, _agentResult, args) => {
9014
9085
  };
9015
9086
 
9016
9087
  // src/scripts/writeRunSummary.ts
9017
- import * as fs28 from "fs";
9088
+ import * as fs29 from "fs";
9018
9089
  var writeRunSummary = async (ctx, profile) => {
9019
9090
  const summaryPath = process.env.GITHUB_STEP_SUMMARY;
9020
9091
  if (!summaryPath) return;
@@ -9036,7 +9107,7 @@ var writeRunSummary = async (ctx, profile) => {
9036
9107
  if (reason) lines.push(`- **Reason:** ${reason}`);
9037
9108
  lines.push("");
9038
9109
  try {
9039
- fs28.appendFileSync(summaryPath, `${lines.join("\n")}
9110
+ fs29.appendFileSync(summaryPath, `${lines.join("\n")}
9040
9111
  `);
9041
9112
  } catch {
9042
9113
  }
@@ -9053,6 +9124,7 @@ var preflightScripts = {
9053
9124
  syncFlow,
9054
9125
  initFlow,
9055
9126
  loadTaskState,
9127
+ loadTaskContext,
9056
9128
  loadIssueContext,
9057
9129
  loadIssueStateComment,
9058
9130
  loadJobFromFile,
@@ -9252,9 +9324,9 @@ async function runExecutable(profileName, input) {
9252
9324
  data: {},
9253
9325
  output: { exitCode: 0 }
9254
9326
  };
9255
- const ndjsonDir = path27.join(input.cwd, ".kody");
9327
+ const ndjsonDir = path28.join(input.cwd, ".kody");
9256
9328
  const invokeAgent = async (prompt) => {
9257
- const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path27.isAbsolute(p) ? p : path27.resolve(profile.dir, p)).filter((p) => p.length > 0);
9329
+ const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path28.isAbsolute(p) ? p : path28.resolve(profile.dir, p)).filter((p) => p.length > 0);
9258
9330
  const syntheticPath = ctx.data.syntheticPluginPath;
9259
9331
  const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
9260
9332
  return runAgent({
@@ -9273,6 +9345,7 @@ async function runExecutable(profileName, input) {
9273
9345
  maxThinkingTokens: profile.claudeCode.maxThinkingTokens,
9274
9346
  maxTurnTimeoutMs: typeof profile.claudeCode.maxTurnTimeoutSec === "number" ? Math.floor(profile.claudeCode.maxTurnTimeoutSec * 1e3) : void 0,
9275
9347
  systemPromptAppend: profile.claudeCode.systemPromptAppend,
9348
+ cacheable: profile.claudeCode.cacheable,
9276
9349
  settingSources: profile.claudeCode.settingSources
9277
9350
  });
9278
9351
  };
@@ -9417,7 +9490,7 @@ function clearStampedLifecycleLabels(profile, ctx) {
9417
9490
  function getProfileInputsForChild(profileName, _cwd) {
9418
9491
  try {
9419
9492
  const profilePath = resolveProfilePath(profileName);
9420
- if (!fs29.existsSync(profilePath)) return null;
9493
+ if (!fs30.existsSync(profilePath)) return null;
9421
9494
  return loadProfile(profilePath).inputs;
9422
9495
  } catch {
9423
9496
  return null;
@@ -9426,17 +9499,17 @@ function getProfileInputsForChild(profileName, _cwd) {
9426
9499
  function resolveProfilePath(profileName) {
9427
9500
  const found = resolveExecutable(profileName);
9428
9501
  if (found) return found;
9429
- const here = path27.dirname(new URL(import.meta.url).pathname);
9502
+ const here = path28.dirname(new URL(import.meta.url).pathname);
9430
9503
  const candidates = [
9431
- path27.join(here, "executables", profileName, "profile.json"),
9504
+ path28.join(here, "executables", profileName, "profile.json"),
9432
9505
  // same-dir sibling (dev)
9433
- path27.join(here, "..", "executables", profileName, "profile.json"),
9506
+ path28.join(here, "..", "executables", profileName, "profile.json"),
9434
9507
  // up one (prod: dist/bin → dist/executables)
9435
- path27.join(here, "..", "src", "executables", profileName, "profile.json")
9508
+ path28.join(here, "..", "src", "executables", profileName, "profile.json")
9436
9509
  // fallback
9437
9510
  ];
9438
9511
  for (const c of candidates) {
9439
- if (fs29.existsSync(c)) return c;
9512
+ if (fs30.existsSync(c)) return c;
9440
9513
  }
9441
9514
  return candidates[0];
9442
9515
  }
@@ -9533,8 +9606,8 @@ function resolveShellTimeoutMs(entry) {
9533
9606
  var SIGKILL_GRACE_MS = 5e3;
9534
9607
  async function runShellEntry(entry, ctx, profile) {
9535
9608
  const shellName = entry.shell;
9536
- const shellPath = path27.join(profile.dir, shellName);
9537
- if (!fs29.existsSync(shellPath)) {
9609
+ const shellPath = path28.join(profile.dir, shellName);
9610
+ if (!fs30.existsSync(shellPath)) {
9538
9611
  ctx.skipAgent = true;
9539
9612
  ctx.output.exitCode = 99;
9540
9613
  ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
@@ -9979,9 +10052,9 @@ function resolveAuthToken(env = process.env) {
9979
10052
  return token;
9980
10053
  }
9981
10054
  function detectPackageManager2(cwd) {
9982
- if (fs30.existsSync(path28.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
9983
- if (fs30.existsSync(path28.join(cwd, "yarn.lock"))) return "yarn";
9984
- if (fs30.existsSync(path28.join(cwd, "bun.lockb"))) return "bun";
10055
+ if (fs31.existsSync(path29.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
10056
+ if (fs31.existsSync(path29.join(cwd, "yarn.lock"))) return "yarn";
10057
+ if (fs31.existsSync(path29.join(cwd, "bun.lockb"))) return "bun";
9985
10058
  return "npm";
9986
10059
  }
9987
10060
  function shellOut(cmd, args, cwd, stream = true) {
@@ -10068,11 +10141,11 @@ function configureGitIdentity(cwd) {
10068
10141
  }
10069
10142
  function postFailureTail(issueNumber, cwd, reason) {
10070
10143
  if (!issueNumber) return;
10071
- const logPath = path28.join(cwd, ".kody", "last-run.jsonl");
10144
+ const logPath = path29.join(cwd, ".kody", "last-run.jsonl");
10072
10145
  let tail = "";
10073
10146
  try {
10074
- if (fs30.existsSync(logPath)) {
10075
- const content = fs30.readFileSync(logPath, "utf-8");
10147
+ if (fs31.existsSync(logPath)) {
10148
+ const content = fs31.readFileSync(logPath, "utf-8");
10076
10149
  tail = content.slice(-3e3);
10077
10150
  }
10078
10151
  } catch {
@@ -10097,7 +10170,7 @@ async function runCi(argv) {
10097
10170
  return 0;
10098
10171
  }
10099
10172
  const args = parseCiArgs(argv);
10100
- const cwd = args.cwd ? path28.resolve(args.cwd) : process.cwd();
10173
+ const cwd = args.cwd ? path29.resolve(args.cwd) : process.cwd();
10101
10174
  let earlyConfig;
10102
10175
  try {
10103
10176
  earlyConfig = loadConfig(cwd);
@@ -10107,9 +10180,9 @@ async function runCi(argv) {
10107
10180
  const eventName = process.env.GITHUB_EVENT_NAME;
10108
10181
  const dispatchEventPath = process.env.GITHUB_EVENT_PATH;
10109
10182
  let manualWorkflowDispatch = false;
10110
- if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs30.existsSync(dispatchEventPath)) {
10183
+ if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs31.existsSync(dispatchEventPath)) {
10111
10184
  try {
10112
- const evt = JSON.parse(fs30.readFileSync(dispatchEventPath, "utf-8"));
10185
+ const evt = JSON.parse(fs31.readFileSync(dispatchEventPath, "utf-8"));
10113
10186
  const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
10114
10187
  const sessionInput = String(evt?.inputs?.sessionId ?? "");
10115
10188
  manualWorkflowDispatch = !sessionInput && !(Number.isFinite(issueInput) && issueInput > 0);
@@ -10368,9 +10441,9 @@ function parseChatArgs(argv, env = process.env) {
10368
10441
  return result;
10369
10442
  }
10370
10443
  function commitChatFiles(cwd, sessionId, verbose) {
10371
- const sessionFile = path29.relative(cwd, sessionFilePath(cwd, sessionId));
10372
- const eventsFile = path29.relative(cwd, eventsFilePath(cwd, sessionId));
10373
- const paths = [sessionFile, eventsFile].filter((p) => fs31.existsSync(path29.join(cwd, p)));
10444
+ const sessionFile = path30.relative(cwd, sessionFilePath(cwd, sessionId));
10445
+ const eventsFile = path30.relative(cwd, eventsFilePath(cwd, sessionId));
10446
+ const paths = [sessionFile, eventsFile].filter((p) => fs32.existsSync(path30.join(cwd, p)));
10374
10447
  if (paths.length === 0) return;
10375
10448
  const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
10376
10449
  try {
@@ -10408,7 +10481,7 @@ async function runChat(argv) {
10408
10481
  ${CHAT_HELP}`);
10409
10482
  return 64;
10410
10483
  }
10411
- const cwd = args.cwd ? path29.resolve(args.cwd) : process.cwd();
10484
+ const cwd = args.cwd ? path30.resolve(args.cwd) : process.cwd();
10412
10485
  const sessionId = args.sessionId;
10413
10486
  const unpackedSecrets = unpackAllSecrets();
10414
10487
  if (unpackedSecrets > 0) {
@@ -10460,7 +10533,7 @@ ${CHAT_HELP}`);
10460
10533
  const sink = buildSink(cwd, sessionId, args.dashboardUrl);
10461
10534
  const meta = readMeta(sessionFile);
10462
10535
  process.stdout.write(
10463
- `\u2192 kody:chat: session file=${sessionFile} exists=${fs31.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
10536
+ `\u2192 kody:chat: session file=${sessionFile} exists=${fs32.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
10464
10537
  `
10465
10538
  );
10466
10539
  try {
@@ -24,6 +24,7 @@
24
24
  "maxTurns": null,
25
25
  "maxThinkingTokens": null,
26
26
  "systemPromptAppend": null,
27
+ "cacheable": true,
27
28
  "tools": [
28
29
  "Read",
29
30
  "Bash"
@@ -25,6 +25,7 @@
25
25
  "maxTurns": null,
26
26
  "maxTurnTimeoutSec": 1200,
27
27
  "systemPromptAppend": null,
28
+ "cacheable": true,
28
29
  "tools": [
29
30
  "Read",
30
31
  "Write",
@@ -24,6 +24,7 @@
24
24
  "maxTurns": null,
25
25
  "maxTurnTimeoutSec": 1200,
26
26
  "systemPromptAppend": null,
27
+ "cacheable": true,
27
28
  "tools": [
28
29
  "Read",
29
30
  "Write",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -24,6 +24,7 @@
24
24
  "maxTurns": null,
25
25
  "maxTurnTimeoutSec": 1200,
26
26
  "systemPromptAppend": null,
27
+ "cacheable": true,
27
28
  "tools": [
28
29
  "Read",
29
30
  "Write",
@@ -163,6 +163,20 @@ export interface ClaudeCodeSpec {
163
163
  maxTurnTimeoutSec?: number | null
164
164
  /** Text appended on top of Claude Code's baseline system prompt. */
165
165
  systemPromptAppend: string | null
166
+ /**
167
+ * Cross-process prompt caching opt-in. When true, the agent invocation
168
+ * sets `systemPrompt.excludeDynamicSections: true` so per-user dynamic
169
+ * content (cwd, git status, auto-memory) is stripped from the preset
170
+ * and re-injected as the first user message. The remaining preset
171
+ * becomes byte-identical across runs and benefits from Anthropic's
172
+ * 5-min server-side prompt cache. Recommended for hot-path stages
173
+ * (`run`, `fix`, `classify`) where the same workflow fires many
174
+ * times in a short window.
175
+ *
176
+ * Default: false (preserves legacy behaviour). No-op if the SDK does
177
+ * not support `excludeDynamicSections` (forward-compatible).
178
+ */
179
+ cacheable?: boolean
166
180
  /** SDK built-in tools this executable is allowed to use (capability pack). */
167
181
  tools: string[]
168
182
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.55",
3
+ "version": "0.4.57",
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",
@@ -12,6 +12,18 @@
12
12
  "templates",
13
13
  "kody.config.schema.json"
14
14
  ],
15
+ "scripts": {
16
+ "kody": "tsx bin/kody.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
+ },
15
27
  "dependencies": {
16
28
  "@actions/cache": "^6.0.0",
17
29
  "@anthropic-ai/claude-agent-sdk": "0.2.119"
@@ -32,16 +44,5 @@
32
44
  "url": "git+https://github.com/aharonyaircohen/kody-engine.git"
33
45
  },
34
46
  "homepage": "https://github.com/aharonyaircohen/kody-engine",
35
- "bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
36
- "scripts": {
37
- "kody": "tsx bin/kody.ts",
38
- "build": "tsup && node scripts/copy-assets.cjs",
39
- "test": "vitest run tests/unit tests/int --no-coverage",
40
- "test:e2e": "vitest run tests/e2e --no-coverage",
41
- "test:all": "vitest run tests --no-coverage",
42
- "typecheck": "tsc --noEmit",
43
- "lint": "biome check",
44
- "lint:fix": "biome check --write",
45
- "format": "biome format --write"
46
- }
47
- }
47
+ "bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
48
+ }