@kody-ade/kody-engine 0.4.496 → 0.4.497

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.496",
18
+ version: "0.4.497",
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",
@@ -4267,56 +4267,6 @@ var init_agencyBoundaryEval = __esm({
4267
4267
  }
4268
4268
  });
4269
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
-
4320
4270
  // src/agency/capability-contract-validation.ts
4321
4271
  import Ajv from "ajv";
4322
4272
  function validateCapabilityContractValue(boundary, schema, value) {
@@ -6949,12 +6899,16 @@ function resolveLitellmCommand() {
6949
6899
  throw new Error("litellm is importable but its console script was not found next to python3");
6950
6900
  }
6951
6901
  }
6952
- async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL) {
6902
+ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL, runtimeEnvironment = {}) {
6953
6903
  if (!needsLitellmProxy(model)) return null;
6954
6904
  const cmd = resolveLitellmCommand();
6955
6905
  let activeUrl = url.replace(/\/+$/, "");
6956
6906
  const modelGroups = litellmModelGroups(model);
6957
- const childEnv = stripBlockingEnv({ ...process.env, ...readDotenvApiKeys(projectDir) });
6907
+ const childEnv = stripBlockingEnv({
6908
+ ...process.env,
6909
+ ...readDotenvApiKeys(projectDir),
6910
+ ...runtimeEnvironment
6911
+ });
6958
6912
  let child;
6959
6913
  let logPath;
6960
6914
  const spawnProxy = () => {
@@ -7332,6 +7286,256 @@ var init_runtimeCleanup = __esm({
7332
7286
  }
7333
7287
  });
7334
7288
 
7289
+ // src/backendVault.ts
7290
+ import { createDecipheriv, createHash as createHash4 } from "crypto";
7291
+ function cacheKey(owner, repo, masterKey) {
7292
+ const keyHash = createHash4("sha256").update(masterKey).digest("hex").slice(0, 16);
7293
+ return `${owner}/${repo}:${keyHash}`.toLowerCase();
7294
+ }
7295
+ function decryptVault(payload, masterKey) {
7296
+ const parts = payload.split(":");
7297
+ if (parts.length !== 4 || parts[0] !== "v1") {
7298
+ throw new Error("invalid vault payload format");
7299
+ }
7300
+ const [, ivB64, ctB64, tagB64] = parts;
7301
+ const iv = Buffer.from(ivB64, "base64");
7302
+ const ct = Buffer.from(ctB64, "base64");
7303
+ const tag = Buffer.from(tagB64, "base64");
7304
+ const decipher = createDecipheriv("aes-256-gcm", masterKey, iv);
7305
+ decipher.setAuthTag(tag);
7306
+ return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
7307
+ }
7308
+ async function readVaultSecrets(opts) {
7309
+ const key = cacheKey(opts.owner, opts.repo, opts.masterKey);
7310
+ const hit = cache.get(key);
7311
+ if (hit && hit.expiresAt > Date.now()) return hit.secrets;
7312
+ const record2 = await createStateBackendFromEnv().getRepoDoc(`${opts.owner}/${opts.repo}`, VAULT_PATH);
7313
+ const raw = record2?.doc;
7314
+ const ciphertext = raw && typeof raw === "object" && !Array.isArray(raw) && typeof raw.ciphertext === "string" ? raw.ciphertext.trim() : "";
7315
+ if (!ciphertext) {
7316
+ cache.set(key, { secrets: {}, expiresAt: Date.now() + CACHE_TTL_MS });
7317
+ return {};
7318
+ }
7319
+ const doc = JSON.parse(decryptVault(ciphertext, opts.masterKey));
7320
+ const flat = {};
7321
+ for (const [name, entry] of Object.entries(doc.secrets ?? {})) {
7322
+ if (entry && typeof entry.value === "string") flat[name] = entry.value;
7323
+ }
7324
+ cache.set(key, { secrets: flat, expiresAt: Date.now() + CACHE_TTL_MS });
7325
+ return flat;
7326
+ }
7327
+ async function readRepoSecret(opts) {
7328
+ const secrets = await readVaultSecrets(opts);
7329
+ const v = secrets[opts.name];
7330
+ return v?.trim() ? v : null;
7331
+ }
7332
+ async function readRepoSecrets(opts) {
7333
+ return readVaultSecrets(opts);
7334
+ }
7335
+ var VAULT_PATH, CACHE_TTL_MS, cache;
7336
+ var init_backendVault = __esm({
7337
+ "src/backendVault.ts"() {
7338
+ "use strict";
7339
+ init_state_backend();
7340
+ VAULT_PATH = "secrets.enc";
7341
+ CACHE_TTL_MS = 6e4;
7342
+ cache = /* @__PURE__ */ new Map();
7343
+ }
7344
+ });
7345
+
7346
+ // src/pool/keys.ts
7347
+ import { hkdfSync } from "crypto";
7348
+ function masterKeyBytes(raw) {
7349
+ const v = raw.trim();
7350
+ if (!v) throw new Error("KODY_MASTER_KEY is empty");
7351
+ if (/^[0-9a-fA-F]+$/.test(v) && v.length === 64) {
7352
+ return Buffer.from(v, "hex");
7353
+ }
7354
+ return Buffer.from(v.replace(/-/g, "+").replace(/_/g, "/"), "base64");
7355
+ }
7356
+ function deriveKey(master, info, length = 32) {
7357
+ return Buffer.from(hkdfSync("sha256", master, Buffer.alloc(0), info, length)).toString("hex");
7358
+ }
7359
+ function derivePoolApiKey(master) {
7360
+ return deriveKey(master, POOL_API_KEY_INFO);
7361
+ }
7362
+ function deriveRunnerApiKey(master) {
7363
+ return deriveKey(master, RUNNER_API_KEY_INFO);
7364
+ }
7365
+ function bearerOk(headerAuth, xApiKey, expected) {
7366
+ const x = (xApiKey ?? "").trim();
7367
+ if (x && timingEqual(x, expected)) return true;
7368
+ const a = (headerAuth ?? "").trim();
7369
+ if (a.toLowerCase().startsWith("bearer ")) {
7370
+ return timingEqual(a.slice(7).trim(), expected);
7371
+ }
7372
+ return false;
7373
+ }
7374
+ function timingEqual(a, b) {
7375
+ if (a.length !== b.length) return false;
7376
+ let diff = 0;
7377
+ for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
7378
+ return diff === 0;
7379
+ }
7380
+ var POOL_API_KEY_INFO, RUNNER_API_KEY_INFO;
7381
+ var init_keys = __esm({
7382
+ "src/pool/keys.ts"() {
7383
+ "use strict";
7384
+ POOL_API_KEY_INFO = "kody-pool-api:v1";
7385
+ RUNNER_API_KEY_INFO = "kody-runner-api:v1";
7386
+ }
7387
+ });
7388
+
7389
+ // src/scripts/runtimeSecrets.ts
7390
+ function envSecret(name, env) {
7391
+ const value = env[name]?.trim() ? env[name] : "";
7392
+ return value ? { value, source: "env" } : { value: "", source: "missing" };
7393
+ }
7394
+ async function resolveRuntimeSecret(name, ctx, opts = {}) {
7395
+ const env = opts.env ?? process.env;
7396
+ if (hasGitHubActionsIdentity(env)) {
7397
+ try {
7398
+ const value = await readRuntimeSecretFromKody(name, env);
7399
+ if (value) return { value, source: "vault" };
7400
+ return envSecret(name, env);
7401
+ } catch (err) {
7402
+ const fallback = envSecret(name, env);
7403
+ return {
7404
+ ...fallback,
7405
+ warning: `Kody secret read failed for ${name}: ${err instanceof Error ? err.message : String(err)}`
7406
+ };
7407
+ }
7408
+ }
7409
+ const masterRaw = env.KODY_MASTER_KEY?.trim() ?? "";
7410
+ if (!masterRaw || !env.CONVEX_URL?.trim() || !env.KODY_SERVICE_KEY?.trim()) return envSecret(name, env);
7411
+ try {
7412
+ const masterKey = masterKeyBytes(masterRaw);
7413
+ if (masterKey.length !== 32) {
7414
+ throw new Error("KODY_MASTER_KEY must decode to 32 bytes");
7415
+ }
7416
+ const value = await readRepoSecret({
7417
+ owner: ctx.config.github.owner,
7418
+ repo: ctx.config.github.repo,
7419
+ name,
7420
+ masterKey
7421
+ });
7422
+ if (value) return { value, source: "vault" };
7423
+ } catch (err) {
7424
+ const fallback = envSecret(name, env);
7425
+ return {
7426
+ ...fallback,
7427
+ warning: `vault read failed for ${name}: ${err instanceof Error ? err.message : String(err)}`
7428
+ };
7429
+ }
7430
+ return envSecret(name, env);
7431
+ }
7432
+ async function resolveRuntimeSecrets(names, ctx, opts = {}) {
7433
+ const declared = Array.isArray(names) ? [...new Set(names.filter((name) => typeof name === "string" && /^[A-Z][A-Z0-9_]*$/.test(name)))] : [];
7434
+ const resolved = [];
7435
+ for (const name of declared) {
7436
+ resolved.push({ name, result: await resolveRuntimeSecret(name, ctx, opts) });
7437
+ }
7438
+ const warnings = resolved.flatMap(({ result }) => result.warning ? [result.warning] : []);
7439
+ const fallbackSecrets = Object.fromEntries(
7440
+ resolved.flatMap(({ name, result }) => result.source === "env" && result.value ? [[name, result.value]] : [])
7441
+ );
7442
+ if (hasGitHubActionsIdentity(opts.env ?? process.env) && Object.keys(fallbackSecrets).length > 0) {
7443
+ try {
7444
+ await writeRuntimeSecretsToKody(fallbackSecrets, opts.env ?? process.env);
7445
+ } catch (err) {
7446
+ warnings.push(`Kody secret migration failed: ${err instanceof Error ? err.message : String(err)}`);
7447
+ }
7448
+ }
7449
+ return {
7450
+ environment: Object.fromEntries(
7451
+ resolved.flatMap(({ name, result }) => result.value ? [[name, result.value]] : [])
7452
+ ),
7453
+ warnings
7454
+ };
7455
+ }
7456
+ var init_runtimeSecrets = __esm({
7457
+ "src/scripts/runtimeSecrets.ts"() {
7458
+ "use strict";
7459
+ init_backendVault();
7460
+ init_kody_api_client();
7461
+ init_keys();
7462
+ }
7463
+ });
7464
+
7465
+ // src/runtimeModelEnvironment.ts
7466
+ async function resolveRuntimeModelEnvironment(model, ctx) {
7467
+ const name = model.apiKeyEnvVar ?? providerApiKeyEnvVar(model.provider);
7468
+ const result = await resolveRuntimeSecret(name, ctx);
7469
+ const warnings = result.warning ? [result.warning] : [];
7470
+ if (!result.value) {
7471
+ return {
7472
+ environment: {},
7473
+ warnings: [...warnings, `Model credential ${name} is missing from the Kody vault.`]
7474
+ };
7475
+ }
7476
+ return {
7477
+ environment: { [name]: result.value },
7478
+ warnings
7479
+ };
7480
+ }
7481
+ var init_runtimeModelEnvironment = __esm({
7482
+ "src/runtimeModelEnvironment.ts"() {
7483
+ "use strict";
7484
+ init_config();
7485
+ init_runtimeSecrets();
7486
+ }
7487
+ });
7488
+
7489
+ // src/scripts/capabilityExecutionEnvironment.ts
7490
+ function capabilityInputEnvironment(input) {
7491
+ const environment = {
7492
+ KODY_CAPABILITY_INPUT: JSON.stringify(input ?? null)
7493
+ };
7494
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
7495
+ return environment;
7496
+ }
7497
+ for (const [name, value] of Object.entries(input)) {
7498
+ if (value === void 0 || value === null) continue;
7499
+ const key = environmentKey(name);
7500
+ environment[`KODY_ARG_${key}`] = typeof value === "string" ? value : JSON.stringify(value);
7501
+ }
7502
+ return environment;
7503
+ }
7504
+ function capabilityConfigEnvironment(config) {
7505
+ if (!config || typeof config !== "object" || Array.isArray(config)) return {};
7506
+ return Object.fromEntries(
7507
+ flattenConfig(config).map(([key, value]) => [
7508
+ `KODY_CFG_${key}`,
7509
+ value
7510
+ ])
7511
+ );
7512
+ }
7513
+ function flattenConfig(config, prefix = "") {
7514
+ const entries = [];
7515
+ for (const [name, value] of Object.entries(config)) {
7516
+ if (value === null || value === void 0) continue;
7517
+ const key = prefix ? `${prefix}_${environmentKey(name)}` : environmentKey(name);
7518
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
7519
+ entries.push([key, String(value)]);
7520
+ } else if (Array.isArray(value)) {
7521
+ entries.push([key, JSON.stringify(value)]);
7522
+ } else if (typeof value === "object") {
7523
+ entries.push(
7524
+ ...flattenConfig(value, key)
7525
+ );
7526
+ }
7527
+ }
7528
+ return entries;
7529
+ }
7530
+ function environmentKey(name) {
7531
+ return name.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
7532
+ }
7533
+ var init_capabilityExecutionEnvironment = __esm({
7534
+ "src/scripts/capabilityExecutionEnvironment.ts"() {
7535
+ "use strict";
7536
+ }
7537
+ });
7538
+
7335
7539
  // src/scripts/evaluateAgencyBoundaries.ts
