@kody-ade/kody-engine 0.4.477 → 0.4.479

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 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.477",
18
+ version: "0.4.479",
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
  type: "module",
@@ -447,6 +447,20 @@ function parseReleaseConfig(raw) {
447
447
  if (!raw || typeof raw !== "object") return void 0;
448
448
  const r = raw;
449
449
  const out = {};
450
+ if (r.version !== void 0) {
451
+ const version = recordValue(r.version);
452
+ const readCommand = typeof version?.readCommand === "string" ? version.readCommand.trim() : "";
453
+ const writeCommand = typeof version?.writeCommand === "string" ? version.writeCommand.trim() : "";
454
+ const files = Array.isArray(version?.files) ? version.files.filter(
455
+ (file) => typeof file === "string" && file.trim().length > 0
456
+ ).map((file) => file.trim()) : [];
457
+ if (!readCommand || !writeCommand || files.length === 0) {
458
+ throw new Error(
459
+ "kody.config.json: release.version requires readCommand, writeCommand, and files"
460
+ );
461
+ }
462
+ out.version = { readCommand, writeCommand, files: [...new Set(files)] };
463
+ }
450
464
  if (Array.isArray(r.versionFiles)) out.versionFiles = r.versionFiles.filter((f) => typeof f === "string");
451
465
  if (typeof r.publishCommand === "string") out.publishCommand = r.publishCommand;
452
466
  if (typeof r.notifyCommand === "string") out.notifyCommand = r.notifyCommand;
@@ -457,24 +471,36 @@ function parseReleaseConfig(raw) {
457
471
  if (typeof r.allowAdminMerge === "boolean") out.allowAdminMerge = r.allowAdminMerge;
458
472
  if (typeof r.releaseBranch === "string") out.releaseBranch = r.releaseBranch;
459
473
  if (typeof r.timeoutMs === "number" && r.timeoutMs > 0) out.timeoutMs = Math.floor(r.timeoutMs);
460
- if (r.validation && typeof r.validation === "object") {
461
- const validation = r.validation;
462
- const workflow = typeof validation.workflow === "string" ? validation.workflow.trim() : "";
463
- if (workflow) {
464
- const inputs = validation.inputs && typeof validation.inputs === "object" ? Object.fromEntries(
465
- Object.entries(
466
- validation.inputs
467
- ).filter(
468
- (entry) => /^[a-z][a-z0-9_]*$/.test(entry[0]) && (typeof entry[1] === "string" || typeof entry[1] === "number" || typeof entry[1] === "boolean")
469
- )
470
- ) : void 0;
471
- out.validation = {
472
- workflow,
473
- ...inputs && Object.keys(inputs).length > 0 ? { inputs } : {}
474
- };
474
+ if (typeof r.productionDeployRequired === "boolean")
475
+ out.productionDeployRequired = r.productionDeployRequired;
476
+ out.validation = parseReleaseWorkflowRequest(r.validation, "validation");
477
+ out.deployment = parseReleaseWorkflowRequest(
478
+ r.deployment,
479
+ "deployment",
480
+ true
481
+ );
482
+ return Object.keys(out).length > 0 ? out : void 0;
483
+ }
484
+ function parseReleaseWorkflowRequest(raw, field, requiredWhenConfigured = false) {
485
+ if (raw === void 0) return void 0;
486
+ const request = recordValue(raw);
487
+ const workflow = typeof request?.workflow === "string" ? request.workflow.trim() : "";
488
+ if (!workflow) {
489
+ if (requiredWhenConfigured) {
490
+ throw new Error(`kody.config.json: release.${field}.workflow is required`);
475
491
  }
492
+ return void 0;
476
493
  }
477
- return Object.keys(out).length > 0 ? out : void 0;
494
+ const rawInputs = recordValue(request?.inputs);
495
+ const inputs = rawInputs ? Object.fromEntries(
496
+ Object.entries(rawInputs).filter(
497
+ (entry) => /^[a-z][a-z0-9_]*$/.test(entry[0]) && (typeof entry[1] === "string" || typeof entry[1] === "number" || typeof entry[1] === "boolean")
498
+ )
499
+ ) : void 0;
500
+ return {
501
+ workflow,
502
+ ...inputs && Object.keys(inputs).length > 0 ? { inputs } : {}
503
+ };
478
504
  }
479
505
  function parseIssueContext(raw) {
480
506
  if (!raw || typeof raw !== "object") return void 0;
@@ -4241,6 +4267,56 @@ var init_agencyBoundaryEval = __esm({
4241
4267
  }
4242
4268
  });
4243
4269
 
4270
+ // src/scripts/capabilityExecutionEnvironment.ts
4271
+ function capabilityInputEnvironment(input) {
4272
+ const environment = {
4273
+ KODY_CAPABILITY_INPUT: JSON.stringify(input ?? null)
4274
+ };
4275
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
4276
+ return environment;
4277
+ }
4278
+ for (const [name, value] of Object.entries(input)) {
4279
+ if (value === void 0 || value === null) continue;
4280
+ const key = environmentKey(name);
4281
+ environment[`KODY_ARG_${key}`] = typeof value === "string" ? value : JSON.stringify(value);
4282
+ }
4283
+ return environment;
4284
+ }
4285
+ function capabilityConfigEnvironment(config) {
4286
+ if (!config || typeof config !== "object" || Array.isArray(config)) return {};
4287
+ return Object.fromEntries(
4288
+ flattenConfig(config).map(([key, value]) => [
4289
+ `KODY_CFG_${key}`,
4290
+ value
4291
+ ])
4292
+ );
4293
+ }
4294
+ function flattenConfig(config, prefix = "") {
4295
+ const entries = [];
4296
+ for (const [name, value] of Object.entries(config)) {
4297
+ if (value === null || value === void 0) continue;
4298
+ const key = prefix ? `${prefix}_${environmentKey(name)}` : environmentKey(name);
4299
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4300
+ entries.push([key, String(value)]);
4301
+ } else if (Array.isArray(value)) {
4302
+ entries.push([key, JSON.stringify(value)]);
4303
+ } else if (typeof value === "object") {
4304
+ entries.push(
4305
+ ...flattenConfig(value, key)
4306
+ );
4307
+ }
4308
+ }
4309
+ return entries;
4310
+ }
4311
+ function environmentKey(name) {
4312
+ return name.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
4313
+ }
4314
+ var init_capabilityExecutionEnvironment = __esm({
4315
+ "src/scripts/capabilityExecutionEnvironment.ts"() {
4316
+ "use strict";
4317
+ }
4318
+ });
4319
+
4244
4320
  // src/agency/capability-contract-validation.ts
4245
4321
  import Ajv from "ajv";
4246
4322
  function validateCapabilityContractValue(boundary, schema, value) {
@@ -15533,18 +15609,6 @@ function scalar(value) {
15533
15609
  if (/^-?\d+$/.test(value)) return Number(value);
15534
15610
  return value;
15535
15611
  }
15536
- function capabilityEnvironment(input) {
15537
- const environment = {
15538
- KODY_CAPABILITY_INPUT: JSON.stringify(input ?? null)
15539
- };
15540
- if (!input || typeof input !== "object" || Array.isArray(input)) return environment;
15541
- for (const [name, value] of Object.entries(input)) {
15542
- if (value === void 0 || value === null) continue;
15543
- const key = name.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
15544
- environment[`KODY_ARG_${key}`] = typeof value === "string" ? value : JSON.stringify(value);
15545
- }
15546
- return environment;
15547
- }
15548
15612
  function listFiles(root) {
15549
15613
  if (!fs43.existsSync(root)) return [];
15550
15614
  const files = [];
@@ -15566,6 +15630,7 @@ var init_loadSimpleCapability = __esm({
15566
15630
  init_capability_contract_validation();
15567
15631
  init_capabilityFolders();
15568
15632
  init_definition_paths();
15633
+ init_capabilityExecutionEnvironment();
15569
15634
  loadSimpleCapability = async (ctx) => {
15570
15635
  const slug = typeof ctx.args.capability === "string" ? ctx.args.capability.trim() : "";
15571
15636
  if (!/^[a-z][a-z0-9-]*$/.test(slug)) {
@@ -15594,7 +15659,10 @@ var init_loadSimpleCapability = __esm({
15594
15659
  if (capability.config.outputSchema) {
15595
15660
  ctx.data.capabilityOutputSchema = capability.config.outputSchema;
15596
15661
  }
15597
- ctx.data.capabilityEnvironment = capabilityEnvironment(input);
15662
+ ctx.data.capabilityEnvironment = {
15663
+ ...capabilityInputEnvironment(input),
15664
+ ...capabilityConfigEnvironment(ctx.config)
15665
+ };
15598
15666
  ctx.data.prompt = [
15599
15667
  capability.rawBody.trim(),
15600
15668
  "",
@@ -19096,7 +19164,7 @@ var init_runSimpleCapabilityScript = __esm({
19096
19164
  ctx.output.reason = 'Script-backed Capability requires a regular "tools/run.sh" entrypoint';
19097
19165
  return;
19098
19166
  }
19099
- const capabilityEnvironment2 = isStringRecord(ctx.data.capabilityEnvironment) ? ctx.data.capabilityEnvironment : {};
19167
+ const capabilityEnvironment = isStringRecord(ctx.data.capabilityEnvironment) ? ctx.data.capabilityEnvironment : {};
19100
19168
  const capabilitySecrets = declaredSecrets(ctx.data.capabilitySecretNames, process.env);
19101
19169
  const timeoutMs = typeof ctx.data.capabilityScriptTimeoutMs === "number" ? ctx.data.capabilityScriptTimeoutMs : DEFAULT_SCRIPT_TIMEOUT_MS;
19102
19170
  const result = spawnSync3("bash", [scriptPath], {
@@ -19104,7 +19172,7 @@ var init_runSimpleCapabilityScript = __esm({
19104
19172
  env: {
19105
19173
  ...buildTickChildEnv(process.env, false),
19106
19174
  ...capabilitySecrets,
19107
- ...capabilityEnvironment2
19175
+ ...capabilityEnvironment
19108
19176
  },
19109
19177
  stdio: ["ignore", "pipe", "pipe"],
19110
19178
  encoding: "utf-8",
@@ -21597,13 +21665,8 @@ async function runShellEntry(entry, ctx, profile) {
21597
21665
  `kody-shell-output-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
21598
21666
  );
21599
21667
  const env = { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", KODY_OUTPUT: outputFile };
21600
- for (const [k, v] of Object.entries(ctx.args)) {
21601
- if (v === void 0 || v === null) continue;
21602
- env[`KODY_ARG_${envKey(k)}`] = String(v);
21603
- }
21604
- for (const [k, v] of flattenConfig(ctx.config)) {
21605
- env[`KODY_CFG_${k}`] = v;
21606
- }
21668
+ Object.assign(env, capabilityInputEnvironment(ctx.args));
21669
+ Object.assign(env, capabilityConfigEnvironment(ctx.config));
21607
21670
  const timeoutMs = resolveShellTimeoutMs(entry);
21608
21671
  const child = spawn8("bash", [shellPath, ...positional], {
21609
21672
  cwd: ctx.cwd,
@@ -21704,28 +21767,11 @@ async function runShellEntry(entry, ctx, profile) {
21704
21767
  }
21705
21768
  }
21706
21769
  }
21707
- function envKey(name) {
21708
- return name.toUpperCase().replace(/-/g, "_");
21709
- }
21710
- function flattenConfig(obj, prefix = "") {
21711
- const out = [];
21712
- for (const [k, v] of Object.entries(obj)) {
21713
- if (v === null || v === void 0) continue;
21714
- const key = prefix ? `${prefix}_${envKey(k)}` : envKey(k);
21715
- if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
21716
- out.push([key, String(v)]);
21717
- } else if (Array.isArray(v)) {
21718
- out.push([key, JSON.stringify(v)]);
21719
- } else if (typeof v === "object") {
21720
- out.push(...flattenConfig(v, key));
21721
- }
21722
- }
21723
- return out;
21724
- }
21725
21770
  var MUTATING_POSTFLIGHTS, SHELL_MARKER_RE, TASK_ARTIFACT_WRITE_TOOLS, MAX_CHAIN_HOPS, DEFAULT_SHELL_TIMEOUT_MS, SIGKILL_GRACE_MS;
21726
21771
  var init_executor = __esm({
21727
21772
  "src/executor.ts"() {
21728
21773
  "use strict";
21774
+ init_capabilityExecutionEnvironment();
21729
21775
  init_capability_contract_validation();
21730
21776
  init_agent();
21731
21777
  init_agents();
File without changes
@@ -140,6 +140,21 @@
140
140
  "type": "object",
141
141
  "additionalProperties": false,
142
142
  "properties": {
143
+ "version": {
144
+ "type": "object",
145
+ "additionalProperties": false,
146
+ "required": ["readCommand", "writeCommand", "files"],
147
+ "properties": {
148
+ "readCommand": { "type": "string", "minLength": 1 },
149
+ "writeCommand": { "type": "string", "minLength": 1 },
150
+ "files": {
151
+ "type": "array",
152
+ "minItems": 1,
153
+ "uniqueItems": true,
154
+ "items": { "type": "string", "minLength": 1 }
155
+ }
156
+ }
157
+ },
143
158
  "versionFiles": {
144
159
  "type": "array",
145
160
  "items": { "type": "string" }
@@ -147,6 +162,9 @@
147
162
  "publishCommand": { "type": "string" },
148
163
  "notifyCommand": { "type": "string" },
149
164
  "e2eCommand": { "type": "string" },
165
+ "productionUrl": { "type": "string" },
166
+ "smokeCommand": { "type": "string" },
167
+ "productionDeployRequired": { "type": "boolean" },
150
168
  "draftRelease": { "type": "boolean" },
151
169
  "releaseBranch": { "type": "string" },
152
170
  "allowAdminMerge": { "type": "boolean" },
@@ -170,6 +188,26 @@
170
188
  }
171
189
  }
172
190
  },
191
+ "deployment": {
192
+ "type": "object",
193
+ "additionalProperties": false,
194
+ "required": ["workflow"],
195
+ "properties": {
196
+ "workflow": {
197
+ "type": "string",
198
+ "minLength": 1
199
+ },
200
+ "inputs": {
201
+ "type": "object",
202
+ "propertyNames": {
203
+ "pattern": "^[a-z][a-z0-9_]*$"
204
+ },
205
+ "additionalProperties": {
206
+ "type": ["string", "number", "boolean"]
207
+ }
208
+ }
209
+ }
210
+ },
173
211
  "timeoutMs": {
174
212
  "type": "integer",
175
213
  "minimum": 1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.477",
3
+ "version": "0.4.479",
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
  "type": "module",
@@ -12,29 +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
- "clean:dist": "node scripts/clean-dist.cjs",
21
- "build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
22
- "check:modularity": "tsx scripts/check-script-modularity.ts",
23
- "pretest": "pnpm check:modularity",
24
- "test": "vitest run tests/unit tests/int --coverage",
25
- "posttest": "tsx scripts/check-coverage-floor.ts",
26
- "test:smoke": "vitest run tests/smoke --no-coverage",
27
- "test:e2e": "vitest run tests/e2e --no-coverage",
28
- "test:runtime-services": "node --test \"tests/runtime-services/*.test.mjs\"",
29
- "test:all": "vitest run tests --no-coverage",
30
- "typecheck": "tsc --noEmit",
31
- "lint": "biome check",
32
- "lint:fix": "biome check --write",
33
- "format": "biome format --write",
34
- "verify:package": "node scripts/verify-package-tarball.cjs",
35
- "brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain --build-arg KODY_ENGINE_REF=$(git rev-parse HEAD) -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner",
36
- "prepublishOnly": "pnpm typecheck && vitest run tests/unit tests/int --no-coverage && pnpm test:runtime-services && pnpm build && pnpm verify:package"
37
- },
38
15
  "dependencies": {
39
16
  "@actions/cache": "^6.0.0",
40
17
  "@anthropic-ai/claude-agent-sdk": "0.2.119",
@@ -61,5 +38,27 @@
61
38
  "url": "git+https://github.com/aharonyaircohen/kody-engine.git"
62
39
  },
63
40
  "homepage": "https://github.com/aharonyaircohen/kody-engine",
64
- "bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
65
- }
41
+ "bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
42
+ "scripts": {
43
+ "kody:run": "tsx bin/kody.ts",
44
+ "serve": "tsx bin/kody.ts serve",
45
+ "serve:vscode": "tsx bin/kody.ts serve vscode",
46
+ "serve:claude": "tsx bin/kody.ts serve claude",
47
+ "clean:dist": "node scripts/clean-dist.cjs",
48
+ "build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
49
+ "check:modularity": "tsx scripts/check-script-modularity.ts",
50
+ "pretest": "pnpm check:modularity",
51
+ "test": "vitest run tests/unit tests/int --coverage",
52
+ "posttest": "tsx scripts/check-coverage-floor.ts",
53
+ "test:smoke": "vitest run tests/smoke --no-coverage",
54
+ "test:e2e": "vitest run tests/e2e --no-coverage",
55
+ "test:runtime-services": "node --test \"tests/runtime-services/*.test.mjs\"",
56
+ "test:all": "vitest run tests --no-coverage",
57
+ "typecheck": "tsc --noEmit",
58
+ "lint": "biome check",
59
+ "lint:fix": "biome check --write",
60
+ "format": "biome format --write",
61
+ "verify:package": "node scripts/verify-package-tarball.cjs",
62
+ "brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain --build-arg KODY_ENGINE_REF=$(git rev-parse HEAD) -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner"
63
+ }
64
+ }