@kody-ade/kody-engine 0.4.623 → 0.4.624
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 +4 -0
- package/dist/bin/kody.js +88 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -115,6 +115,10 @@ repository that adds its application after Kody onboarding still receives a
|
|
|
115
115
|
real verification gate. Explicit `quality` commands in `kody.config.json`
|
|
116
116
|
always override discovery. See [Repository quality gates](docs/quality-gates.md).
|
|
117
117
|
|
|
118
|
+
Lifecycle labels stay attached to both the task and its pull request. A green
|
|
119
|
+
delivery is `kody:reviewing`; after that PR merges, Kody changes the PR and each
|
|
120
|
+
linked closing issue to `kody:done`. See [Pull request lifecycle](docs/pull-request-lifecycle.md).
|
|
121
|
+
|
|
118
122
|
Store model provider keys (for example `MINIMAX_API_KEY`) in the connected
|
|
119
123
|
repository's Kody vault. GitHub Actions uses OIDC to request only the selected
|
|
120
124
|
model key at runtime; user secrets are not copied into Actions. `KODY_TOKEN`
|
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.624",
|
|
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: {
|
|
@@ -26433,7 +26433,7 @@ async function hydrateDefinitionsFromEnv(cwd = process.cwd(), env = process.env)
|
|
|
26433
26433
|
|
|
26434
26434
|
// src/kody-cli.ts
|
|
26435
26435
|
import { execFileSync as execFileSync24 } from "child_process";
|
|
26436
|
-
import * as
|
|
26436
|
+
import * as fs57 from "fs";
|
|
26437
26437
|
import * as path53 from "path";
|
|
26438
26438
|
|
|
26439
26439
|
// src/app-auth.ts
|
|
@@ -26980,6 +26980,55 @@ function readRunRequestFromEnv(env = process.env) {
|
|
|
26980
26980
|
// src/kody-cli.ts
|
|
26981
26981
|
init_runtimePaths();
|
|
26982
26982
|
init_stateWorkspace();
|
|
26983
|
+
|
|
26984
|
+
// src/mergedPrLifecycle.ts
|
|
26985
|
+
init_lifecycleLabels();
|
|
26986
|
+
import * as fs56 from "fs";
|
|
26987
|
+
var DONE3 = {
|
|
26988
|
+
label: "kody:done",
|
|
26989
|
+
color: "0e8a16",
|
|
26990
|
+
description: "kody: work complete"
|
|
26991
|
+
};
|
|
26992
|
+
function mergedKodyPullRequestTargets(event) {
|
|
26993
|
+
if (!event || typeof event !== "object" || Array.isArray(event)) return null;
|
|
26994
|
+
const root = event;
|
|
26995
|
+
if (root.action !== "closed") return null;
|
|
26996
|
+
const pr = root.pull_request;
|
|
26997
|
+
if (!pr || typeof pr !== "object" || Array.isArray(pr)) return null;
|
|
26998
|
+
const record2 = pr;
|
|
26999
|
+
if (record2.merged !== true) return null;
|
|
27000
|
+
const labels = Array.isArray(record2.labels) ? record2.labels : [];
|
|
27001
|
+
const hasKodyLifecycleLabel = labels.some((label) => {
|
|
27002
|
+
if (!label || typeof label !== "object" || Array.isArray(label)) return false;
|
|
27003
|
+
const name = label.name;
|
|
27004
|
+
return typeof name === "string" && name.startsWith("kody:");
|
|
27005
|
+
});
|
|
27006
|
+
if (!hasKodyLifecycleLabel) return null;
|
|
27007
|
+
const prNumber = Number(record2.number ?? root.number ?? 0);
|
|
27008
|
+
if (!Number.isInteger(prNumber) || prNumber <= 0) return null;
|
|
27009
|
+
const body = typeof record2.body === "string" ? record2.body : "";
|
|
27010
|
+
const issues = /* @__PURE__ */ new Set();
|
|
27011
|
+
const closingReference = /\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)\b/gi;
|
|
27012
|
+
for (const match of body.matchAll(closingReference)) {
|
|
27013
|
+
const issue2 = Number(match[1]);
|
|
27014
|
+
if (Number.isInteger(issue2) && issue2 > 0 && issue2 !== prNumber) issues.add(issue2);
|
|
27015
|
+
}
|
|
27016
|
+
return { pr: prNumber, issues: [...issues] };
|
|
27017
|
+
}
|
|
27018
|
+
function finalizeMergedPullRequestEvent(event, cwd, writeLabel = setKodyLabel) {
|
|
27019
|
+
const targets = mergedKodyPullRequestTargets(event);
|
|
27020
|
+
if (!targets) return null;
|
|
27021
|
+
writeLabel(targets.pr, DONE3, cwd);
|
|
27022
|
+
for (const issue2 of targets.issues) writeLabel(issue2, DONE3, cwd);
|
|
27023
|
+
return targets;
|
|
27024
|
+
}
|
|
27025
|
+
function readGitHubEvent(env = process.env) {
|
|
27026
|
+
const eventPath = env.GITHUB_EVENT_PATH;
|
|
27027
|
+
if (!eventPath || !fs56.existsSync(eventPath)) return null;
|
|
27028
|
+
return JSON.parse(fs56.readFileSync(eventPath, "utf-8"));
|
|
27029
|
+
}
|
|
27030
|
+
|
|
27031
|
+
// src/kody-cli.ts
|
|
26983
27032
|
init_workflowDefinitions();
|
|
26984
27033
|
var FAILED_DISPATCH_LABEL = {
|
|
26985
27034
|
label: "kody:failed",
|
|
@@ -27187,9 +27236,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
27187
27236
|
return void 0;
|
|
27188
27237
|
}
|
|
27189
27238
|
function detectPackageManager(cwd) {
|
|
27190
|
-
if (
|
|
27191
|
-
if (
|
|
27192
|
-
if (
|
|
27239
|
+
if (fs57.existsSync(path53.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
27240
|
+
if (fs57.existsSync(path53.join(cwd, "yarn.lock"))) return "yarn";
|
|
27241
|
+
if (fs57.existsSync(path53.join(cwd, "bun.lockb"))) return "bun";
|
|
27193
27242
|
return "npm";
|
|
27194
27243
|
}
|
|
27195
27244
|
function shouldChainScheduledWatch(match) {
|
|
@@ -27230,7 +27279,7 @@ function ensurePackageManagerInstalled(pm, cwd) {
|
|
|
27230
27279
|
return shellOut("npm", ["install", "-g", spec], cwd);
|
|
27231
27280
|
}
|
|
27232
27281
|
function installDeps(pm, cwd) {
|
|
27233
|
-
if (!
|
|
27282
|
+
if (!fs57.existsSync(path53.join(cwd, "package.json"))) {
|
|
27234
27283
|
process.stdout.write("\u2192 kody: no package.json found \u2014 skipping consumer dependency install\n");
|
|
27235
27284
|
return 0;
|
|
27236
27285
|
}
|
|
@@ -27296,8 +27345,8 @@ function postFailureTail(issueNumber, cwd, reason) {
|
|
|
27296
27345
|
const logPath = lastRunLogPath(cwd);
|
|
27297
27346
|
let tail = "";
|
|
27298
27347
|
try {
|
|
27299
|
-
if (
|
|
27300
|
-
const content =
|
|
27348
|
+
if (fs57.existsSync(logPath)) {
|
|
27349
|
+
const content = fs57.readFileSync(logPath, "utf-8");
|
|
27301
27350
|
tail = content.slice(-3e3);
|
|
27302
27351
|
}
|
|
27303
27352
|
} catch {
|
|
@@ -27344,6 +27393,24 @@ async function runCi(argv) {
|
|
|
27344
27393
|
} catch (err) {
|
|
27345
27394
|
earlyConfigError = err instanceof Error ? err : new Error(String(err));
|
|
27346
27395
|
}
|
|
27396
|
+
if (process.env.GITHUB_EVENT_NAME === "pull_request") {
|
|
27397
|
+
try {
|
|
27398
|
+
const finalized = finalizeMergedPullRequestEvent(readGitHubEvent(), cwd);
|
|
27399
|
+
if (finalized) {
|
|
27400
|
+
process.stdout.write(
|
|
27401
|
+
`\u2192 kody: merged PR #${finalized.pr} finalized as done${finalized.issues.length > 0 ? ` (issues ${finalized.issues.map((n) => `#${n}`).join(", ")})` : ""}
|
|
27402
|
+
`
|
|
27403
|
+
);
|
|
27404
|
+
return 0;
|
|
27405
|
+
}
|
|
27406
|
+
} catch (err) {
|
|
27407
|
+
process.stderr.write(
|
|
27408
|
+
`[kody] failed to finalize merged PR lifecycle: ${err instanceof Error ? err.message : String(err)}
|
|
27409
|
+
`
|
|
27410
|
+
);
|
|
27411
|
+
return 99;
|
|
27412
|
+
}
|
|
27413
|
+
}
|
|
27347
27414
|
const dispatchCapabilitiesRoot = capabilitiesRoot(cwd);
|
|
27348
27415
|
const autoFallback = !args.issueNumber ? autoDispatch({ config: earlyConfig, projectCapabilitiesRoot: dispatchCapabilitiesRoot }) : null;
|
|
27349
27416
|
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
@@ -27396,9 +27463,9 @@ async function runCi(argv) {
|
|
|
27396
27463
|
forceRunCliArgs = { goal: envForceMessage };
|
|
27397
27464
|
}
|
|
27398
27465
|
}
|
|
27399
|
-
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath &&
|
|
27466
|
+
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs57.existsSync(dispatchEventPath)) {
|
|
27400
27467
|
try {
|
|
27401
|
-
const evt = JSON.parse(
|
|
27468
|
+
const evt = JSON.parse(fs57.readFileSync(dispatchEventPath, "utf-8"));
|
|
27402
27469
|
const inputs = objectValue2(evt.inputs);
|
|
27403
27470
|
const issueInput = parseInt(String(inputs?.issue_number ?? ""), 10);
|
|
27404
27471
|
const sessionInput = String(inputs?.sessionId ?? "");
|
|
@@ -27814,7 +27881,7 @@ init_repoWorkspace();
|
|
|
27814
27881
|
|
|
27815
27882
|
// src/scripts/brainTurnLog.ts
|
|
27816
27883
|
init_runtimePaths();
|
|
27817
|
-
import * as
|
|
27884
|
+
import * as fs58 from "fs";
|
|
27818
27885
|
import * as path54 from "path";
|
|
27819
27886
|
import posixPath4 from "path/posix";
|
|
27820
27887
|
var live = /* @__PURE__ */ new Map();
|
|
@@ -27823,8 +27890,8 @@ function brainEventsFilePath(dir, chatId) {
|
|
|
27823
27890
|
}
|
|
27824
27891
|
function lastPersistedSeq(dir, chatId) {
|
|
27825
27892
|
const p = brainEventsFilePath(dir, chatId);
|
|
27826
|
-
if (!
|
|
27827
|
-
const lines =
|
|
27893
|
+
if (!fs58.existsSync(p)) return 0;
|
|
27894
|
+
const lines = fs58.readFileSync(p, "utf-8").split("\n").filter(Boolean);
|
|
27828
27895
|
if (lines.length === 0) return 0;
|
|
27829
27896
|
try {
|
|
27830
27897
|
return JSON.parse(lines[lines.length - 1]).seq || 0;
|
|
@@ -27834,9 +27901,9 @@ function lastPersistedSeq(dir, chatId) {
|
|
|
27834
27901
|
}
|
|
27835
27902
|
function readSince(dir, chatId, since) {
|
|
27836
27903
|
const p = brainEventsFilePath(dir, chatId);
|
|
27837
|
-
if (!
|
|
27904
|
+
if (!fs58.existsSync(p)) return [];
|
|
27838
27905
|
const out = [];
|
|
27839
|
-
for (const line of
|
|
27906
|
+
for (const line of fs58.readFileSync(p, "utf-8").split("\n")) {
|
|
27840
27907
|
if (!line) continue;
|
|
27841
27908
|
try {
|
|
27842
27909
|
const rec = JSON.parse(line);
|
|
@@ -27862,12 +27929,12 @@ function beginTurn(dir, chatId) {
|
|
|
27862
27929
|
};
|
|
27863
27930
|
live.set(chatId, state);
|
|
27864
27931
|
const p = brainEventsFilePath(dir, chatId);
|
|
27865
|
-
|
|
27932
|
+
fs58.mkdirSync(path54.dirname(p), { recursive: true });
|
|
27866
27933
|
return (event) => {
|
|
27867
27934
|
state.seq += 1;
|
|
27868
27935
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
27869
27936
|
try {
|
|
27870
|
-
|
|
27937
|
+
fs58.appendFileSync(p, `${JSON.stringify(rec)}
|
|
27871
27938
|
`);
|
|
27872
27939
|
} catch (err) {
|
|
27873
27940
|
process.stderr.write(
|
|
@@ -27906,7 +27973,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
|
|
|
27906
27973
|
event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
|
|
27907
27974
|
};
|
|
27908
27975
|
try {
|
|
27909
|
-
|
|
27976
|
+
fs58.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
|
|
27910
27977
|
`);
|
|
27911
27978
|
} catch {
|
|
27912
27979
|
}
|
|
@@ -30570,7 +30637,7 @@ async function poolServe() {
|
|
|
30570
30637
|
|
|
30571
30638
|
// src/servers/runner-serve.ts
|
|
30572
30639
|
import { spawn as spawn10 } from "child_process";
|
|
30573
|
-
import * as
|
|
30640
|
+
import * as fs59 from "fs";
|
|
30574
30641
|
import { createServer as createServer6 } from "http";
|
|
30575
30642
|
var DEFAULT_PORT2 = 8080;
|
|
30576
30643
|
var DEFAULT_WORKDIR = "/workspace/repo";
|
|
@@ -30646,8 +30713,8 @@ async function defaultRunJob(job) {
|
|
|
30646
30713
|
const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
|
|
30647
30714
|
const branch = job.ref ?? "main";
|
|
30648
30715
|
const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
|
|
30649
|
-
|
|
30650
|
-
|
|
30716
|
+
fs59.rmSync(workdir, { recursive: true, force: true });
|
|
30717
|
+
fs59.mkdirSync(workdir, { recursive: true });
|
|
30651
30718
|
const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
|
|
30652
30719
|
const target = job.runRequest.target;
|
|
30653
30720
|
const interactive = target.type === "chat";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.624",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|