7336
7540
  function shouldEvaluateAgencyBoundaries(data, profile) {
7337
7541
  return Boolean(agencyBoundaryCapabilityKind(data, profile));
@@ -11572,12 +11776,12 @@ var init_classifyByLabel = __esm({
11572
11776
  });
11573
11777
 
11574
11778
  // src/scripts/commitAndPush.ts
11575
- import { createHash as createHash4 } from "crypto";
11779
+ import { createHash as createHash5 } from "crypto";
11576
11780
  import * as fs31 from "fs";
11577
11781
  import * as path29 from "path";
11578
11782
  function sentinelPathForStage(cwd, profileName, workflowExecutionKey) {
11579
11783
  const runId = resolveRunId();
11580
- const executionSuffix = typeof workflowExecutionKey === "string" && workflowExecutionKey.length > 0 ? `-${createHash4("sha256").update(workflowExecutionKey).digest("hex").slice(0, 16)}` : "";
11784
+ const executionSuffix = typeof workflowExecutionKey === "string" && workflowExecutionKey.length > 0 ? `-${createHash5("sha256").update(workflowExecutionKey).digest("hex").slice(0, 16)}` : "";
11581
11785
  return runtimeStatePath(cwd, "agent-runs", runId, `commit-${profileName}${executionSuffix}.lock`);
11582
11786
  }
11583
11787
  var DEFAULT_COMMIT_MESSAGE, commitAndPush2;
@@ -15351,182 +15555,6 @@ var init_kodyVariables = __esm({
15351
15555
  }
15352
15556
  });
