@kody-ade/kody-engine 0.4.645 → 0.4.647
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 +416 -209
- package/dist/implementations/types.ts +4 -1
- package/package.json +1 -1
package/dist/bin/kody.js
CHANGED
|
@@ -15,7 +15,7 @@ var init_package = __esm({
|
|
|
15
15
|
"package.json"() {
|
|
16
16
|
package_default = {
|
|
17
17
|
name: "@kody-ade/kody-engine",
|
|
18
|
-
version: "0.4.
|
|
18
|
+
version: "0.4.647",
|
|
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
|
repository: {
|
|
@@ -4606,6 +4606,8 @@ async function runAgent(opts) {
|
|
|
4606
4606
|
let tokens = { input: 0, output: 0, cacheRead: 0, cacheCreate: 0 };
|
|
4607
4607
|
let costUsd = 0;
|
|
4608
4608
|
let messageCount = 0;
|
|
4609
|
+
let turns = 0;
|
|
4610
|
+
let modelUsage = {};
|
|
4609
4611
|
let finalText = "";
|
|
4610
4612
|
let getSubmitted;
|
|
4611
4613
|
const invokedSubagents = /* @__PURE__ */ new Set();
|
|
@@ -4632,6 +4634,8 @@ async function runAgent(opts) {
|
|
|
4632
4634
|
tokens = { input: 0, output: 0, cacheRead: 0, cacheCreate: 0 };
|
|
4633
4635
|
costUsd = 0;
|
|
4634
4636
|
messageCount = 0;
|
|
4637
|
+
turns = 0;
|
|
4638
|
+
modelUsage = {};
|
|
4635
4639
|
let sawMutatingTool = false;
|
|
4636
4640
|
let sawTerminalSuccess = false;
|
|
4637
4641
|
let sawLoginRequired = false;
|
|
@@ -4940,6 +4944,9 @@ async function runAgent(opts) {
|
|
|
4940
4944
|
}
|
|
4941
4945
|
}
|
|
4942
4946
|
}
|
|
4947
|
+
if (m.type === "result") {
|
|
4948
|
+
tokens = { input: 0, output: 0, cacheRead: 0, cacheCreate: 0 };
|
|
4949
|
+
}
|
|
4943
4950
|
const usage = m.usage;
|
|
4944
4951
|
if (usage && typeof usage === "object") {
|
|
4945
4952
|
const i = Number(usage.input_tokens ?? 0);
|
|
@@ -4966,6 +4973,12 @@ async function runAgent(opts) {
|
|
|
4966
4973
|
if (m.type === "result") {
|
|
4967
4974
|
const reportedCost = Number(m.total_cost_usd ?? 0);
|
|
4968
4975
|
if (Number.isFinite(reportedCost) && reportedCost >= 0) costUsd = reportedCost;
|
|
4976
|
+
const reportedTurns = Number(m.num_turns ?? 0);
|
|
4977
|
+
if (Number.isFinite(reportedTurns) && reportedTurns >= 0) turns = reportedTurns;
|
|
4978
|
+
const reportedModelUsage = m.modelUsage;
|
|
4979
|
+
if (reportedModelUsage && typeof reportedModelUsage === "object" && !Array.isArray(reportedModelUsage)) {
|
|
4980
|
+
modelUsage = structuredClone(reportedModelUsage);
|
|
4981
|
+
}
|
|
4969
4982
|
if (m.subtype === "success") {
|
|
4970
4983
|
outcome = "completed";
|
|
4971
4984
|
outcomeKind = "ok";
|
|
@@ -5051,6 +5064,8 @@ async function runAgent(opts) {
|
|
|
5051
5064
|
tokens,
|
|
5052
5065
|
costUsd,
|
|
5053
5066
|
messageCount,
|
|
5067
|
+
turns,
|
|
5068
|
+
modelUsage,
|
|
5054
5069
|
invokedSubagents: [...invokedSubagents]
|
|
5055
5070
|
};
|
|
5056
5071
|
}
|
|
@@ -7360,17 +7375,155 @@ var init_state = __esm({
|
|
|
7360
7375
|
}
|
|
7361
7376
|
});
|
|
7362
7377
|
|
|
7363
|
-
// src/
|
|
7378
|
+
// src/usage.ts
|
|
7364
7379
|
import * as fs25 from "fs";
|
|
7380
|
+
function safeNumber(value) {
|
|
7381
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
|
|
7382
|
+
}
|
|
7383
|
+
function tokenBreakdown(tokens) {
|
|
7384
|
+
const input = safeNumber(tokens?.input);
|
|
7385
|
+
const output = safeNumber(tokens?.output);
|
|
7386
|
+
const cacheRead = safeNumber(tokens?.cacheRead);
|
|
7387
|
+
const cacheCreate = safeNumber(tokens?.cacheCreate);
|
|
7388
|
+
return { input, output, cacheRead, cacheCreate, total: input + output + cacheRead + cacheCreate };
|
|
7389
|
+
}
|
|
7390
|
+
function addTokenBreakdown(left, right) {
|
|
7391
|
+
const input = left.input + right.input;
|
|
7392
|
+
const output = left.output + right.output;
|
|
7393
|
+
const cacheRead = left.cacheRead + right.cacheRead;
|
|
7394
|
+
const cacheCreate = left.cacheCreate + right.cacheCreate;
|
|
7395
|
+
return { input, output, cacheRead, cacheCreate, total: input + output + cacheRead + cacheCreate };
|
|
7396
|
+
}
|
|
7397
|
+
function createRunUsage(tokens, costUsd, details = {}) {
|
|
7398
|
+
if (!tokens && costUsd === void 0 && details.turns === void 0) return void 0;
|
|
7399
|
+
const normalizedTokens = tokenBreakdown(tokens);
|
|
7400
|
+
const modelUsage = {
|
|
7401
|
+
tokens: normalizedTokens,
|
|
7402
|
+
costUsd: safeNumber(costUsd),
|
|
7403
|
+
agentRuns: 1,
|
|
7404
|
+
turns: safeNumber(details.turns)
|
|
7405
|
+
};
|
|
7406
|
+
const reportedModels = Object.entries(details.modelUsage ?? {});
|
|
7407
|
+
const byModel = reportedModels.length > 0 ? Object.fromEntries(
|
|
7408
|
+
reportedModels.map(([model, usage]) => {
|
|
7409
|
+
const modelTokens = tokenBreakdown({
|
|
7410
|
+
input: usage.inputTokens,
|
|
7411
|
+
output: usage.outputTokens,
|
|
7412
|
+
cacheRead: usage.cacheReadInputTokens,
|
|
7413
|
+
cacheCreate: usage.cacheCreationInputTokens
|
|
7414
|
+
});
|
|
7415
|
+
return [
|
|
7416
|
+
model,
|
|
7417
|
+
{
|
|
7418
|
+
tokens: modelTokens,
|
|
7419
|
+
costUsd: safeNumber(usage.costUSD),
|
|
7420
|
+
agentRuns: 1,
|
|
7421
|
+
turns: reportedModels.length === 1 ? safeNumber(details.turns) : 0
|
|
7422
|
+
}
|
|
7423
|
+
];
|
|
7424
|
+
})
|
|
7425
|
+
) : details.model ? { [details.model]: modelUsage } : {};
|
|
7426
|
+
return {
|
|
7427
|
+
version: 1,
|
|
7428
|
+
...modelUsage,
|
|
7429
|
+
byModel
|
|
7430
|
+
};
|
|
7431
|
+
}
|
|
7432
|
+
function isModelRunUsage(value) {
|
|
7433
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
7434
|
+
const usage = value;
|
|
7435
|
+
if (!usage.tokens || typeof usage.tokens !== "object" || Array.isArray(usage.tokens)) return false;
|
|
7436
|
+
return [
|
|
7437
|
+
usage.tokens.input,
|
|
7438
|
+
usage.tokens.output,
|
|
7439
|
+
usage.tokens.cacheRead,
|
|
7440
|
+
usage.tokens.cacheCreate,
|
|
7441
|
+
usage.tokens.total,
|
|
7442
|
+
usage.costUsd,
|
|
7443
|
+
usage.agentRuns,
|
|
7444
|
+
usage.turns
|
|
7445
|
+
].every((number) => typeof number === "number" && Number.isFinite(number) && number >= 0);
|
|
7446
|
+
}
|
|
7447
|
+
function parseRunUsage(value) {
|
|
7448
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
7449
|
+
const usage = value;
|
|
7450
|
+
if (usage.version !== 1 || !isModelRunUsage(usage)) return void 0;
|
|
7451
|
+
if (!usage.byModel || typeof usage.byModel !== "object" || Array.isArray(usage.byModel)) return void 0;
|
|
7452
|
+
if (!Object.values(usage.byModel).every(isModelRunUsage)) return void 0;
|
|
7453
|
+
return structuredClone(usage);
|
|
7454
|
+
}
|
|
7455
|
+
function mergeRunUsage(left, right) {
|
|
7456
|
+
if (!left) return right ? structuredClone(right) : void 0;
|
|
7457
|
+
if (!right) return structuredClone(left);
|
|
7458
|
+
const byModel = {};
|
|
7459
|
+
for (const model of /* @__PURE__ */ new Set([...Object.keys(left.byModel), ...Object.keys(right.byModel)])) {
|
|
7460
|
+
const first = left.byModel[model];
|
|
7461
|
+
const second = right.byModel[model];
|
|
7462
|
+
if (!first) {
|
|
7463
|
+
byModel[model] = structuredClone(second);
|
|
7464
|
+
} else if (!second) {
|
|
7465
|
+
byModel[model] = structuredClone(first);
|
|
7466
|
+
} else {
|
|
7467
|
+
byModel[model] = {
|
|
7468
|
+
tokens: addTokenBreakdown(first.tokens, second.tokens),
|
|
7469
|
+
costUsd: first.costUsd + second.costUsd,
|
|
7470
|
+
agentRuns: first.agentRuns + second.agentRuns,
|
|
7471
|
+
turns: first.turns + second.turns
|
|
7472
|
+
};
|
|
7473
|
+
}
|
|
7474
|
+
}
|
|
7475
|
+
return {
|
|
7476
|
+
version: 1,
|
|
7477
|
+
tokens: addTokenBreakdown(left.tokens, right.tokens),
|
|
7478
|
+
costUsd: left.costUsd + right.costUsd,
|
|
7479
|
+
agentRuns: left.agentRuns + right.agentRuns,
|
|
7480
|
+
turns: left.turns + right.turns,
|
|
7481
|
+
byModel
|
|
7482
|
+
};
|
|
7483
|
+
}
|
|
7484
|
+
function formatRunUsageMarker(subject, usage) {
|
|
7485
|
+
return `KODY_USAGE=${JSON.stringify({ subject, ...usage })}`;
|
|
7486
|
+
}
|
|
7487
|
+
function appendRunUsageSummary(summaryPath, subject, usage) {
|
|
7488
|
+
if (!summaryPath) return;
|
|
7489
|
+
const tokens = usage.tokens;
|
|
7490
|
+
const lines = [
|
|
7491
|
+
`### Kody usage - ${subject}`,
|
|
7492
|
+
"",
|
|
7493
|
+
`- **Tokens:** ${tokens.input.toLocaleString()} input / ${tokens.cacheRead.toLocaleString()} cache-read / ${tokens.cacheCreate.toLocaleString()} cache-create / ${tokens.output.toLocaleString()} output / ${tokens.total.toLocaleString()} total`,
|
|
7494
|
+
`- **Agent work:** ${usage.agentRuns.toLocaleString()} runs / ${usage.turns.toLocaleString()} turns`,
|
|
7495
|
+
`- **Provider-reported cost:** $${usage.costUsd.toFixed(4)}`,
|
|
7496
|
+
""
|
|
7497
|
+
];
|
|
7498
|
+
try {
|
|
7499
|
+
fs25.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
7500
|
+
`);
|
|
7501
|
+
} catch {
|
|
7502
|
+
}
|
|
7503
|
+
}
|
|
7504
|
+
function publishRunUsage(subject, usage) {
|
|
7505
|
+
if (!usage) return;
|
|
7506
|
+
process.stdout.write(`${formatRunUsageMarker(subject, usage)}
|
|
7507
|
+
`);
|
|
7508
|
+
appendRunUsageSummary(process.env.GITHUB_STEP_SUMMARY, subject, usage);
|
|
7509
|
+
}
|
|
7510
|
+
var init_usage = __esm({
|
|
7511
|
+
"src/usage.ts"() {
|
|
7512
|
+
"use strict";
|
|
7513
|
+
}
|
|
7514
|
+
});
|
|
7515
|
+
|
|
7516
|
+
// src/prompt.ts
|
|
7517
|
+
import * as fs26 from "fs";
|
|
7365
7518
|
import * as path25 from "path";
|
|
7366
7519
|
function loadProjectConventions(projectDir) {
|
|
7367
7520
|
const out = [];
|
|
7368
7521
|
for (const rel of CONVENTION_FILES) {
|
|
7369
7522
|
const abs = path25.join(projectDir, rel);
|
|
7370
|
-
if (!
|
|
7523
|
+
if (!fs26.existsSync(abs)) continue;
|
|
7371
7524
|
let content;
|
|
7372
7525
|
try {
|
|
7373
|
-
content =
|
|
7526
|
+
content = fs26.readFileSync(abs, "utf-8");
|
|
7374
7527
|
} catch {
|
|
7375
7528
|
continue;
|
|
7376
7529
|
}
|
|
@@ -7621,7 +7774,7 @@ var loadMemoryContext_exports = {};
|
|
|
7621
7774
|
__export(loadMemoryContext_exports, {
|
|
7622
7775
|
loadMemoryContext: () => loadMemoryContext
|
|
7623
7776
|
});
|
|
7624
|
-
import * as
|
|
7777
|
+
import * as fs27 from "fs";
|
|
7625
7778
|
import * as path26 from "path";
|
|
7626
7779
|
function formatBlockFromBackend(docs) {
|
|
7627
7780
|
const pages = docs.flatMap((record2) => {
|
|
@@ -7645,13 +7798,13 @@ function collectPages(memoryAbs) {
|
|
|
7645
7798
|
walkMd(memoryAbs, (file) => {
|
|
7646
7799
|
let stat;
|
|
7647
7800
|
try {
|
|
7648
|
-
stat =
|
|
7801
|
+
stat = fs27.statSync(file);
|
|
7649
7802
|
} catch {
|
|
7650
7803
|
return;
|
|
7651
7804
|
}
|
|
7652
7805
|
let raw;
|
|
7653
7806
|
try {
|
|
7654
|
-
raw =
|
|
7807
|
+
raw = fs27.readFileSync(file, "utf-8");
|
|
7655
7808
|
} catch {
|
|
7656
7809
|
return;
|
|
7657
7810
|
}
|
|
@@ -7727,7 +7880,7 @@ function walkMd(root, visit) {
|
|
|
7727
7880
|
const dir = stack.pop();
|
|
7728
7881
|
let names;
|
|
7729
7882
|
try {
|
|
7730
|
-
names =
|
|
7883
|
+
names = fs27.readdirSync(dir);
|
|
7731
7884
|
} catch {
|
|
7732
7885
|
continue;
|
|
7733
7886
|
}
|
|
@@ -7736,7 +7889,7 @@ function walkMd(root, visit) {
|
|
|
7736
7889
|
const full = path26.join(dir, name);
|
|
7737
7890
|
let stat;
|
|
7738
7891
|
try {
|
|
7739
|
-
stat =
|
|
7892
|
+
stat = fs27.statSync(full);
|
|
7740
7893
|
} catch {
|
|
7741
7894
|
continue;
|
|
7742
7895
|
}
|
|
@@ -7772,7 +7925,7 @@ var init_loadMemoryContext = __esm({
|
|
|
7772
7925
|
return;
|
|
7773
7926
|
}
|
|
7774
7927
|
const memoryAbs = path26.join(ctx.cwd, MEMORY_DIR_RELATIVE);
|
|
7775
|
-
if (!
|
|
7928
|
+
if (!fs27.existsSync(memoryAbs)) {
|
|
7776
7929
|
ctx.data.memoryContext = "";
|
|
7777
7930
|
return;
|
|
7778
7931
|
}
|
|
@@ -7816,11 +7969,11 @@ var init_loadCoverageRules = __esm({
|
|
|
7816
7969
|
|
|
7817
7970
|
// src/container.ts
|
|
7818
7971
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
7819
|
-
import * as
|
|
7972
|
+
import * as fs28 from "fs";
|
|
7820
7973
|
function getProfileInputsForChild(profileName, _cwd) {
|
|
7821
7974
|
try {
|
|
7822
7975
|
const profilePath = resolveProfilePath(profileName);
|
|
7823
|
-
if (!
|
|
7976
|
+
if (!fs28.existsSync(profilePath)) return null;
|
|
7824
7977
|
return loadProfile(profilePath).inputs;
|
|
7825
7978
|
} catch {
|
|
7826
7979
|
return null;
|
|
@@ -7952,6 +8105,7 @@ async function runContainerLoop(profile, ctx, input) {
|
|
|
7952
8105
|
// is off, so children fall back to their own loaders.
|
|
7953
8106
|
preloadedData: preloadedSnapshot
|
|
7954
8107
|
});
|
|
8108
|
+
ctx.output.usage = mergeRunUsage(ctx.output.usage, childOut.usage);
|
|
7955
8109
|
emitEvent(input.cwd, {
|
|
7956
8110
|
implementation: profile.name,
|
|
7957
8111
|
kind: "container_child",
|
|
@@ -8103,6 +8257,7 @@ var init_container = __esm({
|
|
|
8103
8257
|
init_executor();
|
|
8104
8258
|
init_profile();
|
|
8105
8259
|
init_state();
|
|
8260
|
+
init_usage();
|
|
8106
8261
|
CONTAINER_MAX_ITERATIONS = 50;
|
|
8107
8262
|
}
|
|
8108
8263
|
});
|
|
@@ -8284,7 +8439,7 @@ var init_lifecycleLabels = __esm({
|
|
|
8284
8439
|
|
|
8285
8440
|
// src/litellm.ts
|
|
8286
8441
|
import { execFileSync as execFileSync4, spawn as spawn4 } from "child_process";
|
|
8287
|
-
import * as
|
|
8442
|
+
import * as fs29 from "fs";
|
|
8288
8443
|
import * as net from "net";
|
|
8289
8444
|
import * as os4 from "os";
|
|
8290
8445
|
import * as path27 from "path";
|
|
@@ -8396,7 +8551,7 @@ function locateLitellmScript() {
|
|
|
8396
8551
|
}
|
|
8397
8552
|
function resolveLitellmCommand() {
|
|
8398
8553
|
const imageScript = "/opt/venv/bin/litellm";
|
|
8399
|
-
if (
|
|
8554
|
+
if (fs29.existsSync(imageScript)) return imageScript;
|
|
8400
8555
|
try {
|
|
8401
8556
|
execFileSync4("which", ["litellm"], { timeout: 3e3, stdio: "pipe" });
|
|
8402
8557
|
return "litellm";
|
|
@@ -8460,12 +8615,12 @@ async function startLitellmProxy(input) {
|
|
|
8460
8615
|
const portMatch = activeUrl.match(/:(\d+)/);
|
|
8461
8616
|
const port = portMatch ? portMatch[1] : "4000";
|
|
8462
8617
|
const configPath = path27.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.yaml`);
|
|
8463
|
-
|
|
8618
|
+
fs29.writeFileSync(configPath, input.configYaml);
|
|
8464
8619
|
const args = ["--config", configPath, "--port", port];
|
|
8465
8620
|
const nextLogPath = path27.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.log`);
|
|
8466
|
-
const outFd =
|
|
8621
|
+
const outFd = fs29.openSync(nextLogPath, "w");
|
|
8467
8622
|
child = spawn4(cmd, args, { stdio: ["ignore", outFd, outFd], detached: true, env: childEnv });
|
|
8468
|
-
|
|
8623
|
+
fs29.closeSync(outFd);
|
|
8469
8624
|
logPath = nextLogPath;
|
|
8470
8625
|
};
|
|
8471
8626
|
const waitForHealth = async () => {
|
|
@@ -8479,7 +8634,7 @@ async function startLitellmProxy(input) {
|
|
|
8479
8634
|
const readLogTail = () => {
|
|
8480
8635
|
if (!logPath) return "";
|
|
8481
8636
|
try {
|
|
8482
|
-
return
|
|
8637
|
+
return fs29.readFileSync(logPath, "utf-8").slice(-2e3);
|
|
8483
8638
|
} catch {
|
|
8484
8639
|
return "";
|
|
8485
8640
|
}
|
|
@@ -8563,9 +8718,9 @@ function canListen(port, host) {
|
|
|
8563
8718
|
}
|
|
8564
8719
|
function readDotenvApiKeys(projectDir) {
|
|
8565
8720
|
const dotenvPath = path27.join(projectDir, ".env");
|
|
8566
|
-
if (!
|
|
8721
|
+
if (!fs29.existsSync(dotenvPath)) return {};
|
|
8567
8722
|
const result = {};
|
|
8568
|
-
for (const rawLine of
|
|
8723
|
+
for (const rawLine of fs29.readFileSync(dotenvPath, "utf-8").split("\n")) {
|
|
8569
8724
|
const line = rawLine.trim();
|
|
8570
8725
|
if (!line || line.startsWith("#")) continue;
|
|
8571
8726
|
const match = line.match(/^([A-Z_][A-Z0-9_]*_API_KEY)=(.*)$/);
|
|
@@ -8647,7 +8802,8 @@ function finalizedRunIndexRow(row, result) {
|
|
|
8647
8802
|
status: result.status,
|
|
8648
8803
|
updatedAt: result.updatedAt,
|
|
8649
8804
|
summary: result.reason ?? row.summary,
|
|
8650
|
-
...result.output === void 0 ? {} : { output: result.output }
|
|
8805
|
+
...result.output === void 0 ? {} : { output: result.output },
|
|
8806
|
+
...result.usage === void 0 ? {} : { usage: result.usage }
|
|
8651
8807
|
};
|
|
8652
8808
|
}
|
|
8653
8809
|
function runIndexRowFromJobContext(input) {
|
|
@@ -8696,7 +8852,8 @@ function runIndexRowFromJobContext(input) {
|
|
|
8696
8852
|
reasoningEffort: stringValue(input.data.jobReasoningEffort) ?? void 0,
|
|
8697
8853
|
target: input.data.jobTarget,
|
|
8698
8854
|
sourceType: "job",
|
|
8699
|
-
output: input.data.capabilityOutput
|
|
8855
|
+
output: input.data.capabilityOutput,
|
|
8856
|
+
usage: input.usage
|
|
8700
8857
|
});
|
|
8701
8858
|
}
|
|
8702
8859
|
function runIndexRowFromGoalEvents(goalId, logPath, events) {
|
|
@@ -9239,7 +9396,7 @@ var init_pushWithRetry = __esm({
|
|
|
9239
9396
|
// src/commit.ts
|
|
9240
9397
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
9241
9398
|
import { isDeepStrictEqual } from "util";
|
|
9242
|
-
import * as
|
|
9399
|
+
import * as fs30 from "fs";
|
|
9243
9400
|
import * as path28 from "path";
|
|
9244
9401
|
function isGitHubYamlPath(filePath) {
|
|
9245
9402
|
const normalized = filePath.replace(/^\.\/+/, "");
|
|
@@ -9284,17 +9441,17 @@ function ensureGitIdentity(cwd) {
|
|
|
9284
9441
|
function abortUnfinishedGitOps(cwd) {
|
|
9285
9442
|
const aborted = [];
|
|
9286
9443
|
const gitDir = path28.join(cwd ?? process.cwd(), ".git");
|
|
9287
|
-
if (!
|
|
9288
|
-
if (
|
|
9444
|
+
if (!fs30.existsSync(gitDir)) return aborted;
|
|
9445
|
+
if (fs30.existsSync(path28.join(gitDir, "MERGE_HEAD"))) {
|
|
9289
9446
|
if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
|
|
9290
9447
|
}
|
|
9291
|
-
if (
|
|
9448
|
+
if (fs30.existsSync(path28.join(gitDir, "CHERRY_PICK_HEAD"))) {
|
|
9292
9449
|
if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
|
|
9293
9450
|
}
|
|
9294
|
-
if (
|
|
9451
|
+
if (fs30.existsSync(path28.join(gitDir, "REVERT_HEAD"))) {
|
|
9295
9452
|
if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
|
|
9296
9453
|
}
|
|
9297
|
-
if (
|
|
9454
|
+
if (fs30.existsSync(path28.join(gitDir, "rebase-merge")) || fs30.existsSync(path28.join(gitDir, "rebase-apply"))) {
|
|
9298
9455
|
if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
|
|
9299
9456
|
}
|
|
9300
9457
|
try {
|
|
@@ -9377,7 +9534,7 @@ function isTrustedConfigActivationChange(filePath, deliveryPathAllowlist, delive
|
|
|
9377
9534
|
if (filePath !== "kody.config.json" || !deliveryPathAllowlist.includes(filePath)) return false;
|
|
9378
9535
|
try {
|
|
9379
9536
|
const before = JSON.parse(git(["show", "HEAD:kody.config.json"], cwd));
|
|
9380
|
-
const after = JSON.parse(
|
|
9537
|
+
const after = JSON.parse(fs30.readFileSync(path28.join(cwd ?? process.cwd(), filePath), "utf-8"));
|
|
9381
9538
|
return isSafeConfigChange(before, after, deliveryConfigAllowlist[filePath] ?? []);
|
|
9382
9539
|
} catch {
|
|
9383
9540
|
return false;
|
|
@@ -9440,7 +9597,7 @@ function commitAndPush(branch, agentMessage, cwd, deliveryPathAllowlist = [], de
|
|
|
9440
9597
|
(f) => isForbiddenPath(f, deliveryPathAllowlist) && !isTrustedConfigActivationChange(f, deliveryPathAllowlist, deliveryConfigAllowlist, cwd)
|
|
9441
9598
|
);
|
|
9442
9599
|
const omittedFiles = forbiddenFiles.filter(isReportableDeliveryOmission);
|
|
9443
|
-
const mergeHeadExists =
|
|
9600
|
+
const mergeHeadExists = fs30.existsSync(path28.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
|
|
9444
9601
|
if (allowedFiles.length === 0 && !mergeHeadExists) {
|
|
9445
9602
|
return { committed: false, pushed: false, sha: "", message: "", omittedFiles };
|
|
9446
9603
|
}
|
|
@@ -10096,7 +10253,7 @@ var init_state2 = __esm({
|
|
|
10096
10253
|
});
|
|
10097
10254
|
|
|
10098
10255
|
// src/goal/runLog.ts
|
|
10099
|
-
import * as
|
|
10256
|
+
import * as fs31 from "fs";
|
|
10100
10257
|
function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
|
|
10101
10258
|
const logs = goalRunLogs(data);
|
|
10102
10259
|
const existing = logs[goalId];
|
|
@@ -10438,8 +10595,8 @@ function readGithubEvent() {
|
|
|
10438
10595
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
10439
10596
|
if (!eventPath) return null;
|
|
10440
10597
|
try {
|
|
10441
|
-
if (!
|
|
10442
|
-
const parsed = JSON.parse(
|
|
10598
|
+
if (!fs31.existsSync(eventPath)) return null;
|
|
10599
|
+
const parsed = JSON.parse(fs31.readFileSync(eventPath, "utf-8"));
|
|
10443
10600
|
return recordValue3(parsed);
|
|
10444
10601
|
} catch {
|
|
10445
10602
|
return null;
|
|
@@ -10549,7 +10706,7 @@ var init_stateStore = __esm({
|
|
|
10549
10706
|
});
|
|
10550
10707
|
|
|
10551
10708
|
// src/goal/targetLoopResolution.ts
|
|
10552
|
-
import * as
|
|
10709
|
+
import * as fs32 from "fs";
|
|
10553
10710
|
import * as path29 from "path";
|
|
10554
10711
|
async function resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal) {
|
|
10555
10712
|
const targetId = loopGoal.loopTarget?.id.trim() ?? "";
|
|
@@ -10631,8 +10788,8 @@ function loadGoalTemplate(cwd, targetId) {
|
|
|
10631
10788
|
return readJsonObject2(path29.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
|
|
10632
10789
|
}
|
|
10633
10790
|
function readJsonObject2(filePath) {
|
|
10634
|
-
if (!
|
|
10635
|
-
const parsed = JSON.parse(
|
|
10791
|
+
if (!fs32.existsSync(filePath)) return null;
|
|
10792
|
+
const parsed = JSON.parse(fs32.readFileSync(filePath, "utf8"));
|
|
10636
10793
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
10637
10794
|
throw new Error(`goal template ${filePath} must be a JSON object`);
|
|
10638
10795
|
}
|
|
@@ -11007,7 +11164,7 @@ var init_backendStateBackend = __esm({
|
|
|
11007
11164
|
});
|
|
11008
11165
|
|
|
11009
11166
|
// src/scripts/jobState/localFileBackend.ts
|
|
11010
|
-
import * as
|
|
11167
|
+
import * as fs33 from "fs";
|
|
11011
11168
|
import * as path30 from "path";
|
|
11012
11169
|
function sanitizeKey(s) {
|
|
11013
11170
|
return s.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
@@ -11079,7 +11236,7 @@ var init_localFileBackend = __esm({
|
|
|
11079
11236
|
`);
|
|
11080
11237
|
return;
|
|
11081
11238
|
}
|
|
11082
|
-
|
|
11239
|
+
fs33.mkdirSync(this.absDir, { recursive: true });
|
|
11083
11240
|
const prefix = this.cacheKeyPrefix();
|
|
11084
11241
|
const probeKey = `${prefix}probe-${Date.now()}`;
|
|
11085
11242
|
try {
|
|
@@ -11108,7 +11265,7 @@ var init_localFileBackend = __esm({
|
|
|
11108
11265
|
`);
|
|
11109
11266
|
return;
|
|
11110
11267
|
}
|
|
11111
|
-
if (!
|
|
11268
|
+
if (!fs33.existsSync(this.absDir)) {
|
|
11112
11269
|
return;
|
|
11113
11270
|
}
|
|
11114
11271
|
const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
|
|
@@ -11125,10 +11282,10 @@ var init_localFileBackend = __esm({
|
|
|
11125
11282
|
load(slug) {
|
|
11126
11283
|
const relPath = stateFilePath(this.jobsDir, slug);
|
|
11127
11284
|
const absPath = path30.resolve(this.cwd, relPath);
|
|
11128
|
-
if (!
|
|
11285
|
+
if (!fs33.existsSync(absPath)) {
|
|
11129
11286
|
return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
11130
11287
|
}
|
|
11131
|
-
const raw =
|
|
11288
|
+
const raw = fs33.readFileSync(absPath, "utf-8");
|
|
11132
11289
|
let parsed;
|
|
11133
11290
|
try {
|
|
11134
11291
|
parsed = JSON.parse(raw);
|
|
@@ -11146,12 +11303,12 @@ var init_localFileBackend = __esm({
|
|
|
11146
11303
|
return false;
|
|
11147
11304
|
}
|
|
11148
11305
|
const absPath = path30.resolve(this.cwd, loaded.path);
|
|
11149
|
-
|
|
11306
|
+
fs33.mkdirSync(path30.dirname(absPath), { recursive: true });
|
|
11150
11307
|
const body = `${JSON.stringify(next, null, 2)}
|
|
11151
11308
|
`;
|
|
11152
11309
|
const tmpPath = `${absPath}.${process.pid}.tmp`;
|
|
11153
|
-
|
|
11154
|
-
|
|
11310
|
+
fs33.writeFileSync(tmpPath, body, "utf-8");
|
|
11311
|
+
fs33.renameSync(tmpPath, absPath);
|
|
11155
11312
|
return true;
|
|
11156
11313
|
}
|
|
11157
11314
|
cacheKeyPrefix() {
|
|
@@ -13060,7 +13217,7 @@ var init_classifyByLabel = __esm({
|
|
|
13060
13217
|
|
|
13061
13218
|
// src/scripts/commitAndPush.ts
|
|
13062
13219
|
import { createHash as createHash5 } from "crypto";
|
|
13063
|
-
import * as
|
|
13220
|
+
import * as fs34 from "fs";
|
|
13064
13221
|
import * as path32 from "path";
|
|
13065
13222
|
function sentinelPathForStage(cwd, profileName, workflowExecutionKey) {
|
|
13066
13223
|
const runId = resolveRunId();
|
|
@@ -13083,9 +13240,9 @@ var init_commitAndPush = __esm({
|
|
|
13083
13240
|
}
|
|
13084
13241
|
const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
|
|
13085
13242
|
const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name, ctx.data.workflowExecutionKey) : null;
|
|
13086
|
-
if (sentinel &&
|
|
13243
|
+
if (sentinel && fs34.existsSync(sentinel)) {
|
|
13087
13244
|
try {
|
|
13088
|
-
const replay = JSON.parse(
|
|
13245
|
+
const replay = JSON.parse(fs34.readFileSync(sentinel, "utf-8"));
|
|
13089
13246
|
ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
|
|
13090
13247
|
if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
|
|
13091
13248
|
if (Array.isArray(replay.deliveryOmissions)) ctx.data.deliveryOmissions = replay.deliveryOmissions;
|
|
@@ -13149,8 +13306,8 @@ var init_commitAndPush = __esm({
|
|
|
13149
13306
|
const result = ctx.data.commitResult;
|
|
13150
13307
|
if (sentinel && result?.committed) {
|
|
13151
13308
|
try {
|
|
13152
|
-
|
|
13153
|
-
|
|
13309
|
+
fs34.mkdirSync(path32.dirname(sentinel), { recursive: true });
|
|
13310
|
+
fs34.writeFileSync(
|
|
13154
13311
|
sentinel,
|
|
13155
13312
|
JSON.stringify(
|
|
13156
13313
|
{
|
|
@@ -13277,7 +13434,7 @@ var init_acceptanceCriteria = __esm({
|
|
|
13277
13434
|
});
|
|
13278
13435
|
|
|
13279
13436
|
// src/scripts/composePrompt.ts
|
|
13280
|
-
import * as
|
|
13437
|
+
import * as fs35 from "fs";
|
|
13281
13438
|
import * as path33 from "path";
|
|
13282
13439
|
function fenceUntrusted(value) {
|
|
13283
13440
|
if (value.trim().length === 0) return value;
|
|
@@ -13419,7 +13576,7 @@ var init_composePrompt = __esm({
|
|
|
13419
13576
|
break;
|
|
13420
13577
|
}
|
|
13421
13578
|
try {
|
|
13422
|
-
template =
|
|
13579
|
+
template = fs35.readFileSync(c, "utf-8");
|
|
13423
13580
|
templatePath = c;
|
|
13424
13581
|
break;
|
|
13425
13582
|
} catch (err) {
|
|
@@ -13430,7 +13587,7 @@ var init_composePrompt = __esm({
|
|
|
13430
13587
|
if (!templatePath) {
|
|
13431
13588
|
let dirState;
|
|
13432
13589
|
try {
|
|
13433
|
-
dirState = `dir contents: [${
|
|
13590
|
+
dirState = `dir contents: [${fs35.readdirSync(profile.dir).join(", ")}]`;
|
|
13434
13591
|
} catch (err) {
|
|
13435
13592
|
dirState = `readdir(${profile.dir}) failed: ${err?.code ?? String(err)}`;
|
|
13436
13593
|
}
|
|
@@ -14168,7 +14325,7 @@ var init_deriveQaScopeFromIssue = __esm({
|
|
|
14168
14325
|
|
|
14169
14326
|
// src/scripts/diagMcp.ts
|
|
14170
14327
|
import { execFileSync as execFileSync9 } from "child_process";
|
|
14171
|
-
import * as
|
|
14328
|
+
import * as fs36 from "fs";
|
|
14172
14329
|
import * as os5 from "os";
|
|
14173
14330
|
import * as path34 from "path";
|
|
14174
14331
|
var diagMcp;
|
|
@@ -14180,7 +14337,7 @@ var init_diagMcp = __esm({
|
|
|
14180
14337
|
const cacheDir = path34.join(home, ".cache", "ms-playwright");
|
|
14181
14338
|
let entries = [];
|
|
14182
14339
|
try {
|
|
14183
|
-
entries =
|
|
14340
|
+
entries = fs36.readdirSync(cacheDir);
|
|
14184
14341
|
} catch {
|
|
14185
14342
|
}
|
|
14186
14343
|
const hasChromium = entries.some((e) => e.startsWith("chromium"));
|
|
@@ -14208,13 +14365,13 @@ var init_diagMcp = __esm({
|
|
|
14208
14365
|
});
|
|
14209
14366
|
|
|
14210
14367
|
// src/scripts/frameworkDetectors.ts
|
|
14211
|
-
import * as
|
|
14368
|
+
import * as fs37 from "fs";
|
|
14212
14369
|
import * as path35 from "path";
|
|
14213
14370
|
function detectFrameworks(cwd) {
|
|
14214
14371
|
const out = [];
|
|
14215
14372
|
let deps = {};
|
|
14216
14373
|
try {
|
|
14217
|
-
const pkg = JSON.parse(
|
|
14374
|
+
const pkg = JSON.parse(fs37.readFileSync(path35.join(cwd, "package.json"), "utf-8"));
|
|
14218
14375
|
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
14219
14376
|
} catch {
|
|
14220
14377
|
return out;
|
|
@@ -14251,7 +14408,7 @@ function detectFrameworks(cwd) {
|
|
|
14251
14408
|
}
|
|
14252
14409
|
function findFile(cwd, candidates) {
|
|
14253
14410
|
for (const c of candidates) {
|
|
14254
|
-
if (
|
|
14411
|
+
if (fs37.existsSync(path35.join(cwd, c))) return c;
|
|
14255
14412
|
}
|
|
14256
14413
|
return null;
|
|
14257
14414
|
}
|
|
@@ -14259,17 +14416,17 @@ function discoverPayloadCollections(cwd) {
|
|
|
14259
14416
|
const out = [];
|
|
14260
14417
|
for (const dir of COLLECTION_DIRS) {
|
|
14261
14418
|
const full = path35.join(cwd, dir);
|
|
14262
|
-
if (!
|
|
14419
|
+
if (!fs37.existsSync(full)) continue;
|
|
14263
14420
|
let files;
|
|
14264
14421
|
try {
|
|
14265
|
-
files =
|
|
14422
|
+
files = fs37.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
14266
14423
|
} catch {
|
|
14267
14424
|
continue;
|
|
14268
14425
|
}
|
|
14269
14426
|
for (const file of files) {
|
|
14270
14427
|
try {
|
|
14271
14428
|
const filePath = path35.join(full, file);
|
|
14272
|
-
const content =
|
|
14429
|
+
const content = fs37.readFileSync(filePath, "utf-8").slice(0, 1e4);
|
|
14273
14430
|
const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
|
|
14274
14431
|
if (!slugMatch) continue;
|
|
14275
14432
|
const slug = slugMatch[1];
|
|
@@ -14297,10 +14454,10 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
14297
14454
|
const out = [];
|
|
14298
14455
|
for (const dir of ADMIN_COMPONENT_DIRS) {
|
|
14299
14456
|
const full = path35.join(cwd, dir);
|
|
14300
|
-
if (!
|
|
14457
|
+
if (!fs37.existsSync(full)) continue;
|
|
14301
14458
|
let entries;
|
|
14302
14459
|
try {
|
|
14303
|
-
entries =
|
|
14460
|
+
entries = fs37.readdirSync(full, { withFileTypes: true });
|
|
14304
14461
|
} catch {
|
|
14305
14462
|
continue;
|
|
14306
14463
|
}
|
|
@@ -14310,7 +14467,7 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
14310
14467
|
let filePath;
|
|
14311
14468
|
if (entry.isDirectory()) {
|
|
14312
14469
|
const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
|
|
14313
|
-
(f) =>
|
|
14470
|
+
(f) => fs37.existsSync(path35.join(entryPath, f))
|
|
14314
14471
|
);
|
|
14315
14472
|
if (!indexFile) continue;
|
|
14316
14473
|
name = entry.name;
|
|
@@ -14325,7 +14482,7 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
14325
14482
|
if (collections) {
|
|
14326
14483
|
for (const col of collections) {
|
|
14327
14484
|
try {
|
|
14328
|
-
const colContent =
|
|
14485
|
+
const colContent = fs37.readFileSync(path35.join(cwd, col.filePath), "utf-8");
|
|
14329
14486
|
if (colContent.includes(name)) {
|
|
14330
14487
|
usedInCollection = col.slug;
|
|
14331
14488
|
break;
|
|
@@ -14344,7 +14501,7 @@ function scanApiRoutes(cwd) {
|
|
|
14344
14501
|
const appDirs = ["src/app", "app"];
|
|
14345
14502
|
for (const appDir of appDirs) {
|
|
14346
14503
|
const apiDir = path35.join(cwd, appDir, "api");
|
|
14347
|
-
if (!
|
|
14504
|
+
if (!fs37.existsSync(apiDir)) continue;
|
|
14348
14505
|
walkApiRoutes(apiDir, "/api", cwd, out);
|
|
14349
14506
|
break;
|
|
14350
14507
|
}
|
|
@@ -14353,14 +14510,14 @@ function scanApiRoutes(cwd) {
|
|
|
14353
14510
|
function walkApiRoutes(dir, prefix, cwd, out) {
|
|
14354
14511
|
let entries;
|
|
14355
14512
|
try {
|
|
14356
|
-
entries =
|
|
14513
|
+
entries = fs37.readdirSync(dir, { withFileTypes: true });
|
|
14357
14514
|
} catch {
|
|
14358
14515
|
return;
|
|
14359
14516
|
}
|
|
14360
14517
|
const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
|
|
14361
14518
|
if (routeFile) {
|
|
14362
14519
|
try {
|
|
14363
|
-
const content =
|
|
14520
|
+
const content = fs37.readFileSync(path35.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
|
|
14364
14521
|
const methods = HTTP_METHODS.filter(
|
|
14365
14522
|
(m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
|
|
14366
14523
|
);
|
|
@@ -14394,9 +14551,9 @@ function scanEnvVars(cwd) {
|
|
|
14394
14551
|
const candidates = [".env.example", ".env.local.example", ".env.template"];
|
|
14395
14552
|
for (const envFile of candidates) {
|
|
14396
14553
|
const envPath = path35.join(cwd, envFile);
|
|
14397
|
-
if (!
|
|
14554
|
+
if (!fs37.existsSync(envPath)) continue;
|
|
14398
14555
|
try {
|
|
14399
|
-
const content =
|
|
14556
|
+
const content = fs37.readFileSync(envPath, "utf-8");
|
|
14400
14557
|
const vars = [];
|
|
14401
14558
|
for (const line of content.split("\n")) {
|
|
14402
14559
|
const trimmed = line.trim();
|
|
@@ -14441,7 +14598,7 @@ var init_frameworkDetectors = __esm({
|
|
|
14441
14598
|
});
|
|
14442
14599
|
|
|
14443
14600
|
// src/scripts/discoverQaContext.ts
|
|
14444
|
-
import * as
|
|
14601
|
+
import * as fs38 from "fs";
|
|
14445
14602
|
import * as path36 from "path";
|
|
14446
14603
|
function runQaDiscovery(cwd) {
|
|
14447
14604
|
const out = {
|
|
@@ -14473,9 +14630,9 @@ function runQaDiscovery(cwd) {
|
|
|
14473
14630
|
}
|
|
14474
14631
|
function detectDevServer(cwd, out) {
|
|
14475
14632
|
try {
|
|
14476
|
-
const pkg = JSON.parse(
|
|
14633
|
+
const pkg = JSON.parse(fs38.readFileSync(path36.join(cwd, "package.json"), "utf-8"));
|
|
14477
14634
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
14478
|
-
const pm =
|
|
14635
|
+
const pm = fs38.existsSync(path36.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs38.existsSync(path36.join(cwd, "yarn.lock")) ? "yarn" : fs38.existsSync(path36.join(cwd, "bun.lockb")) ? "bun" : "npm";
|
|
14479
14636
|
if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
|
|
14480
14637
|
if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
|
|
14481
14638
|
else if (allDeps.vite) out.devPort = 5173;
|
|
@@ -14486,7 +14643,7 @@ function scanFrontendRoutes(cwd, out) {
|
|
|
14486
14643
|
const appDirs = ["src/app", "app"];
|
|
14487
14644
|
for (const appDir of appDirs) {
|
|
14488
14645
|
const full = path36.join(cwd, appDir);
|
|
14489
|
-
if (!
|
|
14646
|
+
if (!fs38.existsSync(full)) continue;
|
|
14490
14647
|
walkFrontendRoutes(full, "", out);
|
|
14491
14648
|
break;
|
|
14492
14649
|
}
|
|
@@ -14494,7 +14651,7 @@ function scanFrontendRoutes(cwd, out) {
|
|
|
14494
14651
|
function walkFrontendRoutes(dir, prefix, out) {
|
|
14495
14652
|
let entries;
|
|
14496
14653
|
try {
|
|
14497
|
-
entries =
|
|
14654
|
+
entries = fs38.readdirSync(dir, { withFileTypes: true });
|
|
14498
14655
|
} catch {
|
|
14499
14656
|
return;
|
|
14500
14657
|
}
|
|
@@ -14536,23 +14693,23 @@ function detectAuthFiles(cwd, out) {
|
|
|
14536
14693
|
"src/app/api/oauth"
|
|
14537
14694
|
];
|
|
14538
14695
|
for (const c of candidates) {
|
|
14539
|
-
if (
|
|
14696
|
+
if (fs38.existsSync(path36.join(cwd, c))) out.authFiles.push(c);
|
|
14540
14697
|
}
|
|
14541
14698
|
}
|
|
14542
14699
|
function detectRoles(cwd, out) {
|
|
14543
14700
|
const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
|
|
14544
14701
|
for (const rp of rolePaths) {
|
|
14545
14702
|
const dir = path36.join(cwd, rp);
|
|
14546
|
-
if (!
|
|
14703
|
+
if (!fs38.existsSync(dir)) continue;
|
|
14547
14704
|
let files;
|
|
14548
14705
|
try {
|
|
14549
|
-
files =
|
|
14706
|
+
files = fs38.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
14550
14707
|
} catch {
|
|
14551
14708
|
continue;
|
|
14552
14709
|
}
|
|
14553
14710
|
for (const f of files) {
|
|
14554
14711
|
try {
|
|
14555
|
-
const content =
|
|
14712
|
+
const content = fs38.readFileSync(path36.join(dir, f), "utf-8").slice(0, 5e3);
|
|
14556
14713
|
const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
|
|
14557
14714
|
if (roleMatches) {
|
|
14558
14715
|
for (const m of roleMatches) {
|
|
@@ -14813,7 +14970,7 @@ var init_dispatchClassified = __esm({
|
|
|
14813
14970
|
});
|
|
14814
14971
|
|
|
14815
14972
|
// src/loopDefinitions.ts
|
|
14816
|
-
import * as
|
|
14973
|
+
import * as fs39 from "fs";
|
|
14817
14974
|
import * as path37 from "path";
|
|
14818
14975
|
function normalizeLoopDefinition(value) {
|
|
14819
14976
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
@@ -14842,9 +14999,9 @@ function readLoopDefinition(cwd, id) {
|
|
|
14842
14999
|
const roots = loopRoots(cwd);
|
|
14843
15000
|
for (const root of roots) {
|
|
14844
15001
|
const filePath = path37.join(root, "loops", id, "loop.json");
|
|
14845
|
-
if (!
|
|
15002
|
+
if (!fs39.existsSync(filePath)) continue;
|
|
14846
15003
|
try {
|
|
14847
|
-
const loop = normalizeLoopDefinition(JSON.parse(
|
|
15004
|
+
const loop = normalizeLoopDefinition(JSON.parse(fs39.readFileSync(filePath, "utf8")));
|
|
14848
15005
|
if (loop?.id === id) return loop;
|
|
14849
15006
|
process.stderr.write(`[kody] invalid Loop definition: ${filePath}
|
|
14850
15007
|
`);
|
|
@@ -14864,13 +15021,13 @@ function listLoopDefinitions(cwd) {
|
|
|
14864
15021
|
const byId = /* @__PURE__ */ new Map();
|
|
14865
15022
|
for (const root of roots.reverse()) {
|
|
14866
15023
|
const loopsDir = path37.join(root, "loops");
|
|
14867
|
-
if (!
|
|
14868
|
-
for (const id of
|
|
15024
|
+
if (!fs39.existsSync(loopsDir)) continue;
|
|
15025
|
+
for (const id of fs39.readdirSync(loopsDir).sort()) {
|
|
14869
15026
|
if (!ID.test(id)) continue;
|
|
14870
15027
|
const filePath = path37.join(loopsDir, id, "loop.json");
|
|
14871
|
-
if (!
|
|
15028
|
+
if (!fs39.existsSync(filePath)) continue;
|
|
14872
15029
|
try {
|
|
14873
|
-
const loop = normalizeLoopDefinition(JSON.parse(
|
|
15030
|
+
const loop = normalizeLoopDefinition(JSON.parse(fs39.readFileSync(filePath, "utf8")));
|
|
14874
15031
|
if (loop?.id === id) byId.set(id, loop);
|
|
14875
15032
|
} catch {
|
|
14876
15033
|
process.stderr.write(`[kody] unreadable Loop definition: ${filePath}
|
|
@@ -16235,15 +16392,15 @@ var init_fixFlow = __esm({
|
|
|
16235
16392
|
});
|
|
16236
16393
|
|
|
16237
16394
|
// src/workflow-template.ts
|
|
16238
|
-
import * as
|
|
16395
|
+
import * as fs40 from "fs";
|
|
16239
16396
|
import * as path38 from "path";
|
|
16240
16397
|
import { fileURLToPath } from "url";
|
|
16241
16398
|
function loadKodyWorkflowTemplate() {
|
|
16242
16399
|
const here = path38.dirname(fileURLToPath(import.meta.url));
|
|
16243
16400
|
const candidates = [path38.resolve(here, "../templates/kody.yml"), path38.resolve(here, "../../templates/kody.yml")];
|
|
16244
|
-
const source = candidates.find((candidate) =>
|
|
16401
|
+
const source = candidates.find((candidate) => fs40.existsSync(candidate));
|
|
16245
16402
|
if (!source) throw new Error(`Kody workflow template is missing: ${KODY_WORKFLOW_TEMPLATE_PATH}`);
|
|
16246
|
-
return
|
|
16403
|
+
return fs40.readFileSync(source, "utf8");
|
|
16247
16404
|
}
|
|
16248
16405
|
var KODY_WORKFLOW_TEMPLATE_PATH;
|
|
16249
16406
|
var init_workflow_template = __esm({
|
|
@@ -16255,7 +16412,7 @@ var init_workflow_template = __esm({
|
|
|
16255
16412
|
|
|
16256
16413
|
// src/scripts/initFlow.ts
|
|
16257
16414
|
import { execFileSync as execFileSync14 } from "child_process";
|
|
16258
|
-
import * as
|
|
16415
|
+
import * as fs41 from "fs";
|
|
16259
16416
|
import * as path39 from "path";
|
|
16260
16417
|
function schemaUrlFromPkg() {
|
|
16261
16418
|
const fallback = "https://raw.githubusercontent.com/aharonyaircohen/kody-engine/main/kody.config.schema.json";
|
|
@@ -16321,21 +16478,21 @@ function performInit(cwd, force, workflowOnly = false) {
|
|
|
16321
16478
|
const configPath = path39.join(cwd, "kody.config.json");
|
|
16322
16479
|
if (workflowOnly) {
|
|
16323
16480
|
skipped.push("kody.config.json");
|
|
16324
|
-
} else if (
|
|
16481
|
+
} else if (fs41.existsSync(configPath) && !force) {
|
|
16325
16482
|
skipped.push("kody.config.json");
|
|
16326
16483
|
} else {
|
|
16327
16484
|
const cfg = makeConfig(cwd, ownerRepo, defaultBranch);
|
|
16328
|
-
|
|
16485
|
+
fs41.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
16329
16486
|
`);
|
|
16330
16487
|
wrote.push("kody.config.json");
|
|
16331
16488
|
}
|
|
16332
16489
|
const workflowDir = path39.join(cwd, ".github", "workflows");
|
|
16333
16490
|
const workflowPath = path39.join(workflowDir, "kody.yml");
|
|
16334
|
-
if (
|
|
16491
|
+
if (fs41.existsSync(workflowPath) && !force) {
|
|
16335
16492
|
skipped.push(".github/workflows/kody.yml");
|
|
16336
16493
|
} else {
|
|
16337
|
-
|
|
16338
|
-
|
|
16494
|
+
fs41.mkdirSync(workflowDir, { recursive: true });
|
|
16495
|
+
fs41.writeFileSync(workflowPath, loadKodyWorkflowTemplate());
|
|
16339
16496
|
wrote.push(".github/workflows/kody.yml");
|
|
16340
16497
|
}
|
|
16341
16498
|
let labels;
|
|
@@ -16388,7 +16545,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
|
|
|
16388
16545
|
});
|
|
16389
16546
|
|
|
16390
16547
|
// src/scripts/loadAgentAdhoc.ts
|
|
16391
|
-
import * as
|
|
16548
|
+
import * as fs42 from "fs";
|
|
16392
16549
|
function resolveMessage(messageArg) {
|
|
16393
16550
|
const fromComment = readCommentBody();
|
|
16394
16551
|
if (fromComment) return stripDirective(fromComment);
|
|
@@ -16396,9 +16553,9 @@ function resolveMessage(messageArg) {
|
|
|
16396
16553
|
}
|
|
16397
16554
|
function readCommentBody() {
|
|
16398
16555
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
16399
|
-
if (!eventPath || !
|
|
16556
|
+
if (!eventPath || !fs42.existsSync(eventPath)) return "";
|
|
16400
16557
|
try {
|
|
16401
|
-
const event = JSON.parse(
|
|
16558
|
+
const event = JSON.parse(fs42.readFileSync(eventPath, "utf-8"));
|
|
16402
16559
|
return String(event.comment?.body ?? "");
|
|
16403
16560
|
} catch {
|
|
16404
16561
|
return "";
|
|
@@ -16452,10 +16609,10 @@ var init_loadAgentAdhoc = __esm({
|
|
|
16452
16609
|
throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
|
|
16453
16610
|
}
|
|
16454
16611
|
const agentPath = resolveAgentFile2(ctx.cwd, agentSlug, agentsDir);
|
|
16455
|
-
if (!
|
|
16612
|
+
if (!fs42.existsSync(agentPath)) {
|
|
16456
16613
|
throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
|
|
16457
16614
|
}
|
|
16458
|
-
const { title, body } = parseAgentFile(
|
|
16615
|
+
const { title, body } = parseAgentFile(fs42.readFileSync(agentPath, "utf-8"), agentSlug);
|
|
16459
16616
|
const message = resolveMessage(ctx.args.message);
|
|
16460
16617
|
if (!message) {
|
|
16461
16618
|
throw new Error(
|
|
@@ -16824,7 +16981,7 @@ var init_loadIssueStateComment = __esm({
|
|
|
16824
16981
|
});
|
|
16825
16982
|
|
|
16826
16983
|
// src/scripts/loadJobFromFile.ts
|
|
16827
|
-
import * as
|
|
16984
|
+
import * as fs43 from "fs";
|
|
16828
16985
|
import * as path40 from "path";
|
|
16829
16986
|
function parseJobFile(raw, slug) {
|
|
16830
16987
|
let stripped = raw;
|
|
@@ -16877,12 +17034,12 @@ var init_loadJobFromFile = __esm({
|
|
|
16877
17034
|
let agentIdentity = "";
|
|
16878
17035
|
if (agentSlug) {
|
|
16879
17036
|
const agentPath = resolveAgentFile2(ctx.cwd, agentSlug, agentsDir);
|
|
16880
|
-
if (!
|
|
17037
|
+
if (!fs43.existsSync(agentPath)) {
|
|
16881
17038
|
throw new Error(
|
|
16882
17039
|
`loadJobFromFile: capability '${slug}' declares agent '${agentSlug}' but ${agentPath} does not exist`
|
|
16883
17040
|
);
|
|
16884
17041
|
}
|
|
16885
|
-
const agentRaw =
|
|
17042
|
+
const agentRaw = fs43.readFileSync(agentPath, "utf-8");
|
|
16886
17043
|
const parsed = parseJobFile(agentRaw, agentSlug);
|
|
16887
17044
|
agentTitle = parsed.title;
|
|
16888
17045
|
agentIdentity = parsed.body;
|
|
@@ -16962,7 +17119,7 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
16962
17119
|
});
|
|
16963
17120
|
|
|
16964
17121
|
// src/scripts/loadLiveAgent.ts
|
|
16965
|
-
import * as
|
|
17122
|
+
import * as fs44 from "fs";
|
|
16966
17123
|
function tenant(config) {
|
|
16967
17124
|
const [envOwner, envRepo] = (process.env.GITHUB_REPOSITORY ?? "").split("/");
|
|
16968
17125
|
const owner = config.github?.owner?.trim() || envOwner;
|
|
@@ -17005,7 +17162,7 @@ var init_loadLiveAgent = __esm({
|
|
|
17005
17162
|
const agent = String(ctx.args.agent ?? ctx.data.jobAgent ?? "").trim();
|
|
17006
17163
|
if (!agent) throw new Error("loadLiveAgent: agent is required");
|
|
17007
17164
|
const file = resolveAgentFile2(ctx.cwd, agent, agentsRoot(ctx.cwd));
|
|
17008
|
-
const raw =
|
|
17165
|
+
const raw = fs44.existsSync(file) ? fs44.readFileSync(file, "utf8") : "";
|
|
17009
17166
|
const metadata = frontmatter(raw);
|
|
17010
17167
|
const assignedIntent = typeof metadata.primaryIntent === "string" ? metadata.primaryIntent : "";
|
|
17011
17168
|
const requestedIntent = String(ctx.args.intent ?? "").trim();
|
|
@@ -17053,13 +17210,13 @@ var init_loadLiveAgent = __esm({
|
|
|
17053
17210
|
});
|
|
17054
17211
|
|
|
17055
17212
|
// src/scripts/kodyVariables.ts
|
|
17056
|
-
import * as
|
|
17213
|
+
import * as fs45 from "fs";
|
|
17057
17214
|
import * as path41 from "path";
|
|
17058
17215
|
function readKodyVariables(cwd) {
|
|
17059
17216
|
const full = path41.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
17060
17217
|
let raw;
|
|
17061
17218
|
try {
|
|
17062
|
-
raw =
|
|
17219
|
+
raw = fs45.readFileSync(full, "utf-8");
|
|
17063
17220
|
} catch {
|
|
17064
17221
|
return {};
|
|
17065
17222
|
}
|
|
@@ -17084,7 +17241,7 @@ var init_kodyVariables = __esm({
|
|
|
17084
17241
|
});
|
|
17085
17242
|
|
|
17086
17243
|
// src/scripts/loadQaContext.ts
|
|
17087
|
-
import * as
|
|
17244
|
+
import * as fs46 from "fs";
|
|
17088
17245
|
import * as path42 from "path";
|
|
17089
17246
|
function parseSlugList(value) {
|
|
17090
17247
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
@@ -17115,17 +17272,17 @@ function readProfileAgents(raw) {
|
|
|
17115
17272
|
}
|
|
17116
17273
|
function readProfile(cwd) {
|
|
17117
17274
|
const dir = path42.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
17118
|
-
if (!
|
|
17275
|
+
if (!fs46.existsSync(dir)) return "";
|
|
17119
17276
|
let entries;
|
|
17120
17277
|
try {
|
|
17121
|
-
entries =
|
|
17278
|
+
entries = fs46.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
17122
17279
|
} catch {
|
|
17123
17280
|
return "";
|
|
17124
17281
|
}
|
|
17125
17282
|
const blocks = [];
|
|
17126
17283
|
for (const file of entries) {
|
|
17127
17284
|
try {
|
|
17128
|
-
const raw =
|
|
17285
|
+
const raw = fs46.readFileSync(path42.join(dir, file), "utf-8");
|
|
17129
17286
|
const { agent, body } = readProfileAgents(raw);
|
|
17130
17287
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
17131
17288
|
blocks.push(`## ${file}
|
|
@@ -17175,7 +17332,7 @@ var init_loadQaContext = __esm({
|
|
|
17175
17332
|
|
|
17176
17333
|
// src/scripts/loadSimpleCapability.ts
|
|
17177
17334
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
17178
|
-
import * as
|
|
17335
|
+
import * as fs47 from "fs";
|
|
17179
17336
|
import * as os6 from "os";
|
|
17180
17337
|
import * as path43 from "path";
|
|
17181
17338
|
function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
|
|
@@ -17190,7 +17347,7 @@ function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
|
|
|
17190
17347
|
profile.subagentTemplates = {
|
|
17191
17348
|
...profile.subagentTemplates ?? {},
|
|
17192
17349
|
...Object.fromEntries(
|
|
17193
|
-
subagentFiles.map(({ name, file }) => [name,
|
|
17350
|
+
subagentFiles.map(({ name, file }) => [name, fs47.readFileSync(path43.join(toolRoot, file), "utf-8")])
|
|
17194
17351
|
)
|
|
17195
17352
|
};
|
|
17196
17353
|
if (!profile.claudeCode.tools.includes("Agent")) {
|
|
@@ -17231,10 +17388,10 @@ function scalar(value) {
|
|
|
17231
17388
|
return value;
|
|
17232
17389
|
}
|
|
17233
17390
|
function listFiles(root) {
|
|
17234
|
-
if (!
|
|
17391
|
+
if (!fs47.existsSync(root)) return [];
|
|
17235
17392
|
const files = [];
|
|
17236
17393
|
const visit = (dir) => {
|
|
17237
|
-
for (const entry of
|
|
17394
|
+
for (const entry of fs47.readdirSync(dir, { withFileTypes: true })) {
|
|
17238
17395
|
const absolute = path43.join(dir, entry.name);
|
|
17239
17396
|
if (entry.isSymbolicLink()) continue;
|
|
17240
17397
|
if (entry.isDirectory()) visit(absolute);
|
|
@@ -17327,7 +17484,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
17327
17484
|
...skillFiles.flatMap((file) => [
|
|
17328
17485
|
`### ${file}`,
|
|
17329
17486
|
"",
|
|
17330
|
-
|
|
17487
|
+
fs47.readFileSync(path43.join(skillRoot, file), "utf-8"),
|
|
17331
17488
|
""
|
|
17332
17489
|
])
|
|
17333
17490
|
] : [],
|
|
@@ -17367,7 +17524,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
17367
17524
|
});
|
|
17368
17525
|
|
|
17369
17526
|
// src/taskContext.ts
|
|
17370
|
-
import * as
|
|
17527
|
+
import * as fs48 from "fs";
|
|
17371
17528
|
import * as path44 from "path";
|
|
17372
17529
|
function buildTaskContext(args) {
|
|
17373
17530
|
return {
|
|
@@ -17384,9 +17541,9 @@ function buildTaskContext(args) {
|
|
|
17384
17541
|
function persistTaskContext(cwd, ctx) {
|
|
17385
17542
|
try {
|
|
17386
17543
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
17387
|
-
|
|
17544
|
+
fs48.mkdirSync(dir, { recursive: true });
|
|
17388
17545
|
const file = path44.join(dir, "task-context.json");
|
|
17389
|
-
|
|
17546
|
+
fs48.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
17390
17547
|
`);
|
|
17391
17548
|
return file;
|
|
17392
17549
|
} catch (err) {
|
|
@@ -18309,7 +18466,7 @@ var init_parseReproOutput = __esm({
|
|
|
18309
18466
|
});
|
|
18310
18467
|
|
|
18311
18468
|
// src/scripts/parseSimpleCapabilityOutput.ts
|
|
18312
|
-
import * as
|
|
18469
|
+
import * as fs49 from "fs";
|
|
18313
18470
|
function acceptAuthoritativeCapabilityOutput(ctx, profile, output) {
|
|
18314
18471
|
ctx.data.agentDone = true;
|
|
18315
18472
|
delete ctx.data.agentFailureReason;
|
|
@@ -18326,11 +18483,11 @@ function stringList2(value) {
|
|
|
18326
18483
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
18327
18484
|
}
|
|
18328
18485
|
function readOutputFile(outputPath) {
|
|
18329
|
-
if (!outputPath || !
|
|
18486
|
+
if (!outputPath || !fs49.existsSync(outputPath)) return { found: false };
|
|
18330
18487
|
try {
|
|
18331
|
-
return { found: true, value: JSON.parse(
|
|
18488
|
+
return { found: true, value: JSON.parse(fs49.readFileSync(outputPath, "utf-8")) };
|
|
18332
18489
|
} finally {
|
|
18333
|
-
|
|
18490
|
+
fs49.rmSync(outputPath, { force: true });
|
|
18334
18491
|
}
|
|
18335
18492
|
}
|
|
18336
18493
|
function parseOutput(text2) {
|
|
@@ -18992,7 +19149,7 @@ var init_postResearchComment = __esm({
|
|
|
18992
19149
|
});
|
|
18993
19150
|
|
|
18994
19151
|
// src/scripts/prepareBrowserAuth.ts
|
|
18995
|
-
import * as
|
|
19152
|
+
import * as fs50 from "fs";
|
|
18996
19153
|
import * as os7 from "os";
|
|
18997
19154
|
import * as path45 from "path";
|
|
18998
19155
|
function appendAuthMessage(ctx, message) {
|
|
@@ -19038,8 +19195,8 @@ async function githubJson(url, token, checkName) {
|
|
|
19038
19195
|
throw new Error(`GitHub ${checkName} check failed`);
|
|
19039
19196
|
}
|
|
19040
19197
|
function writeKodyStorageState(input) {
|
|
19041
|
-
const directory =
|
|
19042
|
-
|
|
19198
|
+
const directory = fs50.mkdtempSync(path45.join(os7.tmpdir(), "kody-browser-auth-"));
|
|
19199
|
+
fs50.chmodSync(directory, 448);
|
|
19043
19200
|
const file = path45.join(directory, "storage-state.json");
|
|
19044
19201
|
const now = Date.now();
|
|
19045
19202
|
const repoEntry = {
|
|
@@ -19071,7 +19228,7 @@ function writeKodyStorageState(input) {
|
|
|
19071
19228
|
}
|
|
19072
19229
|
]
|
|
19073
19230
|
};
|
|
19074
|
-
|
|
19231
|
+
fs50.writeFileSync(file, JSON.stringify(storageState), { mode: 384 });
|
|
19075
19232
|
return { directory, file, auth };
|
|
19076
19233
|
}
|
|
19077
19234
|
function parseSetCookie(value, hostname) {
|
|
@@ -19098,10 +19255,10 @@ function parseSetCookie(value, hostname) {
|
|
|
19098
19255
|
}
|
|
19099
19256
|
function writeCookieStorageState(targetUrl, setCookies) {
|
|
19100
19257
|
const target = new URL(targetUrl);
|
|
19101
|
-
const directory =
|
|
19102
|
-
|
|
19258
|
+
const directory = fs50.mkdtempSync(path45.join(os7.tmpdir(), "kody-browser-auth-"));
|
|
19259
|
+
fs50.chmodSync(directory, 448);
|
|
19103
19260
|
const file = path45.join(directory, "storage-state.json");
|
|
19104
|
-
|
|
19261
|
+
fs50.writeFileSync(
|
|
19105
19262
|
file,
|
|
19106
19263
|
JSON.stringify({
|
|
19107
19264
|
cookies: setCookies.map((cookie) => parseSetCookie(cookie, target.hostname)),
|
|
@@ -19122,9 +19279,9 @@ function currentStorageStatePath(args) {
|
|
|
19122
19279
|
function browserSessionCookieHeader(profile, targetUrl) {
|
|
19123
19280
|
const playwright = profile.claudeCode.mcpServers.find((server) => server.name === "playwright");
|
|
19124
19281
|
const storagePath = currentStorageStatePath(playwright?.args ?? []);
|
|
19125
|
-
if (!storagePath || !
|
|
19282
|
+
if (!storagePath || !fs50.existsSync(storagePath)) return void 0;
|
|
19126
19283
|
const hostname = new URL(targetUrl).hostname;
|
|
19127
|
-
const state = JSON.parse(
|
|
19284
|
+
const state = JSON.parse(fs50.readFileSync(storagePath, "utf-8"));
|
|
19128
19285
|
const cookies = (state.cookies ?? []).filter((cookie) => {
|
|
19129
19286
|
const domain = cookie.domain.replace(/^\./, "");
|
|
19130
19287
|
return hostname === domain || hostname.endsWith(`.${domain}`);
|
|
@@ -19191,9 +19348,9 @@ async function prepareAccountModelSettings(ctx, profile, input) {
|
|
|
19191
19348
|
return true;
|
|
19192
19349
|
}
|
|
19193
19350
|
function mergeStorageStates(existingPath, nextPath) {
|
|
19194
|
-
if (existingPath === nextPath || !
|
|
19195
|
-
const existing = JSON.parse(
|
|
19196
|
-
const next = JSON.parse(
|
|
19351
|
+
if (existingPath === nextPath || !fs50.existsSync(existingPath)) return;
|
|
19352
|
+
const existing = JSON.parse(fs50.readFileSync(existingPath, "utf-8"));
|
|
19353
|
+
const next = JSON.parse(fs50.readFileSync(nextPath, "utf-8"));
|
|
19197
19354
|
const cookies = /* @__PURE__ */ new Map();
|
|
19198
19355
|
for (const cookie of [...existing.cookies ?? [], ...next.cookies ?? []]) {
|
|
19199
19356
|
cookies.set(`${cookie.name}\0${cookie.domain}\0${cookie.path}`, cookie);
|
|
@@ -19207,7 +19364,7 @@ function mergeStorageStates(existingPath, nextPath) {
|
|
|
19207
19364
|
}
|
|
19208
19365
|
origins.set(entry.origin, { origin: entry.origin, localStorage: [...localStorage.values()] });
|
|
19209
19366
|
}
|
|
19210
|
-
|
|
19367
|
+
fs50.writeFileSync(nextPath, JSON.stringify({ cookies: [...cookies.values()], origins: [...origins.values()] }), {
|
|
19211
19368
|
mode: 384
|
|
19212
19369
|
});
|
|
19213
19370
|
}
|
|
@@ -19302,7 +19459,7 @@ async function prepareKodyRepositoryBrowserAuth(ctx, profile, input) {
|
|
|
19302
19459
|
configurePlaywright(profile, state.file);
|
|
19303
19460
|
const authDirectory = state.directory;
|
|
19304
19461
|
registerRuntimeCleanup(ctx, () => {
|
|
19305
|
-
|
|
19462
|
+
fs50.rmSync(authDirectory, { recursive: true, force: true });
|
|
19306
19463
|
});
|
|
19307
19464
|
appendAuthMessage(
|
|
19308
19465
|
ctx,
|
|
@@ -19310,7 +19467,7 @@ async function prepareKodyRepositoryBrowserAuth(ctx, profile, input) {
|
|
|
19310
19467
|
);
|
|
19311
19468
|
return true;
|
|
19312
19469
|
} catch (error) {
|
|
19313
|
-
if (state)
|
|
19470
|
+
if (state) fs50.rmSync(state.directory, { recursive: true, force: true });
|
|
19314
19471
|
const reason = error instanceof Error ? error.message : String(error);
|
|
19315
19472
|
appendAuthMessage(
|
|
19316
19473
|
ctx,
|
|
@@ -19337,11 +19494,11 @@ async function prepareEmailPasswordBrowserAuth(ctx, profile, input) {
|
|
|
19337
19494
|
state = writeCookieStorageState(input.targetUrl, cookies);
|
|
19338
19495
|
configurePlaywright(profile, state.file);
|
|
19339
19496
|
const authDirectory = state.directory;
|
|
19340
|
-
registerRuntimeCleanup(ctx, () =>
|
|
19497
|
+
registerRuntimeCleanup(ctx, () => fs50.rmSync(authDirectory, { recursive: true, force: true }));
|
|
19341
19498
|
ctx.data.qaAuthBlock = "Auth: the app is already signed in through an engine-provided browser session. The login credentials are not available to you; never request, reveal, or report them.";
|
|
19342
19499
|
return true;
|
|
19343
19500
|
} catch (error) {
|
|
19344
|
-
if (state)
|
|
19501
|
+
if (state) fs50.rmSync(state.directory, { recursive: true, force: true });
|
|
19345
19502
|
const reason = error instanceof Error ? error.message : String(error);
|
|
19346
19503
|
ctx.data.qaAuthBlock = `Auth: the engine could not prepare the app login (${reason}). Note this authenticated surface as a gap.`;
|
|
19347
19504
|
return false;
|
|
@@ -19556,6 +19713,18 @@ function appendPrompt(ctx, section) {
|
|
|
19556
19713
|
const prompt = typeof ctx.data.prompt === "string" ? ctx.data.prompt.trim() : "";
|
|
19557
19714
|
ctx.data.prompt = [prompt, section.trim()].filter(Boolean).join("\n\n");
|
|
19558
19715
|
}
|
|
19716
|
+
function capabilityTargetUrl(ctx) {
|
|
19717
|
+
const input = ctx.data.capabilityInput && typeof ctx.data.capabilityInput === "object" && !Array.isArray(ctx.data.capabilityInput) ? ctx.data.capabilityInput : {};
|
|
19718
|
+
return typeof input.url === "string" ? input.url : typeof input.targetUrl === "string" ? input.targetUrl : typeof input.previewUrl === "string" ? input.previewUrl : "";
|
|
19719
|
+
}
|
|
19720
|
+
async function isolatedAuthAttempt(ctx, attempt) {
|
|
19721
|
+
const previous = ctx.data.qaAuthBlock;
|
|
19722
|
+
ctx.data.qaAuthBlock = "";
|
|
19723
|
+
const ready = await attempt();
|
|
19724
|
+
const message = String(ctx.data.qaAuthBlock ?? "").trim();
|
|
19725
|
+
ctx.data.qaAuthBlock = previous;
|
|
19726
|
+
return { ready, message };
|
|
19727
|
+
}
|
|
19559
19728
|
var PLAYWRIGHT_SERVER, prepareSimpleCapabilityRuntime;
|
|
19560
19729
|
var init_prepareSimpleCapabilityRuntime = __esm({
|
|
19561
19730
|
"src/scripts/prepareSimpleCapabilityRuntime.ts"() {
|
|
@@ -19574,21 +19743,29 @@ var init_prepareSimpleCapabilityRuntime = __esm({
|
|
|
19574
19743
|
throw new Error("Capability requires the Dashboard user browser session and cannot run in CI");
|
|
19575
19744
|
}
|
|
19576
19745
|
configureBrowser(ctx, profile, requirements);
|
|
19746
|
+
const targetUrl = capabilityTargetUrl(ctx);
|
|
19747
|
+
const authAttempts = [];
|
|
19577
19748
|
if (requirements.qaCredentials) {
|
|
19578
19749
|
await loadQaContext(ctx, profile);
|
|
19579
|
-
const
|
|
19580
|
-
const
|
|
19581
|
-
|
|
19582
|
-
|
|
19583
|
-
|
|
19750
|
+
const missingCredentialsMessage = String(ctx.data.qaAuthBlock ?? "").trim();
|
|
19751
|
+
const emailAuth = await isolatedAuthAttempt(
|
|
19752
|
+
ctx,
|
|
19753
|
+
() => prepareEmailPasswordBrowserAuth(ctx, profile, {
|
|
19754
|
+
login: String(ctx.data.qaLogin ?? ""),
|
|
19755
|
+
targetUrl
|
|
19756
|
+
})
|
|
19757
|
+
);
|
|
19758
|
+
authAttempts.push({
|
|
19759
|
+
ready: emailAuth.ready,
|
|
19760
|
+
message: emailAuth.message || missingCredentialsMessage
|
|
19584
19761
|
});
|
|
19585
|
-
if (requirements.qaAccountCredentials?.length) {
|
|
19762
|
+
if (emailAuth.ready && requirements.qaAccountCredentials?.length) {
|
|
19586
19763
|
await prepareAccountCredentials(ctx, profile, {
|
|
19587
19764
|
names: requirements.qaAccountCredentials,
|
|
19588
19765
|
targetUrl
|
|
19589
19766
|
});
|
|
19590
19767
|
}
|
|
19591
|
-
if (requirements.qaAccountModelSettings) {
|
|
19768
|
+
if (emailAuth.ready && requirements.qaAccountModelSettings) {
|
|
19592
19769
|
await prepareAccountModelSettings(ctx, profile, {
|
|
19593
19770
|
settings: requirements.qaAccountModelSettings,
|
|
19594
19771
|
targetUrl
|
|
@@ -19596,16 +19773,21 @@ var init_prepareSimpleCapabilityRuntime = __esm({
|
|
|
19596
19773
|
}
|
|
19597
19774
|
}
|
|
19598
19775
|
if (requirements.githubTestToken) {
|
|
19599
|
-
|
|
19600
|
-
|
|
19601
|
-
|
|
19602
|
-
|
|
19603
|
-
|
|
19604
|
-
|
|
19605
|
-
|
|
19606
|
-
|
|
19776
|
+
authAttempts.push(
|
|
19777
|
+
await isolatedAuthAttempt(
|
|
19778
|
+
ctx,
|
|
19779
|
+
() => prepareKodyRepositoryBrowserAuth(ctx, profile, {
|
|
19780
|
+
repositoryUrl: `https://github.com/${ctx.config.github.owner}/${ctx.config.github.repo}`,
|
|
19781
|
+
credentialKey: "E2E_GITHUB_TOKEN",
|
|
19782
|
+
methodName: "Kody repository QA login",
|
|
19783
|
+
targetUrl
|
|
19784
|
+
})
|
|
19785
|
+
)
|
|
19786
|
+
);
|
|
19607
19787
|
}
|
|
19608
19788
|
if (requirements.qaCredentials || requirements.githubTestToken) {
|
|
19789
|
+
const successful = authAttempts.filter(({ ready }) => ready);
|
|
19790
|
+
ctx.data.qaAuthBlock = (successful.length ? successful : authAttempts).map(({ message }) => message).filter(Boolean).join("\n\n");
|
|
19609
19791
|
appendPrompt(
|
|
19610
19792
|
ctx,
|
|
19611
19793
|
[
|
|
@@ -21283,7 +21465,7 @@ var init_tickShellRunner = __esm({
|
|
|
21283
21465
|
});
|
|
21284
21466
|
|
|
21285
21467
|
// src/scripts/runScheduledImplementationTick.ts
|
|
21286
|
-
import * as
|
|
21468
|
+
import * as fs51 from "fs";
|
|
21287
21469
|
import * as path48 from "path";
|
|
21288
21470
|
var runScheduledImplementationTick;
|
|
21289
21471
|
var init_runScheduledImplementationTick = __esm({
|
|
@@ -21312,7 +21494,7 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
21312
21494
|
return;
|
|
21313
21495
|
}
|
|
21314
21496
|
const shellPath = path48.join(profile.dir, shell);
|
|
21315
|
-
if (!
|
|
21497
|
+
if (!fs51.existsSync(shellPath)) {
|
|
21316
21498
|
ctx.output.exitCode = 99;
|
|
21317
21499
|
ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
21318
21500
|
return;
|
|
@@ -21371,13 +21553,13 @@ var init_runtimeConnections = __esm({
|
|
|
21371
21553
|
|
|
21372
21554
|
// src/scripts/runSimpleCapabilityScript.ts
|
|
21373
21555
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
21374
|
-
import * as
|
|
21556
|
+
import * as fs52 from "fs";
|
|
21375
21557
|
function formatDuration2(timeoutMs) {
|
|
21376
21558
|
return timeoutMs % 6e4 === 0 ? `${timeoutMs / 6e4} minutes` : `${timeoutMs}ms`;
|
|
21377
21559
|
}
|
|
21378
21560
|
function isRegularFile2(filePath) {
|
|
21379
21561
|
try {
|
|
21380
|
-
const stat =
|
|
21562
|
+
const stat = fs52.lstatSync(filePath);
|
|
21381
21563
|
return stat.isFile() && !stat.isSymbolicLink();
|
|
21382
21564
|
} catch {
|
|
21383
21565
|
return false;
|
|
@@ -21469,7 +21651,7 @@ var init_runSimpleCapabilityScript = __esm({
|
|
|
21469
21651
|
});
|
|
21470
21652
|
|
|
21471
21653
|
// src/scripts/runTickScript.ts
|
|
21472
|
-
import * as
|
|
21654
|
+
import * as fs53 from "fs";
|
|
21473
21655
|
import * as path49 from "path";
|
|
21474
21656
|
var runTickScript;
|
|
21475
21657
|
var init_runTickScript = __esm({
|
|
@@ -21503,7 +21685,7 @@ var init_runTickScript = __esm({
|
|
|
21503
21685
|
return;
|
|
21504
21686
|
}
|
|
21505
21687
|
const scriptPath = path49.isAbsolute(tickScript) ? tickScript : path49.join(ctx.cwd, tickScript);
|
|
21506
|
-
if (!
|
|
21688
|
+
if (!fs53.existsSync(scriptPath)) {
|
|
21507
21689
|
ctx.output.exitCode = 99;
|
|
21508
21690
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
21509
21691
|
return;
|
|
@@ -22710,7 +22892,7 @@ var init_warmupMcp = __esm({
|
|
|
22710
22892
|
});
|
|
22711
22893
|
|
|
22712
22894
|
// src/scripts/writeAgentRunSummary.ts
|
|
22713
|
-
import * as
|
|
22895
|
+
import * as fs54 from "fs";
|
|
22714
22896
|
var writeAgentRunSummary;
|
|
22715
22897
|
var init_writeAgentRunSummary = __esm({
|
|
22716
22898
|
"src/scripts/writeAgentRunSummary.ts"() {
|
|
@@ -22736,7 +22918,7 @@ var init_writeAgentRunSummary = __esm({
|
|
|
22736
22918
|
if (reason) lines.push(`- **Reason:** ${reason}`);
|
|
22737
22919
|
lines.push("");
|
|
22738
22920
|
try {
|
|
22739
|
-
|
|
22921
|
+
fs54.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
22740
22922
|
`);
|
|
22741
22923
|
} catch {
|
|
22742
22924
|
}
|
|
@@ -23078,7 +23260,7 @@ var init_scripts = __esm({
|
|
|
23078
23260
|
});
|
|
23079
23261
|
|
|
23080
23262
|
// src/stateWorkspace.ts
|
|
23081
|
-
import * as
|
|
23263
|
+
import * as fs55 from "fs";
|
|
23082
23264
|
import * as path51 from "path";
|
|
23083
23265
|
function tenantId(config) {
|
|
23084
23266
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
@@ -23087,8 +23269,8 @@ function tenantId(config) {
|
|
|
23087
23269
|
}
|
|
23088
23270
|
function writeRuntimeFile(cwd, relativePath, content) {
|
|
23089
23271
|
const target = path51.join(cwd, RUNTIME_ROOT, relativePath);
|
|
23090
|
-
|
|
23091
|
-
|
|
23272
|
+
fs55.mkdirSync(path51.dirname(target), { recursive: true });
|
|
23273
|
+
fs55.writeFileSync(target, content, "utf8");
|
|
23092
23274
|
}
|
|
23093
23275
|
function record(value) {
|
|
23094
23276
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -23157,7 +23339,7 @@ async function hydrateStateWorkspace(config, cwd, backendOverride) {
|
|
|
23157
23339
|
if (hydratedWorkspaces.has(key)) return;
|
|
23158
23340
|
const backend = backendOverride ?? createStateBackendFromEnv();
|
|
23159
23341
|
const root = path51.join(cwd, RUNTIME_ROOT);
|
|
23160
|
-
|
|
23342
|
+
fs55.rmSync(root, { recursive: true, force: true });
|
|
23161
23343
|
await Promise.all([
|
|
23162
23344
|
hydratePrefix(backend, tenant2, cwd, "context:"),
|
|
23163
23345
|
hydratePrefix(backend, tenant2, cwd, "memory:"),
|
|
@@ -23244,7 +23426,7 @@ var init_tools = __esm({
|
|
|
23244
23426
|
|
|
23245
23427
|
// src/executor.ts
|
|
23246
23428
|
import { spawn as spawn8 } from "child_process";
|
|
23247
|
-
import * as
|
|
23429
|
+
import * as fs56 from "fs";
|
|
23248
23430
|
import * as os8 from "os";
|
|
23249
23431
|
import * as path52 from "path";
|
|
23250
23432
|
function isMutatingPostflight(scriptName) {
|
|
@@ -23342,6 +23524,7 @@ async function runImplementation(profileName, input) {
|
|
|
23342
23524
|
`);
|
|
23343
23525
|
else if (out.exitCode !== 0 && out.reason) process.stdout.write(`PR_URL=FAILED: ${out.reason}
|
|
23344
23526
|
`);
|
|
23527
|
+
publishRunUsage(`implementation:${profileName}`, out.usage);
|
|
23345
23528
|
return out;
|
|
23346
23529
|
};
|
|
23347
23530
|
const resolved = loadRunnableProfile(profileName, input.cwd);
|
|
@@ -23465,14 +23648,16 @@ async function runImplementation(profileName, input) {
|
|
|
23465
23648
|
status,
|
|
23466
23649
|
startedAt: runIndexStartedAt,
|
|
23467
23650
|
updatedAt: finishedAt,
|
|
23468
|
-
reason: out.reason
|
|
23651
|
+
reason: out.reason,
|
|
23652
|
+
usage: out.usage
|
|
23469
23653
|
})
|
|
23470
23654
|
);
|
|
23471
23655
|
await finalizeStagedRunIndexRowsAsync(config, input.cwd, ctx.data, {
|
|
23472
23656
|
status,
|
|
23473
23657
|
updatedAt: finishedAt,
|
|
23474
23658
|
reason: out.reason,
|
|
23475
|
-
output: ctx.data.capabilityOutput
|
|
23659
|
+
output: ctx.data.capabilityOutput,
|
|
23660
|
+
usage: out.usage
|
|
23476
23661
|
});
|
|
23477
23662
|
};
|
|
23478
23663
|
}
|
|
@@ -23700,10 +23885,11 @@ async function runImplementation(profileName, input) {
|
|
|
23700
23885
|
reason: err instanceof Error ? err.message : String(err)
|
|
23701
23886
|
});
|
|
23702
23887
|
}
|
|
23703
|
-
ctx.output.usage = {
|
|
23704
|
-
|
|
23705
|
-
|
|
23706
|
-
|
|
23888
|
+
ctx.output.usage = createRunUsage(agentResult.tokens, agentResult.costUsd, {
|
|
23889
|
+
model: `${model.provider}/${model.model}`,
|
|
23890
|
+
turns: agentResult.turns,
|
|
23891
|
+
modelUsage: agentResult.modelUsage
|
|
23892
|
+
});
|
|
23707
23893
|
emitEvent(input.cwd, {
|
|
23708
23894
|
implementation: profileName,
|
|
23709
23895
|
kind: "agent_end",
|
|
@@ -23825,7 +24011,8 @@ async function runImplementation(profileName, input) {
|
|
|
23825
24011
|
} catch (error) {
|
|
23826
24012
|
return finishAndEnd({
|
|
23827
24013
|
exitCode: 99,
|
|
23828
|
-
reason: error instanceof Error ? error.message : String(error)
|
|
24014
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
24015
|
+
usage: ctx.output.usage
|
|
23829
24016
|
});
|
|
23830
24017
|
}
|
|
23831
24018
|
}
|
|
@@ -23833,6 +24020,7 @@ async function runImplementation(profileName, input) {
|
|
|
23833
24020
|
exitCode: ctx.output.exitCode ?? 0,
|
|
23834
24021
|
prUrl: ctx.output.prUrl,
|
|
23835
24022
|
reason: ctx.output.reason,
|
|
24023
|
+
usage: ctx.output.usage,
|
|
23836
24024
|
action: ctx.data.action,
|
|
23837
24025
|
nextDispatch: ctx.output.nextDispatch,
|
|
23838
24026
|
nextJob: ctx.output.nextJob,
|
|
@@ -23843,7 +24031,7 @@ async function runImplementation(profileName, input) {
|
|
|
23843
24031
|
});
|
|
23844
24032
|
} catch (err) {
|
|
23845
24033
|
const msg = err instanceof Error ? err.message : String(err);
|
|
23846
|
-
return finishAndEnd({ exitCode: 99, reason: ctx.output.reason ?? msg });
|
|
24034
|
+
return finishAndEnd({ exitCode: 99, reason: ctx.output.reason ?? msg, usage: ctx.output.usage });
|
|
23847
24035
|
} finally {
|
|
23848
24036
|
runRuntimeCleanup(ctx);
|
|
23849
24037
|
clearStampedLifecycleLabels(profile, ctx);
|
|
@@ -23896,6 +24084,8 @@ function lastIndexOfScript(entries, names) {
|
|
|
23896
24084
|
}
|
|
23897
24085
|
async function runImplementationChain(profileName, input) {
|
|
23898
24086
|
let result = await runImplementation(profileName, input);
|
|
24087
|
+
let aggregateUsage = result.usage;
|
|
24088
|
+
let followedHandoff = false;
|
|
23899
24089
|
let chainConfig = input.config;
|
|
23900
24090
|
const configForHandoff = () => {
|
|
23901
24091
|
if (chainConfig || input.skipConfig) return chainConfig;
|
|
@@ -23907,6 +24097,7 @@ async function runImplementationChain(profileName, input) {
|
|
|
23907
24097
|
...result.taskState ? { taskState: result.taskState } : {}
|
|
23908
24098
|
};
|
|
23909
24099
|
for (let hops = 1; (result.nextDispatch || result.nextJob) && hops <= MAX_CHAIN_HOPS; hops++) {
|
|
24100
|
+
followedHandoff = true;
|
|
23910
24101
|
if (result.nextJob) {
|
|
23911
24102
|
const next2 = result.nextJob;
|
|
23912
24103
|
const after = result.afterNextJob;
|
|
@@ -23922,6 +24113,7 @@ async function runImplementationChain(profileName, input) {
|
|
|
23922
24113
|
quiet: input.quiet,
|
|
23923
24114
|
preloadedData: chainData
|
|
23924
24115
|
});
|
|
24116
|
+
aggregateUsage = mergeRunUsage(aggregateUsage, childResult.usage);
|
|
23925
24117
|
if (after && childResult.exitCode === 0 && !childResult.nextDispatch && !childResult.nextJob && !childResult.afterNextJob) {
|
|
23926
24118
|
chainData = {
|
|
23927
24119
|
...chainData,
|
|
@@ -23947,6 +24139,7 @@ async function runImplementationChain(profileName, input) {
|
|
|
23947
24139
|
quiet: input.quiet,
|
|
23948
24140
|
preloadedData: chainData
|
|
23949
24141
|
});
|
|
24142
|
+
aggregateUsage = mergeRunUsage(aggregateUsage, result.usage);
|
|
23950
24143
|
chainData = {
|
|
23951
24144
|
...chainData,
|
|
23952
24145
|
...result.taskState ? { taskState: result.taskState } : {}
|
|
@@ -23981,6 +24174,7 @@ async function runImplementationChain(profileName, input) {
|
|
|
23981
24174
|
quiet: input.quiet,
|
|
23982
24175
|
preloadedData: chainData
|
|
23983
24176
|
});
|
|
24177
|
+
aggregateUsage = mergeRunUsage(aggregateUsage, result.usage);
|
|
23984
24178
|
chainData = {
|
|
23985
24179
|
...chainData,
|
|
23986
24180
|
...result.taskState ? { taskState: result.taskState } : {}
|
|
@@ -23991,7 +24185,9 @@ async function runImplementationChain(profileName, input) {
|
|
|
23991
24185
|
process.stderr.write(`[kody] in-process hand-off cap (${MAX_CHAIN_HOPS}) reached; not running ${pending}
|
|
23992
24186
|
`);
|
|
23993
24187
|
}
|
|
23994
|
-
|
|
24188
|
+
const output = aggregateUsage ? { ...result, usage: aggregateUsage } : result;
|
|
24189
|
+
if (followedHandoff) publishRunUsage(`chain:${profileName}`, output.usage);
|
|
24190
|
+
return output;
|
|
23995
24191
|
}
|
|
23996
24192
|
function handoffToJob(handoff) {
|
|
23997
24193
|
const capabilityOrAction = handoff.workflow ?? handoff.action ?? handoff.capability;
|
|
@@ -24038,7 +24234,7 @@ function resolveProfilePath(profileName, cwd = process.cwd()) {
|
|
|
24038
24234
|
// fallback
|
|
24039
24235
|
];
|
|
24040
24236
|
for (const c of candidates) {
|
|
24041
|
-
if (
|
|
24237
|
+
if (fs56.existsSync(c)) return c;
|
|
24042
24238
|
}
|
|
24043
24239
|
return candidates[0];
|
|
24044
24240
|
}
|
|
@@ -24154,7 +24350,7 @@ function resolveShellTimeoutMs(entry) {
|
|
|
24154
24350
|
async function runShellEntry(entry, ctx, profile) {
|
|
24155
24351
|
const shellName = entry.shell;
|
|
24156
24352
|
const shellPath = path52.join(profile.dir, shellName);
|
|
24157
|
-
if (!
|
|
24353
|
+
if (!fs56.existsSync(shellPath)) {
|
|
24158
24354
|
ctx.skipAgent = true;
|
|
24159
24355
|
ctx.output.exitCode = 99;
|
|
24160
24356
|
ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
|
|
@@ -24228,9 +24424,9 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
24228
24424
|
}
|
|
24229
24425
|
let sideChannelText = "";
|
|
24230
24426
|
try {
|
|
24231
|
-
if (
|
|
24232
|
-
sideChannelText =
|
|
24233
|
-
|
|
24427
|
+
if (fs56.existsSync(outputFile)) {
|
|
24428
|
+
sideChannelText = fs56.readFileSync(outputFile, "utf-8");
|
|
24429
|
+
fs56.rmSync(outputFile, { force: true });
|
|
24234
24430
|
}
|
|
24235
24431
|
} catch {
|
|
24236
24432
|
}
|
|
@@ -24296,6 +24492,7 @@ var init_executor = __esm({
|
|
|
24296
24492
|
init_subagents();
|
|
24297
24493
|
init_task_artifacts();
|
|
24298
24494
|
init_tools();
|
|
24495
|
+
init_usage();
|
|
24299
24496
|
MUTATING_POSTFLIGHTS = /* @__PURE__ */ new Set([
|
|
24300
24497
|
"commitAndPush",
|
|
24301
24498
|
"ensurePr",
|
|
@@ -24446,6 +24643,7 @@ function parseWorkflowRunState(raw) {
|
|
|
24446
24643
|
const artifacts = Array.isArray(state.artifacts) ? state.artifacts.filter(
|
|
24447
24644
|
(artifact) => !!artifact && typeof artifact === "object" && typeof artifact.label === "string" && (artifact.url === void 0 || typeof artifact.url === "string") && (artifact.path === void 0 || typeof artifact.path === "string")
|
|
24448
24645
|
) : [];
|
|
24646
|
+
const usage = parseRunUsage(state.usage);
|
|
24449
24647
|
return {
|
|
24450
24648
|
status: state.status,
|
|
24451
24649
|
...typeof state.currentStepId === "string" ? { currentStepId: state.currentStepId } : {},
|
|
@@ -24458,6 +24656,7 @@ function parseWorkflowRunState(raw) {
|
|
|
24458
24656
|
facts: { ...facts },
|
|
24459
24657
|
evidence: Object.fromEntries(evidenceEntries),
|
|
24460
24658
|
artifacts: artifacts.map((artifact) => ({ ...artifact })),
|
|
24659
|
+
...usage ? { usage } : {},
|
|
24461
24660
|
...typeof state.blocker === "string" ? { blocker: state.blocker } : {}
|
|
24462
24661
|
};
|
|
24463
24662
|
}
|
|
@@ -24521,6 +24720,7 @@ var init_workflowRunState = __esm({
|
|
|
24521
24720
|
"src/workflowRunState.ts"() {
|
|
24522
24721
|
"use strict";
|
|
24523
24722
|
init_state_backend();
|
|
24723
|
+
init_usage();
|
|
24524
24724
|
SAFE_ID = /^[a-z0-9][a-z0-9_-]{0,79}$/;
|
|
24525
24725
|
}
|
|
24526
24726
|
});
|
|
@@ -24741,6 +24941,7 @@ async function runJob(job, base) {
|
|
|
24741
24941
|
...parentRow,
|
|
24742
24942
|
status: result.workflowState?.status === "waiting-approval" ? "waiting" : result.exitCode === 0 ? "success" : "failed",
|
|
24743
24943
|
summary: result.reason,
|
|
24944
|
+
usage: result.usage,
|
|
24744
24945
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
24745
24946
|
});
|
|
24746
24947
|
}
|
|
@@ -24759,6 +24960,7 @@ async function runJob(job, base) {
|
|
|
24759
24960
|
...Object.keys(facts).length > 0 ? { output: facts } : {}
|
|
24760
24961
|
});
|
|
24761
24962
|
}
|
|
24963
|
+
publishRunUsage(`workflow:${workflowIdentity}`, result.usage);
|
|
24762
24964
|
return result;
|
|
24763
24965
|
} finally {
|
|
24764
24966
|
await lease?.release().catch((error) => {
|
|
@@ -24907,16 +25109,17 @@ async function runCapabilityWorkflow(parent, workflow, capability, base, checkpo
|
|
|
24907
25109
|
return { exitCode: 64, reason: resumeBlocker, workflowState: state };
|
|
24908
25110
|
}
|
|
24909
25111
|
const result = isGraphWorkflow(workflow) ? await runGraphCapabilityWorkflow(parent, workflow, capability, base, checkpoint) : await runLinearCapabilityWorkflow(parent, workflow, capability, base, checkpoint);
|
|
24910
|
-
|
|
25112
|
+
const resultWithUsage = result.workflowState?.usage ? { ...result, usage: result.workflowState.usage } : result;
|
|
25113
|
+
if (workflow.report && resultWithUsage.workflowState) {
|
|
24911
25114
|
await publishWorkflowReport({
|
|
24912
25115
|
config: base.config ?? loadConfig(base.cwd),
|
|
24913
25116
|
publication: workflow.report,
|
|
24914
25117
|
workflowId: capability.slug,
|
|
24915
25118
|
workflowTitle: capability.title,
|
|
24916
|
-
state:
|
|
25119
|
+
state: resultWithUsage.workflowState
|
|
24917
25120
|
});
|
|
24918
25121
|
}
|
|
24919
|
-
return
|
|
25122
|
+
return resultWithUsage;
|
|
24920
25123
|
}
|
|
24921
25124
|
async function runLinearCapabilityWorkflow(parent, workflow, capability, base, checkpoint) {
|
|
24922
25125
|
const state = initialWorkflowState(parent, workflow);
|
|
@@ -25045,7 +25248,8 @@ function initialWorkflowState(parent, workflow) {
|
|
|
25045
25248
|
...prior.steps ? { steps: cloneWorkflowSteps(prior.steps) } : {},
|
|
25046
25249
|
facts: { ...prior.facts },
|
|
25047
25250
|
evidence: { ...prior.evidence },
|
|
25048
|
-
artifacts: prior.artifacts.map((artifact) => ({ ...artifact }))
|
|
25251
|
+
artifacts: prior.artifacts.map((artifact) => ({ ...artifact })),
|
|
25252
|
+
...prior.usage ? { usage: structuredClone(prior.usage) } : {}
|
|
25049
25253
|
};
|
|
25050
25254
|
}
|
|
25051
25255
|
const firstStepId = workflow.startAt ?? workflow.steps[0]?.id;
|
|
@@ -25065,7 +25269,8 @@ function initialWorkflowState(parent, workflow) {
|
|
|
25065
25269
|
...prior?.facts ?? {}
|
|
25066
25270
|
},
|
|
25067
25271
|
evidence: { ...prior?.evidence ?? {} },
|
|
25068
|
-
artifacts: (prior?.artifacts ?? []).map((artifact) => ({ ...artifact }))
|
|
25272
|
+
artifacts: (prior?.artifacts ?? []).map((artifact) => ({ ...artifact })),
|
|
25273
|
+
...prior?.usage ? { usage: structuredClone(prior.usage) } : {}
|
|
25069
25274
|
};
|
|
25070
25275
|
}
|
|
25071
25276
|
function workflowChainData(parent, capability, base, state) {
|
|
@@ -25454,6 +25659,7 @@ function finishWorkflowStep(state, step, result) {
|
|
|
25454
25659
|
...result.capabilityOutput !== void 0 ? { output: result.capabilityOutput } : {},
|
|
25455
25660
|
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25456
25661
|
};
|
|
25662
|
+
state.usage = mergeRunUsage(state.usage, result.usage);
|
|
25457
25663
|
}
|
|
25458
25664
|
function usesGenericCapabilityInput(action, cwd) {
|
|
25459
25665
|
const inputs = getCapabilityActionInputs(action, hydratedCapabilitiesRoot(cwd));
|
|
@@ -25689,6 +25895,7 @@ var init_job = __esm({
|
|
|
25689
25895
|
init_publishReport();
|
|
25690
25896
|
init_simpleCapabilityRuntime();
|
|
25691
25897
|
init_state_backend();
|
|
25898
|
+
init_usage();
|
|
25692
25899
|
init_workflowDefinitionIdentity();
|
|
25693
25900
|
init_workflowDefinitions();
|
|
25694
25901
|
init_workflowRunLease();
|
|
@@ -27058,7 +27265,7 @@ async function hydrateDefinitionsFromEnv(cwd = process.cwd(), env = process.env)
|
|
|
27058
27265
|
|
|
27059
27266
|
// src/kody-cli.ts
|
|
27060
27267
|
import { execFileSync as execFileSync24 } from "child_process";
|
|
27061
|
-
import * as
|
|
27268
|
+
import * as fs58 from "fs";
|
|
27062
27269
|
import * as path53 from "path";
|
|
27063
27270
|
|
|
27064
27271
|
// src/app-auth.ts
|
|
@@ -27591,7 +27798,7 @@ init_loopDefinitions();
|
|
|
27591
27798
|
|
|
27592
27799
|
// src/mergedPrLifecycle.ts
|
|
27593
27800
|
init_lifecycleLabels();
|
|
27594
|
-
import * as
|
|
27801
|
+
import * as fs57 from "fs";
|
|
27595
27802
|
var DONE3 = {
|
|
27596
27803
|
label: "kody:done",
|
|
27597
27804
|
color: "0e8a16",
|
|
@@ -27632,8 +27839,8 @@ function finalizeMergedPullRequestEvent(event, cwd, writeLabel = setKodyLabel) {
|
|
|
27632
27839
|
}
|
|
27633
27840
|
function readGitHubEvent(env = process.env) {
|
|
27634
27841
|
const eventPath = env.GITHUB_EVENT_PATH;
|
|
27635
|
-
if (!eventPath || !
|
|
27636
|
-
return JSON.parse(
|
|
27842
|
+
if (!eventPath || !fs57.existsSync(eventPath)) return null;
|
|
27843
|
+
return JSON.parse(fs57.readFileSync(eventPath, "utf-8"));
|
|
27637
27844
|
}
|
|
27638
27845
|
|
|
27639
27846
|
// src/kody-cli.ts
|
|
@@ -27861,9 +28068,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
27861
28068
|
return void 0;
|
|
27862
28069
|
}
|
|
27863
28070
|
function detectPackageManager(cwd) {
|
|
27864
|
-
if (
|
|
27865
|
-
if (
|
|
27866
|
-
if (
|
|
28071
|
+
if (fs58.existsSync(path53.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
28072
|
+
if (fs58.existsSync(path53.join(cwd, "yarn.lock"))) return "yarn";
|
|
28073
|
+
if (fs58.existsSync(path53.join(cwd, "bun.lockb"))) return "bun";
|
|
27867
28074
|
return "npm";
|
|
27868
28075
|
}
|
|
27869
28076
|
function shouldChainScheduledWatch(match) {
|
|
@@ -27904,7 +28111,7 @@ function ensurePackageManagerInstalled(pm, cwd) {
|
|
|
27904
28111
|
return shellOut("npm", ["install", "-g", spec], cwd);
|
|
27905
28112
|
}
|
|
27906
28113
|
function installDeps(pm, cwd) {
|
|
27907
|
-
if (!
|
|
28114
|
+
if (!fs58.existsSync(path53.join(cwd, "package.json"))) {
|
|
27908
28115
|
process.stdout.write("\u2192 kody: no package.json found \u2014 skipping consumer dependency install\n");
|
|
27909
28116
|
return 0;
|
|
27910
28117
|
}
|
|
@@ -27970,8 +28177,8 @@ function postFailureTail(issueNumber, cwd, reason) {
|
|
|
27970
28177
|
const logPath = lastRunLogPath(cwd);
|
|
27971
28178
|
let tail = "";
|
|
27972
28179
|
try {
|
|
27973
|
-
if (
|
|
27974
|
-
const content =
|
|
28180
|
+
if (fs58.existsSync(logPath)) {
|
|
28181
|
+
const content = fs58.readFileSync(logPath, "utf-8");
|
|
27975
28182
|
tail = content.slice(-3e3);
|
|
27976
28183
|
}
|
|
27977
28184
|
} catch {
|
|
@@ -28088,9 +28295,9 @@ async function runCi(argv) {
|
|
|
28088
28295
|
forceRunCliArgs = { goal: envForceMessage };
|
|
28089
28296
|
}
|
|
28090
28297
|
}
|
|
28091
|
-
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath &&
|
|
28298
|
+
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs58.existsSync(dispatchEventPath)) {
|
|
28092
28299
|
try {
|
|
28093
|
-
const evt = JSON.parse(
|
|
28300
|
+
const evt = JSON.parse(fs58.readFileSync(dispatchEventPath, "utf-8"));
|
|
28094
28301
|
const inputs = objectValue2(evt.inputs);
|
|
28095
28302
|
const issueInput = parseInt(String(inputs?.issue_number ?? ""), 10);
|
|
28096
28303
|
const sessionInput = String(inputs?.sessionId ?? "");
|
|
@@ -28506,7 +28713,7 @@ init_repoWorkspace();
|
|
|
28506
28713
|
|
|
28507
28714
|
// src/scripts/brainTurnLog.ts
|
|
28508
28715
|
init_runtimePaths();
|
|
28509
|
-
import * as
|
|
28716
|
+
import * as fs59 from "fs";
|
|
28510
28717
|
import * as path54 from "path";
|
|
28511
28718
|
import posixPath4 from "path/posix";
|
|
28512
28719
|
var live = /* @__PURE__ */ new Map();
|
|
@@ -28515,8 +28722,8 @@ function brainEventsFilePath(dir, chatId) {
|
|
|
28515
28722
|
}
|
|
28516
28723
|
function lastPersistedSeq(dir, chatId) {
|
|
28517
28724
|
const p = brainEventsFilePath(dir, chatId);
|
|
28518
|
-
if (!
|
|
28519
|
-
const lines =
|
|
28725
|
+
if (!fs59.existsSync(p)) return 0;
|
|
28726
|
+
const lines = fs59.readFileSync(p, "utf-8").split("\n").filter(Boolean);
|
|
28520
28727
|
if (lines.length === 0) return 0;
|
|
28521
28728
|
try {
|
|
28522
28729
|
return JSON.parse(lines[lines.length - 1]).seq || 0;
|
|
@@ -28526,9 +28733,9 @@ function lastPersistedSeq(dir, chatId) {
|
|
|
28526
28733
|
}
|
|
28527
28734
|
function readSince(dir, chatId, since) {
|
|
28528
28735
|
const p = brainEventsFilePath(dir, chatId);
|
|
28529
|
-
if (!
|
|
28736
|
+
if (!fs59.existsSync(p)) return [];
|
|
28530
28737
|
const out = [];
|
|
28531
|
-
for (const line of
|
|
28738
|
+
for (const line of fs59.readFileSync(p, "utf-8").split("\n")) {
|
|
28532
28739
|
if (!line) continue;
|
|
28533
28740
|
try {
|
|
28534
28741
|
const rec = JSON.parse(line);
|
|
@@ -28554,12 +28761,12 @@ function beginTurn(dir, chatId) {
|
|
|
28554
28761
|
};
|
|
28555
28762
|
live.set(chatId, state);
|
|
28556
28763
|
const p = brainEventsFilePath(dir, chatId);
|
|
28557
|
-
|
|
28764
|
+
fs59.mkdirSync(path54.dirname(p), { recursive: true });
|
|
28558
28765
|
return (event) => {
|
|
28559
28766
|
state.seq += 1;
|
|
28560
28767
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
28561
28768
|
try {
|
|
28562
|
-
|
|
28769
|
+
fs59.appendFileSync(p, `${JSON.stringify(rec)}
|
|
28563
28770
|
`);
|
|
28564
28771
|
} catch (err) {
|
|
28565
28772
|
process.stderr.write(
|
|
@@ -28598,7 +28805,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
|
|
|
28598
28805
|
event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
|
|
28599
28806
|
};
|
|
28600
28807
|
try {
|
|
28601
|
-
|
|
28808
|
+
fs59.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
|
|
28602
28809
|
`);
|
|
28603
28810
|
} catch {
|
|
28604
28811
|
}
|
|
@@ -31262,7 +31469,7 @@ async function poolServe() {
|
|
|
31262
31469
|
|
|
31263
31470
|
// src/servers/runner-serve.ts
|
|
31264
31471
|
import { spawn as spawn10 } from "child_process";
|
|
31265
|
-
import * as
|
|
31472
|
+
import * as fs60 from "fs";
|
|
31266
31473
|
import { createServer as createServer6 } from "http";
|
|
31267
31474
|
var DEFAULT_PORT2 = 8080;
|
|
31268
31475
|
var DEFAULT_WORKDIR = "/workspace/repo";
|
|
@@ -31338,8 +31545,8 @@ async function defaultRunJob(job) {
|
|
|
31338
31545
|
const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
|
|
31339
31546
|
const branch = job.ref ?? "main";
|
|
31340
31547
|
const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
|
|
31341
|
-
|
|
31342
|
-
|
|
31548
|
+
fs60.rmSync(workdir, { recursive: true, force: true });
|
|
31549
|
+
fs60.mkdirSync(workdir, { recursive: true });
|
|
31343
31550
|
const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
|
|
31344
31551
|
const target = job.runRequest.target;
|
|
31345
31552
|
const interactive = target.type === "chat";
|