@kody-ade/kody-engine 0.4.622 → 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 CHANGED
@@ -109,6 +109,12 @@ fans out scheduled capabilities at runtime, so capability schedules never
109
109
  generate additional GitHub workflow files. Idempotent — pass `--force` to
110
110
  overwrite.
111
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
+
112
118
  Store model provider keys (for example `MINIMAX_API_KEY`) in the connected
113
119
  repository's Kody vault. GitHub Actions uses OIDC to request only the selected
114
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.622",
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: {
@@ -183,6 +183,32 @@ var init_completionGuard = __esm({
183
183
  // src/config.ts
184
184
  import * as fs2 from "fs";
185
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
+ }
186
212
  function parseReasoningEffort(raw) {
187
213
  if (!raw) return null;
188
214
  const v = raw.trim().toLowerCase();
@@ -285,6 +311,7 @@ function loadConfig(projectDir = process.cwd()) {
285
311
  throw new Error(`kody.config.json is invalid JSON: ${msg}`);
286
312
  }
287
313
  const quality = recordValue(raw.quality) ?? {};
314
+ const inferredQuality = inferQualityCommands(projectDir);
288
315
  const git5 = recordValue(raw.git) ?? {};
289
316
  const github = recordValue(raw.github) ?? {};
290
317
  const agent = recordValue(raw.agent) ?? {};
@@ -300,10 +327,10 @@ function loadConfig(projectDir = process.cwd()) {
300
327
  }
301
328
  return {
302
329
  quality: {
303
- typecheck: typeof quality.typecheck === "string" ? quality.typecheck : "",
304
- lint: typeof quality.lint === "string" ? quality.lint : "",
305
- format: typeof quality.format === "string" ? quality.format : "",
306
- 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,
307
334
  coverage: typeof quality.coverage === "string" ? quality.coverage : ""
308
335
  },
309
336
  git: {
@@ -15810,19 +15837,6 @@ var init_workflow_template = __esm({
15810
15837
  import { execFileSync as execFileSync14 } from "child_process";
15811
15838
  import * as fs40 from "fs";
15812
15839
  import * as path39 from "path";
15813
- function detectPackageManager(cwd) {
15814
- if (fs40.existsSync(path39.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
15815
- if (fs40.existsSync(path39.join(cwd, "yarn.lock"))) return "yarn";
15816
- if (fs40.existsSync(path39.join(cwd, "bun.lockb"))) return "bun";
15817
- return "npm";
15818
- }
15819
- function qualityCommandsFor(pm) {
15820
- return {
15821
- typecheck: `${pm} tsc --noEmit`,
15822
- lint: "",
15823
- testUnit: `${pm} test`
15824
- };
15825
- }
15826
15840
  function schemaUrlFromPkg() {
15827
15841
  const fallback = "https://raw.githubusercontent.com/aharonyaircohen/kody-engine/main/kody.config.schema.json";
15828
15842
  const repoUrl = package_default.repository?.url;
@@ -15845,10 +15859,10 @@ function detectOwnerRepo(cwd) {
15845
15859
  if (!m) return null;
15846
15860
  return { owner: m[1], repo: m[2] };
15847
15861
  }
15848
- function makeConfig(pm, ownerRepo, defaultBranch) {
15862
+ function makeConfig(cwd, ownerRepo, defaultBranch) {
15849
15863
  return {
15850
15864
  $schema: schemaUrlFromPkg(),
15851
- quality: qualityCommandsFor(pm),
15865
+ quality: inferQualityCommands(cwd),
15852
15866
  git: { defaultBranch },
15853
15867
  github: {
15854
15868
  owner: ownerRepo?.owner ?? "OWNER",
@@ -15882,14 +15896,13 @@ function defaultBranchFromGit(cwd) {
15882
15896
  function performInit(cwd, force) {
15883
15897
  const wrote = [];
15884
15898
  const skipped = [];
15885
- const pm = detectPackageManager(cwd);
15886
15899
  const ownerRepo = detectOwnerRepo(cwd);
15887
15900
  const defaultBranch = defaultBranchFromGit(cwd);
15888
15901
  const configPath = path39.join(cwd, "kody.config.json");
15889
15902
  if (fs40.existsSync(configPath) && !force) {
15890
15903
  skipped.push("kody.config.json");
15891
15904
  } else {
15892
- const cfg = makeConfig(pm, ownerRepo, defaultBranch);
15905
+ const cfg = makeConfig(cwd, ownerRepo, defaultBranch);
15893
15906
  fs40.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
15894
15907
  `);
15895
15908
  wrote.push("kody.config.json");
@@ -15916,6 +15929,7 @@ var init_initFlow = __esm({
15916
15929
  "src/scripts/initFlow.ts"() {
15917
15930
  "use strict";
15918
15931
  init_package();
15932
+ init_config();
15919
15933
  init_lifecycleLabels();
15920
15934
  init_workflow_template();
15921
15935
  initFlow = async (ctx) => {
@@ -27172,7 +27186,7 @@ async function resolveAuthToken(env = process.env) {
27172
27186
  );
27173
27187
  return void 0;
27174
27188
  }
27175
- function detectPackageManager2(cwd) {
27189
+ function detectPackageManager(cwd) {
27176
27190
  if (fs56.existsSync(path53.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
27177
27191
  if (fs56.existsSync(path53.join(cwd, "yarn.lock"))) return "yarn";
27178
27192
  if (fs56.existsSync(path53.join(cwd, "bun.lockb"))) return "bun";
@@ -27472,7 +27486,7 @@ async function runCi(argv) {
27472
27486
  if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s)
27473
27487
  `);
27474
27488
  await resolveAuthToken();
27475
- const pm = args.packageManager ?? detectPackageManager2(cwd);
27489
+ const pm = args.packageManager ?? detectPackageManager(cwd);
27476
27490
  if (!args.skipInstall) {
27477
27491
  const code = installDeps(pm, cwd);
27478
27492
  if (code !== 0) {
@@ -27633,7 +27647,7 @@ ${CI_HELP}`);
27633
27647
  `);
27634
27648
  await resolveAuthToken();
27635
27649
  reactToTriggerComment(cwd);
27636
- const pm = args.packageManager ?? detectPackageManager2(cwd);
27650
+ const pm = args.packageManager ?? detectPackageManager(cwd);
27637
27651
  process.stdout.write(`\u2192 kody: package manager = ${pm}
27638
27652
  `);
27639
27653
  const buildOnly = dispatch2.implementation === "preview-build";
@@ -27714,7 +27728,7 @@ async function runScheduledFanOut(cwd, args, opts) {
27714
27728
  if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s) from ALL_SECRETS
27715
27729
  `);
27716
27730
  await resolveAuthToken();
27717
- const pm = args.packageManager ?? detectPackageManager2(cwd);
27731
+ const pm = args.packageManager ?? detectPackageManager(cwd);
27718
27732
  process.stdout.write(`\u2192 kody: package manager = ${pm}
27719
27733
  `);
27720
27734
  if (!args.skipInstall) {
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "quality": {
13
13
  "type": "object",
14
- "description": "Quality gate commands. Empty strings disable individual gates.",
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.622",
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": {