@kody-ade/kody-engine 0.4.140 → 0.4.141

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
@@ -672,28 +672,28 @@ var loadMemoryContext_exports = {};
672
672
  __export(loadMemoryContext_exports, {
673
673
  loadMemoryContext: () => loadMemoryContext
674
674
  });
675
- import * as fs32 from "fs";
676
- import * as path31 from "path";
675
+ import * as fs31 from "fs";
676
+ import * as path29 from "path";
677
677
  function collectPages(memoryAbs) {
678
678
  const out = [];
679
679
  walkMd(memoryAbs, (file) => {
680
680
  let stat;
681
681
  try {
682
- stat = fs32.statSync(file);
682
+ stat = fs31.statSync(file);
683
683
  } catch {
684
684
  return;
685
685
  }
686
686
  let raw;
687
687
  try {
688
- raw = fs32.readFileSync(file, "utf-8");
688
+ raw = fs31.readFileSync(file, "utf-8");
689
689
  } catch {
690
690
  return;
691
691
  }
692
692
  const fm = raw.match(/^---\s*\n([\s\S]*?)\n---/);
693
- const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path31.basename(file, ".md");
693
+ const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path29.basename(file, ".md");
694
694
  const updated = fm?.[1]?.match(/^updated:\s*([0-9T:.+\-Z]+)/m)?.[1]?.trim() ?? "";
695
695
  out.push({
696
- relPath: path31.relative(memoryAbs, file),
696
+ relPath: path29.relative(memoryAbs, file),
697
697
  title,
698
698
  updated,
699
699
  content: raw.length > PER_PAGE_MAX_BYTES ? raw.slice(0, PER_PAGE_MAX_BYTES) + TRUNCATED_SUFFIX : raw,
@@ -761,16 +761,16 @@ function walkMd(root, visit) {
761
761
  const dir = stack.pop();
762
762
  let names;
763
763
  try {
764
- names = fs32.readdirSync(dir);
764
+ names = fs31.readdirSync(dir);
765
765
  } catch {
766
766
  continue;
767
767
  }
768
768
  for (const name of names) {
769
769
  if (name.startsWith(".")) continue;
770
- const full = path31.join(dir, name);
770
+ const full = path29.join(dir, name);
771
771
  let stat;
772
772
  try {
773
- stat = fs32.statSync(full);
773
+ stat = fs31.statSync(full);
774
774
  } catch {
775
775
  continue;
776
776
  }
@@ -793,8 +793,8 @@ var init_loadMemoryContext = __esm({
793
793
  TRUNCATED_SUFFIX = "\n\n\u2026 (truncated)";
794
794
  loadMemoryContext = async (ctx) => {
795
795
  if (typeof ctx.data.memoryContext === "string") return;
796
- const memoryAbs = path31.join(ctx.cwd, MEMORY_DIR_RELATIVE);
797
- if (!fs32.existsSync(memoryAbs)) {
796
+ const memoryAbs = path29.join(ctx.cwd, MEMORY_DIR_RELATIVE);
797
+ if (!fs31.existsSync(memoryAbs)) {
798
798
  ctx.data.memoryContext = "";
799
799
  return;
800
800
  }
@@ -926,7 +926,7 @@ var init_loadPriorArt = __esm({
926
926
  // package.json
927
927
  var package_default = {
928
928
  name: "@kody-ade/kody-engine",
929
- version: "0.4.140",
929
+ version: "0.4.141",
930
930
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
931
931
  license: "MIT",
932
932
  type: "module",
@@ -982,9 +982,9 @@ var package_default = {
982
982
  };
983
983
 
984
984
  // src/chat-cli.ts
985
- import { execFileSync as execFileSync32 } from "child_process";
986
- import * as fs42 from "fs";
987
- import * as path39 from "path";
985
+ import { execFileSync as execFileSync30 } from "child_process";
986
+ import * as fs41 from "fs";
987
+ import * as path37 from "path";
988
988
 
989
989
  // src/chat/events.ts
990
990
  import * as fs from "fs";
@@ -2533,9 +2533,9 @@ async function emit2(sink, type, sessionId, suffix, payload) {
2533
2533
  }
2534
2534
 
2535
2535
  // src/kody-cli.ts
2536
- import { execFileSync as execFileSync31 } from "child_process";
2537
- import * as fs41 from "fs";
2538
- import * as path38 from "path";
2536
+ import { execFileSync as execFileSync29 } from "child_process";
2537
+ import * as fs40 from "fs";
2538
+ import * as path36 from "path";
2539
2539
 
2540
2540
  // src/dispatch.ts
2541
2541
  import * as fs11 from "fs";
@@ -2867,9 +2867,9 @@ function coerceBare(spec, value) {
2867
2867
  init_issue();
2868
2868
 
2869
2869
  // src/executor.ts
2870
- import { execFileSync as execFileSync30, spawn as spawn9 } from "child_process";
2871
- import * as fs40 from "fs";
2872
- import * as path37 from "path";
2870
+ import { execFileSync as execFileSync28, spawn as spawn9 } from "child_process";
2871
+ import * as fs39 from "fs";
2872
+ import * as path35 from "path";
2873
2873
 
2874
2874
  // src/discipline.ts
2875
2875
  var DISCIPLINE = `# Working discipline (applies to this entire task)
@@ -5047,43 +5047,181 @@ var commitAndPush2 = async (ctx, profile) => {
5047
5047
  }
5048
5048
  };
5049
5049
 
5050
- // src/scripts/commitGoalState.ts
5051
- import { execFileSync as execFileSync10 } from "child_process";
5052
- import * as path20 from "path";
5053
- var commitGoalState = async (ctx) => {
5054
- const goal = ctx.data.goal;
5055
- if (!goal) return;
5056
- const stateRel = path20.posix.join(".kody", "goals", goal.id, "state.json");
5050
+ // src/goal/stateStore.ts
5051
+ init_issue();
5052
+
5053
+ // src/stateBranch.ts
5054
+ init_issue();
5055
+ var STATE_BRANCH = "kody-state";
5056
+ function is404(err) {
5057
+ const msg = err instanceof Error ? err.message : String(err);
5058
+ return /HTTP 404/i.test(msg) || /Not Found/i.test(msg);
5059
+ }
5060
+ function ensureStateBranch(owner, repo, cwd) {
5057
5061
  try {
5058
- execFileSync10("git", ["add", stateRel], { cwd: ctx.cwd, stdio: "pipe" });
5062
+ gh(["api", `/repos/${owner}/${repo}/git/ref/heads/${STATE_BRANCH}`], { cwd });
5063
+ return;
5059
5064
  } catch (err) {
5060
- process.stderr.write(
5061
- `[goal-tick] commitGoalState: git add failed: ${err instanceof Error ? err.message : String(err)}
5062
- `
5065
+ if (!is404(err)) throw err;
5066
+ }
5067
+ const repoInfo = JSON.parse(gh(["api", `/repos/${owner}/${repo}`], { cwd }));
5068
+ const defaultBranch2 = repoInfo.default_branch;
5069
+ if (!defaultBranch2) {
5070
+ throw new Error(`ensureStateBranch: could not resolve default branch for ${owner}/${repo}`);
5071
+ }
5072
+ const headRef = JSON.parse(
5073
+ gh(["api", `/repos/${owner}/${repo}/git/ref/heads/${defaultBranch2}`], { cwd })
5074
+ );
5075
+ const sha = headRef.object?.sha;
5076
+ if (!sha) {
5077
+ throw new Error(`ensureStateBranch: could not resolve head sha for ${owner}/${repo}@${defaultBranch2}`);
5078
+ }
5079
+ try {
5080
+ gh(["api", "--method", "POST", `/repos/${owner}/${repo}/git/refs`, "--input", "-"], {
5081
+ cwd,
5082
+ input: JSON.stringify({ ref: `refs/heads/${STATE_BRANCH}`, sha })
5083
+ });
5084
+ } catch (err) {
5085
+ const msg = err instanceof Error ? err.message : String(err);
5086
+ if (/already exists/i.test(msg) || /HTTP 422/i.test(msg)) return;
5087
+ throw err;
5088
+ }
5089
+ }
5090
+
5091
+ // src/goal/state.ts
5092
+ import * as fs21 from "fs";
5093
+ import * as path20 from "path";
5094
+ var VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "awaiting-merge", "done"]);
5095
+ var GoalStateError = class extends Error {
5096
+ constructor(path38, message) {
5097
+ super(`Invalid goal state at ${path38}:
5098
+ ${message}`);
5099
+ this.path = path38;
5100
+ this.name = "GoalStateError";
5101
+ }
5102
+ path;
5103
+ };
5104
+ function parseGoalState(filePath, raw) {
5105
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
5106
+ throw new GoalStateError(filePath, "must be a JSON object");
5107
+ }
5108
+ const r = raw;
5109
+ const stateValue = r.state;
5110
+ if (typeof stateValue !== "string" || !VALID_STATES.has(stateValue)) {
5111
+ throw new GoalStateError(
5112
+ filePath,
5113
+ `"state" is required and must be one of: ${[...VALID_STATES].join(" | ")} (got ${JSON.stringify(stateValue)})`
5063
5114
  );
5064
- return;
5065
5115
  }
5116
+ const parsed = {
5117
+ state: stateValue,
5118
+ extra: {}
5119
+ };
5120
+ if (typeof r.mergeApproved === "boolean") {
5121
+ parsed.mergeApproved = r.mergeApproved;
5122
+ }
5123
+ if (typeof r.lastDispatchedIssue === "number" && Number.isFinite(r.lastDispatchedIssue)) {
5124
+ parsed.lastDispatchedIssue = r.lastDispatchedIssue;
5125
+ }
5126
+ for (const ts of ["updatedAt", "createdAt", "startedAt"]) {
5127
+ const v = r[ts];
5128
+ if (typeof v === "string" && v.length > 0) parsed[ts] = v;
5129
+ }
5130
+ const known = /* @__PURE__ */ new Set(["state", "mergeApproved", "lastDispatchedIssue", "updatedAt", "createdAt", "startedAt"]);
5131
+ for (const [k, v] of Object.entries(r)) {
5132
+ if (!known.has(k)) parsed.extra[k] = v;
5133
+ }
5134
+ return parsed;
5135
+ }
5136
+ function serializeGoalState(s) {
5137
+ const obj = { ...s.extra, state: s.state };
5138
+ if (s.mergeApproved !== void 0) obj.mergeApproved = s.mergeApproved;
5139
+ if (s.lastDispatchedIssue !== void 0) obj.lastDispatchedIssue = s.lastDispatchedIssue;
5140
+ if (s.createdAt !== void 0) obj.createdAt = s.createdAt;
5141
+ if (s.startedAt !== void 0) obj.startedAt = s.startedAt;
5142
+ if (s.updatedAt !== void 0) obj.updatedAt = s.updatedAt;
5143
+ return `${JSON.stringify(obj, null, 2)}
5144
+ `;
5145
+ }
5146
+ function nowIso() {
5147
+ return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
5148
+ }
5149
+
5150
+ // src/goal/stateStore.ts
5151
+ function statePath(goalId) {
5152
+ return `.kody/goals/${goalId}/state.json`;
5153
+ }
5154
+ function is4042(err) {
5155
+ const msg = err instanceof Error ? err.message : String(err);
5156
+ return /HTTP 404/i.test(msg) || /Not Found/i.test(msg);
5157
+ }
5158
+ function fetchGoalState(owner, repo, goalId, cwd) {
5159
+ const filePath = statePath(goalId);
5160
+ let raw;
5066
5161
  try {
5067
- execFileSync10("git", ["diff", "--cached", "--quiet"], { cwd: ctx.cwd, stdio: "pipe" });
5162
+ raw = gh(["api", `/repos/${owner}/${repo}/contents/${filePath}?ref=${STATE_BRANCH}`], { cwd });
5163
+ } catch (err) {
5164
+ if (is4042(err)) return null;
5165
+ throw err;
5166
+ }
5167
+ const o = JSON.parse(raw);
5168
+ if (!o.content) return null;
5169
+ const decoded = Buffer.from(o.content, "base64").toString("utf-8");
5170
+ return parseGoalState(filePath, JSON.parse(decoded));
5171
+ }
5172
+ function putGoalState(owner, repo, goalId, state, message, cwd) {
5173
+ ensureStateBranch(owner, repo, cwd);
5174
+ const filePath = statePath(goalId);
5175
+ const content = Buffer.from(serializeGoalState(state), "utf-8").toString("base64");
5176
+ for (let attempt = 1; attempt <= 3; attempt++) {
5177
+ let sha;
5178
+ try {
5179
+ const cur = gh(["api", `/repos/${owner}/${repo}/contents/${filePath}?ref=${STATE_BRANCH}`], { cwd });
5180
+ const o = JSON.parse(cur);
5181
+ if (o.sha) sha = o.sha;
5182
+ } catch (err) {
5183
+ if (!is4042(err)) throw err;
5184
+ }
5185
+ const payload = { message, content, branch: STATE_BRANCH };
5186
+ if (sha) payload.sha = sha;
5187
+ try {
5188
+ gh(["api", "--method", "PUT", `/repos/${owner}/${repo}/contents/${filePath}`, "--input", "-"], {
5189
+ cwd,
5190
+ input: JSON.stringify(payload)
5191
+ });
5192
+ return;
5193
+ } catch (err) {
5194
+ const msg = err instanceof Error ? err.message : String(err);
5195
+ const conflict = /HTTP 409/i.test(msg) || /HTTP 422/i.test(msg) || /does not match|but expected/i.test(msg);
5196
+ if (!conflict || attempt === 3) throw err;
5197
+ }
5198
+ }
5199
+ }
5200
+
5201
+ // src/scripts/commitGoalState.ts
5202
+ var commitGoalState = async (ctx) => {
5203
+ const goal = ctx.data.goal;
5204
+ if (!goal) return;
5205
+ if (ctx.data.goalPersistChanged !== true) return;
5206
+ const updated = ctx.data.goalPersistState;
5207
+ if (!updated) return;
5208
+ const owner = ctx.config.github?.owner;
5209
+ const repo = ctx.config.github?.repo;
5210
+ if (!owner || !repo) {
5211
+ process.stderr.write(`[goal-tick] commitGoalState: missing github owner/repo; cannot persist ${goal.id}
5212
+ `);
5068
5213
  return;
5069
- } catch {
5070
5214
  }
5071
- const msg = describeCommitMessage(goal);
5072
5215
  try {
5073
- execFileSync10("git", ["commit", "-m", msg, "--quiet"], { cwd: ctx.cwd, stdio: "pipe" });
5216
+ putGoalState(owner, repo, goal.id, updated, describeCommitMessage(goal), ctx.cwd);
5074
5217
  } catch (err) {
5075
5218
  process.stderr.write(
5076
- `[goal-tick] commitGoalState: git commit failed: ${err instanceof Error ? err.message : String(err)}
5219
+ `[goal-tick] commitGoalState: persist to ${STATE_BRANCH_LABEL} failed (${err instanceof Error ? err.message : String(err)}); will retry next tick
5077
5220
  `
5078
5221
  );
5079
- return;
5080
- }
5081
- const result = pushWithRetry({ cwd: ctx.cwd });
5082
- if (!result.ok) {
5083
- process.stderr.write(`[goal-tick] commitGoalState: push failed (${result.reason}); will retry next tick
5084
- `);
5085
5222
  }
5086
5223
  };
5224
+ var STATE_BRANCH_LABEL = "kody-state";
5087
5225
  function describeCommitMessage(goal) {
5088
5226
  if (goal.state === "closed") return `chore(goals): abandon ${goal.id} (cleanup complete)`;
5089
5227
  if (goal.state === "awaiting-merge") return `chore(goals): park ${goal.id} awaiting merge`;
@@ -5098,7 +5236,7 @@ function describeCommitMessage(goal) {
5098
5236
  }
5099
5237
 
5100
5238
  // src/scripts/composePrompt.ts
5101
- import * as fs21 from "fs";
5239
+ import * as fs22 from "fs";
5102
5240
  import * as path21 from "path";
5103
5241
  var MUSTACHE = /\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g;
5104
5242
  var composePrompt = async (ctx, profile) => {
@@ -5111,7 +5249,7 @@ var composePrompt = async (ctx, profile) => {
5111
5249
  ].filter(Boolean);
5112
5250
  let templatePath = "";
5113
5251
  for (const c of candidates) {
5114
- if (fs21.existsSync(c)) {
5252
+ if (fs22.existsSync(c)) {
5115
5253
  templatePath = c;
5116
5254
  break;
5117
5255
  }
@@ -5119,7 +5257,7 @@ var composePrompt = async (ctx, profile) => {
5119
5257
  if (!templatePath) {
5120
5258
  throw new Error(`profile at ${profile.dir}: no prompt template found (tried ${candidates.join(", ")})`);
5121
5259
  }
5122
- const template = fs21.readFileSync(templatePath, "utf-8");
5260
+ const template = fs22.readFileSync(templatePath, "utf-8");
5123
5261
  const tokens = {
5124
5262
  ...stringifyAll(ctx.args, "args."),
5125
5263
  ...stringifyAll(ctx.data, ""),
@@ -5197,9 +5335,6 @@ function formatToolsUsage(profile) {
5197
5335
 
5198
5336
  // src/scripts/createQaGoal.ts
5199
5337
  init_issue();
5200
- import { execFileSync as execFileSync11 } from "child_process";
5201
- import * as fs22 from "fs";
5202
- import * as path22 from "path";
5203
5338
 
5204
5339
  // src/scripts/postReviewResult.ts
5205
5340
  init_issue();
@@ -5451,104 +5586,6 @@ function createOrUpdateManifestIssue(number, manifest, cwd) {
5451
5586
  if (!m) throw new Error(`gh issue create returned unexpected output: ${out}`);
5452
5587
  return { number: Number(m[1]), created: true };
5453
5588
  }
5454
- function writeStateFile(cwd, goalId, lastDispatchedIssue) {
5455
- const dir = path22.join(cwd, ".kody", "goals", goalId);
5456
- fs22.mkdirSync(dir, { recursive: true });
5457
- const state = {
5458
- version: 1,
5459
- state: "active",
5460
- startedAt: (/* @__PURE__ */ new Date()).toISOString(),
5461
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
5462
- ...typeof lastDispatchedIssue === "number" ? { lastDispatchedIssue } : {}
5463
- };
5464
- const filePath = path22.join(dir, "state.json");
5465
- fs22.writeFileSync(filePath, `${JSON.stringify(state, null, 2)}
5466
- `);
5467
- return filePath;
5468
- }
5469
- function gitTry(args, cwd) {
5470
- const env = { ...process.env, SKIP_HOOKS: "1", HUSKY: "0" };
5471
- try {
5472
- execFileSync11("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"], env });
5473
- return { ok: true, stderr: "" };
5474
- } catch (err) {
5475
- const e = err;
5476
- const stderr = typeof e?.stderr === "string" ? e.stderr : Buffer.isBuffer(e?.stderr) ? e.stderr.toString("utf8") : e?.message ?? "";
5477
- return { ok: false, stderr: stderr.trim() };
5478
- }
5479
- }
5480
- function commitAndPushState(filePath, goalId, cwd) {
5481
- const add = gitTry(["add", filePath], cwd);
5482
- if (!add.ok) {
5483
- process.stderr.write(`[createQaGoal] git add failed: ${add.stderr.slice(-400) || "(no stderr)"}
5484
- `);
5485
- return;
5486
- }
5487
- const diff = gitTry(["diff", "--cached", "--quiet"], cwd);
5488
- if (diff.ok) {
5489
- process.stderr.write(`[createQaGoal] state.json unchanged \u2014 nothing to commit
5490
- `);
5491
- return;
5492
- }
5493
- const commit = gitTry(["commit", "-m", `chore(goals): activate ${goalId}`, "--quiet"], cwd);
5494
- if (!commit.ok) {
5495
- process.stderr.write(`[createQaGoal] git commit failed: ${commit.stderr.slice(-400) || "(no stderr)"}
5496
- `);
5497
- return;
5498
- }
5499
- const push = gitTry(["push", "--quiet"], cwd);
5500
- if (push.ok) return;
5501
- const stderr = push.stderr;
5502
- const tail = stderr.slice(-400) || "(no stderr captured)";
5503
- if (/non-fast-forward|rejected|fetch first|behind/i.test(stderr)) {
5504
- process.stderr.write(`[createQaGoal] push rejected (non-fast-forward) \u2014 pulling --rebase and retrying
5505
- `);
5506
- const rebase = gitTry(["pull", "--rebase", "--autostash", "--quiet"], cwd);
5507
- if (!rebase.ok) {
5508
- process.stderr.write(
5509
- `[createQaGoal] rebase failed (manual recovery required): ${rebase.stderr.slice(-400) || "(no stderr)"}
5510
- `
5511
- );
5512
- return;
5513
- }
5514
- const retryPush = gitTry(["push", "--quiet"], cwd);
5515
- if (retryPush.ok) {
5516
- process.stderr.write(`[createQaGoal] push succeeded after rebase
5517
- `);
5518
- return;
5519
- }
5520
- process.stderr.write(
5521
- `[createQaGoal] push still failed after rebase: ${retryPush.stderr.slice(-400) || "(no stderr)"}
5522
- `
5523
- );
5524
- return;
5525
- }
5526
- if (/pre-push|hook|husky/i.test(stderr)) {
5527
- process.stderr.write(`[createQaGoal] push rejected by pre-push hook \u2014 retrying with --no-verify
5528
- `);
5529
- process.stderr.write(`[createQaGoal] hook output:
5530
- ${tail}
5531
- `);
5532
- const noVerify = gitTry(["push", "--no-verify", "--quiet"], cwd);
5533
- if (noVerify.ok) {
5534
- process.stderr.write(`[createQaGoal] push succeeded with --no-verify (consider adding kody artifacts to ignore configs)
5535
- `);
5536
- return;
5537
- }
5538
- process.stderr.write(
5539
- `[createQaGoal] --no-verify push also failed: ${noVerify.stderr.slice(-400) || "(no stderr)"}
5540
- `
5541
- );
5542
- return;
5543
- }
5544
- process.stderr.write(
5545
- `[createQaGoal] state.json commit landed but push failed.
5546
- [createQaGoal] The goal will not be visible to goal-scheduler in CI until you run 'git push' manually.
5547
- [createQaGoal] git stderr:
5548
- ${tail}
5549
- `
5550
- );
5551
- }
5552
5589
  function createTaskIssue(finding, goalId, manifestNumber, cwd) {
5553
5590
  const labels = [`goal:${goalId}`, severityLabel(finding.severity), FINDING_LABEL];
5554
5591
  ensureLabel(`goal:${goalId}`, "1d76db", `goal: ${goalId}`, cwd);
@@ -5718,8 +5755,17 @@ ${markdown}`,
5718
5755
  `);
5719
5756
  }
5720
5757
  }
5721
- const stateFile = writeStateFile(ctx.cwd, goalId);
5722
- commitAndPushState(stateFile, goalId, ctx.cwd);
5758
+ const now = nowIso();
5759
+ const goalState = { state: "active", startedAt: now, updatedAt: now, extra: { version: 1 } };
5760
+ try {
5761
+ putGoalState(ctx.config.github.owner, ctx.config.github.repo, goalId, goalState, `chore(goals): activate ${goalId}`, ctx.cwd);
5762
+ } catch (err) {
5763
+ process.stderr.write(
5764
+ `[createQaGoal] failed to persist goal state to kody-state: ${err instanceof Error ? err.message : String(err)}
5765
+ [createQaGoal] goal-scheduler will not see ${goalId} until this succeeds.
5766
+ `
5767
+ );
5768
+ }
5723
5769
  const repoUrl = `https://github.com/${ctx.config.github.owner}/${ctx.config.github.repo}`;
5724
5770
  if (manifestIssueNumber !== null) {
5725
5771
  const verb = manifestUpdated ? manifestCreated ? "OPENED" : "UPDATED" : "TARGETED";
@@ -5988,13 +6034,13 @@ function filterGoalTaskPrs(prs, taskIssueNumbers) {
5988
6034
  }
5989
6035
 
5990
6036
  // src/scripts/diagMcp.ts
5991
- import { execFileSync as execFileSync12 } from "child_process";
6037
+ import { execFileSync as execFileSync10 } from "child_process";
5992
6038
  import * as fs23 from "fs";
5993
6039
  import * as os4 from "os";
5994
- import * as path23 from "path";
6040
+ import * as path22 from "path";
5995
6041
  var diagMcp = async (_ctx) => {
5996
6042
  const home = os4.homedir();
5997
- const cacheDir = path23.join(home, ".cache", "ms-playwright");
6043
+ const cacheDir = path22.join(home, ".cache", "ms-playwright");
5998
6044
  let entries = [];
5999
6045
  try {
6000
6046
  entries = fs23.readdirSync(cacheDir);
@@ -6008,7 +6054,7 @@ var diagMcp = async (_ctx) => {
6008
6054
  process.stderr.write(`[kody diag] chromium present: ${hasChromium ? "yes" : "no"}
6009
6055
  `);
6010
6056
  try {
6011
- const v = execFileSync12("npx", ["-y", "--package=@playwright/mcp@latest", "--", "playwright-mcp", "--version"], {
6057
+ const v = execFileSync10("npx", ["-y", "--package=@playwright/mcp@latest", "--", "playwright-mcp", "--version"], {
6012
6058
  stdio: "pipe",
6013
6059
  timeout: 6e4,
6014
6060
  encoding: "utf8"
@@ -6024,16 +6070,16 @@ var diagMcp = async (_ctx) => {
6024
6070
 
6025
6071
  // src/scripts/discoverQaContext.ts
6026
6072
  import * as fs25 from "fs";
6027
- import * as path25 from "path";
6073
+ import * as path24 from "path";
6028
6074
 
6029
6075
  // src/scripts/frameworkDetectors.ts
6030
6076
  import * as fs24 from "fs";
6031
- import * as path24 from "path";
6077
+ import * as path23 from "path";
6032
6078
  function detectFrameworks(cwd) {
6033
6079
  const out = [];
6034
6080
  let deps = {};
6035
6081
  try {
6036
- const pkg = JSON.parse(fs24.readFileSync(path24.join(cwd, "package.json"), "utf-8"));
6082
+ const pkg = JSON.parse(fs24.readFileSync(path23.join(cwd, "package.json"), "utf-8"));
6037
6083
  deps = { ...pkg.dependencies, ...pkg.devDependencies };
6038
6084
  } catch {
6039
6085
  return out;
@@ -6070,7 +6116,7 @@ function detectFrameworks(cwd) {
6070
6116
  }
6071
6117
  function findFile(cwd, candidates) {
6072
6118
  for (const c of candidates) {
6073
- if (fs24.existsSync(path24.join(cwd, c))) return c;
6119
+ if (fs24.existsSync(path23.join(cwd, c))) return c;
6074
6120
  }
6075
6121
  return null;
6076
6122
  }
@@ -6083,7 +6129,7 @@ var COLLECTION_DIRS = [
6083
6129
  function discoverPayloadCollections(cwd) {
6084
6130
  const out = [];
6085
6131
  for (const dir of COLLECTION_DIRS) {
6086
- const full = path24.join(cwd, dir);
6132
+ const full = path23.join(cwd, dir);
6087
6133
  if (!fs24.existsSync(full)) continue;
6088
6134
  let files;
6089
6135
  try {
@@ -6093,7 +6139,7 @@ function discoverPayloadCollections(cwd) {
6093
6139
  }
6094
6140
  for (const file of files) {
6095
6141
  try {
6096
- const filePath = path24.join(full, file);
6142
+ const filePath = path23.join(full, file);
6097
6143
  const content = fs24.readFileSync(filePath, "utf-8").slice(0, 1e4);
6098
6144
  const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
6099
6145
  if (!slugMatch) continue;
@@ -6108,7 +6154,7 @@ function discoverPayloadCollections(cwd) {
6108
6154
  out.push({
6109
6155
  name,
6110
6156
  slug,
6111
- filePath: path24.relative(cwd, filePath),
6157
+ filePath: path23.relative(cwd, filePath),
6112
6158
  fields: fields.slice(0, 20),
6113
6159
  hasAdmin
6114
6160
  });
@@ -6122,7 +6168,7 @@ var ADMIN_COMPONENT_DIRS = ["src/ui/admin", "src/admin/components", "src/compone
6122
6168
  function discoverAdminComponents(cwd, collections) {
6123
6169
  const out = [];
6124
6170
  for (const dir of ADMIN_COMPONENT_DIRS) {
6125
- const full = path24.join(cwd, dir);
6171
+ const full = path23.join(cwd, dir);
6126
6172
  if (!fs24.existsSync(full)) continue;
6127
6173
  let entries;
6128
6174
  try {
@@ -6131,19 +6177,19 @@ function discoverAdminComponents(cwd, collections) {
6131
6177
  continue;
6132
6178
  }
6133
6179
  for (const entry of entries) {
6134
- const entryPath = path24.join(full, entry.name);
6180
+ const entryPath = path23.join(full, entry.name);
6135
6181
  let name;
6136
6182
  let filePath;
6137
6183
  if (entry.isDirectory()) {
6138
6184
  const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
6139
- (f) => fs24.existsSync(path24.join(entryPath, f))
6185
+ (f) => fs24.existsSync(path23.join(entryPath, f))
6140
6186
  );
6141
6187
  if (!indexFile) continue;
6142
6188
  name = entry.name;
6143
- filePath = path24.relative(cwd, path24.join(entryPath, indexFile));
6189
+ filePath = path23.relative(cwd, path23.join(entryPath, indexFile));
6144
6190
  } else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
6145
6191
  name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
6146
- filePath = path24.relative(cwd, entryPath);
6192
+ filePath = path23.relative(cwd, entryPath);
6147
6193
  } else {
6148
6194
  continue;
6149
6195
  }
@@ -6151,7 +6197,7 @@ function discoverAdminComponents(cwd, collections) {
6151
6197
  if (collections) {
6152
6198
  for (const col of collections) {
6153
6199
  try {
6154
- const colContent = fs24.readFileSync(path24.join(cwd, col.filePath), "utf-8");
6200
+ const colContent = fs24.readFileSync(path23.join(cwd, col.filePath), "utf-8");
6155
6201
  if (colContent.includes(name)) {
6156
6202
  usedInCollection = col.slug;
6157
6203
  break;
@@ -6170,7 +6216,7 @@ function scanApiRoutes(cwd) {
6170
6216
  const out = [];
6171
6217
  const appDirs = ["src/app", "app"];
6172
6218
  for (const appDir of appDirs) {
6173
- const apiDir = path24.join(cwd, appDir, "api");
6219
+ const apiDir = path23.join(cwd, appDir, "api");
6174
6220
  if (!fs24.existsSync(apiDir)) continue;
6175
6221
  walkApiRoutes(apiDir, "/api", cwd, out);
6176
6222
  break;
@@ -6187,7 +6233,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
6187
6233
  const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
6188
6234
  if (routeFile) {
6189
6235
  try {
6190
- const content = fs24.readFileSync(path24.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
6236
+ const content = fs24.readFileSync(path23.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
6191
6237
  const methods = HTTP_METHODS.filter(
6192
6238
  (m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
6193
6239
  );
@@ -6195,7 +6241,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
6195
6241
  out.push({
6196
6242
  path: prefix,
6197
6243
  methods,
6198
- filePath: path24.relative(cwd, path24.join(dir, routeFile.name))
6244
+ filePath: path23.relative(cwd, path23.join(dir, routeFile.name))
6199
6245
  });
6200
6246
  }
6201
6247
  } catch {
@@ -6206,7 +6252,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
6206
6252
  if (entry.name === "node_modules" || entry.name === ".next") continue;
6207
6253
  let segment = entry.name;
6208
6254
  if (segment.startsWith("(") && segment.endsWith(")")) {
6209
- walkApiRoutes(path24.join(dir, entry.name), prefix, cwd, out);
6255
+ walkApiRoutes(path23.join(dir, entry.name), prefix, cwd, out);
6210
6256
  continue;
6211
6257
  }
6212
6258
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -6214,7 +6260,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
6214
6260
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
6215
6261
  segment = `:${segment.slice(1, -1)}`;
6216
6262
  }
6217
- walkApiRoutes(path24.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
6263
+ walkApiRoutes(path23.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
6218
6264
  }
6219
6265
  }
6220
6266
  var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
@@ -6234,7 +6280,7 @@ var BUILTIN_ENV_VARS = /* @__PURE__ */ new Set([
6234
6280
  function scanEnvVars(cwd) {
6235
6281
  const candidates = [".env.example", ".env.local.example", ".env.template"];
6236
6282
  for (const envFile of candidates) {
6237
- const envPath = path24.join(cwd, envFile);
6283
+ const envPath = path23.join(cwd, envFile);
6238
6284
  if (!fs24.existsSync(envPath)) continue;
6239
6285
  try {
6240
6286
  const content = fs24.readFileSync(envPath, "utf-8");
@@ -6285,9 +6331,9 @@ function runQaDiscovery(cwd) {
6285
6331
  }
6286
6332
  function detectDevServer(cwd, out) {
6287
6333
  try {
6288
- const pkg = JSON.parse(fs25.readFileSync(path25.join(cwd, "package.json"), "utf-8"));
6334
+ const pkg = JSON.parse(fs25.readFileSync(path24.join(cwd, "package.json"), "utf-8"));
6289
6335
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
6290
- const pm = fs25.existsSync(path25.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs25.existsSync(path25.join(cwd, "yarn.lock")) ? "yarn" : fs25.existsSync(path25.join(cwd, "bun.lockb")) ? "bun" : "npm";
6336
+ const pm = fs25.existsSync(path24.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs25.existsSync(path24.join(cwd, "yarn.lock")) ? "yarn" : fs25.existsSync(path24.join(cwd, "bun.lockb")) ? "bun" : "npm";
6291
6337
  if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
6292
6338
  if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
6293
6339
  else if (allDeps.vite) out.devPort = 5173;
@@ -6297,7 +6343,7 @@ function detectDevServer(cwd, out) {
6297
6343
  function scanFrontendRoutes(cwd, out) {
6298
6344
  const appDirs = ["src/app", "app"];
6299
6345
  for (const appDir of appDirs) {
6300
- const full = path25.join(cwd, appDir);
6346
+ const full = path24.join(cwd, appDir);
6301
6347
  if (!fs25.existsSync(full)) continue;
6302
6348
  walkFrontendRoutes(full, "", out);
6303
6349
  break;
@@ -6323,7 +6369,7 @@ function walkFrontendRoutes(dir, prefix, out) {
6323
6369
  if (entry.name === "node_modules" || entry.name === ".next") continue;
6324
6370
  let segment = entry.name;
6325
6371
  if (segment.startsWith("(") && segment.endsWith(")")) {
6326
- walkFrontendRoutes(path25.join(dir, entry.name), prefix, out);
6372
+ walkFrontendRoutes(path24.join(dir, entry.name), prefix, out);
6327
6373
  continue;
6328
6374
  }
6329
6375
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -6331,7 +6377,7 @@ function walkFrontendRoutes(dir, prefix, out) {
6331
6377
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
6332
6378
  segment = `:${segment.slice(1, -1)}`;
6333
6379
  }
6334
- walkFrontendRoutes(path25.join(dir, entry.name), `${prefix}/${segment}`, out);
6380
+ walkFrontendRoutes(path24.join(dir, entry.name), `${prefix}/${segment}`, out);
6335
6381
  }
6336
6382
  }
6337
6383
  function detectAuthFiles(cwd, out) {
@@ -6348,13 +6394,13 @@ function detectAuthFiles(cwd, out) {
6348
6394
  "src/app/api/oauth"
6349
6395
  ];
6350
6396
  for (const c of candidates) {
6351
- if (fs25.existsSync(path25.join(cwd, c))) out.authFiles.push(c);
6397
+ if (fs25.existsSync(path24.join(cwd, c))) out.authFiles.push(c);
6352
6398
  }
6353
6399
  }
6354
6400
  function detectRoles(cwd, out) {
6355
6401
  const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
6356
6402
  for (const rp of rolePaths) {
6357
- const dir = path25.join(cwd, rp);
6403
+ const dir = path24.join(cwd, rp);
6358
6404
  if (!fs25.existsSync(dir)) continue;
6359
6405
  let files;
6360
6406
  try {
@@ -6364,7 +6410,7 @@ function detectRoles(cwd, out) {
6364
6410
  }
6365
6411
  for (const f of files) {
6366
6412
  try {
6367
- const content = fs25.readFileSync(path25.join(dir, f), "utf-8").slice(0, 5e3);
6413
+ const content = fs25.readFileSync(path24.join(dir, f), "utf-8").slice(0, 5e3);
6368
6414
  const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
6369
6415
  if (roleMatches) {
6370
6416
  for (const m of roleMatches) {
@@ -6448,7 +6494,7 @@ var discoverQaContext = async (ctx) => {
6448
6494
  };
6449
6495
 
6450
6496
  // src/scripts/dispatch.ts
6451
- import { execFileSync as execFileSync13 } from "child_process";
6497
+ import { execFileSync as execFileSync11 } from "child_process";
6452
6498
  var API_TIMEOUT_MS4 = 3e4;
6453
6499
  var dispatch = async (ctx, _profile, _agentResult, args) => {
6454
6500
  const next = args?.next;
@@ -6484,7 +6530,7 @@ var dispatch = async (ctx, _profile, _agentResult, args) => {
6484
6530
  const sub = usePr ? "pr" : "issue";
6485
6531
  const body = `@kody ${next}`;
6486
6532
  try {
6487
- execFileSync13("gh", [sub, "comment", String(targetNumber), "--body", body], {
6533
+ execFileSync11("gh", [sub, "comment", String(targetNumber), "--body", body], {
6488
6534
  timeout: API_TIMEOUT_MS4,
6489
6535
  cwd: ctx.cwd,
6490
6536
  stdio: ["ignore", "pipe", "pipe"]
@@ -6504,7 +6550,7 @@ function parsePr(url) {
6504
6550
  }
6505
6551
 
6506
6552
  // src/scripts/dispatchClassified.ts
6507
- import { execFileSync as execFileSync14 } from "child_process";
6553
+ import { execFileSync as execFileSync12 } from "child_process";
6508
6554
  var API_TIMEOUT_MS5 = 3e4;
6509
6555
  var VALID_CLASSES2 = /* @__PURE__ */ new Set(["feature", "bug", "spec", "chore"]);
6510
6556
  var dispatchClassified = async (ctx) => {
@@ -6528,7 +6574,7 @@ ${auditLine}
6528
6574
 
6529
6575
  ${stateBody}`;
6530
6576
  try {
6531
- execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", body], {
6577
+ execFileSync12("gh", ["issue", "comment", String(issueNumber), "--body", body], {
6532
6578
  cwd: ctx.cwd,
6533
6579
  timeout: API_TIMEOUT_MS5,
6534
6580
  stdio: ["ignore", "pipe", "pipe"]
@@ -6549,7 +6595,7 @@ function failedAction3(reason) {
6549
6595
 
6550
6596
  // src/scripts/dispatchJobFileTicks.ts
6551
6597
  import * as fs27 from "fs";
6552
- import * as path27 from "path";
6598
+ import * as path26 from "path";
6553
6599
 
6554
6600
  // src/scripts/jobFrontmatter.ts
6555
6601
  var SCHEDULE_EVERY_VALUES = [
@@ -6642,44 +6688,6 @@ function stripQuotes(value) {
6642
6688
  // src/scripts/jobState/contentsApiBackend.ts
6643
6689
  init_issue();
6644
6690
 
6645
- // src/stateBranch.ts
6646
- init_issue();
6647
- var STATE_BRANCH = "kody-state";
6648
- function is404(err) {
6649
- const msg = err instanceof Error ? err.message : String(err);
6650
- return /HTTP 404/i.test(msg) || /Not Found/i.test(msg);
6651
- }
6652
- function ensureStateBranch(owner, repo, cwd) {
6653
- try {
6654
- gh(["api", `/repos/${owner}/${repo}/git/ref/heads/${STATE_BRANCH}`], { cwd });
6655
- return;
6656
- } catch (err) {
6657
- if (!is404(err)) throw err;
6658
- }
6659
- const repoInfo = JSON.parse(gh(["api", `/repos/${owner}/${repo}`], { cwd }));
6660
- const defaultBranch2 = repoInfo.default_branch;
6661
- if (!defaultBranch2) {
6662
- throw new Error(`ensureStateBranch: could not resolve default branch for ${owner}/${repo}`);
6663
- }
6664
- const headRef = JSON.parse(
6665
- gh(["api", `/repos/${owner}/${repo}/git/ref/heads/${defaultBranch2}`], { cwd })
6666
- );
6667
- const sha = headRef.object?.sha;
6668
- if (!sha) {
6669
- throw new Error(`ensureStateBranch: could not resolve head sha for ${owner}/${repo}@${defaultBranch2}`);
6670
- }
6671
- try {
6672
- gh(["api", "--method", "POST", `/repos/${owner}/${repo}/git/refs`, "--input", "-"], {
6673
- cwd,
6674
- input: JSON.stringify({ ref: `refs/heads/${STATE_BRANCH}`, sha })
6675
- });
6676
- } catch (err) {
6677
- const msg = err instanceof Error ? err.message : String(err);
6678
- if (/already exists/i.test(msg) || /HTTP 422/i.test(msg)) return;
6679
- throw err;
6680
- }
6681
- }
6682
-
6683
6691
  // src/scripts/issueStateComment.ts
6684
6692
  init_issue();
6685
6693
  function isStateEnvelope(x) {
@@ -6857,7 +6865,7 @@ var ContentsApiBackend = class {
6857
6865
 
6858
6866
  // src/scripts/jobState/localFileBackend.ts
6859
6867
  import * as fs26 from "fs";
6860
- import * as path26 from "path";
6868
+ import * as path25 from "path";
6861
6869
  var LocalFileBackend = class {
6862
6870
  name = "local-file";
6863
6871
  cwd;
@@ -6872,7 +6880,7 @@ var LocalFileBackend = class {
6872
6880
  if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
6873
6881
  this.cwd = opts.cwd;
6874
6882
  this.jobsDir = opts.jobsDir;
6875
- this.absDir = path26.join(opts.cwd, opts.jobsDir);
6883
+ this.absDir = path25.join(opts.cwd, opts.jobsDir);
6876
6884
  this.owner = opts.owner;
6877
6885
  this.repo = opts.repo;
6878
6886
  this.cache = opts.cache ?? defaultCacheAdapter();
@@ -6932,7 +6940,7 @@ var LocalFileBackend = class {
6932
6940
  }
6933
6941
  load(slug) {
6934
6942
  const relPath = stateFilePath(this.jobsDir, slug);
6935
- const absPath = path26.join(this.cwd, relPath);
6943
+ const absPath = path25.join(this.cwd, relPath);
6936
6944
  if (!fs26.existsSync(absPath)) {
6937
6945
  return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
6938
6946
  }
@@ -6953,8 +6961,8 @@ var LocalFileBackend = class {
6953
6961
  if (!loaded.created && isStateUnchanged(loaded.state, next)) {
6954
6962
  return false;
6955
6963
  }
6956
- const absPath = path26.join(this.cwd, loaded.path);
6957
- fs26.mkdirSync(path26.dirname(absPath), { recursive: true });
6964
+ const absPath = path25.join(this.cwd, loaded.path);
6965
+ fs26.mkdirSync(path25.dirname(absPath), { recursive: true });
6958
6966
  const body = JSON.stringify(next, null, 2) + "\n";
6959
6967
  fs26.writeFileSync(absPath, body, "utf-8");
6960
6968
  return true;
@@ -7034,7 +7042,7 @@ var dispatchJobFileTicks = async (ctx, _profile, args) => {
7034
7042
  await backend.hydrate();
7035
7043
  }
7036
7044
  try {
7037
- const slugs = listJobSlugs(path27.join(ctx.cwd, jobsDir));
7045
+ const slugs = listJobSlugs(path26.join(ctx.cwd, jobsDir));
7038
7046
  ctx.data.jobSlugCount = slugs.length;
7039
7047
  if (slugs.length === 0) {
7040
7048
  process.stdout.write(`[jobs] no job files in ${jobsDir}
@@ -7147,7 +7155,7 @@ function formatAgo(ms) {
7147
7155
  }
7148
7156
  function readJobFrontmatter(cwd, jobsDir, slug) {
7149
7157
  try {
7150
- const raw = fs27.readFileSync(path27.join(cwd, jobsDir, `${slug}.md`), "utf-8");
7158
+ const raw = fs27.readFileSync(path26.join(cwd, jobsDir, `${slug}.md`), "utf-8");
7151
7159
  return splitFrontmatter2(raw).frontmatter;
7152
7160
  } catch {
7153
7161
  return {};
@@ -7684,7 +7692,7 @@ var finalizeTerminal = async (ctx) => {
7684
7692
 
7685
7693
  // src/scripts/finishFlow.ts
7686
7694
  init_issue();
7687
- import { execFileSync as execFileSync15 } from "child_process";
7695
+ import { execFileSync as execFileSync13 } from "child_process";
7688
7696
  var TERMINAL_PHASE = {
7689
7697
  "review-passed": { phase: "shipped", status: "succeeded" },
7690
7698
  "fix-applied": { phase: "shipped", status: "succeeded" },
@@ -7724,7 +7732,7 @@ var finishFlow = async (ctx, profile, _agentResult, args) => {
7724
7732
  **PR:** ${state.core.prUrl}` : "";
7725
7733
  const body = `${icon} kody flow \`${flowName}\` finished \u2014 \`${reason}\`${prSuffix}`;
7726
7734
  try {
7727
- execFileSync15("gh", ["issue", "comment", String(issueNumber), "--body", body], {
7735
+ execFileSync13("gh", ["issue", "comment", String(issueNumber), "--body", body], {
7728
7736
  timeout: API_TIMEOUT_MS6,
7729
7737
  cwd: ctx.cwd,
7730
7738
  stdio: ["ignore", "pipe", "pipe"]
@@ -7754,9 +7762,9 @@ var finishFlow = async (ctx, profile, _agentResult, args) => {
7754
7762
  };
7755
7763
 
7756
7764
  // src/branch.ts
7757
- import { execFileSync as execFileSync16 } from "child_process";
7765
+ import { execFileSync as execFileSync14 } from "child_process";
7758
7766
  function git2(args, cwd) {
7759
- return execFileSync16("git", args, {
7767
+ return execFileSync14("git", args, {
7760
7768
  encoding: "utf-8",
7761
7769
  timeout: 3e4,
7762
7770
  cwd,
@@ -7773,11 +7781,11 @@ function getCurrentBranch(cwd) {
7773
7781
  }
7774
7782
  function resetWorkingTree(cwd) {
7775
7783
  try {
7776
- execFileSync16("git", ["reset", "--hard", "HEAD"], { cwd, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7784
+ execFileSync14("git", ["reset", "--hard", "HEAD"], { cwd, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7777
7785
  } catch {
7778
7786
  }
7779
7787
  try {
7780
- execFileSync16("git", ["clean", "-fd"], { cwd, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7788
+ execFileSync14("git", ["clean", "-fd"], { cwd, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7781
7789
  } catch {
7782
7790
  }
7783
7791
  }
@@ -7789,14 +7797,14 @@ function checkoutPrBranch(prNumber, cwd) {
7789
7797
  GH_TOKEN: process.env.GH_PAT?.trim() || process.env.GH_TOKEN || ""
7790
7798
  };
7791
7799
  try {
7792
- execFileSync16("git", ["reset", "--hard", "HEAD"], { cwd, env, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7800
+ execFileSync14("git", ["reset", "--hard", "HEAD"], { cwd, env, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7793
7801
  } catch {
7794
7802
  }
7795
7803
  try {
7796
- execFileSync16("git", ["clean", "-fd"], { cwd, env, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7804
+ execFileSync14("git", ["clean", "-fd"], { cwd, env, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
7797
7805
  } catch {
7798
7806
  }
7799
- execFileSync16("gh", ["pr", "checkout", String(prNumber)], {
7807
+ execFileSync14("gh", ["pr", "checkout", String(prNumber)], {
7800
7808
  cwd,
7801
7809
  env,
7802
7810
  stdio: ["ignore", "pipe", "pipe"],
@@ -7922,7 +7930,7 @@ function ensureFeatureBranch(issueNumber, title, defaultBranch2, cwd, baseBranch
7922
7930
  }
7923
7931
 
7924
7932
  // src/gha.ts
7925
- import { execFileSync as execFileSync17 } from "child_process";
7933
+ import { execFileSync as execFileSync15 } from "child_process";
7926
7934
  import * as fs28 from "fs";
7927
7935
  function getRunUrl() {
7928
7936
  const server = process.env.GITHUB_SERVER_URL;
@@ -7965,7 +7973,7 @@ function reactToTriggerComment(cwd) {
7965
7973
  for (let attempt = 0; attempt < 3; attempt++) {
7966
7974
  if (attempt > 0) sleepMs(attempt === 1 ? 500 : 1500);
7967
7975
  try {
7968
- execFileSync17("gh", args, opts);
7976
+ execFileSync15("gh", args, opts);
7969
7977
  return;
7970
7978
  } catch (err) {
7971
7979
  lastErr = err;
@@ -7978,7 +7986,7 @@ function reactToTriggerComment(cwd) {
7978
7986
  }
7979
7987
  function sleepMs(ms) {
7980
7988
  try {
7981
- execFileSync17("sleep", [(ms / 1e3).toString()], { stdio: "ignore", timeout: ms + 1e3 });
7989
+ execFileSync15("sleep", [(ms / 1e3).toString()], { stdio: "ignore", timeout: ms + 1e3 });
7982
7990
  } catch {
7983
7991
  }
7984
7992
  }
@@ -7987,7 +7995,7 @@ function sleepMs(ms) {
7987
7995
  init_issue();
7988
7996
 
7989
7997
  // src/workflow.ts
7990
- import { execFileSync as execFileSync18 } from "child_process";
7998
+ import { execFileSync as execFileSync16 } from "child_process";
7991
7999
  var GH_TIMEOUT_MS = 3e4;
7992
8000
  function ghToken3() {
7993
8001
  return process.env.GH_PAT?.trim() || process.env.GH_TOKEN;
@@ -7995,7 +8003,7 @@ function ghToken3() {
7995
8003
  function gh3(args, cwd) {
7996
8004
  const token = ghToken3();
7997
8005
  const env = token ? { ...process.env, GH_TOKEN: token } : { ...process.env };
7998
- return execFileSync18("gh", args, {
8006
+ return execFileSync16("gh", args, {
7999
8007
  encoding: "utf-8",
8000
8008
  timeout: GH_TIMEOUT_MS,
8001
8009
  cwd,
@@ -8230,13 +8238,13 @@ var handleAbandonedGoal = async (ctx) => {
8230
8238
  };
8231
8239
 
8232
8240
  // src/scripts/initFlow.ts
8233
- import { execFileSync as execFileSync19 } from "child_process";
8241
+ import { execFileSync as execFileSync17 } from "child_process";
8234
8242
  import * as fs29 from "fs";
8235
- import * as path28 from "path";
8243
+ import * as path27 from "path";
8236
8244
  function detectPackageManager(cwd) {
8237
- if (fs29.existsSync(path28.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
8238
- if (fs29.existsSync(path28.join(cwd, "yarn.lock"))) return "yarn";
8239
- if (fs29.existsSync(path28.join(cwd, "bun.lockb"))) return "bun";
8245
+ if (fs29.existsSync(path27.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
8246
+ if (fs29.existsSync(path27.join(cwd, "yarn.lock"))) return "yarn";
8247
+ if (fs29.existsSync(path27.join(cwd, "bun.lockb"))) return "bun";
8240
8248
  return "npm";
8241
8249
  }
8242
8250
  function qualityCommandsFor(pm) {
@@ -8256,7 +8264,7 @@ function schemaUrlFromPkg() {
8256
8264
  function detectOwnerRepo(cwd) {
8257
8265
  let url;
8258
8266
  try {
8259
- url = execFileSync19("git", ["remote", "get-url", "origin"], {
8267
+ url = execFileSync17("git", ["remote", "get-url", "origin"], {
8260
8268
  cwd,
8261
8269
  encoding: "utf-8",
8262
8270
  stdio: ["ignore", "pipe", "pipe"]
@@ -8341,7 +8349,7 @@ jobs:
8341
8349
  `;
8342
8350
  function defaultBranchFromGit(cwd) {
8343
8351
  try {
8344
- const ref = execFileSync19("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
8352
+ const ref = execFileSync17("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
8345
8353
  cwd,
8346
8354
  encoding: "utf-8",
8347
8355
  stdio: ["ignore", "pipe", "pipe"]
@@ -8349,7 +8357,7 @@ function defaultBranchFromGit(cwd) {
8349
8357
  return ref.replace("refs/remotes/origin/", "");
8350
8358
  } catch {
8351
8359
  try {
8352
- return execFileSync19("git", ["branch", "--show-current"], {
8360
+ return execFileSync17("git", ["branch", "--show-current"], {
8353
8361
  cwd,
8354
8362
  encoding: "utf-8",
8355
8363
  stdio: ["ignore", "pipe", "pipe"]
@@ -8365,7 +8373,7 @@ function performInit(cwd, force) {
8365
8373
  const pm = detectPackageManager(cwd);
8366
8374
  const ownerRepo = detectOwnerRepo(cwd);
8367
8375
  const defaultBranch2 = defaultBranchFromGit(cwd);
8368
- const configPath = path28.join(cwd, "kody.config.json");
8376
+ const configPath = path27.join(cwd, "kody.config.json");
8369
8377
  if (fs29.existsSync(configPath) && !force) {
8370
8378
  skipped.push("kody.config.json");
8371
8379
  } else {
@@ -8374,8 +8382,8 @@ function performInit(cwd, force) {
8374
8382
  `);
8375
8383
  wrote.push("kody.config.json");
8376
8384
  }
8377
- const workflowDir = path28.join(cwd, ".github", "workflows");
8378
- const workflowPath = path28.join(workflowDir, "kody.yml");
8385
+ const workflowDir = path27.join(cwd, ".github", "workflows");
8386
+ const workflowPath = path27.join(workflowDir, "kody.yml");
8379
8387
  if (fs29.existsSync(workflowPath) && !force) {
8380
8388
  skipped.push(".github/workflows/kody.yml");
8381
8389
  } else {
@@ -8385,11 +8393,11 @@ function performInit(cwd, force) {
8385
8393
  }
8386
8394
  const builtinJobs = listBuiltinJobs();
8387
8395
  if (builtinJobs.length > 0) {
8388
- const jobsDir = path28.join(cwd, ".kody", "duties");
8396
+ const jobsDir = path27.join(cwd, ".kody", "duties");
8389
8397
  fs29.mkdirSync(jobsDir, { recursive: true });
8390
8398
  for (const job of builtinJobs) {
8391
- const rel = path28.join(".kody", "duties", `${job.slug}.md`);
8392
- const target = path28.join(cwd, rel);
8399
+ const rel = path27.join(".kody", "duties", `${job.slug}.md`);
8400
+ const target = path27.join(cwd, rel);
8393
8401
  if (fs29.existsSync(target) && !force) {
8394
8402
  skipped.push(rel);
8395
8403
  continue;
@@ -8406,7 +8414,7 @@ function performInit(cwd, force) {
8406
8414
  continue;
8407
8415
  }
8408
8416
  if (profile.kind !== "scheduled" || !profile.schedule) continue;
8409
- const target = path28.join(workflowDir, `kody-${exe.name}.yml`);
8417
+ const target = path27.join(workflowDir, `kody-${exe.name}.yml`);
8410
8418
  if (fs29.existsSync(target) && !force) {
8411
8419
  skipped.push(`.github/workflows/kody-${exe.name}.yml`);
8412
8420
  continue;
@@ -8488,86 +8496,6 @@ Nothing to do. All files already present. (Use --force to overwrite.)
8488
8496
  init_loadConventions();
8489
8497
  init_loadCoverageRules();
8490
8498
 
8491
- // src/goal/state.ts
8492
- import * as fs30 from "fs";
8493
- import * as path29 from "path";
8494
- var VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "awaiting-merge", "done"]);
8495
- var GoalStateError = class extends Error {
8496
- constructor(path40, message) {
8497
- super(`Invalid goal state at ${path40}:
8498
- ${message}`);
8499
- this.path = path40;
8500
- this.name = "GoalStateError";
8501
- }
8502
- path;
8503
- };
8504
- function parseGoalState(filePath, raw) {
8505
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
8506
- throw new GoalStateError(filePath, "must be a JSON object");
8507
- }
8508
- const r = raw;
8509
- const stateValue = r.state;
8510
- if (typeof stateValue !== "string" || !VALID_STATES.has(stateValue)) {
8511
- throw new GoalStateError(
8512
- filePath,
8513
- `"state" is required and must be one of: ${[...VALID_STATES].join(" | ")} (got ${JSON.stringify(stateValue)})`
8514
- );
8515
- }
8516
- const parsed = {
8517
- state: stateValue,
8518
- extra: {}
8519
- };
8520
- if (typeof r.mergeApproved === "boolean") {
8521
- parsed.mergeApproved = r.mergeApproved;
8522
- }
8523
- if (typeof r.lastDispatchedIssue === "number" && Number.isFinite(r.lastDispatchedIssue)) {
8524
- parsed.lastDispatchedIssue = r.lastDispatchedIssue;
8525
- }
8526
- for (const ts of ["updatedAt", "createdAt", "startedAt"]) {
8527
- const v = r[ts];
8528
- if (typeof v === "string" && v.length > 0) parsed[ts] = v;
8529
- }
8530
- const known = /* @__PURE__ */ new Set(["state", "mergeApproved", "lastDispatchedIssue", "updatedAt", "createdAt", "startedAt"]);
8531
- for (const [k, v] of Object.entries(r)) {
8532
- if (!known.has(k)) parsed.extra[k] = v;
8533
- }
8534
- return parsed;
8535
- }
8536
- function serializeGoalState(s) {
8537
- const obj = { ...s.extra, state: s.state };
8538
- if (s.mergeApproved !== void 0) obj.mergeApproved = s.mergeApproved;
8539
- if (s.lastDispatchedIssue !== void 0) obj.lastDispatchedIssue = s.lastDispatchedIssue;
8540
- if (s.createdAt !== void 0) obj.createdAt = s.createdAt;
8541
- if (s.startedAt !== void 0) obj.startedAt = s.startedAt;
8542
- if (s.updatedAt !== void 0) obj.updatedAt = s.updatedAt;
8543
- return `${JSON.stringify(obj, null, 2)}
8544
- `;
8545
- }
8546
- function goalStatePath(cwd, goalId) {
8547
- return path29.join(cwd, ".kody", "goals", goalId, "state.json");
8548
- }
8549
- function readGoalState(cwd, goalId) {
8550
- const file = goalStatePath(cwd, goalId);
8551
- if (!fs30.existsSync(file)) {
8552
- throw new GoalStateError(file, "file not found");
8553
- }
8554
- let raw;
8555
- try {
8556
- raw = JSON.parse(fs30.readFileSync(file, "utf-8"));
8557
- } catch (err) {
8558
- throw new GoalStateError(file, `invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
8559
- }
8560
- return parseGoalState(file, raw);
8561
- }
8562
- function writeGoalState(cwd, goalId, state) {
8563
- const file = goalStatePath(cwd, goalId);
8564
- fs30.mkdirSync(path29.dirname(file), { recursive: true });
8565
- fs30.writeFileSync(file, serializeGoalState(state), "utf-8");
8566
- }
8567
- function nowIso() {
8568
- return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
8569
- }
8570
-
8571
8499
  // src/scripts/loadGoalState.ts
8572
8500
  var loadGoalState = async (ctx) => {
8573
8501
  const goalId = ctx.args.goal;
@@ -8583,8 +8511,24 @@ var loadGoalState = async (ctx) => {
8583
8511
  ctx.output.reason = "invalid goal id (no slashes or '..' allowed)";
8584
8512
  return;
8585
8513
  }
8514
+ const owner = ctx.config.github?.owner;
8515
+ const repo = ctx.config.github?.repo;
8516
+ if (!owner || !repo) {
8517
+ ctx.skipAgent = true;
8518
+ ctx.output.exitCode = 1;
8519
+ ctx.output.reason = "missing github owner/repo in config";
8520
+ return;
8521
+ }
8586
8522
  try {
8587
- const state = readGoalState(ctx.cwd, goalId);
8523
+ const state = fetchGoalState(owner, repo, goalId, ctx.cwd);
8524
+ if (!state) {
8525
+ process.stdout.write(`[goal-tick] no goal state for ${goalId} on ${owner}/${repo} \u2014 nothing to tick
8526
+ `);
8527
+ ctx.skipAgent = true;
8528
+ ctx.output.exitCode = 0;
8529
+ ctx.output.reason = "no goal state to tick";
8530
+ return;
8531
+ }
8588
8532
  ctx.data.goal = {
8589
8533
  id: goalId,
8590
8534
  state: state.state,
@@ -8659,8 +8603,8 @@ var loadIssueStateComment = async (ctx, _profile, args) => {
8659
8603
  };
8660
8604
 
8661
8605
  // src/scripts/loadJobFromFile.ts
8662
- import * as fs31 from "fs";
8663
- import * as path30 from "path";
8606
+ import * as fs30 from "fs";
8607
+ import * as path28 from "path";
8664
8608
  var loadJobFromFile = async (ctx, _profile, args) => {
8665
8609
  const jobsDir = String(args?.jobsDir ?? ".kody/duties");
8666
8610
  const workersDir = String(args?.workersDir ?? ".kody/staff");
@@ -8669,11 +8613,11 @@ var loadJobFromFile = async (ctx, _profile, args) => {
8669
8613
  if (!slug) {
8670
8614
  throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
8671
8615
  }
8672
- const absPath = path30.join(ctx.cwd, jobsDir, `${slug}.md`);
8673
- if (!fs31.existsSync(absPath)) {
8616
+ const absPath = path28.join(ctx.cwd, jobsDir, `${slug}.md`);
8617
+ if (!fs30.existsSync(absPath)) {
8674
8618
  throw new Error(`loadJobFromFile: job file not found: ${absPath}`);
8675
8619
  }
8676
- const raw = fs31.readFileSync(absPath, "utf-8");
8620
+ const raw = fs30.readFileSync(absPath, "utf-8");
8677
8621
  const { title, body } = parseJobFile(raw, slug);
8678
8622
  const frontmatter = splitFrontmatter2(raw).frontmatter;
8679
8623
  const mentions = (frontmatter.mentions ?? []).map((login) => `@${login}`).join(" ");
@@ -8681,13 +8625,13 @@ var loadJobFromFile = async (ctx, _profile, args) => {
8681
8625
  let workerTitle = "";
8682
8626
  let workerPersona = "";
8683
8627
  if (workerSlug) {
8684
- const workerPath = path30.join(ctx.cwd, workersDir, `${workerSlug}.md`);
8685
- if (!fs31.existsSync(workerPath)) {
8628
+ const workerPath = path28.join(ctx.cwd, workersDir, `${workerSlug}.md`);
8629
+ if (!fs30.existsSync(workerPath)) {
8686
8630
  throw new Error(
8687
8631
  `loadJobFromFile: duty '${slug}' declares staff '${workerSlug}' but ${workerPath} does not exist`
8688
8632
  );
8689
8633
  }
8690
- const workerRaw = fs31.readFileSync(workerPath, "utf-8");
8634
+ const workerRaw = fs30.readFileSync(workerPath, "utf-8");
8691
8635
  const parsed = parseJobFile(workerRaw, workerSlug);
8692
8636
  workerTitle = parsed.title;
8693
8637
  workerPersona = parsed.body;
@@ -8730,18 +8674,18 @@ init_loadMemoryContext();
8730
8674
  init_loadPriorArt();
8731
8675
 
8732
8676
  // src/scripts/loadQaContext.ts
8733
- import * as fs34 from "fs";
8734
- import * as path33 from "path";
8677
+ import * as fs33 from "fs";
8678
+ import * as path31 from "path";
8735
8679
 
8736
8680
  // src/scripts/kodyVariables.ts
8737
- import * as fs33 from "fs";
8738
- import * as path32 from "path";
8681
+ import * as fs32 from "fs";
8682
+ import * as path30 from "path";
8739
8683
  var KODY_VARIABLES_REL_PATH = ".kody/variables.json";
8740
8684
  function readKodyVariables(cwd) {
8741
- const full = path32.join(cwd, KODY_VARIABLES_REL_PATH);
8685
+ const full = path30.join(cwd, KODY_VARIABLES_REL_PATH);
8742
8686
  let raw;
8743
8687
  try {
8744
- raw = fs33.readFileSync(full, "utf-8");
8688
+ raw = fs32.readFileSync(full, "utf-8");
8745
8689
  } catch {
8746
8690
  return {};
8747
8691
  }
@@ -8790,18 +8734,18 @@ function readProfileStaff(raw) {
8790
8734
  return { staff: staff ?? legacy ?? ["kody"], body };
8791
8735
  }
8792
8736
  function readProfile(cwd) {
8793
- const dir = path33.join(cwd, CONTEXT_DIR_REL_PATH);
8794
- if (!fs34.existsSync(dir)) return "";
8737
+ const dir = path31.join(cwd, CONTEXT_DIR_REL_PATH);
8738
+ if (!fs33.existsSync(dir)) return "";
8795
8739
  let entries;
8796
8740
  try {
8797
- entries = fs34.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
8741
+ entries = fs33.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
8798
8742
  } catch {
8799
8743
  return "";
8800
8744
  }
8801
8745
  const blocks = [];
8802
8746
  for (const file of entries) {
8803
8747
  try {
8804
- const raw = fs34.readFileSync(path33.join(dir, file), "utf-8");
8748
+ const raw = fs33.readFileSync(path31.join(dir, file), "utf-8");
8805
8749
  const { staff, body } = readProfileStaff(raw);
8806
8750
  if (!staff.includes(QA_STAFF) && !staff.includes(ALL_STAFF)) continue;
8807
8751
  blocks.push(`## ${file}
@@ -8838,8 +8782,8 @@ var loadQaContext = async (ctx) => {
8838
8782
  init_events();
8839
8783
 
8840
8784
  // src/taskContext.ts
8841
- import * as fs35 from "fs";
8842
- import * as path34 from "path";
8785
+ import * as fs34 from "fs";
8786
+ import * as path32 from "path";
8843
8787
  var TASK_CONTEXT_SCHEMA_VERSION = 1;
8844
8788
  function buildTaskContext(args) {
8845
8789
  return {
@@ -8855,10 +8799,10 @@ function buildTaskContext(args) {
8855
8799
  }
8856
8800
  function persistTaskContext(cwd, ctx) {
8857
8801
  try {
8858
- const dir = path34.join(cwd, ".kody", "runs", ctx.runId);
8859
- fs35.mkdirSync(dir, { recursive: true });
8860
- const file = path34.join(dir, "task-context.json");
8861
- fs35.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
8802
+ const dir = path32.join(cwd, ".kody", "runs", ctx.runId);
8803
+ fs34.mkdirSync(dir, { recursive: true });
8804
+ const file = path32.join(dir, "task-context.json");
8805
+ fs34.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
8862
8806
  `);
8863
8807
  return file;
8864
8808
  } catch (err) {
@@ -8906,19 +8850,19 @@ var loadTaskState = async (ctx) => {
8906
8850
  };
8907
8851
 
8908
8852
  // src/scripts/loadWorkerAdhoc.ts
8909
- import * as fs36 from "fs";
8910
- import * as path35 from "path";
8853
+ import * as fs35 from "fs";
8854
+ import * as path33 from "path";
8911
8855
  var loadWorkerAdhoc = async (ctx, _profile, args) => {
8912
8856
  const workersDir = String(args?.workersDir ?? ".kody/staff");
8913
8857
  const workerSlug = String(ctx.args.worker ?? "").trim();
8914
8858
  if (!workerSlug) {
8915
8859
  throw new Error("loadWorkerAdhoc: ctx.args.worker must be a non-empty slug");
8916
8860
  }
8917
- const workerPath = path35.join(ctx.cwd, workersDir, `${workerSlug}.md`);
8918
- if (!fs36.existsSync(workerPath)) {
8861
+ const workerPath = path33.join(ctx.cwd, workersDir, `${workerSlug}.md`);
8862
+ if (!fs35.existsSync(workerPath)) {
8919
8863
  throw new Error(`loadWorkerAdhoc: worker persona not found: ${workerPath}`);
8920
8864
  }
8921
- const { title, body } = parsePersona(fs36.readFileSync(workerPath, "utf-8"), workerSlug);
8865
+ const { title, body } = parsePersona(fs35.readFileSync(workerPath, "utf-8"), workerSlug);
8922
8866
  const message = resolveMessage(ctx.args.message);
8923
8867
  if (!message) {
8924
8868
  throw new Error(
@@ -8938,9 +8882,9 @@ function resolveMessage(messageArg) {
8938
8882
  }
8939
8883
  function readCommentBody() {
8940
8884
  const eventPath = process.env.GITHUB_EVENT_PATH;
8941
- if (!eventPath || !fs36.existsSync(eventPath)) return "";
8885
+ if (!eventPath || !fs35.existsSync(eventPath)) return "";
8942
8886
  try {
8943
- const event = JSON.parse(fs36.readFileSync(eventPath, "utf-8"));
8887
+ const event = JSON.parse(fs35.readFileSync(eventPath, "utf-8"));
8944
8888
  return String(event.comment?.body ?? "");
8945
8889
  } catch {
8946
8890
  return "";
@@ -9103,7 +9047,7 @@ var mergeFlow = async (ctx) => {
9103
9047
  };
9104
9048
 
9105
9049
  // src/scripts/mergeReleasePr.ts
9106
- import { execFileSync as execFileSync20 } from "child_process";
9050
+ import { execFileSync as execFileSync18 } from "child_process";
9107
9051
  var API_TIMEOUT_MS7 = 6e4;
9108
9052
  var mergeReleasePr = async (ctx) => {
9109
9053
  const state = ctx.data.taskState;
@@ -9122,7 +9066,7 @@ var mergeReleasePr = async (ctx) => {
9122
9066
  process.stderr.write(`[kody mergeReleasePr] merging PR #${prNumber} (${prUrl})
9123
9067
  `);
9124
9068
  try {
9125
- const out = execFileSync20("gh", ["pr", "merge", String(prNumber), "--merge"], {
9069
+ const out = execFileSync18("gh", ["pr", "merge", String(prNumber), "--merge"], {
9126
9070
  timeout: API_TIMEOUT_MS7,
9127
9071
  cwd: ctx.cwd,
9128
9072
  stdio: ["ignore", "pipe", "pipe"]
@@ -9610,8 +9554,8 @@ var FlyClient = class {
9610
9554
  get fetch() {
9611
9555
  return this.opts.fetchImpl ?? fetch;
9612
9556
  }
9613
- async call(path40, init = {}) {
9614
- const res = await this.fetch(`${FLY_API_BASE}${path40}`, {
9557
+ async call(path38, init = {}) {
9558
+ const res = await this.fetch(`${FLY_API_BASE}${path38}`, {
9615
9559
  method: init.method ?? "GET",
9616
9560
  headers: {
9617
9561
  Authorization: `Bearer ${this.opts.token}`,
@@ -9622,7 +9566,7 @@ var FlyClient = class {
9622
9566
  if (res.status === 404 && init.allow404) return null;
9623
9567
  if (!res.ok) {
9624
9568
  const text = await res.text().catch(() => "");
9625
- throw new Error(`Fly API ${res.status} on ${path40}: ${text.slice(0, 200) || res.statusText}`);
9569
+ throw new Error(`Fly API ${res.status} on ${path38}: ${text.slice(0, 200) || res.statusText}`);
9626
9570
  }
9627
9571
  if (res.status === 204) return null;
9628
9572
  const raw = await res.text();
@@ -10521,7 +10465,7 @@ ${body}`;
10521
10465
  }
10522
10466
 
10523
10467
  // src/scripts/recordClassification.ts
10524
- import { execFileSync as execFileSync21 } from "child_process";
10468
+ import { execFileSync as execFileSync19 } from "child_process";
10525
10469
  var API_TIMEOUT_MS8 = 3e4;
10526
10470
  var VALID_CLASSES3 = /* @__PURE__ */ new Set(["feature", "bug", "spec", "chore"]);
10527
10471
  var recordClassification = async (ctx) => {
@@ -10569,7 +10513,7 @@ function parseClassification(prSummary) {
10569
10513
  }
10570
10514
  function tryAuditComment(issueNumber, body, cwd) {
10571
10515
  try {
10572
- execFileSync21("gh", ["issue", "comment", String(issueNumber), "--body", body], {
10516
+ execFileSync19("gh", ["issue", "comment", String(issueNumber), "--body", body], {
10573
10517
  cwd,
10574
10518
  timeout: API_TIMEOUT_MS8,
10575
10519
  stdio: ["ignore", "pipe", "pipe"]
@@ -10683,7 +10627,7 @@ var resolveArtifacts = async (ctx, profile) => {
10683
10627
  };
10684
10628
 
10685
10629
  // src/scripts/resolveFlow.ts
10686
- import { execFileSync as execFileSync22 } from "child_process";
10630
+ import { execFileSync as execFileSync20 } from "child_process";
10687
10631
  init_issue();
10688
10632
  var CONFLICT_DIFF_MAX_BYTES = 4e4;
10689
10633
  var resolveFlow = async (ctx) => {
@@ -10777,7 +10721,7 @@ function buildPreferBlock(prefer, baseBranch) {
10777
10721
  }
10778
10722
  function getConflictedFiles(cwd) {
10779
10723
  try {
10780
- const out = execFileSync22("git", ["diff", "--name-only", "--diff-filter=U"], {
10724
+ const out = execFileSync20("git", ["diff", "--name-only", "--diff-filter=U"], {
10781
10725
  encoding: "utf-8",
10782
10726
  cwd,
10783
10727
  env: { ...process.env, HUSKY: "0" }
@@ -10792,7 +10736,7 @@ function getConflictMarkersPreview(files, cwd, maxBytes = CONFLICT_DIFF_MAX_BYTE
10792
10736
  let total = 0;
10793
10737
  for (const f of files) {
10794
10738
  try {
10795
- const content = execFileSync22("cat", [f], { encoding: "utf-8", cwd }).toString();
10739
+ const content = execFileSync20("cat", [f], { encoding: "utf-8", cwd }).toString();
10796
10740
  const snippet = `### ${f}
10797
10741
 
10798
10742
  \`\`\`
@@ -10816,12 +10760,12 @@ function tryPostPr3(prNumber, body, cwd) {
10816
10760
  function pushEmptyCommit(branch, cwd) {
10817
10761
  const env = { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" };
10818
10762
  try {
10819
- execFileSync22(
10763
+ execFileSync20(
10820
10764
  "git",
10821
10765
  ["commit", "--allow-empty", "-m", "chore: kody resolve refresh \u2014 empty commit to recompute mergeable status"],
10822
10766
  { cwd, env, stdio: ["ignore", "pipe", "pipe"] }
10823
10767
  );
10824
- execFileSync22("git", ["push", "-u", "origin", branch], {
10768
+ execFileSync20("git", ["push", "-u", "origin", branch], {
10825
10769
  cwd,
10826
10770
  env,
10827
10771
  stdio: ["ignore", "pipe", "pipe"]
@@ -10952,10 +10896,10 @@ var resolvePreviewUrl = async (ctx) => {
10952
10896
  };
10953
10897
 
10954
10898
  // src/scripts/resolveQaUrl.ts
10955
- import { execFileSync as execFileSync23 } from "child_process";
10899
+ import { execFileSync as execFileSync21 } from "child_process";
10956
10900
  function ghQuery(args, cwd) {
10957
10901
  try {
10958
- const out = execFileSync23("gh", args, {
10902
+ const out = execFileSync21("gh", args, {
10959
10903
  cwd,
10960
10904
  stdio: ["ignore", "pipe", "pipe"],
10961
10905
  encoding: "utf-8",
@@ -11025,7 +10969,7 @@ var resolveQaUrl = async (ctx) => {
11025
10969
  };
11026
10970
 
11027
10971
  // src/scripts/revertFlow.ts
11028
- import { execFileSync as execFileSync24 } from "child_process";
10972
+ import { execFileSync as execFileSync22 } from "child_process";
11029
10973
  init_issue();
11030
10974
  var SHA_RE = /^[0-9a-f]{4,40}$/i;
11031
10975
  var revertFlow = async (ctx) => {
@@ -11108,7 +11052,7 @@ function buildPrSummary(resolved) {
11108
11052
  return resolved.map((r) => `- Reverted \`${r.full.slice(0, 7)}\`${r.subject ? ` \u2014 ${r.subject}` : ""}`).join("\n");
11109
11053
  }
11110
11054
  function git3(args, cwd) {
11111
- return execFileSync24("git", args, {
11055
+ return execFileSync22("git", args, {
11112
11056
  encoding: "utf-8",
11113
11057
  timeout: 3e4,
11114
11058
  cwd,
@@ -11118,7 +11062,7 @@ function git3(args, cwd) {
11118
11062
  }
11119
11063
  function isAncestorOfHead(sha, cwd) {
11120
11064
  try {
11121
- execFileSync24("git", ["merge-base", "--is-ancestor", sha, "HEAD"], {
11065
+ execFileSync22("git", ["merge-base", "--is-ancestor", sha, "HEAD"], {
11122
11066
  cwd,
11123
11067
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
11124
11068
  stdio: ["ignore", "ignore", "ignore"]
@@ -11215,7 +11159,7 @@ function resolveBaseOverride(value) {
11215
11159
  // src/scripts/runnerServe.ts
11216
11160
  import { spawn as spawn5 } from "child_process";
11217
11161
  import { createServer as createServer3 } from "http";
11218
- import * as fs37 from "fs";
11162
+ import * as fs36 from "fs";
11219
11163
  var DEFAULT_PORT2 = 8080;
11220
11164
  var DEFAULT_WORKDIR = "/workspace/repo";
11221
11165
  function getApiKey2() {
@@ -11296,8 +11240,8 @@ async function defaultRunJob(job) {
11296
11240
  const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
11297
11241
  const branch = job.ref ?? "main";
11298
11242
  const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
11299
- fs37.rmSync(workdir, { recursive: true, force: true });
11300
- fs37.mkdirSync(workdir, { recursive: true });
11243
+ fs36.rmSync(workdir, { recursive: true, force: true });
11244
+ fs36.mkdirSync(workdir, { recursive: true });
11301
11245
  const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
11302
11246
  const interactive = job.mode === "interactive";
11303
11247
  const childEnv = {
@@ -11435,8 +11379,8 @@ var runnerServe = async (ctx) => {
11435
11379
 
11436
11380
  // src/scripts/runTickScript.ts
11437
11381
  import { spawnSync as spawnSync2 } from "child_process";
11438
- import * as fs38 from "fs";
11439
- import * as path36 from "path";
11382
+ import * as fs37 from "fs";
11383
+ import * as path34 from "path";
11440
11384
  var runTickScript = async (ctx, _profile, args) => {
11441
11385
  ctx.skipAgent = true;
11442
11386
  const jobsDir = String(args?.jobsDir ?? ".kody/duties");
@@ -11448,13 +11392,13 @@ var runTickScript = async (ctx, _profile, args) => {
11448
11392
  ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
11449
11393
  return;
11450
11394
  }
11451
- const jobPath = path36.join(ctx.cwd, jobsDir, `${slug}.md`);
11452
- if (!fs38.existsSync(jobPath)) {
11395
+ const jobPath = path34.join(ctx.cwd, jobsDir, `${slug}.md`);
11396
+ if (!fs37.existsSync(jobPath)) {
11453
11397
  ctx.output.exitCode = 99;
11454
11398
  ctx.output.reason = `runTickScript: job file not found: ${jobPath}`;
11455
11399
  return;
11456
11400
  }
11457
- const raw = fs38.readFileSync(jobPath, "utf-8");
11401
+ const raw = fs37.readFileSync(jobPath, "utf-8");
11458
11402
  const { frontmatter } = splitFrontmatter2(raw);
11459
11403
  const tickScript = frontmatter.tickScript;
11460
11404
  if (!tickScript) {
@@ -11462,8 +11406,8 @@ var runTickScript = async (ctx, _profile, args) => {
11462
11406
  ctx.output.reason = `runTickScript: job ${slug} has no \`tickScript:\` frontmatter \u2014 route via job-tick instead`;
11463
11407
  return;
11464
11408
  }
11465
- const scriptPath = path36.isAbsolute(tickScript) ? tickScript : path36.join(ctx.cwd, tickScript);
11466
- if (!fs38.existsSync(scriptPath)) {
11409
+ const scriptPath = path34.isAbsolute(tickScript) ? tickScript : path34.join(ctx.cwd, tickScript);
11410
+ if (!fs37.existsSync(scriptPath)) {
11467
11411
  ctx.output.exitCode = 99;
11468
11412
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
11469
11413
  return;
@@ -11579,7 +11523,8 @@ var saveGoalState = async (ctx) => {
11579
11523
  lastDispatchedIssue: goal.lastDispatchedIssue,
11580
11524
  updatedAt: changed ? nowIso() : prev?.updatedAt
11581
11525
  };
11582
- writeGoalState(ctx.cwd, goal.id, updated);
11526
+ ctx.data.goalPersistState = updated;
11527
+ ctx.data.goalPersistChanged = changed;
11583
11528
  ctx.skipAgent = true;
11584
11529
  };
11585
11530
 
@@ -11760,11 +11705,11 @@ var skipAgent = async (ctx) => {
11760
11705
  };
11761
11706
 
11762
11707
  // src/scripts/stageMergeConflicts.ts
11763
- import { execFileSync as execFileSync25 } from "child_process";
11708
+ import { execFileSync as execFileSync23 } from "child_process";
11764
11709
  var stageMergeConflicts = async (ctx) => {
11765
11710
  if (ctx.data.agentDone === false) return;
11766
11711
  try {
11767
- execFileSync25("git", ["add", "-A"], {
11712
+ execFileSync23("git", ["add", "-A"], {
11768
11713
  cwd: ctx.cwd,
11769
11714
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" },
11770
11715
  stdio: "pipe"
@@ -11775,7 +11720,7 @@ var stageMergeConflicts = async (ctx) => {
11775
11720
 
11776
11721
  // src/scripts/startFlow.ts
11777
11722
  init_issue();
11778
- import { execFileSync as execFileSync26 } from "child_process";
11723
+ import { execFileSync as execFileSync24 } from "child_process";
11779
11724
  var API_TIMEOUT_MS9 = 3e4;
11780
11725
  var startFlow = async (ctx, profile, _agentResult, args) => {
11781
11726
  const entry = args?.entry;
@@ -11809,7 +11754,7 @@ function postKodyComment(target, issueNumber, state, next, cwd) {
11809
11754
  const sub = target === "pr" && state?.core.prUrl ? "pr" : "issue";
11810
11755
  const body = `@kody ${next}`;
11811
11756
  try {
11812
- execFileSync26("gh", [sub, "comment", String(targetNumber), "--body", body], {
11757
+ execFileSync24("gh", [sub, "comment", String(targetNumber), "--body", body], {
11813
11758
  timeout: API_TIMEOUT_MS9,
11814
11759
  cwd,
11815
11760
  stdio: ["ignore", "pipe", "pipe"]
@@ -11823,7 +11768,7 @@ function postKodyComment(target, issueNumber, state, next, cwd) {
11823
11768
  }
11824
11769
 
11825
11770
  // src/scripts/syncFlow.ts
11826
- import { execFileSync as execFileSync27 } from "child_process";
11771
+ import { execFileSync as execFileSync25 } from "child_process";
11827
11772
  init_issue();
11828
11773
  var syncFlow = async (ctx, _profile, args) => {
11829
11774
  const announceOnSuccess = Boolean(args?.announceOnSuccess);
@@ -11888,7 +11833,7 @@ function bail2(ctx, prNumber, reason) {
11888
11833
  }
11889
11834
  function revParseHead(cwd) {
11890
11835
  try {
11891
- return execFileSync27("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
11836
+ return execFileSync25("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
11892
11837
  } catch {
11893
11838
  return "";
11894
11839
  }
@@ -12145,7 +12090,7 @@ var verifyWithRetry = async (ctx) => {
12145
12090
 
12146
12091
  // src/scripts/waitForCi.ts
12147
12092
  init_issue();
12148
- import { execFileSync as execFileSync28 } from "child_process";
12093
+ import { execFileSync as execFileSync26 } from "child_process";
12149
12094
  var API_TIMEOUT_MS10 = 3e4;
12150
12095
  var waitForCi = async (ctx, _profile, _agentResult, args) => {
12151
12096
  const timeoutMinutes = numArg(args, "timeoutMinutes", 30);
@@ -12223,7 +12168,7 @@ var waitForCi = async (ctx, _profile, _agentResult, args) => {
12223
12168
  };
12224
12169
  function fetchChecks(prNumber, cwd) {
12225
12170
  try {
12226
- const raw = execFileSync28("gh", ["pr", "checks", String(prNumber), "--json", "bucket,state,name,workflow,link"], {
12171
+ const raw = execFileSync26("gh", ["pr", "checks", String(prNumber), "--json", "bucket,state,name,workflow,link"], {
12227
12172
  encoding: "utf-8",
12228
12173
  timeout: API_TIMEOUT_MS10,
12229
12174
  cwd,
@@ -12570,7 +12515,7 @@ var writeJobStateFile = async (ctx, _profile, agentResult, args) => {
12570
12515
  };
12571
12516
 
12572
12517
  // src/scripts/writeRunSummary.ts
12573
- import * as fs39 from "fs";
12518
+ import * as fs38 from "fs";
12574
12519
  var writeRunSummary = async (ctx, profile) => {
12575
12520
  const summaryPath = process.env.GITHUB_STEP_SUMMARY;
12576
12521
  if (!summaryPath) return;
@@ -12592,7 +12537,7 @@ var writeRunSummary = async (ctx, profile) => {
12592
12537
  if (reason) lines.push(`- **Reason:** ${reason}`);
12593
12538
  lines.push("");
12594
12539
  try {
12595
- fs39.appendFileSync(summaryPath, `${lines.join("\n")}
12540
+ fs38.appendFileSync(summaryPath, `${lines.join("\n")}
12596
12541
  `);
12597
12542
  } catch {
12598
12543
  }
@@ -12696,7 +12641,7 @@ var allScriptNames = /* @__PURE__ */ new Set([
12696
12641
  ]);
12697
12642
 
12698
12643
  // src/tools.ts
12699
- import { execFileSync as execFileSync29 } from "child_process";
12644
+ import { execFileSync as execFileSync27 } from "child_process";
12700
12645
  function verifyCliTools(tools, cwd) {
12701
12646
  const out = [];
12702
12647
  for (const t of tools) out.push(verifyOne(t, cwd));
@@ -12729,7 +12674,7 @@ function verifyOne(tool3, cwd) {
12729
12674
  }
12730
12675
  function runShell(cmd, cwd, timeoutMs = 3e4) {
12731
12676
  try {
12732
- execFileSync29("sh", ["-c", cmd], { cwd, stdio: "pipe", timeout: timeoutMs });
12677
+ execFileSync27("sh", ["-c", cmd], { cwd, stdio: "pipe", timeout: timeoutMs });
12733
12678
  return true;
12734
12679
  } catch {
12735
12680
  return false;
@@ -12837,9 +12782,9 @@ async function runExecutable(profileName, input) {
12837
12782
  })
12838
12783
  };
12839
12784
  })() : null;
12840
- const ndjsonDir = path37.join(input.cwd, ".kody");
12785
+ const ndjsonDir = path35.join(input.cwd, ".kody");
12841
12786
  const invokeAgent = async (prompt) => {
12842
- const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path37.isAbsolute(p) ? p : path37.resolve(profile.dir, p)).filter((p) => p.length > 0);
12787
+ const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path35.isAbsolute(p) ? p : path35.resolve(profile.dir, p)).filter((p) => p.length > 0);
12843
12788
  const syntheticPath = ctx.data.syntheticPluginPath;
12844
12789
  const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
12845
12790
  const agents = loadSubagents(profile);
@@ -13051,7 +12996,7 @@ function clearStampedLifecycleLabels(profile, ctx) {
13051
12996
  function getProfileInputsForChild(profileName, _cwd) {
13052
12997
  try {
13053
12998
  const profilePath = resolveProfilePath(profileName);
13054
- if (!fs40.existsSync(profilePath)) return null;
12999
+ if (!fs39.existsSync(profilePath)) return null;
13055
13000
  return loadProfile(profilePath).inputs;
13056
13001
  } catch {
13057
13002
  return null;
@@ -13060,17 +13005,17 @@ function getProfileInputsForChild(profileName, _cwd) {
13060
13005
  function resolveProfilePath(profileName) {
13061
13006
  const found = resolveExecutable(profileName);
13062
13007
  if (found) return found;
13063
- const here = path37.dirname(new URL(import.meta.url).pathname);
13008
+ const here = path35.dirname(new URL(import.meta.url).pathname);
13064
13009
  const candidates = [
13065
- path37.join(here, "executables", profileName, "profile.json"),
13010
+ path35.join(here, "executables", profileName, "profile.json"),
13066
13011
  // same-dir sibling (dev)
13067
- path37.join(here, "..", "executables", profileName, "profile.json"),
13012
+ path35.join(here, "..", "executables", profileName, "profile.json"),
13068
13013
  // up one (prod: dist/bin → dist/executables)
13069
- path37.join(here, "..", "src", "executables", profileName, "profile.json")
13014
+ path35.join(here, "..", "src", "executables", profileName, "profile.json")
13070
13015
  // fallback
13071
13016
  ];
13072
13017
  for (const c of candidates) {
13073
- if (fs40.existsSync(c)) return c;
13018
+ if (fs39.existsSync(c)) return c;
13074
13019
  }
13075
13020
  return candidates[0];
13076
13021
  }
@@ -13170,8 +13115,8 @@ function resolveShellTimeoutMs(entry) {
13170
13115
  var SIGKILL_GRACE_MS = 5e3;
13171
13116
  async function runShellEntry(entry, ctx, profile) {
13172
13117
  const shellName = entry.shell;
13173
- const shellPath = path37.join(profile.dir, shellName);
13174
- if (!fs40.existsSync(shellPath)) {
13118
+ const shellPath = path35.join(profile.dir, shellName);
13119
+ if (!fs39.existsSync(shellPath)) {
13175
13120
  ctx.skipAgent = true;
13176
13121
  ctx.output.exitCode = 99;
13177
13122
  ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
@@ -13498,7 +13443,7 @@ async function runContainerLoop(profile, ctx, input) {
13498
13443
  }
13499
13444
  function resetWorkingTree2(cwd) {
13500
13445
  try {
13501
- execFileSync30("git", ["reset", "--hard", "HEAD"], {
13446
+ execFileSync28("git", ["reset", "--hard", "HEAD"], {
13502
13447
  cwd,
13503
13448
  stdio: ["ignore", "pipe", "pipe"],
13504
13449
  timeout: 3e4
@@ -13650,14 +13595,14 @@ function resolveAuthToken(env = process.env) {
13650
13595
  return token;
13651
13596
  }
13652
13597
  function detectPackageManager2(cwd) {
13653
- if (fs41.existsSync(path38.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
13654
- if (fs41.existsSync(path38.join(cwd, "yarn.lock"))) return "yarn";
13655
- if (fs41.existsSync(path38.join(cwd, "bun.lockb"))) return "bun";
13598
+ if (fs40.existsSync(path36.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
13599
+ if (fs40.existsSync(path36.join(cwd, "yarn.lock"))) return "yarn";
13600
+ if (fs40.existsSync(path36.join(cwd, "bun.lockb"))) return "bun";
13656
13601
  return "npm";
13657
13602
  }
13658
13603
  function shellOut(cmd, args, cwd, stream = true) {
13659
13604
  try {
13660
- execFileSync31(cmd, args, {
13605
+ execFileSync29(cmd, args, {
13661
13606
  cwd,
13662
13607
  stdio: stream ? "inherit" : "pipe",
13663
13608
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" }
@@ -13670,7 +13615,7 @@ function shellOut(cmd, args, cwd, stream = true) {
13670
13615
  }
13671
13616
  function isOnPath(bin) {
13672
13617
  try {
13673
- execFileSync31("which", [bin], { stdio: "pipe" });
13618
+ execFileSync29("which", [bin], { stdio: "pipe" });
13674
13619
  return true;
13675
13620
  } catch {
13676
13621
  return false;
@@ -13711,7 +13656,7 @@ function installLitellmIfNeeded(cwd) {
13711
13656
  } catch {
13712
13657
  }
13713
13658
  try {
13714
- execFileSync31("python3", ["-c", "import litellm"], { stdio: "pipe" });
13659
+ execFileSync29("python3", ["-c", "import litellm"], { stdio: "pipe" });
13715
13660
  process.stdout.write("\u2192 kody: litellm already installed\n");
13716
13661
  return 0;
13717
13662
  } catch {
@@ -13721,16 +13666,16 @@ function installLitellmIfNeeded(cwd) {
13721
13666
  }
13722
13667
  function configureGitIdentity(cwd) {
13723
13668
  try {
13724
- const name = execFileSync31("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
13669
+ const name = execFileSync29("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
13725
13670
  if (name) return;
13726
13671
  } catch {
13727
13672
  }
13728
13673
  try {
13729
- execFileSync31("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
13674
+ execFileSync29("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
13730
13675
  } catch {
13731
13676
  }
13732
13677
  try {
13733
- execFileSync31("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
13678
+ execFileSync29("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
13734
13679
  cwd,
13735
13680
  stdio: "pipe"
13736
13681
  });
@@ -13739,11 +13684,11 @@ function configureGitIdentity(cwd) {
13739
13684
  }
13740
13685
  function postFailureTail(issueNumber, cwd, reason) {
13741
13686
  if (!issueNumber) return;
13742
- const logPath = path38.join(cwd, ".kody", "last-run.jsonl");
13687
+ const logPath = path36.join(cwd, ".kody", "last-run.jsonl");
13743
13688
  let tail = "";
13744
13689
  try {
13745
- if (fs41.existsSync(logPath)) {
13746
- const content = fs41.readFileSync(logPath, "utf-8");
13690
+ if (fs40.existsSync(logPath)) {
13691
+ const content = fs40.readFileSync(logPath, "utf-8");
13747
13692
  tail = content.slice(-3e3);
13748
13693
  }
13749
13694
  } catch {
@@ -13768,7 +13713,7 @@ async function runCi(argv) {
13768
13713
  return 0;
13769
13714
  }
13770
13715
  const args = parseCiArgs(argv);
13771
- const cwd = args.cwd ? path38.resolve(args.cwd) : process.cwd();
13716
+ const cwd = args.cwd ? path36.resolve(args.cwd) : process.cwd();
13772
13717
  let earlyConfig;
13773
13718
  try {
13774
13719
  earlyConfig = loadConfig(cwd);
@@ -13778,9 +13723,9 @@ async function runCi(argv) {
13778
13723
  const eventName = process.env.GITHUB_EVENT_NAME;
13779
13724
  const dispatchEventPath = process.env.GITHUB_EVENT_PATH;
13780
13725
  let manualWorkflowDispatch = false;
13781
- if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs41.existsSync(dispatchEventPath)) {
13726
+ if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs40.existsSync(dispatchEventPath)) {
13782
13727
  try {
13783
- const evt = JSON.parse(fs41.readFileSync(dispatchEventPath, "utf-8"));
13728
+ const evt = JSON.parse(fs40.readFileSync(dispatchEventPath, "utf-8"));
13784
13729
  const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
13785
13730
  const sessionInput = String(evt?.inputs?.sessionId ?? "");
13786
13731
  manualWorkflowDispatch = !sessionInput && !(Number.isFinite(issueInput) && issueInput > 0);
@@ -14039,17 +13984,17 @@ function parseChatArgs(argv, env = process.env) {
14039
13984
  return result;
14040
13985
  }
14041
13986
  function commitChatFiles(cwd, sessionId, verbose) {
14042
- const sessionFile = path39.relative(cwd, sessionFilePath(cwd, sessionId));
14043
- const eventsFile = path39.relative(cwd, eventsFilePath(cwd, sessionId));
13987
+ const sessionFile = path37.relative(cwd, sessionFilePath(cwd, sessionId));
13988
+ const eventsFile = path37.relative(cwd, eventsFilePath(cwd, sessionId));
14044
13989
  const safeSession = sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
14045
- const tasksDir = path39.join(".kody", "tasks", safeSession);
13990
+ const tasksDir = path37.join(".kody", "tasks", safeSession);
14046
13991
  const candidatePaths = [sessionFile, eventsFile, tasksDir];
14047
- const paths = candidatePaths.filter((p) => fs42.existsSync(path39.join(cwd, p)));
13992
+ const paths = candidatePaths.filter((p) => fs41.existsSync(path37.join(cwd, p)));
14048
13993
  if (paths.length === 0) return;
14049
13994
  const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
14050
13995
  try {
14051
- execFileSync32("git", ["add", "-f", ...paths], opts);
14052
- execFileSync32("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
13996
+ execFileSync30("git", ["add", "-f", ...paths], opts);
13997
+ execFileSync30("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
14053
13998
  } catch (err) {
14054
13999
  const msg = err instanceof Error ? err.message : String(err);
14055
14000
  process.stderr.write(`[kody:chat] commit skipped: ${msg}
@@ -14088,7 +14033,7 @@ async function runChat(argv) {
14088
14033
  ${CHAT_HELP}`);
14089
14034
  return 64;
14090
14035
  }
14091
- const cwd = args.cwd ? path39.resolve(args.cwd) : process.cwd();
14036
+ const cwd = args.cwd ? path37.resolve(args.cwd) : process.cwd();
14092
14037
  const sessionId = args.sessionId;
14093
14038
  const unpackedSecrets = unpackAllSecrets();
14094
14039
  if (unpackedSecrets > 0) {
@@ -14140,7 +14085,7 @@ ${CHAT_HELP}`);
14140
14085
  const sink = buildSink(cwd, sessionId, args.dashboardUrl);
14141
14086
  const meta = readMeta(sessionFile);
14142
14087
  process.stdout.write(
14143
- `\u2192 kody:chat: session file=${sessionFile} exists=${fs42.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
14088
+ `\u2192 kody:chat: session file=${sessionFile} exists=${fs41.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
14144
14089
  `
14145
14090
  );
14146
14091
  try {