@kody-ade/kody-engine 0.4.56 → 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.56",
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";
@@ -1013,8 +1013,8 @@ async function emit2(sink, type, sessionId, suffix, payload) {
1013
1013
 
1014
1014
  // src/kody-cli.ts
1015
1015
  import { execFileSync as execFileSync30 } from "child_process";
1016
- import * as fs30 from "fs";
1017
- import * as path28 from "path";
1016
+ import * as fs31 from "fs";
1017
+ import * as path29 from "path";
1018
1018
 
1019
1019
  // src/dispatch.ts
1020
1020
  import * as fs7 from "fs";
@@ -1593,8 +1593,8 @@ function postPrReviewComment(prNumber, body, cwd) {
1593
1593
 
1594
1594
  // src/executor.ts
1595
1595
  import { execFileSync as execFileSync29, spawn as spawn5 } from "child_process";
1596
- import * as fs29 from "fs";
1597
- import * as path27 from "path";
1596
+ import * as fs30 from "fs";
1597
+ import * as path28 from "path";
1598
1598
 
1599
1599
  // src/events.ts
1600
1600
  import * as crypto from "crypto";
@@ -5442,6 +5442,19 @@ var finalizeGoal = async (ctx) => {
5442
5442
  return;
5443
5443
  }
5444
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
+ }
5445
5458
  for (const pr of ordered) {
5446
5459
  if (pr.isDraft) {
5447
5460
  process.stdout.write(`[goal-tick] promoting draft PR #${pr.number} \u2192 ready
@@ -5449,18 +5462,6 @@ var finalizeGoal = async (ctx) => {
5449
5462
  const ready = markPrReady(pr.number, ctx.cwd);
5450
5463
  if (!ready.ok) {
5451
5464
  process.stderr.write(`[goal-tick] finalizeGoal: markPrReady #${pr.number} failed: ${ready.error}
5452
- `);
5453
- return;
5454
- }
5455
- }
5456
- if (pr.baseRefName !== goal.defaultBranch) {
5457
- process.stdout.write(
5458
- `[goal-tick] retargeting PR #${pr.number} base ${pr.baseRefName} \u2192 ${goal.defaultBranch}
5459
- `
5460
- );
5461
- const retarget = editPrBase(pr.number, goal.defaultBranch, ctx.cwd);
5462
- if (!retarget.ok) {
5463
- process.stderr.write(`[goal-tick] finalizeGoal: editPrBase #${pr.number} failed: ${retarget.error}
5464
5465
  `);
5465
5466
  return;
5466
5467
  }
@@ -6310,10 +6311,10 @@ import * as fs24 from "fs";
6310
6311
  import * as path23 from "path";
6311
6312
  var VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "done"]);
6312
6313
  var GoalStateError = class extends Error {
6313
- constructor(path30, message) {
6314
- super(`Invalid goal state at ${path30}:
6314
+ constructor(path31, message) {
6315
+ super(`Invalid goal state at ${path31}:
6315
6316
  ${message}`);
6316
- this.path = path30;
6317
+ this.path = path31;
6317
6318
  this.name = "GoalStateError";
6318
6319
  }
6319
6320
  path;
@@ -6743,6 +6744,63 @@ function formatReviewComments(raw) {
6743
6744
  }
6744
6745
  }
6745
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
+
6746
6804
  // src/scripts/loadTaskState.ts
6747
6805
  var loadTaskState = async (ctx) => {
6748
6806
  const target = ctx.data.commentTargetType;
@@ -8062,8 +8120,8 @@ function resolveBaseOverride(value) {
8062
8120
 
8063
8121
  // src/scripts/runTickScript.ts
8064
8122
  import { spawnSync } from "child_process";
8065
- import * as fs27 from "fs";
8066
- import * as path26 from "path";
8123
+ import * as fs28 from "fs";
8124
+ import * as path27 from "path";
8067
8125
  var runTickScript = async (ctx, _profile, args) => {
8068
8126
  ctx.skipAgent = true;
8069
8127
  const jobsDir = String(args?.jobsDir ?? ".kody/jobs");
@@ -8075,13 +8133,13 @@ var runTickScript = async (ctx, _profile, args) => {
8075
8133
  ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
8076
8134
  return;
8077
8135
  }
8078
- const jobPath = path26.join(ctx.cwd, jobsDir, `${slug}.md`);
8079
- if (!fs27.existsSync(jobPath)) {
8136
+ const jobPath = path27.join(ctx.cwd, jobsDir, `${slug}.md`);
8137
+ if (!fs28.existsSync(jobPath)) {
8080
8138
  ctx.output.exitCode = 99;
8081
8139
  ctx.output.reason = `runTickScript: job file not found: ${jobPath}`;
8082
8140
  return;
8083
8141
  }
8084
- const raw = fs27.readFileSync(jobPath, "utf-8");
8142
+ const raw = fs28.readFileSync(jobPath, "utf-8");
8085
8143
  const { frontmatter } = splitFrontmatter(raw);
8086
8144
  const tickScript = frontmatter.tickScript;
8087
8145
  if (!tickScript) {
@@ -8089,8 +8147,8 @@ var runTickScript = async (ctx, _profile, args) => {
8089
8147
  ctx.output.reason = `runTickScript: job ${slug} has no \`tickScript:\` frontmatter \u2014 route via job-tick instead`;
8090
8148
  return;
8091
8149
  }
8092
- const scriptPath = path26.isAbsolute(tickScript) ? tickScript : path26.join(ctx.cwd, tickScript);
8093
- if (!fs27.existsSync(scriptPath)) {
8150
+ const scriptPath = path27.isAbsolute(tickScript) ? tickScript : path27.join(ctx.cwd, tickScript);
8151
+ if (!fs28.existsSync(scriptPath)) {
8094
8152
  ctx.output.exitCode = 99;
8095
8153
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
8096
8154
  return;
@@ -9027,7 +9085,7 @@ var writeJobStateFile = async (ctx, _profile, _agentResult, args) => {
9027
9085
  };
9028
9086
 
9029
9087
  // src/scripts/writeRunSummary.ts
9030
- import * as fs28 from "fs";
9088
+ import * as fs29 from "fs";
9031
9089
  var writeRunSummary = async (ctx, profile) => {
9032
9090
  const summaryPath = process.env.GITHUB_STEP_SUMMARY;
9033
9091
  if (!summaryPath) return;
@@ -9049,7 +9107,7 @@ var writeRunSummary = async (ctx, profile) => {
9049
9107
  if (reason) lines.push(`- **Reason:** ${reason}`);
9050
9108
  lines.push("");
9051
9109
  try {
9052
- fs28.appendFileSync(summaryPath, `${lines.join("\n")}
9110
+ fs29.appendFileSync(summaryPath, `${lines.join("\n")}
9053
9111
  `);
9054
9112
  } catch {
9055
9113
  }
@@ -9066,6 +9124,7 @@ var preflightScripts = {
9066
9124
  syncFlow,
9067
9125
  initFlow,
9068
9126
  loadTaskState,
9127
+ loadTaskContext,
9069
9128
  loadIssueContext,
9070
9129
  loadIssueStateComment,
9071
9130
  loadJobFromFile,
@@ -9265,9 +9324,9 @@ async function runExecutable(profileName, input) {
9265
9324
  data: {},
9266
9325
  output: { exitCode: 0 }
9267
9326
  };
9268
- const ndjsonDir = path27.join(input.cwd, ".kody");
9327
+ const ndjsonDir = path28.join(input.cwd, ".kody");
9269
9328
  const invokeAgent = async (prompt) => {
9270
- 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);
9271
9330
  const syntheticPath = ctx.data.syntheticPluginPath;
9272
9331
  const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
9273
9332
  return runAgent({
@@ -9431,7 +9490,7 @@ function clearStampedLifecycleLabels(profile, ctx) {
9431
9490
  function getProfileInputsForChild(profileName, _cwd) {
9432
9491
  try {
9433
9492
  const profilePath = resolveProfilePath(profileName);
9434
- if (!fs29.existsSync(profilePath)) return null;
9493
+ if (!fs30.existsSync(profilePath)) return null;
9435
9494
  return loadProfile(profilePath).inputs;
9436
9495
  } catch {
9437
9496
  return null;
@@ -9440,17 +9499,17 @@ function getProfileInputsForChild(profileName, _cwd) {
9440
9499
  function resolveProfilePath(profileName) {
9441
9500
  const found = resolveExecutable(profileName);
9442
9501
  if (found) return found;
9443
- const here = path27.dirname(new URL(import.meta.url).pathname);
9502
+ const here = path28.dirname(new URL(import.meta.url).pathname);
9444
9503
  const candidates = [
9445
- path27.join(here, "executables", profileName, "profile.json"),
9504
+ path28.join(here, "executables", profileName, "profile.json"),
9446
9505
  // same-dir sibling (dev)
9447
- path27.join(here, "..", "executables", profileName, "profile.json"),
9506
+ path28.join(here, "..", "executables", profileName, "profile.json"),
9448
9507
  // up one (prod: dist/bin → dist/executables)
9449
- path27.join(here, "..", "src", "executables", profileName, "profile.json")
9508
+ path28.join(here, "..", "src", "executables", profileName, "profile.json")
9450
9509
  // fallback
9451
9510
  ];
9452
9511
  for (const c of candidates) {
9453
- if (fs29.existsSync(c)) return c;
9512
+ if (fs30.existsSync(c)) return c;
9454
9513
  }
9455
9514
  return candidates[0];
9456
9515
  }
@@ -9547,8 +9606,8 @@ function resolveShellTimeoutMs(entry) {
9547
9606
  var SIGKILL_GRACE_MS = 5e3;
9548
9607
  async function runShellEntry(entry, ctx, profile) {
9549
9608
  const shellName = entry.shell;
9550
- const shellPath = path27.join(profile.dir, shellName);
9551
- if (!fs29.existsSync(shellPath)) {
9609
+ const shellPath = path28.join(profile.dir, shellName);
9610
+ if (!fs30.existsSync(shellPath)) {
9552
9611
  ctx.skipAgent = true;
9553
9612
  ctx.output.exitCode = 99;
9554
9613
  ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
@@ -9993,9 +10052,9 @@ function resolveAuthToken(env = process.env) {
9993
10052
  return token;
9994
10053
  }
9995
10054
  function detectPackageManager2(cwd) {
9996
- if (fs30.existsSync(path28.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
9997
- if (fs30.existsSync(path28.join(cwd, "yarn.lock"))) return "yarn";
9998
- 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";
9999
10058
  return "npm";
10000
10059
  }
10001
10060
  function shellOut(cmd, args, cwd, stream = true) {
@@ -10082,11 +10141,11 @@ function configureGitIdentity(cwd) {
10082
10141
  }
10083
10142
  function postFailureTail(issueNumber, cwd, reason) {
10084
10143
  if (!issueNumber) return;
10085
- const logPath = path28.join(cwd, ".kody", "last-run.jsonl");
10144
+ const logPath = path29.join(cwd, ".kody", "last-run.jsonl");
10086
10145
  let tail = "";
10087
10146
  try {
10088
- if (fs30.existsSync(logPath)) {
10089
- const content = fs30.readFileSync(logPath, "utf-8");
10147
+ if (fs31.existsSync(logPath)) {
10148
+ const content = fs31.readFileSync(logPath, "utf-8");
10090
10149
  tail = content.slice(-3e3);
10091
10150
  }
10092
10151
  } catch {
@@ -10111,7 +10170,7 @@ async function runCi(argv) {
10111
10170
  return 0;
10112
10171
  }
10113
10172
  const args = parseCiArgs(argv);
10114
- const cwd = args.cwd ? path28.resolve(args.cwd) : process.cwd();
10173
+ const cwd = args.cwd ? path29.resolve(args.cwd) : process.cwd();
10115
10174
  let earlyConfig;
10116
10175
  try {
10117
10176
  earlyConfig = loadConfig(cwd);
@@ -10121,9 +10180,9 @@ async function runCi(argv) {
10121
10180
  const eventName = process.env.GITHUB_EVENT_NAME;
10122
10181
  const dispatchEventPath = process.env.GITHUB_EVENT_PATH;
10123
10182
  let manualWorkflowDispatch = false;
10124
- if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs30.existsSync(dispatchEventPath)) {
10183
+ if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs31.existsSync(dispatchEventPath)) {
10125
10184
  try {
10126
- const evt = JSON.parse(fs30.readFileSync(dispatchEventPath, "utf-8"));
10185
+ const evt = JSON.parse(fs31.readFileSync(dispatchEventPath, "utf-8"));
10127
10186
  const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
10128
10187
  const sessionInput = String(evt?.inputs?.sessionId ?? "");
10129
10188
  manualWorkflowDispatch = !sessionInput && !(Number.isFinite(issueInput) && issueInput > 0);
@@ -10382,9 +10441,9 @@ function parseChatArgs(argv, env = process.env) {
10382
10441
  return result;
10383
10442
  }
10384
10443
  function commitChatFiles(cwd, sessionId, verbose) {
10385
- const sessionFile = path29.relative(cwd, sessionFilePath(cwd, sessionId));
10386
- const eventsFile = path29.relative(cwd, eventsFilePath(cwd, sessionId));
10387
- 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)));
10388
10447
  if (paths.length === 0) return;
10389
10448
  const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
10390
10449
  try {
@@ -10422,7 +10481,7 @@ async function runChat(argv) {
10422
10481
  ${CHAT_HELP}`);
10423
10482
  return 64;
10424
10483
  }
10425
- const cwd = args.cwd ? path29.resolve(args.cwd) : process.cwd();
10484
+ const cwd = args.cwd ? path30.resolve(args.cwd) : process.cwd();
10426
10485
  const sessionId = args.sessionId;
10427
10486
  const unpackedSecrets = unpackAllSecrets();
10428
10487
  if (unpackedSecrets > 0) {
@@ -10474,7 +10533,7 @@ ${CHAT_HELP}`);
10474
10533
  const sink = buildSink(cwd, sessionId, args.dashboardUrl);
10475
10534
  const meta = readMeta(sessionFile);
10476
10535
  process.stdout.write(
10477
- `\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"}
10478
10537
  `
10479
10538
  );
10480
10539
  try {
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.56",
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
+ }