@kody-ade/kody-engine 0.4.646 → 0.4.648
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 +399 -194
- 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.648",
|
|
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,177 @@ 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 hasBillableUsage = normalizedTokens.total > 0 || safeNumber(costUsd) > 0;
|
|
7401
|
+
const measurement = details.outcome === "failed" && !hasBillableUsage ? "unknown" : "reported";
|
|
7402
|
+
const modelUsage = {
|
|
7403
|
+
tokens: normalizedTokens,
|
|
7404
|
+
costUsd: safeNumber(costUsd),
|
|
7405
|
+
agentRuns: 1,
|
|
7406
|
+
turns: safeNumber(details.turns),
|
|
7407
|
+
measurement
|
|
7408
|
+
};
|
|
7409
|
+
const reportedModels = Object.entries(details.modelUsage ?? {});
|
|
7410
|
+
const byModel = reportedModels.length > 0 ? Object.fromEntries(
|
|
7411
|
+
reportedModels.map(([model, usage]) => {
|
|
7412
|
+
const modelTokens = tokenBreakdown({
|
|
7413
|
+
input: usage.inputTokens,
|
|
7414
|
+
output: usage.outputTokens,
|
|
7415
|
+
cacheRead: usage.cacheReadInputTokens,
|
|
7416
|
+
cacheCreate: usage.cacheCreationInputTokens
|
|
7417
|
+
});
|
|
7418
|
+
return [
|
|
7419
|
+
model,
|
|
7420
|
+
{
|
|
7421
|
+
tokens: modelTokens,
|
|
7422
|
+
costUsd: safeNumber(usage.costUSD),
|
|
7423
|
+
agentRuns: 1,
|
|
7424
|
+
turns: reportedModels.length === 1 ? safeNumber(details.turns) : 0,
|
|
7425
|
+
measurement
|
|
7426
|
+
}
|
|
7427
|
+
];
|
|
7428
|
+
})
|
|
7429
|
+
) : details.model ? { [details.model]: modelUsage } : {};
|
|
7430
|
+
return {
|
|
7431
|
+
version: 1,
|
|
7432
|
+
...modelUsage,
|
|
7433
|
+
byModel
|
|
7434
|
+
};
|
|
7435
|
+
}
|
|
7436
|
+
function isModelRunUsage(value) {
|
|
7437
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
7438
|
+
const usage = value;
|
|
7439
|
+
if (!usage.tokens || typeof usage.tokens !== "object" || Array.isArray(usage.tokens)) return false;
|
|
7440
|
+
return [
|
|
7441
|
+
usage.tokens.input,
|
|
7442
|
+
usage.tokens.output,
|
|
7443
|
+
usage.tokens.cacheRead,
|
|
7444
|
+
usage.tokens.cacheCreate,
|
|
7445
|
+
usage.tokens.total,
|
|
7446
|
+
usage.costUsd,
|
|
7447
|
+
usage.agentRuns,
|
|
7448
|
+
usage.turns
|
|
7449
|
+
].every((number) => typeof number === "number" && Number.isFinite(number) && number >= 0);
|
|
7450
|
+
}
|
|
7451
|
+
function isUsageMeasurement(value) {
|
|
7452
|
+
return value === "reported" || value === "partial" || value === "unknown";
|
|
7453
|
+
}
|
|
7454
|
+
function mergeMeasurement(left, right) {
|
|
7455
|
+
const normalizedLeft = left ?? "reported";
|
|
7456
|
+
const normalizedRight = right ?? "reported";
|
|
7457
|
+
if (normalizedLeft === normalizedRight) return normalizedLeft;
|
|
7458
|
+
return "partial";
|
|
7459
|
+
}
|
|
7460
|
+
function parseRunUsage(value) {
|
|
7461
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
7462
|
+
const usage = value;
|
|
7463
|
+
if (usage.version !== 1 || !isModelRunUsage(usage)) return void 0;
|
|
7464
|
+
if (!usage.byModel || typeof usage.byModel !== "object" || Array.isArray(usage.byModel)) return void 0;
|
|
7465
|
+
if (!Object.values(usage.byModel).every(isModelRunUsage)) return void 0;
|
|
7466
|
+
const normalized = structuredClone(usage);
|
|
7467
|
+
normalized.measurement = isUsageMeasurement(usage.measurement) ? usage.measurement : "reported";
|
|
7468
|
+
for (const [model, modelUsage] of Object.entries(normalized.byModel)) {
|
|
7469
|
+
modelUsage.measurement = isUsageMeasurement(usage.byModel[model]?.measurement) ? usage.byModel[model].measurement : "reported";
|
|
7470
|
+
}
|
|
7471
|
+
return normalized;
|
|
7472
|
+
}
|
|
7473
|
+
function mergeRunUsage(left, right) {
|
|
7474
|
+
if (!left) return right ? structuredClone(right) : void 0;
|
|
7475
|
+
if (!right) return structuredClone(left);
|
|
7476
|
+
const byModel = {};
|
|
7477
|
+
for (const model of /* @__PURE__ */ new Set([...Object.keys(left.byModel), ...Object.keys(right.byModel)])) {
|
|
7478
|
+
const first = left.byModel[model];
|
|
7479
|
+
const second = right.byModel[model];
|
|
7480
|
+
if (!first) {
|
|
7481
|
+
byModel[model] = structuredClone(second);
|
|
7482
|
+
} else if (!second) {
|
|
7483
|
+
byModel[model] = structuredClone(first);
|
|
7484
|
+
} else {
|
|
7485
|
+
byModel[model] = {
|
|
7486
|
+
tokens: addTokenBreakdown(first.tokens, second.tokens),
|
|
7487
|
+
costUsd: first.costUsd + second.costUsd,
|
|
7488
|
+
agentRuns: first.agentRuns + second.agentRuns,
|
|
7489
|
+
turns: first.turns + second.turns,
|
|
7490
|
+
measurement: mergeMeasurement(first.measurement, second.measurement)
|
|
7491
|
+
};
|
|
7492
|
+
}
|
|
7493
|
+
}
|
|
7494
|
+
return {
|
|
7495
|
+
version: 1,
|
|
7496
|
+
tokens: addTokenBreakdown(left.tokens, right.tokens),
|
|
7497
|
+
costUsd: left.costUsd + right.costUsd,
|
|
7498
|
+
agentRuns: left.agentRuns + right.agentRuns,
|
|
7499
|
+
turns: left.turns + right.turns,
|
|
7500
|
+
measurement: mergeMeasurement(left.measurement, right.measurement),
|
|
7501
|
+
byModel
|
|
7502
|
+
};
|
|
7503
|
+
}
|
|
7504
|
+
function formatRunUsageMarker(subject, usage) {
|
|
7505
|
+
return `KODY_USAGE=${JSON.stringify({ subject, ...usage })}`;
|
|
7506
|
+
}
|
|
7507
|
+
function appendRunUsageSummary(summaryPath, subject, usage) {
|
|
7508
|
+
if (!summaryPath) return;
|
|
7509
|
+
const tokens = usage.tokens;
|
|
7510
|
+
const tokenLine = usage.measurement === "unknown" ? "- **Tokens:** usage unknown (provider did not report billable usage)" : `- **${usage.measurement === "partial" ? "Known tokens" : "Tokens"}:** ${tokens.input.toLocaleString()} input / ${tokens.cacheRead.toLocaleString()} cache-read / ${tokens.cacheCreate.toLocaleString()} cache-create / ${tokens.output.toLocaleString()} output / ${tokens.total.toLocaleString()} total${usage.measurement === "partial" ? "; some child usage is unknown" : ""}`;
|
|
7511
|
+
const costLine = usage.measurement === "unknown" ? "- **Provider-reported cost:** unknown" : `- **Provider-reported cost:** $${usage.costUsd.toFixed(4)}${usage.measurement === "partial" ? " known; some child cost is unknown" : ""}`;
|
|
7512
|
+
const lines = [
|
|
7513
|
+
`### Kody usage - ${subject}`,
|
|
7514
|
+
"",
|
|
7515
|
+
tokenLine,
|
|
7516
|
+
`- **Agent work:** ${usage.agentRuns.toLocaleString()} runs / ${usage.turns.toLocaleString()} turns`,
|
|
7517
|
+
costLine,
|
|
7518
|
+
""
|
|
7519
|
+
];
|
|
7520
|
+
try {
|
|
7521
|
+
fs25.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
7522
|
+
`);
|
|
7523
|
+
} catch {
|
|
7524
|
+
}
|
|
7525
|
+
}
|
|
7526
|
+
function publishRunUsage(subject, usage) {
|
|
7527
|
+
if (!usage) return;
|
|
7528
|
+
process.stdout.write(`${formatRunUsageMarker(subject, usage)}
|
|
7529
|
+
`);
|
|
7530
|
+
appendRunUsageSummary(process.env.GITHUB_STEP_SUMMARY, subject, usage);
|
|
7531
|
+
}
|
|
7532
|
+
var init_usage = __esm({
|
|
7533
|
+
"src/usage.ts"() {
|
|
7534
|
+
"use strict";
|
|
7535
|
+
}
|
|
7536
|
+
});
|
|
7537
|
+
|
|
7538
|
+
// src/prompt.ts
|
|
7539
|
+
import * as fs26 from "fs";
|
|
7365
7540
|
import * as path25 from "path";
|
|
7366
7541
|
function loadProjectConventions(projectDir) {
|
|
7367
7542
|
const out = [];
|
|
7368
7543
|
for (const rel of CONVENTION_FILES) {
|
|
7369
7544
|
const abs = path25.join(projectDir, rel);
|
|
7370
|
-
if (!
|
|
7545
|
+
if (!fs26.existsSync(abs)) continue;
|
|
7371
7546
|
let content;
|
|
7372
7547
|
try {
|
|
7373
|
-
content =
|
|
7548
|
+
content = fs26.readFileSync(abs, "utf-8");
|
|
7374
7549
|
} catch {
|
|
7375
7550
|
continue;
|
|
7376
7551
|
}
|
|
@@ -7621,7 +7796,7 @@ var loadMemoryContext_exports = {};
|
|
|
7621
7796
|
__export(loadMemoryContext_exports, {
|
|
7622
7797
|
loadMemoryContext: () => loadMemoryContext
|
|
7623
7798
|
});
|
|
7624
|
-
import * as
|
|
7799
|
+
import * as fs27 from "fs";
|
|
7625
7800
|
import * as path26 from "path";
|
|
7626
7801
|
function formatBlockFromBackend(docs) {
|
|
7627
7802
|
const pages = docs.flatMap((record2) => {
|
|
@@ -7645,13 +7820,13 @@ function collectPages(memoryAbs) {
|
|
|
7645
7820
|
walkMd(memoryAbs, (file) => {
|
|
7646
7821
|
let stat;
|
|
7647
7822
|
try {
|
|
7648
|
-
stat =
|
|
7823
|
+
stat = fs27.statSync(file);
|
|
7649
7824
|
} catch {
|
|
7650
7825
|
return;
|
|
7651
7826
|
}
|
|
7652
7827
|
let raw;
|
|
7653
7828
|
try {
|
|
7654
|
-
raw =
|
|
7829
|
+
raw = fs27.readFileSync(file, "utf-8");
|
|
7655
7830
|
} catch {
|
|
7656
7831
|
return;
|
|
7657
7832
|
}
|
|
@@ -7727,7 +7902,7 @@ function walkMd(root, visit) {
|
|
|
7727
7902
|
const dir = stack.pop();
|
|
7728
7903
|
let names;
|
|
7729
7904
|
try {
|
|
7730
|
-
names =
|
|
7905
|
+
names = fs27.readdirSync(dir);
|
|
7731
7906
|
} catch {
|
|
7732
7907
|
continue;
|
|
7733
7908
|
}
|
|
@@ -7736,7 +7911,7 @@ function walkMd(root, visit) {
|
|
|
7736
7911
|
const full = path26.join(dir, name);
|
|
7737
7912
|
let stat;
|
|
7738
7913
|
try {
|
|
7739
|
-
stat =
|
|
7914
|
+
stat = fs27.statSync(full);
|
|
7740
7915
|
} catch {
|
|
7741
7916
|
continue;
|
|
7742
7917
|
}
|
|
@@ -7772,7 +7947,7 @@ var init_loadMemoryContext = __esm({
|
|
|
7772
7947
|
return;
|
|
7773
7948
|
}
|
|
7774
7949
|
const memoryAbs = path26.join(ctx.cwd, MEMORY_DIR_RELATIVE);
|
|
7775
|
-
if (!
|
|
7950
|
+
if (!fs27.existsSync(memoryAbs)) {
|
|
7776
7951
|
ctx.data.memoryContext = "";
|
|
7777
7952
|
return;
|
|
7778
7953
|
}
|
|
@@ -7816,11 +7991,11 @@ var init_loadCoverageRules = __esm({
|
|
|
7816
7991
|
|
|
7817
7992
|
// src/container.ts
|
|
7818
7993
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
7819
|
-
import * as
|
|
7994
|
+
import * as fs28 from "fs";
|
|
7820
7995
|
function getProfileInputsForChild(profileName, _cwd) {
|
|
7821
7996
|
try {
|
|
7822
7997
|
const profilePath = resolveProfilePath(profileName);
|
|
7823
|
-
if (!
|
|
7998
|
+
if (!fs28.existsSync(profilePath)) return null;
|
|
7824
7999
|
return loadProfile(profilePath).inputs;
|
|
7825
8000
|
} catch {
|
|
7826
8001
|
return null;
|
|
@@ -7952,6 +8127,7 @@ async function runContainerLoop(profile, ctx, input) {
|
|
|
7952
8127
|
// is off, so children fall back to their own loaders.
|
|
7953
8128
|
preloadedData: preloadedSnapshot
|
|
7954
8129
|
});
|
|
8130
|
+
ctx.output.usage = mergeRunUsage(ctx.output.usage, childOut.usage);
|
|
7955
8131
|
emitEvent(input.cwd, {
|
|
7956
8132
|
implementation: profile.name,
|
|
7957
8133
|
kind: "container_child",
|
|
@@ -8103,6 +8279,7 @@ var init_container = __esm({
|
|
|
8103
8279
|
init_executor();
|
|
8104
8280
|
init_profile();
|
|
8105
8281
|
init_state();
|
|
8282
|
+
init_usage();
|
|
8106
8283
|
CONTAINER_MAX_ITERATIONS = 50;
|
|
8107
8284
|
}
|
|
8108
8285
|
});
|
|
@@ -8284,7 +8461,7 @@ var init_lifecycleLabels = __esm({
|
|
|
8284
8461
|
|
|
8285
8462
|
// src/litellm.ts
|
|
8286
8463
|
import { execFileSync as execFileSync4, spawn as spawn4 } from "child_process";
|
|
8287
|
-
import * as
|
|
8464
|
+
import * as fs29 from "fs";
|
|
8288
8465
|
import * as net from "net";
|
|
8289
8466
|
import * as os4 from "os";
|
|
8290
8467
|
import * as path27 from "path";
|
|
@@ -8396,7 +8573,7 @@ function locateLitellmScript() {
|
|
|
8396
8573
|
}
|
|
8397
8574
|
function resolveLitellmCommand() {
|
|
8398
8575
|
const imageScript = "/opt/venv/bin/litellm";
|
|
8399
|
-
if (
|
|
8576
|
+
if (fs29.existsSync(imageScript)) return imageScript;
|
|
8400
8577
|
try {
|
|
8401
8578
|
execFileSync4("which", ["litellm"], { timeout: 3e3, stdio: "pipe" });
|
|
8402
8579
|
return "litellm";
|
|
@@ -8460,12 +8637,12 @@ async function startLitellmProxy(input) {
|
|
|
8460
8637
|
const portMatch = activeUrl.match(/:(\d+)/);
|
|
8461
8638
|
const port = portMatch ? portMatch[1] : "4000";
|
|
8462
8639
|
const configPath = path27.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.yaml`);
|
|
8463
|
-
|
|
8640
|
+
fs29.writeFileSync(configPath, input.configYaml);
|
|
8464
8641
|
const args = ["--config", configPath, "--port", port];
|
|
8465
8642
|
const nextLogPath = path27.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.log`);
|
|
8466
|
-
const outFd =
|
|
8643
|
+
const outFd = fs29.openSync(nextLogPath, "w");
|
|
8467
8644
|
child = spawn4(cmd, args, { stdio: ["ignore", outFd, outFd], detached: true, env: childEnv });
|
|
8468
|
-
|
|
8645
|
+
fs29.closeSync(outFd);
|
|
8469
8646
|
logPath = nextLogPath;
|
|
8470
8647
|
};
|
|
8471
8648
|
const waitForHealth = async () => {
|
|
@@ -8479,7 +8656,7 @@ async function startLitellmProxy(input) {
|
|
|
8479
8656
|
const readLogTail = () => {
|
|
8480
8657
|
if (!logPath) return "";
|
|
8481
8658
|
try {
|
|
8482
|
-
return
|
|
8659
|
+
return fs29.readFileSync(logPath, "utf-8").slice(-2e3);
|
|
8483
8660
|
} catch {
|
|
8484
8661
|
return "";
|
|
8485
8662
|
}
|
|
@@ -8563,9 +8740,9 @@ function canListen(port, host) {
|
|
|
8563
8740
|
}
|
|
8564
8741
|
function readDotenvApiKeys(projectDir) {
|
|
8565
8742
|
const dotenvPath = path27.join(projectDir, ".env");
|
|
8566
|
-
if (!
|
|
8743
|
+
if (!fs29.existsSync(dotenvPath)) return {};
|
|
8567
8744
|
const result = {};
|
|
8568
|
-
for (const rawLine of
|
|
8745
|
+
for (const rawLine of fs29.readFileSync(dotenvPath, "utf-8").split("\n")) {
|
|
8569
8746
|
const line = rawLine.trim();
|
|
8570
8747
|
if (!line || line.startsWith("#")) continue;
|
|
8571
8748
|
const match = line.match(/^([A-Z_][A-Z0-9_]*_API_KEY)=(.*)$/);
|
|
@@ -8647,7 +8824,8 @@ function finalizedRunIndexRow(row, result) {
|
|
|
8647
8824
|
status: result.status,
|
|
8648
8825
|
updatedAt: result.updatedAt,
|
|
8649
8826
|
summary: result.reason ?? row.summary,
|
|
8650
|
-
...result.output === void 0 ? {} : { output: result.output }
|
|
8827
|
+
...result.output === void 0 ? {} : { output: result.output },
|
|
8828
|
+
...result.usage === void 0 ? {} : { usage: result.usage }
|
|
8651
8829
|
};
|
|
8652
8830
|
}
|
|
8653
8831
|
function runIndexRowFromJobContext(input) {
|
|
@@ -8696,7 +8874,8 @@ function runIndexRowFromJobContext(input) {
|
|
|
8696
8874
|
reasoningEffort: stringValue(input.data.jobReasoningEffort) ?? void 0,
|
|
8697
8875
|
target: input.data.jobTarget,
|
|
8698
8876
|
sourceType: "job",
|
|
8699
|
-
output: input.data.capabilityOutput
|
|
8877
|
+
output: input.data.capabilityOutput,
|
|
8878
|
+
usage: input.usage
|
|
8700
8879
|
});
|
|
8701
8880
|
}
|
|
8702
8881
|
function runIndexRowFromGoalEvents(goalId, logPath, events) {
|
|
@@ -9239,7 +9418,7 @@ var init_pushWithRetry = __esm({
|
|
|
9239
9418
|
// src/commit.ts
|
|
9240
9419
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
9241
9420
|
import { isDeepStrictEqual } from "util";
|
|
9242
|
-
import * as
|
|
9421
|
+
import * as fs30 from "fs";
|
|
9243
9422
|
import * as path28 from "path";
|
|
9244
9423
|
function isGitHubYamlPath(filePath) {
|
|
9245
9424
|
const normalized = filePath.replace(/^\.\/+/, "");
|
|
@@ -9284,17 +9463,17 @@ function ensureGitIdentity(cwd) {
|
|
|
9284
9463
|
function abortUnfinishedGitOps(cwd) {
|
|
9285
9464
|
const aborted = [];
|
|
9286
9465
|
const gitDir = path28.join(cwd ?? process.cwd(), ".git");
|
|
9287
|
-
if (!
|
|
9288
|
-
if (
|
|
9466
|
+
if (!fs30.existsSync(gitDir)) return aborted;
|
|
9467
|
+
if (fs30.existsSync(path28.join(gitDir, "MERGE_HEAD"))) {
|
|
9289
9468
|
if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
|
|
9290
9469
|
}
|
|
9291
|
-
if (
|
|
9470
|
+
if (fs30.existsSync(path28.join(gitDir, "CHERRY_PICK_HEAD"))) {
|
|
9292
9471
|
if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
|
|
9293
9472
|
}
|
|
9294
|
-
if (
|
|
9473
|
+
if (fs30.existsSync(path28.join(gitDir, "REVERT_HEAD"))) {
|
|
9295
9474
|
if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
|
|
9296
9475
|
}
|
|
9297
|
-
if (
|
|
9476
|
+
if (fs30.existsSync(path28.join(gitDir, "rebase-merge")) || fs30.existsSync(path28.join(gitDir, "rebase-apply"))) {
|
|
9298
9477
|
if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
|
|
9299
9478
|
}
|
|
9300
9479
|
try {
|
|
@@ -9377,7 +9556,7 @@ function isTrustedConfigActivationChange(filePath, deliveryPathAllowlist, delive
|
|
|
9377
9556
|
if (filePath !== "kody.config.json" || !deliveryPathAllowlist.includes(filePath)) return false;
|
|
9378
9557
|
try {
|
|
9379
9558
|
const before = JSON.parse(git(["show", "HEAD:kody.config.json"], cwd));
|
|
9380
|
-
const after = JSON.parse(
|
|
9559
|
+
const after = JSON.parse(fs30.readFileSync(path28.join(cwd ?? process.cwd(), filePath), "utf-8"));
|
|
9381
9560
|
return isSafeConfigChange(before, after, deliveryConfigAllowlist[filePath] ?? []);
|
|
9382
9561
|
} catch {
|
|
9383
9562
|
return false;
|
|
@@ -9440,7 +9619,7 @@ function commitAndPush(branch, agentMessage, cwd, deliveryPathAllowlist = [], de
|
|
|
9440
9619
|
(f) => isForbiddenPath(f, deliveryPathAllowlist) && !isTrustedConfigActivationChange(f, deliveryPathAllowlist, deliveryConfigAllowlist, cwd)
|
|
9441
9620
|
);
|
|
9442
9621
|
const omittedFiles = forbiddenFiles.filter(isReportableDeliveryOmission);
|
|
9443
|
-
const mergeHeadExists =
|
|
9622
|
+
const mergeHeadExists = fs30.existsSync(path28.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
|
|
9444
9623
|
if (allowedFiles.length === 0 && !mergeHeadExists) {
|
|
9445
9624
|
return { committed: false, pushed: false, sha: "", message: "", omittedFiles };
|
|
9446
9625
|
}
|
|
@@ -10096,7 +10275,7 @@ var init_state2 = __esm({
|
|
|
10096
10275
|
});
|
|
10097
10276
|
|
|
10098
10277
|
// src/goal/runLog.ts
|
|
10099
|
-
import * as
|
|
10278
|
+
import * as fs31 from "fs";
|
|
10100
10279
|
function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
|
|
10101
10280
|
const logs = goalRunLogs(data);
|
|
10102
10281
|
const existing = logs[goalId];
|
|
@@ -10438,8 +10617,8 @@ function readGithubEvent() {
|
|
|
10438
10617
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
10439
10618
|
if (!eventPath) return null;
|
|
10440
10619
|
try {
|
|
10441
|
-
if (!
|
|
10442
|
-
const parsed = JSON.parse(
|
|
10620
|
+
if (!fs31.existsSync(eventPath)) return null;
|
|
10621
|
+
const parsed = JSON.parse(fs31.readFileSync(eventPath, "utf-8"));
|
|
10443
10622
|
return recordValue3(parsed);
|
|
10444
10623
|
} catch {
|
|
10445
10624
|
return null;
|
|
@@ -10549,7 +10728,7 @@ var init_stateStore = __esm({
|
|
|
10549
10728
|
});
|
|
10550
10729
|
|
|
10551
10730
|
// src/goal/targetLoopResolution.ts
|
|
10552
|
-
import * as
|
|
10731
|
+
import * as fs32 from "fs";
|
|
10553
10732
|
import * as path29 from "path";
|
|
10554
10733
|
async function resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal) {
|
|
10555
10734
|
const targetId = loopGoal.loopTarget?.id.trim() ?? "";
|
|
@@ -10631,8 +10810,8 @@ function loadGoalTemplate(cwd, targetId) {
|
|
|
10631
10810
|
return readJsonObject2(path29.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
|
|
10632
10811
|
}
|
|
10633
10812
|
function readJsonObject2(filePath) {
|
|
10634
|
-
if (!
|
|
10635
|
-
const parsed = JSON.parse(
|
|
10813
|
+
if (!fs32.existsSync(filePath)) return null;
|
|
10814
|
+
const parsed = JSON.parse(fs32.readFileSync(filePath, "utf8"));
|
|
10636
10815
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
10637
10816
|
throw new Error(`goal template ${filePath} must be a JSON object`);
|
|
10638
10817
|
}
|
|
@@ -11007,7 +11186,7 @@ var init_backendStateBackend = __esm({
|
|
|
11007
11186
|
});
|
|
11008
11187
|
|
|
11009
11188
|
// src/scripts/jobState/localFileBackend.ts
|
|
11010
|
-
import * as
|
|
11189
|
+
import * as fs33 from "fs";
|
|
11011
11190
|
import * as path30 from "path";
|
|
11012
11191
|
function sanitizeKey(s) {
|
|
11013
11192
|
return s.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
@@ -11079,7 +11258,7 @@ var init_localFileBackend = __esm({
|
|
|
11079
11258
|
`);
|
|
11080
11259
|
return;
|
|
11081
11260
|
}
|
|
11082
|
-
|
|
11261
|
+
fs33.mkdirSync(this.absDir, { recursive: true });
|
|
11083
11262
|
const prefix = this.cacheKeyPrefix();
|
|
11084
11263
|
const probeKey = `${prefix}probe-${Date.now()}`;
|
|
11085
11264
|
try {
|
|
@@ -11108,7 +11287,7 @@ var init_localFileBackend = __esm({
|
|
|
11108
11287
|
`);
|
|
11109
11288
|
return;
|
|
11110
11289
|
}
|
|
11111
|
-
if (!
|
|
11290
|
+
if (!fs33.existsSync(this.absDir)) {
|
|
11112
11291
|
return;
|
|
11113
11292
|
}
|
|
11114
11293
|
const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
|
|
@@ -11125,10 +11304,10 @@ var init_localFileBackend = __esm({
|
|
|
11125
11304
|
load(slug) {
|
|
11126
11305
|
const relPath = stateFilePath(this.jobsDir, slug);
|
|
11127
11306
|
const absPath = path30.resolve(this.cwd, relPath);
|
|
11128
|
-
if (!
|
|
11307
|
+
if (!fs33.existsSync(absPath)) {
|
|
11129
11308
|
return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
11130
11309
|
}
|
|
11131
|
-
const raw =
|
|
11310
|
+
const raw = fs33.readFileSync(absPath, "utf-8");
|
|
11132
11311
|
let parsed;
|
|
11133
11312
|
try {
|
|
11134
11313
|
parsed = JSON.parse(raw);
|
|
@@ -11146,12 +11325,12 @@ var init_localFileBackend = __esm({
|
|
|
11146
11325
|
return false;
|
|
11147
11326
|
}
|
|
11148
11327
|
const absPath = path30.resolve(this.cwd, loaded.path);
|
|
11149
|
-
|
|
11328
|
+
fs33.mkdirSync(path30.dirname(absPath), { recursive: true });
|
|
11150
11329
|
const body = `${JSON.stringify(next, null, 2)}
|
|
11151
11330
|
`;
|
|
11152
11331
|
const tmpPath = `${absPath}.${process.pid}.tmp`;
|
|
11153
|
-
|
|
11154
|
-
|
|
11332
|
+
fs33.writeFileSync(tmpPath, body, "utf-8");
|
|
11333
|
+
fs33.renameSync(tmpPath, absPath);
|
|
11155
11334
|
return true;
|
|
11156
11335
|
}
|
|
11157
11336
|
cacheKeyPrefix() {
|
|
@@ -13060,7 +13239,7 @@ var init_classifyByLabel = __esm({
|
|
|
13060
13239
|
|
|
13061
13240
|
// src/scripts/commitAndPush.ts
|
|
13062
13241
|
import { createHash as createHash5 } from "crypto";
|
|
13063
|
-
import * as
|
|
13242
|
+
import * as fs34 from "fs";
|
|
13064
13243
|
import * as path32 from "path";
|
|
13065
13244
|
function sentinelPathForStage(cwd, profileName, workflowExecutionKey) {
|
|
13066
13245
|
const runId = resolveRunId();
|
|
@@ -13083,9 +13262,9 @@ var init_commitAndPush = __esm({
|
|
|
13083
13262
|
}
|
|
13084
13263
|
const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
|
|
13085
13264
|
const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name, ctx.data.workflowExecutionKey) : null;
|
|
13086
|
-
if (sentinel &&
|
|
13265
|
+
if (sentinel && fs34.existsSync(sentinel)) {
|
|
13087
13266
|
try {
|
|
13088
|
-
const replay = JSON.parse(
|
|
13267
|
+
const replay = JSON.parse(fs34.readFileSync(sentinel, "utf-8"));
|
|
13089
13268
|
ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
|
|
13090
13269
|
if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
|
|
13091
13270
|
if (Array.isArray(replay.deliveryOmissions)) ctx.data.deliveryOmissions = replay.deliveryOmissions;
|
|
@@ -13149,8 +13328,8 @@ var init_commitAndPush = __esm({
|
|
|
13149
13328
|
const result = ctx.data.commitResult;
|
|
13150
13329
|
if (sentinel && result?.committed) {
|
|
13151
13330
|
try {
|
|
13152
|
-
|
|
13153
|
-
|
|
13331
|
+
fs34.mkdirSync(path32.dirname(sentinel), { recursive: true });
|
|
13332
|
+
fs34.writeFileSync(
|
|
13154
13333
|
sentinel,
|
|
13155
13334
|
JSON.stringify(
|
|
13156
13335
|
{
|
|
@@ -13277,7 +13456,7 @@ var init_acceptanceCriteria = __esm({
|
|
|
13277
13456
|
});
|
|
13278
13457
|
|
|
13279
13458
|
// src/scripts/composePrompt.ts
|
|
13280
|
-
import * as
|
|
13459
|
+
import * as fs35 from "fs";
|
|
13281
13460
|
import * as path33 from "path";
|
|
13282
13461
|
function fenceUntrusted(value) {
|
|
13283
13462
|
if (value.trim().length === 0) return value;
|
|
@@ -13419,7 +13598,7 @@ var init_composePrompt = __esm({
|
|
|
13419
13598
|
break;
|
|
13420
13599
|
}
|
|
13421
13600
|
try {
|
|
13422
|
-
template =
|
|
13601
|
+
template = fs35.readFileSync(c, "utf-8");
|
|
13423
13602
|
templatePath = c;
|
|
13424
13603
|
break;
|
|
13425
13604
|
} catch (err) {
|
|
@@ -13430,7 +13609,7 @@ var init_composePrompt = __esm({
|
|
|
13430
13609
|
if (!templatePath) {
|
|
13431
13610
|
let dirState;
|
|
13432
13611
|
try {
|
|
13433
|
-
dirState = `dir contents: [${
|
|
13612
|
+
dirState = `dir contents: [${fs35.readdirSync(profile.dir).join(", ")}]`;
|
|
13434
13613
|
} catch (err) {
|
|
13435
13614
|
dirState = `readdir(${profile.dir}) failed: ${err?.code ?? String(err)}`;
|
|
13436
13615
|
}
|
|
@@ -14168,7 +14347,7 @@ var init_deriveQaScopeFromIssue = __esm({
|
|
|
14168
14347
|
|
|
14169
14348
|
// src/scripts/diagMcp.ts
|
|
14170
14349
|
import { execFileSync as execFileSync9 } from "child_process";
|
|
14171
|
-
import * as
|
|
14350
|
+
import * as fs36 from "fs";
|
|
14172
14351
|
import * as os5 from "os";
|
|
14173
14352
|
import * as path34 from "path";
|
|
14174
14353
|
var diagMcp;
|
|
@@ -14180,7 +14359,7 @@ var init_diagMcp = __esm({
|
|
|
14180
14359
|
const cacheDir = path34.join(home, ".cache", "ms-playwright");
|
|
14181
14360
|
let entries = [];
|
|
14182
14361
|
try {
|
|
14183
|
-
entries =
|
|
14362
|
+
entries = fs36.readdirSync(cacheDir);
|
|
14184
14363
|
} catch {
|
|
14185
14364
|
}
|
|
14186
14365
|
const hasChromium = entries.some((e) => e.startsWith("chromium"));
|
|
@@ -14208,13 +14387,13 @@ var init_diagMcp = __esm({
|
|
|
14208
14387
|
});
|
|
14209
14388
|
|
|
14210
14389
|
// src/scripts/frameworkDetectors.ts
|
|
14211
|
-
import * as
|
|
14390
|
+
import * as fs37 from "fs";
|
|
14212
14391
|
import * as path35 from "path";
|
|
14213
14392
|
function detectFrameworks(cwd) {
|
|
14214
14393
|
const out = [];
|
|
14215
14394
|
let deps = {};
|
|
14216
14395
|
try {
|
|
14217
|
-
const pkg = JSON.parse(
|
|
14396
|
+
const pkg = JSON.parse(fs37.readFileSync(path35.join(cwd, "package.json"), "utf-8"));
|
|
14218
14397
|
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
14219
14398
|
} catch {
|
|
14220
14399
|
return out;
|
|
@@ -14251,7 +14430,7 @@ function detectFrameworks(cwd) {
|
|
|
14251
14430
|
}
|
|
14252
14431
|
function findFile(cwd, candidates) {
|
|
14253
14432
|
for (const c of candidates) {
|
|
14254
|
-
if (
|
|
14433
|
+
if (fs37.existsSync(path35.join(cwd, c))) return c;
|
|
14255
14434
|
}
|
|
14256
14435
|
return null;
|
|
14257
14436
|
}
|
|
@@ -14259,17 +14438,17 @@ function discoverPayloadCollections(cwd) {
|
|
|
14259
14438
|
const out = [];
|
|
14260
14439
|
for (const dir of COLLECTION_DIRS) {
|
|
14261
14440
|
const full = path35.join(cwd, dir);
|
|
14262
|
-
if (!
|
|
14441
|
+
if (!fs37.existsSync(full)) continue;
|
|
14263
14442
|
let files;
|
|
14264
14443
|
try {
|
|
14265
|
-
files =
|
|
14444
|
+
files = fs37.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
14266
14445
|
} catch {
|
|
14267
14446
|
continue;
|
|
14268
14447
|
}
|
|
14269
14448
|
for (const file of files) {
|
|
14270
14449
|
try {
|
|
14271
14450
|
const filePath = path35.join(full, file);
|
|
14272
|
-
const content =
|
|
14451
|
+
const content = fs37.readFileSync(filePath, "utf-8").slice(0, 1e4);
|
|
14273
14452
|
const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
|
|
14274
14453
|
if (!slugMatch) continue;
|
|
14275
14454
|
const slug = slugMatch[1];
|
|
@@ -14297,10 +14476,10 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
14297
14476
|
const out = [];
|
|
14298
14477
|
for (const dir of ADMIN_COMPONENT_DIRS) {
|
|
14299
14478
|
const full = path35.join(cwd, dir);
|
|
14300
|
-
if (!
|
|
14479
|
+
if (!fs37.existsSync(full)) continue;
|
|
14301
14480
|
let entries;
|
|
14302
14481
|
try {
|
|
14303
|
-
entries =
|
|
14482
|
+
entries = fs37.readdirSync(full, { withFileTypes: true });
|
|
14304
14483
|
} catch {
|
|
14305
14484
|
continue;
|
|
14306
14485
|
}
|
|
@@ -14310,7 +14489,7 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
14310
14489
|
let filePath;
|
|
14311
14490
|
if (entry.isDirectory()) {
|
|
14312
14491
|
const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
|
|
14313
|
-
(f) =>
|
|
14492
|
+
(f) => fs37.existsSync(path35.join(entryPath, f))
|
|
14314
14493
|
);
|
|
14315
14494
|
if (!indexFile) continue;
|
|
14316
14495
|
name = entry.name;
|
|
@@ -14325,7 +14504,7 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
14325
14504
|
if (collections) {
|
|
14326
14505
|
for (const col of collections) {
|
|
14327
14506
|
try {
|
|
14328
|
-
const colContent =
|
|
14507
|
+
const colContent = fs37.readFileSync(path35.join(cwd, col.filePath), "utf-8");
|
|
14329
14508
|
if (colContent.includes(name)) {
|
|
14330
14509
|
usedInCollection = col.slug;
|
|
14331
14510
|
break;
|
|
@@ -14344,7 +14523,7 @@ function scanApiRoutes(cwd) {
|
|
|
14344
14523
|
const appDirs = ["src/app", "app"];
|
|
14345
14524
|
for (const appDir of appDirs) {
|
|
14346
14525
|
const apiDir = path35.join(cwd, appDir, "api");
|
|
14347
|
-
if (!
|
|
14526
|
+
if (!fs37.existsSync(apiDir)) continue;
|
|
14348
14527
|
walkApiRoutes(apiDir, "/api", cwd, out);
|
|
14349
14528
|
break;
|
|
14350
14529
|
}
|
|
@@ -14353,14 +14532,14 @@ function scanApiRoutes(cwd) {
|
|
|
14353
14532
|
function walkApiRoutes(dir, prefix, cwd, out) {
|
|
14354
14533
|
let entries;
|
|
14355
14534
|
try {
|
|
14356
|
-
entries =
|
|
14535
|
+
entries = fs37.readdirSync(dir, { withFileTypes: true });
|
|
14357
14536
|
} catch {
|
|
14358
14537
|
return;
|
|
14359
14538
|
}
|
|
14360
14539
|
const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
|
|
14361
14540
|
if (routeFile) {
|
|
14362
14541
|
try {
|
|
14363
|
-
const content =
|
|
14542
|
+
const content = fs37.readFileSync(path35.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
|
|
14364
14543
|
const methods = HTTP_METHODS.filter(
|
|
14365
14544
|
(m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
|
|
14366
14545
|
);
|
|
@@ -14394,9 +14573,9 @@ function scanEnvVars(cwd) {
|
|
|
14394
14573
|
const candidates = [".env.example", ".env.local.example", ".env.template"];
|
|
14395
14574
|
for (const envFile of candidates) {
|
|
14396
14575
|
const envPath = path35.join(cwd, envFile);
|
|
14397
|
-
if (!
|
|
14576
|
+
if (!fs37.existsSync(envPath)) continue;
|
|
14398
14577
|
try {
|
|
14399
|
-
const content =
|
|
14578
|
+
const content = fs37.readFileSync(envPath, "utf-8");
|
|
14400
14579
|
const vars = [];
|
|
14401
14580
|
for (const line of content.split("\n")) {
|
|
14402
14581
|
const trimmed = line.trim();
|
|
@@ -14441,7 +14620,7 @@ var init_frameworkDetectors = __esm({
|
|
|
14441
14620
|
});
|
|
14442
14621
|
|
|
14443
14622
|
// src/scripts/discoverQaContext.ts
|
|
14444
|
-
import * as
|
|
14623
|
+
import * as fs38 from "fs";
|
|
14445
14624
|
import * as path36 from "path";
|
|
14446
14625
|
function runQaDiscovery(cwd) {
|
|
14447
14626
|
const out = {
|
|
@@ -14473,9 +14652,9 @@ function runQaDiscovery(cwd) {
|
|
|
14473
14652
|
}
|
|
14474
14653
|
function detectDevServer(cwd, out) {
|
|
14475
14654
|
try {
|
|
14476
|
-
const pkg = JSON.parse(
|
|
14655
|
+
const pkg = JSON.parse(fs38.readFileSync(path36.join(cwd, "package.json"), "utf-8"));
|
|
14477
14656
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
14478
|
-
const pm =
|
|
14657
|
+
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
14658
|
if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
|
|
14480
14659
|
if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
|
|
14481
14660
|
else if (allDeps.vite) out.devPort = 5173;
|
|
@@ -14486,7 +14665,7 @@ function scanFrontendRoutes(cwd, out) {
|
|
|
14486
14665
|
const appDirs = ["src/app", "app"];
|
|
14487
14666
|
for (const appDir of appDirs) {
|
|
14488
14667
|
const full = path36.join(cwd, appDir);
|
|
14489
|
-
if (!
|
|
14668
|
+
if (!fs38.existsSync(full)) continue;
|
|
14490
14669
|
walkFrontendRoutes(full, "", out);
|
|
14491
14670
|
break;
|
|
14492
14671
|
}
|
|
@@ -14494,7 +14673,7 @@ function scanFrontendRoutes(cwd, out) {
|
|
|
14494
14673
|
function walkFrontendRoutes(dir, prefix, out) {
|
|
14495
14674
|
let entries;
|
|
14496
14675
|
try {
|
|
14497
|
-
entries =
|
|
14676
|
+
entries = fs38.readdirSync(dir, { withFileTypes: true });
|
|
14498
14677
|
} catch {
|
|
14499
14678
|
return;
|
|
14500
14679
|
}
|
|
@@ -14536,23 +14715,23 @@ function detectAuthFiles(cwd, out) {
|
|
|
14536
14715
|
"src/app/api/oauth"
|
|
14537
14716
|
];
|
|
14538
14717
|
for (const c of candidates) {
|
|
14539
|
-
if (
|
|
14718
|
+
if (fs38.existsSync(path36.join(cwd, c))) out.authFiles.push(c);
|
|
14540
14719
|
}
|
|
14541
14720
|
}
|
|
14542
14721
|
function detectRoles(cwd, out) {
|
|
14543
14722
|
const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
|
|
14544
14723
|
for (const rp of rolePaths) {
|
|
14545
14724
|
const dir = path36.join(cwd, rp);
|
|
14546
|
-
if (!
|
|
14725
|
+
if (!fs38.existsSync(dir)) continue;
|
|
14547
14726
|
let files;
|
|
14548
14727
|
try {
|
|
14549
|
-
files =
|
|
14728
|
+
files = fs38.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
14550
14729
|
} catch {
|
|
14551
14730
|
continue;
|
|
14552
14731
|
}
|
|
14553
14732
|
for (const f of files) {
|
|
14554
14733
|
try {
|
|
14555
|
-
const content =
|
|
14734
|
+
const content = fs38.readFileSync(path36.join(dir, f), "utf-8").slice(0, 5e3);
|
|
14556
14735
|
const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
|
|
14557
14736
|
if (roleMatches) {
|
|
14558
14737
|
for (const m of roleMatches) {
|
|
@@ -14813,7 +14992,7 @@ var init_dispatchClassified = __esm({
|
|
|
14813
14992
|
});
|
|
14814
14993
|
|
|
14815
14994
|
// src/loopDefinitions.ts
|
|
14816
|
-
import * as
|
|
14995
|
+
import * as fs39 from "fs";
|
|
14817
14996
|
import * as path37 from "path";
|
|
14818
14997
|
function normalizeLoopDefinition(value) {
|
|
14819
14998
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
@@ -14842,9 +15021,9 @@ function readLoopDefinition(cwd, id) {
|
|
|
14842
15021
|
const roots = loopRoots(cwd);
|
|
14843
15022
|
for (const root of roots) {
|
|
14844
15023
|
const filePath = path37.join(root, "loops", id, "loop.json");
|
|
14845
|
-
if (!
|
|
15024
|
+
if (!fs39.existsSync(filePath)) continue;
|
|
14846
15025
|
try {
|
|
14847
|
-
const loop = normalizeLoopDefinition(JSON.parse(
|
|
15026
|
+
const loop = normalizeLoopDefinition(JSON.parse(fs39.readFileSync(filePath, "utf8")));
|
|
14848
15027
|
if (loop?.id === id) return loop;
|
|
14849
15028
|
process.stderr.write(`[kody] invalid Loop definition: ${filePath}
|
|
14850
15029
|
`);
|
|
@@ -14864,13 +15043,13 @@ function listLoopDefinitions(cwd) {
|
|
|
14864
15043
|
const byId = /* @__PURE__ */ new Map();
|
|
14865
15044
|
for (const root of roots.reverse()) {
|
|
14866
15045
|
const loopsDir = path37.join(root, "loops");
|
|
14867
|
-
if (!
|
|
14868
|
-
for (const id of
|
|
15046
|
+
if (!fs39.existsSync(loopsDir)) continue;
|
|
15047
|
+
for (const id of fs39.readdirSync(loopsDir).sort()) {
|
|
14869
15048
|
if (!ID.test(id)) continue;
|
|
14870
15049
|
const filePath = path37.join(loopsDir, id, "loop.json");
|
|
14871
|
-
if (!
|
|
15050
|
+
if (!fs39.existsSync(filePath)) continue;
|
|
14872
15051
|
try {
|
|
14873
|
-
const loop = normalizeLoopDefinition(JSON.parse(
|
|
15052
|
+
const loop = normalizeLoopDefinition(JSON.parse(fs39.readFileSync(filePath, "utf8")));
|
|
14874
15053
|
if (loop?.id === id) byId.set(id, loop);
|
|
14875
15054
|
} catch {
|
|
14876
15055
|
process.stderr.write(`[kody] unreadable Loop definition: ${filePath}
|
|
@@ -16235,15 +16414,15 @@ var init_fixFlow = __esm({
|
|
|
16235
16414
|
});
|
|
16236
16415
|
|
|
16237
16416
|
// src/workflow-template.ts
|
|
16238
|
-
import * as
|
|
16417
|
+
import * as fs40 from "fs";
|
|
16239
16418
|
import * as path38 from "path";
|
|
16240
16419
|
import { fileURLToPath } from "url";
|
|
16241
16420
|
function loadKodyWorkflowTemplate() {
|
|
16242
16421
|
const here = path38.dirname(fileURLToPath(import.meta.url));
|
|
16243
16422
|
const candidates = [path38.resolve(here, "../templates/kody.yml"), path38.resolve(here, "../../templates/kody.yml")];
|
|
16244
|
-
const source = candidates.find((candidate) =>
|
|
16423
|
+
const source = candidates.find((candidate) => fs40.existsSync(candidate));
|
|
16245
16424
|
if (!source) throw new Error(`Kody workflow template is missing: ${KODY_WORKFLOW_TEMPLATE_PATH}`);
|
|
16246
|
-
return
|
|
16425
|
+
return fs40.readFileSync(source, "utf8");
|
|
16247
16426
|
}
|
|
16248
16427
|
var KODY_WORKFLOW_TEMPLATE_PATH;
|
|
16249
16428
|
var init_workflow_template = __esm({
|
|
@@ -16255,7 +16434,7 @@ var init_workflow_template = __esm({
|
|
|
16255
16434
|
|
|
16256
16435
|
// src/scripts/initFlow.ts
|
|
16257
16436
|
import { execFileSync as execFileSync14 } from "child_process";
|
|
16258
|
-
import * as
|
|
16437
|
+
import * as fs41 from "fs";
|
|
16259
16438
|
import * as path39 from "path";
|
|
16260
16439
|
function schemaUrlFromPkg() {
|
|
16261
16440
|
const fallback = "https://raw.githubusercontent.com/aharonyaircohen/kody-engine/main/kody.config.schema.json";
|
|
@@ -16321,21 +16500,21 @@ function performInit(cwd, force, workflowOnly = false) {
|
|
|
16321
16500
|
const configPath = path39.join(cwd, "kody.config.json");
|
|
16322
16501
|
if (workflowOnly) {
|
|
16323
16502
|
skipped.push("kody.config.json");
|
|
16324
|
-
} else if (
|
|
16503
|
+
} else if (fs41.existsSync(configPath) && !force) {
|
|
16325
16504
|
skipped.push("kody.config.json");
|
|
16326
16505
|
} else {
|
|
16327
16506
|
const cfg = makeConfig(cwd, ownerRepo, defaultBranch);
|
|
16328
|
-
|
|
16507
|
+
fs41.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
16329
16508
|
`);
|
|
16330
16509
|
wrote.push("kody.config.json");
|
|
16331
16510
|
}
|
|
16332
16511
|
const workflowDir = path39.join(cwd, ".github", "workflows");
|
|
16333
16512
|
const workflowPath = path39.join(workflowDir, "kody.yml");
|
|
16334
|
-
if (
|
|
16513
|
+
if (fs41.existsSync(workflowPath) && !force) {
|
|
16335
16514
|
skipped.push(".github/workflows/kody.yml");
|
|
16336
16515
|
} else {
|
|
16337
|
-
|
|
16338
|
-
|
|
16516
|
+
fs41.mkdirSync(workflowDir, { recursive: true });
|
|
16517
|
+
fs41.writeFileSync(workflowPath, loadKodyWorkflowTemplate());
|
|
16339
16518
|
wrote.push(".github/workflows/kody.yml");
|
|
16340
16519
|
}
|
|
16341
16520
|
let labels;
|
|
@@ -16388,7 +16567,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
|
|
|
16388
16567
|
});
|
|
16389
16568
|
|
|
16390
16569
|
// src/scripts/loadAgentAdhoc.ts
|
|
16391
|
-
import * as
|
|
16570
|
+
import * as fs42 from "fs";
|
|
16392
16571
|
function resolveMessage(messageArg) {
|
|
16393
16572
|
const fromComment = readCommentBody();
|
|
16394
16573
|
if (fromComment) return stripDirective(fromComment);
|
|
@@ -16396,9 +16575,9 @@ function resolveMessage(messageArg) {
|
|
|
16396
16575
|
}
|
|
16397
16576
|
function readCommentBody() {
|
|
16398
16577
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
16399
|
-
if (!eventPath || !
|
|
16578
|
+
if (!eventPath || !fs42.existsSync(eventPath)) return "";
|
|
16400
16579
|
try {
|
|
16401
|
-
const event = JSON.parse(
|
|
16580
|
+
const event = JSON.parse(fs42.readFileSync(eventPath, "utf-8"));
|
|
16402
16581
|
return String(event.comment?.body ?? "");
|
|
16403
16582
|
} catch {
|
|
16404
16583
|
return "";
|
|
@@ -16452,10 +16631,10 @@ var init_loadAgentAdhoc = __esm({
|
|
|
16452
16631
|
throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
|
|
16453
16632
|
}
|
|
16454
16633
|
const agentPath = resolveAgentFile2(ctx.cwd, agentSlug, agentsDir);
|
|
16455
|
-
if (!
|
|
16634
|
+
if (!fs42.existsSync(agentPath)) {
|
|
16456
16635
|
throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
|
|
16457
16636
|
}
|
|
16458
|
-
const { title, body } = parseAgentFile(
|
|
16637
|
+
const { title, body } = parseAgentFile(fs42.readFileSync(agentPath, "utf-8"), agentSlug);
|
|
16459
16638
|
const message = resolveMessage(ctx.args.message);
|
|
16460
16639
|
if (!message) {
|
|
16461
16640
|
throw new Error(
|
|
@@ -16824,7 +17003,7 @@ var init_loadIssueStateComment = __esm({
|
|
|
16824
17003
|
});
|
|
16825
17004
|
|
|
16826
17005
|
// src/scripts/loadJobFromFile.ts
|
|
16827
|
-
import * as
|
|
17006
|
+
import * as fs43 from "fs";
|
|
16828
17007
|
import * as path40 from "path";
|
|
16829
17008
|
function parseJobFile(raw, slug) {
|
|
16830
17009
|
let stripped = raw;
|
|
@@ -16877,12 +17056,12 @@ var init_loadJobFromFile = __esm({
|
|
|
16877
17056
|
let agentIdentity = "";
|
|
16878
17057
|
if (agentSlug) {
|
|
16879
17058
|
const agentPath = resolveAgentFile2(ctx.cwd, agentSlug, agentsDir);
|
|
16880
|
-
if (!
|
|
17059
|
+
if (!fs43.existsSync(agentPath)) {
|
|
16881
17060
|
throw new Error(
|
|
16882
17061
|
`loadJobFromFile: capability '${slug}' declares agent '${agentSlug}' but ${agentPath} does not exist`
|
|
16883
17062
|
);
|
|
16884
17063
|
}
|
|
16885
|
-
const agentRaw =
|
|
17064
|
+
const agentRaw = fs43.readFileSync(agentPath, "utf-8");
|
|
16886
17065
|
const parsed = parseJobFile(agentRaw, agentSlug);
|
|
16887
17066
|
agentTitle = parsed.title;
|
|
16888
17067
|
agentIdentity = parsed.body;
|
|
@@ -16962,7 +17141,7 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
16962
17141
|
});
|
|
16963
17142
|
|
|
16964
17143
|
// src/scripts/loadLiveAgent.ts
|
|
16965
|
-
import * as
|
|
17144
|
+
import * as fs44 from "fs";
|
|
16966
17145
|
function tenant(config) {
|
|
16967
17146
|
const [envOwner, envRepo] = (process.env.GITHUB_REPOSITORY ?? "").split("/");
|
|
16968
17147
|
const owner = config.github?.owner?.trim() || envOwner;
|
|
@@ -17005,7 +17184,7 @@ var init_loadLiveAgent = __esm({
|
|
|
17005
17184
|
const agent = String(ctx.args.agent ?? ctx.data.jobAgent ?? "").trim();
|
|
17006
17185
|
if (!agent) throw new Error("loadLiveAgent: agent is required");
|
|
17007
17186
|
const file = resolveAgentFile2(ctx.cwd, agent, agentsRoot(ctx.cwd));
|
|
17008
|
-
const raw =
|
|
17187
|
+
const raw = fs44.existsSync(file) ? fs44.readFileSync(file, "utf8") : "";
|
|
17009
17188
|
const metadata = frontmatter(raw);
|
|
17010
17189
|
const assignedIntent = typeof metadata.primaryIntent === "string" ? metadata.primaryIntent : "";
|
|
17011
17190
|
const requestedIntent = String(ctx.args.intent ?? "").trim();
|
|
@@ -17053,13 +17232,13 @@ var init_loadLiveAgent = __esm({
|
|
|
17053
17232
|
});
|
|
17054
17233
|
|
|
17055
17234
|
// src/scripts/kodyVariables.ts
|
|
17056
|
-
import * as
|
|
17235
|
+
import * as fs45 from "fs";
|
|
17057
17236
|
import * as path41 from "path";
|
|
17058
17237
|
function readKodyVariables(cwd) {
|
|
17059
17238
|
const full = path41.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
17060
17239
|
let raw;
|
|
17061
17240
|
try {
|
|
17062
|
-
raw =
|
|
17241
|
+
raw = fs45.readFileSync(full, "utf-8");
|
|
17063
17242
|
} catch {
|
|
17064
17243
|
return {};
|
|
17065
17244
|
}
|
|
@@ -17084,7 +17263,7 @@ var init_kodyVariables = __esm({
|
|
|
17084
17263
|
});
|
|
17085
17264
|
|
|
17086
17265
|
// src/scripts/loadQaContext.ts
|
|
17087
|
-
import * as
|
|
17266
|
+
import * as fs46 from "fs";
|
|
17088
17267
|
import * as path42 from "path";
|
|
17089
17268
|
function parseSlugList(value) {
|
|
17090
17269
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
@@ -17115,17 +17294,17 @@ function readProfileAgents(raw) {
|
|
|
17115
17294
|
}
|
|
17116
17295
|
function readProfile(cwd) {
|
|
17117
17296
|
const dir = path42.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
17118
|
-
if (!
|
|
17297
|
+
if (!fs46.existsSync(dir)) return "";
|
|
17119
17298
|
let entries;
|
|
17120
17299
|
try {
|
|
17121
|
-
entries =
|
|
17300
|
+
entries = fs46.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
17122
17301
|
} catch {
|
|
17123
17302
|
return "";
|
|
17124
17303
|
}
|
|
17125
17304
|
const blocks = [];
|
|
17126
17305
|
for (const file of entries) {
|
|
17127
17306
|
try {
|
|
17128
|
-
const raw =
|
|
17307
|
+
const raw = fs46.readFileSync(path42.join(dir, file), "utf-8");
|
|
17129
17308
|
const { agent, body } = readProfileAgents(raw);
|
|
17130
17309
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
17131
17310
|
blocks.push(`## ${file}
|
|
@@ -17175,7 +17354,7 @@ var init_loadQaContext = __esm({
|
|
|
17175
17354
|
|
|
17176
17355
|
// src/scripts/loadSimpleCapability.ts
|
|
17177
17356
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
17178
|
-
import * as
|
|
17357
|
+
import * as fs47 from "fs";
|
|
17179
17358
|
import * as os6 from "os";
|
|
17180
17359
|
import * as path43 from "path";
|
|
17181
17360
|
function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
|
|
@@ -17190,7 +17369,7 @@ function registerCapabilitySubagents(profile, toolRoot, toolFiles) {
|
|
|
17190
17369
|
profile.subagentTemplates = {
|
|
17191
17370
|
...profile.subagentTemplates ?? {},
|
|
17192
17371
|
...Object.fromEntries(
|
|
17193
|
-
subagentFiles.map(({ name, file }) => [name,
|
|
17372
|
+
subagentFiles.map(({ name, file }) => [name, fs47.readFileSync(path43.join(toolRoot, file), "utf-8")])
|
|
17194
17373
|
)
|
|
17195
17374
|
};
|
|
17196
17375
|
if (!profile.claudeCode.tools.includes("Agent")) {
|
|
@@ -17231,10 +17410,10 @@ function scalar(value) {
|
|
|
17231
17410
|
return value;
|
|
17232
17411
|
}
|
|
17233
17412
|
function listFiles(root) {
|
|
17234
|
-
if (!
|
|
17413
|
+
if (!fs47.existsSync(root)) return [];
|
|
17235
17414
|
const files = [];
|
|
17236
17415
|
const visit = (dir) => {
|
|
17237
|
-
for (const entry of
|
|
17416
|
+
for (const entry of fs47.readdirSync(dir, { withFileTypes: true })) {
|
|
17238
17417
|
const absolute = path43.join(dir, entry.name);
|
|
17239
17418
|
if (entry.isSymbolicLink()) continue;
|
|
17240
17419
|
if (entry.isDirectory()) visit(absolute);
|
|
@@ -17327,7 +17506,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
17327
17506
|
...skillFiles.flatMap((file) => [
|
|
17328
17507
|
`### ${file}`,
|
|
17329
17508
|
"",
|
|
17330
|
-
|
|
17509
|
+
fs47.readFileSync(path43.join(skillRoot, file), "utf-8"),
|
|
17331
17510
|
""
|
|
17332
17511
|
])
|
|
17333
17512
|
] : [],
|
|
@@ -17367,7 +17546,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
17367
17546
|
});
|
|
17368
17547
|
|
|
17369
17548
|
// src/taskContext.ts
|
|
17370
|
-
import * as
|
|
17549
|
+
import * as fs48 from "fs";
|
|
17371
17550
|
import * as path44 from "path";
|
|
17372
17551
|
function buildTaskContext(args) {
|
|
17373
17552
|
return {
|
|
@@ -17384,9 +17563,9 @@ function buildTaskContext(args) {
|
|
|
17384
17563
|
function persistTaskContext(cwd, ctx) {
|
|
17385
17564
|
try {
|
|
17386
17565
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
17387
|
-
|
|
17566
|
+
fs48.mkdirSync(dir, { recursive: true });
|
|
17388
17567
|
const file = path44.join(dir, "task-context.json");
|
|
17389
|
-
|
|
17568
|
+
fs48.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
17390
17569
|
`);
|
|
17391
17570
|
return file;
|
|
17392
17571
|
} catch (err) {
|
|
@@ -18309,7 +18488,7 @@ var init_parseReproOutput = __esm({
|
|
|
18309
18488
|
});
|
|
18310
18489
|
|
|
18311
18490
|
// src/scripts/parseSimpleCapabilityOutput.ts
|
|
18312
|
-
import * as
|
|
18491
|
+
import * as fs49 from "fs";
|
|
18313
18492
|
function acceptAuthoritativeCapabilityOutput(ctx, profile, output) {
|
|
18314
18493
|
ctx.data.agentDone = true;
|
|
18315
18494
|
delete ctx.data.agentFailureReason;
|
|
@@ -18326,11 +18505,11 @@ function stringList2(value) {
|
|
|
18326
18505
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
18327
18506
|
}
|
|
18328
18507
|
function readOutputFile(outputPath) {
|
|
18329
|
-
if (!outputPath || !
|
|
18508
|
+
if (!outputPath || !fs49.existsSync(outputPath)) return { found: false };
|
|
18330
18509
|
try {
|
|
18331
|
-
return { found: true, value: JSON.parse(
|
|
18510
|
+
return { found: true, value: JSON.parse(fs49.readFileSync(outputPath, "utf-8")) };
|
|
18332
18511
|
} finally {
|
|
18333
|
-
|
|
18512
|
+
fs49.rmSync(outputPath, { force: true });
|
|
18334
18513
|
}
|
|
18335
18514
|
}
|
|
18336
18515
|
function parseOutput(text2) {
|
|
@@ -18992,7 +19171,7 @@ var init_postResearchComment = __esm({
|
|
|
18992
19171
|
});
|
|
18993
19172
|
|
|
18994
19173
|
// src/scripts/prepareBrowserAuth.ts
|
|
18995
|
-
import * as
|
|
19174
|
+
import * as fs50 from "fs";
|
|
18996
19175
|
import * as os7 from "os";
|
|
18997
19176
|
import * as path45 from "path";
|
|
18998
19177
|
function appendAuthMessage(ctx, message) {
|
|
@@ -19038,8 +19217,8 @@ async function githubJson(url, token, checkName) {
|
|
|
19038
19217
|
throw new Error(`GitHub ${checkName} check failed`);
|
|
19039
19218
|
}
|
|
19040
19219
|
function writeKodyStorageState(input) {
|
|
19041
|
-
const directory =
|
|
19042
|
-
|
|
19220
|
+
const directory = fs50.mkdtempSync(path45.join(os7.tmpdir(), "kody-browser-auth-"));
|
|
19221
|
+
fs50.chmodSync(directory, 448);
|
|
19043
19222
|
const file = path45.join(directory, "storage-state.json");
|
|
19044
19223
|
const now = Date.now();
|
|
19045
19224
|
const repoEntry = {
|
|
@@ -19071,7 +19250,7 @@ function writeKodyStorageState(input) {
|
|
|
19071
19250
|
}
|
|
19072
19251
|
]
|
|
19073
19252
|
};
|
|
19074
|
-
|
|
19253
|
+
fs50.writeFileSync(file, JSON.stringify(storageState), { mode: 384 });
|
|
19075
19254
|
return { directory, file, auth };
|
|
19076
19255
|
}
|
|
19077
19256
|
function parseSetCookie(value, hostname) {
|
|
@@ -19098,10 +19277,10 @@ function parseSetCookie(value, hostname) {
|
|
|
19098
19277
|
}
|
|
19099
19278
|
function writeCookieStorageState(targetUrl, setCookies) {
|
|
19100
19279
|
const target = new URL(targetUrl);
|
|
19101
|
-
const directory =
|
|
19102
|
-
|
|
19280
|
+
const directory = fs50.mkdtempSync(path45.join(os7.tmpdir(), "kody-browser-auth-"));
|
|
19281
|
+
fs50.chmodSync(directory, 448);
|
|
19103
19282
|
const file = path45.join(directory, "storage-state.json");
|
|
19104
|
-
|
|
19283
|
+
fs50.writeFileSync(
|
|
19105
19284
|
file,
|
|
19106
19285
|
JSON.stringify({
|
|
19107
19286
|
cookies: setCookies.map((cookie) => parseSetCookie(cookie, target.hostname)),
|
|
@@ -19122,9 +19301,9 @@ function currentStorageStatePath(args) {
|
|
|
19122
19301
|
function browserSessionCookieHeader(profile, targetUrl) {
|
|
19123
19302
|
const playwright = profile.claudeCode.mcpServers.find((server) => server.name === "playwright");
|
|
19124
19303
|
const storagePath = currentStorageStatePath(playwright?.args ?? []);
|
|
19125
|
-
if (!storagePath || !
|
|
19304
|
+
if (!storagePath || !fs50.existsSync(storagePath)) return void 0;
|
|
19126
19305
|
const hostname = new URL(targetUrl).hostname;
|
|
19127
|
-
const state = JSON.parse(
|
|
19306
|
+
const state = JSON.parse(fs50.readFileSync(storagePath, "utf-8"));
|
|
19128
19307
|
const cookies = (state.cookies ?? []).filter((cookie) => {
|
|
19129
19308
|
const domain = cookie.domain.replace(/^\./, "");
|
|
19130
19309
|
return hostname === domain || hostname.endsWith(`.${domain}`);
|
|
@@ -19191,9 +19370,9 @@ async function prepareAccountModelSettings(ctx, profile, input) {
|
|
|
19191
19370
|
return true;
|
|
19192
19371
|
}
|
|
19193
19372
|
function mergeStorageStates(existingPath, nextPath) {
|
|
19194
|
-
if (existingPath === nextPath || !
|
|
19195
|
-
const existing = JSON.parse(
|
|
19196
|
-
const next = JSON.parse(
|
|
19373
|
+
if (existingPath === nextPath || !fs50.existsSync(existingPath)) return;
|
|
19374
|
+
const existing = JSON.parse(fs50.readFileSync(existingPath, "utf-8"));
|
|
19375
|
+
const next = JSON.parse(fs50.readFileSync(nextPath, "utf-8"));
|
|
19197
19376
|
const cookies = /* @__PURE__ */ new Map();
|
|
19198
19377
|
for (const cookie of [...existing.cookies ?? [], ...next.cookies ?? []]) {
|
|
19199
19378
|
cookies.set(`${cookie.name}\0${cookie.domain}\0${cookie.path}`, cookie);
|
|
@@ -19207,7 +19386,7 @@ function mergeStorageStates(existingPath, nextPath) {
|
|
|
19207
19386
|
}
|
|
19208
19387
|
origins.set(entry.origin, { origin: entry.origin, localStorage: [...localStorage.values()] });
|
|
19209
19388
|
}
|
|
19210
|
-
|
|
19389
|
+
fs50.writeFileSync(nextPath, JSON.stringify({ cookies: [...cookies.values()], origins: [...origins.values()] }), {
|
|
19211
19390
|
mode: 384
|
|
19212
19391
|
});
|
|
19213
19392
|
}
|
|
@@ -19302,7 +19481,7 @@ async function prepareKodyRepositoryBrowserAuth(ctx, profile, input) {
|
|
|
19302
19481
|
configurePlaywright(profile, state.file);
|
|
19303
19482
|
const authDirectory = state.directory;
|
|
19304
19483
|
registerRuntimeCleanup(ctx, () => {
|
|
19305
|
-
|
|
19484
|
+
fs50.rmSync(authDirectory, { recursive: true, force: true });
|
|
19306
19485
|
});
|
|
19307
19486
|
appendAuthMessage(
|
|
19308
19487
|
ctx,
|
|
@@ -19310,7 +19489,7 @@ async function prepareKodyRepositoryBrowserAuth(ctx, profile, input) {
|
|
|
19310
19489
|
);
|
|
19311
19490
|
return true;
|
|
19312
19491
|
} catch (error) {
|
|
19313
|
-
if (state)
|
|
19492
|
+
if (state) fs50.rmSync(state.directory, { recursive: true, force: true });
|
|
19314
19493
|
const reason = error instanceof Error ? error.message : String(error);
|
|
19315
19494
|
appendAuthMessage(
|
|
19316
19495
|
ctx,
|
|
@@ -19337,11 +19516,11 @@ async function prepareEmailPasswordBrowserAuth(ctx, profile, input) {
|
|
|
19337
19516
|
state = writeCookieStorageState(input.targetUrl, cookies);
|
|
19338
19517
|
configurePlaywright(profile, state.file);
|
|
19339
19518
|
const authDirectory = state.directory;
|
|
19340
|
-
registerRuntimeCleanup(ctx, () =>
|
|
19519
|
+
registerRuntimeCleanup(ctx, () => fs50.rmSync(authDirectory, { recursive: true, force: true }));
|
|
19341
19520
|
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
19521
|
return true;
|
|
19343
19522
|
} catch (error) {
|
|
19344
|
-
if (state)
|
|
19523
|
+
if (state) fs50.rmSync(state.directory, { recursive: true, force: true });
|
|
19345
19524
|
const reason = error instanceof Error ? error.message : String(error);
|
|
19346
19525
|
ctx.data.qaAuthBlock = `Auth: the engine could not prepare the app login (${reason}). Note this authenticated surface as a gap.`;
|
|
19347
19526
|
return false;
|
|
@@ -21308,7 +21487,7 @@ var init_tickShellRunner = __esm({
|
|
|
21308
21487
|
});
|
|
21309
21488
|
|
|
21310
21489
|
// src/scripts/runScheduledImplementationTick.ts
|
|
21311
|
-
import * as
|
|
21490
|
+
import * as fs51 from "fs";
|
|
21312
21491
|
import * as path48 from "path";
|
|
21313
21492
|
var runScheduledImplementationTick;
|
|
21314
21493
|
var init_runScheduledImplementationTick = __esm({
|
|
@@ -21337,7 +21516,7 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
21337
21516
|
return;
|
|
21338
21517
|
}
|
|
21339
21518
|
const shellPath = path48.join(profile.dir, shell);
|
|
21340
|
-
if (!
|
|
21519
|
+
if (!fs51.existsSync(shellPath)) {
|
|
21341
21520
|
ctx.output.exitCode = 99;
|
|
21342
21521
|
ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
21343
21522
|
return;
|
|
@@ -21396,13 +21575,13 @@ var init_runtimeConnections = __esm({
|
|
|
21396
21575
|
|
|
21397
21576
|
// src/scripts/runSimpleCapabilityScript.ts
|
|
21398
21577
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
21399
|
-
import * as
|
|
21578
|
+
import * as fs52 from "fs";
|
|
21400
21579
|
function formatDuration2(timeoutMs) {
|
|
21401
21580
|
return timeoutMs % 6e4 === 0 ? `${timeoutMs / 6e4} minutes` : `${timeoutMs}ms`;
|
|
21402
21581
|
}
|
|
21403
21582
|
function isRegularFile2(filePath) {
|
|
21404
21583
|
try {
|
|
21405
|
-
const stat =
|
|
21584
|
+
const stat = fs52.lstatSync(filePath);
|
|
21406
21585
|
return stat.isFile() && !stat.isSymbolicLink();
|
|
21407
21586
|
} catch {
|
|
21408
21587
|
return false;
|
|
@@ -21494,7 +21673,7 @@ var init_runSimpleCapabilityScript = __esm({
|
|
|
21494
21673
|
});
|
|
21495
21674
|
|
|
21496
21675
|
// src/scripts/runTickScript.ts
|
|
21497
|
-
import * as
|
|
21676
|
+
import * as fs53 from "fs";
|
|
21498
21677
|
import * as path49 from "path";
|
|
21499
21678
|
var runTickScript;
|
|
21500
21679
|
var init_runTickScript = __esm({
|
|
@@ -21528,7 +21707,7 @@ var init_runTickScript = __esm({
|
|
|
21528
21707
|
return;
|
|
21529
21708
|
}
|
|
21530
21709
|
const scriptPath = path49.isAbsolute(tickScript) ? tickScript : path49.join(ctx.cwd, tickScript);
|
|
21531
|
-
if (!
|
|
21710
|
+
if (!fs53.existsSync(scriptPath)) {
|
|
21532
21711
|
ctx.output.exitCode = 99;
|
|
21533
21712
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
21534
21713
|
return;
|
|
@@ -22735,7 +22914,7 @@ var init_warmupMcp = __esm({
|
|
|
22735
22914
|
});
|
|
22736
22915
|
|
|
22737
22916
|
// src/scripts/writeAgentRunSummary.ts
|
|
22738
|
-
import * as
|
|
22917
|
+
import * as fs54 from "fs";
|
|
22739
22918
|
var writeAgentRunSummary;
|
|
22740
22919
|
var init_writeAgentRunSummary = __esm({
|
|
22741
22920
|
"src/scripts/writeAgentRunSummary.ts"() {
|
|
@@ -22761,7 +22940,7 @@ var init_writeAgentRunSummary = __esm({
|
|
|
22761
22940
|
if (reason) lines.push(`- **Reason:** ${reason}`);
|
|
22762
22941
|
lines.push("");
|
|
22763
22942
|
try {
|
|
22764
|
-
|
|
22943
|
+
fs54.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
22765
22944
|
`);
|
|
22766
22945
|
} catch {
|
|
22767
22946
|
}
|
|
@@ -23103,7 +23282,7 @@ var init_scripts = __esm({
|
|
|
23103
23282
|
});
|
|
23104
23283
|
|
|
23105
23284
|
// src/stateWorkspace.ts
|
|
23106
|
-
import * as
|
|
23285
|
+
import * as fs55 from "fs";
|
|
23107
23286
|
import * as path51 from "path";
|
|
23108
23287
|
function tenantId(config) {
|
|
23109
23288
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
@@ -23112,8 +23291,8 @@ function tenantId(config) {
|
|
|
23112
23291
|
}
|
|
23113
23292
|
function writeRuntimeFile(cwd, relativePath, content) {
|
|
23114
23293
|
const target = path51.join(cwd, RUNTIME_ROOT, relativePath);
|
|
23115
|
-
|
|
23116
|
-
|
|
23294
|
+
fs55.mkdirSync(path51.dirname(target), { recursive: true });
|
|
23295
|
+
fs55.writeFileSync(target, content, "utf8");
|
|
23117
23296
|
}
|
|
23118
23297
|
function record(value) {
|
|
23119
23298
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -23182,7 +23361,7 @@ async function hydrateStateWorkspace(config, cwd, backendOverride) {
|
|
|
23182
23361
|
if (hydratedWorkspaces.has(key)) return;
|
|
23183
23362
|
const backend = backendOverride ?? createStateBackendFromEnv();
|
|
23184
23363
|
const root = path51.join(cwd, RUNTIME_ROOT);
|
|
23185
|
-
|
|
23364
|
+
fs55.rmSync(root, { recursive: true, force: true });
|
|
23186
23365
|
await Promise.all([
|
|
23187
23366
|
hydratePrefix(backend, tenant2, cwd, "context:"),
|
|
23188
23367
|
hydratePrefix(backend, tenant2, cwd, "memory:"),
|
|
@@ -23269,7 +23448,7 @@ var init_tools = __esm({
|
|
|
23269
23448
|
|
|
23270
23449
|
// src/executor.ts
|
|
23271
23450
|
import { spawn as spawn8 } from "child_process";
|
|
23272
|
-
import * as
|
|
23451
|
+
import * as fs56 from "fs";
|
|
23273
23452
|
import * as os8 from "os";
|
|
23274
23453
|
import * as path52 from "path";
|
|
23275
23454
|
function isMutatingPostflight(scriptName) {
|
|
@@ -23367,6 +23546,7 @@ async function runImplementation(profileName, input) {
|
|
|
23367
23546
|
`);
|
|
23368
23547
|
else if (out.exitCode !== 0 && out.reason) process.stdout.write(`PR_URL=FAILED: ${out.reason}
|
|
23369
23548
|
`);
|
|
23549
|
+
publishRunUsage(`implementation:${profileName}`, out.usage);
|
|
23370
23550
|
return out;
|
|
23371
23551
|
};
|
|
23372
23552
|
const resolved = loadRunnableProfile(profileName, input.cwd);
|
|
@@ -23490,14 +23670,16 @@ async function runImplementation(profileName, input) {
|
|
|
23490
23670
|
status,
|
|
23491
23671
|
startedAt: runIndexStartedAt,
|
|
23492
23672
|
updatedAt: finishedAt,
|
|
23493
|
-
reason: out.reason
|
|
23673
|
+
reason: out.reason,
|
|
23674
|
+
usage: out.usage
|
|
23494
23675
|
})
|
|
23495
23676
|
);
|
|
23496
23677
|
await finalizeStagedRunIndexRowsAsync(config, input.cwd, ctx.data, {
|
|
23497
23678
|
status,
|
|
23498
23679
|
updatedAt: finishedAt,
|
|
23499
23680
|
reason: out.reason,
|
|
23500
|
-
output: ctx.data.capabilityOutput
|
|
23681
|
+
output: ctx.data.capabilityOutput,
|
|
23682
|
+
usage: out.usage
|
|
23501
23683
|
});
|
|
23502
23684
|
};
|
|
23503
23685
|
}
|
|
@@ -23725,10 +23907,12 @@ async function runImplementation(profileName, input) {
|
|
|
23725
23907
|
reason: err instanceof Error ? err.message : String(err)
|
|
23726
23908
|
});
|
|
23727
23909
|
}
|
|
23728
|
-
ctx.output.usage = {
|
|
23729
|
-
|
|
23730
|
-
|
|
23731
|
-
|
|
23910
|
+
ctx.output.usage = createRunUsage(agentResult.tokens, agentResult.costUsd, {
|
|
23911
|
+
model: `${model.provider}/${model.model}`,
|
|
23912
|
+
turns: agentResult.turns,
|
|
23913
|
+
modelUsage: agentResult.modelUsage,
|
|
23914
|
+
outcome: agentResult.outcome
|
|
23915
|
+
});
|
|
23732
23916
|
emitEvent(input.cwd, {
|
|
23733
23917
|
implementation: profileName,
|
|
23734
23918
|
kind: "agent_end",
|
|
@@ -23850,7 +24034,8 @@ async function runImplementation(profileName, input) {
|
|
|
23850
24034
|
} catch (error) {
|
|
23851
24035
|
return finishAndEnd({
|
|
23852
24036
|
exitCode: 99,
|
|
23853
|
-
reason: error instanceof Error ? error.message : String(error)
|
|
24037
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
24038
|
+
usage: ctx.output.usage
|
|
23854
24039
|
});
|
|
23855
24040
|
}
|
|
23856
24041
|
}
|
|
@@ -23858,6 +24043,7 @@ async function runImplementation(profileName, input) {
|
|
|
23858
24043
|
exitCode: ctx.output.exitCode ?? 0,
|
|
23859
24044
|
prUrl: ctx.output.prUrl,
|
|
23860
24045
|
reason: ctx.output.reason,
|
|
24046
|
+
usage: ctx.output.usage,
|
|
23861
24047
|
action: ctx.data.action,
|
|
23862
24048
|
nextDispatch: ctx.output.nextDispatch,
|
|
23863
24049
|
nextJob: ctx.output.nextJob,
|
|
@@ -23868,7 +24054,7 @@ async function runImplementation(profileName, input) {
|
|
|
23868
24054
|
});
|
|
23869
24055
|
} catch (err) {
|
|
23870
24056
|
const msg = err instanceof Error ? err.message : String(err);
|
|
23871
|
-
return finishAndEnd({ exitCode: 99, reason: ctx.output.reason ?? msg });
|
|
24057
|
+
return finishAndEnd({ exitCode: 99, reason: ctx.output.reason ?? msg, usage: ctx.output.usage });
|
|
23872
24058
|
} finally {
|
|
23873
24059
|
runRuntimeCleanup(ctx);
|
|
23874
24060
|
clearStampedLifecycleLabels(profile, ctx);
|
|
@@ -23921,6 +24107,8 @@ function lastIndexOfScript(entries, names) {
|
|
|
23921
24107
|
}
|
|
23922
24108
|
async function runImplementationChain(profileName, input) {
|
|
23923
24109
|
let result = await runImplementation(profileName, input);
|
|
24110
|
+
let aggregateUsage = result.usage;
|
|
24111
|
+
let followedHandoff = false;
|
|
23924
24112
|
let chainConfig = input.config;
|
|
23925
24113
|
const configForHandoff = () => {
|
|
23926
24114
|
if (chainConfig || input.skipConfig) return chainConfig;
|
|
@@ -23932,6 +24120,7 @@ async function runImplementationChain(profileName, input) {
|
|
|
23932
24120
|
...result.taskState ? { taskState: result.taskState } : {}
|
|
23933
24121
|
};
|
|
23934
24122
|
for (let hops = 1; (result.nextDispatch || result.nextJob) && hops <= MAX_CHAIN_HOPS; hops++) {
|
|
24123
|
+
followedHandoff = true;
|
|
23935
24124
|
if (result.nextJob) {
|
|
23936
24125
|
const next2 = result.nextJob;
|
|
23937
24126
|
const after = result.afterNextJob;
|
|
@@ -23947,6 +24136,7 @@ async function runImplementationChain(profileName, input) {
|
|
|
23947
24136
|
quiet: input.quiet,
|
|
23948
24137
|
preloadedData: chainData
|
|
23949
24138
|
});
|
|
24139
|
+
aggregateUsage = mergeRunUsage(aggregateUsage, childResult.usage);
|
|
23950
24140
|
if (after && childResult.exitCode === 0 && !childResult.nextDispatch && !childResult.nextJob && !childResult.afterNextJob) {
|
|
23951
24141
|
chainData = {
|
|
23952
24142
|
...chainData,
|
|
@@ -23972,6 +24162,7 @@ async function runImplementationChain(profileName, input) {
|
|
|
23972
24162
|
quiet: input.quiet,
|
|
23973
24163
|
preloadedData: chainData
|
|
23974
24164
|
});
|
|
24165
|
+
aggregateUsage = mergeRunUsage(aggregateUsage, result.usage);
|
|
23975
24166
|
chainData = {
|
|
23976
24167
|
...chainData,
|
|
23977
24168
|
...result.taskState ? { taskState: result.taskState } : {}
|
|
@@ -24006,6 +24197,7 @@ async function runImplementationChain(profileName, input) {
|
|
|
24006
24197
|
quiet: input.quiet,
|
|
24007
24198
|
preloadedData: chainData
|
|
24008
24199
|
});
|
|
24200
|
+
aggregateUsage = mergeRunUsage(aggregateUsage, result.usage);
|
|
24009
24201
|
chainData = {
|
|
24010
24202
|
...chainData,
|
|
24011
24203
|
...result.taskState ? { taskState: result.taskState } : {}
|
|
@@ -24016,7 +24208,9 @@ async function runImplementationChain(profileName, input) {
|
|
|
24016
24208
|
process.stderr.write(`[kody] in-process hand-off cap (${MAX_CHAIN_HOPS}) reached; not running ${pending}
|
|
24017
24209
|
`);
|
|
24018
24210
|
}
|
|
24019
|
-
|
|
24211
|
+
const output = aggregateUsage ? { ...result, usage: aggregateUsage } : result;
|
|
24212
|
+
if (followedHandoff) publishRunUsage(`chain:${profileName}`, output.usage);
|
|
24213
|
+
return output;
|
|
24020
24214
|
}
|
|
24021
24215
|
function handoffToJob(handoff) {
|
|
24022
24216
|
const capabilityOrAction = handoff.workflow ?? handoff.action ?? handoff.capability;
|
|
@@ -24063,7 +24257,7 @@ function resolveProfilePath(profileName, cwd = process.cwd()) {
|
|
|
24063
24257
|
// fallback
|
|
24064
24258
|
];
|
|
24065
24259
|
for (const c of candidates) {
|
|
24066
|
-
if (
|
|
24260
|
+
if (fs56.existsSync(c)) return c;
|
|
24067
24261
|
}
|
|
24068
24262
|
return candidates[0];
|
|
24069
24263
|
}
|
|
@@ -24179,7 +24373,7 @@ function resolveShellTimeoutMs(entry) {
|
|
|
24179
24373
|
async function runShellEntry(entry, ctx, profile) {
|
|
24180
24374
|
const shellName = entry.shell;
|
|
24181
24375
|
const shellPath = path52.join(profile.dir, shellName);
|
|
24182
|
-
if (!
|
|
24376
|
+
if (!fs56.existsSync(shellPath)) {
|
|
24183
24377
|
ctx.skipAgent = true;
|
|
24184
24378
|
ctx.output.exitCode = 99;
|
|
24185
24379
|
ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
|
|
@@ -24253,9 +24447,9 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
24253
24447
|
}
|
|
24254
24448
|
let sideChannelText = "";
|
|
24255
24449
|
try {
|
|
24256
|
-
if (
|
|
24257
|
-
sideChannelText =
|
|
24258
|
-
|
|
24450
|
+
if (fs56.existsSync(outputFile)) {
|
|
24451
|
+
sideChannelText = fs56.readFileSync(outputFile, "utf-8");
|
|
24452
|
+
fs56.rmSync(outputFile, { force: true });
|
|
24259
24453
|
}
|
|
24260
24454
|
} catch {
|
|
24261
24455
|
}
|
|
@@ -24321,6 +24515,7 @@ var init_executor = __esm({
|
|
|
24321
24515
|
init_subagents();
|
|
24322
24516
|
init_task_artifacts();
|
|
24323
24517
|
init_tools();
|
|
24518
|
+
init_usage();
|
|
24324
24519
|
MUTATING_POSTFLIGHTS = /* @__PURE__ */ new Set([
|
|
24325
24520
|
"commitAndPush",
|
|
24326
24521
|
"ensurePr",
|
|
@@ -24471,6 +24666,7 @@ function parseWorkflowRunState(raw) {
|
|
|
24471
24666
|
const artifacts = Array.isArray(state.artifacts) ? state.artifacts.filter(
|
|
24472
24667
|
(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")
|
|
24473
24668
|
) : [];
|
|
24669
|
+
const usage = parseRunUsage(state.usage);
|
|
24474
24670
|
return {
|
|
24475
24671
|
status: state.status,
|
|
24476
24672
|
...typeof state.currentStepId === "string" ? { currentStepId: state.currentStepId } : {},
|
|
@@ -24483,6 +24679,7 @@ function parseWorkflowRunState(raw) {
|
|
|
24483
24679
|
facts: { ...facts },
|
|
24484
24680
|
evidence: Object.fromEntries(evidenceEntries),
|
|
24485
24681
|
artifacts: artifacts.map((artifact) => ({ ...artifact })),
|
|
24682
|
+
...usage ? { usage } : {},
|
|
24486
24683
|
...typeof state.blocker === "string" ? { blocker: state.blocker } : {}
|
|
24487
24684
|
};
|
|
24488
24685
|
}
|
|
@@ -24546,6 +24743,7 @@ var init_workflowRunState = __esm({
|
|
|
24546
24743
|
"src/workflowRunState.ts"() {
|
|
24547
24744
|
"use strict";
|
|
24548
24745
|
init_state_backend();
|
|
24746
|
+
init_usage();
|
|
24549
24747
|
SAFE_ID = /^[a-z0-9][a-z0-9_-]{0,79}$/;
|
|
24550
24748
|
}
|
|
24551
24749
|
});
|
|
@@ -24766,6 +24964,7 @@ async function runJob(job, base) {
|
|
|
24766
24964
|
...parentRow,
|
|
24767
24965
|
status: result.workflowState?.status === "waiting-approval" ? "waiting" : result.exitCode === 0 ? "success" : "failed",
|
|
24768
24966
|
summary: result.reason,
|
|
24967
|
+
usage: result.usage,
|
|
24769
24968
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
24770
24969
|
});
|
|
24771
24970
|
}
|
|
@@ -24784,6 +24983,7 @@ async function runJob(job, base) {
|
|
|
24784
24983
|
...Object.keys(facts).length > 0 ? { output: facts } : {}
|
|
24785
24984
|
});
|
|
24786
24985
|
}
|
|
24986
|
+
publishRunUsage(`workflow:${workflowIdentity}`, result.usage);
|
|
24787
24987
|
return result;
|
|
24788
24988
|
} finally {
|
|
24789
24989
|
await lease?.release().catch((error) => {
|
|
@@ -24932,16 +25132,17 @@ async function runCapabilityWorkflow(parent, workflow, capability, base, checkpo
|
|
|
24932
25132
|
return { exitCode: 64, reason: resumeBlocker, workflowState: state };
|
|
24933
25133
|
}
|
|
24934
25134
|
const result = isGraphWorkflow(workflow) ? await runGraphCapabilityWorkflow(parent, workflow, capability, base, checkpoint) : await runLinearCapabilityWorkflow(parent, workflow, capability, base, checkpoint);
|
|
24935
|
-
|
|
25135
|
+
const resultWithUsage = result.workflowState?.usage ? { ...result, usage: result.workflowState.usage } : result;
|
|
25136
|
+
if (workflow.report && resultWithUsage.workflowState) {
|
|
24936
25137
|
await publishWorkflowReport({
|
|
24937
25138
|
config: base.config ?? loadConfig(base.cwd),
|
|
24938
25139
|
publication: workflow.report,
|
|
24939
25140
|
workflowId: capability.slug,
|
|
24940
25141
|
workflowTitle: capability.title,
|
|
24941
|
-
state:
|
|
25142
|
+
state: resultWithUsage.workflowState
|
|
24942
25143
|
});
|
|
24943
25144
|
}
|
|
24944
|
-
return
|
|
25145
|
+
return resultWithUsage;
|
|
24945
25146
|
}
|
|
24946
25147
|
async function runLinearCapabilityWorkflow(parent, workflow, capability, base, checkpoint) {
|
|
24947
25148
|
const state = initialWorkflowState(parent, workflow);
|
|
@@ -25070,7 +25271,8 @@ function initialWorkflowState(parent, workflow) {
|
|
|
25070
25271
|
...prior.steps ? { steps: cloneWorkflowSteps(prior.steps) } : {},
|
|
25071
25272
|
facts: { ...prior.facts },
|
|
25072
25273
|
evidence: { ...prior.evidence },
|
|
25073
|
-
artifacts: prior.artifacts.map((artifact) => ({ ...artifact }))
|
|
25274
|
+
artifacts: prior.artifacts.map((artifact) => ({ ...artifact })),
|
|
25275
|
+
...prior.usage ? { usage: structuredClone(prior.usage) } : {}
|
|
25074
25276
|
};
|
|
25075
25277
|
}
|
|
25076
25278
|
const firstStepId = workflow.startAt ?? workflow.steps[0]?.id;
|
|
@@ -25090,7 +25292,8 @@ function initialWorkflowState(parent, workflow) {
|
|
|
25090
25292
|
...prior?.facts ?? {}
|
|
25091
25293
|
},
|
|
25092
25294
|
evidence: { ...prior?.evidence ?? {} },
|
|
25093
|
-
artifacts: (prior?.artifacts ?? []).map((artifact) => ({ ...artifact }))
|
|
25295
|
+
artifacts: (prior?.artifacts ?? []).map((artifact) => ({ ...artifact })),
|
|
25296
|
+
...prior?.usage ? { usage: structuredClone(prior.usage) } : {}
|
|
25094
25297
|
};
|
|
25095
25298
|
}
|
|
25096
25299
|
function workflowChainData(parent, capability, base, state) {
|
|
@@ -25479,6 +25682,7 @@ function finishWorkflowStep(state, step, result) {
|
|
|
25479
25682
|
...result.capabilityOutput !== void 0 ? { output: result.capabilityOutput } : {},
|
|
25480
25683
|
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25481
25684
|
};
|
|
25685
|
+
state.usage = mergeRunUsage(state.usage, result.usage);
|
|
25482
25686
|
}
|
|
25483
25687
|
function usesGenericCapabilityInput(action, cwd) {
|
|
25484
25688
|
const inputs = getCapabilityActionInputs(action, hydratedCapabilitiesRoot(cwd));
|
|
@@ -25714,6 +25918,7 @@ var init_job = __esm({
|
|
|
25714
25918
|
init_publishReport();
|
|
25715
25919
|
init_simpleCapabilityRuntime();
|
|
25716
25920
|
init_state_backend();
|
|
25921
|
+
init_usage();
|
|
25717
25922
|
init_workflowDefinitionIdentity();
|
|
25718
25923
|
init_workflowDefinitions();
|
|
25719
25924
|
init_workflowRunLease();
|
|
@@ -27083,7 +27288,7 @@ async function hydrateDefinitionsFromEnv(cwd = process.cwd(), env = process.env)
|
|
|
27083
27288
|
|
|
27084
27289
|
// src/kody-cli.ts
|
|
27085
27290
|
import { execFileSync as execFileSync24 } from "child_process";
|
|
27086
|
-
import * as
|
|
27291
|
+
import * as fs58 from "fs";
|
|
27087
27292
|
import * as path53 from "path";
|
|
27088
27293
|
|
|
27089
27294
|
// src/app-auth.ts
|
|
@@ -27616,7 +27821,7 @@ init_loopDefinitions();
|
|
|
27616
27821
|
|
|
27617
27822
|
// src/mergedPrLifecycle.ts
|
|
27618
27823
|
init_lifecycleLabels();
|
|
27619
|
-
import * as
|
|
27824
|
+
import * as fs57 from "fs";
|
|
27620
27825
|
var DONE3 = {
|
|
27621
27826
|
label: "kody:done",
|
|
27622
27827
|
color: "0e8a16",
|
|
@@ -27657,8 +27862,8 @@ function finalizeMergedPullRequestEvent(event, cwd, writeLabel = setKodyLabel) {
|
|
|
27657
27862
|
}
|
|
27658
27863
|
function readGitHubEvent(env = process.env) {
|
|
27659
27864
|
const eventPath = env.GITHUB_EVENT_PATH;
|
|
27660
|
-
if (!eventPath || !
|
|
27661
|
-
return JSON.parse(
|
|
27865
|
+
if (!eventPath || !fs57.existsSync(eventPath)) return null;
|
|
27866
|
+
return JSON.parse(fs57.readFileSync(eventPath, "utf-8"));
|
|
27662
27867
|
}
|
|
27663
27868
|
|
|
27664
27869
|
// src/kody-cli.ts
|
|
@@ -27886,9 +28091,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
27886
28091
|
return void 0;
|
|
27887
28092
|
}
|
|
27888
28093
|
function detectPackageManager(cwd) {
|
|
27889
|
-
if (
|
|
27890
|
-
if (
|
|
27891
|
-
if (
|
|
28094
|
+
if (fs58.existsSync(path53.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
28095
|
+
if (fs58.existsSync(path53.join(cwd, "yarn.lock"))) return "yarn";
|
|
28096
|
+
if (fs58.existsSync(path53.join(cwd, "bun.lockb"))) return "bun";
|
|
27892
28097
|
return "npm";
|
|
27893
28098
|
}
|
|
27894
28099
|
function shouldChainScheduledWatch(match) {
|
|
@@ -27929,7 +28134,7 @@ function ensurePackageManagerInstalled(pm, cwd) {
|
|
|
27929
28134
|
return shellOut("npm", ["install", "-g", spec], cwd);
|
|
27930
28135
|
}
|
|
27931
28136
|
function installDeps(pm, cwd) {
|
|
27932
|
-
if (!
|
|
28137
|
+
if (!fs58.existsSync(path53.join(cwd, "package.json"))) {
|
|
27933
28138
|
process.stdout.write("\u2192 kody: no package.json found \u2014 skipping consumer dependency install\n");
|
|
27934
28139
|
return 0;
|
|
27935
28140
|
}
|
|
@@ -27995,8 +28200,8 @@ function postFailureTail(issueNumber, cwd, reason) {
|
|
|
27995
28200
|
const logPath = lastRunLogPath(cwd);
|
|
27996
28201
|
let tail = "";
|
|
27997
28202
|
try {
|
|
27998
|
-
if (
|
|
27999
|
-
const content =
|
|
28203
|
+
if (fs58.existsSync(logPath)) {
|
|
28204
|
+
const content = fs58.readFileSync(logPath, "utf-8");
|
|
28000
28205
|
tail = content.slice(-3e3);
|
|
28001
28206
|
}
|
|
28002
28207
|
} catch {
|
|
@@ -28113,9 +28318,9 @@ async function runCi(argv) {
|
|
|
28113
28318
|
forceRunCliArgs = { goal: envForceMessage };
|
|
28114
28319
|
}
|
|
28115
28320
|
}
|
|
28116
|
-
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath &&
|
|
28321
|
+
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs58.existsSync(dispatchEventPath)) {
|
|
28117
28322
|
try {
|
|
28118
|
-
const evt = JSON.parse(
|
|
28323
|
+
const evt = JSON.parse(fs58.readFileSync(dispatchEventPath, "utf-8"));
|
|
28119
28324
|
const inputs = objectValue2(evt.inputs);
|
|
28120
28325
|
const issueInput = parseInt(String(inputs?.issue_number ?? ""), 10);
|
|
28121
28326
|
const sessionInput = String(inputs?.sessionId ?? "");
|
|
@@ -28531,7 +28736,7 @@ init_repoWorkspace();
|
|
|
28531
28736
|
|
|
28532
28737
|
// src/scripts/brainTurnLog.ts
|
|
28533
28738
|
init_runtimePaths();
|
|
28534
|
-
import * as
|
|
28739
|
+
import * as fs59 from "fs";
|
|
28535
28740
|
import * as path54 from "path";
|
|
28536
28741
|
import posixPath4 from "path/posix";
|
|
28537
28742
|
var live = /* @__PURE__ */ new Map();
|
|
@@ -28540,8 +28745,8 @@ function brainEventsFilePath(dir, chatId) {
|
|
|
28540
28745
|
}
|
|
28541
28746
|
function lastPersistedSeq(dir, chatId) {
|
|
28542
28747
|
const p = brainEventsFilePath(dir, chatId);
|
|
28543
|
-
if (!
|
|
28544
|
-
const lines =
|
|
28748
|
+
if (!fs59.existsSync(p)) return 0;
|
|
28749
|
+
const lines = fs59.readFileSync(p, "utf-8").split("\n").filter(Boolean);
|
|
28545
28750
|
if (lines.length === 0) return 0;
|
|
28546
28751
|
try {
|
|
28547
28752
|
return JSON.parse(lines[lines.length - 1]).seq || 0;
|
|
@@ -28551,9 +28756,9 @@ function lastPersistedSeq(dir, chatId) {
|
|
|
28551
28756
|
}
|
|
28552
28757
|
function readSince(dir, chatId, since) {
|
|
28553
28758
|
const p = brainEventsFilePath(dir, chatId);
|
|
28554
|
-
if (!
|
|
28759
|
+
if (!fs59.existsSync(p)) return [];
|
|
28555
28760
|
const out = [];
|
|
28556
|
-
for (const line of
|
|
28761
|
+
for (const line of fs59.readFileSync(p, "utf-8").split("\n")) {
|
|
28557
28762
|
if (!line) continue;
|
|
28558
28763
|
try {
|
|
28559
28764
|
const rec = JSON.parse(line);
|
|
@@ -28579,12 +28784,12 @@ function beginTurn(dir, chatId) {
|
|
|
28579
28784
|
};
|
|
28580
28785
|
live.set(chatId, state);
|
|
28581
28786
|
const p = brainEventsFilePath(dir, chatId);
|
|
28582
|
-
|
|
28787
|
+
fs59.mkdirSync(path54.dirname(p), { recursive: true });
|
|
28583
28788
|
return (event) => {
|
|
28584
28789
|
state.seq += 1;
|
|
28585
28790
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
28586
28791
|
try {
|
|
28587
|
-
|
|
28792
|
+
fs59.appendFileSync(p, `${JSON.stringify(rec)}
|
|
28588
28793
|
`);
|
|
28589
28794
|
} catch (err) {
|
|
28590
28795
|
process.stderr.write(
|
|
@@ -28623,7 +28828,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
|
|
|
28623
28828
|
event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
|
|
28624
28829
|
};
|
|
28625
28830
|
try {
|
|
28626
|
-
|
|
28831
|
+
fs59.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
|
|
28627
28832
|
`);
|
|
28628
28833
|
} catch {
|
|
28629
28834
|
}
|
|
@@ -31287,7 +31492,7 @@ async function poolServe() {
|
|
|
31287
31492
|
|
|
31288
31493
|
// src/servers/runner-serve.ts
|
|
31289
31494
|
import { spawn as spawn10 } from "child_process";
|
|
31290
|
-
import * as
|
|
31495
|
+
import * as fs60 from "fs";
|
|
31291
31496
|
import { createServer as createServer6 } from "http";
|
|
31292
31497
|
var DEFAULT_PORT2 = 8080;
|
|
31293
31498
|
var DEFAULT_WORKDIR = "/workspace/repo";
|
|
@@ -31363,8 +31568,8 @@ async function defaultRunJob(job) {
|
|
|
31363
31568
|
const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
|
|
31364
31569
|
const branch = job.ref ?? "main";
|
|
31365
31570
|
const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
|
|
31366
|
-
|
|
31367
|
-
|
|
31571
|
+
fs60.rmSync(workdir, { recursive: true, force: true });
|
|
31572
|
+
fs60.mkdirSync(workdir, { recursive: true });
|
|
31368
31573
|
const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
|
|
31369
31574
|
const target = job.runRequest.target;
|
|
31370
31575
|
const interactive = target.type === "chat";
|