@kody-ade/kody-engine 0.4.571 → 0.4.573
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 +458 -421
- 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.573",
|
|
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",
|
|
@@ -151,17 +151,23 @@ var init_claudeBinary = __esm({
|
|
|
151
151
|
});
|
|
152
152
|
|
|
153
153
|
// src/completionGuard.ts
|
|
154
|
+
import * as path2 from "path";
|
|
154
155
|
function completionToolCutoffAt(startedAtMs, deadlineAtMs) {
|
|
155
156
|
const availableMs = Math.max(0, deadlineAtMs - startedAtMs);
|
|
156
|
-
const reserveMs = Math.min(MAX_COMPLETION_RESERVE_MS, Math.floor(availableMs /
|
|
157
|
+
const reserveMs = Math.min(MAX_COMPLETION_RESERVE_MS, Math.floor(availableMs / 2));
|
|
157
158
|
return deadlineAtMs - reserveMs;
|
|
158
159
|
}
|
|
159
|
-
function createCompletionToolGuard(cutoffAtMs, now = Date.now) {
|
|
160
|
-
return async () => {
|
|
160
|
+
function createCompletionToolGuard(cutoffAtMs, now = Date.now, requiredOutputPath) {
|
|
161
|
+
return async (input) => {
|
|
161
162
|
if (now() < cutoffAtMs) return {};
|
|
163
|
+
const toolInput = input?.tool_input;
|
|
164
|
+
const filePath = toolInput && typeof toolInput === "object" && !Array.isArray(toolInput) ? toolInput.file_path : void 0;
|
|
165
|
+
if (requiredOutputPath && input?.tool_name === "Write" && typeof filePath === "string" && path2.resolve(filePath) === path2.resolve(requiredOutputPath)) {
|
|
166
|
+
return {};
|
|
167
|
+
}
|
|
162
168
|
return {
|
|
163
169
|
decision: "block",
|
|
164
|
-
reason: "The run has entered its reserved completion window. Do not call more tools. Use the evidence and changes already present, state any verification limits clearly, and return your final response now."
|
|
170
|
+
reason: "The run has entered its reserved completion window. Do not call more tools. " + (requiredOutputPath ? `If the required structured result is missing, write only ${requiredOutputPath}. ` : "") + "Use the evidence and changes already present, state any verification limits clearly, and return your final response now."
|
|
165
171
|
};
|
|
166
172
|
};
|
|
167
173
|
}
|
|
@@ -169,13 +175,13 @@ var MAX_COMPLETION_RESERVE_MS;
|
|
|
169
175
|
var init_completionGuard = __esm({
|
|
170
176
|
"src/completionGuard.ts"() {
|
|
171
177
|
"use strict";
|
|
172
|
-
MAX_COMPLETION_RESERVE_MS =
|
|
178
|
+
MAX_COMPLETION_RESERVE_MS = 15 * 6e4;
|
|
173
179
|
}
|
|
174
180
|
});
|
|
175
181
|
|
|
176
182
|
// src/config.ts
|
|
177
183
|
import * as fs2 from "fs";
|
|
178
|
-
import * as
|
|
184
|
+
import * as path3 from "path";
|
|
179
185
|
function parseReasoningEffort(raw) {
|
|
180
186
|
if (!raw) return null;
|
|
181
187
|
const v = raw.trim().toLowerCase();
|
|
@@ -240,7 +246,7 @@ function needsLitellmProxy(model) {
|
|
|
240
246
|
return model.provider !== "claude" && model.provider !== "anthropic";
|
|
241
247
|
}
|
|
242
248
|
function loadConfig(projectDir = process.cwd()) {
|
|
243
|
-
const configPath =
|
|
249
|
+
const configPath = path3.join(projectDir, "kody.config.json");
|
|
244
250
|
if (!fs2.existsSync(configPath)) {
|
|
245
251
|
throw new Error(`kody.config.json not found at ${configPath}`);
|
|
246
252
|
}
|
|
@@ -573,15 +579,15 @@ var init_config = __esm({
|
|
|
573
579
|
|
|
574
580
|
// src/fileEditGuards.ts
|
|
575
581
|
import * as fs3 from "fs";
|
|
576
|
-
import * as
|
|
582
|
+
import * as path4 from "path";
|
|
577
583
|
function createMissingParentWriteGuard(cwd) {
|
|
578
584
|
return async (input) => {
|
|
579
585
|
const toolInput = input.tool_input;
|
|
580
586
|
if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return {};
|
|
581
587
|
const filePath = toolInput.file_path;
|
|
582
588
|
if (typeof filePath !== "string" || filePath.length === 0) return {};
|
|
583
|
-
const resolvedPath =
|
|
584
|
-
if (fs3.existsSync(
|
|
589
|
+
const resolvedPath = path4.resolve(cwd, filePath);
|
|
590
|
+
if (fs3.existsSync(path4.dirname(resolvedPath))) return {};
|
|
585
591
|
return {
|
|
586
592
|
decision: "block",
|
|
587
593
|
reason: `Cannot write ${resolvedPath}: its parent directory does not exist. Locate and edit the real repository source path first. If this task genuinely requires a new directory, create that directory explicitly before writing the file.`
|
|
@@ -788,7 +794,7 @@ var init_capability_contract_validation = __esm({
|
|
|
788
794
|
|
|
789
795
|
// src/outputContractHooks.ts
|
|
790
796
|
import * as fs4 from "fs";
|
|
791
|
-
import * as
|
|
797
|
+
import * as path5 from "path";
|
|
792
798
|
function outputContractError(contract) {
|
|
793
799
|
let value;
|
|
794
800
|
try {
|
|
@@ -807,12 +813,12 @@ function correctionMessage(contract, error) {
|
|
|
807
813
|
return `The authoritative output does not match its required contract: ${error}. Please overwrite ${contract.path} with only the required JSON shape before finishing.`;
|
|
808
814
|
}
|
|
809
815
|
function createOutputContractPostWriteHook(contract) {
|
|
810
|
-
const expectedPath =
|
|
816
|
+
const expectedPath = path5.resolve(contract.path);
|
|
811
817
|
return async (input) => {
|
|
812
818
|
const toolInput = input.tool_input;
|
|
813
819
|
if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return {};
|
|
814
820
|
const filePath = toolInput.file_path;
|
|
815
|
-
if (typeof filePath !== "string" ||
|
|
821
|
+
if (typeof filePath !== "string" || path5.resolve(filePath) !== expectedPath) return {};
|
|
816
822
|
const error = outputContractError(contract);
|
|
817
823
|
if (!error) return {};
|
|
818
824
|
return {
|
|
@@ -856,21 +862,21 @@ __export(runtimePaths_exports, {
|
|
|
856
862
|
});
|
|
857
863
|
import { createHash } from "crypto";
|
|
858
864
|
import * as os2 from "os";
|
|
859
|
-
import * as
|
|
865
|
+
import * as path6 from "path";
|
|
860
866
|
function runtimeDirForCwd(cwd, ...parts) {
|
|
861
|
-
const key = createHash("sha256").update(
|
|
862
|
-
return
|
|
867
|
+
const key = createHash("sha256").update(path6.resolve(cwd)).digest("hex").slice(0, 16);
|
|
868
|
+
return path6.join(os2.tmpdir(), "kody-engine", key, ...parts);
|
|
863
869
|
}
|
|
864
870
|
function runtimeStatePath(cwd, ...parts) {
|
|
865
871
|
const configuredRoot = process.env.KODY_RUNTIME_DIR?.trim();
|
|
866
|
-
const base = configuredRoot ?
|
|
867
|
-
return
|
|
872
|
+
const base = configuredRoot ? path6.resolve(configuredRoot) : runtimeDirForCwd(cwd);
|
|
873
|
+
return path6.join(base, ...parts);
|
|
868
874
|
}
|
|
869
875
|
function agentRunDir(cwd) {
|
|
870
876
|
return runtimeStatePath(cwd, "agent-runs");
|
|
871
877
|
}
|
|
872
878
|
function lastRunLogPath(cwd) {
|
|
873
|
-
return
|
|
879
|
+
return path6.join(agentRunDir(cwd), "last-run.jsonl");
|
|
874
880
|
}
|
|
875
881
|
var init_runtimePaths = __esm({
|
|
876
882
|
"src/runtimePaths.ts"() {
|
|
@@ -881,15 +887,15 @@ var init_runtimePaths = __esm({
|
|
|
881
887
|
// src/scripts/buildSyntheticPlugin.ts
|
|
882
888
|
import * as fs5 from "fs";
|
|
883
889
|
import * as os3 from "os";
|
|
884
|
-
import * as
|
|
890
|
+
import * as path7 from "path";
|
|
885
891
|
function getPluginsCatalogRoot() {
|
|
886
|
-
const here =
|
|
892
|
+
const here = path7.dirname(new URL(import.meta.url).pathname);
|
|
887
893
|
const candidates = [
|
|
888
|
-
|
|
894
|
+
path7.join(here, "..", "plugins"),
|
|
889
895
|
// dev: src/scripts → src/plugins
|
|
890
|
-
|
|
896
|
+
path7.join(here, "..", "..", "plugins"),
|
|
891
897
|
// built: dist/scripts → dist/plugins
|
|
892
|
-
|
|
898
|
+
path7.join(here, "..", "..", "src", "plugins")
|
|
893
899
|
// fallback
|
|
894
900
|
];
|
|
895
901
|
for (const c of candidates) {
|
|
@@ -900,8 +906,8 @@ function getPluginsCatalogRoot() {
|
|
|
900
906
|
function copyDir(src, dst) {
|
|
901
907
|
fs5.mkdirSync(dst, { recursive: true });
|
|
902
908
|
for (const ent of fs5.readdirSync(src, { withFileTypes: true })) {
|
|
903
|
-
const s =
|
|
904
|
-
const d =
|
|
909
|
+
const s = path7.join(src, ent.name);
|
|
910
|
+
const d = path7.join(dst, ent.name);
|
|
905
911
|
if (ent.isDirectory()) copyDir(s, d);
|
|
906
912
|
else if (ent.isFile()) fs5.copyFileSync(s, d);
|
|
907
913
|
}
|
|
@@ -916,35 +922,35 @@ var init_buildSyntheticPlugin = __esm({
|
|
|
916
922
|
if (!needsSynthetic) return;
|
|
917
923
|
const catalog = getPluginsCatalogRoot();
|
|
918
924
|
const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
919
|
-
const root =
|
|
920
|
-
fs5.mkdirSync(
|
|
925
|
+
const root = path7.join(os3.tmpdir(), `kody-synth-${runId}`);
|
|
926
|
+
fs5.mkdirSync(path7.join(root, ".claude-plugin"), { recursive: true });
|
|
921
927
|
const resolvePart = (bucket, entry) => {
|
|
922
|
-
const local =
|
|
928
|
+
const local = path7.join(profile.dir, bucket, entry);
|
|
923
929
|
if (fs5.existsSync(local)) return local;
|
|
924
|
-
const shared =
|
|
930
|
+
const shared = path7.resolve(profile.dir, "..", "..", "shared", bucket, entry);
|
|
925
931
|
if (fs5.existsSync(shared)) return shared;
|
|
926
|
-
const central =
|
|
932
|
+
const central = path7.join(catalog, bucket, entry);
|
|
927
933
|
if (fs5.existsSync(central)) return central;
|
|
928
934
|
throw new Error(
|
|
929
|
-
`buildSyntheticPlugin: ${bucket} entry '${entry}' not found in implementation dir (${profile.dir}/${bucket}/), Store shared assets (${
|
|
935
|
+
`buildSyntheticPlugin: ${bucket} entry '${entry}' not found in implementation dir (${profile.dir}/${bucket}/), Store shared assets (${path7.dirname(shared)}/), or catalog (${catalog}/${bucket}/)`
|
|
930
936
|
);
|
|
931
937
|
};
|
|
932
938
|
if (cc.skills.length > 0) {
|
|
933
|
-
const dst =
|
|
939
|
+
const dst = path7.join(root, "skills");
|
|
934
940
|
fs5.mkdirSync(dst, { recursive: true });
|
|
935
941
|
for (const name of cc.skills) {
|
|
936
|
-
copyDir(resolvePart("skills", name),
|
|
942
|
+
copyDir(resolvePart("skills", name), path7.join(dst, name));
|
|
937
943
|
}
|
|
938
944
|
}
|
|
939
945
|
if (cc.commands.length > 0) {
|
|
940
|
-
const dst =
|
|
946
|
+
const dst = path7.join(root, "commands");
|
|
941
947
|
fs5.mkdirSync(dst, { recursive: true });
|
|
942
948
|
for (const name of cc.commands) {
|
|
943
|
-
fs5.copyFileSync(resolvePart("commands", `${name}.md`),
|
|
949
|
+
fs5.copyFileSync(resolvePart("commands", `${name}.md`), path7.join(dst, `${name}.md`));
|
|
944
950
|
}
|
|
945
951
|
}
|
|
946
952
|
if (cc.hooks.length > 0) {
|
|
947
|
-
const dst =
|
|
953
|
+
const dst = path7.join(root, "hooks");
|
|
948
954
|
fs5.mkdirSync(dst, { recursive: true });
|
|
949
955
|
const merged = { hooks: {} };
|
|
950
956
|
for (const name of cc.hooks) {
|
|
@@ -956,7 +962,7 @@ var init_buildSyntheticPlugin = __esm({
|
|
|
956
962
|
merged.hooks[event].push(...entries);
|
|
957
963
|
}
|
|
958
964
|
}
|
|
959
|
-
fs5.writeFileSync(
|
|
965
|
+
fs5.writeFileSync(path7.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
|
|
960
966
|
`);
|
|
961
967
|
}
|
|
962
968
|
const manifest = {
|
|
@@ -966,7 +972,7 @@ var init_buildSyntheticPlugin = __esm({
|
|
|
966
972
|
};
|
|
967
973
|
if (cc.skills.length > 0) manifest.skills = ["./skills/"];
|
|
968
974
|
if (cc.commands.length > 0) manifest.commands = ["./commands/"];
|
|
969
|
-
fs5.writeFileSync(
|
|
975
|
+
fs5.writeFileSync(path7.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
|
|
970
976
|
`);
|
|
971
977
|
ctx.data.syntheticPluginPath = root;
|
|
972
978
|
};
|
|
@@ -975,7 +981,7 @@ var init_buildSyntheticPlugin = __esm({
|
|
|
975
981
|
|
|
976
982
|
// src/subagents.ts
|
|
977
983
|
import * as fs6 from "fs";
|
|
978
|
-
import * as
|
|
984
|
+
import * as path8 from "path";
|
|
979
985
|
async function enforceSubagentModelInheritance(input) {
|
|
980
986
|
const toolInput = input.tool_input;
|
|
981
987
|
if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return {};
|
|
@@ -1010,11 +1016,11 @@ function splitFrontmatter(raw) {
|
|
|
1010
1016
|
return { fm, body: (match[2] ?? "").trim() };
|
|
1011
1017
|
}
|
|
1012
1018
|
function resolveAgentFile(profileDir, name) {
|
|
1013
|
-
const local =
|
|
1019
|
+
const local = path8.join(profileDir, "agents", `${name}.md`);
|
|
1014
1020
|
if (fs6.existsSync(local)) return local;
|
|
1015
|
-
const shared =
|
|
1021
|
+
const shared = path8.resolve(profileDir, "..", "..", "shared", "agents", `${name}.md`);
|
|
1016
1022
|
if (fs6.existsSync(shared)) return shared;
|
|
1017
|
-
const central =
|
|
1023
|
+
const central = path8.join(getPluginsCatalogRoot(), "agents", `${name}.md`);
|
|
1018
1024
|
if (fs6.existsSync(central)) return central;
|
|
1019
1025
|
throw new Error(
|
|
1020
1026
|
`loadSubagents: agent '${name}' not found in ${profileDir}/agents/, hydrated shared assets, or engine catalog`
|
|
@@ -1071,7 +1077,7 @@ __export(events_exports, {
|
|
|
1071
1077
|
});
|
|
1072
1078
|
import * as crypto from "crypto";
|
|
1073
1079
|
import * as fs7 from "fs";
|
|
1074
|
-
import * as
|
|
1080
|
+
import * as path9 from "path";
|
|
1075
1081
|
function resolveRunId() {
|
|
1076
1082
|
if (process.env.KODY_RUN_ID) {
|
|
1077
1083
|
cachedRunId = process.env.KODY_RUN_ID;
|
|
@@ -1104,7 +1110,7 @@ function emitEvent(cwd, ev) {
|
|
|
1104
1110
|
...ev
|
|
1105
1111
|
};
|
|
1106
1112
|
const file = eventsPath(cwd, runId);
|
|
1107
|
-
fs7.mkdirSync(
|
|
1113
|
+
fs7.mkdirSync(path9.dirname(file), { recursive: true });
|
|
1108
1114
|
fs7.appendFileSync(file, `${JSON.stringify(fullEvent)}
|
|
1109
1115
|
`);
|
|
1110
1116
|
} catch {
|
|
@@ -1130,7 +1136,7 @@ function listRuns(cwd) {
|
|
|
1130
1136
|
if (!fs7.existsSync(runsDir)) return [];
|
|
1131
1137
|
return fs7.readdirSync(runsDir).filter((name) => {
|
|
1132
1138
|
try {
|
|
1133
|
-
return fs7.statSync(
|
|
1139
|
+
return fs7.statSync(path9.join(runsDir, name)).isDirectory();
|
|
1134
1140
|
} catch {
|
|
1135
1141
|
return false;
|
|
1136
1142
|
}
|
|
@@ -1171,10 +1177,10 @@ function abortMessage(signal) {
|
|
|
1171
1177
|
return reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "verification aborted";
|
|
1172
1178
|
}
|
|
1173
1179
|
function runCommand(command, cwd, signal) {
|
|
1174
|
-
return new Promise((
|
|
1180
|
+
return new Promise((resolve24) => {
|
|
1175
1181
|
const start = Date.now();
|
|
1176
1182
|
if (signal?.aborted) {
|
|
1177
|
-
|
|
1183
|
+
resolve24({ exitCode: -1, durationMs: 0, tail: abortMessage(signal) });
|
|
1178
1184
|
return;
|
|
1179
1185
|
}
|
|
1180
1186
|
const child = spawn(command, {
|
|
@@ -1212,7 +1218,7 @@ function runCommand(command, cwd, signal) {
|
|
|
1212
1218
|
signal?.removeEventListener("abort", onAbort);
|
|
1213
1219
|
const output = Buffer.concat(buffers).toString("utf-8");
|
|
1214
1220
|
const tail = [output, extraTail].filter(Boolean).join("\n").slice(-TAIL_CHARS);
|
|
1215
|
-
|
|
1221
|
+
resolve24({ exitCode, durationMs: Date.now() - start, tail });
|
|
1216
1222
|
};
|
|
1217
1223
|
const terminate = () => {
|
|
1218
1224
|
killTree("SIGTERM");
|
|
@@ -1541,7 +1547,7 @@ function cmsHeaders(opts) {
|
|
|
1541
1547
|
}
|
|
1542
1548
|
};
|
|
1543
1549
|
}
|
|
1544
|
-
async function callDashboardCms(opts,
|
|
1550
|
+
async function callDashboardCms(opts, path59, init = {}) {
|
|
1545
1551
|
const baseUrl = dashboardBaseUrl(opts);
|
|
1546
1552
|
if (!baseUrl) {
|
|
1547
1553
|
return {
|
|
@@ -1553,7 +1559,7 @@ async function callDashboardCms(opts, path58, init = {}) {
|
|
|
1553
1559
|
const headerResult = cmsHeaders(opts);
|
|
1554
1560
|
if (!headerResult.ok) return headerResult;
|
|
1555
1561
|
try {
|
|
1556
|
-
const res = await fetch(`${baseUrl}${
|
|
1562
|
+
const res = await fetch(`${baseUrl}${path59}`, {
|
|
1557
1563
|
...init,
|
|
1558
1564
|
headers: {
|
|
1559
1565
|
...headerResult.headers,
|
|
@@ -1625,8 +1631,8 @@ function documentArg(value) {
|
|
|
1625
1631
|
function normalizeCmsDocumentIdInput(input) {
|
|
1626
1632
|
const trimmed = stripWrappingQuotes(input.trim());
|
|
1627
1633
|
const withoutQuery = trimmed.split(/[?#]/, 1)[0] ?? trimmed;
|
|
1628
|
-
const
|
|
1629
|
-
return
|
|
1634
|
+
const path59 = parseDocumentPath(withoutQuery);
|
|
1635
|
+
return path59 ?? parseDocumentIdSegment(withoutQuery) ?? withoutQuery;
|
|
1630
1636
|
}
|
|
1631
1637
|
function stripWrappingQuotes(value) {
|
|
1632
1638
|
let current = value;
|
|
@@ -1637,9 +1643,9 @@ function stripWrappingQuotes(value) {
|
|
|
1637
1643
|
}
|
|
1638
1644
|
}
|
|
1639
1645
|
function parseDocumentPath(value) {
|
|
1640
|
-
const
|
|
1641
|
-
if (!
|
|
1642
|
-
const parts =
|
|
1646
|
+
const path59 = value.startsWith("http://") || value.startsWith("https://") ? urlPathname(value) : value;
|
|
1647
|
+
if (!path59?.includes("/content/entries/")) return null;
|
|
1648
|
+
const parts = path59.split("/").filter(Boolean).map(decodePathPart);
|
|
1643
1649
|
const entriesIndex = parts.findIndex((part, index) => part === "content" && parts[index + 1] === "entries");
|
|
1644
1650
|
const idPart = parts[entriesIndex + 3];
|
|
1645
1651
|
if (!idPart || idPart === "new") return null;
|
|
@@ -2085,7 +2091,7 @@ var init_issue = __esm({
|
|
|
2085
2091
|
|
|
2086
2092
|
// src/capabilityFolders.ts
|
|
2087
2093
|
import * as fs8 from "fs";
|
|
2088
|
-
import * as
|
|
2094
|
+
import * as path10 from "path";
|
|
2089
2095
|
function capabilityOutputConditionPaths(config) {
|
|
2090
2096
|
if (config.outputSchema) {
|
|
2091
2097
|
return new Set(schemaPropertyPaths(config.outputSchema, "result"));
|
|
@@ -2107,35 +2113,35 @@ function listCapabilityFolderSlugs(absDir) {
|
|
|
2107
2113
|
} catch {
|
|
2108
2114
|
return [];
|
|
2109
2115
|
}
|
|
2110
|
-
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).filter((e) => isCapabilityFolder(
|
|
2116
|
+
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).filter((e) => isCapabilityFolder(path10.join(absDir, e.name))).map((e) => e.name).sort();
|
|
2111
2117
|
}
|
|
2112
2118
|
function isCapabilityFolder(dir) {
|
|
2113
2119
|
const entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
2114
|
-
const legacyBody =
|
|
2120
|
+
const legacyBody = path10.join(dir, CAPABILITY_BODY_FILE);
|
|
2115
2121
|
if (fs8.existsSync(legacyBody)) {
|
|
2116
2122
|
return entries.every(
|
|
2117
2123
|
(entry) => entry.name === CAPABILITY_BODY_FILE || entry.name === CAPABILITY_CONTRACT_FILE || entry.isDirectory() && (entry.name === "skills" || entry.name === "tools")
|
|
2118
2124
|
);
|
|
2119
2125
|
}
|
|
2120
|
-
const canonicalBody =
|
|
2121
|
-
const canonicalDefinition =
|
|
2126
|
+
const canonicalBody = path10.join(dir, CANONICAL_CAPABILITY_BODY_FILE);
|
|
2127
|
+
const canonicalDefinition = path10.join(dir, CANONICAL_CAPABILITY_DEFINITION_FILE);
|
|
2122
2128
|
if (!fs8.existsSync(canonicalBody) || !fs8.existsSync(canonicalDefinition)) return false;
|
|
2123
2129
|
return entries.every(
|
|
2124
2130
|
(entry) => entry.name === CANONICAL_CAPABILITY_BODY_FILE || entry.name === CANONICAL_CAPABILITY_DEFINITION_FILE
|
|
2125
2131
|
);
|
|
2126
2132
|
}
|
|
2127
2133
|
function readCapabilityFolder(root, slug) {
|
|
2128
|
-
const dir =
|
|
2129
|
-
const legacyBodyPath =
|
|
2130
|
-
const canonicalBodyPath =
|
|
2134
|
+
const dir = path10.join(root, slug);
|
|
2135
|
+
const legacyBodyPath = path10.join(dir, CAPABILITY_BODY_FILE);
|
|
2136
|
+
const canonicalBodyPath = path10.join(dir, CANONICAL_CAPABILITY_BODY_FILE);
|
|
2131
2137
|
const bodyPath = fs8.existsSync(legacyBodyPath) ? legacyBodyPath : canonicalBodyPath;
|
|
2132
|
-
const contractPath =
|
|
2138
|
+
const contractPath = path10.join(dir, CAPABILITY_CONTRACT_FILE);
|
|
2133
2139
|
if (!fs8.existsSync(bodyPath) || !fs8.statSync(bodyPath).isFile()) return null;
|
|
2134
2140
|
if (!isCapabilityFolder(dir)) return null;
|
|
2135
2141
|
try {
|
|
2136
2142
|
const rawBody = fs8.readFileSync(bodyPath, "utf-8");
|
|
2137
2143
|
if (bodyPath === canonicalBodyPath) {
|
|
2138
|
-
const definitionPath =
|
|
2144
|
+
const definitionPath = path10.join(dir, CANONICAL_CAPABILITY_DEFINITION_FILE);
|
|
2139
2145
|
const definition = JSON.parse(fs8.readFileSync(definitionPath, "utf-8"));
|
|
2140
2146
|
if (definition.id !== slug || typeof definition.action !== "string") return null;
|
|
2141
2147
|
const { title: title2, body: body2 } = parseCapabilityBody(rawBody, slug);
|
|
@@ -2157,7 +2163,7 @@ function readCapabilityFolder(root, slug) {
|
|
|
2157
2163
|
};
|
|
2158
2164
|
}
|
|
2159
2165
|
const contract = fs8.existsSync(contractPath) ? parseCapabilityContract(fs8.readFileSync(contractPath, "utf-8")) : void 0;
|
|
2160
|
-
if (contract?.execution === "script" && !isRegularFile(
|
|
2166
|
+
if (contract?.execution === "script" && !isRegularFile(path10.join(dir, "tools", "run.sh"))) {
|
|
2161
2167
|
throw new Error('script-backed Capability requires a regular "tools/run.sh" file');
|
|
2162
2168
|
}
|
|
2163
2169
|
const { title, body } = parseCapabilityBody(rawBody, slug);
|
|
@@ -2181,6 +2187,7 @@ function readCapabilityFolder(root, slug) {
|
|
|
2181
2187
|
},
|
|
2182
2188
|
rawProfile: contract ? {
|
|
2183
2189
|
...contract.execution ? { execution: contract.execution } : {},
|
|
2190
|
+
...contract.deliveryPolicy ? { deliveryPolicy: contract.deliveryPolicy } : {},
|
|
2184
2191
|
input: contract.input,
|
|
2185
2192
|
output: contract.output
|
|
2186
2193
|
} : {},
|
|
@@ -2221,13 +2228,20 @@ function parseCapabilityContract(raw) {
|
|
|
2221
2228
|
throw new Error('contract.json requiredSubagents are supported only when execution is "agent"');
|
|
2222
2229
|
}
|
|
2223
2230
|
const unsupported = Object.keys(parsed).filter(
|
|
2224
|
-
(key) => key !== "execution" && key !== "requirements" && key !== "secrets" && key !== "timeoutMs" && key !== "requiredSubagents" && key !== "input" && key !== "output"
|
|
2231
|
+
(key) => key !== "execution" && key !== "deliveryPolicy" && key !== "requirements" && key !== "secrets" && key !== "timeoutMs" && key !== "requiredSubagents" && key !== "input" && key !== "output"
|
|
2225
2232
|
);
|
|
2226
2233
|
if (unsupported.length > 0) {
|
|
2227
2234
|
throw new Error(`contract.json contains unsupported fields: ${unsupported.join(", ")}`);
|
|
2228
2235
|
}
|
|
2236
|
+
if (parsed.deliveryPolicy !== void 0 && parsed.deliveryPolicy !== "checkpoint") {
|
|
2237
|
+
throw new Error('contract.json deliveryPolicy must be "checkpoint"');
|
|
2238
|
+
}
|
|
2239
|
+
if (parsed.deliveryPolicy === "checkpoint" && parsed.execution !== "agent") {
|
|
2240
|
+
throw new Error('contract.json deliveryPolicy "checkpoint" is supported only when execution is "agent"');
|
|
2241
|
+
}
|
|
2229
2242
|
return {
|
|
2230
2243
|
...parsed.execution ? { execution: parsed.execution } : {},
|
|
2244
|
+
...parsed.deliveryPolicy === "checkpoint" ? { deliveryPolicy: "checkpoint" } : {},
|
|
2231
2245
|
...requirements ? { requirements } : {},
|
|
2232
2246
|
...secrets ? { secrets } : {},
|
|
2233
2247
|
...timeoutMs !== void 0 ? { timeoutMs } : {},
|
|
@@ -2279,8 +2293,8 @@ function isRegularFile(filePath) {
|
|
|
2279
2293
|
function schemaPropertyPaths(schema, prefix) {
|
|
2280
2294
|
const properties = isPlainObject(schema.properties) ? schema.properties : {};
|
|
2281
2295
|
return Object.entries(properties).flatMap(([name, property]) => {
|
|
2282
|
-
const
|
|
2283
|
-
return isPlainObject(property) ? [
|
|
2296
|
+
const path59 = `${prefix}.${name}`;
|
|
2297
|
+
return isPlainObject(property) ? [path59, ...schemaPropertyPaths(property, path59)] : [path59];
|
|
2284
2298
|
});
|
|
2285
2299
|
}
|
|
2286
2300
|
function parseCapabilityBody(raw, slug) {
|
|
@@ -2447,47 +2461,47 @@ var init_capabilityFolders = __esm({
|
|
|
2447
2461
|
|
|
2448
2462
|
// src/definition-paths.ts
|
|
2449
2463
|
import * as fs9 from "fs";
|
|
2450
|
-
import * as
|
|
2464
|
+
import * as path11 from "path";
|
|
2451
2465
|
function definitionsRoot(cwd = process.cwd()) {
|
|
2452
2466
|
const override = process.env.KODY_DEFINITIONS_ROOT?.trim();
|
|
2453
2467
|
const overrideCwd = process.env.KODY_DEFINITIONS_ROOT_CWD?.trim();
|
|
2454
|
-
if (override && overrideCwd &&
|
|
2455
|
-
return storeCatalogRoot(
|
|
2468
|
+
if (override && overrideCwd && path11.resolve(cwd) === path11.resolve(overrideCwd)) {
|
|
2469
|
+
return storeCatalogRoot(path11.resolve(override));
|
|
2456
2470
|
}
|
|
2457
|
-
const hydrated =
|
|
2471
|
+
const hydrated = path11.join(cwd, ".kody-engine", "definitions");
|
|
2458
2472
|
if (fs9.existsSync(hydrated)) return hydrated;
|
|
2459
|
-
return override ? storeCatalogRoot(
|
|
2473
|
+
return override ? storeCatalogRoot(path11.resolve(override)) : hydrated;
|
|
2460
2474
|
}
|
|
2461
2475
|
function hasExplicitDefinitionsRoot(cwd = process.cwd(), env = process.env) {
|
|
2462
2476
|
const root = env.KODY_DEFINITIONS_ROOT?.trim();
|
|
2463
2477
|
const rootCwd = env.KODY_DEFINITIONS_ROOT_CWD?.trim();
|
|
2464
|
-
return Boolean(root && rootCwd &&
|
|
2478
|
+
return Boolean(root && rootCwd && path11.resolve(cwd) === path11.resolve(rootCwd));
|
|
2465
2479
|
}
|
|
2466
2480
|
function capabilitiesRoot(cwd = process.cwd()) {
|
|
2467
|
-
return storeAssetRoot(cwd, "capabilities") ??
|
|
2481
|
+
return storeAssetRoot(cwd, "capabilities") ?? path11.join(definitionsRoot(cwd), "capabilities");
|
|
2468
2482
|
}
|
|
2469
2483
|
function implementationsRoot(cwd = process.cwd()) {
|
|
2470
|
-
return
|
|
2484
|
+
return path11.join(definitionsRoot(cwd), "implementations");
|
|
2471
2485
|
}
|
|
2472
2486
|
function agentsRoot(cwd = process.cwd()) {
|
|
2473
|
-
return storeAssetRoot(cwd, "agent") ??
|
|
2487
|
+
return storeAssetRoot(cwd, "agent") ?? path11.join(definitionsRoot(cwd), "agents");
|
|
2474
2488
|
}
|
|
2475
2489
|
function storeCatalogRoot(root) {
|
|
2476
2490
|
const manifest = readStoreManifest(root);
|
|
2477
|
-
const roots = ["capabilities", "workflows", "loops"].map((kind) => manifest?.assetRoots?.[kind]).filter((value) => typeof value === "string" && Boolean(value.trim())).map((value) =>
|
|
2478
|
-
return roots.length === 3 && new Set(roots).size === 1 ?
|
|
2491
|
+
const roots = ["capabilities", "workflows", "loops"].map((kind) => manifest?.assetRoots?.[kind]).filter((value) => typeof value === "string" && Boolean(value.trim())).map((value) => path11.dirname(value));
|
|
2492
|
+
return roots.length === 3 && new Set(roots).size === 1 ? path11.join(root, roots[0]) : root;
|
|
2479
2493
|
}
|
|
2480
2494
|
function storeAssetRoot(cwd, kind) {
|
|
2481
2495
|
const override = process.env.KODY_DEFINITIONS_ROOT?.trim();
|
|
2482
2496
|
if (!override) return null;
|
|
2483
2497
|
const overrideCwd = process.env.KODY_DEFINITIONS_ROOT_CWD?.trim();
|
|
2484
|
-
if (overrideCwd &&
|
|
2485
|
-
const root =
|
|
2498
|
+
if (overrideCwd && path11.resolve(cwd) !== path11.resolve(overrideCwd)) return null;
|
|
2499
|
+
const root = path11.resolve(override);
|
|
2486
2500
|
const configured = readStoreManifest(root)?.assetRoots?.[kind];
|
|
2487
|
-
return typeof configured === "string" && configured.trim() ?
|
|
2501
|
+
return typeof configured === "string" && configured.trim() ? path11.join(root, configured) : null;
|
|
2488
2502
|
}
|
|
2489
2503
|
function readStoreManifest(root) {
|
|
2490
|
-
const file =
|
|
2504
|
+
const file = path11.join(root, "kody-store.json");
|
|
2491
2505
|
if (!fs9.existsSync(file)) return null;
|
|
2492
2506
|
try {
|
|
2493
2507
|
return JSON.parse(fs9.readFileSync(file, "utf8"));
|
|
@@ -2503,15 +2517,15 @@ var init_definition_paths = __esm({
|
|
|
2503
2517
|
|
|
2504
2518
|
// src/registry.ts
|
|
2505
2519
|
import * as fs10 from "fs";
|
|
2506
|
-
import * as
|
|
2520
|
+
import * as path12 from "path";
|
|
2507
2521
|
function getImplementationsRoot() {
|
|
2508
|
-
const here =
|
|
2522
|
+
const here = path12.dirname(new URL(import.meta.url).pathname);
|
|
2509
2523
|
const candidates = [
|
|
2510
|
-
|
|
2524
|
+
path12.join(here, "implementations"),
|
|
2511
2525
|
// dev: src/
|
|
2512
|
-
|
|
2526
|
+
path12.join(here, "..", "implementations"),
|
|
2513
2527
|
// built: dist/bin → dist/implementations
|
|
2514
|
-
|
|
2528
|
+
path12.join(here, "..", "src", "implementations")
|
|
2515
2529
|
// fallback
|
|
2516
2530
|
];
|
|
2517
2531
|
for (const c of candidates) {
|
|
@@ -2520,11 +2534,11 @@ function getImplementationsRoot() {
|
|
|
2520
2534
|
return candidates[0];
|
|
2521
2535
|
}
|
|
2522
2536
|
function getRuntimeServicesRoot() {
|
|
2523
|
-
const here =
|
|
2537
|
+
const here = path12.dirname(new URL(import.meta.url).pathname);
|
|
2524
2538
|
const candidates = [
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2539
|
+
path12.join(here, "runtime-services"),
|
|
2540
|
+
path12.join(here, "..", "runtime-services"),
|
|
2541
|
+
path12.join(here, "..", "src", "runtime-services")
|
|
2528
2542
|
];
|
|
2529
2543
|
for (const candidate of candidates) {
|
|
2530
2544
|
if (fs10.existsSync(candidate) && fs10.statSync(candidate).isDirectory()) return candidate;
|
|
@@ -2535,13 +2549,13 @@ function getProjectCapabilitiesRoot() {
|
|
|
2535
2549
|
return capabilitiesRoot();
|
|
2536
2550
|
}
|
|
2537
2551
|
function getBuiltinCapabilitiesRoot() {
|
|
2538
|
-
const here =
|
|
2552
|
+
const here = path12.dirname(new URL(import.meta.url).pathname);
|
|
2539
2553
|
const candidates = [
|
|
2540
|
-
|
|
2554
|
+
path12.join(here, "capabilities"),
|
|
2541
2555
|
// dev: src/
|
|
2542
|
-
|
|
2556
|
+
path12.join(here, "..", "capabilities"),
|
|
2543
2557
|
// built: dist/bin → dist/capabilities
|
|
2544
|
-
|
|
2558
|
+
path12.join(here, "..", "src", "capabilities")
|
|
2545
2559
|
// fallback
|
|
2546
2560
|
];
|
|
2547
2561
|
for (const c of candidates) {
|
|
@@ -2685,17 +2699,17 @@ function isSafeName(name) {
|
|
|
2685
2699
|
return /^[a-z][a-z0-9-]*$/.test(name) && !name.includes("..");
|
|
2686
2700
|
}
|
|
2687
2701
|
function isCapabilityRoot(root) {
|
|
2688
|
-
const normalized =
|
|
2689
|
-
if (
|
|
2702
|
+
const normalized = path12.normalize(root);
|
|
2703
|
+
if (path12.basename(normalized) === "capabilities") return true;
|
|
2690
2704
|
const knownRoots = [getProjectCapabilitiesRoot(), getBuiltinCapabilitiesRoot()];
|
|
2691
|
-
return knownRoots.some((candidate) => candidate &&
|
|
2705
|
+
return knownRoots.some((candidate) => candidate && path12.normalize(candidate) === normalized);
|
|
2692
2706
|
}
|
|
2693
2707
|
function implementationRuntimePath(root, name) {
|
|
2694
|
-
const runtimePath =
|
|
2708
|
+
const runtimePath = path12.join(root, name, "runtime.json");
|
|
2695
2709
|
if (fs10.existsSync(runtimePath)) return runtimePath;
|
|
2696
|
-
const internalProfilePath =
|
|
2710
|
+
const internalProfilePath = path12.join(root, name, "profile.json");
|
|
2697
2711
|
if (fs10.existsSync(internalProfilePath)) return internalProfilePath;
|
|
2698
|
-
return
|
|
2712
|
+
return path12.join(root, name, CAPABILITY_PROFILE_FILE);
|
|
2699
2713
|
}
|
|
2700
2714
|
function isImplementationProfile(profilePath, requireImplementationProfile) {
|
|
2701
2715
|
if (!requireImplementationProfile) return true;
|
|
@@ -3862,7 +3876,7 @@ var init_capabilityMcp = __esm({
|
|
|
3862
3876
|
// src/repoWorkspace.ts
|
|
3863
3877
|
import { spawn as spawn2, spawnSync } from "child_process";
|
|
3864
3878
|
import * as fs11 from "fs";
|
|
3865
|
-
import * as
|
|
3879
|
+
import * as path13 from "path";
|
|
3866
3880
|
function buildCloneProcess(repo, token, baseEnv = process.env) {
|
|
3867
3881
|
const url = `https://github.com/${repo}.git`;
|
|
3868
3882
|
const env = { ...baseEnv };
|
|
@@ -3877,10 +3891,10 @@ function buildCloneProcess(repo, token, baseEnv = process.env) {
|
|
|
3877
3891
|
async function resolveAndClone(reposRoot, repo, repoToken, cloneRepo) {
|
|
3878
3892
|
const name = repo?.trim();
|
|
3879
3893
|
if (!name || !REPO_RE.test(name)) return null;
|
|
3880
|
-
const root =
|
|
3881
|
-
const dir =
|
|
3882
|
-
if (dir !== root && !dir.startsWith(root +
|
|
3883
|
-
if (fs11.existsSync(
|
|
3894
|
+
const root = path13.resolve(reposRoot);
|
|
3895
|
+
const dir = path13.resolve(root, name);
|
|
3896
|
+
if (dir !== root && !dir.startsWith(root + path13.sep)) return null;
|
|
3897
|
+
if (fs11.existsSync(path13.join(dir, ".git"))) return dir;
|
|
3884
3898
|
const inflight = repoClones.get(dir);
|
|
3885
3899
|
if (inflight) {
|
|
3886
3900
|
await inflight;
|
|
@@ -3912,9 +3926,9 @@ var init_repoWorkspace = __esm({
|
|
|
3912
3926
|
repoClones = /* @__PURE__ */ new Map();
|
|
3913
3927
|
GIT_CREDENTIAL_HELPER = `!f() { if [ "$1" = get ] && [ -n "$GITHUB_TOKEN" ]; then printf '%s\\n' username=x-access-token "password=$GITHUB_TOKEN"; fi; }; f`;
|
|
3914
3928
|
defaultCloneRepo = (repo, token, dir) => {
|
|
3915
|
-
fs11.mkdirSync(
|
|
3929
|
+
fs11.mkdirSync(path13.dirname(dir), { recursive: true });
|
|
3916
3930
|
const clone = buildCloneProcess(repo, token);
|
|
3917
|
-
return new Promise((
|
|
3931
|
+
return new Promise((resolve24, reject) => {
|
|
3918
3932
|
const child = spawn2("git", ["clone", "--depth=1", clone.url, dir], {
|
|
3919
3933
|
env: clone.env,
|
|
3920
3934
|
stdio: "inherit"
|
|
@@ -3934,7 +3948,7 @@ var init_repoWorkspace = __esm({
|
|
|
3934
3948
|
}
|
|
3935
3949
|
} catch {
|
|
3936
3950
|
}
|
|
3937
|
-
|
|
3951
|
+
resolve24();
|
|
3938
3952
|
});
|
|
3939
3953
|
child.on("error", reject);
|
|
3940
3954
|
});
|
|
@@ -4007,7 +4021,7 @@ var init_fetchRepoMcp = __esm({
|
|
|
4007
4021
|
|
|
4008
4022
|
// src/agent.ts
|
|
4009
4023
|
import * as fs12 from "fs";
|
|
4010
|
-
import * as
|
|
4024
|
+
import * as path14 from "path";
|
|
4011
4025
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
4012
4026
|
function classifySubtype(subtype) {
|
|
4013
4027
|
if (!subtype) return "generic_failed";
|
|
@@ -4077,7 +4091,7 @@ function buildAgentEnvironment(baseEnv, repoToken, requestEnvironment) {
|
|
|
4077
4091
|
async function runAgent(opts) {
|
|
4078
4092
|
const ndjsonDir = opts.ndjsonDir ?? agentRunDir(opts.cwd);
|
|
4079
4093
|
fs12.mkdirSync(ndjsonDir, { recursive: true });
|
|
4080
|
-
const ndjsonPath =
|
|
4094
|
+
const ndjsonPath = path14.join(ndjsonDir, "last-run.jsonl");
|
|
4081
4095
|
const env = buildAgentEnvironment(process.env, opts.repoToken, opts.environment);
|
|
4082
4096
|
if (opts.litellmUrl) {
|
|
4083
4097
|
env.ANTHROPIC_BASE_URL = opts.litellmUrl;
|
|
@@ -4085,7 +4099,11 @@ async function runAgent(opts) {
|
|
|
4085
4099
|
}
|
|
4086
4100
|
const startedAt = Date.now();
|
|
4087
4101
|
const turnTimeoutMs = resolveTurnTimeoutMs(opts);
|
|
4088
|
-
const completionGuard = typeof opts.deadlineAtMs === "number" ? createCompletionToolGuard(
|
|
4102
|
+
const completionGuard = typeof opts.deadlineAtMs === "number" ? createCompletionToolGuard(
|
|
4103
|
+
completionToolCutoffAt(startedAt, opts.deadlineAtMs),
|
|
4104
|
+
Date.now,
|
|
4105
|
+
opts.outputContract?.path
|
|
4106
|
+
) : null;
|
|
4089
4107
|
let outcome = "failed";
|
|
4090
4108
|
let outcomeKind = "generic_failed";
|
|
4091
4109
|
let errorMessage2;
|
|
@@ -4294,10 +4312,10 @@ async function runAgent(opts) {
|
|
|
4294
4312
|
let timer;
|
|
4295
4313
|
let next;
|
|
4296
4314
|
if (turnTimeoutMs > 0) {
|
|
4297
|
-
const timeoutPromise = new Promise((
|
|
4315
|
+
const timeoutPromise = new Promise((resolve24) => {
|
|
4298
4316
|
timer = setTimeout(() => {
|
|
4299
4317
|
timedOut = true;
|
|
4300
|
-
|
|
4318
|
+
resolve24({ done: true, value: void 0 });
|
|
4301
4319
|
}, turnTimeoutMs);
|
|
4302
4320
|
});
|
|
4303
4321
|
next = await Promise.race([nextPromise, timeoutPromise]);
|
|
@@ -4313,7 +4331,7 @@ async function runAgent(opts) {
|
|
|
4313
4331
|
try {
|
|
4314
4332
|
await Promise.race([
|
|
4315
4333
|
iterator.return(void 0).catch(() => void 0),
|
|
4316
|
-
new Promise((
|
|
4334
|
+
new Promise((resolve24) => setTimeout(resolve24, 1e4).unref())
|
|
4317
4335
|
]);
|
|
4318
4336
|
} catch {
|
|
4319
4337
|
}
|
|
@@ -4520,7 +4538,7 @@ var init_agent = __esm({
|
|
|
4520
4538
|
|
|
4521
4539
|
// src/agents.ts
|
|
4522
4540
|
import * as fs13 from "fs";
|
|
4523
|
-
import * as
|
|
4541
|
+
import * as path15 from "path";
|
|
4524
4542
|
function stripFrontmatter(raw) {
|
|
4525
4543
|
const match = /^---\n[\s\S]*?\n---\n?([\s\S]*)$/.exec(raw);
|
|
4526
4544
|
return (match ? match[1] : raw).trim();
|
|
@@ -4541,7 +4559,7 @@ function loadAgentIdentity(cwd, slug, agentsDir = agentsRoot(cwd)) {
|
|
|
4541
4559
|
throw new Error(`loadAgentIdentity: agent '${trimmed}' declared but ${agentPath} does not exist`);
|
|
4542
4560
|
}
|
|
4543
4561
|
function resolveAgentFile2(cwd, slug, agentsDir = agentsRoot(cwd)) {
|
|
4544
|
-
const localPath =
|
|
4562
|
+
const localPath = path15.resolve(cwd, agentsDir, `${slug}.md`);
|
|
4545
4563
|
if (fs13.existsSync(localPath)) return localPath;
|
|
4546
4564
|
return localPath;
|
|
4547
4565
|
}
|
|
@@ -4575,7 +4593,7 @@ var init_agents = __esm({
|
|
|
4575
4593
|
|
|
4576
4594
|
// src/task-artifacts.ts
|
|
4577
4595
|
import fs14 from "fs";
|
|
4578
|
-
import
|
|
4596
|
+
import path16 from "path";
|
|
4579
4597
|
import posixPath from "path/posix";
|
|
4580
4598
|
function prepareTaskArtifactsDir(cwd, taskId) {
|
|
4581
4599
|
const safeId = String(taskId).replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
@@ -4611,14 +4629,14 @@ function initializeTaskArtifacts(artifacts, metadata = { taskType: "job" }) {
|
|
|
4611
4629
|
"handoff-notes.md": "Baseline handoff: the agent did not provide additional notes.\n"
|
|
4612
4630
|
};
|
|
4613
4631
|
for (const file of TASK_ARTIFACT_FILES) {
|
|
4614
|
-
const full =
|
|
4632
|
+
const full = path16.join(artifacts.absDir, file);
|
|
4615
4633
|
if (!fs14.existsSync(full)) fs14.writeFileSync(full, defaults[file], "utf8");
|
|
4616
4634
|
}
|
|
4617
4635
|
}
|
|
4618
4636
|
function verifyTaskArtifacts(absDir) {
|
|
4619
4637
|
const missing = [];
|
|
4620
4638
|
for (const name of TASK_ARTIFACT_FILES) {
|
|
4621
|
-
const full =
|
|
4639
|
+
const full = path16.join(absDir, name);
|
|
4622
4640
|
try {
|
|
4623
4641
|
const stat = fs14.statSync(full);
|
|
4624
4642
|
if (!stat.isFile() || stat.size === 0) missing.push(name);
|
|
@@ -4636,7 +4654,7 @@ async function persistTaskArtifactsToState(config, _cwd, artifacts) {
|
|
|
4636
4654
|
if (hasStateBackendConfig() && tenantId2) {
|
|
4637
4655
|
const backend = createStateBackendFromEnv();
|
|
4638
4656
|
for (const file of TASK_ARTIFACT_FILES) {
|
|
4639
|
-
const full =
|
|
4657
|
+
const full = path16.join(artifacts.absDir, file);
|
|
4640
4658
|
if (!fs14.existsSync(full)) continue;
|
|
4641
4659
|
const stat = fs14.statSync(full);
|
|
4642
4660
|
if (!stat.isFile() || stat.size === 0) continue;
|
|
@@ -4949,15 +4967,15 @@ function validateWorkflow(value, options = {}) {
|
|
|
4949
4967
|
}
|
|
4950
4968
|
return issues;
|
|
4951
4969
|
}
|
|
4952
|
-
function validateInputBindings(value,
|
|
4970
|
+
function validateInputBindings(value, path59, issues, declaredInputs) {
|
|
4953
4971
|
if (value === void 0) return;
|
|
4954
4972
|
const bindings = asRecord(value);
|
|
4955
4973
|
if (!bindings || Object.keys(bindings).length === 0) {
|
|
4956
|
-
issue(issues, "invalid_inputs",
|
|
4974
|
+
issue(issues, "invalid_inputs", path59, "workflow step inputs must contain at least one named mapping");
|
|
4957
4975
|
return;
|
|
4958
4976
|
}
|
|
4959
4977
|
for (const [name, value2] of Object.entries(bindings)) {
|
|
4960
|
-
const bindingPath = `${
|
|
4978
|
+
const bindingPath = `${path59}.${name}`;
|
|
4961
4979
|
if (!/^[A-Za-z_][A-Za-z0-9_-]*$/.test(name)) {
|
|
4962
4980
|
issue(issues, "invalid_input_name", bindingPath, `workflow input name ${name} is invalid`);
|
|
4963
4981
|
}
|
|
@@ -4976,7 +4994,7 @@ function validateInputBindings(value, path58, issues, declaredInputs) {
|
|
|
4976
4994
|
}
|
|
4977
4995
|
}
|
|
4978
4996
|
}
|
|
4979
|
-
function validateInputBindingSources(value,
|
|
4997
|
+
function validateInputBindingSources(value, path59, issues, capabilitiesByStep, capabilityOutputs) {
|
|
4980
4998
|
const bindings = asRecord(value);
|
|
4981
4999
|
if (!bindings) return;
|
|
4982
5000
|
for (const [name, rawBinding] of Object.entries(bindings)) {
|
|
@@ -4989,7 +5007,7 @@ function validateInputBindingSources(value, path58, issues, capabilitiesByStep,
|
|
|
4989
5007
|
issue(
|
|
4990
5008
|
issues,
|
|
4991
5009
|
"missing_input_step",
|
|
4992
|
-
`${
|
|
5010
|
+
`${path59}.${name}.from`,
|
|
4993
5011
|
`workflow input mapping references missing step ${sourceStep ?? "<none>"}`
|
|
4994
5012
|
);
|
|
4995
5013
|
continue;
|
|
@@ -5000,7 +5018,7 @@ function validateInputBindingSources(value, path58, issues, capabilitiesByStep,
|
|
|
5000
5018
|
issue(
|
|
5001
5019
|
issues,
|
|
5002
5020
|
"undeclared_step_output",
|
|
5003
|
-
`${
|
|
5021
|
+
`${path59}.${name}.from`,
|
|
5004
5022
|
`workflow input mapping reads ${outputPath}, but step ${sourceStep} does not declare it`
|
|
5005
5023
|
);
|
|
5006
5024
|
}
|
|
@@ -5009,11 +5027,11 @@ function validateInputBindingSources(value, path58, issues, capabilitiesByStep,
|
|
|
5009
5027
|
function formatWorkflowValidationIssues(issues) {
|
|
5010
5028
|
return issues.map((entry) => `${entry.path}: ${entry.message}`);
|
|
5011
5029
|
}
|
|
5012
|
-
function validateDataMatch(value,
|
|
5030
|
+
function validateDataMatch(value, path59, issues, capabilityOutputs) {
|
|
5013
5031
|
if (value === void 0) return;
|
|
5014
5032
|
const match = asRecord(value);
|
|
5015
5033
|
if (!match || Object.keys(match).length === 0) {
|
|
5016
|
-
issue(issues, "invalid_condition",
|
|
5034
|
+
issue(issues, "invalid_condition", path59, "workflow condition must contain at least one match");
|
|
5017
5035
|
return;
|
|
5018
5036
|
}
|
|
5019
5037
|
for (const [field, expected] of Object.entries(match)) {
|
|
@@ -5021,7 +5039,7 @@ function validateDataMatch(value, path58, issues, capabilityOutputs) {
|
|
|
5021
5039
|
issue(
|
|
5022
5040
|
issues,
|
|
5023
5041
|
"invalid_data_path",
|
|
5024
|
-
`${
|
|
5042
|
+
`${path59}.${field}`,
|
|
5025
5043
|
`workflow condition must read from facts, evidence, artifacts, result, workflow, or lastOutcome`
|
|
5026
5044
|
);
|
|
5027
5045
|
}
|
|
@@ -5029,12 +5047,12 @@ function validateDataMatch(value, path58, issues, capabilityOutputs) {
|
|
|
5029
5047
|
issue(
|
|
5030
5048
|
issues,
|
|
5031
5049
|
"undeclared_result_path",
|
|
5032
|
-
`${
|
|
5050
|
+
`${path59}.${field}`,
|
|
5033
5051
|
`workflow condition reads ${field}, but the source capability does not declare it`
|
|
5034
5052
|
);
|
|
5035
5053
|
}
|
|
5036
5054
|
if (!isComparable(expected)) {
|
|
5037
|
-
issue(issues, "invalid_condition_value", `${
|
|
5055
|
+
issue(issues, "invalid_condition_value", `${path59}.${field}`, "workflow condition value must be a JSON scalar");
|
|
5038
5056
|
}
|
|
5039
5057
|
}
|
|
5040
5058
|
}
|
|
@@ -5058,8 +5076,8 @@ function isJsonValue(value) {
|
|
|
5058
5076
|
if (!value || typeof value !== "object") return false;
|
|
5059
5077
|
return Object.values(value).every(isJsonValue);
|
|
5060
5078
|
}
|
|
5061
|
-
function issue(issues, code,
|
|
5062
|
-
issues.push({ code, path:
|
|
5079
|
+
function issue(issues, code, path59, message) {
|
|
5080
|
+
issues.push({ code, path: path59, message });
|
|
5063
5081
|
}
|
|
5064
5082
|
var SAFE_NAME, SAFE_STEP_ID, SAFE_DATA_PATH, SAFE_INPUT_SOURCE, SUPPORTED_STEP_FIELDS, SUPPORTED_TRANSITION_FIELDS;
|
|
5065
5083
|
var init_workflowValidation = __esm({
|
|
@@ -5093,7 +5111,7 @@ var init_workflowValidation = __esm({
|
|
|
5093
5111
|
|
|
5094
5112
|
// src/workflowDefinitions.ts
|
|
5095
5113
|
import * as fs20 from "fs";
|
|
5096
|
-
import * as
|
|
5114
|
+
import * as path22 from "path";
|
|
5097
5115
|
function isWorkflowDefinitionId(value) {
|
|
5098
5116
|
return WORKFLOW_ID_PATTERN.test(value);
|
|
5099
5117
|
}
|
|
@@ -5138,8 +5156,8 @@ function readWorkflowDefinition(_config, cwd, id) {
|
|
|
5138
5156
|
const root = cwd ?? process.cwd();
|
|
5139
5157
|
const relativePath = workflowDefinitionPath(id);
|
|
5140
5158
|
const candidates = [
|
|
5141
|
-
|
|
5142
|
-
|
|
5159
|
+
path22.join(root, ".kody-engine", "runtime", relativePath),
|
|
5160
|
+
path22.join(definitionsRoot(root), relativePath)
|
|
5143
5161
|
];
|
|
5144
5162
|
for (const filePath of candidates) {
|
|
5145
5163
|
if (!fs20.existsSync(filePath)) continue;
|
|
@@ -5151,7 +5169,7 @@ function readWorkflowDefinition(_config, cwd, id) {
|
|
|
5151
5169
|
function workflowDefinitionToCapabilityFolder(id, workflow, source = workflowDefinitionPath(id)) {
|
|
5152
5170
|
return {
|
|
5153
5171
|
slug: id,
|
|
5154
|
-
dir:
|
|
5172
|
+
dir: path22.dirname(source),
|
|
5155
5173
|
profilePath: source,
|
|
5156
5174
|
bodyPath: source,
|
|
5157
5175
|
title: workflow.name,
|
|
@@ -5752,7 +5770,7 @@ var init_lifecycles = __esm({
|
|
|
5752
5770
|
// src/profile.ts
|
|
5753
5771
|
import { createHash as createHash3 } from "crypto";
|
|
5754
5772
|
import * as fs24 from "fs";
|
|
5755
|
-
import * as
|
|
5773
|
+
import * as path24 from "path";
|
|
5756
5774
|
function loadProfile(profilePath) {
|
|
5757
5775
|
if (!fs24.existsSync(profilePath)) {
|
|
5758
5776
|
throw new ProfileError(profilePath, "file not found");
|
|
@@ -5771,7 +5789,7 @@ function loadProfile(profilePath) {
|
|
|
5771
5789
|
const unknownKeys = Object.keys(r).filter((k) => !KNOWN_PROFILE_KEYS.has(k));
|
|
5772
5790
|
if (unknownKeys.length > 0) {
|
|
5773
5791
|
process.stderr.write(
|
|
5774
|
-
`[kody profile] ${
|
|
5792
|
+
`[kody profile] ${path24.basename(path24.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
|
|
5775
5793
|
`
|
|
5776
5794
|
);
|
|
5777
5795
|
}
|
|
@@ -5781,7 +5799,7 @@ function loadProfile(profilePath) {
|
|
|
5781
5799
|
if (!refPath) {
|
|
5782
5800
|
throw new ProfileError(profilePath, `capability references unknown implementation '${execRef}'`);
|
|
5783
5801
|
}
|
|
5784
|
-
if (
|
|
5802
|
+
if (path24.resolve(refPath) === path24.resolve(profilePath)) {
|
|
5785
5803
|
} else {
|
|
5786
5804
|
const base = loadProfile(refPath);
|
|
5787
5805
|
return {
|
|
@@ -5879,8 +5897,8 @@ function loadProfile(profilePath) {
|
|
|
5879
5897
|
// Phase 5 in-process handoff opt-in. Default false; containers
|
|
5880
5898
|
// flip to true after end-to-end verification.
|
|
5881
5899
|
preloadContext: r.preloadContext === true,
|
|
5882
|
-
dir:
|
|
5883
|
-
promptTemplates: readPromptTemplates(
|
|
5900
|
+
dir: path24.dirname(profilePath),
|
|
5901
|
+
promptTemplates: readPromptTemplates(path24.dirname(profilePath))
|
|
5884
5902
|
};
|
|
5885
5903
|
if (lifecycle) {
|
|
5886
5904
|
applyLifecycle(profile, profilePath);
|
|
@@ -5915,19 +5933,19 @@ function loadProfile(profilePath) {
|
|
|
5915
5933
|
return profile;
|
|
5916
5934
|
}
|
|
5917
5935
|
function compileRuntimeDocument(runtimePath, document) {
|
|
5918
|
-
if (
|
|
5936
|
+
if (path24.basename(runtimePath) !== "runtime.json") return document;
|
|
5919
5937
|
if (document.adapter !== "kody-engine-profile") {
|
|
5920
5938
|
throw new ProfileError(runtimePath, "unsupported runtime adapter document");
|
|
5921
5939
|
}
|
|
5922
|
-
const implementationDir =
|
|
5923
|
-
const implementation = readJsonObject(
|
|
5924
|
-
const definitionsRoot2 =
|
|
5940
|
+
const implementationDir = path24.dirname(runtimePath);
|
|
5941
|
+
const implementation = readJsonObject(path24.join(implementationDir, "definition.json"), "Implementation definition");
|
|
5942
|
+
const definitionsRoot2 = path24.dirname(path24.dirname(implementationDir));
|
|
5925
5943
|
const capabilityId = implementation.capabilityRef && typeof implementation.capabilityRef === "object" && !Array.isArray(implementation.capabilityRef) ? implementation.capabilityRef.id : void 0;
|
|
5926
5944
|
if (typeof capabilityId !== "string" || !capabilityId) {
|
|
5927
5945
|
throw new ProfileError(runtimePath, "Implementation capabilityRef is invalid");
|
|
5928
5946
|
}
|
|
5929
5947
|
const capability = readJsonObject(
|
|
5930
|
-
|
|
5948
|
+
path24.join(definitionsRoot2, "capabilities", capabilityId, "definition.json"),
|
|
5931
5949
|
"Capability definition"
|
|
5932
5950
|
);
|
|
5933
5951
|
const {
|
|
@@ -5988,13 +6006,13 @@ function readPromptTemplates(dir) {
|
|
|
5988
6006
|
} catch {
|
|
5989
6007
|
}
|
|
5990
6008
|
};
|
|
5991
|
-
read(
|
|
5992
|
-
read(
|
|
5993
|
-
read(
|
|
6009
|
+
read(path24.join(dir, "prompt.md"));
|
|
6010
|
+
read(path24.join(dir, "capability.md"));
|
|
6011
|
+
read(path24.join(dir, "capability.md"));
|
|
5994
6012
|
try {
|
|
5995
|
-
const promptsDir =
|
|
6013
|
+
const promptsDir = path24.join(dir, "prompts");
|
|
5996
6014
|
for (const ent of fs24.readdirSync(promptsDir)) {
|
|
5997
|
-
if (ent.endsWith(".md")) read(
|
|
6015
|
+
if (ent.endsWith(".md")) read(path24.join(promptsDir, ent));
|
|
5998
6016
|
}
|
|
5999
6017
|
} catch {
|
|
6000
6018
|
}
|
|
@@ -6772,11 +6790,11 @@ var init_state = __esm({
|
|
|
6772
6790
|
|
|
6773
6791
|
// src/prompt.ts
|
|
6774
6792
|
import * as fs25 from "fs";
|
|
6775
|
-
import * as
|
|
6793
|
+
import * as path25 from "path";
|
|
6776
6794
|
function loadProjectConventions(projectDir) {
|
|
6777
6795
|
const out = [];
|
|
6778
6796
|
for (const rel of CONVENTION_FILES) {
|
|
6779
|
-
const abs =
|
|
6797
|
+
const abs = path25.join(projectDir, rel);
|
|
6780
6798
|
if (!fs25.existsSync(abs)) continue;
|
|
6781
6799
|
let content;
|
|
6782
6800
|
try {
|
|
@@ -7016,7 +7034,7 @@ __export(loadMemoryContext_exports, {
|
|
|
7016
7034
|
loadMemoryContext: () => loadMemoryContext
|
|
7017
7035
|
});
|
|
7018
7036
|
import * as fs26 from "fs";
|
|
7019
|
-
import * as
|
|
7037
|
+
import * as path26 from "path";
|
|
7020
7038
|
function formatBlockFromBackend(docs) {
|
|
7021
7039
|
const pages = docs.flatMap((record2) => {
|
|
7022
7040
|
if (!record2.doc || typeof record2.doc !== "object") return [];
|
|
@@ -7050,10 +7068,10 @@ function collectPages(memoryAbs) {
|
|
|
7050
7068
|
return;
|
|
7051
7069
|
}
|
|
7052
7070
|
const fm = raw.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
7053
|
-
const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ??
|
|
7071
|
+
const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path26.basename(file, ".md");
|
|
7054
7072
|
const updated = fm?.[1]?.match(/^updated:\s*([0-9T:.+\-Z]+)/m)?.[1]?.trim() ?? "";
|
|
7055
7073
|
out.push({
|
|
7056
|
-
relPath:
|
|
7074
|
+
relPath: path26.relative(memoryAbs, file),
|
|
7057
7075
|
title,
|
|
7058
7076
|
updated,
|
|
7059
7077
|
content: raw.length > PER_PAGE_MAX_BYTES ? raw.slice(0, PER_PAGE_MAX_BYTES) + TRUNCATED_SUFFIX2 : raw,
|
|
@@ -7127,7 +7145,7 @@ function walkMd(root, visit) {
|
|
|
7127
7145
|
}
|
|
7128
7146
|
for (const name of names) {
|
|
7129
7147
|
if (name.startsWith(".")) continue;
|
|
7130
|
-
const full =
|
|
7148
|
+
const full = path26.join(dir, name);
|
|
7131
7149
|
let stat;
|
|
7132
7150
|
try {
|
|
7133
7151
|
stat = fs26.statSync(full);
|
|
@@ -7165,7 +7183,7 @@ var init_loadMemoryContext = __esm({
|
|
|
7165
7183
|
}
|
|
7166
7184
|
return;
|
|
7167
7185
|
}
|
|
7168
|
-
const memoryAbs =
|
|
7186
|
+
const memoryAbs = path26.join(ctx.cwd, MEMORY_DIR_RELATIVE);
|
|
7169
7187
|
if (!fs26.existsSync(memoryAbs)) {
|
|
7170
7188
|
ctx.data.memoryContext = "";
|
|
7171
7189
|
return;
|
|
@@ -7681,7 +7699,7 @@ import { execFileSync as execFileSync4, spawn as spawn4 } from "child_process";
|
|
|
7681
7699
|
import * as fs28 from "fs";
|
|
7682
7700
|
import * as net from "net";
|
|
7683
7701
|
import * as os4 from "os";
|
|
7684
|
-
import * as
|
|
7702
|
+
import * as path27 from "path";
|
|
7685
7703
|
async function checkLitellmHealth(url) {
|
|
7686
7704
|
try {
|
|
7687
7705
|
const response = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3e3) });
|
|
@@ -7794,10 +7812,10 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
|
|
|
7794
7812
|
const spawnProxy = () => {
|
|
7795
7813
|
const portMatch = activeUrl.match(/:(\d+)/);
|
|
7796
7814
|
const port = portMatch ? portMatch[1] : "4000";
|
|
7797
|
-
const configPath =
|
|
7815
|
+
const configPath = path27.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.yaml`);
|
|
7798
7816
|
fs28.writeFileSync(configPath, generateLitellmConfigYaml(model));
|
|
7799
7817
|
const args = ["--config", configPath, "--port", port];
|
|
7800
|
-
const nextLogPath =
|
|
7818
|
+
const nextLogPath = path27.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.log`);
|
|
7801
7819
|
const outFd = fs28.openSync(nextLogPath, "w");
|
|
7802
7820
|
child = spawn4(cmd, args, { stdio: ["ignore", outFd, outFd], detached: true, env: childEnv });
|
|
7803
7821
|
fs28.closeSync(outFd);
|
|
@@ -7887,17 +7905,17 @@ async function nextAvailableLitellmUrl(url) {
|
|
|
7887
7905
|
throw new Error(`no free LiteLLM port found after ${startPort}`);
|
|
7888
7906
|
}
|
|
7889
7907
|
function canListen(port, host) {
|
|
7890
|
-
return new Promise((
|
|
7908
|
+
return new Promise((resolve24) => {
|
|
7891
7909
|
const server = net.createServer();
|
|
7892
|
-
server.once("error", () =>
|
|
7910
|
+
server.once("error", () => resolve24(false));
|
|
7893
7911
|
server.once("listening", () => {
|
|
7894
|
-
server.close(() =>
|
|
7912
|
+
server.close(() => resolve24(true));
|
|
7895
7913
|
});
|
|
7896
7914
|
server.listen(port, host);
|
|
7897
7915
|
});
|
|
7898
7916
|
}
|
|
7899
7917
|
function readDotenvApiKeys(projectDir) {
|
|
7900
|
-
const dotenvPath =
|
|
7918
|
+
const dotenvPath = path27.join(projectDir, ".env");
|
|
7901
7919
|
if (!fs28.existsSync(dotenvPath)) return {};
|
|
7902
7920
|
const result = {};
|
|
7903
7921
|
for (const rawLine of fs28.readFileSync(dotenvPath, "utf-8").split("\n")) {
|
|
@@ -8560,7 +8578,7 @@ var init_pushWithRetry = __esm({
|
|
|
8560
8578
|
// src/commit.ts
|
|
8561
8579
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
8562
8580
|
import * as fs29 from "fs";
|
|
8563
|
-
import * as
|
|
8581
|
+
import * as path28 from "path";
|
|
8564
8582
|
function isGitHubYamlPath(filePath) {
|
|
8565
8583
|
const normalized = filePath.replace(/^\.\/+/, "");
|
|
8566
8584
|
return normalized.startsWith(".github/") && /\.ya?ml$/i.test(normalized);
|
|
@@ -8602,18 +8620,18 @@ function ensureGitIdentity(cwd) {
|
|
|
8602
8620
|
}
|
|
8603
8621
|
function abortUnfinishedGitOps(cwd) {
|
|
8604
8622
|
const aborted = [];
|
|
8605
|
-
const gitDir =
|
|
8623
|
+
const gitDir = path28.join(cwd ?? process.cwd(), ".git");
|
|
8606
8624
|
if (!fs29.existsSync(gitDir)) return aborted;
|
|
8607
|
-
if (fs29.existsSync(
|
|
8625
|
+
if (fs29.existsSync(path28.join(gitDir, "MERGE_HEAD"))) {
|
|
8608
8626
|
if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
|
|
8609
8627
|
}
|
|
8610
|
-
if (fs29.existsSync(
|
|
8628
|
+
if (fs29.existsSync(path28.join(gitDir, "CHERRY_PICK_HEAD"))) {
|
|
8611
8629
|
if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
|
|
8612
8630
|
}
|
|
8613
|
-
if (fs29.existsSync(
|
|
8631
|
+
if (fs29.existsSync(path28.join(gitDir, "REVERT_HEAD"))) {
|
|
8614
8632
|
if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
|
|
8615
8633
|
}
|
|
8616
|
-
if (fs29.existsSync(
|
|
8634
|
+
if (fs29.existsSync(path28.join(gitDir, "rebase-merge")) || fs29.existsSync(path28.join(gitDir, "rebase-apply"))) {
|
|
8617
8635
|
if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
|
|
8618
8636
|
}
|
|
8619
8637
|
try {
|
|
@@ -8670,7 +8688,7 @@ function normalizeCommitMessage(raw) {
|
|
|
8670
8688
|
function commitAndPush(branch, agentMessage, cwd) {
|
|
8671
8689
|
const allChanged = listChangedFiles(cwd);
|
|
8672
8690
|
const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
|
|
8673
|
-
const mergeHeadExists = fs29.existsSync(
|
|
8691
|
+
const mergeHeadExists = fs29.existsSync(path28.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
|
|
8674
8692
|
if (allowedFiles.length === 0 && !mergeHeadExists) {
|
|
8675
8693
|
return { committed: false, pushed: false, sha: "", message: "" };
|
|
8676
8694
|
}
|
|
@@ -9314,9 +9332,9 @@ import * as fs30 from "fs";
|
|
|
9314
9332
|
function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
|
|
9315
9333
|
const logs = goalRunLogs(data);
|
|
9316
9334
|
const existing = logs[goalId];
|
|
9317
|
-
const
|
|
9335
|
+
const path59 = existing?.path ?? goalRunLogPath(goalId, data);
|
|
9318
9336
|
logs[goalId] = {
|
|
9319
|
-
path:
|
|
9337
|
+
path: path59,
|
|
9320
9338
|
events: [...existing?.events ?? [], buildGoalRunLogEvent(data, goalId, event, at)]
|
|
9321
9339
|
};
|
|
9322
9340
|
}
|
|
@@ -9764,7 +9782,7 @@ var init_stateStore = __esm({
|
|
|
9764
9782
|
|
|
9765
9783
|
// src/goal/targetLoopResolution.ts
|
|
9766
9784
|
import * as fs31 from "fs";
|
|
9767
|
-
import * as
|
|
9785
|
+
import * as path29 from "path";
|
|
9768
9786
|
async function resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal) {
|
|
9769
9787
|
const targetId = loopGoal.loopTarget?.id.trim() ?? "";
|
|
9770
9788
|
assertSafeGoalId(targetId, "loop target");
|
|
@@ -9842,7 +9860,7 @@ function goalInstanceTime(state) {
|
|
|
9842
9860
|
return Number.isNaN(parsed) ? 0 : parsed;
|
|
9843
9861
|
}
|
|
9844
9862
|
function loadGoalTemplate(cwd, targetId) {
|
|
9845
|
-
return readJsonObject2(
|
|
9863
|
+
return readJsonObject2(path29.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
|
|
9846
9864
|
}
|
|
9847
9865
|
function readJsonObject2(filePath) {
|
|
9848
9866
|
if (!fs31.existsSync(filePath)) return null;
|
|
@@ -10193,15 +10211,15 @@ var init_backendStateBackend = __esm({
|
|
|
10193
10211
|
this.jobsDir = opts.jobsDir.replace(/\/+$/, "");
|
|
10194
10212
|
}
|
|
10195
10213
|
async load(slug) {
|
|
10196
|
-
const
|
|
10214
|
+
const path59 = stateFilePath(this.jobsDir, slug);
|
|
10197
10215
|
const loaded = await createStateBackendFromEnv().get(this.tenantId, `capabilities/${slug}`, "job-state");
|
|
10198
10216
|
if (!loaded) {
|
|
10199
|
-
return { path:
|
|
10217
|
+
return { path: path59, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
10200
10218
|
}
|
|
10201
10219
|
if (!isStateEnvelope(loaded.doc)) {
|
|
10202
10220
|
throw new Error(`BackendStateBackend: capabilities/${slug} is not a StateEnvelope`);
|
|
10203
10221
|
}
|
|
10204
|
-
return { path:
|
|
10222
|
+
return { path: path59, handle: loaded.updatedAt, state: loaded.doc, created: false };
|
|
10205
10223
|
}
|
|
10206
10224
|
async save(loaded, next) {
|
|
10207
10225
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) return false;
|
|
@@ -10222,7 +10240,7 @@ var init_backendStateBackend = __esm({
|
|
|
10222
10240
|
|
|
10223
10241
|
// src/scripts/jobState/localFileBackend.ts
|
|
10224
10242
|
import * as fs32 from "fs";
|
|
10225
|
-
import * as
|
|
10243
|
+
import * as path30 from "path";
|
|
10226
10244
|
function sanitizeKey(s) {
|
|
10227
10245
|
return s.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
10228
10246
|
}
|
|
@@ -10278,7 +10296,7 @@ var init_localFileBackend = __esm({
|
|
|
10278
10296
|
if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
|
|
10279
10297
|
this.cwd = opts.cwd;
|
|
10280
10298
|
this.jobsDir = opts.jobsDir;
|
|
10281
|
-
this.absDir =
|
|
10299
|
+
this.absDir = path30.resolve(opts.cwd, opts.jobsDir);
|
|
10282
10300
|
this.owner = opts.owner;
|
|
10283
10301
|
this.repo = opts.repo;
|
|
10284
10302
|
this.cache = opts.cache ?? defaultCacheAdapter();
|
|
@@ -10338,7 +10356,7 @@ var init_localFileBackend = __esm({
|
|
|
10338
10356
|
}
|
|
10339
10357
|
load(slug) {
|
|
10340
10358
|
const relPath = stateFilePath(this.jobsDir, slug);
|
|
10341
|
-
const absPath =
|
|
10359
|
+
const absPath = path30.resolve(this.cwd, relPath);
|
|
10342
10360
|
if (!fs32.existsSync(absPath)) {
|
|
10343
10361
|
return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
10344
10362
|
}
|
|
@@ -10359,8 +10377,8 @@ var init_localFileBackend = __esm({
|
|
|
10359
10377
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) {
|
|
10360
10378
|
return false;
|
|
10361
10379
|
}
|
|
10362
|
-
const absPath =
|
|
10363
|
-
fs32.mkdirSync(
|
|
10380
|
+
const absPath = path30.resolve(this.cwd, loaded.path);
|
|
10381
|
+
fs32.mkdirSync(path30.dirname(absPath), { recursive: true });
|
|
10364
10382
|
const body = `${JSON.stringify(next, null, 2)}
|
|
10365
10383
|
`;
|
|
10366
10384
|
const tmpPath = `${absPath}.${process.pid}.tmp`;
|
|
@@ -10397,7 +10415,7 @@ var init_jobState = __esm({
|
|
|
10397
10415
|
});
|
|
10398
10416
|
|
|
10399
10417
|
// src/scripts/goalCapabilityScheduling.ts
|
|
10400
|
-
import * as
|
|
10418
|
+
import * as path31 from "path";
|
|
10401
10419
|
function isCapabilityCadenceGoal(goal, extra) {
|
|
10402
10420
|
return extra.scheduleMode === "agentLoop" || extra.scheduler === "agentLoop" || goal.type === "standing" && goal.capabilities.length > 0;
|
|
10403
10421
|
}
|
|
@@ -10453,7 +10471,7 @@ function planTargetLoopSchedule(opts) {
|
|
|
10453
10471
|
}
|
|
10454
10472
|
async function planGoalCapabilitySchedule(opts) {
|
|
10455
10473
|
const jobsDir = opts.jobsDir ?? capabilitiesRoot(opts.cwd);
|
|
10456
|
-
const jobsRoot =
|
|
10474
|
+
const jobsRoot = path31.resolve(opts.cwd, jobsDir);
|
|
10457
10475
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
10458
10476
|
const at = now.toISOString();
|
|
10459
10477
|
const backend = resolveBackend({ config: opts.config, cwd: opts.cwd, jobsDir });
|
|
@@ -12176,6 +12194,11 @@ var init_checkCoverageWithRetry = __esm({
|
|
|
12176
12194
|
init_coverage();
|
|
12177
12195
|
init_prompt();
|
|
12178
12196
|
checkCoverageWithRetry = async (ctx) => {
|
|
12197
|
+
if (ctx.data.capabilityDeliveryPolicy === "checkpoint") {
|
|
12198
|
+
ctx.data.verificationDeferred = true;
|
|
12199
|
+
ctx.data.coverageMisses = [];
|
|
12200
|
+
return;
|
|
12201
|
+
}
|
|
12179
12202
|
const reqs = ctx.data.coverageRules ?? [];
|
|
12180
12203
|
if (reqs.length === 0) {
|
|
12181
12204
|
ctx.data.coverageMisses = [];
|
|
@@ -12270,7 +12293,7 @@ var init_classifyByLabel = __esm({
|
|
|
12270
12293
|
// src/scripts/commitAndPush.ts
|
|
12271
12294
|
import { createHash as createHash5 } from "crypto";
|
|
12272
12295
|
import * as fs33 from "fs";
|
|
12273
|
-
import * as
|
|
12296
|
+
import * as path32 from "path";
|
|
12274
12297
|
function sentinelPathForStage(cwd, profileName, workflowExecutionKey) {
|
|
12275
12298
|
const runId = resolveRunId();
|
|
12276
12299
|
const executionSuffix = typeof workflowExecutionKey === "string" && workflowExecutionKey.length > 0 ? `-${createHash5("sha256").update(workflowExecutionKey).digest("hex").slice(0, 16)}` : "";
|
|
@@ -12354,7 +12377,7 @@ var init_commitAndPush = __esm({
|
|
|
12354
12377
|
const result = ctx.data.commitResult;
|
|
12355
12378
|
if (sentinel && result?.committed) {
|
|
12356
12379
|
try {
|
|
12357
|
-
fs33.mkdirSync(
|
|
12380
|
+
fs33.mkdirSync(path32.dirname(sentinel), { recursive: true });
|
|
12358
12381
|
fs33.writeFileSync(
|
|
12359
12382
|
sentinel,
|
|
12360
12383
|
JSON.stringify(
|
|
@@ -12450,7 +12473,7 @@ var init_commitGoalState = __esm({
|
|
|
12450
12473
|
|
|
12451
12474
|
// src/scripts/composePrompt.ts
|
|
12452
12475
|
import * as fs34 from "fs";
|
|
12453
|
-
import * as
|
|
12476
|
+
import * as path33 from "path";
|
|
12454
12477
|
function fenceUntrusted(value) {
|
|
12455
12478
|
if (value.trim().length === 0) return value;
|
|
12456
12479
|
const safe = value.replace(/-{3,}\s*END UNTRUSTED INPUT\s*-{3,}/gi, "[END UNTRUSTED INPUT]");
|
|
@@ -12574,10 +12597,10 @@ var init_composePrompt = __esm({
|
|
|
12574
12597
|
const explicit = ctx.data.promptTemplate;
|
|
12575
12598
|
const mode = ctx.args.mode;
|
|
12576
12599
|
const candidates = [
|
|
12577
|
-
explicit ?
|
|
12578
|
-
mode ?
|
|
12579
|
-
|
|
12580
|
-
|
|
12600
|
+
explicit ? path33.join(profile.dir, explicit) : null,
|
|
12601
|
+
mode ? path33.join(profile.dir, "prompts", `${mode}.md`) : null,
|
|
12602
|
+
path33.join(profile.dir, "prompt.md"),
|
|
12603
|
+
path33.join(profile.dir, "capability.md")
|
|
12581
12604
|
].filter(Boolean);
|
|
12582
12605
|
let templatePath = "";
|
|
12583
12606
|
let template = "";
|
|
@@ -13337,14 +13360,14 @@ var init_deriveQaScopeFromIssue = __esm({
|
|
|
13337
13360
|
import { execFileSync as execFileSync9 } from "child_process";
|
|
13338
13361
|
import * as fs35 from "fs";
|
|
13339
13362
|
import * as os5 from "os";
|
|
13340
|
-
import * as
|
|
13363
|
+
import * as path34 from "path";
|
|
13341
13364
|
var diagMcp;
|
|
13342
13365
|
var init_diagMcp = __esm({
|
|
13343
13366
|
"src/scripts/diagMcp.ts"() {
|
|
13344
13367
|
"use strict";
|
|
13345
13368
|
diagMcp = async (_ctx) => {
|
|
13346
13369
|
const home = os5.homedir();
|
|
13347
|
-
const cacheDir =
|
|
13370
|
+
const cacheDir = path34.join(home, ".cache", "ms-playwright");
|
|
13348
13371
|
let entries = [];
|
|
13349
13372
|
try {
|
|
13350
13373
|
entries = fs35.readdirSync(cacheDir);
|
|
@@ -13376,12 +13399,12 @@ var init_diagMcp = __esm({
|
|
|
13376
13399
|
|
|
13377
13400
|
// src/scripts/frameworkDetectors.ts
|
|
13378
13401
|
import * as fs36 from "fs";
|
|
13379
|
-
import * as
|
|
13402
|
+
import * as path35 from "path";
|
|
13380
13403
|
function detectFrameworks(cwd) {
|
|
13381
13404
|
const out = [];
|
|
13382
13405
|
let deps = {};
|
|
13383
13406
|
try {
|
|
13384
|
-
const pkg = JSON.parse(fs36.readFileSync(
|
|
13407
|
+
const pkg = JSON.parse(fs36.readFileSync(path35.join(cwd, "package.json"), "utf-8"));
|
|
13385
13408
|
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13386
13409
|
} catch {
|
|
13387
13410
|
return out;
|
|
@@ -13418,14 +13441,14 @@ function detectFrameworks(cwd) {
|
|
|
13418
13441
|
}
|
|
13419
13442
|
function findFile(cwd, candidates) {
|
|
13420
13443
|
for (const c of candidates) {
|
|
13421
|
-
if (fs36.existsSync(
|
|
13444
|
+
if (fs36.existsSync(path35.join(cwd, c))) return c;
|
|
13422
13445
|
}
|
|
13423
13446
|
return null;
|
|
13424
13447
|
}
|
|
13425
13448
|
function discoverPayloadCollections(cwd) {
|
|
13426
13449
|
const out = [];
|
|
13427
13450
|
for (const dir of COLLECTION_DIRS) {
|
|
13428
|
-
const full =
|
|
13451
|
+
const full = path35.join(cwd, dir);
|
|
13429
13452
|
if (!fs36.existsSync(full)) continue;
|
|
13430
13453
|
let files;
|
|
13431
13454
|
try {
|
|
@@ -13435,7 +13458,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
13435
13458
|
}
|
|
13436
13459
|
for (const file of files) {
|
|
13437
13460
|
try {
|
|
13438
|
-
const filePath =
|
|
13461
|
+
const filePath = path35.join(full, file);
|
|
13439
13462
|
const content = fs36.readFileSync(filePath, "utf-8").slice(0, 1e4);
|
|
13440
13463
|
const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
|
|
13441
13464
|
if (!slugMatch) continue;
|
|
@@ -13450,7 +13473,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
13450
13473
|
out.push({
|
|
13451
13474
|
name,
|
|
13452
13475
|
slug,
|
|
13453
|
-
filePath:
|
|
13476
|
+
filePath: path35.relative(cwd, filePath),
|
|
13454
13477
|
fields: fields.slice(0, 20),
|
|
13455
13478
|
hasAdmin
|
|
13456
13479
|
});
|
|
@@ -13463,7 +13486,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
13463
13486
|
function discoverAdminComponents(cwd, collections) {
|
|
13464
13487
|
const out = [];
|
|
13465
13488
|
for (const dir of ADMIN_COMPONENT_DIRS) {
|
|
13466
|
-
const full =
|
|
13489
|
+
const full = path35.join(cwd, dir);
|
|
13467
13490
|
if (!fs36.existsSync(full)) continue;
|
|
13468
13491
|
let entries;
|
|
13469
13492
|
try {
|
|
@@ -13472,19 +13495,19 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
13472
13495
|
continue;
|
|
13473
13496
|
}
|
|
13474
13497
|
for (const entry of entries) {
|
|
13475
|
-
const entryPath =
|
|
13498
|
+
const entryPath = path35.join(full, entry.name);
|
|
13476
13499
|
let name;
|
|
13477
13500
|
let filePath;
|
|
13478
13501
|
if (entry.isDirectory()) {
|
|
13479
13502
|
const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
|
|
13480
|
-
(f) => fs36.existsSync(
|
|
13503
|
+
(f) => fs36.existsSync(path35.join(entryPath, f))
|
|
13481
13504
|
);
|
|
13482
13505
|
if (!indexFile) continue;
|
|
13483
13506
|
name = entry.name;
|
|
13484
|
-
filePath =
|
|
13507
|
+
filePath = path35.relative(cwd, path35.join(entryPath, indexFile));
|
|
13485
13508
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
13486
13509
|
name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
|
|
13487
|
-
filePath =
|
|
13510
|
+
filePath = path35.relative(cwd, entryPath);
|
|
13488
13511
|
} else {
|
|
13489
13512
|
continue;
|
|
13490
13513
|
}
|
|
@@ -13492,7 +13515,7 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
13492
13515
|
if (collections) {
|
|
13493
13516
|
for (const col of collections) {
|
|
13494
13517
|
try {
|
|
13495
|
-
const colContent = fs36.readFileSync(
|
|
13518
|
+
const colContent = fs36.readFileSync(path35.join(cwd, col.filePath), "utf-8");
|
|
13496
13519
|
if (colContent.includes(name)) {
|
|
13497
13520
|
usedInCollection = col.slug;
|
|
13498
13521
|
break;
|
|
@@ -13510,7 +13533,7 @@ function scanApiRoutes(cwd) {
|
|
|
13510
13533
|
const out = [];
|
|
13511
13534
|
const appDirs = ["src/app", "app"];
|
|
13512
13535
|
for (const appDir of appDirs) {
|
|
13513
|
-
const apiDir =
|
|
13536
|
+
const apiDir = path35.join(cwd, appDir, "api");
|
|
13514
13537
|
if (!fs36.existsSync(apiDir)) continue;
|
|
13515
13538
|
walkApiRoutes(apiDir, "/api", cwd, out);
|
|
13516
13539
|
break;
|
|
@@ -13527,7 +13550,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
13527
13550
|
const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
|
|
13528
13551
|
if (routeFile) {
|
|
13529
13552
|
try {
|
|
13530
|
-
const content = fs36.readFileSync(
|
|
13553
|
+
const content = fs36.readFileSync(path35.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
|
|
13531
13554
|
const methods = HTTP_METHODS.filter(
|
|
13532
13555
|
(m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
|
|
13533
13556
|
);
|
|
@@ -13535,7 +13558,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
13535
13558
|
out.push({
|
|
13536
13559
|
path: prefix,
|
|
13537
13560
|
methods,
|
|
13538
|
-
filePath:
|
|
13561
|
+
filePath: path35.relative(cwd, path35.join(dir, routeFile.name))
|
|
13539
13562
|
});
|
|
13540
13563
|
}
|
|
13541
13564
|
} catch {
|
|
@@ -13546,7 +13569,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
13546
13569
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
13547
13570
|
let segment = entry.name;
|
|
13548
13571
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
13549
|
-
walkApiRoutes(
|
|
13572
|
+
walkApiRoutes(path35.join(dir, entry.name), prefix, cwd, out);
|
|
13550
13573
|
continue;
|
|
13551
13574
|
}
|
|
13552
13575
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -13554,13 +13577,13 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
13554
13577
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
13555
13578
|
segment = `:${segment.slice(1, -1)}`;
|
|
13556
13579
|
}
|
|
13557
|
-
walkApiRoutes(
|
|
13580
|
+
walkApiRoutes(path35.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
|
|
13558
13581
|
}
|
|
13559
13582
|
}
|
|
13560
13583
|
function scanEnvVars(cwd) {
|
|
13561
13584
|
const candidates = [".env.example", ".env.local.example", ".env.template"];
|
|
13562
13585
|
for (const envFile of candidates) {
|
|
13563
|
-
const envPath =
|
|
13586
|
+
const envPath = path35.join(cwd, envFile);
|
|
13564
13587
|
if (!fs36.existsSync(envPath)) continue;
|
|
13565
13588
|
try {
|
|
13566
13589
|
const content = fs36.readFileSync(envPath, "utf-8");
|
|
@@ -13609,7 +13632,7 @@ var init_frameworkDetectors = __esm({
|
|
|
13609
13632
|
|
|
13610
13633
|
// src/scripts/discoverQaContext.ts
|
|
13611
13634
|
import * as fs37 from "fs";
|
|
13612
|
-
import * as
|
|
13635
|
+
import * as path36 from "path";
|
|
13613
13636
|
function runQaDiscovery(cwd) {
|
|
13614
13637
|
const out = {
|
|
13615
13638
|
routes: [],
|
|
@@ -13640,9 +13663,9 @@ function runQaDiscovery(cwd) {
|
|
|
13640
13663
|
}
|
|
13641
13664
|
function detectDevServer(cwd, out) {
|
|
13642
13665
|
try {
|
|
13643
|
-
const pkg = JSON.parse(fs37.readFileSync(
|
|
13666
|
+
const pkg = JSON.parse(fs37.readFileSync(path36.join(cwd, "package.json"), "utf-8"));
|
|
13644
13667
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13645
|
-
const pm = fs37.existsSync(
|
|
13668
|
+
const pm = fs37.existsSync(path36.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs37.existsSync(path36.join(cwd, "yarn.lock")) ? "yarn" : fs37.existsSync(path36.join(cwd, "bun.lockb")) ? "bun" : "npm";
|
|
13646
13669
|
if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
|
|
13647
13670
|
if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
|
|
13648
13671
|
else if (allDeps.vite) out.devPort = 5173;
|
|
@@ -13652,7 +13675,7 @@ function detectDevServer(cwd, out) {
|
|
|
13652
13675
|
function scanFrontendRoutes(cwd, out) {
|
|
13653
13676
|
const appDirs = ["src/app", "app"];
|
|
13654
13677
|
for (const appDir of appDirs) {
|
|
13655
|
-
const full =
|
|
13678
|
+
const full = path36.join(cwd, appDir);
|
|
13656
13679
|
if (!fs37.existsSync(full)) continue;
|
|
13657
13680
|
walkFrontendRoutes(full, "", out);
|
|
13658
13681
|
break;
|
|
@@ -13678,7 +13701,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
13678
13701
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
13679
13702
|
let segment = entry.name;
|
|
13680
13703
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
13681
|
-
walkFrontendRoutes(
|
|
13704
|
+
walkFrontendRoutes(path36.join(dir, entry.name), prefix, out);
|
|
13682
13705
|
continue;
|
|
13683
13706
|
}
|
|
13684
13707
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -13686,7 +13709,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
13686
13709
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
13687
13710
|
segment = `:${segment.slice(1, -1)}`;
|
|
13688
13711
|
}
|
|
13689
|
-
walkFrontendRoutes(
|
|
13712
|
+
walkFrontendRoutes(path36.join(dir, entry.name), `${prefix}/${segment}`, out);
|
|
13690
13713
|
}
|
|
13691
13714
|
}
|
|
13692
13715
|
function detectAuthFiles(cwd, out) {
|
|
@@ -13703,13 +13726,13 @@ function detectAuthFiles(cwd, out) {
|
|
|
13703
13726
|
"src/app/api/oauth"
|
|
13704
13727
|
];
|
|
13705
13728
|
for (const c of candidates) {
|
|
13706
|
-
if (fs37.existsSync(
|
|
13729
|
+
if (fs37.existsSync(path36.join(cwd, c))) out.authFiles.push(c);
|
|
13707
13730
|
}
|
|
13708
13731
|
}
|
|
13709
13732
|
function detectRoles(cwd, out) {
|
|
13710
13733
|
const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
|
|
13711
13734
|
for (const rp of rolePaths) {
|
|
13712
|
-
const dir =
|
|
13735
|
+
const dir = path36.join(cwd, rp);
|
|
13713
13736
|
if (!fs37.existsSync(dir)) continue;
|
|
13714
13737
|
let files;
|
|
13715
13738
|
try {
|
|
@@ -13719,7 +13742,7 @@ function detectRoles(cwd, out) {
|
|
|
13719
13742
|
}
|
|
13720
13743
|
for (const f of files) {
|
|
13721
13744
|
try {
|
|
13722
|
-
const content = fs37.readFileSync(
|
|
13745
|
+
const content = fs37.readFileSync(path36.join(dir, f), "utf-8").slice(0, 5e3);
|
|
13723
13746
|
const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
|
|
13724
13747
|
if (roleMatches) {
|
|
13725
13748
|
for (const m of roleMatches) {
|
|
@@ -13981,7 +14004,7 @@ var init_dispatchClassified = __esm({
|
|
|
13981
14004
|
|
|
13982
14005
|
// src/loopDefinitions.ts
|
|
13983
14006
|
import * as fs38 from "fs";
|
|
13984
|
-
import * as
|
|
14007
|
+
import * as path37 from "path";
|
|
13985
14008
|
function normalizeLoopDefinition(value) {
|
|
13986
14009
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
13987
14010
|
const raw = value;
|
|
@@ -14008,7 +14031,7 @@ function readLoopDefinition(cwd, id) {
|
|
|
14008
14031
|
if (!ID.test(id)) return null;
|
|
14009
14032
|
const roots = loopRoots(cwd);
|
|
14010
14033
|
for (const root of roots) {
|
|
14011
|
-
const filePath =
|
|
14034
|
+
const filePath = path37.join(root, "loops", id, "loop.json");
|
|
14012
14035
|
if (!fs38.existsSync(filePath)) continue;
|
|
14013
14036
|
try {
|
|
14014
14037
|
const loop = normalizeLoopDefinition(JSON.parse(fs38.readFileSync(filePath, "utf8")));
|
|
@@ -14021,7 +14044,7 @@ function readLoopDefinition(cwd, id) {
|
|
|
14021
14044
|
}
|
|
14022
14045
|
}
|
|
14023
14046
|
process.stderr.write(
|
|
14024
|
-
`[kody] Loop not found: ${id} (${roots.map((root) =>
|
|
14047
|
+
`[kody] Loop not found: ${id} (${roots.map((root) => path37.join(root, "loops", id, "loop.json")).join(", ")})
|
|
14025
14048
|
`
|
|
14026
14049
|
);
|
|
14027
14050
|
return null;
|
|
@@ -14030,11 +14053,11 @@ function listLoopDefinitions(cwd) {
|
|
|
14030
14053
|
const roots = loopRoots(cwd);
|
|
14031
14054
|
const byId = /* @__PURE__ */ new Map();
|
|
14032
14055
|
for (const root of roots.reverse()) {
|
|
14033
|
-
const loopsDir =
|
|
14056
|
+
const loopsDir = path37.join(root, "loops");
|
|
14034
14057
|
if (!fs38.existsSync(loopsDir)) continue;
|
|
14035
14058
|
for (const id of fs38.readdirSync(loopsDir).sort()) {
|
|
14036
14059
|
if (!ID.test(id)) continue;
|
|
14037
|
-
const filePath =
|
|
14060
|
+
const filePath = path37.join(loopsDir, id, "loop.json");
|
|
14038
14061
|
if (!fs38.existsSync(filePath)) continue;
|
|
14039
14062
|
try {
|
|
14040
14063
|
const loop = normalizeLoopDefinition(JSON.parse(fs38.readFileSync(filePath, "utf8")));
|
|
@@ -14049,8 +14072,8 @@ function listLoopDefinitions(cwd) {
|
|
|
14049
14072
|
}
|
|
14050
14073
|
function loopRoots(cwd) {
|
|
14051
14074
|
return [
|
|
14052
|
-
|
|
14053
|
-
|
|
14075
|
+
path37.join(cwd, ".kody-engine", "runtime"),
|
|
14076
|
+
path37.join(cwd, ".kody-engine", "definitions"),
|
|
14054
14077
|
definitionsRoot(cwd)
|
|
14055
14078
|
].filter((root, index, roots) => roots.indexOf(root) === index);
|
|
14056
14079
|
}
|
|
@@ -14618,6 +14641,9 @@ function setOutcome(ctx, outcome) {
|
|
|
14618
14641
|
ctx.output.prUrl = outcome.url;
|
|
14619
14642
|
}
|
|
14620
14643
|
}
|
|
14644
|
+
function deliveryCheckpointReason(data) {
|
|
14645
|
+
return data.capabilityDeliveryPolicy === "checkpoint" ? "Repository-wide verification is deferred to pull request CI." : "";
|
|
14646
|
+
}
|
|
14621
14647
|
function computeFailureReason(ctx) {
|
|
14622
14648
|
const expectedTests = collectExpectedTests(ctx.data.coverageMisses);
|
|
14623
14649
|
if (expectedTests.length > 0) return `missing tests: ${expectedTests.join(", ")}`;
|
|
@@ -14687,7 +14713,8 @@ var init_ensurePr = __esm({
|
|
|
14687
14713
|
setOutcome(ctx, { kind: "skipped", reason: "no branch context (ctx.data.branch missing)" });
|
|
14688
14714
|
return;
|
|
14689
14715
|
}
|
|
14690
|
-
const
|
|
14716
|
+
const checkpointReason = deliveryCheckpointReason(ctx.data);
|
|
14717
|
+
const failureReason = computeFailureReason(ctx) || checkpointReason;
|
|
14691
14718
|
const isFailure = failureReason.length > 0;
|
|
14692
14719
|
const changedFiles = ctx.data.changedFiles ?? [];
|
|
14693
14720
|
const issue2 = ctx.data.issue;
|
|
@@ -15329,11 +15356,11 @@ var init_fixFlow = __esm({
|
|
|
15329
15356
|
|
|
15330
15357
|
// src/workflow-template.ts
|
|
15331
15358
|
import * as fs39 from "fs";
|
|
15332
|
-
import * as
|
|
15359
|
+
import * as path38 from "path";
|
|
15333
15360
|
import { fileURLToPath } from "url";
|
|
15334
15361
|
function loadKodyWorkflowTemplate() {
|
|
15335
|
-
const here =
|
|
15336
|
-
const candidates = [
|
|
15362
|
+
const here = path38.dirname(fileURLToPath(import.meta.url));
|
|
15363
|
+
const candidates = [path38.resolve(here, "../templates/kody.yml"), path38.resolve(here, "../../templates/kody.yml")];
|
|
15337
15364
|
const source = candidates.find((candidate) => fs39.existsSync(candidate));
|
|
15338
15365
|
if (!source) throw new Error(`Kody workflow template is missing: ${KODY_WORKFLOW_TEMPLATE_PATH}`);
|
|
15339
15366
|
return fs39.readFileSync(source, "utf8");
|
|
@@ -15349,11 +15376,11 @@ var init_workflow_template = __esm({
|
|
|
15349
15376
|
// src/scripts/initFlow.ts
|
|
15350
15377
|
import { execFileSync as execFileSync14 } from "child_process";
|
|
15351
15378
|
import * as fs40 from "fs";
|
|
15352
|
-
import * as
|
|
15379
|
+
import * as path39 from "path";
|
|
15353
15380
|
function detectPackageManager(cwd) {
|
|
15354
|
-
if (fs40.existsSync(
|
|
15355
|
-
if (fs40.existsSync(
|
|
15356
|
-
if (fs40.existsSync(
|
|
15381
|
+
if (fs40.existsSync(path39.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
15382
|
+
if (fs40.existsSync(path39.join(cwd, "yarn.lock"))) return "yarn";
|
|
15383
|
+
if (fs40.existsSync(path39.join(cwd, "bun.lockb"))) return "bun";
|
|
15357
15384
|
return "npm";
|
|
15358
15385
|
}
|
|
15359
15386
|
function qualityCommandsFor(pm) {
|
|
@@ -15425,7 +15452,7 @@ function performInit(cwd, force) {
|
|
|
15425
15452
|
const pm = detectPackageManager(cwd);
|
|
15426
15453
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
15427
15454
|
const defaultBranch = defaultBranchFromGit(cwd);
|
|
15428
|
-
const configPath =
|
|
15455
|
+
const configPath = path39.join(cwd, "kody.config.json");
|
|
15429
15456
|
if (fs40.existsSync(configPath) && !force) {
|
|
15430
15457
|
skipped.push("kody.config.json");
|
|
15431
15458
|
} else {
|
|
@@ -15434,8 +15461,8 @@ function performInit(cwd, force) {
|
|
|
15434
15461
|
`);
|
|
15435
15462
|
wrote.push("kody.config.json");
|
|
15436
15463
|
}
|
|
15437
|
-
const workflowDir =
|
|
15438
|
-
const workflowPath =
|
|
15464
|
+
const workflowDir = path39.join(cwd, ".github", "workflows");
|
|
15465
|
+
const workflowPath = path39.join(workflowDir, "kody.yml");
|
|
15439
15466
|
if (fs40.existsSync(workflowPath) && !force) {
|
|
15440
15467
|
skipped.push(".github/workflows/kody.yml");
|
|
15441
15468
|
} else {
|
|
@@ -15630,13 +15657,13 @@ var init_loadCapabilityState = __esm({
|
|
|
15630
15657
|
function isCompanyIntentId(value) {
|
|
15631
15658
|
return SLUG_RE2.test(value);
|
|
15632
15659
|
}
|
|
15633
|
-
function normalizeCompanyIntent(
|
|
15660
|
+
function normalizeCompanyIntent(path59, raw) {
|
|
15634
15661
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
15635
|
-
throw new Error(`${
|
|
15662
|
+
throw new Error(`${path59}: intent must be JSON object`);
|
|
15636
15663
|
}
|
|
15637
15664
|
const input = raw;
|
|
15638
15665
|
const id = stringField4(input.id);
|
|
15639
|
-
if (!id || !isCompanyIntentId(id)) throw new Error(`${
|
|
15666
|
+
if (!id || !isCompanyIntentId(id)) throw new Error(`${path59}: invalid intent id`);
|
|
15640
15667
|
const createdAt = stringField4(input.createdAt) || nowIso();
|
|
15641
15668
|
const updatedAt = stringField4(input.updatedAt) || createdAt;
|
|
15642
15669
|
const description = stringField4(input.description);
|
|
@@ -15798,7 +15825,7 @@ function retryDelaysMs() {
|
|
|
15798
15825
|
}
|
|
15799
15826
|
function sleep(ms) {
|
|
15800
15827
|
if (ms <= 0) return Promise.resolve();
|
|
15801
|
-
return new Promise((
|
|
15828
|
+
return new Promise((resolve24) => setTimeout(resolve24, ms));
|
|
15802
15829
|
}
|
|
15803
15830
|
async function fetchGoalStateWithRetry(config, goalId, cwd) {
|
|
15804
15831
|
let state = await fetchGoalStateAsync(config, goalId, cwd);
|
|
@@ -15928,7 +15955,7 @@ var init_loadIssueStateComment = __esm({
|
|
|
15928
15955
|
|
|
15929
15956
|
// src/scripts/loadJobFromFile.ts
|
|
15930
15957
|
import * as fs42 from "fs";
|
|
15931
|
-
import * as
|
|
15958
|
+
import * as path40 from "path";
|
|
15932
15959
|
function parseJobFile(raw, slug) {
|
|
15933
15960
|
let stripped = raw;
|
|
15934
15961
|
if (stripped.startsWith("---\n")) {
|
|
@@ -15967,10 +15994,10 @@ var init_loadJobFromFile = __esm({
|
|
|
15967
15994
|
if (!slug) {
|
|
15968
15995
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
15969
15996
|
}
|
|
15970
|
-
const capability = resolveCapabilityFolder(slug,
|
|
15997
|
+
const capability = resolveCapabilityFolder(slug, path40.resolve(ctx.cwd, jobsDir));
|
|
15971
15998
|
if (!capability) {
|
|
15972
15999
|
throw new Error(
|
|
15973
|
-
`loadJobFromFile: capability folder not found or incomplete: ${
|
|
16000
|
+
`loadJobFromFile: capability folder not found or incomplete: ${path40.resolve(ctx.cwd, jobsDir, slug)}`
|
|
15974
16001
|
);
|
|
15975
16002
|
}
|
|
15976
16003
|
const { title, body, config } = capability;
|
|
@@ -16066,9 +16093,9 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
16066
16093
|
|
|
16067
16094
|
// src/scripts/kodyVariables.ts
|
|
16068
16095
|
import * as fs43 from "fs";
|
|
16069
|
-
import * as
|
|
16096
|
+
import * as path41 from "path";
|
|
16070
16097
|
function readKodyVariables(cwd) {
|
|
16071
|
-
const full =
|
|
16098
|
+
const full = path41.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
16072
16099
|
let raw;
|
|
16073
16100
|
try {
|
|
16074
16101
|
raw = fs43.readFileSync(full, "utf-8");
|
|
@@ -16097,7 +16124,7 @@ var init_kodyVariables = __esm({
|
|
|
16097
16124
|
|
|
16098
16125
|
// src/scripts/loadQaContext.ts
|
|
16099
16126
|
import * as fs44 from "fs";
|
|
16100
|
-
import * as
|
|
16127
|
+
import * as path42 from "path";
|
|
16101
16128
|
function parseSlugList(value) {
|
|
16102
16129
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
16103
16130
|
return inner.split(",").map(
|
|
@@ -16126,7 +16153,7 @@ function readProfileAgents(raw) {
|
|
|
16126
16153
|
return { agent: agent ?? legacy ?? ["kody"], body };
|
|
16127
16154
|
}
|
|
16128
16155
|
function readProfile(cwd) {
|
|
16129
|
-
const dir =
|
|
16156
|
+
const dir = path42.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
16130
16157
|
if (!fs44.existsSync(dir)) return "";
|
|
16131
16158
|
let entries;
|
|
16132
16159
|
try {
|
|
@@ -16137,7 +16164,7 @@ function readProfile(cwd) {
|
|
|
16137
16164
|
const blocks = [];
|
|
16138
16165
|
for (const file of entries) {
|
|
16139
16166
|
try {
|
|
16140
|
-
const raw = fs44.readFileSync(
|
|
16167
|
+
const raw = fs44.readFileSync(path42.join(dir, file), "utf-8");
|
|
16141
16168
|
const { agent, body } = readProfileAgents(raw);
|
|
16142
16169
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
16143
16170
|
blocks.push(`## ${file}
|
|
@@ -16189,7 +16216,7 @@ var init_loadQaContext = __esm({
|
|
|
16189
16216
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
16190
16217
|
import * as fs45 from "fs";
|
|
16191
16218
|
import * as os6 from "os";
|
|
16192
|
-
import * as
|
|
16219
|
+
import * as path43 from "path";
|
|
16193
16220
|
function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
|
|
16194
16221
|
const subagentFiles = toolFiles.flatMap((file) => {
|
|
16195
16222
|
const match = /^agents\/([a-z][a-z0-9-]{0,63})\.md$/.exec(file);
|
|
@@ -16202,7 +16229,7 @@ function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
|
|
|
16202
16229
|
profile.subagentTemplates = {
|
|
16203
16230
|
...profile.subagentTemplates ?? {},
|
|
16204
16231
|
...Object.fromEntries(
|
|
16205
|
-
subagentFiles.map(({ name, file }) => [name, fs45.readFileSync(
|
|
16232
|
+
subagentFiles.map(({ name, file }) => [name, fs45.readFileSync(path43.join(toolRoot, file), "utf-8")])
|
|
16206
16233
|
)
|
|
16207
16234
|
};
|
|
16208
16235
|
if (!profile.claudeCode.tools.includes("Agent")) {
|
|
@@ -16247,10 +16274,10 @@ function listFiles(root) {
|
|
|
16247
16274
|
const files = [];
|
|
16248
16275
|
const visit = (dir) => {
|
|
16249
16276
|
for (const entry of fs45.readdirSync(dir, { withFileTypes: true })) {
|
|
16250
|
-
const absolute =
|
|
16277
|
+
const absolute = path43.join(dir, entry.name);
|
|
16251
16278
|
if (entry.isSymbolicLink()) continue;
|
|
16252
16279
|
if (entry.isDirectory()) visit(absolute);
|
|
16253
|
-
else if (entry.isFile()) files.push(
|
|
16280
|
+
else if (entry.isFile()) files.push(path43.relative(root, absolute));
|
|
16254
16281
|
}
|
|
16255
16282
|
};
|
|
16256
16283
|
visit(root);
|
|
@@ -16273,8 +16300,8 @@ var init_loadSimpleCapability = __esm({
|
|
|
16273
16300
|
if (!capability) {
|
|
16274
16301
|
throw new Error(`Capability "${slug}" is not a valid simple capability folder`);
|
|
16275
16302
|
}
|
|
16276
|
-
const toolRoot =
|
|
16277
|
-
const skillRoot =
|
|
16303
|
+
const toolRoot = path43.join(capability.dir, "tools");
|
|
16304
|
+
const skillRoot = path43.join(capability.dir, "skills");
|
|
16278
16305
|
const toolFiles = listFiles(toolRoot);
|
|
16279
16306
|
const skillFiles = listFiles(skillRoot);
|
|
16280
16307
|
const parsedInput = parseInput(ctx.args.input);
|
|
@@ -16285,6 +16312,9 @@ var init_loadSimpleCapability = __esm({
|
|
|
16285
16312
|
ctx.data.jobCapability = slug;
|
|
16286
16313
|
ctx.data.capabilityInput = input;
|
|
16287
16314
|
ctx.data.capabilityExecution = capability.contract?.execution ?? "agent";
|
|
16315
|
+
if (capability.contract?.deliveryPolicy) {
|
|
16316
|
+
ctx.data.capabilityDeliveryPolicy = capability.contract.deliveryPolicy;
|
|
16317
|
+
}
|
|
16288
16318
|
if (capability.contract?.requirements) {
|
|
16289
16319
|
ctx.data.capabilityRequirements = capability.contract.requirements;
|
|
16290
16320
|
}
|
|
@@ -16299,14 +16329,14 @@ var init_loadSimpleCapability = __esm({
|
|
|
16299
16329
|
}
|
|
16300
16330
|
if (requiredSubagents.length > 0) ctx.data.requiredSubagents = requiredSubagents;
|
|
16301
16331
|
if (capability.contract?.execution === "script") {
|
|
16302
|
-
ctx.data.capabilityScriptPath =
|
|
16332
|
+
ctx.data.capabilityScriptPath = path43.join(capability.dir, "tools", "run.sh");
|
|
16303
16333
|
ctx.data.capabilitySecretNames = capability.contract.secrets ?? [];
|
|
16304
16334
|
ctx.data.capabilityScriptTimeoutMs = capability.contract.timeoutMs;
|
|
16305
16335
|
}
|
|
16306
16336
|
if (capability.config.outputSchema) {
|
|
16307
16337
|
ctx.data.capabilityOutputSchema = capability.config.outputSchema;
|
|
16308
16338
|
}
|
|
16309
|
-
const outputPath = ctx.data.capabilityExecution === "agent" && capability.config.outputSchema ?
|
|
16339
|
+
const outputPath = ctx.data.capabilityExecution === "agent" && capability.config.outputSchema ? path43.join(os6.tmpdir(), `kody-capability-output-${randomUUID2()}.json`) : void 0;
|
|
16310
16340
|
if (outputPath) ctx.data.capabilityOutputPath = outputPath;
|
|
16311
16341
|
ctx.data.capabilityEnvironment = {
|
|
16312
16342
|
...capabilityInputEnvironment(input),
|
|
@@ -16329,7 +16359,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
16329
16359
|
...skillFiles.flatMap((file) => [
|
|
16330
16360
|
`### ${file}`,
|
|
16331
16361
|
"",
|
|
16332
|
-
fs45.readFileSync(
|
|
16362
|
+
fs45.readFileSync(path43.join(skillRoot, file), "utf-8"),
|
|
16333
16363
|
""
|
|
16334
16364
|
])
|
|
16335
16365
|
] : [],
|
|
@@ -16338,7 +16368,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
16338
16368
|
"## Tools",
|
|
16339
16369
|
"",
|
|
16340
16370
|
"Inspect or run these capability-owned files when needed:",
|
|
16341
|
-
...toolFiles.map((file) => `- ${
|
|
16371
|
+
...toolFiles.map((file) => `- ${path43.join(toolRoot, file)}`)
|
|
16342
16372
|
] : [],
|
|
16343
16373
|
"",
|
|
16344
16374
|
...capability.config.outputSchema ? [
|
|
@@ -16370,7 +16400,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
16370
16400
|
|
|
16371
16401
|
// src/taskContext.ts
|
|
16372
16402
|
import * as fs46 from "fs";
|
|
16373
|
-
import * as
|
|
16403
|
+
import * as path44 from "path";
|
|
16374
16404
|
function buildTaskContext(args) {
|
|
16375
16405
|
return {
|
|
16376
16406
|
schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
|
|
@@ -16387,7 +16417,7 @@ function persistTaskContext(cwd, ctx) {
|
|
|
16387
16417
|
try {
|
|
16388
16418
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
16389
16419
|
fs46.mkdirSync(dir, { recursive: true });
|
|
16390
|
-
const file =
|
|
16420
|
+
const file = path44.join(dir, "task-context.json");
|
|
16391
16421
|
fs46.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
16392
16422
|
`);
|
|
16393
16423
|
return file;
|
|
@@ -16815,19 +16845,19 @@ function parseAgencyModelProposal(raw) {
|
|
|
16815
16845
|
function normalizeBundleFiles(bundle) {
|
|
16816
16846
|
const seen = /* @__PURE__ */ new Set();
|
|
16817
16847
|
return bundle.files.map((file, index) => {
|
|
16818
|
-
const
|
|
16819
|
-
const parts =
|
|
16820
|
-
if (!
|
|
16848
|
+
const path59 = file.path.replace(/^\/+/, "");
|
|
16849
|
+
const parts = path59.split("/");
|
|
16850
|
+
if (!path59 || file.path.startsWith("/") || file.path.includes("\\") || parts.some((part) => !part || part === "." || part === "..")) {
|
|
16821
16851
|
throw new Error(`openAgencyModelReviewPr: files[${index}].path is unsafe`);
|
|
16822
16852
|
}
|
|
16823
16853
|
if (!/^(agents\/[^/]+\.md|capabilities\/[^/]+\/.+|goals\/(?:templates\/)?[^/]+\/.+|workflows\/[^/]+\.json)$/.test(
|
|
16824
|
-
|
|
16854
|
+
path59
|
|
16825
16855
|
)) {
|
|
16826
16856
|
throw new Error(`openAgencyModelReviewPr: files[${index}].path is not a supported definition path`);
|
|
16827
16857
|
}
|
|
16828
|
-
if (seen.has(
|
|
16829
|
-
seen.add(
|
|
16830
|
-
return { path:
|
|
16858
|
+
if (seen.has(path59)) throw new Error(`openAgencyModelReviewPr: duplicate generated file path: ${path59}`);
|
|
16859
|
+
seen.add(path59);
|
|
16860
|
+
return { path: path59, content: file.content.replace(/\r\n?/g, "\n") };
|
|
16831
16861
|
});
|
|
16832
16862
|
}
|
|
16833
16863
|
function buildProposalId(issueNumber, bundle, sourceLabel) {
|
|
@@ -17871,7 +17901,8 @@ var init_postIssueComment = __esm({
|
|
|
17871
17901
|
githubRepo: ctx.config.github?.repo
|
|
17872
17902
|
});
|
|
17873
17903
|
postWith(targetType, targetNumber, msg, ctx.cwd);
|
|
17874
|
-
|
|
17904
|
+
const prIsDraft = (prResult?.kind === "created" || prResult?.kind === "updated") && prResult.draft === true;
|
|
17905
|
+
if (!isFailure && !prIsDraft) {
|
|
17875
17906
|
markPrReadyForReview(ctx, prResult);
|
|
17876
17907
|
}
|
|
17877
17908
|
let exitCode = 0;
|
|
@@ -17939,7 +17970,7 @@ var init_postResearchComment = __esm({
|
|
|
17939
17970
|
// src/scripts/prepareBrowserAuth.ts
|
|
17940
17971
|
import * as fs48 from "fs";
|
|
17941
17972
|
import * as os7 from "os";
|
|
17942
|
-
import * as
|
|
17973
|
+
import * as path45 from "path";
|
|
17943
17974
|
function appendAuthMessage(ctx, message) {
|
|
17944
17975
|
const current = typeof ctx.data.qaAuthBlock === "string" ? ctx.data.qaAuthBlock.trim() : "";
|
|
17945
17976
|
ctx.data.qaAuthBlock = current ? `${current}
|
|
@@ -17978,9 +18009,9 @@ async function githubJson(url, token) {
|
|
|
17978
18009
|
return await response.json();
|
|
17979
18010
|
}
|
|
17980
18011
|
function writeKodyStorageState(input) {
|
|
17981
|
-
const directory = fs48.mkdtempSync(
|
|
18012
|
+
const directory = fs48.mkdtempSync(path45.join(os7.tmpdir(), "kody-browser-auth-"));
|
|
17982
18013
|
fs48.chmodSync(directory, 448);
|
|
17983
|
-
const file =
|
|
18014
|
+
const file = path45.join(directory, "storage-state.json");
|
|
17984
18015
|
const now = Date.now();
|
|
17985
18016
|
const repoEntry = {
|
|
17986
18017
|
repoUrl: input.repoUrl,
|
|
@@ -18239,7 +18270,7 @@ var init_prepareCapabilityDelivery = __esm({
|
|
|
18239
18270
|
|
|
18240
18271
|
// src/scripts/prepareSimpleCapabilityRuntime.ts
|
|
18241
18272
|
import { isIP } from "net";
|
|
18242
|
-
import * as
|
|
18273
|
+
import * as path46 from "path";
|
|
18243
18274
|
function requirementsFrom(ctx) {
|
|
18244
18275
|
const raw = ctx.data.capabilityRequirements;
|
|
18245
18276
|
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
@@ -18283,7 +18314,7 @@ function browserRuntime(ctx, requirements) {
|
|
|
18283
18314
|
"--allowed-origins",
|
|
18284
18315
|
origin,
|
|
18285
18316
|
"--output-dir",
|
|
18286
|
-
|
|
18317
|
+
path46.resolve(ctx.cwd, "test-results", "quality-runs", qualityRunId)
|
|
18287
18318
|
]
|
|
18288
18319
|
};
|
|
18289
18320
|
}
|
|
@@ -18648,9 +18679,9 @@ function latestResult(raw, agentResult) {
|
|
|
18648
18679
|
function recordField4(value) {
|
|
18649
18680
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
18650
18681
|
}
|
|
18651
|
-
function resolveDotted(root,
|
|
18652
|
-
if (!
|
|
18653
|
-
return
|
|
18682
|
+
function resolveDotted(root, path59) {
|
|
18683
|
+
if (!path59) return void 0;
|
|
18684
|
+
return path59.split(".").reduce((value, key) => recordField4(value)?.[key], root);
|
|
18654
18685
|
}
|
|
18655
18686
|
function stringValue5(value) {
|
|
18656
18687
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
@@ -19492,7 +19523,7 @@ var init_previewBuildHelpers = __esm({
|
|
|
19492
19523
|
// src/scripts/previewBuildRun.ts
|
|
19493
19524
|
import { spawn as spawn5 } from "child_process";
|
|
19494
19525
|
async function runCmd(cmd, args, opts = {}) {
|
|
19495
|
-
await new Promise((
|
|
19526
|
+
await new Promise((resolve24, reject) => {
|
|
19496
19527
|
const child = spawn5(cmd, args, {
|
|
19497
19528
|
cwd: opts.cwd,
|
|
19498
19529
|
env: { ...process.env, ...opts.env ?? {} },
|
|
@@ -19504,7 +19535,7 @@ async function runCmd(cmd, args, opts = {}) {
|
|
|
19504
19535
|
}
|
|
19505
19536
|
child.on("error", reject);
|
|
19506
19537
|
child.on("close", (code) => {
|
|
19507
|
-
if (code === 0)
|
|
19538
|
+
if (code === 0) resolve24();
|
|
19508
19539
|
else reject(new Error(`${cmd} ${args.join(" ")} exited ${code}`));
|
|
19509
19540
|
});
|
|
19510
19541
|
});
|
|
@@ -19576,12 +19607,12 @@ fi
|
|
|
19576
19607
|
|
|
19577
19608
|
// src/scripts/runPreviewBuild.ts
|
|
19578
19609
|
import { copyFile, writeFile } from "fs/promises";
|
|
19579
|
-
import * as
|
|
19610
|
+
import * as path47 from "path";
|
|
19580
19611
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
19581
19612
|
function bundledDockerfilePath(mode) {
|
|
19582
|
-
const here =
|
|
19613
|
+
const here = path47.dirname(fileURLToPath2(import.meta.url));
|
|
19583
19614
|
const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
|
|
19584
|
-
return
|
|
19615
|
+
return path47.join(here, "preview-build-templates", file);
|
|
19585
19616
|
}
|
|
19586
19617
|
function required(name) {
|
|
19587
19618
|
const v = (process.env[name] ?? "").trim();
|
|
@@ -19816,10 +19847,10 @@ var init_runPreviewBuild = __esm({
|
|
|
19816
19847
|
console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
|
|
19817
19848
|
if (Object.keys(buildEnv).length > 0) {
|
|
19818
19849
|
const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
19819
|
-
await writeFile(
|
|
19850
|
+
await writeFile(path47.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
|
|
19820
19851
|
`, "utf8");
|
|
19821
19852
|
}
|
|
19822
|
-
const consumerDockerfile =
|
|
19853
|
+
const consumerDockerfile = path47.join(ctx.cwd, "Dockerfile.preview");
|
|
19823
19854
|
const { stat } = await import("fs/promises");
|
|
19824
19855
|
let hasConsumerDockerfile = false;
|
|
19825
19856
|
try {
|
|
@@ -20004,7 +20035,7 @@ var init_tickShellRunner = __esm({
|
|
|
20004
20035
|
|
|
20005
20036
|
// src/scripts/runScheduledImplementationTick.ts
|
|
20006
20037
|
import * as fs49 from "fs";
|
|
20007
|
-
import * as
|
|
20038
|
+
import * as path48 from "path";
|
|
20008
20039
|
var runScheduledImplementationTick;
|
|
20009
20040
|
var init_runScheduledImplementationTick = __esm({
|
|
20010
20041
|
"src/scripts/runScheduledImplementationTick.ts"() {
|
|
@@ -20025,13 +20056,13 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
20025
20056
|
ctx.output.reason = `runScheduledImplementationTick: args.slug or ctx.args.${slugArg} must be non-empty capability slug`;
|
|
20026
20057
|
return;
|
|
20027
20058
|
}
|
|
20028
|
-
const capability = resolveCapabilityFolder(slug,
|
|
20059
|
+
const capability = resolveCapabilityFolder(slug, path48.resolve(ctx.cwd, jobsDir));
|
|
20029
20060
|
if (!capability) {
|
|
20030
20061
|
ctx.output.exitCode = 99;
|
|
20031
20062
|
ctx.output.reason = `runScheduledImplementationTick: capability folder not found or incomplete: ${slug} (searched ${jobsDir} and company store)`;
|
|
20032
20063
|
return;
|
|
20033
20064
|
}
|
|
20034
|
-
const shellPath =
|
|
20065
|
+
const shellPath = path48.join(profile.dir, shell);
|
|
20035
20066
|
if (!fs49.existsSync(shellPath)) {
|
|
20036
20067
|
ctx.output.exitCode = 99;
|
|
20037
20068
|
ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
@@ -20150,7 +20181,7 @@ var init_runSimpleCapabilityScript = __esm({
|
|
|
20150
20181
|
|
|
20151
20182
|
// src/scripts/runTickScript.ts
|
|
20152
20183
|
import * as fs51 from "fs";
|
|
20153
|
-
import * as
|
|
20184
|
+
import * as path49 from "path";
|
|
20154
20185
|
var runTickScript;
|
|
20155
20186
|
var init_runTickScript = __esm({
|
|
20156
20187
|
"src/scripts/runTickScript.ts"() {
|
|
@@ -20170,10 +20201,10 @@ var init_runTickScript = __esm({
|
|
|
20170
20201
|
ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
|
|
20171
20202
|
return;
|
|
20172
20203
|
}
|
|
20173
|
-
const capability = readCapabilityFolder(
|
|
20204
|
+
const capability = readCapabilityFolder(path49.resolve(ctx.cwd, jobsDir), slug);
|
|
20174
20205
|
if (!capability) {
|
|
20175
20206
|
ctx.output.exitCode = 99;
|
|
20176
|
-
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${
|
|
20207
|
+
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path49.resolve(ctx.cwd, jobsDir, slug)}`;
|
|
20177
20208
|
return;
|
|
20178
20209
|
}
|
|
20179
20210
|
const tickScript = capability.config.tickScript;
|
|
@@ -20182,7 +20213,7 @@ var init_runTickScript = __esm({
|
|
|
20182
20213
|
ctx.output.reason = `runTickScript: capability ${slug} has no \`tickScript\` in profile.json \u2014 route via capability-tick instead`;
|
|
20183
20214
|
return;
|
|
20184
20215
|
}
|
|
20185
|
-
const scriptPath =
|
|
20216
|
+
const scriptPath = path49.isAbsolute(tickScript) ? tickScript : path49.join(ctx.cwd, tickScript);
|
|
20186
20217
|
if (!fs51.existsSync(scriptPath)) {
|
|
20187
20218
|
ctx.output.exitCode = 99;
|
|
20188
20219
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
@@ -20465,7 +20496,7 @@ var init_syncFlow = __esm({
|
|
|
20465
20496
|
});
|
|
20466
20497
|
|
|
20467
20498
|
// src/scripts/validateAgencyModelProposal.ts
|
|
20468
|
-
import * as
|
|
20499
|
+
import * as path50 from "path";
|
|
20469
20500
|
function validateModelBundle(bundle, expectedKind, options = {}) {
|
|
20470
20501
|
const failures = [];
|
|
20471
20502
|
validateOneModel(bundle.model, bundle.files, "model", true, failures, expectedKind, options);
|
|
@@ -20783,7 +20814,7 @@ var init_validateAgencyModelProposal = __esm({
|
|
|
20783
20814
|
const bundle = parseAgencyModelProposal(raw);
|
|
20784
20815
|
const expectedKind = readExpectedModelKind(args);
|
|
20785
20816
|
const failures = validateModelBundle(bundle, expectedKind, {
|
|
20786
|
-
capabilityRoot:
|
|
20817
|
+
capabilityRoot: path50.join(ctx.cwd, ".kody", "capabilities")
|
|
20787
20818
|
});
|
|
20788
20819
|
if (failures.length > 0) {
|
|
20789
20820
|
throw new Error(`validateAgencyModelProposal: ${failures.join("; ")}`);
|
|
@@ -20846,7 +20877,7 @@ function stripAnsi2(s) {
|
|
|
20846
20877
|
return s.replace(ANSI_RE2, "");
|
|
20847
20878
|
}
|
|
20848
20879
|
function runCommand2(command, cwd) {
|
|
20849
|
-
return new Promise((
|
|
20880
|
+
return new Promise((resolve24) => {
|
|
20850
20881
|
const child = spawn6(command, {
|
|
20851
20882
|
cwd,
|
|
20852
20883
|
shell: true,
|
|
@@ -20873,11 +20904,11 @@ function runCommand2(command, cwd) {
|
|
|
20873
20904
|
}, TEST_TIMEOUT_MS);
|
|
20874
20905
|
child.on("exit", (code) => {
|
|
20875
20906
|
clearTimeout(timer);
|
|
20876
|
-
|
|
20907
|
+
resolve24({ exitCode: code ?? -1, output: Buffer.concat(buffers).toString("utf-8") });
|
|
20877
20908
|
});
|
|
20878
20909
|
child.on("error", (err) => {
|
|
20879
20910
|
clearTimeout(timer);
|
|
20880
|
-
|
|
20911
|
+
resolve24({ exitCode: -1, output: err.message });
|
|
20881
20912
|
});
|
|
20882
20913
|
});
|
|
20883
20914
|
}
|
|
@@ -20996,6 +21027,12 @@ var init_verifyWithRetry = __esm({
|
|
|
20996
21027
|
init_prompt();
|
|
20997
21028
|
init_verify();
|
|
20998
21029
|
verifyWithRetry = async (ctx) => {
|
|
21030
|
+
if (ctx.data.capabilityDeliveryPolicy === "checkpoint") {
|
|
21031
|
+
ctx.data.verificationDeferred = true;
|
|
21032
|
+
delete ctx.data.verifyOk;
|
|
21033
|
+
delete ctx.data.verifyReason;
|
|
21034
|
+
return;
|
|
21035
|
+
}
|
|
20999
21036
|
await runVerify(ctx);
|
|
21000
21037
|
if (ctx.data.verifyOk !== false) return;
|
|
21001
21038
|
if (ctx.abortSignal?.aborted) {
|
|
@@ -21291,21 +21328,21 @@ function lineStream(stream) {
|
|
|
21291
21328
|
tryDeliver();
|
|
21292
21329
|
});
|
|
21293
21330
|
return {
|
|
21294
|
-
next: (timeoutMs) => new Promise((
|
|
21331
|
+
next: (timeoutMs) => new Promise((resolve24) => {
|
|
21295
21332
|
if (queue.length > 0) {
|
|
21296
|
-
|
|
21333
|
+
resolve24(queue.shift());
|
|
21297
21334
|
return;
|
|
21298
21335
|
}
|
|
21299
21336
|
if (ended) {
|
|
21300
|
-
|
|
21337
|
+
resolve24(null);
|
|
21301
21338
|
return;
|
|
21302
21339
|
}
|
|
21303
|
-
waiter =
|
|
21340
|
+
waiter = resolve24;
|
|
21304
21341
|
const t = setTimeout(
|
|
21305
21342
|
() => {
|
|
21306
|
-
if (waiter ===
|
|
21343
|
+
if (waiter === resolve24) {
|
|
21307
21344
|
waiter = null;
|
|
21308
|
-
|
|
21345
|
+
resolve24(null);
|
|
21309
21346
|
}
|
|
21310
21347
|
},
|
|
21311
21348
|
Math.max(0, timeoutMs)
|
|
@@ -21707,15 +21744,15 @@ var init_scripts = __esm({
|
|
|
21707
21744
|
|
|
21708
21745
|
// src/stateWorkspace.ts
|
|
21709
21746
|
import * as fs53 from "fs";
|
|
21710
|
-
import * as
|
|
21747
|
+
import * as path51 from "path";
|
|
21711
21748
|
function tenantId(config) {
|
|
21712
21749
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
21713
21750
|
const repo = config.github?.repo?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim();
|
|
21714
21751
|
return owner && repo ? `${owner}/${repo}` : null;
|
|
21715
21752
|
}
|
|
21716
21753
|
function writeRuntimeFile(cwd, relativePath, content) {
|
|
21717
|
-
const target =
|
|
21718
|
-
fs53.mkdirSync(
|
|
21754
|
+
const target = path51.join(cwd, RUNTIME_ROOT, relativePath);
|
|
21755
|
+
fs53.mkdirSync(path51.dirname(target), { recursive: true });
|
|
21719
21756
|
fs53.writeFileSync(target, content, "utf8");
|
|
21720
21757
|
}
|
|
21721
21758
|
function record(value) {
|
|
@@ -21781,10 +21818,10 @@ async function hydrateStateWorkspace(config, cwd, backendOverride) {
|
|
|
21781
21818
|
throw new Error("Kody backend access is required for runtime workspace documents");
|
|
21782
21819
|
return;
|
|
21783
21820
|
}
|
|
21784
|
-
const key = `${
|
|
21821
|
+
const key = `${path51.resolve(cwd)}|${tenant}`;
|
|
21785
21822
|
if (hydratedWorkspaces.has(key)) return;
|
|
21786
21823
|
const backend = backendOverride ?? createStateBackendFromEnv();
|
|
21787
|
-
const root =
|
|
21824
|
+
const root = path51.join(cwd, RUNTIME_ROOT);
|
|
21788
21825
|
fs53.rmSync(root, { recursive: true, force: true });
|
|
21789
21826
|
await Promise.all([
|
|
21790
21827
|
hydratePrefix(backend, tenant, cwd, "context:"),
|
|
@@ -21801,7 +21838,7 @@ var init_stateWorkspace = __esm({
|
|
|
21801
21838
|
"src/stateWorkspace.ts"() {
|
|
21802
21839
|
"use strict";
|
|
21803
21840
|
init_state_backend();
|
|
21804
|
-
RUNTIME_ROOT =
|
|
21841
|
+
RUNTIME_ROOT = path51.join(".kody-engine", "runtime");
|
|
21805
21842
|
hydratedWorkspaces = /* @__PURE__ */ new Set();
|
|
21806
21843
|
}
|
|
21807
21844
|
});
|
|
@@ -21874,7 +21911,7 @@ var init_tools = __esm({
|
|
|
21874
21911
|
import { spawn as spawn8 } from "child_process";
|
|
21875
21912
|
import * as fs54 from "fs";
|
|
21876
21913
|
import * as os8 from "os";
|
|
21877
|
-
import * as
|
|
21914
|
+
import * as path52 from "path";
|
|
21878
21915
|
function isMutatingPostflight(scriptName) {
|
|
21879
21916
|
return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
|
|
21880
21917
|
}
|
|
@@ -22131,7 +22168,7 @@ async function runImplementation(profileName, input) {
|
|
|
22131
22168
|
const reason = input.abortController.signal.reason;
|
|
22132
22169
|
throw reason instanceof Error ? reason : new Error("agent invocation aborted");
|
|
22133
22170
|
}
|
|
22134
|
-
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) =>
|
|
22171
|
+
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path52.isAbsolute(p) ? p : path52.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
22135
22172
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
22136
22173
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
22137
22174
|
const agents = loadSubagents(profile);
|
|
@@ -22613,13 +22650,13 @@ function clearStampedLifecycleLabels(profile, ctx) {
|
|
|
22613
22650
|
function resolveProfilePath(profileName, cwd = process.cwd()) {
|
|
22614
22651
|
const found = resolveImplementation(profileName, getRuntimeProfileRootsForCwd(cwd));
|
|
22615
22652
|
if (found) return found;
|
|
22616
|
-
const here =
|
|
22653
|
+
const here = path52.dirname(new URL(import.meta.url).pathname);
|
|
22617
22654
|
const candidates = [
|
|
22618
|
-
|
|
22655
|
+
path52.join(here, "implementations", profileName, "profile.json"),
|
|
22619
22656
|
// same-dir sibling (dev)
|
|
22620
|
-
|
|
22657
|
+
path52.join(here, "..", "implementations", profileName, "profile.json"),
|
|
22621
22658
|
// up one (prod: dist/bin → dist/implementations)
|
|
22622
|
-
|
|
22659
|
+
path52.join(here, "..", "src", "implementations", profileName, "profile.json")
|
|
22623
22660
|
// fallback
|
|
22624
22661
|
];
|
|
22625
22662
|
for (const c of candidates) {
|
|
@@ -22738,7 +22775,7 @@ function resolveShellTimeoutMs(entry) {
|
|
|
22738
22775
|
}
|
|
22739
22776
|
async function runShellEntry(entry, ctx, profile) {
|
|
22740
22777
|
const shellName = entry.shell;
|
|
22741
|
-
const shellPath =
|
|
22778
|
+
const shellPath = path52.join(profile.dir, shellName);
|
|
22742
22779
|
if (!fs54.existsSync(shellPath)) {
|
|
22743
22780
|
ctx.skipAgent = true;
|
|
22744
22781
|
ctx.output.exitCode = 99;
|
|
@@ -22746,7 +22783,7 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
22746
22783
|
return;
|
|
22747
22784
|
}
|
|
22748
22785
|
const positional = entry.with ? Object.values(entry.with).map((v) => String(v)) : [];
|
|
22749
|
-
const outputFile =
|
|
22786
|
+
const outputFile = path52.join(
|
|
22750
22787
|
os8.tmpdir(),
|
|
22751
22788
|
`kody-shell-output-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
22752
22789
|
);
|
|
@@ -22776,14 +22813,14 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
22776
22813
|
let killTimer;
|
|
22777
22814
|
let escalateTimer;
|
|
22778
22815
|
const result = await new Promise(
|
|
22779
|
-
(
|
|
22816
|
+
(resolve24) => {
|
|
22780
22817
|
let settled = false;
|
|
22781
22818
|
const settle = (code, signal, spawnErr) => {
|
|
22782
22819
|
if (settled) return;
|
|
22783
22820
|
settled = true;
|
|
22784
22821
|
if (killTimer) clearTimeout(killTimer);
|
|
22785
22822
|
if (escalateTimer) clearTimeout(escalateTimer);
|
|
22786
|
-
|
|
22823
|
+
resolve24({ code, signal, spawnErr });
|
|
22787
22824
|
};
|
|
22788
22825
|
child.on("error", (err) => settle(null, null, err));
|
|
22789
22826
|
child.on("close", (code, signal) => settle(code, signal));
|
|
@@ -23828,11 +23865,11 @@ function exhaustedWorkflowTransitions(step, data, counts) {
|
|
|
23828
23865
|
}
|
|
23829
23866
|
function workflowResultConditionPaths(transitions) {
|
|
23830
23867
|
return transitions.flatMap(
|
|
23831
|
-
(transition) => Object.keys(transition.when ?? {}).filter((
|
|
23868
|
+
(transition) => Object.keys(transition.when ?? {}).filter((path59) => path59.startsWith("result."))
|
|
23832
23869
|
);
|
|
23833
23870
|
}
|
|
23834
23871
|
function conditionMatches(condition, context) {
|
|
23835
|
-
return Object.entries(condition).every(([
|
|
23872
|
+
return Object.entries(condition).every(([path59, expected]) => valueMatches(resolveDottedPath2(context, path59), expected));
|
|
23836
23873
|
}
|
|
23837
23874
|
function withWorkflowBoundaryEval(capability, result) {
|
|
23838
23875
|
const capabilityKind = capability.config.capabilityKind;
|
|
@@ -24307,7 +24344,7 @@ function translateOpenAISseToBrain(opts) {
|
|
|
24307
24344
|
|
|
24308
24345
|
// src/servers/brain-serve.ts
|
|
24309
24346
|
import { createServer as createServer2 } from "http";
|
|
24310
|
-
import * as
|
|
24347
|
+
import * as path55 from "path";
|
|
24311
24348
|
|
|
24312
24349
|
// src/chat/loop.ts
|
|
24313
24350
|
init_agent();
|
|
@@ -24316,12 +24353,12 @@ init_config();
|
|
|
24316
24353
|
init_registry();
|
|
24317
24354
|
init_task_artifacts();
|
|
24318
24355
|
import * as fs18 from "fs";
|
|
24319
|
-
import * as
|
|
24356
|
+
import * as path20 from "path";
|
|
24320
24357
|
|
|
24321
24358
|
// src/chat/attachments.ts
|
|
24322
24359
|
init_runtimePaths();
|
|
24323
24360
|
import * as fs15 from "fs";
|
|
24324
|
-
import * as
|
|
24361
|
+
import * as path17 from "path";
|
|
24325
24362
|
var INLINE_ATTACHMENT_RE = /(?:\[(?:Image|File): ([^\]]*)\]\n)?data:([\w.+-]+\/[\w.+-]+);base64,([A-Za-z0-9+/=]+)/g;
|
|
24326
24363
|
var EXT_BY_MIME = {
|
|
24327
24364
|
"image/png": "png",
|
|
@@ -24357,7 +24394,7 @@ function prepareAttachments(turns, cwd, sessionId) {
|
|
|
24357
24394
|
fs15.mkdirSync(dir, { recursive: true });
|
|
24358
24395
|
dirEnsured = true;
|
|
24359
24396
|
}
|
|
24360
|
-
const filePath =
|
|
24397
|
+
const filePath = path17.join(dir, `${imageCounter}.${extFor(mime)}`);
|
|
24361
24398
|
fs15.writeFileSync(filePath, Buffer.from(data, "base64"));
|
|
24362
24399
|
imageCounter += 1;
|
|
24363
24400
|
imagePaths.push(filePath);
|
|
@@ -24376,7 +24413,7 @@ function prepareAttachments(turns, cwd, sessionId) {
|
|
|
24376
24413
|
// src/chat/codex-app-server.ts
|
|
24377
24414
|
import { spawn as spawn3 } from "child_process";
|
|
24378
24415
|
import * as fs16 from "fs";
|
|
24379
|
-
import * as
|
|
24416
|
+
import * as path18 from "path";
|
|
24380
24417
|
import { createInterface } from "readline";
|
|
24381
24418
|
function codexThreadStartParams(args) {
|
|
24382
24419
|
return {
|
|
@@ -24461,9 +24498,9 @@ var CodexAppServerClient = class {
|
|
|
24461
24498
|
await this.request("thread/resume", { threadId });
|
|
24462
24499
|
}
|
|
24463
24500
|
async runTurn(args) {
|
|
24464
|
-
await new Promise((
|
|
24501
|
+
await new Promise((resolve24, reject) => {
|
|
24465
24502
|
this.process.turnWaiters.set(args.threadId, {
|
|
24466
|
-
resolve:
|
|
24503
|
+
resolve: resolve24,
|
|
24467
24504
|
reject,
|
|
24468
24505
|
onNotification: args.onNotification,
|
|
24469
24506
|
queue: Promise.resolve()
|
|
@@ -24480,8 +24517,8 @@ var CodexAppServerClient = class {
|
|
|
24480
24517
|
}
|
|
24481
24518
|
request(method, params) {
|
|
24482
24519
|
const id = this.process.nextId++;
|
|
24483
|
-
return new Promise((
|
|
24484
|
-
this.process.pending.set(id, { resolve:
|
|
24520
|
+
return new Promise((resolve24, reject) => {
|
|
24521
|
+
this.process.pending.set(id, { resolve: resolve24, reject });
|
|
24485
24522
|
this.process.child.stdin.write(`${JSON.stringify({ method, id, params })}
|
|
24486
24523
|
`);
|
|
24487
24524
|
});
|
|
@@ -24547,7 +24584,7 @@ var CodexAppServerClient = class {
|
|
|
24547
24584
|
};
|
|
24548
24585
|
var clients = /* @__PURE__ */ new Map();
|
|
24549
24586
|
function threadMapPath(cwd) {
|
|
24550
|
-
return
|
|
24587
|
+
return path18.join(cwd, ".kody-engine", "runtime", "codex-threads.json");
|
|
24551
24588
|
}
|
|
24552
24589
|
function readThreadMap(cwd) {
|
|
24553
24590
|
try {
|
|
@@ -24564,7 +24601,7 @@ function readThreadMap(cwd) {
|
|
|
24564
24601
|
}
|
|
24565
24602
|
function writeThreadMap(cwd, map) {
|
|
24566
24603
|
const file = threadMapPath(cwd);
|
|
24567
|
-
fs16.mkdirSync(
|
|
24604
|
+
fs16.mkdirSync(path18.dirname(file), { recursive: true });
|
|
24568
24605
|
fs16.writeFileSync(file, `${JSON.stringify(map, null, 2)}
|
|
24569
24606
|
`);
|
|
24570
24607
|
}
|
|
@@ -24656,7 +24693,7 @@ async function runCodexChatTurn(args) {
|
|
|
24656
24693
|
|
|
24657
24694
|
// src/chat/events.ts
|
|
24658
24695
|
import * as fs17 from "fs";
|
|
24659
|
-
import * as
|
|
24696
|
+
import * as path19 from "path";
|
|
24660
24697
|
import posixPath2 from "path/posix";
|
|
24661
24698
|
var BackendEventSink = class {
|
|
24662
24699
|
constructor(append, tenantId2, sessionId) {
|
|
@@ -24672,7 +24709,7 @@ var BackendEventSink = class {
|
|
|
24672
24709
|
}
|
|
24673
24710
|
};
|
|
24674
24711
|
function eventsFilePath(cwd, sessionId) {
|
|
24675
|
-
return
|
|
24712
|
+
return path19.join(cwd, ".kody-engine", "runtime", "events", `${sessionId}.jsonl`);
|
|
24676
24713
|
}
|
|
24677
24714
|
var FileSink = class {
|
|
24678
24715
|
constructor(file) {
|
|
@@ -24680,7 +24717,7 @@ var FileSink = class {
|
|
|
24680
24717
|
}
|
|
24681
24718
|
file;
|
|
24682
24719
|
async emit(event) {
|
|
24683
|
-
fs17.mkdirSync(
|
|
24720
|
+
fs17.mkdirSync(path19.dirname(this.file), { recursive: true });
|
|
24684
24721
|
fs17.appendFileSync(this.file, `${JSON.stringify(event)}
|
|
24685
24722
|
`);
|
|
24686
24723
|
}
|
|
@@ -25068,7 +25105,7 @@ async function runChatTurn(opts) {
|
|
|
25068
25105
|
quiet: opts.quiet,
|
|
25069
25106
|
additionalDirectories: [
|
|
25070
25107
|
taskArtifactsPaths.absDir,
|
|
25071
|
-
...Array.from(new Set(imagePaths.map((p2) =>
|
|
25108
|
+
...Array.from(new Set(imagePaths.map((p2) => path20.dirname(p2))))
|
|
25072
25109
|
],
|
|
25073
25110
|
systemPromptAppend: systemPrompt,
|
|
25074
25111
|
...opts.reasoningEffort ? { reasoningEffort: opts.reasoningEffort } : {},
|
|
@@ -25256,7 +25293,7 @@ async function emit(sink, type, sessionId, suffix, payload) {
|
|
|
25256
25293
|
var MEMORY_INDEX_REL = ".kody-engine/runtime/memory/INDEX.md";
|
|
25257
25294
|
var MAX_INDEX_BYTES = 8e3;
|
|
25258
25295
|
function readMemoryIndexBlock(cwd) {
|
|
25259
|
-
const indexPath =
|
|
25296
|
+
const indexPath = path20.join(cwd, MEMORY_INDEX_REL);
|
|
25260
25297
|
let raw;
|
|
25261
25298
|
try {
|
|
25262
25299
|
raw = fs18.readFileSync(indexPath, "utf-8");
|
|
@@ -25279,7 +25316,7 @@ _\u2026 (memory index truncated; use recall_search to read more)_` : trimmed;
|
|
|
25279
25316
|
var CONTEXT_DIR_REL = ".kody-engine/runtime/context";
|
|
25280
25317
|
var MAX_CONTEXT_BYTES = 12e3;
|
|
25281
25318
|
function readContextBlock(cwd) {
|
|
25282
|
-
const dir =
|
|
25319
|
+
const dir = path20.join(cwd, CONTEXT_DIR_REL);
|
|
25283
25320
|
let files;
|
|
25284
25321
|
try {
|
|
25285
25322
|
files = fs18.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
@@ -25289,7 +25326,7 @@ function readContextBlock(cwd) {
|
|
|
25289
25326
|
const sections = [];
|
|
25290
25327
|
for (const file of files) {
|
|
25291
25328
|
try {
|
|
25292
|
-
const content = fs18.readFileSync(
|
|
25329
|
+
const content = fs18.readFileSync(path20.join(dir, file), "utf-8").trim();
|
|
25293
25330
|
if (content) sections.push(`### ${file.replace(/\.md$/, "")}
|
|
25294
25331
|
|
|
25295
25332
|
${content}`);
|
|
@@ -25315,7 +25352,7 @@ var SYSTEM_PROMPT_OVERRIDE_REL = ".kody-engine/runtime/system-prompt.md";
|
|
|
25315
25352
|
function readSystemPromptOverride(cwd) {
|
|
25316
25353
|
let raw;
|
|
25317
25354
|
try {
|
|
25318
|
-
raw = fs18.readFileSync(
|
|
25355
|
+
raw = fs18.readFileSync(path20.join(cwd, SYSTEM_PROMPT_OVERRIDE_REL), "utf-8");
|
|
25319
25356
|
} catch {
|
|
25320
25357
|
return null;
|
|
25321
25358
|
}
|
|
@@ -25323,7 +25360,7 @@ function readSystemPromptOverride(cwd) {
|
|
|
25323
25360
|
return trimmed.length > 0 ? trimmed : null;
|
|
25324
25361
|
}
|
|
25325
25362
|
function readInstructionsBlock(cwd) {
|
|
25326
|
-
const instructionsPath =
|
|
25363
|
+
const instructionsPath = path20.join(cwd, INSTRUCTIONS_REL);
|
|
25327
25364
|
let raw;
|
|
25328
25365
|
try {
|
|
25329
25366
|
raw = fs18.readFileSync(instructionsPath, "utf-8");
|
|
@@ -25361,10 +25398,10 @@ function resolveBrainDriver(runtime) {
|
|
|
25361
25398
|
|
|
25362
25399
|
// src/chat/session.ts
|
|
25363
25400
|
import * as fs19 from "fs";
|
|
25364
|
-
import * as
|
|
25401
|
+
import * as path21 from "path";
|
|
25365
25402
|
import posixPath3 from "path/posix";
|
|
25366
25403
|
function sessionFilePath(cwd, sessionId) {
|
|
25367
|
-
return
|
|
25404
|
+
return path21.join(cwd, ".kody-engine", "runtime", "sessions", `${sessionId}.jsonl`);
|
|
25368
25405
|
}
|
|
25369
25406
|
function readSession(file) {
|
|
25370
25407
|
if (!fs19.existsSync(file)) return [];
|
|
@@ -25392,7 +25429,7 @@ init_state_backend();
|
|
|
25392
25429
|
init_workflowDefinitions();
|
|
25393
25430
|
import { createHash as createHash2 } from "crypto";
|
|
25394
25431
|
import * as fs21 from "fs";
|
|
25395
|
-
import * as
|
|
25432
|
+
import * as path23 from "path";
|
|
25396
25433
|
var SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,127}$/;
|
|
25397
25434
|
var REPOSITORY_OWNED_NAMESPACES = ["loops"];
|
|
25398
25435
|
function assertSafeDefinitionPath(filePath) {
|
|
@@ -25424,8 +25461,8 @@ function verifyDefinition(definition) {
|
|
|
25424
25461
|
}
|
|
25425
25462
|
function writeBundle(root, bundle) {
|
|
25426
25463
|
for (const [filePath, contents] of Object.entries(bundle.files)) {
|
|
25427
|
-
const target =
|
|
25428
|
-
fs21.mkdirSync(
|
|
25464
|
+
const target = path23.join(root, filePath);
|
|
25465
|
+
fs21.mkdirSync(path23.dirname(target), { recursive: true });
|
|
25429
25466
|
fs21.writeFileSync(target, contents, "utf8");
|
|
25430
25467
|
}
|
|
25431
25468
|
}
|
|
@@ -25434,22 +25471,22 @@ function writeDefinition(root, kind, definition) {
|
|
|
25434
25471
|
if (kind === "agent") {
|
|
25435
25472
|
const raw = bundle.files["agent.md"];
|
|
25436
25473
|
if (typeof raw !== "string") throw new Error(`agent definition ${definition.slug} is missing agent.md`);
|
|
25437
|
-
fs21.writeFileSync(
|
|
25474
|
+
fs21.writeFileSync(path23.join(root, "agents", `${definition.slug}.md`), raw, "utf8");
|
|
25438
25475
|
return;
|
|
25439
25476
|
}
|
|
25440
25477
|
if (kind === "goal") {
|
|
25441
|
-
writeBundle(
|
|
25478
|
+
writeBundle(path23.join(root, "goals", definition.slug), bundle);
|
|
25442
25479
|
return;
|
|
25443
25480
|
}
|
|
25444
25481
|
if (kind === "implementation") {
|
|
25445
|
-
writeBundle(
|
|
25482
|
+
writeBundle(path23.join(root, "implementations", definition.slug), bundle);
|
|
25446
25483
|
return;
|
|
25447
25484
|
}
|
|
25448
25485
|
if (kind === "asset") {
|
|
25449
|
-
writeBundle(
|
|
25486
|
+
writeBundle(path23.join(root, "shared"), bundle);
|
|
25450
25487
|
return;
|
|
25451
25488
|
}
|
|
25452
|
-
writeBundle(
|
|
25489
|
+
writeBundle(path23.join(root, "capabilities", definition.slug), bundle);
|
|
25453
25490
|
}
|
|
25454
25491
|
function writeWorkflow(root, document) {
|
|
25455
25492
|
const workflow = normalizeWorkflowDefinition(document.definition);
|
|
@@ -25457,28 +25494,28 @@ function writeWorkflow(root, document) {
|
|
|
25457
25494
|
const contents = `${JSON.stringify(workflow, null, 2)}
|
|
25458
25495
|
`;
|
|
25459
25496
|
const bundle = { schemaVersion: 1, files: { "workflow.json": contents } };
|
|
25460
|
-
const target =
|
|
25461
|
-
fs21.mkdirSync(
|
|
25497
|
+
const target = path23.join(root, workflowDefinitionPath(document.workflowId));
|
|
25498
|
+
fs21.mkdirSync(path23.dirname(target), { recursive: true });
|
|
25462
25499
|
fs21.writeFileSync(target, contents, "utf8");
|
|
25463
25500
|
return definitionVersion(bundle);
|
|
25464
25501
|
}
|
|
25465
25502
|
function preserveRepositoryDefinitions(root, staging) {
|
|
25466
25503
|
for (const namespace of REPOSITORY_OWNED_NAMESPACES) {
|
|
25467
|
-
const source =
|
|
25504
|
+
const source = path23.join(root, namespace);
|
|
25468
25505
|
if (!fs21.existsSync(source)) continue;
|
|
25469
|
-
fs21.cpSync(source,
|
|
25506
|
+
fs21.cpSync(source, path23.join(staging, namespace), { recursive: true });
|
|
25470
25507
|
}
|
|
25471
25508
|
}
|
|
25472
25509
|
async function hydrateDefinitions(options) {
|
|
25473
|
-
const root =
|
|
25510
|
+
const root = path23.join(options.cwd, ".kody-engine", "definitions");
|
|
25474
25511
|
const staging = `${root}.tmp-${process.pid}-${Date.now()}`;
|
|
25475
25512
|
fs21.rmSync(staging, { recursive: true, force: true });
|
|
25476
|
-
fs21.mkdirSync(
|
|
25477
|
-
fs21.mkdirSync(
|
|
25478
|
-
fs21.mkdirSync(
|
|
25479
|
-
fs21.mkdirSync(
|
|
25480
|
-
fs21.mkdirSync(
|
|
25481
|
-
fs21.mkdirSync(
|
|
25513
|
+
fs21.mkdirSync(path23.join(staging, "agents"), { recursive: true });
|
|
25514
|
+
fs21.mkdirSync(path23.join(staging, "capabilities"), { recursive: true });
|
|
25515
|
+
fs21.mkdirSync(path23.join(staging, "goals"), { recursive: true });
|
|
25516
|
+
fs21.mkdirSync(path23.join(staging, "implementations"), { recursive: true });
|
|
25517
|
+
fs21.mkdirSync(path23.join(staging, "shared"), { recursive: true });
|
|
25518
|
+
fs21.mkdirSync(path23.join(staging, "workflows"), { recursive: true });
|
|
25482
25519
|
try {
|
|
25483
25520
|
const [capabilities, agents, goals, implementations, assets, workflows] = await Promise.all([
|
|
25484
25521
|
options.backend.listDefinitions(options.tenantId, "capability"),
|
|
@@ -25519,7 +25556,7 @@ async function hydrateDefinitions(options) {
|
|
|
25519
25556
|
hydratedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25520
25557
|
versions: Object.fromEntries(Object.entries(versions).sort(([left], [right]) => left.localeCompare(right)))
|
|
25521
25558
|
};
|
|
25522
|
-
fs21.writeFileSync(
|
|
25559
|
+
fs21.writeFileSync(path23.join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
25523
25560
|
`, "utf8");
|
|
25524
25561
|
fs21.rmSync(root, { recursive: true, force: true });
|
|
25525
25562
|
fs21.renameSync(staging, root);
|
|
@@ -25548,7 +25585,7 @@ async function hydrateDefinitionsFromEnv(cwd = process.cwd(), env = process.env)
|
|
|
25548
25585
|
// src/kody-cli.ts
|
|
25549
25586
|
import { execFileSync as execFileSync24 } from "child_process";
|
|
25550
25587
|
import * as fs55 from "fs";
|
|
25551
|
-
import * as
|
|
25588
|
+
import * as path53 from "path";
|
|
25552
25589
|
|
|
25553
25590
|
// src/app-auth.ts
|
|
25554
25591
|
import { createSign } from "crypto";
|
|
@@ -26350,9 +26387,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
26350
26387
|
return void 0;
|
|
26351
26388
|
}
|
|
26352
26389
|
function detectPackageManager2(cwd) {
|
|
26353
|
-
if (fs55.existsSync(
|
|
26354
|
-
if (fs55.existsSync(
|
|
26355
|
-
if (fs55.existsSync(
|
|
26390
|
+
if (fs55.existsSync(path53.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
26391
|
+
if (fs55.existsSync(path53.join(cwd, "yarn.lock"))) return "yarn";
|
|
26392
|
+
if (fs55.existsSync(path53.join(cwd, "bun.lockb"))) return "bun";
|
|
26356
26393
|
return "npm";
|
|
26357
26394
|
}
|
|
26358
26395
|
function shouldChainScheduledWatch(match) {
|
|
@@ -26485,7 +26522,7 @@ async function runCi(argv) {
|
|
|
26485
26522
|
return 0;
|
|
26486
26523
|
}
|
|
26487
26524
|
const args = parseCiArgs(argv);
|
|
26488
|
-
const cwd = args.cwd ?
|
|
26525
|
+
const cwd = args.cwd ? path53.resolve(args.cwd) : process.cwd();
|
|
26489
26526
|
try {
|
|
26490
26527
|
const n = unpackAllSecrets();
|
|
26491
26528
|
if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s) from ALL_SECRETS
|
|
@@ -26969,7 +27006,7 @@ init_repoWorkspace();
|
|
|
26969
27006
|
// src/scripts/brainTurnLog.ts
|
|
26970
27007
|
init_runtimePaths();
|
|
26971
27008
|
import * as fs56 from "fs";
|
|
26972
|
-
import * as
|
|
27009
|
+
import * as path54 from "path";
|
|
26973
27010
|
import posixPath4 from "path/posix";
|
|
26974
27011
|
var live = /* @__PURE__ */ new Map();
|
|
26975
27012
|
function brainEventsFilePath(dir, chatId) {
|
|
@@ -27016,7 +27053,7 @@ function beginTurn(dir, chatId) {
|
|
|
27016
27053
|
};
|
|
27017
27054
|
live.set(chatId, state);
|
|
27018
27055
|
const p = brainEventsFilePath(dir, chatId);
|
|
27019
|
-
fs56.mkdirSync(
|
|
27056
|
+
fs56.mkdirSync(path54.dirname(p), { recursive: true });
|
|
27020
27057
|
return (event) => {
|
|
27021
27058
|
state.seq += 1;
|
|
27022
27059
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
@@ -27154,17 +27191,17 @@ function authOk(req, expected) {
|
|
|
27154
27191
|
return false;
|
|
27155
27192
|
}
|
|
27156
27193
|
function readJsonBody(req) {
|
|
27157
|
-
return new Promise((
|
|
27194
|
+
return new Promise((resolve24, reject) => {
|
|
27158
27195
|
const chunks = [];
|
|
27159
27196
|
req.on("data", (c) => chunks.push(c));
|
|
27160
27197
|
req.on("end", () => {
|
|
27161
27198
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
27162
27199
|
if (!raw.trim()) {
|
|
27163
|
-
|
|
27200
|
+
resolve24({});
|
|
27164
27201
|
return;
|
|
27165
27202
|
}
|
|
27166
27203
|
try {
|
|
27167
|
-
|
|
27204
|
+
resolve24(JSON.parse(raw));
|
|
27168
27205
|
} catch (err) {
|
|
27169
27206
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
27170
27207
|
}
|
|
@@ -27456,7 +27493,7 @@ function buildServer(opts) {
|
|
|
27456
27493
|
const runTurn = opts.runTurn ?? runChatTurn;
|
|
27457
27494
|
const createStore = opts.createStore ?? createSessionStore;
|
|
27458
27495
|
const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
|
|
27459
|
-
const reposRoot = opts.reposRoot ??
|
|
27496
|
+
const reposRoot = opts.reposRoot ?? path55.join(path55.dirname(path55.resolve(opts.cwd)), "repos");
|
|
27460
27497
|
return createServer2(async (req, res) => {
|
|
27461
27498
|
if (!req.method || !req.url) {
|
|
27462
27499
|
sendJson(res, 400, { error: "bad request" });
|
|
@@ -27537,11 +27574,11 @@ async function brainServe(opts) {
|
|
|
27537
27574
|
litellmUrl,
|
|
27538
27575
|
driver
|
|
27539
27576
|
});
|
|
27540
|
-
await new Promise((
|
|
27577
|
+
await new Promise((resolve24) => {
|
|
27541
27578
|
server.listen(port, "0.0.0.0", () => {
|
|
27542
27579
|
process.stdout.write(`[brain-serve] listening on 0.0.0.0:${port} (cwd=${opts.cwd})
|
|
27543
27580
|
`);
|
|
27544
|
-
|
|
27581
|
+
resolve24();
|
|
27545
27582
|
});
|
|
27546
27583
|
});
|
|
27547
27584
|
const shutdown = (signal) => {
|
|
@@ -27796,14 +27833,14 @@ async function startBrainProxy(opts) {
|
|
|
27796
27833
|
const { httpServer, handler } = buildBrainProxy(opts);
|
|
27797
27834
|
const port = opts.port ?? 0;
|
|
27798
27835
|
const host = opts.host ?? "127.0.0.1";
|
|
27799
|
-
await new Promise((
|
|
27836
|
+
await new Promise((resolve24) => httpServer.listen(port, host, () => resolve24()));
|
|
27800
27837
|
const addr = httpServer.address();
|
|
27801
27838
|
return {
|
|
27802
27839
|
httpServer,
|
|
27803
27840
|
port: addr.port,
|
|
27804
27841
|
url: `http://${host}:${addr.port}`,
|
|
27805
|
-
stop: () => new Promise((
|
|
27806
|
-
httpServer.close(() =>
|
|
27842
|
+
stop: () => new Promise((resolve24) => {
|
|
27843
|
+
httpServer.close(() => resolve24());
|
|
27807
27844
|
}),
|
|
27808
27845
|
handler
|
|
27809
27846
|
};
|
|
@@ -27953,23 +27990,23 @@ function buildMcpHttpServer(opts) {
|
|
|
27953
27990
|
httpServer,
|
|
27954
27991
|
routes,
|
|
27955
27992
|
port,
|
|
27956
|
-
stop: () => new Promise((
|
|
27993
|
+
stop: () => new Promise((resolve24) => {
|
|
27957
27994
|
let pending = transports.size;
|
|
27958
27995
|
if (pending === 0) {
|
|
27959
|
-
httpServer.close(() =>
|
|
27996
|
+
httpServer.close(() => resolve24());
|
|
27960
27997
|
return;
|
|
27961
27998
|
}
|
|
27962
27999
|
for (const transport of transports.values()) {
|
|
27963
28000
|
void transport.close().finally(() => {
|
|
27964
28001
|
pending--;
|
|
27965
|
-
if (pending === 0) httpServer.close(() =>
|
|
28002
|
+
if (pending === 0) httpServer.close(() => resolve24());
|
|
27966
28003
|
});
|
|
27967
28004
|
}
|
|
27968
28005
|
})
|
|
27969
28006
|
};
|
|
27970
28007
|
}
|
|
27971
28008
|
function listenMcpHttpServer(server, host = "127.0.0.1") {
|
|
27972
|
-
return new Promise((
|
|
28009
|
+
return new Promise((resolve24, reject) => {
|
|
27973
28010
|
server.httpServer.once("error", reject);
|
|
27974
28011
|
server.httpServer.listen(server.port, host, () => {
|
|
27975
28012
|
server.httpServer.off("error", reject);
|
|
@@ -27977,7 +28014,7 @@ function listenMcpHttpServer(server, host = "127.0.0.1") {
|
|
|
27977
28014
|
if (addr && typeof addr === "object") {
|
|
27978
28015
|
server.port = addr.port;
|
|
27979
28016
|
}
|
|
27980
|
-
|
|
28017
|
+
resolve24();
|
|
27981
28018
|
});
|
|
27982
28019
|
});
|
|
27983
28020
|
}
|
|
@@ -28060,7 +28097,7 @@ async function loadConfigSafe() {
|
|
|
28060
28097
|
}
|
|
28061
28098
|
|
|
28062
28099
|
// src/chat-cli.ts
|
|
28063
|
-
import * as
|
|
28100
|
+
import * as path56 from "path";
|
|
28064
28101
|
|
|
28065
28102
|
// src/chat/inbox.ts
|
|
28066
28103
|
import { execFileSync as execFileSync25 } from "child_process";
|
|
@@ -28127,7 +28164,7 @@ async function waitForNextUserMessage(opts) {
|
|
|
28127
28164
|
}
|
|
28128
28165
|
}
|
|
28129
28166
|
function sleep3(ms) {
|
|
28130
|
-
return new Promise((
|
|
28167
|
+
return new Promise((resolve24) => setTimeout(resolve24, ms));
|
|
28131
28168
|
}
|
|
28132
28169
|
function currentBranch(cwd) {
|
|
28133
28170
|
try {
|
|
@@ -28351,7 +28388,7 @@ async function runChat(argv) {
|
|
|
28351
28388
|
${CHAT_HELP}`);
|
|
28352
28389
|
return 64;
|
|
28353
28390
|
}
|
|
28354
|
-
const cwd = args.cwd ?
|
|
28391
|
+
const cwd = args.cwd ? path56.resolve(args.cwd) : process.cwd();
|
|
28355
28392
|
const sessionId = args.sessionId;
|
|
28356
28393
|
const runRequest = readRunRequestFromEnv();
|
|
28357
28394
|
if (runRequest && "request" in runRequest) {
|
|
@@ -28478,7 +28515,7 @@ init_registry();
|
|
|
28478
28515
|
|
|
28479
28516
|
// src/servers/brain-terminal-agent.ts
|
|
28480
28517
|
init_repoWorkspace();
|
|
28481
|
-
import * as
|
|
28518
|
+
import * as path58 from "path";
|
|
28482
28519
|
import { createInterface as createInterface2 } from "readline";
|
|
28483
28520
|
|
|
28484
28521
|
// src/terminal/brain-terminal-session.ts
|
|
@@ -28792,10 +28829,10 @@ var BrainTerminalSessionAgent = class {
|
|
|
28792
28829
|
// src/terminal/brain-terminal-adapters.ts
|
|
28793
28830
|
import { createHash as createHash10, randomBytes as randomBytes2 } from "crypto";
|
|
28794
28831
|
import { mkdir, readFile, rename, writeFile as writeFile2 } from "fs/promises";
|
|
28795
|
-
import * as
|
|
28832
|
+
import * as path57 from "path";
|
|
28796
28833
|
import { spawn as spawn9 } from "child_process";
|
|
28797
28834
|
function runTerminalCommand(command, args, input) {
|
|
28798
|
-
return new Promise((
|
|
28835
|
+
return new Promise((resolve24, reject) => {
|
|
28799
28836
|
const child = spawn9(command, args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
28800
28837
|
const stdout = [];
|
|
28801
28838
|
const stderr = [];
|
|
@@ -28803,7 +28840,7 @@ function runTerminalCommand(command, args, input) {
|
|
|
28803
28840
|
child.stderr.on("data", (chunk) => stderr.push(chunk));
|
|
28804
28841
|
child.on("error", reject);
|
|
28805
28842
|
child.on("close", (code) => {
|
|
28806
|
-
|
|
28843
|
+
resolve24({
|
|
28807
28844
|
code: code ?? 1,
|
|
28808
28845
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
28809
28846
|
stderr: Buffer.concat(stderr).toString("utf8")
|
|
@@ -28827,7 +28864,7 @@ var FileBrainTerminalMetadataStore = class {
|
|
|
28827
28864
|
}
|
|
28828
28865
|
root;
|
|
28829
28866
|
file(id) {
|
|
28830
|
-
return
|
|
28867
|
+
return path57.join(this.root, `${storeKey(id)}.json`);
|
|
28831
28868
|
}
|
|
28832
28869
|
async read(id) {
|
|
28833
28870
|
try {
|
|
@@ -28948,8 +28985,8 @@ async function brainTerminalAgent(options) {
|
|
|
28948
28985
|
const input = options.input ?? process.stdin;
|
|
28949
28986
|
const output = options.output ?? process.stdout;
|
|
28950
28987
|
const error = options.error ?? process.stderr;
|
|
28951
|
-
const reposRoot = process.env.BRAIN_REPOS_ROOT?.trim() ||
|
|
28952
|
-
const stateRoot = process.env.BRAIN_TERMINAL_STATE_ROOT?.trim() ||
|
|
28988
|
+
const reposRoot = process.env.BRAIN_REPOS_ROOT?.trim() || path58.join(path58.dirname(path58.resolve(options.cwd)), "repos");
|
|
28989
|
+
const stateRoot = process.env.BRAIN_TERMINAL_STATE_ROOT?.trim() || path58.join(path58.dirname(reposRoot), ".kody", "terminal-sessions");
|
|
28953
28990
|
const agent = new BrainTerminalSessionAgent({
|
|
28954
28991
|
store: new FileBrainTerminalMetadataStore(stateRoot),
|
|
28955
28992
|
runtime: new TmuxBrainTerminalRuntime()
|
|
@@ -29116,8 +29153,8 @@ var FlyClient = class {
|
|
|
29116
29153
|
get fetch() {
|
|
29117
29154
|
return this.opts.fetchImpl ?? fetch;
|
|
29118
29155
|
}
|
|
29119
|
-
async call(
|
|
29120
|
-
const res = await this.fetch(`${FLY_API_BASE}${
|
|
29156
|
+
async call(path59, init = {}) {
|
|
29157
|
+
const res = await this.fetch(`${FLY_API_BASE}${path59}`, {
|
|
29121
29158
|
method: init.method ?? "GET",
|
|
29122
29159
|
headers: {
|
|
29123
29160
|
Authorization: `Bearer ${this.opts.token}`,
|
|
@@ -29128,7 +29165,7 @@ var FlyClient = class {
|
|
|
29128
29165
|
if (res.status === 404 && init.allow404) return null;
|
|
29129
29166
|
if (!res.ok) {
|
|
29130
29167
|
const text2 = await res.text().catch(() => "");
|
|
29131
|
-
throw new Error(`Fly API ${res.status} on ${
|
|
29168
|
+
throw new Error(`Fly API ${res.status} on ${path59}: ${text2.slice(0, 200) || res.statusText}`);
|
|
29132
29169
|
}
|
|
29133
29170
|
if (res.status === 204) return null;
|
|
29134
29171
|
const raw = await res.text();
|
|
@@ -29641,14 +29678,14 @@ function sendJson2(res, status, body) {
|
|
|
29641
29678
|
res.end(JSON.stringify(body));
|
|
29642
29679
|
}
|
|
29643
29680
|
function readJsonBody2(req) {
|
|
29644
|
-
return new Promise((
|
|
29681
|
+
return new Promise((resolve24, reject) => {
|
|
29645
29682
|
const chunks = [];
|
|
29646
29683
|
req.on("data", (c) => chunks.push(c));
|
|
29647
29684
|
req.on("end", () => {
|
|
29648
29685
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
29649
|
-
if (!raw.trim()) return
|
|
29686
|
+
if (!raw.trim()) return resolve24({});
|
|
29650
29687
|
try {
|
|
29651
|
-
|
|
29688
|
+
resolve24(JSON.parse(raw));
|
|
29652
29689
|
} catch (err) {
|
|
29653
29690
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
29654
29691
|
}
|
|
@@ -29802,10 +29839,10 @@ async function poolServe() {
|
|
|
29802
29839
|
}
|
|
29803
29840
|
});
|
|
29804
29841
|
const apiHost = process.env.POOL_API_HOST ?? "::";
|
|
29805
|
-
await new Promise((
|
|
29842
|
+
await new Promise((resolve24) => {
|
|
29806
29843
|
server.listen(apiPort, apiHost, () => {
|
|
29807
29844
|
log(`listening on ${apiHost}:${apiPort} (min=${min}, app=${app}, region=${region})`);
|
|
29808
|
-
|
|
29845
|
+
resolve24();
|
|
29809
29846
|
});
|
|
29810
29847
|
});
|
|
29811
29848
|
if (loopTickEnabled) void runLoopTick();
|
|
@@ -29845,17 +29882,17 @@ function authOk2(req, expected) {
|
|
|
29845
29882
|
return false;
|
|
29846
29883
|
}
|
|
29847
29884
|
function readJsonBody3(req) {
|
|
29848
|
-
return new Promise((
|
|
29885
|
+
return new Promise((resolve24, reject) => {
|
|
29849
29886
|
const chunks = [];
|
|
29850
29887
|
req.on("data", (c) => chunks.push(c));
|
|
29851
29888
|
req.on("end", () => {
|
|
29852
29889
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
29853
29890
|
if (!raw.trim()) {
|
|
29854
|
-
|
|
29891
|
+
resolve24({});
|
|
29855
29892
|
return;
|
|
29856
29893
|
}
|
|
29857
29894
|
try {
|
|
29858
|
-
|
|
29895
|
+
resolve24(JSON.parse(raw));
|
|
29859
29896
|
} catch (err) {
|
|
29860
29897
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
29861
29898
|
}
|
|
@@ -29930,13 +29967,13 @@ async function defaultRunJob(job) {
|
|
|
29930
29967
|
...interactive && job.idleExitMs ? { KODY_IDLE_EXIT_MS: String(job.idleExitMs) } : {},
|
|
29931
29968
|
...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
|
|
29932
29969
|
};
|
|
29933
|
-
const run = (cmd, args, cwd) => new Promise((
|
|
29970
|
+
const run = (cmd, args, cwd) => new Promise((resolve24) => {
|
|
29934
29971
|
const child = spawn10(cmd, args, { stdio: "inherit", env: childEnv, cwd });
|
|
29935
|
-
child.on("exit", (code) =>
|
|
29972
|
+
child.on("exit", (code) => resolve24(code ?? 0));
|
|
29936
29973
|
child.on("error", (err) => {
|
|
29937
29974
|
process.stderr.write(`[runner-serve] ${cmd} failed: ${err.message}
|
|
29938
29975
|
`);
|
|
29939
|
-
|
|
29976
|
+
resolve24(1);
|
|
29940
29977
|
});
|
|
29941
29978
|
});
|
|
29942
29979
|
process.stdout.write(`[runner-serve] job ${job.jobId}: cloning ${job.repo}@${branch}
|
|
@@ -30012,11 +30049,11 @@ async function runnerServe() {
|
|
|
30012
30049
|
const port = Number(process.env.PORT ?? DEFAULT_PORT2);
|
|
30013
30050
|
const server = buildServer2({ apiKey });
|
|
30014
30051
|
const host = process.env.RUNNER_HOST ?? "::";
|
|
30015
|
-
await new Promise((
|
|
30052
|
+
await new Promise((resolve24) => {
|
|
30016
30053
|
server.listen(port, host, () => {
|
|
30017
30054
|
process.stdout.write(`[runner-serve] listening on ${host}:${port} (idle, awaiting job)
|
|
30018
30055
|
`);
|
|
30019
|
-
|
|
30056
|
+
resolve24();
|
|
30020
30057
|
});
|
|
30021
30058
|
});
|
|
30022
30059
|
const shutdown = (signal) => {
|
|
@@ -30085,14 +30122,14 @@ async function serve(opts) {
|
|
|
30085
30122
|
`);
|
|
30086
30123
|
const args = ["--dangerously-skip-permissions", "--model", model.model];
|
|
30087
30124
|
const child = spawn11("claude", args, { stdio: "inherit", env: editorEnv, cwd: opts.cwd });
|
|
30088
|
-
const exitCode = await new Promise((
|
|
30089
|
-
child.on("exit", (code) =>
|
|
30125
|
+
const exitCode = await new Promise((resolve24) => {
|
|
30126
|
+
child.on("exit", (code) => resolve24(code ?? 0));
|
|
30090
30127
|
child.on("error", (err) => {
|
|
30091
30128
|
process.stderr.write(`[kody serve] failed to launch Claude Code: ${err.message}
|
|
30092
30129
|
`);
|
|
30093
30130
|
process.stderr.write(` Install: https://docs.anthropic.com/claude/docs/claude-code
|
|
30094
30131
|
`);
|
|
30095
|
-
|
|
30132
|
+
resolve24(1);
|
|
30096
30133
|
});
|
|
30097
30134
|
});
|
|
30098
30135
|
killProxy();
|