@kody-ade/kody-engine 0.4.409 → 0.4.411
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 +435 -408
- package/package.json +1 -1
- package/templates/kody.yml +88 -0
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.411",
|
|
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",
|
|
@@ -746,7 +746,7 @@ function buildVerifyEnv(source = process.env) {
|
|
|
746
746
|
return env;
|
|
747
747
|
}
|
|
748
748
|
function runCommand(command, cwd) {
|
|
749
|
-
return new Promise((
|
|
749
|
+
return new Promise((resolve17) => {
|
|
750
750
|
const start = Date.now();
|
|
751
751
|
const child = spawn(command, {
|
|
752
752
|
cwd,
|
|
@@ -775,11 +775,11 @@ function runCommand(command, cwd) {
|
|
|
775
775
|
child.on("exit", (code) => {
|
|
776
776
|
clearTimeout(timer);
|
|
777
777
|
const tail = Buffer.concat(buffers).toString("utf-8").slice(-TAIL_CHARS);
|
|
778
|
-
|
|
778
|
+
resolve17({ exitCode: code ?? -1, durationMs: Date.now() - start, tail });
|
|
779
779
|
});
|
|
780
780
|
child.on("error", (err) => {
|
|
781
781
|
clearTimeout(timer);
|
|
782
|
-
|
|
782
|
+
resolve17({ exitCode: -1, durationMs: Date.now() - start, tail: err.message });
|
|
783
783
|
});
|
|
784
784
|
});
|
|
785
785
|
}
|
|
@@ -1088,7 +1088,7 @@ function cmsHeaders(opts) {
|
|
|
1088
1088
|
}
|
|
1089
1089
|
};
|
|
1090
1090
|
}
|
|
1091
|
-
async function callDashboardCms(opts,
|
|
1091
|
+
async function callDashboardCms(opts, path52, init = {}) {
|
|
1092
1092
|
const baseUrl = dashboardBaseUrl(opts);
|
|
1093
1093
|
if (!baseUrl) {
|
|
1094
1094
|
return {
|
|
@@ -1100,7 +1100,7 @@ async function callDashboardCms(opts, path51, init = {}) {
|
|
|
1100
1100
|
const headerResult = cmsHeaders(opts);
|
|
1101
1101
|
if (!headerResult.ok) return headerResult;
|
|
1102
1102
|
try {
|
|
1103
|
-
const res = await fetch(`${baseUrl}${
|
|
1103
|
+
const res = await fetch(`${baseUrl}${path52}`, {
|
|
1104
1104
|
...init,
|
|
1105
1105
|
headers: {
|
|
1106
1106
|
...headerResult.headers,
|
|
@@ -1172,8 +1172,8 @@ function documentArg(value) {
|
|
|
1172
1172
|
function normalizeCmsDocumentIdInput(input) {
|
|
1173
1173
|
const trimmed = stripWrappingQuotes(input.trim());
|
|
1174
1174
|
const withoutQuery = trimmed.split(/[?#]/, 1)[0] ?? trimmed;
|
|
1175
|
-
const
|
|
1176
|
-
return
|
|
1175
|
+
const path52 = parseDocumentPath(withoutQuery);
|
|
1176
|
+
return path52 ?? parseDocumentIdSegment(withoutQuery) ?? withoutQuery;
|
|
1177
1177
|
}
|
|
1178
1178
|
function stripWrappingQuotes(value) {
|
|
1179
1179
|
let current = value;
|
|
@@ -1184,9 +1184,9 @@ function stripWrappingQuotes(value) {
|
|
|
1184
1184
|
}
|
|
1185
1185
|
}
|
|
1186
1186
|
function parseDocumentPath(value) {
|
|
1187
|
-
const
|
|
1188
|
-
if (!
|
|
1189
|
-
const parts =
|
|
1187
|
+
const path52 = value.startsWith("http://") || value.startsWith("https://") ? urlPathname(value) : value;
|
|
1188
|
+
if (!path52?.includes("/content/entries/")) return null;
|
|
1189
|
+
const parts = path52.split("/").filter(Boolean).map(decodePathPart);
|
|
1190
1190
|
const entriesIndex = parts.findIndex((part, index) => part === "content" && parts[index + 1] === "entries");
|
|
1191
1191
|
const idPart = parts[entriesIndex + 3];
|
|
1192
1192
|
if (!idPart || idPart === "new") return null;
|
|
@@ -2219,6 +2219,108 @@ var init_convex_client = __esm({
|
|
|
2219
2219
|
}
|
|
2220
2220
|
});
|
|
2221
2221
|
|
|
2222
|
+
// src/kody-api-client.ts
|
|
2223
|
+
import { getFunctionName } from "convex/server";
|
|
2224
|
+
function apiUrl(env) {
|
|
2225
|
+
return (env.KODY_API_URL?.trim() || DEFAULT_KODY_API_URL).replace(/\/$/, "");
|
|
2226
|
+
}
|
|
2227
|
+
function oidcRequestUrl(env) {
|
|
2228
|
+
const raw = env.ACTIONS_ID_TOKEN_REQUEST_URL?.trim();
|
|
2229
|
+
if (!raw) throw new Error("GitHub Actions OIDC request URL is unavailable");
|
|
2230
|
+
const url = new URL(raw);
|
|
2231
|
+
if (url.protocol !== "https:") throw new Error("GitHub Actions OIDC request URL must use HTTPS");
|
|
2232
|
+
url.searchParams.set("audience", OIDC_AUDIENCE);
|
|
2233
|
+
return url;
|
|
2234
|
+
}
|
|
2235
|
+
function tokenExpiry(token) {
|
|
2236
|
+
try {
|
|
2237
|
+
const payload = JSON.parse(Buffer.from(token.split(".")[1] ?? "", "base64url").toString("utf8"));
|
|
2238
|
+
return typeof payload.exp === "number" ? payload.exp * 1e3 : Date.now() + 4 * 6e4;
|
|
2239
|
+
} catch {
|
|
2240
|
+
return Date.now() + 4 * 6e4;
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
async function githubOidcToken(env, force = false) {
|
|
2244
|
+
if (!force && cachedToken && cachedToken.expiresAt - 6e4 > Date.now()) return cachedToken.value;
|
|
2245
|
+
const requestToken = env.ACTIONS_ID_TOKEN_REQUEST_TOKEN?.trim();
|
|
2246
|
+
if (!requestToken) throw new Error("GitHub Actions OIDC request token is unavailable");
|
|
2247
|
+
const response = await fetch(oidcRequestUrl(env), {
|
|
2248
|
+
headers: { Authorization: `Bearer ${requestToken}` },
|
|
2249
|
+
signal: AbortSignal.timeout(15e3)
|
|
2250
|
+
});
|
|
2251
|
+
if (!response.ok) throw new Error(`GitHub Actions identity request failed (${response.status})`);
|
|
2252
|
+
const body = await response.json();
|
|
2253
|
+
if (typeof body.value !== "string" || !body.value) throw new Error("GitHub Actions identity response was invalid");
|
|
2254
|
+
cachedToken = { value: body.value, expiresAt: tokenExpiry(body.value) };
|
|
2255
|
+
return body.value;
|
|
2256
|
+
}
|
|
2257
|
+
function operationName(fn) {
|
|
2258
|
+
return getFunctionName(fn).replace(":", ".");
|
|
2259
|
+
}
|
|
2260
|
+
async function callKodyApi(kind, fn, args, env) {
|
|
2261
|
+
const call = async (forceToken) => {
|
|
2262
|
+
const token = await githubOidcToken(env, forceToken);
|
|
2263
|
+
return fetch(`${apiUrl(env)}/api/kody/engine/backend`, {
|
|
2264
|
+
method: "POST",
|
|
2265
|
+
headers: {
|
|
2266
|
+
Authorization: `Bearer ${token}`,
|
|
2267
|
+
"Content-Type": "application/json"
|
|
2268
|
+
},
|
|
2269
|
+
body: JSON.stringify({ kind, operation: operationName(fn), args }),
|
|
2270
|
+
signal: AbortSignal.timeout(3e4)
|
|
2271
|
+
});
|
|
2272
|
+
};
|
|
2273
|
+
let response = await call(false);
|
|
2274
|
+
if (response.status === 401) response = await call(true);
|
|
2275
|
+
if (!response.ok) throw new Error(`Kody backend request failed (${response.status})`);
|
|
2276
|
+
const body = await response.json();
|
|
2277
|
+
return body.result;
|
|
2278
|
+
}
|
|
2279
|
+
function hasGitHubActionsIdentity(env = process.env) {
|
|
2280
|
+
return Boolean(
|
|
2281
|
+
env.GITHUB_ACTIONS === "true" && env.ACTIONS_ID_TOKEN_REQUEST_URL?.trim() && env.ACTIONS_ID_TOKEN_REQUEST_TOKEN?.trim()
|
|
2282
|
+
);
|
|
2283
|
+
}
|
|
2284
|
+
function createKodyApiBackendClient(env = process.env) {
|
|
2285
|
+
if (!hasGitHubActionsIdentity(env)) throw new Error("GitHub Actions workflow identity is unavailable");
|
|
2286
|
+
return {
|
|
2287
|
+
query: (fn, args) => callKodyApi("query", fn, args, env),
|
|
2288
|
+
mutation: (fn, args) => callKodyApi("mutation", fn, args, env)
|
|
2289
|
+
};
|
|
2290
|
+
}
|
|
2291
|
+
async function readRuntimeSecretFromKody(name, env = process.env) {
|
|
2292
|
+
const token = await githubOidcToken(env);
|
|
2293
|
+
const response = await fetch(`${apiUrl(env)}/api/kody/engine/secret`, {
|
|
2294
|
+
method: "POST",
|
|
2295
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|
|
2296
|
+
body: JSON.stringify({ name }),
|
|
2297
|
+
signal: AbortSignal.timeout(3e4)
|
|
2298
|
+
});
|
|
2299
|
+
if (response.status === 404) return null;
|
|
2300
|
+
if (!response.ok) throw new Error(`Kody secret request failed (${response.status})`);
|
|
2301
|
+
const body = await response.json();
|
|
2302
|
+
return typeof body.value === "string" ? body.value : null;
|
|
2303
|
+
}
|
|
2304
|
+
async function readPreviewContextFromKody(env = process.env) {
|
|
2305
|
+
const token = await githubOidcToken(env);
|
|
2306
|
+
const response = await fetch(`${apiUrl(env)}/api/kody/engine/preview-context`, {
|
|
2307
|
+
method: "POST",
|
|
2308
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
2309
|
+
signal: AbortSignal.timeout(3e4)
|
|
2310
|
+
});
|
|
2311
|
+
if (!response.ok) throw new Error(`Kody preview context request failed (${response.status})`);
|
|
2312
|
+
return await response.json();
|
|
2313
|
+
}
|
|
2314
|
+
var DEFAULT_KODY_API_URL, OIDC_AUDIENCE, cachedToken;
|
|
2315
|
+
var init_kody_api_client = __esm({
|
|
2316
|
+
"src/kody-api-client.ts"() {
|
|
2317
|
+
"use strict";
|
|
2318
|
+
DEFAULT_KODY_API_URL = "https://kody-dashboard-khaki.vercel.app";
|
|
2319
|
+
OIDC_AUDIENCE = "kody-api";
|
|
2320
|
+
cachedToken = null;
|
|
2321
|
+
}
|
|
2322
|
+
});
|
|
2323
|
+
|
|
2222
2324
|
// src/state-backend.ts
|
|
2223
2325
|
import { anyApi } from "convex/server";
|
|
2224
2326
|
function requireTenant(tenantId2) {
|
|
@@ -2236,10 +2338,16 @@ function requireNonEmpty(value, name) {
|
|
|
2236
2338
|
return normalized;
|
|
2237
2339
|
}
|
|
2238
2340
|
function createStateBackendFromEnv(env = process.env, client) {
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
if (!
|
|
2242
|
-
|
|
2341
|
+
let transport = client;
|
|
2342
|
+
if (!transport && hasGitHubActionsIdentity(env)) transport = createKodyApiBackendClient(env);
|
|
2343
|
+
if (!transport) {
|
|
2344
|
+
const url = env.CONVEX_URL?.trim();
|
|
2345
|
+
const serviceKey = env.KODY_SERVICE_KEY?.trim();
|
|
2346
|
+
if (!url || !serviceKey) {
|
|
2347
|
+
throw new Error("GitHub Actions identity or direct Kody backend credentials are required");
|
|
2348
|
+
}
|
|
2349
|
+
transport = createConvexClientFromEnv(env);
|
|
2350
|
+
}
|
|
2243
2351
|
return {
|
|
2244
2352
|
async get(tenantId2, taskKey, kind) {
|
|
2245
2353
|
const result = await transport.query(anyApi.taskState.get, {
|
|
@@ -2412,10 +2520,14 @@ function createStateBackendFromEnv(env = process.env, client) {
|
|
|
2412
2520
|
}
|
|
2413
2521
|
};
|
|
2414
2522
|
}
|
|
2523
|
+
function hasStateBackendConfig(env = process.env) {
|
|
2524
|
+
return hasGitHubActionsIdentity(env) || Boolean(env.CONVEX_URL?.trim() && env.KODY_SERVICE_KEY?.trim());
|
|
2525
|
+
}
|
|
2415
2526
|
var init_state_backend = __esm({
|
|
2416
2527
|
"src/state-backend.ts"() {
|
|
2417
2528
|
"use strict";
|
|
2418
2529
|
init_convex_client();
|
|
2530
|
+
init_kody_api_client();
|
|
2419
2531
|
}
|
|
2420
2532
|
});
|
|
2421
2533
|
|
|
@@ -3041,7 +3153,7 @@ var init_repoWorkspace = __esm({
|
|
|
3041
3153
|
defaultCloneRepo = (repo, token, dir) => {
|
|
3042
3154
|
fs7.mkdirSync(path8.dirname(dir), { recursive: true });
|
|
3043
3155
|
const clone = buildCloneProcess(repo, token);
|
|
3044
|
-
return new Promise((
|
|
3156
|
+
return new Promise((resolve17, reject) => {
|
|
3045
3157
|
const child = spawn2("git", ["clone", "--depth=1", clone.url, dir], {
|
|
3046
3158
|
env: clone.env,
|
|
3047
3159
|
stdio: "inherit"
|
|
@@ -3061,7 +3173,7 @@ var init_repoWorkspace = __esm({
|
|
|
3061
3173
|
}
|
|
3062
3174
|
} catch {
|
|
3063
3175
|
}
|
|
3064
|
-
|
|
3176
|
+
resolve17();
|
|
3065
3177
|
});
|
|
3066
3178
|
child.on("error", reject);
|
|
3067
3179
|
});
|
|
@@ -3372,10 +3484,10 @@ async function runAgent(opts) {
|
|
|
3372
3484
|
let timer;
|
|
3373
3485
|
let next;
|
|
3374
3486
|
if (turnTimeoutMs > 0) {
|
|
3375
|
-
const timeoutPromise = new Promise((
|
|
3487
|
+
const timeoutPromise = new Promise((resolve17) => {
|
|
3376
3488
|
timer = setTimeout(() => {
|
|
3377
3489
|
timedOut = true;
|
|
3378
|
-
|
|
3490
|
+
resolve17({ done: true, value: void 0 });
|
|
3379
3491
|
}, turnTimeoutMs);
|
|
3380
3492
|
});
|
|
3381
3493
|
next = await Promise.race([nextPromise, timeoutPromise]);
|
|
@@ -3391,7 +3503,7 @@ async function runAgent(opts) {
|
|
|
3391
3503
|
try {
|
|
3392
3504
|
await Promise.race([
|
|
3393
3505
|
iterator.return(void 0).catch(() => void 0),
|
|
3394
|
-
new Promise((
|
|
3506
|
+
new Promise((resolve17) => setTimeout(resolve17, 1e4).unref())
|
|
3395
3507
|
]);
|
|
3396
3508
|
} catch {
|
|
3397
3509
|
}
|
|
@@ -3657,7 +3769,7 @@ function prepareTaskArtifactsDir(cwd, taskId) {
|
|
|
3657
3769
|
function initializeTaskArtifacts(artifacts, metadata = { taskType: "job" }) {
|
|
3658
3770
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3659
3771
|
const defaults = {
|
|
3660
|
-
"context.json": JSON.stringify(
|
|
3772
|
+
"context.json": `${JSON.stringify(
|
|
3661
3773
|
{
|
|
3662
3774
|
taskId: artifacts.taskId,
|
|
3663
3775
|
taskType: metadata.taskType,
|
|
@@ -3674,7 +3786,8 @@ function initializeTaskArtifacts(artifacts, metadata = { taskType: "job" }) {
|
|
|
3674
3786
|
},
|
|
3675
3787
|
null,
|
|
3676
3788
|
2
|
|
3677
|
-
)
|
|
3789
|
+
)}
|
|
3790
|
+
`,
|
|
3678
3791
|
"memory-recs.json": "[]\n",
|
|
3679
3792
|
"followups.json": "[]\n",
|
|
3680
3793
|
"handoff-notes.md": "Baseline handoff: the agent did not provide additional notes.\n"
|
|
@@ -3699,12 +3812,10 @@ function verifyTaskArtifacts(absDir) {
|
|
|
3699
3812
|
}
|
|
3700
3813
|
async function persistTaskArtifactsToState(config, _cwd, artifacts) {
|
|
3701
3814
|
const tenantId2 = config.github?.owner && config.github.repo ? `${config.github.owner}/${config.github.repo}` : process.env.GITHUB_REPOSITORY?.trim();
|
|
3702
|
-
if (process.env.GITHUB_ACTIONS === "true" && (!
|
|
3703
|
-
throw new Error(
|
|
3704
|
-
"Convex artifact backend is required in GitHub Actions (CONVEX_URL, KODY_SERVICE_KEY, and repository identity)"
|
|
3705
|
-
);
|
|
3815
|
+
if (process.env.GITHUB_ACTIONS === "true" && (!hasStateBackendConfig() || !tenantId2)) {
|
|
3816
|
+
throw new Error("Kody backend access and repository identity are required in GitHub Actions");
|
|
3706
3817
|
}
|
|
3707
|
-
if (
|
|
3818
|
+
if (hasStateBackendConfig() && tenantId2) {
|
|
3708
3819
|
const backend = createStateBackendFromEnv();
|
|
3709
3820
|
for (const file of TASK_ARTIFACT_FILES) {
|
|
3710
3821
|
const full = path11.join(artifacts.absDir, file);
|
|
@@ -5834,7 +5945,7 @@ var init_loadMemoryContext = __esm({
|
|
|
5834
5945
|
loadMemoryContext = async (ctx) => {
|
|
5835
5946
|
if (typeof ctx.data.memoryContext === "string") return;
|
|
5836
5947
|
const tenantId2 = ctx.config.github?.owner && ctx.config.github.repo ? `${ctx.config.github.owner}/${ctx.config.github.repo}` : process.env.GITHUB_REPOSITORY?.trim();
|
|
5837
|
-
if (
|
|
5948
|
+
if (hasStateBackendConfig() && tenantId2) {
|
|
5838
5949
|
try {
|
|
5839
5950
|
const backend = createStateBackendFromEnv();
|
|
5840
5951
|
const docs = await backend.listRepoDocs(tenantId2, "memory:");
|
|
@@ -6559,11 +6670,11 @@ async function nextAvailableLitellmUrl(url) {
|
|
|
6559
6670
|
throw new Error(`no free LiteLLM port found after ${startPort}`);
|
|
6560
6671
|
}
|
|
6561
6672
|
function canListen(port, host) {
|
|
6562
|
-
return new Promise((
|
|
6673
|
+
return new Promise((resolve17) => {
|
|
6563
6674
|
const server = net.createServer();
|
|
6564
|
-
server.once("error", () =>
|
|
6675
|
+
server.once("error", () => resolve17(false));
|
|
6565
6676
|
server.once("listening", () => {
|
|
6566
|
-
server.close(() =>
|
|
6677
|
+
server.close(() => resolve17(true));
|
|
6567
6678
|
});
|
|
6568
6679
|
server.listen(port, host);
|
|
6569
6680
|
});
|
|
@@ -7724,9 +7835,9 @@ import * as fs26 from "fs";
|
|
|
7724
7835
|
function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
|
|
7725
7836
|
const logs = goalRunLogs(data);
|
|
7726
7837
|
const existing = logs[goalId];
|
|
7727
|
-
const
|
|
7838
|
+
const path52 = existing?.path ?? goalRunLogPath(goalId, data);
|
|
7728
7839
|
logs[goalId] = {
|
|
7729
|
-
path:
|
|
7840
|
+
path: path52,
|
|
7730
7841
|
events: [...existing?.events ?? [], buildGoalRunLogEvent(data, goalId, event, at)]
|
|
7731
7842
|
};
|
|
7732
7843
|
}
|
|
@@ -7851,7 +7962,7 @@ function buildGoalRunLogEvent(data, goalId, event, at) {
|
|
|
7851
7962
|
if (context !== void 0) base.dispatchContext = context;
|
|
7852
7963
|
return base;
|
|
7853
7964
|
}
|
|
7854
|
-
function enrichGoalRunLogEvent(config, data,
|
|
7965
|
+
function enrichGoalRunLogEvent(config, data, _logPath, event) {
|
|
7855
7966
|
const trigger = event.trigger ?? triggerContext();
|
|
7856
7967
|
const job = event.job ?? jobContext(data);
|
|
7857
7968
|
const run = event.run ?? runContext(data);
|
|
@@ -8142,7 +8253,7 @@ function backendTenant(config) {
|
|
|
8142
8253
|
return owner && repo ? `${owner}/${repo}` : null;
|
|
8143
8254
|
}
|
|
8144
8255
|
function decodeGoal(doc) {
|
|
8145
|
-
if (!doc
|
|
8256
|
+
if (!doc?.state || typeof doc.state !== "object" || Array.isArray(doc.state)) return null;
|
|
8146
8257
|
const state = doc.state;
|
|
8147
8258
|
if (typeof state.state !== "string" || !state.extra || typeof state.extra !== "object") return null;
|
|
8148
8259
|
return state;
|
|
@@ -8699,11 +8810,11 @@ function validateWorkflow(value, options = {}) {
|
|
|
8699
8810
|
function formatWorkflowValidationIssues(issues) {
|
|
8700
8811
|
return issues.map((entry) => `${entry.path}: ${entry.message}`);
|
|
8701
8812
|
}
|
|
8702
|
-
function validateDataMatch(value,
|
|
8813
|
+
function validateDataMatch(value, path52, issues, capabilityOutputs) {
|
|
8703
8814
|
if (value === void 0) return;
|
|
8704
8815
|
const match = asRecord2(value);
|
|
8705
8816
|
if (!match || Object.keys(match).length === 0) {
|
|
8706
|
-
issue(issues, "invalid_condition",
|
|
8817
|
+
issue(issues, "invalid_condition", path52, "workflow condition must contain at least one match");
|
|
8707
8818
|
return;
|
|
8708
8819
|
}
|
|
8709
8820
|
for (const [field, expected] of Object.entries(match)) {
|
|
@@ -8711,7 +8822,7 @@ function validateDataMatch(value, path51, issues, capabilityOutputs) {
|
|
|
8711
8822
|
issue(
|
|
8712
8823
|
issues,
|
|
8713
8824
|
"invalid_data_path",
|
|
8714
|
-
`${
|
|
8825
|
+
`${path52}.${field}`,
|
|
8715
8826
|
`workflow condition must read from facts, evidence, artifacts, result, workflow, or lastOutcome`
|
|
8716
8827
|
);
|
|
8717
8828
|
}
|
|
@@ -8719,12 +8830,12 @@ function validateDataMatch(value, path51, issues, capabilityOutputs) {
|
|
|
8719
8830
|
issue(
|
|
8720
8831
|
issues,
|
|
8721
8832
|
"undeclared_result_path",
|
|
8722
|
-
`${
|
|
8833
|
+
`${path52}.${field}`,
|
|
8723
8834
|
`workflow condition reads ${field}, but the source capability does not declare it`
|
|
8724
8835
|
);
|
|
8725
8836
|
}
|
|
8726
8837
|
if (!isComparable(expected)) {
|
|
8727
|
-
issue(issues, "invalid_condition_value", `${
|
|
8838
|
+
issue(issues, "invalid_condition_value", `${path52}.${field}`, "workflow condition value must be a JSON scalar");
|
|
8728
8839
|
}
|
|
8729
8840
|
}
|
|
8730
8841
|
}
|
|
@@ -8742,8 +8853,8 @@ function isComparable(value) {
|
|
|
8742
8853
|
if (value === null || ["string", "number", "boolean"].includes(typeof value)) return true;
|
|
8743
8854
|
return Array.isArray(value) && value.length > 0 && value.every((item) => isComparable(item) && !Array.isArray(item));
|
|
8744
8855
|
}
|
|
8745
|
-
function issue(issues, code,
|
|
8746
|
-
issues.push({ code, path:
|
|
8856
|
+
function issue(issues, code, path52, message) {
|
|
8857
|
+
issues.push({ code, path: path52, message });
|
|
8747
8858
|
}
|
|
8748
8859
|
var SAFE_NAME, SAFE_STEP_ID, SAFE_DATA_PATH, SUPPORTED_STEP_FIELDS, SUPPORTED_TRANSITION_FIELDS;
|
|
8749
8860
|
var init_workflowValidation = __esm({
|
|
@@ -9001,15 +9112,15 @@ var init_backendStateBackend = __esm({
|
|
|
9001
9112
|
this.jobsDir = opts.jobsDir.replace(/\/+$/, "");
|
|
9002
9113
|
}
|
|
9003
9114
|
async load(slug) {
|
|
9004
|
-
const
|
|
9115
|
+
const path52 = stateFilePath(this.jobsDir, slug);
|
|
9005
9116
|
const loaded = await createStateBackendFromEnv().get(this.tenantId, `capabilities/${slug}`, "job-state");
|
|
9006
9117
|
if (!loaded) {
|
|
9007
|
-
return { path:
|
|
9118
|
+
return { path: path52, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
9008
9119
|
}
|
|
9009
9120
|
if (!isStateEnvelope(loaded.doc)) {
|
|
9010
9121
|
throw new Error(`BackendStateBackend: capabilities/${slug} is not a StateEnvelope`);
|
|
9011
9122
|
}
|
|
9012
|
-
return { path:
|
|
9123
|
+
return { path: path52, handle: loaded.updatedAt, state: loaded.doc, created: false };
|
|
9013
9124
|
}
|
|
9014
9125
|
async save(loaded, next) {
|
|
9015
9126
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) return false;
|
|
@@ -9535,7 +9646,7 @@ function subjectCandidates(kind, id, state) {
|
|
|
9535
9646
|
return [...ids].map((candidate) => ({ kind, id: candidate }));
|
|
9536
9647
|
}
|
|
9537
9648
|
async function firstTrustOverride(ctx, subjects) {
|
|
9538
|
-
const backendConfigured =
|
|
9649
|
+
const backendConfigured = hasStateBackendConfig();
|
|
9539
9650
|
if (!backendConfigured) return null;
|
|
9540
9651
|
const repoSlug = ctx.config.github?.owner && ctx.config.github?.repo ? `${ctx.config.github.owner}/${ctx.config.github.repo}` : "";
|
|
9541
9652
|
for (const subject of subjects) {
|
|
@@ -9751,6 +9862,7 @@ var init_advanceManagedGoal = __esm({
|
|
|
9751
9862
|
init_typeDefinitions();
|
|
9752
9863
|
init_issue();
|
|
9753
9864
|
init_registry();
|
|
9865
|
+
init_state_backend();
|
|
9754
9866
|
init_trustPolicy();
|
|
9755
9867
|
init_workflowDefinitions();
|
|
9756
9868
|
init_goalCapabilityScheduling();
|
|
@@ -10048,12 +10160,12 @@ function resolveTrigger(force) {
|
|
|
10048
10160
|
}
|
|
10049
10161
|
async function appendActivity(ctx, record2) {
|
|
10050
10162
|
const tenantId2 = ctx.config.github?.owner && ctx.config.github.repo ? `${ctx.config.github.owner}/${ctx.config.github.repo}` : process.env.GITHUB_REPOSITORY;
|
|
10051
|
-
if (
|
|
10163
|
+
if (hasStateBackendConfig() && tenantId2) {
|
|
10052
10164
|
await createStateBackendFromEnv().appendDailyLog(tenantId2, "activity", record2.ts.slice(0, 10), record2);
|
|
10053
10165
|
return;
|
|
10054
10166
|
}
|
|
10055
10167
|
if (process.env.GITHUB_ACTIONS === "true") {
|
|
10056
|
-
throw new Error("
|
|
10168
|
+
throw new Error("Kody backend access is required for company activity in GitHub Actions");
|
|
10057
10169
|
}
|
|
10058
10170
|
}
|
|
10059
10171
|
var appendCompanyActivity;
|
|
@@ -13804,14 +13916,33 @@ var init_fixFlow = __esm({
|
|
|
13804
13916
|
}
|
|
13805
13917
|
});
|
|
13806
13918
|
|
|
13807
|
-
// src/
|
|
13808
|
-
import { execFileSync as execFileSync14 } from "child_process";
|
|
13919
|
+
// src/workflow-template.ts
|
|
13809
13920
|
import * as fs35 from "fs";
|
|
13810
13921
|
import * as path33 from "path";
|
|
13922
|
+
import { fileURLToPath } from "url";
|
|
13923
|
+
function loadKodyWorkflowTemplate() {
|
|
13924
|
+
const here = path33.dirname(fileURLToPath(import.meta.url));
|
|
13925
|
+
const candidates = [path33.resolve(here, "../templates/kody.yml"), path33.resolve(here, "../../templates/kody.yml")];
|
|
13926
|
+
const source = candidates.find((candidate) => fs35.existsSync(candidate));
|
|
13927
|
+
if (!source) throw new Error(`Kody workflow template is missing: ${KODY_WORKFLOW_TEMPLATE_PATH}`);
|
|
13928
|
+
return fs35.readFileSync(source, "utf8");
|
|
13929
|
+
}
|
|
13930
|
+
var KODY_WORKFLOW_TEMPLATE_PATH;
|
|
13931
|
+
var init_workflow_template = __esm({
|
|
13932
|
+
"src/workflow-template.ts"() {
|
|
13933
|
+
"use strict";
|
|
13934
|
+
KODY_WORKFLOW_TEMPLATE_PATH = "templates/kody.yml";
|
|
13935
|
+
}
|
|
13936
|
+
});
|
|
13937
|
+
|
|
13938
|
+
// src/scripts/initFlow.ts
|
|
13939
|
+
import { execFileSync as execFileSync14 } from "child_process";
|
|
13940
|
+
import * as fs36 from "fs";
|
|
13941
|
+
import * as path34 from "path";
|
|
13811
13942
|
function detectPackageManager(cwd) {
|
|
13812
|
-
if (
|
|
13813
|
-
if (
|
|
13814
|
-
if (
|
|
13943
|
+
if (fs36.existsSync(path34.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
13944
|
+
if (fs36.existsSync(path34.join(cwd, "yarn.lock"))) return "yarn";
|
|
13945
|
+
if (fs36.existsSync(path34.join(cwd, "bun.lockb"))) return "bun";
|
|
13815
13946
|
return "npm";
|
|
13816
13947
|
}
|
|
13817
13948
|
function qualityCommandsFor(pm) {
|
|
@@ -13883,22 +14014,22 @@ function performInit(cwd, force) {
|
|
|
13883
14014
|
const pm = detectPackageManager(cwd);
|
|
13884
14015
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
13885
14016
|
const defaultBranch = defaultBranchFromGit(cwd);
|
|
13886
|
-
const configPath =
|
|
13887
|
-
if (
|
|
14017
|
+
const configPath = path34.join(cwd, "kody.config.json");
|
|
14018
|
+
if (fs36.existsSync(configPath) && !force) {
|
|
13888
14019
|
skipped.push("kody.config.json");
|
|
13889
14020
|
} else {
|
|
13890
14021
|
const cfg = makeConfig(pm, ownerRepo, defaultBranch);
|
|
13891
|
-
|
|
14022
|
+
fs36.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
13892
14023
|
`);
|
|
13893
14024
|
wrote.push("kody.config.json");
|
|
13894
14025
|
}
|
|
13895
|
-
const workflowDir =
|
|
13896
|
-
const workflowPath =
|
|
13897
|
-
if (
|
|
14026
|
+
const workflowDir = path34.join(cwd, ".github", "workflows");
|
|
14027
|
+
const workflowPath = path34.join(workflowDir, "kody.yml");
|
|
14028
|
+
if (fs36.existsSync(workflowPath) && !force) {
|
|
13898
14029
|
skipped.push(".github/workflows/kody.yml");
|
|
13899
14030
|
} else {
|
|
13900
|
-
|
|
13901
|
-
|
|
14031
|
+
fs36.mkdirSync(workflowDir, { recursive: true });
|
|
14032
|
+
fs36.writeFileSync(workflowPath, loadKodyWorkflowTemplate());
|
|
13902
14033
|
wrote.push(".github/workflows/kody.yml");
|
|
13903
14034
|
}
|
|
13904
14035
|
for (const exe of listImplementations()) {
|
|
@@ -13909,12 +14040,12 @@ function performInit(cwd, force) {
|
|
|
13909
14040
|
continue;
|
|
13910
14041
|
}
|
|
13911
14042
|
if (profile.kind !== "scheduled" || !profile.schedule) continue;
|
|
13912
|
-
const target =
|
|
13913
|
-
if (
|
|
14043
|
+
const target = path34.join(workflowDir, `kody-${exe.name}.yml`);
|
|
14044
|
+
if (fs36.existsSync(target) && !force) {
|
|
13914
14045
|
skipped.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
13915
14046
|
continue;
|
|
13916
14047
|
}
|
|
13917
|
-
|
|
14048
|
+
fs36.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
|
|
13918
14049
|
wrote.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
13919
14050
|
}
|
|
13920
14051
|
let labels;
|
|
@@ -13960,7 +14091,7 @@ jobs:
|
|
|
13960
14091
|
run: npx -y -p @kody-ade/kody-engine@latest kody-engine implementation ${name}
|
|
13961
14092
|
`;
|
|
13962
14093
|
}
|
|
13963
|
-
var
|
|
14094
|
+
var initFlow;
|
|
13964
14095
|
var init_initFlow = __esm({
|
|
13965
14096
|
"src/scripts/initFlow.ts"() {
|
|
13966
14097
|
"use strict";
|
|
@@ -13968,67 +14099,7 @@ var init_initFlow = __esm({
|
|
|
13968
14099
|
init_lifecycleLabels();
|
|
13969
14100
|
init_profile();
|
|
13970
14101
|
init_registry();
|
|
13971
|
-
|
|
13972
|
-
#
|
|
13973
|
-
# Triggers: @kody comment on an issue or PR, or manual workflow_dispatch.
|
|
13974
|
-
# Everything else (install deps, set up LiteLLM, run the agent, open the PR)
|
|
13975
|
-
# is handled inside the @kody-ade/kody-engine package.
|
|
13976
|
-
#
|
|
13977
|
-
# Required repo secrets: at least one model provider key (e.g. MINIMAX_API_KEY,
|
|
13978
|
-
# ANTHROPIC_API_KEY). kody reads any *_API_KEY secret automatically via
|
|
13979
|
-
# toJSON(secrets) \u2014 no need to list them here.
|
|
13980
|
-
#
|
|
13981
|
-
# Recommended: KODY_TOKEN secret \u2014 a PAT or GitHub App token with repo
|
|
13982
|
-
# scope so kody's pushes trigger downstream CI and PR-body edits succeed.
|
|
13983
|
-
|
|
13984
|
-
name: kody
|
|
13985
|
-
|
|
13986
|
-
on:
|
|
13987
|
-
workflow_dispatch:
|
|
13988
|
-
inputs:
|
|
13989
|
-
issue_number:
|
|
13990
|
-
description: "GitHub issue number"
|
|
13991
|
-
required: true
|
|
13992
|
-
type: string
|
|
13993
|
-
capability:
|
|
13994
|
-
description: "Capability action to run (default: run)"
|
|
13995
|
-
required: false
|
|
13996
|
-
type: string
|
|
13997
|
-
default: ""
|
|
13998
|
-
issue_comment:
|
|
13999
|
-
types: [created]
|
|
14000
|
-
|
|
14001
|
-
jobs:
|
|
14002
|
-
run:
|
|
14003
|
-
if: >-
|
|
14004
|
-
\${{ github.event_name == 'workflow_dispatch' ||
|
|
14005
|
-
(github.event_name == 'issue_comment' &&
|
|
14006
|
-
contains(github.event.comment.body, '@kody')) }}
|
|
14007
|
-
runs-on: ubuntu-latest
|
|
14008
|
-
timeout-minutes: 60
|
|
14009
|
-
permissions:
|
|
14010
|
-
issues: write
|
|
14011
|
-
pull-requests: write
|
|
14012
|
-
contents: write
|
|
14013
|
-
actions: read
|
|
14014
|
-
steps:
|
|
14015
|
-
- uses: actions/checkout@v4
|
|
14016
|
-
with:
|
|
14017
|
-
fetch-depth: 0
|
|
14018
|
-
token: \${{ secrets.KODY_TOKEN || github.token }}
|
|
14019
|
-
|
|
14020
|
-
- uses: actions/setup-node@v4
|
|
14021
|
-
with:
|
|
14022
|
-
node-version: 22
|
|
14023
|
-
|
|
14024
|
-
- uses: actions/setup-python@v5
|
|
14025
|
-
with:
|
|
14026
|
-
python-version: "3.12"
|
|
14027
|
-
|
|
14028
|
-
- env:
|
|
14029
|
-
ALL_SECRETS: \${{ toJSON(secrets) }}
|
|
14030
|
-
run: npx -y -p @kody-ade/kody-engine@latest kody-engine ci
|
|
14031
|
-
`;
|
|
14102
|
+
init_workflow_template();
|
|
14032
14103
|
initFlow = async (ctx) => {
|
|
14033
14104
|
const force = ctx.args.force === true;
|
|
14034
14105
|
const cwd = ctx.cwd;
|
|
@@ -14062,7 +14133,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
|
|
|
14062
14133
|
});
|
|
14063
14134
|
|
|
14064
14135
|
// src/scripts/loadAgentAdhoc.ts
|
|
14065
|
-
import * as
|
|
14136
|
+
import * as fs37 from "fs";
|
|
14066
14137
|
function resolveMessage(messageArg) {
|
|
14067
14138
|
const fromComment = readCommentBody();
|
|
14068
14139
|
if (fromComment) return stripDirective(fromComment);
|
|
@@ -14070,9 +14141,9 @@ function resolveMessage(messageArg) {
|
|
|
14070
14141
|
}
|
|
14071
14142
|
function readCommentBody() {
|
|
14072
14143
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
14073
|
-
if (!eventPath || !
|
|
14144
|
+
if (!eventPath || !fs37.existsSync(eventPath)) return "";
|
|
14074
14145
|
try {
|
|
14075
|
-
const event = JSON.parse(
|
|
14146
|
+
const event = JSON.parse(fs37.readFileSync(eventPath, "utf-8"));
|
|
14076
14147
|
return String(event.comment?.body ?? "");
|
|
14077
14148
|
} catch {
|
|
14078
14149
|
return "";
|
|
@@ -14126,10 +14197,10 @@ var init_loadAgentAdhoc = __esm({
|
|
|
14126
14197
|
throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
|
|
14127
14198
|
}
|
|
14128
14199
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
14129
|
-
if (!
|
|
14200
|
+
if (!fs37.existsSync(agentPath)) {
|
|
14130
14201
|
throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
|
|
14131
14202
|
}
|
|
14132
|
-
const { title, body } = parseAgentFile(
|
|
14203
|
+
const { title, body } = parseAgentFile(fs37.readFileSync(agentPath, "utf-8"), agentSlug);
|
|
14133
14204
|
const message = resolveMessage(ctx.args.message);
|
|
14134
14205
|
if (!message) {
|
|
14135
14206
|
throw new Error(
|
|
@@ -14201,13 +14272,13 @@ var init_loadCapabilityState = __esm({
|
|
|
14201
14272
|
function isCompanyIntentId(value) {
|
|
14202
14273
|
return SLUG_RE.test(value);
|
|
14203
14274
|
}
|
|
14204
|
-
function normalizeCompanyIntent(
|
|
14275
|
+
function normalizeCompanyIntent(path52, raw) {
|
|
14205
14276
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
14206
|
-
throw new Error(`${
|
|
14277
|
+
throw new Error(`${path52}: intent must be JSON object`);
|
|
14207
14278
|
}
|
|
14208
14279
|
const input = raw;
|
|
14209
14280
|
const id = stringField4(input.id);
|
|
14210
|
-
if (!id || !isCompanyIntentId(id)) throw new Error(`${
|
|
14281
|
+
if (!id || !isCompanyIntentId(id)) throw new Error(`${path52}: invalid intent id`);
|
|
14211
14282
|
const createdAt = stringField4(input.createdAt) || nowIso();
|
|
14212
14283
|
const updatedAt = stringField4(input.updatedAt) || createdAt;
|
|
14213
14284
|
const description = stringField4(input.description);
|
|
@@ -14369,7 +14440,7 @@ function retryDelaysMs() {
|
|
|
14369
14440
|
}
|
|
14370
14441
|
function sleep(ms) {
|
|
14371
14442
|
if (ms <= 0) return Promise.resolve();
|
|
14372
|
-
return new Promise((
|
|
14443
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
14373
14444
|
}
|
|
14374
14445
|
async function fetchGoalStateWithRetry(config, goalId, cwd) {
|
|
14375
14446
|
let state = await fetchGoalStateAsync(config, goalId, cwd);
|
|
@@ -14498,8 +14569,8 @@ var init_loadIssueStateComment = __esm({
|
|
|
14498
14569
|
});
|
|
14499
14570
|
|
|
14500
14571
|
// src/scripts/loadJobFromFile.ts
|
|
14501
|
-
import * as
|
|
14502
|
-
import * as
|
|
14572
|
+
import * as fs38 from "fs";
|
|
14573
|
+
import * as path35 from "path";
|
|
14503
14574
|
function parseJobFile(raw, slug) {
|
|
14504
14575
|
let stripped = raw;
|
|
14505
14576
|
if (stripped.startsWith("---\n")) {
|
|
@@ -14538,10 +14609,10 @@ var init_loadJobFromFile = __esm({
|
|
|
14538
14609
|
if (!slug) {
|
|
14539
14610
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
14540
14611
|
}
|
|
14541
|
-
const capability = resolveCapabilityFolder(slug,
|
|
14612
|
+
const capability = resolveCapabilityFolder(slug, path35.resolve(ctx.cwd, jobsDir));
|
|
14542
14613
|
if (!capability) {
|
|
14543
14614
|
throw new Error(
|
|
14544
|
-
`loadJobFromFile: capability folder not found or incomplete: ${
|
|
14615
|
+
`loadJobFromFile: capability folder not found or incomplete: ${path35.resolve(ctx.cwd, jobsDir, slug)}`
|
|
14545
14616
|
);
|
|
14546
14617
|
}
|
|
14547
14618
|
const { title, body, config } = capability;
|
|
@@ -14551,12 +14622,12 @@ var init_loadJobFromFile = __esm({
|
|
|
14551
14622
|
let agentIdentity = "";
|
|
14552
14623
|
if (agentSlug) {
|
|
14553
14624
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
14554
|
-
if (!
|
|
14625
|
+
if (!fs38.existsSync(agentPath)) {
|
|
14555
14626
|
throw new Error(
|
|
14556
14627
|
`loadJobFromFile: capability '${slug}' declares agent '${agentSlug}' but ${agentPath} does not exist`
|
|
14557
14628
|
);
|
|
14558
14629
|
}
|
|
14559
|
-
const agentRaw =
|
|
14630
|
+
const agentRaw = fs38.readFileSync(agentPath, "utf-8");
|
|
14560
14631
|
const parsed = parseJobFile(agentRaw, agentSlug);
|
|
14561
14632
|
agentTitle = parsed.title;
|
|
14562
14633
|
agentIdentity = parsed.body;
|
|
@@ -14636,13 +14707,13 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
14636
14707
|
});
|
|
14637
14708
|
|
|
14638
14709
|
// src/scripts/kodyVariables.ts
|
|
14639
|
-
import * as
|
|
14640
|
-
import * as
|
|
14710
|
+
import * as fs39 from "fs";
|
|
14711
|
+
import * as path36 from "path";
|
|
14641
14712
|
function readKodyVariables(cwd) {
|
|
14642
|
-
const full =
|
|
14713
|
+
const full = path36.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
14643
14714
|
let raw;
|
|
14644
14715
|
try {
|
|
14645
|
-
raw =
|
|
14716
|
+
raw = fs39.readFileSync(full, "utf-8");
|
|
14646
14717
|
} catch {
|
|
14647
14718
|
return {};
|
|
14648
14719
|
}
|
|
@@ -14773,6 +14844,18 @@ function envSecret(name, env) {
|
|
|
14773
14844
|
}
|
|
14774
14845
|
async function resolveRuntimeSecret(name, ctx, opts = {}) {
|
|
14775
14846
|
const env = opts.env ?? process.env;
|
|
14847
|
+
if (hasGitHubActionsIdentity(env)) {
|
|
14848
|
+
try {
|
|
14849
|
+
const value = await readRuntimeSecretFromKody(name, env);
|
|
14850
|
+
return value ? { value, source: "vault" } : envSecret(name, env);
|
|
14851
|
+
} catch (err) {
|
|
14852
|
+
const fallback = envSecret(name, env);
|
|
14853
|
+
return {
|
|
14854
|
+
...fallback,
|
|
14855
|
+
warning: `Kody secret read failed for ${name}: ${err instanceof Error ? err.message : String(err)}`
|
|
14856
|
+
};
|
|
14857
|
+
}
|
|
14858
|
+
}
|
|
14776
14859
|
const masterRaw = env.KODY_MASTER_KEY?.trim() ?? "";
|
|
14777
14860
|
if (!masterRaw || !env.CONVEX_URL?.trim() || !env.KODY_SERVICE_KEY?.trim()) return envSecret(name, env);
|
|
14778
14861
|
try {
|
|
@@ -14800,13 +14883,14 @@ var init_runtimeSecrets = __esm({
|
|
|
14800
14883
|
"src/scripts/runtimeSecrets.ts"() {
|
|
14801
14884
|
"use strict";
|
|
14802
14885
|
init_backendVault();
|
|
14886
|
+
init_kody_api_client();
|
|
14803
14887
|
init_keys();
|
|
14804
14888
|
}
|
|
14805
14889
|
});
|
|
14806
14890
|
|
|
14807
14891
|
// src/scripts/loadQaContext.ts
|
|
14808
|
-
import * as
|
|
14809
|
-
import * as
|
|
14892
|
+
import * as fs40 from "fs";
|
|
14893
|
+
import * as path37 from "path";
|
|
14810
14894
|
function parseSlugList(value) {
|
|
14811
14895
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
14812
14896
|
return inner.split(",").map(
|
|
@@ -14835,18 +14919,18 @@ function readProfileAgents(raw) {
|
|
|
14835
14919
|
return { agent: agent ?? legacy ?? ["kody"], body };
|
|
14836
14920
|
}
|
|
14837
14921
|
function readProfile(cwd) {
|
|
14838
|
-
const dir =
|
|
14839
|
-
if (!
|
|
14922
|
+
const dir = path37.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
14923
|
+
if (!fs40.existsSync(dir)) return "";
|
|
14840
14924
|
let entries;
|
|
14841
14925
|
try {
|
|
14842
|
-
entries =
|
|
14926
|
+
entries = fs40.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
14843
14927
|
} catch {
|
|
14844
14928
|
return "";
|
|
14845
14929
|
}
|
|
14846
14930
|
const blocks = [];
|
|
14847
14931
|
for (const file of entries) {
|
|
14848
14932
|
try {
|
|
14849
|
-
const raw =
|
|
14933
|
+
const raw = fs40.readFileSync(path37.join(dir, file), "utf-8");
|
|
14850
14934
|
const { agent, body } = readProfileAgents(raw);
|
|
14851
14935
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
14852
14936
|
blocks.push(`## ${file}
|
|
@@ -14895,8 +14979,8 @@ var init_loadQaContext = __esm({
|
|
|
14895
14979
|
});
|
|
14896
14980
|
|
|
14897
14981
|
// src/taskContext.ts
|
|
14898
|
-
import * as
|
|
14899
|
-
import * as
|
|
14982
|
+
import * as fs41 from "fs";
|
|
14983
|
+
import * as path38 from "path";
|
|
14900
14984
|
function buildTaskContext(args) {
|
|
14901
14985
|
return {
|
|
14902
14986
|
schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
|
|
@@ -14912,9 +14996,9 @@ function buildTaskContext(args) {
|
|
|
14912
14996
|
function persistTaskContext(cwd, ctx) {
|
|
14913
14997
|
try {
|
|
14914
14998
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
14915
|
-
|
|
14916
|
-
const file =
|
|
14917
|
-
|
|
14999
|
+
fs41.mkdirSync(dir, { recursive: true });
|
|
15000
|
+
const file = path38.join(dir, "task-context.json");
|
|
15001
|
+
fs41.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
14918
15002
|
`);
|
|
14919
15003
|
return file;
|
|
14920
15004
|
} catch (err) {
|
|
@@ -15341,19 +15425,19 @@ function parseAgencyModelProposal(raw) {
|
|
|
15341
15425
|
function normalizeBundleFiles(bundle) {
|
|
15342
15426
|
const seen = /* @__PURE__ */ new Set();
|
|
15343
15427
|
return bundle.files.map((file, index) => {
|
|
15344
|
-
const
|
|
15345
|
-
const parts =
|
|
15346
|
-
if (!
|
|
15428
|
+
const path52 = file.path.replace(/^\/+/, "");
|
|
15429
|
+
const parts = path52.split("/");
|
|
15430
|
+
if (!path52 || file.path.startsWith("/") || file.path.includes("\\") || parts.some((part) => !part || part === "." || part === "..")) {
|
|
15347
15431
|
throw new Error(`openAgencyModelReviewPr: files[${index}].path is unsafe`);
|
|
15348
15432
|
}
|
|
15349
15433
|
if (!/^(agents\/[^/]+\.md|capabilities\/[^/]+\/.+|goals\/(?:templates\/)?[^/]+\/.+|workflows\/[^/]+\.json)$/.test(
|
|
15350
|
-
|
|
15434
|
+
path52
|
|
15351
15435
|
)) {
|
|
15352
15436
|
throw new Error(`openAgencyModelReviewPr: files[${index}].path is not a supported definition path`);
|
|
15353
15437
|
}
|
|
15354
|
-
if (seen.has(
|
|
15355
|
-
seen.add(
|
|
15356
|
-
return { path:
|
|
15438
|
+
if (seen.has(path52)) throw new Error(`openAgencyModelReviewPr: duplicate generated file path: ${path52}`);
|
|
15439
|
+
seen.add(path52);
|
|
15440
|
+
return { path: path52, content: file.content.replace(/\r\n?/g, "\n") };
|
|
15357
15441
|
});
|
|
15358
15442
|
}
|
|
15359
15443
|
function buildProposalId(issueNumber, bundle, sourceLabel) {
|
|
@@ -16297,9 +16381,9 @@ var init_postResearchComment = __esm({
|
|
|
16297
16381
|
});
|
|
16298
16382
|
|
|
16299
16383
|
// src/scripts/prepareBrowserAuth.ts
|
|
16300
|
-
import * as
|
|
16384
|
+
import * as fs42 from "fs";
|
|
16301
16385
|
import * as os6 from "os";
|
|
16302
|
-
import * as
|
|
16386
|
+
import * as path39 from "path";
|
|
16303
16387
|
function appendAuthMessage(ctx, message) {
|
|
16304
16388
|
const current = typeof ctx.data.qaAuthBlock === "string" ? ctx.data.qaAuthBlock.trim() : "";
|
|
16305
16389
|
ctx.data.qaAuthBlock = current ? `${current}
|
|
@@ -16338,9 +16422,9 @@ async function githubJson(url, token) {
|
|
|
16338
16422
|
return await response.json();
|
|
16339
16423
|
}
|
|
16340
16424
|
function writeKodyStorageState(input) {
|
|
16341
|
-
const directory =
|
|
16342
|
-
|
|
16343
|
-
const file =
|
|
16425
|
+
const directory = fs42.mkdtempSync(path39.join(os6.tmpdir(), "kody-browser-auth-"));
|
|
16426
|
+
fs42.chmodSync(directory, 448);
|
|
16427
|
+
const file = path39.join(directory, "storage-state.json");
|
|
16344
16428
|
const now = Date.now();
|
|
16345
16429
|
const repoEntry = {
|
|
16346
16430
|
repoUrl: input.repoUrl,
|
|
@@ -16370,7 +16454,7 @@ function writeKodyStorageState(input) {
|
|
|
16370
16454
|
}
|
|
16371
16455
|
]
|
|
16372
16456
|
};
|
|
16373
|
-
|
|
16457
|
+
fs42.writeFileSync(file, JSON.stringify(storageState), { mode: 384 });
|
|
16374
16458
|
return { directory, file };
|
|
16375
16459
|
}
|
|
16376
16460
|
function configurePlaywright(profile, storageStatePath) {
|
|
@@ -16452,7 +16536,7 @@ async function prepareMethod(ctx, profile, method) {
|
|
|
16452
16536
|
configurePlaywright(profile, state.file);
|
|
16453
16537
|
const authDirectory = state.directory;
|
|
16454
16538
|
registerRuntimeCleanup(ctx, () => {
|
|
16455
|
-
|
|
16539
|
+
fs42.rmSync(authDirectory, { recursive: true, force: true });
|
|
16456
16540
|
});
|
|
16457
16541
|
appendAuthMessage(
|
|
16458
16542
|
ctx,
|
|
@@ -16460,7 +16544,7 @@ async function prepareMethod(ctx, profile, method) {
|
|
|
16460
16544
|
);
|
|
16461
16545
|
return true;
|
|
16462
16546
|
} catch (error) {
|
|
16463
|
-
if (state)
|
|
16547
|
+
if (state) fs42.rmSync(state.directory, { recursive: true, force: true });
|
|
16464
16548
|
const reason = error instanceof Error ? error.message : String(error);
|
|
16465
16549
|
appendAuthMessage(
|
|
16466
16550
|
ctx,
|
|
@@ -16573,9 +16657,9 @@ function latestResult(raw, agentResult) {
|
|
|
16573
16657
|
function recordField4(value) {
|
|
16574
16658
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
16575
16659
|
}
|
|
16576
|
-
function resolveDotted(root,
|
|
16577
|
-
if (!
|
|
16578
|
-
return
|
|
16660
|
+
function resolveDotted(root, path52) {
|
|
16661
|
+
if (!path52) return void 0;
|
|
16662
|
+
return path52.split(".").reduce((value, key) => recordField4(value)?.[key], root);
|
|
16579
16663
|
}
|
|
16580
16664
|
function stringValue4(value) {
|
|
16581
16665
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
@@ -16618,7 +16702,7 @@ var init_publishReport = __esm({
|
|
|
16618
16702
|
});
|
|
16619
16703
|
const runId = generatedAt.replace(/\.\d{3}Z$/, "Z").replace(/:/g, "-");
|
|
16620
16704
|
const tenantId2 = ctx.config.github?.owner && ctx.config.github.repo ? `${ctx.config.github.owner}/${ctx.config.github.repo}` : process.env.GITHUB_REPOSITORY;
|
|
16621
|
-
if (
|
|
16705
|
+
if (hasStateBackendConfig() && tenantId2) {
|
|
16622
16706
|
await createStateBackendFromEnv().saveReport(
|
|
16623
16707
|
tenantId2,
|
|
16624
16708
|
slug,
|
|
@@ -16634,7 +16718,7 @@ var init_publishReport = __esm({
|
|
|
16634
16718
|
generatedAt
|
|
16635
16719
|
);
|
|
16636
16720
|
} else if (process.env.GITHUB_ACTIONS === "true") {
|
|
16637
|
-
throw new Error("
|
|
16721
|
+
throw new Error("Kody backend access is required for reports in GitHub Actions");
|
|
16638
16722
|
}
|
|
16639
16723
|
};
|
|
16640
16724
|
}
|
|
@@ -17447,53 +17531,14 @@ function basePreviewAppName(repo) {
|
|
|
17447
17531
|
}
|
|
17448
17532
|
return `kp-${shortHash(owner)}-${shortHash(name)}-base`;
|
|
17449
17533
|
}
|
|
17450
|
-
function decryptVaultPayload(payload, keyRaw) {
|
|
17451
|
-
const parts = payload.split(":");
|
|
17452
|
-
if (parts.length !== 4 || parts[0] !== "v1") {
|
|
17453
|
-
throw new Error("invalid vault payload format");
|
|
17454
|
-
}
|
|
17455
|
-
const [, ivB64, ctB64, tagB64] = parts;
|
|
17456
|
-
const key = decodeMasterKey(keyRaw);
|
|
17457
|
-
if (key.length !== 32) {
|
|
17458
|
-
throw new Error("KODY_MASTER_KEY must decode to 32 bytes");
|
|
17459
|
-
}
|
|
17460
|
-
const iv = Buffer.from(ivB64, "base64");
|
|
17461
|
-
const ct = Buffer.from(ctB64, "base64");
|
|
17462
|
-
const tag = Buffer.from(tagB64, "base64");
|
|
17463
|
-
const decipher = createDecipheriv2("aes-256-gcm", key, iv);
|
|
17464
|
-
decipher.setAuthTag(tag);
|
|
17465
|
-
return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
|
|
17466
|
-
}
|
|
17467
|
-
function decodeMasterKey(keyRaw) {
|
|
17468
|
-
if (/^[0-9a-fA-F]{64}$/.test(keyRaw)) return Buffer.from(keyRaw, "hex");
|
|
17469
|
-
return Buffer.from(keyRaw.replace(/-/g, "+").replace(/_/g, "/"), "base64");
|
|
17470
|
-
}
|
|
17471
|
-
function derivePreviewVerifyKey(masterKeyRaw) {
|
|
17472
|
-
const masterKey = decodeMasterKey(masterKeyRaw);
|
|
17473
|
-
if (masterKey.length !== 32) {
|
|
17474
|
-
throw new Error("KODY_MASTER_KEY must decode to 32 bytes");
|
|
17475
|
-
}
|
|
17476
|
-
return Buffer.from(hkdfSync2("sha256", masterKey, Buffer.alloc(0), PREVIEW_KEY_INFO, 32)).toString("hex");
|
|
17477
|
-
}
|
|
17478
17534
|
function previewRuntimeEnv(args) {
|
|
17479
17535
|
return {
|
|
17480
17536
|
...args.buildEnv,
|
|
17481
|
-
KODY_PREVIEW_VERIFY_KEY:
|
|
17537
|
+
KODY_PREVIEW_VERIFY_KEY: args.previewVerifyKey,
|
|
17482
17538
|
KODY_REPO_CONTEXT: args.repo,
|
|
17483
17539
|
KODY_PR: String(args.pr)
|
|
17484
17540
|
};
|
|
17485
17541
|
}
|
|
17486
|
-
function buildEnvFromVault(doc) {
|
|
17487
|
-
const buildEnv = {};
|
|
17488
|
-
for (const [name, entry] of Object.entries(doc.secrets ?? {})) {
|
|
17489
|
-
if (!entry?.value) continue;
|
|
17490
|
-
if (NEVER_PASS_TO_BUILD.has(name)) continue;
|
|
17491
|
-
buildEnv[name] = entry.value;
|
|
17492
|
-
}
|
|
17493
|
-
const raw = doc.secrets?.KODY_PREVIEW_BUILD_MODE?.value;
|
|
17494
|
-
const buildMode = raw?.toLowerCase().trim() === "dev" ? "dev" : "prod";
|
|
17495
|
-
return { buildEnv, buildMode };
|
|
17496
|
-
}
|
|
17497
17542
|
function formatPreviewComment(args) {
|
|
17498
17543
|
return [
|
|
17499
17544
|
"<!-- kody-fly-preview -->",
|
|
@@ -17505,30 +17550,16 @@ function formatPreviewComment(args) {
|
|
|
17505
17550
|
function defaultImageTag(repo, ref) {
|
|
17506
17551
|
return createHash4("sha256").update(`${repo}@${ref}`).digest("hex").slice(0, 12);
|
|
17507
17552
|
}
|
|
17508
|
-
var NEVER_PASS_TO_BUILD, PREVIEW_KEY_INFO;
|
|
17509
17553
|
var init_previewBuildHelpers = __esm({
|
|
17510
17554
|
"src/scripts/previewBuildHelpers.ts"() {
|
|
17511
17555
|
"use strict";
|
|
17512
|
-
NEVER_PASS_TO_BUILD = /* @__PURE__ */ new Set([
|
|
17513
|
-
"FLY_API_TOKEN",
|
|
17514
|
-
"FLY_ORG_SLUG",
|
|
17515
|
-
"FLY_DEFAULT_REGION",
|
|
17516
|
-
"KODY_MASTER_KEY",
|
|
17517
|
-
// Preview-config knob; consumed by the dispatcher before spawn.
|
|
17518
|
-
"KODY_PREVIEW_BUILD_MODE",
|
|
17519
|
-
"KODY_PREVIEW_VERIFY_KEY",
|
|
17520
|
-
"KODY_REPO_CONTEXT",
|
|
17521
|
-
"KODY_PR",
|
|
17522
|
-
"KODY_BRANCH"
|
|
17523
|
-
]);
|
|
17524
|
-
PREVIEW_KEY_INFO = "kody-preview:v1";
|
|
17525
17556
|
}
|
|
17526
17557
|
});
|
|
17527
17558
|
|
|
17528
17559
|
// src/scripts/previewBuildRun.ts
|
|
17529
17560
|
import { spawn as spawn5 } from "child_process";
|
|
17530
17561
|
async function runCmd(cmd, args, opts = {}) {
|
|
17531
|
-
await new Promise((
|
|
17562
|
+
await new Promise((resolve17, reject) => {
|
|
17532
17563
|
const child = spawn5(cmd, args, {
|
|
17533
17564
|
cwd: opts.cwd,
|
|
17534
17565
|
env: { ...process.env, ...opts.env ?? {} },
|
|
@@ -17540,7 +17571,7 @@ async function runCmd(cmd, args, opts = {}) {
|
|
|
17540
17571
|
}
|
|
17541
17572
|
child.on("error", reject);
|
|
17542
17573
|
child.on("close", (code) => {
|
|
17543
|
-
if (code === 0)
|
|
17574
|
+
if (code === 0) resolve17();
|
|
17544
17575
|
else reject(new Error(`${cmd} ${args.join(" ")} exited ${code}`));
|
|
17545
17576
|
});
|
|
17546
17577
|
});
|
|
@@ -17612,12 +17643,12 @@ fi
|
|
|
17612
17643
|
|
|
17613
17644
|
// src/scripts/runPreviewBuild.ts
|
|
17614
17645
|
import { copyFile, writeFile } from "fs/promises";
|
|
17615
|
-
import * as
|
|
17616
|
-
import { fileURLToPath } from "url";
|
|
17646
|
+
import * as path40 from "path";
|
|
17647
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
17617
17648
|
function bundledDockerfilePath(mode) {
|
|
17618
|
-
const here =
|
|
17649
|
+
const here = path40.dirname(fileURLToPath2(import.meta.url));
|
|
17619
17650
|
const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
|
|
17620
|
-
return
|
|
17651
|
+
return path40.join(here, "preview-build-templates", file);
|
|
17621
17652
|
}
|
|
17622
17653
|
function required(name) {
|
|
17623
17654
|
const v = (process.env[name] ?? "").trim();
|
|
@@ -17630,16 +17661,6 @@ function flyHeaders(token) {
|
|
|
17630
17661
|
"Content-Type": "application/json"
|
|
17631
17662
|
};
|
|
17632
17663
|
}
|
|
17633
|
-
async function fetchVaultDoc(repo, masterKey) {
|
|
17634
|
-
const [owner, name] = repo.split("/", 2);
|
|
17635
|
-
if (!owner || !name) throw new Error(`invalid GITHUB_REPOSITORY "${repo}"`);
|
|
17636
|
-
const record2 = await createStateBackendFromEnv().getRepoDoc(`${owner}/${name}`, "secrets.enc");
|
|
17637
|
-
const raw = record2?.doc;
|
|
17638
|
-
const payload = raw && typeof raw === "object" && !Array.isArray(raw) && typeof raw.ciphertext === "string" ? raw.ciphertext : "";
|
|
17639
|
-
if (!payload) throw new Error("backend vault is empty \u2014 save secrets from the dashboard first");
|
|
17640
|
-
const plaintext = decryptVaultPayload(payload, masterKey);
|
|
17641
|
-
return JSON.parse(plaintext);
|
|
17642
|
-
}
|
|
17643
17664
|
async function flyAppExists(name, token) {
|
|
17644
17665
|
const res = await fetch(`${FLY_MACHINES}/apps/${encodeURIComponent(name)}`, {
|
|
17645
17666
|
headers: flyHeaders(token),
|
|
@@ -17814,7 +17835,7 @@ var FLY_MACHINES, FLY_GRAPHQL, REQ_TIMEOUT_MS2, runPreviewBuild;
|
|
|
17814
17835
|
var init_runPreviewBuild = __esm({
|
|
17815
17836
|
"src/scripts/runPreviewBuild.ts"() {
|
|
17816
17837
|
"use strict";
|
|
17817
|
-
|
|
17838
|
+
init_kody_api_client();
|
|
17818
17839
|
init_previewBuildHelpers();
|
|
17819
17840
|
init_previewBuildNamespace();
|
|
17820
17841
|
init_previewBuildRun();
|
|
@@ -17831,12 +17852,10 @@ var init_runPreviewBuild = __esm({
|
|
|
17831
17852
|
}
|
|
17832
17853
|
let repo;
|
|
17833
17854
|
let ref;
|
|
17834
|
-
let masterKey;
|
|
17835
17855
|
let ghToken3;
|
|
17836
17856
|
try {
|
|
17837
17857
|
repo = required("GITHUB_REPOSITORY");
|
|
17838
17858
|
ref = required("GITHUB_SHA");
|
|
17839
|
-
masterKey = required("KODY_MASTER_KEY");
|
|
17840
17859
|
ghToken3 = (process.env.KODY_TOKEN ?? process.env.GH_TOKEN ?? process.env.GITHUB_TOKEN ?? process.env.GH_PAT ?? "").trim();
|
|
17841
17860
|
if (!ghToken3) {
|
|
17842
17861
|
throw new Error("GitHub auth token missing (KODY_TOKEN / GH_TOKEN / GITHUB_TOKEN / GH_PAT all empty)");
|
|
@@ -17850,24 +17869,24 @@ var init_runPreviewBuild = __esm({
|
|
|
17850
17869
|
const appName = previewAppName(repo, pr);
|
|
17851
17870
|
const tag = defaultImageTag(repo, ref);
|
|
17852
17871
|
try {
|
|
17853
|
-
const
|
|
17854
|
-
const { buildEnv, buildMode } =
|
|
17855
|
-
const flyToken =
|
|
17872
|
+
const previewContext = await readPreviewContextFromKody();
|
|
17873
|
+
const { buildEnv, buildMode } = previewContext;
|
|
17874
|
+
const flyToken = previewContext.flyApiToken?.trim();
|
|
17856
17875
|
if (!flyToken) {
|
|
17857
17876
|
ctx.output.exitCode = 99;
|
|
17858
17877
|
ctx.output.reason = "runPreviewBuild: vault has no FLY_API_TOKEN \u2014 add it via the dashboard's /secrets page";
|
|
17859
17878
|
return;
|
|
17860
17879
|
}
|
|
17861
|
-
const orgSlug =
|
|
17862
|
-
const region =
|
|
17863
|
-
const nscTenantId =
|
|
17880
|
+
const orgSlug = previewContext.flyOrgSlug?.trim() || (process.env.FLY_ORG_SLUG ?? "personal").trim();
|
|
17881
|
+
const region = previewContext.flyRegion?.trim() || (process.env.FLY_REGION ?? "fra").trim();
|
|
17882
|
+
const nscTenantId = previewContext.namespaceTenantId?.trim() || "";
|
|
17864
17883
|
console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
|
|
17865
17884
|
if (Object.keys(buildEnv).length > 0) {
|
|
17866
17885
|
const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
17867
|
-
await writeFile(
|
|
17886
|
+
await writeFile(path40.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
|
|
17868
17887
|
`, "utf8");
|
|
17869
17888
|
}
|
|
17870
|
-
const consumerDockerfile =
|
|
17889
|
+
const consumerDockerfile = path40.join(ctx.cwd, "Dockerfile.preview");
|
|
17871
17890
|
const { stat } = await import("fs/promises");
|
|
17872
17891
|
let hasConsumerDockerfile = false;
|
|
17873
17892
|
try {
|
|
@@ -17942,7 +17961,7 @@ var init_runPreviewBuild = __esm({
|
|
|
17942
17961
|
appName,
|
|
17943
17962
|
region,
|
|
17944
17963
|
image: `registry.fly.io/${appName}:${tag}`,
|
|
17945
|
-
env: previewRuntimeEnv({ buildEnv,
|
|
17964
|
+
env: previewRuntimeEnv({ buildEnv, previewVerifyKey: previewContext.previewVerifyKey, pr, repo })
|
|
17946
17965
|
},
|
|
17947
17966
|
flyToken
|
|
17948
17967
|
);
|
|
@@ -18051,8 +18070,8 @@ var init_tickShellRunner = __esm({
|
|
|
18051
18070
|
});
|
|
18052
18071
|
|
|
18053
18072
|
// src/scripts/runScheduledImplementationTick.ts
|
|
18054
|
-
import * as
|
|
18055
|
-
import * as
|
|
18073
|
+
import * as fs43 from "fs";
|
|
18074
|
+
import * as path41 from "path";
|
|
18056
18075
|
var runScheduledImplementationTick;
|
|
18057
18076
|
var init_runScheduledImplementationTick = __esm({
|
|
18058
18077
|
"src/scripts/runScheduledImplementationTick.ts"() {
|
|
@@ -18073,14 +18092,14 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
18073
18092
|
ctx.output.reason = `runScheduledImplementationTick: args.slug or ctx.args.${slugArg} must be non-empty capability slug`;
|
|
18074
18093
|
return;
|
|
18075
18094
|
}
|
|
18076
|
-
const capability = resolveCapabilityFolder(slug,
|
|
18095
|
+
const capability = resolveCapabilityFolder(slug, path41.resolve(ctx.cwd, jobsDir));
|
|
18077
18096
|
if (!capability) {
|
|
18078
18097
|
ctx.output.exitCode = 99;
|
|
18079
18098
|
ctx.output.reason = `runScheduledImplementationTick: capability folder not found or incomplete: ${slug} (searched ${jobsDir} and company store)`;
|
|
18080
18099
|
return;
|
|
18081
18100
|
}
|
|
18082
|
-
const shellPath =
|
|
18083
|
-
if (!
|
|
18101
|
+
const shellPath = path41.join(profile.dir, shell);
|
|
18102
|
+
if (!fs43.existsSync(shellPath)) {
|
|
18084
18103
|
ctx.output.exitCode = 99;
|
|
18085
18104
|
ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
18086
18105
|
return;
|
|
@@ -18111,8 +18130,8 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
18111
18130
|
});
|
|
18112
18131
|
|
|
18113
18132
|
// src/scripts/runTickScript.ts
|
|
18114
|
-
import * as
|
|
18115
|
-
import * as
|
|
18133
|
+
import * as fs44 from "fs";
|
|
18134
|
+
import * as path42 from "path";
|
|
18116
18135
|
var runTickScript;
|
|
18117
18136
|
var init_runTickScript = __esm({
|
|
18118
18137
|
"src/scripts/runTickScript.ts"() {
|
|
@@ -18132,10 +18151,10 @@ var init_runTickScript = __esm({
|
|
|
18132
18151
|
ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
|
|
18133
18152
|
return;
|
|
18134
18153
|
}
|
|
18135
|
-
const capability = readCapabilityFolder(
|
|
18154
|
+
const capability = readCapabilityFolder(path42.resolve(ctx.cwd, jobsDir), slug);
|
|
18136
18155
|
if (!capability) {
|
|
18137
18156
|
ctx.output.exitCode = 99;
|
|
18138
|
-
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${
|
|
18157
|
+
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path42.resolve(ctx.cwd, jobsDir, slug)}`;
|
|
18139
18158
|
return;
|
|
18140
18159
|
}
|
|
18141
18160
|
const tickScript = capability.config.tickScript;
|
|
@@ -18144,8 +18163,8 @@ var init_runTickScript = __esm({
|
|
|
18144
18163
|
ctx.output.reason = `runTickScript: capability ${slug} has no \`tickScript\` in profile.json \u2014 route via capability-tick instead`;
|
|
18145
18164
|
return;
|
|
18146
18165
|
}
|
|
18147
|
-
const scriptPath =
|
|
18148
|
-
if (!
|
|
18166
|
+
const scriptPath = path42.isAbsolute(tickScript) ? tickScript : path42.join(ctx.cwd, tickScript);
|
|
18167
|
+
if (!fs44.existsSync(scriptPath)) {
|
|
18149
18168
|
ctx.output.exitCode = 99;
|
|
18150
18169
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
18151
18170
|
return;
|
|
@@ -18427,7 +18446,7 @@ var init_syncFlow = __esm({
|
|
|
18427
18446
|
});
|
|
18428
18447
|
|
|
18429
18448
|
// src/scripts/validateAgencyModelProposal.ts
|
|
18430
|
-
import * as
|
|
18449
|
+
import * as path43 from "path";
|
|
18431
18450
|
function validateModelBundle(bundle, expectedKind, options = {}) {
|
|
18432
18451
|
const failures = [];
|
|
18433
18452
|
validateOneModel(bundle.model, bundle.files, "model", true, failures, expectedKind, options);
|
|
@@ -18753,7 +18772,7 @@ var init_validateAgencyModelProposal = __esm({
|
|
|
18753
18772
|
const bundle = parseAgencyModelProposal(raw);
|
|
18754
18773
|
const expectedKind = readExpectedModelKind(args);
|
|
18755
18774
|
const failures = validateModelBundle(bundle, expectedKind, {
|
|
18756
|
-
capabilityRoot:
|
|
18775
|
+
capabilityRoot: path43.join(ctx.cwd, ".kody", "capabilities")
|
|
18757
18776
|
});
|
|
18758
18777
|
if (failures.length > 0) {
|
|
18759
18778
|
throw new Error(`validateAgencyModelProposal: ${failures.join("; ")}`);
|
|
@@ -18816,7 +18835,7 @@ function stripAnsi2(s) {
|
|
|
18816
18835
|
return s.replace(ANSI_RE2, "");
|
|
18817
18836
|
}
|
|
18818
18837
|
function runCommand2(command, cwd) {
|
|
18819
|
-
return new Promise((
|
|
18838
|
+
return new Promise((resolve17) => {
|
|
18820
18839
|
const child = spawn6(command, {
|
|
18821
18840
|
cwd,
|
|
18822
18841
|
shell: true,
|
|
@@ -18843,11 +18862,11 @@ function runCommand2(command, cwd) {
|
|
|
18843
18862
|
}, TEST_TIMEOUT_MS);
|
|
18844
18863
|
child.on("exit", (code) => {
|
|
18845
18864
|
clearTimeout(timer);
|
|
18846
|
-
|
|
18865
|
+
resolve17({ exitCode: code ?? -1, output: Buffer.concat(buffers).toString("utf-8") });
|
|
18847
18866
|
});
|
|
18848
18867
|
child.on("error", (err) => {
|
|
18849
18868
|
clearTimeout(timer);
|
|
18850
|
-
|
|
18869
|
+
resolve17({ exitCode: -1, output: err.message });
|
|
18851
18870
|
});
|
|
18852
18871
|
});
|
|
18853
18872
|
}
|
|
@@ -19253,21 +19272,21 @@ function lineStream(stream) {
|
|
|
19253
19272
|
tryDeliver();
|
|
19254
19273
|
});
|
|
19255
19274
|
return {
|
|
19256
|
-
next: (timeoutMs) => new Promise((
|
|
19275
|
+
next: (timeoutMs) => new Promise((resolve17) => {
|
|
19257
19276
|
if (queue.length > 0) {
|
|
19258
|
-
|
|
19277
|
+
resolve17(queue.shift());
|
|
19259
19278
|
return;
|
|
19260
19279
|
}
|
|
19261
19280
|
if (ended) {
|
|
19262
|
-
|
|
19281
|
+
resolve17(null);
|
|
19263
19282
|
return;
|
|
19264
19283
|
}
|
|
19265
|
-
waiter =
|
|
19284
|
+
waiter = resolve17;
|
|
19266
19285
|
const t = setTimeout(
|
|
19267
19286
|
() => {
|
|
19268
|
-
if (waiter ===
|
|
19287
|
+
if (waiter === resolve17) {
|
|
19269
19288
|
waiter = null;
|
|
19270
|
-
|
|
19289
|
+
resolve17(null);
|
|
19271
19290
|
}
|
|
19272
19291
|
},
|
|
19273
19292
|
Math.max(0, timeoutMs)
|
|
@@ -19304,7 +19323,7 @@ var init_warmupMcp = __esm({
|
|
|
19304
19323
|
});
|
|
19305
19324
|
|
|
19306
19325
|
// src/scripts/writeAgentRunSummary.ts
|
|
19307
|
-
import * as
|
|
19326
|
+
import * as fs45 from "fs";
|
|
19308
19327
|
var writeAgentRunSummary;
|
|
19309
19328
|
var init_writeAgentRunSummary = __esm({
|
|
19310
19329
|
"src/scripts/writeAgentRunSummary.ts"() {
|
|
@@ -19330,7 +19349,7 @@ var init_writeAgentRunSummary = __esm({
|
|
|
19330
19349
|
if (reason) lines.push(`- **Reason:** ${reason}`);
|
|
19331
19350
|
lines.push("");
|
|
19332
19351
|
try {
|
|
19333
|
-
|
|
19352
|
+
fs45.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
19334
19353
|
`);
|
|
19335
19354
|
} catch {
|
|
19336
19355
|
}
|
|
@@ -19656,17 +19675,17 @@ var init_scripts = __esm({
|
|
|
19656
19675
|
});
|
|
19657
19676
|
|
|
19658
19677
|
// src/stateWorkspace.ts
|
|
19659
|
-
import * as
|
|
19660
|
-
import * as
|
|
19678
|
+
import * as fs46 from "fs";
|
|
19679
|
+
import * as path44 from "path";
|
|
19661
19680
|
function tenantId(config) {
|
|
19662
19681
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
19663
19682
|
const repo = config.github?.repo?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim();
|
|
19664
19683
|
return owner && repo ? `${owner}/${repo}` : null;
|
|
19665
19684
|
}
|
|
19666
19685
|
function writeRuntimeFile(cwd, relativePath, content) {
|
|
19667
|
-
const target =
|
|
19668
|
-
|
|
19669
|
-
|
|
19686
|
+
const target = path44.join(cwd, RUNTIME_ROOT, relativePath);
|
|
19687
|
+
fs46.mkdirSync(path44.dirname(target), { recursive: true });
|
|
19688
|
+
fs46.writeFileSync(target, content, "utf8");
|
|
19670
19689
|
}
|
|
19671
19690
|
function record(value) {
|
|
19672
19691
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -19725,17 +19744,17 @@ async function hydrateWorkflows(backend, tenant, cwd) {
|
|
|
19725
19744
|
}
|
|
19726
19745
|
async function hydrateStateWorkspace(config, cwd, backendOverride) {
|
|
19727
19746
|
const tenant = tenantId(config);
|
|
19728
|
-
const configured =
|
|
19747
|
+
const configured = hasStateBackendConfig();
|
|
19729
19748
|
if (!tenant || !configured) {
|
|
19730
19749
|
if (process.env.GITHUB_ACTIONS === "true")
|
|
19731
|
-
throw new Error("
|
|
19750
|
+
throw new Error("Kody backend access is required for runtime workspace documents");
|
|
19732
19751
|
return;
|
|
19733
19752
|
}
|
|
19734
|
-
const key = `${
|
|
19753
|
+
const key = `${path44.resolve(cwd)}|${tenant}`;
|
|
19735
19754
|
if (hydratedWorkspaces.has(key)) return;
|
|
19736
19755
|
const backend = backendOverride ?? createStateBackendFromEnv();
|
|
19737
|
-
const root =
|
|
19738
|
-
|
|
19756
|
+
const root = path44.join(cwd, RUNTIME_ROOT);
|
|
19757
|
+
fs46.rmSync(root, { recursive: true, force: true });
|
|
19739
19758
|
await Promise.all([
|
|
19740
19759
|
hydratePrefix(backend, tenant, cwd, "context:"),
|
|
19741
19760
|
hydratePrefix(backend, tenant, cwd, "memory:"),
|
|
@@ -19751,7 +19770,7 @@ var init_stateWorkspace = __esm({
|
|
|
19751
19770
|
"src/stateWorkspace.ts"() {
|
|
19752
19771
|
"use strict";
|
|
19753
19772
|
init_state_backend();
|
|
19754
|
-
RUNTIME_ROOT =
|
|
19773
|
+
RUNTIME_ROOT = path44.join(".kody-engine", "runtime");
|
|
19755
19774
|
hydratedWorkspaces = /* @__PURE__ */ new Set();
|
|
19756
19775
|
}
|
|
19757
19776
|
});
|
|
@@ -19822,9 +19841,9 @@ var init_tools = __esm({
|
|
|
19822
19841
|
|
|
19823
19842
|
// src/executor.ts
|
|
19824
19843
|
import { spawn as spawn8 } from "child_process";
|
|
19825
|
-
import * as
|
|
19844
|
+
import * as fs47 from "fs";
|
|
19826
19845
|
import * as os7 from "os";
|
|
19827
|
-
import * as
|
|
19846
|
+
import * as path45 from "path";
|
|
19828
19847
|
function isMutatingPostflight(scriptName) {
|
|
19829
19848
|
return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
|
|
19830
19849
|
}
|
|
@@ -20056,7 +20075,7 @@ async function runImplementation(profileName, input) {
|
|
|
20056
20075
|
const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
|
|
20057
20076
|
const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
|
|
20058
20077
|
const invokeAgent = async (prompt) => {
|
|
20059
|
-
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) =>
|
|
20078
|
+
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path45.isAbsolute(p) ? p : path45.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
20060
20079
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
20061
20080
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
20062
20081
|
const agents = loadSubagents(profile);
|
|
@@ -20494,17 +20513,17 @@ function clearStampedLifecycleLabels(profile, ctx) {
|
|
|
20494
20513
|
function resolveProfilePath(profileName) {
|
|
20495
20514
|
const found = resolveImplementation(profileName);
|
|
20496
20515
|
if (found) return found;
|
|
20497
|
-
const here =
|
|
20516
|
+
const here = path45.dirname(new URL(import.meta.url).pathname);
|
|
20498
20517
|
const candidates = [
|
|
20499
|
-
|
|
20518
|
+
path45.join(here, "implementations", profileName, "profile.json"),
|
|
20500
20519
|
// same-dir sibling (dev)
|
|
20501
|
-
|
|
20520
|
+
path45.join(here, "..", "implementations", profileName, "profile.json"),
|
|
20502
20521
|
// up one (prod: dist/bin → dist/implementations)
|
|
20503
|
-
|
|
20522
|
+
path45.join(here, "..", "src", "implementations", profileName, "profile.json")
|
|
20504
20523
|
// fallback
|
|
20505
20524
|
];
|
|
20506
20525
|
for (const c of candidates) {
|
|
20507
|
-
if (
|
|
20526
|
+
if (fs47.existsSync(c)) return c;
|
|
20508
20527
|
}
|
|
20509
20528
|
return candidates[0];
|
|
20510
20529
|
}
|
|
@@ -20619,15 +20638,15 @@ function resolveShellTimeoutMs(entry) {
|
|
|
20619
20638
|
}
|
|
20620
20639
|
async function runShellEntry(entry, ctx, profile) {
|
|
20621
20640
|
const shellName = entry.shell;
|
|
20622
|
-
const shellPath =
|
|
20623
|
-
if (!
|
|
20641
|
+
const shellPath = path45.join(profile.dir, shellName);
|
|
20642
|
+
if (!fs47.existsSync(shellPath)) {
|
|
20624
20643
|
ctx.skipAgent = true;
|
|
20625
20644
|
ctx.output.exitCode = 99;
|
|
20626
20645
|
ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
|
|
20627
20646
|
return;
|
|
20628
20647
|
}
|
|
20629
20648
|
const positional = entry.with ? Object.values(entry.with).map((v) => String(v)) : [];
|
|
20630
|
-
const outputFile =
|
|
20649
|
+
const outputFile = path45.join(
|
|
20631
20650
|
os7.tmpdir(),
|
|
20632
20651
|
`kody-shell-output-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
20633
20652
|
);
|
|
@@ -20662,14 +20681,14 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
20662
20681
|
let killTimer;
|
|
20663
20682
|
let escalateTimer;
|
|
20664
20683
|
const result = await new Promise(
|
|
20665
|
-
(
|
|
20684
|
+
(resolve17) => {
|
|
20666
20685
|
let settled = false;
|
|
20667
20686
|
const settle = (code, signal, spawnErr) => {
|
|
20668
20687
|
if (settled) return;
|
|
20669
20688
|
settled = true;
|
|
20670
20689
|
if (killTimer) clearTimeout(killTimer);
|
|
20671
20690
|
if (escalateTimer) clearTimeout(escalateTimer);
|
|
20672
|
-
|
|
20691
|
+
resolve17({ code, signal, spawnErr });
|
|
20673
20692
|
};
|
|
20674
20693
|
child.on("error", (err) => settle(null, null, err));
|
|
20675
20694
|
child.on("close", (code, signal) => settle(code, signal));
|
|
@@ -20699,9 +20718,9 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
20699
20718
|
}
|
|
20700
20719
|
let sideChannelText = "";
|
|
20701
20720
|
try {
|
|
20702
|
-
if (
|
|
20703
|
-
sideChannelText =
|
|
20704
|
-
|
|
20721
|
+
if (fs47.existsSync(outputFile)) {
|
|
20722
|
+
sideChannelText = fs47.readFileSync(outputFile, "utf-8");
|
|
20723
|
+
fs47.rmSync(outputFile, { force: true });
|
|
20705
20724
|
}
|
|
20706
20725
|
} catch {
|
|
20707
20726
|
}
|
|
@@ -20872,7 +20891,7 @@ __export(job_exports, {
|
|
|
20872
20891
|
stableJobKey: () => stableJobKey,
|
|
20873
20892
|
validateJob: () => validateJob
|
|
20874
20893
|
});
|
|
20875
|
-
import * as
|
|
20894
|
+
import * as path46 from "path";
|
|
20876
20895
|
function newJobId(flavor) {
|
|
20877
20896
|
localJobSeq += 1;
|
|
20878
20897
|
const runId = process.env.GITHUB_RUN_ID;
|
|
@@ -21335,11 +21354,11 @@ function selectWorkflowTransition(step, data, counts) {
|
|
|
21335
21354
|
}
|
|
21336
21355
|
function workflowResultConditionPaths(transitions) {
|
|
21337
21356
|
return transitions.flatMap(
|
|
21338
|
-
(transition) => Object.keys(transition.when ?? {}).filter((
|
|
21357
|
+
(transition) => Object.keys(transition.when ?? {}).filter((path52) => path52.startsWith("result."))
|
|
21339
21358
|
);
|
|
21340
21359
|
}
|
|
21341
21360
|
function conditionMatches(condition, context) {
|
|
21342
|
-
return Object.entries(condition).every(([
|
|
21361
|
+
return Object.entries(condition).every(([path52, expected]) => valueMatches(resolveDottedPath2(context, path52), expected));
|
|
21343
21362
|
}
|
|
21344
21363
|
function withWorkflowBoundaryEval(capability, result) {
|
|
21345
21364
|
const capabilityKind = capability.config.capabilityKind;
|
|
@@ -21497,7 +21516,7 @@ function loadCapabilityContext(slug, cwd) {
|
|
|
21497
21516
|
return resolveCapabilityFolder(slug, hydratedCapabilitiesRoot(cwd));
|
|
21498
21517
|
}
|
|
21499
21518
|
function hydratedCapabilitiesRoot(cwd) {
|
|
21500
|
-
return
|
|
21519
|
+
return path46.join(cwd, ".kody-engine", "definitions", "capabilities");
|
|
21501
21520
|
}
|
|
21502
21521
|
function loadWorkflowContext(slug, base) {
|
|
21503
21522
|
if (!slug || !base.config || !isWorkflowDefinitionId(slug)) return null;
|
|
@@ -21660,7 +21679,7 @@ function translateOpenAISseToBrain(opts) {
|
|
|
21660
21679
|
|
|
21661
21680
|
// src/servers/brain-serve.ts
|
|
21662
21681
|
import { createServer as createServer2 } from "http";
|
|
21663
|
-
import * as
|
|
21682
|
+
import * as path49 from "path";
|
|
21664
21683
|
|
|
21665
21684
|
// src/chat/loop.ts
|
|
21666
21685
|
init_agent();
|
|
@@ -21814,9 +21833,9 @@ var CodexAppServerClient = class {
|
|
|
21814
21833
|
await this.request("thread/resume", { threadId });
|
|
21815
21834
|
}
|
|
21816
21835
|
async runTurn(args) {
|
|
21817
|
-
await new Promise((
|
|
21836
|
+
await new Promise((resolve17, reject) => {
|
|
21818
21837
|
this.process.turnWaiters.set(args.threadId, {
|
|
21819
|
-
resolve:
|
|
21838
|
+
resolve: resolve17,
|
|
21820
21839
|
reject,
|
|
21821
21840
|
onNotification: args.onNotification,
|
|
21822
21841
|
queue: Promise.resolve()
|
|
@@ -21833,8 +21852,8 @@ var CodexAppServerClient = class {
|
|
|
21833
21852
|
}
|
|
21834
21853
|
request(method, params) {
|
|
21835
21854
|
const id = this.process.nextId++;
|
|
21836
|
-
return new Promise((
|
|
21837
|
-
this.process.pending.set(id, { resolve:
|
|
21855
|
+
return new Promise((resolve17, reject) => {
|
|
21856
|
+
this.process.pending.set(id, { resolve: resolve17, reject });
|
|
21838
21857
|
this.process.child.stdin.write(`${JSON.stringify({ method, id, params })}
|
|
21839
21858
|
`);
|
|
21840
21859
|
});
|
|
@@ -22702,8 +22721,8 @@ init_config();
|
|
|
22702
22721
|
|
|
22703
22722
|
// src/kody-cli.ts
|
|
22704
22723
|
import { execFileSync as execFileSync24 } from "child_process";
|
|
22705
|
-
import * as
|
|
22706
|
-
import * as
|
|
22724
|
+
import * as fs48 from "fs";
|
|
22725
|
+
import * as path47 from "path";
|
|
22707
22726
|
|
|
22708
22727
|
// src/app-auth.ts
|
|
22709
22728
|
import { createSign } from "crypto";
|
|
@@ -23471,6 +23490,20 @@ function recoverCheckoutToken(env = process.env, cwd = process.cwd()) {
|
|
|
23471
23490
|
return token;
|
|
23472
23491
|
}
|
|
23473
23492
|
async function resolveAuthToken(env = process.env) {
|
|
23493
|
+
const readySources = [
|
|
23494
|
+
["GH_PAT", env.GH_PAT],
|
|
23495
|
+
["KODY_TOKEN", env.KODY_TOKEN],
|
|
23496
|
+
["GH_TOKEN", env.GH_TOKEN]
|
|
23497
|
+
];
|
|
23498
|
+
const ready = readySources.find(([, value]) => !!value?.trim());
|
|
23499
|
+
if (ready?.[1]) {
|
|
23500
|
+
const token2 = ready[1].trim();
|
|
23501
|
+
env.GH_TOKEN = token2;
|
|
23502
|
+
recoverCheckoutToken(env);
|
|
23503
|
+
process.stdout.write(`\u2192 kody: GH_TOKEN sourced from env.${ready[0]}
|
|
23504
|
+
`);
|
|
23505
|
+
return token2;
|
|
23506
|
+
}
|
|
23474
23507
|
const creds = readAppCreds(env);
|
|
23475
23508
|
if (creds) {
|
|
23476
23509
|
try {
|
|
@@ -23484,12 +23517,7 @@ async function resolveAuthToken(env = process.env) {
|
|
|
23484
23517
|
`);
|
|
23485
23518
|
}
|
|
23486
23519
|
}
|
|
23487
|
-
const sources = [
|
|
23488
|
-
["KODY_TOKEN", env.KODY_TOKEN],
|
|
23489
|
-
["GH_TOKEN", env.GH_TOKEN],
|
|
23490
|
-
["GITHUB_TOKEN", env.GITHUB_TOKEN],
|
|
23491
|
-
["GH_PAT", env.GH_PAT]
|
|
23492
|
-
];
|
|
23520
|
+
const sources = [["GITHUB_TOKEN", env.GITHUB_TOKEN]];
|
|
23493
23521
|
const picked = sources.find(([, v]) => !!v);
|
|
23494
23522
|
const token = picked?.[1];
|
|
23495
23523
|
if (token && !env.GH_TOKEN) env.GH_TOKEN = token;
|
|
@@ -23505,9 +23533,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
23505
23533
|
return void 0;
|
|
23506
23534
|
}
|
|
23507
23535
|
function detectPackageManager2(cwd) {
|
|
23508
|
-
if (
|
|
23509
|
-
if (
|
|
23510
|
-
if (
|
|
23536
|
+
if (fs48.existsSync(path47.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
23537
|
+
if (fs48.existsSync(path47.join(cwd, "yarn.lock"))) return "yarn";
|
|
23538
|
+
if (fs48.existsSync(path47.join(cwd, "bun.lockb"))) return "bun";
|
|
23511
23539
|
return "npm";
|
|
23512
23540
|
}
|
|
23513
23541
|
function shouldChainScheduledWatch(match) {
|
|
@@ -23600,8 +23628,8 @@ function postFailureTail(issueNumber, cwd, reason) {
|
|
|
23600
23628
|
const logPath = lastRunLogPath(cwd);
|
|
23601
23629
|
let tail = "";
|
|
23602
23630
|
try {
|
|
23603
|
-
if (
|
|
23604
|
-
const content =
|
|
23631
|
+
if (fs48.existsSync(logPath)) {
|
|
23632
|
+
const content = fs48.readFileSync(logPath, "utf-8");
|
|
23605
23633
|
tail = content.slice(-3e3);
|
|
23606
23634
|
}
|
|
23607
23635
|
} catch {
|
|
@@ -23630,7 +23658,7 @@ async function runCi(argv) {
|
|
|
23630
23658
|
return 0;
|
|
23631
23659
|
}
|
|
23632
23660
|
const args = parseCiArgs(argv);
|
|
23633
|
-
const cwd = args.cwd ?
|
|
23661
|
+
const cwd = args.cwd ? path47.resolve(args.cwd) : process.cwd();
|
|
23634
23662
|
try {
|
|
23635
23663
|
const n = unpackAllSecrets();
|
|
23636
23664
|
if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s) from ALL_SECRETS
|
|
@@ -23689,9 +23717,9 @@ async function runCi(argv) {
|
|
|
23689
23717
|
forceRunCliArgs = { goal: envForceMessage };
|
|
23690
23718
|
}
|
|
23691
23719
|
}
|
|
23692
|
-
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath &&
|
|
23720
|
+
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs48.existsSync(dispatchEventPath)) {
|
|
23693
23721
|
try {
|
|
23694
|
-
const evt = JSON.parse(
|
|
23722
|
+
const evt = JSON.parse(fs48.readFileSync(dispatchEventPath, "utf-8"));
|
|
23695
23723
|
const inputs = objectValue2(evt.inputs);
|
|
23696
23724
|
const issueInput = parseInt(String(inputs?.issue_number ?? ""), 10);
|
|
23697
23725
|
const sessionInput = String(inputs?.sessionId ?? "");
|
|
@@ -24064,8 +24092,8 @@ init_repoWorkspace();
|
|
|
24064
24092
|
|
|
24065
24093
|
// src/scripts/brainTurnLog.ts
|
|
24066
24094
|
init_runtimePaths();
|
|
24067
|
-
import * as
|
|
24068
|
-
import * as
|
|
24095
|
+
import * as fs49 from "fs";
|
|
24096
|
+
import * as path48 from "path";
|
|
24069
24097
|
import posixPath4 from "path/posix";
|
|
24070
24098
|
var live = /* @__PURE__ */ new Map();
|
|
24071
24099
|
function brainEventsFilePath(dir, chatId) {
|
|
@@ -24073,8 +24101,8 @@ function brainEventsFilePath(dir, chatId) {
|
|
|
24073
24101
|
}
|
|
24074
24102
|
function lastPersistedSeq(dir, chatId) {
|
|
24075
24103
|
const p = brainEventsFilePath(dir, chatId);
|
|
24076
|
-
if (!
|
|
24077
|
-
const lines =
|
|
24104
|
+
if (!fs49.existsSync(p)) return 0;
|
|
24105
|
+
const lines = fs49.readFileSync(p, "utf-8").split("\n").filter(Boolean);
|
|
24078
24106
|
if (lines.length === 0) return 0;
|
|
24079
24107
|
try {
|
|
24080
24108
|
return JSON.parse(lines[lines.length - 1]).seq || 0;
|
|
@@ -24084,9 +24112,9 @@ function lastPersistedSeq(dir, chatId) {
|
|
|
24084
24112
|
}
|
|
24085
24113
|
function readSince(dir, chatId, since) {
|
|
24086
24114
|
const p = brainEventsFilePath(dir, chatId);
|
|
24087
|
-
if (!
|
|
24115
|
+
if (!fs49.existsSync(p)) return [];
|
|
24088
24116
|
const out = [];
|
|
24089
|
-
for (const line of
|
|
24117
|
+
for (const line of fs49.readFileSync(p, "utf-8").split("\n")) {
|
|
24090
24118
|
if (!line) continue;
|
|
24091
24119
|
try {
|
|
24092
24120
|
const rec = JSON.parse(line);
|
|
@@ -24112,12 +24140,12 @@ function beginTurn(dir, chatId) {
|
|
|
24112
24140
|
};
|
|
24113
24141
|
live.set(chatId, state);
|
|
24114
24142
|
const p = brainEventsFilePath(dir, chatId);
|
|
24115
|
-
|
|
24143
|
+
fs49.mkdirSync(path48.dirname(p), { recursive: true });
|
|
24116
24144
|
return (event) => {
|
|
24117
24145
|
state.seq += 1;
|
|
24118
24146
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
24119
24147
|
try {
|
|
24120
|
-
|
|
24148
|
+
fs49.appendFileSync(p, `${JSON.stringify(rec)}
|
|
24121
24149
|
`);
|
|
24122
24150
|
} catch (err) {
|
|
24123
24151
|
process.stderr.write(
|
|
@@ -24156,7 +24184,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
|
|
|
24156
24184
|
event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
|
|
24157
24185
|
};
|
|
24158
24186
|
try {
|
|
24159
|
-
|
|
24187
|
+
fs49.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
|
|
24160
24188
|
`);
|
|
24161
24189
|
} catch {
|
|
24162
24190
|
}
|
|
@@ -24250,17 +24278,17 @@ function authOk(req, expected) {
|
|
|
24250
24278
|
return false;
|
|
24251
24279
|
}
|
|
24252
24280
|
function readJsonBody(req) {
|
|
24253
|
-
return new Promise((
|
|
24281
|
+
return new Promise((resolve17, reject) => {
|
|
24254
24282
|
const chunks = [];
|
|
24255
24283
|
req.on("data", (c) => chunks.push(c));
|
|
24256
24284
|
req.on("end", () => {
|
|
24257
24285
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
24258
24286
|
if (!raw.trim()) {
|
|
24259
|
-
|
|
24287
|
+
resolve17({});
|
|
24260
24288
|
return;
|
|
24261
24289
|
}
|
|
24262
24290
|
try {
|
|
24263
|
-
|
|
24291
|
+
resolve17(JSON.parse(raw));
|
|
24264
24292
|
} catch (err) {
|
|
24265
24293
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
24266
24294
|
}
|
|
@@ -24353,12 +24381,12 @@ var BrokerSink = class {
|
|
|
24353
24381
|
const be = translateChatEvent(event, this.chatId);
|
|
24354
24382
|
if (!be) return;
|
|
24355
24383
|
this.emitToLog(be);
|
|
24356
|
-
if (this.tenantId &&
|
|
24384
|
+
if (this.tenantId && hasStateBackendConfig2()) {
|
|
24357
24385
|
await createStateBackendFromEnv().appendChatEvent(this.tenantId, this.chatId, be);
|
|
24358
24386
|
}
|
|
24359
24387
|
}
|
|
24360
24388
|
};
|
|
24361
|
-
function
|
|
24389
|
+
function hasStateBackendConfig2(env = process.env) {
|
|
24362
24390
|
return Boolean(env.CONVEX_URL?.trim() && env.KODY_SERVICE_KEY?.trim());
|
|
24363
24391
|
}
|
|
24364
24392
|
var chatQueues = /* @__PURE__ */ new Map();
|
|
@@ -24519,7 +24547,7 @@ function buildServer(opts) {
|
|
|
24519
24547
|
const runTurn = opts.runTurn ?? runChatTurn;
|
|
24520
24548
|
const createStore = opts.createStore ?? createSessionStore;
|
|
24521
24549
|
const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
|
|
24522
|
-
const reposRoot = opts.reposRoot ??
|
|
24550
|
+
const reposRoot = opts.reposRoot ?? path49.join(path49.dirname(path49.resolve(opts.cwd)), "repos");
|
|
24523
24551
|
return createServer2(async (req, res) => {
|
|
24524
24552
|
if (!req.method || !req.url) {
|
|
24525
24553
|
sendJson(res, 400, { error: "bad request" });
|
|
@@ -24600,11 +24628,11 @@ async function brainServe(opts) {
|
|
|
24600
24628
|
litellmUrl,
|
|
24601
24629
|
driver
|
|
24602
24630
|
});
|
|
24603
|
-
await new Promise((
|
|
24631
|
+
await new Promise((resolve17) => {
|
|
24604
24632
|
server.listen(port, "0.0.0.0", () => {
|
|
24605
24633
|
process.stdout.write(`[brain-serve] listening on 0.0.0.0:${port} (cwd=${opts.cwd})
|
|
24606
24634
|
`);
|
|
24607
|
-
|
|
24635
|
+
resolve17();
|
|
24608
24636
|
});
|
|
24609
24637
|
});
|
|
24610
24638
|
const shutdown = (signal) => {
|
|
@@ -24859,14 +24887,14 @@ async function startBrainProxy(opts) {
|
|
|
24859
24887
|
const { httpServer, handler } = buildBrainProxy(opts);
|
|
24860
24888
|
const port = opts.port ?? 0;
|
|
24861
24889
|
const host = opts.host ?? "127.0.0.1";
|
|
24862
|
-
await new Promise((
|
|
24890
|
+
await new Promise((resolve17) => httpServer.listen(port, host, () => resolve17()));
|
|
24863
24891
|
const addr = httpServer.address();
|
|
24864
24892
|
return {
|
|
24865
24893
|
httpServer,
|
|
24866
24894
|
port: addr.port,
|
|
24867
24895
|
url: `http://${host}:${addr.port}`,
|
|
24868
|
-
stop: () => new Promise((
|
|
24869
|
-
httpServer.close(() =>
|
|
24896
|
+
stop: () => new Promise((resolve17) => {
|
|
24897
|
+
httpServer.close(() => resolve17());
|
|
24870
24898
|
}),
|
|
24871
24899
|
handler
|
|
24872
24900
|
};
|
|
@@ -25016,23 +25044,23 @@ function buildMcpHttpServer(opts) {
|
|
|
25016
25044
|
httpServer,
|
|
25017
25045
|
routes,
|
|
25018
25046
|
port,
|
|
25019
|
-
stop: () => new Promise((
|
|
25047
|
+
stop: () => new Promise((resolve17) => {
|
|
25020
25048
|
let pending = transports.size;
|
|
25021
25049
|
if (pending === 0) {
|
|
25022
|
-
httpServer.close(() =>
|
|
25050
|
+
httpServer.close(() => resolve17());
|
|
25023
25051
|
return;
|
|
25024
25052
|
}
|
|
25025
25053
|
for (const transport of transports.values()) {
|
|
25026
25054
|
void transport.close().finally(() => {
|
|
25027
25055
|
pending--;
|
|
25028
|
-
if (pending === 0) httpServer.close(() =>
|
|
25056
|
+
if (pending === 0) httpServer.close(() => resolve17());
|
|
25029
25057
|
});
|
|
25030
25058
|
}
|
|
25031
25059
|
})
|
|
25032
25060
|
};
|
|
25033
25061
|
}
|
|
25034
25062
|
function listenMcpHttpServer(server, host = "127.0.0.1") {
|
|
25035
|
-
return new Promise((
|
|
25063
|
+
return new Promise((resolve17, reject) => {
|
|
25036
25064
|
server.httpServer.once("error", reject);
|
|
25037
25065
|
server.httpServer.listen(server.port, host, () => {
|
|
25038
25066
|
server.httpServer.off("error", reject);
|
|
@@ -25040,7 +25068,7 @@ function listenMcpHttpServer(server, host = "127.0.0.1") {
|
|
|
25040
25068
|
if (addr && typeof addr === "object") {
|
|
25041
25069
|
server.port = addr.port;
|
|
25042
25070
|
}
|
|
25043
|
-
|
|
25071
|
+
resolve17();
|
|
25044
25072
|
});
|
|
25045
25073
|
});
|
|
25046
25074
|
}
|
|
@@ -25123,7 +25151,7 @@ async function loadConfigSafe() {
|
|
|
25123
25151
|
}
|
|
25124
25152
|
|
|
25125
25153
|
// src/chat-cli.ts
|
|
25126
|
-
import * as
|
|
25154
|
+
import * as path50 from "path";
|
|
25127
25155
|
|
|
25128
25156
|
// src/chat/inbox.ts
|
|
25129
25157
|
import { execFileSync as execFileSync25 } from "child_process";
|
|
@@ -25190,7 +25218,7 @@ async function waitForNextUserMessage(opts) {
|
|
|
25190
25218
|
}
|
|
25191
25219
|
}
|
|
25192
25220
|
function sleep3(ms) {
|
|
25193
|
-
return new Promise((
|
|
25221
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
25194
25222
|
}
|
|
25195
25223
|
function currentBranch(cwd) {
|
|
25196
25224
|
try {
|
|
@@ -25404,7 +25432,7 @@ async function runChat(argv) {
|
|
|
25404
25432
|
${CHAT_HELP}`);
|
|
25405
25433
|
return 64;
|
|
25406
25434
|
}
|
|
25407
|
-
const cwd = args.cwd ?
|
|
25435
|
+
const cwd = args.cwd ? path50.resolve(args.cwd) : process.cwd();
|
|
25408
25436
|
const sessionId = args.sessionId;
|
|
25409
25437
|
const runRequest = readRunRequestFromEnv();
|
|
25410
25438
|
if (runRequest && "request" in runRequest) {
|
|
@@ -25525,8 +25553,8 @@ init_config();
|
|
|
25525
25553
|
// src/definition-hydration.ts
|
|
25526
25554
|
init_state_backend();
|
|
25527
25555
|
import { createHash as createHash5 } from "crypto";
|
|
25528
|
-
import * as
|
|
25529
|
-
import * as
|
|
25556
|
+
import * as fs50 from "fs";
|
|
25557
|
+
import * as path51 from "path";
|
|
25530
25558
|
var SLUG_RE2 = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
25531
25559
|
function assertSafeDefinitionPath(filePath) {
|
|
25532
25560
|
const segments = filePath.split("/");
|
|
@@ -25560,32 +25588,32 @@ function writeDefinition(root, kind, definition) {
|
|
|
25560
25588
|
if (kind === "agent") {
|
|
25561
25589
|
const raw = bundle.files["agent.md"];
|
|
25562
25590
|
if (typeof raw !== "string") throw new Error(`agent definition ${definition.slug} is missing agent.md`);
|
|
25563
|
-
|
|
25591
|
+
fs50.writeFileSync(path51.join(root, "agents", `${definition.slug}.md`), raw, "utf8");
|
|
25564
25592
|
return;
|
|
25565
25593
|
}
|
|
25566
25594
|
if (kind === "goal") {
|
|
25567
|
-
const goalRoot =
|
|
25595
|
+
const goalRoot = path51.join(root, "goals", definition.slug);
|
|
25568
25596
|
for (const [filePath, contents] of Object.entries(bundle.files)) {
|
|
25569
|
-
const target =
|
|
25570
|
-
|
|
25571
|
-
|
|
25597
|
+
const target = path51.join(goalRoot, filePath);
|
|
25598
|
+
fs50.mkdirSync(path51.dirname(target), { recursive: true });
|
|
25599
|
+
fs50.writeFileSync(target, contents, "utf8");
|
|
25572
25600
|
}
|
|
25573
25601
|
return;
|
|
25574
25602
|
}
|
|
25575
|
-
const capabilityRoot =
|
|
25603
|
+
const capabilityRoot = path51.join(root, "capabilities", definition.slug);
|
|
25576
25604
|
for (const [filePath, contents] of Object.entries(bundle.files)) {
|
|
25577
|
-
const target =
|
|
25578
|
-
|
|
25579
|
-
|
|
25605
|
+
const target = path51.join(capabilityRoot, filePath);
|
|
25606
|
+
fs50.mkdirSync(path51.dirname(target), { recursive: true });
|
|
25607
|
+
fs50.writeFileSync(target, contents, "utf8");
|
|
25580
25608
|
}
|
|
25581
25609
|
}
|
|
25582
25610
|
async function hydrateDefinitions(options) {
|
|
25583
|
-
const root =
|
|
25611
|
+
const root = path51.join(options.cwd, ".kody-engine", "definitions");
|
|
25584
25612
|
const staging = `${root}.tmp-${process.pid}-${Date.now()}`;
|
|
25585
|
-
|
|
25586
|
-
|
|
25587
|
-
|
|
25588
|
-
|
|
25613
|
+
fs50.rmSync(staging, { recursive: true, force: true });
|
|
25614
|
+
fs50.mkdirSync(path51.join(staging, "agents"), { recursive: true });
|
|
25615
|
+
fs50.mkdirSync(path51.join(staging, "capabilities"), { recursive: true });
|
|
25616
|
+
fs50.mkdirSync(path51.join(staging, "goals"), { recursive: true });
|
|
25589
25617
|
try {
|
|
25590
25618
|
const [capabilities, agents, goals] = await Promise.all([
|
|
25591
25619
|
options.backend.listDefinitions(options.tenantId, "capability"),
|
|
@@ -25611,22 +25639,21 @@ async function hydrateDefinitions(options) {
|
|
|
25611
25639
|
hydratedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25612
25640
|
versions: Object.fromEntries(Object.entries(versions).sort(([left], [right]) => left.localeCompare(right)))
|
|
25613
25641
|
};
|
|
25614
|
-
|
|
25642
|
+
fs50.writeFileSync(path51.join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
25615
25643
|
`, "utf8");
|
|
25616
|
-
|
|
25617
|
-
|
|
25644
|
+
fs50.rmSync(root, { recursive: true, force: true });
|
|
25645
|
+
fs50.renameSync(staging, root);
|
|
25618
25646
|
return { root, tenantId: options.tenantId, versions: manifest.versions };
|
|
25619
25647
|
} catch (error) {
|
|
25620
|
-
|
|
25648
|
+
fs50.rmSync(staging, { recursive: true, force: true });
|
|
25621
25649
|
throw error;
|
|
25622
25650
|
}
|
|
25623
25651
|
}
|
|
25624
25652
|
async function hydrateDefinitionsFromEnv(cwd = process.cwd(), env = process.env) {
|
|
25625
25653
|
const tenantId2 = env.GITHUB_REPOSITORY?.trim();
|
|
25626
|
-
|
|
25627
|
-
if (!hasCredentials) {
|
|
25654
|
+
if (!hasStateBackendConfig(env)) {
|
|
25628
25655
|
if (env.GITHUB_ACTIONS === "true") {
|
|
25629
|
-
throw new Error("
|
|
25656
|
+
throw new Error("GitHub Actions workflow identity is required for backend definitions");
|
|
25630
25657
|
}
|
|
25631
25658
|
return null;
|
|
25632
25659
|
}
|
|
@@ -25711,8 +25738,8 @@ var FlyClient = class {
|
|
|
25711
25738
|
get fetch() {
|
|
25712
25739
|
return this.opts.fetchImpl ?? fetch;
|
|
25713
25740
|
}
|
|
25714
|
-
async call(
|
|
25715
|
-
const res = await this.fetch(`${FLY_API_BASE}${
|
|
25741
|
+
async call(path52, init = {}) {
|
|
25742
|
+
const res = await this.fetch(`${FLY_API_BASE}${path52}`, {
|
|
25716
25743
|
method: init.method ?? "GET",
|
|
25717
25744
|
headers: {
|
|
25718
25745
|
Authorization: `Bearer ${this.opts.token}`,
|
|
@@ -25723,7 +25750,7 @@ var FlyClient = class {
|
|
|
25723
25750
|
if (res.status === 404 && init.allow404) return null;
|
|
25724
25751
|
if (!res.ok) {
|
|
25725
25752
|
const text2 = await res.text().catch(() => "");
|
|
25726
|
-
throw new Error(`Fly API ${res.status} on ${
|
|
25753
|
+
throw new Error(`Fly API ${res.status} on ${path52}: ${text2.slice(0, 200) || res.statusText}`);
|
|
25727
25754
|
}
|
|
25728
25755
|
if (res.status === 204) return null;
|
|
25729
25756
|
const raw = await res.text();
|
|
@@ -26236,14 +26263,14 @@ function sendJson2(res, status, body) {
|
|
|
26236
26263
|
res.end(JSON.stringify(body));
|
|
26237
26264
|
}
|
|
26238
26265
|
function readJsonBody2(req) {
|
|
26239
|
-
return new Promise((
|
|
26266
|
+
return new Promise((resolve17, reject) => {
|
|
26240
26267
|
const chunks = [];
|
|
26241
26268
|
req.on("data", (c) => chunks.push(c));
|
|
26242
26269
|
req.on("end", () => {
|
|
26243
26270
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
26244
|
-
if (!raw.trim()) return
|
|
26271
|
+
if (!raw.trim()) return resolve17({});
|
|
26245
26272
|
try {
|
|
26246
|
-
|
|
26273
|
+
resolve17(JSON.parse(raw));
|
|
26247
26274
|
} catch (err) {
|
|
26248
26275
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
26249
26276
|
}
|
|
@@ -26454,10 +26481,10 @@ async function poolServe() {
|
|
|
26454
26481
|
}
|
|
26455
26482
|
});
|
|
26456
26483
|
const apiHost = process.env.POOL_API_HOST ?? "::";
|
|
26457
|
-
await new Promise((
|
|
26484
|
+
await new Promise((resolve17) => {
|
|
26458
26485
|
server.listen(apiPort, apiHost, () => {
|
|
26459
26486
|
log(`listening on ${apiHost}:${apiPort} (min=${min}, app=${app}, region=${region})`);
|
|
26460
|
-
|
|
26487
|
+
resolve17();
|
|
26461
26488
|
});
|
|
26462
26489
|
});
|
|
26463
26490
|
if (loopTickEnabled) void runLoopTick();
|
|
@@ -26476,7 +26503,7 @@ async function poolServe() {
|
|
|
26476
26503
|
|
|
26477
26504
|
// src/servers/runner-serve.ts
|
|
26478
26505
|
import { spawn as spawn9 } from "child_process";
|
|
26479
|
-
import * as
|
|
26506
|
+
import * as fs51 from "fs";
|
|
26480
26507
|
import { createServer as createServer6 } from "http";
|
|
26481
26508
|
var DEFAULT_PORT2 = 8080;
|
|
26482
26509
|
var DEFAULT_WORKDIR = "/workspace/repo";
|
|
@@ -26497,17 +26524,17 @@ function authOk2(req, expected) {
|
|
|
26497
26524
|
return false;
|
|
26498
26525
|
}
|
|
26499
26526
|
function readJsonBody3(req) {
|
|
26500
|
-
return new Promise((
|
|
26527
|
+
return new Promise((resolve17, reject) => {
|
|
26501
26528
|
const chunks = [];
|
|
26502
26529
|
req.on("data", (c) => chunks.push(c));
|
|
26503
26530
|
req.on("end", () => {
|
|
26504
26531
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
26505
26532
|
if (!raw.trim()) {
|
|
26506
|
-
|
|
26533
|
+
resolve17({});
|
|
26507
26534
|
return;
|
|
26508
26535
|
}
|
|
26509
26536
|
try {
|
|
26510
|
-
|
|
26537
|
+
resolve17(JSON.parse(raw));
|
|
26511
26538
|
} catch (err) {
|
|
26512
26539
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
26513
26540
|
}
|
|
@@ -26611,8 +26638,8 @@ async function defaultRunJob(job) {
|
|
|
26611
26638
|
const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
|
|
26612
26639
|
const branch = job.ref ?? "main";
|
|
26613
26640
|
const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
|
|
26614
|
-
|
|
26615
|
-
|
|
26641
|
+
fs51.rmSync(workdir, { recursive: true, force: true });
|
|
26642
|
+
fs51.mkdirSync(workdir, { recursive: true });
|
|
26616
26643
|
const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
|
|
26617
26644
|
const target = job.runRequest.target;
|
|
26618
26645
|
const interactive = target.type === "chat";
|
|
@@ -26641,13 +26668,13 @@ async function defaultRunJob(job) {
|
|
|
26641
26668
|
...interactive && job.idleExitMs ? { KODY_IDLE_EXIT_MS: String(job.idleExitMs) } : {},
|
|
26642
26669
|
...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
|
|
26643
26670
|
};
|
|
26644
|
-
const run = (cmd, args, cwd) => new Promise((
|
|
26671
|
+
const run = (cmd, args, cwd) => new Promise((resolve17) => {
|
|
26645
26672
|
const child = spawn9(cmd, args, { stdio: "inherit", env: childEnv, cwd });
|
|
26646
|
-
child.on("exit", (code) =>
|
|
26673
|
+
child.on("exit", (code) => resolve17(code ?? 0));
|
|
26647
26674
|
child.on("error", (err) => {
|
|
26648
26675
|
process.stderr.write(`[runner-serve] ${cmd} failed: ${err.message}
|
|
26649
26676
|
`);
|
|
26650
|
-
|
|
26677
|
+
resolve17(1);
|
|
26651
26678
|
});
|
|
26652
26679
|
});
|
|
26653
26680
|
process.stdout.write(`[runner-serve] job ${job.jobId}: cloning ${job.repo}@${branch}
|
|
@@ -26723,11 +26750,11 @@ async function runnerServe() {
|
|
|
26723
26750
|
const port = Number(process.env.PORT ?? DEFAULT_PORT2);
|
|
26724
26751
|
const server = buildServer2({ apiKey });
|
|
26725
26752
|
const host = process.env.RUNNER_HOST ?? "::";
|
|
26726
|
-
await new Promise((
|
|
26753
|
+
await new Promise((resolve17) => {
|
|
26727
26754
|
server.listen(port, host, () => {
|
|
26728
26755
|
process.stdout.write(`[runner-serve] listening on ${host}:${port} (idle, awaiting job)
|
|
26729
26756
|
`);
|
|
26730
|
-
|
|
26757
|
+
resolve17();
|
|
26731
26758
|
});
|
|
26732
26759
|
});
|
|
26733
26760
|
const shutdown = (signal) => {
|
|
@@ -26796,14 +26823,14 @@ async function serve(opts) {
|
|
|
26796
26823
|
`);
|
|
26797
26824
|
const args = ["--dangerously-skip-permissions", "--model", model.model];
|
|
26798
26825
|
const child = spawn10("claude", args, { stdio: "inherit", env: editorEnv, cwd: opts.cwd });
|
|
26799
|
-
const exitCode = await new Promise((
|
|
26800
|
-
child.on("exit", (code) =>
|
|
26826
|
+
const exitCode = await new Promise((resolve17) => {
|
|
26827
|
+
child.on("exit", (code) => resolve17(code ?? 0));
|
|
26801
26828
|
child.on("error", (err) => {
|
|
26802
26829
|
process.stderr.write(`[kody serve] failed to launch Claude Code: ${err.message}
|
|
26803
26830
|
`);
|
|
26804
26831
|
process.stderr.write(` Install: https://docs.anthropic.com/claude/docs/claude-code
|
|
26805
26832
|
`);
|
|
26806
|
-
|
|
26833
|
+
resolve17(1);
|
|
26807
26834
|
});
|
|
26808
26835
|
});
|
|
26809
26836
|
killProxy();
|
|
@@ -27187,7 +27214,7 @@ function parseArgs(argv) {
|
|
|
27187
27214
|
}
|
|
27188
27215
|
async function main(argv = process.argv.slice(2)) {
|
|
27189
27216
|
unpackAllSecrets();
|
|
27190
|
-
const cwdFlag = argv.
|
|
27217
|
+
const cwdFlag = argv.indexOf("--cwd");
|
|
27191
27218
|
const definitionCwd = cwdFlag >= 0 && argv[cwdFlag + 1] ? argv[cwdFlag + 1] : process.cwd();
|
|
27192
27219
|
const shouldHydrate = Boolean(process.env.CONVEX_URL?.trim()) || process.env.GITHUB_ACTIONS === "true" && Boolean(process.env.GITHUB_EVENT_NAME);
|
|
27193
27220
|
if (shouldHydrate) {
|