15353
15557
 
15354
- // src/backendVault.ts
15355
- import { createDecipheriv, createHash as createHash5 } from "crypto";
15356
- function cacheKey(owner, repo, masterKey) {
15357
- const keyHash = createHash5("sha256").update(masterKey).digest("hex").slice(0, 16);
15358
- return `${owner}/${repo}:${keyHash}`.toLowerCase();
15359
- }
15360
- function decryptVault(payload, masterKey) {
15361
- const parts = payload.split(":");
15362
- if (parts.length !== 4 || parts[0] !== "v1") {
15363
- throw new Error("invalid vault payload format");
15364
- }
15365
- const [, ivB64, ctB64, tagB64] = parts;
15366
- const iv = Buffer.from(ivB64, "base64");
15367
- const ct = Buffer.from(ctB64, "base64");
15368
- const tag = Buffer.from(tagB64, "base64");
15369
- const decipher = createDecipheriv("aes-256-gcm", masterKey, iv);
15370
- decipher.setAuthTag(tag);
15371
- return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
15372
- }
15373
- async function readVaultSecrets(opts) {
15374
- const key = cacheKey(opts.owner, opts.repo, opts.masterKey);
15375
- const hit = cache.get(key);
15376
- if (hit && hit.expiresAt > Date.now()) return hit.secrets;
15377
- const record2 = await createStateBackendFromEnv().getRepoDoc(`${opts.owner}/${opts.repo}`, VAULT_PATH);
15378
- const raw = record2?.doc;
15379
- const ciphertext = raw && typeof raw === "object" && !Array.isArray(raw) && typeof raw.ciphertext === "string" ? raw.ciphertext.trim() : "";
15380
- if (!ciphertext) {
15381
- cache.set(key, { secrets: {}, expiresAt: Date.now() + CACHE_TTL_MS });
15382
- return {};
15383
- }
15384
- const doc = JSON.parse(decryptVault(ciphertext, opts.masterKey));
15385
- const flat = {};
15386
- for (const [name, entry] of Object.entries(doc.secrets ?? {})) {
15387
- if (entry && typeof entry.value === "string") flat[name] = entry.value;
15388
- }
15389
- cache.set(key, { secrets: flat, expiresAt: Date.now() + CACHE_TTL_MS });
15390
- return flat;
15391
- }
15392
- async function readRepoSecret(opts) {
15393
- const secrets = await readVaultSecrets(opts);
15394
- const v = secrets[opts.name];
15395
- return v?.trim() ? v : null;
15396
- }
15397
- async function readRepoSecrets(opts) {
15398
- return readVaultSecrets(opts);
15399
- }
15400
- var VAULT_PATH, CACHE_TTL_MS, cache;
15401
- var init_backendVault = __esm({
15402
- "src/backendVault.ts"() {
15403
- "use strict";
15404
- init_state_backend();
15405
- VAULT_PATH = "secrets.enc";
15406
- CACHE_TTL_MS = 6e4;
15407
- cache = /* @__PURE__ */ new Map();
15408
- }
15409
- });
15410
-
15411
- // src/pool/keys.ts
15412
- import { hkdfSync } from "crypto";
15413
- function masterKeyBytes(raw) {
15414
- const v = raw.trim();
15415
- if (!v) throw new Error("KODY_MASTER_KEY is empty");
15416
- if (/^[0-9a-fA-F]+$/.test(v) && v.length === 64) {
15417
- return Buffer.from(v, "hex");
15418
- }
15419
- return Buffer.from(v.replace(/-/g, "+").replace(/_/g, "/"), "base64");
15420
- }
15421
- function deriveKey(master, info, length = 32) {
15422
- return Buffer.from(hkdfSync("sha256", master, Buffer.alloc(0), info, length)).toString("hex");
15423
- }
15424
- function derivePoolApiKey(master) {
15425
- return deriveKey(master, POOL_API_KEY_INFO);
15426
- }
15427
- function deriveRunnerApiKey(master) {
15428
- return deriveKey(master, RUNNER_API_KEY_INFO);
15429
- }
15430
- function bearerOk(headerAuth, xApiKey, expected) {
15431
- const x = (xApiKey ?? "").trim();
15432
- if (x && timingEqual(x, expected)) return true;
15433
- const a = (headerAuth ?? "").trim();
15434
- if (a.toLowerCase().startsWith("bearer ")) {
15435
- return timingEqual(a.slice(7).trim(), expected);
15436
- }
15437
- return false;
15438
- }
15439
- function timingEqual(a, b) {
15440
- if (a.length !== b.length) return false;
15441
- let diff = 0;
15442
- for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
15443
- return diff === 0;
15444
- }
15445
- var POOL_API_KEY_INFO, RUNNER_API_KEY_INFO;
15446
- var init_keys = __esm({
15447
- "src/pool/keys.ts"() {
15448
- "use strict";
15449
- POOL_API_KEY_INFO = "kody-pool-api:v1";
15450
- RUNNER_API_KEY_INFO = "kody-runner-api:v1";
15451
- }
15452
- });
15453
-
15454
- // src/scripts/runtimeSecrets.ts
15455
- function envSecret(name, env) {
15456
- const value = env[name]?.trim() ? env[name] : "";
15457
- return value ? { value, source: "env" } : { value: "", source: "missing" };
15458
- }
15459
- async function resolveRuntimeSecret(name, ctx, opts = {}) {
15460
- const env = opts.env ?? process.env;
15461
- if (hasGitHubActionsIdentity(env)) {
15462
- try {
15463
- const value = await readRuntimeSecretFromKody(name, env);
15464
- if (value) return { value, source: "vault" };
15465
- return envSecret(name, env);
15466
- } catch (err) {
15467
- const fallback = envSecret(name, env);
15468
- return {
15469
- ...fallback,
15470
- warning: `Kody secret read failed for ${name}: ${err instanceof Error ? err.message : String(err)}`
15471
- };
15472
- }
15473
- }
15474
- const masterRaw = env.KODY_MASTER_KEY?.trim() ?? "";
15475
- if (!masterRaw || !env.CONVEX_URL?.trim() || !env.KODY_SERVICE_KEY?.trim()) return envSecret(name, env);
15476
- try {
15477
- const masterKey = masterKeyBytes(masterRaw);
15478
- if (masterKey.length !== 32) {
15479
- throw new Error("KODY_MASTER_KEY must decode to 32 bytes");
15480
- }
15481
- const value = await readRepoSecret({
15482
- owner: ctx.config.github.owner,
15483
- repo: ctx.config.github.repo,
15484
- name,
15485
- masterKey
15486
- });
15487
- if (value) return { value, source: "vault" };
15488
- } catch (err) {
15489
- const fallback = envSecret(name, env);
15490
- return {
15491
- ...fallback,
15492
- warning: `vault read failed for ${name}: ${err instanceof Error ? err.message : String(err)}`
15493
- };
15494
- }
15495
- return envSecret(name, env);
15496
- }
15497
- async function resolveRuntimeSecrets(names, ctx, opts = {}) {
15498
- const declared = Array.isArray(names) ? [...new Set(names.filter((name) => typeof name === "string" && /^[A-Z][A-Z0-9_]*$/.test(name)))] : [];
15499
- const resolved = [];
15500
- for (const name of declared) {
15501
- resolved.push({ name, result: await resolveRuntimeSecret(name, ctx, opts) });
15502
- }
15503
- const warnings = resolved.flatMap(({ result }) => result.warning ? [result.warning] : []);
15504
- const fallbackSecrets = Object.fromEntries(
15505
- resolved.flatMap(({ name, result }) => result.source === "env" && result.value ? [[name, result.value]] : [])
15506
- );
15507
- if (hasGitHubActionsIdentity(opts.env ?? process.env) && Object.keys(fallbackSecrets).length > 0) {
15508
- try {
15509
- await writeRuntimeSecretsToKody(fallbackSecrets, opts.env ?? process.env);
15510
- } catch (err) {
15511
- warnings.push(`Kody secret migration failed: ${err instanceof Error ? err.message : String(err)}`);
15512
- }
15513
- }
15514
- return {
15515
- environment: Object.fromEntries(
15516
- resolved.flatMap(({ name, result }) => result.value ? [[name, result.value]] : [])
15517
- ),
15518
- warnings
15519
- };
15520
- }
15521
- var init_runtimeSecrets = __esm({
15522
- "src/scripts/runtimeSecrets.ts"() {
15523
- "use strict";
15524
- init_backendVault();
15525
- init_kody_api_client();
15526
- init_keys();
15527
- }
15528
- });
15529
-
15530
15558
  // src/scripts/loadQaContext.ts
