@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.
- package/dist/bin/kody.js +763 -690
- 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.
|
|
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
|
|
786
|
+
import * as path4 from "path";
|
|
682
787
|
function runtimeDirForCwd(cwd, ...parts) {
|
|
683
|
-
const key = createHash("sha256").update(
|
|
684
|
-
return
|
|
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 ?
|
|
689
|
-
return
|
|
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
|
|
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
|
|
809
|
+
import * as fs4 from "fs";
|
|
705
810
|
import * as os3 from "os";
|
|
706
|
-
import * as
|
|
811
|
+
import * as path5 from "path";
|
|
707
812
|
function getPluginsCatalogRoot() {
|
|
708
|
-
const here =
|
|
813
|
+
const here = path5.dirname(new URL(import.meta.url).pathname);
|
|
709
814
|
const candidates = [
|
|
710
|
-
|
|
815
|
+
path5.join(here, "..", "plugins"),
|
|
711
816
|
// dev: src/scripts → src/plugins
|
|
712
|
-
|
|
817
|
+
path5.join(here, "..", "..", "plugins"),
|
|
713
818
|
// built: dist/scripts → dist/plugins
|
|
714
|
-
|
|
819
|
+
path5.join(here, "..", "..", "src", "plugins")
|
|
715
820
|
// fallback
|
|
716
821
|
];
|
|
717
822
|
for (const c of candidates) {
|
|
718
|
-
if (
|
|
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
|
-
|
|
724
|
-
for (const ent of
|
|
725
|
-
const s =
|
|
726
|
-
const d =
|
|
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())
|
|
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 =
|
|
742
|
-
|
|
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 =
|
|
745
|
-
if (
|
|
746
|
-
const shared =
|
|
747
|
-
if (
|
|
748
|
-
const central =
|
|
749
|
-
if (
|
|
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 (${
|
|
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 =
|
|
756
|
-
|
|
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),
|
|
863
|
+
copyDir(resolvePart("skills", name), path5.join(dst, name));
|
|
759
864
|
}
|
|
760
865
|
}
|
|
761
866
|
if (cc.commands.length > 0) {
|
|
762
|
-
const dst =
|
|
763
|
-
|
|
867
|
+
const dst = path5.join(root, "commands");
|
|
868
|
+
fs4.mkdirSync(dst, { recursive: true });
|
|
764
869
|
for (const name of cc.commands) {
|
|
765
|
-
|
|
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 =
|
|
770
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
800
|
-
import * as
|
|
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 =
|
|
836
|
-
if (
|
|
837
|
-
const shared =
|
|
838
|
-
if (
|
|
839
|
-
const central =
|
|
840
|
-
if (
|
|
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] =
|
|
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] ??
|
|
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
|
|
896
|
-
import * as
|
|
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
|
-
|
|
930
|
-
|
|
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 (!
|
|
938
|
-
const lines =
|
|
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 (!
|
|
953
|
-
return
|
|
1057
|
+
if (!fs6.existsSync(runsDir)) return [];
|
|
1058
|
+
return fs6.readdirSync(runsDir).filter((name) => {
|
|
954
1059
|
try {
|
|
955
|
-
return
|
|
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((
|
|
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
|
-
|
|
1126
|
+
resolve21({ exitCode: code ?? -1, durationMs: Date.now() - start, tail });
|
|
1022
1127
|
});
|
|
1023
1128
|
child.on("error", (err) => {
|
|
1024
1129
|
clearTimeout(timer);
|
|
1025
|
-
|
|
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,
|
|
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}${
|
|
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
|
|
1419
|
-
return
|
|
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
|
|
1431
|
-
if (!
|
|
1432
|
-
const parts =
|
|
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
|
|
1878
|
-
import * as
|
|
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 (!
|
|
1998
|
+
if (!fs7.existsSync(absDir)) return [];
|
|
1894
1999
|
let entries;
|
|
1895
2000
|
try {
|
|
1896
|
-
entries =
|
|
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(
|
|
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 (!
|
|
1904
|
-
const entries =
|
|
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 =
|
|
1911
|
-
const bodyPath =
|
|
1912
|
-
const contractPath =
|
|
1913
|
-
if (!
|
|
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 =
|
|
1917
|
-
const contract =
|
|
1918
|
-
if (contract?.execution === "script" && !isRegularFile(
|
|
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 =
|
|
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
|
|
2041
|
-
return isPlainObject(property) ? [
|
|
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
|
|
2204
|
-
import * as
|
|
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 &&
|
|
2209
|
-
return storeCatalogRoot(
|
|
2313
|
+
if (override && overrideCwd && path9.resolve(cwd) === path9.resolve(overrideCwd)) {
|
|
2314
|
+
return storeCatalogRoot(path9.resolve(override));
|
|
2210
2315
|
}
|
|
2211
|
-
const hydrated =
|
|
2212
|
-
if (
|
|
2213
|
-
return override ? storeCatalogRoot(
|
|
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 &&
|
|
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") ??
|
|
2326
|
+
return storeAssetRoot(cwd, "capabilities") ?? path9.join(definitionsRoot(cwd), "capabilities");
|
|
2222
2327
|
}
|
|
2223
2328
|
function implementationsRoot(cwd = process.cwd()) {
|
|
2224
|
-
return
|
|
2329
|
+
return path9.join(definitionsRoot(cwd), "implementations");
|
|
2225
2330
|
}
|
|
2226
2331
|
function agentsRoot(cwd = process.cwd()) {
|
|
2227
|
-
return storeAssetRoot(cwd, "agent") ??
|
|
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) =>
|
|
2232
|
-
return roots.length === 3 && new Set(roots).size === 1 ?
|
|
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 &&
|
|
2239
|
-
const root =
|
|
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() ?
|
|
2346
|
+
return typeof configured === "string" && configured.trim() ? path9.join(root, configured) : null;
|
|
2242
2347
|
}
|
|
2243
2348
|
function readStoreManifest(root) {
|
|
2244
|
-
const file =
|
|
2245
|
-
if (!
|
|
2349
|
+
const file = path9.join(root, "kody-store.json");
|
|
2350
|
+
if (!fs8.existsSync(file)) return null;
|
|
2246
2351
|
try {
|
|
2247
|
-
return JSON.parse(
|
|
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
|
|
2260
|
-
import * as
|
|
2364
|
+
import * as fs9 from "fs";
|
|
2365
|
+
import * as path10 from "path";
|
|
2261
2366
|
function getImplementationsRoot() {
|
|
2262
|
-
const here =
|
|
2367
|
+
const here = path10.dirname(new URL(import.meta.url).pathname);
|
|
2263
2368
|
const candidates = [
|
|
2264
|
-
|
|
2369
|
+
path10.join(here, "implementations"),
|
|
2265
2370
|
// dev: src/
|
|
2266
|
-
|
|
2371
|
+
path10.join(here, "..", "implementations"),
|
|
2267
2372
|
// built: dist/bin → dist/implementations
|
|
2268
|
-
|
|
2373
|
+
path10.join(here, "..", "src", "implementations")
|
|
2269
2374
|
// fallback
|
|
2270
2375
|
];
|
|
2271
2376
|
for (const c of candidates) {
|
|
2272
|
-
if (
|
|
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 =
|
|
2382
|
+
const here = path10.dirname(new URL(import.meta.url).pathname);
|
|
2278
2383
|
const candidates = [
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
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 (
|
|
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 =
|
|
2397
|
+
const here = path10.dirname(new URL(import.meta.url).pathname);
|
|
2293
2398
|
const candidates = [
|
|
2294
|
-
|
|
2399
|
+
path10.join(here, "capabilities"),
|
|
2295
2400
|
// dev: src/
|
|
2296
|
-
|
|
2401
|
+
path10.join(here, "..", "capabilities"),
|
|
2297
2402
|
// built: dist/bin → dist/capabilities
|
|
2298
|
-
|
|
2403
|
+
path10.join(here, "..", "src", "capabilities")
|
|
2299
2404
|
// fallback
|
|
2300
2405
|
];
|
|
2301
2406
|
for (const c of candidates) {
|
|
2302
|
-
if (
|
|
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 (!
|
|
2430
|
+
if (!fs9.existsSync(root)) continue;
|
|
2326
2431
|
const requireImplementationProfile = isCapabilityRoot(root);
|
|
2327
|
-
const entries =
|
|
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 (
|
|
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 (
|
|
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(
|
|
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 =
|
|
2438
|
-
if (
|
|
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 &&
|
|
2545
|
+
return knownRoots.some((candidate) => candidate && path10.normalize(candidate) === normalized);
|
|
2441
2546
|
}
|
|
2442
2547
|
function implementationRuntimePath(root, name) {
|
|
2443
|
-
const runtimePath =
|
|
2444
|
-
if (
|
|
2445
|
-
const internalProfilePath =
|
|
2446
|
-
if (
|
|
2447
|
-
return
|
|
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(
|
|
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 (!
|
|
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 (!
|
|
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(
|
|
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
|
|
3581
|
-
import * as
|
|
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 =
|
|
3597
|
-
const dir =
|
|
3598
|
-
if (dir !== root && !dir.startsWith(root +
|
|
3599
|
-
if (
|
|
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
|
-
|
|
3736
|
+
fs10.mkdirSync(path11.dirname(dir), { recursive: true });
|
|
3632
3737
|
const clone = buildCloneProcess(repo, token);
|
|
3633
|
-
return new Promise((
|
|
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
|
-
|
|
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
|
|
3726
|
-
import * as
|
|
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
|
-
|
|
3796
|
-
const ndjsonPath =
|
|
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 =
|
|
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((
|
|
4105
|
+
const timeoutPromise = new Promise((resolve21) => {
|
|
3986
4106
|
timer = setTimeout(() => {
|
|
3987
4107
|
timedOut = true;
|
|
3988
|
-
|
|
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((
|
|
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
|
|
4208
|
-
import * as
|
|
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 (
|
|
4218
|
-
const body = stripFrontmatter(
|
|
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 =
|
|
4230
|
-
if (
|
|
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
|
|
4263
|
-
import
|
|
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
|
-
|
|
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 =
|
|
4300
|
-
if (!
|
|
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 =
|
|
4427
|
+
const full = path14.join(absDir, name);
|
|
4307
4428
|
try {
|
|
4308
|
-
const stat =
|
|
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 =
|
|
4325
|
-
if (!
|
|
4326
|
-
const stat =
|
|
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 =
|
|
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,
|
|
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",
|
|
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 = `${
|
|
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,
|
|
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
|
-
`${
|
|
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
|
-
`${
|
|
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,
|
|
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",
|
|
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
|
-
`${
|
|
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
|
-
`${
|
|
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", `${
|
|
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,
|
|
4738
|
-
issues.push({ code, path:
|
|
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
|
|
4771
|
-
import * as
|
|
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
|
-
|
|
4817
|
-
|
|
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 (!
|
|
4821
|
-
const workflow = parseWorkflowDefinition(
|
|
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:
|
|
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
|
|
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 || !
|
|
5017
|
+
if (!eventPath || !fs22.existsSync(eventPath)) return;
|
|
4897
5018
|
let event = null;
|
|
4898
5019
|
try {
|
|
4899
|
-
event = JSON.parse(
|
|
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
|
|
5481
|
-
import * as
|
|
5550
|
+
import * as fs23 from "fs";
|
|
5551
|
+
import * as path22 from "path";
|
|
5482
5552
|
function loadProfile(profilePath) {
|
|
5483
|
-
if (!
|
|
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(
|
|
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] ${
|
|
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 (
|
|
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:
|
|
5609
|
-
promptTemplates: readPromptTemplates(
|
|
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 (
|
|
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 =
|
|
5649
|
-
const implementation = readJsonObject(
|
|
5650
|
-
const definitionsRoot2 =
|
|
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
|
-
|
|
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(
|
|
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] =
|
|
5783
|
+
out[p] = fs23.readFileSync(p, "utf-8");
|
|
5714
5784
|
} catch {
|
|
5715
5785
|
}
|
|
5716
5786
|
};
|
|
5717
|
-
read(
|
|
5718
|
-
read(
|
|
5719
|
-
read(
|
|
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 =
|
|
5722
|
-
for (const ent of
|
|
5723
|
-
if (ent.endsWith(".md")) read(
|
|
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
|
|
6501
|
-
import * as
|
|
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 =
|
|
6506
|
-
if (!
|
|
6575
|
+
const abs = path23.join(projectDir, rel);
|
|
6576
|
+
if (!fs24.existsSync(abs)) continue;
|
|
6507
6577
|
let content;
|
|
6508
6578
|
try {
|
|
6509
|
-
content =
|
|
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
|
|
6745
|
-
import * as
|
|
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 =
|
|
6838
|
+
stat = fs25.statSync(file);
|
|
6769
6839
|
} catch {
|
|
6770
6840
|
return;
|
|
6771
6841
|
}
|
|
6772
6842
|
let raw;
|
|
6773
6843
|
try {
|
|
6774
|
-
raw =
|
|
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() ??
|
|
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:
|
|
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 =
|
|
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 =
|
|
6926
|
+
const full = path24.join(dir, name);
|
|
6857
6927
|
let stat;
|
|
6858
6928
|
try {
|
|
6859
|
-
stat =
|
|
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 =
|
|
6895
|
-
if (!
|
|
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
|
|
7009
|
+
import * as fs26 from "fs";
|
|
6940
7010
|
function getProfileInputsForChild(profileName, _cwd) {
|
|
6941
7011
|
try {
|
|
6942
7012
|
const profilePath = resolveProfilePath(profileName);
|
|
6943
|
-
if (!
|
|
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
|
|
7477
|
+
import * as fs27 from "fs";
|
|
7408
7478
|
import * as net from "net";
|
|
7409
7479
|
import * as os4 from "os";
|
|
7410
|
-
import * as
|
|
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 (
|
|
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 =
|
|
7524
|
-
|
|
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 =
|
|
7527
|
-
const outFd =
|
|
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
|
-
|
|
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
|
|
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((
|
|
7686
|
+
return new Promise((resolve21) => {
|
|
7617
7687
|
const server = net.createServer();
|
|
7618
|
-
server.once("error", () =>
|
|
7688
|
+
server.once("error", () => resolve21(false));
|
|
7619
7689
|
server.once("listening", () => {
|
|
7620
|
-
server.close(() =>
|
|
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 =
|
|
7627
|
-
if (!
|
|
7696
|
+
const dotenvPath = path25.join(projectDir, ".env");
|
|
7697
|
+
if (!fs27.existsSync(dotenvPath)) return {};
|
|
7628
7698
|
const result = {};
|
|
7629
|
-
for (const rawLine of
|
|
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
|
|
8289
|
-
import * as
|
|
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 =
|
|
8332
|
-
if (!
|
|
8333
|
-
if (
|
|
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 (
|
|
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 (
|
|
8409
|
+
if (fs28.existsSync(path26.join(gitDir, "REVERT_HEAD"))) {
|
|
8340
8410
|
if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
|
|
8341
8411
|
}
|
|
8342
|
-
if (
|
|
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 =
|
|
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
|
|
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
|
|
9113
|
+
const path55 = existing?.path ?? goalRunLogPath(goalId, data);
|
|
9044
9114
|
logs[goalId] = {
|
|
9045
|
-
path:
|
|
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 (!
|
|
9382
|
-
const parsed = JSON.parse(
|
|
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
|
|
9493
|
-
import * as
|
|
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(
|
|
9641
|
+
return readJsonObject2(path27.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
|
|
9572
9642
|
}
|
|
9573
9643
|
function readJsonObject2(filePath) {
|
|
9574
|
-
if (!
|
|
9575
|
-
const parsed = JSON.parse(
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
9951
|
-
import * as
|
|
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 =
|
|
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
|
-
|
|
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 (!
|
|
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 =
|
|
10068
|
-
if (!
|
|
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 =
|
|
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 =
|
|
10089
|
-
|
|
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
|
-
|
|
10094
|
-
|
|
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
|
|
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 =
|
|
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
|
|
11999
|
-
import * as
|
|
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 &&
|
|
12091
|
+
if (sentinel && fs32.existsSync(sentinel)) {
|
|
12022
12092
|
try {
|
|
12023
|
-
const replay = JSON.parse(
|
|
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
|
-
|
|
12084
|
-
|
|
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
|
|
12179
|
-
import * as
|
|
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 ?
|
|
12304
|
-
mode ?
|
|
12305
|
-
|
|
12306
|
-
|
|
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 =
|
|
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: [${
|
|
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
|
|
13134
|
+
import * as fs34 from "fs";
|
|
13065
13135
|
import * as os5 from "os";
|
|
13066
|
-
import * as
|
|
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 =
|
|
13143
|
+
const cacheDir = path32.join(home, ".cache", "ms-playwright");
|
|
13074
13144
|
let entries = [];
|
|
13075
13145
|
try {
|
|
13076
|
-
entries =
|
|
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
|
|
13105
|
-
import * as
|
|
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(
|
|
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 (
|
|
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 =
|
|
13155
|
-
if (!
|
|
13224
|
+
const full = path33.join(cwd, dir);
|
|
13225
|
+
if (!fs35.existsSync(full)) continue;
|
|
13156
13226
|
let files;
|
|
13157
13227
|
try {
|
|
13158
|
-
files =
|
|
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 =
|
|
13165
|
-
const content =
|
|
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:
|
|
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 =
|
|
13193
|
-
if (!
|
|
13262
|
+
const full = path33.join(cwd, dir);
|
|
13263
|
+
if (!fs35.existsSync(full)) continue;
|
|
13194
13264
|
let entries;
|
|
13195
13265
|
try {
|
|
13196
|
-
entries =
|
|
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 =
|
|
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) =>
|
|
13276
|
+
(f) => fs35.existsSync(path33.join(entryPath, f))
|
|
13207
13277
|
);
|
|
13208
13278
|
if (!indexFile) continue;
|
|
13209
13279
|
name = entry.name;
|
|
13210
|
-
filePath =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
13240
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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:
|
|
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(
|
|
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(
|
|
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 =
|
|
13290
|
-
if (!
|
|
13359
|
+
const envPath = path33.join(cwd, envFile);
|
|
13360
|
+
if (!fs35.existsSync(envPath)) continue;
|
|
13291
13361
|
try {
|
|
13292
|
-
const content =
|
|
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
|
|
13338
|
-
import * as
|
|
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(
|
|
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 =
|
|
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 =
|
|
13382
|
-
if (!
|
|
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 =
|
|
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(
|
|
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(
|
|
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 (
|
|
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 =
|
|
13439
|
-
if (!
|
|
13508
|
+
const dir = path34.join(cwd, rp);
|
|
13509
|
+
if (!fs36.existsSync(dir)) continue;
|
|
13440
13510
|
let files;
|
|
13441
13511
|
try {
|
|
13442
|
-
files =
|
|
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 =
|
|
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
|
|
13710
|
-
import * as
|
|
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 =
|
|
13738
|
-
if (!
|
|
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(
|
|
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) =>
|
|
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 =
|
|
13760
|
-
if (!
|
|
13761
|
-
for (const id of
|
|
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 =
|
|
13764
|
-
if (!
|
|
13833
|
+
const filePath = path35.join(loopsDir, id, "loop.json");
|
|
13834
|
+
if (!fs37.existsSync(filePath)) continue;
|
|
13765
13835
|
try {
|
|
13766
|
-
const loop = normalizeLoopDefinition(JSON.parse(
|
|
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
|
-
|
|
13779
|
-
|
|
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
|
|
15058
|
-
import * as
|
|
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 =
|
|
15062
|
-
const candidates = [
|
|
15063
|
-
const source = candidates.find((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
|
|
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
|
|
15078
|
-
import * as
|
|
15147
|
+
import * as fs39 from "fs";
|
|
15148
|
+
import * as path37 from "path";
|
|
15079
15149
|
function detectPackageManager(cwd) {
|
|
15080
|
-
if (
|
|
15081
|
-
if (
|
|
15082
|
-
if (
|
|
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 =
|
|
15155
|
-
if (
|
|
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
|
-
|
|
15229
|
+
fs39.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
15160
15230
|
`);
|
|
15161
15231
|
wrote.push("kody.config.json");
|
|
15162
15232
|
}
|
|
15163
|
-
const workflowDir =
|
|
15164
|
-
const workflowPath =
|
|
15165
|
-
if (
|
|
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
|
-
|
|
15169
|
-
|
|
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
|
|
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 || !
|
|
15298
|
+
if (!eventPath || !fs40.existsSync(eventPath)) return "";
|
|
15229
15299
|
try {
|
|
15230
|
-
const event = JSON.parse(
|
|
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 (!
|
|
15354
|
+
if (!fs40.existsSync(agentPath)) {
|
|
15285
15355
|
throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
|
|
15286
15356
|
}
|
|
15287
|
-
const { title, body } = parseAgentFile(
|
|
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(
|
|
15429
|
+
function normalizeCompanyIntent(path55, raw) {
|
|
15360
15430
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
15361
|
-
throw new Error(`${
|
|
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(`${
|
|
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((
|
|
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
|
|
15657
|
-
import * as
|
|
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,
|
|
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: ${
|
|
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 (!
|
|
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 =
|
|
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
|
|
15795
|
-
import * as
|
|
15864
|
+
import * as fs42 from "fs";
|
|
15865
|
+
import * as path39 from "path";
|
|
15796
15866
|
function readKodyVariables(cwd) {
|
|
15797
|
-
const full =
|
|
15867
|
+
const full = path39.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
15798
15868
|
let raw;
|
|
15799
15869
|
try {
|
|
15800
|
-
raw =
|
|
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
|
|
15826
|
-
import * as
|
|
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 =
|
|
15856
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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
|
|
15986
|
+
import * as fs44 from "fs";
|
|
15917
15987
|
import * as os6 from "os";
|
|
15918
|
-
import * as
|
|
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,
|
|
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 (!
|
|
16042
|
+
if (!fs44.existsSync(root)) return [];
|
|
15973
16043
|
const files = [];
|
|
15974
16044
|
const visit = (dir) => {
|
|
15975
|
-
for (const entry of
|
|
15976
|
-
const absolute =
|
|
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(
|
|
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 =
|
|
16003
|
-
const skillRoot =
|
|
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 =
|
|
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 ?
|
|
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
|
-
|
|
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) => `- ${
|
|
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
|
|
16099
|
-
import * as
|
|
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
|
-
|
|
16116
|
-
const file =
|
|
16117
|
-
|
|
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
|
|
16545
|
-
const parts =
|
|
16546
|
-
if (!
|
|
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
|
-
|
|
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(
|
|
16555
|
-
seen.add(
|
|
16556
|
-
return { path:
|
|
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
|
|
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 || !
|
|
17113
|
+
if (!outputPath || !fs46.existsSync(outputPath)) return { found: false };
|
|
17044
17114
|
try {
|
|
17045
|
-
return { found: true, value: JSON.parse(
|
|
17115
|
+
return { found: true, value: JSON.parse(fs46.readFileSync(outputPath, "utf-8")) };
|
|
17046
17116
|
} finally {
|
|
17047
|
-
|
|
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
|
|
17736
|
+
import * as fs47 from "fs";
|
|
17667
17737
|
import * as os7 from "os";
|
|
17668
|
-
import * as
|
|
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 =
|
|
17708
|
-
|
|
17709
|
-
const file =
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
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
|
|
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
|
-
|
|
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,
|
|
18378
|
-
if (!
|
|
18379
|
-
return
|
|
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((
|
|
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)
|
|
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
|
|
19375
|
+
import * as path45 from "path";
|
|
19306
19376
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
19307
19377
|
function bundledDockerfilePath(mode) {
|
|
19308
|
-
const here =
|
|
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
|
|
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(
|
|
19615
|
+
await writeFile(path45.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
|
|
19546
19616
|
`, "utf8");
|
|
19547
19617
|
}
|
|
19548
|
-
const consumerDockerfile =
|
|
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
|
|
19733
|
-
import * as
|
|
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,
|
|
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 =
|
|
19761
|
-
if (!
|
|
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
|
|
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 =
|
|
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
|
|
19879
|
-
import * as
|
|
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(
|
|
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: ${
|
|
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 =
|
|
19912
|
-
if (!
|
|
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
|
|
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:
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
21082
|
+
next: (timeoutMs) => new Promise((resolve21) => {
|
|
21013
21083
|
if (queue.length > 0) {
|
|
21014
|
-
|
|
21084
|
+
resolve21(queue.shift());
|
|
21015
21085
|
return;
|
|
21016
21086
|
}
|
|
21017
21087
|
if (ended) {
|
|
21018
|
-
|
|
21088
|
+
resolve21(null);
|
|
21019
21089
|
return;
|
|
21020
21090
|
}
|
|
21021
|
-
waiter =
|
|
21091
|
+
waiter = resolve21;
|
|
21022
21092
|
const t = setTimeout(
|
|
21023
21093
|
() => {
|
|
21024
|
-
if (waiter ===
|
|
21094
|
+
if (waiter === resolve21) {
|
|
21025
21095
|
waiter = null;
|
|
21026
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
21428
|
-
import * as
|
|
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 =
|
|
21436
|
-
|
|
21437
|
-
|
|
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 = `${
|
|
21572
|
+
const key = `${path49.resolve(cwd)}|${tenant}`;
|
|
21503
21573
|
if (hydratedWorkspaces.has(key)) return;
|
|
21504
21574
|
const backend = backendOverride ?? createStateBackendFromEnv();
|
|
21505
|
-
const root =
|
|
21506
|
-
|
|
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 =
|
|
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
|
|
21663
|
+
import * as fs53 from "fs";
|
|
21594
21664
|
import * as os8 from "os";
|
|
21595
|
-
import * as
|
|
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) =>
|
|
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 =
|
|
22398
|
+
const here = path50.dirname(new URL(import.meta.url).pathname);
|
|
22325
22399
|
const candidates = [
|
|
22326
|
-
|
|
22400
|
+
path50.join(here, "implementations", profileName, "profile.json"),
|
|
22327
22401
|
// same-dir sibling (dev)
|
|
22328
|
-
|
|
22402
|
+
path50.join(here, "..", "implementations", profileName, "profile.json"),
|
|
22329
22403
|
// up one (prod: dist/bin → dist/implementations)
|
|
22330
|
-
|
|
22404
|
+
path50.join(here, "..", "src", "implementations", profileName, "profile.json")
|
|
22331
22405
|
// fallback
|
|
22332
22406
|
];
|
|
22333
22407
|
for (const c of candidates) {
|
|
22334
|
-
if (
|
|
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 =
|
|
22450
|
-
if (!
|
|
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 =
|
|
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
|
-
(
|
|
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
|
-
|
|
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 (
|
|
22525
|
-
sideChannelText =
|
|
22526
|
-
|
|
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((
|
|
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(([
|
|
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
|
|
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
|
|
23832
|
-
import * as
|
|
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
|
|
23837
|
-
import * as
|
|
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
|
-
|
|
23943
|
+
fs14.mkdirSync(dir, { recursive: true });
|
|
23871
23944
|
dirEnsured = true;
|
|
23872
23945
|
}
|
|
23873
|
-
const filePath =
|
|
23874
|
-
|
|
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
|
|
23892
|
-
import * as
|
|
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((
|
|
24050
|
+
await new Promise((resolve21, reject) => {
|
|
23978
24051
|
this.process.turnWaiters.set(args.threadId, {
|
|
23979
|
-
resolve:
|
|
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((
|
|
23997
|
-
this.process.pending.set(id, { resolve:
|
|
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
|
|
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(
|
|
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
|
-
|
|
24081
|
-
|
|
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
|
|
24172
|
-
import * as
|
|
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
|
|
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
|
-
|
|
24197
|
-
|
|
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(
|
|
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) =>
|
|
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 =
|
|
24845
|
+
const indexPath = path18.join(cwd, MEMORY_INDEX_REL);
|
|
24773
24846
|
let raw;
|
|
24774
24847
|
try {
|
|
24775
|
-
raw =
|
|
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 =
|
|
24868
|
+
const dir = path18.join(cwd, CONTEXT_DIR_REL);
|
|
24796
24869
|
let files;
|
|
24797
24870
|
try {
|
|
24798
|
-
files =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
24912
|
+
const instructionsPath = path18.join(cwd, INSTRUCTIONS_REL);
|
|
24840
24913
|
let raw;
|
|
24841
24914
|
try {
|
|
24842
|
-
raw =
|
|
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
|
|
24877
|
-
import * as
|
|
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
|
|
24953
|
+
return path19.join(cwd, ".kody-engine", "runtime", "sessions", `${sessionId}.jsonl`);
|
|
24881
24954
|
}
|
|
24882
24955
|
function readSession(file) {
|
|
24883
|
-
if (!
|
|
24884
|
-
const raw =
|
|
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
|
|
24908
|
-
import * as
|
|
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 =
|
|
24941
|
-
|
|
24942
|
-
|
|
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
|
-
|
|
25023
|
+
fs20.writeFileSync(path21.join(root, "agents", `${definition.slug}.md`), raw, "utf8");
|
|
24951
25024
|
return;
|
|
24952
25025
|
}
|
|
24953
25026
|
if (kind === "goal") {
|
|
24954
|
-
writeBundle(
|
|
25027
|
+
writeBundle(path21.join(root, "goals", definition.slug), bundle);
|
|
24955
25028
|
return;
|
|
24956
25029
|
}
|
|
24957
25030
|
if (kind === "implementation") {
|
|
24958
|
-
writeBundle(
|
|
25031
|
+
writeBundle(path21.join(root, "implementations", definition.slug), bundle);
|
|
24959
25032
|
return;
|
|
24960
25033
|
}
|
|
24961
25034
|
if (kind === "asset") {
|
|
24962
|
-
writeBundle(
|
|
25035
|
+
writeBundle(path21.join(root, "shared"), bundle);
|
|
24963
25036
|
return;
|
|
24964
25037
|
}
|
|
24965
|
-
writeBundle(
|
|
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 =
|
|
24974
|
-
|
|
24975
|
-
|
|
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 =
|
|
24981
|
-
if (!
|
|
24982
|
-
|
|
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 =
|
|
25059
|
+
const root = path21.join(options.cwd, ".kody-engine", "definitions");
|
|
24987
25060
|
const staging = `${root}.tmp-${process.pid}-${Date.now()}`;
|
|
24988
|
-
|
|
24989
|
-
|
|
24990
|
-
|
|
24991
|
-
|
|
24992
|
-
|
|
24993
|
-
|
|
24994
|
-
|
|
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
|
-
|
|
25108
|
+
fs20.writeFileSync(path21.join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
25036
25109
|
`, "utf8");
|
|
25037
|
-
|
|
25038
|
-
|
|
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
|
-
|
|
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
|
|
25064
|
-
import * as
|
|
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
|
|
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 || !
|
|
25373
|
+
if (!eventName || !eventPath || !fs21.existsSync(eventPath)) return null;
|
|
25301
25374
|
let event = {};
|
|
25302
25375
|
try {
|
|
25303
|
-
event = JSON.parse(
|
|
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 || !
|
|
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(
|
|
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 =
|
|
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 (
|
|
25867
|
-
if (
|
|
25868
|
-
if (
|
|
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 (
|
|
25972
|
-
const content =
|
|
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 ?
|
|
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 &&
|
|
26140
|
+
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs54.existsSync(dispatchEventPath)) {
|
|
26068
26141
|
try {
|
|
26069
|
-
const evt = JSON.parse(
|
|
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
|
|
26485
|
-
import * as
|
|
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 (!
|
|
26494
|
-
const lines =
|
|
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 (!
|
|
26577
|
+
if (!fs55.existsSync(p)) return [];
|
|
26505
26578
|
const out = [];
|
|
26506
|
-
for (const line of
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
26749
|
+
resolve21({});
|
|
26677
26750
|
return;
|
|
26678
26751
|
}
|
|
26679
26752
|
try {
|
|
26680
|
-
|
|
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 ??
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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((
|
|
27319
|
-
httpServer.close(() =>
|
|
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((
|
|
27542
|
+
stop: () => new Promise((resolve21) => {
|
|
27470
27543
|
let pending = transports.size;
|
|
27471
27544
|
if (pending === 0) {
|
|
27472
|
-
httpServer.close(() =>
|
|
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(() =>
|
|
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((
|
|
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
|
-
|
|
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
|
|
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((
|
|
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 ?
|
|
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(
|
|
28064
|
-
const res = await this.fetch(`${FLY_API_BASE}${
|
|
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 ${
|
|
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((
|
|
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
|
|
28666
|
+
if (!raw.trim()) return resolve21({});
|
|
28594
28667
|
try {
|
|
28595
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
|
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((
|
|
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
|
-
|
|
28871
|
+
resolve21({});
|
|
28799
28872
|
return;
|
|
28800
28873
|
}
|
|
28801
28874
|
try {
|
|
28802
|
-
|
|
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
|
-
|
|
28848
|
-
|
|
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((
|
|
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) =>
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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((
|
|
29033
|
-
child.on("exit", (code) =>
|
|
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
|
-
|
|
29112
|
+
resolve21(1);
|
|
29040
29113
|
});
|
|
29041
29114
|
});
|
|
29042
29115
|
killProxy();
|