@kody-ade/kody-engine 0.4.117 → 0.4.119
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 +100 -16
- package/dist/executables/goal-scheduler/scheduler.sh +0 -0
- package/dist/executables/release-deploy/deploy.sh +0 -0
- package/dist/executables/release-prepare/prepare.sh +0 -0
- package/dist/executables/release-publish/publish.sh +0 -0
- package/dist/executables/resolve/apply-prefer.sh +0 -0
- package/dist/executables/revert/revert.sh +0 -0
- package/package.json +19 -20
- package/templates/kody.yml +1 -1
package/dist/bin/kody.js
CHANGED
|
@@ -880,7 +880,7 @@ var init_loadPriorArt = __esm({
|
|
|
880
880
|
// package.json
|
|
881
881
|
var package_default = {
|
|
882
882
|
name: "@kody-ade/kody-engine",
|
|
883
|
-
version: "0.4.
|
|
883
|
+
version: "0.4.119",
|
|
884
884
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
885
885
|
license: "MIT",
|
|
886
886
|
type: "module",
|
|
@@ -1227,9 +1227,51 @@ function loadConfig(projectDir = process.cwd()) {
|
|
|
1227
1227
|
classify: parseClassifyConfig(raw.classify),
|
|
1228
1228
|
release: parseReleaseConfig(raw.release),
|
|
1229
1229
|
jobs: parseJobsConfig(raw.jobs),
|
|
1230
|
+
access: parseAccessConfig(raw.access),
|
|
1230
1231
|
qa: parseQaConfig(raw.qa)
|
|
1231
1232
|
};
|
|
1232
1233
|
}
|
|
1234
|
+
var GITHUB_AUTHOR_ASSOCIATIONS = [
|
|
1235
|
+
"OWNER",
|
|
1236
|
+
"MEMBER",
|
|
1237
|
+
"COLLABORATOR",
|
|
1238
|
+
"CONTRIBUTOR",
|
|
1239
|
+
"FIRST_TIME_CONTRIBUTOR",
|
|
1240
|
+
"FIRST_TIMER",
|
|
1241
|
+
"MANNEQUIN",
|
|
1242
|
+
"NONE"
|
|
1243
|
+
];
|
|
1244
|
+
var DEFAULT_ALLOWED_ASSOCIATIONS = ["OWNER", "MEMBER", "COLLABORATOR"];
|
|
1245
|
+
function parseAccessConfig(raw) {
|
|
1246
|
+
if (raw === void 0 || raw === null) {
|
|
1247
|
+
return { allowedAssociations: [...DEFAULT_ALLOWED_ASSOCIATIONS] };
|
|
1248
|
+
}
|
|
1249
|
+
if (typeof raw !== "object") {
|
|
1250
|
+
throw new Error(`kody.config.json: access must be an object`);
|
|
1251
|
+
}
|
|
1252
|
+
const r = raw;
|
|
1253
|
+
if (r.allowedAssociations === void 0) {
|
|
1254
|
+
return { allowedAssociations: [...DEFAULT_ALLOWED_ASSOCIATIONS] };
|
|
1255
|
+
}
|
|
1256
|
+
if (!Array.isArray(r.allowedAssociations)) {
|
|
1257
|
+
throw new Error(`kody.config.json: access.allowedAssociations must be an array of strings`);
|
|
1258
|
+
}
|
|
1259
|
+
const valid = new Set(GITHUB_AUTHOR_ASSOCIATIONS);
|
|
1260
|
+
const out = [];
|
|
1261
|
+
for (const v of r.allowedAssociations) {
|
|
1262
|
+
if (typeof v !== "string") {
|
|
1263
|
+
throw new Error(`kody.config.json: access.allowedAssociations entries must be strings`);
|
|
1264
|
+
}
|
|
1265
|
+
const up = v.trim().toUpperCase();
|
|
1266
|
+
if (!valid.has(up)) {
|
|
1267
|
+
throw new Error(
|
|
1268
|
+
`kody.config.json: access.allowedAssociations contains "${v}" \u2014 must be one of ${GITHUB_AUTHOR_ASSOCIATIONS.join(", ")}`
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
out.push(up);
|
|
1272
|
+
}
|
|
1273
|
+
return { allowedAssociations: out };
|
|
1274
|
+
}
|
|
1233
1275
|
function parseQaConfig(raw) {
|
|
1234
1276
|
if (!raw || typeof raw !== "object") return void 0;
|
|
1235
1277
|
const r = raw;
|
|
@@ -2496,6 +2538,7 @@ function autoDispatch(opts) {
|
|
|
2496
2538
|
const authorType = String(event.comment?.user?.type ?? "");
|
|
2497
2539
|
if (!rawBody.toLowerCase().includes("@kody")) return null;
|
|
2498
2540
|
if (authorLogin === "kody-bot" || authorType === "Bot") return null;
|
|
2541
|
+
if (!associationAllowed(event, opts?.config)) return null;
|
|
2499
2542
|
const body = rawBody.toLowerCase();
|
|
2500
2543
|
const targetNum = Number(event.issue?.number ?? 0);
|
|
2501
2544
|
const isPr = !!event.issue?.pull_request;
|
|
@@ -2571,6 +2614,10 @@ function autoDispatchTyped(opts) {
|
|
|
2571
2614
|
if (authorLogin === "kody-bot" || authorType === "Bot") {
|
|
2572
2615
|
return { kind: "silent", reason: `bot-authored comment (${authorLogin || authorType})` };
|
|
2573
2616
|
}
|
|
2617
|
+
if (!associationAllowed(event, opts?.config)) {
|
|
2618
|
+
const assoc = String(event.comment?.author_association ?? "").toUpperCase() || "<none>";
|
|
2619
|
+
return { kind: "silent", reason: `commenter association '${assoc}' not in access.allowedAssociations` };
|
|
2620
|
+
}
|
|
2574
2621
|
const targetNum = Number(event.issue?.number ?? 0);
|
|
2575
2622
|
const isPr = !!event.issue?.pull_request;
|
|
2576
2623
|
if (!targetNum) {
|
|
@@ -2622,6 +2669,12 @@ function dispatchScheduledWatches(opts) {
|
|
|
2622
2669
|
}
|
|
2623
2670
|
return out;
|
|
2624
2671
|
}
|
|
2672
|
+
function associationAllowed(event, config) {
|
|
2673
|
+
const allowed = config?.access?.allowedAssociations;
|
|
2674
|
+
if (!allowed || allowed.length === 0) return true;
|
|
2675
|
+
const assoc = String(event.comment?.author_association ?? "").toUpperCase();
|
|
2676
|
+
return allowed.includes(assoc);
|
|
2677
|
+
}
|
|
2625
2678
|
function extractAfterTag(body) {
|
|
2626
2679
|
const idx = body.indexOf("@kody");
|
|
2627
2680
|
if (idx === -1) return body;
|
|
@@ -4635,13 +4688,23 @@ function parseJob(body) {
|
|
|
4635
4688
|
if (!jobId) return { error: "jobId required" };
|
|
4636
4689
|
const repo = typeof b.repo === "string" ? b.repo.trim() : "";
|
|
4637
4690
|
if (!/^[^/\s]+\/[^/\s]+$/.test(repo)) return { error: "repo must be 'owner/name'" };
|
|
4638
|
-
const issueNumber = Number(b.issueNumber);
|
|
4639
|
-
if (!Number.isInteger(issueNumber) || issueNumber <= 0) {
|
|
4640
|
-
return { error: "issueNumber (positive integer) required" };
|
|
4641
|
-
}
|
|
4642
4691
|
const githubToken = typeof b.githubToken === "string" ? b.githubToken.trim() : "";
|
|
4643
4692
|
if (!githubToken) return { error: "githubToken required" };
|
|
4644
|
-
const
|
|
4693
|
+
const mode = b.mode === "interactive" ? "interactive" : "issue";
|
|
4694
|
+
const job = { jobId, repo, githubToken, mode };
|
|
4695
|
+
if (mode === "issue") {
|
|
4696
|
+
const issueNumber = Number(b.issueNumber);
|
|
4697
|
+
if (!Number.isInteger(issueNumber) || issueNumber <= 0) {
|
|
4698
|
+
return { error: "issueNumber (positive integer) required for issue mode" };
|
|
4699
|
+
}
|
|
4700
|
+
job.issueNumber = issueNumber;
|
|
4701
|
+
} else {
|
|
4702
|
+
const sessionId = typeof b.sessionId === "string" ? b.sessionId.trim() : "";
|
|
4703
|
+
if (!sessionId) return { error: "sessionId required for interactive mode" };
|
|
4704
|
+
job.sessionId = sessionId;
|
|
4705
|
+
if (Number.isFinite(Number(b.idleExitMs))) job.idleExitMs = Number(b.idleExitMs);
|
|
4706
|
+
if (Number.isFinite(Number(b.hardCapMs))) job.hardCapMs = Number(b.hardCapMs);
|
|
4707
|
+
}
|
|
4645
4708
|
if (typeof b.ref === "string" && b.ref.trim()) job.ref = b.ref.trim();
|
|
4646
4709
|
if (typeof b.model === "string" && b.model.trim()) job.model = b.model.trim();
|
|
4647
4710
|
if (typeof b.sessionId === "string" && b.sessionId.trim()) job.sessionId = b.sessionId.trim();
|
|
@@ -4658,16 +4721,21 @@ async function defaultRunJob(job) {
|
|
|
4658
4721
|
fs19.rmSync(workdir, { recursive: true, force: true });
|
|
4659
4722
|
fs19.mkdirSync(workdir, { recursive: true });
|
|
4660
4723
|
const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
|
|
4724
|
+
const interactive = job.mode === "interactive";
|
|
4661
4725
|
const childEnv = {
|
|
4662
4726
|
...process.env,
|
|
4663
4727
|
REPO: job.repo,
|
|
4664
4728
|
REF: branch,
|
|
4665
4729
|
GITHUB_TOKEN: job.githubToken,
|
|
4666
|
-
ISSUE_NUMBER
|
|
4730
|
+
// Issue mode bakes ISSUE_NUMBER → `kody run --issue N`. Interactive mode
|
|
4731
|
+
// leaves it empty and sets SESSION_ID so the engine boots a chat session.
|
|
4732
|
+
ISSUE_NUMBER: interactive ? "" : String(job.issueNumber),
|
|
4667
4733
|
ALL_SECRETS: allSecrets,
|
|
4668
4734
|
SESSION_ID: job.sessionId ?? "",
|
|
4669
4735
|
DASHBOARD_URL: job.dashboardUrl ?? "",
|
|
4670
|
-
MODEL: job.model ?? ""
|
|
4736
|
+
MODEL: job.model ?? "",
|
|
4737
|
+
...interactive && job.idleExitMs ? { KODY_IDLE_EXIT_MS: String(job.idleExitMs) } : {},
|
|
4738
|
+
...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
|
|
4671
4739
|
};
|
|
4672
4740
|
const run = (cmd, args, cwd) => new Promise((resolve4) => {
|
|
4673
4741
|
const child = spawn3(cmd, args, { stdio: "inherit", env: childEnv, cwd });
|
|
@@ -4699,9 +4767,12 @@ async function defaultRunJob(job) {
|
|
|
4699
4767
|
const authorEmail = process.env.GIT_AUTHOR_EMAIL ?? "kody-bot@users.noreply.github.com";
|
|
4700
4768
|
await run("git", ["config", "user.name", authorName], workdir);
|
|
4701
4769
|
await run("git", ["config", "user.email", authorEmail], workdir);
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4770
|
+
const runArgs = interactive ? [] : ["run", "--issue", String(job.issueNumber)];
|
|
4771
|
+
process.stdout.write(
|
|
4772
|
+
`[runner-serve] job ${job.jobId}: ${interactive ? `interactive session ${job.sessionId}` : `running issue #${job.issueNumber}`}
|
|
4773
|
+
`
|
|
4774
|
+
);
|
|
4775
|
+
const runCode = await run("kody", runArgs, workdir);
|
|
4705
4776
|
process.stdout.write(`[runner-serve] job ${job.jobId}: finished (exit ${runCode})
|
|
4706
4777
|
`);
|
|
4707
4778
|
process.exit(runCode);
|
|
@@ -5215,12 +5286,15 @@ var PoolRegistry = class {
|
|
|
5215
5286
|
const job = {
|
|
5216
5287
|
jobId: req.jobId,
|
|
5217
5288
|
repo: `${owner}/${repo}`,
|
|
5218
|
-
issueNumber: req.issueNumber,
|
|
5219
5289
|
githubToken: this.cfg.githubToken,
|
|
5290
|
+
mode: req.mode ?? "issue",
|
|
5291
|
+
issueNumber: req.issueNumber,
|
|
5292
|
+
sessionId: req.sessionId,
|
|
5293
|
+
idleExitMs: req.idleExitMs,
|
|
5294
|
+
hardCapMs: req.hardCapMs,
|
|
5220
5295
|
ref: req.ref,
|
|
5221
5296
|
allSecrets,
|
|
5222
5297
|
model: req.model,
|
|
5223
|
-
sessionId: req.sessionId,
|
|
5224
5298
|
dashboardUrl: req.dashboardUrl
|
|
5225
5299
|
};
|
|
5226
5300
|
return pm.claim(job);
|
|
@@ -5318,9 +5392,19 @@ function parseClaimRequest(body) {
|
|
|
5318
5392
|
if (!jobId) return { error: "jobId required" };
|
|
5319
5393
|
const repo = typeof b.repo === "string" ? b.repo.trim() : "";
|
|
5320
5394
|
if (!/^[^/\s]+\/[^/\s]+$/.test(repo)) return { error: "repo must be 'owner/name'" };
|
|
5321
|
-
const
|
|
5322
|
-
|
|
5323
|
-
|
|
5395
|
+
const mode = b.mode === "interactive" ? "interactive" : "issue";
|
|
5396
|
+
const req = { jobId, repo, mode };
|
|
5397
|
+
if (mode === "issue") {
|
|
5398
|
+
const issueNumber = Number(b.issueNumber);
|
|
5399
|
+
if (!Number.isInteger(issueNumber) || issueNumber <= 0) return { error: "issueNumber required for issue mode" };
|
|
5400
|
+
req.issueNumber = issueNumber;
|
|
5401
|
+
} else {
|
|
5402
|
+
const sessionId = typeof b.sessionId === "string" ? b.sessionId.trim() : "";
|
|
5403
|
+
if (!sessionId) return { error: "sessionId required for interactive mode" };
|
|
5404
|
+
req.sessionId = sessionId;
|
|
5405
|
+
if (Number.isFinite(Number(b.idleExitMs))) req.idleExitMs = Number(b.idleExitMs);
|
|
5406
|
+
if (Number.isFinite(Number(b.hardCapMs))) req.hardCapMs = Number(b.hardCapMs);
|
|
5407
|
+
}
|
|
5324
5408
|
if (typeof b.ref === "string" && b.ref.trim()) req.ref = b.ref.trim();
|
|
5325
5409
|
if (typeof b.model === "string" && b.model.trim()) req.model = b.model.trim();
|
|
5326
5410
|
if (typeof b.sessionId === "string" && b.sessionId.trim()) req.sessionId = b.sessionId.trim();
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
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.119",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -12,23 +12,6 @@
|
|
|
12
12
|
"templates",
|
|
13
13
|
"kody.config.schema.json"
|
|
14
14
|
],
|
|
15
|
-
"scripts": {
|
|
16
|
-
"kody:run": "tsx bin/kody.ts",
|
|
17
|
-
"serve": "tsx bin/kody.ts serve",
|
|
18
|
-
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
19
|
-
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
20
|
-
"build": "tsup && node scripts/copy-assets.cjs",
|
|
21
|
-
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
22
|
-
"pretest": "pnpm check:modularity",
|
|
23
|
-
"test": "vitest run tests/unit tests/int --no-coverage",
|
|
24
|
-
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
25
|
-
"test:all": "vitest run tests --no-coverage",
|
|
26
|
-
"typecheck": "tsc --noEmit",
|
|
27
|
-
"lint": "biome check",
|
|
28
|
-
"lint:fix": "biome check --write",
|
|
29
|
-
"format": "biome format --write",
|
|
30
|
-
"prepublishOnly": "pnpm build"
|
|
31
|
-
},
|
|
32
15
|
"dependencies": {
|
|
33
16
|
"@actions/cache": "^6.0.0",
|
|
34
17
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
@@ -50,5 +33,21 @@
|
|
|
50
33
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
51
34
|
},
|
|
52
35
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
53
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
54
|
-
|
|
36
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
|
|
37
|
+
"scripts": {
|
|
38
|
+
"kody:run": "tsx bin/kody.ts",
|
|
39
|
+
"serve": "tsx bin/kody.ts serve",
|
|
40
|
+
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
41
|
+
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
42
|
+
"build": "tsup && node scripts/copy-assets.cjs",
|
|
43
|
+
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
44
|
+
"pretest": "pnpm check:modularity",
|
|
45
|
+
"test": "vitest run tests/unit tests/int --no-coverage",
|
|
46
|
+
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
47
|
+
"test:all": "vitest run tests --no-coverage",
|
|
48
|
+
"typecheck": "tsc --noEmit",
|
|
49
|
+
"lint": "biome check",
|
|
50
|
+
"lint:fix": "biome check --write",
|
|
51
|
+
"format": "biome format --write"
|
|
52
|
+
}
|
|
53
|
+
}
|
package/templates/kody.yml
CHANGED