@kody-ade/kody-engine 0.4.552 → 0.4.554
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 +781 -690
- package/dist/implementations/types.ts +2 -0
- 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.554",
|
|
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);
|
|
@@ -3837,6 +3944,7 @@ async function runAgent(opts) {
|
|
|
3837
3944
|
// Fresh array (never mutate the shared DEFAULT_ALLOWED_TOOLS const) so
|
|
3838
3945
|
// opt-in tools like fetch_repo can be appended below.
|
|
3839
3946
|
allowedTools: [...opts.allowedToolsOverride ?? DEFAULT_ALLOWED_TOOLS],
|
|
3947
|
+
...opts.disallowedToolsOverride?.length ? { disallowedTools: [...opts.disallowedToolsOverride] } : {},
|
|
3840
3948
|
permissionMode: opts.permissionModeOverride ?? "acceptEdits",
|
|
3841
3949
|
env,
|
|
3842
3950
|
hooks: {
|
|
@@ -3850,8 +3958,21 @@ async function runAgent(opts) {
|
|
|
3850
3958
|
{
|
|
3851
3959
|
matcher: "Agent",
|
|
3852
3960
|
hooks: [subagentInvocationHook]
|
|
3853
|
-
}
|
|
3854
|
-
|
|
3961
|
+
},
|
|
3962
|
+
...outputContractPostWriteHook ? [
|
|
3963
|
+
{
|
|
3964
|
+
matcher: "Write",
|
|
3965
|
+
hooks: [outputContractPostWriteHook]
|
|
3966
|
+
}
|
|
3967
|
+
] : []
|
|
3968
|
+
],
|
|
3969
|
+
...outputContractStopHook ? {
|
|
3970
|
+
Stop: [
|
|
3971
|
+
{
|
|
3972
|
+
hooks: [outputContractStopHook]
|
|
3973
|
+
}
|
|
3974
|
+
]
|
|
3975
|
+
} : {}
|
|
3855
3976
|
}
|
|
3856
3977
|
};
|
|
3857
3978
|
const additionalDirectories = new Set(opts.additionalDirectories ?? []);
|
|
@@ -3981,10 +4102,10 @@ async function runAgent(opts) {
|
|
|
3981
4102
|
let timer;
|
|
3982
4103
|
let next;
|
|
3983
4104
|
if (turnTimeoutMs > 0) {
|
|
3984
|
-
const timeoutPromise = new Promise((
|
|
4105
|
+
const timeoutPromise = new Promise((resolve21) => {
|
|
3985
4106
|
timer = setTimeout(() => {
|
|
3986
4107
|
timedOut = true;
|
|
3987
|
-
|
|
4108
|
+
resolve21({ done: true, value: void 0 });
|
|
3988
4109
|
}, turnTimeoutMs);
|
|
3989
4110
|
});
|
|
3990
4111
|
next = await Promise.race([nextPromise, timeoutPromise]);
|
|
@@ -4000,7 +4121,7 @@ async function runAgent(opts) {
|
|
|
4000
4121
|
try {
|
|
4001
4122
|
await Promise.race([
|
|
4002
4123
|
iterator.return(void 0).catch(() => void 0),
|
|
4003
|
-
new Promise((
|
|
4124
|
+
new Promise((resolve21) => setTimeout(resolve21, 1e4).unref())
|
|
4004
4125
|
]);
|
|
4005
4126
|
} catch {
|
|
4006
4127
|
}
|
|
@@ -4183,6 +4304,7 @@ var init_agent = __esm({
|
|
|
4183
4304
|
init_claudeBinary();
|
|
4184
4305
|
init_config();
|
|
4185
4306
|
init_format();
|
|
4307
|
+
init_outputContractHooks();
|
|
4186
4308
|
init_runtimePaths();
|
|
4187
4309
|
init_subagents();
|
|
4188
4310
|
DEFAULT_ALLOWED_TOOLS = ["Bash", "Edit", "Read", "Write", "Glob", "Grep"];
|
|
@@ -4203,8 +4325,8 @@ var init_agent = __esm({
|
|
|
4203
4325
|
});
|
|
4204
4326
|
|
|
4205
4327
|
// src/agents.ts
|
|
4206
|
-
import * as
|
|
4207
|
-
import * as
|
|
4328
|
+
import * as fs12 from "fs";
|
|
4329
|
+
import * as path13 from "path";
|
|
4208
4330
|
function stripFrontmatter(raw) {
|
|
4209
4331
|
const match = /^---\n[\s\S]*?\n---\n?([\s\S]*)$/.exec(raw);
|
|
4210
4332
|
return (match ? match[1] : raw).trim();
|
|
@@ -4213,8 +4335,8 @@ function loadAgentIdentity(cwd, slug, agentsDir = agentsRoot(cwd)) {
|
|
|
4213
4335
|
const trimmed = slug.trim();
|
|
4214
4336
|
if (!trimmed) throw new Error("loadAgentIdentity: empty agent slug");
|
|
4215
4337
|
const agentPath = resolveAgentFile2(cwd, trimmed, agentsDir);
|
|
4216
|
-
if (
|
|
4217
|
-
const body = stripFrontmatter(
|
|
4338
|
+
if (fs12.existsSync(agentPath)) {
|
|
4339
|
+
const body = stripFrontmatter(fs12.readFileSync(agentPath, "utf-8"));
|
|
4218
4340
|
if (body) return body;
|
|
4219
4341
|
const builtinForEmpty = BUILTIN_AGENTS[trimmed];
|
|
4220
4342
|
if (builtinForEmpty) return builtinForEmpty;
|
|
@@ -4225,8 +4347,8 @@ function loadAgentIdentity(cwd, slug, agentsDir = agentsRoot(cwd)) {
|
|
|
4225
4347
|
throw new Error(`loadAgentIdentity: agent '${trimmed}' declared but ${agentPath} does not exist`);
|
|
4226
4348
|
}
|
|
4227
4349
|
function resolveAgentFile2(cwd, slug, agentsDir = agentsRoot(cwd)) {
|
|
4228
|
-
const localPath =
|
|
4229
|
-
if (
|
|
4350
|
+
const localPath = path13.resolve(cwd, agentsDir, `${slug}.md`);
|
|
4351
|
+
if (fs12.existsSync(localPath)) return localPath;
|
|
4230
4352
|
return localPath;
|
|
4231
4353
|
}
|
|
4232
4354
|
function frameAgentIdentity(slug, agent) {
|
|
@@ -4258,14 +4380,14 @@ var init_agents = __esm({
|
|
|
4258
4380
|
});
|
|
4259
4381
|
|
|
4260
4382
|
// src/task-artifacts.ts
|
|
4261
|
-
import
|
|
4262
|
-
import
|
|
4383
|
+
import fs13 from "fs";
|
|
4384
|
+
import path14 from "path";
|
|
4263
4385
|
import posixPath from "path/posix";
|
|
4264
4386
|
function prepareTaskArtifactsDir(cwd, taskId) {
|
|
4265
4387
|
const safeId = String(taskId).replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
4266
4388
|
const absDir = runtimeStatePath(cwd, "task-artifacts", safeId);
|
|
4267
4389
|
const relDir = absDir;
|
|
4268
|
-
|
|
4390
|
+
fs13.mkdirSync(absDir, { recursive: true });
|
|
4269
4391
|
return { taskId: safeId, absDir, relDir };
|
|
4270
4392
|
}
|
|
4271
4393
|
function initializeTaskArtifacts(artifacts, metadata = { taskType: "job" }) {
|
|
@@ -4295,16 +4417,16 @@ function initializeTaskArtifacts(artifacts, metadata = { taskType: "job" }) {
|
|
|
4295
4417
|
"handoff-notes.md": "Baseline handoff: the agent did not provide additional notes.\n"
|
|
4296
4418
|
};
|
|
4297
4419
|
for (const file of TASK_ARTIFACT_FILES) {
|
|
4298
|
-
const full =
|
|
4299
|
-
if (!
|
|
4420
|
+
const full = path14.join(artifacts.absDir, file);
|
|
4421
|
+
if (!fs13.existsSync(full)) fs13.writeFileSync(full, defaults[file], "utf8");
|
|
4300
4422
|
}
|
|
4301
4423
|
}
|
|
4302
4424
|
function verifyTaskArtifacts(absDir) {
|
|
4303
4425
|
const missing = [];
|
|
4304
4426
|
for (const name of TASK_ARTIFACT_FILES) {
|
|
4305
|
-
const full =
|
|
4427
|
+
const full = path14.join(absDir, name);
|
|
4306
4428
|
try {
|
|
4307
|
-
const stat =
|
|
4429
|
+
const stat = fs13.statSync(full);
|
|
4308
4430
|
if (!stat.isFile() || stat.size === 0) missing.push(name);
|
|
4309
4431
|
} catch {
|
|
4310
4432
|
missing.push(name);
|
|
@@ -4320,11 +4442,11 @@ async function persistTaskArtifactsToState(config, _cwd, artifacts) {
|
|
|
4320
4442
|
if (hasStateBackendConfig() && tenantId2) {
|
|
4321
4443
|
const backend = createStateBackendFromEnv();
|
|
4322
4444
|
for (const file of TASK_ARTIFACT_FILES) {
|
|
4323
|
-
const full =
|
|
4324
|
-
if (!
|
|
4325
|
-
const stat =
|
|
4445
|
+
const full = path14.join(artifacts.absDir, file);
|
|
4446
|
+
if (!fs13.existsSync(full)) continue;
|
|
4447
|
+
const stat = fs13.statSync(full);
|
|
4326
4448
|
if (!stat.isFile() || stat.size === 0) continue;
|
|
4327
|
-
const content =
|
|
4449
|
+
const content = fs13.readFileSync(full, "utf-8");
|
|
4328
4450
|
const kind = file.replace(/\.(json|md)$/, "");
|
|
4329
4451
|
let doc = content;
|
|
4330
4452
|
if (file.endsWith(".json")) {
|
|
@@ -4624,15 +4746,15 @@ function validateWorkflow(value, options = {}) {
|
|
|
4624
4746
|
}
|
|
4625
4747
|
return issues;
|
|
4626
4748
|
}
|
|
4627
|
-
function validateInputBindings(value,
|
|
4749
|
+
function validateInputBindings(value, path55, issues, declaredInputs) {
|
|
4628
4750
|
if (value === void 0) return;
|
|
4629
4751
|
const bindings = asRecord(value);
|
|
4630
4752
|
if (!bindings || Object.keys(bindings).length === 0) {
|
|
4631
|
-
issue(issues, "invalid_inputs",
|
|
4753
|
+
issue(issues, "invalid_inputs", path55, "workflow step inputs must contain at least one named mapping");
|
|
4632
4754
|
return;
|
|
4633
4755
|
}
|
|
4634
4756
|
for (const [name, value2] of Object.entries(bindings)) {
|
|
4635
|
-
const bindingPath = `${
|
|
4757
|
+
const bindingPath = `${path55}.${name}`;
|
|
4636
4758
|
if (!/^[A-Za-z_][A-Za-z0-9_-]*$/.test(name)) {
|
|
4637
4759
|
issue(issues, "invalid_input_name", bindingPath, `workflow input name ${name} is invalid`);
|
|
4638
4760
|
}
|
|
@@ -4651,7 +4773,7 @@ function validateInputBindings(value, path54, issues, declaredInputs) {
|
|
|
4651
4773
|
}
|
|
4652
4774
|
}
|
|
4653
4775
|
}
|
|
4654
|
-
function validateInputBindingSources(value,
|
|
4776
|
+
function validateInputBindingSources(value, path55, issues, capabilitiesByStep, capabilityOutputs) {
|
|
4655
4777
|
const bindings = asRecord(value);
|
|
4656
4778
|
if (!bindings) return;
|
|
4657
4779
|
for (const [name, rawBinding] of Object.entries(bindings)) {
|
|
@@ -4664,7 +4786,7 @@ function validateInputBindingSources(value, path54, issues, capabilitiesByStep,
|
|
|
4664
4786
|
issue(
|
|
4665
4787
|
issues,
|
|
4666
4788
|
"missing_input_step",
|
|
4667
|
-
`${
|
|
4789
|
+
`${path55}.${name}.from`,
|
|
4668
4790
|
`workflow input mapping references missing step ${sourceStep ?? "<none>"}`
|
|
4669
4791
|
);
|
|
4670
4792
|
continue;
|
|
@@ -4675,7 +4797,7 @@ function validateInputBindingSources(value, path54, issues, capabilitiesByStep,
|
|
|
4675
4797
|
issue(
|
|
4676
4798
|
issues,
|
|
4677
4799
|
"undeclared_step_output",
|
|
4678
|
-
`${
|
|
4800
|
+
`${path55}.${name}.from`,
|
|
4679
4801
|
`workflow input mapping reads ${outputPath}, but step ${sourceStep} does not declare it`
|
|
4680
4802
|
);
|
|
4681
4803
|
}
|
|
@@ -4684,11 +4806,11 @@ function validateInputBindingSources(value, path54, issues, capabilitiesByStep,
|
|
|
4684
4806
|
function formatWorkflowValidationIssues(issues) {
|
|
4685
4807
|
return issues.map((entry) => `${entry.path}: ${entry.message}`);
|
|
4686
4808
|
}
|
|
4687
|
-
function validateDataMatch(value,
|
|
4809
|
+
function validateDataMatch(value, path55, issues, capabilityOutputs) {
|
|
4688
4810
|
if (value === void 0) return;
|
|
4689
4811
|
const match = asRecord(value);
|
|
4690
4812
|
if (!match || Object.keys(match).length === 0) {
|
|
4691
|
-
issue(issues, "invalid_condition",
|
|
4813
|
+
issue(issues, "invalid_condition", path55, "workflow condition must contain at least one match");
|
|
4692
4814
|
return;
|
|
4693
4815
|
}
|
|
4694
4816
|
for (const [field, expected] of Object.entries(match)) {
|
|
@@ -4696,7 +4818,7 @@ function validateDataMatch(value, path54, issues, capabilityOutputs) {
|
|
|
4696
4818
|
issue(
|
|
4697
4819
|
issues,
|
|
4698
4820
|
"invalid_data_path",
|
|
4699
|
-
`${
|
|
4821
|
+
`${path55}.${field}`,
|
|
4700
4822
|
`workflow condition must read from facts, evidence, artifacts, result, workflow, or lastOutcome`
|
|
4701
4823
|
);
|
|
4702
4824
|
}
|
|
@@ -4704,12 +4826,12 @@ function validateDataMatch(value, path54, issues, capabilityOutputs) {
|
|
|
4704
4826
|
issue(
|
|
4705
4827
|
issues,
|
|
4706
4828
|
"undeclared_result_path",
|
|
4707
|
-
`${
|
|
4829
|
+
`${path55}.${field}`,
|
|
4708
4830
|
`workflow condition reads ${field}, but the source capability does not declare it`
|
|
4709
4831
|
);
|
|
4710
4832
|
}
|
|
4711
4833
|
if (!isComparable(expected)) {
|
|
4712
|
-
issue(issues, "invalid_condition_value", `${
|
|
4834
|
+
issue(issues, "invalid_condition_value", `${path55}.${field}`, "workflow condition value must be a JSON scalar");
|
|
4713
4835
|
}
|
|
4714
4836
|
}
|
|
4715
4837
|
}
|
|
@@ -4733,8 +4855,8 @@ function isJsonValue(value) {
|
|
|
4733
4855
|
if (!value || typeof value !== "object") return false;
|
|
4734
4856
|
return Object.values(value).every(isJsonValue);
|
|
4735
4857
|
}
|
|
4736
|
-
function issue(issues, code,
|
|
4737
|
-
issues.push({ code, path:
|
|
4858
|
+
function issue(issues, code, path55, message) {
|
|
4859
|
+
issues.push({ code, path: path55, message });
|
|
4738
4860
|
}
|
|
4739
4861
|
var SAFE_NAME, SAFE_STEP_ID, SAFE_DATA_PATH, SAFE_INPUT_SOURCE, SUPPORTED_STEP_FIELDS, SUPPORTED_TRANSITION_FIELDS;
|
|
4740
4862
|
var init_workflowValidation = __esm({
|
|
@@ -4766,8 +4888,8 @@ var init_workflowValidation = __esm({
|
|
|
4766
4888
|
});
|
|
4767
4889
|
|
|
4768
4890
|
// src/workflowDefinitions.ts
|
|
4769
|
-
import * as
|
|
4770
|
-
import * as
|
|
4891
|
+
import * as fs19 from "fs";
|
|
4892
|
+
import * as path20 from "path";
|
|
4771
4893
|
function isWorkflowDefinitionId(value) {
|
|
4772
4894
|
return WORKFLOW_ID_PATTERN.test(value);
|
|
4773
4895
|
}
|
|
@@ -4812,12 +4934,12 @@ function readWorkflowDefinition(_config, cwd, id) {
|
|
|
4812
4934
|
const root = cwd ?? process.cwd();
|
|
4813
4935
|
const relativePath = workflowDefinitionPath(id);
|
|
4814
4936
|
const candidates = [
|
|
4815
|
-
|
|
4816
|
-
|
|
4937
|
+
path20.join(root, ".kody-engine", "runtime", relativePath),
|
|
4938
|
+
path20.join(definitionsRoot(root), relativePath)
|
|
4817
4939
|
];
|
|
4818
4940
|
for (const filePath of candidates) {
|
|
4819
|
-
if (!
|
|
4820
|
-
const workflow = parseWorkflowDefinition(
|
|
4941
|
+
if (!fs19.existsSync(filePath)) continue;
|
|
4942
|
+
const workflow = parseWorkflowDefinition(fs19.readFileSync(filePath, "utf8"));
|
|
4821
4943
|
if (workflow) return workflow;
|
|
4822
4944
|
}
|
|
4823
4945
|
return null;
|
|
@@ -4825,7 +4947,7 @@ function readWorkflowDefinition(_config, cwd, id) {
|
|
|
4825
4947
|
function workflowDefinitionToCapabilityFolder(id, workflow, source = workflowDefinitionPath(id)) {
|
|
4826
4948
|
return {
|
|
4827
4949
|
slug: id,
|
|
4828
|
-
dir:
|
|
4950
|
+
dir: path20.dirname(source),
|
|
4829
4951
|
profilePath: source,
|
|
4830
4952
|
bodyPath: source,
|
|
4831
4953
|
title: workflow.name,
|
|
@@ -4881,7 +5003,7 @@ var init_workflowDefinitions = __esm({
|
|
|
4881
5003
|
|
|
4882
5004
|
// src/gha.ts
|
|
4883
5005
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
4884
|
-
import * as
|
|
5006
|
+
import * as fs22 from "fs";
|
|
4885
5007
|
function getRunUrl() {
|
|
4886
5008
|
const server = process.env.GITHUB_SERVER_URL;
|
|
4887
5009
|
const repo = process.env.GITHUB_REPOSITORY;
|
|
@@ -4892,10 +5014,10 @@ function getRunUrl() {
|
|
|
4892
5014
|
function reactToTriggerComment(cwd) {
|
|
4893
5015
|
if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
|
|
4894
5016
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
4895
|
-
if (!eventPath || !
|
|
5017
|
+
if (!eventPath || !fs22.existsSync(eventPath)) return;
|
|
4896
5018
|
let event = null;
|
|
4897
5019
|
try {
|
|
4898
|
-
event = JSON.parse(
|
|
5020
|
+
event = JSON.parse(fs22.readFileSync(eventPath, "utf-8"));
|
|
4899
5021
|
} catch {
|
|
4900
5022
|
return;
|
|
4901
5023
|
}
|
|
@@ -5029,57 +5151,6 @@ var init_agencyBoundaryEval = __esm({
|
|
|
5029
5151
|
}
|
|
5030
5152
|
});
|
|
5031
5153
|
|
|
5032
|
-
// src/agency/capability-contract-validation.ts
|
|
5033
|
-
import Ajv from "ajv";
|
|
5034
|
-
function validateCapabilityContractValue(boundary, schema, value) {
|
|
5035
|
-
const validate = validator.compile(schema);
|
|
5036
|
-
if (!validate(value)) {
|
|
5037
|
-
throw new CapabilityContractValidationError(boundary, validate.errors ?? []);
|
|
5038
|
-
}
|
|
5039
|
-
}
|
|
5040
|
-
function capabilityContractInput(inputs, args, capabilityId, contractProperties = []) {
|
|
5041
|
-
const isGenericRunnerInput = inputs.some((input) => input.name === "input") && Object.hasOwn(args, "input");
|
|
5042
|
-
if (!isGenericRunnerInput) {
|
|
5043
|
-
const isParameterlessGenericRunner = (inputs.some((input) => input.name === "capability") || args.capability === capabilityId || !contractProperties.includes("capability")) && Object.hasOwn(args, "capability");
|
|
5044
|
-
if (!isParameterlessGenericRunner) return args;
|
|
5045
|
-
const { capability: _routingCapability, ...businessArgs } = args;
|
|
5046
|
-
return businessArgs;
|
|
5047
|
-
}
|
|
5048
|
-
const value = args.input;
|
|
5049
|
-
if (typeof value !== "string") return value;
|
|
5050
|
-
try {
|
|
5051
|
-
return JSON.parse(value);
|
|
5052
|
-
} catch {
|
|
5053
|
-
return value;
|
|
5054
|
-
}
|
|
5055
|
-
}
|
|
5056
|
-
var validator, CapabilityContractValidationError;
|
|
5057
|
-
var init_capability_contract_validation = __esm({
|
|
5058
|
-
"src/agency/capability-contract-validation.ts"() {
|
|
5059
|
-
"use strict";
|
|
5060
|
-
validator = new Ajv({
|
|
5061
|
-
allErrors: true,
|
|
5062
|
-
strict: true,
|
|
5063
|
-
validateFormats: false
|
|
5064
|
-
});
|
|
5065
|
-
CapabilityContractValidationError = class extends Error {
|
|
5066
|
-
constructor(boundary, errors) {
|
|
5067
|
-
const details = errors.map((error) => {
|
|
5068
|
-
const location = error.instancePath || "$";
|
|
5069
|
-
const property = error.keyword === "additionalProperties" && typeof error.params.additionalProperty === "string" ? ` (${error.params.additionalProperty})` : "";
|
|
5070
|
-
return `${location}: ${error.message ?? error.keyword}${property}`;
|
|
5071
|
-
}).join("; ");
|
|
5072
|
-
super(`Capability ${boundary} does not match its declared contract: ${details}`);
|
|
5073
|
-
this.boundary = boundary;
|
|
5074
|
-
this.errors = errors;
|
|
5075
|
-
this.name = "CapabilityContractValidationError";
|
|
5076
|
-
}
|
|
5077
|
-
boundary;
|
|
5078
|
-
errors;
|
|
5079
|
-
};
|
|
5080
|
-
}
|
|
5081
|
-
});
|
|
5082
|
-
|
|
5083
5154
|
// src/capabilityReport.ts
|
|
5084
5155
|
function parseCapabilityReportsFromText(text2) {
|
|
5085
5156
|
const reports = [];
|
|
@@ -5476,15 +5547,15 @@ var init_lifecycles = __esm({
|
|
|
5476
5547
|
|
|
5477
5548
|
// src/profile.ts
|
|
5478
5549
|
import { createHash as createHash3 } from "crypto";
|
|
5479
|
-
import * as
|
|
5480
|
-
import * as
|
|
5550
|
+
import * as fs23 from "fs";
|
|
5551
|
+
import * as path22 from "path";
|
|
5481
5552
|
function loadProfile(profilePath) {
|
|
5482
|
-
if (!
|
|
5553
|
+
if (!fs23.existsSync(profilePath)) {
|
|
5483
5554
|
throw new ProfileError(profilePath, "file not found");
|
|
5484
5555
|
}
|
|
5485
5556
|
let raw;
|
|
5486
5557
|
try {
|
|
5487
|
-
raw = JSON.parse(
|
|
5558
|
+
raw = JSON.parse(fs23.readFileSync(profilePath, "utf-8"));
|
|
5488
5559
|
} catch (err) {
|
|
5489
5560
|
throw new ProfileError(profilePath, `invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
5490
5561
|
}
|
|
@@ -5496,7 +5567,7 @@ function loadProfile(profilePath) {
|
|
|
5496
5567
|
const unknownKeys = Object.keys(r).filter((k) => !KNOWN_PROFILE_KEYS.has(k));
|
|
5497
5568
|
if (unknownKeys.length > 0) {
|
|
5498
5569
|
process.stderr.write(
|
|
5499
|
-
`[kody profile] ${
|
|
5570
|
+
`[kody profile] ${path22.basename(path22.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
|
|
5500
5571
|
`
|
|
5501
5572
|
);
|
|
5502
5573
|
}
|
|
@@ -5506,7 +5577,7 @@ function loadProfile(profilePath) {
|
|
|
5506
5577
|
if (!refPath) {
|
|
5507
5578
|
throw new ProfileError(profilePath, `capability references unknown implementation '${execRef}'`);
|
|
5508
5579
|
}
|
|
5509
|
-
if (
|
|
5580
|
+
if (path22.resolve(refPath) === path22.resolve(profilePath)) {
|
|
5510
5581
|
} else {
|
|
5511
5582
|
const base = loadProfile(refPath);
|
|
5512
5583
|
return {
|
|
@@ -5604,8 +5675,8 @@ function loadProfile(profilePath) {
|
|
|
5604
5675
|
// Phase 5 in-process handoff opt-in. Default false; containers
|
|
5605
5676
|
// flip to true after end-to-end verification.
|
|
5606
5677
|
preloadContext: r.preloadContext === true,
|
|
5607
|
-
dir:
|
|
5608
|
-
promptTemplates: readPromptTemplates(
|
|
5678
|
+
dir: path22.dirname(profilePath),
|
|
5679
|
+
promptTemplates: readPromptTemplates(path22.dirname(profilePath))
|
|
5609
5680
|
};
|
|
5610
5681
|
if (lifecycle) {
|
|
5611
5682
|
applyLifecycle(profile, profilePath);
|
|
@@ -5640,19 +5711,19 @@ function loadProfile(profilePath) {
|
|
|
5640
5711
|
return profile;
|
|
5641
5712
|
}
|
|
5642
5713
|
function compileRuntimeDocument(runtimePath, document) {
|
|
5643
|
-
if (
|
|
5714
|
+
if (path22.basename(runtimePath) !== "runtime.json") return document;
|
|
5644
5715
|
if (document.adapter !== "kody-engine-profile") {
|
|
5645
5716
|
throw new ProfileError(runtimePath, "unsupported runtime adapter document");
|
|
5646
5717
|
}
|
|
5647
|
-
const implementationDir =
|
|
5648
|
-
const implementation = readJsonObject(
|
|
5649
|
-
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));
|
|
5650
5721
|
const capabilityId = implementation.capabilityRef && typeof implementation.capabilityRef === "object" && !Array.isArray(implementation.capabilityRef) ? implementation.capabilityRef.id : void 0;
|
|
5651
5722
|
if (typeof capabilityId !== "string" || !capabilityId) {
|
|
5652
5723
|
throw new ProfileError(runtimePath, "Implementation capabilityRef is invalid");
|
|
5653
5724
|
}
|
|
5654
5725
|
const capability = readJsonObject(
|
|
5655
|
-
|
|
5726
|
+
path22.join(definitionsRoot2, "capabilities", capabilityId, "definition.json"),
|
|
5656
5727
|
"Capability definition"
|
|
5657
5728
|
);
|
|
5658
5729
|
const {
|
|
@@ -5691,7 +5762,7 @@ function canonical(value) {
|
|
|
5691
5762
|
}
|
|
5692
5763
|
function readJsonObject(filePath, label) {
|
|
5693
5764
|
try {
|
|
5694
|
-
const value = JSON.parse(
|
|
5765
|
+
const value = JSON.parse(fs23.readFileSync(filePath, "utf-8"));
|
|
5695
5766
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5696
5767
|
throw new Error("must be an object");
|
|
5697
5768
|
}
|
|
@@ -5709,17 +5780,17 @@ function readPromptTemplates(dir) {
|
|
|
5709
5780
|
const out = {};
|
|
5710
5781
|
const read = (p) => {
|
|
5711
5782
|
try {
|
|
5712
|
-
out[p] =
|
|
5783
|
+
out[p] = fs23.readFileSync(p, "utf-8");
|
|
5713
5784
|
} catch {
|
|
5714
5785
|
}
|
|
5715
5786
|
};
|
|
5716
|
-
read(
|
|
5717
|
-
read(
|
|
5718
|
-
read(
|
|
5787
|
+
read(path22.join(dir, "prompt.md"));
|
|
5788
|
+
read(path22.join(dir, "capability.md"));
|
|
5789
|
+
read(path22.join(dir, "capability.md"));
|
|
5719
5790
|
try {
|
|
5720
|
-
const promptsDir =
|
|
5721
|
-
for (const ent of
|
|
5722
|
-
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));
|
|
5723
5794
|
}
|
|
5724
5795
|
} catch {
|
|
5725
5796
|
}
|
|
@@ -5866,10 +5937,12 @@ function parseClaudeCode(p, raw) {
|
|
|
5866
5937
|
throw new ProfileError(p, `claudeCode.permissionMode must be one of default|acceptEdits|plan|bypassPermissions`);
|
|
5867
5938
|
}
|
|
5868
5939
|
const tools = Array.isArray(r.tools) ? r.tools : [];
|
|
5940
|
+
const disallowedTools = Array.isArray(r.disallowedTools) ? r.disallowedTools : [];
|
|
5869
5941
|
return {
|
|
5870
5942
|
model: typeof r.model === "string" ? r.model : "inherit",
|
|
5871
5943
|
permissionMode,
|
|
5872
5944
|
maxTurns: typeof r.maxTurns === "number" ? r.maxTurns : null,
|
|
5945
|
+
disallowedTools,
|
|
5873
5946
|
maxThinkingTokens: typeof r.maxThinkingTokens === "number" ? r.maxThinkingTokens : null,
|
|
5874
5947
|
reasoningEffort: typeof r.reasoningEffort === "string" ? parseReasoningEffort(r.reasoningEffort) : null,
|
|
5875
5948
|
maxTurnTimeoutSec: typeof r.maxTurnTimeoutSec === "number" ? r.maxTurnTimeoutSec : null,
|
|
@@ -6494,16 +6567,16 @@ var init_state = __esm({
|
|
|
6494
6567
|
});
|
|
6495
6568
|
|
|
6496
6569
|
// src/prompt.ts
|
|
6497
|
-
import * as
|
|
6498
|
-
import * as
|
|
6570
|
+
import * as fs24 from "fs";
|
|
6571
|
+
import * as path23 from "path";
|
|
6499
6572
|
function loadProjectConventions(projectDir) {
|
|
6500
6573
|
const out = [];
|
|
6501
6574
|
for (const rel of CONVENTION_FILES) {
|
|
6502
|
-
const abs =
|
|
6503
|
-
if (!
|
|
6575
|
+
const abs = path23.join(projectDir, rel);
|
|
6576
|
+
if (!fs24.existsSync(abs)) continue;
|
|
6504
6577
|
let content;
|
|
6505
6578
|
try {
|
|
6506
|
-
content =
|
|
6579
|
+
content = fs24.readFileSync(abs, "utf-8");
|
|
6507
6580
|
} catch {
|
|
6508
6581
|
continue;
|
|
6509
6582
|
}
|
|
@@ -6738,8 +6811,8 @@ var loadMemoryContext_exports = {};
|
|
|
6738
6811
|
__export(loadMemoryContext_exports, {
|
|
6739
6812
|
loadMemoryContext: () => loadMemoryContext
|
|
6740
6813
|
});
|
|
6741
|
-
import * as
|
|
6742
|
-
import * as
|
|
6814
|
+
import * as fs25 from "fs";
|
|
6815
|
+
import * as path24 from "path";
|
|
6743
6816
|
function formatBlockFromBackend(docs) {
|
|
6744
6817
|
const pages = docs.flatMap((record2) => {
|
|
6745
6818
|
if (!record2.doc || typeof record2.doc !== "object") return [];
|
|
@@ -6762,21 +6835,21 @@ function collectPages(memoryAbs) {
|
|
|
6762
6835
|
walkMd(memoryAbs, (file) => {
|
|
6763
6836
|
let stat;
|
|
6764
6837
|
try {
|
|
6765
|
-
stat =
|
|
6838
|
+
stat = fs25.statSync(file);
|
|
6766
6839
|
} catch {
|
|
6767
6840
|
return;
|
|
6768
6841
|
}
|
|
6769
6842
|
let raw;
|
|
6770
6843
|
try {
|
|
6771
|
-
raw =
|
|
6844
|
+
raw = fs25.readFileSync(file, "utf-8");
|
|
6772
6845
|
} catch {
|
|
6773
6846
|
return;
|
|
6774
6847
|
}
|
|
6775
6848
|
const fm = raw.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
6776
|
-
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");
|
|
6777
6850
|
const updated = fm?.[1]?.match(/^updated:\s*([0-9T:.+\-Z]+)/m)?.[1]?.trim() ?? "";
|
|
6778
6851
|
out.push({
|
|
6779
|
-
relPath:
|
|
6852
|
+
relPath: path24.relative(memoryAbs, file),
|
|
6780
6853
|
title,
|
|
6781
6854
|
updated,
|
|
6782
6855
|
content: raw.length > PER_PAGE_MAX_BYTES ? raw.slice(0, PER_PAGE_MAX_BYTES) + TRUNCATED_SUFFIX2 : raw,
|
|
@@ -6844,16 +6917,16 @@ function walkMd(root, visit) {
|
|
|
6844
6917
|
const dir = stack.pop();
|
|
6845
6918
|
let names;
|
|
6846
6919
|
try {
|
|
6847
|
-
names =
|
|
6920
|
+
names = fs25.readdirSync(dir);
|
|
6848
6921
|
} catch {
|
|
6849
6922
|
continue;
|
|
6850
6923
|
}
|
|
6851
6924
|
for (const name of names) {
|
|
6852
6925
|
if (name.startsWith(".")) continue;
|
|
6853
|
-
const full =
|
|
6926
|
+
const full = path24.join(dir, name);
|
|
6854
6927
|
let stat;
|
|
6855
6928
|
try {
|
|
6856
|
-
stat =
|
|
6929
|
+
stat = fs25.statSync(full);
|
|
6857
6930
|
} catch {
|
|
6858
6931
|
continue;
|
|
6859
6932
|
}
|
|
@@ -6888,8 +6961,8 @@ var init_loadMemoryContext = __esm({
|
|
|
6888
6961
|
}
|
|
6889
6962
|
return;
|
|
6890
6963
|
}
|
|
6891
|
-
const memoryAbs =
|
|
6892
|
-
if (!
|
|
6964
|
+
const memoryAbs = path24.join(ctx.cwd, MEMORY_DIR_RELATIVE);
|
|
6965
|
+
if (!fs25.existsSync(memoryAbs)) {
|
|
6893
6966
|
ctx.data.memoryContext = "";
|
|
6894
6967
|
return;
|
|
6895
6968
|
}
|
|
@@ -6933,11 +7006,11 @@ var init_loadCoverageRules = __esm({
|
|
|
6933
7006
|
|
|
6934
7007
|
// src/container.ts
|
|
6935
7008
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
6936
|
-
import * as
|
|
7009
|
+
import * as fs26 from "fs";
|
|
6937
7010
|
function getProfileInputsForChild(profileName, _cwd) {
|
|
6938
7011
|
try {
|
|
6939
7012
|
const profilePath = resolveProfilePath(profileName);
|
|
6940
|
-
if (!
|
|
7013
|
+
if (!fs26.existsSync(profilePath)) return null;
|
|
6941
7014
|
return loadProfile(profilePath).inputs;
|
|
6942
7015
|
} catch {
|
|
6943
7016
|
return null;
|
|
@@ -7401,10 +7474,10 @@ var init_lifecycleLabels = __esm({
|
|
|
7401
7474
|
|
|
7402
7475
|
// src/litellm.ts
|
|
7403
7476
|
import { execFileSync as execFileSync4, spawn as spawn4 } from "child_process";
|
|
7404
|
-
import * as
|
|
7477
|
+
import * as fs27 from "fs";
|
|
7405
7478
|
import * as net from "net";
|
|
7406
7479
|
import * as os4 from "os";
|
|
7407
|
-
import * as
|
|
7480
|
+
import * as path25 from "path";
|
|
7408
7481
|
async function checkLitellmHealth(url) {
|
|
7409
7482
|
try {
|
|
7410
7483
|
const response = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3e3) });
|
|
@@ -7474,7 +7547,7 @@ function locateLitellmScript() {
|
|
|
7474
7547
|
}
|
|
7475
7548
|
function resolveLitellmCommand() {
|
|
7476
7549
|
const imageScript = "/opt/venv/bin/litellm";
|
|
7477
|
-
if (
|
|
7550
|
+
if (fs27.existsSync(imageScript)) return imageScript;
|
|
7478
7551
|
try {
|
|
7479
7552
|
execFileSync4("which", ["litellm"], { timeout: 3e3, stdio: "pipe" });
|
|
7480
7553
|
return "litellm";
|
|
@@ -7517,13 +7590,13 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
|
|
|
7517
7590
|
const spawnProxy = () => {
|
|
7518
7591
|
const portMatch = activeUrl.match(/:(\d+)/);
|
|
7519
7592
|
const port = portMatch ? portMatch[1] : "4000";
|
|
7520
|
-
const configPath =
|
|
7521
|
-
|
|
7593
|
+
const configPath = path25.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.yaml`);
|
|
7594
|
+
fs27.writeFileSync(configPath, generateLitellmConfigYaml(model));
|
|
7522
7595
|
const args = ["--config", configPath, "--port", port];
|
|
7523
|
-
const nextLogPath =
|
|
7524
|
-
const outFd =
|
|
7596
|
+
const nextLogPath = path25.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.log`);
|
|
7597
|
+
const outFd = fs27.openSync(nextLogPath, "w");
|
|
7525
7598
|
child = spawn4(cmd, args, { stdio: ["ignore", outFd, outFd], detached: true, env: childEnv });
|
|
7526
|
-
|
|
7599
|
+
fs27.closeSync(outFd);
|
|
7527
7600
|
logPath = nextLogPath;
|
|
7528
7601
|
};
|
|
7529
7602
|
const waitForHealth = async () => {
|
|
@@ -7537,7 +7610,7 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
|
|
|
7537
7610
|
const readLogTail = () => {
|
|
7538
7611
|
if (!logPath) return "";
|
|
7539
7612
|
try {
|
|
7540
|
-
return
|
|
7613
|
+
return fs27.readFileSync(logPath, "utf-8").slice(-2e3);
|
|
7541
7614
|
} catch {
|
|
7542
7615
|
return "";
|
|
7543
7616
|
}
|
|
@@ -7610,20 +7683,20 @@ async function nextAvailableLitellmUrl(url) {
|
|
|
7610
7683
|
throw new Error(`no free LiteLLM port found after ${startPort}`);
|
|
7611
7684
|
}
|
|
7612
7685
|
function canListen(port, host) {
|
|
7613
|
-
return new Promise((
|
|
7686
|
+
return new Promise((resolve21) => {
|
|
7614
7687
|
const server = net.createServer();
|
|
7615
|
-
server.once("error", () =>
|
|
7688
|
+
server.once("error", () => resolve21(false));
|
|
7616
7689
|
server.once("listening", () => {
|
|
7617
|
-
server.close(() =>
|
|
7690
|
+
server.close(() => resolve21(true));
|
|
7618
7691
|
});
|
|
7619
7692
|
server.listen(port, host);
|
|
7620
7693
|
});
|
|
7621
7694
|
}
|
|
7622
7695
|
function readDotenvApiKeys(projectDir) {
|
|
7623
|
-
const dotenvPath =
|
|
7624
|
-
if (!
|
|
7696
|
+
const dotenvPath = path25.join(projectDir, ".env");
|
|
7697
|
+
if (!fs27.existsSync(dotenvPath)) return {};
|
|
7625
7698
|
const result = {};
|
|
7626
|
-
for (const rawLine of
|
|
7699
|
+
for (const rawLine of fs27.readFileSync(dotenvPath, "utf-8").split("\n")) {
|
|
7627
7700
|
const line = rawLine.trim();
|
|
7628
7701
|
if (!line || line.startsWith("#")) continue;
|
|
7629
7702
|
const match = line.match(/^([A-Z_][A-Z0-9_]*_API_KEY)=(.*)$/);
|
|
@@ -8282,8 +8355,8 @@ var init_pushWithRetry = __esm({
|
|
|
8282
8355
|
|
|
8283
8356
|
// src/commit.ts
|
|
8284
8357
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
8285
|
-
import * as
|
|
8286
|
-
import * as
|
|
8358
|
+
import * as fs28 from "fs";
|
|
8359
|
+
import * as path26 from "path";
|
|
8287
8360
|
function isGitHubYamlPath(filePath) {
|
|
8288
8361
|
const normalized = filePath.replace(/^\.\/+/, "");
|
|
8289
8362
|
return normalized.startsWith(".github/") && /\.ya?ml$/i.test(normalized);
|
|
@@ -8325,18 +8398,18 @@ function ensureGitIdentity(cwd) {
|
|
|
8325
8398
|
}
|
|
8326
8399
|
function abortUnfinishedGitOps(cwd) {
|
|
8327
8400
|
const aborted = [];
|
|
8328
|
-
const gitDir =
|
|
8329
|
-
if (!
|
|
8330
|
-
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"))) {
|
|
8331
8404
|
if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
|
|
8332
8405
|
}
|
|
8333
|
-
if (
|
|
8406
|
+
if (fs28.existsSync(path26.join(gitDir, "CHERRY_PICK_HEAD"))) {
|
|
8334
8407
|
if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
|
|
8335
8408
|
}
|
|
8336
|
-
if (
|
|
8409
|
+
if (fs28.existsSync(path26.join(gitDir, "REVERT_HEAD"))) {
|
|
8337
8410
|
if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
|
|
8338
8411
|
}
|
|
8339
|
-
if (
|
|
8412
|
+
if (fs28.existsSync(path26.join(gitDir, "rebase-merge")) || fs28.existsSync(path26.join(gitDir, "rebase-apply"))) {
|
|
8340
8413
|
if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
|
|
8341
8414
|
}
|
|
8342
8415
|
try {
|
|
@@ -8393,7 +8466,7 @@ function normalizeCommitMessage(raw) {
|
|
|
8393
8466
|
function commitAndPush(branch, agentMessage, cwd) {
|
|
8394
8467
|
const allChanged = listChangedFiles(cwd);
|
|
8395
8468
|
const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
|
|
8396
|
-
const mergeHeadExists =
|
|
8469
|
+
const mergeHeadExists = fs28.existsSync(path26.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
|
|
8397
8470
|
if (allowedFiles.length === 0 && !mergeHeadExists) {
|
|
8398
8471
|
return { committed: false, pushed: false, sha: "", message: "" };
|
|
8399
8472
|
}
|
|
@@ -9033,13 +9106,13 @@ var init_state2 = __esm({
|
|
|
9033
9106
|
});
|
|
9034
9107
|
|
|
9035
9108
|
// src/goal/runLog.ts
|
|
9036
|
-
import * as
|
|
9109
|
+
import * as fs29 from "fs";
|
|
9037
9110
|
function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
|
|
9038
9111
|
const logs = goalRunLogs(data);
|
|
9039
9112
|
const existing = logs[goalId];
|
|
9040
|
-
const
|
|
9113
|
+
const path55 = existing?.path ?? goalRunLogPath(goalId, data);
|
|
9041
9114
|
logs[goalId] = {
|
|
9042
|
-
path:
|
|
9115
|
+
path: path55,
|
|
9043
9116
|
events: [...existing?.events ?? [], buildGoalRunLogEvent(data, goalId, event, at)]
|
|
9044
9117
|
};
|
|
9045
9118
|
}
|
|
@@ -9375,8 +9448,8 @@ function readGithubEvent() {
|
|
|
9375
9448
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
9376
9449
|
if (!eventPath) return null;
|
|
9377
9450
|
try {
|
|
9378
|
-
if (!
|
|
9379
|
-
const parsed = JSON.parse(
|
|
9451
|
+
if (!fs29.existsSync(eventPath)) return null;
|
|
9452
|
+
const parsed = JSON.parse(fs29.readFileSync(eventPath, "utf-8"));
|
|
9380
9453
|
return recordValue3(parsed);
|
|
9381
9454
|
} catch {
|
|
9382
9455
|
return null;
|
|
@@ -9486,8 +9559,8 @@ var init_stateStore = __esm({
|
|
|
9486
9559
|
});
|
|
9487
9560
|
|
|
9488
9561
|
// src/goal/targetLoopResolution.ts
|
|
9489
|
-
import * as
|
|
9490
|
-
import * as
|
|
9562
|
+
import * as fs30 from "fs";
|
|
9563
|
+
import * as path27 from "path";
|
|
9491
9564
|
async function resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal) {
|
|
9492
9565
|
const targetId = loopGoal.loopTarget?.id.trim() ?? "";
|
|
9493
9566
|
assertSafeGoalId(targetId, "loop target");
|
|
@@ -9565,11 +9638,11 @@ function goalInstanceTime(state) {
|
|
|
9565
9638
|
return Number.isNaN(parsed) ? 0 : parsed;
|
|
9566
9639
|
}
|
|
9567
9640
|
function loadGoalTemplate(cwd, targetId) {
|
|
9568
|
-
return readJsonObject2(
|
|
9641
|
+
return readJsonObject2(path27.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
|
|
9569
9642
|
}
|
|
9570
9643
|
function readJsonObject2(filePath) {
|
|
9571
|
-
if (!
|
|
9572
|
-
const parsed = JSON.parse(
|
|
9644
|
+
if (!fs30.existsSync(filePath)) return null;
|
|
9645
|
+
const parsed = JSON.parse(fs30.readFileSync(filePath, "utf8"));
|
|
9573
9646
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
9574
9647
|
throw new Error(`goal template ${filePath} must be a JSON object`);
|
|
9575
9648
|
}
|
|
@@ -9916,15 +9989,15 @@ var init_backendStateBackend = __esm({
|
|
|
9916
9989
|
this.jobsDir = opts.jobsDir.replace(/\/+$/, "");
|
|
9917
9990
|
}
|
|
9918
9991
|
async load(slug) {
|
|
9919
|
-
const
|
|
9992
|
+
const path55 = stateFilePath(this.jobsDir, slug);
|
|
9920
9993
|
const loaded = await createStateBackendFromEnv().get(this.tenantId, `capabilities/${slug}`, "job-state");
|
|
9921
9994
|
if (!loaded) {
|
|
9922
|
-
return { path:
|
|
9995
|
+
return { path: path55, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
9923
9996
|
}
|
|
9924
9997
|
if (!isStateEnvelope(loaded.doc)) {
|
|
9925
9998
|
throw new Error(`BackendStateBackend: capabilities/${slug} is not a StateEnvelope`);
|
|
9926
9999
|
}
|
|
9927
|
-
return { path:
|
|
10000
|
+
return { path: path55, handle: loaded.updatedAt, state: loaded.doc, created: false };
|
|
9928
10001
|
}
|
|
9929
10002
|
async save(loaded, next) {
|
|
9930
10003
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) return false;
|
|
@@ -9944,8 +10017,8 @@ var init_backendStateBackend = __esm({
|
|
|
9944
10017
|
});
|
|
9945
10018
|
|
|
9946
10019
|
// src/scripts/jobState/localFileBackend.ts
|
|
9947
|
-
import * as
|
|
9948
|
-
import * as
|
|
10020
|
+
import * as fs31 from "fs";
|
|
10021
|
+
import * as path28 from "path";
|
|
9949
10022
|
function sanitizeKey(s) {
|
|
9950
10023
|
return s.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
9951
10024
|
}
|
|
@@ -10001,7 +10074,7 @@ var init_localFileBackend = __esm({
|
|
|
10001
10074
|
if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
|
|
10002
10075
|
this.cwd = opts.cwd;
|
|
10003
10076
|
this.jobsDir = opts.jobsDir;
|
|
10004
|
-
this.absDir =
|
|
10077
|
+
this.absDir = path28.resolve(opts.cwd, opts.jobsDir);
|
|
10005
10078
|
this.owner = opts.owner;
|
|
10006
10079
|
this.repo = opts.repo;
|
|
10007
10080
|
this.cache = opts.cache ?? defaultCacheAdapter();
|
|
@@ -10016,7 +10089,7 @@ var init_localFileBackend = __esm({
|
|
|
10016
10089
|
`);
|
|
10017
10090
|
return;
|
|
10018
10091
|
}
|
|
10019
|
-
|
|
10092
|
+
fs31.mkdirSync(this.absDir, { recursive: true });
|
|
10020
10093
|
const prefix = this.cacheKeyPrefix();
|
|
10021
10094
|
const probeKey = `${prefix}probe-${Date.now()}`;
|
|
10022
10095
|
try {
|
|
@@ -10045,7 +10118,7 @@ var init_localFileBackend = __esm({
|
|
|
10045
10118
|
`);
|
|
10046
10119
|
return;
|
|
10047
10120
|
}
|
|
10048
|
-
if (!
|
|
10121
|
+
if (!fs31.existsSync(this.absDir)) {
|
|
10049
10122
|
return;
|
|
10050
10123
|
}
|
|
10051
10124
|
const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
|
|
@@ -10061,11 +10134,11 @@ var init_localFileBackend = __esm({
|
|
|
10061
10134
|
}
|
|
10062
10135
|
load(slug) {
|
|
10063
10136
|
const relPath = stateFilePath(this.jobsDir, slug);
|
|
10064
|
-
const absPath =
|
|
10065
|
-
if (!
|
|
10137
|
+
const absPath = path28.resolve(this.cwd, relPath);
|
|
10138
|
+
if (!fs31.existsSync(absPath)) {
|
|
10066
10139
|
return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
10067
10140
|
}
|
|
10068
|
-
const raw =
|
|
10141
|
+
const raw = fs31.readFileSync(absPath, "utf-8");
|
|
10069
10142
|
let parsed;
|
|
10070
10143
|
try {
|
|
10071
10144
|
parsed = JSON.parse(raw);
|
|
@@ -10082,13 +10155,13 @@ var init_localFileBackend = __esm({
|
|
|
10082
10155
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) {
|
|
10083
10156
|
return false;
|
|
10084
10157
|
}
|
|
10085
|
-
const absPath =
|
|
10086
|
-
|
|
10158
|
+
const absPath = path28.resolve(this.cwd, loaded.path);
|
|
10159
|
+
fs31.mkdirSync(path28.dirname(absPath), { recursive: true });
|
|
10087
10160
|
const body = `${JSON.stringify(next, null, 2)}
|
|
10088
10161
|
`;
|
|
10089
10162
|
const tmpPath = `${absPath}.${process.pid}.tmp`;
|
|
10090
|
-
|
|
10091
|
-
|
|
10163
|
+
fs31.writeFileSync(tmpPath, body, "utf-8");
|
|
10164
|
+
fs31.renameSync(tmpPath, absPath);
|
|
10092
10165
|
return true;
|
|
10093
10166
|
}
|
|
10094
10167
|
cacheKeyPrefix() {
|
|
@@ -10120,7 +10193,7 @@ var init_jobState = __esm({
|
|
|
10120
10193
|
});
|
|
10121
10194
|
|
|
10122
10195
|
// src/scripts/goalCapabilityScheduling.ts
|
|
10123
|
-
import * as
|
|
10196
|
+
import * as path29 from "path";
|
|
10124
10197
|
function isCapabilityCadenceGoal(goal, extra) {
|
|
10125
10198
|
return extra.scheduleMode === "agentLoop" || extra.scheduler === "agentLoop" || goal.type === "standing" && goal.capabilities.length > 0;
|
|
10126
10199
|
}
|
|
@@ -10176,7 +10249,7 @@ function planTargetLoopSchedule(opts) {
|
|
|
10176
10249
|
}
|
|
10177
10250
|
async function planGoalCapabilitySchedule(opts) {
|
|
10178
10251
|
const jobsDir = opts.jobsDir ?? capabilitiesRoot(opts.cwd);
|
|
10179
|
-
const jobsRoot =
|
|
10252
|
+
const jobsRoot = path29.resolve(opts.cwd, jobsDir);
|
|
10180
10253
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
10181
10254
|
const at = now.toISOString();
|
|
10182
10255
|
const backend = resolveBackend({ config: opts.config, cwd: opts.cwd, jobsDir });
|
|
@@ -11992,8 +12065,8 @@ var init_classifyByLabel = __esm({
|
|
|
11992
12065
|
|
|
11993
12066
|
// src/scripts/commitAndPush.ts
|
|
11994
12067
|
import { createHash as createHash5 } from "crypto";
|
|
11995
|
-
import * as
|
|
11996
|
-
import * as
|
|
12068
|
+
import * as fs32 from "fs";
|
|
12069
|
+
import * as path30 from "path";
|
|
11997
12070
|
function sentinelPathForStage(cwd, profileName, workflowExecutionKey) {
|
|
11998
12071
|
const runId = resolveRunId();
|
|
11999
12072
|
const executionSuffix = typeof workflowExecutionKey === "string" && workflowExecutionKey.length > 0 ? `-${createHash5("sha256").update(workflowExecutionKey).digest("hex").slice(0, 16)}` : "";
|
|
@@ -12015,9 +12088,9 @@ var init_commitAndPush = __esm({
|
|
|
12015
12088
|
}
|
|
12016
12089
|
const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
|
|
12017
12090
|
const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name, ctx.data.workflowExecutionKey) : null;
|
|
12018
|
-
if (sentinel &&
|
|
12091
|
+
if (sentinel && fs32.existsSync(sentinel)) {
|
|
12019
12092
|
try {
|
|
12020
|
-
const replay = JSON.parse(
|
|
12093
|
+
const replay = JSON.parse(fs32.readFileSync(sentinel, "utf-8"));
|
|
12021
12094
|
ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
|
|
12022
12095
|
if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
|
|
12023
12096
|
if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
|
|
@@ -12077,8 +12150,8 @@ var init_commitAndPush = __esm({
|
|
|
12077
12150
|
const result = ctx.data.commitResult;
|
|
12078
12151
|
if (sentinel && result?.committed) {
|
|
12079
12152
|
try {
|
|
12080
|
-
|
|
12081
|
-
|
|
12153
|
+
fs32.mkdirSync(path30.dirname(sentinel), { recursive: true });
|
|
12154
|
+
fs32.writeFileSync(
|
|
12082
12155
|
sentinel,
|
|
12083
12156
|
JSON.stringify(
|
|
12084
12157
|
{
|
|
@@ -12172,8 +12245,8 @@ var init_commitGoalState = __esm({
|
|
|
12172
12245
|
});
|
|
12173
12246
|
|
|
12174
12247
|
// src/scripts/composePrompt.ts
|
|
12175
|
-
import * as
|
|
12176
|
-
import * as
|
|
12248
|
+
import * as fs33 from "fs";
|
|
12249
|
+
import * as path31 from "path";
|
|
12177
12250
|
function fenceUntrusted(value) {
|
|
12178
12251
|
if (value.trim().length === 0) return value;
|
|
12179
12252
|
const safe = value.replace(/-{3,}\s*END UNTRUSTED INPUT\s*-{3,}/gi, "[END UNTRUSTED INPUT]");
|
|
@@ -12297,10 +12370,10 @@ var init_composePrompt = __esm({
|
|
|
12297
12370
|
const explicit = ctx.data.promptTemplate;
|
|
12298
12371
|
const mode = ctx.args.mode;
|
|
12299
12372
|
const candidates = [
|
|
12300
|
-
explicit ?
|
|
12301
|
-
mode ?
|
|
12302
|
-
|
|
12303
|
-
|
|
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")
|
|
12304
12377
|
].filter(Boolean);
|
|
12305
12378
|
let templatePath = "";
|
|
12306
12379
|
let template = "";
|
|
@@ -12313,7 +12386,7 @@ var init_composePrompt = __esm({
|
|
|
12313
12386
|
break;
|
|
12314
12387
|
}
|
|
12315
12388
|
try {
|
|
12316
|
-
template =
|
|
12389
|
+
template = fs33.readFileSync(c, "utf-8");
|
|
12317
12390
|
templatePath = c;
|
|
12318
12391
|
break;
|
|
12319
12392
|
} catch (err) {
|
|
@@ -12324,7 +12397,7 @@ var init_composePrompt = __esm({
|
|
|
12324
12397
|
if (!templatePath) {
|
|
12325
12398
|
let dirState;
|
|
12326
12399
|
try {
|
|
12327
|
-
dirState = `dir contents: [${
|
|
12400
|
+
dirState = `dir contents: [${fs33.readdirSync(profile.dir).join(", ")}]`;
|
|
12328
12401
|
} catch (err) {
|
|
12329
12402
|
dirState = `readdir(${profile.dir}) failed: ${err?.code ?? String(err)}`;
|
|
12330
12403
|
}
|
|
@@ -13058,19 +13131,19 @@ var init_deriveQaScopeFromIssue = __esm({
|
|
|
13058
13131
|
|
|
13059
13132
|
// src/scripts/diagMcp.ts
|
|
13060
13133
|
import { execFileSync as execFileSync9 } from "child_process";
|
|
13061
|
-
import * as
|
|
13134
|
+
import * as fs34 from "fs";
|
|
13062
13135
|
import * as os5 from "os";
|
|
13063
|
-
import * as
|
|
13136
|
+
import * as path32 from "path";
|
|
13064
13137
|
var diagMcp;
|
|
13065
13138
|
var init_diagMcp = __esm({
|
|
13066
13139
|
"src/scripts/diagMcp.ts"() {
|
|
13067
13140
|
"use strict";
|
|
13068
13141
|
diagMcp = async (_ctx) => {
|
|
13069
13142
|
const home = os5.homedir();
|
|
13070
|
-
const cacheDir =
|
|
13143
|
+
const cacheDir = path32.join(home, ".cache", "ms-playwright");
|
|
13071
13144
|
let entries = [];
|
|
13072
13145
|
try {
|
|
13073
|
-
entries =
|
|
13146
|
+
entries = fs34.readdirSync(cacheDir);
|
|
13074
13147
|
} catch {
|
|
13075
13148
|
}
|
|
13076
13149
|
const hasChromium = entries.some((e) => e.startsWith("chromium"));
|
|
@@ -13098,13 +13171,13 @@ var init_diagMcp = __esm({
|
|
|
13098
13171
|
});
|
|
13099
13172
|
|
|
13100
13173
|
// src/scripts/frameworkDetectors.ts
|
|
13101
|
-
import * as
|
|
13102
|
-
import * as
|
|
13174
|
+
import * as fs35 from "fs";
|
|
13175
|
+
import * as path33 from "path";
|
|
13103
13176
|
function detectFrameworks(cwd) {
|
|
13104
13177
|
const out = [];
|
|
13105
13178
|
let deps = {};
|
|
13106
13179
|
try {
|
|
13107
|
-
const pkg = JSON.parse(
|
|
13180
|
+
const pkg = JSON.parse(fs35.readFileSync(path33.join(cwd, "package.json"), "utf-8"));
|
|
13108
13181
|
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13109
13182
|
} catch {
|
|
13110
13183
|
return out;
|
|
@@ -13141,25 +13214,25 @@ function detectFrameworks(cwd) {
|
|
|
13141
13214
|
}
|
|
13142
13215
|
function findFile(cwd, candidates) {
|
|
13143
13216
|
for (const c of candidates) {
|
|
13144
|
-
if (
|
|
13217
|
+
if (fs35.existsSync(path33.join(cwd, c))) return c;
|
|
13145
13218
|
}
|
|
13146
13219
|
return null;
|
|
13147
13220
|
}
|
|
13148
13221
|
function discoverPayloadCollections(cwd) {
|
|
13149
13222
|
const out = [];
|
|
13150
13223
|
for (const dir of COLLECTION_DIRS) {
|
|
13151
|
-
const full =
|
|
13152
|
-
if (!
|
|
13224
|
+
const full = path33.join(cwd, dir);
|
|
13225
|
+
if (!fs35.existsSync(full)) continue;
|
|
13153
13226
|
let files;
|
|
13154
13227
|
try {
|
|
13155
|
-
files =
|
|
13228
|
+
files = fs35.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
13156
13229
|
} catch {
|
|
13157
13230
|
continue;
|
|
13158
13231
|
}
|
|
13159
13232
|
for (const file of files) {
|
|
13160
13233
|
try {
|
|
13161
|
-
const filePath =
|
|
13162
|
-
const content =
|
|
13234
|
+
const filePath = path33.join(full, file);
|
|
13235
|
+
const content = fs35.readFileSync(filePath, "utf-8").slice(0, 1e4);
|
|
13163
13236
|
const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
|
|
13164
13237
|
if (!slugMatch) continue;
|
|
13165
13238
|
const slug = slugMatch[1];
|
|
@@ -13173,7 +13246,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
13173
13246
|
out.push({
|
|
13174
13247
|
name,
|
|
13175
13248
|
slug,
|
|
13176
|
-
filePath:
|
|
13249
|
+
filePath: path33.relative(cwd, filePath),
|
|
13177
13250
|
fields: fields.slice(0, 20),
|
|
13178
13251
|
hasAdmin
|
|
13179
13252
|
});
|
|
@@ -13186,28 +13259,28 @@ function discoverPayloadCollections(cwd) {
|
|
|
13186
13259
|
function discoverAdminComponents(cwd, collections) {
|
|
13187
13260
|
const out = [];
|
|
13188
13261
|
for (const dir of ADMIN_COMPONENT_DIRS) {
|
|
13189
|
-
const full =
|
|
13190
|
-
if (!
|
|
13262
|
+
const full = path33.join(cwd, dir);
|
|
13263
|
+
if (!fs35.existsSync(full)) continue;
|
|
13191
13264
|
let entries;
|
|
13192
13265
|
try {
|
|
13193
|
-
entries =
|
|
13266
|
+
entries = fs35.readdirSync(full, { withFileTypes: true });
|
|
13194
13267
|
} catch {
|
|
13195
13268
|
continue;
|
|
13196
13269
|
}
|
|
13197
13270
|
for (const entry of entries) {
|
|
13198
|
-
const entryPath =
|
|
13271
|
+
const entryPath = path33.join(full, entry.name);
|
|
13199
13272
|
let name;
|
|
13200
13273
|
let filePath;
|
|
13201
13274
|
if (entry.isDirectory()) {
|
|
13202
13275
|
const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
|
|
13203
|
-
(f) =>
|
|
13276
|
+
(f) => fs35.existsSync(path33.join(entryPath, f))
|
|
13204
13277
|
);
|
|
13205
13278
|
if (!indexFile) continue;
|
|
13206
13279
|
name = entry.name;
|
|
13207
|
-
filePath =
|
|
13280
|
+
filePath = path33.relative(cwd, path33.join(entryPath, indexFile));
|
|
13208
13281
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
13209
13282
|
name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
|
|
13210
|
-
filePath =
|
|
13283
|
+
filePath = path33.relative(cwd, entryPath);
|
|
13211
13284
|
} else {
|
|
13212
13285
|
continue;
|
|
13213
13286
|
}
|
|
@@ -13215,7 +13288,7 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
13215
13288
|
if (collections) {
|
|
13216
13289
|
for (const col of collections) {
|
|
13217
13290
|
try {
|
|
13218
|
-
const colContent =
|
|
13291
|
+
const colContent = fs35.readFileSync(path33.join(cwd, col.filePath), "utf-8");
|
|
13219
13292
|
if (colContent.includes(name)) {
|
|
13220
13293
|
usedInCollection = col.slug;
|
|
13221
13294
|
break;
|
|
@@ -13233,8 +13306,8 @@ function scanApiRoutes(cwd) {
|
|
|
13233
13306
|
const out = [];
|
|
13234
13307
|
const appDirs = ["src/app", "app"];
|
|
13235
13308
|
for (const appDir of appDirs) {
|
|
13236
|
-
const apiDir =
|
|
13237
|
-
if (!
|
|
13309
|
+
const apiDir = path33.join(cwd, appDir, "api");
|
|
13310
|
+
if (!fs35.existsSync(apiDir)) continue;
|
|
13238
13311
|
walkApiRoutes(apiDir, "/api", cwd, out);
|
|
13239
13312
|
break;
|
|
13240
13313
|
}
|
|
@@ -13243,14 +13316,14 @@ function scanApiRoutes(cwd) {
|
|
|
13243
13316
|
function walkApiRoutes(dir, prefix, cwd, out) {
|
|
13244
13317
|
let entries;
|
|
13245
13318
|
try {
|
|
13246
|
-
entries =
|
|
13319
|
+
entries = fs35.readdirSync(dir, { withFileTypes: true });
|
|
13247
13320
|
} catch {
|
|
13248
13321
|
return;
|
|
13249
13322
|
}
|
|
13250
13323
|
const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
|
|
13251
13324
|
if (routeFile) {
|
|
13252
13325
|
try {
|
|
13253
|
-
const content =
|
|
13326
|
+
const content = fs35.readFileSync(path33.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
|
|
13254
13327
|
const methods = HTTP_METHODS.filter(
|
|
13255
13328
|
(m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
|
|
13256
13329
|
);
|
|
@@ -13258,7 +13331,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
13258
13331
|
out.push({
|
|
13259
13332
|
path: prefix,
|
|
13260
13333
|
methods,
|
|
13261
|
-
filePath:
|
|
13334
|
+
filePath: path33.relative(cwd, path33.join(dir, routeFile.name))
|
|
13262
13335
|
});
|
|
13263
13336
|
}
|
|
13264
13337
|
} catch {
|
|
@@ -13269,7 +13342,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
13269
13342
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
13270
13343
|
let segment = entry.name;
|
|
13271
13344
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
13272
|
-
walkApiRoutes(
|
|
13345
|
+
walkApiRoutes(path33.join(dir, entry.name), prefix, cwd, out);
|
|
13273
13346
|
continue;
|
|
13274
13347
|
}
|
|
13275
13348
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -13277,16 +13350,16 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
13277
13350
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
13278
13351
|
segment = `:${segment.slice(1, -1)}`;
|
|
13279
13352
|
}
|
|
13280
|
-
walkApiRoutes(
|
|
13353
|
+
walkApiRoutes(path33.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
|
|
13281
13354
|
}
|
|
13282
13355
|
}
|
|
13283
13356
|
function scanEnvVars(cwd) {
|
|
13284
13357
|
const candidates = [".env.example", ".env.local.example", ".env.template"];
|
|
13285
13358
|
for (const envFile of candidates) {
|
|
13286
|
-
const envPath =
|
|
13287
|
-
if (!
|
|
13359
|
+
const envPath = path33.join(cwd, envFile);
|
|
13360
|
+
if (!fs35.existsSync(envPath)) continue;
|
|
13288
13361
|
try {
|
|
13289
|
-
const content =
|
|
13362
|
+
const content = fs35.readFileSync(envPath, "utf-8");
|
|
13290
13363
|
const vars = [];
|
|
13291
13364
|
for (const line of content.split("\n")) {
|
|
13292
13365
|
const trimmed = line.trim();
|
|
@@ -13331,8 +13404,8 @@ var init_frameworkDetectors = __esm({
|
|
|
13331
13404
|
});
|
|
13332
13405
|
|
|
13333
13406
|
// src/scripts/discoverQaContext.ts
|
|
13334
|
-
import * as
|
|
13335
|
-
import * as
|
|
13407
|
+
import * as fs36 from "fs";
|
|
13408
|
+
import * as path34 from "path";
|
|
13336
13409
|
function runQaDiscovery(cwd) {
|
|
13337
13410
|
const out = {
|
|
13338
13411
|
routes: [],
|
|
@@ -13363,9 +13436,9 @@ function runQaDiscovery(cwd) {
|
|
|
13363
13436
|
}
|
|
13364
13437
|
function detectDevServer(cwd, out) {
|
|
13365
13438
|
try {
|
|
13366
|
-
const pkg = JSON.parse(
|
|
13439
|
+
const pkg = JSON.parse(fs36.readFileSync(path34.join(cwd, "package.json"), "utf-8"));
|
|
13367
13440
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13368
|
-
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";
|
|
13369
13442
|
if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
|
|
13370
13443
|
if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
|
|
13371
13444
|
else if (allDeps.vite) out.devPort = 5173;
|
|
@@ -13375,8 +13448,8 @@ function detectDevServer(cwd, out) {
|
|
|
13375
13448
|
function scanFrontendRoutes(cwd, out) {
|
|
13376
13449
|
const appDirs = ["src/app", "app"];
|
|
13377
13450
|
for (const appDir of appDirs) {
|
|
13378
|
-
const full =
|
|
13379
|
-
if (!
|
|
13451
|
+
const full = path34.join(cwd, appDir);
|
|
13452
|
+
if (!fs36.existsSync(full)) continue;
|
|
13380
13453
|
walkFrontendRoutes(full, "", out);
|
|
13381
13454
|
break;
|
|
13382
13455
|
}
|
|
@@ -13384,7 +13457,7 @@ function scanFrontendRoutes(cwd, out) {
|
|
|
13384
13457
|
function walkFrontendRoutes(dir, prefix, out) {
|
|
13385
13458
|
let entries;
|
|
13386
13459
|
try {
|
|
13387
|
-
entries =
|
|
13460
|
+
entries = fs36.readdirSync(dir, { withFileTypes: true });
|
|
13388
13461
|
} catch {
|
|
13389
13462
|
return;
|
|
13390
13463
|
}
|
|
@@ -13401,7 +13474,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
13401
13474
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
13402
13475
|
let segment = entry.name;
|
|
13403
13476
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
13404
|
-
walkFrontendRoutes(
|
|
13477
|
+
walkFrontendRoutes(path34.join(dir, entry.name), prefix, out);
|
|
13405
13478
|
continue;
|
|
13406
13479
|
}
|
|
13407
13480
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -13409,7 +13482,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
13409
13482
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
13410
13483
|
segment = `:${segment.slice(1, -1)}`;
|
|
13411
13484
|
}
|
|
13412
|
-
walkFrontendRoutes(
|
|
13485
|
+
walkFrontendRoutes(path34.join(dir, entry.name), `${prefix}/${segment}`, out);
|
|
13413
13486
|
}
|
|
13414
13487
|
}
|
|
13415
13488
|
function detectAuthFiles(cwd, out) {
|
|
@@ -13426,23 +13499,23 @@ function detectAuthFiles(cwd, out) {
|
|
|
13426
13499
|
"src/app/api/oauth"
|
|
13427
13500
|
];
|
|
13428
13501
|
for (const c of candidates) {
|
|
13429
|
-
if (
|
|
13502
|
+
if (fs36.existsSync(path34.join(cwd, c))) out.authFiles.push(c);
|
|
13430
13503
|
}
|
|
13431
13504
|
}
|
|
13432
13505
|
function detectRoles(cwd, out) {
|
|
13433
13506
|
const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
|
|
13434
13507
|
for (const rp of rolePaths) {
|
|
13435
|
-
const dir =
|
|
13436
|
-
if (!
|
|
13508
|
+
const dir = path34.join(cwd, rp);
|
|
13509
|
+
if (!fs36.existsSync(dir)) continue;
|
|
13437
13510
|
let files;
|
|
13438
13511
|
try {
|
|
13439
|
-
files =
|
|
13512
|
+
files = fs36.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
13440
13513
|
} catch {
|
|
13441
13514
|
continue;
|
|
13442
13515
|
}
|
|
13443
13516
|
for (const f of files) {
|
|
13444
13517
|
try {
|
|
13445
|
-
const content =
|
|
13518
|
+
const content = fs36.readFileSync(path34.join(dir, f), "utf-8").slice(0, 5e3);
|
|
13446
13519
|
const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
|
|
13447
13520
|
if (roleMatches) {
|
|
13448
13521
|
for (const m of roleMatches) {
|
|
@@ -13703,8 +13776,8 @@ var init_dispatchClassified = __esm({
|
|
|
13703
13776
|
});
|
|
13704
13777
|
|
|
13705
13778
|
// src/loopDefinitions.ts
|
|
13706
|
-
import * as
|
|
13707
|
-
import * as
|
|
13779
|
+
import * as fs37 from "fs";
|
|
13780
|
+
import * as path35 from "path";
|
|
13708
13781
|
function normalizeLoopDefinition(value) {
|
|
13709
13782
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
13710
13783
|
const raw = value;
|
|
@@ -13731,10 +13804,10 @@ function readLoopDefinition(cwd, id) {
|
|
|
13731
13804
|
if (!ID.test(id)) return null;
|
|
13732
13805
|
const roots = loopRoots(cwd);
|
|
13733
13806
|
for (const root of roots) {
|
|
13734
|
-
const filePath =
|
|
13735
|
-
if (!
|
|
13807
|
+
const filePath = path35.join(root, "loops", id, "loop.json");
|
|
13808
|
+
if (!fs37.existsSync(filePath)) continue;
|
|
13736
13809
|
try {
|
|
13737
|
-
const loop = normalizeLoopDefinition(JSON.parse(
|
|
13810
|
+
const loop = normalizeLoopDefinition(JSON.parse(fs37.readFileSync(filePath, "utf8")));
|
|
13738
13811
|
if (loop?.id === id) return loop;
|
|
13739
13812
|
process.stderr.write(`[kody] invalid Loop definition: ${filePath}
|
|
13740
13813
|
`);
|
|
@@ -13744,7 +13817,7 @@ function readLoopDefinition(cwd, id) {
|
|
|
13744
13817
|
}
|
|
13745
13818
|
}
|
|
13746
13819
|
process.stderr.write(
|
|
13747
|
-
`[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(", ")})
|
|
13748
13821
|
`
|
|
13749
13822
|
);
|
|
13750
13823
|
return null;
|
|
@@ -13753,14 +13826,14 @@ function listLoopDefinitions(cwd) {
|
|
|
13753
13826
|
const roots = loopRoots(cwd);
|
|
13754
13827
|
const byId = /* @__PURE__ */ new Map();
|
|
13755
13828
|
for (const root of roots.reverse()) {
|
|
13756
|
-
const loopsDir =
|
|
13757
|
-
if (!
|
|
13758
|
-
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()) {
|
|
13759
13832
|
if (!ID.test(id)) continue;
|
|
13760
|
-
const filePath =
|
|
13761
|
-
if (!
|
|
13833
|
+
const filePath = path35.join(loopsDir, id, "loop.json");
|
|
13834
|
+
if (!fs37.existsSync(filePath)) continue;
|
|
13762
13835
|
try {
|
|
13763
|
-
const loop = normalizeLoopDefinition(JSON.parse(
|
|
13836
|
+
const loop = normalizeLoopDefinition(JSON.parse(fs37.readFileSync(filePath, "utf8")));
|
|
13764
13837
|
if (loop?.id === id) byId.set(id, loop);
|
|
13765
13838
|
} catch {
|
|
13766
13839
|
process.stderr.write(`[kody] unreadable Loop definition: ${filePath}
|
|
@@ -13772,8 +13845,8 @@ function listLoopDefinitions(cwd) {
|
|
|
13772
13845
|
}
|
|
13773
13846
|
function loopRoots(cwd) {
|
|
13774
13847
|
return [
|
|
13775
|
-
|
|
13776
|
-
|
|
13848
|
+
path35.join(cwd, ".kody-engine", "runtime"),
|
|
13849
|
+
path35.join(cwd, ".kody-engine", "definitions"),
|
|
13777
13850
|
definitionsRoot(cwd)
|
|
13778
13851
|
].filter((root, index, roots) => roots.indexOf(root) === index);
|
|
13779
13852
|
}
|
|
@@ -15051,15 +15124,15 @@ var init_fixFlow = __esm({
|
|
|
15051
15124
|
});
|
|
15052
15125
|
|
|
15053
15126
|
// src/workflow-template.ts
|
|
15054
|
-
import * as
|
|
15055
|
-
import * as
|
|
15127
|
+
import * as fs38 from "fs";
|
|
15128
|
+
import * as path36 from "path";
|
|
15056
15129
|
import { fileURLToPath } from "url";
|
|
15057
15130
|
function loadKodyWorkflowTemplate() {
|
|
15058
|
-
const here =
|
|
15059
|
-
const candidates = [
|
|
15060
|
-
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));
|
|
15061
15134
|
if (!source) throw new Error(`Kody workflow template is missing: ${KODY_WORKFLOW_TEMPLATE_PATH}`);
|
|
15062
|
-
return
|
|
15135
|
+
return fs38.readFileSync(source, "utf8");
|
|
15063
15136
|
}
|
|
15064
15137
|
var KODY_WORKFLOW_TEMPLATE_PATH;
|
|
15065
15138
|
var init_workflow_template = __esm({
|
|
@@ -15071,12 +15144,12 @@ var init_workflow_template = __esm({
|
|
|
15071
15144
|
|
|
15072
15145
|
// src/scripts/initFlow.ts
|
|
15073
15146
|
import { execFileSync as execFileSync14 } from "child_process";
|
|
15074
|
-
import * as
|
|
15075
|
-
import * as
|
|
15147
|
+
import * as fs39 from "fs";
|
|
15148
|
+
import * as path37 from "path";
|
|
15076
15149
|
function detectPackageManager(cwd) {
|
|
15077
|
-
if (
|
|
15078
|
-
if (
|
|
15079
|
-
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";
|
|
15080
15153
|
return "npm";
|
|
15081
15154
|
}
|
|
15082
15155
|
function qualityCommandsFor(pm) {
|
|
@@ -15148,22 +15221,22 @@ function performInit(cwd, force) {
|
|
|
15148
15221
|
const pm = detectPackageManager(cwd);
|
|
15149
15222
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
15150
15223
|
const defaultBranch = defaultBranchFromGit(cwd);
|
|
15151
|
-
const configPath =
|
|
15152
|
-
if (
|
|
15224
|
+
const configPath = path37.join(cwd, "kody.config.json");
|
|
15225
|
+
if (fs39.existsSync(configPath) && !force) {
|
|
15153
15226
|
skipped.push("kody.config.json");
|
|
15154
15227
|
} else {
|
|
15155
15228
|
const cfg = makeConfig(pm, ownerRepo, defaultBranch);
|
|
15156
|
-
|
|
15229
|
+
fs39.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
15157
15230
|
`);
|
|
15158
15231
|
wrote.push("kody.config.json");
|
|
15159
15232
|
}
|
|
15160
|
-
const workflowDir =
|
|
15161
|
-
const workflowPath =
|
|
15162
|
-
if (
|
|
15233
|
+
const workflowDir = path37.join(cwd, ".github", "workflows");
|
|
15234
|
+
const workflowPath = path37.join(workflowDir, "kody.yml");
|
|
15235
|
+
if (fs39.existsSync(workflowPath) && !force) {
|
|
15163
15236
|
skipped.push(".github/workflows/kody.yml");
|
|
15164
15237
|
} else {
|
|
15165
|
-
|
|
15166
|
-
|
|
15238
|
+
fs39.mkdirSync(workflowDir, { recursive: true });
|
|
15239
|
+
fs39.writeFileSync(workflowPath, loadKodyWorkflowTemplate());
|
|
15167
15240
|
wrote.push(".github/workflows/kody.yml");
|
|
15168
15241
|
}
|
|
15169
15242
|
let labels;
|
|
@@ -15214,7 +15287,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
|
|
|
15214
15287
|
});
|
|
15215
15288
|
|
|
15216
15289
|
// src/scripts/loadAgentAdhoc.ts
|
|
15217
|
-
import * as
|
|
15290
|
+
import * as fs40 from "fs";
|
|
15218
15291
|
function resolveMessage(messageArg) {
|
|
15219
15292
|
const fromComment = readCommentBody();
|
|
15220
15293
|
if (fromComment) return stripDirective(fromComment);
|
|
@@ -15222,9 +15295,9 @@ function resolveMessage(messageArg) {
|
|
|
15222
15295
|
}
|
|
15223
15296
|
function readCommentBody() {
|
|
15224
15297
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
15225
|
-
if (!eventPath || !
|
|
15298
|
+
if (!eventPath || !fs40.existsSync(eventPath)) return "";
|
|
15226
15299
|
try {
|
|
15227
|
-
const event = JSON.parse(
|
|
15300
|
+
const event = JSON.parse(fs40.readFileSync(eventPath, "utf-8"));
|
|
15228
15301
|
return String(event.comment?.body ?? "");
|
|
15229
15302
|
} catch {
|
|
15230
15303
|
return "";
|
|
@@ -15278,10 +15351,10 @@ var init_loadAgentAdhoc = __esm({
|
|
|
15278
15351
|
throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
|
|
15279
15352
|
}
|
|
15280
15353
|
const agentPath = resolveAgentFile2(ctx.cwd, agentSlug, agentsDir);
|
|
15281
|
-
if (!
|
|
15354
|
+
if (!fs40.existsSync(agentPath)) {
|
|
15282
15355
|
throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
|
|
15283
15356
|
}
|
|
15284
|
-
const { title, body } = parseAgentFile(
|
|
15357
|
+
const { title, body } = parseAgentFile(fs40.readFileSync(agentPath, "utf-8"), agentSlug);
|
|
15285
15358
|
const message = resolveMessage(ctx.args.message);
|
|
15286
15359
|
if (!message) {
|
|
15287
15360
|
throw new Error(
|
|
@@ -15353,13 +15426,13 @@ var init_loadCapabilityState = __esm({
|
|
|
15353
15426
|
function isCompanyIntentId(value) {
|
|
15354
15427
|
return SLUG_RE2.test(value);
|
|
15355
15428
|
}
|
|
15356
|
-
function normalizeCompanyIntent(
|
|
15429
|
+
function normalizeCompanyIntent(path55, raw) {
|
|
15357
15430
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
15358
|
-
throw new Error(`${
|
|
15431
|
+
throw new Error(`${path55}: intent must be JSON object`);
|
|
15359
15432
|
}
|
|
15360
15433
|
const input = raw;
|
|
15361
15434
|
const id = stringField4(input.id);
|
|
15362
|
-
if (!id || !isCompanyIntentId(id)) throw new Error(`${
|
|
15435
|
+
if (!id || !isCompanyIntentId(id)) throw new Error(`${path55}: invalid intent id`);
|
|
15363
15436
|
const createdAt = stringField4(input.createdAt) || nowIso();
|
|
15364
15437
|
const updatedAt = stringField4(input.updatedAt) || createdAt;
|
|
15365
15438
|
const description = stringField4(input.description);
|
|
@@ -15521,7 +15594,7 @@ function retryDelaysMs() {
|
|
|
15521
15594
|
}
|
|
15522
15595
|
function sleep(ms) {
|
|
15523
15596
|
if (ms <= 0) return Promise.resolve();
|
|
15524
|
-
return new Promise((
|
|
15597
|
+
return new Promise((resolve21) => setTimeout(resolve21, ms));
|
|
15525
15598
|
}
|
|
15526
15599
|
async function fetchGoalStateWithRetry(config, goalId, cwd) {
|
|
15527
15600
|
let state = await fetchGoalStateAsync(config, goalId, cwd);
|
|
@@ -15650,8 +15723,8 @@ var init_loadIssueStateComment = __esm({
|
|
|
15650
15723
|
});
|
|
15651
15724
|
|
|
15652
15725
|
// src/scripts/loadJobFromFile.ts
|
|
15653
|
-
import * as
|
|
15654
|
-
import * as
|
|
15726
|
+
import * as fs41 from "fs";
|
|
15727
|
+
import * as path38 from "path";
|
|
15655
15728
|
function parseJobFile(raw, slug) {
|
|
15656
15729
|
let stripped = raw;
|
|
15657
15730
|
if (stripped.startsWith("---\n")) {
|
|
@@ -15690,10 +15763,10 @@ var init_loadJobFromFile = __esm({
|
|
|
15690
15763
|
if (!slug) {
|
|
15691
15764
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
15692
15765
|
}
|
|
15693
|
-
const capability = resolveCapabilityFolder(slug,
|
|
15766
|
+
const capability = resolveCapabilityFolder(slug, path38.resolve(ctx.cwd, jobsDir));
|
|
15694
15767
|
if (!capability) {
|
|
15695
15768
|
throw new Error(
|
|
15696
|
-
`loadJobFromFile: capability folder not found or incomplete: ${
|
|
15769
|
+
`loadJobFromFile: capability folder not found or incomplete: ${path38.resolve(ctx.cwd, jobsDir, slug)}`
|
|
15697
15770
|
);
|
|
15698
15771
|
}
|
|
15699
15772
|
const { title, body, config } = capability;
|
|
@@ -15703,12 +15776,12 @@ var init_loadJobFromFile = __esm({
|
|
|
15703
15776
|
let agentIdentity = "";
|
|
15704
15777
|
if (agentSlug) {
|
|
15705
15778
|
const agentPath = resolveAgentFile2(ctx.cwd, agentSlug, agentsDir);
|
|
15706
|
-
if (!
|
|
15779
|
+
if (!fs41.existsSync(agentPath)) {
|
|
15707
15780
|
throw new Error(
|
|
15708
15781
|
`loadJobFromFile: capability '${slug}' declares agent '${agentSlug}' but ${agentPath} does not exist`
|
|
15709
15782
|
);
|
|
15710
15783
|
}
|
|
15711
|
-
const agentRaw =
|
|
15784
|
+
const agentRaw = fs41.readFileSync(agentPath, "utf-8");
|
|
15712
15785
|
const parsed = parseJobFile(agentRaw, agentSlug);
|
|
15713
15786
|
agentTitle = parsed.title;
|
|
15714
15787
|
agentIdentity = parsed.body;
|
|
@@ -15788,13 +15861,13 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
15788
15861
|
});
|
|
15789
15862
|
|
|
15790
15863
|
// src/scripts/kodyVariables.ts
|
|
15791
|
-
import * as
|
|
15792
|
-
import * as
|
|
15864
|
+
import * as fs42 from "fs";
|
|
15865
|
+
import * as path39 from "path";
|
|
15793
15866
|
function readKodyVariables(cwd) {
|
|
15794
|
-
const full =
|
|
15867
|
+
const full = path39.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
15795
15868
|
let raw;
|
|
15796
15869
|
try {
|
|
15797
|
-
raw =
|
|
15870
|
+
raw = fs42.readFileSync(full, "utf-8");
|
|
15798
15871
|
} catch {
|
|
15799
15872
|
return {};
|
|
15800
15873
|
}
|
|
@@ -15819,8 +15892,8 @@ var init_kodyVariables = __esm({
|
|
|
15819
15892
|
});
|
|
15820
15893
|
|
|
15821
15894
|
// src/scripts/loadQaContext.ts
|
|
15822
|
-
import * as
|
|
15823
|
-
import * as
|
|
15895
|
+
import * as fs43 from "fs";
|
|
15896
|
+
import * as path40 from "path";
|
|
15824
15897
|
function parseSlugList(value) {
|
|
15825
15898
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
15826
15899
|
return inner.split(",").map(
|
|
@@ -15849,18 +15922,18 @@ function readProfileAgents(raw) {
|
|
|
15849
15922
|
return { agent: agent ?? legacy ?? ["kody"], body };
|
|
15850
15923
|
}
|
|
15851
15924
|
function readProfile(cwd) {
|
|
15852
|
-
const dir =
|
|
15853
|
-
if (!
|
|
15925
|
+
const dir = path40.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
15926
|
+
if (!fs43.existsSync(dir)) return "";
|
|
15854
15927
|
let entries;
|
|
15855
15928
|
try {
|
|
15856
|
-
entries =
|
|
15929
|
+
entries = fs43.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
15857
15930
|
} catch {
|
|
15858
15931
|
return "";
|
|
15859
15932
|
}
|
|
15860
15933
|
const blocks = [];
|
|
15861
15934
|
for (const file of entries) {
|
|
15862
15935
|
try {
|
|
15863
|
-
const raw =
|
|
15936
|
+
const raw = fs43.readFileSync(path40.join(dir, file), "utf-8");
|
|
15864
15937
|
const { agent, body } = readProfileAgents(raw);
|
|
15865
15938
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
15866
15939
|
blocks.push(`## ${file}
|
|
@@ -15910,9 +15983,9 @@ var init_loadQaContext = __esm({
|
|
|
15910
15983
|
|
|
15911
15984
|
// src/scripts/loadSimpleCapability.ts
|
|
15912
15985
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
15913
|
-
import * as
|
|
15986
|
+
import * as fs44 from "fs";
|
|
15914
15987
|
import * as os6 from "os";
|
|
15915
|
-
import * as
|
|
15988
|
+
import * as path41 from "path";
|
|
15916
15989
|
function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
|
|
15917
15990
|
const subagentFiles = toolFiles.flatMap((file) => {
|
|
15918
15991
|
const match = /^agents\/([a-z][a-z0-9-]{0,63})\.md$/.exec(file);
|
|
@@ -15925,7 +15998,7 @@ function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
|
|
|
15925
15998
|
profile.subagentTemplates = {
|
|
15926
15999
|
...profile.subagentTemplates ?? {},
|
|
15927
16000
|
...Object.fromEntries(
|
|
15928
|
-
subagentFiles.map(({ name, file }) => [name,
|
|
16001
|
+
subagentFiles.map(({ name, file }) => [name, fs44.readFileSync(path41.join(toolRoot, file), "utf-8")])
|
|
15929
16002
|
)
|
|
15930
16003
|
};
|
|
15931
16004
|
if (!profile.claudeCode.tools.includes("Agent")) {
|
|
@@ -15966,14 +16039,14 @@ function scalar(value) {
|
|
|
15966
16039
|
return value;
|
|
15967
16040
|
}
|
|
15968
16041
|
function listFiles(root) {
|
|
15969
|
-
if (!
|
|
16042
|
+
if (!fs44.existsSync(root)) return [];
|
|
15970
16043
|
const files = [];
|
|
15971
16044
|
const visit = (dir) => {
|
|
15972
|
-
for (const entry of
|
|
15973
|
-
const absolute =
|
|
16045
|
+
for (const entry of fs44.readdirSync(dir, { withFileTypes: true })) {
|
|
16046
|
+
const absolute = path41.join(dir, entry.name);
|
|
15974
16047
|
if (entry.isSymbolicLink()) continue;
|
|
15975
16048
|
if (entry.isDirectory()) visit(absolute);
|
|
15976
|
-
else if (entry.isFile()) files.push(
|
|
16049
|
+
else if (entry.isFile()) files.push(path41.relative(root, absolute));
|
|
15977
16050
|
}
|
|
15978
16051
|
};
|
|
15979
16052
|
visit(root);
|
|
@@ -15996,8 +16069,8 @@ var init_loadSimpleCapability = __esm({
|
|
|
15996
16069
|
if (!capability) {
|
|
15997
16070
|
throw new Error(`Capability "${slug}" is not a valid simple capability folder`);
|
|
15998
16071
|
}
|
|
15999
|
-
const toolRoot =
|
|
16000
|
-
const skillRoot =
|
|
16072
|
+
const toolRoot = path41.join(capability.dir, "tools");
|
|
16073
|
+
const skillRoot = path41.join(capability.dir, "skills");
|
|
16001
16074
|
const toolFiles = listFiles(toolRoot);
|
|
16002
16075
|
const skillFiles = listFiles(skillRoot);
|
|
16003
16076
|
const parsedInput = parseInput(ctx.args.input);
|
|
@@ -16022,14 +16095,14 @@ var init_loadSimpleCapability = __esm({
|
|
|
16022
16095
|
}
|
|
16023
16096
|
if (requiredSubagents.length > 0) ctx.data.requiredSubagents = requiredSubagents;
|
|
16024
16097
|
if (capability.contract?.execution === "script") {
|
|
16025
|
-
ctx.data.capabilityScriptPath =
|
|
16098
|
+
ctx.data.capabilityScriptPath = path41.join(capability.dir, "tools", "run.sh");
|
|
16026
16099
|
ctx.data.capabilitySecretNames = capability.contract.secrets ?? [];
|
|
16027
16100
|
ctx.data.capabilityScriptTimeoutMs = capability.contract.timeoutMs;
|
|
16028
16101
|
}
|
|
16029
16102
|
if (capability.config.outputSchema) {
|
|
16030
16103
|
ctx.data.capabilityOutputSchema = capability.config.outputSchema;
|
|
16031
16104
|
}
|
|
16032
|
-
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;
|
|
16033
16106
|
if (outputPath) ctx.data.capabilityOutputPath = outputPath;
|
|
16034
16107
|
ctx.data.capabilityEnvironment = {
|
|
16035
16108
|
...capabilityInputEnvironment(input),
|
|
@@ -16052,7 +16125,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
16052
16125
|
...skillFiles.flatMap((file) => [
|
|
16053
16126
|
`### ${file}`,
|
|
16054
16127
|
"",
|
|
16055
|
-
|
|
16128
|
+
fs44.readFileSync(path41.join(skillRoot, file), "utf-8"),
|
|
16056
16129
|
""
|
|
16057
16130
|
])
|
|
16058
16131
|
] : [],
|
|
@@ -16061,7 +16134,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
16061
16134
|
"## Tools",
|
|
16062
16135
|
"",
|
|
16063
16136
|
"Inspect or run these capability-owned files when needed:",
|
|
16064
|
-
...toolFiles.map((file) => `- ${
|
|
16137
|
+
...toolFiles.map((file) => `- ${path41.join(toolRoot, file)}`)
|
|
16065
16138
|
] : [],
|
|
16066
16139
|
"",
|
|
16067
16140
|
...capability.config.outputSchema ? [
|
|
@@ -16092,8 +16165,8 @@ var init_loadSimpleCapability = __esm({
|
|
|
16092
16165
|
});
|
|
16093
16166
|
|
|
16094
16167
|
// src/taskContext.ts
|
|
16095
|
-
import * as
|
|
16096
|
-
import * as
|
|
16168
|
+
import * as fs45 from "fs";
|
|
16169
|
+
import * as path42 from "path";
|
|
16097
16170
|
function buildTaskContext(args) {
|
|
16098
16171
|
return {
|
|
16099
16172
|
schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
|
|
@@ -16109,9 +16182,9 @@ function buildTaskContext(args) {
|
|
|
16109
16182
|
function persistTaskContext(cwd, ctx) {
|
|
16110
16183
|
try {
|
|
16111
16184
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
16112
|
-
|
|
16113
|
-
const file =
|
|
16114
|
-
|
|
16185
|
+
fs45.mkdirSync(dir, { recursive: true });
|
|
16186
|
+
const file = path42.join(dir, "task-context.json");
|
|
16187
|
+
fs45.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
16115
16188
|
`);
|
|
16116
16189
|
return file;
|
|
16117
16190
|
} catch (err) {
|
|
@@ -16538,19 +16611,19 @@ function parseAgencyModelProposal(raw) {
|
|
|
16538
16611
|
function normalizeBundleFiles(bundle) {
|
|
16539
16612
|
const seen = /* @__PURE__ */ new Set();
|
|
16540
16613
|
return bundle.files.map((file, index) => {
|
|
16541
|
-
const
|
|
16542
|
-
const parts =
|
|
16543
|
-
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 === "..")) {
|
|
16544
16617
|
throw new Error(`openAgencyModelReviewPr: files[${index}].path is unsafe`);
|
|
16545
16618
|
}
|
|
16546
16619
|
if (!/^(agents\/[^/]+\.md|capabilities\/[^/]+\/.+|goals\/(?:templates\/)?[^/]+\/.+|workflows\/[^/]+\.json)$/.test(
|
|
16547
|
-
|
|
16620
|
+
path55
|
|
16548
16621
|
)) {
|
|
16549
16622
|
throw new Error(`openAgencyModelReviewPr: files[${index}].path is not a supported definition path`);
|
|
16550
16623
|
}
|
|
16551
|
-
if (seen.has(
|
|
16552
|
-
seen.add(
|
|
16553
|
-
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") };
|
|
16554
16627
|
});
|
|
16555
16628
|
}
|
|
16556
16629
|
function buildProposalId(issueNumber, bundle, sourceLabel) {
|
|
@@ -17032,16 +17105,16 @@ var init_parseReproOutput = __esm({
|
|
|
17032
17105
|
});
|
|
17033
17106
|
|
|
17034
17107
|
// src/scripts/parseSimpleCapabilityOutput.ts
|
|
17035
|
-
import * as
|
|
17108
|
+
import * as fs46 from "fs";
|
|
17036
17109
|
function stringList2(value) {
|
|
17037
17110
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
17038
17111
|
}
|
|
17039
17112
|
function readOutputFile(outputPath) {
|
|
17040
|
-
if (!outputPath || !
|
|
17113
|
+
if (!outputPath || !fs46.existsSync(outputPath)) return { found: false };
|
|
17041
17114
|
try {
|
|
17042
|
-
return { found: true, value: JSON.parse(
|
|
17115
|
+
return { found: true, value: JSON.parse(fs46.readFileSync(outputPath, "utf-8")) };
|
|
17043
17116
|
} finally {
|
|
17044
|
-
|
|
17117
|
+
fs46.rmSync(outputPath, { force: true });
|
|
17045
17118
|
}
|
|
17046
17119
|
}
|
|
17047
17120
|
function parseOutput(text2) {
|
|
@@ -17660,9 +17733,9 @@ var init_postResearchComment = __esm({
|
|
|
17660
17733
|
});
|
|
17661
17734
|
|
|
17662
17735
|
// src/scripts/prepareBrowserAuth.ts
|
|
17663
|
-
import * as
|
|
17736
|
+
import * as fs47 from "fs";
|
|
17664
17737
|
import * as os7 from "os";
|
|
17665
|
-
import * as
|
|
17738
|
+
import * as path43 from "path";
|
|
17666
17739
|
function appendAuthMessage(ctx, message) {
|
|
17667
17740
|
const current = typeof ctx.data.qaAuthBlock === "string" ? ctx.data.qaAuthBlock.trim() : "";
|
|
17668
17741
|
ctx.data.qaAuthBlock = current ? `${current}
|
|
@@ -17701,9 +17774,9 @@ async function githubJson(url, token) {
|
|
|
17701
17774
|
return await response.json();
|
|
17702
17775
|
}
|
|
17703
17776
|
function writeKodyStorageState(input) {
|
|
17704
|
-
const directory =
|
|
17705
|
-
|
|
17706
|
-
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");
|
|
17707
17780
|
const now = Date.now();
|
|
17708
17781
|
const repoEntry = {
|
|
17709
17782
|
repoUrl: input.repoUrl,
|
|
@@ -17733,7 +17806,7 @@ function writeKodyStorageState(input) {
|
|
|
17733
17806
|
}
|
|
17734
17807
|
]
|
|
17735
17808
|
};
|
|
17736
|
-
|
|
17809
|
+
fs47.writeFileSync(file, JSON.stringify(storageState), { mode: 384 });
|
|
17737
17810
|
return { directory, file };
|
|
17738
17811
|
}
|
|
17739
17812
|
function configurePlaywright(profile, storageStatePath) {
|
|
@@ -17815,7 +17888,7 @@ async function prepareMethod(ctx, profile, method) {
|
|
|
17815
17888
|
configurePlaywright(profile, state.file);
|
|
17816
17889
|
const authDirectory = state.directory;
|
|
17817
17890
|
registerRuntimeCleanup(ctx, () => {
|
|
17818
|
-
|
|
17891
|
+
fs47.rmSync(authDirectory, { recursive: true, force: true });
|
|
17819
17892
|
});
|
|
17820
17893
|
appendAuthMessage(
|
|
17821
17894
|
ctx,
|
|
@@ -17823,7 +17896,7 @@ async function prepareMethod(ctx, profile, method) {
|
|
|
17823
17896
|
);
|
|
17824
17897
|
return true;
|
|
17825
17898
|
} catch (error) {
|
|
17826
|
-
if (state)
|
|
17899
|
+
if (state) fs47.rmSync(state.directory, { recursive: true, force: true });
|
|
17827
17900
|
const reason = error instanceof Error ? error.message : String(error);
|
|
17828
17901
|
appendAuthMessage(
|
|
17829
17902
|
ctx,
|
|
@@ -17962,7 +18035,7 @@ var init_prepareCapabilityDelivery = __esm({
|
|
|
17962
18035
|
|
|
17963
18036
|
// src/scripts/prepareSimpleCapabilityRuntime.ts
|
|
17964
18037
|
import { isIP } from "net";
|
|
17965
|
-
import * as
|
|
18038
|
+
import * as path44 from "path";
|
|
17966
18039
|
function requirementsFrom(ctx) {
|
|
17967
18040
|
const raw = ctx.data.capabilityRequirements;
|
|
17968
18041
|
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
@@ -18006,7 +18079,7 @@ function browserRuntime(ctx, requirements) {
|
|
|
18006
18079
|
"--allowed-origins",
|
|
18007
18080
|
origin,
|
|
18008
18081
|
"--output-dir",
|
|
18009
|
-
|
|
18082
|
+
path44.resolve(ctx.cwd, "test-results", "quality-runs", qualityRunId)
|
|
18010
18083
|
]
|
|
18011
18084
|
};
|
|
18012
18085
|
}
|
|
@@ -18014,8 +18087,21 @@ function configureBrowser(ctx, profile, requirements) {
|
|
|
18014
18087
|
const server = browserRuntime(ctx, requirements);
|
|
18015
18088
|
if (requirements.browserOnly) {
|
|
18016
18089
|
profile.claudeCode.tools = ["Write"];
|
|
18090
|
+
profile.claudeCode.disallowedTools = [
|
|
18091
|
+
"Agent",
|
|
18092
|
+
"Bash",
|
|
18093
|
+
"Edit",
|
|
18094
|
+
"Glob",
|
|
18095
|
+
"Grep",
|
|
18096
|
+
"NotebookEdit",
|
|
18097
|
+
"Read",
|
|
18098
|
+
"Task",
|
|
18099
|
+
"TodoWrite",
|
|
18100
|
+
"WebFetch",
|
|
18101
|
+
"WebSearch"
|
|
18102
|
+
];
|
|
18017
18103
|
profile.claudeCode.permissionMode = "default";
|
|
18018
|
-
profile.claudeCode.maxTurns = Math.min(profile.claudeCode.maxTurns ??
|
|
18104
|
+
profile.claudeCode.maxTurns = Math.min(profile.claudeCode.maxTurns ?? 100, 100);
|
|
18019
18105
|
}
|
|
18020
18106
|
if (!profile.claudeCode.tools.includes("mcp__playwright")) {
|
|
18021
18107
|
profile.claudeCode.tools = [...profile.claudeCode.tools, "mcp__playwright"];
|
|
@@ -18358,9 +18444,9 @@ function latestResult(raw, agentResult) {
|
|
|
18358
18444
|
function recordField4(value) {
|
|
18359
18445
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
18360
18446
|
}
|
|
18361
|
-
function resolveDotted(root,
|
|
18362
|
-
if (!
|
|
18363
|
-
return
|
|
18447
|
+
function resolveDotted(root, path55) {
|
|
18448
|
+
if (!path55) return void 0;
|
|
18449
|
+
return path55.split(".").reduce((value, key) => recordField4(value)?.[key], root);
|
|
18364
18450
|
}
|
|
18365
18451
|
function stringValue5(value) {
|
|
18366
18452
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
@@ -19202,7 +19288,7 @@ var init_previewBuildHelpers = __esm({
|
|
|
19202
19288
|
// src/scripts/previewBuildRun.ts
|
|
19203
19289
|
import { spawn as spawn5 } from "child_process";
|
|
19204
19290
|
async function runCmd(cmd, args, opts = {}) {
|
|
19205
|
-
await new Promise((
|
|
19291
|
+
await new Promise((resolve21, reject) => {
|
|
19206
19292
|
const child = spawn5(cmd, args, {
|
|
19207
19293
|
cwd: opts.cwd,
|
|
19208
19294
|
env: { ...process.env, ...opts.env ?? {} },
|
|
@@ -19214,7 +19300,7 @@ async function runCmd(cmd, args, opts = {}) {
|
|
|
19214
19300
|
}
|
|
19215
19301
|
child.on("error", reject);
|
|
19216
19302
|
child.on("close", (code) => {
|
|
19217
|
-
if (code === 0)
|
|
19303
|
+
if (code === 0) resolve21();
|
|
19218
19304
|
else reject(new Error(`${cmd} ${args.join(" ")} exited ${code}`));
|
|
19219
19305
|
});
|
|
19220
19306
|
});
|
|
@@ -19286,12 +19372,12 @@ fi
|
|
|
19286
19372
|
|
|
19287
19373
|
// src/scripts/runPreviewBuild.ts
|
|
19288
19374
|
import { copyFile, writeFile } from "fs/promises";
|
|
19289
|
-
import * as
|
|
19375
|
+
import * as path45 from "path";
|
|
19290
19376
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
19291
19377
|
function bundledDockerfilePath(mode) {
|
|
19292
|
-
const here =
|
|
19378
|
+
const here = path45.dirname(fileURLToPath2(import.meta.url));
|
|
19293
19379
|
const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
|
|
19294
|
-
return
|
|
19380
|
+
return path45.join(here, "preview-build-templates", file);
|
|
19295
19381
|
}
|
|
19296
19382
|
function required(name) {
|
|
19297
19383
|
const v = (process.env[name] ?? "").trim();
|
|
@@ -19526,10 +19612,10 @@ var init_runPreviewBuild = __esm({
|
|
|
19526
19612
|
console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
|
|
19527
19613
|
if (Object.keys(buildEnv).length > 0) {
|
|
19528
19614
|
const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
19529
|
-
await writeFile(
|
|
19615
|
+
await writeFile(path45.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
|
|
19530
19616
|
`, "utf8");
|
|
19531
19617
|
}
|
|
19532
|
-
const consumerDockerfile =
|
|
19618
|
+
const consumerDockerfile = path45.join(ctx.cwd, "Dockerfile.preview");
|
|
19533
19619
|
const { stat } = await import("fs/promises");
|
|
19534
19620
|
let hasConsumerDockerfile = false;
|
|
19535
19621
|
try {
|
|
@@ -19713,8 +19799,8 @@ var init_tickShellRunner = __esm({
|
|
|
19713
19799
|
});
|
|
19714
19800
|
|
|
19715
19801
|
// src/scripts/runScheduledImplementationTick.ts
|
|
19716
|
-
import * as
|
|
19717
|
-
import * as
|
|
19802
|
+
import * as fs48 from "fs";
|
|
19803
|
+
import * as path46 from "path";
|
|
19718
19804
|
var runScheduledImplementationTick;
|
|
19719
19805
|
var init_runScheduledImplementationTick = __esm({
|
|
19720
19806
|
"src/scripts/runScheduledImplementationTick.ts"() {
|
|
@@ -19735,14 +19821,14 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
19735
19821
|
ctx.output.reason = `runScheduledImplementationTick: args.slug or ctx.args.${slugArg} must be non-empty capability slug`;
|
|
19736
19822
|
return;
|
|
19737
19823
|
}
|
|
19738
|
-
const capability = resolveCapabilityFolder(slug,
|
|
19824
|
+
const capability = resolveCapabilityFolder(slug, path46.resolve(ctx.cwd, jobsDir));
|
|
19739
19825
|
if (!capability) {
|
|
19740
19826
|
ctx.output.exitCode = 99;
|
|
19741
19827
|
ctx.output.reason = `runScheduledImplementationTick: capability folder not found or incomplete: ${slug} (searched ${jobsDir} and company store)`;
|
|
19742
19828
|
return;
|
|
19743
19829
|
}
|
|
19744
|
-
const shellPath =
|
|
19745
|
-
if (!
|
|
19830
|
+
const shellPath = path46.join(profile.dir, shell);
|
|
19831
|
+
if (!fs48.existsSync(shellPath)) {
|
|
19746
19832
|
ctx.output.exitCode = 99;
|
|
19747
19833
|
ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
19748
19834
|
return;
|
|
@@ -19774,13 +19860,13 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
19774
19860
|
|
|
19775
19861
|
// src/scripts/runSimpleCapabilityScript.ts
|
|
19776
19862
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
19777
|
-
import * as
|
|
19863
|
+
import * as fs49 from "fs";
|
|
19778
19864
|
function formatDuration2(timeoutMs) {
|
|
19779
19865
|
return timeoutMs % 6e4 === 0 ? `${timeoutMs / 6e4} minutes` : `${timeoutMs}ms`;
|
|
19780
19866
|
}
|
|
19781
19867
|
function isRegularFile2(filePath) {
|
|
19782
19868
|
try {
|
|
19783
|
-
const stat =
|
|
19869
|
+
const stat = fs49.lstatSync(filePath);
|
|
19784
19870
|
return stat.isFile() && !stat.isSymbolicLink();
|
|
19785
19871
|
} catch {
|
|
19786
19872
|
return false;
|
|
@@ -19859,8 +19945,8 @@ var init_runSimpleCapabilityScript = __esm({
|
|
|
19859
19945
|
});
|
|
19860
19946
|
|
|
19861
19947
|
// src/scripts/runTickScript.ts
|
|
19862
|
-
import * as
|
|
19863
|
-
import * as
|
|
19948
|
+
import * as fs50 from "fs";
|
|
19949
|
+
import * as path47 from "path";
|
|
19864
19950
|
var runTickScript;
|
|
19865
19951
|
var init_runTickScript = __esm({
|
|
19866
19952
|
"src/scripts/runTickScript.ts"() {
|
|
@@ -19880,10 +19966,10 @@ var init_runTickScript = __esm({
|
|
|
19880
19966
|
ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
|
|
19881
19967
|
return;
|
|
19882
19968
|
}
|
|
19883
|
-
const capability = readCapabilityFolder(
|
|
19969
|
+
const capability = readCapabilityFolder(path47.resolve(ctx.cwd, jobsDir), slug);
|
|
19884
19970
|
if (!capability) {
|
|
19885
19971
|
ctx.output.exitCode = 99;
|
|
19886
|
-
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)}`;
|
|
19887
19973
|
return;
|
|
19888
19974
|
}
|
|
19889
19975
|
const tickScript = capability.config.tickScript;
|
|
@@ -19892,8 +19978,8 @@ var init_runTickScript = __esm({
|
|
|
19892
19978
|
ctx.output.reason = `runTickScript: capability ${slug} has no \`tickScript\` in profile.json \u2014 route via capability-tick instead`;
|
|
19893
19979
|
return;
|
|
19894
19980
|
}
|
|
19895
|
-
const scriptPath =
|
|
19896
|
-
if (!
|
|
19981
|
+
const scriptPath = path47.isAbsolute(tickScript) ? tickScript : path47.join(ctx.cwd, tickScript);
|
|
19982
|
+
if (!fs50.existsSync(scriptPath)) {
|
|
19897
19983
|
ctx.output.exitCode = 99;
|
|
19898
19984
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
19899
19985
|
return;
|
|
@@ -20175,7 +20261,7 @@ var init_syncFlow = __esm({
|
|
|
20175
20261
|
});
|
|
20176
20262
|
|
|
20177
20263
|
// src/scripts/validateAgencyModelProposal.ts
|
|
20178
|
-
import * as
|
|
20264
|
+
import * as path48 from "path";
|
|
20179
20265
|
function validateModelBundle(bundle, expectedKind, options = {}) {
|
|
20180
20266
|
const failures = [];
|
|
20181
20267
|
validateOneModel(bundle.model, bundle.files, "model", true, failures, expectedKind, options);
|
|
@@ -20493,7 +20579,7 @@ var init_validateAgencyModelProposal = __esm({
|
|
|
20493
20579
|
const bundle = parseAgencyModelProposal(raw);
|
|
20494
20580
|
const expectedKind = readExpectedModelKind(args);
|
|
20495
20581
|
const failures = validateModelBundle(bundle, expectedKind, {
|
|
20496
|
-
capabilityRoot:
|
|
20582
|
+
capabilityRoot: path48.join(ctx.cwd, ".kody", "capabilities")
|
|
20497
20583
|
});
|
|
20498
20584
|
if (failures.length > 0) {
|
|
20499
20585
|
throw new Error(`validateAgencyModelProposal: ${failures.join("; ")}`);
|
|
@@ -20556,7 +20642,7 @@ function stripAnsi2(s) {
|
|
|
20556
20642
|
return s.replace(ANSI_RE2, "");
|
|
20557
20643
|
}
|
|
20558
20644
|
function runCommand2(command, cwd) {
|
|
20559
|
-
return new Promise((
|
|
20645
|
+
return new Promise((resolve21) => {
|
|
20560
20646
|
const child = spawn6(command, {
|
|
20561
20647
|
cwd,
|
|
20562
20648
|
shell: true,
|
|
@@ -20583,11 +20669,11 @@ function runCommand2(command, cwd) {
|
|
|
20583
20669
|
}, TEST_TIMEOUT_MS);
|
|
20584
20670
|
child.on("exit", (code) => {
|
|
20585
20671
|
clearTimeout(timer);
|
|
20586
|
-
|
|
20672
|
+
resolve21({ exitCode: code ?? -1, output: Buffer.concat(buffers).toString("utf-8") });
|
|
20587
20673
|
});
|
|
20588
20674
|
child.on("error", (err) => {
|
|
20589
20675
|
clearTimeout(timer);
|
|
20590
|
-
|
|
20676
|
+
resolve21({ exitCode: -1, output: err.message });
|
|
20591
20677
|
});
|
|
20592
20678
|
});
|
|
20593
20679
|
}
|
|
@@ -20993,21 +21079,21 @@ function lineStream(stream) {
|
|
|
20993
21079
|
tryDeliver();
|
|
20994
21080
|
});
|
|
20995
21081
|
return {
|
|
20996
|
-
next: (timeoutMs) => new Promise((
|
|
21082
|
+
next: (timeoutMs) => new Promise((resolve21) => {
|
|
20997
21083
|
if (queue.length > 0) {
|
|
20998
|
-
|
|
21084
|
+
resolve21(queue.shift());
|
|
20999
21085
|
return;
|
|
21000
21086
|
}
|
|
21001
21087
|
if (ended) {
|
|
21002
|
-
|
|
21088
|
+
resolve21(null);
|
|
21003
21089
|
return;
|
|
21004
21090
|
}
|
|
21005
|
-
waiter =
|
|
21091
|
+
waiter = resolve21;
|
|
21006
21092
|
const t = setTimeout(
|
|
21007
21093
|
() => {
|
|
21008
|
-
if (waiter ===
|
|
21094
|
+
if (waiter === resolve21) {
|
|
21009
21095
|
waiter = null;
|
|
21010
|
-
|
|
21096
|
+
resolve21(null);
|
|
21011
21097
|
}
|
|
21012
21098
|
},
|
|
21013
21099
|
Math.max(0, timeoutMs)
|
|
@@ -21044,7 +21130,7 @@ var init_warmupMcp = __esm({
|
|
|
21044
21130
|
});
|
|
21045
21131
|
|
|
21046
21132
|
// src/scripts/writeAgentRunSummary.ts
|
|
21047
|
-
import * as
|
|
21133
|
+
import * as fs51 from "fs";
|
|
21048
21134
|
var writeAgentRunSummary;
|
|
21049
21135
|
var init_writeAgentRunSummary = __esm({
|
|
21050
21136
|
"src/scripts/writeAgentRunSummary.ts"() {
|
|
@@ -21070,7 +21156,7 @@ var init_writeAgentRunSummary = __esm({
|
|
|
21070
21156
|
if (reason) lines.push(`- **Reason:** ${reason}`);
|
|
21071
21157
|
lines.push("");
|
|
21072
21158
|
try {
|
|
21073
|
-
|
|
21159
|
+
fs51.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
21074
21160
|
`);
|
|
21075
21161
|
} catch {
|
|
21076
21162
|
}
|
|
@@ -21408,17 +21494,17 @@ var init_scripts = __esm({
|
|
|
21408
21494
|
});
|
|
21409
21495
|
|
|
21410
21496
|
// src/stateWorkspace.ts
|
|
21411
|
-
import * as
|
|
21412
|
-
import * as
|
|
21497
|
+
import * as fs52 from "fs";
|
|
21498
|
+
import * as path49 from "path";
|
|
21413
21499
|
function tenantId(config) {
|
|
21414
21500
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
21415
21501
|
const repo = config.github?.repo?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim();
|
|
21416
21502
|
return owner && repo ? `${owner}/${repo}` : null;
|
|
21417
21503
|
}
|
|
21418
21504
|
function writeRuntimeFile(cwd, relativePath, content) {
|
|
21419
|
-
const target =
|
|
21420
|
-
|
|
21421
|
-
|
|
21505
|
+
const target = path49.join(cwd, RUNTIME_ROOT, relativePath);
|
|
21506
|
+
fs52.mkdirSync(path49.dirname(target), { recursive: true });
|
|
21507
|
+
fs52.writeFileSync(target, content, "utf8");
|
|
21422
21508
|
}
|
|
21423
21509
|
function record(value) {
|
|
21424
21510
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -21483,11 +21569,11 @@ async function hydrateStateWorkspace(config, cwd, backendOverride) {
|
|
|
21483
21569
|
throw new Error("Kody backend access is required for runtime workspace documents");
|
|
21484
21570
|
return;
|
|
21485
21571
|
}
|
|
21486
|
-
const key = `${
|
|
21572
|
+
const key = `${path49.resolve(cwd)}|${tenant}`;
|
|
21487
21573
|
if (hydratedWorkspaces.has(key)) return;
|
|
21488
21574
|
const backend = backendOverride ?? createStateBackendFromEnv();
|
|
21489
|
-
const root =
|
|
21490
|
-
|
|
21575
|
+
const root = path49.join(cwd, RUNTIME_ROOT);
|
|
21576
|
+
fs52.rmSync(root, { recursive: true, force: true });
|
|
21491
21577
|
await Promise.all([
|
|
21492
21578
|
hydratePrefix(backend, tenant, cwd, "context:"),
|
|
21493
21579
|
hydratePrefix(backend, tenant, cwd, "memory:"),
|
|
@@ -21503,7 +21589,7 @@ var init_stateWorkspace = __esm({
|
|
|
21503
21589
|
"src/stateWorkspace.ts"() {
|
|
21504
21590
|
"use strict";
|
|
21505
21591
|
init_state_backend();
|
|
21506
|
-
RUNTIME_ROOT =
|
|
21592
|
+
RUNTIME_ROOT = path49.join(".kody-engine", "runtime");
|
|
21507
21593
|
hydratedWorkspaces = /* @__PURE__ */ new Set();
|
|
21508
21594
|
}
|
|
21509
21595
|
});
|
|
@@ -21574,9 +21660,9 @@ var init_tools = __esm({
|
|
|
21574
21660
|
|
|
21575
21661
|
// src/executor.ts
|
|
21576
21662
|
import { spawn as spawn8 } from "child_process";
|
|
21577
|
-
import * as
|
|
21663
|
+
import * as fs53 from "fs";
|
|
21578
21664
|
import * as os8 from "os";
|
|
21579
|
-
import * as
|
|
21665
|
+
import * as path50 from "path";
|
|
21580
21666
|
function isMutatingPostflight(scriptName) {
|
|
21581
21667
|
return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
|
|
21582
21668
|
}
|
|
@@ -21828,7 +21914,7 @@ async function runImplementation(profileName, input) {
|
|
|
21828
21914
|
const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
|
|
21829
21915
|
const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
|
|
21830
21916
|
const invokeAgent = async (prompt) => {
|
|
21831
|
-
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);
|
|
21832
21918
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
21833
21919
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
21834
21920
|
const agents = loadSubagents(profile);
|
|
@@ -21870,6 +21956,7 @@ async function runImplementation(profileName, input) {
|
|
|
21870
21956
|
ndjsonDir,
|
|
21871
21957
|
additionalDirectories: agentTaskArtifacts ? [agentTaskArtifacts.absDir] : void 0,
|
|
21872
21958
|
allowedToolsOverride: profile.claudeCode.tools,
|
|
21959
|
+
disallowedToolsOverride: profile.claudeCode.disallowedTools,
|
|
21873
21960
|
permissionModeOverride: profile.claudeCode.permissionMode,
|
|
21874
21961
|
mcpServers: profile.claudeCode.mcpServers.length > 0 ? profile.claudeCode.mcpServers : void 0,
|
|
21875
21962
|
pluginPaths: pluginPaths.length > 0 ? pluginPaths : void 0,
|
|
@@ -21908,7 +21995,11 @@ async function runImplementation(profileName, input) {
|
|
|
21908
21995
|
verifyToolMaxAttempts: profile.claudeCode.verifyAttempts ?? null,
|
|
21909
21996
|
verifyConfig: profile.claudeCode.enableVerifyTool ? config : void 0,
|
|
21910
21997
|
implementationName: profileName,
|
|
21911
|
-
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
|
|
21912
22003
|
});
|
|
21913
22004
|
};
|
|
21914
22005
|
ctx.data.__invokeAgent = invokeAgent;
|
|
@@ -22304,17 +22395,17 @@ function clearStampedLifecycleLabels(profile, ctx) {
|
|
|
22304
22395
|
function resolveProfilePath(profileName, cwd = process.cwd()) {
|
|
22305
22396
|
const found = resolveImplementation(profileName, getRuntimeProfileRootsForCwd(cwd));
|
|
22306
22397
|
if (found) return found;
|
|
22307
|
-
const here =
|
|
22398
|
+
const here = path50.dirname(new URL(import.meta.url).pathname);
|
|
22308
22399
|
const candidates = [
|
|
22309
|
-
|
|
22400
|
+
path50.join(here, "implementations", profileName, "profile.json"),
|
|
22310
22401
|
// same-dir sibling (dev)
|
|
22311
|
-
|
|
22402
|
+
path50.join(here, "..", "implementations", profileName, "profile.json"),
|
|
22312
22403
|
// up one (prod: dist/bin → dist/implementations)
|
|
22313
|
-
|
|
22404
|
+
path50.join(here, "..", "src", "implementations", profileName, "profile.json")
|
|
22314
22405
|
// fallback
|
|
22315
22406
|
];
|
|
22316
22407
|
for (const c of candidates) {
|
|
22317
|
-
if (
|
|
22408
|
+
if (fs53.existsSync(c)) return c;
|
|
22318
22409
|
}
|
|
22319
22410
|
return candidates[0];
|
|
22320
22411
|
}
|
|
@@ -22429,15 +22520,15 @@ function resolveShellTimeoutMs(entry) {
|
|
|
22429
22520
|
}
|
|
22430
22521
|
async function runShellEntry(entry, ctx, profile) {
|
|
22431
22522
|
const shellName = entry.shell;
|
|
22432
|
-
const shellPath =
|
|
22433
|
-
if (!
|
|
22523
|
+
const shellPath = path50.join(profile.dir, shellName);
|
|
22524
|
+
if (!fs53.existsSync(shellPath)) {
|
|
22434
22525
|
ctx.skipAgent = true;
|
|
22435
22526
|
ctx.output.exitCode = 99;
|
|
22436
22527
|
ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
|
|
22437
22528
|
return;
|
|
22438
22529
|
}
|
|
22439
22530
|
const positional = entry.with ? Object.values(entry.with).map((v) => String(v)) : [];
|
|
22440
|
-
const outputFile =
|
|
22531
|
+
const outputFile = path50.join(
|
|
22441
22532
|
os8.tmpdir(),
|
|
22442
22533
|
`kody-shell-output-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
22443
22534
|
);
|
|
@@ -22467,14 +22558,14 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
22467
22558
|
let killTimer;
|
|
22468
22559
|
let escalateTimer;
|
|
22469
22560
|
const result = await new Promise(
|
|
22470
|
-
(
|
|
22561
|
+
(resolve21) => {
|
|
22471
22562
|
let settled = false;
|
|
22472
22563
|
const settle = (code, signal, spawnErr) => {
|
|
22473
22564
|
if (settled) return;
|
|
22474
22565
|
settled = true;
|
|
22475
22566
|
if (killTimer) clearTimeout(killTimer);
|
|
22476
22567
|
if (escalateTimer) clearTimeout(escalateTimer);
|
|
22477
|
-
|
|
22568
|
+
resolve21({ code, signal, spawnErr });
|
|
22478
22569
|
};
|
|
22479
22570
|
child.on("error", (err) => settle(null, null, err));
|
|
22480
22571
|
child.on("close", (code, signal) => settle(code, signal));
|
|
@@ -22504,9 +22595,9 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
22504
22595
|
}
|
|
22505
22596
|
let sideChannelText = "";
|
|
22506
22597
|
try {
|
|
22507
|
-
if (
|
|
22508
|
-
sideChannelText =
|
|
22509
|
-
|
|
22598
|
+
if (fs53.existsSync(outputFile)) {
|
|
22599
|
+
sideChannelText = fs53.readFileSync(outputFile, "utf-8");
|
|
22600
|
+
fs53.rmSync(outputFile, { force: true });
|
|
22510
22601
|
}
|
|
22511
22602
|
} catch {
|
|
22512
22603
|
}
|
|
@@ -23362,11 +23453,11 @@ function exhaustedWorkflowTransitions(step, data, counts) {
|
|
|
23362
23453
|
}
|
|
23363
23454
|
function workflowResultConditionPaths(transitions) {
|
|
23364
23455
|
return transitions.flatMap(
|
|
23365
|
-
(transition) => Object.keys(transition.when ?? {}).filter((
|
|
23456
|
+
(transition) => Object.keys(transition.when ?? {}).filter((path55) => path55.startsWith("result."))
|
|
23366
23457
|
);
|
|
23367
23458
|
}
|
|
23368
23459
|
function conditionMatches(condition, context) {
|
|
23369
|
-
return Object.entries(condition).every(([
|
|
23460
|
+
return Object.entries(condition).every(([path55, expected]) => valueMatches(resolveDottedPath2(context, path55), expected));
|
|
23370
23461
|
}
|
|
23371
23462
|
function withWorkflowBoundaryEval(capability, result) {
|
|
23372
23463
|
const capabilityKind = capability.config.capabilityKind;
|
|
@@ -23803,7 +23894,7 @@ function translateOpenAISseToBrain(opts) {
|
|
|
23803
23894
|
|
|
23804
23895
|
// src/servers/brain-serve.ts
|
|
23805
23896
|
import { createServer as createServer2 } from "http";
|
|
23806
|
-
import * as
|
|
23897
|
+
import * as path53 from "path";
|
|
23807
23898
|
|
|
23808
23899
|
// src/chat/loop.ts
|
|
23809
23900
|
init_agent();
|
|
@@ -23811,13 +23902,13 @@ init_agents();
|
|
|
23811
23902
|
init_config();
|
|
23812
23903
|
init_registry();
|
|
23813
23904
|
init_task_artifacts();
|
|
23814
|
-
import * as
|
|
23815
|
-
import * as
|
|
23905
|
+
import * as fs17 from "fs";
|
|
23906
|
+
import * as path18 from "path";
|
|
23816
23907
|
|
|
23817
23908
|
// src/chat/attachments.ts
|
|
23818
23909
|
init_runtimePaths();
|
|
23819
|
-
import * as
|
|
23820
|
-
import * as
|
|
23910
|
+
import * as fs14 from "fs";
|
|
23911
|
+
import * as path15 from "path";
|
|
23821
23912
|
var INLINE_ATTACHMENT_RE = /(?:\[(?:Image|File): ([^\]]*)\]\n)?data:([\w.+-]+\/[\w.+-]+);base64,([A-Za-z0-9+/=]+)/g;
|
|
23822
23913
|
var EXT_BY_MIME = {
|
|
23823
23914
|
"image/png": "png",
|
|
@@ -23850,11 +23941,11 @@ function prepareAttachments(turns, cwd, sessionId) {
|
|
|
23850
23941
|
if (!isImage) return `[File: ${name}]`;
|
|
23851
23942
|
try {
|
|
23852
23943
|
if (!dirEnsured) {
|
|
23853
|
-
|
|
23944
|
+
fs14.mkdirSync(dir, { recursive: true });
|
|
23854
23945
|
dirEnsured = true;
|
|
23855
23946
|
}
|
|
23856
|
-
const filePath =
|
|
23857
|
-
|
|
23947
|
+
const filePath = path15.join(dir, `${imageCounter}.${extFor(mime)}`);
|
|
23948
|
+
fs14.writeFileSync(filePath, Buffer.from(data, "base64"));
|
|
23858
23949
|
imageCounter += 1;
|
|
23859
23950
|
imagePaths.push(filePath);
|
|
23860
23951
|
return `[Image "${name}" is attached \u2014 saved to ${filePath}. Use the Read tool on that exact path to view it.]`;
|
|
@@ -23871,8 +23962,8 @@ function prepareAttachments(turns, cwd, sessionId) {
|
|
|
23871
23962
|
|
|
23872
23963
|
// src/chat/codex-app-server.ts
|
|
23873
23964
|
import { spawn as spawn3 } from "child_process";
|
|
23874
|
-
import * as
|
|
23875
|
-
import * as
|
|
23965
|
+
import * as fs15 from "fs";
|
|
23966
|
+
import * as path16 from "path";
|
|
23876
23967
|
import { createInterface } from "readline";
|
|
23877
23968
|
function codexThreadStartParams(args) {
|
|
23878
23969
|
return {
|
|
@@ -23957,9 +24048,9 @@ var CodexAppServerClient = class {
|
|
|
23957
24048
|
await this.request("thread/resume", { threadId });
|
|
23958
24049
|
}
|
|
23959
24050
|
async runTurn(args) {
|
|
23960
|
-
await new Promise((
|
|
24051
|
+
await new Promise((resolve21, reject) => {
|
|
23961
24052
|
this.process.turnWaiters.set(args.threadId, {
|
|
23962
|
-
resolve:
|
|
24053
|
+
resolve: resolve21,
|
|
23963
24054
|
reject,
|
|
23964
24055
|
onNotification: args.onNotification,
|
|
23965
24056
|
queue: Promise.resolve()
|
|
@@ -23976,8 +24067,8 @@ var CodexAppServerClient = class {
|
|
|
23976
24067
|
}
|
|
23977
24068
|
request(method, params) {
|
|
23978
24069
|
const id = this.process.nextId++;
|
|
23979
|
-
return new Promise((
|
|
23980
|
-
this.process.pending.set(id, { resolve:
|
|
24070
|
+
return new Promise((resolve21, reject) => {
|
|
24071
|
+
this.process.pending.set(id, { resolve: resolve21, reject });
|
|
23981
24072
|
this.process.child.stdin.write(`${JSON.stringify({ method, id, params })}
|
|
23982
24073
|
`);
|
|
23983
24074
|
});
|
|
@@ -24043,11 +24134,11 @@ var CodexAppServerClient = class {
|
|
|
24043
24134
|
};
|
|
24044
24135
|
var clients = /* @__PURE__ */ new Map();
|
|
24045
24136
|
function threadMapPath(cwd) {
|
|
24046
|
-
return
|
|
24137
|
+
return path16.join(cwd, ".kody-engine", "runtime", "codex-threads.json");
|
|
24047
24138
|
}
|
|
24048
24139
|
function readThreadMap(cwd) {
|
|
24049
24140
|
try {
|
|
24050
|
-
const value = JSON.parse(
|
|
24141
|
+
const value = JSON.parse(fs15.readFileSync(threadMapPath(cwd), "utf8"));
|
|
24051
24142
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
24052
24143
|
return Object.fromEntries(
|
|
24053
24144
|
Object.entries(value).filter(
|
|
@@ -24060,8 +24151,8 @@ function readThreadMap(cwd) {
|
|
|
24060
24151
|
}
|
|
24061
24152
|
function writeThreadMap(cwd, map) {
|
|
24062
24153
|
const file = threadMapPath(cwd);
|
|
24063
|
-
|
|
24064
|
-
|
|
24154
|
+
fs15.mkdirSync(path16.dirname(file), { recursive: true });
|
|
24155
|
+
fs15.writeFileSync(file, `${JSON.stringify(map, null, 2)}
|
|
24065
24156
|
`);
|
|
24066
24157
|
}
|
|
24067
24158
|
async function runCodexChatTurn(args) {
|
|
@@ -24151,8 +24242,8 @@ async function runCodexChatTurn(args) {
|
|
|
24151
24242
|
}
|
|
24152
24243
|
|
|
24153
24244
|
// src/chat/events.ts
|
|
24154
|
-
import * as
|
|
24155
|
-
import * as
|
|
24245
|
+
import * as fs16 from "fs";
|
|
24246
|
+
import * as path17 from "path";
|
|
24156
24247
|
import posixPath2 from "path/posix";
|
|
24157
24248
|
var BackendEventSink = class {
|
|
24158
24249
|
constructor(append, tenantId2, sessionId) {
|
|
@@ -24168,7 +24259,7 @@ var BackendEventSink = class {
|
|
|
24168
24259
|
}
|
|
24169
24260
|
};
|
|
24170
24261
|
function eventsFilePath(cwd, sessionId) {
|
|
24171
|
-
return
|
|
24262
|
+
return path17.join(cwd, ".kody-engine", "runtime", "events", `${sessionId}.jsonl`);
|
|
24172
24263
|
}
|
|
24173
24264
|
var FileSink = class {
|
|
24174
24265
|
constructor(file) {
|
|
@@ -24176,8 +24267,8 @@ var FileSink = class {
|
|
|
24176
24267
|
}
|
|
24177
24268
|
file;
|
|
24178
24269
|
async emit(event) {
|
|
24179
|
-
|
|
24180
|
-
|
|
24270
|
+
fs16.mkdirSync(path17.dirname(this.file), { recursive: true });
|
|
24271
|
+
fs16.appendFileSync(this.file, `${JSON.stringify(event)}
|
|
24181
24272
|
`);
|
|
24182
24273
|
}
|
|
24183
24274
|
};
|
|
@@ -24442,7 +24533,7 @@ function buildImplementationCatalog() {
|
|
|
24442
24533
|
const entries = [];
|
|
24443
24534
|
for (const { name, profilePath } of discovered) {
|
|
24444
24535
|
try {
|
|
24445
|
-
const raw = JSON.parse(
|
|
24536
|
+
const raw = JSON.parse(fs17.readFileSync(profilePath, "utf-8"));
|
|
24446
24537
|
const describe = typeof raw.describe === "string" ? raw.describe : "";
|
|
24447
24538
|
const firstSentence = describe.split(/(?<=[.!?])\s+/, 1)[0] ?? "";
|
|
24448
24539
|
entries.push({ name, describe: firstSentence.trim() });
|
|
@@ -24564,7 +24655,7 @@ async function runChatTurn(opts) {
|
|
|
24564
24655
|
quiet: opts.quiet,
|
|
24565
24656
|
additionalDirectories: [
|
|
24566
24657
|
taskArtifactsPaths.absDir,
|
|
24567
|
-
...Array.from(new Set(imagePaths.map((p2) =>
|
|
24658
|
+
...Array.from(new Set(imagePaths.map((p2) => path18.dirname(p2))))
|
|
24568
24659
|
],
|
|
24569
24660
|
systemPromptAppend: systemPrompt,
|
|
24570
24661
|
...opts.reasoningEffort ? { reasoningEffort: opts.reasoningEffort } : {},
|
|
@@ -24752,10 +24843,10 @@ async function emit(sink, type, sessionId, suffix, payload) {
|
|
|
24752
24843
|
var MEMORY_INDEX_REL = ".kody-engine/runtime/memory/INDEX.md";
|
|
24753
24844
|
var MAX_INDEX_BYTES = 8e3;
|
|
24754
24845
|
function readMemoryIndexBlock(cwd) {
|
|
24755
|
-
const indexPath =
|
|
24846
|
+
const indexPath = path18.join(cwd, MEMORY_INDEX_REL);
|
|
24756
24847
|
let raw;
|
|
24757
24848
|
try {
|
|
24758
|
-
raw =
|
|
24849
|
+
raw = fs17.readFileSync(indexPath, "utf-8");
|
|
24759
24850
|
} catch {
|
|
24760
24851
|
return "";
|
|
24761
24852
|
}
|
|
@@ -24775,17 +24866,17 @@ _\u2026 (memory index truncated; use recall_search to read more)_` : trimmed;
|
|
|
24775
24866
|
var CONTEXT_DIR_REL = ".kody-engine/runtime/context";
|
|
24776
24867
|
var MAX_CONTEXT_BYTES = 12e3;
|
|
24777
24868
|
function readContextBlock(cwd) {
|
|
24778
|
-
const dir =
|
|
24869
|
+
const dir = path18.join(cwd, CONTEXT_DIR_REL);
|
|
24779
24870
|
let files;
|
|
24780
24871
|
try {
|
|
24781
|
-
files =
|
|
24872
|
+
files = fs17.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
24782
24873
|
} catch {
|
|
24783
24874
|
return "";
|
|
24784
24875
|
}
|
|
24785
24876
|
const sections = [];
|
|
24786
24877
|
for (const file of files) {
|
|
24787
24878
|
try {
|
|
24788
|
-
const content =
|
|
24879
|
+
const content = fs17.readFileSync(path18.join(dir, file), "utf-8").trim();
|
|
24789
24880
|
if (content) sections.push(`### ${file.replace(/\.md$/, "")}
|
|
24790
24881
|
|
|
24791
24882
|
${content}`);
|
|
@@ -24811,7 +24902,7 @@ var SYSTEM_PROMPT_OVERRIDE_REL = ".kody-engine/runtime/system-prompt.md";
|
|
|
24811
24902
|
function readSystemPromptOverride(cwd) {
|
|
24812
24903
|
let raw;
|
|
24813
24904
|
try {
|
|
24814
|
-
raw =
|
|
24905
|
+
raw = fs17.readFileSync(path18.join(cwd, SYSTEM_PROMPT_OVERRIDE_REL), "utf-8");
|
|
24815
24906
|
} catch {
|
|
24816
24907
|
return null;
|
|
24817
24908
|
}
|
|
@@ -24819,10 +24910,10 @@ function readSystemPromptOverride(cwd) {
|
|
|
24819
24910
|
return trimmed.length > 0 ? trimmed : null;
|
|
24820
24911
|
}
|
|
24821
24912
|
function readInstructionsBlock(cwd) {
|
|
24822
|
-
const instructionsPath =
|
|
24913
|
+
const instructionsPath = path18.join(cwd, INSTRUCTIONS_REL);
|
|
24823
24914
|
let raw;
|
|
24824
24915
|
try {
|
|
24825
|
-
raw =
|
|
24916
|
+
raw = fs17.readFileSync(instructionsPath, "utf-8");
|
|
24826
24917
|
} catch {
|
|
24827
24918
|
return "";
|
|
24828
24919
|
}
|
|
@@ -24856,15 +24947,15 @@ function resolveBrainDriver(runtime) {
|
|
|
24856
24947
|
}
|
|
24857
24948
|
|
|
24858
24949
|
// src/chat/session.ts
|
|
24859
|
-
import * as
|
|
24860
|
-
import * as
|
|
24950
|
+
import * as fs18 from "fs";
|
|
24951
|
+
import * as path19 from "path";
|
|
24861
24952
|
import posixPath3 from "path/posix";
|
|
24862
24953
|
function sessionFilePath(cwd, sessionId) {
|
|
24863
|
-
return
|
|
24954
|
+
return path19.join(cwd, ".kody-engine", "runtime", "sessions", `${sessionId}.jsonl`);
|
|
24864
24955
|
}
|
|
24865
24956
|
function readSession(file) {
|
|
24866
|
-
if (!
|
|
24867
|
-
const raw =
|
|
24957
|
+
if (!fs18.existsSync(file)) return [];
|
|
24958
|
+
const raw = fs18.readFileSync(file, "utf-8").trim();
|
|
24868
24959
|
if (!raw) return [];
|
|
24869
24960
|
const turns = [];
|
|
24870
24961
|
for (const line of raw.split("\n")) {
|
|
@@ -24887,8 +24978,8 @@ init_config();
|
|
|
24887
24978
|
init_state_backend();
|
|
24888
24979
|
init_workflowDefinitions();
|
|
24889
24980
|
import { createHash as createHash2 } from "crypto";
|
|
24890
|
-
import * as
|
|
24891
|
-
import * as
|
|
24981
|
+
import * as fs20 from "fs";
|
|
24982
|
+
import * as path21 from "path";
|
|
24892
24983
|
var SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,127}$/;
|
|
24893
24984
|
var REPOSITORY_OWNED_NAMESPACES = ["loops"];
|
|
24894
24985
|
function assertSafeDefinitionPath(filePath) {
|
|
@@ -24920,9 +25011,9 @@ function verifyDefinition(definition) {
|
|
|
24920
25011
|
}
|
|
24921
25012
|
function writeBundle(root, bundle) {
|
|
24922
25013
|
for (const [filePath, contents] of Object.entries(bundle.files)) {
|
|
24923
|
-
const target =
|
|
24924
|
-
|
|
24925
|
-
|
|
25014
|
+
const target = path21.join(root, filePath);
|
|
25015
|
+
fs20.mkdirSync(path21.dirname(target), { recursive: true });
|
|
25016
|
+
fs20.writeFileSync(target, contents, "utf8");
|
|
24926
25017
|
}
|
|
24927
25018
|
}
|
|
24928
25019
|
function writeDefinition(root, kind, definition) {
|
|
@@ -24930,22 +25021,22 @@ function writeDefinition(root, kind, definition) {
|
|
|
24930
25021
|
if (kind === "agent") {
|
|
24931
25022
|
const raw = bundle.files["agent.md"];
|
|
24932
25023
|
if (typeof raw !== "string") throw new Error(`agent definition ${definition.slug} is missing agent.md`);
|
|
24933
|
-
|
|
25024
|
+
fs20.writeFileSync(path21.join(root, "agents", `${definition.slug}.md`), raw, "utf8");
|
|
24934
25025
|
return;
|
|
24935
25026
|
}
|
|
24936
25027
|
if (kind === "goal") {
|
|
24937
|
-
writeBundle(
|
|
25028
|
+
writeBundle(path21.join(root, "goals", definition.slug), bundle);
|
|
24938
25029
|
return;
|
|
24939
25030
|
}
|
|
24940
25031
|
if (kind === "implementation") {
|
|
24941
|
-
writeBundle(
|
|
25032
|
+
writeBundle(path21.join(root, "implementations", definition.slug), bundle);
|
|
24942
25033
|
return;
|
|
24943
25034
|
}
|
|
24944
25035
|
if (kind === "asset") {
|
|
24945
|
-
writeBundle(
|
|
25036
|
+
writeBundle(path21.join(root, "shared"), bundle);
|
|
24946
25037
|
return;
|
|
24947
25038
|
}
|
|
24948
|
-
writeBundle(
|
|
25039
|
+
writeBundle(path21.join(root, "capabilities", definition.slug), bundle);
|
|
24949
25040
|
}
|
|
24950
25041
|
function writeWorkflow(root, document) {
|
|
24951
25042
|
const workflow = normalizeWorkflowDefinition(document.definition);
|
|
@@ -24953,28 +25044,28 @@ function writeWorkflow(root, document) {
|
|
|
24953
25044
|
const contents = `${JSON.stringify(workflow, null, 2)}
|
|
24954
25045
|
`;
|
|
24955
25046
|
const bundle = { schemaVersion: 1, files: { "workflow.json": contents } };
|
|
24956
|
-
const target =
|
|
24957
|
-
|
|
24958
|
-
|
|
25047
|
+
const target = path21.join(root, workflowDefinitionPath(document.workflowId));
|
|
25048
|
+
fs20.mkdirSync(path21.dirname(target), { recursive: true });
|
|
25049
|
+
fs20.writeFileSync(target, contents, "utf8");
|
|
24959
25050
|
return definitionVersion(bundle);
|
|
24960
25051
|
}
|
|
24961
25052
|
function preserveRepositoryDefinitions(root, staging) {
|
|
24962
25053
|
for (const namespace of REPOSITORY_OWNED_NAMESPACES) {
|
|
24963
|
-
const source =
|
|
24964
|
-
if (!
|
|
24965
|
-
|
|
25054
|
+
const source = path21.join(root, namespace);
|
|
25055
|
+
if (!fs20.existsSync(source)) continue;
|
|
25056
|
+
fs20.cpSync(source, path21.join(staging, namespace), { recursive: true });
|
|
24966
25057
|
}
|
|
24967
25058
|
}
|
|
24968
25059
|
async function hydrateDefinitions(options) {
|
|
24969
|
-
const root =
|
|
25060
|
+
const root = path21.join(options.cwd, ".kody-engine", "definitions");
|
|
24970
25061
|
const staging = `${root}.tmp-${process.pid}-${Date.now()}`;
|
|
24971
|
-
|
|
24972
|
-
|
|
24973
|
-
|
|
24974
|
-
|
|
24975
|
-
|
|
24976
|
-
|
|
24977
|
-
|
|
25062
|
+
fs20.rmSync(staging, { recursive: true, force: true });
|
|
25063
|
+
fs20.mkdirSync(path21.join(staging, "agents"), { recursive: true });
|
|
25064
|
+
fs20.mkdirSync(path21.join(staging, "capabilities"), { recursive: true });
|
|
25065
|
+
fs20.mkdirSync(path21.join(staging, "goals"), { recursive: true });
|
|
25066
|
+
fs20.mkdirSync(path21.join(staging, "implementations"), { recursive: true });
|
|
25067
|
+
fs20.mkdirSync(path21.join(staging, "shared"), { recursive: true });
|
|
25068
|
+
fs20.mkdirSync(path21.join(staging, "workflows"), { recursive: true });
|
|
24978
25069
|
try {
|
|
24979
25070
|
const [capabilities, agents, goals, implementations, assets, workflows] = await Promise.all([
|
|
24980
25071
|
options.backend.listDefinitions(options.tenantId, "capability"),
|
|
@@ -25015,13 +25106,13 @@ async function hydrateDefinitions(options) {
|
|
|
25015
25106
|
hydratedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25016
25107
|
versions: Object.fromEntries(Object.entries(versions).sort(([left], [right]) => left.localeCompare(right)))
|
|
25017
25108
|
};
|
|
25018
|
-
|
|
25109
|
+
fs20.writeFileSync(path21.join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
25019
25110
|
`, "utf8");
|
|
25020
|
-
|
|
25021
|
-
|
|
25111
|
+
fs20.rmSync(root, { recursive: true, force: true });
|
|
25112
|
+
fs20.renameSync(staging, root);
|
|
25022
25113
|
return { root, tenantId: options.tenantId, versions: manifest.versions };
|
|
25023
25114
|
} catch (error) {
|
|
25024
|
-
|
|
25115
|
+
fs20.rmSync(staging, { recursive: true, force: true });
|
|
25025
25116
|
throw error;
|
|
25026
25117
|
}
|
|
25027
25118
|
}
|
|
@@ -25043,8 +25134,8 @@ async function hydrateDefinitionsFromEnv(cwd = process.cwd(), env = process.env)
|
|
|
25043
25134
|
|
|
25044
25135
|
// src/kody-cli.ts
|
|
25045
25136
|
import { execFileSync as execFileSync24 } from "child_process";
|
|
25046
|
-
import * as
|
|
25047
|
-
import * as
|
|
25137
|
+
import * as fs54 from "fs";
|
|
25138
|
+
import * as path51 from "path";
|
|
25048
25139
|
|
|
25049
25140
|
// src/app-auth.ts
|
|
25050
25141
|
import { createSign } from "crypto";
|
|
@@ -25173,7 +25264,7 @@ init_definition_paths();
|
|
|
25173
25264
|
|
|
25174
25265
|
// src/dispatch.ts
|
|
25175
25266
|
init_config();
|
|
25176
|
-
import * as
|
|
25267
|
+
import * as fs21 from "fs";
|
|
25177
25268
|
|
|
25178
25269
|
// src/cron-match.ts
|
|
25179
25270
|
var FIELD_BOUNDS = [
|
|
@@ -25280,10 +25371,10 @@ function autoDispatch(opts) {
|
|
|
25280
25371
|
}
|
|
25281
25372
|
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
25282
25373
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
25283
|
-
if (!eventName || !eventPath || !
|
|
25374
|
+
if (!eventName || !eventPath || !fs21.existsSync(eventPath)) return null;
|
|
25284
25375
|
let event = {};
|
|
25285
25376
|
try {
|
|
25286
|
-
event = JSON.parse(
|
|
25377
|
+
event = JSON.parse(fs21.readFileSync(eventPath, "utf-8"));
|
|
25287
25378
|
} catch {
|
|
25288
25379
|
return null;
|
|
25289
25380
|
}
|
|
@@ -25407,7 +25498,7 @@ function autoDispatchTyped(opts) {
|
|
|
25407
25498
|
if (legacy) return { kind: "route", ...legacy };
|
|
25408
25499
|
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
25409
25500
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
25410
|
-
if (!eventName || !eventPath || !
|
|
25501
|
+
if (!eventName || !eventPath || !fs21.existsSync(eventPath)) {
|
|
25411
25502
|
return { kind: "silent", reason: "no GHA event context" };
|
|
25412
25503
|
}
|
|
25413
25504
|
if (eventName !== "issue_comment") {
|
|
@@ -25415,7 +25506,7 @@ function autoDispatchTyped(opts) {
|
|
|
25415
25506
|
}
|
|
25416
25507
|
let event = {};
|
|
25417
25508
|
try {
|
|
25418
|
-
event = JSON.parse(
|
|
25509
|
+
event = JSON.parse(fs21.readFileSync(eventPath, "utf-8"));
|
|
25419
25510
|
} catch {
|
|
25420
25511
|
return { kind: "silent", reason: "GHA event payload unreadable" };
|
|
25421
25512
|
}
|
|
@@ -25469,7 +25560,7 @@ function dispatchScheduledWatches(opts) {
|
|
|
25469
25560
|
for (const exe of listRuntimeProfilesForCwd(opts?.cwd ?? process.cwd())) {
|
|
25470
25561
|
let raw;
|
|
25471
25562
|
try {
|
|
25472
|
-
raw =
|
|
25563
|
+
raw = fs21.readFileSync(exe.profilePath, "utf-8");
|
|
25473
25564
|
} catch {
|
|
25474
25565
|
continue;
|
|
25475
25566
|
}
|
|
@@ -25846,9 +25937,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
25846
25937
|
return void 0;
|
|
25847
25938
|
}
|
|
25848
25939
|
function detectPackageManager2(cwd) {
|
|
25849
|
-
if (
|
|
25850
|
-
if (
|
|
25851
|
-
if (
|
|
25940
|
+
if (fs54.existsSync(path51.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
25941
|
+
if (fs54.existsSync(path51.join(cwd, "yarn.lock"))) return "yarn";
|
|
25942
|
+
if (fs54.existsSync(path51.join(cwd, "bun.lockb"))) return "bun";
|
|
25852
25943
|
return "npm";
|
|
25853
25944
|
}
|
|
25854
25945
|
function shouldChainScheduledWatch(match) {
|
|
@@ -25951,8 +26042,8 @@ function postFailureTail(issueNumber, cwd, reason) {
|
|
|
25951
26042
|
const logPath = lastRunLogPath(cwd);
|
|
25952
26043
|
let tail = "";
|
|
25953
26044
|
try {
|
|
25954
|
-
if (
|
|
25955
|
-
const content =
|
|
26045
|
+
if (fs54.existsSync(logPath)) {
|
|
26046
|
+
const content = fs54.readFileSync(logPath, "utf-8");
|
|
25956
26047
|
tail = content.slice(-3e3);
|
|
25957
26048
|
}
|
|
25958
26049
|
} catch {
|
|
@@ -25981,7 +26072,7 @@ async function runCi(argv) {
|
|
|
25981
26072
|
return 0;
|
|
25982
26073
|
}
|
|
25983
26074
|
const args = parseCiArgs(argv);
|
|
25984
|
-
const cwd = args.cwd ?
|
|
26075
|
+
const cwd = args.cwd ? path51.resolve(args.cwd) : process.cwd();
|
|
25985
26076
|
try {
|
|
25986
26077
|
const n = unpackAllSecrets();
|
|
25987
26078
|
if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s) from ALL_SECRETS
|
|
@@ -26047,9 +26138,9 @@ async function runCi(argv) {
|
|
|
26047
26138
|
forceRunCliArgs = { goal: envForceMessage };
|
|
26048
26139
|
}
|
|
26049
26140
|
}
|
|
26050
|
-
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath &&
|
|
26141
|
+
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs54.existsSync(dispatchEventPath)) {
|
|
26051
26142
|
try {
|
|
26052
|
-
const evt = JSON.parse(
|
|
26143
|
+
const evt = JSON.parse(fs54.readFileSync(dispatchEventPath, "utf-8"));
|
|
26053
26144
|
const inputs = objectValue2(evt.inputs);
|
|
26054
26145
|
const issueInput = parseInt(String(inputs?.issue_number ?? ""), 10);
|
|
26055
26146
|
const sessionInput = String(inputs?.sessionId ?? "");
|
|
@@ -26464,8 +26555,8 @@ init_repoWorkspace();
|
|
|
26464
26555
|
|
|
26465
26556
|
// src/scripts/brainTurnLog.ts
|
|
26466
26557
|
init_runtimePaths();
|
|
26467
|
-
import * as
|
|
26468
|
-
import * as
|
|
26558
|
+
import * as fs55 from "fs";
|
|
26559
|
+
import * as path52 from "path";
|
|
26469
26560
|
import posixPath4 from "path/posix";
|
|
26470
26561
|
var live = /* @__PURE__ */ new Map();
|
|
26471
26562
|
function brainEventsFilePath(dir, chatId) {
|
|
@@ -26473,8 +26564,8 @@ function brainEventsFilePath(dir, chatId) {
|
|
|
26473
26564
|
}
|
|
26474
26565
|
function lastPersistedSeq(dir, chatId) {
|
|
26475
26566
|
const p = brainEventsFilePath(dir, chatId);
|
|
26476
|
-
if (!
|
|
26477
|
-
const lines =
|
|
26567
|
+
if (!fs55.existsSync(p)) return 0;
|
|
26568
|
+
const lines = fs55.readFileSync(p, "utf-8").split("\n").filter(Boolean);
|
|
26478
26569
|
if (lines.length === 0) return 0;
|
|
26479
26570
|
try {
|
|
26480
26571
|
return JSON.parse(lines[lines.length - 1]).seq || 0;
|
|
@@ -26484,9 +26575,9 @@ function lastPersistedSeq(dir, chatId) {
|
|
|
26484
26575
|
}
|
|
26485
26576
|
function readSince(dir, chatId, since) {
|
|
26486
26577
|
const p = brainEventsFilePath(dir, chatId);
|
|
26487
|
-
if (!
|
|
26578
|
+
if (!fs55.existsSync(p)) return [];
|
|
26488
26579
|
const out = [];
|
|
26489
|
-
for (const line of
|
|
26580
|
+
for (const line of fs55.readFileSync(p, "utf-8").split("\n")) {
|
|
26490
26581
|
if (!line) continue;
|
|
26491
26582
|
try {
|
|
26492
26583
|
const rec = JSON.parse(line);
|
|
@@ -26512,12 +26603,12 @@ function beginTurn(dir, chatId) {
|
|
|
26512
26603
|
};
|
|
26513
26604
|
live.set(chatId, state);
|
|
26514
26605
|
const p = brainEventsFilePath(dir, chatId);
|
|
26515
|
-
|
|
26606
|
+
fs55.mkdirSync(path52.dirname(p), { recursive: true });
|
|
26516
26607
|
return (event) => {
|
|
26517
26608
|
state.seq += 1;
|
|
26518
26609
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
26519
26610
|
try {
|
|
26520
|
-
|
|
26611
|
+
fs55.appendFileSync(p, `${JSON.stringify(rec)}
|
|
26521
26612
|
`);
|
|
26522
26613
|
} catch (err) {
|
|
26523
26614
|
process.stderr.write(
|
|
@@ -26556,7 +26647,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
|
|
|
26556
26647
|
event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
|
|
26557
26648
|
};
|
|
26558
26649
|
try {
|
|
26559
|
-
|
|
26650
|
+
fs55.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
|
|
26560
26651
|
`);
|
|
26561
26652
|
} catch {
|
|
26562
26653
|
}
|
|
@@ -26650,17 +26741,17 @@ function authOk(req, expected) {
|
|
|
26650
26741
|
return false;
|
|
26651
26742
|
}
|
|
26652
26743
|
function readJsonBody(req) {
|
|
26653
|
-
return new Promise((
|
|
26744
|
+
return new Promise((resolve21, reject) => {
|
|
26654
26745
|
const chunks = [];
|
|
26655
26746
|
req.on("data", (c) => chunks.push(c));
|
|
26656
26747
|
req.on("end", () => {
|
|
26657
26748
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
26658
26749
|
if (!raw.trim()) {
|
|
26659
|
-
|
|
26750
|
+
resolve21({});
|
|
26660
26751
|
return;
|
|
26661
26752
|
}
|
|
26662
26753
|
try {
|
|
26663
|
-
|
|
26754
|
+
resolve21(JSON.parse(raw));
|
|
26664
26755
|
} catch (err) {
|
|
26665
26756
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
26666
26757
|
}
|
|
@@ -26952,7 +27043,7 @@ function buildServer(opts) {
|
|
|
26952
27043
|
const runTurn = opts.runTurn ?? runChatTurn;
|
|
26953
27044
|
const createStore = opts.createStore ?? createSessionStore;
|
|
26954
27045
|
const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
|
|
26955
|
-
const reposRoot = opts.reposRoot ??
|
|
27046
|
+
const reposRoot = opts.reposRoot ?? path53.join(path53.dirname(path53.resolve(opts.cwd)), "repos");
|
|
26956
27047
|
return createServer2(async (req, res) => {
|
|
26957
27048
|
if (!req.method || !req.url) {
|
|
26958
27049
|
sendJson(res, 400, { error: "bad request" });
|
|
@@ -27033,11 +27124,11 @@ async function brainServe(opts) {
|
|
|
27033
27124
|
litellmUrl,
|
|
27034
27125
|
driver
|
|
27035
27126
|
});
|
|
27036
|
-
await new Promise((
|
|
27127
|
+
await new Promise((resolve21) => {
|
|
27037
27128
|
server.listen(port, "0.0.0.0", () => {
|
|
27038
27129
|
process.stdout.write(`[brain-serve] listening on 0.0.0.0:${port} (cwd=${opts.cwd})
|
|
27039
27130
|
`);
|
|
27040
|
-
|
|
27131
|
+
resolve21();
|
|
27041
27132
|
});
|
|
27042
27133
|
});
|
|
27043
27134
|
const shutdown = (signal) => {
|
|
@@ -27292,14 +27383,14 @@ async function startBrainProxy(opts) {
|
|
|
27292
27383
|
const { httpServer, handler } = buildBrainProxy(opts);
|
|
27293
27384
|
const port = opts.port ?? 0;
|
|
27294
27385
|
const host = opts.host ?? "127.0.0.1";
|
|
27295
|
-
await new Promise((
|
|
27386
|
+
await new Promise((resolve21) => httpServer.listen(port, host, () => resolve21()));
|
|
27296
27387
|
const addr = httpServer.address();
|
|
27297
27388
|
return {
|
|
27298
27389
|
httpServer,
|
|
27299
27390
|
port: addr.port,
|
|
27300
27391
|
url: `http://${host}:${addr.port}`,
|
|
27301
|
-
stop: () => new Promise((
|
|
27302
|
-
httpServer.close(() =>
|
|
27392
|
+
stop: () => new Promise((resolve21) => {
|
|
27393
|
+
httpServer.close(() => resolve21());
|
|
27303
27394
|
}),
|
|
27304
27395
|
handler
|
|
27305
27396
|
};
|
|
@@ -27449,23 +27540,23 @@ function buildMcpHttpServer(opts) {
|
|
|
27449
27540
|
httpServer,
|
|
27450
27541
|
routes,
|
|
27451
27542
|
port,
|
|
27452
|
-
stop: () => new Promise((
|
|
27543
|
+
stop: () => new Promise((resolve21) => {
|
|
27453
27544
|
let pending = transports.size;
|
|
27454
27545
|
if (pending === 0) {
|
|
27455
|
-
httpServer.close(() =>
|
|
27546
|
+
httpServer.close(() => resolve21());
|
|
27456
27547
|
return;
|
|
27457
27548
|
}
|
|
27458
27549
|
for (const transport of transports.values()) {
|
|
27459
27550
|
void transport.close().finally(() => {
|
|
27460
27551
|
pending--;
|
|
27461
|
-
if (pending === 0) httpServer.close(() =>
|
|
27552
|
+
if (pending === 0) httpServer.close(() => resolve21());
|
|
27462
27553
|
});
|
|
27463
27554
|
}
|
|
27464
27555
|
})
|
|
27465
27556
|
};
|
|
27466
27557
|
}
|
|
27467
27558
|
function listenMcpHttpServer(server, host = "127.0.0.1") {
|
|
27468
|
-
return new Promise((
|
|
27559
|
+
return new Promise((resolve21, reject) => {
|
|
27469
27560
|
server.httpServer.once("error", reject);
|
|
27470
27561
|
server.httpServer.listen(server.port, host, () => {
|
|
27471
27562
|
server.httpServer.off("error", reject);
|
|
@@ -27473,7 +27564,7 @@ function listenMcpHttpServer(server, host = "127.0.0.1") {
|
|
|
27473
27564
|
if (addr && typeof addr === "object") {
|
|
27474
27565
|
server.port = addr.port;
|
|
27475
27566
|
}
|
|
27476
|
-
|
|
27567
|
+
resolve21();
|
|
27477
27568
|
});
|
|
27478
27569
|
});
|
|
27479
27570
|
}
|
|
@@ -27556,7 +27647,7 @@ async function loadConfigSafe() {
|
|
|
27556
27647
|
}
|
|
27557
27648
|
|
|
27558
27649
|
// src/chat-cli.ts
|
|
27559
|
-
import * as
|
|
27650
|
+
import * as path54 from "path";
|
|
27560
27651
|
|
|
27561
27652
|
// src/chat/inbox.ts
|
|
27562
27653
|
import { execFileSync as execFileSync25 } from "child_process";
|
|
@@ -27623,7 +27714,7 @@ async function waitForNextUserMessage(opts) {
|
|
|
27623
27714
|
}
|
|
27624
27715
|
}
|
|
27625
27716
|
function sleep3(ms) {
|
|
27626
|
-
return new Promise((
|
|
27717
|
+
return new Promise((resolve21) => setTimeout(resolve21, ms));
|
|
27627
27718
|
}
|
|
27628
27719
|
function currentBranch(cwd) {
|
|
27629
27720
|
try {
|
|
@@ -27847,7 +27938,7 @@ async function runChat(argv) {
|
|
|
27847
27938
|
${CHAT_HELP}`);
|
|
27848
27939
|
return 64;
|
|
27849
27940
|
}
|
|
27850
|
-
const cwd = args.cwd ?
|
|
27941
|
+
const cwd = args.cwd ? path54.resolve(args.cwd) : process.cwd();
|
|
27851
27942
|
const sessionId = args.sessionId;
|
|
27852
27943
|
const runRequest = readRunRequestFromEnv();
|
|
27853
27944
|
if (runRequest && "request" in runRequest) {
|
|
@@ -28043,8 +28134,8 @@ var FlyClient = class {
|
|
|
28043
28134
|
get fetch() {
|
|
28044
28135
|
return this.opts.fetchImpl ?? fetch;
|
|
28045
28136
|
}
|
|
28046
|
-
async call(
|
|
28047
|
-
const res = await this.fetch(`${FLY_API_BASE}${
|
|
28137
|
+
async call(path55, init = {}) {
|
|
28138
|
+
const res = await this.fetch(`${FLY_API_BASE}${path55}`, {
|
|
28048
28139
|
method: init.method ?? "GET",
|
|
28049
28140
|
headers: {
|
|
28050
28141
|
Authorization: `Bearer ${this.opts.token}`,
|
|
@@ -28055,7 +28146,7 @@ var FlyClient = class {
|
|
|
28055
28146
|
if (res.status === 404 && init.allow404) return null;
|
|
28056
28147
|
if (!res.ok) {
|
|
28057
28148
|
const text2 = await res.text().catch(() => "");
|
|
28058
|
-
throw new Error(`Fly API ${res.status} on ${
|
|
28149
|
+
throw new Error(`Fly API ${res.status} on ${path55}: ${text2.slice(0, 200) || res.statusText}`);
|
|
28059
28150
|
}
|
|
28060
28151
|
if (res.status === 204) return null;
|
|
28061
28152
|
const raw = await res.text();
|
|
@@ -28568,14 +28659,14 @@ function sendJson2(res, status, body) {
|
|
|
28568
28659
|
res.end(JSON.stringify(body));
|
|
28569
28660
|
}
|
|
28570
28661
|
function readJsonBody2(req) {
|
|
28571
|
-
return new Promise((
|
|
28662
|
+
return new Promise((resolve21, reject) => {
|
|
28572
28663
|
const chunks = [];
|
|
28573
28664
|
req.on("data", (c) => chunks.push(c));
|
|
28574
28665
|
req.on("end", () => {
|
|
28575
28666
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
28576
|
-
if (!raw.trim()) return
|
|
28667
|
+
if (!raw.trim()) return resolve21({});
|
|
28577
28668
|
try {
|
|
28578
|
-
|
|
28669
|
+
resolve21(JSON.parse(raw));
|
|
28579
28670
|
} catch (err) {
|
|
28580
28671
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
28581
28672
|
}
|
|
@@ -28729,10 +28820,10 @@ async function poolServe() {
|
|
|
28729
28820
|
}
|
|
28730
28821
|
});
|
|
28731
28822
|
const apiHost = process.env.POOL_API_HOST ?? "::";
|
|
28732
|
-
await new Promise((
|
|
28823
|
+
await new Promise((resolve21) => {
|
|
28733
28824
|
server.listen(apiPort, apiHost, () => {
|
|
28734
28825
|
log(`listening on ${apiHost}:${apiPort} (min=${min}, app=${app}, region=${region})`);
|
|
28735
|
-
|
|
28826
|
+
resolve21();
|
|
28736
28827
|
});
|
|
28737
28828
|
});
|
|
28738
28829
|
if (loopTickEnabled) void runLoopTick();
|
|
@@ -28751,7 +28842,7 @@ async function poolServe() {
|
|
|
28751
28842
|
|
|
28752
28843
|
// src/servers/runner-serve.ts
|
|
28753
28844
|
import { spawn as spawn9 } from "child_process";
|
|
28754
|
-
import * as
|
|
28845
|
+
import * as fs56 from "fs";
|
|
28755
28846
|
import { createServer as createServer6 } from "http";
|
|
28756
28847
|
var DEFAULT_PORT2 = 8080;
|
|
28757
28848
|
var DEFAULT_WORKDIR = "/workspace/repo";
|
|
@@ -28772,17 +28863,17 @@ function authOk2(req, expected) {
|
|
|
28772
28863
|
return false;
|
|
28773
28864
|
}
|
|
28774
28865
|
function readJsonBody3(req) {
|
|
28775
|
-
return new Promise((
|
|
28866
|
+
return new Promise((resolve21, reject) => {
|
|
28776
28867
|
const chunks = [];
|
|
28777
28868
|
req.on("data", (c) => chunks.push(c));
|
|
28778
28869
|
req.on("end", () => {
|
|
28779
28870
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
28780
28871
|
if (!raw.trim()) {
|
|
28781
|
-
|
|
28872
|
+
resolve21({});
|
|
28782
28873
|
return;
|
|
28783
28874
|
}
|
|
28784
28875
|
try {
|
|
28785
|
-
|
|
28876
|
+
resolve21(JSON.parse(raw));
|
|
28786
28877
|
} catch (err) {
|
|
28787
28878
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
28788
28879
|
}
|
|
@@ -28827,8 +28918,8 @@ async function defaultRunJob(job) {
|
|
|
28827
28918
|
const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
|
|
28828
28919
|
const branch = job.ref ?? "main";
|
|
28829
28920
|
const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
|
|
28830
|
-
|
|
28831
|
-
|
|
28921
|
+
fs56.rmSync(workdir, { recursive: true, force: true });
|
|
28922
|
+
fs56.mkdirSync(workdir, { recursive: true });
|
|
28832
28923
|
const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
|
|
28833
28924
|
const target = job.runRequest.target;
|
|
28834
28925
|
const interactive = target.type === "chat";
|
|
@@ -28857,13 +28948,13 @@ async function defaultRunJob(job) {
|
|
|
28857
28948
|
...interactive && job.idleExitMs ? { KODY_IDLE_EXIT_MS: String(job.idleExitMs) } : {},
|
|
28858
28949
|
...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
|
|
28859
28950
|
};
|
|
28860
|
-
const run = (cmd, args, cwd) => new Promise((
|
|
28951
|
+
const run = (cmd, args, cwd) => new Promise((resolve21) => {
|
|
28861
28952
|
const child = spawn9(cmd, args, { stdio: "inherit", env: childEnv, cwd });
|
|
28862
|
-
child.on("exit", (code) =>
|
|
28953
|
+
child.on("exit", (code) => resolve21(code ?? 0));
|
|
28863
28954
|
child.on("error", (err) => {
|
|
28864
28955
|
process.stderr.write(`[runner-serve] ${cmd} failed: ${err.message}
|
|
28865
28956
|
`);
|
|
28866
|
-
|
|
28957
|
+
resolve21(1);
|
|
28867
28958
|
});
|
|
28868
28959
|
});
|
|
28869
28960
|
process.stdout.write(`[runner-serve] job ${job.jobId}: cloning ${job.repo}@${branch}
|
|
@@ -28939,11 +29030,11 @@ async function runnerServe() {
|
|
|
28939
29030
|
const port = Number(process.env.PORT ?? DEFAULT_PORT2);
|
|
28940
29031
|
const server = buildServer2({ apiKey });
|
|
28941
29032
|
const host = process.env.RUNNER_HOST ?? "::";
|
|
28942
|
-
await new Promise((
|
|
29033
|
+
await new Promise((resolve21) => {
|
|
28943
29034
|
server.listen(port, host, () => {
|
|
28944
29035
|
process.stdout.write(`[runner-serve] listening on ${host}:${port} (idle, awaiting job)
|
|
28945
29036
|
`);
|
|
28946
|
-
|
|
29037
|
+
resolve21();
|
|
28947
29038
|
});
|
|
28948
29039
|
});
|
|
28949
29040
|
const shutdown = (signal) => {
|
|
@@ -29012,14 +29103,14 @@ async function serve(opts) {
|
|
|
29012
29103
|
`);
|
|
29013
29104
|
const args = ["--dangerously-skip-permissions", "--model", model.model];
|
|
29014
29105
|
const child = spawn10("claude", args, { stdio: "inherit", env: editorEnv, cwd: opts.cwd });
|
|
29015
|
-
const exitCode = await new Promise((
|
|
29016
|
-
child.on("exit", (code) =>
|
|
29106
|
+
const exitCode = await new Promise((resolve21) => {
|
|
29107
|
+
child.on("exit", (code) => resolve21(code ?? 0));
|
|
29017
29108
|
child.on("error", (err) => {
|
|
29018
29109
|
process.stderr.write(`[kody serve] failed to launch Claude Code: ${err.message}
|
|
29019
29110
|
`);
|
|
29020
29111
|
process.stderr.write(` Install: https://docs.anthropic.com/claude/docs/claude-code
|
|
29021
29112
|
`);
|
|
29022
|
-
|
|
29113
|
+
resolve21(1);
|
|
29023
29114
|
});
|
|
29024
29115
|
});
|
|
29025
29116
|
killProxy();
|