@kody-ade/kody-engine 0.4.570 → 0.4.572
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 +483 -436
- 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.572",
|
|
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",
|
|
@@ -150,9 +150,38 @@ var init_claudeBinary = __esm({
|
|
|
150
150
|
}
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
+
// src/completionGuard.ts
|
|
154
|
+
import * as path2 from "path";
|
|
155
|
+
function completionToolCutoffAt(startedAtMs, deadlineAtMs) {
|
|
156
|
+
const availableMs = Math.max(0, deadlineAtMs - startedAtMs);
|
|
157
|
+
const reserveMs = Math.min(MAX_COMPLETION_RESERVE_MS, Math.floor(availableMs / 2));
|
|
158
|
+
return deadlineAtMs - reserveMs;
|
|
159
|
+
}
|
|
160
|
+
function createCompletionToolGuard(cutoffAtMs, now = Date.now, requiredOutputPath) {
|
|
161
|
+
return async (input) => {
|
|
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
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
decision: "block",
|
|
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."
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
var MAX_COMPLETION_RESERVE_MS;
|
|
175
|
+
var init_completionGuard = __esm({
|
|
176
|
+
"src/completionGuard.ts"() {
|
|
177
|
+
"use strict";
|
|
178
|
+
MAX_COMPLETION_RESERVE_MS = 15 * 6e4;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
153
182
|
// src/config.ts
|
|
154
183
|
import * as fs2 from "fs";
|
|
155
|
-
import * as
|
|
184
|
+
import * as path3 from "path";
|
|
156
185
|
function parseReasoningEffort(raw) {
|
|
157
186
|
if (!raw) return null;
|
|
158
187
|
const v = raw.trim().toLowerCase();
|
|
@@ -217,7 +246,7 @@ function needsLitellmProxy(model) {
|
|
|
217
246
|
return model.provider !== "claude" && model.provider !== "anthropic";
|
|
218
247
|
}
|
|
219
248
|
function loadConfig(projectDir = process.cwd()) {
|
|
220
|
-
const configPath =
|
|
249
|
+
const configPath = path3.join(projectDir, "kody.config.json");
|
|
221
250
|
if (!fs2.existsSync(configPath)) {
|
|
222
251
|
throw new Error(`kody.config.json not found at ${configPath}`);
|
|
223
252
|
}
|
|
@@ -548,6 +577,29 @@ var init_config = __esm({
|
|
|
548
577
|
}
|
|
549
578
|
});
|
|
550
579
|
|
|
580
|
+
// src/fileEditGuards.ts
|
|
581
|
+
import * as fs3 from "fs";
|
|
582
|
+
import * as path4 from "path";
|
|
583
|
+
function createMissingParentWriteGuard(cwd) {
|
|
584
|
+
return async (input) => {
|
|
585
|
+
const toolInput = input.tool_input;
|
|
586
|
+
if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return {};
|
|
587
|
+
const filePath = toolInput.file_path;
|
|
588
|
+
if (typeof filePath !== "string" || filePath.length === 0) return {};
|
|
589
|
+
const resolvedPath = path4.resolve(cwd, filePath);
|
|
590
|
+
if (fs3.existsSync(path4.dirname(resolvedPath))) return {};
|
|
591
|
+
return {
|
|
592
|
+
decision: "block",
|
|
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.`
|
|
594
|
+
};
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
var init_fileEditGuards = __esm({
|
|
598
|
+
"src/fileEditGuards.ts"() {
|
|
599
|
+
"use strict";
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
|
|
551
603
|
// src/format.ts
|
|
552
604
|
function renderEvent(msg, opts = {}) {
|
|
553
605
|
if (opts.quiet) {
|
|
@@ -669,29 +721,6 @@ var init_format = __esm({
|
|
|
669
721
|
}
|
|
670
722
|
});
|
|
671
723
|
|
|
672
|
-
// src/fileEditGuards.ts
|
|
673
|
-
import * as fs3 from "fs";
|
|
674
|
-
import * as path3 from "path";
|
|
675
|
-
function createMissingParentWriteGuard(cwd) {
|
|
676
|
-
return async (input) => {
|
|
677
|
-
const toolInput = input.tool_input;
|
|
678
|
-
if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return {};
|
|
679
|
-
const filePath = toolInput.file_path;
|
|
680
|
-
if (typeof filePath !== "string" || filePath.length === 0) return {};
|
|
681
|
-
const resolvedPath = path3.resolve(cwd, filePath);
|
|
682
|
-
if (fs3.existsSync(path3.dirname(resolvedPath))) return {};
|
|
683
|
-
return {
|
|
684
|
-
decision: "block",
|
|
685
|
-
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.`
|
|
686
|
-
};
|
|
687
|
-
};
|
|
688
|
-
}
|
|
689
|
-
var init_fileEditGuards = __esm({
|
|
690
|
-
"src/fileEditGuards.ts"() {
|
|
691
|
-
"use strict";
|
|
692
|
-
}
|
|
693
|
-
});
|
|
694
|
-
|
|
695
724
|
// src/agency/capability-contract-validation.ts
|
|
696
725
|
import Ajv from "ajv";
|
|
697
726
|
function createCapabilityContractValueValidator(compile) {
|
|
@@ -765,7 +794,7 @@ var init_capability_contract_validation = __esm({
|
|
|
765
794
|
|
|
766
795
|
// src/outputContractHooks.ts
|
|
767
796
|
import * as fs4 from "fs";
|
|
768
|
-
import * as
|
|
797
|
+
import * as path5 from "path";
|
|
769
798
|
function outputContractError(contract) {
|
|
770
799
|
let value;
|
|
771
800
|
try {
|
|
@@ -784,12 +813,12 @@ function correctionMessage(contract, error) {
|
|
|
784
813
|
return `The authoritative output does not match its required contract: ${error}. Please overwrite ${contract.path} with only the required JSON shape before finishing.`;
|
|
785
814
|
}
|
|
786
815
|
function createOutputContractPostWriteHook(contract) {
|
|
787
|
-
const expectedPath =
|
|
816
|
+
const expectedPath = path5.resolve(contract.path);
|
|
788
817
|
return async (input) => {
|
|
789
818
|
const toolInput = input.tool_input;
|
|
790
819
|
if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return {};
|
|
791
820
|
const filePath = toolInput.file_path;
|
|
792
|
-
if (typeof filePath !== "string" ||
|
|
821
|
+
if (typeof filePath !== "string" || path5.resolve(filePath) !== expectedPath) return {};
|
|
793
822
|
const error = outputContractError(contract);
|
|
794
823
|
if (!error) return {};
|
|
795
824
|
return {
|
|
@@ -833,21 +862,21 @@ __export(runtimePaths_exports, {
|
|
|
833
862
|
});
|
|
834
863
|
import { createHash } from "crypto";
|
|
835
864
|
import * as os2 from "os";
|
|
836
|
-
import * as
|
|
865
|
+
import * as path6 from "path";
|
|
837
866
|
function runtimeDirForCwd(cwd, ...parts) {
|
|
838
|
-
const key = createHash("sha256").update(
|
|
839
|
-
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);
|
|
840
869
|
}
|
|
841
870
|
function runtimeStatePath(cwd, ...parts) {
|
|
842
871
|
const configuredRoot = process.env.KODY_RUNTIME_DIR?.trim();
|
|
843
|
-
const base = configuredRoot ?
|
|
844
|
-
return
|
|
872
|
+
const base = configuredRoot ? path6.resolve(configuredRoot) : runtimeDirForCwd(cwd);
|
|
873
|
+
return path6.join(base, ...parts);
|
|
845
874
|
}
|
|
846
875
|
function agentRunDir(cwd) {
|
|
847
876
|
return runtimeStatePath(cwd, "agent-runs");
|
|
848
877
|
}
|
|
849
878
|
function lastRunLogPath(cwd) {
|
|
850
|
-
return
|
|
879
|
+
return path6.join(agentRunDir(cwd), "last-run.jsonl");
|
|
851
880
|
}
|
|
852
881
|
var init_runtimePaths = __esm({
|
|
853
882
|
"src/runtimePaths.ts"() {
|
|
@@ -858,15 +887,15 @@ var init_runtimePaths = __esm({
|
|
|
858
887
|
// src/scripts/buildSyntheticPlugin.ts
|
|
859
888
|
import * as fs5 from "fs";
|
|
860
889
|
import * as os3 from "os";
|
|
861
|
-
import * as
|
|
890
|
+
import * as path7 from "path";
|
|
862
891
|
function getPluginsCatalogRoot() {
|
|
863
|
-
const here =
|
|
892
|
+
const here = path7.dirname(new URL(import.meta.url).pathname);
|
|
864
893
|
const candidates = [
|
|
865
|
-
|
|
894
|
+
path7.join(here, "..", "plugins"),
|
|
866
895
|
// dev: src/scripts → src/plugins
|
|
867
|
-
|
|
896
|
+
path7.join(here, "..", "..", "plugins"),
|
|
868
897
|
// built: dist/scripts → dist/plugins
|
|
869
|
-
|
|
898
|
+
path7.join(here, "..", "..", "src", "plugins")
|
|
870
899
|
// fallback
|
|
871
900
|
];
|
|
872
901
|
for (const c of candidates) {
|
|
@@ -877,8 +906,8 @@ function getPluginsCatalogRoot() {
|
|
|
877
906
|
function copyDir(src, dst) {
|
|
878
907
|
fs5.mkdirSync(dst, { recursive: true });
|
|
879
908
|
for (const ent of fs5.readdirSync(src, { withFileTypes: true })) {
|
|
880
|
-
const s =
|
|
881
|
-
const d =
|
|
909
|
+
const s = path7.join(src, ent.name);
|
|
910
|
+
const d = path7.join(dst, ent.name);
|
|
882
911
|
if (ent.isDirectory()) copyDir(s, d);
|
|
883
912
|
else if (ent.isFile()) fs5.copyFileSync(s, d);
|
|
884
913
|
}
|
|
@@ -893,35 +922,35 @@ var init_buildSyntheticPlugin = __esm({
|
|
|
893
922
|
if (!needsSynthetic) return;
|
|
894
923
|
const catalog = getPluginsCatalogRoot();
|
|
895
924
|
const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
896
|
-
const root =
|
|
897
|
-
fs5.mkdirSync(
|
|
925
|
+
const root = path7.join(os3.tmpdir(), `kody-synth-${runId}`);
|
|
926
|
+
fs5.mkdirSync(path7.join(root, ".claude-plugin"), { recursive: true });
|
|
898
927
|
const resolvePart = (bucket, entry) => {
|
|
899
|
-
const local =
|
|
928
|
+
const local = path7.join(profile.dir, bucket, entry);
|
|
900
929
|
if (fs5.existsSync(local)) return local;
|
|
901
|
-
const shared =
|
|
930
|
+
const shared = path7.resolve(profile.dir, "..", "..", "shared", bucket, entry);
|
|
902
931
|
if (fs5.existsSync(shared)) return shared;
|
|
903
|
-
const central =
|
|
932
|
+
const central = path7.join(catalog, bucket, entry);
|
|
904
933
|
if (fs5.existsSync(central)) return central;
|
|
905
934
|
throw new Error(
|
|
906
|
-
`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}/)`
|
|
907
936
|
);
|
|
908
937
|
};
|
|
909
938
|
if (cc.skills.length > 0) {
|
|
910
|
-
const dst =
|
|
939
|
+
const dst = path7.join(root, "skills");
|
|
911
940
|
fs5.mkdirSync(dst, { recursive: true });
|
|
912
941
|
for (const name of cc.skills) {
|
|
913
|
-
copyDir(resolvePart("skills", name),
|
|
942
|
+
copyDir(resolvePart("skills", name), path7.join(dst, name));
|
|
914
943
|
}
|
|
915
944
|
}
|
|
916
945
|
if (cc.commands.length > 0) {
|
|
917
|
-
const dst =
|
|
946
|
+
const dst = path7.join(root, "commands");
|
|
918
947
|
fs5.mkdirSync(dst, { recursive: true });
|
|
919
948
|
for (const name of cc.commands) {
|
|
920
|
-
fs5.copyFileSync(resolvePart("commands", `${name}.md`),
|
|
949
|
+
fs5.copyFileSync(resolvePart("commands", `${name}.md`), path7.join(dst, `${name}.md`));
|
|
921
950
|
}
|
|
922
951
|
}
|
|
923
952
|
if (cc.hooks.length > 0) {
|
|
924
|
-
const dst =
|
|
953
|
+
const dst = path7.join(root, "hooks");
|
|
925
954
|
fs5.mkdirSync(dst, { recursive: true });
|
|
926
955
|
const merged = { hooks: {} };
|
|
927
956
|
for (const name of cc.hooks) {
|
|
@@ -933,7 +962,7 @@ var init_buildSyntheticPlugin = __esm({
|
|
|
933
962
|
merged.hooks[event].push(...entries);
|
|
934
963
|
}
|
|
935
964
|
}
|
|
936
|
-
fs5.writeFileSync(
|
|
965
|
+
fs5.writeFileSync(path7.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
|
|
937
966
|
`);
|
|
938
967
|
}
|
|
939
968
|
const manifest = {
|
|
@@ -943,7 +972,7 @@ var init_buildSyntheticPlugin = __esm({
|
|
|
943
972
|
};
|
|
944
973
|
if (cc.skills.length > 0) manifest.skills = ["./skills/"];
|
|
945
974
|
if (cc.commands.length > 0) manifest.commands = ["./commands/"];
|
|
946
|
-
fs5.writeFileSync(
|
|
975
|
+
fs5.writeFileSync(path7.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
|
|
947
976
|
`);
|
|
948
977
|
ctx.data.syntheticPluginPath = root;
|
|
949
978
|
};
|
|
@@ -952,7 +981,7 @@ var init_buildSyntheticPlugin = __esm({
|
|
|
952
981
|
|
|
953
982
|
// src/subagents.ts
|
|
954
983
|
import * as fs6 from "fs";
|
|
955
|
-
import * as
|
|
984
|
+
import * as path8 from "path";
|
|
956
985
|
async function enforceSubagentModelInheritance(input) {
|
|
957
986
|
const toolInput = input.tool_input;
|
|
958
987
|
if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return {};
|
|
@@ -987,11 +1016,11 @@ function splitFrontmatter(raw) {
|
|
|
987
1016
|
return { fm, body: (match[2] ?? "").trim() };
|
|
988
1017
|
}
|
|
989
1018
|
function resolveAgentFile(profileDir, name) {
|
|
990
|
-
const local =
|
|
1019
|
+
const local = path8.join(profileDir, "agents", `${name}.md`);
|
|
991
1020
|
if (fs6.existsSync(local)) return local;
|
|
992
|
-
const shared =
|
|
1021
|
+
const shared = path8.resolve(profileDir, "..", "..", "shared", "agents", `${name}.md`);
|
|
993
1022
|
if (fs6.existsSync(shared)) return shared;
|
|
994
|
-
const central =
|
|
1023
|
+
const central = path8.join(getPluginsCatalogRoot(), "agents", `${name}.md`);
|
|
995
1024
|
if (fs6.existsSync(central)) return central;
|
|
996
1025
|
throw new Error(
|
|
997
1026
|
`loadSubagents: agent '${name}' not found in ${profileDir}/agents/, hydrated shared assets, or engine catalog`
|
|
@@ -1048,7 +1077,7 @@ __export(events_exports, {
|
|
|
1048
1077
|
});
|
|
1049
1078
|
import * as crypto from "crypto";
|
|
1050
1079
|
import * as fs7 from "fs";
|
|
1051
|
-
import * as
|
|
1080
|
+
import * as path9 from "path";
|
|
1052
1081
|
function resolveRunId() {
|
|
1053
1082
|
if (process.env.KODY_RUN_ID) {
|
|
1054
1083
|
cachedRunId = process.env.KODY_RUN_ID;
|
|
@@ -1081,7 +1110,7 @@ function emitEvent(cwd, ev) {
|
|
|
1081
1110
|
...ev
|
|
1082
1111
|
};
|
|
1083
1112
|
const file = eventsPath(cwd, runId);
|
|
1084
|
-
fs7.mkdirSync(
|
|
1113
|
+
fs7.mkdirSync(path9.dirname(file), { recursive: true });
|
|
1085
1114
|
fs7.appendFileSync(file, `${JSON.stringify(fullEvent)}
|
|
1086
1115
|
`);
|
|
1087
1116
|
} catch {
|
|
@@ -1107,7 +1136,7 @@ function listRuns(cwd) {
|
|
|
1107
1136
|
if (!fs7.existsSync(runsDir)) return [];
|
|
1108
1137
|
return fs7.readdirSync(runsDir).filter((name) => {
|
|
1109
1138
|
try {
|
|
1110
|
-
return fs7.statSync(
|
|
1139
|
+
return fs7.statSync(path9.join(runsDir, name)).isDirectory();
|
|
1111
1140
|
} catch {
|
|
1112
1141
|
return false;
|
|
1113
1142
|
}
|
|
@@ -1148,10 +1177,10 @@ function abortMessage(signal) {
|
|
|
1148
1177
|
return reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "verification aborted";
|
|
1149
1178
|
}
|
|
1150
1179
|
function runCommand(command, cwd, signal) {
|
|
1151
|
-
return new Promise((
|
|
1180
|
+
return new Promise((resolve24) => {
|
|
1152
1181
|
const start = Date.now();
|
|
1153
1182
|
if (signal?.aborted) {
|
|
1154
|
-
|
|
1183
|
+
resolve24({ exitCode: -1, durationMs: 0, tail: abortMessage(signal) });
|
|
1155
1184
|
return;
|
|
1156
1185
|
}
|
|
1157
1186
|
const child = spawn(command, {
|
|
@@ -1189,7 +1218,7 @@ function runCommand(command, cwd, signal) {
|
|
|
1189
1218
|
signal?.removeEventListener("abort", onAbort);
|
|
1190
1219
|
const output = Buffer.concat(buffers).toString("utf-8");
|
|
1191
1220
|
const tail = [output, extraTail].filter(Boolean).join("\n").slice(-TAIL_CHARS);
|
|
1192
|
-
|
|
1221
|
+
resolve24({ exitCode, durationMs: Date.now() - start, tail });
|
|
1193
1222
|
};
|
|
1194
1223
|
const terminate = () => {
|
|
1195
1224
|
killTree("SIGTERM");
|
|
@@ -1518,7 +1547,7 @@ function cmsHeaders(opts) {
|
|
|
1518
1547
|
}
|
|
1519
1548
|
};
|
|
1520
1549
|
}
|
|
1521
|
-
async function callDashboardCms(opts,
|
|
1550
|
+
async function callDashboardCms(opts, path59, init = {}) {
|
|
1522
1551
|
const baseUrl = dashboardBaseUrl(opts);
|
|
1523
1552
|
if (!baseUrl) {
|
|
1524
1553
|
return {
|
|
@@ -1530,7 +1559,7 @@ async function callDashboardCms(opts, path58, init = {}) {
|
|
|
1530
1559
|
const headerResult = cmsHeaders(opts);
|
|
1531
1560
|
if (!headerResult.ok) return headerResult;
|
|
1532
1561
|
try {
|
|
1533
|
-
const res = await fetch(`${baseUrl}${
|
|
1562
|
+
const res = await fetch(`${baseUrl}${path59}`, {
|
|
1534
1563
|
...init,
|
|
1535
1564
|
headers: {
|
|
1536
1565
|
...headerResult.headers,
|
|
@@ -1602,8 +1631,8 @@ function documentArg(value) {
|
|
|
1602
1631
|
function normalizeCmsDocumentIdInput(input) {
|
|
1603
1632
|
const trimmed = stripWrappingQuotes(input.trim());
|
|
1604
1633
|
const withoutQuery = trimmed.split(/[?#]/, 1)[0] ?? trimmed;
|
|
1605
|
-
const
|
|
1606
|
-
return
|
|
1634
|
+
const path59 = parseDocumentPath(withoutQuery);
|
|
1635
|
+
return path59 ?? parseDocumentIdSegment(withoutQuery) ?? withoutQuery;
|
|
1607
1636
|
}
|
|
1608
1637
|
function stripWrappingQuotes(value) {
|
|
1609
1638
|
let current = value;
|
|
@@ -1614,9 +1643,9 @@ function stripWrappingQuotes(value) {
|
|
|
1614
1643
|
}
|
|
1615
1644
|
}
|
|
1616
1645
|
function parseDocumentPath(value) {
|
|
1617
|
-
const
|
|
1618
|
-
if (!
|
|
1619
|
-
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);
|
|
1620
1649
|
const entriesIndex = parts.findIndex((part, index) => part === "content" && parts[index + 1] === "entries");
|
|
1621
1650
|
const idPart = parts[entriesIndex + 3];
|
|
1622
1651
|
if (!idPart || idPart === "new") return null;
|
|
@@ -2062,7 +2091,7 @@ var init_issue = __esm({
|
|
|
2062
2091
|
|
|
2063
2092
|
// src/capabilityFolders.ts
|
|
2064
2093
|
import * as fs8 from "fs";
|
|
2065
|
-
import * as
|
|
2094
|
+
import * as path10 from "path";
|
|
2066
2095
|
function capabilityOutputConditionPaths(config) {
|
|
2067
2096
|
if (config.outputSchema) {
|
|
2068
2097
|
return new Set(schemaPropertyPaths(config.outputSchema, "result"));
|
|
@@ -2084,35 +2113,35 @@ function listCapabilityFolderSlugs(absDir) {
|
|
|
2084
2113
|
} catch {
|
|
2085
2114
|
return [];
|
|
2086
2115
|
}
|
|
2087
|
-
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();
|
|
2088
2117
|
}
|
|
2089
2118
|
function isCapabilityFolder(dir) {
|
|
2090
2119
|
const entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
2091
|
-
const legacyBody =
|
|
2120
|
+
const legacyBody = path10.join(dir, CAPABILITY_BODY_FILE);
|
|
2092
2121
|
if (fs8.existsSync(legacyBody)) {
|
|
2093
2122
|
return entries.every(
|
|
2094
2123
|
(entry) => entry.name === CAPABILITY_BODY_FILE || entry.name === CAPABILITY_CONTRACT_FILE || entry.isDirectory() && (entry.name === "skills" || entry.name === "tools")
|
|
2095
2124
|
);
|
|
2096
2125
|
}
|
|
2097
|
-
const canonicalBody =
|
|
2098
|
-
const canonicalDefinition =
|
|
2126
|
+
const canonicalBody = path10.join(dir, CANONICAL_CAPABILITY_BODY_FILE);
|
|
2127
|
+
const canonicalDefinition = path10.join(dir, CANONICAL_CAPABILITY_DEFINITION_FILE);
|
|
2099
2128
|
if (!fs8.existsSync(canonicalBody) || !fs8.existsSync(canonicalDefinition)) return false;
|
|
2100
2129
|
return entries.every(
|
|
2101
2130
|
(entry) => entry.name === CANONICAL_CAPABILITY_BODY_FILE || entry.name === CANONICAL_CAPABILITY_DEFINITION_FILE
|
|
2102
2131
|
);
|
|
2103
2132
|
}
|
|
2104
2133
|
function readCapabilityFolder(root, slug) {
|
|
2105
|
-
const dir =
|
|
2106
|
-
const legacyBodyPath =
|
|
2107
|
-
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);
|
|
2108
2137
|
const bodyPath = fs8.existsSync(legacyBodyPath) ? legacyBodyPath : canonicalBodyPath;
|
|
2109
|
-
const contractPath =
|
|
2138
|
+
const contractPath = path10.join(dir, CAPABILITY_CONTRACT_FILE);
|
|
2110
2139
|
if (!fs8.existsSync(bodyPath) || !fs8.statSync(bodyPath).isFile()) return null;
|
|
2111
2140
|
if (!isCapabilityFolder(dir)) return null;
|
|
2112
2141
|
try {
|
|
2113
2142
|
const rawBody = fs8.readFileSync(bodyPath, "utf-8");
|
|
2114
2143
|
if (bodyPath === canonicalBodyPath) {
|
|
2115
|
-
const definitionPath =
|
|
2144
|
+
const definitionPath = path10.join(dir, CANONICAL_CAPABILITY_DEFINITION_FILE);
|
|
2116
2145
|
const definition = JSON.parse(fs8.readFileSync(definitionPath, "utf-8"));
|
|
2117
2146
|
if (definition.id !== slug || typeof definition.action !== "string") return null;
|
|
2118
2147
|
const { title: title2, body: body2 } = parseCapabilityBody(rawBody, slug);
|
|
@@ -2134,7 +2163,7 @@ function readCapabilityFolder(root, slug) {
|
|
|
2134
2163
|
};
|
|
2135
2164
|
}
|
|
2136
2165
|
const contract = fs8.existsSync(contractPath) ? parseCapabilityContract(fs8.readFileSync(contractPath, "utf-8")) : void 0;
|
|
2137
|
-
if (contract?.execution === "script" && !isRegularFile(
|
|
2166
|
+
if (contract?.execution === "script" && !isRegularFile(path10.join(dir, "tools", "run.sh"))) {
|
|
2138
2167
|
throw new Error('script-backed Capability requires a regular "tools/run.sh" file');
|
|
2139
2168
|
}
|
|
2140
2169
|
const { title, body } = parseCapabilityBody(rawBody, slug);
|
|
@@ -2256,8 +2285,8 @@ function isRegularFile(filePath) {
|
|
|
2256
2285
|
function schemaPropertyPaths(schema, prefix) {
|
|
2257
2286
|
const properties = isPlainObject(schema.properties) ? schema.properties : {};
|
|
2258
2287
|
return Object.entries(properties).flatMap(([name, property]) => {
|
|
2259
|
-
const
|
|
2260
|
-
return isPlainObject(property) ? [
|
|
2288
|
+
const path59 = `${prefix}.${name}`;
|
|
2289
|
+
return isPlainObject(property) ? [path59, ...schemaPropertyPaths(property, path59)] : [path59];
|
|
2261
2290
|
});
|
|
2262
2291
|
}
|
|
2263
2292
|
function parseCapabilityBody(raw, slug) {
|
|
@@ -2424,47 +2453,47 @@ var init_capabilityFolders = __esm({
|
|
|
2424
2453
|
|
|
2425
2454
|
// src/definition-paths.ts
|
|
2426
2455
|
import * as fs9 from "fs";
|
|
2427
|
-
import * as
|
|
2456
|
+
import * as path11 from "path";
|
|
2428
2457
|
function definitionsRoot(cwd = process.cwd()) {
|
|
2429
2458
|
const override = process.env.KODY_DEFINITIONS_ROOT?.trim();
|
|
2430
2459
|
const overrideCwd = process.env.KODY_DEFINITIONS_ROOT_CWD?.trim();
|
|
2431
|
-
if (override && overrideCwd &&
|
|
2432
|
-
return storeCatalogRoot(
|
|
2460
|
+
if (override && overrideCwd && path11.resolve(cwd) === path11.resolve(overrideCwd)) {
|
|
2461
|
+
return storeCatalogRoot(path11.resolve(override));
|
|
2433
2462
|
}
|
|
2434
|
-
const hydrated =
|
|
2463
|
+
const hydrated = path11.join(cwd, ".kody-engine", "definitions");
|
|
2435
2464
|
if (fs9.existsSync(hydrated)) return hydrated;
|
|
2436
|
-
return override ? storeCatalogRoot(
|
|
2465
|
+
return override ? storeCatalogRoot(path11.resolve(override)) : hydrated;
|
|
2437
2466
|
}
|
|
2438
2467
|
function hasExplicitDefinitionsRoot(cwd = process.cwd(), env = process.env) {
|
|
2439
2468
|
const root = env.KODY_DEFINITIONS_ROOT?.trim();
|
|
2440
2469
|
const rootCwd = env.KODY_DEFINITIONS_ROOT_CWD?.trim();
|
|
2441
|
-
return Boolean(root && rootCwd &&
|
|
2470
|
+
return Boolean(root && rootCwd && path11.resolve(cwd) === path11.resolve(rootCwd));
|
|
2442
2471
|
}
|
|
2443
2472
|
function capabilitiesRoot(cwd = process.cwd()) {
|
|
2444
|
-
return storeAssetRoot(cwd, "capabilities") ??
|
|
2473
|
+
return storeAssetRoot(cwd, "capabilities") ?? path11.join(definitionsRoot(cwd), "capabilities");
|
|
2445
2474
|
}
|
|
2446
2475
|
function implementationsRoot(cwd = process.cwd()) {
|
|
2447
|
-
return
|
|
2476
|
+
return path11.join(definitionsRoot(cwd), "implementations");
|
|
2448
2477
|
}
|
|
2449
2478
|
function agentsRoot(cwd = process.cwd()) {
|
|
2450
|
-
return storeAssetRoot(cwd, "agent") ??
|
|
2479
|
+
return storeAssetRoot(cwd, "agent") ?? path11.join(definitionsRoot(cwd), "agents");
|
|
2451
2480
|
}
|
|
2452
2481
|
function storeCatalogRoot(root) {
|
|
2453
2482
|
const manifest = readStoreManifest(root);
|
|
2454
|
-
const roots = ["capabilities", "workflows", "loops"].map((kind) => manifest?.assetRoots?.[kind]).filter((value) => typeof value === "string" && Boolean(value.trim())).map((value) =>
|
|
2455
|
-
return roots.length === 3 && new Set(roots).size === 1 ?
|
|
2483
|
+
const roots = ["capabilities", "workflows", "loops"].map((kind) => manifest?.assetRoots?.[kind]).filter((value) => typeof value === "string" && Boolean(value.trim())).map((value) => path11.dirname(value));
|
|
2484
|
+
return roots.length === 3 && new Set(roots).size === 1 ? path11.join(root, roots[0]) : root;
|
|
2456
2485
|
}
|
|
2457
2486
|
function storeAssetRoot(cwd, kind) {
|
|
2458
2487
|
const override = process.env.KODY_DEFINITIONS_ROOT?.trim();
|
|
2459
2488
|
if (!override) return null;
|
|
2460
2489
|
const overrideCwd = process.env.KODY_DEFINITIONS_ROOT_CWD?.trim();
|
|
2461
|
-
if (overrideCwd &&
|
|
2462
|
-
const root =
|
|
2490
|
+
if (overrideCwd && path11.resolve(cwd) !== path11.resolve(overrideCwd)) return null;
|
|
2491
|
+
const root = path11.resolve(override);
|
|
2463
2492
|
const configured = readStoreManifest(root)?.assetRoots?.[kind];
|
|
2464
|
-
return typeof configured === "string" && configured.trim() ?
|
|
2493
|
+
return typeof configured === "string" && configured.trim() ? path11.join(root, configured) : null;
|
|
2465
2494
|
}
|
|
2466
2495
|
function readStoreManifest(root) {
|
|
2467
|
-
const file =
|
|
2496
|
+
const file = path11.join(root, "kody-store.json");
|
|
2468
2497
|
if (!fs9.existsSync(file)) return null;
|
|
2469
2498
|
try {
|
|
2470
2499
|
return JSON.parse(fs9.readFileSync(file, "utf8"));
|
|
@@ -2480,15 +2509,15 @@ var init_definition_paths = __esm({
|
|
|
2480
2509
|
|
|
2481
2510
|
// src/registry.ts
|
|
2482
2511
|
import * as fs10 from "fs";
|
|
2483
|
-
import * as
|
|
2512
|
+
import * as path12 from "path";
|
|
2484
2513
|
function getImplementationsRoot() {
|
|
2485
|
-
const here =
|
|
2514
|
+
const here = path12.dirname(new URL(import.meta.url).pathname);
|
|
2486
2515
|
const candidates = [
|
|
2487
|
-
|
|
2516
|
+
path12.join(here, "implementations"),
|
|
2488
2517
|
// dev: src/
|
|
2489
|
-
|
|
2518
|
+
path12.join(here, "..", "implementations"),
|
|
2490
2519
|
// built: dist/bin → dist/implementations
|
|
2491
|
-
|
|
2520
|
+
path12.join(here, "..", "src", "implementations")
|
|
2492
2521
|
// fallback
|
|
2493
2522
|
];
|
|
2494
2523
|
for (const c of candidates) {
|
|
@@ -2497,11 +2526,11 @@ function getImplementationsRoot() {
|
|
|
2497
2526
|
return candidates[0];
|
|
2498
2527
|
}
|
|
2499
2528
|
function getRuntimeServicesRoot() {
|
|
2500
|
-
const here =
|
|
2529
|
+
const here = path12.dirname(new URL(import.meta.url).pathname);
|
|
2501
2530
|
const candidates = [
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2531
|
+
path12.join(here, "runtime-services"),
|
|
2532
|
+
path12.join(here, "..", "runtime-services"),
|
|
2533
|
+
path12.join(here, "..", "src", "runtime-services")
|
|
2505
2534
|
];
|
|
2506
2535
|
for (const candidate of candidates) {
|
|
2507
2536
|
if (fs10.existsSync(candidate) && fs10.statSync(candidate).isDirectory()) return candidate;
|
|
@@ -2512,13 +2541,13 @@ function getProjectCapabilitiesRoot() {
|
|
|
2512
2541
|
return capabilitiesRoot();
|
|
2513
2542
|
}
|
|
2514
2543
|
function getBuiltinCapabilitiesRoot() {
|
|
2515
|
-
const here =
|
|
2544
|
+
const here = path12.dirname(new URL(import.meta.url).pathname);
|
|
2516
2545
|
const candidates = [
|
|
2517
|
-
|
|
2546
|
+
path12.join(here, "capabilities"),
|
|
2518
2547
|
// dev: src/
|
|
2519
|
-
|
|
2548
|
+
path12.join(here, "..", "capabilities"),
|
|
2520
2549
|
// built: dist/bin → dist/capabilities
|
|
2521
|
-
|
|
2550
|
+
path12.join(here, "..", "src", "capabilities")
|
|
2522
2551
|
// fallback
|
|
2523
2552
|
];
|
|
2524
2553
|
for (const c of candidates) {
|
|
@@ -2662,17 +2691,17 @@ function isSafeName(name) {
|
|
|
2662
2691
|
return /^[a-z][a-z0-9-]*$/.test(name) && !name.includes("..");
|
|
2663
2692
|
}
|
|
2664
2693
|
function isCapabilityRoot(root) {
|
|
2665
|
-
const normalized =
|
|
2666
|
-
if (
|
|
2694
|
+
const normalized = path12.normalize(root);
|
|
2695
|
+
if (path12.basename(normalized) === "capabilities") return true;
|
|
2667
2696
|
const knownRoots = [getProjectCapabilitiesRoot(), getBuiltinCapabilitiesRoot()];
|
|
2668
|
-
return knownRoots.some((candidate) => candidate &&
|
|
2697
|
+
return knownRoots.some((candidate) => candidate && path12.normalize(candidate) === normalized);
|
|
2669
2698
|
}
|
|
2670
2699
|
function implementationRuntimePath(root, name) {
|
|
2671
|
-
const runtimePath =
|
|
2700
|
+
const runtimePath = path12.join(root, name, "runtime.json");
|
|
2672
2701
|
if (fs10.existsSync(runtimePath)) return runtimePath;
|
|
2673
|
-
const internalProfilePath =
|
|
2702
|
+
const internalProfilePath = path12.join(root, name, "profile.json");
|
|
2674
2703
|
if (fs10.existsSync(internalProfilePath)) return internalProfilePath;
|
|
2675
|
-
return
|
|
2704
|
+
return path12.join(root, name, CAPABILITY_PROFILE_FILE);
|
|
2676
2705
|
}
|
|
2677
2706
|
function isImplementationProfile(profilePath, requireImplementationProfile) {
|
|
2678
2707
|
if (!requireImplementationProfile) return true;
|
|
@@ -3839,7 +3868,7 @@ var init_capabilityMcp = __esm({
|
|
|
3839
3868
|
// src/repoWorkspace.ts
|
|
3840
3869
|
import { spawn as spawn2, spawnSync } from "child_process";
|
|
3841
3870
|
import * as fs11 from "fs";
|
|
3842
|
-
import * as
|
|
3871
|
+
import * as path13 from "path";
|
|
3843
3872
|
function buildCloneProcess(repo, token, baseEnv = process.env) {
|
|
3844
3873
|
const url = `https://github.com/${repo}.git`;
|
|
3845
3874
|
const env = { ...baseEnv };
|
|
@@ -3854,10 +3883,10 @@ function buildCloneProcess(repo, token, baseEnv = process.env) {
|
|
|
3854
3883
|
async function resolveAndClone(reposRoot, repo, repoToken, cloneRepo) {
|
|
3855
3884
|
const name = repo?.trim();
|
|
3856
3885
|
if (!name || !REPO_RE.test(name)) return null;
|
|
3857
|
-
const root =
|
|
3858
|
-
const dir =
|
|
3859
|
-
if (dir !== root && !dir.startsWith(root +
|
|
3860
|
-
if (fs11.existsSync(
|
|
3886
|
+
const root = path13.resolve(reposRoot);
|
|
3887
|
+
const dir = path13.resolve(root, name);
|
|
3888
|
+
if (dir !== root && !dir.startsWith(root + path13.sep)) return null;
|
|
3889
|
+
if (fs11.existsSync(path13.join(dir, ".git"))) return dir;
|
|
3861
3890
|
const inflight = repoClones.get(dir);
|
|
3862
3891
|
if (inflight) {
|
|
3863
3892
|
await inflight;
|
|
@@ -3889,9 +3918,9 @@ var init_repoWorkspace = __esm({
|
|
|
3889
3918
|
repoClones = /* @__PURE__ */ new Map();
|
|
3890
3919
|
GIT_CREDENTIAL_HELPER = `!f() { if [ "$1" = get ] && [ -n "$GITHUB_TOKEN" ]; then printf '%s\\n' username=x-access-token "password=$GITHUB_TOKEN"; fi; }; f`;
|
|
3891
3920
|
defaultCloneRepo = (repo, token, dir) => {
|
|
3892
|
-
fs11.mkdirSync(
|
|
3921
|
+
fs11.mkdirSync(path13.dirname(dir), { recursive: true });
|
|
3893
3922
|
const clone = buildCloneProcess(repo, token);
|
|
3894
|
-
return new Promise((
|
|
3923
|
+
return new Promise((resolve24, reject) => {
|
|
3895
3924
|
const child = spawn2("git", ["clone", "--depth=1", clone.url, dir], {
|
|
3896
3925
|
env: clone.env,
|
|
3897
3926
|
stdio: "inherit"
|
|
@@ -3911,7 +3940,7 @@ var init_repoWorkspace = __esm({
|
|
|
3911
3940
|
}
|
|
3912
3941
|
} catch {
|
|
3913
3942
|
}
|
|
3914
|
-
|
|
3943
|
+
resolve24();
|
|
3915
3944
|
});
|
|
3916
3945
|
child.on("error", reject);
|
|
3917
3946
|
});
|
|
@@ -3984,7 +4013,7 @@ var init_fetchRepoMcp = __esm({
|
|
|
3984
4013
|
|
|
3985
4014
|
// src/agent.ts
|
|
3986
4015
|
import * as fs12 from "fs";
|
|
3987
|
-
import * as
|
|
4016
|
+
import * as path14 from "path";
|
|
3988
4017
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
3989
4018
|
function classifySubtype(subtype) {
|
|
3990
4019
|
if (!subtype) return "generic_failed";
|
|
@@ -4054,7 +4083,7 @@ function buildAgentEnvironment(baseEnv, repoToken, requestEnvironment) {
|
|
|
4054
4083
|
async function runAgent(opts) {
|
|
4055
4084
|
const ndjsonDir = opts.ndjsonDir ?? agentRunDir(opts.cwd);
|
|
4056
4085
|
fs12.mkdirSync(ndjsonDir, { recursive: true });
|
|
4057
|
-
const ndjsonPath =
|
|
4086
|
+
const ndjsonPath = path14.join(ndjsonDir, "last-run.jsonl");
|
|
4058
4087
|
const env = buildAgentEnvironment(process.env, opts.repoToken, opts.environment);
|
|
4059
4088
|
if (opts.litellmUrl) {
|
|
4060
4089
|
env.ANTHROPIC_BASE_URL = opts.litellmUrl;
|
|
@@ -4062,6 +4091,11 @@ async function runAgent(opts) {
|
|
|
4062
4091
|
}
|
|
4063
4092
|
const startedAt = Date.now();
|
|
4064
4093
|
const turnTimeoutMs = resolveTurnTimeoutMs(opts);
|
|
4094
|
+
const completionGuard = typeof opts.deadlineAtMs === "number" ? createCompletionToolGuard(
|
|
4095
|
+
completionToolCutoffAt(startedAt, opts.deadlineAtMs),
|
|
4096
|
+
Date.now,
|
|
4097
|
+
opts.outputContract?.path
|
|
4098
|
+
) : null;
|
|
4065
4099
|
let outcome = "failed";
|
|
4066
4100
|
let outcomeKind = "generic_failed";
|
|
4067
4101
|
let errorMessage2;
|
|
@@ -4106,6 +4140,11 @@ async function runAgent(opts) {
|
|
|
4106
4140
|
env,
|
|
4107
4141
|
hooks: {
|
|
4108
4142
|
PreToolUse: [
|
|
4143
|
+
...completionGuard ? [
|
|
4144
|
+
{
|
|
4145
|
+
hooks: [completionGuard]
|
|
4146
|
+
}
|
|
4147
|
+
] : [],
|
|
4109
4148
|
{
|
|
4110
4149
|
matcher: "Agent",
|
|
4111
4150
|
hooks: [enforceSubagentModelInheritance]
|
|
@@ -4229,11 +4268,13 @@ async function runAgent(opts) {
|
|
|
4229
4268
|
} else if (typeof opts.maxThinkingTokens === "number" && opts.maxThinkingTokens > 0) {
|
|
4230
4269
|
queryOptions.maxThinkingTokens = opts.maxThinkingTokens;
|
|
4231
4270
|
}
|
|
4232
|
-
|
|
4271
|
+
const completionNotice = completionGuard ? "Work within the enforced run time. Tool access closes before the hard deadline to reserve time for a final response. When that happens, stop using tools and finish immediately." : null;
|
|
4272
|
+
const systemPromptAppend = [opts.systemPromptAppend, completionNotice].filter((value) => typeof value === "string" && value.length > 0).join("\n\n");
|
|
4273
|
+
if (systemPromptAppend.length > 0) {
|
|
4233
4274
|
const systemPrompt = {
|
|
4234
4275
|
type: "preset",
|
|
4235
4276
|
preset: "claude_code",
|
|
4236
|
-
append:
|
|
4277
|
+
append: systemPromptAppend
|
|
4237
4278
|
};
|
|
4238
4279
|
if (opts.cacheable) systemPrompt.excludeDynamicSections = true;
|
|
4239
4280
|
queryOptions.systemPrompt = systemPrompt;
|
|
@@ -4263,10 +4304,10 @@ async function runAgent(opts) {
|
|
|
4263
4304
|
let timer;
|
|
4264
4305
|
let next;
|
|
4265
4306
|
if (turnTimeoutMs > 0) {
|
|
4266
|
-
const timeoutPromise = new Promise((
|
|
4307
|
+
const timeoutPromise = new Promise((resolve24) => {
|
|
4267
4308
|
timer = setTimeout(() => {
|
|
4268
4309
|
timedOut = true;
|
|
4269
|
-
|
|
4310
|
+
resolve24({ done: true, value: void 0 });
|
|
4270
4311
|
}, turnTimeoutMs);
|
|
4271
4312
|
});
|
|
4272
4313
|
next = await Promise.race([nextPromise, timeoutPromise]);
|
|
@@ -4282,7 +4323,7 @@ async function runAgent(opts) {
|
|
|
4282
4323
|
try {
|
|
4283
4324
|
await Promise.race([
|
|
4284
4325
|
iterator.return(void 0).catch(() => void 0),
|
|
4285
|
-
new Promise((
|
|
4326
|
+
new Promise((resolve24) => setTimeout(resolve24, 1e4).unref())
|
|
4286
4327
|
]);
|
|
4287
4328
|
} catch {
|
|
4288
4329
|
}
|
|
@@ -4463,9 +4504,10 @@ var init_agent = __esm({
|
|
|
4463
4504
|
"src/agent.ts"() {
|
|
4464
4505
|
"use strict";
|
|
4465
4506
|
init_claudeBinary();
|
|
4507
|
+
init_completionGuard();
|
|
4466
4508
|
init_config();
|
|
4467
|
-
init_format();
|
|
4468
4509
|
init_fileEditGuards();
|
|
4510
|
+
init_format();
|
|
4469
4511
|
init_outputContractHooks();
|
|
4470
4512
|
init_runtimePaths();
|
|
4471
4513
|
init_subagents();
|
|
@@ -4488,7 +4530,7 @@ var init_agent = __esm({
|
|
|
4488
4530
|
|
|
4489
4531
|
// src/agents.ts
|
|
4490
4532
|
import * as fs13 from "fs";
|
|
4491
|
-
import * as
|
|
4533
|
+
import * as path15 from "path";
|
|
4492
4534
|
function stripFrontmatter(raw) {
|
|
4493
4535
|
const match = /^---\n[\s\S]*?\n---\n?([\s\S]*)$/.exec(raw);
|
|
4494
4536
|
return (match ? match[1] : raw).trim();
|
|
@@ -4509,7 +4551,7 @@ function loadAgentIdentity(cwd, slug, agentsDir = agentsRoot(cwd)) {
|
|
|
4509
4551
|
throw new Error(`loadAgentIdentity: agent '${trimmed}' declared but ${agentPath} does not exist`);
|
|
4510
4552
|
}
|
|
4511
4553
|
function resolveAgentFile2(cwd, slug, agentsDir = agentsRoot(cwd)) {
|
|
4512
|
-
const localPath =
|
|
4554
|
+
const localPath = path15.resolve(cwd, agentsDir, `${slug}.md`);
|
|
4513
4555
|
if (fs13.existsSync(localPath)) return localPath;
|
|
4514
4556
|
return localPath;
|
|
4515
4557
|
}
|
|
@@ -4543,7 +4585,7 @@ var init_agents = __esm({
|
|
|
4543
4585
|
|
|
4544
4586
|
// src/task-artifacts.ts
|
|
4545
4587
|
import fs14 from "fs";
|
|
4546
|
-
import
|
|
4588
|
+
import path16 from "path";
|
|
4547
4589
|
import posixPath from "path/posix";
|
|
4548
4590
|
function prepareTaskArtifactsDir(cwd, taskId) {
|
|
4549
4591
|
const safeId = String(taskId).replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
@@ -4579,14 +4621,14 @@ function initializeTaskArtifacts(artifacts, metadata = { taskType: "job" }) {
|
|
|
4579
4621
|
"handoff-notes.md": "Baseline handoff: the agent did not provide additional notes.\n"
|
|
4580
4622
|
};
|
|
4581
4623
|
for (const file of TASK_ARTIFACT_FILES) {
|
|
4582
|
-
const full =
|
|
4624
|
+
const full = path16.join(artifacts.absDir, file);
|
|
4583
4625
|
if (!fs14.existsSync(full)) fs14.writeFileSync(full, defaults[file], "utf8");
|
|
4584
4626
|
}
|
|
4585
4627
|
}
|
|
4586
4628
|
function verifyTaskArtifacts(absDir) {
|
|
4587
4629
|
const missing = [];
|
|
4588
4630
|
for (const name of TASK_ARTIFACT_FILES) {
|
|
4589
|
-
const full =
|
|
4631
|
+
const full = path16.join(absDir, name);
|
|
4590
4632
|
try {
|
|
4591
4633
|
const stat = fs14.statSync(full);
|
|
4592
4634
|
if (!stat.isFile() || stat.size === 0) missing.push(name);
|
|
@@ -4604,7 +4646,7 @@ async function persistTaskArtifactsToState(config, _cwd, artifacts) {
|
|
|
4604
4646
|
if (hasStateBackendConfig() && tenantId2) {
|
|
4605
4647
|
const backend = createStateBackendFromEnv();
|
|
4606
4648
|
for (const file of TASK_ARTIFACT_FILES) {
|
|
4607
|
-
const full =
|
|
4649
|
+
const full = path16.join(artifacts.absDir, file);
|
|
4608
4650
|
if (!fs14.existsSync(full)) continue;
|
|
4609
4651
|
const stat = fs14.statSync(full);
|
|
4610
4652
|
if (!stat.isFile() || stat.size === 0) continue;
|
|
@@ -4917,15 +4959,15 @@ function validateWorkflow(value, options = {}) {
|
|
|
4917
4959
|
}
|
|
4918
4960
|
return issues;
|
|
4919
4961
|
}
|
|
4920
|
-
function validateInputBindings(value,
|
|
4962
|
+
function validateInputBindings(value, path59, issues, declaredInputs) {
|
|
4921
4963
|
if (value === void 0) return;
|
|
4922
4964
|
const bindings = asRecord(value);
|
|
4923
4965
|
if (!bindings || Object.keys(bindings).length === 0) {
|
|
4924
|
-
issue(issues, "invalid_inputs",
|
|
4966
|
+
issue(issues, "invalid_inputs", path59, "workflow step inputs must contain at least one named mapping");
|
|
4925
4967
|
return;
|
|
4926
4968
|
}
|
|
4927
4969
|
for (const [name, value2] of Object.entries(bindings)) {
|
|
4928
|
-
const bindingPath = `${
|
|
4970
|
+
const bindingPath = `${path59}.${name}`;
|
|
4929
4971
|
if (!/^[A-Za-z_][A-Za-z0-9_-]*$/.test(name)) {
|
|
4930
4972
|
issue(issues, "invalid_input_name", bindingPath, `workflow input name ${name} is invalid`);
|
|
4931
4973
|
}
|
|
@@ -4944,7 +4986,7 @@ function validateInputBindings(value, path58, issues, declaredInputs) {
|
|
|
4944
4986
|
}
|
|
4945
4987
|
}
|
|
4946
4988
|
}
|
|
4947
|
-
function validateInputBindingSources(value,
|
|
4989
|
+
function validateInputBindingSources(value, path59, issues, capabilitiesByStep, capabilityOutputs) {
|
|
4948
4990
|
const bindings = asRecord(value);
|
|
4949
4991
|
if (!bindings) return;
|
|
4950
4992
|
for (const [name, rawBinding] of Object.entries(bindings)) {
|
|
@@ -4957,7 +4999,7 @@ function validateInputBindingSources(value, path58, issues, capabilitiesByStep,
|
|
|
4957
4999
|
issue(
|
|
4958
5000
|
issues,
|
|
4959
5001
|
"missing_input_step",
|
|
4960
|
-
`${
|
|
5002
|
+
`${path59}.${name}.from`,
|
|
4961
5003
|
`workflow input mapping references missing step ${sourceStep ?? "<none>"}`
|
|
4962
5004
|
);
|
|
4963
5005
|
continue;
|
|
@@ -4968,7 +5010,7 @@ function validateInputBindingSources(value, path58, issues, capabilitiesByStep,
|
|
|
4968
5010
|
issue(
|
|
4969
5011
|
issues,
|
|
4970
5012
|
"undeclared_step_output",
|
|
4971
|
-
`${
|
|
5013
|
+
`${path59}.${name}.from`,
|
|
4972
5014
|
`workflow input mapping reads ${outputPath}, but step ${sourceStep} does not declare it`
|
|
4973
5015
|
);
|
|
4974
5016
|
}
|
|
@@ -4977,11 +5019,11 @@ function validateInputBindingSources(value, path58, issues, capabilitiesByStep,
|
|
|
4977
5019
|
function formatWorkflowValidationIssues(issues) {
|
|
4978
5020
|
return issues.map((entry) => `${entry.path}: ${entry.message}`);
|
|
4979
5021
|
}
|
|
4980
|
-
function validateDataMatch(value,
|
|
5022
|
+
function validateDataMatch(value, path59, issues, capabilityOutputs) {
|
|
4981
5023
|
if (value === void 0) return;
|
|
4982
5024
|
const match = asRecord(value);
|
|
4983
5025
|
if (!match || Object.keys(match).length === 0) {
|
|
4984
|
-
issue(issues, "invalid_condition",
|
|
5026
|
+
issue(issues, "invalid_condition", path59, "workflow condition must contain at least one match");
|
|
4985
5027
|
return;
|
|
4986
5028
|
}
|
|
4987
5029
|
for (const [field, expected] of Object.entries(match)) {
|
|
@@ -4989,7 +5031,7 @@ function validateDataMatch(value, path58, issues, capabilityOutputs) {
|
|
|
4989
5031
|
issue(
|
|
4990
5032
|
issues,
|
|
4991
5033
|
"invalid_data_path",
|
|
4992
|
-
`${
|
|
5034
|
+
`${path59}.${field}`,
|
|
4993
5035
|
`workflow condition must read from facts, evidence, artifacts, result, workflow, or lastOutcome`
|
|
4994
5036
|
);
|
|
4995
5037
|
}
|
|
@@ -4997,12 +5039,12 @@ function validateDataMatch(value, path58, issues, capabilityOutputs) {
|
|
|
4997
5039
|
issue(
|
|
4998
5040
|
issues,
|
|
4999
5041
|
"undeclared_result_path",
|
|
5000
|
-
`${
|
|
5042
|
+
`${path59}.${field}`,
|
|
5001
5043
|
`workflow condition reads ${field}, but the source capability does not declare it`
|
|
5002
5044
|
);
|
|
5003
5045
|
}
|
|
5004
5046
|
if (!isComparable(expected)) {
|
|
5005
|
-
issue(issues, "invalid_condition_value", `${
|
|
5047
|
+
issue(issues, "invalid_condition_value", `${path59}.${field}`, "workflow condition value must be a JSON scalar");
|
|
5006
5048
|
}
|
|
5007
5049
|
}
|
|
5008
5050
|
}
|
|
@@ -5026,8 +5068,8 @@ function isJsonValue(value) {
|
|
|
5026
5068
|
if (!value || typeof value !== "object") return false;
|
|
5027
5069
|
return Object.values(value).every(isJsonValue);
|
|
5028
5070
|
}
|
|
5029
|
-
function issue(issues, code,
|
|
5030
|
-
issues.push({ code, path:
|
|
5071
|
+
function issue(issues, code, path59, message) {
|
|
5072
|
+
issues.push({ code, path: path59, message });
|
|
5031
5073
|
}
|
|
5032
5074
|
var SAFE_NAME, SAFE_STEP_ID, SAFE_DATA_PATH, SAFE_INPUT_SOURCE, SUPPORTED_STEP_FIELDS, SUPPORTED_TRANSITION_FIELDS;
|
|
5033
5075
|
var init_workflowValidation = __esm({
|
|
@@ -5061,7 +5103,7 @@ var init_workflowValidation = __esm({
|
|
|
5061
5103
|
|
|
5062
5104
|
// src/workflowDefinitions.ts
|
|
5063
5105
|
import * as fs20 from "fs";
|
|
5064
|
-
import * as
|
|
5106
|
+
import * as path22 from "path";
|
|
5065
5107
|
function isWorkflowDefinitionId(value) {
|
|
5066
5108
|
return WORKFLOW_ID_PATTERN.test(value);
|
|
5067
5109
|
}
|
|
@@ -5106,8 +5148,8 @@ function readWorkflowDefinition(_config, cwd, id) {
|
|
|
5106
5148
|
const root = cwd ?? process.cwd();
|
|
5107
5149
|
const relativePath = workflowDefinitionPath(id);
|
|
5108
5150
|
const candidates = [
|
|
5109
|
-
|
|
5110
|
-
|
|
5151
|
+
path22.join(root, ".kody-engine", "runtime", relativePath),
|
|
5152
|
+
path22.join(definitionsRoot(root), relativePath)
|
|
5111
5153
|
];
|
|
5112
5154
|
for (const filePath of candidates) {
|
|
5113
5155
|
if (!fs20.existsSync(filePath)) continue;
|
|
@@ -5119,7 +5161,7 @@ function readWorkflowDefinition(_config, cwd, id) {
|
|
|
5119
5161
|
function workflowDefinitionToCapabilityFolder(id, workflow, source = workflowDefinitionPath(id)) {
|
|
5120
5162
|
return {
|
|
5121
5163
|
slug: id,
|
|
5122
|
-
dir:
|
|
5164
|
+
dir: path22.dirname(source),
|
|
5123
5165
|
profilePath: source,
|
|
5124
5166
|
bodyPath: source,
|
|
5125
5167
|
title: workflow.name,
|
|
@@ -5720,7 +5762,7 @@ var init_lifecycles = __esm({
|
|
|
5720
5762
|
// src/profile.ts
|
|
5721
5763
|
import { createHash as createHash3 } from "crypto";
|
|
5722
5764
|
import * as fs24 from "fs";
|
|
5723
|
-
import * as
|
|
5765
|
+
import * as path24 from "path";
|
|
5724
5766
|
function loadProfile(profilePath) {
|
|
5725
5767
|
if (!fs24.existsSync(profilePath)) {
|
|
5726
5768
|
throw new ProfileError(profilePath, "file not found");
|
|
@@ -5739,7 +5781,7 @@ function loadProfile(profilePath) {
|
|
|
5739
5781
|
const unknownKeys = Object.keys(r).filter((k) => !KNOWN_PROFILE_KEYS.has(k));
|
|
5740
5782
|
if (unknownKeys.length > 0) {
|
|
5741
5783
|
process.stderr.write(
|
|
5742
|
-
`[kody profile] ${
|
|
5784
|
+
`[kody profile] ${path24.basename(path24.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
|
|
5743
5785
|
`
|
|
5744
5786
|
);
|
|
5745
5787
|
}
|
|
@@ -5749,7 +5791,7 @@ function loadProfile(profilePath) {
|
|
|
5749
5791
|
if (!refPath) {
|
|
5750
5792
|
throw new ProfileError(profilePath, `capability references unknown implementation '${execRef}'`);
|
|
5751
5793
|
}
|
|
5752
|
-
if (
|
|
5794
|
+
if (path24.resolve(refPath) === path24.resolve(profilePath)) {
|
|
5753
5795
|
} else {
|
|
5754
5796
|
const base = loadProfile(refPath);
|
|
5755
5797
|
return {
|
|
@@ -5847,8 +5889,8 @@ function loadProfile(profilePath) {
|
|
|
5847
5889
|
// Phase 5 in-process handoff opt-in. Default false; containers
|
|
5848
5890
|
// flip to true after end-to-end verification.
|
|
5849
5891
|
preloadContext: r.preloadContext === true,
|
|
5850
|
-
dir:
|
|
5851
|
-
promptTemplates: readPromptTemplates(
|
|
5892
|
+
dir: path24.dirname(profilePath),
|
|
5893
|
+
promptTemplates: readPromptTemplates(path24.dirname(profilePath))
|
|
5852
5894
|
};
|
|
5853
5895
|
if (lifecycle) {
|
|
5854
5896
|
applyLifecycle(profile, profilePath);
|
|
@@ -5883,19 +5925,19 @@ function loadProfile(profilePath) {
|
|
|
5883
5925
|
return profile;
|
|
5884
5926
|
}
|
|
5885
5927
|
function compileRuntimeDocument(runtimePath, document) {
|
|
5886
|
-
if (
|
|
5928
|
+
if (path24.basename(runtimePath) !== "runtime.json") return document;
|
|
5887
5929
|
if (document.adapter !== "kody-engine-profile") {
|
|
5888
5930
|
throw new ProfileError(runtimePath, "unsupported runtime adapter document");
|
|
5889
5931
|
}
|
|
5890
|
-
const implementationDir =
|
|
5891
|
-
const implementation = readJsonObject(
|
|
5892
|
-
const definitionsRoot2 =
|
|
5932
|
+
const implementationDir = path24.dirname(runtimePath);
|
|
5933
|
+
const implementation = readJsonObject(path24.join(implementationDir, "definition.json"), "Implementation definition");
|
|
5934
|
+
const definitionsRoot2 = path24.dirname(path24.dirname(implementationDir));
|
|
5893
5935
|
const capabilityId = implementation.capabilityRef && typeof implementation.capabilityRef === "object" && !Array.isArray(implementation.capabilityRef) ? implementation.capabilityRef.id : void 0;
|
|
5894
5936
|
if (typeof capabilityId !== "string" || !capabilityId) {
|
|
5895
5937
|
throw new ProfileError(runtimePath, "Implementation capabilityRef is invalid");
|
|
5896
5938
|
}
|
|
5897
5939
|
const capability = readJsonObject(
|
|
5898
|
-
|
|
5940
|
+
path24.join(definitionsRoot2, "capabilities", capabilityId, "definition.json"),
|
|
5899
5941
|
"Capability definition"
|
|
5900
5942
|
);
|
|
5901
5943
|
const {
|
|
@@ -5956,13 +5998,13 @@ function readPromptTemplates(dir) {
|
|
|
5956
5998
|
} catch {
|
|
5957
5999
|
}
|
|
5958
6000
|
};
|
|
5959
|
-
read(
|
|
5960
|
-
read(
|
|
5961
|
-
read(
|
|
6001
|
+
read(path24.join(dir, "prompt.md"));
|
|
6002
|
+
read(path24.join(dir, "capability.md"));
|
|
6003
|
+
read(path24.join(dir, "capability.md"));
|
|
5962
6004
|
try {
|
|
5963
|
-
const promptsDir =
|
|
6005
|
+
const promptsDir = path24.join(dir, "prompts");
|
|
5964
6006
|
for (const ent of fs24.readdirSync(promptsDir)) {
|
|
5965
|
-
if (ent.endsWith(".md")) read(
|
|
6007
|
+
if (ent.endsWith(".md")) read(path24.join(promptsDir, ent));
|
|
5966
6008
|
}
|
|
5967
6009
|
} catch {
|
|
5968
6010
|
}
|
|
@@ -6740,11 +6782,11 @@ var init_state = __esm({
|
|
|
6740
6782
|
|
|
6741
6783
|
// src/prompt.ts
|
|
6742
6784
|
import * as fs25 from "fs";
|
|
6743
|
-
import * as
|
|
6785
|
+
import * as path25 from "path";
|
|
6744
6786
|
function loadProjectConventions(projectDir) {
|
|
6745
6787
|
const out = [];
|
|
6746
6788
|
for (const rel of CONVENTION_FILES) {
|
|
6747
|
-
const abs =
|
|
6789
|
+
const abs = path25.join(projectDir, rel);
|
|
6748
6790
|
if (!fs25.existsSync(abs)) continue;
|
|
6749
6791
|
let content;
|
|
6750
6792
|
try {
|
|
@@ -6984,7 +7026,7 @@ __export(loadMemoryContext_exports, {
|
|
|
6984
7026
|
loadMemoryContext: () => loadMemoryContext
|
|
6985
7027
|
});
|
|
6986
7028
|
import * as fs26 from "fs";
|
|
6987
|
-
import * as
|
|
7029
|
+
import * as path26 from "path";
|
|
6988
7030
|
function formatBlockFromBackend(docs) {
|
|
6989
7031
|
const pages = docs.flatMap((record2) => {
|
|
6990
7032
|
if (!record2.doc || typeof record2.doc !== "object") return [];
|
|
@@ -7018,10 +7060,10 @@ function collectPages(memoryAbs) {
|
|
|
7018
7060
|
return;
|
|
7019
7061
|
}
|
|
7020
7062
|
const fm = raw.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
7021
|
-
const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ??
|
|
7063
|
+
const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path26.basename(file, ".md");
|
|
7022
7064
|
const updated = fm?.[1]?.match(/^updated:\s*([0-9T:.+\-Z]+)/m)?.[1]?.trim() ?? "";
|
|
7023
7065
|
out.push({
|
|
7024
|
-
relPath:
|
|
7066
|
+
relPath: path26.relative(memoryAbs, file),
|
|
7025
7067
|
title,
|
|
7026
7068
|
updated,
|
|
7027
7069
|
content: raw.length > PER_PAGE_MAX_BYTES ? raw.slice(0, PER_PAGE_MAX_BYTES) + TRUNCATED_SUFFIX2 : raw,
|
|
@@ -7095,7 +7137,7 @@ function walkMd(root, visit) {
|
|
|
7095
7137
|
}
|
|
7096
7138
|
for (const name of names) {
|
|
7097
7139
|
if (name.startsWith(".")) continue;
|
|
7098
|
-
const full =
|
|
7140
|
+
const full = path26.join(dir, name);
|
|
7099
7141
|
let stat;
|
|
7100
7142
|
try {
|
|
7101
7143
|
stat = fs26.statSync(full);
|
|
@@ -7133,7 +7175,7 @@ var init_loadMemoryContext = __esm({
|
|
|
7133
7175
|
}
|
|
7134
7176
|
return;
|
|
7135
7177
|
}
|
|
7136
|
-
const memoryAbs =
|
|
7178
|
+
const memoryAbs = path26.join(ctx.cwd, MEMORY_DIR_RELATIVE);
|
|
7137
7179
|
if (!fs26.existsSync(memoryAbs)) {
|
|
7138
7180
|
ctx.data.memoryContext = "";
|
|
7139
7181
|
return;
|
|
@@ -7649,7 +7691,7 @@ import { execFileSync as execFileSync4, spawn as spawn4 } from "child_process";
|
|
|
7649
7691
|
import * as fs28 from "fs";
|
|
7650
7692
|
import * as net from "net";
|
|
7651
7693
|
import * as os4 from "os";
|
|
7652
|
-
import * as
|
|
7694
|
+
import * as path27 from "path";
|
|
7653
7695
|
async function checkLitellmHealth(url) {
|
|
7654
7696
|
try {
|
|
7655
7697
|
const response = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3e3) });
|
|
@@ -7762,10 +7804,10 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
|
|
|
7762
7804
|
const spawnProxy = () => {
|
|
7763
7805
|
const portMatch = activeUrl.match(/:(\d+)/);
|
|
7764
7806
|
const port = portMatch ? portMatch[1] : "4000";
|
|
7765
|
-
const configPath =
|
|
7807
|
+
const configPath = path27.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.yaml`);
|
|
7766
7808
|
fs28.writeFileSync(configPath, generateLitellmConfigYaml(model));
|
|
7767
7809
|
const args = ["--config", configPath, "--port", port];
|
|
7768
|
-
const nextLogPath =
|
|
7810
|
+
const nextLogPath = path27.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.log`);
|
|
7769
7811
|
const outFd = fs28.openSync(nextLogPath, "w");
|
|
7770
7812
|
child = spawn4(cmd, args, { stdio: ["ignore", outFd, outFd], detached: true, env: childEnv });
|
|
7771
7813
|
fs28.closeSync(outFd);
|
|
@@ -7855,17 +7897,17 @@ async function nextAvailableLitellmUrl(url) {
|
|
|
7855
7897
|
throw new Error(`no free LiteLLM port found after ${startPort}`);
|
|
7856
7898
|
}
|
|
7857
7899
|
function canListen(port, host) {
|
|
7858
|
-
return new Promise((
|
|
7900
|
+
return new Promise((resolve24) => {
|
|
7859
7901
|
const server = net.createServer();
|
|
7860
|
-
server.once("error", () =>
|
|
7902
|
+
server.once("error", () => resolve24(false));
|
|
7861
7903
|
server.once("listening", () => {
|
|
7862
|
-
server.close(() =>
|
|
7904
|
+
server.close(() => resolve24(true));
|
|
7863
7905
|
});
|
|
7864
7906
|
server.listen(port, host);
|
|
7865
7907
|
});
|
|
7866
7908
|
}
|
|
7867
7909
|
function readDotenvApiKeys(projectDir) {
|
|
7868
|
-
const dotenvPath =
|
|
7910
|
+
const dotenvPath = path27.join(projectDir, ".env");
|
|
7869
7911
|
if (!fs28.existsSync(dotenvPath)) return {};
|
|
7870
7912
|
const result = {};
|
|
7871
7913
|
for (const rawLine of fs28.readFileSync(dotenvPath, "utf-8").split("\n")) {
|
|
@@ -8528,7 +8570,7 @@ var init_pushWithRetry = __esm({
|
|
|
8528
8570
|
// src/commit.ts
|
|
8529
8571
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
8530
8572
|
import * as fs29 from "fs";
|
|
8531
|
-
import * as
|
|
8573
|
+
import * as path28 from "path";
|
|
8532
8574
|
function isGitHubYamlPath(filePath) {
|
|
8533
8575
|
const normalized = filePath.replace(/^\.\/+/, "");
|
|
8534
8576
|
return normalized.startsWith(".github/") && /\.ya?ml$/i.test(normalized);
|
|
@@ -8570,18 +8612,18 @@ function ensureGitIdentity(cwd) {
|
|
|
8570
8612
|
}
|
|
8571
8613
|
function abortUnfinishedGitOps(cwd) {
|
|
8572
8614
|
const aborted = [];
|
|
8573
|
-
const gitDir =
|
|
8615
|
+
const gitDir = path28.join(cwd ?? process.cwd(), ".git");
|
|
8574
8616
|
if (!fs29.existsSync(gitDir)) return aborted;
|
|
8575
|
-
if (fs29.existsSync(
|
|
8617
|
+
if (fs29.existsSync(path28.join(gitDir, "MERGE_HEAD"))) {
|
|
8576
8618
|
if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
|
|
8577
8619
|
}
|
|
8578
|
-
if (fs29.existsSync(
|
|
8620
|
+
if (fs29.existsSync(path28.join(gitDir, "CHERRY_PICK_HEAD"))) {
|
|
8579
8621
|
if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
|
|
8580
8622
|
}
|
|
8581
|
-
if (fs29.existsSync(
|
|
8623
|
+
if (fs29.existsSync(path28.join(gitDir, "REVERT_HEAD"))) {
|
|
8582
8624
|
if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
|
|
8583
8625
|
}
|
|
8584
|
-
if (fs29.existsSync(
|
|
8626
|
+
if (fs29.existsSync(path28.join(gitDir, "rebase-merge")) || fs29.existsSync(path28.join(gitDir, "rebase-apply"))) {
|
|
8585
8627
|
if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
|
|
8586
8628
|
}
|
|
8587
8629
|
try {
|
|
@@ -8638,7 +8680,7 @@ function normalizeCommitMessage(raw) {
|
|
|
8638
8680
|
function commitAndPush(branch, agentMessage, cwd) {
|
|
8639
8681
|
const allChanged = listChangedFiles(cwd);
|
|
8640
8682
|
const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
|
|
8641
|
-
const mergeHeadExists = fs29.existsSync(
|
|
8683
|
+
const mergeHeadExists = fs29.existsSync(path28.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
|
|
8642
8684
|
if (allowedFiles.length === 0 && !mergeHeadExists) {
|
|
8643
8685
|
return { committed: false, pushed: false, sha: "", message: "" };
|
|
8644
8686
|
}
|
|
@@ -9282,9 +9324,9 @@ import * as fs30 from "fs";
|
|
|
9282
9324
|
function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
|
|
9283
9325
|
const logs = goalRunLogs(data);
|
|
9284
9326
|
const existing = logs[goalId];
|
|
9285
|
-
const
|
|
9327
|
+
const path59 = existing?.path ?? goalRunLogPath(goalId, data);
|
|
9286
9328
|
logs[goalId] = {
|
|
9287
|
-
path:
|
|
9329
|
+
path: path59,
|
|
9288
9330
|
events: [...existing?.events ?? [], buildGoalRunLogEvent(data, goalId, event, at)]
|
|
9289
9331
|
};
|
|
9290
9332
|
}
|
|
@@ -9732,7 +9774,7 @@ var init_stateStore = __esm({
|
|
|
9732
9774
|
|
|
9733
9775
|
// src/goal/targetLoopResolution.ts
|
|
9734
9776
|
import * as fs31 from "fs";
|
|
9735
|
-
import * as
|
|
9777
|
+
import * as path29 from "path";
|
|
9736
9778
|
async function resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal) {
|
|
9737
9779
|
const targetId = loopGoal.loopTarget?.id.trim() ?? "";
|
|
9738
9780
|
assertSafeGoalId(targetId, "loop target");
|
|
@@ -9810,7 +9852,7 @@ function goalInstanceTime(state) {
|
|
|
9810
9852
|
return Number.isNaN(parsed) ? 0 : parsed;
|
|
9811
9853
|
}
|
|
9812
9854
|
function loadGoalTemplate(cwd, targetId) {
|
|
9813
|
-
return readJsonObject2(
|
|
9855
|
+
return readJsonObject2(path29.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
|
|
9814
9856
|
}
|
|
9815
9857
|
function readJsonObject2(filePath) {
|
|
9816
9858
|
if (!fs31.existsSync(filePath)) return null;
|
|
@@ -10161,15 +10203,15 @@ var init_backendStateBackend = __esm({
|
|
|
10161
10203
|
this.jobsDir = opts.jobsDir.replace(/\/+$/, "");
|
|
10162
10204
|
}
|
|
10163
10205
|
async load(slug) {
|
|
10164
|
-
const
|
|
10206
|
+
const path59 = stateFilePath(this.jobsDir, slug);
|
|
10165
10207
|
const loaded = await createStateBackendFromEnv().get(this.tenantId, `capabilities/${slug}`, "job-state");
|
|
10166
10208
|
if (!loaded) {
|
|
10167
|
-
return { path:
|
|
10209
|
+
return { path: path59, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
10168
10210
|
}
|
|
10169
10211
|
if (!isStateEnvelope(loaded.doc)) {
|
|
10170
10212
|
throw new Error(`BackendStateBackend: capabilities/${slug} is not a StateEnvelope`);
|
|
10171
10213
|
}
|
|
10172
|
-
return { path:
|
|
10214
|
+
return { path: path59, handle: loaded.updatedAt, state: loaded.doc, created: false };
|
|
10173
10215
|
}
|
|
10174
10216
|
async save(loaded, next) {
|
|
10175
10217
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) return false;
|
|
@@ -10190,7 +10232,7 @@ var init_backendStateBackend = __esm({
|
|
|
10190
10232
|
|
|
10191
10233
|
// src/scripts/jobState/localFileBackend.ts
|
|
10192
10234
|
import * as fs32 from "fs";
|
|
10193
|
-
import * as
|
|
10235
|
+
import * as path30 from "path";
|
|
10194
10236
|
function sanitizeKey(s) {
|
|
10195
10237
|
return s.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
10196
10238
|
}
|
|
@@ -10246,7 +10288,7 @@ var init_localFileBackend = __esm({
|
|
|
10246
10288
|
if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
|
|
10247
10289
|
this.cwd = opts.cwd;
|
|
10248
10290
|
this.jobsDir = opts.jobsDir;
|
|
10249
|
-
this.absDir =
|
|
10291
|
+
this.absDir = path30.resolve(opts.cwd, opts.jobsDir);
|
|
10250
10292
|
this.owner = opts.owner;
|
|
10251
10293
|
this.repo = opts.repo;
|
|
10252
10294
|
this.cache = opts.cache ?? defaultCacheAdapter();
|
|
@@ -10306,7 +10348,7 @@ var init_localFileBackend = __esm({
|
|
|
10306
10348
|
}
|
|
10307
10349
|
load(slug) {
|
|
10308
10350
|
const relPath = stateFilePath(this.jobsDir, slug);
|
|
10309
|
-
const absPath =
|
|
10351
|
+
const absPath = path30.resolve(this.cwd, relPath);
|
|
10310
10352
|
if (!fs32.existsSync(absPath)) {
|
|
10311
10353
|
return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
10312
10354
|
}
|
|
@@ -10327,8 +10369,8 @@ var init_localFileBackend = __esm({
|
|
|
10327
10369
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) {
|
|
10328
10370
|
return false;
|
|
10329
10371
|
}
|
|
10330
|
-
const absPath =
|
|
10331
|
-
fs32.mkdirSync(
|
|
10372
|
+
const absPath = path30.resolve(this.cwd, loaded.path);
|
|
10373
|
+
fs32.mkdirSync(path30.dirname(absPath), { recursive: true });
|
|
10332
10374
|
const body = `${JSON.stringify(next, null, 2)}
|
|
10333
10375
|
`;
|
|
10334
10376
|
const tmpPath = `${absPath}.${process.pid}.tmp`;
|
|
@@ -10365,7 +10407,7 @@ var init_jobState = __esm({
|
|
|
10365
10407
|
});
|
|
10366
10408
|
|
|
10367
10409
|
// src/scripts/goalCapabilityScheduling.ts
|
|
10368
|
-
import * as
|
|
10410
|
+
import * as path31 from "path";
|
|
10369
10411
|
function isCapabilityCadenceGoal(goal, extra) {
|
|
10370
10412
|
return extra.scheduleMode === "agentLoop" || extra.scheduler === "agentLoop" || goal.type === "standing" && goal.capabilities.length > 0;
|
|
10371
10413
|
}
|
|
@@ -10421,7 +10463,7 @@ function planTargetLoopSchedule(opts) {
|
|
|
10421
10463
|
}
|
|
10422
10464
|
async function planGoalCapabilitySchedule(opts) {
|
|
10423
10465
|
const jobsDir = opts.jobsDir ?? capabilitiesRoot(opts.cwd);
|
|
10424
|
-
const jobsRoot =
|
|
10466
|
+
const jobsRoot = path31.resolve(opts.cwd, jobsDir);
|
|
10425
10467
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
10426
10468
|
const at = now.toISOString();
|
|
10427
10469
|
const backend = resolveBackend({ config: opts.config, cwd: opts.cwd, jobsDir });
|
|
@@ -12238,7 +12280,7 @@ var init_classifyByLabel = __esm({
|
|
|
12238
12280
|
// src/scripts/commitAndPush.ts
|
|
12239
12281
|
import { createHash as createHash5 } from "crypto";
|
|
12240
12282
|
import * as fs33 from "fs";
|
|
12241
|
-
import * as
|
|
12283
|
+
import * as path32 from "path";
|
|
12242
12284
|
function sentinelPathForStage(cwd, profileName, workflowExecutionKey) {
|
|
12243
12285
|
const runId = resolveRunId();
|
|
12244
12286
|
const executionSuffix = typeof workflowExecutionKey === "string" && workflowExecutionKey.length > 0 ? `-${createHash5("sha256").update(workflowExecutionKey).digest("hex").slice(0, 16)}` : "";
|
|
@@ -12322,7 +12364,7 @@ var init_commitAndPush = __esm({
|
|
|
12322
12364
|
const result = ctx.data.commitResult;
|
|
12323
12365
|
if (sentinel && result?.committed) {
|
|
12324
12366
|
try {
|
|
12325
|
-
fs33.mkdirSync(
|
|
12367
|
+
fs33.mkdirSync(path32.dirname(sentinel), { recursive: true });
|
|
12326
12368
|
fs33.writeFileSync(
|
|
12327
12369
|
sentinel,
|
|
12328
12370
|
JSON.stringify(
|
|
@@ -12418,7 +12460,7 @@ var init_commitGoalState = __esm({
|
|
|
12418
12460
|
|
|
12419
12461
|
// src/scripts/composePrompt.ts
|
|
12420
12462
|
import * as fs34 from "fs";
|
|
12421
|
-
import * as
|
|
12463
|
+
import * as path33 from "path";
|
|
12422
12464
|
function fenceUntrusted(value) {
|
|
12423
12465
|
if (value.trim().length === 0) return value;
|
|
12424
12466
|
const safe = value.replace(/-{3,}\s*END UNTRUSTED INPUT\s*-{3,}/gi, "[END UNTRUSTED INPUT]");
|
|
@@ -12542,10 +12584,10 @@ var init_composePrompt = __esm({
|
|
|
12542
12584
|
const explicit = ctx.data.promptTemplate;
|
|
12543
12585
|
const mode = ctx.args.mode;
|
|
12544
12586
|
const candidates = [
|
|
12545
|
-
explicit ?
|
|
12546
|
-
mode ?
|
|
12547
|
-
|
|
12548
|
-
|
|
12587
|
+
explicit ? path33.join(profile.dir, explicit) : null,
|
|
12588
|
+
mode ? path33.join(profile.dir, "prompts", `${mode}.md`) : null,
|
|
12589
|
+
path33.join(profile.dir, "prompt.md"),
|
|
12590
|
+
path33.join(profile.dir, "capability.md")
|
|
12549
12591
|
].filter(Boolean);
|
|
12550
12592
|
let templatePath = "";
|
|
12551
12593
|
let template = "";
|
|
@@ -13305,14 +13347,14 @@ var init_deriveQaScopeFromIssue = __esm({
|
|
|
13305
13347
|
import { execFileSync as execFileSync9 } from "child_process";
|
|
13306
13348
|
import * as fs35 from "fs";
|
|
13307
13349
|
import * as os5 from "os";
|
|
13308
|
-
import * as
|
|
13350
|
+
import * as path34 from "path";
|
|
13309
13351
|
var diagMcp;
|
|
13310
13352
|
var init_diagMcp = __esm({
|
|
13311
13353
|
"src/scripts/diagMcp.ts"() {
|
|
13312
13354
|
"use strict";
|
|
13313
13355
|
diagMcp = async (_ctx) => {
|
|
13314
13356
|
const home = os5.homedir();
|
|
13315
|
-
const cacheDir =
|
|
13357
|
+
const cacheDir = path34.join(home, ".cache", "ms-playwright");
|
|
13316
13358
|
let entries = [];
|
|
13317
13359
|
try {
|
|
13318
13360
|
entries = fs35.readdirSync(cacheDir);
|
|
@@ -13344,12 +13386,12 @@ var init_diagMcp = __esm({
|
|
|
13344
13386
|
|
|
13345
13387
|
// src/scripts/frameworkDetectors.ts
|
|
13346
13388
|
import * as fs36 from "fs";
|
|
13347
|
-
import * as
|
|
13389
|
+
import * as path35 from "path";
|
|
13348
13390
|
function detectFrameworks(cwd) {
|
|
13349
13391
|
const out = [];
|
|
13350
13392
|
let deps = {};
|
|
13351
13393
|
try {
|
|
13352
|
-
const pkg = JSON.parse(fs36.readFileSync(
|
|
13394
|
+
const pkg = JSON.parse(fs36.readFileSync(path35.join(cwd, "package.json"), "utf-8"));
|
|
13353
13395
|
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13354
13396
|
} catch {
|
|
13355
13397
|
return out;
|
|
@@ -13386,14 +13428,14 @@ function detectFrameworks(cwd) {
|
|
|
13386
13428
|
}
|
|
13387
13429
|
function findFile(cwd, candidates) {
|
|
13388
13430
|
for (const c of candidates) {
|
|
13389
|
-
if (fs36.existsSync(
|
|
13431
|
+
if (fs36.existsSync(path35.join(cwd, c))) return c;
|
|
13390
13432
|
}
|
|
13391
13433
|
return null;
|
|
13392
13434
|
}
|
|
13393
13435
|
function discoverPayloadCollections(cwd) {
|
|
13394
13436
|
const out = [];
|
|
13395
13437
|
for (const dir of COLLECTION_DIRS) {
|
|
13396
|
-
const full =
|
|
13438
|
+
const full = path35.join(cwd, dir);
|
|
13397
13439
|
if (!fs36.existsSync(full)) continue;
|
|
13398
13440
|
let files;
|
|
13399
13441
|
try {
|
|
@@ -13403,7 +13445,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
13403
13445
|
}
|
|
13404
13446
|
for (const file of files) {
|
|
13405
13447
|
try {
|
|
13406
|
-
const filePath =
|
|
13448
|
+
const filePath = path35.join(full, file);
|
|
13407
13449
|
const content = fs36.readFileSync(filePath, "utf-8").slice(0, 1e4);
|
|
13408
13450
|
const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
|
|
13409
13451
|
if (!slugMatch) continue;
|
|
@@ -13418,7 +13460,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
13418
13460
|
out.push({
|
|
13419
13461
|
name,
|
|
13420
13462
|
slug,
|
|
13421
|
-
filePath:
|
|
13463
|
+
filePath: path35.relative(cwd, filePath),
|
|
13422
13464
|
fields: fields.slice(0, 20),
|
|
13423
13465
|
hasAdmin
|
|
13424
13466
|
});
|
|
@@ -13431,7 +13473,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
13431
13473
|
function discoverAdminComponents(cwd, collections) {
|
|
13432
13474
|
const out = [];
|
|
13433
13475
|
for (const dir of ADMIN_COMPONENT_DIRS) {
|
|
13434
|
-
const full =
|
|
13476
|
+
const full = path35.join(cwd, dir);
|
|
13435
13477
|
if (!fs36.existsSync(full)) continue;
|
|
13436
13478
|
let entries;
|
|
13437
13479
|
try {
|
|
@@ -13440,19 +13482,19 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
13440
13482
|
continue;
|
|
13441
13483
|
}
|
|
13442
13484
|
for (const entry of entries) {
|
|
13443
|
-
const entryPath =
|
|
13485
|
+
const entryPath = path35.join(full, entry.name);
|
|
13444
13486
|
let name;
|
|
13445
13487
|
let filePath;
|
|
13446
13488
|
if (entry.isDirectory()) {
|
|
13447
13489
|
const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
|
|
13448
|
-
(f) => fs36.existsSync(
|
|
13490
|
+
(f) => fs36.existsSync(path35.join(entryPath, f))
|
|
13449
13491
|
);
|
|
13450
13492
|
if (!indexFile) continue;
|
|
13451
13493
|
name = entry.name;
|
|
13452
|
-
filePath =
|
|
13494
|
+
filePath = path35.relative(cwd, path35.join(entryPath, indexFile));
|
|
13453
13495
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
13454
13496
|
name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
|
|
13455
|
-
filePath =
|
|
13497
|
+
filePath = path35.relative(cwd, entryPath);
|
|
13456
13498
|
} else {
|
|
13457
13499
|
continue;
|
|
13458
13500
|
}
|
|
@@ -13460,7 +13502,7 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
13460
13502
|
if (collections) {
|
|
13461
13503
|
for (const col of collections) {
|
|
13462
13504
|
try {
|
|
13463
|
-
const colContent = fs36.readFileSync(
|
|
13505
|
+
const colContent = fs36.readFileSync(path35.join(cwd, col.filePath), "utf-8");
|
|
13464
13506
|
if (colContent.includes(name)) {
|
|
13465
13507
|
usedInCollection = col.slug;
|
|
13466
13508
|
break;
|
|
@@ -13478,7 +13520,7 @@ function scanApiRoutes(cwd) {
|
|
|
13478
13520
|
const out = [];
|
|
13479
13521
|
const appDirs = ["src/app", "app"];
|
|
13480
13522
|
for (const appDir of appDirs) {
|
|
13481
|
-
const apiDir =
|
|
13523
|
+
const apiDir = path35.join(cwd, appDir, "api");
|
|
13482
13524
|
if (!fs36.existsSync(apiDir)) continue;
|
|
13483
13525
|
walkApiRoutes(apiDir, "/api", cwd, out);
|
|
13484
13526
|
break;
|
|
@@ -13495,7 +13537,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
13495
13537
|
const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
|
|
13496
13538
|
if (routeFile) {
|
|
13497
13539
|
try {
|
|
13498
|
-
const content = fs36.readFileSync(
|
|
13540
|
+
const content = fs36.readFileSync(path35.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
|
|
13499
13541
|
const methods = HTTP_METHODS.filter(
|
|
13500
13542
|
(m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
|
|
13501
13543
|
);
|
|
@@ -13503,7 +13545,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
13503
13545
|
out.push({
|
|
13504
13546
|
path: prefix,
|
|
13505
13547
|
methods,
|
|
13506
|
-
filePath:
|
|
13548
|
+
filePath: path35.relative(cwd, path35.join(dir, routeFile.name))
|
|
13507
13549
|
});
|
|
13508
13550
|
}
|
|
13509
13551
|
} catch {
|
|
@@ -13514,7 +13556,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
13514
13556
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
13515
13557
|
let segment = entry.name;
|
|
13516
13558
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
13517
|
-
walkApiRoutes(
|
|
13559
|
+
walkApiRoutes(path35.join(dir, entry.name), prefix, cwd, out);
|
|
13518
13560
|
continue;
|
|
13519
13561
|
}
|
|
13520
13562
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -13522,13 +13564,13 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
13522
13564
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
13523
13565
|
segment = `:${segment.slice(1, -1)}`;
|
|
13524
13566
|
}
|
|
13525
|
-
walkApiRoutes(
|
|
13567
|
+
walkApiRoutes(path35.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
|
|
13526
13568
|
}
|
|
13527
13569
|
}
|
|
13528
13570
|
function scanEnvVars(cwd) {
|
|
13529
13571
|
const candidates = [".env.example", ".env.local.example", ".env.template"];
|
|
13530
13572
|
for (const envFile of candidates) {
|
|
13531
|
-
const envPath =
|
|
13573
|
+
const envPath = path35.join(cwd, envFile);
|
|
13532
13574
|
if (!fs36.existsSync(envPath)) continue;
|
|
13533
13575
|
try {
|
|
13534
13576
|
const content = fs36.readFileSync(envPath, "utf-8");
|
|
@@ -13577,7 +13619,7 @@ var init_frameworkDetectors = __esm({
|
|
|
13577
13619
|
|
|
13578
13620
|
// src/scripts/discoverQaContext.ts
|
|
13579
13621
|
import * as fs37 from "fs";
|
|
13580
|
-
import * as
|
|
13622
|
+
import * as path36 from "path";
|
|
13581
13623
|
function runQaDiscovery(cwd) {
|
|
13582
13624
|
const out = {
|
|
13583
13625
|
routes: [],
|
|
@@ -13608,9 +13650,9 @@ function runQaDiscovery(cwd) {
|
|
|
13608
13650
|
}
|
|
13609
13651
|
function detectDevServer(cwd, out) {
|
|
13610
13652
|
try {
|
|
13611
|
-
const pkg = JSON.parse(fs37.readFileSync(
|
|
13653
|
+
const pkg = JSON.parse(fs37.readFileSync(path36.join(cwd, "package.json"), "utf-8"));
|
|
13612
13654
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13613
|
-
const pm = fs37.existsSync(
|
|
13655
|
+
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";
|
|
13614
13656
|
if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
|
|
13615
13657
|
if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
|
|
13616
13658
|
else if (allDeps.vite) out.devPort = 5173;
|
|
@@ -13620,7 +13662,7 @@ function detectDevServer(cwd, out) {
|
|
|
13620
13662
|
function scanFrontendRoutes(cwd, out) {
|
|
13621
13663
|
const appDirs = ["src/app", "app"];
|
|
13622
13664
|
for (const appDir of appDirs) {
|
|
13623
|
-
const full =
|
|
13665
|
+
const full = path36.join(cwd, appDir);
|
|
13624
13666
|
if (!fs37.existsSync(full)) continue;
|
|
13625
13667
|
walkFrontendRoutes(full, "", out);
|
|
13626
13668
|
break;
|
|
@@ -13646,7 +13688,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
13646
13688
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
13647
13689
|
let segment = entry.name;
|
|
13648
13690
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
13649
|
-
walkFrontendRoutes(
|
|
13691
|
+
walkFrontendRoutes(path36.join(dir, entry.name), prefix, out);
|
|
13650
13692
|
continue;
|
|
13651
13693
|
}
|
|
13652
13694
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -13654,7 +13696,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
13654
13696
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
13655
13697
|
segment = `:${segment.slice(1, -1)}`;
|
|
13656
13698
|
}
|
|
13657
|
-
walkFrontendRoutes(
|
|
13699
|
+
walkFrontendRoutes(path36.join(dir, entry.name), `${prefix}/${segment}`, out);
|
|
13658
13700
|
}
|
|
13659
13701
|
}
|
|
13660
13702
|
function detectAuthFiles(cwd, out) {
|
|
@@ -13671,13 +13713,13 @@ function detectAuthFiles(cwd, out) {
|
|
|
13671
13713
|
"src/app/api/oauth"
|
|
13672
13714
|
];
|
|
13673
13715
|
for (const c of candidates) {
|
|
13674
|
-
if (fs37.existsSync(
|
|
13716
|
+
if (fs37.existsSync(path36.join(cwd, c))) out.authFiles.push(c);
|
|
13675
13717
|
}
|
|
13676
13718
|
}
|
|
13677
13719
|
function detectRoles(cwd, out) {
|
|
13678
13720
|
const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
|
|
13679
13721
|
for (const rp of rolePaths) {
|
|
13680
|
-
const dir =
|
|
13722
|
+
const dir = path36.join(cwd, rp);
|
|
13681
13723
|
if (!fs37.existsSync(dir)) continue;
|
|
13682
13724
|
let files;
|
|
13683
13725
|
try {
|
|
@@ -13687,7 +13729,7 @@ function detectRoles(cwd, out) {
|
|
|
13687
13729
|
}
|
|
13688
13730
|
for (const f of files) {
|
|
13689
13731
|
try {
|
|
13690
|
-
const content = fs37.readFileSync(
|
|
13732
|
+
const content = fs37.readFileSync(path36.join(dir, f), "utf-8").slice(0, 5e3);
|
|
13691
13733
|
const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
|
|
13692
13734
|
if (roleMatches) {
|
|
13693
13735
|
for (const m of roleMatches) {
|
|
@@ -13949,7 +13991,7 @@ var init_dispatchClassified = __esm({
|
|
|
13949
13991
|
|
|
13950
13992
|
// src/loopDefinitions.ts
|
|
13951
13993
|
import * as fs38 from "fs";
|
|
13952
|
-
import * as
|
|
13994
|
+
import * as path37 from "path";
|
|
13953
13995
|
function normalizeLoopDefinition(value) {
|
|
13954
13996
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
13955
13997
|
const raw = value;
|
|
@@ -13976,7 +14018,7 @@ function readLoopDefinition(cwd, id) {
|
|
|
13976
14018
|
if (!ID.test(id)) return null;
|
|
13977
14019
|
const roots = loopRoots(cwd);
|
|
13978
14020
|
for (const root of roots) {
|
|
13979
|
-
const filePath =
|
|
14021
|
+
const filePath = path37.join(root, "loops", id, "loop.json");
|
|
13980
14022
|
if (!fs38.existsSync(filePath)) continue;
|
|
13981
14023
|
try {
|
|
13982
14024
|
const loop = normalizeLoopDefinition(JSON.parse(fs38.readFileSync(filePath, "utf8")));
|
|
@@ -13989,7 +14031,7 @@ function readLoopDefinition(cwd, id) {
|
|
|
13989
14031
|
}
|
|
13990
14032
|
}
|
|
13991
14033
|
process.stderr.write(
|
|
13992
|
-
`[kody] Loop not found: ${id} (${roots.map((root) =>
|
|
14034
|
+
`[kody] Loop not found: ${id} (${roots.map((root) => path37.join(root, "loops", id, "loop.json")).join(", ")})
|
|
13993
14035
|
`
|
|
13994
14036
|
);
|
|
13995
14037
|
return null;
|
|
@@ -13998,11 +14040,11 @@ function listLoopDefinitions(cwd) {
|
|
|
13998
14040
|
const roots = loopRoots(cwd);
|
|
13999
14041
|
const byId = /* @__PURE__ */ new Map();
|
|
14000
14042
|
for (const root of roots.reverse()) {
|
|
14001
|
-
const loopsDir =
|
|
14043
|
+
const loopsDir = path37.join(root, "loops");
|
|
14002
14044
|
if (!fs38.existsSync(loopsDir)) continue;
|
|
14003
14045
|
for (const id of fs38.readdirSync(loopsDir).sort()) {
|
|
14004
14046
|
if (!ID.test(id)) continue;
|
|
14005
|
-
const filePath =
|
|
14047
|
+
const filePath = path37.join(loopsDir, id, "loop.json");
|
|
14006
14048
|
if (!fs38.existsSync(filePath)) continue;
|
|
14007
14049
|
try {
|
|
14008
14050
|
const loop = normalizeLoopDefinition(JSON.parse(fs38.readFileSync(filePath, "utf8")));
|
|
@@ -14017,8 +14059,8 @@ function listLoopDefinitions(cwd) {
|
|
|
14017
14059
|
}
|
|
14018
14060
|
function loopRoots(cwd) {
|
|
14019
14061
|
return [
|
|
14020
|
-
|
|
14021
|
-
|
|
14062
|
+
path37.join(cwd, ".kody-engine", "runtime"),
|
|
14063
|
+
path37.join(cwd, ".kody-engine", "definitions"),
|
|
14022
14064
|
definitionsRoot(cwd)
|
|
14023
14065
|
].filter((root, index, roots) => roots.indexOf(root) === index);
|
|
14024
14066
|
}
|
|
@@ -15297,11 +15339,11 @@ var init_fixFlow = __esm({
|
|
|
15297
15339
|
|
|
15298
15340
|
// src/workflow-template.ts
|
|
15299
15341
|
import * as fs39 from "fs";
|
|
15300
|
-
import * as
|
|
15342
|
+
import * as path38 from "path";
|
|
15301
15343
|
import { fileURLToPath } from "url";
|
|
15302
15344
|
function loadKodyWorkflowTemplate() {
|
|
15303
|
-
const here =
|
|
15304
|
-
const candidates = [
|
|
15345
|
+
const here = path38.dirname(fileURLToPath(import.meta.url));
|
|
15346
|
+
const candidates = [path38.resolve(here, "../templates/kody.yml"), path38.resolve(here, "../../templates/kody.yml")];
|
|
15305
15347
|
const source = candidates.find((candidate) => fs39.existsSync(candidate));
|
|
15306
15348
|
if (!source) throw new Error(`Kody workflow template is missing: ${KODY_WORKFLOW_TEMPLATE_PATH}`);
|
|
15307
15349
|
return fs39.readFileSync(source, "utf8");
|
|
@@ -15317,11 +15359,11 @@ var init_workflow_template = __esm({
|
|
|
15317
15359
|
// src/scripts/initFlow.ts
|
|
15318
15360
|
import { execFileSync as execFileSync14 } from "child_process";
|
|
15319
15361
|
import * as fs40 from "fs";
|
|
15320
|
-
import * as
|
|
15362
|
+
import * as path39 from "path";
|
|
15321
15363
|
function detectPackageManager(cwd) {
|
|
15322
|
-
if (fs40.existsSync(
|
|
15323
|
-
if (fs40.existsSync(
|
|
15324
|
-
if (fs40.existsSync(
|
|
15364
|
+
if (fs40.existsSync(path39.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
15365
|
+
if (fs40.existsSync(path39.join(cwd, "yarn.lock"))) return "yarn";
|
|
15366
|
+
if (fs40.existsSync(path39.join(cwd, "bun.lockb"))) return "bun";
|
|
15325
15367
|
return "npm";
|
|
15326
15368
|
}
|
|
15327
15369
|
function qualityCommandsFor(pm) {
|
|
@@ -15393,7 +15435,7 @@ function performInit(cwd, force) {
|
|
|
15393
15435
|
const pm = detectPackageManager(cwd);
|
|
15394
15436
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
15395
15437
|
const defaultBranch = defaultBranchFromGit(cwd);
|
|
15396
|
-
const configPath =
|
|
15438
|
+
const configPath = path39.join(cwd, "kody.config.json");
|
|
15397
15439
|
if (fs40.existsSync(configPath) && !force) {
|
|
15398
15440
|
skipped.push("kody.config.json");
|
|
15399
15441
|
} else {
|
|
@@ -15402,8 +15444,8 @@ function performInit(cwd, force) {
|
|
|
15402
15444
|
`);
|
|
15403
15445
|
wrote.push("kody.config.json");
|
|
15404
15446
|
}
|
|
15405
|
-
const workflowDir =
|
|
15406
|
-
const workflowPath =
|
|
15447
|
+
const workflowDir = path39.join(cwd, ".github", "workflows");
|
|
15448
|
+
const workflowPath = path39.join(workflowDir, "kody.yml");
|
|
15407
15449
|
if (fs40.existsSync(workflowPath) && !force) {
|
|
15408
15450
|
skipped.push(".github/workflows/kody.yml");
|
|
15409
15451
|
} else {
|
|
@@ -15598,13 +15640,13 @@ var init_loadCapabilityState = __esm({
|
|
|
15598
15640
|
function isCompanyIntentId(value) {
|
|
15599
15641
|
return SLUG_RE2.test(value);
|
|
15600
15642
|
}
|
|
15601
|
-
function normalizeCompanyIntent(
|
|
15643
|
+
function normalizeCompanyIntent(path59, raw) {
|
|
15602
15644
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
15603
|
-
throw new Error(`${
|
|
15645
|
+
throw new Error(`${path59}: intent must be JSON object`);
|
|
15604
15646
|
}
|
|
15605
15647
|
const input = raw;
|
|
15606
15648
|
const id = stringField4(input.id);
|
|
15607
|
-
if (!id || !isCompanyIntentId(id)) throw new Error(`${
|
|
15649
|
+
if (!id || !isCompanyIntentId(id)) throw new Error(`${path59}: invalid intent id`);
|
|
15608
15650
|
const createdAt = stringField4(input.createdAt) || nowIso();
|
|
15609
15651
|
const updatedAt = stringField4(input.updatedAt) || createdAt;
|
|
15610
15652
|
const description = stringField4(input.description);
|
|
@@ -15766,7 +15808,7 @@ function retryDelaysMs() {
|
|
|
15766
15808
|
}
|
|
15767
15809
|
function sleep(ms) {
|
|
15768
15810
|
if (ms <= 0) return Promise.resolve();
|
|
15769
|
-
return new Promise((
|
|
15811
|
+
return new Promise((resolve24) => setTimeout(resolve24, ms));
|
|
15770
15812
|
}
|
|
15771
15813
|
async function fetchGoalStateWithRetry(config, goalId, cwd) {
|
|
15772
15814
|
let state = await fetchGoalStateAsync(config, goalId, cwd);
|
|
@@ -15896,7 +15938,7 @@ var init_loadIssueStateComment = __esm({
|
|
|
15896
15938
|
|
|
15897
15939
|
// src/scripts/loadJobFromFile.ts
|
|
15898
15940
|
import * as fs42 from "fs";
|
|
15899
|
-
import * as
|
|
15941
|
+
import * as path40 from "path";
|
|
15900
15942
|
function parseJobFile(raw, slug) {
|
|
15901
15943
|
let stripped = raw;
|
|
15902
15944
|
if (stripped.startsWith("---\n")) {
|
|
@@ -15935,10 +15977,10 @@ var init_loadJobFromFile = __esm({
|
|
|
15935
15977
|
if (!slug) {
|
|
15936
15978
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
15937
15979
|
}
|
|
15938
|
-
const capability = resolveCapabilityFolder(slug,
|
|
15980
|
+
const capability = resolveCapabilityFolder(slug, path40.resolve(ctx.cwd, jobsDir));
|
|
15939
15981
|
if (!capability) {
|
|
15940
15982
|
throw new Error(
|
|
15941
|
-
`loadJobFromFile: capability folder not found or incomplete: ${
|
|
15983
|
+
`loadJobFromFile: capability folder not found or incomplete: ${path40.resolve(ctx.cwd, jobsDir, slug)}`
|
|
15942
15984
|
);
|
|
15943
15985
|
}
|
|
15944
15986
|
const { title, body, config } = capability;
|
|
@@ -16034,9 +16076,9 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
16034
16076
|
|
|
16035
16077
|
// src/scripts/kodyVariables.ts
|
|
16036
16078
|
import * as fs43 from "fs";
|
|
16037
|
-
import * as
|
|
16079
|
+
import * as path41 from "path";
|
|
16038
16080
|
function readKodyVariables(cwd) {
|
|
16039
|
-
const full =
|
|
16081
|
+
const full = path41.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
16040
16082
|
let raw;
|
|
16041
16083
|
try {
|
|
16042
16084
|
raw = fs43.readFileSync(full, "utf-8");
|
|
@@ -16065,7 +16107,7 @@ var init_kodyVariables = __esm({
|
|
|
16065
16107
|
|
|
16066
16108
|
// src/scripts/loadQaContext.ts
|
|
16067
16109
|
import * as fs44 from "fs";
|
|
16068
|
-
import * as
|
|
16110
|
+
import * as path42 from "path";
|
|
16069
16111
|
function parseSlugList(value) {
|
|
16070
16112
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
16071
16113
|
return inner.split(",").map(
|
|
@@ -16094,7 +16136,7 @@ function readProfileAgents(raw) {
|
|
|
16094
16136
|
return { agent: agent ?? legacy ?? ["kody"], body };
|
|
16095
16137
|
}
|
|
16096
16138
|
function readProfile(cwd) {
|
|
16097
|
-
const dir =
|
|
16139
|
+
const dir = path42.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
16098
16140
|
if (!fs44.existsSync(dir)) return "";
|
|
16099
16141
|
let entries;
|
|
16100
16142
|
try {
|
|
@@ -16105,7 +16147,7 @@ function readProfile(cwd) {
|
|
|
16105
16147
|
const blocks = [];
|
|
16106
16148
|
for (const file of entries) {
|
|
16107
16149
|
try {
|
|
16108
|
-
const raw = fs44.readFileSync(
|
|
16150
|
+
const raw = fs44.readFileSync(path42.join(dir, file), "utf-8");
|
|
16109
16151
|
const { agent, body } = readProfileAgents(raw);
|
|
16110
16152
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
16111
16153
|
blocks.push(`## ${file}
|
|
@@ -16157,7 +16199,7 @@ var init_loadQaContext = __esm({
|
|
|
16157
16199
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
16158
16200
|
import * as fs45 from "fs";
|
|
16159
16201
|
import * as os6 from "os";
|
|
16160
|
-
import * as
|
|
16202
|
+
import * as path43 from "path";
|
|
16161
16203
|
function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
|
|
16162
16204
|
const subagentFiles = toolFiles.flatMap((file) => {
|
|
16163
16205
|
const match = /^agents\/([a-z][a-z0-9-]{0,63})\.md$/.exec(file);
|
|
@@ -16170,7 +16212,7 @@ function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
|
|
|
16170
16212
|
profile.subagentTemplates = {
|
|
16171
16213
|
...profile.subagentTemplates ?? {},
|
|
16172
16214
|
...Object.fromEntries(
|
|
16173
|
-
subagentFiles.map(({ name, file }) => [name, fs45.readFileSync(
|
|
16215
|
+
subagentFiles.map(({ name, file }) => [name, fs45.readFileSync(path43.join(toolRoot, file), "utf-8")])
|
|
16174
16216
|
)
|
|
16175
16217
|
};
|
|
16176
16218
|
if (!profile.claudeCode.tools.includes("Agent")) {
|
|
@@ -16215,10 +16257,10 @@ function listFiles(root) {
|
|
|
16215
16257
|
const files = [];
|
|
16216
16258
|
const visit = (dir) => {
|
|
16217
16259
|
for (const entry of fs45.readdirSync(dir, { withFileTypes: true })) {
|
|
16218
|
-
const absolute =
|
|
16260
|
+
const absolute = path43.join(dir, entry.name);
|
|
16219
16261
|
if (entry.isSymbolicLink()) continue;
|
|
16220
16262
|
if (entry.isDirectory()) visit(absolute);
|
|
16221
|
-
else if (entry.isFile()) files.push(
|
|
16263
|
+
else if (entry.isFile()) files.push(path43.relative(root, absolute));
|
|
16222
16264
|
}
|
|
16223
16265
|
};
|
|
16224
16266
|
visit(root);
|
|
@@ -16241,8 +16283,8 @@ var init_loadSimpleCapability = __esm({
|
|
|
16241
16283
|
if (!capability) {
|
|
16242
16284
|
throw new Error(`Capability "${slug}" is not a valid simple capability folder`);
|
|
16243
16285
|
}
|
|
16244
|
-
const toolRoot =
|
|
16245
|
-
const skillRoot =
|
|
16286
|
+
const toolRoot = path43.join(capability.dir, "tools");
|
|
16287
|
+
const skillRoot = path43.join(capability.dir, "skills");
|
|
16246
16288
|
const toolFiles = listFiles(toolRoot);
|
|
16247
16289
|
const skillFiles = listFiles(skillRoot);
|
|
16248
16290
|
const parsedInput = parseInput(ctx.args.input);
|
|
@@ -16267,14 +16309,14 @@ var init_loadSimpleCapability = __esm({
|
|
|
16267
16309
|
}
|
|
16268
16310
|
if (requiredSubagents.length > 0) ctx.data.requiredSubagents = requiredSubagents;
|
|
16269
16311
|
if (capability.contract?.execution === "script") {
|
|
16270
|
-
ctx.data.capabilityScriptPath =
|
|
16312
|
+
ctx.data.capabilityScriptPath = path43.join(capability.dir, "tools", "run.sh");
|
|
16271
16313
|
ctx.data.capabilitySecretNames = capability.contract.secrets ?? [];
|
|
16272
16314
|
ctx.data.capabilityScriptTimeoutMs = capability.contract.timeoutMs;
|
|
16273
16315
|
}
|
|
16274
16316
|
if (capability.config.outputSchema) {
|
|
16275
16317
|
ctx.data.capabilityOutputSchema = capability.config.outputSchema;
|
|
16276
16318
|
}
|
|
16277
|
-
const outputPath = ctx.data.capabilityExecution === "agent" && capability.config.outputSchema ?
|
|
16319
|
+
const outputPath = ctx.data.capabilityExecution === "agent" && capability.config.outputSchema ? path43.join(os6.tmpdir(), `kody-capability-output-${randomUUID2()}.json`) : void 0;
|
|
16278
16320
|
if (outputPath) ctx.data.capabilityOutputPath = outputPath;
|
|
16279
16321
|
ctx.data.capabilityEnvironment = {
|
|
16280
16322
|
...capabilityInputEnvironment(input),
|
|
@@ -16297,7 +16339,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
16297
16339
|
...skillFiles.flatMap((file) => [
|
|
16298
16340
|
`### ${file}`,
|
|
16299
16341
|
"",
|
|
16300
|
-
fs45.readFileSync(
|
|
16342
|
+
fs45.readFileSync(path43.join(skillRoot, file), "utf-8"),
|
|
16301
16343
|
""
|
|
16302
16344
|
])
|
|
16303
16345
|
] : [],
|
|
@@ -16306,7 +16348,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
16306
16348
|
"## Tools",
|
|
16307
16349
|
"",
|
|
16308
16350
|
"Inspect or run these capability-owned files when needed:",
|
|
16309
|
-
...toolFiles.map((file) => `- ${
|
|
16351
|
+
...toolFiles.map((file) => `- ${path43.join(toolRoot, file)}`)
|
|
16310
16352
|
] : [],
|
|
16311
16353
|
"",
|
|
16312
16354
|
...capability.config.outputSchema ? [
|
|
@@ -16338,7 +16380,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
16338
16380
|
|
|
16339
16381
|
// src/taskContext.ts
|
|
16340
16382
|
import * as fs46 from "fs";
|
|
16341
|
-
import * as
|
|
16383
|
+
import * as path44 from "path";
|
|
16342
16384
|
function buildTaskContext(args) {
|
|
16343
16385
|
return {
|
|
16344
16386
|
schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
|
|
@@ -16355,7 +16397,7 @@ function persistTaskContext(cwd, ctx) {
|
|
|
16355
16397
|
try {
|
|
16356
16398
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
16357
16399
|
fs46.mkdirSync(dir, { recursive: true });
|
|
16358
|
-
const file =
|
|
16400
|
+
const file = path44.join(dir, "task-context.json");
|
|
16359
16401
|
fs46.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
16360
16402
|
`);
|
|
16361
16403
|
return file;
|
|
@@ -16783,19 +16825,19 @@ function parseAgencyModelProposal(raw) {
|
|
|
16783
16825
|
function normalizeBundleFiles(bundle) {
|
|
16784
16826
|
const seen = /* @__PURE__ */ new Set();
|
|
16785
16827
|
return bundle.files.map((file, index) => {
|
|
16786
|
-
const
|
|
16787
|
-
const parts =
|
|
16788
|
-
if (!
|
|
16828
|
+
const path59 = file.path.replace(/^\/+/, "");
|
|
16829
|
+
const parts = path59.split("/");
|
|
16830
|
+
if (!path59 || file.path.startsWith("/") || file.path.includes("\\") || parts.some((part) => !part || part === "." || part === "..")) {
|
|
16789
16831
|
throw new Error(`openAgencyModelReviewPr: files[${index}].path is unsafe`);
|
|
16790
16832
|
}
|
|
16791
16833
|
if (!/^(agents\/[^/]+\.md|capabilities\/[^/]+\/.+|goals\/(?:templates\/)?[^/]+\/.+|workflows\/[^/]+\.json)$/.test(
|
|
16792
|
-
|
|
16834
|
+
path59
|
|
16793
16835
|
)) {
|
|
16794
16836
|
throw new Error(`openAgencyModelReviewPr: files[${index}].path is not a supported definition path`);
|
|
16795
16837
|
}
|
|
16796
|
-
if (seen.has(
|
|
16797
|
-
seen.add(
|
|
16798
|
-
return { path:
|
|
16838
|
+
if (seen.has(path59)) throw new Error(`openAgencyModelReviewPr: duplicate generated file path: ${path59}`);
|
|
16839
|
+
seen.add(path59);
|
|
16840
|
+
return { path: path59, content: file.content.replace(/\r\n?/g, "\n") };
|
|
16799
16841
|
});
|
|
16800
16842
|
}
|
|
16801
16843
|
function buildProposalId(issueNumber, bundle, sourceLabel) {
|
|
@@ -17907,7 +17949,7 @@ var init_postResearchComment = __esm({
|
|
|
17907
17949
|
// src/scripts/prepareBrowserAuth.ts
|
|
17908
17950
|
import * as fs48 from "fs";
|
|
17909
17951
|
import * as os7 from "os";
|
|
17910
|
-
import * as
|
|
17952
|
+
import * as path45 from "path";
|
|
17911
17953
|
function appendAuthMessage(ctx, message) {
|
|
17912
17954
|
const current = typeof ctx.data.qaAuthBlock === "string" ? ctx.data.qaAuthBlock.trim() : "";
|
|
17913
17955
|
ctx.data.qaAuthBlock = current ? `${current}
|
|
@@ -17946,9 +17988,9 @@ async function githubJson(url, token) {
|
|
|
17946
17988
|
return await response.json();
|
|
17947
17989
|
}
|
|
17948
17990
|
function writeKodyStorageState(input) {
|
|
17949
|
-
const directory = fs48.mkdtempSync(
|
|
17991
|
+
const directory = fs48.mkdtempSync(path45.join(os7.tmpdir(), "kody-browser-auth-"));
|
|
17950
17992
|
fs48.chmodSync(directory, 448);
|
|
17951
|
-
const file =
|
|
17993
|
+
const file = path45.join(directory, "storage-state.json");
|
|
17952
17994
|
const now = Date.now();
|
|
17953
17995
|
const repoEntry = {
|
|
17954
17996
|
repoUrl: input.repoUrl,
|
|
@@ -18207,7 +18249,7 @@ var init_prepareCapabilityDelivery = __esm({
|
|
|
18207
18249
|
|
|
18208
18250
|
// src/scripts/prepareSimpleCapabilityRuntime.ts
|
|
18209
18251
|
import { isIP } from "net";
|
|
18210
|
-
import * as
|
|
18252
|
+
import * as path46 from "path";
|
|
18211
18253
|
function requirementsFrom(ctx) {
|
|
18212
18254
|
const raw = ctx.data.capabilityRequirements;
|
|
18213
18255
|
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
@@ -18251,7 +18293,7 @@ function browserRuntime(ctx, requirements) {
|
|
|
18251
18293
|
"--allowed-origins",
|
|
18252
18294
|
origin,
|
|
18253
18295
|
"--output-dir",
|
|
18254
|
-
|
|
18296
|
+
path46.resolve(ctx.cwd, "test-results", "quality-runs", qualityRunId)
|
|
18255
18297
|
]
|
|
18256
18298
|
};
|
|
18257
18299
|
}
|
|
@@ -18616,9 +18658,9 @@ function latestResult(raw, agentResult) {
|
|
|
18616
18658
|
function recordField4(value) {
|
|
18617
18659
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
18618
18660
|
}
|
|
18619
|
-
function resolveDotted(root,
|
|
18620
|
-
if (!
|
|
18621
|
-
return
|
|
18661
|
+
function resolveDotted(root, path59) {
|
|
18662
|
+
if (!path59) return void 0;
|
|
18663
|
+
return path59.split(".").reduce((value, key) => recordField4(value)?.[key], root);
|
|
18622
18664
|
}
|
|
18623
18665
|
function stringValue5(value) {
|
|
18624
18666
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
@@ -19460,7 +19502,7 @@ var init_previewBuildHelpers = __esm({
|
|
|
19460
19502
|
// src/scripts/previewBuildRun.ts
|
|
19461
19503
|
import { spawn as spawn5 } from "child_process";
|
|
19462
19504
|
async function runCmd(cmd, args, opts = {}) {
|
|
19463
|
-
await new Promise((
|
|
19505
|
+
await new Promise((resolve24, reject) => {
|
|
19464
19506
|
const child = spawn5(cmd, args, {
|
|
19465
19507
|
cwd: opts.cwd,
|
|
19466
19508
|
env: { ...process.env, ...opts.env ?? {} },
|
|
@@ -19472,7 +19514,7 @@ async function runCmd(cmd, args, opts = {}) {
|
|
|
19472
19514
|
}
|
|
19473
19515
|
child.on("error", reject);
|
|
19474
19516
|
child.on("close", (code) => {
|
|
19475
|
-
if (code === 0)
|
|
19517
|
+
if (code === 0) resolve24();
|
|
19476
19518
|
else reject(new Error(`${cmd} ${args.join(" ")} exited ${code}`));
|
|
19477
19519
|
});
|
|
19478
19520
|
});
|
|
@@ -19544,12 +19586,12 @@ fi
|
|
|
19544
19586
|
|
|
19545
19587
|
// src/scripts/runPreviewBuild.ts
|
|
19546
19588
|
import { copyFile, writeFile } from "fs/promises";
|
|
19547
|
-
import * as
|
|
19589
|
+
import * as path47 from "path";
|
|
19548
19590
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
19549
19591
|
function bundledDockerfilePath(mode) {
|
|
19550
|
-
const here =
|
|
19592
|
+
const here = path47.dirname(fileURLToPath2(import.meta.url));
|
|
19551
19593
|
const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
|
|
19552
|
-
return
|
|
19594
|
+
return path47.join(here, "preview-build-templates", file);
|
|
19553
19595
|
}
|
|
19554
19596
|
function required(name) {
|
|
19555
19597
|
const v = (process.env[name] ?? "").trim();
|
|
@@ -19784,10 +19826,10 @@ var init_runPreviewBuild = __esm({
|
|
|
19784
19826
|
console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
|
|
19785
19827
|
if (Object.keys(buildEnv).length > 0) {
|
|
19786
19828
|
const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
19787
|
-
await writeFile(
|
|
19829
|
+
await writeFile(path47.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
|
|
19788
19830
|
`, "utf8");
|
|
19789
19831
|
}
|
|
19790
|
-
const consumerDockerfile =
|
|
19832
|
+
const consumerDockerfile = path47.join(ctx.cwd, "Dockerfile.preview");
|
|
19791
19833
|
const { stat } = await import("fs/promises");
|
|
19792
19834
|
let hasConsumerDockerfile = false;
|
|
19793
19835
|
try {
|
|
@@ -19972,7 +20014,7 @@ var init_tickShellRunner = __esm({
|
|
|
19972
20014
|
|
|
19973
20015
|
// src/scripts/runScheduledImplementationTick.ts
|
|
19974
20016
|
import * as fs49 from "fs";
|
|
19975
|
-
import * as
|
|
20017
|
+
import * as path48 from "path";
|
|
19976
20018
|
var runScheduledImplementationTick;
|
|
19977
20019
|
var init_runScheduledImplementationTick = __esm({
|
|
19978
20020
|
"src/scripts/runScheduledImplementationTick.ts"() {
|
|
@@ -19993,13 +20035,13 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
19993
20035
|
ctx.output.reason = `runScheduledImplementationTick: args.slug or ctx.args.${slugArg} must be non-empty capability slug`;
|
|
19994
20036
|
return;
|
|
19995
20037
|
}
|
|
19996
|
-
const capability = resolveCapabilityFolder(slug,
|
|
20038
|
+
const capability = resolveCapabilityFolder(slug, path48.resolve(ctx.cwd, jobsDir));
|
|
19997
20039
|
if (!capability) {
|
|
19998
20040
|
ctx.output.exitCode = 99;
|
|
19999
20041
|
ctx.output.reason = `runScheduledImplementationTick: capability folder not found or incomplete: ${slug} (searched ${jobsDir} and company store)`;
|
|
20000
20042
|
return;
|
|
20001
20043
|
}
|
|
20002
|
-
const shellPath =
|
|
20044
|
+
const shellPath = path48.join(profile.dir, shell);
|
|
20003
20045
|
if (!fs49.existsSync(shellPath)) {
|
|
20004
20046
|
ctx.output.exitCode = 99;
|
|
20005
20047
|
ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
@@ -20118,7 +20160,7 @@ var init_runSimpleCapabilityScript = __esm({
|
|
|
20118
20160
|
|
|
20119
20161
|
// src/scripts/runTickScript.ts
|
|
20120
20162
|
import * as fs51 from "fs";
|
|
20121
|
-
import * as
|
|
20163
|
+
import * as path49 from "path";
|
|
20122
20164
|
var runTickScript;
|
|
20123
20165
|
var init_runTickScript = __esm({
|
|
20124
20166
|
"src/scripts/runTickScript.ts"() {
|
|
@@ -20138,10 +20180,10 @@ var init_runTickScript = __esm({
|
|
|
20138
20180
|
ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
|
|
20139
20181
|
return;
|
|
20140
20182
|
}
|
|
20141
|
-
const capability = readCapabilityFolder(
|
|
20183
|
+
const capability = readCapabilityFolder(path49.resolve(ctx.cwd, jobsDir), slug);
|
|
20142
20184
|
if (!capability) {
|
|
20143
20185
|
ctx.output.exitCode = 99;
|
|
20144
|
-
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${
|
|
20186
|
+
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path49.resolve(ctx.cwd, jobsDir, slug)}`;
|
|
20145
20187
|
return;
|
|
20146
20188
|
}
|
|
20147
20189
|
const tickScript = capability.config.tickScript;
|
|
@@ -20150,7 +20192,7 @@ var init_runTickScript = __esm({
|
|
|
20150
20192
|
ctx.output.reason = `runTickScript: capability ${slug} has no \`tickScript\` in profile.json \u2014 route via capability-tick instead`;
|
|
20151
20193
|
return;
|
|
20152
20194
|
}
|
|
20153
|
-
const scriptPath =
|
|
20195
|
+
const scriptPath = path49.isAbsolute(tickScript) ? tickScript : path49.join(ctx.cwd, tickScript);
|
|
20154
20196
|
if (!fs51.existsSync(scriptPath)) {
|
|
20155
20197
|
ctx.output.exitCode = 99;
|
|
20156
20198
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
@@ -20433,7 +20475,7 @@ var init_syncFlow = __esm({
|
|
|
20433
20475
|
});
|
|
20434
20476
|
|
|
20435
20477
|
// src/scripts/validateAgencyModelProposal.ts
|
|
20436
|
-
import * as
|
|
20478
|
+
import * as path50 from "path";
|
|
20437
20479
|
function validateModelBundle(bundle, expectedKind, options = {}) {
|
|
20438
20480
|
const failures = [];
|
|
20439
20481
|
validateOneModel(bundle.model, bundle.files, "model", true, failures, expectedKind, options);
|
|
@@ -20751,7 +20793,7 @@ var init_validateAgencyModelProposal = __esm({
|
|
|
20751
20793
|
const bundle = parseAgencyModelProposal(raw);
|
|
20752
20794
|
const expectedKind = readExpectedModelKind(args);
|
|
20753
20795
|
const failures = validateModelBundle(bundle, expectedKind, {
|
|
20754
|
-
capabilityRoot:
|
|
20796
|
+
capabilityRoot: path50.join(ctx.cwd, ".kody", "capabilities")
|
|
20755
20797
|
});
|
|
20756
20798
|
if (failures.length > 0) {
|
|
20757
20799
|
throw new Error(`validateAgencyModelProposal: ${failures.join("; ")}`);
|
|
@@ -20814,7 +20856,7 @@ function stripAnsi2(s) {
|
|
|
20814
20856
|
return s.replace(ANSI_RE2, "");
|
|
20815
20857
|
}
|
|
20816
20858
|
function runCommand2(command, cwd) {
|
|
20817
|
-
return new Promise((
|
|
20859
|
+
return new Promise((resolve24) => {
|
|
20818
20860
|
const child = spawn6(command, {
|
|
20819
20861
|
cwd,
|
|
20820
20862
|
shell: true,
|
|
@@ -20841,11 +20883,11 @@ function runCommand2(command, cwd) {
|
|
|
20841
20883
|
}, TEST_TIMEOUT_MS);
|
|
20842
20884
|
child.on("exit", (code) => {
|
|
20843
20885
|
clearTimeout(timer);
|
|
20844
|
-
|
|
20886
|
+
resolve24({ exitCode: code ?? -1, output: Buffer.concat(buffers).toString("utf-8") });
|
|
20845
20887
|
});
|
|
20846
20888
|
child.on("error", (err) => {
|
|
20847
20889
|
clearTimeout(timer);
|
|
20848
|
-
|
|
20890
|
+
resolve24({ exitCode: -1, output: err.message });
|
|
20849
20891
|
});
|
|
20850
20892
|
});
|
|
20851
20893
|
}
|
|
@@ -21259,21 +21301,21 @@ function lineStream(stream) {
|
|
|
21259
21301
|
tryDeliver();
|
|
21260
21302
|
});
|
|
21261
21303
|
return {
|
|
21262
|
-
next: (timeoutMs) => new Promise((
|
|
21304
|
+
next: (timeoutMs) => new Promise((resolve24) => {
|
|
21263
21305
|
if (queue.length > 0) {
|
|
21264
|
-
|
|
21306
|
+
resolve24(queue.shift());
|
|
21265
21307
|
return;
|
|
21266
21308
|
}
|
|
21267
21309
|
if (ended) {
|
|
21268
|
-
|
|
21310
|
+
resolve24(null);
|
|
21269
21311
|
return;
|
|
21270
21312
|
}
|
|
21271
|
-
waiter =
|
|
21313
|
+
waiter = resolve24;
|
|
21272
21314
|
const t = setTimeout(
|
|
21273
21315
|
() => {
|
|
21274
|
-
if (waiter ===
|
|
21316
|
+
if (waiter === resolve24) {
|
|
21275
21317
|
waiter = null;
|
|
21276
|
-
|
|
21318
|
+
resolve24(null);
|
|
21277
21319
|
}
|
|
21278
21320
|
},
|
|
21279
21321
|
Math.max(0, timeoutMs)
|
|
@@ -21675,15 +21717,15 @@ var init_scripts = __esm({
|
|
|
21675
21717
|
|
|
21676
21718
|
// src/stateWorkspace.ts
|
|
21677
21719
|
import * as fs53 from "fs";
|
|
21678
|
-
import * as
|
|
21720
|
+
import * as path51 from "path";
|
|
21679
21721
|
function tenantId(config) {
|
|
21680
21722
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
21681
21723
|
const repo = config.github?.repo?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim();
|
|
21682
21724
|
return owner && repo ? `${owner}/${repo}` : null;
|
|
21683
21725
|
}
|
|
21684
21726
|
function writeRuntimeFile(cwd, relativePath, content) {
|
|
21685
|
-
const target =
|
|
21686
|
-
fs53.mkdirSync(
|
|
21727
|
+
const target = path51.join(cwd, RUNTIME_ROOT, relativePath);
|
|
21728
|
+
fs53.mkdirSync(path51.dirname(target), { recursive: true });
|
|
21687
21729
|
fs53.writeFileSync(target, content, "utf8");
|
|
21688
21730
|
}
|
|
21689
21731
|
function record(value) {
|
|
@@ -21749,10 +21791,10 @@ async function hydrateStateWorkspace(config, cwd, backendOverride) {
|
|
|
21749
21791
|
throw new Error("Kody backend access is required for runtime workspace documents");
|
|
21750
21792
|
return;
|
|
21751
21793
|
}
|
|
21752
|
-
const key = `${
|
|
21794
|
+
const key = `${path51.resolve(cwd)}|${tenant}`;
|
|
21753
21795
|
if (hydratedWorkspaces.has(key)) return;
|
|
21754
21796
|
const backend = backendOverride ?? createStateBackendFromEnv();
|
|
21755
|
-
const root =
|
|
21797
|
+
const root = path51.join(cwd, RUNTIME_ROOT);
|
|
21756
21798
|
fs53.rmSync(root, { recursive: true, force: true });
|
|
21757
21799
|
await Promise.all([
|
|
21758
21800
|
hydratePrefix(backend, tenant, cwd, "context:"),
|
|
@@ -21769,7 +21811,7 @@ var init_stateWorkspace = __esm({
|
|
|
21769
21811
|
"src/stateWorkspace.ts"() {
|
|
21770
21812
|
"use strict";
|
|
21771
21813
|
init_state_backend();
|
|
21772
|
-
RUNTIME_ROOT =
|
|
21814
|
+
RUNTIME_ROOT = path51.join(".kody-engine", "runtime");
|
|
21773
21815
|
hydratedWorkspaces = /* @__PURE__ */ new Set();
|
|
21774
21816
|
}
|
|
21775
21817
|
});
|
|
@@ -21842,7 +21884,7 @@ var init_tools = __esm({
|
|
|
21842
21884
|
import { spawn as spawn8 } from "child_process";
|
|
21843
21885
|
import * as fs54 from "fs";
|
|
21844
21886
|
import * as os8 from "os";
|
|
21845
|
-
import * as
|
|
21887
|
+
import * as path52 from "path";
|
|
21846
21888
|
function isMutatingPostflight(scriptName) {
|
|
21847
21889
|
return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
|
|
21848
21890
|
}
|
|
@@ -22099,7 +22141,7 @@ async function runImplementation(profileName, input) {
|
|
|
22099
22141
|
const reason = input.abortController.signal.reason;
|
|
22100
22142
|
throw reason instanceof Error ? reason : new Error("agent invocation aborted");
|
|
22101
22143
|
}
|
|
22102
|
-
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) =>
|
|
22144
|
+
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path52.isAbsolute(p) ? p : path52.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
22103
22145
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
22104
22146
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
22105
22147
|
const agents = loadSubagents(profile);
|
|
@@ -22138,6 +22180,7 @@ async function runImplementation(profileName, input) {
|
|
|
22138
22180
|
verbose: input.verbose,
|
|
22139
22181
|
quiet: input.quiet,
|
|
22140
22182
|
abortController: input.abortController,
|
|
22183
|
+
deadlineAtMs: input.deadlineAtMs,
|
|
22141
22184
|
ndjsonDir,
|
|
22142
22185
|
additionalDirectories: agentTaskArtifacts ? [agentTaskArtifacts.absDir] : void 0,
|
|
22143
22186
|
allowedToolsOverride: profile.claudeCode.tools,
|
|
@@ -22580,13 +22623,13 @@ function clearStampedLifecycleLabels(profile, ctx) {
|
|
|
22580
22623
|
function resolveProfilePath(profileName, cwd = process.cwd()) {
|
|
22581
22624
|
const found = resolveImplementation(profileName, getRuntimeProfileRootsForCwd(cwd));
|
|
22582
22625
|
if (found) return found;
|
|
22583
|
-
const here =
|
|
22626
|
+
const here = path52.dirname(new URL(import.meta.url).pathname);
|
|
22584
22627
|
const candidates = [
|
|
22585
|
-
|
|
22628
|
+
path52.join(here, "implementations", profileName, "profile.json"),
|
|
22586
22629
|
// same-dir sibling (dev)
|
|
22587
|
-
|
|
22630
|
+
path52.join(here, "..", "implementations", profileName, "profile.json"),
|
|
22588
22631
|
// up one (prod: dist/bin → dist/implementations)
|
|
22589
|
-
|
|
22632
|
+
path52.join(here, "..", "src", "implementations", profileName, "profile.json")
|
|
22590
22633
|
// fallback
|
|
22591
22634
|
];
|
|
22592
22635
|
for (const c of candidates) {
|
|
@@ -22705,7 +22748,7 @@ function resolveShellTimeoutMs(entry) {
|
|
|
22705
22748
|
}
|
|
22706
22749
|
async function runShellEntry(entry, ctx, profile) {
|
|
22707
22750
|
const shellName = entry.shell;
|
|
22708
|
-
const shellPath =
|
|
22751
|
+
const shellPath = path52.join(profile.dir, shellName);
|
|
22709
22752
|
if (!fs54.existsSync(shellPath)) {
|
|
22710
22753
|
ctx.skipAgent = true;
|
|
22711
22754
|
ctx.output.exitCode = 99;
|
|
@@ -22713,7 +22756,7 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
22713
22756
|
return;
|
|
22714
22757
|
}
|
|
22715
22758
|
const positional = entry.with ? Object.values(entry.with).map((v) => String(v)) : [];
|
|
22716
|
-
const outputFile =
|
|
22759
|
+
const outputFile = path52.join(
|
|
22717
22760
|
os8.tmpdir(),
|
|
22718
22761
|
`kody-shell-output-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
22719
22762
|
);
|
|
@@ -22743,14 +22786,14 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
22743
22786
|
let killTimer;
|
|
22744
22787
|
let escalateTimer;
|
|
22745
22788
|
const result = await new Promise(
|
|
22746
|
-
(
|
|
22789
|
+
(resolve24) => {
|
|
22747
22790
|
let settled = false;
|
|
22748
22791
|
const settle = (code, signal, spawnErr) => {
|
|
22749
22792
|
if (settled) return;
|
|
22750
22793
|
settled = true;
|
|
22751
22794
|
if (killTimer) clearTimeout(killTimer);
|
|
22752
22795
|
if (escalateTimer) clearTimeout(escalateTimer);
|
|
22753
|
-
|
|
22796
|
+
resolve24({ code, signal, spawnErr });
|
|
22754
22797
|
};
|
|
22755
22798
|
child.on("error", (err) => settle(null, null, err));
|
|
22756
22799
|
child.on("close", (code, signal) => settle(code, signal));
|
|
@@ -23324,6 +23367,7 @@ async function runCapabilityImplementationStep(valid, profileName, capabilityIde
|
|
|
23324
23367
|
verbose: base.verbose,
|
|
23325
23368
|
quiet: base.quiet,
|
|
23326
23369
|
abortController: base.abortController,
|
|
23370
|
+
deadlineAtMs: base.deadlineAtMs,
|
|
23327
23371
|
preloadedData: Object.keys(preloadedData).length > 0 ? preloadedData : void 0
|
|
23328
23372
|
};
|
|
23329
23373
|
const shouldApplyResolvedCapabilityArgs = valid.implementation === void 0 && resolvedCapability && profileName === resolvedCapability.implementation;
|
|
@@ -23637,6 +23681,7 @@ async function runGraphCapabilityWorkflow(parent, workflow, capability, base, ch
|
|
|
23637
23681
|
result = await runJob(child, {
|
|
23638
23682
|
...base,
|
|
23639
23683
|
abortController: stepAbort.controller,
|
|
23684
|
+
deadlineAtMs: stepAbort.deadlineAtMs,
|
|
23640
23685
|
preloadedData: {
|
|
23641
23686
|
...chainData,
|
|
23642
23687
|
runSubjectType: "capability",
|
|
@@ -23793,11 +23838,11 @@ function exhaustedWorkflowTransitions(step, data, counts) {
|
|
|
23793
23838
|
}
|
|
23794
23839
|
function workflowResultConditionPaths(transitions) {
|
|
23795
23840
|
return transitions.flatMap(
|
|
23796
|
-
(transition) => Object.keys(transition.when ?? {}).filter((
|
|
23841
|
+
(transition) => Object.keys(transition.when ?? {}).filter((path59) => path59.startsWith("result."))
|
|
23797
23842
|
);
|
|
23798
23843
|
}
|
|
23799
23844
|
function conditionMatches(condition, context) {
|
|
23800
|
-
return Object.entries(condition).every(([
|
|
23845
|
+
return Object.entries(condition).every(([path59, expected]) => valueMatches(resolveDottedPath2(context, path59), expected));
|
|
23801
23846
|
}
|
|
23802
23847
|
function withWorkflowBoundaryEval(capability, result) {
|
|
23803
23848
|
const capabilityKind = capability.config.capabilityKind;
|
|
@@ -23966,8 +24011,9 @@ function canContinueWorkflow(step, outcome) {
|
|
|
23966
24011
|
return step.continueOn.includes(outcome.type);
|
|
23967
24012
|
}
|
|
23968
24013
|
function workflowStepAbortController(parent, timeoutSeconds) {
|
|
23969
|
-
if (!timeoutSeconds) return { controller: parent, cleanup: () => void 0 };
|
|
24014
|
+
if (!timeoutSeconds) return { controller: parent, deadlineAtMs: void 0, cleanup: () => void 0 };
|
|
23970
24015
|
const controller = new AbortController();
|
|
24016
|
+
const deadlineAtMs = Date.now() + timeoutSeconds * 1e3;
|
|
23971
24017
|
const forwardParentAbort = () => controller.abort(parent?.signal.reason);
|
|
23972
24018
|
if (parent?.signal.aborted) forwardParentAbort();
|
|
23973
24019
|
else parent?.signal.addEventListener("abort", forwardParentAbort, { once: true });
|
|
@@ -23977,6 +24023,7 @@ function workflowStepAbortController(parent, timeoutSeconds) {
|
|
|
23977
24023
|
timer.unref?.();
|
|
23978
24024
|
return {
|
|
23979
24025
|
controller,
|
|
24026
|
+
deadlineAtMs,
|
|
23980
24027
|
cleanup: () => {
|
|
23981
24028
|
clearTimeout(timer);
|
|
23982
24029
|
parent?.signal.removeEventListener("abort", forwardParentAbort);
|
|
@@ -24270,7 +24317,7 @@ function translateOpenAISseToBrain(opts) {
|
|
|
24270
24317
|
|
|
24271
24318
|
// src/servers/brain-serve.ts
|
|
24272
24319
|
import { createServer as createServer2 } from "http";
|
|
24273
|
-
import * as
|
|
24320
|
+
import * as path55 from "path";
|
|
24274
24321
|
|
|
24275
24322
|
// src/chat/loop.ts
|
|
24276
24323
|
init_agent();
|
|
@@ -24279,12 +24326,12 @@ init_config();
|
|
|
24279
24326
|
init_registry();
|
|
24280
24327
|
init_task_artifacts();
|
|
24281
24328
|
import * as fs18 from "fs";
|
|
24282
|
-
import * as
|
|
24329
|
+
import * as path20 from "path";
|
|
24283
24330
|
|
|
24284
24331
|
// src/chat/attachments.ts
|
|
24285
24332
|
init_runtimePaths();
|
|
24286
24333
|
import * as fs15 from "fs";
|
|
24287
|
-
import * as
|
|
24334
|
+
import * as path17 from "path";
|
|
24288
24335
|
var INLINE_ATTACHMENT_RE = /(?:\[(?:Image|File): ([^\]]*)\]\n)?data:([\w.+-]+\/[\w.+-]+);base64,([A-Za-z0-9+/=]+)/g;
|
|
24289
24336
|
var EXT_BY_MIME = {
|
|
24290
24337
|
"image/png": "png",
|
|
@@ -24320,7 +24367,7 @@ function prepareAttachments(turns, cwd, sessionId) {
|
|
|
24320
24367
|
fs15.mkdirSync(dir, { recursive: true });
|
|
24321
24368
|
dirEnsured = true;
|
|
24322
24369
|
}
|
|
24323
|
-
const filePath =
|
|
24370
|
+
const filePath = path17.join(dir, `${imageCounter}.${extFor(mime)}`);
|
|
24324
24371
|
fs15.writeFileSync(filePath, Buffer.from(data, "base64"));
|
|
24325
24372
|
imageCounter += 1;
|
|
24326
24373
|
imagePaths.push(filePath);
|
|
@@ -24339,7 +24386,7 @@ function prepareAttachments(turns, cwd, sessionId) {
|
|
|
24339
24386
|
// src/chat/codex-app-server.ts
|
|
24340
24387
|
import { spawn as spawn3 } from "child_process";
|
|
24341
24388
|
import * as fs16 from "fs";
|
|
24342
|
-
import * as
|
|
24389
|
+
import * as path18 from "path";
|
|
24343
24390
|
import { createInterface } from "readline";
|
|
24344
24391
|
function codexThreadStartParams(args) {
|
|
24345
24392
|
return {
|
|
@@ -24424,9 +24471,9 @@ var CodexAppServerClient = class {
|
|
|
24424
24471
|
await this.request("thread/resume", { threadId });
|
|
24425
24472
|
}
|
|
24426
24473
|
async runTurn(args) {
|
|
24427
|
-
await new Promise((
|
|
24474
|
+
await new Promise((resolve24, reject) => {
|
|
24428
24475
|
this.process.turnWaiters.set(args.threadId, {
|
|
24429
|
-
resolve:
|
|
24476
|
+
resolve: resolve24,
|
|
24430
24477
|
reject,
|
|
24431
24478
|
onNotification: args.onNotification,
|
|
24432
24479
|
queue: Promise.resolve()
|
|
@@ -24443,8 +24490,8 @@ var CodexAppServerClient = class {
|
|
|
24443
24490
|
}
|
|
24444
24491
|
request(method, params) {
|
|
24445
24492
|
const id = this.process.nextId++;
|
|
24446
|
-
return new Promise((
|
|
24447
|
-
this.process.pending.set(id, { resolve:
|
|
24493
|
+
return new Promise((resolve24, reject) => {
|
|
24494
|
+
this.process.pending.set(id, { resolve: resolve24, reject });
|
|
24448
24495
|
this.process.child.stdin.write(`${JSON.stringify({ method, id, params })}
|
|
24449
24496
|
`);
|
|
24450
24497
|
});
|
|
@@ -24510,7 +24557,7 @@ var CodexAppServerClient = class {
|
|
|
24510
24557
|
};
|
|
24511
24558
|
var clients = /* @__PURE__ */ new Map();
|
|
24512
24559
|
function threadMapPath(cwd) {
|
|
24513
|
-
return
|
|
24560
|
+
return path18.join(cwd, ".kody-engine", "runtime", "codex-threads.json");
|
|
24514
24561
|
}
|
|
24515
24562
|
function readThreadMap(cwd) {
|
|
24516
24563
|
try {
|
|
@@ -24527,7 +24574,7 @@ function readThreadMap(cwd) {
|
|
|
24527
24574
|
}
|
|
24528
24575
|
function writeThreadMap(cwd, map) {
|
|
24529
24576
|
const file = threadMapPath(cwd);
|
|
24530
|
-
fs16.mkdirSync(
|
|
24577
|
+
fs16.mkdirSync(path18.dirname(file), { recursive: true });
|
|
24531
24578
|
fs16.writeFileSync(file, `${JSON.stringify(map, null, 2)}
|
|
24532
24579
|
`);
|
|
24533
24580
|
}
|
|
@@ -24619,7 +24666,7 @@ async function runCodexChatTurn(args) {
|
|
|
24619
24666
|
|
|
24620
24667
|
// src/chat/events.ts
|
|
24621
24668
|
import * as fs17 from "fs";
|
|
24622
|
-
import * as
|
|
24669
|
+
import * as path19 from "path";
|
|
24623
24670
|
import posixPath2 from "path/posix";
|
|
24624
24671
|
var BackendEventSink = class {
|
|
24625
24672
|
constructor(append, tenantId2, sessionId) {
|
|
@@ -24635,7 +24682,7 @@ var BackendEventSink = class {
|
|
|
24635
24682
|
}
|
|
24636
24683
|
};
|
|
24637
24684
|
function eventsFilePath(cwd, sessionId) {
|
|
24638
|
-
return
|
|
24685
|
+
return path19.join(cwd, ".kody-engine", "runtime", "events", `${sessionId}.jsonl`);
|
|
24639
24686
|
}
|
|
24640
24687
|
var FileSink = class {
|
|
24641
24688
|
constructor(file) {
|
|
@@ -24643,7 +24690,7 @@ var FileSink = class {
|
|
|
24643
24690
|
}
|
|
24644
24691
|
file;
|
|
24645
24692
|
async emit(event) {
|
|
24646
|
-
fs17.mkdirSync(
|
|
24693
|
+
fs17.mkdirSync(path19.dirname(this.file), { recursive: true });
|
|
24647
24694
|
fs17.appendFileSync(this.file, `${JSON.stringify(event)}
|
|
24648
24695
|
`);
|
|
24649
24696
|
}
|
|
@@ -25031,7 +25078,7 @@ async function runChatTurn(opts) {
|
|
|
25031
25078
|
quiet: opts.quiet,
|
|
25032
25079
|
additionalDirectories: [
|
|
25033
25080
|
taskArtifactsPaths.absDir,
|
|
25034
|
-
...Array.from(new Set(imagePaths.map((p2) =>
|
|
25081
|
+
...Array.from(new Set(imagePaths.map((p2) => path20.dirname(p2))))
|
|
25035
25082
|
],
|
|
25036
25083
|
systemPromptAppend: systemPrompt,
|
|
25037
25084
|
...opts.reasoningEffort ? { reasoningEffort: opts.reasoningEffort } : {},
|
|
@@ -25219,7 +25266,7 @@ async function emit(sink, type, sessionId, suffix, payload) {
|
|
|
25219
25266
|
var MEMORY_INDEX_REL = ".kody-engine/runtime/memory/INDEX.md";
|
|
25220
25267
|
var MAX_INDEX_BYTES = 8e3;
|
|
25221
25268
|
function readMemoryIndexBlock(cwd) {
|
|
25222
|
-
const indexPath =
|
|
25269
|
+
const indexPath = path20.join(cwd, MEMORY_INDEX_REL);
|
|
25223
25270
|
let raw;
|
|
25224
25271
|
try {
|
|
25225
25272
|
raw = fs18.readFileSync(indexPath, "utf-8");
|
|
@@ -25242,7 +25289,7 @@ _\u2026 (memory index truncated; use recall_search to read more)_` : trimmed;
|
|
|
25242
25289
|
var CONTEXT_DIR_REL = ".kody-engine/runtime/context";
|
|
25243
25290
|
var MAX_CONTEXT_BYTES = 12e3;
|
|
25244
25291
|
function readContextBlock(cwd) {
|
|
25245
|
-
const dir =
|
|
25292
|
+
const dir = path20.join(cwd, CONTEXT_DIR_REL);
|
|
25246
25293
|
let files;
|
|
25247
25294
|
try {
|
|
25248
25295
|
files = fs18.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
@@ -25252,7 +25299,7 @@ function readContextBlock(cwd) {
|
|
|
25252
25299
|
const sections = [];
|
|
25253
25300
|
for (const file of files) {
|
|
25254
25301
|
try {
|
|
25255
|
-
const content = fs18.readFileSync(
|
|
25302
|
+
const content = fs18.readFileSync(path20.join(dir, file), "utf-8").trim();
|
|
25256
25303
|
if (content) sections.push(`### ${file.replace(/\.md$/, "")}
|
|
25257
25304
|
|
|
25258
25305
|
${content}`);
|
|
@@ -25278,7 +25325,7 @@ var SYSTEM_PROMPT_OVERRIDE_REL = ".kody-engine/runtime/system-prompt.md";
|
|
|
25278
25325
|
function readSystemPromptOverride(cwd) {
|
|
25279
25326
|
let raw;
|
|
25280
25327
|
try {
|
|
25281
|
-
raw = fs18.readFileSync(
|
|
25328
|
+
raw = fs18.readFileSync(path20.join(cwd, SYSTEM_PROMPT_OVERRIDE_REL), "utf-8");
|
|
25282
25329
|
} catch {
|
|
25283
25330
|
return null;
|
|
25284
25331
|
}
|
|
@@ -25286,7 +25333,7 @@ function readSystemPromptOverride(cwd) {
|
|
|
25286
25333
|
return trimmed.length > 0 ? trimmed : null;
|
|
25287
25334
|
}
|
|
25288
25335
|
function readInstructionsBlock(cwd) {
|
|
25289
|
-
const instructionsPath =
|
|
25336
|
+
const instructionsPath = path20.join(cwd, INSTRUCTIONS_REL);
|
|
25290
25337
|
let raw;
|
|
25291
25338
|
try {
|
|
25292
25339
|
raw = fs18.readFileSync(instructionsPath, "utf-8");
|
|
@@ -25324,10 +25371,10 @@ function resolveBrainDriver(runtime) {
|
|
|
25324
25371
|
|
|
25325
25372
|
// src/chat/session.ts
|
|
25326
25373
|
import * as fs19 from "fs";
|
|
25327
|
-
import * as
|
|
25374
|
+
import * as path21 from "path";
|
|
25328
25375
|
import posixPath3 from "path/posix";
|
|
25329
25376
|
function sessionFilePath(cwd, sessionId) {
|
|
25330
|
-
return
|
|
25377
|
+
return path21.join(cwd, ".kody-engine", "runtime", "sessions", `${sessionId}.jsonl`);
|
|
25331
25378
|
}
|
|
25332
25379
|
function readSession(file) {
|
|
25333
25380
|
if (!fs19.existsSync(file)) return [];
|
|
@@ -25355,7 +25402,7 @@ init_state_backend();
|
|
|
25355
25402
|
init_workflowDefinitions();
|
|
25356
25403
|
import { createHash as createHash2 } from "crypto";
|
|
25357
25404
|
import * as fs21 from "fs";
|
|
25358
|
-
import * as
|
|
25405
|
+
import * as path23 from "path";
|
|
25359
25406
|
var SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,127}$/;
|
|
25360
25407
|
var REPOSITORY_OWNED_NAMESPACES = ["loops"];
|
|
25361
25408
|
function assertSafeDefinitionPath(filePath) {
|
|
@@ -25387,8 +25434,8 @@ function verifyDefinition(definition) {
|
|
|
25387
25434
|
}
|
|
25388
25435
|
function writeBundle(root, bundle) {
|
|
25389
25436
|
for (const [filePath, contents] of Object.entries(bundle.files)) {
|
|
25390
|
-
const target =
|
|
25391
|
-
fs21.mkdirSync(
|
|
25437
|
+
const target = path23.join(root, filePath);
|
|
25438
|
+
fs21.mkdirSync(path23.dirname(target), { recursive: true });
|
|
25392
25439
|
fs21.writeFileSync(target, contents, "utf8");
|
|
25393
25440
|
}
|
|
25394
25441
|
}
|
|
@@ -25397,22 +25444,22 @@ function writeDefinition(root, kind, definition) {
|
|
|
25397
25444
|
if (kind === "agent") {
|
|
25398
25445
|
const raw = bundle.files["agent.md"];
|
|
25399
25446
|
if (typeof raw !== "string") throw new Error(`agent definition ${definition.slug} is missing agent.md`);
|
|
25400
|
-
fs21.writeFileSync(
|
|
25447
|
+
fs21.writeFileSync(path23.join(root, "agents", `${definition.slug}.md`), raw, "utf8");
|
|
25401
25448
|
return;
|
|
25402
25449
|
}
|
|
25403
25450
|
if (kind === "goal") {
|
|
25404
|
-
writeBundle(
|
|
25451
|
+
writeBundle(path23.join(root, "goals", definition.slug), bundle);
|
|
25405
25452
|
return;
|
|
25406
25453
|
}
|
|
25407
25454
|
if (kind === "implementation") {
|
|
25408
|
-
writeBundle(
|
|
25455
|
+
writeBundle(path23.join(root, "implementations", definition.slug), bundle);
|
|
25409
25456
|
return;
|
|
25410
25457
|
}
|
|
25411
25458
|
if (kind === "asset") {
|
|
25412
|
-
writeBundle(
|
|
25459
|
+
writeBundle(path23.join(root, "shared"), bundle);
|
|
25413
25460
|
return;
|
|
25414
25461
|
}
|
|
25415
|
-
writeBundle(
|
|
25462
|
+
writeBundle(path23.join(root, "capabilities", definition.slug), bundle);
|
|
25416
25463
|
}
|
|
25417
25464
|
function writeWorkflow(root, document) {
|
|
25418
25465
|
const workflow = normalizeWorkflowDefinition(document.definition);
|
|
@@ -25420,28 +25467,28 @@ function writeWorkflow(root, document) {
|
|
|
25420
25467
|
const contents = `${JSON.stringify(workflow, null, 2)}
|
|
25421
25468
|
`;
|
|
25422
25469
|
const bundle = { schemaVersion: 1, files: { "workflow.json": contents } };
|
|
25423
|
-
const target =
|
|
25424
|
-
fs21.mkdirSync(
|
|
25470
|
+
const target = path23.join(root, workflowDefinitionPath(document.workflowId));
|
|
25471
|
+
fs21.mkdirSync(path23.dirname(target), { recursive: true });
|
|
25425
25472
|
fs21.writeFileSync(target, contents, "utf8");
|
|
25426
25473
|
return definitionVersion(bundle);
|
|
25427
25474
|
}
|
|
25428
25475
|
function preserveRepositoryDefinitions(root, staging) {
|
|
25429
25476
|
for (const namespace of REPOSITORY_OWNED_NAMESPACES) {
|
|
25430
|
-
const source =
|
|
25477
|
+
const source = path23.join(root, namespace);
|
|
25431
25478
|
if (!fs21.existsSync(source)) continue;
|
|
25432
|
-
fs21.cpSync(source,
|
|
25479
|
+
fs21.cpSync(source, path23.join(staging, namespace), { recursive: true });
|
|
25433
25480
|
}
|
|
25434
25481
|
}
|
|
25435
25482
|
async function hydrateDefinitions(options) {
|
|
25436
|
-
const root =
|
|
25483
|
+
const root = path23.join(options.cwd, ".kody-engine", "definitions");
|
|
25437
25484
|
const staging = `${root}.tmp-${process.pid}-${Date.now()}`;
|
|
25438
25485
|
fs21.rmSync(staging, { recursive: true, force: true });
|
|
25439
|
-
fs21.mkdirSync(
|
|
25440
|
-
fs21.mkdirSync(
|
|
25441
|
-
fs21.mkdirSync(
|
|
25442
|
-
fs21.mkdirSync(
|
|
25443
|
-
fs21.mkdirSync(
|
|
25444
|
-
fs21.mkdirSync(
|
|
25486
|
+
fs21.mkdirSync(path23.join(staging, "agents"), { recursive: true });
|
|
25487
|
+
fs21.mkdirSync(path23.join(staging, "capabilities"), { recursive: true });
|
|
25488
|
+
fs21.mkdirSync(path23.join(staging, "goals"), { recursive: true });
|
|
25489
|
+
fs21.mkdirSync(path23.join(staging, "implementations"), { recursive: true });
|
|
25490
|
+
fs21.mkdirSync(path23.join(staging, "shared"), { recursive: true });
|
|
25491
|
+
fs21.mkdirSync(path23.join(staging, "workflows"), { recursive: true });
|
|
25445
25492
|
try {
|
|
25446
25493
|
const [capabilities, agents, goals, implementations, assets, workflows] = await Promise.all([
|
|
25447
25494
|
options.backend.listDefinitions(options.tenantId, "capability"),
|
|
@@ -25482,7 +25529,7 @@ async function hydrateDefinitions(options) {
|
|
|
25482
25529
|
hydratedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25483
25530
|
versions: Object.fromEntries(Object.entries(versions).sort(([left], [right]) => left.localeCompare(right)))
|
|
25484
25531
|
};
|
|
25485
|
-
fs21.writeFileSync(
|
|
25532
|
+
fs21.writeFileSync(path23.join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
25486
25533
|
`, "utf8");
|
|
25487
25534
|
fs21.rmSync(root, { recursive: true, force: true });
|
|
25488
25535
|
fs21.renameSync(staging, root);
|
|
@@ -25511,7 +25558,7 @@ async function hydrateDefinitionsFromEnv(cwd = process.cwd(), env = process.env)
|
|
|
25511
25558
|
// src/kody-cli.ts
|
|
25512
25559
|
import { execFileSync as execFileSync24 } from "child_process";
|
|
25513
25560
|
import * as fs55 from "fs";
|
|
25514
|
-
import * as
|
|
25561
|
+
import * as path53 from "path";
|
|
25515
25562
|
|
|
25516
25563
|
// src/app-auth.ts
|
|
25517
25564
|
import { createSign } from "crypto";
|
|
@@ -26313,9 +26360,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
26313
26360
|
return void 0;
|
|
26314
26361
|
}
|
|
26315
26362
|
function detectPackageManager2(cwd) {
|
|
26316
|
-
if (fs55.existsSync(
|
|
26317
|
-
if (fs55.existsSync(
|
|
26318
|
-
if (fs55.existsSync(
|
|
26363
|
+
if (fs55.existsSync(path53.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
26364
|
+
if (fs55.existsSync(path53.join(cwd, "yarn.lock"))) return "yarn";
|
|
26365
|
+
if (fs55.existsSync(path53.join(cwd, "bun.lockb"))) return "bun";
|
|
26319
26366
|
return "npm";
|
|
26320
26367
|
}
|
|
26321
26368
|
function shouldChainScheduledWatch(match) {
|
|
@@ -26448,7 +26495,7 @@ async function runCi(argv) {
|
|
|
26448
26495
|
return 0;
|
|
26449
26496
|
}
|
|
26450
26497
|
const args = parseCiArgs(argv);
|
|
26451
|
-
const cwd = args.cwd ?
|
|
26498
|
+
const cwd = args.cwd ? path53.resolve(args.cwd) : process.cwd();
|
|
26452
26499
|
try {
|
|
26453
26500
|
const n = unpackAllSecrets();
|
|
26454
26501
|
if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s) from ALL_SECRETS
|
|
@@ -26932,7 +26979,7 @@ init_repoWorkspace();
|
|
|
26932
26979
|
// src/scripts/brainTurnLog.ts
|
|
26933
26980
|
init_runtimePaths();
|
|
26934
26981
|
import * as fs56 from "fs";
|
|
26935
|
-
import * as
|
|
26982
|
+
import * as path54 from "path";
|
|
26936
26983
|
import posixPath4 from "path/posix";
|
|
26937
26984
|
var live = /* @__PURE__ */ new Map();
|
|
26938
26985
|
function brainEventsFilePath(dir, chatId) {
|
|
@@ -26979,7 +27026,7 @@ function beginTurn(dir, chatId) {
|
|
|
26979
27026
|
};
|
|
26980
27027
|
live.set(chatId, state);
|
|
26981
27028
|
const p = brainEventsFilePath(dir, chatId);
|
|
26982
|
-
fs56.mkdirSync(
|
|
27029
|
+
fs56.mkdirSync(path54.dirname(p), { recursive: true });
|
|
26983
27030
|
return (event) => {
|
|
26984
27031
|
state.seq += 1;
|
|
26985
27032
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
@@ -27117,17 +27164,17 @@ function authOk(req, expected) {
|
|
|
27117
27164
|
return false;
|
|
27118
27165
|
}
|
|
27119
27166
|
function readJsonBody(req) {
|
|
27120
|
-
return new Promise((
|
|
27167
|
+
return new Promise((resolve24, reject) => {
|
|
27121
27168
|
const chunks = [];
|
|
27122
27169
|
req.on("data", (c) => chunks.push(c));
|
|
27123
27170
|
req.on("end", () => {
|
|
27124
27171
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
27125
27172
|
if (!raw.trim()) {
|
|
27126
|
-
|
|
27173
|
+
resolve24({});
|
|
27127
27174
|
return;
|
|
27128
27175
|
}
|
|
27129
27176
|
try {
|
|
27130
|
-
|
|
27177
|
+
resolve24(JSON.parse(raw));
|
|
27131
27178
|
} catch (err) {
|
|
27132
27179
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
27133
27180
|
}
|
|
@@ -27419,7 +27466,7 @@ function buildServer(opts) {
|
|
|
27419
27466
|
const runTurn = opts.runTurn ?? runChatTurn;
|
|
27420
27467
|
const createStore = opts.createStore ?? createSessionStore;
|
|
27421
27468
|
const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
|
|
27422
|
-
const reposRoot = opts.reposRoot ??
|
|
27469
|
+
const reposRoot = opts.reposRoot ?? path55.join(path55.dirname(path55.resolve(opts.cwd)), "repos");
|
|
27423
27470
|
return createServer2(async (req, res) => {
|
|
27424
27471
|
if (!req.method || !req.url) {
|
|
27425
27472
|
sendJson(res, 400, { error: "bad request" });
|
|
@@ -27500,11 +27547,11 @@ async function brainServe(opts) {
|
|
|
27500
27547
|
litellmUrl,
|
|
27501
27548
|
driver
|
|
27502
27549
|
});
|
|
27503
|
-
await new Promise((
|
|
27550
|
+
await new Promise((resolve24) => {
|
|
27504
27551
|
server.listen(port, "0.0.0.0", () => {
|
|
27505
27552
|
process.stdout.write(`[brain-serve] listening on 0.0.0.0:${port} (cwd=${opts.cwd})
|
|
27506
27553
|
`);
|
|
27507
|
-
|
|
27554
|
+
resolve24();
|
|
27508
27555
|
});
|
|
27509
27556
|
});
|
|
27510
27557
|
const shutdown = (signal) => {
|
|
@@ -27759,14 +27806,14 @@ async function startBrainProxy(opts) {
|
|
|
27759
27806
|
const { httpServer, handler } = buildBrainProxy(opts);
|
|
27760
27807
|
const port = opts.port ?? 0;
|
|
27761
27808
|
const host = opts.host ?? "127.0.0.1";
|
|
27762
|
-
await new Promise((
|
|
27809
|
+
await new Promise((resolve24) => httpServer.listen(port, host, () => resolve24()));
|
|
27763
27810
|
const addr = httpServer.address();
|
|
27764
27811
|
return {
|
|
27765
27812
|
httpServer,
|
|
27766
27813
|
port: addr.port,
|
|
27767
27814
|
url: `http://${host}:${addr.port}`,
|
|
27768
|
-
stop: () => new Promise((
|
|
27769
|
-
httpServer.close(() =>
|
|
27815
|
+
stop: () => new Promise((resolve24) => {
|
|
27816
|
+
httpServer.close(() => resolve24());
|
|
27770
27817
|
}),
|
|
27771
27818
|
handler
|
|
27772
27819
|
};
|
|
@@ -27916,23 +27963,23 @@ function buildMcpHttpServer(opts) {
|
|
|
27916
27963
|
httpServer,
|
|
27917
27964
|
routes,
|
|
27918
27965
|
port,
|
|
27919
|
-
stop: () => new Promise((
|
|
27966
|
+
stop: () => new Promise((resolve24) => {
|
|
27920
27967
|
let pending = transports.size;
|
|
27921
27968
|
if (pending === 0) {
|
|
27922
|
-
httpServer.close(() =>
|
|
27969
|
+
httpServer.close(() => resolve24());
|
|
27923
27970
|
return;
|
|
27924
27971
|
}
|
|
27925
27972
|
for (const transport of transports.values()) {
|
|
27926
27973
|
void transport.close().finally(() => {
|
|
27927
27974
|
pending--;
|
|
27928
|
-
if (pending === 0) httpServer.close(() =>
|
|
27975
|
+
if (pending === 0) httpServer.close(() => resolve24());
|
|
27929
27976
|
});
|
|
27930
27977
|
}
|
|
27931
27978
|
})
|
|
27932
27979
|
};
|
|
27933
27980
|
}
|
|
27934
27981
|
function listenMcpHttpServer(server, host = "127.0.0.1") {
|
|
27935
|
-
return new Promise((
|
|
27982
|
+
return new Promise((resolve24, reject) => {
|
|
27936
27983
|
server.httpServer.once("error", reject);
|
|
27937
27984
|
server.httpServer.listen(server.port, host, () => {
|
|
27938
27985
|
server.httpServer.off("error", reject);
|
|
@@ -27940,7 +27987,7 @@ function listenMcpHttpServer(server, host = "127.0.0.1") {
|
|
|
27940
27987
|
if (addr && typeof addr === "object") {
|
|
27941
27988
|
server.port = addr.port;
|
|
27942
27989
|
}
|
|
27943
|
-
|
|
27990
|
+
resolve24();
|
|
27944
27991
|
});
|
|
27945
27992
|
});
|
|
27946
27993
|
}
|
|
@@ -28023,7 +28070,7 @@ async function loadConfigSafe() {
|
|
|
28023
28070
|
}
|
|
28024
28071
|
|
|
28025
28072
|
// src/chat-cli.ts
|
|
28026
|
-
import * as
|
|
28073
|
+
import * as path56 from "path";
|
|
28027
28074
|
|
|
28028
28075
|
// src/chat/inbox.ts
|
|
28029
28076
|
import { execFileSync as execFileSync25 } from "child_process";
|
|
@@ -28090,7 +28137,7 @@ async function waitForNextUserMessage(opts) {
|
|
|
28090
28137
|
}
|
|
28091
28138
|
}
|
|
28092
28139
|
function sleep3(ms) {
|
|
28093
|
-
return new Promise((
|
|
28140
|
+
return new Promise((resolve24) => setTimeout(resolve24, ms));
|
|
28094
28141
|
}
|
|
28095
28142
|
function currentBranch(cwd) {
|
|
28096
28143
|
try {
|
|
@@ -28314,7 +28361,7 @@ async function runChat(argv) {
|
|
|
28314
28361
|
${CHAT_HELP}`);
|
|
28315
28362
|
return 64;
|
|
28316
28363
|
}
|
|
28317
|
-
const cwd = args.cwd ?
|
|
28364
|
+
const cwd = args.cwd ? path56.resolve(args.cwd) : process.cwd();
|
|
28318
28365
|
const sessionId = args.sessionId;
|
|
28319
28366
|
const runRequest = readRunRequestFromEnv();
|
|
28320
28367
|
if (runRequest && "request" in runRequest) {
|
|
@@ -28441,7 +28488,7 @@ init_registry();
|
|
|
28441
28488
|
|
|
28442
28489
|
// src/servers/brain-terminal-agent.ts
|
|
28443
28490
|
init_repoWorkspace();
|
|
28444
|
-
import * as
|
|
28491
|
+
import * as path58 from "path";
|
|
28445
28492
|
import { createInterface as createInterface2 } from "readline";
|
|
28446
28493
|
|
|
28447
28494
|
// src/terminal/brain-terminal-session.ts
|
|
@@ -28755,10 +28802,10 @@ var BrainTerminalSessionAgent = class {
|
|
|
28755
28802
|
// src/terminal/brain-terminal-adapters.ts
|
|
28756
28803
|
import { createHash as createHash10, randomBytes as randomBytes2 } from "crypto";
|
|
28757
28804
|
import { mkdir, readFile, rename, writeFile as writeFile2 } from "fs/promises";
|
|
28758
|
-
import * as
|
|
28805
|
+
import * as path57 from "path";
|
|
28759
28806
|
import { spawn as spawn9 } from "child_process";
|
|
28760
28807
|
function runTerminalCommand(command, args, input) {
|
|
28761
|
-
return new Promise((
|
|
28808
|
+
return new Promise((resolve24, reject) => {
|
|
28762
28809
|
const child = spawn9(command, args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
28763
28810
|
const stdout = [];
|
|
28764
28811
|
const stderr = [];
|
|
@@ -28766,7 +28813,7 @@ function runTerminalCommand(command, args, input) {
|
|
|
28766
28813
|
child.stderr.on("data", (chunk) => stderr.push(chunk));
|
|
28767
28814
|
child.on("error", reject);
|
|
28768
28815
|
child.on("close", (code) => {
|
|
28769
|
-
|
|
28816
|
+
resolve24({
|
|
28770
28817
|
code: code ?? 1,
|
|
28771
28818
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
28772
28819
|
stderr: Buffer.concat(stderr).toString("utf8")
|
|
@@ -28790,7 +28837,7 @@ var FileBrainTerminalMetadataStore = class {
|
|
|
28790
28837
|
}
|
|
28791
28838
|
root;
|
|
28792
28839
|
file(id) {
|
|
28793
|
-
return
|
|
28840
|
+
return path57.join(this.root, `${storeKey(id)}.json`);
|
|
28794
28841
|
}
|
|
28795
28842
|
async read(id) {
|
|
28796
28843
|
try {
|
|
@@ -28911,8 +28958,8 @@ async function brainTerminalAgent(options) {
|
|
|
28911
28958
|
const input = options.input ?? process.stdin;
|
|
28912
28959
|
const output = options.output ?? process.stdout;
|
|
28913
28960
|
const error = options.error ?? process.stderr;
|
|
28914
|
-
const reposRoot = process.env.BRAIN_REPOS_ROOT?.trim() ||
|
|
28915
|
-
const stateRoot = process.env.BRAIN_TERMINAL_STATE_ROOT?.trim() ||
|
|
28961
|
+
const reposRoot = process.env.BRAIN_REPOS_ROOT?.trim() || path58.join(path58.dirname(path58.resolve(options.cwd)), "repos");
|
|
28962
|
+
const stateRoot = process.env.BRAIN_TERMINAL_STATE_ROOT?.trim() || path58.join(path58.dirname(reposRoot), ".kody", "terminal-sessions");
|
|
28916
28963
|
const agent = new BrainTerminalSessionAgent({
|
|
28917
28964
|
store: new FileBrainTerminalMetadataStore(stateRoot),
|
|
28918
28965
|
runtime: new TmuxBrainTerminalRuntime()
|
|
@@ -29079,8 +29126,8 @@ var FlyClient = class {
|
|
|
29079
29126
|
get fetch() {
|
|
29080
29127
|
return this.opts.fetchImpl ?? fetch;
|
|
29081
29128
|
}
|
|
29082
|
-
async call(
|
|
29083
|
-
const res = await this.fetch(`${FLY_API_BASE}${
|
|
29129
|
+
async call(path59, init = {}) {
|
|
29130
|
+
const res = await this.fetch(`${FLY_API_BASE}${path59}`, {
|
|
29084
29131
|
method: init.method ?? "GET",
|
|
29085
29132
|
headers: {
|
|
29086
29133
|
Authorization: `Bearer ${this.opts.token}`,
|
|
@@ -29091,7 +29138,7 @@ var FlyClient = class {
|
|
|
29091
29138
|
if (res.status === 404 && init.allow404) return null;
|
|
29092
29139
|
if (!res.ok) {
|
|
29093
29140
|
const text2 = await res.text().catch(() => "");
|
|
29094
|
-
throw new Error(`Fly API ${res.status} on ${
|
|
29141
|
+
throw new Error(`Fly API ${res.status} on ${path59}: ${text2.slice(0, 200) || res.statusText}`);
|
|
29095
29142
|
}
|
|
29096
29143
|
if (res.status === 204) return null;
|
|
29097
29144
|
const raw = await res.text();
|
|
@@ -29604,14 +29651,14 @@ function sendJson2(res, status, body) {
|
|
|
29604
29651
|
res.end(JSON.stringify(body));
|
|
29605
29652
|
}
|
|
29606
29653
|
function readJsonBody2(req) {
|
|
29607
|
-
return new Promise((
|
|
29654
|
+
return new Promise((resolve24, reject) => {
|
|
29608
29655
|
const chunks = [];
|
|
29609
29656
|
req.on("data", (c) => chunks.push(c));
|
|
29610
29657
|
req.on("end", () => {
|
|
29611
29658
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
29612
|
-
if (!raw.trim()) return
|
|
29659
|
+
if (!raw.trim()) return resolve24({});
|
|
29613
29660
|
try {
|
|
29614
|
-
|
|
29661
|
+
resolve24(JSON.parse(raw));
|
|
29615
29662
|
} catch (err) {
|
|
29616
29663
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
29617
29664
|
}
|
|
@@ -29765,10 +29812,10 @@ async function poolServe() {
|
|
|
29765
29812
|
}
|
|
29766
29813
|
});
|
|
29767
29814
|
const apiHost = process.env.POOL_API_HOST ?? "::";
|
|
29768
|
-
await new Promise((
|
|
29815
|
+
await new Promise((resolve24) => {
|
|
29769
29816
|
server.listen(apiPort, apiHost, () => {
|
|
29770
29817
|
log(`listening on ${apiHost}:${apiPort} (min=${min}, app=${app}, region=${region})`);
|
|
29771
|
-
|
|
29818
|
+
resolve24();
|
|
29772
29819
|
});
|
|
29773
29820
|
});
|
|
29774
29821
|
if (loopTickEnabled) void runLoopTick();
|
|
@@ -29808,17 +29855,17 @@ function authOk2(req, expected) {
|
|
|
29808
29855
|
return false;
|
|
29809
29856
|
}
|
|
29810
29857
|
function readJsonBody3(req) {
|
|
29811
|
-
return new Promise((
|
|
29858
|
+
return new Promise((resolve24, reject) => {
|
|
29812
29859
|
const chunks = [];
|
|
29813
29860
|
req.on("data", (c) => chunks.push(c));
|
|
29814
29861
|
req.on("end", () => {
|
|
29815
29862
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
29816
29863
|
if (!raw.trim()) {
|
|
29817
|
-
|
|
29864
|
+
resolve24({});
|
|
29818
29865
|
return;
|
|
29819
29866
|
}
|
|
29820
29867
|
try {
|
|
29821
|
-
|
|
29868
|
+
resolve24(JSON.parse(raw));
|
|
29822
29869
|
} catch (err) {
|
|
29823
29870
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
29824
29871
|
}
|
|
@@ -29893,13 +29940,13 @@ async function defaultRunJob(job) {
|
|
|
29893
29940
|
...interactive && job.idleExitMs ? { KODY_IDLE_EXIT_MS: String(job.idleExitMs) } : {},
|
|
29894
29941
|
...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
|
|
29895
29942
|
};
|
|
29896
|
-
const run = (cmd, args, cwd) => new Promise((
|
|
29943
|
+
const run = (cmd, args, cwd) => new Promise((resolve24) => {
|
|
29897
29944
|
const child = spawn10(cmd, args, { stdio: "inherit", env: childEnv, cwd });
|
|
29898
|
-
child.on("exit", (code) =>
|
|
29945
|
+
child.on("exit", (code) => resolve24(code ?? 0));
|
|
29899
29946
|
child.on("error", (err) => {
|
|
29900
29947
|
process.stderr.write(`[runner-serve] ${cmd} failed: ${err.message}
|
|
29901
29948
|
`);
|
|
29902
|
-
|
|
29949
|
+
resolve24(1);
|
|
29903
29950
|
});
|
|
29904
29951
|
});
|
|
29905
29952
|
process.stdout.write(`[runner-serve] job ${job.jobId}: cloning ${job.repo}@${branch}
|
|
@@ -29975,11 +30022,11 @@ async function runnerServe() {
|
|
|
29975
30022
|
const port = Number(process.env.PORT ?? DEFAULT_PORT2);
|
|
29976
30023
|
const server = buildServer2({ apiKey });
|
|
29977
30024
|
const host = process.env.RUNNER_HOST ?? "::";
|
|
29978
|
-
await new Promise((
|
|
30025
|
+
await new Promise((resolve24) => {
|
|
29979
30026
|
server.listen(port, host, () => {
|
|
29980
30027
|
process.stdout.write(`[runner-serve] listening on ${host}:${port} (idle, awaiting job)
|
|
29981
30028
|
`);
|
|
29982
|
-
|
|
30029
|
+
resolve24();
|
|
29983
30030
|
});
|
|
29984
30031
|
});
|
|
29985
30032
|
const shutdown = (signal) => {
|
|
@@ -30048,14 +30095,14 @@ async function serve(opts) {
|
|
|
30048
30095
|
`);
|
|
30049
30096
|
const args = ["--dangerously-skip-permissions", "--model", model.model];
|
|
30050
30097
|
const child = spawn11("claude", args, { stdio: "inherit", env: editorEnv, cwd: opts.cwd });
|
|
30051
|
-
const exitCode = await new Promise((
|
|
30052
|
-
child.on("exit", (code) =>
|
|
30098
|
+
const exitCode = await new Promise((resolve24) => {
|
|
30099
|
+
child.on("exit", (code) => resolve24(code ?? 0));
|
|
30053
30100
|
child.on("error", (err) => {
|
|
30054
30101
|
process.stderr.write(`[kody serve] failed to launch Claude Code: ${err.message}
|
|
30055
30102
|
`);
|
|
30056
30103
|
process.stderr.write(` Install: https://docs.anthropic.com/claude/docs/claude-code
|
|
30057
30104
|
`);
|
|
30058
|
-
|
|
30105
|
+
resolve24(1);
|
|
30059
30106
|
});
|
|
30060
30107
|
});
|
|
30061
30108
|
killProxy();
|