@kody-ade/kody-engine 0.4.553 → 0.4.555

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 +763 -690
  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.553",
18
+ version: "0.4.555",
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",
@@ -668,6 +668,111 @@ var init_format = __esm({
668
668
  }
669
669
  });
670
670
 
671
+ // src/agency/capability-contract-validation.ts
672
+ import Ajv from "ajv";
673
+ function validateCapabilityContractValue(boundary, schema, value) {
674
+ const validate = validator.compile(schema);
675
+ if (!validate(value)) {
676
+ throw new CapabilityContractValidationError(boundary, validate.errors ?? []);
677
+ }
678
+ }
679
+ function capabilityContractInput(inputs, args, capabilityId, contractProperties = []) {
680
+ const isGenericRunnerInput = inputs.some((input) => input.name === "input") && Object.hasOwn(args, "input");
681
+ if (!isGenericRunnerInput) {
682
+ const isParameterlessGenericRunner = (inputs.some((input) => input.name === "capability") || args.capability === capabilityId || !contractProperties.includes("capability")) && Object.hasOwn(args, "capability");
683
+ if (!isParameterlessGenericRunner) return args;
684
+ const { capability: _routingCapability, ...businessArgs } = args;
685
+ return businessArgs;
686
+ }
687
+ const value = args.input;
688
+ if (typeof value !== "string") return value;
689
+ try {
690
+ return JSON.parse(value);
691
+ } catch {
692
+ return value;
693
+ }
694
+ }
695
+ var validator, CapabilityContractValidationError;
696
+ var init_capability_contract_validation = __esm({
697
+ "src/agency/capability-contract-validation.ts"() {
698
+ "use strict";
699
+ validator = new Ajv({
700
+ allErrors: true,
701
+ strict: true,
702
+ validateFormats: false
703
+ });
704
+ CapabilityContractValidationError = class extends Error {
705
+ constructor(boundary, errors) {
706
+ const details = errors.map((error) => {
707
+ const location = error.instancePath || "$";
708
+ const property = error.keyword === "additionalProperties" && typeof error.params.additionalProperty === "string" ? ` (${error.params.additionalProperty})` : "";
709
+ return `${location}: ${error.message ?? error.keyword}${property}`;
710
+ }).join("; ");
711
+ super(`Capability ${boundary} does not match its declared contract: ${details}`);
712
+ this.boundary = boundary;
713
+ this.errors = errors;
714
+ this.name = "CapabilityContractValidationError";
715
+ }
716
+ boundary;
717
+ errors;
718
+ };
719
+ }
720
+ });
721
+
722
+ // src/outputContractHooks.ts
723
+ import * as fs3 from "fs";
724
+ import * as path3 from "path";
725
+ function outputContractError(contract) {
726
+ let value;
727
+ try {
728
+ value = JSON.parse(fs3.readFileSync(contract.path, "utf8"));
729
+ } catch (error) {
730
+ return `The required output file is missing or is not valid JSON: ${error instanceof Error ? error.message : String(error)}`;
731
+ }
732
+ try {
733
+ validateCapabilityContractValue("output", contract.schema, value);
734
+ return null;
735
+ } catch (error) {
736
+ return error instanceof Error ? error.message : String(error);
737
+ }
738
+ }
739
+ function correctionMessage(contract, error) {
740
+ return `The authoritative output does not match its required contract: ${error}. Please overwrite ${contract.path} with only the required JSON shape before finishing.`;
741
+ }
742
+ function createOutputContractPostWriteHook(contract) {
743
+ const expectedPath = path3.resolve(contract.path);
744
+ return async (input) => {
745
+ const toolInput = input.tool_input;
746
+ if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return {};
747
+ const filePath = toolInput.file_path;
748
+ if (typeof filePath !== "string" || path3.resolve(filePath) !== expectedPath) return {};
749
+ const error = outputContractError(contract);
750
+ if (!error) return {};
751
+ return {
752
+ hookSpecificOutput: {
753
+ hookEventName: "PostToolUse",
754
+ additionalContext: correctionMessage(contract, error)
755
+ }
756
+ };
757
+ };
758
+ }
759
+ function createOutputContractStopHook(contract) {
760
+ return async () => {
761
+ const error = outputContractError(contract);
762
+ if (!error) return {};
763
+ return {
764
+ decision: "block",
765
+ reason: correctionMessage(contract, error)
766
+ };
767
+ };
768
+ }
769
+ var init_outputContractHooks = __esm({
770
+ "src/outputContractHooks.ts"() {
771
+ "use strict";
772
+ init_capability_contract_validation();
773
+ }
774
+ });
775
+
671
776
  // src/runtimePaths.ts
672
777
  var runtimePaths_exports = {};
