@kody-ade/kody-engine 0.4.621 → 0.4.623
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 +9 -1
- package/dist/bin/kody.js +41 -26
- package/docs/delivery-boundary.md +29 -0
- package/kody.config.schema.json +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -57,7 +57,9 @@ key. It's built to keep that blast radius small:
|
|
|
57
57
|
downstream CI.
|
|
58
58
|
- **Write allowlist.** The agent commits through `commitAndPush`, which blocks
|
|
59
59
|
writes to engine runtime or configuration paths — it can't touch your
|
|
60
|
-
runtime state.
|
|
60
|
+
runtime state. See [Delivery boundary](docs/delivery-boundary.md) for what is
|
|
61
|
+
silently discarded, what fails visibly, and how an approved workflow file is
|
|
62
|
+
delivered.
|
|
61
63
|
- **Locked-toolbox mode.** A job can declare `tools: [...]` to drop `Bash` and
|
|
62
64
|
shell entirely, running only a fixed set of high-level intents.
|
|
63
65
|
- **Review like any contributor.** kody opens PRs; you merge them.
|
|
@@ -107,6 +109,12 @@ fans out scheduled capabilities at runtime, so capability schedules never
|
|
|
107
109
|
generate additional GitHub workflow files. Idempotent — pass `--force` to
|
|
108
110
|
overwrite.
|
|
109
111
|
|
|
112
|
+
Kody also discovers conventional package scripts (`typecheck`, `lint`,
|
|
113
|
+
`test:unit` or `test`, and non-mutating format-check scripts). This means a
|
|
114
|
+
repository that adds its application after Kody onboarding still receives a
|
|
115
|
+
real verification gate. Explicit `quality` commands in `kody.config.json`
|
|
116
|
+
always override discovery. See [Repository quality gates](docs/quality-gates.md).
|
|
117
|
+
|
|
110
118
|
Store model provider keys (for example `MINIMAX_API_KEY`) in the connected
|
|
111
119
|
repository's Kody vault. GitHub Actions uses OIDC to request only the selected
|
|
112
120
|
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.623",
|
|
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: {
|
|
@@ -29,6 +29,7 @@ var init_package = __esm({
|
|
|
29
29
|
files: [
|
|
30
30
|
"dist",
|
|
31
31
|
"templates",
|
|
32
|
+
"docs/delivery-boundary.md",
|
|
32
33
|
"kody.config.schema.json"
|
|
33
34
|
],
|
|
34
35
|
scripts: {
|
|
@@ -182,6 +183,32 @@ var init_completionGuard = __esm({
|
|
|
182
183
|
// src/config.ts
|
|
183
184
|
import * as fs2 from "fs";
|
|
184
185
|
import * as path3 from "path";
|
|
186
|
+
function packageManagerFor(projectDir) {
|
|
187
|
+
if (fs2.existsSync(path3.join(projectDir, "pnpm-lock.yaml"))) return "pnpm";
|
|
188
|
+
if (fs2.existsSync(path3.join(projectDir, "yarn.lock"))) return "yarn";
|
|
189
|
+
if (fs2.existsSync(path3.join(projectDir, "bun.lockb")) || fs2.existsSync(path3.join(projectDir, "bun.lock"))) return "bun";
|
|
190
|
+
return "npm";
|
|
191
|
+
}
|
|
192
|
+
function inferQualityCommands(projectDir) {
|
|
193
|
+
const empty = { typecheck: "", lint: "", format: "", testUnit: "" };
|
|
194
|
+
try {
|
|
195
|
+
const pkg = JSON.parse(fs2.readFileSync(path3.join(projectDir, "package.json"), "utf-8"));
|
|
196
|
+
const scripts = pkg.scripts ?? {};
|
|
197
|
+
const pm = packageManagerFor(projectDir);
|
|
198
|
+
const command = (names) => {
|
|
199
|
+
const name = names.find((candidate) => typeof scripts[candidate] === "string");
|
|
200
|
+
return name ? `${pm} run ${name}` : "";
|
|
201
|
+
};
|
|
202
|
+
return {
|
|
203
|
+
typecheck: command(["typecheck", "type-check", "check:types"]),
|
|
204
|
+
lint: command(["lint"]),
|
|
205
|
+
format: command(["format:check", "format-check", "prettier:check"]),
|
|
206
|
+
testUnit: command(["test:unit", "test"])
|
|
207
|
+
};
|
|
208
|
+
} catch {
|
|
209
|
+
return empty;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
185
212
|
function parseReasoningEffort(raw) {
|
|
186
213
|
if (!raw) return null;
|
|
187
214
|
const v = raw.trim().toLowerCase();
|
|
@@ -284,6 +311,7 @@ function loadConfig(projectDir = process.cwd()) {
|
|
|
284
311
|
throw new Error(`kody.config.json is invalid JSON: ${msg}`);
|
|
285
312
|
}
|
|
286
313
|
const quality = recordValue(raw.quality) ?? {};
|
|
314
|
+
const inferredQuality = inferQualityCommands(projectDir);
|
|
287
315
|
const git5 = recordValue(raw.git) ?? {};
|
|
288
316
|
const github = recordValue(raw.github) ?? {};
|
|
289
317
|
const agent = recordValue(raw.agent) ?? {};
|
|
@@ -299,10 +327,10 @@ function loadConfig(projectDir = process.cwd()) {
|
|
|
299
327
|
}
|
|
300
328
|
return {
|
|
301
329
|
quality: {
|
|
302
|
-
typecheck: typeof quality.typecheck === "string" ? quality.typecheck :
|
|
303
|
-
lint: typeof quality.lint === "string" ? quality.lint :
|
|
304
|
-
format: typeof quality.format === "string" ? quality.format :
|
|
305
|
-
testUnit: typeof quality.testUnit === "string" ? quality.testUnit :
|
|
330
|
+
typecheck: typeof quality.typecheck === "string" ? quality.typecheck : inferredQuality.typecheck,
|
|
331
|
+
lint: typeof quality.lint === "string" ? quality.lint : inferredQuality.lint,
|
|
332
|
+
format: typeof quality.format === "string" ? quality.format : inferredQuality.format,
|
|
333
|
+
testUnit: typeof quality.testUnit === "string" ? quality.testUnit : inferredQuality.testUnit,
|
|
306
334
|
coverage: typeof quality.coverage === "string" ? quality.coverage : ""
|
|
307
335
|
},
|
|
308
336
|
git: {
|
|
@@ -15809,19 +15837,6 @@ var init_workflow_template = __esm({
|
|
|
15809
15837
|
import { execFileSync as execFileSync14 } from "child_process";
|
|
15810
15838
|
import * as fs40 from "fs";
|
|
15811
15839
|
import * as path39 from "path";
|
|
15812
|
-
function detectPackageManager(cwd) {
|
|
15813
|
-
if (fs40.existsSync(path39.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
15814
|
-
if (fs40.existsSync(path39.join(cwd, "yarn.lock"))) return "yarn";
|
|
15815
|
-
if (fs40.existsSync(path39.join(cwd, "bun.lockb"))) return "bun";
|
|
15816
|
-
return "npm";
|
|
15817
|
-
}
|
|
15818
|
-
function qualityCommandsFor(pm) {
|
|
15819
|
-
return {
|
|
15820
|
-
typecheck: `${pm} tsc --noEmit`,
|
|
15821
|
-
lint: "",
|
|
15822
|
-
testUnit: `${pm} test`
|
|
15823
|
-
};
|
|
15824
|
-
}
|
|
15825
15840
|
function schemaUrlFromPkg() {
|
|
15826
15841
|
const fallback = "https://raw.githubusercontent.com/aharonyaircohen/kody-engine/main/kody.config.schema.json";
|
|
15827
15842
|
const repoUrl = package_default.repository?.url;
|
|
@@ -15844,10 +15859,10 @@ function detectOwnerRepo(cwd) {
|
|
|
15844
15859
|
if (!m) return null;
|
|
15845
15860
|
return { owner: m[1], repo: m[2] };
|
|
15846
15861
|
}
|
|
15847
|
-
function makeConfig(
|
|
15862
|
+
function makeConfig(cwd, ownerRepo, defaultBranch) {
|
|
15848
15863
|
return {
|
|
15849
15864
|
$schema: schemaUrlFromPkg(),
|
|
15850
|
-
quality:
|
|
15865
|
+
quality: inferQualityCommands(cwd),
|
|
15851
15866
|
git: { defaultBranch },
|
|
15852
15867
|
github: {
|
|
15853
15868
|
owner: ownerRepo?.owner ?? "OWNER",
|
|
@@ -15881,14 +15896,13 @@ function defaultBranchFromGit(cwd) {
|
|
|
15881
15896
|
function performInit(cwd, force) {
|
|
15882
15897
|
const wrote = [];
|
|
15883
15898
|
const skipped = [];
|
|
15884
|
-
const pm = detectPackageManager(cwd);
|
|
15885
15899
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
15886
15900
|
const defaultBranch = defaultBranchFromGit(cwd);
|
|
15887
15901
|
const configPath = path39.join(cwd, "kody.config.json");
|
|
15888
15902
|
if (fs40.existsSync(configPath) && !force) {
|
|
15889
15903
|
skipped.push("kody.config.json");
|
|
15890
15904
|
} else {
|
|
15891
|
-
const cfg = makeConfig(
|
|
15905
|
+
const cfg = makeConfig(cwd, ownerRepo, defaultBranch);
|
|
15892
15906
|
fs40.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
15893
15907
|
`);
|
|
15894
15908
|
wrote.push("kody.config.json");
|
|
@@ -15915,6 +15929,7 @@ var init_initFlow = __esm({
|
|
|
15915
15929
|
"src/scripts/initFlow.ts"() {
|
|
15916
15930
|
"use strict";
|
|
15917
15931
|
init_package();
|
|
15932
|
+
init_config();
|
|
15918
15933
|
init_lifecycleLabels();
|
|
15919
15934
|
init_workflow_template();
|
|
15920
15935
|
initFlow = async (ctx) => {
|
|
@@ -27171,7 +27186,7 @@ async function resolveAuthToken(env = process.env) {
|
|
|
27171
27186
|
);
|
|
27172
27187
|
return void 0;
|
|
27173
27188
|
}
|
|
27174
|
-
function
|
|
27189
|
+
function detectPackageManager(cwd) {
|
|
27175
27190
|
if (fs56.existsSync(path53.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
27176
27191
|
if (fs56.existsSync(path53.join(cwd, "yarn.lock"))) return "yarn";
|
|
27177
27192
|
if (fs56.existsSync(path53.join(cwd, "bun.lockb"))) return "bun";
|
|
@@ -27471,7 +27486,7 @@ async function runCi(argv) {
|
|
|
27471
27486
|
if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s)
|
|
27472
27487
|
`);
|
|
27473
27488
|
await resolveAuthToken();
|
|
27474
|
-
const pm = args.packageManager ??
|
|
27489
|
+
const pm = args.packageManager ?? detectPackageManager(cwd);
|
|
27475
27490
|
if (!args.skipInstall) {
|
|
27476
27491
|
const code = installDeps(pm, cwd);
|
|
27477
27492
|
if (code !== 0) {
|
|
@@ -27632,7 +27647,7 @@ ${CI_HELP}`);
|
|
|
27632
27647
|
`);
|
|
27633
27648
|
await resolveAuthToken();
|
|
27634
27649
|
reactToTriggerComment(cwd);
|
|
27635
|
-
const pm = args.packageManager ??
|
|
27650
|
+
const pm = args.packageManager ?? detectPackageManager(cwd);
|
|
27636
27651
|
process.stdout.write(`\u2192 kody: package manager = ${pm}
|
|
27637
27652
|
`);
|
|
27638
27653
|
const buildOnly = dispatch2.implementation === "preview-build";
|
|
@@ -27713,7 +27728,7 @@ async function runScheduledFanOut(cwd, args, opts) {
|
|
|
27713
27728
|
if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s) from ALL_SECRETS
|
|
27714
27729
|
`);
|
|
27715
27730
|
await resolveAuthToken();
|
|
27716
|
-
const pm = args.packageManager ??
|
|
27731
|
+
const pm = args.packageManager ?? detectPackageManager(cwd);
|
|
27717
27732
|
process.stdout.write(`\u2192 kody: package manager = ${pm}
|
|
27718
27733
|
`);
|
|
27719
27734
|
if (!args.skipInstall) {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Delivery boundary
|
|
2
|
+
|
|
3
|
+
Kody may inspect the whole checkout, but it does not commit every changed file.
|
|
4
|
+
The postflight delivery step separates product work from runtime state and
|
|
5
|
+
operator-owned configuration before creating the PR.
|
|
6
|
+
|
|
7
|
+
## What happens to each kind of change
|
|
8
|
+
|
|
9
|
+
| Change | Result |
|
|
10
|
+
|---|---|
|
|
11
|
+
| Normal source, test, or documentation file | Committed and pushed to the task branch |
|
|
12
|
+
| Engine-generated cache or runtime state (`.kody-engine/`, `.kody-lean/`, `.codegraph/`, `node_modules/`, `dist/`, `build/`, logs) | Discarded from delivery without failing otherwise valid product work |
|
|
13
|
+
| Protected operator or security configuration (`.github/*.yml`, `.env`, `kody.config.json`, legacy `.kody/` state) | Excluded from the commit and reported as a blocked delivery; the run fails visibly instead of claiming full completion |
|
|
14
|
+
|
|
15
|
+
This distinction matters because definition hydration updates
|
|
16
|
+
`.kody-engine/definitions/manifest.json` on normal runs. That file belongs to
|
|
17
|
+
the Engine runtime; it is not work the agent attempted to deliver.
|
|
18
|
+
|
|
19
|
+
## Delivering an approved protected file
|
|
20
|
+
|
|
21
|
+
Do not weaken the global boundary. A capability that legitimately owns a
|
|
22
|
+
GitHub workflow or a repository loop definition must declare the exact path in
|
|
23
|
+
its delivery contract. The Engine validates that allowlist and only then stages
|
|
24
|
+
the ignored file. Ordinary `run` work cannot opt itself into that permission.
|
|
25
|
+
|
|
26
|
+
When a requested protected change is blocked, the issue status names the exact
|
|
27
|
+
omitted path and the workflow exits nonzero. The PR can still contain the safe
|
|
28
|
+
files that were successfully delivered; treat it as partial work until an
|
|
29
|
+
approved owner supplies the protected file.
|
package/kody.config.schema.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"quality": {
|
|
13
13
|
"type": "object",
|
|
14
|
-
"description": "Quality gate commands.
|
|
14
|
+
"description": "Quality gate commands. Missing commands are inferred from conventional package.json scripts; explicit empty strings disable individual gates.",
|
|
15
15
|
"additionalProperties": false,
|
|
16
16
|
"properties": {
|
|
17
17
|
"typecheck": { "type": "string", "default": "" },
|
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.623",
|
|
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": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"files": [
|
|
15
15
|
"dist",
|
|
16
16
|
"templates",
|
|
17
|
+
"docs/delivery-boundary.md",
|
|
17
18
|
"kody.config.schema.json"
|
|
18
19
|
],
|
|
19
20
|
"scripts": {
|