@kody-ade/kody-engine 0.4.400 → 0.4.402

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bin/kody.js +750 -416
  2. package/package.json +1 -1
package/dist/bin/kody.js CHANGED
@@ -15,7 +15,7 @@ var init_package = __esm({
15
15
  "package.json"() {
16
16
  package_default = {
17
17
  name: "@kody-ade/kody-engine",
18
- version: "0.4.400",
18
+ version: "0.4.402",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -1088,7 +1088,7 @@ function cmsHeaders(opts) {
1088
1088
  }
1089
1089
  };
1090
1090
  }
1091
- async function callDashboardCms(opts, path50, init = {}) {
1091
+ async function callDashboardCms(opts, path51, init = {}) {
1092
1092
  const baseUrl = dashboardBaseUrl(opts);
1093
1093
  if (!baseUrl) {
1094
1094
  return {
@@ -1100,7 +1100,7 @@ async function callDashboardCms(opts, path50, init = {}) {
1100
1100
  const headerResult = cmsHeaders(opts);
1101
1101
  if (!headerResult.ok) return headerResult;
1102
1102
  try {
1103
- const res = await fetch(`${baseUrl}${path50}`, {
1103
+ const res = await fetch(`${baseUrl}${path51}`, {
1104
1104
  ...init,
1105
1105
  headers: {
1106
1106
  ...headerResult.headers,
@@ -1172,8 +1172,8 @@ function documentArg(value) {
1172
1172
  function normalizeCmsDocumentIdInput(input) {
1173
1173
  const trimmed = stripWrappingQuotes(input.trim());
1174
1174
  const withoutQuery = trimmed.split(/[?#]/, 1)[0] ?? trimmed;
1175
- const path50 = parseDocumentPath(withoutQuery);
1176
- return path50 ?? parseDocumentIdSegment(withoutQuery) ?? withoutQuery;
1175
+ const path51 = parseDocumentPath(withoutQuery);
1176
+ return path51 ?? parseDocumentIdSegment(withoutQuery) ?? withoutQuery;
1177
1177
  }
1178
1178
  function stripWrappingQuotes(value) {
1179
1179
  let current = value;
@@ -1184,9 +1184,9 @@ function stripWrappingQuotes(value) {
1184
1184
  }
1185
1185
  }
1186
1186
  function parseDocumentPath(value) {
1187
- const path50 = value.startsWith("http://") || value.startsWith("https://") ? urlPathname(value) : value;
1188
- if (!path50?.includes("/content/entries/")) return null;
1189
- const parts = path50.split("/").filter(Boolean).map(decodePathPart);
1187
+ const path51 = value.startsWith("http://") || value.startsWith("https://") ? urlPathname(value) : value;
1188
+ if (!path51?.includes("/content/entries/")) return null;
1189
+ const parts = path51.split("/").filter(Boolean).map(decodePathPart);
1190
1190
  const entriesIndex = parts.findIndex((part, index) => part === "content" && parts[index + 1] === "entries");
1191
1191
  const idPart = parts[entriesIndex + 3];
1192
1192
  if (!idPart || idPart === "new") return null;
@@ -3604,7 +3604,14 @@ var init_agents = __esm({
3604
3604
  "src/agents.ts"() {
3605
3605
  "use strict";
3606
3606
  init_definition_paths();
3607
- BUILTIN_AGENTS = {};
3607
+ BUILTIN_AGENTS = {
3608
+ kody: [
3609
+ "# Kody",
3610
+ "",
3611
+ "You are Kody, the autonomous development engine running this task.",
3612
+ "Stay concise, make the smallest correct change, verify the real path, and report blockers honestly."
3613
+ ].join("\n")
3614
+ };
3608
3615
  }
3609
3616
  });
3610
3617
 
@@ -3763,7 +3770,7 @@ var init_task_artifacts = __esm({
3763
3770
 
3764
3771
  // src/gha.ts
3765
3772
  import { execFileSync as execFileSync2 } from "child_process";
3766
- import * as fs16 from "fs";
3773
+ import * as fs17 from "fs";
3767
3774
  function getRunUrl() {
3768
3775
  const server = process.env.GITHUB_SERVER_URL;
3769
3776
  const repo = process.env.GITHUB_REPOSITORY;
@@ -3774,10 +3781,10 @@ function getRunUrl() {
3774
3781
  function reactToTriggerComment(cwd) {
3775
3782
  if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
3776
3783
  const eventPath = process.env.GITHUB_EVENT_PATH;
3777
- if (!eventPath || !fs16.existsSync(eventPath)) return;
3784
+ if (!eventPath || !fs17.existsSync(eventPath)) return;
3778
3785
  let event = null;
3779
3786
  try {
3780
- event = JSON.parse(fs16.readFileSync(eventPath, "utf-8"));
3787
+ event = JSON.parse(fs17.readFileSync(eventPath, "utf-8"));
3781
3788
  } catch {
3782
3789
  return;
3783
3790
  }
@@ -4306,31 +4313,31 @@ var init_lifecycles = __esm({
4306
4313
  });
4307
4314
 
4308
4315
  // src/scripts/buildSyntheticPlugin.ts
4309
- import * as fs17 from "fs";
4316
+ import * as fs18 from "fs";
4310
4317
  import * as os3 from "os";
4311
- import * as path16 from "path";
4318
+ import * as path17 from "path";
4312
4319
  function getPluginsCatalogRoot() {
4313
- const here = path16.dirname(new URL(import.meta.url).pathname);
4320
+ const here = path17.dirname(new URL(import.meta.url).pathname);
4314
4321
  const candidates = [
4315
- path16.join(here, "..", "plugins"),
4322
+ path17.join(here, "..", "plugins"),
4316
4323
  // dev: src/scripts → src/plugins
4317
- path16.join(here, "..", "..", "plugins"),
4324
+ path17.join(here, "..", "..", "plugins"),
4318
4325
  // built: dist/scripts → dist/plugins
4319
- path16.join(here, "..", "..", "src", "plugins")
4326
+ path17.join(here, "..", "..", "src", "plugins")
4320
4327
  // fallback
4321
4328
  ];
4322
4329
  for (const c of candidates) {
4323
- if (fs17.existsSync(c) && fs17.statSync(c).isDirectory()) return c;
4330
+ if (fs18.existsSync(c) && fs18.statSync(c).isDirectory()) return c;
4324
4331
  }
4325
4332
  return candidates[0];
4326
4333
  }
4327
4334
  function copyDir(src, dst) {
4328
- fs17.mkdirSync(dst, { recursive: true });
4329
- for (const ent of fs17.readdirSync(src, { withFileTypes: true })) {
4330
- const s = path16.join(src, ent.name);
4331
- const d = path16.join(dst, ent.name);
4335
+ fs18.mkdirSync(dst, { recursive: true });
4336
+ for (const ent of fs18.readdirSync(src, { withFileTypes: true })) {
4337
+ const s = path17.join(src, ent.name);
4338
+ const d = path17.join(dst, ent.name);
4332
4339
  if (ent.isDirectory()) copyDir(s, d);
4333
- else if (ent.isFile()) fs17.copyFileSync(s, d);
4340
+ else if (ent.isFile()) fs18.copyFileSync(s, d);
4334
4341
  }
4335
4342
  }
4336
4343
  var buildSyntheticPlugin;
@@ -4343,45 +4350,45 @@ var init_buildSyntheticPlugin = __esm({
4343
4350
  if (!needsSynthetic) return;
4344
4351
  const catalog = getPluginsCatalogRoot();
4345
4352
  const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
4346
- const root = path16.join(os3.tmpdir(), `kody-synth-${runId}`);
4347
- fs17.mkdirSync(path16.join(root, ".claude-plugin"), { recursive: true });
4353
+ const root = path17.join(os3.tmpdir(), `kody-synth-${runId}`);
4354
+ fs18.mkdirSync(path17.join(root, ".claude-plugin"), { recursive: true });
4348
4355
  const resolvePart = (bucket, entry) => {
4349
- const local = path16.join(profile.dir, bucket, entry);
4350
- if (fs17.existsSync(local)) return local;
4351
- const central = path16.join(catalog, bucket, entry);
4352
- if (fs17.existsSync(central)) return central;
4356
+ const local = path17.join(profile.dir, bucket, entry);
4357
+ if (fs18.existsSync(local)) return local;
4358
+ const central = path17.join(catalog, bucket, entry);
4359
+ if (fs18.existsSync(central)) return central;
4353
4360
  throw new Error(
4354
4361
  `buildSyntheticPlugin: ${bucket} entry '${entry}' not found in implementation dir (${profile.dir}/${bucket}/) or catalog (${catalog}/${bucket}/)`
4355
4362
  );
4356
4363
  };
4357
4364
  if (cc.skills.length > 0) {
4358
- const dst = path16.join(root, "skills");
4359
- fs17.mkdirSync(dst, { recursive: true });
4365
+ const dst = path17.join(root, "skills");
4366
+ fs18.mkdirSync(dst, { recursive: true });
4360
4367
  for (const name of cc.skills) {
4361
- copyDir(resolvePart("skills", name), path16.join(dst, name));
4368
+ copyDir(resolvePart("skills", name), path17.join(dst, name));
4362
4369
  }
4363
4370
  }
4364
4371
  if (cc.commands.length > 0) {
4365
- const dst = path16.join(root, "commands");
4366
- fs17.mkdirSync(dst, { recursive: true });
4372
+ const dst = path17.join(root, "commands");
4373
+ fs18.mkdirSync(dst, { recursive: true });
4367
4374
  for (const name of cc.commands) {
4368
- fs17.copyFileSync(resolvePart("commands", `${name}.md`), path16.join(dst, `${name}.md`));
4375
+ fs18.copyFileSync(resolvePart("commands", `${name}.md`), path17.join(dst, `${name}.md`));
4369
4376
  }
4370
4377
  }
4371
4378
  if (cc.hooks.length > 0) {
4372
- const dst = path16.join(root, "hooks");
4373
- fs17.mkdirSync(dst, { recursive: true });
4379
+ const dst = path17.join(root, "hooks");
4380
+ fs18.mkdirSync(dst, { recursive: true });
4374
4381
  const merged = { hooks: {} };
4375
4382
  for (const name of cc.hooks) {
4376
4383
  const src = resolvePart("hooks", `${name}.json`);
4377
- const parsed = JSON.parse(fs17.readFileSync(src, "utf-8"));
4384
+ const parsed = JSON.parse(fs18.readFileSync(src, "utf-8"));
4378
4385
  for (const [event, entries] of Object.entries(parsed.hooks ?? {})) {
4379
4386
  if (!Array.isArray(entries)) continue;
4380
4387
  if (!merged.hooks[event]) merged.hooks[event] = [];
4381
4388
  merged.hooks[event].push(...entries);
4382
4389
  }
4383
4390
  }
4384
- fs17.writeFileSync(path16.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
4391
+ fs18.writeFileSync(path17.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
4385
4392
  `);
4386
4393
  }
4387
4394
  const manifest = {
@@ -4391,7 +4398,7 @@ var init_buildSyntheticPlugin = __esm({
4391
4398
  };
4392
4399
  if (cc.skills.length > 0) manifest.skills = ["./skills/"];
4393
4400
  if (cc.commands.length > 0) manifest.commands = ["./commands/"];
4394
- fs17.writeFileSync(path16.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
4401
+ fs18.writeFileSync(path17.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
4395
4402
  `);
4396
4403
  ctx.data.syntheticPluginPath = root;
4397
4404
  };
@@ -4399,8 +4406,8 @@ var init_buildSyntheticPlugin = __esm({
4399
4406
  });
4400
4407
 
4401
4408
  // src/subagents.ts
4402
- import * as fs18 from "fs";
4403
- import * as path17 from "path";
4409
+ import * as fs19 from "fs";
4410
+ import * as path18 from "path";
4404
4411
  function splitFrontmatter(raw) {
4405
4412
  const match = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(raw);
4406
4413
  if (!match) return { fm: {}, body: raw.trim() };
@@ -4413,10 +4420,10 @@ function splitFrontmatter(raw) {
4413
4420
  return { fm, body: (match[2] ?? "").trim() };
4414
4421
  }
4415
4422
  function resolveAgentFile2(profileDir, name) {
4416
- const local = path17.join(profileDir, "agents", `${name}.md`);
4417
- if (fs18.existsSync(local)) return local;
4418
- const central = path17.join(getPluginsCatalogRoot(), "agents", `${name}.md`);
4419
- if (fs18.existsSync(central)) return central;
4423
+ const local = path18.join(profileDir, "agents", `${name}.md`);
4424
+ if (fs19.existsSync(local)) return local;
4425
+ const central = path18.join(getPluginsCatalogRoot(), "agents", `${name}.md`);
4426
+ if (fs19.existsSync(central)) return central;
4420
4427
  throw new Error(`loadSubagents: agent '${name}' not found in ${profileDir}/agents/ or shared catalog`);
4421
4428
  }
4422
4429
  function captureSubagentTemplates(profile) {
@@ -4425,7 +4432,7 @@ function captureSubagentTemplates(profile) {
4425
4432
  const out = {};
4426
4433
  for (const name of names) {
4427
4434
  try {
4428
- out[name] = fs18.readFileSync(resolveAgentFile2(profile.dir, name), "utf-8");
4435
+ out[name] = fs19.readFileSync(resolveAgentFile2(profile.dir, name), "utf-8");
4429
4436
  } catch {
4430
4437
  }
4431
4438
  }
@@ -4436,7 +4443,7 @@ function loadSubagents(profile) {
4436
4443
  if (!names || names.length === 0) return void 0;
4437
4444
  const agents = {};
4438
4445
  for (const name of names) {
4439
- const raw = profile.subagentTemplates?.[name] ?? fs18.readFileSync(resolveAgentFile2(profile.dir, name), "utf-8");
4446
+ const raw = profile.subagentTemplates?.[name] ?? fs19.readFileSync(resolveAgentFile2(profile.dir, name), "utf-8");
4440
4447
  const { fm, body } = splitFrontmatter(raw);
4441
4448
  if (!body) throw new Error(`loadSubagents: agent '${name}' has an empty prompt body`);
4442
4449
  const def = {
@@ -4460,15 +4467,15 @@ var init_subagents = __esm({
4460
4467
  });
4461
4468
 
4462
4469
  // src/profile.ts
4463
- import * as fs19 from "fs";
4464
- import * as path18 from "path";
4470
+ import * as fs20 from "fs";
4471
+ import * as path19 from "path";
4465
4472
  function loadProfile(profilePath) {
4466
- if (!fs19.existsSync(profilePath)) {
4473
+ if (!fs20.existsSync(profilePath)) {
4467
4474
  throw new ProfileError(profilePath, "file not found");
4468
4475
  }
4469
4476
  let raw;
4470
4477
  try {
4471
- raw = JSON.parse(fs19.readFileSync(profilePath, "utf-8"));
4478
+ raw = JSON.parse(fs20.readFileSync(profilePath, "utf-8"));
4472
4479
  } catch (err) {
4473
4480
  throw new ProfileError(profilePath, `invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
4474
4481
  }
@@ -4479,7 +4486,7 @@ function loadProfile(profilePath) {
4479
4486
  const unknownKeys = Object.keys(r).filter((k) => !KNOWN_PROFILE_KEYS.has(k));
4480
4487
  if (unknownKeys.length > 0) {
4481
4488
  process.stderr.write(
4482
- `[kody profile] ${path18.basename(path18.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
4489
+ `[kody profile] ${path19.basename(path19.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
4483
4490
  `
4484
4491
  );
4485
4492
  }
@@ -4489,7 +4496,7 @@ function loadProfile(profilePath) {
4489
4496
  if (!refPath) {
4490
4497
  throw new ProfileError(profilePath, `capability references unknown implementation '${execRef}'`);
4491
4498
  }
4492
- if (path18.resolve(refPath) === path18.resolve(profilePath)) {
4499
+ if (path19.resolve(refPath) === path19.resolve(profilePath)) {
4493
4500
  } else {
4494
4501
  const base = loadProfile(refPath);
4495
4502
  return {
@@ -4587,8 +4594,8 @@ function loadProfile(profilePath) {
4587
4594
  // Phase 5 in-process handoff opt-in. Default false; containers
4588
4595
  // flip to true after end-to-end verification.
4589
4596
  preloadContext: r.preloadContext === true,
4590
- dir: path18.dirname(profilePath),
4591
- promptTemplates: readPromptTemplates(path18.dirname(profilePath))
4597
+ dir: path19.dirname(profilePath),
4598
+ promptTemplates: readPromptTemplates(path19.dirname(profilePath))
4592
4599
  };
4593
4600
  if (lifecycle) {
4594
4601
  applyLifecycle(profile, profilePath);
@@ -4631,17 +4638,17 @@ function readPromptTemplates(dir) {
4631
4638
  const out = {};
4632
4639
  const read = (p) => {
4633
4640
  try {
4634
- out[p] = fs19.readFileSync(p, "utf-8");
4641
+ out[p] = fs20.readFileSync(p, "utf-8");
4635
4642
  } catch {
4636
4643
  }
4637
4644
  };
4638
- read(path18.join(dir, "prompt.md"));
4639
- read(path18.join(dir, "capability.md"));
4640
- read(path18.join(dir, "capability.md"));
4645
+ read(path19.join(dir, "prompt.md"));
4646
+ read(path19.join(dir, "capability.md"));
4647
+ read(path19.join(dir, "capability.md"));
4641
4648
  try {
4642
- const promptsDir = path18.join(dir, "prompts");
4643
- for (const ent of fs19.readdirSync(promptsDir)) {
4644
- if (ent.endsWith(".md")) read(path18.join(promptsDir, ent));
4649
+ const promptsDir = path19.join(dir, "prompts");
4650
+ for (const ent of fs20.readdirSync(promptsDir)) {
4651
+ if (ent.endsWith(".md")) read(path19.join(promptsDir, ent));
4645
4652
  }
4646
4653
  } catch {
4647
4654
  }
@@ -5415,16 +5422,16 @@ var init_state = __esm({
5415
5422
  });
5416
5423
 
5417
5424
  // src/prompt.ts
5418
- import * as fs20 from "fs";
5419
- import * as path19 from "path";
5425
+ import * as fs21 from "fs";
5426
+ import * as path20 from "path";
5420
5427
  function loadProjectConventions(projectDir) {
5421
5428
  const out = [];
5422
5429
  for (const rel of CONVENTION_FILES) {
5423
- const abs = path19.join(projectDir, rel);
5424
- if (!fs20.existsSync(abs)) continue;
5430
+ const abs = path20.join(projectDir, rel);
5431
+ if (!fs21.existsSync(abs)) continue;
5425
5432
  let content;
5426
5433
  try {
5427
- content = fs20.readFileSync(abs, "utf-8");
5434
+ content = fs21.readFileSync(abs, "utf-8");
5428
5435
  } catch {
5429
5436
  continue;
5430
5437
  }
@@ -5659,8 +5666,8 @@ var loadMemoryContext_exports = {};
5659
5666
  __export(loadMemoryContext_exports, {
5660
5667
  loadMemoryContext: () => loadMemoryContext
5661
5668
  });
5662
- import * as fs21 from "fs";
5663
- import * as path20 from "path";
5669
+ import * as fs22 from "fs";
5670
+ import * as path21 from "path";
5664
5671
  function formatBlockFromBackend(docs) {
5665
5672
  const pages = docs.flatMap((record2) => {
5666
5673
  if (!record2.doc || typeof record2.doc !== "object") return [];
@@ -5683,21 +5690,21 @@ function collectPages(memoryAbs) {
5683
5690
  walkMd(memoryAbs, (file) => {
5684
5691
  let stat;
5685
5692
  try {
5686
- stat = fs21.statSync(file);
5693
+ stat = fs22.statSync(file);
5687
5694
  } catch {
5688
5695
  return;
5689
5696
  }
5690
5697
  let raw;
5691
5698
  try {
5692
- raw = fs21.readFileSync(file, "utf-8");
5699
+ raw = fs22.readFileSync(file, "utf-8");
5693
5700
  } catch {
5694
5701
  return;
5695
5702
  }
5696
5703
  const fm = raw.match(/^---\s*\n([\s\S]*?)\n---/);
5697
- const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path20.basename(file, ".md");
5704
+ const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path21.basename(file, ".md");
5698
5705
  const updated = fm?.[1]?.match(/^updated:\s*([0-9T:.+\-Z]+)/m)?.[1]?.trim() ?? "";
5699
5706
  out.push({
5700
- relPath: path20.relative(memoryAbs, file),
5707
+ relPath: path21.relative(memoryAbs, file),
5701
5708
  title,
5702
5709
  updated,
5703
5710
  content: raw.length > PER_PAGE_MAX_BYTES ? raw.slice(0, PER_PAGE_MAX_BYTES) + TRUNCATED_SUFFIX2 : raw,
@@ -5765,16 +5772,16 @@ function walkMd(root, visit) {
5765
5772
  const dir = stack.pop();
5766
5773
  let names;
5767
5774
  try {
5768
- names = fs21.readdirSync(dir);
5775
+ names = fs22.readdirSync(dir);
5769
5776
  } catch {
5770
5777
  continue;
5771
5778
  }
5772
5779
  for (const name of names) {
5773
5780
  if (name.startsWith(".")) continue;
5774
- const full = path20.join(dir, name);
5781
+ const full = path21.join(dir, name);
5775
5782
  let stat;
5776
5783
  try {
5777
- stat = fs21.statSync(full);
5784
+ stat = fs22.statSync(full);
5778
5785
  } catch {
5779
5786
  continue;
5780
5787
  }
@@ -5809,8 +5816,8 @@ var init_loadMemoryContext = __esm({
5809
5816
  }
5810
5817
  return;
5811
5818
  }
5812
- const memoryAbs = path20.join(ctx.cwd, MEMORY_DIR_RELATIVE);
5813
- if (!fs21.existsSync(memoryAbs)) {
5819
+ const memoryAbs = path21.join(ctx.cwd, MEMORY_DIR_RELATIVE);
5820
+ if (!fs22.existsSync(memoryAbs)) {
5814
5821
  ctx.data.memoryContext = "";
5815
5822
  return;
5816
5823
  }
@@ -5854,11 +5861,11 @@ var init_loadCoverageRules = __esm({
5854
5861
 
5855
5862
  // src/container.ts
5856
5863
  import { execFileSync as execFileSync3 } from "child_process";
5857
- import * as fs22 from "fs";
5864
+ import * as fs23 from "fs";
5858
5865
  function getProfileInputsForChild(profileName, _cwd) {
5859
5866
  try {
5860
5867
  const profilePath = resolveProfilePath(profileName);
5861
- if (!fs22.existsSync(profilePath)) return null;
5868
+ if (!fs23.existsSync(profilePath)) return null;
5862
5869
  return loadProfile(profilePath).inputs;
5863
5870
  } catch {
5864
5871
  return null;
@@ -6321,11 +6328,11 @@ var init_lifecycleLabels = __esm({
6321
6328
  });
6322
6329
 
6323
6330
  // src/litellm.ts
6324
- import { execFileSync as execFileSync4, spawn as spawn3 } from "child_process";
6325
- import * as fs23 from "fs";
6331
+ import { execFileSync as execFileSync4, spawn as spawn4 } from "child_process";
6332
+ import * as fs24 from "fs";
6326
6333
  import * as net from "net";
6327
6334
  import * as os4 from "os";
6328
- import * as path21 from "path";
6335
+ import * as path22 from "path";
6329
6336
  async function checkLitellmHealth(url) {
6330
6337
  try {
6331
6338
  const response = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3e3) });
@@ -6394,6 +6401,8 @@ function locateLitellmScript() {
6394
6401
  }
6395
6402
  }
6396
6403
  function resolveLitellmCommand() {
6404
+ const imageScript = "/opt/venv/bin/litellm";
6405
+ if (fs24.existsSync(imageScript)) return imageScript;
6397
6406
  try {
6398
6407
  execFileSync4("which", ["litellm"], { timeout: 3e3, stdio: "pipe" });
6399
6408
  return "litellm";
@@ -6429,13 +6438,13 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
6429
6438
  const spawnProxy = () => {
6430
6439
  const portMatch = activeUrl.match(/:(\d+)/);
6431
6440
  const port = portMatch ? portMatch[1] : "4000";
6432
- const configPath = path21.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.yaml`);
6433
- fs23.writeFileSync(configPath, generateLitellmConfigYaml(model));
6441
+ const configPath = path22.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.yaml`);
6442
+ fs24.writeFileSync(configPath, generateLitellmConfigYaml(model));
6434
6443
  const args = ["--config", configPath, "--port", port];
6435
- const nextLogPath = path21.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.log`);
6436
- const outFd = fs23.openSync(nextLogPath, "w");
6437
- child = spawn3(cmd, args, { stdio: ["ignore", outFd, outFd], detached: true, env: childEnv });
6438
- fs23.closeSync(outFd);
6444
+ const nextLogPath = path22.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.log`);
6445
+ const outFd = fs24.openSync(nextLogPath, "w");
6446
+ child = spawn4(cmd, args, { stdio: ["ignore", outFd, outFd], detached: true, env: childEnv });
6447
+ fs24.closeSync(outFd);
6439
6448
  logPath = nextLogPath;
6440
6449
  };
6441
6450
  const waitForHealth = async () => {
@@ -6449,7 +6458,7 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
6449
6458
  const readLogTail = () => {
6450
6459
  if (!logPath) return "";
6451
6460
  try {
6452
- return fs23.readFileSync(logPath, "utf-8").slice(-2e3);
6461
+ return fs24.readFileSync(logPath, "utf-8").slice(-2e3);
6453
6462
  } catch {
6454
6463
  return "";
6455
6464
  }
@@ -6532,10 +6541,10 @@ function canListen(port, host) {
6532
6541
  });
6533
6542
  }
6534
6543
  function readDotenvApiKeys(projectDir) {
6535
- const dotenvPath = path21.join(projectDir, ".env");
6536
- if (!fs23.existsSync(dotenvPath)) return {};
6544
+ const dotenvPath = path22.join(projectDir, ".env");
6545
+ if (!fs24.existsSync(dotenvPath)) return {};
6537
6546
  const result = {};
6538
- for (const rawLine of fs23.readFileSync(dotenvPath, "utf-8").split("\n")) {
6547
+ for (const rawLine of fs24.readFileSync(dotenvPath, "utf-8").split("\n")) {
6539
6548
  const line = rawLine.trim();
6540
6549
  if (!line || line.startsWith("#")) continue;
6541
6550
  const match = line.match(/^([A-Z_][A-Z0-9_]*_API_KEY)=(.*)$/);
@@ -6932,8 +6941,8 @@ var init_pushWithRetry = __esm({
6932
6941
 
6933
6942
  // src/commit.ts
6934
6943
  import { execFileSync as execFileSync6 } from "child_process";
6935
- import * as fs24 from "fs";
6936
- import * as path22 from "path";
6944
+ import * as fs25 from "fs";
6945
+ import * as path23 from "path";
6937
6946
  function isGitHubYamlPath(filePath) {
6938
6947
  const normalized = filePath.replace(/^\.\/+/, "");
6939
6948
  return normalized.startsWith(".github/") && /\.ya?ml$/i.test(normalized);
@@ -6975,18 +6984,18 @@ function ensureGitIdentity(cwd) {
6975
6984
  }
6976
6985
  function abortUnfinishedGitOps(cwd) {
6977
6986
  const aborted = [];
6978
- const gitDir = path22.join(cwd ?? process.cwd(), ".git");
6979
- if (!fs24.existsSync(gitDir)) return aborted;
6980
- if (fs24.existsSync(path22.join(gitDir, "MERGE_HEAD"))) {
6987
+ const gitDir = path23.join(cwd ?? process.cwd(), ".git");
6988
+ if (!fs25.existsSync(gitDir)) return aborted;
6989
+ if (fs25.existsSync(path23.join(gitDir, "MERGE_HEAD"))) {
6981
6990
  if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
6982
6991
  }
6983
- if (fs24.existsSync(path22.join(gitDir, "CHERRY_PICK_HEAD"))) {
6992
+ if (fs25.existsSync(path23.join(gitDir, "CHERRY_PICK_HEAD"))) {
6984
6993
  if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
6985
6994
  }
6986
- if (fs24.existsSync(path22.join(gitDir, "REVERT_HEAD"))) {
6995
+ if (fs25.existsSync(path23.join(gitDir, "REVERT_HEAD"))) {
6987
6996
  if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
6988
6997
  }
6989
- if (fs24.existsSync(path22.join(gitDir, "rebase-merge")) || fs24.existsSync(path22.join(gitDir, "rebase-apply"))) {
6998
+ if (fs25.existsSync(path23.join(gitDir, "rebase-merge")) || fs25.existsSync(path23.join(gitDir, "rebase-apply"))) {
6990
6999
  if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
6991
7000
  }
6992
7001
  try {
@@ -7043,7 +7052,7 @@ function normalizeCommitMessage(raw) {
7043
7052
  function commitAndPush(branch, agentMessage, cwd) {
7044
7053
  const allChanged = listChangedFiles(cwd);
7045
7054
  const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
7046
- const mergeHeadExists = fs24.existsSync(path22.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
7055
+ const mergeHeadExists = fs25.existsSync(path23.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
7047
7056
  if (allowedFiles.length === 0 && !mergeHeadExists) {
7048
7057
  return { committed: false, pushed: false, sha: "", message: "" };
7049
7058
  }
@@ -7683,13 +7692,13 @@ var init_state2 = __esm({
7683
7692
  });
7684
7693
 
7685
7694
  // src/goal/runLog.ts
7686
- import * as fs25 from "fs";
7695
+ import * as fs26 from "fs";
7687
7696
  function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
7688
7697
  const logs = goalRunLogs(data);
7689
7698
  const existing = logs[goalId];
7690
- const path50 = existing?.path ?? goalRunLogPath(goalId, data);
7699
+ const path51 = existing?.path ?? goalRunLogPath(goalId, data);
7691
7700
  logs[goalId] = {
7692
- path: path50,
7701
+ path: path51,
7693
7702
  events: [...existing?.events ?? [], buildGoalRunLogEvent(data, goalId, event, at)]
7694
7703
  };
7695
7704
  }
@@ -8025,8 +8034,8 @@ function readGithubEvent() {
8025
8034
  const eventPath = process.env.GITHUB_EVENT_PATH;
8026
8035
  if (!eventPath) return null;
8027
8036
  try {
8028
- if (!fs25.existsSync(eventPath)) return null;
8029
- const parsed = JSON.parse(fs25.readFileSync(eventPath, "utf-8"));
8037
+ if (!fs26.existsSync(eventPath)) return null;
8038
+ const parsed = JSON.parse(fs26.readFileSync(eventPath, "utf-8"));
8030
8039
  return recordValue3(parsed);
8031
8040
  } catch {
8032
8041
  return null;
@@ -8136,8 +8145,8 @@ var init_stateStore = __esm({
8136
8145
  });
8137
8146
 
8138
8147
  // src/goal/targetLoopResolution.ts
8139
- import * as fs26 from "fs";
8140
- import * as path23 from "path";
8148
+ import * as fs27 from "fs";
8149
+ import * as path24 from "path";
8141
8150
  async function resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal) {
8142
8151
  const targetId = loopGoal.loopTarget?.id.trim() ?? "";
8143
8152
  assertSafeGoalId(targetId, "loop target");
@@ -8215,11 +8224,11 @@ function goalInstanceTime(state) {
8215
8224
  return Number.isNaN(parsed) ? 0 : parsed;
8216
8225
  }
8217
8226
  function loadGoalTemplate(cwd, targetId) {
8218
- return readJsonObject(path23.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
8227
+ return readJsonObject(path24.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
8219
8228
  }
8220
8229
  function readJsonObject(filePath) {
8221
- if (!fs26.existsSync(filePath)) return null;
8222
- const parsed = JSON.parse(fs26.readFileSync(filePath, "utf8"));
8230
+ if (!fs27.existsSync(filePath)) return null;
8231
+ const parsed = JSON.parse(fs27.readFileSync(filePath, "utf8"));
8223
8232
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
8224
8233
  throw new Error(`goal template ${filePath} must be a JSON object`);
8225
8234
  }
@@ -8662,11 +8671,11 @@ function validateWorkflow(value, options = {}) {
8662
8671
  function formatWorkflowValidationIssues(issues) {
8663
8672
  return issues.map((entry) => `${entry.path}: ${entry.message}`);
8664
8673
  }
8665
- function validateDataMatch(value, path50, issues, capabilityOutputs) {
8674
+ function validateDataMatch(value, path51, issues, capabilityOutputs) {
8666
8675
  if (value === void 0) return;
8667
8676
  const match = asRecord2(value);
8668
8677
  if (!match || Object.keys(match).length === 0) {
8669
- issue(issues, "invalid_condition", path50, "workflow condition must contain at least one match");
8678
+ issue(issues, "invalid_condition", path51, "workflow condition must contain at least one match");
8670
8679
  return;
8671
8680
  }
8672
8681
  for (const [field, expected] of Object.entries(match)) {
@@ -8674,7 +8683,7 @@ function validateDataMatch(value, path50, issues, capabilityOutputs) {
8674
8683
  issue(
8675
8684
  issues,
8676
8685
  "invalid_data_path",
8677
- `${path50}.${field}`,
8686
+ `${path51}.${field}`,
8678
8687
  `workflow condition must read from facts, evidence, artifacts, result, workflow, or lastOutcome`
8679
8688
  );
8680
8689
  }
@@ -8682,12 +8691,12 @@ function validateDataMatch(value, path50, issues, capabilityOutputs) {
8682
8691
  issue(
8683
8692
  issues,
8684
8693
  "undeclared_result_path",
8685
- `${path50}.${field}`,
8694
+ `${path51}.${field}`,
8686
8695
  `workflow condition reads ${field}, but the source capability does not declare it`
8687
8696
  );
8688
8697
  }
8689
8698
  if (!isComparable(expected)) {
8690
- issue(issues, "invalid_condition_value", `${path50}.${field}`, "workflow condition value must be a JSON scalar");
8699
+ issue(issues, "invalid_condition_value", `${path51}.${field}`, "workflow condition value must be a JSON scalar");
8691
8700
  }
8692
8701
  }
8693
8702
  }
@@ -8705,8 +8714,8 @@ function isComparable(value) {
8705
8714
  if (value === null || ["string", "number", "boolean"].includes(typeof value)) return true;
8706
8715
  return Array.isArray(value) && value.length > 0 && value.every((item) => isComparable(item) && !Array.isArray(item));
8707
8716
  }
8708
- function issue(issues, code, path50, message) {
8709
- issues.push({ code, path: path50, message });
8717
+ function issue(issues, code, path51, message) {
8718
+ issues.push({ code, path: path51, message });
8710
8719
  }
8711
8720
  var SAFE_NAME, SAFE_STEP_ID, SAFE_DATA_PATH, SUPPORTED_STEP_FIELDS, SUPPORTED_TRANSITION_FIELDS;
8712
8721
  var init_workflowValidation = __esm({
@@ -8738,8 +8747,8 @@ var init_workflowValidation = __esm({
8738
8747
  });
8739
8748
 
8740
8749
  // src/workflowDefinitions.ts
8741
- import * as fs27 from "fs";
8742
- import * as path24 from "path";
8750
+ import * as fs28 from "fs";
8751
+ import * as path25 from "path";
8743
8752
  function isWorkflowDefinitionId(value) {
8744
8753
  return WORKFLOW_ID_PATTERN.test(value);
8745
8754
  }
@@ -8780,14 +8789,14 @@ function normalizeWorkflowDefinition(value) {
8780
8789
  };
8781
8790
  }
8782
8791
  function readWorkflowDefinition(_config, cwd, id) {
8783
- const filePath = path24.join(cwd ?? process.cwd(), ".kody-engine", "runtime", workflowDefinitionPath(id));
8784
- if (!fs27.existsSync(filePath)) return null;
8785
- return parseWorkflowDefinition(fs27.readFileSync(filePath, "utf8"));
8792
+ const filePath = path25.join(cwd ?? process.cwd(), ".kody-engine", "runtime", workflowDefinitionPath(id));
8793
+ if (!fs28.existsSync(filePath)) return null;
8794
+ return parseWorkflowDefinition(fs28.readFileSync(filePath, "utf8"));
8786
8795
  }
8787
8796
  function workflowDefinitionToCapabilityFolder(id, workflow, source = workflowDefinitionPath(id)) {
8788
8797
  return {
8789
8798
  slug: id,
8790
- dir: path24.dirname(source),
8799
+ dir: path25.dirname(source),
8791
8800
  profilePath: source,
8792
8801
  bodyPath: source,
8793
8802
  title: workflow.name,
@@ -8964,15 +8973,15 @@ var init_backendStateBackend = __esm({
8964
8973
  this.jobsDir = opts.jobsDir.replace(/\/+$/, "");
8965
8974
  }
8966
8975
  async load(slug) {
8967
- const path50 = stateFilePath(this.jobsDir, slug);
8976
+ const path51 = stateFilePath(this.jobsDir, slug);
8968
8977
  const loaded = await createStateBackendFromEnv().get(this.tenantId, `capabilities/${slug}`, "job-state");
8969
8978
  if (!loaded) {
8970
- return { path: path50, handle: null, state: initialStateEnvelope("seed"), created: true };
8979
+ return { path: path51, handle: null, state: initialStateEnvelope("seed"), created: true };
8971
8980
  }
8972
8981
  if (!isStateEnvelope(loaded.doc)) {
8973
8982
  throw new Error(`BackendStateBackend: capabilities/${slug} is not a StateEnvelope`);
8974
8983
  }
8975
- return { path: path50, handle: loaded.updatedAt, state: loaded.doc, created: false };
8984
+ return { path: path51, handle: loaded.updatedAt, state: loaded.doc, created: false };
8976
8985
  }
8977
8986
  async save(loaded, next) {
8978
8987
  if (!loaded.created && isStateUnchanged(loaded.state, next)) return false;
@@ -8992,8 +9001,8 @@ var init_backendStateBackend = __esm({
8992
9001
  });
8993
9002
 
8994
9003
  // src/scripts/jobState/localFileBackend.ts
8995
- import * as fs28 from "fs";
8996
- import * as path25 from "path";
9004
+ import * as fs29 from "fs";
9005
+ import * as path26 from "path";
8997
9006
  function sanitizeKey(s) {
8998
9007
  return s.replace(/[^A-Za-z0-9._-]/g, "-");
8999
9008
  }
@@ -9049,7 +9058,7 @@ var init_localFileBackend = __esm({
9049
9058
  if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
9050
9059
  this.cwd = opts.cwd;
9051
9060
  this.jobsDir = opts.jobsDir;
9052
- this.absDir = path25.resolve(opts.cwd, opts.jobsDir);
9061
+ this.absDir = path26.resolve(opts.cwd, opts.jobsDir);
9053
9062
  this.owner = opts.owner;
9054
9063
  this.repo = opts.repo;
9055
9064
  this.cache = opts.cache ?? defaultCacheAdapter();
@@ -9064,7 +9073,7 @@ var init_localFileBackend = __esm({
9064
9073
  `);
9065
9074
  return;
9066
9075
  }
9067
- fs28.mkdirSync(this.absDir, { recursive: true });
9076
+ fs29.mkdirSync(this.absDir, { recursive: true });
9068
9077
  const prefix = this.cacheKeyPrefix();
9069
9078
  const probeKey = `${prefix}probe-${Date.now()}`;
9070
9079
  try {
@@ -9093,7 +9102,7 @@ var init_localFileBackend = __esm({
9093
9102
  `);
9094
9103
  return;
9095
9104
  }
9096
- if (!fs28.existsSync(this.absDir)) {
9105
+ if (!fs29.existsSync(this.absDir)) {
9097
9106
  return;
9098
9107
  }
9099
9108
  const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
@@ -9109,11 +9118,11 @@ var init_localFileBackend = __esm({
9109
9118
  }
9110
9119
  load(slug) {
9111
9120
  const relPath = stateFilePath(this.jobsDir, slug);
9112
- const absPath = path25.resolve(this.cwd, relPath);
9113
- if (!fs28.existsSync(absPath)) {
9121
+ const absPath = path26.resolve(this.cwd, relPath);
9122
+ if (!fs29.existsSync(absPath)) {
9114
9123
  return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
9115
9124
  }
9116
- const raw = fs28.readFileSync(absPath, "utf-8");
9125
+ const raw = fs29.readFileSync(absPath, "utf-8");
9117
9126
  let parsed;
9118
9127
  try {
9119
9128
  parsed = JSON.parse(raw);
@@ -9130,13 +9139,13 @@ var init_localFileBackend = __esm({
9130
9139
  if (!loaded.created && isStateUnchanged(loaded.state, next)) {
9131
9140
  return false;
9132
9141
  }
9133
- const absPath = path25.resolve(this.cwd, loaded.path);
9134
- fs28.mkdirSync(path25.dirname(absPath), { recursive: true });
9142
+ const absPath = path26.resolve(this.cwd, loaded.path);
9143
+ fs29.mkdirSync(path26.dirname(absPath), { recursive: true });
9135
9144
  const body = `${JSON.stringify(next, null, 2)}
9136
9145
  `;
9137
9146
  const tmpPath = `${absPath}.${process.pid}.tmp`;
9138
- fs28.writeFileSync(tmpPath, body, "utf-8");
9139
- fs28.renameSync(tmpPath, absPath);
9147
+ fs29.writeFileSync(tmpPath, body, "utf-8");
9148
+ fs29.renameSync(tmpPath, absPath);
9140
9149
  return true;
9141
9150
  }
9142
9151
  cacheKeyPrefix() {
@@ -9168,7 +9177,7 @@ var init_jobState = __esm({
9168
9177
  });
9169
9178
 
9170
9179
  // src/scripts/goalCapabilityScheduling.ts
9171
- import * as path26 from "path";
9180
+ import * as path27 from "path";
9172
9181
  function isCapabilityCadenceGoal(goal, extra) {
9173
9182
  return extra.scheduleMode === "agentLoop" || extra.scheduler === "agentLoop" || goal.type === "standing" && goal.capabilities.length > 0;
9174
9183
  }
@@ -9224,7 +9233,7 @@ function planTargetLoopSchedule(opts) {
9224
9233
  }
9225
9234
  async function planGoalCapabilitySchedule(opts) {
9226
9235
  const jobsDir = opts.jobsDir ?? capabilitiesRoot(opts.cwd);
9227
- const jobsRoot = path26.resolve(opts.cwd, jobsDir);
9236
+ const jobsRoot = path27.resolve(opts.cwd, jobsDir);
9228
9237
  const now = opts.now ?? /* @__PURE__ */ new Date();
9229
9238
  const at = now.toISOString();
9230
9239
  const backend = resolveBackend({ config: opts.config, cwd: opts.cwd, jobsDir });
@@ -11039,8 +11048,8 @@ var init_classifyByLabel = __esm({
11039
11048
  });
11040
11049
 
11041
11050
  // src/scripts/commitAndPush.ts
11042
- import * as fs29 from "fs";
11043
- import * as path27 from "path";
11051
+ import * as fs30 from "fs";
11052
+ import * as path28 from "path";
11044
11053
  function sentinelPathForStage(cwd, profileName) {
11045
11054
  const runId = resolveRunId();
11046
11055
  return runtimeStatePath(cwd, "agent-runs", runId, `commit-${profileName}.lock`);
@@ -11061,9 +11070,9 @@ var init_commitAndPush = __esm({
11061
11070
  }
11062
11071
  const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
11063
11072
  const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name) : null;
11064
- if (sentinel && fs29.existsSync(sentinel)) {
11073
+ if (sentinel && fs30.existsSync(sentinel)) {
11065
11074
  try {
11066
- const replay = JSON.parse(fs29.readFileSync(sentinel, "utf-8"));
11075
+ const replay = JSON.parse(fs30.readFileSync(sentinel, "utf-8"));
11067
11076
  ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
11068
11077
  if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
11069
11078
  if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
@@ -11123,8 +11132,8 @@ var init_commitAndPush = __esm({
11123
11132
  const result = ctx.data.commitResult;
11124
11133
  if (sentinel && result?.committed) {
11125
11134
  try {
11126
- fs29.mkdirSync(path27.dirname(sentinel), { recursive: true });
11127
- fs29.writeFileSync(
11135
+ fs30.mkdirSync(path28.dirname(sentinel), { recursive: true });
11136
+ fs30.writeFileSync(
11128
11137
  sentinel,
11129
11138
  JSON.stringify(
11130
11139
  {
@@ -11218,8 +11227,8 @@ var init_commitGoalState = __esm({
11218
11227
  });
11219
11228
 
11220
11229
  // src/scripts/composePrompt.ts
11221
- import * as fs30 from "fs";
11222
- import * as path28 from "path";
11230
+ import * as fs31 from "fs";
11231
+ import * as path29 from "path";
11223
11232
  function fenceUntrusted(value) {
11224
11233
  if (value.trim().length === 0) return value;
11225
11234
  const safe = value.replace(/-{3,}\s*END UNTRUSTED INPUT\s*-{3,}/gi, "[END UNTRUSTED INPUT]");
@@ -11343,10 +11352,10 @@ var init_composePrompt = __esm({
11343
11352
  const explicit = ctx.data.promptTemplate;
11344
11353
  const mode = ctx.args.mode;
11345
11354
  const candidates = [
11346
- explicit ? path28.join(profile.dir, explicit) : null,
11347
- mode ? path28.join(profile.dir, "prompts", `${mode}.md`) : null,
11348
- path28.join(profile.dir, "prompt.md"),
11349
- path28.join(profile.dir, "capability.md")
11355
+ explicit ? path29.join(profile.dir, explicit) : null,
11356
+ mode ? path29.join(profile.dir, "prompts", `${mode}.md`) : null,
11357
+ path29.join(profile.dir, "prompt.md"),
11358
+ path29.join(profile.dir, "capability.md")
11350
11359
  ].filter(Boolean);
11351
11360
  let templatePath = "";
11352
11361
  let template = "";
@@ -11359,7 +11368,7 @@ var init_composePrompt = __esm({
11359
11368
  break;
11360
11369
  }
11361
11370
  try {
11362
- template = fs30.readFileSync(c, "utf-8");
11371
+ template = fs31.readFileSync(c, "utf-8");
11363
11372
  templatePath = c;
11364
11373
  break;
11365
11374
  } catch (err) {
@@ -11370,7 +11379,7 @@ var init_composePrompt = __esm({
11370
11379
  if (!templatePath) {
11371
11380
  let dirState;
11372
11381
  try {
11373
- dirState = `dir contents: [${fs30.readdirSync(profile.dir).join(", ")}]`;
11382
+ dirState = `dir contents: [${fs31.readdirSync(profile.dir).join(", ")}]`;
11374
11383
  } catch (err) {
11375
11384
  dirState = `readdir(${profile.dir}) failed: ${err?.code ?? String(err)}`;
11376
11385
  }
@@ -12059,19 +12068,19 @@ var init_deriveQaScopeFromIssue = __esm({
12059
12068
 
12060
12069
  // src/scripts/diagMcp.ts
12061
12070
  import { execFileSync as execFileSync9 } from "child_process";
12062
- import * as fs31 from "fs";
12071
+ import * as fs32 from "fs";
12063
12072
  import * as os5 from "os";
12064
- import * as path29 from "path";
12073
+ import * as path30 from "path";
12065
12074
  var diagMcp;
12066
12075
  var init_diagMcp = __esm({
12067
12076
  "src/scripts/diagMcp.ts"() {
12068
12077
  "use strict";
12069
12078
  diagMcp = async (_ctx) => {
12070
12079
  const home = os5.homedir();
12071
- const cacheDir = path29.join(home, ".cache", "ms-playwright");
12080
+ const cacheDir = path30.join(home, ".cache", "ms-playwright");
12072
12081
  let entries = [];
12073
12082
  try {
12074
- entries = fs31.readdirSync(cacheDir);
12083
+ entries = fs32.readdirSync(cacheDir);
12075
12084
  } catch {
12076
12085
  }
12077
12086
  const hasChromium = entries.some((e) => e.startsWith("chromium"));
@@ -12099,13 +12108,13 @@ var init_diagMcp = __esm({
12099
12108
  });
12100
12109
 
12101
12110
  // src/scripts/frameworkDetectors.ts
12102
- import * as fs32 from "fs";
12103
- import * as path30 from "path";
12111
+ import * as fs33 from "fs";
12112
+ import * as path31 from "path";
12104
12113
  function detectFrameworks(cwd) {
12105
12114
  const out = [];
12106
12115
  let deps = {};
12107
12116
  try {
12108
- const pkg = JSON.parse(fs32.readFileSync(path30.join(cwd, "package.json"), "utf-8"));
12117
+ const pkg = JSON.parse(fs33.readFileSync(path31.join(cwd, "package.json"), "utf-8"));
12109
12118
  deps = { ...pkg.dependencies, ...pkg.devDependencies };
12110
12119
  } catch {
12111
12120
  return out;
@@ -12142,25 +12151,25 @@ function detectFrameworks(cwd) {
12142
12151
  }
12143
12152
  function findFile(cwd, candidates) {
12144
12153
  for (const c of candidates) {
12145
- if (fs32.existsSync(path30.join(cwd, c))) return c;
12154
+ if (fs33.existsSync(path31.join(cwd, c))) return c;
12146
12155
  }
12147
12156
  return null;
12148
12157
  }
12149
12158
  function discoverPayloadCollections(cwd) {
12150
12159
  const out = [];
12151
12160
  for (const dir of COLLECTION_DIRS) {
12152
- const full = path30.join(cwd, dir);
12153
- if (!fs32.existsSync(full)) continue;
12161
+ const full = path31.join(cwd, dir);
12162
+ if (!fs33.existsSync(full)) continue;
12154
12163
  let files;
12155
12164
  try {
12156
- files = fs32.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
12165
+ files = fs33.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
12157
12166
  } catch {
12158
12167
  continue;
12159
12168
  }
12160
12169
  for (const file of files) {
12161
12170
  try {
12162
- const filePath = path30.join(full, file);
12163
- const content = fs32.readFileSync(filePath, "utf-8").slice(0, 1e4);
12171
+ const filePath = path31.join(full, file);
12172
+ const content = fs33.readFileSync(filePath, "utf-8").slice(0, 1e4);
12164
12173
  const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
12165
12174
  if (!slugMatch) continue;
12166
12175
  const slug = slugMatch[1];
@@ -12174,7 +12183,7 @@ function discoverPayloadCollections(cwd) {
12174
12183
  out.push({
12175
12184
  name,
12176
12185
  slug,
12177
- filePath: path30.relative(cwd, filePath),
12186
+ filePath: path31.relative(cwd, filePath),
12178
12187
  fields: fields.slice(0, 20),
12179
12188
  hasAdmin
12180
12189
  });
@@ -12187,28 +12196,28 @@ function discoverPayloadCollections(cwd) {
12187
12196
  function discoverAdminComponents(cwd, collections) {
12188
12197
  const out = [];
12189
12198
  for (const dir of ADMIN_COMPONENT_DIRS) {
12190
- const full = path30.join(cwd, dir);
12191
- if (!fs32.existsSync(full)) continue;
12199
+ const full = path31.join(cwd, dir);
12200
+ if (!fs33.existsSync(full)) continue;
12192
12201
  let entries;
12193
12202
  try {
12194
- entries = fs32.readdirSync(full, { withFileTypes: true });
12203
+ entries = fs33.readdirSync(full, { withFileTypes: true });
12195
12204
  } catch {
12196
12205
  continue;
12197
12206
  }
12198
12207
  for (const entry of entries) {
12199
- const entryPath = path30.join(full, entry.name);
12208
+ const entryPath = path31.join(full, entry.name);
12200
12209
  let name;
12201
12210
  let filePath;
12202
12211
  if (entry.isDirectory()) {
12203
12212
  const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
12204
- (f) => fs32.existsSync(path30.join(entryPath, f))
12213
+ (f) => fs33.existsSync(path31.join(entryPath, f))
12205
12214
  );
12206
12215
  if (!indexFile) continue;
12207
12216
  name = entry.name;
12208
- filePath = path30.relative(cwd, path30.join(entryPath, indexFile));
12217
+ filePath = path31.relative(cwd, path31.join(entryPath, indexFile));
12209
12218
  } else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
12210
12219
  name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
12211
- filePath = path30.relative(cwd, entryPath);
12220
+ filePath = path31.relative(cwd, entryPath);
12212
12221
  } else {
12213
12222
  continue;
12214
12223
  }
@@ -12216,7 +12225,7 @@ function discoverAdminComponents(cwd, collections) {
12216
12225
  if (collections) {
12217
12226
  for (const col of collections) {
12218
12227
  try {
12219
- const colContent = fs32.readFileSync(path30.join(cwd, col.filePath), "utf-8");
12228
+ const colContent = fs33.readFileSync(path31.join(cwd, col.filePath), "utf-8");
12220
12229
  if (colContent.includes(name)) {
12221
12230
  usedInCollection = col.slug;
12222
12231
  break;
@@ -12234,8 +12243,8 @@ function scanApiRoutes(cwd) {
12234
12243
  const out = [];
12235
12244
  const appDirs = ["src/app", "app"];
12236
12245
  for (const appDir of appDirs) {
12237
- const apiDir = path30.join(cwd, appDir, "api");
12238
- if (!fs32.existsSync(apiDir)) continue;
12246
+ const apiDir = path31.join(cwd, appDir, "api");
12247
+ if (!fs33.existsSync(apiDir)) continue;
12239
12248
  walkApiRoutes(apiDir, "/api", cwd, out);
12240
12249
  break;
12241
12250
  }
@@ -12244,14 +12253,14 @@ function scanApiRoutes(cwd) {
12244
12253
  function walkApiRoutes(dir, prefix, cwd, out) {
12245
12254
  let entries;
12246
12255
  try {
12247
- entries = fs32.readdirSync(dir, { withFileTypes: true });
12256
+ entries = fs33.readdirSync(dir, { withFileTypes: true });
12248
12257
  } catch {
12249
12258
  return;
12250
12259
  }
12251
12260
  const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
12252
12261
  if (routeFile) {
12253
12262
  try {
12254
- const content = fs32.readFileSync(path30.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
12263
+ const content = fs33.readFileSync(path31.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
12255
12264
  const methods = HTTP_METHODS.filter(
12256
12265
  (m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
12257
12266
  );
@@ -12259,7 +12268,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
12259
12268
  out.push({
12260
12269
  path: prefix,
12261
12270
  methods,
12262
- filePath: path30.relative(cwd, path30.join(dir, routeFile.name))
12271
+ filePath: path31.relative(cwd, path31.join(dir, routeFile.name))
12263
12272
  });
12264
12273
  }
12265
12274
  } catch {
@@ -12270,7 +12279,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
12270
12279
  if (entry.name === "node_modules" || entry.name === ".next") continue;
12271
12280
  let segment = entry.name;
12272
12281
  if (segment.startsWith("(") && segment.endsWith(")")) {
12273
- walkApiRoutes(path30.join(dir, entry.name), prefix, cwd, out);
12282
+ walkApiRoutes(path31.join(dir, entry.name), prefix, cwd, out);
12274
12283
  continue;
12275
12284
  }
12276
12285
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -12278,16 +12287,16 @@ function walkApiRoutes(dir, prefix, cwd, out) {
12278
12287
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
12279
12288
  segment = `:${segment.slice(1, -1)}`;
12280
12289
  }
12281
- walkApiRoutes(path30.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
12290
+ walkApiRoutes(path31.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
12282
12291
  }
12283
12292
  }
12284
12293
  function scanEnvVars(cwd) {
12285
12294
  const candidates = [".env.example", ".env.local.example", ".env.template"];
12286
12295
  for (const envFile of candidates) {
12287
- const envPath = path30.join(cwd, envFile);
12288
- if (!fs32.existsSync(envPath)) continue;
12296
+ const envPath = path31.join(cwd, envFile);
12297
+ if (!fs33.existsSync(envPath)) continue;
12289
12298
  try {
12290
- const content = fs32.readFileSync(envPath, "utf-8");
12299
+ const content = fs33.readFileSync(envPath, "utf-8");
12291
12300
  const vars = [];
12292
12301
  for (const line of content.split("\n")) {
12293
12302
  const trimmed = line.trim();
@@ -12332,8 +12341,8 @@ var init_frameworkDetectors = __esm({
12332
12341
  });
12333
12342
 
12334
12343
  // src/scripts/discoverQaContext.ts
12335
- import * as fs33 from "fs";
12336
- import * as path31 from "path";
12344
+ import * as fs34 from "fs";
12345
+ import * as path32 from "path";
12337
12346
  function runQaDiscovery(cwd) {
12338
12347
  const out = {
12339
12348
  routes: [],
@@ -12364,9 +12373,9 @@ function runQaDiscovery(cwd) {
12364
12373
  }
12365
12374
  function detectDevServer(cwd, out) {
12366
12375
  try {
12367
- const pkg = JSON.parse(fs33.readFileSync(path31.join(cwd, "package.json"), "utf-8"));
12376
+ const pkg = JSON.parse(fs34.readFileSync(path32.join(cwd, "package.json"), "utf-8"));
12368
12377
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
12369
- const pm = fs33.existsSync(path31.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs33.existsSync(path31.join(cwd, "yarn.lock")) ? "yarn" : fs33.existsSync(path31.join(cwd, "bun.lockb")) ? "bun" : "npm";
12378
+ const pm = fs34.existsSync(path32.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs34.existsSync(path32.join(cwd, "yarn.lock")) ? "yarn" : fs34.existsSync(path32.join(cwd, "bun.lockb")) ? "bun" : "npm";
12370
12379
  if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
12371
12380
  if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
12372
12381
  else if (allDeps.vite) out.devPort = 5173;
@@ -12376,8 +12385,8 @@ function detectDevServer(cwd, out) {
12376
12385
  function scanFrontendRoutes(cwd, out) {
12377
12386
  const appDirs = ["src/app", "app"];
12378
12387
  for (const appDir of appDirs) {
12379
- const full = path31.join(cwd, appDir);
12380
- if (!fs33.existsSync(full)) continue;
12388
+ const full = path32.join(cwd, appDir);
12389
+ if (!fs34.existsSync(full)) continue;
12381
12390
  walkFrontendRoutes(full, "", out);
12382
12391
  break;
12383
12392
  }
@@ -12385,7 +12394,7 @@ function scanFrontendRoutes(cwd, out) {
12385
12394
  function walkFrontendRoutes(dir, prefix, out) {
12386
12395
  let entries;
12387
12396
  try {
12388
- entries = fs33.readdirSync(dir, { withFileTypes: true });
12397
+ entries = fs34.readdirSync(dir, { withFileTypes: true });
12389
12398
  } catch {
12390
12399
  return;
12391
12400
  }
@@ -12402,7 +12411,7 @@ function walkFrontendRoutes(dir, prefix, out) {
12402
12411
  if (entry.name === "node_modules" || entry.name === ".next") continue;
12403
12412
  let segment = entry.name;
12404
12413
  if (segment.startsWith("(") && segment.endsWith(")")) {
12405
- walkFrontendRoutes(path31.join(dir, entry.name), prefix, out);
12414
+ walkFrontendRoutes(path32.join(dir, entry.name), prefix, out);
12406
12415
  continue;
12407
12416
  }
12408
12417
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -12410,7 +12419,7 @@ function walkFrontendRoutes(dir, prefix, out) {
12410
12419
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
12411
12420
  segment = `:${segment.slice(1, -1)}`;
12412
12421
  }
12413
- walkFrontendRoutes(path31.join(dir, entry.name), `${prefix}/${segment}`, out);
12422
+ walkFrontendRoutes(path32.join(dir, entry.name), `${prefix}/${segment}`, out);
12414
12423
  }
12415
12424
  }
12416
12425
  function detectAuthFiles(cwd, out) {
@@ -12427,23 +12436,23 @@ function detectAuthFiles(cwd, out) {
12427
12436
  "src/app/api/oauth"
12428
12437
  ];
12429
12438
  for (const c of candidates) {
12430
- if (fs33.existsSync(path31.join(cwd, c))) out.authFiles.push(c);
12439
+ if (fs34.existsSync(path32.join(cwd, c))) out.authFiles.push(c);
12431
12440
  }
12432
12441
  }
12433
12442
  function detectRoles(cwd, out) {
12434
12443
  const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
12435
12444
  for (const rp of rolePaths) {
12436
- const dir = path31.join(cwd, rp);
12437
- if (!fs33.existsSync(dir)) continue;
12445
+ const dir = path32.join(cwd, rp);
12446
+ if (!fs34.existsSync(dir)) continue;
12438
12447
  let files;
12439
12448
  try {
12440
- files = fs33.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
12449
+ files = fs34.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
12441
12450
  } catch {
12442
12451
  continue;
12443
12452
  }
12444
12453
  for (const f of files) {
12445
12454
  try {
12446
- const content = fs33.readFileSync(path31.join(dir, f), "utf-8").slice(0, 5e3);
12455
+ const content = fs34.readFileSync(path32.join(dir, f), "utf-8").slice(0, 5e3);
12447
12456
  const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
12448
12457
  if (roleMatches) {
12449
12458
  for (const m of roleMatches) {
@@ -13724,12 +13733,12 @@ var init_fixFlow = __esm({
13724
13733
 
13725
13734
  // src/scripts/initFlow.ts
13726
13735
  import { execFileSync as execFileSync14 } from "child_process";
13727
- import * as fs34 from "fs";
13728
- import * as path32 from "path";
13736
+ import * as fs35 from "fs";
13737
+ import * as path33 from "path";
13729
13738
  function detectPackageManager(cwd) {
13730
- if (fs34.existsSync(path32.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
13731
- if (fs34.existsSync(path32.join(cwd, "yarn.lock"))) return "yarn";
13732
- if (fs34.existsSync(path32.join(cwd, "bun.lockb"))) return "bun";
13739
+ if (fs35.existsSync(path33.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
13740
+ if (fs35.existsSync(path33.join(cwd, "yarn.lock"))) return "yarn";
13741
+ if (fs35.existsSync(path33.join(cwd, "bun.lockb"))) return "bun";
13733
13742
  return "npm";
13734
13743
  }
13735
13744
  function qualityCommandsFor(pm) {
@@ -13801,22 +13810,22 @@ function performInit(cwd, force) {
13801
13810
  const pm = detectPackageManager(cwd);
13802
13811
  const ownerRepo = detectOwnerRepo(cwd);
13803
13812
  const defaultBranch = defaultBranchFromGit(cwd);
13804
- const configPath = path32.join(cwd, "kody.config.json");
13805
- if (fs34.existsSync(configPath) && !force) {
13813
+ const configPath = path33.join(cwd, "kody.config.json");
13814
+ if (fs35.existsSync(configPath) && !force) {
13806
13815
  skipped.push("kody.config.json");
13807
13816
  } else {
13808
13817
  const cfg = makeConfig(pm, ownerRepo, defaultBranch);
13809
- fs34.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
13818
+ fs35.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
13810
13819
  `);
13811
13820
  wrote.push("kody.config.json");
13812
13821
  }
13813
- const workflowDir = path32.join(cwd, ".github", "workflows");
13814
- const workflowPath = path32.join(workflowDir, "kody.yml");
13815
- if (fs34.existsSync(workflowPath) && !force) {
13822
+ const workflowDir = path33.join(cwd, ".github", "workflows");
13823
+ const workflowPath = path33.join(workflowDir, "kody.yml");
13824
+ if (fs35.existsSync(workflowPath) && !force) {
13816
13825
  skipped.push(".github/workflows/kody.yml");
13817
13826
  } else {
13818
- fs34.mkdirSync(workflowDir, { recursive: true });
13819
- fs34.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
13827
+ fs35.mkdirSync(workflowDir, { recursive: true });
13828
+ fs35.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
13820
13829
  wrote.push(".github/workflows/kody.yml");
13821
13830
  }
13822
13831
  for (const exe of listImplementations()) {
@@ -13827,12 +13836,12 @@ function performInit(cwd, force) {
13827
13836
  continue;
13828
13837
  }
13829
13838
  if (profile.kind !== "scheduled" || !profile.schedule) continue;
13830
- const target = path32.join(workflowDir, `kody-${exe.name}.yml`);
13831
- if (fs34.existsSync(target) && !force) {
13839
+ const target = path33.join(workflowDir, `kody-${exe.name}.yml`);
13840
+ if (fs35.existsSync(target) && !force) {
13832
13841
  skipped.push(`.github/workflows/kody-${exe.name}.yml`);
13833
13842
  continue;
13834
13843
  }
13835
- fs34.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
13844
+ fs35.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
13836
13845
  wrote.push(`.github/workflows/kody-${exe.name}.yml`);
13837
13846
  }
13838
13847
  let labels;
@@ -13980,7 +13989,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
13980
13989
  });
13981
13990
 
13982
13991
  // src/scripts/loadAgentAdhoc.ts
13983
- import * as fs35 from "fs";
13992
+ import * as fs36 from "fs";
13984
13993
  function resolveMessage(messageArg) {
13985
13994
  const fromComment = readCommentBody();
13986
13995
  if (fromComment) return stripDirective(fromComment);
@@ -13988,9 +13997,9 @@ function resolveMessage(messageArg) {
13988
13997
  }
13989
13998
  function readCommentBody() {
13990
13999
  const eventPath = process.env.GITHUB_EVENT_PATH;
13991
- if (!eventPath || !fs35.existsSync(eventPath)) return "";
14000
+ if (!eventPath || !fs36.existsSync(eventPath)) return "";
13992
14001
  try {
13993
- const event = JSON.parse(fs35.readFileSync(eventPath, "utf-8"));
14002
+ const event = JSON.parse(fs36.readFileSync(eventPath, "utf-8"));
13994
14003
  return String(event.comment?.body ?? "");
13995
14004
  } catch {
13996
14005
  return "";
@@ -14044,10 +14053,10 @@ var init_loadAgentAdhoc = __esm({
14044
14053
  throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
14045
14054
  }
14046
14055
  const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
14047
- if (!fs35.existsSync(agentPath)) {
14056
+ if (!fs36.existsSync(agentPath)) {
14048
14057
  throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
14049
14058
  }
14050
- const { title, body } = parseAgentFile(fs35.readFileSync(agentPath, "utf-8"), agentSlug);
14059
+ const { title, body } = parseAgentFile(fs36.readFileSync(agentPath, "utf-8"), agentSlug);
14051
14060
  const message = resolveMessage(ctx.args.message);
14052
14061
  if (!message) {
14053
14062
  throw new Error(
@@ -14119,13 +14128,13 @@ var init_loadCapabilityState = __esm({
14119
14128
  function isCompanyIntentId(value) {
14120
14129
  return SLUG_RE.test(value);
14121
14130
  }
14122
- function normalizeCompanyIntent(path50, raw) {
14131
+ function normalizeCompanyIntent(path51, raw) {
14123
14132
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
14124
- throw new Error(`${path50}: intent must be JSON object`);
14133
+ throw new Error(`${path51}: intent must be JSON object`);
14125
14134
  }
14126
14135
  const input = raw;
14127
14136
  const id = stringField4(input.id);
14128
- if (!id || !isCompanyIntentId(id)) throw new Error(`${path50}: invalid intent id`);
14137
+ if (!id || !isCompanyIntentId(id)) throw new Error(`${path51}: invalid intent id`);
14129
14138
  const createdAt = stringField4(input.createdAt) || nowIso();
14130
14139
  const updatedAt = stringField4(input.updatedAt) || createdAt;
14131
14140
  const description = stringField4(input.description);
@@ -14416,8 +14425,8 @@ var init_loadIssueStateComment = __esm({
14416
14425
  });
14417
14426
 
14418
14427
  // src/scripts/loadJobFromFile.ts
14419
- import * as fs36 from "fs";
14420
- import * as path33 from "path";
14428
+ import * as fs37 from "fs";
14429
+ import * as path34 from "path";
14421
14430
  function parseJobFile(raw, slug) {
14422
14431
  let stripped = raw;
14423
14432
  if (stripped.startsWith("---\n")) {
@@ -14456,10 +14465,10 @@ var init_loadJobFromFile = __esm({
14456
14465
  if (!slug) {
14457
14466
  throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
14458
14467
  }
14459
- const capability = resolveCapabilityFolder(slug, path33.resolve(ctx.cwd, jobsDir));
14468
+ const capability = resolveCapabilityFolder(slug, path34.resolve(ctx.cwd, jobsDir));
14460
14469
  if (!capability) {
14461
14470
  throw new Error(
14462
- `loadJobFromFile: capability folder not found or incomplete: ${path33.resolve(ctx.cwd, jobsDir, slug)}`
14471
+ `loadJobFromFile: capability folder not found or incomplete: ${path34.resolve(ctx.cwd, jobsDir, slug)}`
14463
14472
  );
14464
14473
  }
14465
14474
  const { title, body, config } = capability;
@@ -14469,12 +14478,12 @@ var init_loadJobFromFile = __esm({
14469
14478
  let agentIdentity = "";
14470
14479
  if (agentSlug) {
14471
14480
  const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
14472
- if (!fs36.existsSync(agentPath)) {
14481
+ if (!fs37.existsSync(agentPath)) {
14473
14482
  throw new Error(
14474
14483
  `loadJobFromFile: capability '${slug}' declares agent '${agentSlug}' but ${agentPath} does not exist`
14475
14484
  );
14476
14485
  }
14477
- const agentRaw = fs36.readFileSync(agentPath, "utf-8");
14486
+ const agentRaw = fs37.readFileSync(agentPath, "utf-8");
14478
14487
  const parsed = parseJobFile(agentRaw, agentSlug);
14479
14488
  agentTitle = parsed.title;
14480
14489
  agentIdentity = parsed.body;
@@ -14554,13 +14563,13 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
14554
14563
  });
14555
14564
 
14556
14565
  // src/scripts/kodyVariables.ts
14557
- import * as fs37 from "fs";
14558
- import * as path34 from "path";
14566
+ import * as fs38 from "fs";
14567
+ import * as path35 from "path";
14559
14568
  function readKodyVariables(cwd) {
14560
- const full = path34.join(cwd, KODY_VARIABLES_REL_PATH);
14569
+ const full = path35.join(cwd, KODY_VARIABLES_REL_PATH);
14561
14570
  let raw;
14562
14571
  try {
14563
- raw = fs37.readFileSync(full, "utf-8");
14572
+ raw = fs38.readFileSync(full, "utf-8");
14564
14573
  } catch {
14565
14574
  return {};
14566
14575
  }
@@ -14723,8 +14732,8 @@ var init_runtimeSecrets = __esm({
14723
14732
  });
14724
14733
 
14725
14734
  // src/scripts/loadQaContext.ts
14726
- import * as fs38 from "fs";
14727
- import * as path35 from "path";
14735
+ import * as fs39 from "fs";
14736
+ import * as path36 from "path";
14728
14737
  function parseSlugList(value) {
14729
14738
  const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
14730
14739
  return inner.split(",").map(
@@ -14753,18 +14762,18 @@ function readProfileAgents(raw) {
14753
14762
  return { agent: agent ?? legacy ?? ["kody"], body };
14754
14763
  }
14755
14764
  function readProfile(cwd) {
14756
- const dir = path35.join(cwd, CONTEXT_DIR_REL_PATH);
14757
- if (!fs38.existsSync(dir)) return "";
14765
+ const dir = path36.join(cwd, CONTEXT_DIR_REL_PATH);
14766
+ if (!fs39.existsSync(dir)) return "";
14758
14767
  let entries;
14759
14768
  try {
14760
- entries = fs38.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
14769
+ entries = fs39.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
14761
14770
  } catch {
14762
14771
  return "";
14763
14772
  }
14764
14773
  const blocks = [];
14765
14774
  for (const file of entries) {
14766
14775
  try {
14767
- const raw = fs38.readFileSync(path35.join(dir, file), "utf-8");
14776
+ const raw = fs39.readFileSync(path36.join(dir, file), "utf-8");
14768
14777
  const { agent, body } = readProfileAgents(raw);
14769
14778
  if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
14770
14779
  blocks.push(`## ${file}
@@ -14813,8 +14822,8 @@ var init_loadQaContext = __esm({
14813
14822
  });
14814
14823
 
14815
14824
  // src/taskContext.ts
14816
- import * as fs39 from "fs";
14817
- import * as path36 from "path";
14825
+ import * as fs40 from "fs";
14826
+ import * as path37 from "path";
14818
14827
  function buildTaskContext(args) {
14819
14828
  return {
14820
14829
  schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
@@ -14830,9 +14839,9 @@ function buildTaskContext(args) {
14830
14839
  function persistTaskContext(cwd, ctx) {
14831
14840
  try {
14832
14841
  const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
14833
- fs39.mkdirSync(dir, { recursive: true });
14834
- const file = path36.join(dir, "task-context.json");
14835
- fs39.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
14842
+ fs40.mkdirSync(dir, { recursive: true });
14843
+ const file = path37.join(dir, "task-context.json");
14844
+ fs40.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
14836
14845
  `);
14837
14846
  return file;
14838
14847
  } catch (err) {
@@ -15259,19 +15268,19 @@ function parseAgencyModelProposal(raw) {
15259
15268
  function normalizeBundleFiles(bundle) {
15260
15269
  const seen = /* @__PURE__ */ new Set();
15261
15270
  return bundle.files.map((file, index) => {
15262
- const path50 = file.path.replace(/^\/+/, "");
15263
- const parts = path50.split("/");
15264
- if (!path50 || file.path.startsWith("/") || file.path.includes("\\") || parts.some((part) => !part || part === "." || part === "..")) {
15271
+ const path51 = file.path.replace(/^\/+/, "");
15272
+ const parts = path51.split("/");
15273
+ if (!path51 || file.path.startsWith("/") || file.path.includes("\\") || parts.some((part) => !part || part === "." || part === "..")) {
15265
15274
  throw new Error(`openAgencyModelReviewPr: files[${index}].path is unsafe`);
15266
15275
  }
15267
15276
  if (!/^(agents\/[^/]+\.md|capabilities\/[^/]+\/.+|goals\/(?:templates\/)?[^/]+\/.+|workflows\/[^/]+\.json)$/.test(
15268
- path50
15277
+ path51
15269
15278
  )) {
15270
15279
  throw new Error(`openAgencyModelReviewPr: files[${index}].path is not a supported definition path`);
15271
15280
  }
15272
- if (seen.has(path50)) throw new Error(`openAgencyModelReviewPr: duplicate generated file path: ${path50}`);
15273
- seen.add(path50);
15274
- return { path: path50, content: file.content.replace(/\r\n?/g, "\n") };
15281
+ if (seen.has(path51)) throw new Error(`openAgencyModelReviewPr: duplicate generated file path: ${path51}`);
15282
+ seen.add(path51);
15283
+ return { path: path51, content: file.content.replace(/\r\n?/g, "\n") };
15275
15284
  });
15276
15285
  }
15277
15286
  function buildProposalId(issueNumber, bundle, sourceLabel) {
@@ -16215,9 +16224,9 @@ var init_postResearchComment = __esm({
16215
16224
  });
16216
16225
 
16217
16226
  // src/scripts/prepareBrowserAuth.ts
16218
- import * as fs40 from "fs";
16227
+ import * as fs41 from "fs";
16219
16228
  import * as os6 from "os";
16220
- import * as path37 from "path";
16229
+ import * as path38 from "path";
16221
16230
  function appendAuthMessage(ctx, message) {
16222
16231
  const current = typeof ctx.data.qaAuthBlock === "string" ? ctx.data.qaAuthBlock.trim() : "";
16223
16232
  ctx.data.qaAuthBlock = current ? `${current}
@@ -16256,9 +16265,9 @@ async function githubJson(url, token) {
16256
16265
  return await response.json();
16257
16266
  }
16258
16267
  function writeKodyStorageState(input) {
16259
- const directory = fs40.mkdtempSync(path37.join(os6.tmpdir(), "kody-browser-auth-"));
16260
- fs40.chmodSync(directory, 448);
16261
- const file = path37.join(directory, "storage-state.json");
16268
+ const directory = fs41.mkdtempSync(path38.join(os6.tmpdir(), "kody-browser-auth-"));
16269
+ fs41.chmodSync(directory, 448);
16270
+ const file = path38.join(directory, "storage-state.json");
16262
16271
  const now = Date.now();
16263
16272
  const repoEntry = {
16264
16273
  repoUrl: input.repoUrl,
@@ -16288,7 +16297,7 @@ function writeKodyStorageState(input) {
16288
16297
  }
16289
16298
  ]
16290
16299
  };
16291
- fs40.writeFileSync(file, JSON.stringify(storageState), { mode: 384 });
16300
+ fs41.writeFileSync(file, JSON.stringify(storageState), { mode: 384 });
16292
16301
  return { directory, file };
16293
16302
  }
16294
16303
  function configurePlaywright(profile, storageStatePath) {
@@ -16370,7 +16379,7 @@ async function prepareMethod(ctx, profile, method) {
16370
16379
  configurePlaywright(profile, state.file);
16371
16380
  const authDirectory = state.directory;
16372
16381
  registerRuntimeCleanup(ctx, () => {
16373
- fs40.rmSync(authDirectory, { recursive: true, force: true });
16382
+ fs41.rmSync(authDirectory, { recursive: true, force: true });
16374
16383
  });
16375
16384
  appendAuthMessage(
16376
16385
  ctx,
@@ -16378,7 +16387,7 @@ async function prepareMethod(ctx, profile, method) {
16378
16387
  );
16379
16388
  return true;
16380
16389
  } catch (error) {
16381
- if (state) fs40.rmSync(state.directory, { recursive: true, force: true });
16390
+ if (state) fs41.rmSync(state.directory, { recursive: true, force: true });
16382
16391
  const reason = error instanceof Error ? error.message : String(error);
16383
16392
  appendAuthMessage(
16384
16393
  ctx,
@@ -16491,9 +16500,9 @@ function latestResult(raw, agentResult) {
16491
16500
  function recordField4(value) {
16492
16501
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
16493
16502
  }
16494
- function resolveDotted(root, path50) {
16495
- if (!path50) return void 0;
16496
- return path50.split(".").reduce((value, key) => recordField4(value)?.[key], root);
16503
+ function resolveDotted(root, path51) {
16504
+ if (!path51) return void 0;
16505
+ return path51.split(".").reduce((value, key) => recordField4(value)?.[key], root);
16497
16506
  }
16498
16507
  function stringValue4(value) {
16499
16508
  return typeof value === "string" && value.trim() ? value.trim() : null;
@@ -17444,10 +17453,10 @@ var init_previewBuildHelpers = __esm({
17444
17453
  });
17445
17454
 
17446
17455
  // src/scripts/previewBuildRun.ts
17447
- import { spawn as spawn4 } from "child_process";
17456
+ import { spawn as spawn5 } from "child_process";
17448
17457
  async function runCmd(cmd, args, opts = {}) {
17449
17458
  await new Promise((resolve16, reject) => {
17450
- const child = spawn4(cmd, args, {
17459
+ const child = spawn5(cmd, args, {
17451
17460
  cwd: opts.cwd,
17452
17461
  env: { ...process.env, ...opts.env ?? {} },
17453
17462
  stdio: opts.input ? ["pipe", "inherit", "inherit"] : "inherit"
@@ -17530,12 +17539,12 @@ fi
17530
17539
 
17531
17540
  // src/scripts/runPreviewBuild.ts
17532
17541
  import { copyFile, writeFile } from "fs/promises";
17533
- import * as path38 from "path";
17542
+ import * as path39 from "path";
17534
17543
  import { fileURLToPath } from "url";
17535
17544
  function bundledDockerfilePath(mode) {
17536
- const here = path38.dirname(fileURLToPath(import.meta.url));
17545
+ const here = path39.dirname(fileURLToPath(import.meta.url));
17537
17546
  const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
17538
- return path38.join(here, "preview-build-templates", file);
17547
+ return path39.join(here, "preview-build-templates", file);
17539
17548
  }
17540
17549
  function required(name) {
17541
17550
  const v = (process.env[name] ?? "").trim();
@@ -17782,10 +17791,10 @@ var init_runPreviewBuild = __esm({
17782
17791
  console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
17783
17792
  if (Object.keys(buildEnv).length > 0) {
17784
17793
  const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
17785
- await writeFile(path38.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
17794
+ await writeFile(path39.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
17786
17795
  `, "utf8");
17787
17796
  }
17788
- const consumerDockerfile = path38.join(ctx.cwd, "Dockerfile.preview");
17797
+ const consumerDockerfile = path39.join(ctx.cwd, "Dockerfile.preview");
17789
17798
  const { stat } = await import("fs/promises");
17790
17799
  let hasConsumerDockerfile = false;
17791
17800
  try {
@@ -17969,8 +17978,8 @@ var init_tickShellRunner = __esm({
17969
17978
  });
17970
17979
 
17971
17980
  // src/scripts/runScheduledImplementationTick.ts
17972
- import * as fs41 from "fs";
17973
- import * as path39 from "path";
17981
+ import * as fs42 from "fs";
17982
+ import * as path40 from "path";
17974
17983
  var runScheduledImplementationTick;
17975
17984
  var init_runScheduledImplementationTick = __esm({
17976
17985
  "src/scripts/runScheduledImplementationTick.ts"() {
@@ -17991,14 +18000,14 @@ var init_runScheduledImplementationTick = __esm({
17991
18000
  ctx.output.reason = `runScheduledImplementationTick: args.slug or ctx.args.${slugArg} must be non-empty capability slug`;
17992
18001
  return;
17993
18002
  }
17994
- const capability = resolveCapabilityFolder(slug, path39.resolve(ctx.cwd, jobsDir));
18003
+ const capability = resolveCapabilityFolder(slug, path40.resolve(ctx.cwd, jobsDir));
17995
18004
  if (!capability) {
17996
18005
  ctx.output.exitCode = 99;
17997
18006
  ctx.output.reason = `runScheduledImplementationTick: capability folder not found or incomplete: ${slug} (searched ${jobsDir} and company store)`;
17998
18007
  return;
17999
18008
  }
18000
- const shellPath = path39.join(profile.dir, shell);
18001
- if (!fs41.existsSync(shellPath)) {
18009
+ const shellPath = path40.join(profile.dir, shell);
18010
+ if (!fs42.existsSync(shellPath)) {
18002
18011
  ctx.output.exitCode = 99;
18003
18012
  ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
18004
18013
  return;
@@ -18029,8 +18038,8 @@ var init_runScheduledImplementationTick = __esm({
18029
18038
  });
18030
18039
 
18031
18040
  // src/scripts/runTickScript.ts
18032
- import * as fs42 from "fs";
18033
- import * as path40 from "path";
18041
+ import * as fs43 from "fs";
18042
+ import * as path41 from "path";
18034
18043
  var runTickScript;
18035
18044
  var init_runTickScript = __esm({
18036
18045
  "src/scripts/runTickScript.ts"() {
@@ -18050,10 +18059,10 @@ var init_runTickScript = __esm({
18050
18059
  ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
18051
18060
  return;
18052
18061
  }
18053
- const capability = readCapabilityFolder(path40.resolve(ctx.cwd, jobsDir), slug);
18062
+ const capability = readCapabilityFolder(path41.resolve(ctx.cwd, jobsDir), slug);
18054
18063
  if (!capability) {
18055
18064
  ctx.output.exitCode = 99;
18056
- ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path40.resolve(ctx.cwd, jobsDir, slug)}`;
18065
+ ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path41.resolve(ctx.cwd, jobsDir, slug)}`;
18057
18066
  return;
18058
18067
  }
18059
18068
  const tickScript = capability.config.tickScript;
@@ -18062,8 +18071,8 @@ var init_runTickScript = __esm({
18062
18071
  ctx.output.reason = `runTickScript: capability ${slug} has no \`tickScript\` in profile.json \u2014 route via capability-tick instead`;
18063
18072
  return;
18064
18073
  }
18065
- const scriptPath = path40.isAbsolute(tickScript) ? tickScript : path40.join(ctx.cwd, tickScript);
18066
- if (!fs42.existsSync(scriptPath)) {
18074
+ const scriptPath = path41.isAbsolute(tickScript) ? tickScript : path41.join(ctx.cwd, tickScript);
18075
+ if (!fs43.existsSync(scriptPath)) {
18067
18076
  ctx.output.exitCode = 99;
18068
18077
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
18069
18078
  return;
@@ -18345,7 +18354,7 @@ var init_syncFlow = __esm({
18345
18354
  });
18346
18355
 
18347
18356
  // src/scripts/validateAgencyModelProposal.ts
18348
- import * as path41 from "path";
18357
+ import * as path42 from "path";
18349
18358
  function validateModelBundle(bundle, expectedKind, options = {}) {
18350
18359
  const failures = [];
18351
18360
  validateOneModel(bundle.model, bundle.files, "model", true, failures, expectedKind, options);
@@ -18671,7 +18680,7 @@ var init_validateAgencyModelProposal = __esm({
18671
18680
  const bundle = parseAgencyModelProposal(raw);
18672
18681
  const expectedKind = readExpectedModelKind(args);
18673
18682
  const failures = validateModelBundle(bundle, expectedKind, {
18674
- capabilityRoot: path41.join(ctx.cwd, ".kody", "capabilities")
18683
+ capabilityRoot: path42.join(ctx.cwd, ".kody", "capabilities")
18675
18684
  });
18676
18685
  if (failures.length > 0) {
18677
18686
  throw new Error(`validateAgencyModelProposal: ${failures.join("; ")}`);
@@ -18716,7 +18725,7 @@ var init_verify2 = __esm({
18716
18725
  });
18717
18726
 
18718
18727
  // src/scripts/verifyReproFails.ts
18719
- import { spawn as spawn5 } from "child_process";
18728
+ import { spawn as spawn6 } from "child_process";
18720
18729
  function composeTestCommand(baseCmd, testPath) {
18721
18730
  const trimmed = baseCmd.trim();
18722
18731
  const lower = trimmed.toLowerCase();
@@ -18735,7 +18744,7 @@ function stripAnsi2(s) {
18735
18744
  }
18736
18745
  function runCommand2(command, cwd) {
18737
18746
  return new Promise((resolve16) => {
18738
- const child = spawn5(command, {
18747
+ const child = spawn6(command, {
18739
18748
  cwd,
18740
18749
  shell: true,
18741
18750
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" },
@@ -19065,9 +19074,9 @@ var init_waitForCi = __esm({
19065
19074
  });
19066
19075
 
19067
19076
  // src/scripts/warmupMcp.ts
19068
- import { spawn as spawn6 } from "child_process";
19077
+ import { spawn as spawn7 } from "child_process";
19069
19078
  async function warmupOne(command, args, env) {
19070
- const child = spawn6(command, args, {
19079
+ const child = spawn7(command, args, {
19071
19080
  stdio: ["pipe", "pipe", "pipe"],
19072
19081
  env: env ? { ...process.env, ...env } : process.env
19073
19082
  });
@@ -19222,7 +19231,7 @@ var init_warmupMcp = __esm({
19222
19231
  });
19223
19232
 
19224
19233
  // src/scripts/writeAgentRunSummary.ts
19225
- import * as fs43 from "fs";
19234
+ import * as fs44 from "fs";
19226
19235
  var writeAgentRunSummary;
19227
19236
  var init_writeAgentRunSummary = __esm({
19228
19237
  "src/scripts/writeAgentRunSummary.ts"() {
@@ -19248,7 +19257,7 @@ var init_writeAgentRunSummary = __esm({
19248
19257
  if (reason) lines.push(`- **Reason:** ${reason}`);
19249
19258
  lines.push("");
19250
19259
  try {
19251
- fs43.appendFileSync(summaryPath, `${lines.join("\n")}
19260
+ fs44.appendFileSync(summaryPath, `${lines.join("\n")}
19252
19261
  `);
19253
19262
  } catch {
19254
19263
  }
@@ -19574,17 +19583,17 @@ var init_scripts = __esm({
19574
19583
  });
19575
19584
 
19576
19585
  // src/stateWorkspace.ts
19577
- import * as fs44 from "fs";
19578
- import * as path42 from "path";
19586
+ import * as fs45 from "fs";
19587
+ import * as path43 from "path";
19579
19588
  function tenantId(config) {
19580
19589
  const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
19581
19590
  const repo = config.github?.repo?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim();
19582
19591
  return owner && repo ? `${owner}/${repo}` : null;
19583
19592
  }
19584
19593
  function writeRuntimeFile(cwd, relativePath, content) {
19585
- const target = path42.join(cwd, RUNTIME_ROOT, relativePath);
19586
- fs44.mkdirSync(path42.dirname(target), { recursive: true });
19587
- fs44.writeFileSync(target, content, "utf8");
19594
+ const target = path43.join(cwd, RUNTIME_ROOT, relativePath);
19595
+ fs45.mkdirSync(path43.dirname(target), { recursive: true });
19596
+ fs45.writeFileSync(target, content, "utf8");
19588
19597
  }
19589
19598
  function record(value) {
19590
19599
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -19649,11 +19658,11 @@ async function hydrateStateWorkspace(config, cwd, backendOverride) {
19649
19658
  throw new Error("Convex backend is required for runtime workspace documents");
19650
19659
  return;
19651
19660
  }
19652
- const key = `${path42.resolve(cwd)}|${tenant}`;
19661
+ const key = `${path43.resolve(cwd)}|${tenant}`;
19653
19662
  if (hydratedWorkspaces.has(key)) return;
19654
19663
  const backend = backendOverride ?? createStateBackendFromEnv();
19655
- const root = path42.join(cwd, RUNTIME_ROOT);
19656
- fs44.rmSync(root, { recursive: true, force: true });
19664
+ const root = path43.join(cwd, RUNTIME_ROOT);
19665
+ fs45.rmSync(root, { recursive: true, force: true });
19657
19666
  await Promise.all([
19658
19667
  hydratePrefix(backend, tenant, cwd, "context:"),
19659
19668
  hydratePrefix(backend, tenant, cwd, "memory:"),
@@ -19669,7 +19678,7 @@ var init_stateWorkspace = __esm({
19669
19678
  "src/stateWorkspace.ts"() {
19670
19679
  "use strict";
19671
19680
  init_state_backend();
19672
- RUNTIME_ROOT = path42.join(".kody-engine", "runtime");
19681
+ RUNTIME_ROOT = path43.join(".kody-engine", "runtime");
19673
19682
  hydratedWorkspaces = /* @__PURE__ */ new Set();
19674
19683
  }
19675
19684
  });
@@ -19739,10 +19748,10 @@ var init_tools = __esm({
19739
19748
  });
19740
19749
 
19741
19750
  // src/executor.ts
19742
- import { spawn as spawn7 } from "child_process";
19743
- import * as fs45 from "fs";
19751
+ import { spawn as spawn8 } from "child_process";
19752
+ import * as fs46 from "fs";
19744
19753
  import * as os7 from "os";
19745
- import * as path43 from "path";
19754
+ import * as path44 from "path";
19746
19755
  function isMutatingPostflight(scriptName) {
19747
19756
  return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
19748
19757
  }
@@ -19970,7 +19979,7 @@ async function runImplementation(profileName, input) {
19970
19979
  const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
19971
19980
  const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
19972
19981
  const invokeAgent = async (prompt) => {
19973
- const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path43.isAbsolute(p) ? p : path43.resolve(profile.dir, p)).filter((p) => p.length > 0);
19982
+ const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path44.isAbsolute(p) ? p : path44.resolve(profile.dir, p)).filter((p) => p.length > 0);
19974
19983
  const syntheticPath = ctx.data.syntheticPluginPath;
19975
19984
  const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
19976
19985
  const agents = loadSubagents(profile);
@@ -20408,17 +20417,17 @@ function clearStampedLifecycleLabels(profile, ctx) {
20408
20417
  function resolveProfilePath(profileName) {
20409
20418
  const found = resolveImplementation(profileName);
20410
20419
  if (found) return found;
20411
- const here = path43.dirname(new URL(import.meta.url).pathname);
20420
+ const here = path44.dirname(new URL(import.meta.url).pathname);
20412
20421
  const candidates = [
20413
- path43.join(here, "implementations", profileName, "profile.json"),
20422
+ path44.join(here, "implementations", profileName, "profile.json"),
20414
20423
  // same-dir sibling (dev)
20415
- path43.join(here, "..", "implementations", profileName, "profile.json"),
20424
+ path44.join(here, "..", "implementations", profileName, "profile.json"),
20416
20425
  // up one (prod: dist/bin → dist/implementations)
20417
- path43.join(here, "..", "src", "implementations", profileName, "profile.json")
20426
+ path44.join(here, "..", "src", "implementations", profileName, "profile.json")
20418
20427
  // fallback
20419
20428
  ];
20420
20429
  for (const c of candidates) {
20421
- if (fs45.existsSync(c)) return c;
20430
+ if (fs46.existsSync(c)) return c;
20422
20431
  }
20423
20432
  return candidates[0];
20424
20433
  }
@@ -20533,15 +20542,15 @@ function resolveShellTimeoutMs(entry) {
20533
20542
  }
20534
20543
  async function runShellEntry(entry, ctx, profile) {
20535
20544
  const shellName = entry.shell;
20536
- const shellPath = path43.join(profile.dir, shellName);
20537
- if (!fs45.existsSync(shellPath)) {
20545
+ const shellPath = path44.join(profile.dir, shellName);
20546
+ if (!fs46.existsSync(shellPath)) {
20538
20547
  ctx.skipAgent = true;
20539
20548
  ctx.output.exitCode = 99;
20540
20549
  ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
20541
20550
  return;
20542
20551
  }
20543
20552
  const positional = entry.with ? Object.values(entry.with).map((v) => String(v)) : [];
20544
- const outputFile = path43.join(
20553
+ const outputFile = path44.join(
20545
20554
  os7.tmpdir(),
20546
20555
  `kody-shell-output-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
20547
20556
  );
@@ -20554,7 +20563,7 @@ async function runShellEntry(entry, ctx, profile) {
20554
20563
  env[`KODY_CFG_${k}`] = v;
20555
20564
  }
20556
20565
  const timeoutMs = resolveShellTimeoutMs(entry);
20557
- const child = spawn7("bash", [shellPath, ...positional], {
20566
+ const child = spawn8("bash", [shellPath, ...positional], {
20558
20567
  cwd: ctx.cwd,
20559
20568
  env,
20560
20569
  stdio: ["pipe", "pipe", "pipe"],
@@ -20613,9 +20622,9 @@ async function runShellEntry(entry, ctx, profile) {
20613
20622
  }
20614
20623
  let sideChannelText = "";
20615
20624
  try {
20616
- if (fs45.existsSync(outputFile)) {
20617
- sideChannelText = fs45.readFileSync(outputFile, "utf-8");
20618
- fs45.rmSync(outputFile, { force: true });
20625
+ if (fs46.existsSync(outputFile)) {
20626
+ sideChannelText = fs46.readFileSync(outputFile, "utf-8");
20627
+ fs46.rmSync(outputFile, { force: true });
20619
20628
  }
20620
20629
  } catch {
20621
20630
  }
@@ -20785,7 +20794,7 @@ __export(job_exports, {
20785
20794
  stableJobKey: () => stableJobKey,
20786
20795
  validateJob: () => validateJob
20787
20796
  });
20788
- import * as path44 from "path";
20797
+ import * as path45 from "path";
20789
20798
  function newJobId(flavor) {
20790
20799
  localJobSeq += 1;
20791
20800
  const runId = process.env.GITHUB_RUN_ID;
@@ -21248,11 +21257,11 @@ function selectWorkflowTransition(step, data, counts) {
21248
21257
  }
21249
21258
  function workflowResultConditionPaths(transitions) {
21250
21259
  return transitions.flatMap(
21251
- (transition) => Object.keys(transition.when ?? {}).filter((path50) => path50.startsWith("result."))
21260
+ (transition) => Object.keys(transition.when ?? {}).filter((path51) => path51.startsWith("result."))
21252
21261
  );
21253
21262
  }
21254
21263
  function conditionMatches(condition, context) {
21255
- return Object.entries(condition).every(([path50, expected]) => valueMatches(resolveDottedPath2(context, path50), expected));
21264
+ return Object.entries(condition).every(([path51, expected]) => valueMatches(resolveDottedPath2(context, path51), expected));
21256
21265
  }
21257
21266
  function withWorkflowBoundaryEval(capability, result) {
21258
21267
  const capabilityKind = capability.config.capabilityKind;
@@ -21410,7 +21419,7 @@ function loadCapabilityContext(slug, cwd) {
21410
21419
  return resolveCapabilityFolder(slug, hydratedCapabilitiesRoot(cwd));
21411
21420
  }
21412
21421
  function hydratedCapabilitiesRoot(cwd) {
21413
- return path44.join(cwd, ".kody-engine", "definitions", "capabilities");
21422
+ return path45.join(cwd, ".kody-engine", "definitions", "capabilities");
21414
21423
  }
21415
21424
  function loadWorkflowContext(slug, base) {
21416
21425
  if (!slug || !base.config || !isWorkflowDefinitionId(slug)) return null;
@@ -21573,7 +21582,7 @@ function translateOpenAISseToBrain(opts) {
21573
21582
 
21574
21583
  // src/servers/brain-serve.ts
21575
21584
  import { createServer as createServer2 } from "http";
21576
- import * as path47 from "path";
21585
+ import * as path48 from "path";
21577
21586
 
21578
21587
  // src/chat/loop.ts
21579
21588
  init_agent();
@@ -21581,8 +21590,8 @@ init_agents();
21581
21590
  init_config();
21582
21591
  init_registry();
21583
21592
  init_task_artifacts();
21584
- import * as fs14 from "fs";
21585
- import * as path15 from "path";
21593
+ import * as fs15 from "fs";
21594
+ import * as path16 from "path";
21586
21595
 
21587
21596
  // src/chat/attachments.ts
21588
21597
  init_runtimePaths();
@@ -21639,12 +21648,293 @@ function prepareAttachments(turns, cwd, sessionId) {
21639
21648
  return { turns: rewritten, imagePaths };
21640
21649
  }
21641
21650
 
21642
- // src/chat/events.ts
21651
+ // src/chat/codex-app-server.ts
21652
+ import { spawn as spawn3 } from "child_process";
21643
21653
  import * as fs12 from "fs";
21644
21654
  import * as path13 from "path";
21655
+ import { createInterface } from "readline";
21656
+ function codexThreadStartParams(args) {
21657
+ return {
21658
+ cwd: args.cwd,
21659
+ developerInstructions: args.developerInstructions
21660
+ };
21661
+ }
21662
+ function codexTurnStartParams(args) {
21663
+ return {
21664
+ threadId: args.threadId,
21665
+ input: [{ type: "text", text: args.message }]
21666
+ };
21667
+ }
21668
+ function translateCodexNotification(notification, chatId) {
21669
+ const params = notification.params ?? {};
21670
+ if (notification.method === "item/agentMessage/delta") {
21671
+ const delta = params.delta;
21672
+ return typeof delta === "string" && delta.length > 0 ? [{ type: "text", text: delta, chatId }] : [];
21673
+ }
21674
+ if (notification.method === "turn/completed") {
21675
+ return [{ type: "done", chatId }];
21676
+ }
21677
+ if (notification.method === "error") {
21678
+ const message = params.message;
21679
+ return [
21680
+ {
21681
+ type: "error",
21682
+ error: typeof message === "string" ? message : "Codex app-server error",
21683
+ chatId
21684
+ }
21685
+ ];
21686
+ }
21687
+ if (notification.method === "item/started") {
21688
+ const item = params.item;
21689
+ if (!item || typeof item !== "object") return [];
21690
+ const record2 = item;
21691
+ return [
21692
+ {
21693
+ type: "tool_use",
21694
+ name: typeof record2.type === "string" ? record2.type : "tool",
21695
+ input: record2,
21696
+ chatId
21697
+ }
21698
+ ];
21699
+ }
21700
+ return [];
21701
+ }
21702
+ var CodexAppServerClient = class {
21703
+ process;
21704
+ initialized = false;
21705
+ constructor(options) {
21706
+ const child = (options.spawnImpl ?? spawn3)("codex", ["app-server", "--stdio"], {
21707
+ cwd: options.cwd,
21708
+ stdio: ["pipe", "pipe", "pipe"]
21709
+ });
21710
+ this.process = {
21711
+ child,
21712
+ nextId: 1,
21713
+ pending: /* @__PURE__ */ new Map(),
21714
+ turnWaiters: /* @__PURE__ */ new Map()
21715
+ };
21716
+ const lines = createInterface({ input: child.stdout });
21717
+ lines.on("line", (line) => this.handleLine(line));
21718
+ child.on("error", (error) => this.fail(error));
21719
+ child.on("exit", (code, signal) => {
21720
+ this.fail(new Error(`codex app-server exited (${code ?? `signal ${signal}`})`));
21721
+ });
21722
+ }
21723
+ async startThread(args) {
21724
+ await this.ensureInitialized();
21725
+ const result = await this.request("thread/start", codexThreadStartParams(args));
21726
+ const thread = result.thread;
21727
+ if (!thread || typeof thread !== "object") {
21728
+ throw new Error("Codex app-server returned no thread");
21729
+ }
21730
+ const id = thread.id;
21731
+ if (typeof id !== "string" || !id) throw new Error("Codex app-server returned an invalid thread id");
21732
+ return id;
21733
+ }
21734
+ async resumeThread(threadId) {
21735
+ await this.ensureInitialized();
21736
+ await this.request("thread/resume", { threadId });
21737
+ }
21738
+ async runTurn(args) {
21739
+ await new Promise((resolve16, reject) => {
21740
+ this.process.turnWaiters.set(args.threadId, {
21741
+ resolve: resolve16,
21742
+ reject,
21743
+ onNotification: args.onNotification,
21744
+ queue: Promise.resolve()
21745
+ });
21746
+ void this.request("turn/start", codexTurnStartParams(args)).catch((error) => {
21747
+ this.process.turnWaiters.delete(args.threadId);
21748
+ reject(error);
21749
+ });
21750
+ });
21751
+ }
21752
+ close() {
21753
+ this.process.child.kill();
21754
+ this.fail(new Error("Codex app-server client closed"));
21755
+ }
21756
+ request(method, params) {
21757
+ const id = this.process.nextId++;
21758
+ return new Promise((resolve16, reject) => {
21759
+ this.process.pending.set(id, { resolve: resolve16, reject });
21760
+ this.process.child.stdin.write(`${JSON.stringify({ method, id, params })}
21761
+ `);
21762
+ });
21763
+ }
21764
+ notify(method, params) {
21765
+ this.process.child.stdin.write(`${JSON.stringify({ method, params })}
21766
+ `);
21767
+ }
21768
+ async ensureInitialized() {
21769
+ if (this.initialized) return;
21770
+ await this.request("initialize", {
21771
+ clientInfo: { name: "kody-brain", version: "0.1.0" }
21772
+ });
21773
+ this.notify("initialized", {});
21774
+ this.initialized = true;
21775
+ }
21776
+ handleLine(line) {
21777
+ let message;
21778
+ try {
21779
+ message = JSON.parse(line);
21780
+ } catch {
21781
+ return;
21782
+ }
21783
+ if (typeof message.id === "number") {
21784
+ const pending = this.process.pending.get(message.id);
21785
+ if (!pending) return;
21786
+ this.process.pending.delete(message.id);
21787
+ if (message.error && typeof message.error === "object") {
21788
+ const error = message.error;
21789
+ pending.reject(new Error(typeof error.message === "string" ? error.message : "Codex request failed"));
21790
+ } else {
21791
+ pending.resolve(message.result ?? {});
21792
+ }
21793
+ return;
21794
+ }
21795
+ if (typeof message.method !== "string") return;
21796
+ const notification = {
21797
+ method: message.method,
21798
+ params: typeof message.params === "object" && message.params !== null ? message.params : {}
21799
+ };
21800
+ const threadId = notification.params?.threadId;
21801
+ if (typeof threadId !== "string") return;
21802
+ const waiter = this.process.turnWaiters.get(threadId);
21803
+ if (!waiter) return;
21804
+ waiter.queue = waiter.queue.then(() => waiter.onNotification(notification));
21805
+ if (notification.method === "turn/completed" || notification.method === "error") {
21806
+ this.process.turnWaiters.delete(threadId);
21807
+ void waiter.queue.then(() => {
21808
+ if (notification.method === "error") {
21809
+ waiter.reject(new Error(String(notification.params?.message ?? "Codex turn failed")));
21810
+ } else {
21811
+ waiter.resolve();
21812
+ }
21813
+ }, waiter.reject);
21814
+ }
21815
+ }
21816
+ fail(error) {
21817
+ for (const pending of this.process.pending.values()) pending.reject(error);
21818
+ this.process.pending.clear();
21819
+ for (const waiter of this.process.turnWaiters.values()) waiter.reject(error);
21820
+ this.process.turnWaiters.clear();
21821
+ }
21822
+ };
21823
+ var clients = /* @__PURE__ */ new Map();
21824
+ function threadMapPath(cwd) {
21825
+ return path13.join(cwd, ".kody-engine", "runtime", "codex-threads.json");
21826
+ }
21827
+ function readThreadMap(cwd) {
21828
+ try {
21829
+ const value = JSON.parse(fs12.readFileSync(threadMapPath(cwd), "utf8"));
21830
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
21831
+ return Object.fromEntries(
21832
+ Object.entries(value).filter(
21833
+ (entry) => typeof entry[1] === "string"
21834
+ )
21835
+ );
21836
+ } catch {
21837
+ return {};
21838
+ }
21839
+ }
21840
+ function writeThreadMap(cwd, map) {
21841
+ const file = threadMapPath(cwd);
21842
+ fs12.mkdirSync(path13.dirname(file), { recursive: true });
21843
+ fs12.writeFileSync(file, `${JSON.stringify(map, null, 2)}
21844
+ `);
21845
+ }
21846
+ async function runCodexChatTurn(args) {
21847
+ const { opts, turns, systemPrompt, store } = args;
21848
+ const last = turns.at(-1);
21849
+ if (!last || last.role !== "user") {
21850
+ const error = "last turn is not a user message";
21851
+ await opts.sink.emit({
21852
+ event: "chat.error",
21853
+ payload: { error },
21854
+ runId: opts.sessionId,
21855
+ emittedAt: (/* @__PURE__ */ new Date()).toISOString()
21856
+ });
21857
+ return { exitCode: 64, error };
21858
+ }
21859
+ const client = clients.get(opts.cwd) ?? new CodexAppServerClient({ cwd: opts.cwd });
21860
+ clients.set(opts.cwd, client);
21861
+ const map = readThreadMap(opts.cwd);
21862
+ let threadId = map[opts.sessionId];
21863
+ if (threadId) {
21864
+ try {
21865
+ await client.resumeThread(threadId);
21866
+ } catch {
21867
+ threadId = void 0;
21868
+ }
21869
+ }
21870
+ threadId ??= await client.startThread({ cwd: opts.cwd, developerInstructions: systemPrompt });
21871
+ if (!map[opts.sessionId]) {
21872
+ map[opts.sessionId] = threadId;
21873
+ writeThreadMap(opts.cwd, map);
21874
+ }
21875
+ const replyParts = [];
21876
+ try {
21877
+ await client.runTurn({
21878
+ threadId,
21879
+ message: last.content,
21880
+ onNotification: async (notification) => {
21881
+ for (const event of translateCodexNotification(notification, opts.sessionId)) {
21882
+ if (event.type === "text" && event.text) {
21883
+ replyParts.push(event.text);
21884
+ await opts.sink.emit({
21885
+ event: "chat.message",
21886
+ payload: { sessionId: opts.sessionId, role: "assistant", content: event.text },
21887
+ runId: opts.sessionId,
21888
+ emittedAt: (/* @__PURE__ */ new Date()).toISOString()
21889
+ });
21890
+ } else if (event.type === "tool_use") {
21891
+ await opts.sink.emit({
21892
+ event: "chat.tool",
21893
+ payload: { phase: "use", name: event.name, input: event.input },
21894
+ runId: opts.sessionId,
21895
+ emittedAt: (/* @__PURE__ */ new Date()).toISOString()
21896
+ });
21897
+ }
21898
+ }
21899
+ }
21900
+ });
21901
+ } catch (error) {
21902
+ const message = error instanceof Error ? error.message : String(error);
21903
+ await opts.sink.emit({
21904
+ event: "chat.error",
21905
+ payload: { error: message },
21906
+ runId: opts.sessionId,
21907
+ emittedAt: (/* @__PURE__ */ new Date()).toISOString()
21908
+ });
21909
+ return { exitCode: 99, error: message };
21910
+ }
21911
+ const reply = replyParts.join("").trim();
21912
+ if (!reply) {
21913
+ const error = "Codex completed without producing a reply";
21914
+ await opts.sink.emit({
21915
+ event: "chat.error",
21916
+ payload: { error },
21917
+ runId: opts.sessionId,
21918
+ emittedAt: (/* @__PURE__ */ new Date()).toISOString()
21919
+ });
21920
+ return { exitCode: 99, error };
21921
+ }
21922
+ await store.appendTurn({ role: "assistant", content: reply, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
21923
+ await opts.sink.emit({
21924
+ event: "chat.done",
21925
+ payload: { sessionId: opts.sessionId },
21926
+ runId: opts.sessionId,
21927
+ emittedAt: (/* @__PURE__ */ new Date()).toISOString()
21928
+ });
21929
+ return { exitCode: 0, reply };
21930
+ }
21931
+
21932
+ // src/chat/events.ts
21933
+ import * as fs13 from "fs";
21934
+ import * as path14 from "path";
21645
21935
  import posixPath2 from "path/posix";
21646
21936
  function eventsFilePath(cwd, sessionId) {
21647
- return path13.join(cwd, ".kody-engine", "runtime", "events", `${sessionId}.jsonl`);
21937
+ return path14.join(cwd, ".kody-engine", "runtime", "events", `${sessionId}.jsonl`);
21648
21938
  }
21649
21939
  var FileSink = class {
21650
21940
  constructor(file) {
@@ -21652,8 +21942,8 @@ var FileSink = class {
21652
21942
  }
21653
21943
  file;
21654
21944
  async emit(event) {
21655
- fs12.mkdirSync(path13.dirname(this.file), { recursive: true });
21656
- fs12.appendFileSync(this.file, `${JSON.stringify(event)}
21945
+ fs13.mkdirSync(path14.dirname(this.file), { recursive: true });
21946
+ fs13.appendFileSync(this.file, `${JSON.stringify(event)}
21657
21947
  `);
21658
21948
  }
21659
21949
  };
@@ -21711,15 +22001,15 @@ init_convex_client();
21711
22001
  import { anyApi as anyApi2 } from "convex/server";
21712
22002
 
21713
22003
  // src/chat/session.ts
21714
- import * as fs13 from "fs";
21715
- import * as path14 from "path";
22004
+ import * as fs14 from "fs";
22005
+ import * as path15 from "path";
21716
22006
  import posixPath3 from "path/posix";
21717
22007
  function sessionFilePath(cwd, sessionId) {
21718
- return path14.join(cwd, ".kody-engine", "runtime", "sessions", `${sessionId}.jsonl`);
22008
+ return path15.join(cwd, ".kody-engine", "runtime", "sessions", `${sessionId}.jsonl`);
21719
22009
  }
21720
22010
  function readMeta(file) {
21721
- if (!fs13.existsSync(file)) return null;
21722
- const raw = fs13.readFileSync(file, "utf-8");
22011
+ if (!fs14.existsSync(file)) return null;
22012
+ const raw = fs14.readFileSync(file, "utf-8");
21723
22013
  const firstLine2 = raw.split("\n", 1)[0]?.trim();
21724
22014
  if (!firstLine2) return null;
21725
22015
  try {
@@ -21732,8 +22022,8 @@ function readMeta(file) {
21732
22022
  }
21733
22023
  }
21734
22024
  function readSession(file) {
21735
- if (!fs13.existsSync(file)) return [];
21736
- const raw = fs13.readFileSync(file, "utf-8").trim();
22025
+ if (!fs14.existsSync(file)) return [];
22026
+ const raw = fs14.readFileSync(file, "utf-8").trim();
21737
22027
  if (!raw) return [];
21738
22028
  const turns = [];
21739
22029
  for (const line of raw.split("\n")) {
@@ -21749,14 +22039,14 @@ function readSession(file) {
21749
22039
  return turns;
21750
22040
  }
21751
22041
  function appendTurn(file, turn) {
21752
- fs13.mkdirSync(path14.dirname(file), { recursive: true });
22042
+ fs14.mkdirSync(path15.dirname(file), { recursive: true });
21753
22043
  const line = JSON.stringify({
21754
22044
  role: turn.role,
21755
22045
  content: turn.content,
21756
22046
  timestamp: turn.timestamp,
21757
22047
  toolCalls: turn.toolCalls ?? []
21758
22048
  });
21759
- fs13.appendFileSync(file, `${line}
22049
+ fs14.appendFileSync(file, `${line}
21760
22050
  `);
21761
22051
  }
21762
22052
  function seedInitialMessage(file, message) {
@@ -21989,7 +22279,7 @@ function buildImplementationCatalog() {
21989
22279
  const entries = [];
21990
22280
  for (const { name, profilePath } of discovered) {
21991
22281
  try {
21992
- const raw = JSON.parse(fs14.readFileSync(profilePath, "utf-8"));
22282
+ const raw = JSON.parse(fs15.readFileSync(profilePath, "utf-8"));
21993
22283
  const describe = typeof raw.describe === "string" ? raw.describe : "";
21994
22284
  const firstSentence = describe.split(/(?<=[.!?])\s+/, 1)[0] ?? "";
21995
22285
  entries.push({ name, describe: firstSentence.trim() });
@@ -22011,6 +22301,9 @@ function buildImplementationCatalog() {
22011
22301
  }
22012
22302
  return lines.join("\n");
22013
22303
  }
22304
+ function shouldWriteTaskArtifacts(driver) {
22305
+ return driver !== "codex-app-server";
22306
+ }
22014
22307
  async function runChatTurn(opts) {
22015
22308
  const store = opts.store ?? createSessionStore({ sessionId: opts.sessionId, sessionFile: opts.sessionFile });
22016
22309
  const turns = await store.readTurns();
@@ -22034,11 +22327,11 @@ async function runChatTurn(opts) {
22034
22327
  taskKey: `sessions/${opts.sessionId}`
22035
22328
  };
22036
22329
  initializeTaskArtifacts(taskArtifactsPaths, { taskType: "chat", target: opts.sessionId });
22037
- const artifactAddendum = taskArtifactsPromptAddendum({
22330
+ const artifactAddendum = shouldWriteTaskArtifacts(opts.driver) ? taskArtifactsPromptAddendum({
22038
22331
  taskId: taskArtifactsPaths.taskId,
22039
22332
  taskType: "chat",
22040
22333
  relDir: taskArtifactsPaths.relDir
22041
- });
22334
+ }) : null;
22042
22335
  const contextBlock = readContextBlock(opts.cwd);
22043
22336
  const memoryBlock = readMemoryIndexBlock(opts.cwd);
22044
22337
  const instructionsBlock = readInstructionsBlock(opts.cwd);
@@ -22067,6 +22360,14 @@ async function runChatTurn(opts) {
22067
22360
  artifactAddendum
22068
22361
  ].filter((s) => typeof s === "string" && s.length > 0).join("\n\n");
22069
22362
  const prompt = buildPrompt(promptTurns);
22363
+ if (opts.driver === "codex-app-server") {
22364
+ return runCodexChatTurn({
22365
+ opts,
22366
+ turns: promptTurns,
22367
+ systemPrompt,
22368
+ store
22369
+ });
22370
+ }
22070
22371
  if (opts.model.protocol === "openai" && opts.litellmUrl) {
22071
22372
  return runOpenAIChatTurn({
22072
22373
  opts,
@@ -22085,7 +22386,7 @@ async function runChatTurn(opts) {
22085
22386
  quiet: opts.quiet,
22086
22387
  additionalDirectories: [
22087
22388
  taskArtifactsPaths.absDir,
22088
- ...Array.from(new Set(imagePaths.map((p2) => path15.dirname(p2))))
22389
+ ...Array.from(new Set(imagePaths.map((p2) => path16.dirname(p2))))
22089
22390
  ],
22090
22391
  systemPromptAppend: systemPrompt,
22091
22392
  ...opts.reasoningEffort ? { reasoningEffort: opts.reasoningEffort } : {},
@@ -22268,10 +22569,10 @@ async function emit(sink, type, sessionId, suffix, payload) {
22268
22569
  var MEMORY_INDEX_REL = ".kody-engine/runtime/memory/INDEX.md";
22269
22570
  var MAX_INDEX_BYTES = 8e3;
22270
22571
  function readMemoryIndexBlock(cwd) {
22271
- const indexPath = path15.join(cwd, MEMORY_INDEX_REL);
22572
+ const indexPath = path16.join(cwd, MEMORY_INDEX_REL);
22272
22573
  let raw;
22273
22574
  try {
22274
- raw = fs14.readFileSync(indexPath, "utf-8");
22575
+ raw = fs15.readFileSync(indexPath, "utf-8");
22275
22576
  } catch {
22276
22577
  return "";
22277
22578
  }
@@ -22291,17 +22592,17 @@ _\u2026 (memory index truncated; use recall_search to read more)_` : trimmed;
22291
22592
  var CONTEXT_DIR_REL = ".kody-engine/runtime/context";
22292
22593
  var MAX_CONTEXT_BYTES = 12e3;
22293
22594
  function readContextBlock(cwd) {
22294
- const dir = path15.join(cwd, CONTEXT_DIR_REL);
22595
+ const dir = path16.join(cwd, CONTEXT_DIR_REL);
22295
22596
  let files;
22296
22597
  try {
22297
- files = fs14.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
22598
+ files = fs15.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
22298
22599
  } catch {
22299
22600
  return "";
22300
22601
  }
22301
22602
  const sections = [];
22302
22603
  for (const file of files) {
22303
22604
  try {
22304
- const content = fs14.readFileSync(path15.join(dir, file), "utf-8").trim();
22605
+ const content = fs15.readFileSync(path16.join(dir, file), "utf-8").trim();
22305
22606
  if (content) sections.push(`### ${file.replace(/\.md$/, "")}
22306
22607
 
22307
22608
  ${content}`);
@@ -22327,7 +22628,7 @@ var SYSTEM_PROMPT_OVERRIDE_REL = ".kody-engine/runtime/system-prompt.md";
22327
22628
  function readSystemPromptOverride(cwd) {
22328
22629
  let raw;
22329
22630
  try {
22330
- raw = fs14.readFileSync(path15.join(cwd, SYSTEM_PROMPT_OVERRIDE_REL), "utf-8");
22631
+ raw = fs15.readFileSync(path16.join(cwd, SYSTEM_PROMPT_OVERRIDE_REL), "utf-8");
22331
22632
  } catch {
22332
22633
  return null;
22333
22634
  }
@@ -22335,10 +22636,10 @@ function readSystemPromptOverride(cwd) {
22335
22636
  return trimmed.length > 0 ? trimmed : null;
22336
22637
  }
22337
22638
  function readInstructionsBlock(cwd) {
22338
- const instructionsPath = path15.join(cwd, INSTRUCTIONS_REL);
22639
+ const instructionsPath = path16.join(cwd, INSTRUCTIONS_REL);
22339
22640
  let raw;
22340
22641
  try {
22341
- raw = fs14.readFileSync(instructionsPath, "utf-8");
22642
+ raw = fs15.readFileSync(instructionsPath, "utf-8");
22342
22643
  } catch {
22343
22644
  return "";
22344
22645
  }
@@ -22356,13 +22657,28 @@ _\u2026 (instructions truncated)_` : trimmed;
22356
22657
  ].join("\n");
22357
22658
  }
22358
22659
 
22660
+ // src/chat/runtime-drivers.ts
22661
+ var RUNTIME_DRIVERS = {
22662
+ native: "native",
22663
+ "codex app-server": "codex-app-server",
22664
+ "codex-app-server": "codex-app-server"
22665
+ };
22666
+ function resolveBrainDriver(runtime) {
22667
+ const normalized = runtime.trim().toLowerCase();
22668
+ const driver = RUNTIME_DRIVERS[normalized];
22669
+ if (!driver) {
22670
+ throw new Error(`Unsupported Brain runtime: ${runtime}`);
22671
+ }
22672
+ return driver;
22673
+ }
22674
+
22359
22675
  // src/servers/brain-serve.ts
22360
22676
  init_config();
22361
22677
 
22362
22678
  // src/kody-cli.ts
22363
22679
  import { execFileSync as execFileSync24 } from "child_process";
22364
- import * as fs46 from "fs";
22365
- import * as path45 from "path";
22680
+ import * as fs47 from "fs";
22681
+ import * as path46 from "path";
22366
22682
 
22367
22683
  // src/app-auth.ts
22368
22684
  import { createSign } from "crypto";
@@ -22489,7 +22805,7 @@ init_config();
22489
22805
 
22490
22806
  // src/dispatch.ts
22491
22807
  init_config();
22492
- import * as fs15 from "fs";
22808
+ import * as fs16 from "fs";
22493
22809
 
22494
22810
  // src/cron-match.ts
22495
22811
  var FIELD_BOUNDS = [
@@ -22591,10 +22907,10 @@ function autoDispatch(opts) {
22591
22907
  }
22592
22908
  const eventName = process.env.GITHUB_EVENT_NAME;
22593
22909
  const eventPath = process.env.GITHUB_EVENT_PATH;
22594
- if (!eventName || !eventPath || !fs15.existsSync(eventPath)) return null;
22910
+ if (!eventName || !eventPath || !fs16.existsSync(eventPath)) return null;
22595
22911
  let event = {};
22596
22912
  try {
22597
- event = JSON.parse(fs15.readFileSync(eventPath, "utf-8"));
22913
+ event = JSON.parse(fs16.readFileSync(eventPath, "utf-8"));
22598
22914
  } catch {
22599
22915
  return null;
22600
22916
  }
@@ -22718,7 +23034,7 @@ function autoDispatchTyped(opts) {
22718
23034
  if (legacy) return { kind: "route", ...legacy };
22719
23035
  const eventName = process.env.GITHUB_EVENT_NAME;
22720
23036
  const eventPath = process.env.GITHUB_EVENT_PATH;
22721
- if (!eventName || !eventPath || !fs15.existsSync(eventPath)) {
23037
+ if (!eventName || !eventPath || !fs16.existsSync(eventPath)) {
22722
23038
  return { kind: "silent", reason: "no GHA event context" };
22723
23039
  }
22724
23040
  if (eventName !== "issue_comment") {
@@ -22726,7 +23042,7 @@ function autoDispatchTyped(opts) {
22726
23042
  }
22727
23043
  let event = {};
22728
23044
  try {
22729
- event = JSON.parse(fs15.readFileSync(eventPath, "utf-8"));
23045
+ event = JSON.parse(fs16.readFileSync(eventPath, "utf-8"));
22730
23046
  } catch {
22731
23047
  return { kind: "silent", reason: "GHA event payload unreadable" };
22732
23048
  }
@@ -22780,7 +23096,7 @@ function dispatchScheduledWatches(opts) {
22780
23096
  for (const exe of listImplementations()) {
22781
23097
  let raw;
22782
23098
  try {
22783
- raw = fs15.readFileSync(exe.profilePath, "utf-8");
23099
+ raw = fs16.readFileSync(exe.profilePath, "utf-8");
22784
23100
  } catch {
22785
23101
  continue;
22786
23102
  }
@@ -23164,9 +23480,9 @@ async function resolveAuthToken(env = process.env) {
23164
23480
  return void 0;
23165
23481
  }
23166
23482
  function detectPackageManager2(cwd) {
23167
- if (fs46.existsSync(path45.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
23168
- if (fs46.existsSync(path45.join(cwd, "yarn.lock"))) return "yarn";
23169
- if (fs46.existsSync(path45.join(cwd, "bun.lockb"))) return "bun";
23483
+ if (fs47.existsSync(path46.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
23484
+ if (fs47.existsSync(path46.join(cwd, "yarn.lock"))) return "yarn";
23485
+ if (fs47.existsSync(path46.join(cwd, "bun.lockb"))) return "bun";
23170
23486
  return "npm";
23171
23487
  }
23172
23488
  function shouldChainScheduledWatch(match) {
@@ -23259,8 +23575,8 @@ function postFailureTail(issueNumber, cwd, reason) {
23259
23575
  const logPath = lastRunLogPath(cwd);
23260
23576
  let tail = "";
23261
23577
  try {
23262
- if (fs46.existsSync(logPath)) {
23263
- const content = fs46.readFileSync(logPath, "utf-8");
23578
+ if (fs47.existsSync(logPath)) {
23579
+ const content = fs47.readFileSync(logPath, "utf-8");
23264
23580
  tail = content.slice(-3e3);
23265
23581
  }
23266
23582
  } catch {
@@ -23289,7 +23605,7 @@ async function runCi(argv) {
23289
23605
  return 0;
23290
23606
  }
23291
23607
  const args = parseCiArgs(argv);
23292
- const cwd = args.cwd ? path45.resolve(args.cwd) : process.cwd();
23608
+ const cwd = args.cwd ? path46.resolve(args.cwd) : process.cwd();
23293
23609
  try {
23294
23610
  const n = unpackAllSecrets();
23295
23611
  if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s) from ALL_SECRETS
@@ -23348,9 +23664,9 @@ async function runCi(argv) {
23348
23664
  forceRunCliArgs = { goal: envForceMessage };
23349
23665
  }
23350
23666
  }
23351
- if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs46.existsSync(dispatchEventPath)) {
23667
+ if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs47.existsSync(dispatchEventPath)) {
23352
23668
  try {
23353
- const evt = JSON.parse(fs46.readFileSync(dispatchEventPath, "utf-8"));
23669
+ const evt = JSON.parse(fs47.readFileSync(dispatchEventPath, "utf-8"));
23354
23670
  const inputs = objectValue2(evt.inputs);
23355
23671
  const issueInput = parseInt(String(inputs?.issue_number ?? ""), 10);
23356
23672
  const sessionInput = String(inputs?.sessionId ?? "");
@@ -23723,8 +24039,8 @@ init_repoWorkspace();
23723
24039
 
23724
24040
  // src/scripts/brainTurnLog.ts
23725
24041
  init_runtimePaths();
23726
- import * as fs47 from "fs";
23727
- import * as path46 from "path";
24042
+ import * as fs48 from "fs";
24043
+ import * as path47 from "path";
23728
24044
  import posixPath4 from "path/posix";
23729
24045
  var live = /* @__PURE__ */ new Map();
23730
24046
  function brainEventsFilePath(dir, chatId) {
@@ -23732,8 +24048,8 @@ function brainEventsFilePath(dir, chatId) {
23732
24048
  }
23733
24049
  function lastPersistedSeq(dir, chatId) {
23734
24050
  const p = brainEventsFilePath(dir, chatId);
23735
- if (!fs47.existsSync(p)) return 0;
23736
- const lines = fs47.readFileSync(p, "utf-8").split("\n").filter(Boolean);
24051
+ if (!fs48.existsSync(p)) return 0;
24052
+ const lines = fs48.readFileSync(p, "utf-8").split("\n").filter(Boolean);
23737
24053
  if (lines.length === 0) return 0;
23738
24054
  try {
23739
24055
  return JSON.parse(lines[lines.length - 1]).seq || 0;
@@ -23743,9 +24059,9 @@ function lastPersistedSeq(dir, chatId) {
23743
24059
  }
23744
24060
  function readSince(dir, chatId, since) {
23745
24061
  const p = brainEventsFilePath(dir, chatId);
23746
- if (!fs47.existsSync(p)) return [];
24062
+ if (!fs48.existsSync(p)) return [];
23747
24063
  const out = [];
23748
- for (const line of fs47.readFileSync(p, "utf-8").split("\n")) {
24064
+ for (const line of fs48.readFileSync(p, "utf-8").split("\n")) {
23749
24065
  if (!line) continue;
23750
24066
  try {
23751
24067
  const rec = JSON.parse(line);
@@ -23771,12 +24087,12 @@ function beginTurn(dir, chatId) {
23771
24087
  };
23772
24088
  live.set(chatId, state);
23773
24089
  const p = brainEventsFilePath(dir, chatId);
23774
- fs47.mkdirSync(path46.dirname(p), { recursive: true });
24090
+ fs48.mkdirSync(path47.dirname(p), { recursive: true });
23775
24091
  return (event) => {
23776
24092
  state.seq += 1;
23777
24093
  const rec = { seq: state.seq, turn, ts: Date.now(), event };
23778
24094
  try {
23779
- fs47.appendFileSync(p, `${JSON.stringify(rec)}
24095
+ fs48.appendFileSync(p, `${JSON.stringify(rec)}
23780
24096
  `);
23781
24097
  } catch (err) {
23782
24098
  process.stderr.write(
@@ -23815,7 +24131,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
23815
24131
  event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
23816
24132
  };
23817
24133
  try {
23818
- fs47.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
24134
+ fs48.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
23819
24135
  `);
23820
24136
  } catch {
23821
24137
  }
@@ -24012,9 +24328,14 @@ var BrokerSink = class {
24012
24328
  const be = translateChatEvent(event, this.chatId);
24013
24329
  if (!be) return;
24014
24330
  this.emitToLog(be);
24015
- if (this.tenantId) await createStateBackendFromEnv().appendChatEvent(this.tenantId, this.chatId, be);
24331
+ if (this.tenantId && hasStateBackendConfig()) {
24332
+ await createStateBackendFromEnv().appendChatEvent(this.tenantId, this.chatId, be);
24333
+ }
24016
24334
  }
24017
24335
  };
24336
+ function hasStateBackendConfig(env = process.env) {
24337
+ return Boolean(env.CONVEX_URL?.trim() && env.KODY_SERVICE_KEY?.trim());
24338
+ }
24018
24339
  var chatQueues = /* @__PURE__ */ new Map();
24019
24340
  function enqueue(chatId, fn) {
24020
24341
  const prev = chatQueues.get(chatId) ?? Promise.resolve();
@@ -24074,8 +24395,18 @@ async function handleChatTurn(req, res, chatId, opts) {
24074
24395
  const dashboardUrl = strField(body, "dashboardUrl");
24075
24396
  const storeRepoUrl = strField(body, "storeRepoUrl");
24076
24397
  const storeRef = strField(body, "storeRef");
24398
+ const runtime = strField(body, "runtime");
24077
24399
  const allowCrossRepo = boolField(body, "allowCrossRepo");
24078
24400
  const agentIdentity = agentIdentityField(body);
24401
+ let turnDriver = opts.driver;
24402
+ if (runtime) {
24403
+ try {
24404
+ turnDriver = resolveBrainDriver(runtime);
24405
+ } catch (err) {
24406
+ sendJson(res, 400, { error: err instanceof Error ? err.message : String(err) });
24407
+ return;
24408
+ }
24409
+ }
24079
24410
  openSseStream(res, chatId);
24080
24411
  if (repo) {
24081
24412
  emitSse(res, {
@@ -24105,7 +24436,6 @@ async function handleChatTurn(req, res, chatId, opts) {
24105
24436
  }
24106
24437
  const stateToken = repoToken || envGithubToken();
24107
24438
  const sessionFile = sessionFilePath(agentCwd, chatId);
24108
- const brainEventsFile = brainEventsFilePath(agentCwd, chatId);
24109
24439
  const sessionStore = createSessionStore({
24110
24440
  sessionId: chatId,
24111
24441
  sessionFile,
@@ -24135,6 +24465,7 @@ async function handleChatTurn(req, res, chatId, opts) {
24135
24465
  ...allowCrossRepo ? { enableFetchRepoTool: true } : {},
24136
24466
  repoToken,
24137
24467
  ...agentIdentity ? { agentIdentity } : {},
24468
+ ...turnDriver ? { driver: turnDriver } : {},
24138
24469
  ...dashboardUrl && repo && stateToken ? {
24139
24470
  cmsDashboardUrl: dashboardUrl,
24140
24471
  cmsRepoSlug: repo,
@@ -24161,7 +24492,7 @@ async function handleChatTurn(req, res, chatId, opts) {
24161
24492
  function buildServer(opts) {
24162
24493
  const runTurn = opts.runTurn ?? runChatTurn;
24163
24494
  const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
24164
- const reposRoot = opts.reposRoot ?? path47.join(path47.dirname(path47.resolve(opts.cwd)), "repos");
24495
+ const reposRoot = opts.reposRoot ?? path48.join(path48.dirname(path48.resolve(opts.cwd)), "repos");
24165
24496
  return createServer2(async (req, res) => {
24166
24497
  if (!req.method || !req.url) {
24167
24498
  sendJson(res, 400, { error: "bad request" });
@@ -24189,7 +24520,8 @@ function buildServer(opts) {
24189
24520
  cloneRepo,
24190
24521
  model: opts.model,
24191
24522
  litellmUrl: opts.litellmUrl,
24192
- runTurn
24523
+ runTurn,
24524
+ driver: opts.driver
24193
24525
  });
24194
24526
  return;
24195
24527
  }
@@ -24216,11 +24548,12 @@ async function brainServe(opts) {
24216
24548
  }
24217
24549
  const apiKey = getApiKey();
24218
24550
  const port = Number(process.env.PORT ?? DEFAULT_PORT);
24551
+ const driver = process.env.BRAIN_DRIVER?.trim() === "codex-app-server" ? "codex-app-server" : "native";
24219
24552
  const model = parseModelRuntimeConfig(
24220
24553
  process.env.MODEL?.trim() || "claude/claude-haiku-4-5-20251001",
24221
24554
  process.env.KODY_MODEL_CONFIG
24222
24555
  );
24223
- const usesProxy = needsLitellmProxy(model);
24556
+ const usesProxy = driver === "native" && needsLitellmProxy(model);
24224
24557
  let handle = null;
24225
24558
  if (usesProxy) {
24226
24559
  process.stdout.write(`[brain-serve] starting LiteLLM proxy for ${model.provider}/${model.model}...
@@ -24236,7 +24569,8 @@ async function brainServe(opts) {
24236
24569
  // Per-repo clones live here; defaults to a `repos` sibling of cwd.
24237
24570
  reposRoot: process.env.BRAIN_REPOS_ROOT?.trim() || void 0,
24238
24571
  model,
24239
- litellmUrl
24572
+ litellmUrl,
24573
+ driver
24240
24574
  });
24241
24575
  await new Promise((resolve16) => {
24242
24576
  server.listen(port, "0.0.0.0", () => {
@@ -24761,8 +25095,8 @@ async function loadConfigSafe() {
24761
25095
  }
24762
25096
 
24763
25097
  // src/chat-cli.ts
24764
- import * as fs48 from "fs";
24765
- import * as path48 from "path";
25098
+ import * as fs49 from "fs";
25099
+ import * as path49 from "path";
24766
25100
 
24767
25101
  // src/chat/inbox.ts
24768
25102
  import { execFileSync as execFileSync25 } from "child_process";
@@ -25034,7 +25368,7 @@ async function runChat(argv) {
25034
25368
  ${CHAT_HELP}`);
25035
25369
  return 64;
25036
25370
  }
25037
- const cwd = args.cwd ? path48.resolve(args.cwd) : process.cwd();
25371
+ const cwd = args.cwd ? path49.resolve(args.cwd) : process.cwd();
25038
25372
  const sessionId = args.sessionId;
25039
25373
  const runRequest = readRunRequestFromEnv();
25040
25374
  if (runRequest && "request" in runRequest) {
@@ -25095,7 +25429,7 @@ ${CHAT_HELP}`);
25095
25429
  const sink = buildSink(cwd, sessionId, args.dashboardUrl);
25096
25430
  const meta = readMeta(sessionFile);
25097
25431
  process.stdout.write(
25098
- `\u2192 kody:chat: session file=${sessionFile} exists=${fs48.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
25432
+ `\u2192 kody:chat: session file=${sessionFile} exists=${fs49.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
25099
25433
  `
25100
25434
  );
25101
25435
  try {
@@ -25141,8 +25475,8 @@ init_config();
25141
25475
  // src/definition-hydration.ts
25142
25476
  init_state_backend();
25143
25477
  import { createHash as createHash5 } from "crypto";
25144
- import * as fs49 from "fs";
25145
- import * as path49 from "path";
25478
+ import * as fs50 from "fs";
25479
+ import * as path50 from "path";
25146
25480
  var SLUG_RE2 = /^[a-z0-9][a-z0-9_-]{0,63}$/;
25147
25481
  function assertSafeDefinitionPath(filePath) {
25148
25482
  const segments = filePath.split("/");
@@ -25176,32 +25510,32 @@ function writeDefinition(root, kind, definition) {
25176
25510
  if (kind === "agent") {
25177
25511
  const raw = bundle.files["agent.md"];
25178
25512
  if (typeof raw !== "string") throw new Error(`agent definition ${definition.slug} is missing agent.md`);
25179
- fs49.writeFileSync(path49.join(root, "agents", `${definition.slug}.md`), raw, "utf8");
25513
+ fs50.writeFileSync(path50.join(root, "agents", `${definition.slug}.md`), raw, "utf8");
25180
25514
  return;
25181
25515
  }
25182
25516
  if (kind === "goal") {
25183
- const goalRoot = path49.join(root, "goals", definition.slug);
25517
+ const goalRoot = path50.join(root, "goals", definition.slug);
25184
25518
  for (const [filePath, contents] of Object.entries(bundle.files)) {
25185
- const target = path49.join(goalRoot, filePath);
25186
- fs49.mkdirSync(path49.dirname(target), { recursive: true });
25187
- fs49.writeFileSync(target, contents, "utf8");
25519
+ const target = path50.join(goalRoot, filePath);
25520
+ fs50.mkdirSync(path50.dirname(target), { recursive: true });
25521
+ fs50.writeFileSync(target, contents, "utf8");
25188
25522
  }
25189
25523
  return;
25190
25524
  }
25191
- const capabilityRoot = path49.join(root, "capabilities", definition.slug);
25525
+ const capabilityRoot = path50.join(root, "capabilities", definition.slug);
25192
25526
  for (const [filePath, contents] of Object.entries(bundle.files)) {
25193
- const target = path49.join(capabilityRoot, filePath);
25194
- fs49.mkdirSync(path49.dirname(target), { recursive: true });
25195
- fs49.writeFileSync(target, contents, "utf8");
25527
+ const target = path50.join(capabilityRoot, filePath);
25528
+ fs50.mkdirSync(path50.dirname(target), { recursive: true });
25529
+ fs50.writeFileSync(target, contents, "utf8");
25196
25530
  }
25197
25531
  }
25198
25532
  async function hydrateDefinitions(options) {
25199
- const root = path49.join(options.cwd, ".kody-engine", "definitions");
25533
+ const root = path50.join(options.cwd, ".kody-engine", "definitions");
25200
25534
  const staging = `${root}.tmp-${process.pid}-${Date.now()}`;
25201
- fs49.rmSync(staging, { recursive: true, force: true });
25202
- fs49.mkdirSync(path49.join(staging, "agents"), { recursive: true });
25203
- fs49.mkdirSync(path49.join(staging, "capabilities"), { recursive: true });
25204
- fs49.mkdirSync(path49.join(staging, "goals"), { recursive: true });
25535
+ fs50.rmSync(staging, { recursive: true, force: true });
25536
+ fs50.mkdirSync(path50.join(staging, "agents"), { recursive: true });
25537
+ fs50.mkdirSync(path50.join(staging, "capabilities"), { recursive: true });
25538
+ fs50.mkdirSync(path50.join(staging, "goals"), { recursive: true });
25205
25539
  try {
25206
25540
  const [capabilities, agents, goals] = await Promise.all([
25207
25541
  options.backend.listDefinitions(options.tenantId, "capability"),
@@ -25227,13 +25561,13 @@ async function hydrateDefinitions(options) {
25227
25561
  hydratedAt: (/* @__PURE__ */ new Date()).toISOString(),
25228
25562
  versions: Object.fromEntries(Object.entries(versions).sort(([left], [right]) => left.localeCompare(right)))
25229
25563
  };
25230
- fs49.writeFileSync(path49.join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
25564
+ fs50.writeFileSync(path50.join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
25231
25565
  `, "utf8");
25232
- fs49.rmSync(root, { recursive: true, force: true });
25233
- fs49.renameSync(staging, root);
25566
+ fs50.rmSync(root, { recursive: true, force: true });
25567
+ fs50.renameSync(staging, root);
25234
25568
  return { root, tenantId: options.tenantId, versions: manifest.versions };
25235
25569
  } catch (error) {
25236
- fs49.rmSync(staging, { recursive: true, force: true });
25570
+ fs50.rmSync(staging, { recursive: true, force: true });
25237
25571
  throw error;
25238
25572
  }
25239
25573
  }
@@ -25327,8 +25661,8 @@ var FlyClient = class {
25327
25661
  get fetch() {
25328
25662
  return this.opts.fetchImpl ?? fetch;
25329
25663
  }
25330
- async call(path50, init = {}) {
25331
- const res = await this.fetch(`${FLY_API_BASE}${path50}`, {
25664
+ async call(path51, init = {}) {
25665
+ const res = await this.fetch(`${FLY_API_BASE}${path51}`, {
25332
25666
  method: init.method ?? "GET",
25333
25667
  headers: {
25334
25668
  Authorization: `Bearer ${this.opts.token}`,
@@ -25339,7 +25673,7 @@ var FlyClient = class {
25339
25673
  if (res.status === 404 && init.allow404) return null;
25340
25674
  if (!res.ok) {
25341
25675
  const text2 = await res.text().catch(() => "");
25342
- throw new Error(`Fly API ${res.status} on ${path50}: ${text2.slice(0, 200) || res.statusText}`);
25676
+ throw new Error(`Fly API ${res.status} on ${path51}: ${text2.slice(0, 200) || res.statusText}`);
25343
25677
  }
25344
25678
  if (res.status === 204) return null;
25345
25679
  const raw = await res.text();
@@ -26091,8 +26425,8 @@ async function poolServe() {
26091
26425
  }
26092
26426
 
26093
26427
  // src/servers/runner-serve.ts
26094
- import { spawn as spawn8 } from "child_process";
26095
- import * as fs50 from "fs";
26428
+ import { spawn as spawn9 } from "child_process";
26429
+ import * as fs51 from "fs";
26096
26430
  import { createServer as createServer6 } from "http";
26097
26431
  var DEFAULT_PORT2 = 8080;
26098
26432
  var DEFAULT_WORKDIR = "/workspace/repo";
@@ -26227,8 +26561,8 @@ async function defaultRunJob(job) {
26227
26561
  const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
26228
26562
  const branch = job.ref ?? "main";
26229
26563
  const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
26230
- fs50.rmSync(workdir, { recursive: true, force: true });
26231
- fs50.mkdirSync(workdir, { recursive: true });
26564
+ fs51.rmSync(workdir, { recursive: true, force: true });
26565
+ fs51.mkdirSync(workdir, { recursive: true });
26232
26566
  const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
26233
26567
  const target = job.runRequest.target;
26234
26568
  const interactive = target.type === "chat";
@@ -26258,7 +26592,7 @@ async function defaultRunJob(job) {
26258
26592
  ...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
26259
26593
  };
26260
26594
  const run = (cmd, args, cwd) => new Promise((resolve16) => {
26261
- const child = spawn8(cmd, args, { stdio: "inherit", env: childEnv, cwd });
26595
+ const child = spawn9(cmd, args, { stdio: "inherit", env: childEnv, cwd });
26262
26596
  child.on("exit", (code) => resolve16(code ?? 0));
26263
26597
  child.on("error", (err) => {
26264
26598
  process.stderr.write(`[runner-serve] ${cmd} failed: ${err.message}
@@ -26361,7 +26695,7 @@ async function runnerServe() {
26361
26695
  // src/servers/serve.ts
26362
26696
  init_config();
26363
26697
  init_litellm();
26364
- import { spawn as spawn9 } from "child_process";
26698
+ import { spawn as spawn10 } from "child_process";
26365
26699
  function parseTarget2(positional) {
26366
26700
  if (!Array.isArray(positional) || positional.length === 0) return "none";
26367
26701
  const first = String(positional[0]).toLowerCase();
@@ -26411,7 +26745,7 @@ async function serve(opts) {
26411
26745
  if (usesProxy) process.stdout.write(` ANTHROPIC_BASE_URL=${url}
26412
26746
  `);
26413
26747
  const args = ["--dangerously-skip-permissions", "--model", model.model];
26414
- const child = spawn9("claude", args, { stdio: "inherit", env: editorEnv, cwd: opts.cwd });
26748
+ const child = spawn10("claude", args, { stdio: "inherit", env: editorEnv, cwd: opts.cwd });
26415
26749
  const exitCode = await new Promise((resolve16) => {
26416
26750
  child.on("exit", (code) => resolve16(code ?? 0));
26417
26751
  child.on("error", (err) => {
@@ -26431,7 +26765,7 @@ async function serve(opts) {
26431
26765
  if (usesProxy) process.stdout.write(` ANTHROPIC_BASE_URL=${url}
26432
26766
  `);
26433
26767
  try {
26434
- const code = spawn9("code", [opts.cwd], { stdio: "inherit", env: editorEnv, detached: true });
26768
+ const code = spawn10("code", [opts.cwd], { stdio: "inherit", env: editorEnv, detached: true });
26435
26769
  code.on("error", (err) => {
26436
26770
  process.stderr.write(`[kody serve] failed to launch VS Code: ${err.message}
26437
26771
  `);