673
778
  __export(runtimePaths_exports, {
@@ -678,21 +783,21 @@ __export(runtimePaths_exports, {
678
783
  });
679
784
  import { createHash } from "crypto";
680
785
  import * as os2 from "os";
681
- import * as path3 from "path";
786
+ import * as path4 from "path";
682
787
  function runtimeDirForCwd(cwd, ...parts) {
683
- const key = createHash("sha256").update(path3.resolve(cwd)).digest("hex").slice(0, 16);
684
- return path3.join(os2.tmpdir(), "kody-engine", key, ...parts);
788
+ const key = createHash("sha256").update(path4.resolve(cwd)).digest("hex").slice(0, 16);
789
+ return path4.join(os2.tmpdir(), "kody-engine", key, ...parts);
685
790
  }
686
791
  function runtimeStatePath(cwd, ...parts) {
687
792
  const configuredRoot = process.env.KODY_RUNTIME_DIR?.trim();
688
- const base = configuredRoot ? path3.resolve(configuredRoot) : runtimeDirForCwd(cwd);
689
- return path3.join(base, ...parts);
793
+ const base = configuredRoot ? path4.resolve(configuredRoot) : runtimeDirForCwd(cwd);
794
+ return path4.join(base, ...parts);
690
795
  }
691
796
  function agentRunDir(cwd) {
692
797
  return runtimeStatePath(cwd, "agent-runs");
693
798
  }
694
799
  function lastRunLogPath(cwd) {
695
- return path3.join(agentRunDir(cwd), "last-run.jsonl");
800
+ return path4.join(agentRunDir(cwd), "last-run.jsonl");
696
801
  }
697
802
  var init_runtimePaths = __esm({
698
803
  "src/runtimePaths.ts"() {
@@ -701,31 +806,31 @@ var init_runtimePaths = __esm({
701
806
  });
702
807
 
703
808
  // src/scripts/buildSyntheticPlugin.ts
704
- import * as fs3 from "fs";
809
+ import * as fs4 from "fs";
705
810
  import * as os3 from "os";
706
- import * as path4 from "path";
811
+ import * as path5 from "path";
707
812
  function getPluginsCatalogRoot() {
708
- const here = path4.dirname(new URL(import.meta.url).pathname);
813
+ const here = path5.dirname(new URL(import.meta.url).pathname);
709
814
  const candidates = [
710
- path4.join(here, "..", "plugins"),
815
+ path5.join(here, "..", "plugins"),
711
816
  // dev: src/scripts → src/plugins
712
- path4.join(here, "..", "..", "plugins"),
817
+ path5.join(here, "..", "..", "plugins"),
713
818
  // built: dist/scripts → dist/plugins
714
- path4.join(here, "..", "..", "src", "plugins")
819
+ path5.join(here, "..", "..", "src", "plugins")
715
820
  // fallback
716
821
  ];
717
822
  for (const c of candidates) {
718
- if (fs3.existsSync(c) && fs3.statSync(c).isDirectory()) return c;
823
+ if (fs4.existsSync(c) && fs4.statSync(c).isDirectory()) return c;
719
824
  }
720
825
  return candidates[0];
721
826
  }
722
827
  function copyDir(src, dst) {
723
- fs3.mkdirSync(dst, { recursive: true });
724
- for (const ent of fs3.readdirSync(src, { withFileTypes: true })) {
725
- const s = path4.join(src, ent.name);
726
- const d = path4.join(dst, ent.name);
828
+ fs4.mkdirSync(dst, { recursive: true });
829
+ for (const ent of fs4.readdirSync(src, { withFileTypes: true })) {
830
+ const s = path5.join(src, ent.name);
831
+ const d = path5.join(dst, ent.name);
727
832
  if (ent.isDirectory()) copyDir(s, d);
728
- else if (ent.isFile()) fs3.copyFileSync(s, d);
833
+ else if (ent.isFile()) fs4.copyFileSync(s, d);
729
834
  }
730
835
  }
731
836
  var buildSyntheticPlugin;
@@ -738,47 +843,47 @@ var init_buildSyntheticPlugin = __esm({
738
843
  if (!needsSynthetic) return;
739
844
  const catalog = getPluginsCatalogRoot();
740
845
  const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
741
- const root = path4.join(os3.tmpdir(), `kody-synth-${runId}`);
742
- fs3.mkdirSync(path4.join(root, ".claude-plugin"), { recursive: true });
846
+ const root = path5.join(os3.tmpdir(), `kody-synth-${runId}`);
847
+ fs4.mkdirSync(path5.join(root, ".claude-plugin"), { recursive: true });
743
848
  const resolvePart = (bucket, entry) => {
744
- const local = path4.join(profile.dir, bucket, entry);
745
- if (fs3.existsSync(local)) return local;
746
- const shared = path4.resolve(profile.dir, "..", "..", "shared", bucket, entry);
747
- if (fs3.existsSync(shared)) return shared;
748
- const central = path4.join(catalog, bucket, entry);
749
- if (fs3.existsSync(central)) return central;
849
+ const local = path5.join(profile.dir, bucket, entry);
850
+ if (fs4.existsSync(local)) return local;
851
+ const shared = path5.resolve(profile.dir, "..", "..", "shared", bucket, entry);
852
+ if (fs4.existsSync(shared)) return shared;
853
+ const central = path5.join(catalog, bucket, entry);
854
+ if (fs4.existsSync(central)) return central;
750
855
  throw new Error(
751
- `buildSyntheticPlugin: ${bucket} entry '${entry}' not found in implementation dir (${profile.dir}/${bucket}/), Store shared assets (${path4.dirname(shared)}/), or catalog (${catalog}/${bucket}/)`
856
+ `buildSyntheticPlugin: ${bucket} entry '${entry}' not found in implementation dir (${profile.dir}/${bucket}/), Store shared assets (${path5.dirname(shared)}/), or catalog (${catalog}/${bucket}/)`
752
857
  );
753
858
  };
754
859
  if (cc.skills.length > 0) {
755
- const dst = path4.join(root, "skills");
756
- fs3.mkdirSync(dst, { recursive: true });
860
+ const dst = path5.join(root, "skills");
861
+ fs4.mkdirSync(dst, { recursive: true });
757
862
  for (const name of cc.skills) {
758
- copyDir(resolvePart("skills", name), path4.join(dst, name));
863
+ copyDir(resolvePart("skills", name), path5.join(dst, name));
759
864
  }
760
865
  }
761
866
  if (cc.commands.length > 0) {
762
- const dst = path4.join(root, "commands");
763
- fs3.mkdirSync(dst, { recursive: true });
867
+ const dst = path5.join(root, "commands");
868
+ fs4.mkdirSync(dst, { recursive: true });
764
869
  for (const name of cc.commands) {
765
- fs3.copyFileSync(resolvePart("commands", `${name}.md`), path4.join(dst, `${name}.md`));
870
+ fs4.copyFileSync(resolvePart("commands", `${name}.md`), path5.join(dst, `${name}.md`));
766
871
  }
767
872
  }
768
873
  if (cc.hooks.length > 0) {
769
- const dst = path4.join(root, "hooks");
770
- fs3.mkdirSync(dst, { recursive: true });
874
+ const dst = path5.join(root, "hooks");
875
+ fs4.mkdirSync(dst, { recursive: true });
771
876
  const merged = { hooks: {} };
772
877
  for (const name of cc.hooks) {
773
878
  const src = resolvePart("hooks", `${name}.json`);
774
- const parsed = JSON.parse(fs3.readFileSync(src, "utf-8"));
879
+ const parsed = JSON.parse(fs4.readFileSync(src, "utf-8"));
775
880
  for (const [event, entries] of Object.entries(parsed.hooks ?? {})) {
776
881
  if (!Array.isArray(entries)) continue;
777
882
  if (!merged.hooks[event]) merged.hooks[event] = [];
778
883
  merged.hooks[event].push(...entries);
779
884
  }
780
885
  }
781
- fs3.writeFileSync(path4.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
886
+ fs4.writeFileSync(path5.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
782
887
  `);
783
888
  }
784
889
  const manifest = {
@@ -788,7 +893,7 @@ var init_buildSyntheticPlugin = __esm({
788
893
  };
789
894
  if (cc.skills.length > 0) manifest.skills = ["./skills/"];
790
895
  if (cc.commands.length > 0) manifest.commands = ["./commands/"];
791
- fs3.writeFileSync(path4.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
896
+ fs4.writeFileSync(path5.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
792
897
  `);
793
898
  ctx.data.syntheticPluginPath = root;
794
899
  };
@@ -796,8 +901,8 @@ var init_buildSyntheticPlugin = __esm({
796
901
  });
797
902
 
798
903
  // src/subagents.ts
799
- import * as fs4 from "fs";
800
- import * as path5 from "path";
904
+ import * as fs5 from "fs";
905
+ import * as path6 from "path";
801
906
  async function enforceSubagentModelInheritance(input) {
802
907
  const toolInput = input.tool_input;
803
908
  if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return {};
@@ -832,12 +937,12 @@ function splitFrontmatter(raw) {
832
937
  return { fm, body: (match[2] ?? "").trim() };
833
938
  }
834
939
  function resolveAgentFile(profileDir, name) {
835
- const local = path5.join(profileDir, "agents", `${name}.md`);
836
- if (fs4.existsSync(local)) return local;
837
- const shared = path5.resolve(profileDir, "..", "..", "shared", "agents", `${name}.md`);
838
- if (fs4.existsSync(shared)) return shared;
839
- const central = path5.join(getPluginsCatalogRoot(), "agents", `${name}.md`);
840
- if (fs4.existsSync(central)) return central;
940
+ const local = path6.join(profileDir, "agents", `${name}.md`);
941
+ if (fs5.existsSync(local)) return local;
942
+ const shared = path6.resolve(profileDir, "..", "..", "shared", "agents", `${name}.md`);
943
+ if (fs5.existsSync(shared)) return shared;
944
+ const central = path6.join(getPluginsCatalogRoot(), "agents", `${name}.md`);
945
+ if (fs5.existsSync(central)) return central;
841
946
  throw new Error(
842
947
  `loadSubagents: agent '${name}' not found in ${profileDir}/agents/, hydrated shared assets, or engine catalog`
843
948
  );
@@ -848,7 +953,7 @@ function captureSubagentTemplates(profile) {
848
953
  const out = {};
849
954
  for (const name of names) {
850
955
  try {
851
- out[name] = fs4.readFileSync(resolveAgentFile(profile.dir, name), "utf-8");
956
+ out[name] = fs5.readFileSync(resolveAgentFile(profile.dir, name), "utf-8");
852
957
  } catch {
853
958
  }
854
959
  }
@@ -859,7 +964,7 @@ function loadSubagents(profile) {
859
964
  if (!names || names.length === 0) return void 0;
860
965
  const agents = {};
861
966
  for (const name of names) {
862
- const raw = profile.subagentTemplates?.[name] ?? fs4.readFileSync(resolveAgentFile(profile.dir, name), "utf-8");
967
+ const raw = profile.subagentTemplates?.[name] ?? fs5.readFileSync(resolveAgentFile(profile.dir, name), "utf-8");
863
968
  const { fm, body } = splitFrontmatter(raw);
864
969
  if (!body) throw new Error(`loadSubagents: agent '${name}' has an empty prompt body`);
865
970
  const def = {
@@ -892,8 +997,8 @@ __export(events_exports, {
892
997
  resolveRunId: () => resolveRunId
893
998
  });
894
999
  import * as crypto from "crypto";
895
- import * as fs5 from "fs";
896
- import * as path6 from "path";
1000
+ import * as fs6 from "fs";
1001
+ import * as path7 from "path";
897
1002
  function resolveRunId() {
898
1003
  if (process.env.KODY_RUN_ID) {
899
1004
  cachedRunId = process.env.KODY_RUN_ID;
@@ -926,16 +1031,16 @@ function emitEvent(cwd, ev) {
926
1031
  ...ev
927
1032
  };
928
1033
  const file = eventsPath(cwd, runId);
929
- fs5.mkdirSync(path6.dirname(file), { recursive: true });
930
- fs5.appendFileSync(file, `${JSON.stringify(fullEvent)}
1034
+ fs6.mkdirSync(path7.dirname(file), { recursive: true });
1035
+ fs6.appendFileSync(file, `${JSON.stringify(fullEvent)}
931
1036
  `);
932
1037
  } catch {
933
1038
  }
934
1039
  }
935
1040
  function readEvents(cwd, runId) {
936
1041
  const file = eventsPath(cwd, runId);
937
- if (!fs5.existsSync(file)) return [];
938
- const lines = fs5.readFileSync(file, "utf-8").split("\n");
1042
+ if (!fs6.existsSync(file)) return [];
1043
+ const lines = fs6.readFileSync(file, "utf-8").split("\n");
939
1044
  const out = [];
940
1045
  for (const line of lines) {
941
1046
  const trimmed = line.trim();
@@ -949,10 +1054,10 @@ function readEvents(cwd, runId) {
949
1054
  }
950
1055
  function listRuns(cwd) {
951
1056
  const runsDir = runtimeStatePath(cwd, "agent-runs");
952
- if (!fs5.existsSync(runsDir)) return [];
953
- return fs5.readdirSync(runsDir).filter((name) => {
1057
+ if (!fs6.existsSync(runsDir)) return [];
1058
+ return fs6.readdirSync(runsDir).filter((name) => {
954
1059
  try {
955
- return fs5.statSync(path6.join(runsDir, name)).isDirectory();
1060
+ return fs6.statSync(path7.join(runsDir, name)).isDirectory();
956
1061
  } catch {
957
1062
  return false;
958
1063
  }
@@ -989,7 +1094,7 @@ function buildVerifyEnv(source = process.env) {
989
1094
  return env;
990
1095
  }
991
1096
  function runCommand(command, cwd) {
992
- return new Promise((resolve20) => {
1097
+ return new Promise((resolve21) => {
993
1098
  const start = Date.now();
994
1099
  const child = spawn(command, {
995
1100
  cwd,
@@ -1018,11 +1123,11 @@ function runCommand(command, cwd) {
1018
1123
  child.on("exit", (code) => {
1019
1124
  clearTimeout(timer);
1020
1125
  const tail = Buffer.concat(buffers).toString("utf-8").slice(-TAIL_CHARS);
1021
- resolve20({ exitCode: code ?? -1, durationMs: Date.now() - start, tail });
1126
+ resolve21({ exitCode: code ?? -1, durationMs: Date.now() - start, tail });
1022
1127
  });
1023
1128
  child.on("error", (err) => {
1024
1129
  clearTimeout(timer);
1025
- resolve20({ exitCode: -1, durationMs: Date.now() - start, tail: err.message });
1130
+ resolve21({ exitCode: -1, durationMs: Date.now() - start, tail: err.message });
1026
1131
  });
1027
1132
  });
1028
1133
  }
@@ -1331,7 +1436,7 @@ function cmsHeaders(opts) {
1331
1436
  }
1332
1437
  };
1333
1438
  }
1334
- async function callDashboardCms(opts, path54, init = {}) {
1439
+ async function callDashboardCms(opts, path55, init = {}) {
1335
1440
  const baseUrl = dashboardBaseUrl(opts);
1336
1441
  if (!baseUrl) {
1337
1442
  return {
@@ -1343,7 +1448,7 @@ async function callDashboardCms(opts, path54, init = {}) {
1343
1448
  const headerResult = cmsHeaders(opts);
1344
1449
  if (!headerResult.ok) return headerResult;
1345
1450
  try {
1346
- const res = await fetch(`${baseUrl}${path54}`, {
1451
+ const res = await fetch(`${baseUrl}${path55}`, {
1347
1452
  ...init,
1348
1453
  headers: {
1349
1454
  ...headerResult.headers,
@@ -1415,8 +1520,8 @@ function documentArg(value) {
1415
1520
  function normalizeCmsDocumentIdInput(input) {
1416
1521
  const trimmed = stripWrappingQuotes(input.trim());
1417
1522
  const withoutQuery = trimmed.split(/[?#]/, 1)[0] ?? trimmed;
1418
- const path54 = parseDocumentPath(withoutQuery);
1419
- return path54 ?? parseDocumentIdSegment(withoutQuery) ?? withoutQuery;
1523
+ const path55 = parseDocumentPath(withoutQuery);
1524
+ return path55 ?? parseDocumentIdSegment(withoutQuery) ?? withoutQuery;
1420
1525
  }
1421
1526
  function stripWrappingQuotes(value) {
1422
1527
  let current = value;
@@ -1427,9 +1532,9 @@ function stripWrappingQuotes(value) {
1427
1532
  }
1428
1533
  }
1429
1534
  function parseDocumentPath(value) {
1430
- const path54 = value.startsWith("http://") || value.startsWith("https://") ? urlPathname(value) : value;
1431
- if (!path54?.includes("/content/entries/")) return null;
1432
- const parts = path54.split("/").filter(Boolean).map(decodePathPart);
1535
+ const path55 = value.startsWith("http://") || value.startsWith("https://") ? urlPathname(value) : value;
1536
+ if (!path55?.includes("/content/entries/")) return null;
1537
+ const parts = path55.split("/").filter(Boolean).map(decodePathPart);
1433
1538
  const entriesIndex = parts.findIndex((part, index) => part === "content" && parts[index + 1] === "entries");
1434
1539
  const idPart = parts[entriesIndex + 3];
1435
1540
  if (!idPart || idPart === "new") return null;
@@ -1874,8 +1979,8 @@ var init_issue = __esm({
1874
1979
  });
1875
1980
 
1876
1981
  // src/capabilityFolders.ts
1877
- import * as fs6 from "fs";
1878
- import * as path7 from "path";
1982
+ import * as fs7 from "fs";
1983
+ import * as path8 from "path";
1879
1984
  function capabilityOutputConditionPaths(config) {
1880
1985
  if (config.outputSchema) {
1881
1986
  return new Set(schemaPropertyPaths(config.outputSchema, "result"));
@@ -1890,32 +1995,32 @@ function capabilityOutputConditionPaths(config) {
1890
1995
  ]);
1891
1996
  }
1892
1997
  function listCapabilityFolderSlugs(absDir) {
1893
- if (!fs6.existsSync(absDir)) return [];
1998
+ if (!fs7.existsSync(absDir)) return [];
1894
1999
  let entries;
1895
2000
  try {
1896
- entries = fs6.readdirSync(absDir, { withFileTypes: true });
2001
+ entries = fs7.readdirSync(absDir, { withFileTypes: true });
1897
2002
  } catch {
1898
2003
  return [];
1899
2004
  }
1900
- return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).filter((e) => isCapabilityFolder(path7.join(absDir, e.name))).map((e) => e.name).sort();
2005
+ return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).filter((e) => isCapabilityFolder(path8.join(absDir, e.name))).map((e) => e.name).sort();
1901
2006
  }
1902
2007
  function isCapabilityFolder(dir) {
1903
- if (!fs6.existsSync(path7.join(dir, CAPABILITY_BODY_FILE))) return false;
1904
- const entries = fs6.readdirSync(dir, { withFileTypes: true });
2008
+ if (!fs7.existsSync(path8.join(dir, CAPABILITY_BODY_FILE))) return false;
2009
+ const entries = fs7.readdirSync(dir, { withFileTypes: true });
1905
2010
  return entries.every(
1906
2011
  (entry) => entry.name === CAPABILITY_BODY_FILE || entry.name === CAPABILITY_CONTRACT_FILE || entry.isDirectory() && (entry.name === "skills" || entry.name === "tools")
1907
2012
  );
1908
2013
  }
1909
2014
  function readCapabilityFolder(root, slug) {
1910
- const dir = path7.join(root, slug);
1911
- const bodyPath = path7.join(dir, CAPABILITY_BODY_FILE);
1912
- const contractPath = path7.join(dir, CAPABILITY_CONTRACT_FILE);
1913
- if (!fs6.existsSync(bodyPath) || !fs6.statSync(bodyPath).isFile()) return null;
2015
+ const dir = path8.join(root, slug);
2016
+ const bodyPath = path8.join(dir, CAPABILITY_BODY_FILE);
2017
+ const contractPath = path8.join(dir, CAPABILITY_CONTRACT_FILE);
2018
+ if (!fs7.existsSync(bodyPath) || !fs7.statSync(bodyPath).isFile()) return null;
1914
2019
  if (!isCapabilityFolder(dir)) return null;
1915
2020
  try {
1916
- const rawBody = fs6.readFileSync(bodyPath, "utf-8");
1917
- const contract = fs6.existsSync(contractPath) ? parseCapabilityContract(fs6.readFileSync(contractPath, "utf-8")) : void 0;
1918
- if (contract?.execution === "script" && !isRegularFile(path7.join(dir, "tools", "run.sh"))) {
2021
+ const rawBody = fs7.readFileSync(bodyPath, "utf-8");
2022
+ const contract = fs7.existsSync(contractPath) ? parseCapabilityContract(fs7.readFileSync(contractPath, "utf-8")) : void 0;
2023
+ if (contract?.execution === "script" && !isRegularFile(path8.join(dir, "tools", "run.sh"))) {
1919
2024
  throw new Error('script-backed Capability requires a regular "tools/run.sh" file');
1920
2025
  }
1921
2026
  const { title, body } = parseCapabilityBody(rawBody, slug);
@@ -2028,7 +2133,7 @@ function parseCapabilityRequirements(raw) {
2028
2133
  }
2029
2134
  function isRegularFile(filePath) {
2030
2135
  try {
2031
- const stat = fs6.lstatSync(filePath);
2136
+ const stat = fs7.lstatSync(filePath);
2032
2137
  return stat.isFile() && !stat.isSymbolicLink();
2033
2138
  } catch {
2034
2139
  return false;
@@ -2037,8 +2142,8 @@ function isRegularFile(filePath) {
2037
2142
  function schemaPropertyPaths(schema, prefix) {
2038
2143
  const properties = isPlainObject(schema.properties) ? schema.properties : {};
2039
2144
  return Object.entries(properties).flatMap(([name, property]) => {
2040
- const path54 = `${prefix}.${name}`;
2041
- return isPlainObject(property) ? [path54, ...schemaPropertyPaths(property, path54)] : [path54];
2145
+ const path55 = `${prefix}.${name}`;
2146
+ return isPlainObject(property) ? [path55, ...schemaPropertyPaths(property, path55)] : [path55];
2042
2147
  });
2043
2148
  }
2044
2149
  function parseCapabilityBody(raw, slug) {
@@ -2200,51 +2305,51 @@ var init_capabilityFolders = __esm({
2200
2305
  });
2201
2306
 
2202
2307
  // src/definition-paths.ts
2203
- import * as fs7 from "fs";
2204
- import * as path8 from "path";
2308
+ import * as fs8 from "fs";
2309
+ import * as path9 from "path";
2205
2310
  function definitionsRoot(cwd = process.cwd()) {
2206
2311
  const override = process.env.KODY_DEFINITIONS_ROOT?.trim();
2207
2312
  const overrideCwd = process.env.KODY_DEFINITIONS_ROOT_CWD?.trim();
2208
- if (override && overrideCwd && path8.resolve(cwd) === path8.resolve(overrideCwd)) {
2209
- return storeCatalogRoot(path8.resolve(override));
2313
+ if (override && overrideCwd && path9.resolve(cwd) === path9.resolve(overrideCwd)) {
2314
+ return storeCatalogRoot(path9.resolve(override));
2210
2315
  }
2211
- const hydrated = path8.join(cwd, ".kody-engine", "definitions");
2212
- if (fs7.existsSync(hydrated)) return hydrated;
2213
- return override ? storeCatalogRoot(path8.resolve(override)) : hydrated;
2316
+ const hydrated = path9.join(cwd, ".kody-engine", "definitions");
2317
+ if (fs8.existsSync(hydrated)) return hydrated;
2318
+ return override ? storeCatalogRoot(path9.resolve(override)) : hydrated;
2214
2319
  }
2215
2320
  function hasExplicitDefinitionsRoot(cwd = process.cwd(), env = process.env) {
2216
2321
  const root = env.KODY_DEFINITIONS_ROOT?.trim();
2217
2322
  const rootCwd = env.KODY_DEFINITIONS_ROOT_CWD?.trim();
2218
- return Boolean(root && rootCwd && path8.resolve(cwd) === path8.resolve(rootCwd));
2323
+ return Boolean(root && rootCwd && path9.resolve(cwd) === path9.resolve(rootCwd));
2219
2324
  }
2220
2325
  function capabilitiesRoot(cwd = process.cwd()) {
2221
- return storeAssetRoot(cwd, "capabilities") ?? path8.join(definitionsRoot(cwd), "capabilities");
2326
+ return storeAssetRoot(cwd, "capabilities") ?? path9.join(definitionsRoot(cwd), "capabilities");
2222
2327
  }
2223
2328
  function implementationsRoot(cwd = process.cwd()) {
2224
- return path8.join(definitionsRoot(cwd), "implementations");
2329
+ return path9.join(definitionsRoot(cwd), "implementations");
2225
2330
  }
2226
2331
  function agentsRoot(cwd = process.cwd()) {
2227
- return storeAssetRoot(cwd, "agent") ?? path8.join(definitionsRoot(cwd), "agents");
2332
+ return storeAssetRoot(cwd, "agent") ?? path9.join(definitionsRoot(cwd), "agents");
2228
2333
  }
2229
2334
  function storeCatalogRoot(root) {
2230
2335
  const manifest = readStoreManifest(root);
2231
- const roots = ["capabilities", "workflows", "loops"].map((kind) => manifest?.assetRoots?.[kind]).filter((value) => typeof value === "string" && Boolean(value.trim())).map((value) => path8.dirname(value));
2232
- return roots.length === 3 && new Set(roots).size === 1 ? path8.join(root, roots[0]) : root;
2336
+ const roots = ["capabilities", "workflows", "loops"].map((kind) => manifest?.assetRoots?.[kind]).filter((value) => typeof value === "string" && Boolean(value.trim())).map((value) => path9.dirname(value));
2337
+ return roots.length === 3 && new Set(roots).size === 1 ? path9.join(root, roots[0]) : root;
2233
2338
  }
2234
2339
  function storeAssetRoot(cwd, kind) {
2235
2340
  const override = process.env.KODY_DEFINITIONS_ROOT?.trim();
2236
2341
  if (!override) return null;
2237
2342
  const overrideCwd = process.env.KODY_DEFINITIONS_ROOT_CWD?.trim();
2238
- if (overrideCwd && path8.resolve(cwd) !== path8.resolve(overrideCwd)) return null;
2239
- const root = path8.resolve(override);
2343
+ if (overrideCwd && path9.resolve(cwd) !== path9.resolve(overrideCwd)) return null;
2344
+ const root = path9.resolve(override);
2240
2345
  const configured = readStoreManifest(root)?.assetRoots?.[kind];
2241
- return typeof configured === "string" && configured.trim() ? path8.join(root, configured) : null;
2346
+ return typeof configured === "string" && configured.trim() ? path9.join(root, configured) : null;
2242
2347
  }
2243
2348
  function readStoreManifest(root) {
2244
- const file = path8.join(root, "kody-store.json");
2245
- if (!fs7.existsSync(file)) return null;
2349
+ const file = path9.join(root, "kody-store.json");
2350
+ if (!fs8.existsSync(file)) return null;
2246
2351
  try {
2247
- return JSON.parse(fs7.readFileSync(file, "utf8"));
2352
+ return JSON.parse(fs8.readFileSync(file, "utf8"));
2248
2353
  } catch {
2249
2354
  return null;
2250
2355
  }
@@ -2256,32 +2361,32 @@ var init_definition_paths = __esm({
2256
2361
  });
2257
2362
 
2258
2363
  // src/registry.ts
2259
- import * as fs8 from "fs";
2260
- import * as path9 from "path";
2364
+ import * as fs9 from "fs";
2365
+ import * as path10 from "path";
2261
2366
  function getImplementationsRoot() {
2262
- const here = path9.dirname(new URL(import.meta.url).pathname);
2367
+ const here = path10.dirname(new URL(import.meta.url).pathname);
2263
2368
  const candidates = [
2264
- path9.join(here, "implementations"),
2369
+ path10.join(here, "implementations"),
2265
2370
  // dev: src/
2266
- path9.join(here, "..", "implementations"),
2371
+ path10.join(here, "..", "implementations"),
2267
2372
  // built: dist/bin → dist/implementations
2268
- path9.join(here, "..", "src", "implementations")
2373
+ path10.join(here, "..", "src", "implementations")
2269
2374
  // fallback
2270
2375
  ];
2271
2376
  for (const c of candidates) {
2272
- if (fs8.existsSync(c) && fs8.statSync(c).isDirectory()) return c;
2377
+ if (fs9.existsSync(c) && fs9.statSync(c).isDirectory()) return c;
2273
2378
  }
2274
2379
  return candidates[0];
2275
2380
  }
2276
2381
  function getRuntimeServicesRoot() {
2277
- const here = path9.dirname(new URL(import.meta.url).pathname);
2382
+ const here = path10.dirname(new URL(import.meta.url).pathname);
2278
2383
  const candidates = [
2279
- path9.join(here, "runtime-services"),
2280
- path9.join(here, "..", "runtime-services"),
2281
- path9.join(here, "..", "src", "runtime-services")
2384
+ path10.join(here, "runtime-services"),
2385
+ path10.join(here, "..", "runtime-services"),
2386
+ path10.join(here, "..", "src", "runtime-services")
2282
2387
  ];
2283
2388
  for (const candidate of candidates) {
2284
- if (fs8.existsSync(candidate) && fs8.statSync(candidate).isDirectory()) return candidate;
2389
+ if (fs9.existsSync(candidate) && fs9.statSync(candidate).isDirectory()) return candidate;
2285
2390
  }
2286
2391
  return candidates[0];
2287
2392
  }
@@ -2289,17 +2394,17 @@ function getProjectCapabilitiesRoot() {
2289
2394
  return capabilitiesRoot();
2290
2395
  }
2291
2396
  function getBuiltinCapabilitiesRoot() {
2292
- const here = path9.dirname(new URL(import.meta.url).pathname);
2397
+ const here = path10.dirname(new URL(import.meta.url).pathname);
2293
2398
  const candidates = [
2294
- path9.join(here, "capabilities"),
2399
+ path10.join(here, "capabilities"),
2295
2400
  // dev: src/
2296
- path9.join(here, "..", "capabilities"),
2401
+ path10.join(here, "..", "capabilities"),
2297
2402
  // built: dist/bin → dist/capabilities
2298
- path9.join(here, "..", "src", "capabilities")
2403
+ path10.join(here, "..", "src", "capabilities")
2299
2404
  // fallback
2300
2405
  ];
2301
2406
  for (const c of candidates) {
2302
- if (fs8.existsSync(c) && fs8.statSync(c).isDirectory()) return c;
2407
+ if (fs9.existsSync(c) && fs9.statSync(c).isDirectory()) return c;
2303
2408
  }
2304
2409
  return candidates[0];
2305
2410
  }
@@ -2322,14 +2427,14 @@ function listImplementations(roots = getImplementationRoots()) {
2322
2427
  const seen = /* @__PURE__ */ new Set();
2323
2428
  const out = [];
2324
2429
  for (const root of rootList) {
2325
- if (!fs8.existsSync(root)) continue;
2430
+ if (!fs9.existsSync(root)) continue;
2326
2431
  const requireImplementationProfile = isCapabilityRoot(root);
2327
- const entries = fs8.readdirSync(root, { withFileTypes: true });
2432
+ const entries = fs9.readdirSync(root, { withFileTypes: true });
2328
2433
  for (const ent of entries) {
2329
2434
  if (!ent.isDirectory()) continue;
2330
2435
  if (seen.has(ent.name)) continue;
2331
2436
  const profilePath = implementationRuntimePath(root, ent.name);
2332
- if (fs8.existsSync(profilePath) && fs8.statSync(profilePath).isFile() && isImplementationProfile(profilePath, requireImplementationProfile)) {
2437
+ if (fs9.existsSync(profilePath) && fs9.statSync(profilePath).isFile() && isImplementationProfile(profilePath, requireImplementationProfile)) {
2333
2438
  out.push({ name: ent.name, profilePath });
2334
2439
  seen.add(ent.name);
2335
2440
  }
@@ -2349,7 +2454,7 @@ function resolveImplementationCandidates(name, roots = getRuntimeProfileRootsFor
2349
2454
  const out = [];
2350
2455
  for (const root of rootList) {
2351
2456
  const profilePath = implementationRuntimePath(root, name);
2352
- if (fs8.existsSync(profilePath) && fs8.statSync(profilePath).isFile() && isImplementationProfile(profilePath, isCapabilityRoot(root))) {
2457
+ if (fs9.existsSync(profilePath) && fs9.statSync(profilePath).isFile() && isImplementationProfile(profilePath, isCapabilityRoot(root))) {
2353
2458
  out.push(profilePath);
2354
2459
  }
2355
2460
  }
@@ -2418,7 +2523,7 @@ function implementationDeclaresInput(implementation, inputName, cwd = process.cw
2418
2523
  const profilePath = resolveImplementation(implementation, getRuntimeProfileRootsForCwd(cwd));
2419
2524
  if (!profilePath) return false;
2420
2525
  try {
2421
- const document = JSON.parse(fs8.readFileSync(profilePath, "utf-8"));
2526
+ const document = JSON.parse(fs9.readFileSync(profilePath, "utf-8"));
2422
2527
  const raw = document.config ?? document;
2423
2528
  if (!Array.isArray(raw.inputs)) return false;
2424
2529
  return raw.inputs.some((entry) => {
@@ -2434,29 +2539,29 @@ function isSafeName(name) {
2434
2539
  return /^[a-z][a-z0-9-]*$/.test(name) && !name.includes("..");
2435
2540
  }
2436
2541
  function isCapabilityRoot(root) {
2437
- const normalized = path9.normalize(root);
2438
- if (path9.basename(normalized) === "capabilities") return true;
2542
+ const normalized = path10.normalize(root);
2543
+ if (path10.basename(normalized) === "capabilities") return true;
2439
2544
  const knownRoots = [getProjectCapabilitiesRoot(), getBuiltinCapabilitiesRoot()];
2440
- return knownRoots.some((candidate) => candidate && path9.normalize(candidate) === normalized);
2545
+ return knownRoots.some((candidate) => candidate && path10.normalize(candidate) === normalized);
2441
2546
  }
2442
2547
  function implementationRuntimePath(root, name) {
2443
- const runtimePath = path9.join(root, name, "runtime.json");
2444
- if (fs8.existsSync(runtimePath)) return runtimePath;
2445
- const internalProfilePath = path9.join(root, name, "profile.json");
2446
- if (fs8.existsSync(internalProfilePath)) return internalProfilePath;
2447
- return path9.join(root, name, CAPABILITY_PROFILE_FILE);
2548
+ const runtimePath = path10.join(root, name, "runtime.json");
2549
+ if (fs9.existsSync(runtimePath)) return runtimePath;
2550
+ const internalProfilePath = path10.join(root, name, "profile.json");
2551
+ if (fs9.existsSync(internalProfilePath)) return internalProfilePath;
2552
+ return path10.join(root, name, CAPABILITY_PROFILE_FILE);
2448
2553
  }
2449
2554
  function isImplementationProfile(profilePath, requireImplementationProfile) {
2450
2555
  if (!requireImplementationProfile) return true;
2451
2556
  try {
2452
- const raw = JSON.parse(fs8.readFileSync(profilePath, "utf-8"));
2557
+ const raw = JSON.parse(fs9.readFileSync(profilePath, "utf-8"));
2453
2558
  return typeof raw.role === "string" && PUBLIC_IMPLEMENTATION_ROLES.has(raw.role);
2454
2559
  } catch {
2455
2560
  return false;
2456
2561
  }
2457
2562
  }
2458
2563
  function listFolderCapabilityActions(root, source) {
2459
- if (!fs8.existsSync(root) || !fs8.statSync(root).isDirectory()) return [];
2564
+ if (!fs9.existsSync(root) || !fs9.statSync(root).isDirectory()) return [];
2460
2565
  const out = [];
2461
2566
  for (const slug of listCapabilityFolderSlugs(root)) {
2462
2567
  if (!isSafeName(slug)) continue;
@@ -2488,7 +2593,7 @@ function hasUnresolvedExplicitImplementation(capability, implementation) {
2488
2593
  return resolveImplementation(implementation) === null;
2489
2594
  }
2490
2595
  function listBuiltinCapabilityActions(root = getBuiltinCapabilitiesRoot()) {
2491
- if (!fs8.existsSync(root) || !fs8.statSync(root).isDirectory()) return [];
2596
+ if (!fs9.existsSync(root) || !fs9.statSync(root).isDirectory()) return [];
2492
2597
  const out = [];
2493
2598
  for (const slug of listCapabilityFolderSlugs(root)) {
2494
2599
  if (!isSafeName(slug)) continue;
@@ -2513,7 +2618,7 @@ function getProfileInputs(name, roots = getImplementationRoots()) {
2513
2618
  const profilePath = resolveImplementation(name, roots);
2514
2619
  if (!profilePath) return null;
2515
2620
  try {
2516
- const document = JSON.parse(fs8.readFileSync(profilePath, "utf-8"));
2621
+ const document = JSON.parse(fs9.readFileSync(profilePath, "utf-8"));
2517
2622
  if (!document || typeof document !== "object") return [];
2518
2623
  const raw = "config" in document && document.config && typeof document.config === "object" ? document.config : document;
2519
2624
  if (!Array.isArray(raw.inputs)) return [];
@@ -3577,8 +3682,8 @@ var init_capabilityMcp = __esm({
3577
3682
 
3578
3683
  // src/repoWorkspace.ts
3579
3684
  import { spawn as spawn2, spawnSync } from "child_process";
3580
- import * as fs9 from "fs";
3581
- import * as path10 from "path";
3685
+ import * as fs10 from "fs";
3686
+ import * as path11 from "path";
3582
3687
  function buildCloneProcess(repo, token, baseEnv = process.env) {
3583
3688
  const url = `https://github.com/${repo}.git`;
3584
3689
  const env = { ...baseEnv };
@@ -3593,10 +3698,10 @@ function buildCloneProcess(repo, token, baseEnv = process.env) {
3593
3698
  async function resolveAndClone(reposRoot, repo, repoToken, cloneRepo) {
3594
3699
  const name = repo?.trim();
3595
3700
  if (!name || !REPO_RE.test(name)) return null;
3596
- const root = path10.resolve(reposRoot);
3597
- const dir = path10.resolve(root, name);
3598
- if (dir !== root && !dir.startsWith(root + path10.sep)) return null;
3599
- if (fs9.existsSync(path10.join(dir, ".git"))) return dir;
3701
+ const root = path11.resolve(reposRoot);
3702
+ const dir = path11.resolve(root, name);
3703
+ if (dir !== root && !dir.startsWith(root + path11.sep)) return null;
3704
+ if (fs10.existsSync(path11.join(dir, ".git"))) return dir;
3600
3705
  const inflight = repoClones.get(dir);
3601
3706
  if (inflight) {
3602
3707
  await inflight;
@@ -3628,9 +3733,9 @@ var init_repoWorkspace = __esm({
3628
3733
  repoClones = /* @__PURE__ */ new Map();
3629
3734
  GIT_CREDENTIAL_HELPER = `!f() { if [ "$1" = get ] && [ -n "$GITHUB_TOKEN" ]; then printf '%s\\n' username=x-access-token "password=$GITHUB_TOKEN"; fi; }; f`;
3630
3735
  defaultCloneRepo = (repo, token, dir) => {
3631
- fs9.mkdirSync(path10.dirname(dir), { recursive: true });
3736
+ fs10.mkdirSync(path11.dirname(dir), { recursive: true });
3632
3737
  const clone = buildCloneProcess(repo, token);
3633
- return new Promise((resolve20, reject) => {
3738
+ return new Promise((resolve21, reject) => {
3634
3739
  const child = spawn2("git", ["clone", "--depth=1", clone.url, dir], {
3635
3740
  env: clone.env,
3636
3741
  stdio: "inherit"
@@ -3650,7 +3755,7 @@ var init_repoWorkspace = __esm({
3650
3755
  }
3651
3756
  } catch {
3652
3757
  }
3653
- resolve20();
3758
+ resolve21();
3654
3759
  });
3655
3760
  child.on("error", reject);
3656
3761
  });
@@ -3722,8 +3827,8 @@ var init_fetchRepoMcp = __esm({
3722
3827
  });
3723
3828
 
3724
3829
  // src/agent.ts
3725
- import * as fs10 from "fs";
3726
- import * as path11 from "path";
3830
+ import * as fs11 from "fs";
3831
+ import * as path12 from "path";
3727
3832
  import { query } from "@anthropic-ai/claude-agent-sdk";
3728
3833
  function classifySubtype(subtype) {
3729
3834
  if (!subtype) return "generic_failed";
@@ -3792,8 +3897,8 @@ function buildAgentEnvironment(baseEnv, repoToken, requestEnvironment) {
3792
3897
  }
3793
3898
  async function runAgent(opts) {
3794
3899
  const ndjsonDir = opts.ndjsonDir ?? agentRunDir(opts.cwd);
3795
- fs10.mkdirSync(ndjsonDir, { recursive: true });
3796
- const ndjsonPath = path11.join(ndjsonDir, "last-run.jsonl");
3900
+ fs11.mkdirSync(ndjsonDir, { recursive: true });
3901
+ const ndjsonPath = path12.join(ndjsonDir, "last-run.jsonl");
3797
3902
  const env = buildAgentEnvironment(process.env, opts.repoToken, opts.environment);
3798
3903
  if (opts.litellmUrl) {
3799
3904
  env.ANTHROPIC_BASE_URL = opts.litellmUrl;
@@ -3811,10 +3916,12 @@ async function runAgent(opts) {
3811
3916
  let getSubmitted;
3812
3917
  const invokedSubagents = /* @__PURE__ */ new Set();
3813
3918
  const subagentInvocationHook = createSubagentInvocationHook(invokedSubagents);
3919
+ const outputContractPostWriteHook = opts.outputContract ? createOutputContractPostWriteHook(opts.outputContract) : null;
3920
+ const outputContractStopHook = opts.outputContract ? createOutputContractStopHook(opts.outputContract) : null;
3814
3921
  for (let attempt = 0; ; attempt++) {
3815
3922
  let ndjsonWriteFailed = false;
3816
3923
  let ndjsonWriteError;
3817
- const fullLog = fs10.createWriteStream(ndjsonPath, { flags: "w" });
3924
+ const fullLog = fs11.createWriteStream(ndjsonPath, { flags: "w" });
3818
3925
  fullLog.on("error", (err) => {
3819
3926
  ndjsonWriteFailed = true;
3820
3927
  ndjsonWriteError = err instanceof Error ? err.message : String(err);
@@ -3851,8 +3958,21 @@ async function runAgent(opts) {
3851
3958
  {
3852
3959
  matcher: "Agent",
3853
3960
  hooks: [subagentInvocationHook]
3854
- }
3855
- ]
3961
+ },
3962
+ ...outputContractPostWriteHook ? [
3963
+ {
3964
+ matcher: "Write",
3965
+ hooks: [outputContractPostWriteHook]
3966
+ }
3967
+ ] : []
3968
+ ],
3969
+ ...outputContractStopHook ? {
3970
+ Stop: [
3971
+ {
3972
+ hooks: [outputContractStopHook]
3973
+ }
3974
+ ]
3975
+ } : {}
3856
3976
  }
3857
3977
  };
3858
3978
  const additionalDirectories = new Set(opts.additionalDirectories ?? []);
@@ -3982,10 +4102,10 @@ async function runAgent(opts) {
3982
4102
  let timer;
3983
4103
  let next;
3984
4104
  if (turnTimeoutMs > 0) {
3985
- const timeoutPromise = new Promise((resolve20) => {
4105
+ const timeoutPromise = new Promise((resolve21) => {
3986
4106
  timer = setTimeout(() => {
3987
4107
  timedOut = true;
3988
- resolve20({ done: true, value: void 0 });
4108
+ resolve21({ done: true, value: void 0 });
3989
4109
  }, turnTimeoutMs);
3990
4110
  });
3991
4111
  next = await Promise.race([nextPromise, timeoutPromise]);
@@ -4001,7 +4121,7 @@ async function runAgent(opts) {
4001
4121
  try {
4002
4122
  await Promise.race([
4003
4123
  iterator.return(void 0).catch(() => void 0),
4004
- new Promise((resolve20) => setTimeout(resolve20, 1e4).unref())
4124
+ new Promise((resolve21) => setTimeout(resolve21, 1e4).unref())
4005
4125
  ]);
4006
4126
  } catch {
4007
4127
  }
@@ -4184,6 +4304,7 @@ var init_agent = __esm({
4184
4304
  init_claudeBinary();
4185
4305
  init_config();
4186
4306
  init_format();
4307
+ init_outputContractHooks();
4187
4308
  init_runtimePaths();
4188
4309
  init_subagents();
4189
4310
  DEFAULT_ALLOWED_TOOLS = ["Bash", "Edit", "Read", "Write", "Glob", "Grep"];
@@ -4204,8 +4325,8 @@ var init_agent = __esm({
4204
4325
  });
4205
4326
 
4206
4327
  // src/agents.ts
4207
- import * as fs11 from "fs";
4208
- import * as path12 from "path";
4328
+ import * as fs12 from "fs";
4329
+ import * as path13 from "path";
4209
4330
  function stripFrontmatter(raw) {
4210
4331
  const match = /^---\n[\s\S]*?\n---\n?([\s\S]*)$/.exec(raw);
4211
4332
  return (match ? match[1] : raw).trim();
@@ -4214,8 +4335,8 @@ function loadAgentIdentity(cwd, slug, agentsDir = agentsRoot(cwd)) {
4214
4335
  const trimmed = slug.trim();
4215
4336
  if (!trimmed) throw new Error("loadAgentIdentity: empty agent slug");
4216
4337
  const agentPath = resolveAgentFile2(cwd, trimmed, agentsDir);
4217
- if (fs11.existsSync(agentPath)) {
4218
- const body = stripFrontmatter(fs11.readFileSync(agentPath, "utf-8"));
4338
+ if (fs12.existsSync(agentPath)) {
4339
+ const body = stripFrontmatter(fs12.readFileSync(agentPath, "utf-8"));
4219
4340
  if (body) return body;
4220
4341
  const builtinForEmpty = BUILTIN_AGENTS[trimmed];
4221
4342
  if (builtinForEmpty) return builtinForEmpty;
@@ -4226,8 +4347,8 @@ function loadAgentIdentity(cwd, slug, agentsDir = agentsRoot(cwd)) {
4226
4347
  throw new Error(`loadAgentIdentity: agent '${trimmed}' declared but ${agentPath} does not exist`);
4227
4348
  }
4228
4349
  function resolveAgentFile2(cwd, slug, agentsDir = agentsRoot(cwd)) {
4229
- const localPath = path12.resolve(cwd, agentsDir, `${slug}.md`);
4230
- if (fs11.existsSync(localPath)) return localPath;
4350
+ const localPath = path13.resolve(cwd, agentsDir, `${slug}.md`);
4351
+ if (fs12.existsSync(localPath)) return localPath;
4231
4352
  return localPath;
4232
4353
  }
4233
4354
  function frameAgentIdentity(slug, agent) {
@@ -4259,14 +4380,14 @@ var init_agents = __esm({
4259
4380
  });
4260
4381
 
4261
4382
  // src/task-artifacts.ts
4262
- import fs12 from "fs";
4263
- import path13 from "path";
4383
+ import fs13 from "fs";
4384
+ import path14 from "path";
4264
4385
  import posixPath from "path/posix";
4265
4386
  function prepareTaskArtifactsDir(cwd, taskId) {
4266
4387
  const safeId = String(taskId).replace(/[^a-zA-Z0-9._-]/g, "_");
4267
4388
  const absDir = runtimeStatePath(cwd, "task-artifacts", safeId);
4268
4389
  const relDir = absDir;
4269
- fs12.mkdirSync(absDir, { recursive: true });
4390
+ fs13.mkdirSync(absDir, { recursive: true });
4270
4391
  return { taskId: safeId, absDir, relDir };
4271
4392
  }
4272
4393
  function initializeTaskArtifacts(artifacts, metadata = { taskType: "job" }) {
@@ -4296,16 +4417,16 @@ function initializeTaskArtifacts(artifacts, metadata = { taskType: "job" }) {
4296
4417
  "handoff-notes.md": "Baseline handoff: the agent did not provide additional notes.\n"
4297
4418
  };
4298
4419
  for (const file of TASK_ARTIFACT_FILES) {
4299
- const full = path13.join(artifacts.absDir, file);
4300
- if (!fs12.existsSync(full)) fs12.writeFileSync(full, defaults[file], "utf8");
4420
+ const full = path14.join(artifacts.absDir, file);
4421
+ if (!fs13.existsSync(full)) fs13.writeFileSync(full, defaults[file], "utf8");
4301
4422
  }
4302
4423
  }
4303
4424
  function verifyTaskArtifacts(absDir) {
4304
4425
  const missing = [];
4305
4426
  for (const name of TASK_ARTIFACT_FILES) {
4306
- const full = path13.join(absDir, name);
4427
+ const full = path14.join(absDir, name);
4307
4428
  try {
4308
- const stat = fs12.statSync(full);
4429
+ const stat = fs13.statSync(full);
4309
4430
  if (!stat.isFile() || stat.size === 0) missing.push(name);
4310
4431
  } catch {
4311
4432
  missing.push(name);
@@ -4321,11 +4442,11 @@ async function persistTaskArtifactsToState(config, _cwd, artifacts) {
4321
4442
  if (hasStateBackendConfig() && tenantId2) {
4322
4443
  const backend = createStateBackendFromEnv();
4323
4444
  for (const file of TASK_ARTIFACT_FILES) {
4324
- const full = path13.join(artifacts.absDir, file);
4325
- if (!fs12.existsSync(full)) continue;
4326
- const stat = fs12.statSync(full);
4445
+ const full = path14.join(artifacts.absDir, file);
4446
+ if (!fs13.existsSync(full)) continue;
4447
+ const stat = fs13.statSync(full);
4327
4448
  if (!stat.isFile() || stat.size === 0) continue;
4328
- const content = fs12.readFileSync(full, "utf-8");
4449
+ const content = fs13.readFileSync(full, "utf-8");
4329
4450
  const kind = file.replace(/\.(json|md)$/, "");
4330
4451
  let doc = content;
4331
4452
  if (file.endsWith(".json")) {
@@ -4625,15 +4746,15 @@ function validateWorkflow(value, options = {}) {
4625
4746
  }
4626
4747
  return issues;
4627
4748
  }
4628
- function validateInputBindings(value, path54, issues, declaredInputs) {
4749
+ function validateInputBindings(value, path55, issues, declaredInputs) {
4629
4750
  if (value === void 0) return;
4630
4751
  const bindings = asRecord(value);
4631
4752
  if (!bindings || Object.keys(bindings).length === 0) {
4632
- issue(issues, "invalid_inputs", path54, "workflow step inputs must contain at least one named mapping");
4753
+ issue(issues, "invalid_inputs", path55, "workflow step inputs must contain at least one named mapping");
4633
4754
  return;
4634
4755
  }
4635
4756
  for (const [name, value2] of Object.entries(bindings)) {
4636
- const bindingPath = `${path54}.${name}`;
4757
+ const bindingPath = `${path55}.${name}`;
4637
4758
  if (!/^[A-Za-z_][A-Za-z0-9_-]*$/.test(name)) {
4638
4759
  issue(issues, "invalid_input_name", bindingPath, `workflow input name ${name} is invalid`);
4639
4760
  }
@@ -4652,7 +4773,7 @@ function validateInputBindings(value, path54, issues, declaredInputs) {
4652
4773
  }
4653
4774
  }
4654
4775
  }
4655
- function validateInputBindingSources(value, path54, issues, capabilitiesByStep, capabilityOutputs) {
4776
+ function validateInputBindingSources(value, path55, issues, capabilitiesByStep, capabilityOutputs) {
4656
4777
  const bindings = asRecord(value);
4657
4778
  if (!bindings) return;
4658
4779
  for (const [name, rawBinding] of Object.entries(bindings)) {
@@ -4665,7 +4786,7 @@ function validateInputBindingSources(value, path54, issues, capabilitiesByStep,
4665
4786
  issue(
4666
4787
  issues,
4667
4788
  "missing_input_step",
4668
- `${path54}.${name}.from`,
4789
+ `${path55}.${name}.from`,
4669
4790
  `workflow input mapping references missing step ${sourceStep ?? "<none>"}`
4670
4791
  );
4671
4792
  continue;
@@ -4676,7 +4797,7 @@ function validateInputBindingSources(value, path54, issues, capabilitiesByStep,
4676
4797
  issue(
4677
4798
  issues,
4678
4799
  "undeclared_step_output",
4679
- `${path54}.${name}.from`,
4800
+ `${path55}.${name}.from`,
4680
4801
  `workflow input mapping reads ${outputPath}, but step ${sourceStep} does not declare it`
4681
4802
  );
4682
4803
  }
@@ -4685,11 +4806,11 @@ function validateInputBindingSources(value, path54, issues, capabilitiesByStep,
4685
4806
  function formatWorkflowValidationIssues(issues) {
4686
4807
  return issues.map((entry) => `${entry.path}: ${entry.message}`);
4687
4808
  }
4688
- function validateDataMatch(value, path54, issues, capabilityOutputs) {
4809
+ function validateDataMatch(value, path55, issues, capabilityOutputs) {
4689
4810
  if (value === void 0) return;
4690
4811
  const match = asRecord(value);
4691
4812
  if (!match || Object.keys(match).length === 0) {
4692
- issue(issues, "invalid_condition", path54, "workflow condition must contain at least one match");
4813
+ issue(issues, "invalid_condition", path55, "workflow condition must contain at least one match");
4693
4814
  return;
4694
4815
  }
4695
4816
  for (const [field, expected] of Object.entries(match)) {
@@ -4697,7 +4818,7 @@ function validateDataMatch(value, path54, issues, capabilityOutputs) {
4697
4818
  issue(
4698
4819
  issues,
4699
4820
  "invalid_data_path",
4700
- `${path54}.${field}`,
4821
+ `${path55}.${field}`,
4701
4822
  `workflow condition must read from facts, evidence, artifacts, result, workflow, or lastOutcome`
4702
4823
  );
4703
4824
  }
@@ -4705,12 +4826,12 @@ function validateDataMatch(value, path54, issues, capabilityOutputs) {
4705
4826
  issue(
4706
4827
  issues,
4707
4828
  "undeclared_result_path",
4708
- `${path54}.${field}`,
4829
+ `${path55}.${field}`,
4709
4830
  `workflow condition reads ${field}, but the source capability does not declare it`
4710
4831
  );
4711
4832
  }
4712
4833
  if (!isComparable(expected)) {
4713
- issue(issues, "invalid_condition_value", `${path54}.${field}`, "workflow condition value must be a JSON scalar");
4834
+ issue(issues, "invalid_condition_value", `${path55}.${field}`, "workflow condition value must be a JSON scalar");
4714
4835
  }
4715
4836
  }
4716
4837
  }
@@ -4734,8 +4855,8 @@ function isJsonValue(value) {
4734
4855
  if (!value || typeof value !== "object") return false;
4735
4856
  return Object.values(value).every(isJsonValue);
4736
4857
  }
4737
- function issue(issues, code, path54, message) {
4738
- issues.push({ code, path: path54, message });
4858
+ function issue(issues, code, path55, message) {
4859
+ issues.push({ code, path: path55, message });
4739
4860
  }
4740
4861
  var SAFE_NAME, SAFE_STEP_ID, SAFE_DATA_PATH, SAFE_INPUT_SOURCE, SUPPORTED_STEP_FIELDS, SUPPORTED_TRANSITION_FIELDS;
4741
4862
  var init_workflowValidation = __esm({
@@ -4767,8 +4888,8 @@ var init_workflowValidation = __esm({
4767
4888
  });
4768
4889
 
4769
4890
  // src/workflowDefinitions.ts
4770
- import * as fs18 from "fs";
4771
- import * as path19 from "path";
4891
+ import * as fs19 from "fs";
4892
+ import * as path20 from "path";
4772
4893
  function isWorkflowDefinitionId(value) {
4773
4894
  return WORKFLOW_ID_PATTERN.test(value);
4774
4895
  }
@@ -4813,12 +4934,12 @@ function readWorkflowDefinition(_config, cwd, id) {
4813
4934
  const root = cwd ?? process.cwd();
4814
4935
  const relativePath = workflowDefinitionPath(id);
4815
4936
  const candidates = [
4816
- path19.join(root, ".kody-engine", "runtime", relativePath),
4817
- path19.join(definitionsRoot(root), relativePath)
4937
+ path20.join(root, ".kody-engine", "runtime", relativePath),
4938
+ path20.join(definitionsRoot(root), relativePath)
4818
4939
  ];
4819
4940
  for (const filePath of candidates) {
4820
- if (!fs18.existsSync(filePath)) continue;
4821
- const workflow = parseWorkflowDefinition(fs18.readFileSync(filePath, "utf8"));
4941
+ if (!fs19.existsSync(filePath)) continue;
4942
+ const workflow = parseWorkflowDefinition(fs19.readFileSync(filePath, "utf8"));
4822
4943
  if (workflow) return workflow;
4823
4944
  }
4824
4945
  return null;
@@ -4826,7 +4947,7 @@ function readWorkflowDefinition(_config, cwd, id) {
4826
4947
  function workflowDefinitionToCapabilityFolder(id, workflow, source = workflowDefinitionPath(id)) {
4827
4948
  return {
4828
4949
  slug: id,
4829
- dir: path19.dirname(source),
4950
+ dir: path20.dirname(source),
4830
4951
  profilePath: source,
4831
4952
  bodyPath: source,
4832
4953
  title: workflow.name,
@@ -4882,7 +5003,7 @@ var init_workflowDefinitions = __esm({
4882
5003
 
4883
5004
  // src/gha.ts
4884
5005
  import { execFileSync as execFileSync2 } from "child_process";
4885
- import * as fs21 from "fs";
5006
+ import * as fs22 from "fs";
4886
5007
  function getRunUrl() {
4887
5008
  const server = process.env.GITHUB_SERVER_URL;
4888
5009
  const repo = process.env.GITHUB_REPOSITORY;
@@ -4893,10 +5014,10 @@ function getRunUrl() {
4893
5014
  function reactToTriggerComment(cwd) {
4894
5015
  if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
4895
5016
  const eventPath = process.env.GITHUB_EVENT_PATH;
4896
- if (!eventPath || !fs21.existsSync(eventPath)) return;
5017
+ if (!eventPath || !fs22.existsSync(eventPath)) return;
4897
5018
  let event = null;
4898
5019
  try {
4899
- event = JSON.parse(fs21.readFileSync(eventPath, "utf-8"));
5020
+ event = JSON.parse(fs22.readFileSync(eventPath, "utf-8"));
4900
5021
  } catch {
4901
5022
  return;
4902
5023
  }
@@ -5030,57 +5151,6 @@ var init_agencyBoundaryEval = __esm({
5030
5151
  }
5031
5152
  });
5032
5153
 
5033
- // src/agency/capability-contract-validation.ts
5034
- import Ajv from "ajv";
5035
- function validateCapabilityContractValue(boundary, schema, value) {
5036
- const validate = validator.compile(schema);
5037
- if (!validate(value)) {
5038
- throw new CapabilityContractValidationError(boundary, validate.errors ?? []);
5039
- }
5040
- }
5041
- function capabilityContractInput(inputs, args, capabilityId, contractProperties = []) {
5042
- const isGenericRunnerInput = inputs.some((input) => input.name === "input") && Object.hasOwn(args, "input");
5043
- if (!isGenericRunnerInput) {
5044
- const isParameterlessGenericRunner = (inputs.some((input) => input.name === "capability") || args.capability === capabilityId || !contractProperties.includes("capability")) && Object.hasOwn(args, "capability");
5045
- if (!isParameterlessGenericRunner) return args;
5046
- const { capability: _routingCapability, ...businessArgs } = args;
5047
- return businessArgs;
5048
- }
5049
- const value = args.input;
5050
- if (typeof value !== "string") return value;
5051
- try {
5052
- return JSON.parse(value);
5053
- } catch {
5054
- return value;
5055
- }
5056
- }
5057
- var validator, CapabilityContractValidationError;
5058
- var init_capability_contract_validation = __esm({
5059
- "src/agency/capability-contract-validation.ts"() {
5060
- "use strict";
5061
- validator = new Ajv({
5062
- allErrors: true,
5063
- strict: true,
5064
- validateFormats: false
5065
- });
5066
- CapabilityContractValidationError = class extends Error {
5067
- constructor(boundary, errors) {
5068
- const details = errors.map((error) => {
5069
- const location = error.instancePath || "$";
5070
- const property = error.keyword === "additionalProperties" && typeof error.params.additionalProperty === "string" ? ` (${error.params.additionalProperty})` : "";
5071
- return `${location}: ${error.message ?? error.keyword}${property}`;
5072
- }).join("; ");
5073
- super(`Capability ${boundary} does not match its declared contract: ${details}`);
5074
- this.boundary = boundary;
5075
- this.errors = errors;
5076
- this.name = "CapabilityContractValidationError";
5077
- }
5078
- boundary;
5079
- errors;
5080
- };
5081
- }
5082
- });
5083
-
5084
5154
  // src/capabilityReport.ts
5085
5155
  function parseCapabilityReportsFromText(text2) {
5086
5156
  const reports = [];
@@ -5477,15 +5547,15 @@ var init_lifecycles = __esm({
5477
5547
 
5478
5548
  // src/profile.ts
5479
5549
  import { createHash as createHash3 } from "crypto";
5480
- import * as fs22 from "fs";
5481
- import * as path21 from "path";
5550
+ import * as fs23 from "fs";
5551
+ import * as path22 from "path";
5482
5552
  function loadProfile(profilePath) {
5483
- if (!fs22.existsSync(profilePath)) {
5553
+ if (!fs23.existsSync(profilePath)) {
5484
5554
  throw new ProfileError(profilePath, "file not found");
5485
5555
  }
5486
5556
  let raw;
5487
5557
  try {
5488
- raw = JSON.parse(fs22.readFileSync(profilePath, "utf-8"));
5558
+ raw = JSON.parse(fs23.readFileSync(profilePath, "utf-8"));
5489
5559
  } catch (err) {
5490
5560
  throw new ProfileError(profilePath, `invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
5491
5561
  }
@@ -5497,7 +5567,7 @@ function loadProfile(profilePath) {
5497
5567
  const unknownKeys = Object.keys(r).filter((k) => !KNOWN_PROFILE_KEYS.has(k));
5498
5568
  if (unknownKeys.length > 0) {
5499
5569
  process.stderr.write(
5500
- `[kody profile] ${path21.basename(path21.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
5570
+ `[kody profile] ${path22.basename(path22.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
5501
5571
  `
5502
5572
  );
5503
5573
  }
@@ -5507,7 +5577,7 @@ function loadProfile(profilePath) {
5507
5577
  if (!refPath) {
5508
5578
  throw new ProfileError(profilePath, `capability references unknown implementation '${execRef}'`);
5509
5579
  }
5510
- if (path21.resolve(refPath) === path21.resolve(profilePath)) {
5580
+ if (path22.resolve(refPath) === path22.resolve(profilePath)) {
5511
5581
  } else {
5512
5582
  const base = loadProfile(refPath);
5513
5583
  return {
@@ -5605,8 +5675,8 @@ function loadProfile(profilePath) {
5605
5675
  // Phase 5 in-process handoff opt-in. Default false; containers
5606
5676
  // flip to true after end-to-end verification.
5607
5677
  preloadContext: r.preloadContext === true,
5608
- dir: path21.dirname(profilePath),
5609
- promptTemplates: readPromptTemplates(path21.dirname(profilePath))
5678
+ dir: path22.dirname(profilePath),
5679
+ promptTemplates: readPromptTemplates(path22.dirname(profilePath))
5610
5680
  };
5611
5681
  if (lifecycle) {
5612
5682
  applyLifecycle(profile, profilePath);
@@ -5641,19 +5711,19 @@ function loadProfile(profilePath) {
5641
5711
  return profile;
5642
5712
  }
5643
5713
  function compileRuntimeDocument(runtimePath, document) {
5644
- if (path21.basename(runtimePath) !== "runtime.json") return document;
5714
+ if (path22.basename(runtimePath) !== "runtime.json") return document;
5645
5715
  if (document.adapter !== "kody-engine-profile") {
5646
5716
  throw new ProfileError(runtimePath, "unsupported runtime adapter document");
5647
5717
  }
5648
- const implementationDir = path21.dirname(runtimePath);
5649
- const implementation = readJsonObject(path21.join(implementationDir, "definition.json"), "Implementation definition");
5650
- const definitionsRoot2 = path21.dirname(path21.dirname(implementationDir));
5718
+ const implementationDir = path22.dirname(runtimePath);
5719
+ const implementation = readJsonObject(path22.join(implementationDir, "definition.json"), "Implementation definition");
5720
+ const definitionsRoot2 = path22.dirname(path22.dirname(implementationDir));
5651
5721
  const capabilityId = implementation.capabilityRef && typeof implementation.capabilityRef === "object" && !Array.isArray(implementation.capabilityRef) ? implementation.capabilityRef.id : void 0;
5652
5722
  if (typeof capabilityId !== "string" || !capabilityId) {
5653
5723
  throw new ProfileError(runtimePath, "Implementation capabilityRef is invalid");
5654
5724
  }
5655
5725
  const capability = readJsonObject(
5656
- path21.join(definitionsRoot2, "capabilities", capabilityId, "definition.json"),
5726
+ path22.join(definitionsRoot2, "capabilities", capabilityId, "definition.json"),
5657
5727
  "Capability definition"
5658
5728
  );
5659
5729
  const {
@@ -5692,7 +5762,7 @@ function canonical(value) {
5692
5762
  }
5693
5763
  function readJsonObject(filePath, label) {
5694
5764
  try {
5695
- const value = JSON.parse(fs22.readFileSync(filePath, "utf-8"));
5765
+ const value = JSON.parse(fs23.readFileSync(filePath, "utf-8"));
5696
5766
  if (!value || typeof value !== "object" || Array.isArray(value)) {
5697
5767
  throw new Error("must be an object");
5698
5768
  }
@@ -5710,17 +5780,17 @@ function readPromptTemplates(dir) {
5710
5780
  const out = {};
5711
5781
  const read = (p) => {
5712
5782
  try {
5713
- out[p] = fs22.readFileSync(p, "utf-8");
5783
+ out[p] = fs23.readFileSync(p, "utf-8");
5714
5784
  } catch {
5715
5785
  }
5716
5786
  };
5717
- read(path21.join(dir, "prompt.md"));
5718
- read(path21.join(dir, "capability.md"));
5719
- read(path21.join(dir, "capability.md"));
5787
+ read(path22.join(dir, "prompt.md"));
5788
+ read(path22.join(dir, "capability.md"));
5789
+ read(path22.join(dir, "capability.md"));
5720
5790
  try {
5721
- const promptsDir = path21.join(dir, "prompts");
5722
- for (const ent of fs22.readdirSync(promptsDir)) {
5723
- if (ent.endsWith(".md")) read(path21.join(promptsDir, ent));
5791
+ const promptsDir = path22.join(dir, "prompts");
5792
+ for (const ent of fs23.readdirSync(promptsDir)) {
5793
+ if (ent.endsWith(".md")) read(path22.join(promptsDir, ent));
5724
5794
  }
5725
5795
  } catch {
5726
5796
  }
@@ -6497,16 +6567,16 @@ var init_state = __esm({
6497
6567
  });
6498
6568
 
6499
6569
  // src/prompt.ts
6500
- import * as fs23 from "fs";
6501
- import * as path22 from "path";
6570
+ import * as fs24 from "fs";
6571
+ import * as path23 from "path";
6502
6572
  function loadProjectConventions(projectDir) {
6503
6573
  const out = [];
6504
6574
  for (const rel of CONVENTION_FILES) {
6505
- const abs = path22.join(projectDir, rel);
6506
- if (!fs23.existsSync(abs)) continue;
6575
+ const abs = path23.join(projectDir, rel);
6576
+ if (!fs24.existsSync(abs)) continue;
6507
6577
  let content;
6508
6578
  try {
6509
- content = fs23.readFileSync(abs, "utf-8");
6579
+ content = fs24.readFileSync(abs, "utf-8");
6510
6580
  } catch {
6511
6581
  continue;
6512
6582
  }
@@ -6741,8 +6811,8 @@ var loadMemoryContext_exports = {};
6741
6811
  __export(loadMemoryContext_exports, {
6742
6812
  loadMemoryContext: () => loadMemoryContext
6743
6813
  });
6744
- import * as fs24 from "fs";
6745
- import * as path23 from "path";
6814
+ import * as fs25 from "fs";
6815
+ import * as path24 from "path";
6746
6816
  function formatBlockFromBackend(docs) {
6747
6817
  const pages = docs.flatMap((record2) => {
6748
6818
  if (!record2.doc || typeof record2.doc !== "object") return [];
@@ -6765,21 +6835,21 @@ function collectPages(memoryAbs) {
6765
6835
  walkMd(memoryAbs, (file) => {
6766
6836
  let stat;
6767
6837
  try {
6768
- stat = fs24.statSync(file);
6838
+ stat = fs25.statSync(file);
6769
6839
  } catch {
6770
6840
  return;
6771
6841
  }
6772
6842
  let raw;
6773
6843
  try {
6774
- raw = fs24.readFileSync(file, "utf-8");
6844
+ raw = fs25.readFileSync(file, "utf-8");
6775
6845
  } catch {
6776
6846
  return;
6777
6847
  }
6778
6848
  const fm = raw.match(/^---\s*\n([\s\S]*?)\n---/);
6779
- const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path23.basename(file, ".md");
6849
+ const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path24.basename(file, ".md");
6780
6850
  const updated = fm?.[1]?.match(/^updated:\s*([0-9T:.+\-Z]+)/m)?.[1]?.trim() ?? "";
6781
6851
  out.push({
6782
- relPath: path23.relative(memoryAbs, file),
6852
+ relPath: path24.relative(memoryAbs, file),
6783
6853
  title,
6784
6854
  updated,
6785
6855
  content: raw.length > PER_PAGE_MAX_BYTES ? raw.slice(0, PER_PAGE_MAX_BYTES) + TRUNCATED_SUFFIX2 : raw,
@@ -6847,16 +6917,16 @@ function walkMd(root, visit) {
6847
6917
  const dir = stack.pop();
6848
6918
  let names;
6849
6919
  try {
6850
- names = fs24.readdirSync(dir);
6920
+ names = fs25.readdirSync(dir);
6851
6921
  } catch {
6852
6922
  continue;
6853
6923
  }
6854
6924
  for (const name of names) {
6855
6925
  if (name.startsWith(".")) continue;
6856
- const full = path23.join(dir, name);
6926
+ const full = path24.join(dir, name);
6857
6927
  let stat;
6858
6928
  try {
6859
- stat = fs24.statSync(full);
6929
+ stat = fs25.statSync(full);
6860
6930
  } catch {
6861
6931
  continue;
6862
6932
  }
@@ -6891,8 +6961,8 @@ var init_loadMemoryContext = __esm({
6891
6961
  }
6892
6962
  return;
6893
6963
  }
6894
- const memoryAbs = path23.join(ctx.cwd, MEMORY_DIR_RELATIVE);
6895
- if (!fs24.existsSync(memoryAbs)) {
6964
+ const memoryAbs = path24.join(ctx.cwd, MEMORY_DIR_RELATIVE);
6965
+ if (!fs25.existsSync(memoryAbs)) {
6896
6966
  ctx.data.memoryContext = "";
6897
6967
  return;
6898
6968
  }
@@ -6936,11 +7006,11 @@ var init_loadCoverageRules = __esm({
6936
7006
 
6937
7007
  // src/container.ts
6938
7008
  import { execFileSync as execFileSync3 } from "child_process";
6939
- import * as fs25 from "fs";
7009
+ import * as fs26 from "fs";
6940
7010
  function getProfileInputsForChild(profileName, _cwd) {
6941
7011
  try {
6942
7012
  const profilePath = resolveProfilePath(profileName);
6943
- if (!fs25.existsSync(profilePath)) return null;
7013
+ if (!fs26.existsSync(profilePath)) return null;
6944
7014
  return loadProfile(profilePath).inputs;
6945
7015
  } catch {
6946
7016
  return null;
@@ -7404,10 +7474,10 @@ var init_lifecycleLabels = __esm({
7404
7474
 
7405
7475
  // src/litellm.ts
7406
7476
  import { execFileSync as execFileSync4, spawn as spawn4 } from "child_process";
7407
- import * as fs26 from "fs";
7477
+ import * as fs27 from "fs";
7408
7478
  import * as net from "net";
7409
7479
  import * as os4 from "os";
7410
- import * as path24 from "path";
7480
+ import * as path25 from "path";
7411
7481
  async function checkLitellmHealth(url) {
7412
7482
  try {
7413
7483
  const response = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3e3) });
@@ -7477,7 +7547,7 @@ function locateLitellmScript() {
7477
7547
  }
7478
7548
  function resolveLitellmCommand() {
7479
7549
  const imageScript = "/opt/venv/bin/litellm";
7480
- if (fs26.existsSync(imageScript)) return imageScript;
7550
+ if (fs27.existsSync(imageScript)) return imageScript;
7481
7551
  try {
7482
7552
  execFileSync4("which", ["litellm"], { timeout: 3e3, stdio: "pipe" });
7483
7553
  return "litellm";
@@ -7520,13 +7590,13 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
7520
7590
  const spawnProxy = () => {
7521
7591
  const portMatch = activeUrl.match(/:(\d+)/);
7522
7592
  const port = portMatch ? portMatch[1] : "4000";
7523
- const configPath = path24.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.yaml`);
7524
- fs26.writeFileSync(configPath, generateLitellmConfigYaml(model));
7593
+ const configPath = path25.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.yaml`);
7594
+ fs27.writeFileSync(configPath, generateLitellmConfigYaml(model));
7525
7595
  const args = ["--config", configPath, "--port", port];
7526
- const nextLogPath = path24.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.log`);
7527
- const outFd = fs26.openSync(nextLogPath, "w");
7596
+ const nextLogPath = path25.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.log`);
7597
+ const outFd = fs27.openSync(nextLogPath, "w");
7528
7598
  child = spawn4(cmd, args, { stdio: ["ignore", outFd, outFd], detached: true, env: childEnv });
7529
- fs26.closeSync(outFd);
7599
+ fs27.closeSync(outFd);
7530
7600
  logPath = nextLogPath;
7531
7601
  };
7532
7602
  const waitForHealth = async () => {
@@ -7540,7 +7610,7 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
7540
7610
  const readLogTail = () => {
7541
7611
  if (!logPath) return "";
7542
7612
  try {
7543
- return fs26.readFileSync(logPath, "utf-8").slice(-2e3);
7613
+ return fs27.readFileSync(logPath, "utf-8").slice(-2e3);
7544
7614
  } catch {
7545
7615
  return "";
7546
7616
  }
@@ -7613,20 +7683,20 @@ async function nextAvailableLitellmUrl(url) {
7613
7683
  throw new Error(`no free LiteLLM port found after ${startPort}`);
7614
7684
  }
7615
7685
  function canListen(port, host) {
7616
- return new Promise((resolve20) => {
7686
+ return new Promise((resolve21) => {
7617
7687
  const server = net.createServer();
7618
- server.once("error", () => resolve20(false));
7688
+ server.once("error", () => resolve21(false));
7619
7689
  server.once("listening", () => {
7620
- server.close(() => resolve20(true));
7690
+ server.close(() => resolve21(true));
7621
7691
  });
7622
7692
  server.listen(port, host);
7623
7693
  });
7624
7694
  }
7625
7695
  function readDotenvApiKeys(projectDir) {
7626
- const dotenvPath = path24.join(projectDir, ".env");
7627
- if (!fs26.existsSync(dotenvPath)) return {};
7696
+ const dotenvPath = path25.join(projectDir, ".env");
7697
+ if (!fs27.existsSync(dotenvPath)) return {};
7628
7698
  const result = {};
7629
- for (const rawLine of fs26.readFileSync(dotenvPath, "utf-8").split("\n")) {
7699
+ for (const rawLine of fs27.readFileSync(dotenvPath, "utf-8").split("\n")) {
7630
7700
  const line = rawLine.trim();
7631
7701
  if (!line || line.startsWith("#")) continue;
7632
7702
  const match = line.match(/^([A-Z_][A-Z0-9_]*_API_KEY)=(.*)$/);
@@ -8285,8 +8355,8 @@ var init_pushWithRetry = __esm({
8285
8355
 
8286
8356
  // src/commit.ts
8287
8357
  import { execFileSync as execFileSync6 } from "child_process";
8288
- import * as fs27 from "fs";
8289
- import * as path25 from "path";
8358
+ import * as fs28 from "fs";
8359
+ import * as path26 from "path";
8290
8360
  function isGitHubYamlPath(filePath) {
8291
8361
  const normalized = filePath.replace(/^\.\/+/, "");
8292
8362
  return normalized.startsWith(".github/") && /\.ya?ml$/i.test(normalized);
@@ -8328,18 +8398,18 @@ function ensureGitIdentity(cwd) {
8328
8398
  }
8329
8399
  function abortUnfinishedGitOps(cwd) {
8330
8400
  const aborted = [];
8331
- const gitDir = path25.join(cwd ?? process.cwd(), ".git");
8332
- if (!fs27.existsSync(gitDir)) return aborted;
8333
- if (fs27.existsSync(path25.join(gitDir, "MERGE_HEAD"))) {
8401
+ const gitDir = path26.join(cwd ?? process.cwd(), ".git");
8402
+ if (!fs28.existsSync(gitDir)) return aborted;
8403
+ if (fs28.existsSync(path26.join(gitDir, "MERGE_HEAD"))) {
8334
8404
  if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
8335
8405
  }
8336
- if (fs27.existsSync(path25.join(gitDir, "CHERRY_PICK_HEAD"))) {
8406
+ if (fs28.existsSync(path26.join(gitDir, "CHERRY_PICK_HEAD"))) {
8337
8407
  if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
8338
8408
  }
8339
- if (fs27.existsSync(path25.join(gitDir, "REVERT_HEAD"))) {
8409
+ if (fs28.existsSync(path26.join(gitDir, "REVERT_HEAD"))) {
8340
8410
  if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
8341
8411
  }
8342
- if (fs27.existsSync(path25.join(gitDir, "rebase-merge")) || fs27.existsSync(path25.join(gitDir, "rebase-apply"))) {
8412
+ if (fs28.existsSync(path26.join(gitDir, "rebase-merge")) || fs28.existsSync(path26.join(gitDir, "rebase-apply"))) {
8343
8413
  if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
8344
8414
  }
8345
8415
  try {
@@ -8396,7 +8466,7 @@ function normalizeCommitMessage(raw) {
8396
8466
  function commitAndPush(branch, agentMessage, cwd) {
8397
8467
  const allChanged = listChangedFiles(cwd);
8398
8468
  const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
8399
- const mergeHeadExists = fs27.existsSync(path25.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
8469
+ const mergeHeadExists = fs28.existsSync(path26.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
8400
8470
  if (allowedFiles.length === 0 && !mergeHeadExists) {
8401
8471
  return { committed: false, pushed: false, sha: "", message: "" };
8402
8472
  }
@@ -9036,13 +9106,13 @@ var init_state2 = __esm({
9036
9106
  });
9037
9107
 
9038
9108
  // src/goal/runLog.ts
9039
- import * as fs28 from "fs";
9109
+ import * as fs29 from "fs";
9040
9110
  function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
9041
9111
  const logs = goalRunLogs(data);
9042
9112
  const existing = logs[goalId];
9043
- const path54 = existing?.path ?? goalRunLogPath(goalId, data);
9113
+ const path55 = existing?.path ?? goalRunLogPath(goalId, data);
9044
9114
  logs[goalId] = {
9045
- path: path54,
9115
+ path: path55,
9046
9116
  events: [...existing?.events ?? [], buildGoalRunLogEvent(data, goalId, event, at)]
9047
9117
  };
9048
9118
  }
@@ -9378,8 +9448,8 @@ function readGithubEvent() {
9378
9448
  const eventPath = process.env.GITHUB_EVENT_PATH;
9379
9449
  if (!eventPath) return null;
9380
9450
  try {
9381
- if (!fs28.existsSync(eventPath)) return null;
9382
- const parsed = JSON.parse(fs28.readFileSync(eventPath, "utf-8"));
9451
+ if (!fs29.existsSync(eventPath)) return null;
9452
+ const parsed = JSON.parse(fs29.readFileSync(eventPath, "utf-8"));
9383
9453
  return recordValue3(parsed);
9384
9454
  } catch {
9385
9455
  return null;
@@ -9489,8 +9559,8 @@ var init_stateStore = __esm({
9489
9559
  });
9490
9560
 
9491
9561
  // src/goal/targetLoopResolution.ts
9492
- import * as fs29 from "fs";
9493
- import * as path26 from "path";
9562
+ import * as fs30 from "fs";
9563
+ import * as path27 from "path";
9494
9564
  async function resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal) {
9495
9565
  const targetId = loopGoal.loopTarget?.id.trim() ?? "";
9496
9566
  assertSafeGoalId(targetId, "loop target");
@@ -9568,11 +9638,11 @@ function goalInstanceTime(state) {
9568
9638
  return Number.isNaN(parsed) ? 0 : parsed;
9569
9639
  }
9570
9640
  function loadGoalTemplate(cwd, targetId) {
9571
- return readJsonObject2(path26.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
9641
+ return readJsonObject2(path27.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
9572
9642
  }
9573
9643
  function readJsonObject2(filePath) {
9574
- if (!fs29.existsSync(filePath)) return null;
9575
- const parsed = JSON.parse(fs29.readFileSync(filePath, "utf8"));
9644
+ if (!fs30.existsSync(filePath)) return null;
9645
+ const parsed = JSON.parse(fs30.readFileSync(filePath, "utf8"));
9576
9646
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
9577
9647
  throw new Error(`goal template ${filePath} must be a JSON object`);
9578
9648
  }
@@ -9919,15 +9989,15 @@ var init_backendStateBackend = __esm({
9919
9989
  this.jobsDir = opts.jobsDir.replace(/\/+$/, "");
9920
9990
  }
9921
9991
  async load(slug) {
9922
- const path54 = stateFilePath(this.jobsDir, slug);
9992
+ const path55 = stateFilePath(this.jobsDir, slug);
9923
9993
  const loaded = await createStateBackendFromEnv().get(this.tenantId, `capabilities/${slug}`, "job-state");
9924
9994
  if (!loaded) {
9925
- return { path: path54, handle: null, state: initialStateEnvelope("seed"), created: true };
9995
+ return { path: path55, handle: null, state: initialStateEnvelope("seed"), created: true };
9926
9996
  }
9927
9997
  if (!isStateEnvelope(loaded.doc)) {
9928
9998
  throw new Error(`BackendStateBackend: capabilities/${slug} is not a StateEnvelope`);
9929
9999
  }
9930
- return { path: path54, handle: loaded.updatedAt, state: loaded.doc, created: false };
10000
+ return { path: path55, handle: loaded.updatedAt, state: loaded.doc, created: false };
9931
10001
  }
9932
10002
  async save(loaded, next) {
9933
10003
  if (!loaded.created && isStateUnchanged(loaded.state, next)) return false;
@@ -9947,8 +10017,8 @@ var init_backendStateBackend = __esm({
9947
10017
  });
9948
10018
 
9949
10019
  // src/scripts/jobState/localFileBackend.ts
9950
- import * as fs30 from "fs";
9951
- import * as path27 from "path";
10020
+ import * as fs31 from "fs";
10021
+ import * as path28 from "path";
9952
10022
  function sanitizeKey(s) {
9953
10023
  return s.replace(/[^A-Za-z0-9._-]/g, "-");
9954
10024
  }
@@ -10004,7 +10074,7 @@ var init_localFileBackend = __esm({
10004
10074
  if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
10005
10075
  this.cwd = opts.cwd;
10006
10076
  this.jobsDir = opts.jobsDir;
10007
- this.absDir = path27.resolve(opts.cwd, opts.jobsDir);
10077
+ this.absDir = path28.resolve(opts.cwd, opts.jobsDir);
10008
10078
  this.owner = opts.owner;
10009
10079
  this.repo = opts.repo;
10010
10080
  this.cache = opts.cache ?? defaultCacheAdapter();
@@ -10019,7 +10089,7 @@ var init_localFileBackend = __esm({
10019
10089
  `);
10020
10090
  return;
10021
10091
  }
10022
- fs30.mkdirSync(this.absDir, { recursive: true });
10092
+ fs31.mkdirSync(this.absDir, { recursive: true });
10023
10093
  const prefix = this.cacheKeyPrefix();
10024
10094
  const probeKey = `${prefix}probe-${Date.now()}`;
10025
10095
  try {
@@ -10048,7 +10118,7 @@ var init_localFileBackend = __esm({
10048
10118
  `);
10049
10119
  return;
10050
10120
  }
10051
- if (!fs30.existsSync(this.absDir)) {
10121
+ if (!fs31.existsSync(this.absDir)) {
10052
10122
  return;
10053
10123
  }
10054
10124
  const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
@@ -10064,11 +10134,11 @@ var init_localFileBackend = __esm({
10064
10134
  }
10065
10135
  load(slug) {
10066
10136
  const relPath = stateFilePath(this.jobsDir, slug);
10067
- const absPath = path27.resolve(this.cwd, relPath);
10068
- if (!fs30.existsSync(absPath)) {
10137
+ const absPath = path28.resolve(this.cwd, relPath);
10138
+ if (!fs31.existsSync(absPath)) {
10069
10139
  return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
10070
10140
  }
10071
- const raw = fs30.readFileSync(absPath, "utf-8");
10141
+ const raw = fs31.readFileSync(absPath, "utf-8");
10072
10142
  let parsed;
10073
10143
  try {
10074
10144
  parsed = JSON.parse(raw);
@@ -10085,13 +10155,13 @@ var init_localFileBackend = __esm({
10085
10155
  if (!loaded.created && isStateUnchanged(loaded.state, next)) {
10086
10156
  return false;
10087
10157
  }
10088
- const absPath = path27.resolve(this.cwd, loaded.path);
10089
- fs30.mkdirSync(path27.dirname(absPath), { recursive: true });
10158
+ const absPath = path28.resolve(this.cwd, loaded.path);
10159
+ fs31.mkdirSync(path28.dirname(absPath), { recursive: true });
10090
10160
  const body = `${JSON.stringify(next, null, 2)}
10091
10161
  `;
10092
10162
  const tmpPath = `${absPath}.${process.pid}.tmp`;
10093
- fs30.writeFileSync(tmpPath, body, "utf-8");
10094
- fs30.renameSync(tmpPath, absPath);
10163
+ fs31.writeFileSync(tmpPath, body, "utf-8");
10164
+ fs31.renameSync(tmpPath, absPath);
10095
10165
  return true;
10096
10166
  }
10097
10167
  cacheKeyPrefix() {
@@ -10123,7 +10193,7 @@ var init_jobState = __esm({
10123
10193
  });
10124
10194
 
10125
10195
  // src/scripts/goalCapabilityScheduling.ts
10126
- import * as path28 from "path";
10196
+ import * as path29 from "path";
10127
10197
  function isCapabilityCadenceGoal(goal, extra) {
10128
10198
  return extra.scheduleMode === "agentLoop" || extra.scheduler === "agentLoop" || goal.type === "standing" && goal.capabilities.length > 0;
10129
10199
  }
@@ -10179,7 +10249,7 @@ function planTargetLoopSchedule(opts) {
10179
10249
  }
10180
10250
  async function planGoalCapabilitySchedule(opts) {
10181
10251
  const jobsDir = opts.jobsDir ?? capabilitiesRoot(opts.cwd);
10182
- const jobsRoot = path28.resolve(opts.cwd, jobsDir);
10252
+ const jobsRoot = path29.resolve(opts.cwd, jobsDir);
10183
10253
  const now = opts.now ?? /* @__PURE__ */ new Date();
10184
10254
  const at = now.toISOString();
10185
10255
  const backend = resolveBackend({ config: opts.config, cwd: opts.cwd, jobsDir });
@@ -11995,8 +12065,8 @@ var init_classifyByLabel = __esm({
11995
12065
 
11996
12066
  // src/scripts/commitAndPush.ts
11997
12067
  import { createHash as createHash5 } from "crypto";
11998
- import * as fs31 from "fs";
11999
- import * as path29 from "path";
12068
+ import * as fs32 from "fs";
12069
+ import * as path30 from "path";
12000
12070
  function sentinelPathForStage(cwd, profileName, workflowExecutionKey) {
12001
12071
  const runId = resolveRunId();
12002
12072
  const executionSuffix = typeof workflowExecutionKey === "string" && workflowExecutionKey.length > 0 ? `-${createHash5("sha256").update(workflowExecutionKey).digest("hex").slice(0, 16)}` : "";
@@ -12018,9 +12088,9 @@ var init_commitAndPush = __esm({
12018
12088
  }
12019
12089
  const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
12020
12090
  const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name, ctx.data.workflowExecutionKey) : null;
12021
- if (sentinel && fs31.existsSync(sentinel)) {
12091
+ if (sentinel && fs32.existsSync(sentinel)) {
12022
12092
  try {
12023
- const replay = JSON.parse(fs31.readFileSync(sentinel, "utf-8"));
12093
+ const replay = JSON.parse(fs32.readFileSync(sentinel, "utf-8"));
12024
12094
  ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
12025
12095
  if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
12026
12096
  if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
@@ -12080,8 +12150,8 @@ var init_commitAndPush = __esm({
12080
12150
  const result = ctx.data.commitResult;
12081
12151
  if (sentinel && result?.committed) {
12082
12152
  try {
12083
- fs31.mkdirSync(path29.dirname(sentinel), { recursive: true });
12084
- fs31.writeFileSync(
12153
+ fs32.mkdirSync(path30.dirname(sentinel), { recursive: true });
12154
+ fs32.writeFileSync(
12085
12155
  sentinel,
12086
12156
  JSON.stringify(
12087
12157
  {
@@ -12175,8 +12245,8 @@ var init_commitGoalState = __esm({
12175
12245
  });
12176
12246
 
12177
12247
  // src/scripts/composePrompt.ts
12178
- import * as fs32 from "fs";
12179
- import * as path30 from "path";
12248
+ import * as fs33 from "fs";
12249
+ import * as path31 from "path";
12180
12250
  function fenceUntrusted(value) {
12181
12251
  if (value.trim().length === 0) return value;
12182
12252
  const safe = value.replace(/-{3,}\s*END UNTRUSTED INPUT\s*-{3,}/gi, "[END UNTRUSTED INPUT]");
@@ -12300,10 +12370,10 @@ var init_composePrompt = __esm({
12300
12370
  const explicit = ctx.data.promptTemplate;
12301
12371
  const mode = ctx.args.mode;
12302
12372
  const candidates = [
12303
- explicit ? path30.join(profile.dir, explicit) : null,
12304
- mode ? path30.join(profile.dir, "prompts", `${mode}.md`) : null,
12305
- path30.join(profile.dir, "prompt.md"),
12306
- path30.join(profile.dir, "capability.md")
12373
+ explicit ? path31.join(profile.dir, explicit) : null,
12374
+ mode ? path31.join(profile.dir, "prompts", `${mode}.md`) : null,
12375
+ path31.join(profile.dir, "prompt.md"),
12376
+ path31.join(profile.dir, "capability.md")
12307
12377
  ].filter(Boolean);
12308
12378
  let templatePath = "";
12309
12379
  let template = "";
@@ -12316,7 +12386,7 @@ var init_composePrompt = __esm({
12316
12386
  break;
12317
12387
  }
12318
12388
  try {
12319
- template = fs32.readFileSync(c, "utf-8");
12389
+ template = fs33.readFileSync(c, "utf-8");
12320
12390
  templatePath = c;
12321
12391
  break;
12322
12392
  } catch (err) {
@@ -12327,7 +12397,7 @@ var init_composePrompt = __esm({
12327
12397
  if (!templatePath) {
12328
12398
  let dirState;
12329
12399
  try {
12330
- dirState = `dir contents: [${fs32.readdirSync(profile.dir).join(", ")}]`;
12400
+ dirState = `dir contents: [${fs33.readdirSync(profile.dir).join(", ")}]`;
12331
12401
  } catch (err) {
12332
12402
  dirState = `readdir(${profile.dir}) failed: ${err?.code ?? String(err)}`;
12333
12403
  }
@@ -13061,19 +13131,19 @@ var init_deriveQaScopeFromIssue = __esm({
13061
13131
 
13062
13132
  // src/scripts/diagMcp.ts
13063
13133
  import { execFileSync as execFileSync9 } from "child_process";
13064
- import * as fs33 from "fs";
13134
+ import * as fs34 from "fs";
13065
13135
  import * as os5 from "os";
13066
- import * as path31 from "path";
13136
+ import * as path32 from "path";
13067
13137
  var diagMcp;
13068
13138
  var init_diagMcp = __esm({
13069
13139
  "src/scripts/diagMcp.ts"() {
13070
13140
  "use strict";
13071
13141
  diagMcp = async (_ctx) => {
13072
13142
  const home = os5.homedir();
13073
- const cacheDir = path31.join(home, ".cache", "ms-playwright");
13143
+ const cacheDir = path32.join(home, ".cache", "ms-playwright");
13074
13144
  let entries = [];
13075
13145
  try {
13076
- entries = fs33.readdirSync(cacheDir);
13146
+ entries = fs34.readdirSync(cacheDir);
13077
13147
  } catch {
13078
13148
  }
13079
13149
  const hasChromium = entries.some((e) => e.startsWith("chromium"));
@@ -13101,13 +13171,13 @@ var init_diagMcp = __esm({
13101
13171
  });
13102
13172
 
13103
13173
  // src/scripts/frameworkDetectors.ts
13104
- import * as fs34 from "fs";
13105
- import * as path32 from "path";
13174
+ import * as fs35 from "fs";
13175
+ import * as path33 from "path";
13106
13176
  function detectFrameworks(cwd) {
13107
13177
  const out = [];
13108
13178
  let deps = {};
13109
13179
  try {
13110
- const pkg = JSON.parse(fs34.readFileSync(path32.join(cwd, "package.json"), "utf-8"));
13180
+ const pkg = JSON.parse(fs35.readFileSync(path33.join(cwd, "package.json"), "utf-8"));
13111
13181
  deps = { ...pkg.dependencies, ...pkg.devDependencies };
13112
13182
  } catch {
13113
13183
  return out;
@@ -13144,25 +13214,25 @@ function detectFrameworks(cwd) {
13144
13214
  }
13145
13215
  function findFile(cwd, candidates) {
13146
13216
  for (const c of candidates) {
13147
- if (fs34.existsSync(path32.join(cwd, c))) return c;
13217
+ if (fs35.existsSync(path33.join(cwd, c))) return c;
13148
13218
  }
13149
13219
  return null;
13150
13220
  }
13151
13221
  function discoverPayloadCollections(cwd) {
13152
13222
  const out = [];
13153
13223
  for (const dir of COLLECTION_DIRS) {
13154
- const full = path32.join(cwd, dir);
13155
- if (!fs34.existsSync(full)) continue;
13224
+ const full = path33.join(cwd, dir);
13225
+ if (!fs35.existsSync(full)) continue;
13156
13226
  let files;
13157
13227
  try {
13158
- files = fs34.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
13228
+ files = fs35.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
13159
13229
  } catch {
13160
13230
  continue;
13161
13231
  }
13162
13232
  for (const file of files) {
13163
13233
  try {
13164
- const filePath = path32.join(full, file);
13165
- const content = fs34.readFileSync(filePath, "utf-8").slice(0, 1e4);
13234
+ const filePath = path33.join(full, file);
13235
+ const content = fs35.readFileSync(filePath, "utf-8").slice(0, 1e4);
13166
13236
  const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
13167
13237
  if (!slugMatch) continue;
13168
13238
  const slug = slugMatch[1];
@@ -13176,7 +13246,7 @@ function discoverPayloadCollections(cwd) {
13176
13246
  out.push({
13177
13247
  name,
13178
13248
  slug,
13179
- filePath: path32.relative(cwd, filePath),
13249
+ filePath: path33.relative(cwd, filePath),
13180
13250
  fields: fields.slice(0, 20),
13181
13251
  hasAdmin
13182
13252
  });
@@ -13189,28 +13259,28 @@ function discoverPayloadCollections(cwd) {
13189
13259
  function discoverAdminComponents(cwd, collections) {
13190
13260
  const out = [];
13191
13261
  for (const dir of ADMIN_COMPONENT_DIRS) {
13192
- const full = path32.join(cwd, dir);
13193
- if (!fs34.existsSync(full)) continue;
13262
+ const full = path33.join(cwd, dir);
13263
+ if (!fs35.existsSync(full)) continue;
13194
13264
  let entries;
13195
13265
  try {
13196
- entries = fs34.readdirSync(full, { withFileTypes: true });
13266
+ entries = fs35.readdirSync(full, { withFileTypes: true });
13197
13267
  } catch {
13198
13268
  continue;
13199
13269
  }
13200
13270
  for (const entry of entries) {
13201
- const entryPath = path32.join(full, entry.name);
13271
+ const entryPath = path33.join(full, entry.name);
13202
13272
  let name;
13203
13273
  let filePath;
13204
13274
  if (entry.isDirectory()) {
13205
13275
  const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
13206
- (f) => fs34.existsSync(path32.join(entryPath, f))
13276
+ (f) => fs35.existsSync(path33.join(entryPath, f))
13207
13277
  );
13208
13278
  if (!indexFile) continue;
13209
13279
  name = entry.name;
13210
- filePath = path32.relative(cwd, path32.join(entryPath, indexFile));
13280
+ filePath = path33.relative(cwd, path33.join(entryPath, indexFile));
13211
13281
  } else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
13212
13282
  name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
13213
- filePath = path32.relative(cwd, entryPath);
13283
+ filePath = path33.relative(cwd, entryPath);
13214
13284
  } else {
13215
13285
  continue;
13216
13286
  }
@@ -13218,7 +13288,7 @@ function discoverAdminComponents(cwd, collections) {
13218
13288
  if (collections) {
13219
13289
  for (const col of collections) {
13220
13290
  try {
13221
- const colContent = fs34.readFileSync(path32.join(cwd, col.filePath), "utf-8");
13291
+ const colContent = fs35.readFileSync(path33.join(cwd, col.filePath), "utf-8");
13222
13292
  if (colContent.includes(name)) {
13223
13293
  usedInCollection = col.slug;
13224
13294
  break;
@@ -13236,8 +13306,8 @@ function scanApiRoutes(cwd) {
13236
13306
  const out = [];
13237
13307
  const appDirs = ["src/app", "app"];
13238
13308
  for (const appDir of appDirs) {
13239
- const apiDir = path32.join(cwd, appDir, "api");
13240
- if (!fs34.existsSync(apiDir)) continue;
13309
+ const apiDir = path33.join(cwd, appDir, "api");
13310
+ if (!fs35.existsSync(apiDir)) continue;
13241
13311
  walkApiRoutes(apiDir, "/api", cwd, out);
13242
13312
  break;
13243
13313
  }
@@ -13246,14 +13316,14 @@ function scanApiRoutes(cwd) {
13246
13316
  function walkApiRoutes(dir, prefix, cwd, out) {
13247
13317
  let entries;
13248
13318
  try {
13249
- entries = fs34.readdirSync(dir, { withFileTypes: true });
13319
+ entries = fs35.readdirSync(dir, { withFileTypes: true });
13250
13320
  } catch {
13251
13321
  return;
13252
13322
  }
13253
13323
  const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
13254
13324
  if (routeFile) {
13255
13325
  try {
13256
- const content = fs34.readFileSync(path32.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
13326
+ const content = fs35.readFileSync(path33.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
13257
13327
  const methods = HTTP_METHODS.filter(
13258
13328
  (m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
13259
13329
  );
@@ -13261,7 +13331,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
13261
13331
  out.push({
13262
13332
  path: prefix,
13263
13333
  methods,
13264
- filePath: path32.relative(cwd, path32.join(dir, routeFile.name))
13334
+ filePath: path33.relative(cwd, path33.join(dir, routeFile.name))
13265
13335
  });
13266
13336
  }
13267
13337
  } catch {
@@ -13272,7 +13342,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
13272
13342
  if (entry.name === "node_modules" || entry.name === ".next") continue;
13273
13343
  let segment = entry.name;
13274
13344
  if (segment.startsWith("(") && segment.endsWith(")")) {
13275
- walkApiRoutes(path32.join(dir, entry.name), prefix, cwd, out);
13345
+ walkApiRoutes(path33.join(dir, entry.name), prefix, cwd, out);
13276
13346
  continue;
13277
13347
  }
13278
13348
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -13280,16 +13350,16 @@ function walkApiRoutes(dir, prefix, cwd, out) {
13280
13350
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
13281
13351
  segment = `:${segment.slice(1, -1)}`;
13282
13352
  }
13283
- walkApiRoutes(path32.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
13353
+ walkApiRoutes(path33.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
13284
13354
  }
13285
13355
  }
13286
13356
  function scanEnvVars(cwd) {
13287
13357
  const candidates = [".env.example", ".env.local.example", ".env.template"];
13288
13358
  for (const envFile of candidates) {
13289
- const envPath = path32.join(cwd, envFile);
13290
- if (!fs34.existsSync(envPath)) continue;
13359
+ const envPath = path33.join(cwd, envFile);
13360
+ if (!fs35.existsSync(envPath)) continue;
13291
13361
  try {
13292
- const content = fs34.readFileSync(envPath, "utf-8");
13362
+ const content = fs35.readFileSync(envPath, "utf-8");
13293
13363
  const vars = [];
13294
13364
  for (const line of content.split("\n")) {
13295
13365
  const trimmed = line.trim();
@@ -13334,8 +13404,8 @@ var init_frameworkDetectors = __esm({
13334
13404
  });
13335
13405
 
13336
13406
  // src/scripts/discoverQaContext.ts
13337
- import * as fs35 from "fs";
13338
- import * as path33 from "path";
13407
+ import * as fs36 from "fs";
13408
+ import * as path34 from "path";
13339
13409
  function runQaDiscovery(cwd) {
13340
13410
  const out = {
13341
13411
  routes: [],
@@ -13366,9 +13436,9 @@ function runQaDiscovery(cwd) {
13366
13436
  }
13367
13437
  function detectDevServer(cwd, out) {
13368
13438
  try {
13369
- const pkg = JSON.parse(fs35.readFileSync(path33.join(cwd, "package.json"), "utf-8"));
13439
+ const pkg = JSON.parse(fs36.readFileSync(path34.join(cwd, "package.json"), "utf-8"));
13370
13440
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
13371
- const pm = fs35.existsSync(path33.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs35.existsSync(path33.join(cwd, "yarn.lock")) ? "yarn" : fs35.existsSync(path33.join(cwd, "bun.lockb")) ? "bun" : "npm";
13441
+ const pm = fs36.existsSync(path34.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs36.existsSync(path34.join(cwd, "yarn.lock")) ? "yarn" : fs36.existsSync(path34.join(cwd, "bun.lockb")) ? "bun" : "npm";
13372
13442
  if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
13373
13443
  if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
13374
13444
  else if (allDeps.vite) out.devPort = 5173;
@@ -13378,8 +13448,8 @@ function detectDevServer(cwd, out) {
13378
13448
  function scanFrontendRoutes(cwd, out) {
13379
13449
  const appDirs = ["src/app", "app"];
13380
13450
  for (const appDir of appDirs) {
13381
- const full = path33.join(cwd, appDir);
13382
- if (!fs35.existsSync(full)) continue;
13451
+ const full = path34.join(cwd, appDir);
13452
+ if (!fs36.existsSync(full)) continue;
13383
13453
  walkFrontendRoutes(full, "", out);
13384
13454
  break;
13385
13455
  }
@@ -13387,7 +13457,7 @@ function scanFrontendRoutes(cwd, out) {
13387
13457
  function walkFrontendRoutes(dir, prefix, out) {
13388
13458
  let entries;
13389
13459
  try {
13390
- entries = fs35.readdirSync(dir, { withFileTypes: true });
13460
+ entries = fs36.readdirSync(dir, { withFileTypes: true });
13391
13461
  } catch {
13392
13462
  return;
13393
13463
  }
@@ -13404,7 +13474,7 @@ function walkFrontendRoutes(dir, prefix, out) {
13404
13474
  if (entry.name === "node_modules" || entry.name === ".next") continue;
13405
13475
  let segment = entry.name;
13406
13476
  if (segment.startsWith("(") && segment.endsWith(")")) {
13407
- walkFrontendRoutes(path33.join(dir, entry.name), prefix, out);
13477
+ walkFrontendRoutes(path34.join(dir, entry.name), prefix, out);
13408
13478
  continue;
13409
13479
  }
13410
13480
  if (segment.startsWith("[[") && segment.endsWith("]]")) {
@@ -13412,7 +13482,7 @@ function walkFrontendRoutes(dir, prefix, out) {
13412
13482
  } else if (segment.startsWith("[") && segment.endsWith("]")) {
13413
13483
  segment = `:${segment.slice(1, -1)}`;
13414
13484
  }
13415
- walkFrontendRoutes(path33.join(dir, entry.name), `${prefix}/${segment}`, out);
13485
+ walkFrontendRoutes(path34.join(dir, entry.name), `${prefix}/${segment}`, out);
13416
13486
  }
13417
13487
  }
13418
13488
  function detectAuthFiles(cwd, out) {
@@ -13429,23 +13499,23 @@ function detectAuthFiles(cwd, out) {
13429
13499
  "src/app/api/oauth"
13430
13500
  ];
13431
13501
  for (const c of candidates) {
13432
- if (fs35.existsSync(path33.join(cwd, c))) out.authFiles.push(c);
13502
+ if (fs36.existsSync(path34.join(cwd, c))) out.authFiles.push(c);
13433
13503
  }
13434
13504
  }
13435
13505
  function detectRoles(cwd, out) {
13436
13506
  const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
13437
13507
  for (const rp of rolePaths) {
13438
- const dir = path33.join(cwd, rp);
13439
- if (!fs35.existsSync(dir)) continue;
13508
+ const dir = path34.join(cwd, rp);
13509
+ if (!fs36.existsSync(dir)) continue;
13440
13510
  let files;
13441
13511
  try {
13442
- files = fs35.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
13512
+ files = fs36.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
13443
13513
  } catch {
13444
13514
  continue;
13445
13515
  }
13446
13516
  for (const f of files) {
13447
13517
  try {
13448
- const content = fs35.readFileSync(path33.join(dir, f), "utf-8").slice(0, 5e3);
13518
+ const content = fs36.readFileSync(path34.join(dir, f), "utf-8").slice(0, 5e3);
13449
13519
  const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
13450
13520
  if (roleMatches) {
13451
13521
  for (const m of roleMatches) {
@@ -13706,8 +13776,8 @@ var init_dispatchClassified = __esm({
13706
13776
  });
13707
13777
 
13708
13778
  // src/loopDefinitions.ts
13709
- import * as fs36 from "fs";
13710
- import * as path34 from "path";
13779
+ import * as fs37 from "fs";
13780
+ import * as path35 from "path";
13711
13781
  function normalizeLoopDefinition(value) {
13712
13782
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
13713
13783
  const raw = value;
@@ -13734,10 +13804,10 @@ function readLoopDefinition(cwd, id) {
13734
13804
  if (!ID.test(id)) return null;
13735
13805
  const roots = loopRoots(cwd);
13736
13806
  for (const root of roots) {
13737
- const filePath = path34.join(root, "loops", id, "loop.json");
13738
- if (!fs36.existsSync(filePath)) continue;
13807
+ const filePath = path35.join(root, "loops", id, "loop.json");
13808
+ if (!fs37.existsSync(filePath)) continue;
13739
13809
  try {
13740
- const loop = normalizeLoopDefinition(JSON.parse(fs36.readFileSync(filePath, "utf8")));
13810
+ const loop = normalizeLoopDefinition(JSON.parse(fs37.readFileSync(filePath, "utf8")));
13741
13811
  if (loop?.id === id) return loop;
13742
13812
  process.stderr.write(`[kody] invalid Loop definition: ${filePath}
13743
13813
  `);
@@ -13747,7 +13817,7 @@ function readLoopDefinition(cwd, id) {
13747
13817
  }
13748
13818
  }
13749
13819
  process.stderr.write(
13750
- `[kody] Loop not found: ${id} (${roots.map((root) => path34.join(root, "loops", id, "loop.json")).join(", ")})
13820
+ `[kody] Loop not found: ${id} (${roots.map((root) => path35.join(root, "loops", id, "loop.json")).join(", ")})
13751
13821
  `
13752
13822
  );
13753
13823
  return null;
@@ -13756,14 +13826,14 @@ function listLoopDefinitions(cwd) {
13756
13826
  const roots = loopRoots(cwd);
13757
13827
  const byId = /* @__PURE__ */ new Map();
13758
13828
  for (const root of roots.reverse()) {
13759
- const loopsDir = path34.join(root, "loops");
13760
- if (!fs36.existsSync(loopsDir)) continue;
13761
- for (const id of fs36.readdirSync(loopsDir).sort()) {
13829
+ const loopsDir = path35.join(root, "loops");
13830
+ if (!fs37.existsSync(loopsDir)) continue;
13831
+ for (const id of fs37.readdirSync(loopsDir).sort()) {
13762
13832
  if (!ID.test(id)) continue;
13763
- const filePath = path34.join(loopsDir, id, "loop.json");
13764
- if (!fs36.existsSync(filePath)) continue;
13833
+ const filePath = path35.join(loopsDir, id, "loop.json");
13834
+ if (!fs37.existsSync(filePath)) continue;
13765
13835
  try {
13766
- const loop = normalizeLoopDefinition(JSON.parse(fs36.readFileSync(filePath, "utf8")));
13836
+ const loop = normalizeLoopDefinition(JSON.parse(fs37.readFileSync(filePath, "utf8")));
13767
13837
  if (loop?.id === id) byId.set(id, loop);
13768
13838
  } catch {
13769
13839
  process.stderr.write(`[kody] unreadable Loop definition: ${filePath}
@@ -13775,8 +13845,8 @@ function listLoopDefinitions(cwd) {
13775
13845
  }
13776
13846
  function loopRoots(cwd) {
13777
13847
  return [
13778
- path34.join(cwd, ".kody-engine", "runtime"),
13779
- path34.join(cwd, ".kody-engine", "definitions"),
13848
+ path35.join(cwd, ".kody-engine", "runtime"),
13849
+ path35.join(cwd, ".kody-engine", "definitions"),
13780
13850
  definitionsRoot(cwd)
13781
13851
  ].filter((root, index, roots) => roots.indexOf(root) === index);
13782
13852
  }
@@ -15054,15 +15124,15 @@ var init_fixFlow = __esm({
15054
15124
  });
15055
15125
 
15056
15126
  // src/workflow-template.ts
15057
- import * as fs37 from "fs";
15058
- import * as path35 from "path";
15127
+ import * as fs38 from "fs";
15128
+ import * as path36 from "path";
15059
15129
  import { fileURLToPath } from "url";
15060
15130
  function loadKodyWorkflowTemplate() {
15061
- const here = path35.dirname(fileURLToPath(import.meta.url));
15062
- const candidates = [path35.resolve(here, "../templates/kody.yml"), path35.resolve(here, "../../templates/kody.yml")];
15063
- const source = candidates.find((candidate) => fs37.existsSync(candidate));
15131
+ const here = path36.dirname(fileURLToPath(import.meta.url));
15132
+ const candidates = [path36.resolve(here, "../templates/kody.yml"), path36.resolve(here, "../../templates/kody.yml")];
15133
+ const source = candidates.find((candidate) => fs38.existsSync(candidate));
15064
15134
  if (!source) throw new Error(`Kody workflow template is missing: ${KODY_WORKFLOW_TEMPLATE_PATH}`);
15065
- return fs37.readFileSync(source, "utf8");
15135
+ return fs38.readFileSync(source, "utf8");
15066
15136
  }
15067
15137
  var KODY_WORKFLOW_TEMPLATE_PATH;
15068
15138
  var init_workflow_template = __esm({
@@ -15074,12 +15144,12 @@ var init_workflow_template = __esm({
15074
15144
 
15075
15145
  // src/scripts/initFlow.ts
15076
15146
  import { execFileSync as execFileSync14 } from "child_process";
15077
- import * as fs38 from "fs";
15078
- import * as path36 from "path";
15147
+ import * as fs39 from "fs";
15148
+ import * as path37 from "path";
15079
15149
  function detectPackageManager(cwd) {
15080
- if (fs38.existsSync(path36.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
15081
- if (fs38.existsSync(path36.join(cwd, "yarn.lock"))) return "yarn";
15082
- if (fs38.existsSync(path36.join(cwd, "bun.lockb"))) return "bun";
15150
+ if (fs39.existsSync(path37.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
15151
+ if (fs39.existsSync(path37.join(cwd, "yarn.lock"))) return "yarn";
15152
+ if (fs39.existsSync(path37.join(cwd, "bun.lockb"))) return "bun";
15083
15153
  return "npm";
15084
15154
  }
15085
15155
  function qualityCommandsFor(pm) {
@@ -15151,22 +15221,22 @@ function performInit(cwd, force) {
15151
15221
  const pm = detectPackageManager(cwd);
15152
15222
  const ownerRepo = detectOwnerRepo(cwd);
15153
15223
  const defaultBranch = defaultBranchFromGit(cwd);
15154
- const configPath = path36.join(cwd, "kody.config.json");
15155
- if (fs38.existsSync(configPath) && !force) {
15224
+ const configPath = path37.join(cwd, "kody.config.json");
15225
+ if (fs39.existsSync(configPath) && !force) {
15156
15226
  skipped.push("kody.config.json");
15157
15227
  } else {
15158
15228
  const cfg = makeConfig(pm, ownerRepo, defaultBranch);
15159
- fs38.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
15229
+ fs39.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
15160
15230
  `);
15161
15231
  wrote.push("kody.config.json");
15162
15232
  }
15163
- const workflowDir = path36.join(cwd, ".github", "workflows");
15164
- const workflowPath = path36.join(workflowDir, "kody.yml");
15165
- if (fs38.existsSync(workflowPath) && !force) {
15233
+ const workflowDir = path37.join(cwd, ".github", "workflows");
15234
+ const workflowPath = path37.join(workflowDir, "kody.yml");
15235
+ if (fs39.existsSync(workflowPath) && !force) {
15166
15236
  skipped.push(".github/workflows/kody.yml");
15167
15237
  } else {
15168
- fs38.mkdirSync(workflowDir, { recursive: true });
15169
- fs38.writeFileSync(workflowPath, loadKodyWorkflowTemplate());
15238
+ fs39.mkdirSync(workflowDir, { recursive: true });
15239
+ fs39.writeFileSync(workflowPath, loadKodyWorkflowTemplate());
15170
15240
  wrote.push(".github/workflows/kody.yml");
15171
15241
  }
15172
15242
  let labels;
@@ -15217,7 +15287,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
15217
15287
  });
15218
15288
 
15219
15289
  // src/scripts/loadAgentAdhoc.ts
15220
- import * as fs39 from "fs";
15290
+ import * as fs40 from "fs";
15221
15291
  function resolveMessage(messageArg) {
15222
15292
  const fromComment = readCommentBody();
15223
15293
  if (fromComment) return stripDirective(fromComment);
@@ -15225,9 +15295,9 @@ function resolveMessage(messageArg) {
15225
15295
  }
15226
15296
  function readCommentBody() {
15227
15297
  const eventPath = process.env.GITHUB_EVENT_PATH;
15228
- if (!eventPath || !fs39.existsSync(eventPath)) return "";
15298
+ if (!eventPath || !fs40.existsSync(eventPath)) return "";
15229
15299
  try {
15230
- const event = JSON.parse(fs39.readFileSync(eventPath, "utf-8"));
15300
+ const event = JSON.parse(fs40.readFileSync(eventPath, "utf-8"));
15231
15301
  return String(event.comment?.body ?? "");
15232
15302
  } catch {
15233
15303
  return "";
@@ -15281,10 +15351,10 @@ var init_loadAgentAdhoc = __esm({
15281
15351
  throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
15282
15352
  }
15283
15353
  const agentPath = resolveAgentFile2(ctx.cwd, agentSlug, agentsDir);
15284
- if (!fs39.existsSync(agentPath)) {
15354
+ if (!fs40.existsSync(agentPath)) {
15285
15355
  throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
15286
15356
  }
15287
- const { title, body } = parseAgentFile(fs39.readFileSync(agentPath, "utf-8"), agentSlug);
15357
+ const { title, body } = parseAgentFile(fs40.readFileSync(agentPath, "utf-8"), agentSlug);
15288
15358
  const message = resolveMessage(ctx.args.message);
15289
15359
  if (!message) {
15290
15360
  throw new Error(
@@ -15356,13 +15426,13 @@ var init_loadCapabilityState = __esm({
15356
15426
  function isCompanyIntentId(value) {
15357
15427
  return SLUG_RE2.test(value);
15358
15428
  }
15359
- function normalizeCompanyIntent(path54, raw) {
15429
+ function normalizeCompanyIntent(path55, raw) {
15360
15430
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
15361
- throw new Error(`${path54}: intent must be JSON object`);
15431
+ throw new Error(`${path55}: intent must be JSON object`);
15362
15432
  }
15363
15433
  const input = raw;
15364
15434
  const id = stringField4(input.id);
15365
- if (!id || !isCompanyIntentId(id)) throw new Error(`${path54}: invalid intent id`);
15435
+ if (!id || !isCompanyIntentId(id)) throw new Error(`${path55}: invalid intent id`);
15366
15436
  const createdAt = stringField4(input.createdAt) || nowIso();
15367
15437
  const updatedAt = stringField4(input.updatedAt) || createdAt;
15368
15438
  const description = stringField4(input.description);
@@ -15524,7 +15594,7 @@ function retryDelaysMs() {
15524
15594
  }
15525
15595
  function sleep(ms) {
15526
15596
  if (ms <= 0) return Promise.resolve();
15527
- return new Promise((resolve20) => setTimeout(resolve20, ms));
15597
+ return new Promise((resolve21) => setTimeout(resolve21, ms));
15528
15598
  }
15529
15599
  async function fetchGoalStateWithRetry(config, goalId, cwd) {
15530
15600
  let state = await fetchGoalStateAsync(config, goalId, cwd);
@@ -15653,8 +15723,8 @@ var init_loadIssueStateComment = __esm({
15653
15723
  });
15654
15724
 
15655
15725
  // src/scripts/loadJobFromFile.ts
15656
- import * as fs40 from "fs";
15657
- import * as path37 from "path";
15726
+ import * as fs41 from "fs";
15727
+ import * as path38 from "path";
15658
15728
  function parseJobFile(raw, slug) {
15659
15729
  let stripped = raw;
15660
15730
  if (stripped.startsWith("---\n")) {
@@ -15693,10 +15763,10 @@ var init_loadJobFromFile = __esm({
15693
15763
  if (!slug) {
15694
15764
  throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
15695
15765
  }
15696
- const capability = resolveCapabilityFolder(slug, path37.resolve(ctx.cwd, jobsDir));
15766
+ const capability = resolveCapabilityFolder(slug, path38.resolve(ctx.cwd, jobsDir));
15697
15767
  if (!capability) {
15698
15768
  throw new Error(
15699
- `loadJobFromFile: capability folder not found or incomplete: ${path37.resolve(ctx.cwd, jobsDir, slug)}`
15769
+ `loadJobFromFile: capability folder not found or incomplete: ${path38.resolve(ctx.cwd, jobsDir, slug)}`
15700
15770
  );
15701
15771
  }
15702
15772
  const { title, body, config } = capability;
@@ -15706,12 +15776,12 @@ var init_loadJobFromFile = __esm({
15706
15776
  let agentIdentity = "";
15707
15777
  if (agentSlug) {
15708
15778
  const agentPath = resolveAgentFile2(ctx.cwd, agentSlug, agentsDir);
15709
- if (!fs40.existsSync(agentPath)) {
15779
+ if (!fs41.existsSync(agentPath)) {
15710
15780
  throw new Error(
15711
15781
  `loadJobFromFile: capability '${slug}' declares agent '${agentSlug}' but ${agentPath} does not exist`
15712
15782
  );
15713
15783
  }
15714
- const agentRaw = fs40.readFileSync(agentPath, "utf-8");
15784
+ const agentRaw = fs41.readFileSync(agentPath, "utf-8");
15715
15785
  const parsed = parseJobFile(agentRaw, agentSlug);
15716
15786
  agentTitle = parsed.title;
15717
15787
  agentIdentity = parsed.body;
@@ -15791,13 +15861,13 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
15791
15861
  });
15792
15862
 
15793
15863
  // src/scripts/kodyVariables.ts
15794
- import * as fs41 from "fs";
15795
- import * as path38 from "path";
15864
+ import * as fs42 from "fs";
15865
+ import * as path39 from "path";
15796
15866
  function readKodyVariables(cwd) {
15797
- const full = path38.join(cwd, KODY_VARIABLES_REL_PATH);
15867
+ const full = path39.join(cwd, KODY_VARIABLES_REL_PATH);
15798
15868
  let raw;
15799
15869
  try {
15800
- raw = fs41.readFileSync(full, "utf-8");
15870
+ raw = fs42.readFileSync(full, "utf-8");
15801
15871
  } catch {
15802
15872
  return {};
15803
15873
  }
@@ -15822,8 +15892,8 @@ var init_kodyVariables = __esm({
15822
15892
  });
15823
15893
 
15824
15894
  // src/scripts/loadQaContext.ts
15825
- import * as fs42 from "fs";
15826
- import * as path39 from "path";
15895
+ import * as fs43 from "fs";
15896
+ import * as path40 from "path";
15827
15897
  function parseSlugList(value) {
15828
15898
  const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
15829
15899
  return inner.split(",").map(
@@ -15852,18 +15922,18 @@ function readProfileAgents(raw) {
15852
15922
  return { agent: agent ?? legacy ?? ["kody"], body };
15853
15923
  }
15854
15924
  function readProfile(cwd) {
15855
- const dir = path39.join(cwd, CONTEXT_DIR_REL_PATH);
15856
- if (!fs42.existsSync(dir)) return "";
15925
+ const dir = path40.join(cwd, CONTEXT_DIR_REL_PATH);
15926
+ if (!fs43.existsSync(dir)) return "";
15857
15927
  let entries;
15858
15928
  try {
15859
- entries = fs42.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
15929
+ entries = fs43.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
15860
15930
  } catch {
15861
15931
  return "";
15862
15932
  }
15863
15933
  const blocks = [];
15864
15934
  for (const file of entries) {
15865
15935
  try {
15866
- const raw = fs42.readFileSync(path39.join(dir, file), "utf-8");
15936
+ const raw = fs43.readFileSync(path40.join(dir, file), "utf-8");
15867
15937
  const { agent, body } = readProfileAgents(raw);
15868
15938
  if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
15869
15939
  blocks.push(`## ${file}
@@ -15913,9 +15983,9 @@ var init_loadQaContext = __esm({
15913
15983
 
15914
15984
  // src/scripts/loadSimpleCapability.ts
15915
15985
  import { randomUUID as randomUUID2 } from "crypto";
15916
- import * as fs43 from "fs";
15986
+ import * as fs44 from "fs";
15917
15987
  import * as os6 from "os";
15918
- import * as path40 from "path";
15988
+ import * as path41 from "path";
15919
15989
  function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
15920
15990
  const subagentFiles = toolFiles.flatMap((file) => {
15921
15991
  const match = /^agents\/([a-z][a-z0-9-]{0,63})\.md$/.exec(file);
@@ -15928,7 +15998,7 @@ function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
15928
15998
  profile.subagentTemplates = {
15929
15999
  ...profile.subagentTemplates ?? {},
15930
16000
  ...Object.fromEntries(
15931
- subagentFiles.map(({ name, file }) => [name, fs43.readFileSync(path40.join(toolRoot, file), "utf-8")])
16001
+ subagentFiles.map(({ name, file }) => [name, fs44.readFileSync(path41.join(toolRoot, file), "utf-8")])
15932
16002
  )
15933
16003
  };
15934
16004
  if (!profile.claudeCode.tools.includes("Agent")) {
@@ -15969,14 +16039,14 @@ function scalar(value) {
15969
16039
  return value;
15970
16040
  }
15971
16041
  function listFiles(root) {
15972
- if (!fs43.existsSync(root)) return [];
16042
+ if (!fs44.existsSync(root)) return [];
15973
16043
  const files = [];
15974
16044
  const visit = (dir) => {
15975
- for (const entry of fs43.readdirSync(dir, { withFileTypes: true })) {
15976
- const absolute = path40.join(dir, entry.name);
16045
+ for (const entry of fs44.readdirSync(dir, { withFileTypes: true })) {
16046
+ const absolute = path41.join(dir, entry.name);
15977
16047
  if (entry.isSymbolicLink()) continue;
15978
16048
  if (entry.isDirectory()) visit(absolute);
15979
- else if (entry.isFile()) files.push(path40.relative(root, absolute));
16049
+ else if (entry.isFile()) files.push(path41.relative(root, absolute));
15980
16050
  }
15981
16051
  };
15982
16052
  visit(root);
@@ -15999,8 +16069,8 @@ var init_loadSimpleCapability = __esm({
15999
16069
  if (!capability) {
16000
16070
  throw new Error(`Capability "${slug}" is not a valid simple capability folder`);
16001
16071
  }
16002
- const toolRoot = path40.join(capability.dir, "tools");
16003
- const skillRoot = path40.join(capability.dir, "skills");
16072
+ const toolRoot = path41.join(capability.dir, "tools");
16073
+ const skillRoot = path41.join(capability.dir, "skills");
16004
16074
  const toolFiles = listFiles(toolRoot);
16005
16075
  const skillFiles = listFiles(skillRoot);
16006
16076
  const parsedInput = parseInput(ctx.args.input);
@@ -16025,14 +16095,14 @@ var init_loadSimpleCapability = __esm({
16025
16095
  }
16026
16096
  if (requiredSubagents.length > 0) ctx.data.requiredSubagents = requiredSubagents;
16027
16097
  if (capability.contract?.execution === "script") {
16028
- ctx.data.capabilityScriptPath = path40.join(capability.dir, "tools", "run.sh");
16098
+ ctx.data.capabilityScriptPath = path41.join(capability.dir, "tools", "run.sh");
16029
16099
  ctx.data.capabilitySecretNames = capability.contract.secrets ?? [];
16030
16100
  ctx.data.capabilityScriptTimeoutMs = capability.contract.timeoutMs;
16031
16101
  }
16032
16102
  if (capability.config.outputSchema) {
16033
16103
  ctx.data.capabilityOutputSchema = capability.config.outputSchema;
16034
16104
  }
16035
- const outputPath = ctx.data.capabilityExecution === "agent" && capability.config.outputSchema ? path40.join(os6.tmpdir(), `kody-capability-output-${randomUUID2()}.json`) : void 0;
16105
+ const outputPath = ctx.data.capabilityExecution === "agent" && capability.config.outputSchema ? path41.join(os6.tmpdir(), `kody-capability-output-${randomUUID2()}.json`) : void 0;
16036
16106
  if (outputPath) ctx.data.capabilityOutputPath = outputPath;
16037
16107
  ctx.data.capabilityEnvironment = {
16038
16108
  ...capabilityInputEnvironment(input),
@@ -16055,7 +16125,7 @@ var init_loadSimpleCapability = __esm({
16055
16125
  ...skillFiles.flatMap((file) => [
16056
16126
  `### ${file}`,
16057
16127
  "",
16058
- fs43.readFileSync(path40.join(skillRoot, file), "utf-8"),
16128
+ fs44.readFileSync(path41.join(skillRoot, file), "utf-8"),
16059
16129
  ""
16060
16130
  ])
16061
16131
  ] : [],
@@ -16064,7 +16134,7 @@ var init_loadSimpleCapability = __esm({
16064
16134
  "## Tools",
16065
16135
  "",
16066
16136
  "Inspect or run these capability-owned files when needed:",
16067
- ...toolFiles.map((file) => `- ${path40.join(toolRoot, file)}`)
16137
+ ...toolFiles.map((file) => `- ${path41.join(toolRoot, file)}`)
16068
16138
  ] : [],
16069
16139
  "",
16070
16140
  ...capability.config.outputSchema ? [
@@ -16095,8 +16165,8 @@ var init_loadSimpleCapability = __esm({
16095
16165
  });
16096
16166
 
16097
16167
  // src/taskContext.ts
16098
- import * as fs44 from "fs";
16099
- import * as path41 from "path";
16168
+ import * as fs45 from "fs";
16169
+ import * as path42 from "path";
16100
16170
  function buildTaskContext(args) {
16101
16171
  return {
16102
16172
  schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
@@ -16112,9 +16182,9 @@ function buildTaskContext(args) {
16112
16182
  function persistTaskContext(cwd, ctx) {
16113
16183
  try {
16114
16184
  const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
16115
- fs44.mkdirSync(dir, { recursive: true });
16116
- const file = path41.join(dir, "task-context.json");
16117
- fs44.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
16185
+ fs45.mkdirSync(dir, { recursive: true });
16186
+ const file = path42.join(dir, "task-context.json");
16187
+ fs45.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
16118
16188
  `);
16119
16189
  return file;
16120
16190
  } catch (err) {
@@ -16541,19 +16611,19 @@ function parseAgencyModelProposal(raw) {
16541
16611
  function normalizeBundleFiles(bundle) {
16542
16612
  const seen = /* @__PURE__ */ new Set();
16543
16613
  return bundle.files.map((file, index) => {
16544
- const path54 = file.path.replace(/^\/+/, "");
16545
- const parts = path54.split("/");
16546
- if (!path54 || file.path.startsWith("/") || file.path.includes("\\") || parts.some((part) => !part || part === "." || part === "..")) {
16614
+ const path55 = file.path.replace(/^\/+/, "");
16615
+ const parts = path55.split("/");
16616
+ if (!path55 || file.path.startsWith("/") || file.path.includes("\\") || parts.some((part) => !part || part === "." || part === "..")) {
16547
16617
  throw new Error(`openAgencyModelReviewPr: files[${index}].path is unsafe`);
16548
16618
  }
16549
16619
  if (!/^(agents\/[^/]+\.md|capabilities\/[^/]+\/.+|goals\/(?:templates\/)?[^/]+\/.+|workflows\/[^/]+\.json)$/.test(
16550
- path54
16620
+ path55
16551
16621
  )) {
16552
16622
  throw new Error(`openAgencyModelReviewPr: files[${index}].path is not a supported definition path`);
16553
16623
  }
16554
- if (seen.has(path54)) throw new Error(`openAgencyModelReviewPr: duplicate generated file path: ${path54}`);
16555
- seen.add(path54);
16556
- return { path: path54, content: file.content.replace(/\r\n?/g, "\n") };
16624
+ if (seen.has(path55)) throw new Error(`openAgencyModelReviewPr: duplicate generated file path: ${path55}`);
16625
+ seen.add(path55);
16626
+ return { path: path55, content: file.content.replace(/\r\n?/g, "\n") };
16557
16627
  });
16558
16628
  }
16559
16629
  function buildProposalId(issueNumber, bundle, sourceLabel) {
@@ -17035,16 +17105,16 @@ var init_parseReproOutput = __esm({
17035
17105
  });
17036
17106
 
17037
17107
  // src/scripts/parseSimpleCapabilityOutput.ts
17038
- import * as fs45 from "fs";
17108
+ import * as fs46 from "fs";
17039
17109
  function stringList2(value) {
17040
17110
  return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
17041
17111
  }
17042
17112
  function readOutputFile(outputPath) {
17043
- if (!outputPath || !fs45.existsSync(outputPath)) return { found: false };
17113
+ if (!outputPath || !fs46.existsSync(outputPath)) return { found: false };
17044
17114
  try {
17045
- return { found: true, value: JSON.parse(fs45.readFileSync(outputPath, "utf-8")) };
17115
+ return { found: true, value: JSON.parse(fs46.readFileSync(outputPath, "utf-8")) };
17046
17116
  } finally {
17047
- fs45.rmSync(outputPath, { force: true });
17117
+ fs46.rmSync(outputPath, { force: true });
17048
17118
  }
17049
17119
  }
17050
17120
  function parseOutput(text2) {
@@ -17663,9 +17733,9 @@ var init_postResearchComment = __esm({
17663
17733
  });
17664
17734
 
17665
17735
  // src/scripts/prepareBrowserAuth.ts
17666
- import * as fs46 from "fs";
17736
+ import * as fs47 from "fs";
17667
17737
  import * as os7 from "os";
17668
- import * as path42 from "path";
17738
+ import * as path43 from "path";
17669
17739
  function appendAuthMessage(ctx, message) {
17670
17740
  const current = typeof ctx.data.qaAuthBlock === "string" ? ctx.data.qaAuthBlock.trim() : "";
17671
17741
  ctx.data.qaAuthBlock = current ? `${current}
@@ -17704,9 +17774,9 @@ async function githubJson(url, token) {
17704
17774
  return await response.json();
17705
17775
  }
17706
17776
  function writeKodyStorageState(input) {
17707
- const directory = fs46.mkdtempSync(path42.join(os7.tmpdir(), "kody-browser-auth-"));
17708
- fs46.chmodSync(directory, 448);
17709
- const file = path42.join(directory, "storage-state.json");
17777
+ const directory = fs47.mkdtempSync(path43.join(os7.tmpdir(), "kody-browser-auth-"));
17778
+ fs47.chmodSync(directory, 448);
17779
+ const file = path43.join(directory, "storage-state.json");
17710
17780
  const now = Date.now();
17711
17781
  const repoEntry = {
17712
17782
  repoUrl: input.repoUrl,
@@ -17736,7 +17806,7 @@ function writeKodyStorageState(input) {
17736
17806
  }
17737
17807
  ]
17738
17808
  };
17739
- fs46.writeFileSync(file, JSON.stringify(storageState), { mode: 384 });
17809
+ fs47.writeFileSync(file, JSON.stringify(storageState), { mode: 384 });
17740
17810
  return { directory, file };
17741
17811
  }
17742
17812
  function configurePlaywright(profile, storageStatePath) {
@@ -17818,7 +17888,7 @@ async function prepareMethod(ctx, profile, method) {
17818
17888
  configurePlaywright(profile, state.file);
17819
17889
  const authDirectory = state.directory;
17820
17890
  registerRuntimeCleanup(ctx, () => {
17821
- fs46.rmSync(authDirectory, { recursive: true, force: true });
17891
+ fs47.rmSync(authDirectory, { recursive: true, force: true });
17822
17892
  });
17823
17893
  appendAuthMessage(
17824
17894
  ctx,
@@ -17826,7 +17896,7 @@ async function prepareMethod(ctx, profile, method) {
17826
17896
  );
17827
17897
  return true;
17828
17898
  } catch (error) {
17829
- if (state) fs46.rmSync(state.directory, { recursive: true, force: true });
17899
+ if (state) fs47.rmSync(state.directory, { recursive: true, force: true });
17830
17900
  const reason = error instanceof Error ? error.message : String(error);
17831
17901
  appendAuthMessage(
17832
17902
  ctx,
@@ -17965,7 +18035,7 @@ var init_prepareCapabilityDelivery = __esm({
17965
18035
 
17966
18036
  // src/scripts/prepareSimpleCapabilityRuntime.ts
17967
18037
  import { isIP } from "net";
17968
- import * as path43 from "path";
18038
+ import * as path44 from "path";
17969
18039
  function requirementsFrom(ctx) {
17970
18040
  const raw = ctx.data.capabilityRequirements;
17971
18041
  return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
@@ -18009,7 +18079,7 @@ function browserRuntime(ctx, requirements) {
18009
18079
  "--allowed-origins",
18010
18080
  origin,
18011
18081
  "--output-dir",
18012
- path43.resolve(ctx.cwd, "test-results", "quality-runs", qualityRunId)
18082
+ path44.resolve(ctx.cwd, "test-results", "quality-runs", qualityRunId)
18013
18083
  ]
18014
18084
  };
18015
18085
  }
@@ -18374,9 +18444,9 @@ function latestResult(raw, agentResult) {
18374
18444
  function recordField4(value) {
18375
18445
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
18376
18446
  }
18377
- function resolveDotted(root, path54) {
18378
- if (!path54) return void 0;
18379
- return path54.split(".").reduce((value, key) => recordField4(value)?.[key], root);
18447
+ function resolveDotted(root, path55) {
18448
+ if (!path55) return void 0;
18449
+ return path55.split(".").reduce((value, key) => recordField4(value)?.[key], root);
18380
18450
  }
18381
18451
  function stringValue5(value) {
18382
18452
  return typeof value === "string" && value.trim() ? value.trim() : null;
@@ -19218,7 +19288,7 @@ var init_previewBuildHelpers = __esm({
19218
19288
  // src/scripts/previewBuildRun.ts
19219
19289
  import { spawn as spawn5 } from "child_process";
19220
19290
  async function runCmd(cmd, args, opts = {}) {
19221
- await new Promise((resolve20, reject) => {
19291
+ await new Promise((resolve21, reject) => {
19222
19292
  const child = spawn5(cmd, args, {
19223
19293
  cwd: opts.cwd,
19224
19294
  env: { ...process.env, ...opts.env ?? {} },
@@ -19230,7 +19300,7 @@ async function runCmd(cmd, args, opts = {}) {
19230
19300
  }
19231
19301
  child.on("error", reject);
19232
19302
  child.on("close", (code) => {
19233
- if (code === 0) resolve20();
19303
+ if (code === 0) resolve21();
19234
19304
  else reject(new Error(`${cmd} ${args.join(" ")} exited ${code}`));
19235
19305
  });
19236
19306
  });
@@ -19302,12 +19372,12 @@ fi
19302
19372
 
19303
19373
  // src/scripts/runPreviewBuild.ts
19304
19374
  import { copyFile, writeFile } from "fs/promises";
19305
- import * as path44 from "path";
19375
+ import * as path45 from "path";
19306
19376
  import { fileURLToPath as fileURLToPath2 } from "url";
19307
19377
  function bundledDockerfilePath(mode) {
19308
- const here = path44.dirname(fileURLToPath2(import.meta.url));
19378
+ const here = path45.dirname(fileURLToPath2(import.meta.url));
19309
19379
  const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
19310
- return path44.join(here, "preview-build-templates", file);
19380
+ return path45.join(here, "preview-build-templates", file);
19311
19381
  }
19312
19382
  function required(name) {
19313
19383
  const v = (process.env[name] ?? "").trim();
@@ -19542,10 +19612,10 @@ var init_runPreviewBuild = __esm({
19542
19612
  console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
19543
19613
  if (Object.keys(buildEnv).length > 0) {
19544
19614
  const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
19545
- await writeFile(path44.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
19615
+ await writeFile(path45.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
19546
19616
  `, "utf8");
19547
19617
  }
19548
- const consumerDockerfile = path44.join(ctx.cwd, "Dockerfile.preview");
19618
+ const consumerDockerfile = path45.join(ctx.cwd, "Dockerfile.preview");
19549
19619
  const { stat } = await import("fs/promises");
19550
19620
  let hasConsumerDockerfile = false;
19551
19621
  try {
@@ -19729,8 +19799,8 @@ var init_tickShellRunner = __esm({
19729
19799
  });
19730
19800
 
19731
19801
  // src/scripts/runScheduledImplementationTick.ts
19732
- import * as fs47 from "fs";
19733
- import * as path45 from "path";
19802
+ import * as fs48 from "fs";
19803
+ import * as path46 from "path";
19734
19804
  var runScheduledImplementationTick;
19735
19805
  var init_runScheduledImplementationTick = __esm({
19736
19806
  "src/scripts/runScheduledImplementationTick.ts"() {
@@ -19751,14 +19821,14 @@ var init_runScheduledImplementationTick = __esm({
19751
19821
  ctx.output.reason = `runScheduledImplementationTick: args.slug or ctx.args.${slugArg} must be non-empty capability slug`;
19752
19822
  return;
19753
19823
  }
19754
- const capability = resolveCapabilityFolder(slug, path45.resolve(ctx.cwd, jobsDir));
19824
+ const capability = resolveCapabilityFolder(slug, path46.resolve(ctx.cwd, jobsDir));
19755
19825
  if (!capability) {
19756
19826
  ctx.output.exitCode = 99;
19757
19827
  ctx.output.reason = `runScheduledImplementationTick: capability folder not found or incomplete: ${slug} (searched ${jobsDir} and company store)`;
19758
19828
  return;
19759
19829
  }
19760
- const shellPath = path45.join(profile.dir, shell);
19761
- if (!fs47.existsSync(shellPath)) {
19830
+ const shellPath = path46.join(profile.dir, shell);
19831
+ if (!fs48.existsSync(shellPath)) {
19762
19832
  ctx.output.exitCode = 99;
19763
19833
  ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
19764
19834
  return;
@@ -19790,13 +19860,13 @@ var init_runScheduledImplementationTick = __esm({
19790
19860
 
19791
19861
  // src/scripts/runSimpleCapabilityScript.ts
19792
19862
  import { spawnSync as spawnSync3 } from "child_process";
19793
- import * as fs48 from "fs";
19863
+ import * as fs49 from "fs";
19794
19864
  function formatDuration2(timeoutMs) {
19795
19865
  return timeoutMs % 6e4 === 0 ? `${timeoutMs / 6e4} minutes` : `${timeoutMs}ms`;
19796
19866
  }
19797
19867
  function isRegularFile2(filePath) {
19798
19868
  try {
19799
- const stat = fs48.lstatSync(filePath);
19869
+ const stat = fs49.lstatSync(filePath);
19800
19870
  return stat.isFile() && !stat.isSymbolicLink();
19801
19871
  } catch {
19802
19872
  return false;
@@ -19875,8 +19945,8 @@ var init_runSimpleCapabilityScript = __esm({
19875
19945
  });
19876
19946
 
19877
19947
  // src/scripts/runTickScript.ts
19878
- import * as fs49 from "fs";
19879
- import * as path46 from "path";
19948
+ import * as fs50 from "fs";
19949
+ import * as path47 from "path";
19880
19950
  var runTickScript;
19881
19951
  var init_runTickScript = __esm({
19882
19952
  "src/scripts/runTickScript.ts"() {
@@ -19896,10 +19966,10 @@ var init_runTickScript = __esm({
19896
19966
  ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
19897
19967
  return;
19898
19968
  }
19899
- const capability = readCapabilityFolder(path46.resolve(ctx.cwd, jobsDir), slug);
19969
+ const capability = readCapabilityFolder(path47.resolve(ctx.cwd, jobsDir), slug);
19900
19970
  if (!capability) {
19901
19971
  ctx.output.exitCode = 99;
19902
- ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path46.resolve(ctx.cwd, jobsDir, slug)}`;
19972
+ ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path47.resolve(ctx.cwd, jobsDir, slug)}`;
19903
19973
  return;
19904
19974
  }
19905
19975
  const tickScript = capability.config.tickScript;
@@ -19908,8 +19978,8 @@ var init_runTickScript = __esm({
19908
19978
  ctx.output.reason = `runTickScript: capability ${slug} has no \`tickScript\` in profile.json \u2014 route via capability-tick instead`;
19909
19979
  return;
19910
19980
  }
19911
- const scriptPath = path46.isAbsolute(tickScript) ? tickScript : path46.join(ctx.cwd, tickScript);
19912
- if (!fs49.existsSync(scriptPath)) {
19981
+ const scriptPath = path47.isAbsolute(tickScript) ? tickScript : path47.join(ctx.cwd, tickScript);
19982
+ if (!fs50.existsSync(scriptPath)) {
19913
19983
  ctx.output.exitCode = 99;
19914
19984
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
19915
19985
  return;
@@ -20191,7 +20261,7 @@ var init_syncFlow = __esm({
20191
20261
  });
20192
20262
 
20193
20263
  // src/scripts/validateAgencyModelProposal.ts
20194
- import * as path47 from "path";
20264
+ import * as path48 from "path";
20195
20265
  function validateModelBundle(bundle, expectedKind, options = {}) {
20196
20266
  const failures = [];
20197
20267
  validateOneModel(bundle.model, bundle.files, "model", true, failures, expectedKind, options);
@@ -20509,7 +20579,7 @@ var init_validateAgencyModelProposal = __esm({
20509
20579
  const bundle = parseAgencyModelProposal(raw);
20510
20580
  const expectedKind = readExpectedModelKind(args);
20511
20581
  const failures = validateModelBundle(bundle, expectedKind, {
20512
- capabilityRoot: path47.join(ctx.cwd, ".kody", "capabilities")
20582
+ capabilityRoot: path48.join(ctx.cwd, ".kody", "capabilities")
20513
20583
  });
20514
20584
  if (failures.length > 0) {
20515
20585
  throw new Error(`validateAgencyModelProposal: ${failures.join("; ")}`);
@@ -20572,7 +20642,7 @@ function stripAnsi2(s) {
20572
20642
  return s.replace(ANSI_RE2, "");
20573
20643
  }
20574
20644
  function runCommand2(command, cwd) {
20575
- return new Promise((resolve20) => {
20645
+ return new Promise((resolve21) => {
20576
20646
  const child = spawn6(command, {
20577
20647
  cwd,
20578
20648
  shell: true,
@@ -20599,11 +20669,11 @@ function runCommand2(command, cwd) {
20599
20669
  }, TEST_TIMEOUT_MS);
20600
20670
  child.on("exit", (code) => {
20601
20671
  clearTimeout(timer);
20602
- resolve20({ exitCode: code ?? -1, output: Buffer.concat(buffers).toString("utf-8") });
20672
+ resolve21({ exitCode: code ?? -1, output: Buffer.concat(buffers).toString("utf-8") });
20603
20673
  });
20604
20674
  child.on("error", (err) => {
20605
20675
  clearTimeout(timer);
20606
- resolve20({ exitCode: -1, output: err.message });
20676
+ resolve21({ exitCode: -1, output: err.message });
20607
20677
  });
20608
20678
  });
20609
20679
  }
@@ -21009,21 +21079,21 @@ function lineStream(stream) {
21009
21079
  tryDeliver();
21010
21080
  });
21011
21081
  return {
21012
- next: (timeoutMs) => new Promise((resolve20) => {
21082
+ next: (timeoutMs) => new Promise((resolve21) => {
21013
21083
  if (queue.length > 0) {
21014
- resolve20(queue.shift());
21084
+ resolve21(queue.shift());
21015
21085
  return;
21016
21086
  }
21017
21087
  if (ended) {
21018
- resolve20(null);
21088
+ resolve21(null);
21019
21089
  return;
21020
21090
  }
21021
- waiter = resolve20;
21091
+ waiter = resolve21;
21022
21092
  const t = setTimeout(
21023
21093
  () => {
21024
- if (waiter === resolve20) {
21094
+ if (waiter === resolve21) {
21025
21095
  waiter = null;
21026
- resolve20(null);
21096
+ resolve21(null);
21027
21097
  }
21028
21098
  },
21029
21099
  Math.max(0, timeoutMs)
@@ -21060,7 +21130,7 @@ var init_warmupMcp = __esm({
21060
21130
  });
21061
21131
 
21062
21132
  // src/scripts/writeAgentRunSummary.ts
21063
- import * as fs50 from "fs";
21133
+ import * as fs51 from "fs";
21064
21134
  var writeAgentRunSummary;
21065
21135
  var init_writeAgentRunSummary = __esm({
21066
21136
  "src/scripts/writeAgentRunSummary.ts"() {
@@ -21086,7 +21156,7 @@ var init_writeAgentRunSummary = __esm({
21086
21156
  if (reason) lines.push(`- **Reason:** ${reason}`);
21087
21157
  lines.push("");
21088
21158
  try {
21089
- fs50.appendFileSync(summaryPath, `${lines.join("\n")}
21159
+ fs51.appendFileSync(summaryPath, `${lines.join("\n")}
21090
21160
  `);
21091
21161
  } catch {
21092
21162
  }
@@ -21424,17 +21494,17 @@ var init_scripts = __esm({
21424
21494
  });
21425
21495
 
21426
21496
  // src/stateWorkspace.ts
21427
- import * as fs51 from "fs";
21428
- import * as path48 from "path";
21497
+ import * as fs52 from "fs";
21498
+ import * as path49 from "path";
21429
21499
  function tenantId(config) {
21430
21500
  const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
21431
21501
  const repo = config.github?.repo?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim();
21432
21502
  return owner && repo ? `${owner}/${repo}` : null;
21433
21503
  }
21434
21504
  function writeRuntimeFile(cwd, relativePath, content) {
21435
- const target = path48.join(cwd, RUNTIME_ROOT, relativePath);
21436
- fs51.mkdirSync(path48.dirname(target), { recursive: true });
21437
- fs51.writeFileSync(target, content, "utf8");
21505
+ const target = path49.join(cwd, RUNTIME_ROOT, relativePath);
21506
+ fs52.mkdirSync(path49.dirname(target), { recursive: true });
21507
+ fs52.writeFileSync(target, content, "utf8");
21438
21508
  }
21439
21509
  function record(value) {
21440
21510
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -21499,11 +21569,11 @@ async function hydrateStateWorkspace(config, cwd, backendOverride) {
21499
21569
  throw new Error("Kody backend access is required for runtime workspace documents");
21500
21570
  return;
21501
21571
  }
21502
- const key = `${path48.resolve(cwd)}|${tenant}`;
21572
+ const key = `${path49.resolve(cwd)}|${tenant}`;
21503
21573
  if (hydratedWorkspaces.has(key)) return;
21504
21574
  const backend = backendOverride ?? createStateBackendFromEnv();
21505
- const root = path48.join(cwd, RUNTIME_ROOT);
21506
- fs51.rmSync(root, { recursive: true, force: true });
21575
+ const root = path49.join(cwd, RUNTIME_ROOT);
21576
+ fs52.rmSync(root, { recursive: true, force: true });
21507
21577
  await Promise.all([
21508
21578
  hydratePrefix(backend, tenant, cwd, "context:"),
21509
21579
  hydratePrefix(backend, tenant, cwd, "memory:"),
@@ -21519,7 +21589,7 @@ var init_stateWorkspace = __esm({
21519
21589
  "src/stateWorkspace.ts"() {
21520
21590
  "use strict";
21521
21591
  init_state_backend();
21522
- RUNTIME_ROOT = path48.join(".kody-engine", "runtime");
21592
+ RUNTIME_ROOT = path49.join(".kody-engine", "runtime");
21523
21593
  hydratedWorkspaces = /* @__PURE__ */ new Set();
21524
21594
  }
21525
21595
  });
@@ -21590,9 +21660,9 @@ var init_tools = __esm({
21590
21660
 
21591
21661
  // src/executor.ts
21592
21662
  import { spawn as spawn8 } from "child_process";
21593
- import * as fs52 from "fs";
21663
+ import * as fs53 from "fs";
21594
21664
  import * as os8 from "os";
21595
- import * as path49 from "path";
21665
+ import * as path50 from "path";
21596
21666
  function isMutatingPostflight(scriptName) {
21597
21667
  return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
21598
21668
  }
@@ -21844,7 +21914,7 @@ async function runImplementation(profileName, input) {
21844
21914
  const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
21845
21915
  const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
21846
21916
  const invokeAgent = async (prompt) => {
21847
- const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path49.isAbsolute(p) ? p : path49.resolve(profile.dir, p)).filter((p) => p.length > 0);
21917
+ const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path50.isAbsolute(p) ? p : path50.resolve(profile.dir, p)).filter((p) => p.length > 0);
21848
21918
  const syntheticPath = ctx.data.syntheticPluginPath;
21849
21919
  const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
21850
21920
  const agents = loadSubagents(profile);
@@ -21925,7 +21995,11 @@ async function runImplementation(profileName, input) {
21925
21995
  verifyToolMaxAttempts: profile.claudeCode.verifyAttempts ?? null,
21926
21996
  verifyConfig: profile.claudeCode.enableVerifyTool ? config : void 0,
21927
21997
  implementationName: profileName,
21928
- settingSources: profile.claudeCode.settingSources
21998
+ settingSources: profile.claudeCode.settingSources,
21999
+ outputContract: typeof ctx.data.capabilityOutputPath === "string" && ctx.data.capabilityOutputSchema && typeof ctx.data.capabilityOutputSchema === "object" && !Array.isArray(ctx.data.capabilityOutputSchema) ? {
22000
+ path: ctx.data.capabilityOutputPath,
22001
+ schema: ctx.data.capabilityOutputSchema
22002
+ } : void 0
21929
22003
  });
21930
22004
  };
21931
22005
  ctx.data.__invokeAgent = invokeAgent;
@@ -22321,17 +22395,17 @@ function clearStampedLifecycleLabels(profile, ctx) {
22321
22395
  function resolveProfilePath(profileName, cwd = process.cwd()) {
22322
22396
  const found = resolveImplementation(profileName, getRuntimeProfileRootsForCwd(cwd));
22323
22397
  if (found) return found;
22324
- const here = path49.dirname(new URL(import.meta.url).pathname);
22398
+ const here = path50.dirname(new URL(import.meta.url).pathname);
22325
22399
  const candidates = [
22326
- path49.join(here, "implementations", profileName, "profile.json"),
22400
+ path50.join(here, "implementations", profileName, "profile.json"),
22327
22401
  // same-dir sibling (dev)
22328
- path49.join(here, "..", "implementations", profileName, "profile.json"),
22402
+ path50.join(here, "..", "implementations", profileName, "profile.json"),
22329
22403
  // up one (prod: dist/bin → dist/implementations)
22330
- path49.join(here, "..", "src", "implementations", profileName, "profile.json")
22404
+ path50.join(here, "..", "src", "implementations", profileName, "profile.json")
22331
22405
  // fallback
22332
22406
  ];
22333
22407
  for (const c of candidates) {
22334
- if (fs52.existsSync(c)) return c;
22408
+ if (fs53.existsSync(c)) return c;
22335
22409
  }
22336
22410
  return candidates[0];
22337
22411
  }
@@ -22446,15 +22520,15 @@ function resolveShellTimeoutMs(entry) {
22446
22520
  }
22447
22521
  async function runShellEntry(entry, ctx, profile) {
22448
22522
  const shellName = entry.shell;
22449
- const shellPath = path49.join(profile.dir, shellName);
22450
- if (!fs52.existsSync(shellPath)) {
22523
+ const shellPath = path50.join(profile.dir, shellName);
22524
+ if (!fs53.existsSync(shellPath)) {
22451
22525
  ctx.skipAgent = true;
22452
22526
  ctx.output.exitCode = 99;
22453
22527
  ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
22454
22528
  return;
22455
22529
  }
22456
22530
  const positional = entry.with ? Object.values(entry.with).map((v) => String(v)) : [];
22457
- const outputFile = path49.join(
22531
+ const outputFile = path50.join(
22458
22532
  os8.tmpdir(),
22459
22533
  `kody-shell-output-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
22460
22534
  );
@@ -22484,14 +22558,14 @@ async function runShellEntry(entry, ctx, profile) {
22484
22558
  let killTimer;
22485
22559
  let escalateTimer;
22486
22560
  const result = await new Promise(
22487
- (resolve20) => {
22561
+ (resolve21) => {
22488
22562
  let settled = false;
22489
22563
  const settle = (code, signal, spawnErr) => {
22490
22564
  if (settled) return;
22491
22565
  settled = true;
22492
22566
  if (killTimer) clearTimeout(killTimer);
22493
22567
  if (escalateTimer) clearTimeout(escalateTimer);
22494
- resolve20({ code, signal, spawnErr });
22568
+ resolve21({ code, signal, spawnErr });
22495
22569
  };
22496
22570
  child.on("error", (err) => settle(null, null, err));
22497
22571
  child.on("close", (code, signal) => settle(code, signal));
@@ -22521,9 +22595,9 @@ async function runShellEntry(entry, ctx, profile) {
22521
22595
  }
22522
22596
  let sideChannelText = "";
22523
22597
  try {
22524
- if (fs52.existsSync(outputFile)) {
22525
- sideChannelText = fs52.readFileSync(outputFile, "utf-8");
22526
- fs52.rmSync(outputFile, { force: true });
22598
+ if (fs53.existsSync(outputFile)) {
22599
+ sideChannelText = fs53.readFileSync(outputFile, "utf-8");
22600
+ fs53.rmSync(outputFile, { force: true });
22527
22601
  }
22528
22602
  } catch {
22529
22603
  }
@@ -22593,7 +22667,6 @@ var init_executor = __esm({
22593
22667
  "commitAndPush",
22594
22668
  "ensurePr",
22595
22669
  "applyCapabilityReports",
22596
- "publishReport",
22597
22670
  "openAgencyModelReviewPr"
22598
22671
  ]);
22599
22672
  SHELL_MARKER_RE = /^KODY_(SKIP_AGENT|PR_URL|REASON|CAPABILITY_REPORT|CAPABILITY_RESULT)=/m;
@@ -23379,11 +23452,11 @@ function exhaustedWorkflowTransitions(step, data, counts) {
23379
23452
  }
23380
23453
  function workflowResultConditionPaths(transitions) {
23381
23454
  return transitions.flatMap(
23382
- (transition) => Object.keys(transition.when ?? {}).filter((path54) => path54.startsWith("result."))
23455
+ (transition) => Object.keys(transition.when ?? {}).filter((path55) => path55.startsWith("result."))
23383
23456
  );
23384
23457
  }
23385
23458
  function conditionMatches(condition, context) {
23386
- return Object.entries(condition).every(([path54, expected]) => valueMatches(resolveDottedPath2(context, path54), expected));
23459
+ return Object.entries(condition).every(([path55, expected]) => valueMatches(resolveDottedPath2(context, path55), expected));
23387
23460
  }
23388
23461
  function withWorkflowBoundaryEval(capability, result) {
23389
23462
  const capabilityKind = capability.config.capabilityKind;
@@ -23820,7 +23893,7 @@ function translateOpenAISseToBrain(opts) {
23820
23893
 
23821
23894
  // src/servers/brain-serve.ts
23822
23895
  import { createServer as createServer2 } from "http";
23823
- import * as path52 from "path";
23896
+ import * as path53 from "path";
23824
23897
 
23825
23898
  // src/chat/loop.ts
23826
23899
  init_agent();
@@ -23828,13 +23901,13 @@ init_agents();
23828
23901
  init_config();
23829
23902
  init_registry();
23830
23903
  init_task_artifacts();
23831
- import * as fs16 from "fs";
23832
- import * as path17 from "path";
23904
+ import * as fs17 from "fs";
23905
+ import * as path18 from "path";
23833
23906
 
23834
23907
  // src/chat/attachments.ts
23835
23908
  init_runtimePaths();
23836
- import * as fs13 from "fs";
23837
- import * as path14 from "path";
23909
+ import * as fs14 from "fs";
23910
+ import * as path15 from "path";
23838
23911
  var INLINE_ATTACHMENT_RE = /(?:\[(?:Image|File): ([^\]]*)\]\n)?data:([\w.+-]+\/[\w.+-]+);base64,([A-Za-z0-9+/=]+)/g;
23839
23912
  var EXT_BY_MIME = {
23840
23913
  "image/png": "png",
@@ -23867,11 +23940,11 @@ function prepareAttachments(turns, cwd, sessionId) {
23867
23940
  if (!isImage) return `[File: ${name}]`;
23868
23941
  try {
23869
23942
  if (!dirEnsured) {
23870
- fs13.mkdirSync(dir, { recursive: true });
23943
+ fs14.mkdirSync(dir, { recursive: true });
23871
23944
  dirEnsured = true;
23872
23945
  }
23873
- const filePath = path14.join(dir, `${imageCounter}.${extFor(mime)}`);
23874
- fs13.writeFileSync(filePath, Buffer.from(data, "base64"));
23946
+ const filePath = path15.join(dir, `${imageCounter}.${extFor(mime)}`);
23947
+ fs14.writeFileSync(filePath, Buffer.from(data, "base64"));
23875
23948
  imageCounter += 1;
23876
23949
  imagePaths.push(filePath);
23877
23950
  return `[Image "${name}" is attached \u2014 saved to ${filePath}. Use the Read tool on that exact path to view it.]`;
@@ -23888,8 +23961,8 @@ function prepareAttachments(turns, cwd, sessionId) {
23888
23961
 
23889
23962
  // src/chat/codex-app-server.ts
23890
23963
  import { spawn as spawn3 } from "child_process";
23891
- import * as fs14 from "fs";
23892
- import * as path15 from "path";
23964
+ import * as fs15 from "fs";
23965
+ import * as path16 from "path";
23893
23966
  import { createInterface } from "readline";
23894
23967
  function codexThreadStartParams(args) {
23895
23968
  return {
@@ -23974,9 +24047,9 @@ var CodexAppServerClient = class {
23974
24047
  await this.request("thread/resume", { threadId });
23975
24048
  }
23976
24049
  async runTurn(args) {
23977
- await new Promise((resolve20, reject) => {
24050
+ await new Promise((resolve21, reject) => {
23978
24051
  this.process.turnWaiters.set(args.threadId, {
23979
- resolve: resolve20,
24052
+ resolve: resolve21,
23980
24053
  reject,
23981
24054
  onNotification: args.onNotification,
23982
24055
  queue: Promise.resolve()
@@ -23993,8 +24066,8 @@ var CodexAppServerClient = class {
23993
24066
  }
23994
24067
  request(method, params) {
23995
24068
  const id = this.process.nextId++;
23996
- return new Promise((resolve20, reject) => {
23997
- this.process.pending.set(id, { resolve: resolve20, reject });
24069
+ return new Promise((resolve21, reject) => {
24070
+ this.process.pending.set(id, { resolve: resolve21, reject });
23998
24071
  this.process.child.stdin.write(`${JSON.stringify({ method, id, params })}
23999
24072
  `);
24000
24073
  });
@@ -24060,11 +24133,11 @@ var CodexAppServerClient = class {
24060
24133
  };
24061
24134
  var clients = /* @__PURE__ */ new Map();
24062
24135
  function threadMapPath(cwd) {
24063
- return path15.join(cwd, ".kody-engine", "runtime", "codex-threads.json");
24136
+ return path16.join(cwd, ".kody-engine", "runtime", "codex-threads.json");
24064
24137
  }
24065
24138
  function readThreadMap(cwd) {
24066
24139
  try {
24067
- const value = JSON.parse(fs14.readFileSync(threadMapPath(cwd), "utf8"));
24140
+ const value = JSON.parse(fs15.readFileSync(threadMapPath(cwd), "utf8"));
24068
24141
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
24069
24142
  return Object.fromEntries(
24070
24143
  Object.entries(value).filter(
@@ -24077,8 +24150,8 @@ function readThreadMap(cwd) {
24077
24150
  }
24078
24151
  function writeThreadMap(cwd, map) {
24079
24152
  const file = threadMapPath(cwd);
24080
- fs14.mkdirSync(path15.dirname(file), { recursive: true });
24081
- fs14.writeFileSync(file, `${JSON.stringify(map, null, 2)}
24153
+ fs15.mkdirSync(path16.dirname(file), { recursive: true });
24154
+ fs15.writeFileSync(file, `${JSON.stringify(map, null, 2)}
24082
24155
  `);
24083
24156
  }
24084
24157
  async function runCodexChatTurn(args) {
@@ -24168,8 +24241,8 @@ async function runCodexChatTurn(args) {
24168
24241
  }
24169
24242
 
24170
24243
  // src/chat/events.ts
24171
- import * as fs15 from "fs";
24172
- import * as path16 from "path";
24244
+ import * as fs16 from "fs";
24245
+ import * as path17 from "path";
24173
24246
  import posixPath2 from "path/posix";
24174
24247
  var BackendEventSink = class {
24175
24248
  constructor(append, tenantId2, sessionId) {
@@ -24185,7 +24258,7 @@ var BackendEventSink = class {
24185
24258
  }
24186
24259
  };
24187
24260
  function eventsFilePath(cwd, sessionId) {
24188
- return path16.join(cwd, ".kody-engine", "runtime", "events", `${sessionId}.jsonl`);
24261
+ return path17.join(cwd, ".kody-engine", "runtime", "events", `${sessionId}.jsonl`);
24189
24262
  }
24190
24263
  var FileSink = class {
24191
24264
  constructor(file) {
@@ -24193,8 +24266,8 @@ var FileSink = class {
24193
24266
  }
24194
24267
  file;
24195
24268
  async emit(event) {
24196
- fs15.mkdirSync(path16.dirname(this.file), { recursive: true });
24197
- fs15.appendFileSync(this.file, `${JSON.stringify(event)}
24269
+ fs16.mkdirSync(path17.dirname(this.file), { recursive: true });
24270
+ fs16.appendFileSync(this.file, `${JSON.stringify(event)}
24198
24271
  `);
24199
24272
  }
24200
24273
  };
@@ -24459,7 +24532,7 @@ function buildImplementationCatalog() {
24459
24532
  const entries = [];
24460
24533
  for (const { name, profilePath } of discovered) {
24461
24534
  try {
24462
- const raw = JSON.parse(fs16.readFileSync(profilePath, "utf-8"));
24535
+ const raw = JSON.parse(fs17.readFileSync(profilePath, "utf-8"));
24463
24536
  const describe = typeof raw.describe === "string" ? raw.describe : "";
24464
24537
  const firstSentence = describe.split(/(?<=[.!?])\s+/, 1)[0] ?? "";
24465
24538
  entries.push({ name, describe: firstSentence.trim() });
@@ -24581,7 +24654,7 @@ async function runChatTurn(opts) {
24581
24654
  quiet: opts.quiet,
24582
24655
  additionalDirectories: [
24583
24656
  taskArtifactsPaths.absDir,
24584
- ...Array.from(new Set(imagePaths.map((p2) => path17.dirname(p2))))
24657
+ ...Array.from(new Set(imagePaths.map((p2) => path18.dirname(p2))))
24585
24658
  ],
24586
24659
  systemPromptAppend: systemPrompt,
24587
24660
  ...opts.reasoningEffort ? { reasoningEffort: opts.reasoningEffort } : {},
@@ -24769,10 +24842,10 @@ async function emit(sink, type, sessionId, suffix, payload) {
24769
24842
  var MEMORY_INDEX_REL = ".kody-engine/runtime/memory/INDEX.md";
24770
24843
  var MAX_INDEX_BYTES = 8e3;
24771
24844
  function readMemoryIndexBlock(cwd) {
24772
- const indexPath = path17.join(cwd, MEMORY_INDEX_REL);
24845
+ const indexPath = path18.join(cwd, MEMORY_INDEX_REL);
24773
24846
  let raw;
24774
24847
  try {
24775
- raw = fs16.readFileSync(indexPath, "utf-8");
24848
+ raw = fs17.readFileSync(indexPath, "utf-8");
24776
24849
  } catch {
24777
24850
  return "";
24778
24851
  }
@@ -24792,17 +24865,17 @@ _\u2026 (memory index truncated; use recall_search to read more)_` : trimmed;
24792
24865
  var CONTEXT_DIR_REL = ".kody-engine/runtime/context";
24793
24866
  var MAX_CONTEXT_BYTES = 12e3;
24794
24867
  function readContextBlock(cwd) {
24795
- const dir = path17.join(cwd, CONTEXT_DIR_REL);
24868
+ const dir = path18.join(cwd, CONTEXT_DIR_REL);
24796
24869
  let files;
24797
24870
  try {
24798
- files = fs16.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
24871
+ files = fs17.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
24799
24872
  } catch {
24800
24873
  return "";
24801
24874
  }
24802
24875
  const sections = [];
24803
24876
  for (const file of files) {
24804
24877
  try {
24805
- const content = fs16.readFileSync(path17.join(dir, file), "utf-8").trim();
24878
+ const content = fs17.readFileSync(path18.join(dir, file), "utf-8").trim();
24806
24879
  if (content) sections.push(`### ${file.replace(/\.md$/, "")}
24807
24880
 
24808
24881
  ${content}`);
@@ -24828,7 +24901,7 @@ var SYSTEM_PROMPT_OVERRIDE_REL = ".kody-engine/runtime/system-prompt.md";
24828
24901
  function readSystemPromptOverride(cwd) {
24829
24902
  let raw;
24830
24903
  try {
24831
- raw = fs16.readFileSync(path17.join(cwd, SYSTEM_PROMPT_OVERRIDE_REL), "utf-8");
24904
+ raw = fs17.readFileSync(path18.join(cwd, SYSTEM_PROMPT_OVERRIDE_REL), "utf-8");
24832
24905
  } catch {
24833
24906
  return null;
24834
24907
  }
@@ -24836,10 +24909,10 @@ function readSystemPromptOverride(cwd) {
24836
24909
  return trimmed.length > 0 ? trimmed : null;
24837
24910
  }
24838
24911
  function readInstructionsBlock(cwd) {
24839
- const instructionsPath = path17.join(cwd, INSTRUCTIONS_REL);
24912
+ const instructionsPath = path18.join(cwd, INSTRUCTIONS_REL);
24840
24913
  let raw;
24841
24914
  try {
24842
- raw = fs16.readFileSync(instructionsPath, "utf-8");
24915
+ raw = fs17.readFileSync(instructionsPath, "utf-8");
24843
24916
  } catch {
24844
24917
  return "";
24845
24918
  }
@@ -24873,15 +24946,15 @@ function resolveBrainDriver(runtime) {
24873
24946
  }
24874
24947
 
24875
24948
  // src/chat/session.ts
24876
- import * as fs17 from "fs";
24877
- import * as path18 from "path";
24949
+ import * as fs18 from "fs";
24950
+ import * as path19 from "path";
24878
24951
  import posixPath3 from "path/posix";
24879
24952
  function sessionFilePath(cwd, sessionId) {
24880
- return path18.join(cwd, ".kody-engine", "runtime", "sessions", `${sessionId}.jsonl`);
24953
+ return path19.join(cwd, ".kody-engine", "runtime", "sessions", `${sessionId}.jsonl`);
24881
24954
  }
24882
24955
  function readSession(file) {
24883
- if (!fs17.existsSync(file)) return [];
24884
- const raw = fs17.readFileSync(file, "utf-8").trim();
24956
+ if (!fs18.existsSync(file)) return [];
24957
+ const raw = fs18.readFileSync(file, "utf-8").trim();
24885
24958
  if (!raw) return [];
24886
24959
  const turns = [];
24887
24960
  for (const line of raw.split("\n")) {
@@ -24904,8 +24977,8 @@ init_config();
24904
24977
  init_state_backend();
24905
24978
  init_workflowDefinitions();
24906
24979
  import { createHash as createHash2 } from "crypto";
24907
- import * as fs19 from "fs";
24908
- import * as path20 from "path";
24980
+ import * as fs20 from "fs";
24981
+ import * as path21 from "path";
24909
24982
  var SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,127}$/;
24910
24983
  var REPOSITORY_OWNED_NAMESPACES = ["loops"];
24911
24984
  function assertSafeDefinitionPath(filePath) {
@@ -24937,9 +25010,9 @@ function verifyDefinition(definition) {
24937
25010
  }
24938
25011
  function writeBundle(root, bundle) {
24939
25012
  for (const [filePath, contents] of Object.entries(bundle.files)) {
24940
- const target = path20.join(root, filePath);
24941
- fs19.mkdirSync(path20.dirname(target), { recursive: true });
24942
- fs19.writeFileSync(target, contents, "utf8");
25013
+ const target = path21.join(root, filePath);
25014
+ fs20.mkdirSync(path21.dirname(target), { recursive: true });
25015
+ fs20.writeFileSync(target, contents, "utf8");
24943
25016
  }
24944
25017
  }
24945
25018
  function writeDefinition(root, kind, definition) {
@@ -24947,22 +25020,22 @@ function writeDefinition(root, kind, definition) {
24947
25020
  if (kind === "agent") {
24948
25021
  const raw = bundle.files["agent.md"];
24949
25022
  if (typeof raw !== "string") throw new Error(`agent definition ${definition.slug} is missing agent.md`);
24950
- fs19.writeFileSync(path20.join(root, "agents", `${definition.slug}.md`), raw, "utf8");
25023
+ fs20.writeFileSync(path21.join(root, "agents", `${definition.slug}.md`), raw, "utf8");
24951
25024
  return;
24952
25025
  }
24953
25026
  if (kind === "goal") {
24954
- writeBundle(path20.join(root, "goals", definition.slug), bundle);
25027
+ writeBundle(path21.join(root, "goals", definition.slug), bundle);
24955
25028
  return;
24956
25029
  }
24957
25030
  if (kind === "implementation") {
24958
- writeBundle(path20.join(root, "implementations", definition.slug), bundle);
25031
+ writeBundle(path21.join(root, "implementations", definition.slug), bundle);
24959
25032
  return;
24960
25033
  }
24961
25034
  if (kind === "asset") {
24962
- writeBundle(path20.join(root, "shared"), bundle);
25035
+ writeBundle(path21.join(root, "shared"), bundle);
24963
25036
  return;
24964
25037
  }
24965
- writeBundle(path20.join(root, "capabilities", definition.slug), bundle);
25038
+ writeBundle(path21.join(root, "capabilities", definition.slug), bundle);
24966
25039
  }
24967
25040
  function writeWorkflow(root, document) {
24968
25041
  const workflow = normalizeWorkflowDefinition(document.definition);
@@ -24970,28 +25043,28 @@ function writeWorkflow(root, document) {
24970
25043
  const contents = `${JSON.stringify(workflow, null, 2)}
24971
25044
  `;
24972
25045
  const bundle = { schemaVersion: 1, files: { "workflow.json": contents } };
24973
- const target = path20.join(root, workflowDefinitionPath(document.workflowId));
24974
- fs19.mkdirSync(path20.dirname(target), { recursive: true });
24975
- fs19.writeFileSync(target, contents, "utf8");
25046
+ const target = path21.join(root, workflowDefinitionPath(document.workflowId));
25047
+ fs20.mkdirSync(path21.dirname(target), { recursive: true });
25048
+ fs20.writeFileSync(target, contents, "utf8");
24976
25049
  return definitionVersion(bundle);
24977
25050
  }
24978
25051
  function preserveRepositoryDefinitions(root, staging) {
24979
25052
  for (const namespace of REPOSITORY_OWNED_NAMESPACES) {
24980
- const source = path20.join(root, namespace);
24981
- if (!fs19.existsSync(source)) continue;
24982
- fs19.cpSync(source, path20.join(staging, namespace), { recursive: true });
25053
+ const source = path21.join(root, namespace);
25054
+ if (!fs20.existsSync(source)) continue;
25055
+ fs20.cpSync(source, path21.join(staging, namespace), { recursive: true });
24983
25056
  }
24984
25057
  }
24985
25058
  async function hydrateDefinitions(options) {
24986
- const root = path20.join(options.cwd, ".kody-engine", "definitions");
25059
+ const root = path21.join(options.cwd, ".kody-engine", "definitions");
24987
25060
  const staging = `${root}.tmp-${process.pid}-${Date.now()}`;
24988
- fs19.rmSync(staging, { recursive: true, force: true });
24989
- fs19.mkdirSync(path20.join(staging, "agents"), { recursive: true });
24990
- fs19.mkdirSync(path20.join(staging, "capabilities"), { recursive: true });
24991
- fs19.mkdirSync(path20.join(staging, "goals"), { recursive: true });
24992
- fs19.mkdirSync(path20.join(staging, "implementations"), { recursive: true });
24993
- fs19.mkdirSync(path20.join(staging, "shared"), { recursive: true });
24994
- fs19.mkdirSync(path20.join(staging, "workflows"), { recursive: true });
25061
+ fs20.rmSync(staging, { recursive: true, force: true });
25062
+ fs20.mkdirSync(path21.join(staging, "agents"), { recursive: true });
25063
+ fs20.mkdirSync(path21.join(staging, "capabilities"), { recursive: true });
25064
+ fs20.mkdirSync(path21.join(staging, "goals"), { recursive: true });
25065
+ fs20.mkdirSync(path21.join(staging, "implementations"), { recursive: true });
25066
+ fs20.mkdirSync(path21.join(staging, "shared"), { recursive: true });
25067
+ fs20.mkdirSync(path21.join(staging, "workflows"), { recursive: true });
24995
25068
  try {
24996
25069
  const [capabilities, agents, goals, implementations, assets, workflows] = await Promise.all([
24997
25070
  options.backend.listDefinitions(options.tenantId, "capability"),
@@ -25032,13 +25105,13 @@ async function hydrateDefinitions(options) {
25032
25105
  hydratedAt: (/* @__PURE__ */ new Date()).toISOString(),
25033
25106
  versions: Object.fromEntries(Object.entries(versions).sort(([left], [right]) => left.localeCompare(right)))
25034
25107
  };
25035
- fs19.writeFileSync(path20.join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
25108
+ fs20.writeFileSync(path21.join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
25036
25109
  `, "utf8");
25037
- fs19.rmSync(root, { recursive: true, force: true });
25038
- fs19.renameSync(staging, root);
25110
+ fs20.rmSync(root, { recursive: true, force: true });
25111
+ fs20.renameSync(staging, root);
25039
25112
  return { root, tenantId: options.tenantId, versions: manifest.versions };
25040
25113
  } catch (error) {
25041
- fs19.rmSync(staging, { recursive: true, force: true });
25114
+ fs20.rmSync(staging, { recursive: true, force: true });
25042
25115
  throw error;
25043
25116
  }
25044
25117
  }
@@ -25060,8 +25133,8 @@ async function hydrateDefinitionsFromEnv(cwd = process.cwd(), env = process.env)
25060
25133
 
25061
25134
  // src/kody-cli.ts
25062
25135
  import { execFileSync as execFileSync24 } from "child_process";
25063
- import * as fs53 from "fs";
25064
- import * as path50 from "path";
25136
+ import * as fs54 from "fs";
25137
+ import * as path51 from "path";
25065
25138
 
25066
25139
  // src/app-auth.ts
25067
25140
  import { createSign } from "crypto";
@@ -25190,7 +25263,7 @@ init_definition_paths();
25190
25263
 
25191
25264
  // src/dispatch.ts
25192
25265
  init_config();
25193
- import * as fs20 from "fs";
25266
+ import * as fs21 from "fs";
25194
25267
 
25195
25268
  // src/cron-match.ts
25196
25269
  var FIELD_BOUNDS = [
@@ -25297,10 +25370,10 @@ function autoDispatch(opts) {
25297
25370
  }
25298
25371
  const eventName = process.env.GITHUB_EVENT_NAME;
25299
25372
  const eventPath = process.env.GITHUB_EVENT_PATH;
25300
- if (!eventName || !eventPath || !fs20.existsSync(eventPath)) return null;
25373
+ if (!eventName || !eventPath || !fs21.existsSync(eventPath)) return null;
25301
25374
  let event = {};
25302
25375
  try {
25303
- event = JSON.parse(fs20.readFileSync(eventPath, "utf-8"));
25376
+ event = JSON.parse(fs21.readFileSync(eventPath, "utf-8"));
25304
25377
  } catch {
25305
25378
  return null;
25306
25379
  }
@@ -25424,7 +25497,7 @@ function autoDispatchTyped(opts) {
25424
25497
  if (legacy) return { kind: "route", ...legacy };
25425
25498
  const eventName = process.env.GITHUB_EVENT_NAME;
25426
25499
  const eventPath = process.env.GITHUB_EVENT_PATH;
25427
- if (!eventName || !eventPath || !fs20.existsSync(eventPath)) {
25500
+ if (!eventName || !eventPath || !fs21.existsSync(eventPath)) {
25428
25501
  return { kind: "silent", reason: "no GHA event context" };
25429
25502
  }
25430
25503
  if (eventName !== "issue_comment") {
@@ -25432,7 +25505,7 @@ function autoDispatchTyped(opts) {
25432
25505
  }
25433
25506
  let event = {};
25434
25507
  try {
25435
- event = JSON.parse(fs20.readFileSync(eventPath, "utf-8"));
25508
+ event = JSON.parse(fs21.readFileSync(eventPath, "utf-8"));
25436
25509
  } catch {
25437
25510
  return { kind: "silent", reason: "GHA event payload unreadable" };
25438
25511
  }
@@ -25486,7 +25559,7 @@ function dispatchScheduledWatches(opts) {
25486
25559
  for (const exe of listRuntimeProfilesForCwd(opts?.cwd ?? process.cwd())) {
25487
25560
  let raw;
25488
25561
  try {
25489
- raw = fs20.readFileSync(exe.profilePath, "utf-8");
25562
+ raw = fs21.readFileSync(exe.profilePath, "utf-8");
25490
25563
  } catch {
25491
25564
  continue;
25492
25565
  }
@@ -25863,9 +25936,9 @@ async function resolveAuthToken(env = process.env) {
25863
25936
  return void 0;
25864
25937
  }
25865
25938
  function detectPackageManager2(cwd) {
25866
- if (fs53.existsSync(path50.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
25867
- if (fs53.existsSync(path50.join(cwd, "yarn.lock"))) return "yarn";
25868
- if (fs53.existsSync(path50.join(cwd, "bun.lockb"))) return "bun";
25939
+ if (fs54.existsSync(path51.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
25940
+ if (fs54.existsSync(path51.join(cwd, "yarn.lock"))) return "yarn";
25941
+ if (fs54.existsSync(path51.join(cwd, "bun.lockb"))) return "bun";
25869
25942
  return "npm";
25870
25943
  }
25871
25944
  function shouldChainScheduledWatch(match) {
@@ -25968,8 +26041,8 @@ function postFailureTail(issueNumber, cwd, reason) {
25968
26041
  const logPath = lastRunLogPath(cwd);
25969
26042
  let tail = "";
25970
26043
  try {
25971
- if (fs53.existsSync(logPath)) {
25972
- const content = fs53.readFileSync(logPath, "utf-8");
26044
+ if (fs54.existsSync(logPath)) {
26045
+ const content = fs54.readFileSync(logPath, "utf-8");
25973
26046
  tail = content.slice(-3e3);
25974
26047
  }
25975
26048
  } catch {
@@ -25998,7 +26071,7 @@ async function runCi(argv) {
25998
26071
  return 0;
25999
26072
  }
26000
26073
  const args = parseCiArgs(argv);
26001
- const cwd = args.cwd ? path50.resolve(args.cwd) : process.cwd();
26074
+ const cwd = args.cwd ? path51.resolve(args.cwd) : process.cwd();
26002
26075
  try {
26003
26076
  const n = unpackAllSecrets();
26004
26077
  if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s) from ALL_SECRETS
@@ -26064,9 +26137,9 @@ async function runCi(argv) {
26064
26137
  forceRunCliArgs = { goal: envForceMessage };
26065
26138
  }
26066
26139
  }
26067
- if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs53.existsSync(dispatchEventPath)) {
26140
+ if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs54.existsSync(dispatchEventPath)) {
26068
26141
  try {
26069
- const evt = JSON.parse(fs53.readFileSync(dispatchEventPath, "utf-8"));
26142
+ const evt = JSON.parse(fs54.readFileSync(dispatchEventPath, "utf-8"));
26070
26143
  const inputs = objectValue2(evt.inputs);
26071
26144
  const issueInput = parseInt(String(inputs?.issue_number ?? ""), 10);
26072
26145
  const sessionInput = String(inputs?.sessionId ?? "");
@@ -26481,8 +26554,8 @@ init_repoWorkspace();
26481
26554
 
26482
26555
  // src/scripts/brainTurnLog.ts
26483
26556
  init_runtimePaths();
26484
- import * as fs54 from "fs";
26485
- import * as path51 from "path";
26557
+ import * as fs55 from "fs";
26558
+ import * as path52 from "path";
26486
26559
  import posixPath4 from "path/posix";
26487
26560
  var live = /* @__PURE__ */ new Map();
26488
26561
  function brainEventsFilePath(dir, chatId) {
@@ -26490,8 +26563,8 @@ function brainEventsFilePath(dir, chatId) {
26490
26563
  }
26491
26564
  function lastPersistedSeq(dir, chatId) {
26492
26565
  const p = brainEventsFilePath(dir, chatId);
26493
- if (!fs54.existsSync(p)) return 0;
26494
- const lines = fs54.readFileSync(p, "utf-8").split("\n").filter(Boolean);
26566
+ if (!fs55.existsSync(p)) return 0;
26567
+ const lines = fs55.readFileSync(p, "utf-8").split("\n").filter(Boolean);
26495
26568
  if (lines.length === 0) return 0;
26496
26569
  try {
26497
26570
  return JSON.parse(lines[lines.length - 1]).seq || 0;
@@ -26501,9 +26574,9 @@ function lastPersistedSeq(dir, chatId) {
26501
26574
  }
26502
26575
  function readSince(dir, chatId, since) {
26503
26576
  const p = brainEventsFilePath(dir, chatId);
26504
- if (!fs54.existsSync(p)) return [];
26577
+ if (!fs55.existsSync(p)) return [];
26505
26578
  const out = [];
26506
- for (const line of fs54.readFileSync(p, "utf-8").split("\n")) {
26579
+ for (const line of fs55.readFileSync(p, "utf-8").split("\n")) {
26507
26580
  if (!line) continue;
26508
26581
  try {
26509
26582
  const rec = JSON.parse(line);
@@ -26529,12 +26602,12 @@ function beginTurn(dir, chatId) {
26529
26602
  };
26530
26603
  live.set(chatId, state);
26531
26604
  const p = brainEventsFilePath(dir, chatId);
26532
- fs54.mkdirSync(path51.dirname(p), { recursive: true });
26605
+ fs55.mkdirSync(path52.dirname(p), { recursive: true });
26533
26606
  return (event) => {
26534
26607
  state.seq += 1;
26535
26608
  const rec = { seq: state.seq, turn, ts: Date.now(), event };
26536
26609
  try {
26537
- fs54.appendFileSync(p, `${JSON.stringify(rec)}
26610
+ fs55.appendFileSync(p, `${JSON.stringify(rec)}
26538
26611
  `);
26539
26612
  } catch (err) {
26540
26613
  process.stderr.write(
@@ -26573,7 +26646,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
26573
26646
  event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
26574
26647
  };
26575
26648
  try {
26576
- fs54.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
26649
+ fs55.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
26577
26650
  `);
26578
26651
  } catch {
26579
26652
  }
@@ -26667,17 +26740,17 @@ function authOk(req, expected) {
26667
26740
  return false;
26668
26741
  }
26669
26742
  function readJsonBody(req) {
26670
- return new Promise((resolve20, reject) => {
26743
+ return new Promise((resolve21, reject) => {
26671
26744
  const chunks = [];
26672
26745
  req.on("data", (c) => chunks.push(c));
26673
26746
  req.on("end", () => {
26674
26747
  const raw = Buffer.concat(chunks).toString("utf-8");
26675
26748
  if (!raw.trim()) {
26676
- resolve20({});
26749
+ resolve21({});
26677
26750
  return;
26678
26751
  }
26679
26752
  try {
26680
- resolve20(JSON.parse(raw));
26753
+ resolve21(JSON.parse(raw));
26681
26754
  } catch (err) {
26682
26755
  reject(err instanceof Error ? err : new Error(String(err)));
26683
26756
  }
@@ -26969,7 +27042,7 @@ function buildServer(opts) {
26969
27042
  const runTurn = opts.runTurn ?? runChatTurn;
26970
27043
  const createStore = opts.createStore ?? createSessionStore;
26971
27044
  const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
26972
- const reposRoot = opts.reposRoot ?? path52.join(path52.dirname(path52.resolve(opts.cwd)), "repos");
27045
+ const reposRoot = opts.reposRoot ?? path53.join(path53.dirname(path53.resolve(opts.cwd)), "repos");
26973
27046
  return createServer2(async (req, res) => {
26974
27047
  if (!req.method || !req.url) {
26975
27048
  sendJson(res, 400, { error: "bad request" });
@@ -27050,11 +27123,11 @@ async function brainServe(opts) {
27050
27123
  litellmUrl,
27051
27124
  driver
27052
27125
  });
27053
- await new Promise((resolve20) => {
27126
+ await new Promise((resolve21) => {
27054
27127
  server.listen(port, "0.0.0.0", () => {
27055
27128
  process.stdout.write(`[brain-serve] listening on 0.0.0.0:${port} (cwd=${opts.cwd})
27056
27129
  `);
27057
- resolve20();
27130
+ resolve21();
27058
27131
  });
27059
27132
  });
27060
27133
  const shutdown = (signal) => {
@@ -27309,14 +27382,14 @@ async function startBrainProxy(opts) {
27309
27382
  const { httpServer, handler } = buildBrainProxy(opts);
27310
27383
  const port = opts.port ?? 0;
27311
27384
  const host = opts.host ?? "127.0.0.1";
27312
- await new Promise((resolve20) => httpServer.listen(port, host, () => resolve20()));
27385
+ await new Promise((resolve21) => httpServer.listen(port, host, () => resolve21()));
27313
27386
  const addr = httpServer.address();
27314
27387
  return {
27315
27388
  httpServer,
27316
27389
  port: addr.port,
27317
27390
  url: `http://${host}:${addr.port}`,
27318
- stop: () => new Promise((resolve20) => {
27319
- httpServer.close(() => resolve20());
27391
+ stop: () => new Promise((resolve21) => {
27392
+ httpServer.close(() => resolve21());
27320
27393
  }),
27321
27394
  handler
27322
27395
  };
@@ -27466,23 +27539,23 @@ function buildMcpHttpServer(opts) {
27466
27539
  httpServer,
27467
27540
  routes,
27468
27541
  port,
27469
- stop: () => new Promise((resolve20) => {
27542
+ stop: () => new Promise((resolve21) => {
27470
27543
  let pending = transports.size;
27471
27544
  if (pending === 0) {
27472
- httpServer.close(() => resolve20());
27545
+ httpServer.close(() => resolve21());
27473
27546
  return;
27474
27547
  }
27475
27548
  for (const transport of transports.values()) {
27476
27549
  void transport.close().finally(() => {
27477
27550
  pending--;
27478
- if (pending === 0) httpServer.close(() => resolve20());
27551
+ if (pending === 0) httpServer.close(() => resolve21());
27479
27552
  });
27480
27553
  }
27481
27554
  })
27482
27555
  };
27483
27556
  }
27484
27557
  function listenMcpHttpServer(server, host = "127.0.0.1") {
27485
- return new Promise((resolve20, reject) => {
27558
+ return new Promise((resolve21, reject) => {
27486
27559
  server.httpServer.once("error", reject);
27487
27560
  server.httpServer.listen(server.port, host, () => {
27488
27561
  server.httpServer.off("error", reject);
@@ -27490,7 +27563,7 @@ function listenMcpHttpServer(server, host = "127.0.0.1") {
27490
27563
  if (addr && typeof addr === "object") {
27491
27564
  server.port = addr.port;
27492
27565
  }
27493
- resolve20();
27566
+ resolve21();
27494
27567
  });
27495
27568
  });
27496
27569
  }
@@ -27573,7 +27646,7 @@ async function loadConfigSafe() {
27573
27646
  }
27574
27647
 
27575
27648
  // src/chat-cli.ts
27576
- import * as path53 from "path";
27649
+ import * as path54 from "path";
27577
27650
 
27578
27651
  // src/chat/inbox.ts
27579
27652
  import { execFileSync as execFileSync25 } from "child_process";
@@ -27640,7 +27713,7 @@ async function waitForNextUserMessage(opts) {
27640
27713
  }
27641
27714
  }
27642
27715
  function sleep3(ms) {
27643
- return new Promise((resolve20) => setTimeout(resolve20, ms));
27716
+ return new Promise((resolve21) => setTimeout(resolve21, ms));
27644
27717
  }
27645
27718
  function currentBranch(cwd) {
27646
27719
  try {
@@ -27864,7 +27937,7 @@ async function runChat(argv) {
27864
27937
  ${CHAT_HELP}`);
27865
27938
  return 64;
27866
27939
  }
27867
- const cwd = args.cwd ? path53.resolve(args.cwd) : process.cwd();
27940
+ const cwd = args.cwd ? path54.resolve(args.cwd) : process.cwd();
27868
27941
  const sessionId = args.sessionId;
27869
27942
  const runRequest = readRunRequestFromEnv();
27870
27943
  if (runRequest && "request" in runRequest) {
@@ -28060,8 +28133,8 @@ var FlyClient = class {
28060
28133
  get fetch() {
28061
28134
  return this.opts.fetchImpl ?? fetch;
28062
28135
  }
28063
- async call(path54, init = {}) {
28064
- const res = await this.fetch(`${FLY_API_BASE}${path54}`, {
28136
+ async call(path55, init = {}) {
28137
+ const res = await this.fetch(`${FLY_API_BASE}${path55}`, {
28065
28138
  method: init.method ?? "GET",
28066
28139
  headers: {
28067
28140
  Authorization: `Bearer ${this.opts.token}`,
@@ -28072,7 +28145,7 @@ var FlyClient = class {
28072
28145
  if (res.status === 404 && init.allow404) return null;
28073
28146
  if (!res.ok) {
28074
28147
  const text2 = await res.text().catch(() => "");
28075
- throw new Error(`Fly API ${res.status} on ${path54}: ${text2.slice(0, 200) || res.statusText}`);
28148
+ throw new Error(`Fly API ${res.status} on ${path55}: ${text2.slice(0, 200) || res.statusText}`);
28076
28149
  }
28077
28150
  if (res.status === 204) return null;
28078
28151
  const raw = await res.text();
@@ -28585,14 +28658,14 @@ function sendJson2(res, status, body) {
28585
28658
  res.end(JSON.stringify(body));
28586
28659
  }
28587
28660
  function readJsonBody2(req) {
28588
- return new Promise((resolve20, reject) => {
28661
+ return new Promise((resolve21, reject) => {
28589
28662
  const chunks = [];
28590
28663
  req.on("data", (c) => chunks.push(c));
28591
28664
  req.on("end", () => {
28592
28665
  const raw = Buffer.concat(chunks).toString("utf-8");
28593
- if (!raw.trim()) return resolve20({});
28666
+ if (!raw.trim()) return resolve21({});
28594
28667
  try {
28595
- resolve20(JSON.parse(raw));
28668
+ resolve21(JSON.parse(raw));
28596
28669
  } catch (err) {
28597
28670
  reject(err instanceof Error ? err : new Error(String(err)));
28598
28671
  }
@@ -28746,10 +28819,10 @@ async function poolServe() {
28746
28819
  }
28747
28820
  });
28748
28821
  const apiHost = process.env.POOL_API_HOST ?? "::";
28749
- await new Promise((resolve20) => {
28822
+ await new Promise((resolve21) => {
28750
28823
  server.listen(apiPort, apiHost, () => {
28751
28824
  log(`listening on ${apiHost}:${apiPort} (min=${min}, app=${app}, region=${region})`);
28752
- resolve20();
28825
+ resolve21();
28753
28826
  });
28754
28827
  });
28755
28828
  if (loopTickEnabled) void runLoopTick();
@@ -28768,7 +28841,7 @@ async function poolServe() {
28768
28841
 
28769
28842
  // src/servers/runner-serve.ts
28770
28843
  import { spawn as spawn9 } from "child_process";
28771
- import * as fs55 from "fs";
28844
+ import * as fs56 from "fs";
28772
28845
  import { createServer as createServer6 } from "http";
28773
28846
  var DEFAULT_PORT2 = 8080;
28774
28847
  var DEFAULT_WORKDIR = "/workspace/repo";
@@ -28789,17 +28862,17 @@ function authOk2(req, expected) {
28789
28862
  return false;
28790
28863
  }
28791
28864
  function readJsonBody3(req) {
28792
- return new Promise((resolve20, reject) => {
28865
+ return new Promise((resolve21, reject) => {
28793
28866
  const chunks = [];
28794
28867
  req.on("data", (c) => chunks.push(c));
28795
28868
  req.on("end", () => {
28796
28869
  const raw = Buffer.concat(chunks).toString("utf-8");
28797
28870
  if (!raw.trim()) {
28798
- resolve20({});
28871
+ resolve21({});
28799
28872
  return;
28800
28873
  }
28801
28874
  try {
28802
- resolve20(JSON.parse(raw));
28875
+ resolve21(JSON.parse(raw));
28803
28876
  } catch (err) {
28804
28877
  reject(err instanceof Error ? err : new Error(String(err)));
28805
28878
  }
@@ -28844,8 +28917,8 @@ async function defaultRunJob(job) {
28844
28917
  const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
28845
28918
  const branch = job.ref ?? "main";
28846
28919
  const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
28847
- fs55.rmSync(workdir, { recursive: true, force: true });
28848
- fs55.mkdirSync(workdir, { recursive: true });
28920
+ fs56.rmSync(workdir, { recursive: true, force: true });
28921
+ fs56.mkdirSync(workdir, { recursive: true });
28849
28922
  const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
28850
28923
  const target = job.runRequest.target;
28851
28924
  const interactive = target.type === "chat";
@@ -28874,13 +28947,13 @@ async function defaultRunJob(job) {
28874
28947
  ...interactive && job.idleExitMs ? { KODY_IDLE_EXIT_MS: String(job.idleExitMs) } : {},
28875
28948
  ...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
28876
28949
  };
28877
- const run = (cmd, args, cwd) => new Promise((resolve20) => {
28950
+ const run = (cmd, args, cwd) => new Promise((resolve21) => {
28878
28951
  const child = spawn9(cmd, args, { stdio: "inherit", env: childEnv, cwd });
28879
- child.on("exit", (code) => resolve20(code ?? 0));
28952
+ child.on("exit", (code) => resolve21(code ?? 0));
28880
28953
  child.on("error", (err) => {
28881
28954
  process.stderr.write(`[runner-serve] ${cmd} failed: ${err.message}
28882
28955
  `);
28883
- resolve20(1);
28956
+ resolve21(1);
28884
28957
  });
28885
28958
  });
28886
28959
  process.stdout.write(`[runner-serve] job ${job.jobId}: cloning ${job.repo}@${branch}
@@ -28956,11 +29029,11 @@ async function runnerServe() {
28956
29029
  const port = Number(process.env.PORT ?? DEFAULT_PORT2);
28957
29030
  const server = buildServer2({ apiKey });
28958
29031
  const host = process.env.RUNNER_HOST ?? "::";
28959
- await new Promise((resolve20) => {
29032
+ await new Promise((resolve21) => {
28960
29033
  server.listen(port, host, () => {
28961
29034
  process.stdout.write(`[runner-serve] listening on ${host}:${port} (idle, awaiting job)
28962
29035
  `);
28963
- resolve20();
29036
+ resolve21();
28964
29037
  });
28965
29038
  });
28966
29039
  const shutdown = (signal) => {
@@ -29029,14 +29102,14 @@ async function serve(opts) {
29029
29102
  `);
29030
29103
  const args = ["--dangerously-skip-permissions", "--model", model.model];
29031
29104
  const child = spawn10("claude", args, { stdio: "inherit", env: editorEnv, cwd: opts.cwd });
29032
- const exitCode = await new Promise((resolve20) => {
29033
- child.on("exit", (code) => resolve20(code ?? 0));
29105
+ const exitCode = await new Promise((resolve21) => {
29106
+ child.on("exit", (code) => resolve21(code ?? 0));
29034
29107
  child.on("error", (err) => {
29035
29108
  process.stderr.write(`[kody serve] failed to launch Claude Code: ${err.message}
29036
29109
  `);
29037
29110
  process.stderr.write(` Install: https://docs.anthropic.com/claude/docs/claude-code
29038
29111
  `);
29039
- resolve20(1);
29112
+ resolve21(1);
29040
29113
  });
29041
29114
  });
29042
29115
  killProxy();