15531
15559
  import * as fs42 from "fs";
15532
15560
  import * as path39 from "path";
@@ -21052,6 +21080,7 @@ async function runImplementation(profileName, input) {
21052
21080
  });
21053
21081
  }
21054
21082
  let litellm;
21083
+ let runtimeModelEnvironment;
21055
21084
  const ctx = {
21056
21085
  args,
21057
21086
  cwd: input.cwd,
@@ -21143,9 +21172,18 @@ async function runImplementation(profileName, input) {
21143
21172
  const syntheticPath = ctx.data.syntheticPluginPath;
21144
21173
  const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
21145
21174
  const agents = loadSubagents(profile);
21175
+ if (runtimeModelEnvironment === void 0) {
21176
+ runtimeModelEnvironment = {};
21177
+ if (needsLitellmProxy(model)) {
21178
+ const resolved2 = await resolveRuntimeModelEnvironment(model, ctx);
21179
+ runtimeModelEnvironment = resolved2.environment;
21180
+ for (const warning of resolved2.warnings) process.stderr.write(`\u26A0 ${warning}
21181
+ `);
21182
+ }
21183
+ }
21146
21184
  if (litellm === void 0) {
21147
21185
  try {
21148
- litellm = await startLitellmIfNeeded(model, input.cwd);
21186
+ litellm = await startLitellmIfNeeded(model, input.cwd, void 0, runtimeModelEnvironment);
21149
21187
  } catch (err) {
21150
21188
  throw new Error(`litellm startup failed: ${err instanceof Error ? err.message : String(err)}`);
21151
21189
  }
@@ -21155,7 +21193,10 @@ async function runImplementation(profileName, input) {
21155
21193
  prompt,
21156
21194
  model,
21157
21195
  cwd: input.cwd,
21158
- environment: ctx.data.capabilityEnvironment && typeof ctx.data.capabilityEnvironment === "object" && !Array.isArray(ctx.data.capabilityEnvironment) ? ctx.data.capabilityEnvironment : void 0,
21196
+ environment: {
21197
+ ...ctx.data.capabilityEnvironment && typeof ctx.data.capabilityEnvironment === "object" && !Array.isArray(ctx.data.capabilityEnvironment) ? ctx.data.capabilityEnvironment : {},
21198
+ ...runtimeModelEnvironment
21199
+ },
21159
21200
  litellmUrl: lm?.url ?? null,
21160
21201
  // On a connection drop mid-run, restart the (possibly crashed) proxy
21161
21202
  // before the agent retries. No-op for direct-Anthropic runs (lm null).
@@ -21847,7 +21888,6 @@ var MUTATING_POSTFLIGHTS, SHELL_MARKER_RE, TASK_ARTIFACT_WRITE_TOOLS, MAX_CHAIN_
21847
21888
  var init_executor = __esm({
21848
21889
  "src/executor.ts"() {
21849
21890
  "use strict";
21850
- init_capabilityExecutionEnvironment();
21851
21891
  init_capability_contract_validation();
21852
21892
  init_agent();
21853
21893
  init_agents();
@@ -21863,7 +21903,9 @@ var init_executor = __esm({
21863
21903
  init_registry();
21864
21904
  init_runIndex();
21865
21905
  init_runtimeCleanup();
21906
+ init_runtimeModelEnvironment();
21866
21907
  init_runtimePaths();
21908
+ init_capabilityExecutionEnvironment();
21867
21909
  init_evaluateAgencyBoundaries();
21868
21910
  init_scripts();
21869
21911
  init_stateWorkspace();
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.496",
3
+ "version": "0.4.497",
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
+ }