@kody-ade/kody-engine 0.2.62 → 0.3.0
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/README.md +24 -24
- package/dist/bin/{kody2.js → kody.js} +171 -169
- package/dist/executables/bug/profile.json +6 -6
- package/dist/executables/chore/profile.json +6 -6
- package/dist/executables/classify/profile.json +1 -1
- package/dist/executables/feature/profile.json +6 -6
- package/dist/executables/fix/profile.json +1 -1
- package/dist/executables/fix/prompt.md +1 -1
- package/dist/executables/fix-ci/profile.json +1 -1
- package/dist/executables/init/profile.json +1 -1
- package/dist/executables/plan/profile.json +1 -1
- package/dist/executables/plan-verify/profile.json +2 -2
- package/dist/executables/plan-verify/prompt.md +1 -1
- package/dist/executables/research/profile.json +1 -1
- package/dist/executables/resolve/profile.json +1 -1
- package/dist/executables/review/profile.json +1 -1
- package/dist/executables/run/profile.json +1 -1
- package/dist/executables/run/prompt.md +2 -2
- package/dist/executables/spec/profile.json +4 -4
- package/dist/executables/sync/profile.json +1 -1
- package/dist/executables/types.ts +3 -3
- package/dist/executables/ui-review/profile.json +3 -3
- package/dist/executables/ui-review/prompt.md +8 -8
- package/dist/plugins/commands/kody-live-probe.md +2 -2
- package/dist/plugins/skills/kody-live-marker/SKILL.md +3 -3
- package/dist/plugins/test-plugin/.claude-plugin/plugin.json +2 -2
- package/dist/plugins/test-plugin/skills/kody-plugin-marker/SKILL.md +2 -2
- package/kody.config.schema.json +3 -3
- package/package.json +4 -4
- package/templates/{kody2.yml → kody.yml} +16 -16
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@kody-ade/kody-engine",
|
|
6
|
-
version: "0.
|
|
7
|
-
description: "
|
|
6
|
+
version: "0.3.0",
|
|
7
|
+
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
8
8
|
license: "MIT",
|
|
9
9
|
type: "module",
|
|
10
10
|
bin: {
|
|
11
|
-
|
|
11
|
+
kody: "dist/bin/kody.js"
|
|
12
12
|
},
|
|
13
13
|
files: [
|
|
14
14
|
"dist",
|
|
@@ -16,7 +16,7 @@ var package_default = {
|
|
|
16
16
|
"kody.config.schema.json"
|
|
17
17
|
],
|
|
18
18
|
scripts: {
|
|
19
|
-
|
|
19
|
+
kody: "tsx bin/kody.ts",
|
|
20
20
|
build: "tsup && node scripts/copy-assets.cjs",
|
|
21
21
|
test: "vitest run tests/unit tests/int --no-coverage",
|
|
22
22
|
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
@@ -73,7 +73,7 @@ var FileSink = class {
|
|
|
73
73
|
};
|
|
74
74
|
var HttpSink = class {
|
|
75
75
|
constructor(baseUrl, sessionId, logger = {
|
|
76
|
-
warn: (m) => process.stderr.write(`[
|
|
76
|
+
warn: (m) => process.stderr.write(`[kody:chat] ${m}
|
|
77
77
|
`)
|
|
78
78
|
}) {
|
|
79
79
|
this.baseUrl = baseUrl;
|
|
@@ -181,7 +181,7 @@ function loadConfig(projectDir = process.cwd()) {
|
|
|
181
181
|
},
|
|
182
182
|
issueContext: parseIssueContext(raw.issueContext),
|
|
183
183
|
testRequirements: parseTestRequirements(raw.testRequirements),
|
|
184
|
-
defaultExecutable: typeof raw.defaultExecutable === "string" && raw.defaultExecutable.length > 0 ? raw.defaultExecutable :
|
|
184
|
+
defaultExecutable: typeof raw.defaultExecutable === "string" && raw.defaultExecutable.length > 0 ? raw.defaultExecutable : "classify",
|
|
185
185
|
classify: parseClassifyConfig(raw.classify),
|
|
186
186
|
release: parseReleaseConfig(raw.release)
|
|
187
187
|
};
|
|
@@ -295,7 +295,7 @@ ${truncate(text, 4e3)}`);
|
|
|
295
295
|
}
|
|
296
296
|
function formatResult(msg) {
|
|
297
297
|
const ok = msg.subtype === "success";
|
|
298
|
-
const tag = ok ? "
|
|
298
|
+
const tag = ok ? "SESSION ok" : `SESSION failed (${msg.subtype ?? "unknown"})`;
|
|
299
299
|
const dur = msg.duration_ms ? ` ${(msg.duration_ms / 1e3).toFixed(1)}s` : "";
|
|
300
300
|
const turns = msg.num_turns ? ` ${msg.num_turns} turns` : "";
|
|
301
301
|
const cost = typeof msg.total_cost_usd === "number" ? ` $${msg.total_cost_usd.toFixed(4)}` : "";
|
|
@@ -340,7 +340,7 @@ function formatBytes(bytes) {
|
|
|
340
340
|
// src/agent.ts
|
|
341
341
|
var DEFAULT_ALLOWED_TOOLS = ["Bash", "Edit", "Read", "Write", "Glob", "Grep"];
|
|
342
342
|
async function runAgent(opts) {
|
|
343
|
-
const ndjsonDir = opts.ndjsonDir ?? path3.join(opts.cwd, ".
|
|
343
|
+
const ndjsonDir = opts.ndjsonDir ?? path3.join(opts.cwd, ".kody");
|
|
344
344
|
fs3.mkdirSync(ndjsonDir, { recursive: true });
|
|
345
345
|
const ndjsonPath = path3.join(ndjsonDir, "last-run.jsonl");
|
|
346
346
|
const fullLog = fs3.createWriteStream(ndjsonPath, { flags: "w" });
|
|
@@ -354,7 +354,7 @@ async function runAgent(opts) {
|
|
|
354
354
|
env.ANTHROPIC_BASE_URL = opts.litellmUrl;
|
|
355
355
|
env.ANTHROPIC_API_KEY = getAnthropicApiKeyOrDummy();
|
|
356
356
|
}
|
|
357
|
-
|
|
357
|
+
const resultTexts = [];
|
|
358
358
|
let outcome = "failed";
|
|
359
359
|
let errorMessage;
|
|
360
360
|
try {
|
|
@@ -399,7 +399,8 @@ async function runAgent(opts) {
|
|
|
399
399
|
if (m.type === "result") {
|
|
400
400
|
if (m.subtype === "success") {
|
|
401
401
|
outcome = "completed";
|
|
402
|
-
|
|
402
|
+
const text = (typeof m.result === "string" ? m.result : "").trim();
|
|
403
|
+
if (text) resultTexts.push(text);
|
|
403
404
|
} else {
|
|
404
405
|
outcome = "failed";
|
|
405
406
|
errorMessage = `result subtype: ${m.subtype ?? "unknown"}`;
|
|
@@ -415,6 +416,7 @@ async function runAgent(opts) {
|
|
|
415
416
|
} catch {
|
|
416
417
|
}
|
|
417
418
|
}
|
|
419
|
+
const finalText = resultTexts.join("\n\n---\n\n");
|
|
418
420
|
return { outcome, finalText, error: errorMessage, ndjsonPath };
|
|
419
421
|
}
|
|
420
422
|
|
|
@@ -542,7 +544,7 @@ async function emit(sink, type, sessionId, suffix, payload) {
|
|
|
542
544
|
});
|
|
543
545
|
}
|
|
544
546
|
|
|
545
|
-
// src/
|
|
547
|
+
// src/kody-cli.ts
|
|
546
548
|
import { execFileSync as execFileSync20 } from "child_process";
|
|
547
549
|
import * as fs21 from "fs";
|
|
548
550
|
import * as path18 from "path";
|
|
@@ -604,8 +606,9 @@ function autoDispatch(opts) {
|
|
|
604
606
|
};
|
|
605
607
|
}
|
|
606
608
|
const sub = extractSubcommand(afterTag);
|
|
607
|
-
const defaultExec = opts?.config?.defaultExecutable ?? "run";
|
|
608
609
|
if (!sub) {
|
|
610
|
+
const defaultExec = opts?.config?.defaultExecutable;
|
|
611
|
+
if (!defaultExec) return null;
|
|
609
612
|
return asDispatch(defaultExec, targetNum);
|
|
610
613
|
}
|
|
611
614
|
if (sub === "build") {
|
|
@@ -620,9 +623,9 @@ function asDispatch(executable, target) {
|
|
|
620
623
|
return { executable, cliArgs: { issue: target }, target };
|
|
621
624
|
}
|
|
622
625
|
function extractAfterTag(body) {
|
|
623
|
-
const idx = body.indexOf("@
|
|
626
|
+
const idx = body.indexOf("@kody");
|
|
624
627
|
if (idx === -1) return body;
|
|
625
|
-
return body.slice(idx + "@
|
|
628
|
+
return body.slice(idx + "@kody".length).trim();
|
|
626
629
|
}
|
|
627
630
|
function extractSubcommand(afterTag) {
|
|
628
631
|
const match = afterTag.match(/^([a-z][a-z0-9-]{1,40})\b/);
|
|
@@ -682,13 +685,13 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
|
|
|
682
685
|
throw new Error("litellm not installed \u2014 run: pip install 'litellm[proxy]'");
|
|
683
686
|
}
|
|
684
687
|
}
|
|
685
|
-
const configPath = path5.join(os.tmpdir(), `
|
|
688
|
+
const configPath = path5.join(os.tmpdir(), `kody-litellm-${Date.now()}.yaml`);
|
|
686
689
|
fs6.writeFileSync(configPath, generateLitellmConfigYaml(model));
|
|
687
690
|
const portMatch = url.match(/:(\d+)/);
|
|
688
691
|
const port = portMatch ? portMatch[1] : "4000";
|
|
689
692
|
const args = cmd === "litellm" ? ["--config", configPath, "--port", port] : ["-m", "litellm", "--config", configPath, "--port", port];
|
|
690
693
|
const dotenvVars = readDotenvApiKeys(projectDir);
|
|
691
|
-
const logPath = path5.join(os.tmpdir(), `
|
|
694
|
+
const logPath = path5.join(os.tmpdir(), `kody-litellm-${Date.now()}.log`);
|
|
692
695
|
const outFd = fs6.openSync(logPath, "w");
|
|
693
696
|
const child = spawn(cmd, args, {
|
|
694
697
|
stdio: ["ignore", outFd, outFd],
|
|
@@ -997,8 +1000,8 @@ import { execFileSync as execFileSync3 } from "child_process";
|
|
|
997
1000
|
|
|
998
1001
|
// src/state.ts
|
|
999
1002
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
1000
|
-
var STATE_BEGIN = "<!--
|
|
1001
|
-
var STATE_END = "<!--
|
|
1003
|
+
var STATE_BEGIN = "<!-- kody:state:v1:begin -->";
|
|
1004
|
+
var STATE_END = "<!-- kody:state:v1:end -->";
|
|
1002
1005
|
var HISTORY_MAX_ENTRIES = 20;
|
|
1003
1006
|
var API_TIMEOUT_MS = 3e4;
|
|
1004
1007
|
function emptyState() {
|
|
@@ -1114,7 +1117,7 @@ function noteFromAction(action) {
|
|
|
1114
1117
|
}
|
|
1115
1118
|
function renderStateComment(state) {
|
|
1116
1119
|
const lines = [];
|
|
1117
|
-
lines.push("## \u{1F4CB}
|
|
1120
|
+
lines.push("## \u{1F4CB} kody task state");
|
|
1118
1121
|
lines.push("");
|
|
1119
1122
|
if (state.flow) {
|
|
1120
1123
|
lines.push(`- **Flow:** \`${state.flow.name}\` (step: \`${state.flow.step}\`)`);
|
|
@@ -1194,7 +1197,7 @@ function writeTaskState(target, number, state, cwd) {
|
|
|
1194
1197
|
}
|
|
1195
1198
|
} catch (err) {
|
|
1196
1199
|
process.stderr.write(
|
|
1197
|
-
`[
|
|
1200
|
+
`[kody state] failed to write state on ${target} #${number}: ${err instanceof Error ? err.message : String(err)}
|
|
1198
1201
|
`
|
|
1199
1202
|
);
|
|
1200
1203
|
}
|
|
@@ -1218,12 +1221,12 @@ var advanceFlow = async (ctx, profile) => {
|
|
|
1218
1221
|
writeTaskState("issue", flow.issueNumber, next, ctx.cwd);
|
|
1219
1222
|
} catch (err) {
|
|
1220
1223
|
process.stderr.write(
|
|
1221
|
-
`[
|
|
1224
|
+
`[kody advanceFlow] failed to mirror action to issue #${flow.issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
1222
1225
|
`
|
|
1223
1226
|
);
|
|
1224
1227
|
}
|
|
1225
1228
|
}
|
|
1226
|
-
const body = `@
|
|
1229
|
+
const body = `@kody ${flow.name}`;
|
|
1227
1230
|
try {
|
|
1228
1231
|
execFileSync3("gh", ["issue", "comment", String(flow.issueNumber), "--body", body], {
|
|
1229
1232
|
timeout: API_TIMEOUT_MS2,
|
|
@@ -1232,7 +1235,7 @@ var advanceFlow = async (ctx, profile) => {
|
|
|
1232
1235
|
});
|
|
1233
1236
|
} catch (err) {
|
|
1234
1237
|
process.stderr.write(
|
|
1235
|
-
`[
|
|
1238
|
+
`[kody advanceFlow] failed to re-trigger orchestrator on issue #${flow.issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
1236
1239
|
`
|
|
1237
1240
|
);
|
|
1238
1241
|
}
|
|
@@ -1263,7 +1266,7 @@ var buildSyntheticPlugin = async (ctx, profile) => {
|
|
|
1263
1266
|
if (!needsSynthetic) return;
|
|
1264
1267
|
const catalog = getPluginsCatalogRoot();
|
|
1265
1268
|
const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1266
|
-
const root = path7.join(os2.tmpdir(), `
|
|
1269
|
+
const root = path7.join(os2.tmpdir(), `kody-synth-${runId}`);
|
|
1267
1270
|
fs8.mkdirSync(path7.join(root, ".claude-plugin"), { recursive: true });
|
|
1268
1271
|
if (cc.skills.length > 0) {
|
|
1269
1272
|
const dst = path7.join(root, "skills");
|
|
@@ -1310,9 +1313,9 @@ var buildSyntheticPlugin = async (ctx, profile) => {
|
|
|
1310
1313
|
`);
|
|
1311
1314
|
}
|
|
1312
1315
|
const manifest = {
|
|
1313
|
-
name: `
|
|
1316
|
+
name: `kody-synth-${profile.name}`,
|
|
1314
1317
|
version: "1.0.0",
|
|
1315
|
-
description: `Synthetic plugin assembled by
|
|
1318
|
+
description: `Synthetic plugin assembled by Kody for profile '${profile.name}' at runtime.`
|
|
1316
1319
|
};
|
|
1317
1320
|
if (cc.skills.length > 0) manifest.skills = ["./skills/"];
|
|
1318
1321
|
if (cc.commands.length > 0) manifest.commands = ["./commands/"];
|
|
@@ -1438,7 +1441,9 @@ function parseAgentResult(finalText) {
|
|
|
1438
1441
|
failureReason: failedMatch[1].trim()
|
|
1439
1442
|
};
|
|
1440
1443
|
}
|
|
1441
|
-
|
|
1444
|
+
const hasDoneMarker = /(^|\n)\s*DONE\b/i.test(text);
|
|
1445
|
+
const hasCommitMsg = /^[ \t]*COMMIT_MSG\s*:/im.test(text);
|
|
1446
|
+
if (!hasDoneMarker && !hasCommitMsg) {
|
|
1442
1447
|
return {
|
|
1443
1448
|
done: false,
|
|
1444
1449
|
commitMessage: "",
|
|
@@ -1503,7 +1508,7 @@ var checkCoverageWithRetry = async (ctx) => {
|
|
|
1503
1508
|
ctx.data.coverageMisses = misses;
|
|
1504
1509
|
return;
|
|
1505
1510
|
}
|
|
1506
|
-
process.stderr.write(`[
|
|
1511
|
+
process.stderr.write(`[kody] coverage check found ${misses.length} missing test(s); retrying agent once
|
|
1507
1512
|
`);
|
|
1508
1513
|
const retryPrompt = `${basePrompt}
|
|
1509
1514
|
|
|
@@ -1565,14 +1570,14 @@ import * as path9 from "path";
|
|
|
1565
1570
|
var FORBIDDEN_PATH_PREFIXES = [
|
|
1566
1571
|
".kody/",
|
|
1567
1572
|
".kody-engine/",
|
|
1568
|
-
".
|
|
1573
|
+
".kody/",
|
|
1569
1574
|
".kody-lean/",
|
|
1570
1575
|
// back-compat: stale runtime dir from kody-lean v0.5.x
|
|
1571
1576
|
"node_modules/",
|
|
1572
1577
|
"dist/",
|
|
1573
1578
|
"build/"
|
|
1574
1579
|
];
|
|
1575
|
-
var FORBIDDEN_PATH_EXACT = /* @__PURE__ */ new Set([".env", ".
|
|
1580
|
+
var FORBIDDEN_PATH_EXACT = /* @__PURE__ */ new Set([".env", ".kody-pip-requirements.txt"]);
|
|
1576
1581
|
var FORBIDDEN_PATH_SUFFIXES = [".log"];
|
|
1577
1582
|
var CONVENTIONAL_PREFIXES = [
|
|
1578
1583
|
"feat:",
|
|
@@ -1672,7 +1677,7 @@ function listFilesInCommit(ref = "HEAD", cwd) {
|
|
|
1672
1677
|
}
|
|
1673
1678
|
function normalizeCommitMessage(raw) {
|
|
1674
1679
|
const trimmed = raw.trim().replace(/^['"]|['"]$/g, "").trim();
|
|
1675
|
-
if (!trimmed) return "chore:
|
|
1680
|
+
if (!trimmed) return "chore: kody update";
|
|
1676
1681
|
const firstLine2 = trimmed.split("\n")[0];
|
|
1677
1682
|
for (const prefix of CONVENTIONAL_PREFIXES) {
|
|
1678
1683
|
if (firstLine2.toLowerCase().startsWith(prefix)) return trimmed;
|
|
@@ -1745,7 +1750,7 @@ var commitAndPush2 = async (ctx, profile) => {
|
|
|
1745
1750
|
} else {
|
|
1746
1751
|
const aborted = abortUnfinishedGitOps(ctx.cwd);
|
|
1747
1752
|
if (aborted.length > 0) {
|
|
1748
|
-
process.stderr.write(`[
|
|
1753
|
+
process.stderr.write(`[kody] cleaned up unfinished git ops: ${aborted.join(", ")}
|
|
1749
1754
|
`);
|
|
1750
1755
|
}
|
|
1751
1756
|
}
|
|
@@ -1765,15 +1770,15 @@ var commitAndPush2 = async (ctx, profile) => {
|
|
|
1765
1770
|
function defaultCommitMessage(mode, data) {
|
|
1766
1771
|
switch (mode) {
|
|
1767
1772
|
case "run":
|
|
1768
|
-
return `chore:
|
|
1773
|
+
return `chore: kody changes for #${data.commentTargetNumber}`;
|
|
1769
1774
|
case "fix":
|
|
1770
|
-
return `chore(fix):
|
|
1775
|
+
return `chore(fix): kody fix for PR #${data.commentTargetNumber}`;
|
|
1771
1776
|
case "fix-ci":
|
|
1772
|
-
return `fix(ci):
|
|
1777
|
+
return `fix(ci): kody fix-ci for PR #${data.commentTargetNumber}`;
|
|
1773
1778
|
case "resolve":
|
|
1774
1779
|
return `fix: resolve merge conflicts with ${data.baseBranch}`;
|
|
1775
1780
|
default:
|
|
1776
|
-
return `chore:
|
|
1781
|
+
return `chore: kody changes`;
|
|
1777
1782
|
}
|
|
1778
1783
|
}
|
|
1779
1784
|
|
|
@@ -2296,7 +2301,7 @@ function generateQaGuideTemplate(d) {
|
|
|
2296
2301
|
const lines = [];
|
|
2297
2302
|
lines.push("# QA guide");
|
|
2298
2303
|
lines.push("");
|
|
2299
|
-
lines.push("This file is read by `
|
|
2304
|
+
lines.push("This file is read by `kody ui-review`. Fill in the credential placeholders");
|
|
2300
2305
|
lines.push("below and commit \u2014 the agent uses them to log in to your preview deployment.");
|
|
2301
2306
|
lines.push("");
|
|
2302
2307
|
lines.push("## Test accounts");
|
|
@@ -2366,13 +2371,13 @@ var API_TIMEOUT_MS3 = 3e4;
|
|
|
2366
2371
|
var dispatch = async (ctx, _profile, _agentResult, args) => {
|
|
2367
2372
|
const next = args?.next;
|
|
2368
2373
|
if (!next) {
|
|
2369
|
-
process.stderr.write("[
|
|
2374
|
+
process.stderr.write("[kody dispatch] missing `with.next` \u2014 skipping\n");
|
|
2370
2375
|
return;
|
|
2371
2376
|
}
|
|
2372
2377
|
const target = args?.target ?? "issue";
|
|
2373
2378
|
const issueNumber = ctx.args.issue;
|
|
2374
2379
|
if (!issueNumber) {
|
|
2375
|
-
process.stderr.write("[
|
|
2380
|
+
process.stderr.write("[kody dispatch] no --issue arg \u2014 skipping\n");
|
|
2376
2381
|
return;
|
|
2377
2382
|
}
|
|
2378
2383
|
const state = ctx.data.taskState;
|
|
@@ -2382,7 +2387,7 @@ var dispatch = async (ctx, _profile, _agentResult, args) => {
|
|
|
2382
2387
|
const usePr = target === "pr" && state?.core.prUrl;
|
|
2383
2388
|
const targetNumber = usePr ? parsePr(state.core.prUrl) ?? issueNumber : issueNumber;
|
|
2384
2389
|
const sub = usePr ? "pr" : "issue";
|
|
2385
|
-
const body = `@
|
|
2390
|
+
const body = `@kody ${next}`;
|
|
2386
2391
|
try {
|
|
2387
2392
|
execFileSync7("gh", [sub, "comment", String(targetNumber), "--body", body], {
|
|
2388
2393
|
timeout: API_TIMEOUT_MS3,
|
|
@@ -2391,7 +2396,7 @@ var dispatch = async (ctx, _profile, _agentResult, args) => {
|
|
|
2391
2396
|
});
|
|
2392
2397
|
} catch (err) {
|
|
2393
2398
|
process.stderr.write(
|
|
2394
|
-
`[
|
|
2399
|
+
`[kody dispatch] failed to post @kody ${next} on ${sub} #${targetNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
2395
2400
|
`
|
|
2396
2401
|
);
|
|
2397
2402
|
}
|
|
@@ -2439,15 +2444,15 @@ function getIssue(issueNumber, cwd) {
|
|
|
2439
2444
|
labels: Array.isArray(parsed.labels) ? parsed.labels.map((l) => l.name ?? "").filter((n) => n.length > 0) : []
|
|
2440
2445
|
};
|
|
2441
2446
|
}
|
|
2442
|
-
function
|
|
2443
|
-
return body.replace(/(@)(
|
|
2447
|
+
function stripKodyMentions(body) {
|
|
2448
|
+
return body.replace(/(@)(kody)/gi, "$1\u200B$2");
|
|
2444
2449
|
}
|
|
2445
2450
|
function postIssueComment(issueNumber, body, cwd) {
|
|
2446
2451
|
try {
|
|
2447
|
-
gh2(["issue", "comment", String(issueNumber), "--body-file", "-"], { input:
|
|
2452
|
+
gh2(["issue", "comment", String(issueNumber), "--body-file", "-"], { input: stripKodyMentions(body), cwd });
|
|
2448
2453
|
} catch (err) {
|
|
2449
2454
|
process.stderr.write(
|
|
2450
|
-
`[
|
|
2455
|
+
`[kody] failed to post comment on #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
2451
2456
|
`
|
|
2452
2457
|
);
|
|
2453
2458
|
}
|
|
@@ -2478,7 +2483,7 @@ function getPrDiff(prNumber, cwd) {
|
|
|
2478
2483
|
return gh2(["pr", "diff", String(prNumber)], { cwd });
|
|
2479
2484
|
} catch (err) {
|
|
2480
2485
|
process.stderr.write(
|
|
2481
|
-
`[
|
|
2486
|
+
`[kody] failed to fetch diff for PR #${prNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
2482
2487
|
`
|
|
2483
2488
|
);
|
|
2484
2489
|
return "";
|
|
@@ -2529,10 +2534,10 @@ function getPrLatestReviewBody(prNumber, cwd) {
|
|
|
2529
2534
|
}
|
|
2530
2535
|
function postPrReviewComment(prNumber, body, cwd) {
|
|
2531
2536
|
try {
|
|
2532
|
-
gh2(["pr", "comment", String(prNumber), "--body-file", "-"], { input:
|
|
2537
|
+
gh2(["pr", "comment", String(prNumber), "--body-file", "-"], { input: stripKodyMentions(body), cwd });
|
|
2533
2538
|
} catch (err) {
|
|
2534
2539
|
process.stderr.write(
|
|
2535
|
-
`[
|
|
2540
|
+
`[kody] failed to post review comment on PR #${prNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
2536
2541
|
`
|
|
2537
2542
|
);
|
|
2538
2543
|
}
|
|
@@ -2595,7 +2600,7 @@ function buildPrBody(opts) {
|
|
|
2595
2600
|
lines.push("");
|
|
2596
2601
|
}
|
|
2597
2602
|
lines.push("---");
|
|
2598
|
-
lines.push("_Opened by
|
|
2603
|
+
lines.push("_Opened by kody (single-session autonomous run)._ ");
|
|
2599
2604
|
return lines.join("\n");
|
|
2600
2605
|
}
|
|
2601
2606
|
function firstLine(s) {
|
|
@@ -2624,10 +2629,7 @@ function ensurePr(opts) {
|
|
|
2624
2629
|
try {
|
|
2625
2630
|
gh2(["pr", "edit", String(existing.number), "--body-file", "-"], { input: body, cwd: opts.cwd });
|
|
2626
2631
|
} catch (err) {
|
|
2627
|
-
|
|
2628
|
-
`[kody2] failed to update PR #${existing.number}: ${err instanceof Error ? err.message : String(err)}
|
|
2629
|
-
`
|
|
2630
|
-
);
|
|
2632
|
+
throw new Error(`gh pr edit #${existing.number} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2631
2633
|
}
|
|
2632
2634
|
return { url: existing.url, number: existing.number, draft: opts.draft, action: "updated" };
|
|
2633
2635
|
}
|
|
@@ -2669,7 +2671,7 @@ var ensurePr2 = async (ctx) => {
|
|
|
2669
2671
|
const issue = ctx.data.issue;
|
|
2670
2672
|
const pr = ctx.data.pr;
|
|
2671
2673
|
const targetNumber = Number(ctx.data.commentTargetNumber ?? 0);
|
|
2672
|
-
const title = issue?.title ?? pr?.title ?? `
|
|
2674
|
+
const title = issue?.title ?? pr?.title ?? `kody changes`;
|
|
2673
2675
|
try {
|
|
2674
2676
|
const result = ensurePr({
|
|
2675
2677
|
branch,
|
|
@@ -2841,7 +2843,7 @@ function setKodyLabel(issueNumber, spec, cwd) {
|
|
|
2841
2843
|
const target = spec.label;
|
|
2842
2844
|
if (!target.startsWith(KODY_NAMESPACE)) {
|
|
2843
2845
|
process.stderr.write(
|
|
2844
|
-
`[
|
|
2846
|
+
`[kody] setKodyLabel: refusing to set non-kody label "${target}"
|
|
2845
2847
|
`
|
|
2846
2848
|
);
|
|
2847
2849
|
return;
|
|
@@ -2863,14 +2865,14 @@ function setKodyLabel(issueNumber, spec, cwd) {
|
|
|
2863
2865
|
return;
|
|
2864
2866
|
} catch (retryErr) {
|
|
2865
2867
|
process.stderr.write(
|
|
2866
|
-
`[
|
|
2868
|
+
`[kody] setKodyLabel: create+retry failed for ${target} on #${issueNumber}: ${errMsg(retryErr)}
|
|
2867
2869
|
`
|
|
2868
2870
|
);
|
|
2869
2871
|
return;
|
|
2870
2872
|
}
|
|
2871
2873
|
}
|
|
2872
2874
|
process.stderr.write(
|
|
2873
|
-
`[
|
|
2875
|
+
`[kody] setKodyLabel: failed to add ${target} on #${issueNumber}: ${errMsg(err)}
|
|
2874
2876
|
`
|
|
2875
2877
|
);
|
|
2876
2878
|
}
|
|
@@ -2921,7 +2923,7 @@ var finishFlow = async (ctx, _profile, _agentResult, args) => {
|
|
|
2921
2923
|
const prSuffix = state?.core.prUrl ? `
|
|
2922
2924
|
|
|
2923
2925
|
**PR:** ${state.core.prUrl}` : "";
|
|
2924
|
-
const body = `${icon}
|
|
2926
|
+
const body = `${icon} kody flow \`${flowName}\` finished \u2014 \`${reason}\`${prSuffix}`;
|
|
2925
2927
|
try {
|
|
2926
2928
|
execFileSync9("gh", ["issue", "comment", String(issueNumber), "--body", body], {
|
|
2927
2929
|
timeout: API_TIMEOUT_MS5,
|
|
@@ -2930,7 +2932,7 @@ var finishFlow = async (ctx, _profile, _agentResult, args) => {
|
|
|
2930
2932
|
});
|
|
2931
2933
|
} catch (err) {
|
|
2932
2934
|
process.stderr.write(
|
|
2933
|
-
`[
|
|
2935
|
+
`[kody finishFlow] failed to post final summary on issue #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
2934
2936
|
`
|
|
2935
2937
|
);
|
|
2936
2938
|
}
|
|
@@ -3089,7 +3091,7 @@ function reactToTriggerComment(cwd) {
|
|
|
3089
3091
|
}
|
|
3090
3092
|
}
|
|
3091
3093
|
process.stderr.write(
|
|
3092
|
-
`[
|
|
3094
|
+
`[kody] \u{1F440} reaction failed after 3 attempts on comment ${commentId}: ${lastErr instanceof Error ? lastErr.message : String(lastErr)}
|
|
3093
3095
|
`
|
|
3094
3096
|
);
|
|
3095
3097
|
}
|
|
@@ -3165,13 +3167,13 @@ function getFailedRunLogTail(runId, maxBytes, cwd) {
|
|
|
3165
3167
|
return "";
|
|
3166
3168
|
}
|
|
3167
3169
|
}
|
|
3168
|
-
function
|
|
3169
|
-
return workflowName.trim().toLowerCase() === "
|
|
3170
|
+
function isKodyDispatchWorkflow(workflowName) {
|
|
3171
|
+
return workflowName.trim().toLowerCase() === "kody";
|
|
3170
3172
|
}
|
|
3171
3173
|
function pickFailedRunForFixCi(prNumber, maxBytes, limit, cwd) {
|
|
3172
3174
|
const runs = getRecentFailedRunsForPr(prNumber, limit, cwd);
|
|
3173
3175
|
for (const run of runs) {
|
|
3174
|
-
if (
|
|
3176
|
+
if (isKodyDispatchWorkflow(run.workflowName)) continue;
|
|
3175
3177
|
const logTail = getFailedRunLogTail(run.id, maxBytes, cwd);
|
|
3176
3178
|
if (logTail) return { run, logTail };
|
|
3177
3179
|
}
|
|
@@ -3215,7 +3217,7 @@ var fixCiFlow = async (ctx) => {
|
|
|
3215
3217
|
bail(
|
|
3216
3218
|
ctx,
|
|
3217
3219
|
prNumber,
|
|
3218
|
-
`no actionable failed workflow run found on PR #${prNumber}'s branch (looked at last ${RUN_LOOKBACK} failed runs \u2014 all were either
|
|
3220
|
+
`no actionable failed workflow run found on PR #${prNumber}'s branch (looked at last ${RUN_LOOKBACK} failed runs \u2014 all were either kody's own dispatch workflow or had no fetchable logs; pass --run-id to target a specific run)`
|
|
3219
3221
|
);
|
|
3220
3222
|
return;
|
|
3221
3223
|
}
|
|
@@ -3230,10 +3232,10 @@ var fixCiFlow = async (ctx) => {
|
|
|
3230
3232
|
ctx.data.failedLogTail = logTail;
|
|
3231
3233
|
ctx.data.prDiff = getPrDiff(prNumber, ctx.cwd);
|
|
3232
3234
|
const runUrl = getRunUrl();
|
|
3233
|
-
const runSuffix = runUrl ? `,
|
|
3235
|
+
const runSuffix = runUrl ? `, kody run ${runUrl}` : "";
|
|
3234
3236
|
tryPostPr(
|
|
3235
3237
|
prNumber,
|
|
3236
|
-
`\u2699\uFE0F
|
|
3238
|
+
`\u2699\uFE0F kody fix-ci started on \`${ctx.data.branch}\`${runSuffix} \u2014 analyzing workflow run ${runId}`,
|
|
3237
3239
|
ctx.cwd
|
|
3238
3240
|
);
|
|
3239
3241
|
};
|
|
@@ -3243,7 +3245,7 @@ function bail(ctx, prNumber, reason) {
|
|
|
3243
3245
|
ctx.skipAgent = true;
|
|
3244
3246
|
const runUrl = getRunUrl();
|
|
3245
3247
|
const runSuffix = runUrl ? ` ([logs](${runUrl}))` : "";
|
|
3246
|
-
tryPostPr(prNumber, `\u274C
|
|
3248
|
+
tryPostPr(prNumber, `\u274C kody fix-ci could not run${runSuffix}: ${reason}`, ctx.cwd);
|
|
3247
3249
|
}
|
|
3248
3250
|
function tryPostPr(prNumber, body, cwd) {
|
|
3249
3251
|
try {
|
|
@@ -3281,7 +3283,7 @@ var fixFlow = async (ctx) => {
|
|
|
3281
3283
|
const runSuffix = runUrl ? `, run ${runUrl}` : "";
|
|
3282
3284
|
tryPostPr2(
|
|
3283
3285
|
prNumber,
|
|
3284
|
-
`\u2699\uFE0F
|
|
3286
|
+
`\u2699\uFE0F kody fix started on \`${ctx.data.branch}\`${runSuffix} \u2014 applying feedback (${truncate2(feedback.replace(/\n/g, " "), 200)})`,
|
|
3285
3287
|
ctx.cwd
|
|
3286
3288
|
);
|
|
3287
3289
|
};
|
|
@@ -3300,7 +3302,7 @@ import * as path15 from "path";
|
|
|
3300
3302
|
// src/scripts/loadQaGuide.ts
|
|
3301
3303
|
import * as fs16 from "fs";
|
|
3302
3304
|
import * as path14 from "path";
|
|
3303
|
-
var QA_GUIDE_REL_PATH = ".
|
|
3305
|
+
var QA_GUIDE_REL_PATH = ".kody/qa-guide.md";
|
|
3304
3306
|
var loadQaGuide = async (ctx) => {
|
|
3305
3307
|
const full = path14.join(ctx.cwd, QA_GUIDE_REL_PATH);
|
|
3306
3308
|
if (!fs16.existsSync(full)) {
|
|
@@ -3360,20 +3362,20 @@ function makeConfig(pm, ownerRepo, defaultBranch) {
|
|
|
3360
3362
|
}
|
|
3361
3363
|
};
|
|
3362
3364
|
}
|
|
3363
|
-
var WORKFLOW_TEMPLATE = `# Drop this file at .github/workflows/
|
|
3365
|
+
var WORKFLOW_TEMPLATE = `# Drop this file at .github/workflows/kody.yml in your repo.
|
|
3364
3366
|
#
|
|
3365
|
-
# Triggers: @
|
|
3367
|
+
# Triggers: @kody comment on an issue or PR, or manual workflow_dispatch.
|
|
3366
3368
|
# Everything else (install deps, set up LiteLLM, run the agent, open the PR)
|
|
3367
3369
|
# is handled inside the @kody-ade/kody-engine package.
|
|
3368
3370
|
#
|
|
3369
3371
|
# Required repo secrets: at least one model provider key (e.g. MINIMAX_API_KEY,
|
|
3370
|
-
# ANTHROPIC_API_KEY).
|
|
3372
|
+
# ANTHROPIC_API_KEY). kody reads any *_API_KEY secret automatically via
|
|
3371
3373
|
# toJSON(secrets) \u2014 no need to list them here.
|
|
3372
3374
|
#
|
|
3373
3375
|
# Recommended: KODY_TOKEN secret \u2014 a PAT or GitHub App token with repo
|
|
3374
|
-
# scope so
|
|
3376
|
+
# scope so kody's pushes trigger downstream CI and PR-body edits succeed.
|
|
3375
3377
|
|
|
3376
|
-
name:
|
|
3378
|
+
name: kody
|
|
3377
3379
|
|
|
3378
3380
|
on:
|
|
3379
3381
|
workflow_dispatch:
|
|
@@ -3391,7 +3393,7 @@ jobs:
|
|
|
3391
3393
|
\${{ github.event_name == 'workflow_dispatch' ||
|
|
3392
3394
|
(github.event_name == 'issue_comment' &&
|
|
3393
3395
|
!github.event.issue.pull_request &&
|
|
3394
|
-
contains(github.event.comment.body, '@
|
|
3396
|
+
contains(github.event.comment.body, '@kody')) }}
|
|
3395
3397
|
runs-on: ubuntu-latest
|
|
3396
3398
|
timeout-minutes: 60
|
|
3397
3399
|
permissions:
|
|
@@ -3414,7 +3416,7 @@ jobs:
|
|
|
3414
3416
|
|
|
3415
3417
|
- env:
|
|
3416
3418
|
ALL_SECRETS: \${{ toJSON(secrets) }}
|
|
3417
|
-
run: npx -y -p @kody-ade/kody-engine@latest
|
|
3419
|
+
run: npx -y -p @kody-ade/kody-engine@latest kody ci --issue \${{ github.event.inputs.issue_number || github.event.issue.number }}
|
|
3418
3420
|
`;
|
|
3419
3421
|
function defaultBranchFromGit(cwd) {
|
|
3420
3422
|
try {
|
|
@@ -3452,13 +3454,13 @@ function performInit(cwd, force) {
|
|
|
3452
3454
|
wrote.push("kody.config.json");
|
|
3453
3455
|
}
|
|
3454
3456
|
const workflowDir = path15.join(cwd, ".github", "workflows");
|
|
3455
|
-
const workflowPath = path15.join(workflowDir, "
|
|
3457
|
+
const workflowPath = path15.join(workflowDir, "kody.yml");
|
|
3456
3458
|
if (fs17.existsSync(workflowPath) && !force) {
|
|
3457
|
-
skipped.push(".github/workflows/
|
|
3459
|
+
skipped.push(".github/workflows/kody.yml");
|
|
3458
3460
|
} else {
|
|
3459
3461
|
fs17.mkdirSync(workflowDir, { recursive: true });
|
|
3460
3462
|
fs17.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
|
|
3461
|
-
wrote.push(".github/workflows/
|
|
3463
|
+
wrote.push(".github/workflows/kody.yml");
|
|
3462
3464
|
}
|
|
3463
3465
|
const hasUi = fs17.existsSync(path15.join(cwd, "src/app")) || fs17.existsSync(path15.join(cwd, "app")) || fs17.existsSync(path15.join(cwd, "pages"));
|
|
3464
3466
|
if (hasUi) {
|
|
@@ -3480,13 +3482,13 @@ function performInit(cwd, force) {
|
|
|
3480
3482
|
continue;
|
|
3481
3483
|
}
|
|
3482
3484
|
if (profile.kind !== "scheduled" || !profile.schedule) continue;
|
|
3483
|
-
const target = path15.join(workflowDir, `
|
|
3485
|
+
const target = path15.join(workflowDir, `kody-${exe.name}.yml`);
|
|
3484
3486
|
if (fs17.existsSync(target) && !force) {
|
|
3485
|
-
skipped.push(`.github/workflows/
|
|
3487
|
+
skipped.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
3486
3488
|
continue;
|
|
3487
3489
|
}
|
|
3488
3490
|
fs17.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
|
|
3489
|
-
wrote.push(`.github/workflows/
|
|
3491
|
+
wrote.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
3490
3492
|
}
|
|
3491
3493
|
let labels;
|
|
3492
3494
|
try {
|
|
@@ -3497,11 +3499,11 @@ function performInit(cwd, force) {
|
|
|
3497
3499
|
return { wrote, skipped, labels };
|
|
3498
3500
|
}
|
|
3499
3501
|
function renderScheduledWorkflow(name, cron) {
|
|
3500
|
-
return `# Scheduled
|
|
3501
|
-
# Generated by \`
|
|
3502
|
+
return `# Scheduled kody executable: ${name}
|
|
3503
|
+
# Generated by \`kody init\`. Regenerate with \`kody init --force\`.
|
|
3502
3504
|
# Edit the cron below or the executable's profile.json#schedule.
|
|
3503
3505
|
|
|
3504
|
-
name:
|
|
3506
|
+
name: kody ${name}
|
|
3505
3507
|
|
|
3506
3508
|
on:
|
|
3507
3509
|
schedule:
|
|
@@ -3525,14 +3527,14 @@ jobs:
|
|
|
3525
3527
|
node-version: 22
|
|
3526
3528
|
- env:
|
|
3527
3529
|
GH_TOKEN: \${{ secrets.KODY_TOKEN || github.token }}
|
|
3528
|
-
run: npx -y -p @kody-ade/kody-engine@latest
|
|
3530
|
+
run: npx -y -p @kody-ade/kody-engine@latest kody ${name}
|
|
3529
3531
|
`;
|
|
3530
3532
|
}
|
|
3531
3533
|
var initFlow = async (ctx) => {
|
|
3532
3534
|
const force = ctx.args.force === true;
|
|
3533
3535
|
const cwd = ctx.cwd;
|
|
3534
3536
|
const { wrote, skipped, labels } = performInit(cwd, force);
|
|
3535
|
-
process.stdout.write("\u2192
|
|
3537
|
+
process.stdout.write("\u2192 kody init\n");
|
|
3536
3538
|
for (const f of wrote) process.stdout.write(` wrote ${f}
|
|
3537
3539
|
`);
|
|
3538
3540
|
for (const f of skipped) process.stdout.write(` skipped ${f} (already exists; pass --force to overwrite)
|
|
@@ -3565,7 +3567,7 @@ var loadConventions = async (ctx) => {
|
|
|
3565
3567
|
const conventions = loadProjectConventions(ctx.cwd);
|
|
3566
3568
|
ctx.data.conventions = conventions;
|
|
3567
3569
|
if (conventions.length > 0) {
|
|
3568
|
-
process.stderr.write(`[
|
|
3570
|
+
process.stderr.write(`[kody] loaded conventions: ${conventions.map((c) => c.path).join(", ")}
|
|
3569
3571
|
`);
|
|
3570
3572
|
}
|
|
3571
3573
|
};
|
|
@@ -3629,7 +3631,7 @@ var mirrorStateToPr = async (ctx) => {
|
|
|
3629
3631
|
writeTaskState("pr", prNumber, state, ctx.cwd);
|
|
3630
3632
|
} catch (err) {
|
|
3631
3633
|
process.stderr.write(
|
|
3632
|
-
`[
|
|
3634
|
+
`[kody mirrorStateToPr] failed to mirror state to PR #${prNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
3633
3635
|
`
|
|
3634
3636
|
);
|
|
3635
3637
|
}
|
|
@@ -3712,7 +3714,7 @@ var persistFlowState = async (ctx) => {
|
|
|
3712
3714
|
writeTaskState("issue", issueNumber, state, ctx.cwd);
|
|
3713
3715
|
} catch (err) {
|
|
3714
3716
|
process.stderr.write(
|
|
3715
|
-
`[
|
|
3717
|
+
`[kody persistFlowState] failed to write state on issue #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
3716
3718
|
`
|
|
3717
3719
|
);
|
|
3718
3720
|
}
|
|
@@ -3738,25 +3740,25 @@ var postClassification = async (ctx) => {
|
|
|
3738
3740
|
}
|
|
3739
3741
|
if (!classification) {
|
|
3740
3742
|
ctx.data.action = failedAction("classification missing or invalid");
|
|
3741
|
-
tryAuditComment(issueNumber, "\u26A0\uFE0F
|
|
3743
|
+
tryAuditComment(issueNumber, "\u26A0\uFE0F kody classifier could not decide \u2014 please re-run with an explicit `@kody <type>`.", ctx.cwd);
|
|
3742
3744
|
ctx.output.exitCode = 1;
|
|
3743
3745
|
ctx.output.reason = "classify: no decision";
|
|
3744
3746
|
return;
|
|
3745
3747
|
}
|
|
3746
3748
|
tryAuditComment(
|
|
3747
3749
|
issueNumber,
|
|
3748
|
-
`\u{1F50E}
|
|
3750
|
+
`\u{1F50E} kody classified as \`${classification}\`${reason ? ` \u2014 ${reason}` : ""}`,
|
|
3749
3751
|
ctx.cwd
|
|
3750
3752
|
);
|
|
3751
3753
|
try {
|
|
3752
|
-
execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", `@
|
|
3754
|
+
execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", `@kody ${classification}`], {
|
|
3753
3755
|
cwd: ctx.cwd,
|
|
3754
3756
|
timeout: API_TIMEOUT_MS6,
|
|
3755
3757
|
stdio: ["ignore", "pipe", "pipe"]
|
|
3756
3758
|
});
|
|
3757
3759
|
} catch (err) {
|
|
3758
3760
|
process.stderr.write(
|
|
3759
|
-
`[
|
|
3761
|
+
`[kody postClassification] failed to dispatch @kody ${classification}: ${err instanceof Error ? err.message : String(err)}
|
|
3760
3762
|
`
|
|
3761
3763
|
);
|
|
3762
3764
|
ctx.data.action = failedAction("dispatch post failed");
|
|
@@ -3810,22 +3812,22 @@ var postIssueComment2 = async (ctx) => {
|
|
|
3810
3812
|
const prAction = ctx.data.prResult?.action;
|
|
3811
3813
|
if (!commitResult?.committed && !hasCommits) {
|
|
3812
3814
|
const reason = "no changes to commit";
|
|
3813
|
-
postWith(targetType, targetNumber, `\u26A0\uFE0F
|
|
3815
|
+
postWith(targetType, targetNumber, `\u26A0\uFE0F kody FAILED: ${reason}`, ctx.cwd);
|
|
3814
3816
|
ctx.output.exitCode = 3;
|
|
3815
3817
|
ctx.output.reason = reason;
|
|
3816
3818
|
return;
|
|
3817
3819
|
}
|
|
3818
3820
|
if (ctx.output.exitCode === 4 && ctx.data.prCrashReason) {
|
|
3819
|
-
postWith(targetType, targetNumber, `\u26A0\uFE0F
|
|
3821
|
+
postWith(targetType, targetNumber, `\u26A0\uFE0F kody FAILED: ${truncate2(ctx.data.prCrashReason, 1500)}`, ctx.cwd);
|
|
3820
3822
|
ctx.output.reason = ctx.data.prCrashReason;
|
|
3821
3823
|
return;
|
|
3822
3824
|
}
|
|
3823
3825
|
const failureReason = computeFailureReason2(ctx);
|
|
3824
3826
|
const isFailure = failureReason.length > 0;
|
|
3825
3827
|
const justPushedToExistingPr = prAction === "updated" && commitResult?.committed === true;
|
|
3826
|
-
const successMsg = justPushedToExistingPr ? `\u2705
|
|
3828
|
+
const successMsg = justPushedToExistingPr ? `\u2705 kody pushed to ${prUrl}` : prAction === "updated" ? `\u2139\uFE0F kody made no changes \u2014 PR: ${prUrl}` : `\u2705 kody PR opened: ${prUrl}`;
|
|
3827
3829
|
const failurePrSuffix = prUrl ? prAction === "updated" ? ` \u2014 PR: ${prUrl}` : ` \u2014 draft PR: ${prUrl}` : "";
|
|
3828
|
-
const msg = isFailure ? `\u26A0\uFE0F
|
|
3830
|
+
const msg = isFailure ? `\u26A0\uFE0F kody FAILED: ${truncate2(failureReason, 1500)}${failurePrSuffix}` : successMsg;
|
|
3829
3831
|
postWith(targetType, targetNumber, msg, ctx.cwd);
|
|
3830
3832
|
let exitCode = 0;
|
|
3831
3833
|
const agentDone = Boolean(ctx.data.agentDone);
|
|
@@ -3881,7 +3883,7 @@ _Orchestrator will advance to the next step automatically._`;
|
|
|
3881
3883
|
return `${head}
|
|
3882
3884
|
|
|
3883
3885
|
---
|
|
3884
|
-
Comment \`
|
|
3886
|
+
Comment \`kody run\` (prefixed with \`@\`) to execute this plan.`;
|
|
3885
3887
|
}
|
|
3886
3888
|
|
|
3887
3889
|
// src/scripts/postResearchComment.ts
|
|
@@ -3926,7 +3928,7 @@ var postReviewResult = async (ctx, _profile, agentResult) => {
|
|
|
3926
3928
|
if (!agentResult || agentResult.outcome !== "completed") {
|
|
3927
3929
|
const reason = agentResult?.error ?? "agent did not complete";
|
|
3928
3930
|
try {
|
|
3929
|
-
postPrReviewComment(prNumber, `\u26A0\uFE0F
|
|
3931
|
+
postPrReviewComment(prNumber, `\u26A0\uFE0F kody review FAILED: ${truncate2(reason, 1e3)}`, ctx.cwd);
|
|
3930
3932
|
} catch {
|
|
3931
3933
|
}
|
|
3932
3934
|
ctx.output.exitCode = 1;
|
|
@@ -3937,7 +3939,7 @@ var postReviewResult = async (ctx, _profile, agentResult) => {
|
|
|
3937
3939
|
const reviewBody = agentResult.finalText.trim();
|
|
3938
3940
|
if (!reviewBody) {
|
|
3939
3941
|
try {
|
|
3940
|
-
postPrReviewComment(prNumber, `\u26A0\uFE0F
|
|
3942
|
+
postPrReviewComment(prNumber, `\u26A0\uFE0F kody review FAILED: agent produced no review body`, ctx.cwd);
|
|
3941
3943
|
} catch {
|
|
3942
3944
|
}
|
|
3943
3945
|
ctx.output.exitCode = 1;
|
|
@@ -4154,11 +4156,11 @@ async function runPrepare(args) {
|
|
|
4154
4156
|
}
|
|
4155
4157
|
const base = ctx.config.git.defaultBranch;
|
|
4156
4158
|
const title = `chore: release ${tag}`;
|
|
4157
|
-
const body = `Automated release PR opened by
|
|
4159
|
+
const body = `Automated release PR opened by kody.
|
|
4158
4160
|
|
|
4159
4161
|
${entry}
|
|
4160
4162
|
|
|
4161
|
-
Merge this and then run \`
|
|
4163
|
+
Merge this and then run \`kody release --mode finalize\`.`;
|
|
4162
4164
|
let prUrl = "";
|
|
4163
4165
|
try {
|
|
4164
4166
|
prUrl = gh2(["pr", "create", "--head", releaseBranch, "--base", base, "--title", title, "--body-file", "-"], {
|
|
@@ -4229,19 +4231,19 @@ async function runFinalize(args) {
|
|
|
4229
4231
|
const r = runShell(cmd, cwd, timeoutMs);
|
|
4230
4232
|
publishStatus = r.exitCode === 0 ? "ok" : "failed";
|
|
4231
4233
|
if (r.exitCode !== 0) {
|
|
4232
|
-
process.stderr.write(`[
|
|
4234
|
+
process.stderr.write(`[kody release] publishCommand exit ${r.exitCode}
|
|
4233
4235
|
${truncate2(r.stderr, 2e3)}
|
|
4234
4236
|
`);
|
|
4235
4237
|
}
|
|
4236
4238
|
}
|
|
4237
4239
|
let releaseUrl = "";
|
|
4238
4240
|
try {
|
|
4239
|
-
const releaseArgs = ["release", "create", tag, "--title", tag, "--notes", `Release ${tag} \u2014 automated by
|
|
4241
|
+
const releaseArgs = ["release", "create", tag, "--title", tag, "--notes", `Release ${tag} \u2014 automated by kody.`];
|
|
4240
4242
|
if (releaseCfg.draftRelease) releaseArgs.push("--draft");
|
|
4241
4243
|
releaseUrl = gh2(releaseArgs, { cwd }).trim();
|
|
4242
4244
|
} catch (err) {
|
|
4243
4245
|
process.stderr.write(
|
|
4244
|
-
`[
|
|
4246
|
+
`[kody release] gh release create failed: ${err instanceof Error ? err.message : String(err)}
|
|
4245
4247
|
`
|
|
4246
4248
|
);
|
|
4247
4249
|
}
|
|
@@ -4380,14 +4382,14 @@ var resolveFlow = async (ctx) => {
|
|
|
4380
4382
|
ctx.output.exitCode = 0;
|
|
4381
4383
|
ctx.output.reason = `already up to date with origin/${baseBranch} \u2014 nothing to resolve`;
|
|
4382
4384
|
ctx.skipAgent = true;
|
|
4383
|
-
tryPostPr3(prNumber, `\u2139\uFE0F
|
|
4385
|
+
tryPostPr3(prNumber, `\u2139\uFE0F kody resolve: ${ctx.output.reason}`, ctx.cwd);
|
|
4384
4386
|
return;
|
|
4385
4387
|
}
|
|
4386
4388
|
if (mergeStatus === "error") {
|
|
4387
4389
|
ctx.output.exitCode = 99;
|
|
4388
4390
|
ctx.output.reason = `failed to merge origin/${baseBranch} (non-conflict error); see runner log`;
|
|
4389
4391
|
ctx.skipAgent = true;
|
|
4390
|
-
tryPostPr3(prNumber, `\u26A0\uFE0F
|
|
4392
|
+
tryPostPr3(prNumber, `\u26A0\uFE0F kody resolve FAILED: ${ctx.output.reason}`, ctx.cwd);
|
|
4391
4393
|
return;
|
|
4392
4394
|
}
|
|
4393
4395
|
const conflictedFiles = getConflictedFiles(ctx.cwd);
|
|
@@ -4403,7 +4405,7 @@ var resolveFlow = async (ctx) => {
|
|
|
4403
4405
|
const runSuffix = runUrl ? `, run ${runUrl}` : "";
|
|
4404
4406
|
tryPostPr3(
|
|
4405
4407
|
prNumber,
|
|
4406
|
-
`\u2699\uFE0F
|
|
4408
|
+
`\u2699\uFE0F kody resolve started on \`${ctx.data.branch}\`${runSuffix} \u2014 ${conflictedFiles.length} conflicted file(s)`,
|
|
4407
4409
|
ctx.cwd
|
|
4408
4410
|
);
|
|
4409
4411
|
};
|
|
@@ -4483,7 +4485,7 @@ var reviewFlow = async (ctx) => {
|
|
|
4483
4485
|
ctx.data.prDiff = getPrDiff(prNumber, ctx.cwd);
|
|
4484
4486
|
const runUrl = getRunUrl();
|
|
4485
4487
|
const runSuffix = runUrl ? `, run ${runUrl}` : "";
|
|
4486
|
-
tryPostPr4(prNumber, `\u{1F440}
|
|
4488
|
+
tryPostPr4(prNumber, `\u{1F440} kody review started on PR #${prNumber}${runSuffix}`, ctx.cwd);
|
|
4487
4489
|
};
|
|
4488
4490
|
function tryPostPr4(prNumber, body, cwd) {
|
|
4489
4491
|
try {
|
|
@@ -4507,13 +4509,13 @@ var runFlow = async (ctx) => {
|
|
|
4507
4509
|
ctx.output.exitCode = 5;
|
|
4508
4510
|
ctx.output.reason = err.message;
|
|
4509
4511
|
ctx.skipAgent = true;
|
|
4510
|
-
tryPost(issueNumber, `\u26A0\uFE0F
|
|
4512
|
+
tryPost(issueNumber, `\u26A0\uFE0F kody refused to start: ${err.message}`, ctx.cwd);
|
|
4511
4513
|
return;
|
|
4512
4514
|
}
|
|
4513
4515
|
throw err;
|
|
4514
4516
|
}
|
|
4515
4517
|
const runUrl = getRunUrl();
|
|
4516
|
-
const startMsg = runUrl ? `\u2699\uFE0F
|
|
4518
|
+
const startMsg = runUrl ? `\u2699\uFE0F kody started \u2014 branch \`${ctx.data.branch}\`, run ${runUrl}` : `\u2699\uFE0F kody started \u2014 branch \`${ctx.data.branch}\``;
|
|
4517
4519
|
tryPost(issueNumber, startMsg, ctx.cwd);
|
|
4518
4520
|
};
|
|
4519
4521
|
function tryPost(issueNumber, body, cwd) {
|
|
@@ -4557,7 +4559,7 @@ var setLifecycleLabel = async (ctx, _profile, args) => {
|
|
|
4557
4559
|
const label = args?.label;
|
|
4558
4560
|
if (typeof label !== "string" || !label.startsWith(KODY_NAMESPACE)) {
|
|
4559
4561
|
process.stderr.write(
|
|
4560
|
-
`[
|
|
4562
|
+
`[kody] setLifecycleLabel: missing or invalid "label" arg (must start with "${KODY_NAMESPACE}"): ${String(label)}
|
|
4561
4563
|
`
|
|
4562
4564
|
);
|
|
4563
4565
|
return;
|
|
@@ -4593,14 +4595,14 @@ var API_TIMEOUT_MS7 = 3e4;
|
|
|
4593
4595
|
var startFlow = async (ctx, profile, _agentResult, args) => {
|
|
4594
4596
|
const entry = args?.entry;
|
|
4595
4597
|
if (!entry) {
|
|
4596
|
-
process.stderr.write("[
|
|
4598
|
+
process.stderr.write("[kody startFlow] missing `with.entry` \u2014 skipping\n");
|
|
4597
4599
|
return;
|
|
4598
4600
|
}
|
|
4599
4601
|
const target = args?.target ?? "issue";
|
|
4600
4602
|
const flowName = profile.name;
|
|
4601
4603
|
const issueNumber = ctx.args.issue;
|
|
4602
4604
|
if (!issueNumber) {
|
|
4603
|
-
process.stderr.write("[
|
|
4605
|
+
process.stderr.write("[kody startFlow] no --issue arg \u2014 skipping\n");
|
|
4604
4606
|
return;
|
|
4605
4607
|
}
|
|
4606
4608
|
const state = ctx.data.taskState;
|
|
@@ -4615,12 +4617,12 @@ var startFlow = async (ctx, profile, _agentResult, args) => {
|
|
|
4615
4617
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4616
4618
|
};
|
|
4617
4619
|
}
|
|
4618
|
-
|
|
4620
|
+
postKodyComment(target, issueNumber, state, entry, ctx.cwd);
|
|
4619
4621
|
};
|
|
4620
|
-
function
|
|
4622
|
+
function postKodyComment(target, issueNumber, state, next, cwd) {
|
|
4621
4623
|
const targetNumber = target === "pr" && state?.core.prUrl ? parsePr2(state.core.prUrl) ?? issueNumber : issueNumber;
|
|
4622
4624
|
const sub = target === "pr" && state?.core.prUrl ? "pr" : "issue";
|
|
4623
|
-
const body = `@
|
|
4625
|
+
const body = `@kody ${next}`;
|
|
4624
4626
|
try {
|
|
4625
4627
|
execFileSync17("gh", [sub, "comment", String(targetNumber), "--body", body], {
|
|
4626
4628
|
timeout: API_TIMEOUT_MS7,
|
|
@@ -4629,7 +4631,7 @@ function postKody2Comment(target, issueNumber, state, next, cwd) {
|
|
|
4629
4631
|
});
|
|
4630
4632
|
} catch (err) {
|
|
4631
4633
|
process.stderr.write(
|
|
4632
|
-
`[
|
|
4634
|
+
`[kody startFlow] failed to post @kody ${next} on ${sub} #${targetNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
4633
4635
|
`
|
|
4634
4636
|
);
|
|
4635
4637
|
}
|
|
@@ -4668,7 +4670,7 @@ var syncFlow = async (ctx) => {
|
|
|
4668
4670
|
bail2(
|
|
4669
4671
|
ctx,
|
|
4670
4672
|
prNumber,
|
|
4671
|
-
`merge from origin/${baseBranch} produced conflicts \u2014 run \`@
|
|
4673
|
+
`merge from origin/${baseBranch} produced conflicts \u2014 run \`@kody resolve\` to let kody resolve them`
|
|
4672
4674
|
);
|
|
4673
4675
|
return;
|
|
4674
4676
|
}
|
|
@@ -4676,7 +4678,7 @@ var syncFlow = async (ctx) => {
|
|
|
4676
4678
|
if (headAfter === headBefore) {
|
|
4677
4679
|
ctx.output.exitCode = 0;
|
|
4678
4680
|
ctx.output.reason = `already up to date with origin/${baseBranch}`;
|
|
4679
|
-
tryPostPr5(prNumber, `\u2139\uFE0F
|
|
4681
|
+
tryPostPr5(prNumber, `\u2139\uFE0F kody sync: already up to date with origin/${baseBranch}`, ctx.cwd);
|
|
4680
4682
|
return;
|
|
4681
4683
|
}
|
|
4682
4684
|
try {
|
|
@@ -4690,14 +4692,14 @@ var syncFlow = async (ctx) => {
|
|
|
4690
4692
|
ctx.output.reason = `merged origin/${baseBranch} into ${ctx.data.branch}`;
|
|
4691
4693
|
const runUrl = getRunUrl();
|
|
4692
4694
|
const runSuffix = runUrl ? ` ([logs](${runUrl}))` : "";
|
|
4693
|
-
tryPostPr5(prNumber, `\u2705
|
|
4695
|
+
tryPostPr5(prNumber, `\u2705 kody sync: merged \`origin/${baseBranch}\` into \`${ctx.data.branch}\`${runSuffix}`, ctx.cwd);
|
|
4694
4696
|
};
|
|
4695
4697
|
function bail2(ctx, prNumber, reason) {
|
|
4696
4698
|
ctx.output.exitCode = 1;
|
|
4697
4699
|
ctx.output.reason = reason;
|
|
4698
4700
|
const runUrl = getRunUrl();
|
|
4699
4701
|
const runSuffix = runUrl ? ` ([logs](${runUrl}))` : "";
|
|
4700
|
-
tryPostPr5(prNumber, `\u274C
|
|
4702
|
+
tryPostPr5(prNumber, `\u274C kody sync could not complete${runSuffix}: ${reason}`, ctx.cwd);
|
|
4701
4703
|
}
|
|
4702
4704
|
function revParseHead(cwd) {
|
|
4703
4705
|
try {
|
|
@@ -4845,10 +4847,10 @@ function findStalePrs(cwd, staleDays, now = /* @__PURE__ */ new Date()) {
|
|
|
4845
4847
|
}
|
|
4846
4848
|
function formatStaleReport(stale, staleDays) {
|
|
4847
4849
|
if (stale.length === 0) {
|
|
4848
|
-
return `\u{1F7E2} **
|
|
4850
|
+
return `\u{1F7E2} **kody watch-stale-prs** \u2014 no open PRs untouched for more than ${staleDays} days. \u2728`;
|
|
4849
4851
|
}
|
|
4850
4852
|
const lines = [
|
|
4851
|
-
`\u{1F7E1} **
|
|
4853
|
+
`\u{1F7E1} **kody watch-stale-prs** \u2014 ${stale.length} PR(s) untouched for > ${staleDays} days:`,
|
|
4852
4854
|
""
|
|
4853
4855
|
];
|
|
4854
4856
|
for (const pr of stale.slice(0, 50)) {
|
|
@@ -4869,7 +4871,7 @@ var watchStalePrsFlow = async (ctx) => {
|
|
|
4869
4871
|
postIssueComment(reportIssueNumber, report, ctx.cwd);
|
|
4870
4872
|
} catch (err) {
|
|
4871
4873
|
process.stderr.write(
|
|
4872
|
-
`[
|
|
4874
|
+
`[kody watch] failed to post to issue #${reportIssueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
4873
4875
|
`
|
|
4874
4876
|
);
|
|
4875
4877
|
}
|
|
@@ -4892,7 +4894,7 @@ var writeRunSummary = async (ctx, profile) => {
|
|
|
4892
4894
|
const reason = ctx.output.reason;
|
|
4893
4895
|
const status = exitCode === 0 ? "\u2705 success" : exitCode === 3 ? "\u23ED\uFE0F no-op" : "\u26A0\uFE0F failed";
|
|
4894
4896
|
const lines = [];
|
|
4895
|
-
lines.push(`##
|
|
4897
|
+
lines.push(`## kody ${executable} \u2014 ${status}`);
|
|
4896
4898
|
lines.push("");
|
|
4897
4899
|
lines.push(`- **Executable:** \`${executable}\``);
|
|
4898
4900
|
lines.push(`- **Target:** ${target}`);
|
|
@@ -5062,7 +5064,7 @@ async function runExecutable(profileName, input) {
|
|
|
5062
5064
|
data: {},
|
|
5063
5065
|
output: { exitCode: 0 }
|
|
5064
5066
|
};
|
|
5065
|
-
const ndjsonDir = path17.join(input.cwd, ".
|
|
5067
|
+
const ndjsonDir = path17.join(input.cwd, ".kody");
|
|
5066
5068
|
const invokeAgent = async (prompt) => {
|
|
5067
5069
|
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path17.isAbsolute(p) ? p : path17.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
5068
5070
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
@@ -5112,7 +5114,7 @@ async function runExecutable(profileName, input) {
|
|
|
5112
5114
|
await fn(ctx, profile, agentResult, entry.with);
|
|
5113
5115
|
} catch (err) {
|
|
5114
5116
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5115
|
-
process.stderr.write(`[
|
|
5117
|
+
process.stderr.write(`[kody] postflight script "${entry.script}" crashed: ${msg}
|
|
5116
5118
|
`);
|
|
5117
5119
|
if (!ctx.output.reason) ctx.output.reason = `postflight ${entry.script} crashed: ${msg}`;
|
|
5118
5120
|
if (ctx.output.exitCode === 0) ctx.output.exitCode = 99;
|
|
@@ -5232,11 +5234,11 @@ function finish(out) {
|
|
|
5232
5234
|
return out;
|
|
5233
5235
|
}
|
|
5234
5236
|
|
|
5235
|
-
// src/
|
|
5236
|
-
var CI_HELP = `
|
|
5237
|
+
// src/kody-cli.ts
|
|
5238
|
+
var CI_HELP = `kody ci \u2014 minimal-YAML autonomous engineer (CI preflight + run)
|
|
5237
5239
|
|
|
5238
5240
|
Usage:
|
|
5239
|
-
|
|
5241
|
+
kody ci --issue <N> [--cwd <path>] [--verbose|--quiet]
|
|
5240
5242
|
[--skip-install] [--skip-litellm] [--package-manager pnpm|yarn|bun|npm]
|
|
5241
5243
|
|
|
5242
5244
|
Options:
|
|
@@ -5252,7 +5254,7 @@ Environment:
|
|
|
5252
5254
|
ALL_SECRETS JSON blob of all GitHub secrets (auto-populated in CI)
|
|
5253
5255
|
KODY_TOKEN|GH_TOKEN|GITHUB_TOKEN|GH_PAT auth token for gh/git operations
|
|
5254
5256
|
|
|
5255
|
-
Exit codes (inherited from
|
|
5257
|
+
Exit codes (inherited from kody run):
|
|
5256
5258
|
0 success (PR opened, verify passed)
|
|
5257
5259
|
1 agent reported FAILED (draft PR opened)
|
|
5258
5260
|
2 verify failed (draft PR opened)
|
|
@@ -5345,7 +5347,7 @@ function isOnPath(bin) {
|
|
|
5345
5347
|
}
|
|
5346
5348
|
function ensurePackageManagerInstalled(pm, cwd) {
|
|
5347
5349
|
if (pm === "npm" || isOnPath(pm)) return 0;
|
|
5348
|
-
process.stdout.write(`\u2192
|
|
5350
|
+
process.stdout.write(`\u2192 kody: ${pm} not on PATH \u2014 installing via npm install -g ${pm}
|
|
5349
5351
|
`);
|
|
5350
5352
|
return shellOut("npm", ["install", "-g", pm], cwd);
|
|
5351
5353
|
}
|
|
@@ -5365,18 +5367,18 @@ function installLitellmIfNeeded(cwd) {
|
|
|
5365
5367
|
const cfg = loadConfig(cwd);
|
|
5366
5368
|
const model = parseProviderModel(cfg.agent.model);
|
|
5367
5369
|
if (!needsLitellmProxy(model)) {
|
|
5368
|
-
process.stdout.write("\u2192
|
|
5370
|
+
process.stdout.write("\u2192 kody: provider is anthropic/claude, skipping LiteLLM install\n");
|
|
5369
5371
|
return 0;
|
|
5370
5372
|
}
|
|
5371
5373
|
} catch {
|
|
5372
5374
|
}
|
|
5373
5375
|
try {
|
|
5374
5376
|
execFileSync20("python3", ["-c", "import litellm"], { stdio: "pipe" });
|
|
5375
|
-
process.stdout.write("\u2192
|
|
5377
|
+
process.stdout.write("\u2192 kody: litellm already installed\n");
|
|
5376
5378
|
return 0;
|
|
5377
5379
|
} catch {
|
|
5378
5380
|
}
|
|
5379
|
-
process.stdout.write("\u2192
|
|
5381
|
+
process.stdout.write("\u2192 kody: installing litellm (pip install 'litellm[proxy]')\n");
|
|
5380
5382
|
return shellOut("pip", ["install", "litellm[proxy]"], cwd);
|
|
5381
5383
|
}
|
|
5382
5384
|
function configureGitIdentity(cwd) {
|
|
@@ -5399,7 +5401,7 @@ function configureGitIdentity(cwd) {
|
|
|
5399
5401
|
}
|
|
5400
5402
|
function postFailureTail(issueNumber, cwd, reason) {
|
|
5401
5403
|
if (!issueNumber) return;
|
|
5402
|
-
const logPath = path18.join(cwd, ".
|
|
5404
|
+
const logPath = path18.join(cwd, ".kody", "last-run.jsonl");
|
|
5403
5405
|
let tail = "";
|
|
5404
5406
|
try {
|
|
5405
5407
|
if (fs21.existsSync(logPath)) {
|
|
@@ -5408,7 +5410,7 @@ function postFailureTail(issueNumber, cwd, reason) {
|
|
|
5408
5410
|
}
|
|
5409
5411
|
} catch {
|
|
5410
5412
|
}
|
|
5411
|
-
const body = tail ? `\u26A0\uFE0F
|
|
5413
|
+
const body = tail ? `\u26A0\uFE0F kody preflight failed: ${truncate2(reason, 500)}
|
|
5412
5414
|
|
|
5413
5415
|
<details><summary>Last-run log tail</summary>
|
|
5414
5416
|
|
|
@@ -5416,7 +5418,7 @@ function postFailureTail(issueNumber, cwd, reason) {
|
|
|
5416
5418
|
${tail}
|
|
5417
5419
|
\`\`\`
|
|
5418
5420
|
|
|
5419
|
-
</details>` : `\u26A0\uFE0F
|
|
5421
|
+
</details>` : `\u26A0\uFE0F kody preflight failed: ${truncate2(reason, 1500)}`;
|
|
5420
5422
|
try {
|
|
5421
5423
|
postIssueComment(issueNumber, body, cwd);
|
|
5422
5424
|
} catch {
|
|
@@ -5452,16 +5454,16 @@ ${CI_HELP}`);
|
|
|
5452
5454
|
target: args.issueNumber
|
|
5453
5455
|
};
|
|
5454
5456
|
const issueNumber = dispatch2.target;
|
|
5455
|
-
process.stdout.write(`\u2192
|
|
5457
|
+
process.stdout.write(`\u2192 kody preflight (cwd=${cwd}, executable=${dispatch2.executable}, target=${issueNumber})
|
|
5456
5458
|
`);
|
|
5457
5459
|
try {
|
|
5458
5460
|
const n = unpackAllSecrets();
|
|
5459
|
-
if (n > 0) process.stdout.write(`\u2192
|
|
5461
|
+
if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s) from ALL_SECRETS
|
|
5460
5462
|
`);
|
|
5461
5463
|
resolveAuthToken();
|
|
5462
5464
|
reactToTriggerComment(cwd);
|
|
5463
5465
|
const pm = args.packageManager ?? detectPackageManager2(cwd);
|
|
5464
|
-
process.stdout.write(`\u2192
|
|
5466
|
+
process.stdout.write(`\u2192 kody: package manager = ${pm}
|
|
5465
5467
|
`);
|
|
5466
5468
|
if (!args.skipInstall) {
|
|
5467
5469
|
const code = installDeps(pm, cwd);
|
|
@@ -5470,7 +5472,7 @@ ${CI_HELP}`);
|
|
|
5470
5472
|
return 99;
|
|
5471
5473
|
}
|
|
5472
5474
|
} else {
|
|
5473
|
-
process.stdout.write("\u2192
|
|
5475
|
+
process.stdout.write("\u2192 kody: skipping dep install (--skip-install)\n");
|
|
5474
5476
|
}
|
|
5475
5477
|
if (!args.skipLitellm) {
|
|
5476
5478
|
const code = installLitellmIfNeeded(cwd);
|
|
@@ -5479,17 +5481,17 @@ ${CI_HELP}`);
|
|
|
5479
5481
|
return 99;
|
|
5480
5482
|
}
|
|
5481
5483
|
} else {
|
|
5482
|
-
process.stdout.write("\u2192
|
|
5484
|
+
process.stdout.write("\u2192 kody: skipping LiteLLM install (--skip-litellm)\n");
|
|
5483
5485
|
}
|
|
5484
5486
|
configureGitIdentity(cwd);
|
|
5485
5487
|
} catch (err) {
|
|
5486
5488
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5487
|
-
process.stderr.write(`[
|
|
5489
|
+
process.stderr.write(`[kody] preflight crashed: ${msg}
|
|
5488
5490
|
`);
|
|
5489
5491
|
postFailureTail(issueNumber, cwd, `preflight crashed: ${msg}`);
|
|
5490
5492
|
return 99;
|
|
5491
5493
|
}
|
|
5492
|
-
process.stdout.write(`\u2192
|
|
5494
|
+
process.stdout.write(`\u2192 kody: preflight done, handing off to kody ${dispatch2.executable}
|
|
5493
5495
|
|
|
5494
5496
|
`);
|
|
5495
5497
|
try {
|
|
@@ -5507,7 +5509,7 @@ ${CI_HELP}`);
|
|
|
5507
5509
|
return result.exitCode;
|
|
5508
5510
|
} catch (err) {
|
|
5509
5511
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5510
|
-
process.stderr.write(`[
|
|
5512
|
+
process.stderr.write(`[kody] run crashed: ${msg}
|
|
5511
5513
|
`);
|
|
5512
5514
|
if (err instanceof Error && err.stack) process.stderr.write(`${err.stack}
|
|
5513
5515
|
`);
|
|
@@ -5518,10 +5520,10 @@ ${CI_HELP}`);
|
|
|
5518
5520
|
|
|
5519
5521
|
// src/chat-cli.ts
|
|
5520
5522
|
var DEFAULT_MODEL = "claude/claude-haiku-4-5-20251001";
|
|
5521
|
-
var CHAT_HELP = `
|
|
5523
|
+
var CHAT_HELP = `kody chat \u2014 dashboard-driven chat session
|
|
5522
5524
|
|
|
5523
5525
|
Usage:
|
|
5524
|
-
|
|
5526
|
+
kody chat [--session <id>] [--message <text>] [--model <provider/model>]
|
|
5525
5527
|
[--dashboard-url <url>] [--cwd <path>] [--verbose|--quiet]
|
|
5526
5528
|
|
|
5527
5529
|
All inputs may also come from env: SESSION_ID, INIT_MESSAGE, MODEL, DASHBOARD_URL.
|
|
@@ -5572,7 +5574,7 @@ function commitChatFiles(cwd, sessionId, verbose) {
|
|
|
5572
5574
|
execFileSync21("git", ["push", "--quiet", "origin", "HEAD"], opts);
|
|
5573
5575
|
} catch (err) {
|
|
5574
5576
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5575
|
-
process.stderr.write(`[
|
|
5577
|
+
process.stderr.write(`[kody:chat] commit/push skipped: ${msg}
|
|
5576
5578
|
`);
|
|
5577
5579
|
}
|
|
5578
5580
|
}
|
|
@@ -5605,7 +5607,7 @@ ${CHAT_HELP}`);
|
|
|
5605
5607
|
const sessionId = args.sessionId;
|
|
5606
5608
|
const unpackedSecrets = unpackAllSecrets();
|
|
5607
5609
|
if (unpackedSecrets > 0) {
|
|
5608
|
-
process.stdout.write(`\u2192
|
|
5610
|
+
process.stdout.write(`\u2192 kody: unpacked ${unpackedSecrets} secret(s) from ALL_SECRETS
|
|
5609
5611
|
`);
|
|
5610
5612
|
}
|
|
5611
5613
|
resolveAuthToken();
|
|
@@ -5667,19 +5669,19 @@ ${CHAT_HELP}`);
|
|
|
5667
5669
|
}
|
|
5668
5670
|
|
|
5669
5671
|
// src/entry.ts
|
|
5670
|
-
var HELP_TEXT = `
|
|
5672
|
+
var HELP_TEXT = `kody \u2014 single-session autonomous engineer
|
|
5671
5673
|
|
|
5672
5674
|
Usage:
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5675
|
+
kody run --issue <N> [--cwd <path>] [--verbose|--quiet]
|
|
5676
|
+
kody fix --pr <N> [--feedback "..."] [--cwd <path>] [--verbose|--quiet]
|
|
5677
|
+
kody fix-ci --pr <N> [--run-id <ID>] [--cwd <path>] [--verbose|--quiet]
|
|
5678
|
+
kody resolve --pr <N> [--cwd <path>] [--verbose|--quiet]
|
|
5679
|
+
kody review --pr <N> [--cwd <path>] [--verbose|--quiet]
|
|
5680
|
+
kody <other> [--cwd <path>] [--verbose|--quiet]
|
|
5681
|
+
kody ci --issue <N> [preflight flags \u2014 see: kody ci --help]
|
|
5682
|
+
kody chat [chat flags \u2014 see: kody chat --help]
|
|
5683
|
+
kody help
|
|
5684
|
+
kody version
|
|
5683
5685
|
|
|
5684
5686
|
Each top-level command (run, fix, fix-ci, resolve, review, \u2026) is a discovered
|
|
5685
5687
|
executable under \`src/executables/<name>/profile.json\`. Drop in a new
|
|
@@ -5735,7 +5737,7 @@ ${HELP_TEXT}`);
|
|
|
5735
5737
|
return 0;
|
|
5736
5738
|
}
|
|
5737
5739
|
if (args.command === "version") {
|
|
5738
|
-
process.stdout.write(`
|
|
5740
|
+
process.stdout.write(`kody ${package_default.version}
|
|
5739
5741
|
`);
|
|
5740
5742
|
return 0;
|
|
5741
5743
|
}
|
|
@@ -5744,7 +5746,7 @@ ${HELP_TEXT}`);
|
|
|
5744
5746
|
return await runCi(args.ciArgv ?? []);
|
|
5745
5747
|
} catch (err) {
|
|
5746
5748
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5747
|
-
process.stderr.write(`[
|
|
5749
|
+
process.stderr.write(`[kody] fatal: ${msg}
|
|
5748
5750
|
`);
|
|
5749
5751
|
if (err instanceof Error && err.stack) process.stderr.write(`${err.stack}
|
|
5750
5752
|
`);
|
|
@@ -5756,7 +5758,7 @@ ${HELP_TEXT}`);
|
|
|
5756
5758
|
return await runChat(args.chatArgv ?? []);
|
|
5757
5759
|
} catch (err) {
|
|
5758
5760
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5759
|
-
process.stderr.write(`[
|
|
5761
|
+
process.stderr.write(`[kody] fatal: ${msg}
|
|
5760
5762
|
`);
|
|
5761
5763
|
if (err instanceof Error && err.stack) process.stderr.write(`${err.stack}
|
|
5762
5764
|
`);
|
|
@@ -5781,7 +5783,7 @@ ${HELP_TEXT}`);
|
|
|
5781
5783
|
return result.exitCode;
|
|
5782
5784
|
} catch (err) {
|
|
5783
5785
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5784
|
-
process.stderr.write(`[
|
|
5786
|
+
process.stderr.write(`[kody] ${args.executableName} crashed: ${msg}
|
|
5785
5787
|
`);
|
|
5786
5788
|
if (err instanceof Error && err.stack) process.stderr.write(`${err.stack}
|
|
5787
5789
|
`);
|
|
@@ -5791,11 +5793,11 @@ ${HELP_TEXT}`);
|
|
|
5791
5793
|
}
|
|
5792
5794
|
}
|
|
5793
5795
|
|
|
5794
|
-
// bin/
|
|
5796
|
+
// bin/kody.ts
|
|
5795
5797
|
main().then((code) => {
|
|
5796
5798
|
process.exit(code);
|
|
5797
5799
|
}).catch((err) => {
|
|
5798
|
-
process.stderr.write(`[
|
|
5800
|
+
process.stderr.write(`[kody] fatal: ${err instanceof Error ? err.message : String(err)}
|
|
5799
5801
|
`);
|
|
5800
5802
|
process.exit(99);
|
|
5801
5803
|
});
|